Strace na Linux: akụkọ ihe mere eme, imewe na ojiji

Strace na Linux: akụkọ ihe mere eme, imewe na ojiji

Na sistemụ arụmọrụ dị ka Unix, nkwurịta okwu mmemme na ụwa dị n'èzí na sistemụ arụ ọrụ na-eme site na obere usoro ọrụ - oku sistemụ. Nke a pụtara na maka debugging nzube ọ nwere ike bara uru ka ndị nledo na usoro oku na-egbu site Filiks.

Ngwa na-enyere gị aka inyocha “ndụ chiri anya” nke mmemme na Linux strace, nke bụ isiokwu nke isiokwu a. Ihe atụ nke iji ngwa nledo na obere akụkọ ihe mere eme na-esonyere ya strace na nkọwa nke imewe nke mmemme ndị dị otú ahụ.

Ihe

Mmalite nke ụdị

Isi ihe dị n'etiti mmemme na kernel OS dị na Unix bụ oku sistemụ. oku usoro, okpokoro), mmekọrịta nke mmemme na ụwa dị n'èzí na-eme naanị site na ha.

Mana na mbipụta ọha mbụ nke Unix (Ụdị 6 Unix, 1975) enweghị ụzọ dabara adaba iji soro omume nke usoro ndị ọrụ. Iji dozie esemokwu a, Bell Labs ga-emelite na ụdị ọzọ (Ụdị 7 Unix, 1979) tụrụ aro oku usoro ọhụrụ - ptrace.

Emepụtara ptrace bụ isi maka ndị debuggers mmekọrịta, mana na njedebe nke 80s (n'oge azụmahịa. Mwepụta Sistemu V 4) na ndabere nke a, ndị debuggers lekwasịrị anya dị warara — usoro oku tracers — pụtara wee bụrụ nke a na-ejikarị eme ihe.

Nke mbụ Paul Cronenburg bipụtara otu ụdị strace ahụ na listi nzipu ozi comp.sources.sun na 1992 dị ka ihe ọzọ maka ọrụ mechiri emechi. trace site na Sun. Ma clone na nke mbụ bụ maka SunOS, mana site na 1994 strace ebugara ya na Sistemu V, Solaris na Linux na-ewu ewu.

Taa strace na-akwado Linux naanị ma dabere n'otu ihe ahụ ptrace, tojuru na ọtụtụ ndọtị.

Onye na-echekwa ọgbara ọhụrụ (ma na-arụsi ọrụ ike). strace - Dmitry Levin. Ekele dịrị ya, akụrụngwa ahụ nwetara atụmatụ dị elu dị ka ịgbanye njehie n'ime oku sistemụ, nkwado maka ọtụtụ ụlọ ọrụ na, nke kachasị mkpa, mascot. Akwụkwọ ndị na-akwadoghị na-ekwu na nhọrọ ahụ dabara na enyí nnụnụ n'ihi nkwenye dị n'etiti okwu Russian "ostrich" na okwu Bekee "strace".

Ọ dịkwa mkpa na akpọnyeghị oku usoro ptrace na tracers na POSIX, n'agbanyeghị ogologo akụkọ ihe mere eme na mmejuputa ya na Linux, FreeBSD, OpenBSD na Unix ọdịnala.

Ngwa strace na nkenke: Piglet Trace

"A naghị atụ anya na ị ga-aghọta nke a" (Dennis Ritchie, nkọwa na Version 6 Unix code code)

Kemgbe m bụ nwata, enweghị m ike iguzo igbe ojii: Ejighị m ihe egwuregwu egwuri egwu, ma gbalịa ịghọta usoro ha (ndị okenye na-eji okwu ahụ bụ "agbajikwa," ma ekwenyeghị na ire ọjọọ). Ikekwe nke a mere omenala na-adịghị ahụkebe nke Unix mbụ na mmegharị oghere ọgbara ọhụrụ dị m nso.

Maka ebumnuche nke isiokwu a, ọ bụ ihe ezi uche na-adịghị na ya ịkwasa koodu isi iyi nke strace, nke torola kemgbe ọtụtụ iri afọ. Ma e kwesịghị inwe ihe nzuzo ọ bụla fọdụrụ maka ndị na-agụ akwụkwọ. Ya mere, iji gosipụta ụkpụrụ nke ịrụ ọrụ nke mmemme strace dị otú ahụ, m ga-enye koodu maka tracer miniature - Trace Piglet (ptr). Ọ maghị ka esi eme ihe ọ bụla pụrụ iche, ma isi ihe bụ oku usoro nke mmemme - ọ na-emepụta:

$ 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 na-amata ihe dị ka narị narị oku sistemụ Linux (lee. okpokoro) ma na-arụ ọrụ naanị na x86-64 architecture. Nke a zuru ezu maka ebumnuche agụmakwụkwọ.

Ka anyị leba anya n'ọrụ nke clone anyị. N'ihe banyere Linux, ndị debuggers na tracers na-eji, dịka ekwuru n'elu, usoro ptrace na-akpọ. Ọ na-arụ ọrụ site n'ịgafe na arụmụka mbụ ihe nchọpụta iwu, nke naanị anyị chọrọ PTRACE_TRACEME, PTRACE_SYSCALL и PTRACE_GETREGS.

Ihe nchọgharị ahụ na-amalite n'ụdị Unix na-emebu: fork(2) malite usoro nwata, nke n'aka nke ya na-eji exec(3) malite mmemme a na-amụ. Naanị aghụghọ ebe a bụ ihe ịma aka ptrace(PTRACE_TRACEME) tupu execUsoro ụmụaka na-atụ anya ka usoro nne na nna nyochaa ya:

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");
}

Usoro nne na nna kwesịrị ịkpọ ugbu a wait(2) n'ime usoro ụmụaka, ya bụ, gbaa mbọ hụ na ịgbanwee na ọnọdụ trace emela:

/* 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");

N'oge a, nkwadebe zuru ezu ma ị nwere ike ịga n'ihu ozugbo na oku usoro nsochi na akaghị agwụ agwụ.

Kpọọ ptrace(PTRACE_SYSCALL) na-ekwe nkwa na-esote wait Nne na nna ga-emecha ma tupu e gbuo oku sistemụ ma ọ bụ ozugbo emechara. N'etiti oku abụọ ị nwere ike ịme omume ọ bụla: dochie oku na nke ọzọ, gbanwee arụmụka ma ọ bụ uru nloghachi.

Anyị kwesịrị ịkpọ iwu ahụ ugboro abụọ ptrace(PTRACE_GETREGS)iji nweta steeti ndekọ aha rax tupu oku (nọmba oku sistemụ) na ozugbo (ọnụahịa nloghachi).

N'ezie, okirikiri:

/* 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);
}

Nke ahụ bụ tracer niile. Ugbu a ị maara ebe ị ga-amalite ọdụ ụgbọ mmiri na-esote DTrace na Linux.

Basics: na-agba ọsọ a mmemme na-agba ọsọ strace

Dị ka nke mbụ ojiji ikpe strace, ikekwe ọ bara uru ịkọwa usoro kachasị mfe - ịmalite ngwa na-agba ọsọ strace.

Ka anyị ghara ịbanye n'ime ndepụta oku na-adịghị agwụ agwụ nke mmemme a na-ahụkarị, anyị na-ede opekempe mmemme gburugburu 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;
}

Ka anyị wulite mmemme wee hụ na ọ na-arụ ọrụ:

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

N'ikpeazụ, ka anyị mee ya n'okpuru njikwa 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)                           = ?

Ezigbo “okwu ọnụ” na ọ bụghị ezigbo nkuzi. Enwere nsogbu abụọ ebe a: a na-agwakọta mmepụta mmemme na mmepụta strace na ọtụtụ oku usoro na-adịghị amasị anyị.

Ị nwere ike ikewapụ iyi mmepụta ọkọlọtọ nke mmemme na mmepụta njehie strace site na iji -o switch, nke na-atụgharị ndepụta oku usoro na faịlụ arụmụka.

Ọ na-anọgide na-edozi nsogbu nke oku "mgbakwunye". Ka anyị were na anyị nwere mmasị na oku write. Igodo -e na-enye gị ohere ịkọwapụta okwu nke a ga-eji chịkọta oku sistemụ. Nhọrọ ọnọdụ kachasị ewu ewu bụ, n'ezie, trace=*, nke ị nwere ike ịhapụ naanị oku na-amasị anyị.

Mgbe ejiri ya n'otu oge -o и -e anyị ga-enweta:

$ 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 +++

Yabụ, ị na-ahụ, ọ dị mfe ịgụ.

Ị nwekwara ike wepu oku sistemu, dịka ọmụmaatụ ndị metụtara oke ebe nchekwa na ịtọhapụ:

$ 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 +++

Rịba ama akara mkpu mgbanarị dị na listi oku ewepụrụ: nke a chọrọ site na shei iwu. shei).

Na ụdị glibc m, oku sistemụ na-akwụsị usoro a exit_group, ọ bụghị omenala _exit. Nke a bụ ihe isi ike nke ịrụ ọrụ na oku sistemụ: interface nke onye mmemme na-arụ ọrụ enweghị njikọ na oku sistemụ. Ọzọkwa, ọ na-agbanwe mgbe niile dabere na mmejuputa na ikpo okwu.

Isi ihe: isonye na usoro na ofufe

Na mbụ, a na-akpọ usoro ptrace nke e wuru ya strace, enwere ike iji naanị mgbe ị na-eme mmemme na ọnọdụ pụrụ iche. Mmachi a nwere ike bụrụ ihe ezi uche dị na ya n'ụbọchị nke Version 6 Unix. N'oge a, nke a ezughị ezu: mgbe ụfọdụ ị ga-achọ nyocha nsogbu nke mmemme na-arụ ọrụ. Otu ihe atụ bụ usoro akpọchiri n'aka ma ọ bụ ihi ụra. Ya mere ọgbara ọhụrụ strace nwere ike isonyere usoro na ofufe.

Ihe atụ na-ekpo ọkụ mmemme:

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;
}

Ka anyị wuo mmemme ma hụ na ọ jụrụ oyi:

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

Ugbu a, ka anyị gbalịa isonyere ya:

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

Eji oku akpọchie mmemme pause. Ka anyị hụ otú o si emeghachi omume na akara ngosi ndị a:

$ 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 +++

Anyị malitere mmemme oyi kpọnwụrụ wee jiri ya sonye strace. Ihe abụọ bịara doo anya: oku nkwụsịtụ na-eleghara akara ngosi na-enweghị ndị na-ahụ maka ya na, na-adọrọ mmasị karị, strace Monitors ọ bụghị naanị oku usoro, kamakwa akara mbata.

Ọmụmaatụ: nsochi usoro ụmụaka

Na-arụ ọrụ na usoro site na oku fork - ndabere nke Unixes niile. Ka anyị hụ ka strace si arụ ọrụ na osisi usoro na-eji ihe atụ nke “ịzụlite” dị mfe. mmemme:

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);
}

N'ebe a usoro izizi na-emepụta usoro nwata, ma na-ede na mmepụta ọkọlọtọ:

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

Site na ndabara, anyị ga-ahụ naanị oku sistemu sitere na usoro nne na nna:

$ 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 +++

Ọkọlọtọ na-enyere gị aka soro usoro osisi niile -f, nke strace Monitors usoro oku na nwa Filiks. Nke a na-agbakwunye na ahịrị mmepụta ọ bụla pid Ihe na-eme ka usoro ahụ pụta:

$ 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 +++

N'okwu a, nzacha site na otu oku sistemụ nwere ike ịba uru:

$ 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 +++

Site n'ụzọ, kedu oku usoro eji emepụta usoro ọhụrụ?

Ọmụmaatụ: faịlụ ụzọ kama aka

Ịmara ndị na-akọwa faịlụ bara uru n'ezie, mana aha faịlụ ndị akọwapụtara nke mmemme na-enweta nwekwara ike ịba uru.

Na-esote ihe omume ahụ na-ede ahịrị na faịlụ nwa oge:

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;
}

N'oge oku nkịtị strace ga-egosi uru nke nọmba nkọwa gafere na oku sistemụ:

$ 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 +++

Ya na ọkọlọtọ -y Ngwa ahụ na-egosi ụzọ nke faịlụ nke onye nkọwa kwekọrọ na ya:

$ 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 +++

Ọmụmaatụ: Nnweta faịlụ nsuso

Njirimara ọzọ bara uru: gosipụta naanị oku sistemu ejikọrọ na otu faịlụ. Osote ihe omume ahụ na-etinye ahịrị na faịlụ aka ike gafere dị ka arụmụka:

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;
}

ndabara strace na-egosiputa ọtụtụ ozi na-enweghị isi. Ọkọlọtọ -P na arụmụka na-eme ka eriri bipụta naanị oku na faịlụ akọwapụtara:

$ 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 +++

Ọmụmaatụ: Mmemme Multithreaded

Ịbara uru strace nwekwara ike inye aka mgbe ị na-arụ ọrụ na multi-threaded mmemme. Mmemme na-esonụ na-ede na mmepụta ọkọlọtọ sitere na iyi abụọ:

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);
}

Dị ka o kwesịrị ịdị, a ga-ejikọta ya na ekele pụrụ iche nye onye njikọ - ọkọlọtọ -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, dị ka ọ dị na usoro nhazi oge niile, ga-agbakwunye pid nke usoro ahụ na mmalite nke ahịrị ọ bụla.

Dị ka o kwesịrị ịdị, anyị anaghị ekwu maka njirimara eri n'echiche nke mmejuputa ụkpụrụ POSIX Threads, mana maka ọnụọgụ nke onye nhazi ọrụ na Linux. Site n'echiche nke ikpeazụ, ọ dịghị usoro ma ọ bụ eri - enwere ọrụ ndị dị mkpa ka ekesa n'etiti isi ihe dị na igwe.

Mgbe ị na-arụ ọrụ n'ọtụtụ eri, oku sistemụ na-abawanye nke ukwuu:

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

Ọ bụ ihe ezi uche dị na ya ịmachi onwe gị na njikwa nhazi na oku sistemụ naanị 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 +++

Site n'ụzọ, ajụjụ. Kedu oku sistemu eji emepụta eri ọhụrụ? Kedu ka oku maka eri a si dị iche na oku maka usoro?

Klas Master: nhazi usoro n'oge oku sistemụ

Otu n'ime ndị pụtara nso nso a strace ikike - igosipụta njupụta nke oku ọrụ n'oge oku sistemụ. Dị mfe ihe atụ:

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;
}

Dị ka o kwesịrị ịdị, mmepụta ihe omume na-aghọ nke ukwuu, na, na mgbakwunye na ọkọlọtọ -k (Ngosipụta ọkpụkpọ oku), ọ bụ ihe ezi uche dị na iji aha nzacha oku sistemụ:

$ 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 +++

Master klas: njehie injection

Na otu ihe ọhụrụ na nke bara uru nke ukwuu: njehie injection. Ebe a ihe omume ahụ, na-ede ahịrị abụọ na iyi mmepụta:

#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;
}

Ka anyị chọpụta oku abụọ a dee oku:

$ 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 +++

Ugbu a, anyị na-eji okwu ahụ injectitinye mperi EBADF dee oku niile:

$ 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 +++

Ọ bụ ihe na-akpali mmasị ndị eweghachiri mperi niile nsogbu write, gụnyere oku zoro ezo n'azụ ụjọ. Ọ bụ naanị ihe ezi uche dị na ya iweghachi mperi maka oku nke mbụ:

$ 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 +++

Ma ọ bụ nke abụọ:

$ 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 +++

Ọ dịghị mkpa ịkọwapụta ụdị njehie:

$ 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 +++

Na mgbakwunye na ọkọlọtọ ndị ọzọ, ị nwere ike "gbajie" ịnweta otu faịlụ. Ọmụmaatụ:

$ 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 +++

E wezụga ịgba ọgwụ mgbochi, nwere ike ewebata igbu oge mgbe ị na-akpọ oku ma ọ bụ na-anata akara.

Afterword

Ịbara uru strace - ngwá ọrụ dị mfe na nke a pụrụ ịdabere na ya. Ma na mgbakwunye na oku usoro, akụkụ ndị ọzọ nke ọrụ mmemme na sistemụ arụmọrụ nwere ike ịmegharị. Dịka ọmụmaatụ, ọ nwere ike soro oku gaa na ọba akwụkwọ nwere njikọ chiri anya. ụzọ, ha nwere ike ileba anya na ọrụ nke sistemụ arụmọrụ SystemTap и mgbapu, na-enye gị ohere inyocha omimi arụmọrụ mmemme zuru oke. Otú o sina dị, ọ bụ strace - usoro nchebe mbụ ma ọ bụrụ na enwere nsogbu na mmemme nke m na nke ndị ọzọ, ana m eji ya ma ọ dịkarịa ala ugboro abụọ n'izu.

Na nkenke, ọ bụrụ na ị hụrụ Unix n'anya, gụọ man 1 strace ma nweere onwe gị ilele mmemme gị!

isi: www.habr.com

Tinye a comment