Strace ni Linux: itan, oniru ati lilo

Strace ni Linux: itan, oniru ati lilo

Ni awọn ọna ṣiṣe bii Unix, ibaraẹnisọrọ eto pẹlu agbaye ita ati ẹrọ ṣiṣe waye nipasẹ eto iṣẹ kekere kan - awọn ipe eto. Eyi tumọ si pe fun awọn idi n ṣatunṣe aṣiṣe o le wulo lati ṣe amí lori awọn ipe eto ni ṣiṣe nipasẹ awọn ilana.

IwUlO kan ṣe iranlọwọ fun ọ lati ṣe atẹle “igbesi aye timotimo” ti awọn eto lori Lainos strace, eyiti o jẹ koko-ọrọ ti nkan yii. Awọn apẹẹrẹ ti lilo awọn ohun elo amí wa pẹlu itan kukuru kan strace ati apejuwe ti awọn oniru ti iru awọn eto.

Awọn akoonu

Oti ti eya

Ni wiwo akọkọ laarin awọn eto ati ekuro OS ni Unix jẹ awọn ipe eto. awọn ipe eto, syscals), ibaraenisepo ti awọn eto pẹlu ita ita waye nipasẹ wọn nikan.

Ṣugbọn ni ẹya akọkọ ti gbangba ti Unix (Ẹya 6 Unix, 1975) ko si awọn ọna irọrun lati tọpa ihuwasi ti awọn ilana olumulo. Lati yanju ọran yii, Bell Labs yoo ṣe imudojuiwọn si ẹya atẹle (Ẹya 7 Unix, 1979) dabaa ipe eto titun kan - ptrace.

ptrace ti ni idagbasoke ni akọkọ fun awọn olutọpa ibaraenisepo, ṣugbọn ni opin awọn ọdun 80 (ni akoko ti iṣowo Itusilẹ eto V 4) lori ipilẹ yii, awọn olutọpa ti o ni idojukọ dín — awọn olutọpa ipe eto — han ati di lilo pupọ.

Ni igba akọkọ ti ẹya kanna ti strace ni a tẹjade nipasẹ Paul Cronenburg lori atokọ ifiweranṣẹ comp.sources.sun ni ọdun 1992 bi yiyan si ohun elo pipade trace lati Sun. Mejeeji ẹda oniye ati atilẹba jẹ ipinnu fun SunOS, ṣugbọn nipasẹ ọdun 1994 strace ti gbejade si System V, Solaris ati Lainos olokiki ti o pọ si.

Loni strace ṣe atilẹyin Linux nikan ati dale lori kanna ptrace, poju pẹlu ọpọlọpọ awọn amugbooro.

Modern (ati ki o gidigidi lọwọ) olutọju strace - Dmitry Levin. Ṣeun si i, ohun elo naa gba awọn ẹya ilọsiwaju gẹgẹbi abẹrẹ aṣiṣe sinu awọn ipe eto, atilẹyin fun ọpọlọpọ awọn faaji ati, pataki julọ, mascot. Awọn orisun laigba aṣẹ beere pe yiyan naa ṣubu lori ostrich nitori ifọkanbalẹ laarin ọrọ Russian “ostrich” ati ọrọ Gẹẹsi “strace”.

O tun ṣe pataki pe ipe eto ptrace ati awọn olutọpa ko wa ninu POSIX, laibikita itan-akọọlẹ gigun ati imuse ni Lainos, FreeBSD, OpenBSD ati Unix ibile.

Ẹrọ Strace ni kukuru: Piglet Trace

"O ko nireti lati loye eyi" (Dennis Ritchie, asọye ni Ẹya 6 koodu orisun Unix)

Lati igba ewe, Emi ko le duro awọn apoti dudu: Emi ko ṣere pẹlu awọn nkan isere, ṣugbọn gbiyanju lati ni oye eto wọn (awọn agbalagba lo ọrọ naa "fifọ," ṣugbọn ko gbagbọ awọn ahọn buburu). Boya eyi ni idi ti aṣa aiṣedeede ti Unix akọkọ ati egbe ṣiṣi-orisun igbalode ti sunmọ mi.

Fun awọn idi ti nkan yii, ko bọgbọnmu lati ṣajọ koodu orisun ti strace, eyiti o ti dagba ni awọn ọdun sẹhin. Ṣugbọn ko yẹ ki o jẹ awọn aṣiri ti o fi silẹ fun awọn onkawe. Nitorinaa, lati ṣafihan ipilẹ ti iṣiṣẹ ti iru awọn eto strace, Emi yoo pese koodu fun olutọpa kekere kan - Piglet Trace (ptr). Ko mọ bi o ṣe le ṣe ohunkohun pataki, ṣugbọn ohun akọkọ ni awọn ipe eto ti eto naa - o jade:

$ gcc examples/piglet-trace.c -o ptr
$ ptr echo test > /dev/null
BRK(12) -> 94744690540544
ACCESS(21) -> 18446744073709551614
ACCESS(21) -> 18446744073709551614
unknown(257) -> 3
FSTAT(5) -> 0
MMAP(9) -> 140694657216512
CLOSE(3) -> 0
ACCESS(21) -> 18446744073709551614
unknown(257) -> 3
READ(0) -> 832
FSTAT(5) -> 0
MMAP(9) -> 140694657208320
MMAP(9) -> 140694650953728
MPROTECT(10) -> 0
MMAP(9) -> 140694655045632
MMAP(9) -> 140694655070208
CLOSE(3) -> 0
unknown(158) -> 0
MPROTECT(10) -> 0
MPROTECT(10) -> 0
MPROTECT(10) -> 0
MUNMAP(11) -> 0
BRK(12) -> 94744690540544
BRK(12) -> 94744690675712
unknown(257) -> 3
FSTAT(5) -> 0
MMAP(9) -> 140694646390784
CLOSE(3) -> 0
FSTAT(5) -> 0
IOCTL(16) -> 18446744073709551591
WRITE(1) -> 5
CLOSE(3) -> 0
CLOSE(3) -> 0
unknown(231)
Tracee terminated

Piglet Trace ṣe idanimọ nipa awọn ọgọọgọrun ti awọn ipe eto Linux (wo. tabili) ati ki o ṣiṣẹ nikan lori x86-64 faaji. Eyi to fun awọn idi ẹkọ.

Jẹ ki a wo iṣẹ ti ẹda oniye wa. Ninu ọran ti Lainos, awọn olutọpa ati awọn olutọpa lo, gẹgẹbi a ti sọ loke, ipe eto ptrace. O ṣiṣẹ nipa gbigbe ni ariyanjiyan akọkọ awọn idamọ aṣẹ, eyiti a nilo nikan PTRACE_TRACEME, PTRACE_SYSCALL и PTRACE_GETREGS.

Olutọpa bẹrẹ ni aṣa Unix deede: fork(2) ifilọlẹ ọmọ ilana, eyi ti o ni Tan nlo exec(3) ṣe ifilọlẹ eto ti o wa labẹ ikẹkọ. Awọn arekereke nikan nibi ni ipenija ptrace(PTRACE_TRACEME) diẹ ẹ sii exec: Ilana ọmọ nireti ilana obi lati ṣe atẹle rẹ:

pid_t child_pid = fork();
switch (child_pid) {
case -1:
    err(EXIT_FAILURE, "fork");
case 0:
    /* Child here */
    /* A traced mode has to be enabled. A parent will have to wait(2) for it
     * to happen. */
    ptrace(PTRACE_TRACEME, 0, NULL, NULL);
    /* Replace itself with a program to be run. */
    execvp(argv[1], argv + 1);
    err(EXIT_FAILURE, "exec");
}

Ilana obi yẹ ki o pe bayi wait(2) ninu ilana ọmọ, iyẹn ni, rii daju pe iyipada si ipo itọpa ti ṣẹlẹ:

/* Parent */

/* First we wait for the child to set the traced mode (see
 * ptrace(PTRACE_TRACEME) above) */
if (waitpid(child_pid, NULL, 0) == -1)
    err(EXIT_FAILURE, "traceme -> waitpid");

Ni aaye yii, awọn igbaradi ti pari ati pe o le tẹsiwaju taara si awọn ipe eto titele ni lupu ailopin.

Pe ptrace(PTRACE_SYSCALL) onigbọwọ wipe o tele wait obi yoo pari boya ṣaaju ṣiṣe ipe eto tabi lẹsẹkẹsẹ lẹhin ti o pari. Laarin awọn ipe meji o le ṣe awọn iṣe eyikeyi: rọpo ipe pẹlu omiiran miiran, yi awọn ariyanjiyan pada tabi iye ipadabọ.

A kan nilo lati pe aṣẹ naa lẹẹmeji ptrace(PTRACE_GETREGS)lati gba ipo iforukọsilẹ rax ṣaaju ipe (nọmba ipe eto) ati lẹsẹkẹsẹ lẹhin (iye ipadabọ).

Lootọ, iwọnyi:

/* A system call tracing loop, one interation per call. */
for (;;) {
    /* A non-portable structure defined for ptrace/GDB/strace usage mostly.
     * It allows to conveniently dump and access register state using
     * ptrace. */
    struct user_regs_struct registers;

    /* Enter syscall: continue execution until the next system call
     * beginning. Stop right before syscall.
     *
     * It's possible to change the system call number, system call
     * arguments, return value or even avoid executing the system call
     * completely. */
  if (ptrace(PTRACE_SYSCALL, child_pid, NULL, NULL) == -1)
      err(EXIT_FAILURE, "enter_syscall");
  if (waitpid(child_pid, NULL, 0) == -1)
      err(EXIT_FAILURE, "enter_syscall -> waitpid");

  /* According to the x86-64 system call convention on Linux (see man 2
   * syscall) the number identifying a syscall should be put into the rax
   * general purpose register, with the rest of the arguments residing in
   * other general purpose registers (rdi,rsi, rdx, r10, r8, r9). */
  if (ptrace(PTRACE_GETREGS, child_pid, NULL, &registers) == -1)
      err(EXIT_FAILURE, "enter_syscall -> getregs");

  /* Note how orig_rax is used here. That's because on x86-64 rax is used
   * both for executing a syscall, and returning a value from it. To
   * differentiate between the cases both rax and orig_rax are updated on
   * syscall entry/exit, and only rax is updated on exit. */
  print_syscall_enter(registers.orig_rax);

  /* Exit syscall: execute of the syscall, and stop on system
   * call exit.
   *
   * More system call tinkering possible: change the return value, record
   * time it took to finish the system call, etc. */
  if (ptrace(PTRACE_SYSCALL, child_pid, NULL, NULL) == -1)
      err(EXIT_FAILURE, "exit_syscall");
  if (waitpid(child_pid, NULL, 0) == -1)
      err(EXIT_FAILURE, "exit_syscall -> waitpid");

  /* Retrieve register state again as we want to inspect system call
   * return value. */
  if (ptrace(PTRACE_GETREGS, child_pid, NULL, &registers) == -1) {
      /* ESRCH is returned when a child terminates using a syscall and no
       * return value is possible, e.g. as a result of exit(2). */
      if (errno == ESRCH) {
          fprintf(stderr, "nTracee terminatedn");
          break;
      }
      err(EXIT_FAILURE, "exit_syscall -> getregs");
  }

  /* Done with this system call, let the next iteration handle the next
   * one */
  print_syscall_exit(registers.rax);
}

Iyẹn ni gbogbo olutọpa. Bayi o mọ ibiti o ti le bẹrẹ ibudo atẹle DTrace lori Linux.

Ipilẹ: nṣiṣẹ a eto nṣiṣẹ strace

Gẹgẹbi ọran lilo akọkọ strace, boya o tọ lati tọka ọna ti o rọrun julọ - ifilọlẹ ohun elo nṣiṣẹ strace.

Ni ibere ki o má ba lọ sinu atokọ ailopin ti awọn ipe ti eto aṣoju, a kọ kere eto ni ayika write:

int main(int argc, char *argv[])
{
    char str[] = "write me to stdoutn";
    /* write(2) is a simple wrapper around a syscall so it should be easy to
     * find in the syscall trace. */
    if (sizeof(str) != write(STDOUT_FILENO, str, sizeof(str))){
        perror("write");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

Jẹ ki a kọ eto naa ki o rii daju pe o ṣiṣẹ:

$ gcc examples/write-simple.c -o write-simple
$ ./write-simple
write me to stdout

Ati nikẹhin, jẹ ki a ṣiṣẹ labẹ iṣakoso strace:

$ strace ./write-simple
pexecve("./write", ["./write"], 0x7ffebd6145b0 /* 71 vars */) = 0
brk(NULL)                               = 0x55ff5489e000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=197410, ...}) = 0
mmap(NULL, 197410, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7a2a633000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF21133>1260342"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7a2a631000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7a2a04c000
mprotect(0x7f7a2a233000, 2097152, PROT_NONE) = 0
mmap(0x7f7a2a433000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f7a2a433000
mmap(0x7f7a2a439000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7a2a439000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f7a2a6324c0) = 0
mprotect(0x7f7a2a433000, 16384, PROT_READ) = 0
mprotect(0x55ff52b52000, 4096, PROT_READ) = 0
mprotect(0x7f7a2a664000, 4096, PROT_READ) = 0
munmap(0x7f7a2a633000, 197410)          = 0
write(1, "write me to stdoutn", 20write me to stdout
)  = 20
exit_group(0)                           = ?

Pupọ “ọrọ” ati kii ṣe ẹkọ pupọ. Awọn iṣoro meji wa nibi: iṣẹjade eto ti dapọ pẹlu iṣẹjade strace ati awọn ẹya opo ti awọn ipe eto ti ko ni anfani wa.

O le ya awọn eto ká boṣewa o wu san ati strace o wu aṣiṣe nipa lilo awọn -o yipada, eyi ti o àtúnjúwe awọn akojọ ti awọn ipe eto si ohun ariyanjiyan faili.

O wa lati koju iṣoro ti awọn ipe “afikun”. Jẹ ki a ro pe a nifẹ si awọn ipe nikan write. Bọtini -e faye gba o lati pato awọn ikosile nipa eyi ti awọn ipe eto yoo wa ni filtered. Aṣayan ipo olokiki julọ ni, nipa ti ara, trace=*, pẹlu eyiti o le fi awọn ipe nikan ti o nifẹ si wa.

Nigbati o ba lo nigbakanna -o и -e a yoo gba:

$ strace -e trace=write -owrite-simple.log ./write-simple
write me to stdout
$ cat write-simple.log
write(1, "write me to stdoutn", 20
)  = 20
+++ exited with 0 +++

Nitorinaa, o rii, o rọrun pupọ lati ka.

O tun le yọ awọn ipe eto kuro, fun apẹẹrẹ awọn ti o ni ibatan si ipin iranti ati idasilẹ:

$ strace -e trace=!brk,mmap,mprotect,munmap -owrite-simple.log ./write-simple
write me to stdout
$ cat write-simple.log
execve("./write-simple", ["./write-simple"], 0x7ffe9972a498 /* 69 vars */) = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=124066, ...}) = 0
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF21133>1260342"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f00f0be74c0) = 0
write(1, "write me to stdoutn", 20)  = 20
exit_group(0)                           = ?
+++ exited with 0 +++

Ṣe akiyesi ami iyanju ti o salọ ninu atokọ ti awọn ipe ti a yọkuro: eyi ni a beere nipasẹ ikarahun aṣẹ. ikarahun).

Ninu ẹya mi ti glibc, ipe eto kan fopin si ilana naa exit_group, kii ṣe aṣa _exit. Eyi ni iṣoro ti ṣiṣẹ pẹlu awọn ipe eto: wiwo pẹlu eyiti olupilẹṣẹ n ṣiṣẹ ko ni ibatan taara si awọn ipe eto. Pẹlupẹlu, o yipada nigbagbogbo da lori imuse ati pẹpẹ.

Awọn ipilẹ: didapọ mọ ilana lori fo

Ni ibẹrẹ, ipe eto ptrace lori eyiti o ti kọ strace, le ṣee lo nikan nigbati o nṣiṣẹ eto ni ipo pataki kan. Opin yii le ti dun ni oye ni awọn ọjọ ti Ẹya 6 Unix. Ni ode oni, eyi ko to: nigbakan o nilo lati ṣe iwadii awọn iṣoro ti eto iṣẹ kan. Apeere aṣoju jẹ ilana ti dina lori mimu tabi sisun. Nitorina igbalode strace le darapọ mọ awọn ilana lori fo.

Apeere didi eto naa:

int main(int argc, char *argv[])
{
    (void) argc; (void) argv;

    char str[] = "write men";

    write(STDOUT_FILENO, str, sizeof(str));

    /* Sleep indefinitely or until a signal arrives */
    pause();

    write(STDOUT_FILENO, str, sizeof(str));

    return EXIT_SUCCESS;
}

Jẹ ki a kọ eto naa ki o rii daju pe o ti di tutu:

$ gcc examples/write-sleep.c -o write-sleep
$ ./write-sleep
./write-sleep
write me
^C
$

Bayi jẹ ki a gbiyanju lati darapọ mọ rẹ:

$ ./write-sleep &
[1] 15329
write me
$ strace -p 15329
strace: Process 15329 attached
pause(
^Cstrace: Process 15329 detached
 <detached ...>

Eto dina nipasẹ ipe pause. Jẹ ki a wo bi o ṣe ṣe si awọn ifihan agbara:

$ strace -o write-sleep.log -p 15329 &
strace: Process 15329 attached
$
$ kill -CONT 15329
$ cat write-sleep.log
pause()                                 = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
pause(
$
$ kill -TERM 15329
$ cat write-sleep.log
pause()                                 = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
pause()                                 = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
+++ killed by SIGTERM +++

A ṣe ifilọlẹ eto tio tutunini ati darapọ mọ pẹlu lilo strace. Awọn nkan meji di mimọ: ipe eto idaduro foju awọn ifihan agbara laisi awọn oluṣakoso ati, ni iyanilenu, awọn atẹle strace kii ṣe awọn ipe eto nikan, ṣugbọn awọn ifihan agbara ti nwọle.

Apeere: Ipasẹ Awọn ilana Ọmọ

Ṣiṣẹ pẹlu awọn ilana nipasẹ ipe kan fork - ipilẹ gbogbo Unixes. Jẹ ki a wo bii strace ṣe n ṣiṣẹ pẹlu igi ilana nipa lilo apẹẹrẹ ti “ibisi” ti o rọrun. eto naa:

int main(int argc, char *argv[])
{
    pid_t parent_pid = getpid();
    pid_t child_pid = fork();
    if (child_pid == 0) {
        /* A child is born! */
        child_pid = getpid();

        /* In the end of the day printf is just a call to write(2). */
        printf("child (self=%d)n", child_pid);
        exit(EXIT_SUCCESS);
    }

    printf("parent (self=%d, child=%d)n", parent_pid, child_pid);

    wait(NULL);

    exit(EXIT_SUCCESS);
}

Nibi ilana atilẹba ṣẹda ilana ọmọ, mejeeji kikọ si iṣẹjade boṣewa:

$ gcc examples/fork-write.c -o fork-write
$ ./fork-write
parent (self=11274, child=11275)
child (self=11275)

Nipa aiyipada, a yoo rii awọn ipe eto nikan lati ilana obi:

$ strace -e trace=write -ofork-write.log ./fork-write
child (self=22049)
parent (self=22048, child=22049)
$ cat fork-write.log
write(1, "parent (self=22048, child=22049)"..., 33) = 33
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22049, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

Asia ṣe iranlọwọ fun ọ lati tọpa gbogbo igi ilana naa -f, eyiti strace diigi eto awọn ipe ni ọmọ lakọkọ. Eyi ṣe afikun si laini iṣẹjade kọọkan pid ilana ti o mu ki eto jade:

$ strace -f -e trace=write -ofork-write.log ./fork-write
parent (self=22710, child=22711)
child (self=22711)
$ cat fork-write.log
22710 write(1, "parent (self=22710, child=22711)"..., 33) = 33
22711 write(1, "child (self=22711)n", 19) = 19
22711 +++ exited with 0 +++
22710 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22711, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
22710 +++ exited with 0 +++

Ni aaye yii, sisẹ nipasẹ ẹgbẹ awọn ipe eto le wulo:

$ strace -f -e trace=%process -ofork-write.log ./fork-write
parent (self=23610, child=23611)
child (self=23611)
$ cat fork-write.log
23610 execve("./fork-write", ["./fork-write"], 0x7fff696ff720 /* 63 vars */) = 0
23610 arch_prctl(ARCH_SET_FS, 0x7f3d03ba44c0) = 0
23610 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f3d03ba4790) = 23611
23610 wait4(-1,  <unfinished ...>
23611 exit_group(0)                     = ?
23611 +++ exited with 0 +++
23610 <... wait4 resumed> NULL, 0, NULL) = 23611
23610 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=23611, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
23610 exit_group(0)                     = ?
23610 +++ exited with 0 +++

Nipa ọna, kini ipe eto ti a lo lati ṣẹda ilana tuntun kan?

Apeere: Awọn ọna faili dipo awọn ọwọ

Mọ awọn apejuwe faili jẹ iwulo nitõtọ, ṣugbọn awọn orukọ ti awọn faili kan pato ti eto n wọle si le tun wa ni ọwọ.

Nigbamii ti o wa eto naa kọ ila si faili igba diẹ:

void do_write(int out_fd)
{
    char str[] = "write me to a filen";

    if (sizeof(str) != write(out_fd, str, sizeof(str))){
        perror("write");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    char tmp_filename_template[] = "/tmp/output_fileXXXXXX";

    int out_fd = mkstemp(tmp_filename_template);
    if (out_fd == -1) {
        perror("mkstemp");
        exit(EXIT_FAILURE);
    }

    do_write(out_fd);

    return EXIT_SUCCESS;
}

Lakoko ipe deede strace yoo ṣe afihan iye nọmba onitumọ ti o kọja si ipe eto naa:

$ strace -e trace=write -o write-tmp-file.log ./write-tmp-file
$ cat write-tmp-file.log
write(3, "write me to a filen", 20)  = 20
+++ exited with 0 +++

Pẹlu asia -y IwUlO n ṣe afihan ọna si faili eyiti apejuwe ṣe badọgba:

$ strace -y -e trace=write -o write-tmp-file.log ./write-tmp-file
$ cat write-tmp-file.log
write(3</tmp/output_fileCf5MyW>, "write me to a filen", 20) = 20
+++ exited with 0 +++

Apeere: Titele Wiwọle Faili

Ẹya ti o wulo miiran: ṣafihan awọn ipe eto nikan ni nkan ṣe pẹlu faili kan pato. Itele eto naa fi ila kan si faili lainidii ti o kọja bi ariyanjiyan:

void do_write(int out_fd)
{
    char str[] = "write me to a filen";

    if (sizeof(str) != write(out_fd, str, sizeof(str))){
        perror("write");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    /*
     * Path will be provided by the first program argument.
     *  */
    const char *path = argv[1];

    /*
     * Open an existing file for writing in append mode.
     *  */
    int out_fd = open(path, O_APPEND | O_WRONLY);
    if (out_fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    do_write(out_fd);

    return EXIT_SUCCESS;
}

Nipa aiyipada strace ṣafihan ọpọlọpọ alaye ti ko wulo. Flag -P pẹlu ariyanjiyan fa strace lati tẹjade awọn ipe nikan si faili ti a sọ pato:

$ strace -y -P/tmp/test_file.log -o write-file.log ./write-file /tmp/test_file.log
$ cat write-file.log
openat(AT_FDCWD, "/tmp/test_file.log", O_WRONLY|O_APPEND) = 3</tmp/test_file.log>
write(3</tmp/test_file.log>, "write me to a filen", 20) = 20
+++ exited with 0 +++

Apeere: Awọn Eto Onitẹpọ

IwUlO strace tun le ṣe iranlọwọ nigbati o ba ṣiṣẹ pẹlu olona-asapo eto. Eto atẹle naa kọwe si iṣelọpọ boṣewa lati awọn ṣiṣan meji:

void *thread(void *arg)
{
    (void) arg;

    printf("Secondary thread: workingn");
    sleep(1);
    printf("Secondary thread: donen");

    return NULL;
}

int main(int argc, char *argv[])
{
    printf("Initial thread: launching a threadn");

    pthread_t thr;
    if (0 != pthread_create(&thr, NULL, thread, NULL)) {
        fprintf(stderr, "Initial thread: failed to create a thread");
        exit(EXIT_FAILURE);
    }

    printf("Initial thread: joining a threadn");
    if (0 != pthread_join(thr, NULL)) {
        fprintf(stderr, "Initial thread: failed to join a thread");
        exit(EXIT_FAILURE);
    };

    printf("Initial thread: done");

    exit(EXIT_SUCCESS);
}

Nipa ti, o gbọdọ ṣe akopọ pẹlu ikini pataki kan si ọna asopọ - asia -pthread:

$ gcc examples/thread-write.c -pthread -o thread-write
$ ./thread-write
/thread-write
Initial thread: launching a thread
Initial thread: joining a thread
Secondary thread: working
Secondary thread: done
Initial thread: done
$

Flag -f, bi ninu ọran ti awọn ilana deede, yoo ṣafikun pid ti ilana naa si ibẹrẹ ti laini kọọkan.

Nipa ti ara, a ko sọrọ nipa idanimọ okun ni ori ti imuse ti boṣewa POSIX Threads, ṣugbọn nipa nọmba ti oluṣeto iṣẹ ṣiṣe ni Linux. Lati oju wiwo igbehin, ko si awọn ilana tabi awọn okun - awọn iṣẹ ṣiṣe wa ti o nilo lati pin laarin awọn ohun kohun ti ẹrọ naa.

Nigbati o ba n ṣiṣẹ ni ọpọlọpọ awọn okun, awọn ipe eto di pupọ:

$ strace -f -othread-write.log ./thread-write
$ wc -l thread-write.log
60 thread-write.log

O jẹ oye lati fi opin si ararẹ si iṣakoso ilana ati awọn ipe eto nikan write:

$ strace -f -e trace="%process,write" -othread-write.log ./thread-write
$ cat thread-write.log
18211 execve("./thread-write", ["./thread-write"], 0x7ffc6b8d58f0 /* 64 vars */) = 0
18211 arch_prctl(ARCH_SET_FS, 0x7f38ea3b7740) = 0
18211 write(1, "Initial thread: launching a thre"..., 35) = 35
18211 clone(child_stack=0x7f38e9ba2fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f38e9ba39d0, tls=0x7f38e9ba3700, child_tidptr=0x7f38e9ba39d0) = 18212
18211 write(1, "Initial thread: joining a thread"..., 33) = 33
18212 write(1, "Secondary thread: workingn", 26) = 26
18212 write(1, "Secondary thread: donen", 23) = 23
18212 exit(0)                           = ?
18212 +++ exited with 0 +++
18211 write(1, "Initial thread: done", 20) = 20
18211 exit_group(0)                     = ?
18211 +++ exited with 0 +++

Nipa ọna, awọn ibeere. Ipe eto wo ni a lo lati ṣẹda okun tuntun kan? Bawo ni ipe fun awọn okun ṣe yatọ si ipe fun awọn ilana?

Titunto si kilasi: akopọ ilana ni akoko ipe eto kan

Ọkan ninu awọn laipe han strace awọn agbara - iṣafihan akopọ ti awọn ipe iṣẹ ni akoko ipe eto. Rọrun apẹẹrẹ:

void do_write(void)
{
    char str[] = "write me to stdoutn";
    if (sizeof(str) != write(STDOUT_FILENO, str, sizeof(str))){
        perror("write");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    do_write();
    return EXIT_SUCCESS;
}

Nipa ti, iṣelọpọ eto naa di pupọ, ati, ni afikun si asia -k (ifihan akopọ ipe), o jẹ oye lati ṣe àlẹmọ awọn ipe eto nipasẹ orukọ:

$ gcc examples/write-simple.c -o write-simple
$ strace -k -e trace=write -o write-simple.log ./write-simple
write me to stdout
$ cat write-simple.log
write(1, "write me to stdoutn", 20)  = 20
 > /lib/x86_64-linux-gnu/libc-2.27.so(__write+0x14) [0x110154]
 > /home/vkazanov/projects-my/strace-post/write-simple(do_write+0x50) [0x78a]
 > /home/vkazanov/projects-my/strace-post/write-simple(main+0x14) [0x7d1]
 > /lib/x86_64-linux-gnu/libc-2.27.so(__libc_start_main+0xe7) [0x21b97]
 > /home/vkazanov/projects-my/strace-post/write-simple(_start+0x2a) [0x65a]
+++ exited with 0 +++

Titunto si kilasi: abẹrẹ aṣiṣe

Ati ẹya tuntun diẹ sii ati iwulo pupọ: abẹrẹ aṣiṣe. Nibi eto naa, kikọ awọn ila meji si ṣiṣan ti njade:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void do_write(const char *str, ssize_t len)
{
    if (len != write(STDOUT_FILENO, str, (size_t)len)){
        perror("write");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    (void) argc; (void) argv;

    char str1[] = "write me 1n";
    do_write(str1, sizeof(str1));

    char str2[] = "write me 2n";
    do_write(str2, sizeof(str2));

    return EXIT_SUCCESS;
}

Jẹ ki a tọpa awọn ipe mejeeji kọ:

$ gcc examples/write-twice.c -o write-twice
$ ./write-twice
write me 1
write me 2
$ strace -e trace=write -owrite-twice.log ./write-twice
write me 1
write me 2
$ cat write-twice.log
write(1, "write me 1n", 12)          = 12
write(1, "write me 2n", 12)          = 12
+++ exited with 0 +++

Bayi a lo ọrọ naa injectlati fi sii aṣiṣe EBADF ni gbogbo kọ awọn ipe:

$ strace -e trace=write -e inject=write:error=EBADF -owrite-twice.log ./write-twice
$ cat write-twice.log
write(1, "write me 1n", 12)          = -1 EBADF (Bad file descriptor) (INJECTED)
write(3, "write: Bad file descriptorn", 27) = -1 EBADF (Bad file descriptor) (INJECTED)
+++ exited with 1 +++

O jẹ iyanilenu kini awọn aṣiṣe pada gbogbo awọn italaya write, pẹlu ipe ti o farapamọ lẹhin ẹru. O jẹ oye nikan lati da aṣiṣe pada fun akọkọ ti awọn ipe:

$ strace -e trace=write -e inject=write:error=EBADF:when=1 -owrite-twice.log ./write-twice
write: Bad file descriptor
$ cat write-twice.log
write(1, "write me 1n", 12)          = -1 EBADF (Bad file descriptor) (INJECTED)
write(3, "write: Bad file descriptorn", 27) = 27
+++ exited with 1 +++

Tabi keji:

$ strace -e trace=write -e inject=write:error=EBADF:when=2 -owrite-twice.log ./write-twice
write me 1
write: Bad file descriptor
$ cat write-twice.log
write(1, "write me 1n", 12)          = 12
write(1, "write me 2n", 12)          = -1 EBADF (Bad file descriptor) (INJECTED)
write(3, "write: Bad file descriptorn", 27) = 27
+++ exited with 1 +++

Ko ṣe pataki lati pato iru aṣiṣe:

$ strace -e trace=write -e fault=write:when=1 -owrite-twice.log ./write-twice
$ cat write-twice.log
write(1, "write me 1n", 12)          = -1 ENOSYS (Function not implemented) (INJECTED)
write(3, "write: Function not implementedn", 32) = 32
+++ exited with 1 +++

Ni apapo pẹlu awọn asia miiran, o le "fifọ" wiwọle si faili kan pato. Apeere:

$ strace -y -P/tmp/test_file.log -e inject=file:error=ENOENT -o write-file.log ./write-file /tmp/test_file.log
open: No such file or directory
$ cat write-file.log
openat(AT_FDCWD, "/tmp/test_file.log", O_WRONLY|O_APPEND) = -1 ENOENT (No such file or directory) (INJECTED)
+++ exited with 1 +++

Ni afikun si abẹrẹ aṣiṣe, le ṣafihan awọn idaduro nigba ṣiṣe awọn ipe tabi gbigba awọn ifihan agbara.

Lẹhin Ọrọ

IwUlO strace - ohun elo ti o rọrun ati igbẹkẹle. Ṣugbọn ni afikun si awọn ipe eto, awọn ẹya miiran ti iṣẹ ti awọn eto ati ẹrọ ṣiṣe le jẹ yokokoro. Fun apẹẹrẹ, o le tọpa awọn ipe si awọn ile-ikawe ti o ni asopọ ni agbara. ltrace, wọn le wo iṣẹ ti ẹrọ ṣiṣe SystemTap и fifọ, ati ki o faye gba o lati jinna iwadi iṣẹ eto lofinda. Sibẹsibẹ, o jẹ strace - akọkọ ila ti olugbeja ni irú ti awọn iṣoro pẹlu ara mi ati awọn miiran eniyan eto, ati ki o Mo lo o ni o kere kan tọkọtaya ti igba kan ọsẹ.

Ni kukuru, ti o ba nifẹ Unix, ka man 1 strace ati ki o lero ọfẹ lati wo awọn eto rẹ!

orisun: www.habr.com

Fi ọrọìwòye kun