Strace in Linux: taariikhda, design iyo isticmaalka

Strace in Linux: taariikhda, design iyo isticmaalka

Nidaamyada hawlgalka ee u eg Unix, xidhiidhka barnaamijku la leeyahay dunida ka baxsan iyo nidaamka qalliinka waxa ay ku dhacdaa iyada oo loo marayo tiro yar oo hawlo ah - wicitaannada nidaamka. Tani waxay ka dhigan tahay in ujeedooyinka khaladka ah ay faa'iido u yeelan karto in la basaasto wicitaanada nidaamka lagu fuliyo hababka.

Utility wuxuu kaa caawinayaa inaad la socoto "nolosha dhow" ee barnaamijyada Linux strace, kaas oo ah mawduuca maqaalkan. Tusaalooyinka isticmaalka qalabka basaaska waxaa weheliya taariikh kooban strace iyo sharaxaad ku saabsan naqshadaynta barnaamijyadaas.

Tusmo

Asalka noocyada

Isku xirka ugu weyn ee u dhexeeya barnaamijyada iyo kernel OS ee Unix waa wicitaanada nidaamka. nidaamka wicitaanada, qaylodhaan), is dhexgalka barnaamijyada ee dunida dibadda si gaar ah iyaga ka mid ah.

Laakiin nooca ugu horreeya ee dadweynaha ee Unix (Nooca 6 Unix, 1975) ma jirin habab ku habboon oo lagula socon karo hab-dhaqanka hababka isticmaalaha. Si arrintan loo xalliyo, Bell Labs ayaa u cusbooneysiin doona nooca xiga (Nooca 7 Unix, 1979) wuxuu soo jeediyay hab cusub oo wac - ptrace.

ptrace waxaa loo sameeyay ugu horeyn loogu talagalay cilladaha isdhexgalka, laakiin dhamaadkii 80-meeyadii (xiligi ganacsiga Nidaamka V Siideynta 4Sidan awgeed, cillado cidhiidhi ah oo diiradda saaraya - nidaamka wicitaanka raadraacayaasha - ayaa soo muuqday oo noqday kuwo si weyn loo isticmaalo.

Marka hore isla nooca strace ayaa waxaa daabacay Paul Cronenburg liiska boostada comp.sources.sun sanadkii 1992 iyadoo badal u ah tasiilaadka xiran trace ka Sun. Labada clone iyo asalka labadaba waxaa loogu talagalay SunOS, laakiin 1994 strace waxaa loo gudbiyay Nidaamka V, Solaris iyo Linux-ka caanka ah ee sii kordhaya.

Maanta strace kaliya waxay taageertaa Linux waxayna ku tiirsan tahay isku mid ptrace, oo ay ka buuxsameen kordhin badan.

Casriyeyn (oo aad u firfircoon) ilaaliye strace - Dmitry Levin. Waad ku mahadsan tahay isaga, utility wuxuu helay astaamo horumarsan sida cirbadeynta qaladka wicitaanada nidaamka, taageerada naqshado kala duwan iyo, tan ugu muhiimsan, mascot. Ilaha aan rasmiga ahayn waxay sheeganayaan in doorashadu ay ku dhacday gorayada sababtoo ah isfahamka u dhexeeya ereyga Ruushka "gorayada" iyo ereyga Ingiriisiga "strace".

Waxa kale oo muhiim ah in wicitaanka nidaamka ptrace-ka iyo raadraacayaasha aan weligood lagu darin POSIX, in kasta oo taariikh dheer iyo hirgelinta Linux, FreeBSD, OpenBSD iyo Unix-dhaqameedka.

Qalabka Strace oo kooban: Piglet Trace

"Lama filayo inaad tan fahanto" (Dennis Ritchie, faallo ka bixi nooca 6 Unix code code)

Tan iyo caruurnimadii hore, ma adkeysan karo sanduuqyada madow: kumaan ciyaarin alaabta lagu ciyaaro, laakiin waxay isku dayeen inay fahmaan qaab-dhismeedkooda (dadka waaweyni waxay isticmaaleen ereyga "jabiyey," laakiin ha rumaysan carrabyada xun). Waxaa laga yaabaa in tani ay tahay sababta dhaqanka aan rasmiga ahayn ee Unix ugu horeysay iyo dhaqdhaqaaqa casriga casriga ah ee furan ayaa iigu dhow.

Ujeedada maqaalkan, waa wax aan macquul ahayn in la kala diro koodhka isha ee xargaha, kaas oo koray tobaneeyo sano. Laakiin waa in aanay jirin wax sir ah oo u hadhay akhristayaasha. Sidaa darteed, si loo muujiyo mabda'a hawlgalka ee barnaamijyada strace sida, waxaan ku siin doonaa code loogu talagalay raadiyaha yar - Raadraaca Doofaarka (ptr) Ma garanayo sida loo sameeyo wax gaar ah, laakiin waxa ugu muhiimsan waa wicitaanada nidaamka ee barnaamijka - waxay soo saartaa:

$ 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 waxa ay aqoonsan tahay boqollaal wicitaan oo nidaamka Linux ah (eeg. miiska) oo ka shaqeeya kaliya x86-64 naqshadeynta. Tani waxay ku filan tahay ujeeddooyin waxbarasho.

Aan eegno shaqada clone our. Marka laga hadlayo Linux, qaladiyeyaasha iyo raadraacayaasha ayaa isticmaala, sida kor ku xusan, nidaamka ptrace ayaa wacaya. Waxay ku shaqeysaa iyada oo la marayo doodda koowaad ee tilmaamayaasha amarka, kuwaas oo aan u baahanahay oo kaliya PTRACE_TRACEME, PTRACE_SYSCALL ΠΈ PTRACE_GETREGS.

Baad-raacuhu wuxuu ku bilaabmaa qaabka caadiga ah ee Unix: fork(2) wuxuu bilaabaa habraaca ilmaha, kaas oo isna isticmaala exec(3) bilaabay barnaamijka daraasadda. Kaliya khiyaanada halkan waa caqabadda ptrace(PTRACE_TRACEME) ka hor execHabraaca ubadku waxa uu filayaa in nidaamka waalidku la socdo:

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

Habka waalidku hadda waa inuu soo waco wait(2) habka ilmaha, taas oo ah, hubi in u beddelashada habka raadraaca ay dhacday:

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

Halkaa marka ay marayso, diyaargarowgu waa dhammaystiran yahay oo waxaad si toos ah ugu socon kartaa wicitaannada nidaamka raadraaca ee wareeg aan dhammaad lahayn.

Wac ptrace(PTRACE_SYSCALL) dammaanad qaadaya in danbe wait Waalidku waxa uu dhamaystiri doonaa ka hor inta aan la fulin wicida nidaamka ama isla marka uu dhammeeyo. Inta u dhaxaysa laba wicitaan waxaad samayn kartaa ficil kasta: ku beddel wicitaanka mid kale, beddel doodaha ama qiimaha soo celinta.

Kaliya waxaan u baahanahay inaan wacno amarka laba jeer ptrace(PTRACE_GETREGS)si aad u hesho gobolka diiwaanka rax ka hor wicitaanka (lambarka wicitaanka nidaamka) iyo isla markiiba ka dib (qiimaha soo celinta).

Dhab ahaantii, wareegga:

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

Taasi waa raadiyaha oo dhan. Hadda waad garanaysaa meesha aad ka bilaabi lahayd xawaaladda soo socota DTrace Linux.

Aasaaska: socodsiinta barmaamij ordaya strace

Sida kiis isticmaalka ugu horreeya strace, laga yaabee in ay mudan tahay in la tixraaco habka ugu fudud - bilaabista codsiga socda strace.

Si aan u dhexgalin liiska aan dhamaadka lahayn ee wicitaanada barnaamijka caadiga ah, waan qoraynaa barnaamijka ugu yar hareeraha 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;
}

Aan dhisno barnaamijka oo aan hubinno inuu shaqeeyo:

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

Ugu dambayntii, aynu ku maamulno xakamaynta 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)                           = ?

Aad "hadal badan" oo aan aad u waxbarasho ahayn. Waxaa jira laba dhibaato oo halkan ah: soo-saarka barnaamijku wuxuu ku qasan yahay wax-soo-saarka strace iyo baaqyo badan oo nadaam ah oo aan dan noo lahayn.

Waxaad kala saari kartaa qulqulka wax soo saarka caadiga ah ee barnaamijka iyo soo saarida qaladka strace adigoo isticmaalaya -o switch, kaas oo u rogaya liiska wicitaanada nidaamka faylka dooda.

Way hadhaysaa in wax laga qabto dhibaatada wicitaanada "dheeraad ah". Aan ka soo qaadno in aan xiisayno wicitaannada oo keliya write. Furaha -e Waxay kuu ogolaaneysaa inaad qeexdo tibaaxaha nidaamka wicitaanada lagu sifeyn doono. Xulashada xaaladda ugu caansan waa, dabiici ahaan, trace=*, kaas oo aad kaga tagi karto kaliya wicitaanada na daneeya.

Marka isku mar la isticmaalo -o ΠΈ -e waxaan heli doonaa:

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

Markaa, waad aragtaa, way fududahay in la akhriyo.

Waxa kale oo aad ka saari kartaa wicitaanada nidaamka, tusaale ahaan kuwa la xidhiidha qoondaynta xusuusta iyo xoraynta:

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

U fiirso calaamada cajaa'ibka ee ka baxsatay liiska wicitaanada laga saaray: tan waxaa looga baahan yahay qolofka taliska. qolof).

Noocayga glibc, wicitaanka nidaamka ayaa joojinaya habka exit_group, ma aha dhaqan _exit. Tani waa dhibka la shaqeynta wicitaannada nidaamka: interface-ka uu barnaamij-sameeyaha ku shaqeeyo si toos ah uma xirna wicitaannada nidaamka. Waxaa intaa dheer, waxay si joogto ah u beddeshaa iyadoo ku xiran hirgelinta iyo madal.

Aasaaska: ku biirista habka duulista

Bilowgii, nidaamka ptrace-ka ayaa wacaya kaas oo lagu dhisay strace, waxa kaliya oo loo isticmaali karaa marka barnaamijka lagu wado qaab gaar ah. Xaddidaaddan ayaa laga yaabaa inay u muuqatay mid macquul ah maalmihii Version 6 Unix. Maalmahan, tani kuma filna: mararka qaarkood waxaad u baahan tahay inaad baarto dhibaatooyinka barnaamijka shaqada. Tusaalaha caadiga ah waa habka lagu xannibay gacanta ama hurdada. Sidaa darteed casri ah strace ku biiri kara hababka duulista.

Tusaalaha qaboojinta barnaamijyada:

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

Aan dhisno barnaamijka oo aan hubinno inuu barafoobay:

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

Hadda aan isku dayno inaan ku biirno:

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

Barnaamijka waxaa xannibay wicitaan pause. Aan aragno sida ay uga fal celiso calaamadaha:

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

Waxaan furnay barnaamijkii la qaboojiyey oo ku biirnay annaga oo adeegsanayna strace. Laba shay ayaa caddaatay: wicitaanka nidaamka hakadku wuxuu iska indho-tiraa calaamadaha aan lahayn maamuleyaal, iyo, waxaa aad u xiiso badan, kormeerayaasha xargaha ma aha oo kaliya wicitaannada nidaamka, laakiin sidoo kale calaamadaha soo socda.

Tusaale: Dabagalka Hababka Ilmaha

Ku shaqaynta hababka iyada oo loo marayo wicitaan fork - saldhigga oo dhan Unixes. Aynu aragno sida strace ula shaqeyso geed geeddi-socod annagoo tusaale u ah β€œtaranta” fudud barnaamijyada:

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

Halkan nidaamka asalka ah wuxuu abuuraa habka ilmaha, labadaba wax u qorista heerka caadiga ah:

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

Sida caadiga ah, waxaan kaliya ku arki doonaa nidaamka wicitaanada habka waalidka:

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

Calanku wuxuu kaa caawinayaa inaad la socoto geedka geeddi-socodka oo dhan -f, kaas strace wuxuu kormeeraa wicitaanada nidaamka habsocodka ilmaha. Tani waxay ku daraysaa khad kasta oo wax soo saarka ah pid habka sameeya soo saarida nidaamka:

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

Xaaladdan oo kale, shaandhaynta koox ahaan wicitaannada nidaamka waxay noqon kartaa mid faa'iido leh:

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

By habka, waa maxay nidaamka call loo isticmaalo in la abuuro hab cusub?

Tusaale: dariiqyada fayl-gareeya beddelka gacan-qabsiga

Ogaanshaha sharraxayaasha faylka xaqiiqdii waa faa'iido, laakiin magacyada faylasha gaarka ah ee barnaamijku galo ayaa sidoo kale ku iman kara anfaca.

Marka xigta barnaamijka wuxuu khadka u qoraa fayl ku meel gaar ah:

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

Inta lagu jiro wicitaanka caadiga ah strace waxay tusi doontaa qiimaha nambarka sharaxaha ee loo gudbiyay nidaamka wicitaanka:

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

Calan wata -y Utility-gu wuxuu tusinayaa dariiqa loo maro faylka uu sharraxuhu u dhigmayo:

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

Tusaale: Raadinta Galitaanka Faylka

Muuqaal kale oo faa'iido leh: soo bandhig kaliya wicitaannada nidaamka ee la xidhiidha fayl gaar ah. Xiga barnaamijka waxay ku dhejisaa xariiq fayl gardarro ah oo loo gudbiyay dood ahaan:

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

by default strace waxay soo bandhigaysaa macluumaad badan oo aan loo baahnayn. Calan -P dood leh waxay sababtaa xadhig lagu daabaco wicitaanada faylka la cayimay:

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

Tusaale: Barnaamijyada Taxanaha Badan

Faa'iidada strace Waxa kale oo ay ku caawin kartaa marka la shaqaynayo multi-threaded barnaamijka. Barnaamijka soo socdaa wuxuu u qoraa wax soo saarka caadiga ah ee laba durdur:

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

Dabcan, waa in lagu soo ururiyaa salaan gaar ah oo ku socota xiriiriyaha - calanka -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
$

Calanka -f, sida kiisaska hababka caadiga ah, waxay ku dari doonaan pid ee habka bilawga xariiq kasta.

Dabcan, kama hadlayno aqoonsiga dunta ee macnaha hirgelinta POSIX Threads standard, laakiin ku saabsan tirada uu isticmaalo jadwalka hawsha Linux. Marka laga eego dhinaca dambe, ma jiraan wax habab ama dun - waxaa jira hawlo loo baahan yahay in lagu qaybiyo qaybaha la heli karo ee mashiinka.

Markaad ka shaqaynayso taxane badan, wicitaanada nidaamka ayaa noqda kuwa aad u badan:

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

Waxay macno samaynaysaa in aad naftaada ku xaddiddo maaraynta habsocodka iyo wicitaannada nidaamka oo keliya 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 +++

By habka, su'aalo. Waa maxay wicitaanka nidaamka loo isticmaalo si loo abuuro dun cusub? Sidee buu baaqa dunta uga duwan yahay baaqa habsocodka?

Fasalka Master-ka: habka xidhmada wakhtiga wicitaanka nidaamka

Mid ka mid ah kuwa dhawaan soo muuqday strace awoodaha - soo bandhigida xidhmada wicitaanada shaqada wakhtiga wicitaanka nidaamka. Fudud Tusaale:

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

Dabiici ahaan, wax-soo-saarka barnaamijku wuxuu noqonayaa mid aad u badan, iyo, marka lagu daro calanka -k (muujinta xirmada wicitaanka), waxay macno samaynaysaa in lagu sifeeyo wicitaanada nidaamka magac ahaan:

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

Heerka sare: cirbad qalad ah

Iyo mid kale oo cusub oo aad waxtar u leh: cirbadeynta qaladka. Halkan barnaamijka, oo ku qoraya laba sadar qulqulka wax soo saarka:

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

Aynu raad raacno labadaba qor wicitaanada:

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

Hadda waxaan isticmaalnaa tibaaxaha injectin qalad la geliyo EBADF Dhamaan wicitaanada ku qor:

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

Waxa xiiso leh waxa khaladaadka lagu soo celiyo oo dhan caqabadaha write, oo ay ku jiraan baaqa qarsoon ee argagixisada. Waxa kaliya oo macno samaynaysa in lagu soo celiyo khaladka ugu horreeya ee wicitaanada:

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

Ama kan labaad:

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

Looma baahna in la qeexo nooca qaladka:

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

Marka lagu daro calamada kale, waxaad "jebin kartaa" gelitaanka fayl gaar ah. Tusaale:

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

Ka sokow cirbadeynta qaladka, awooddo soo bandhig dib u dhac marka la wacayo ama la helayo calaamadaha.

Kadib

Faa'iidada strace - qalab fudud oo lagu kalsoonaan karo. Laakiin marka lagu daro wicitaanada nidaamka, dhinacyada kale ee hawlgalka barnaamijyada iyo nidaamka hawlgalka ayaa laga saari karaa. Tusaale ahaan, waxay la socon kartaa wicitaannada maktabadaha si firfircoon ugu xiran. raad, waxay eegi karaan hawlgalka nidaamka qalliinka SystemTap ΠΈ jajab, oo kuu ogolaanaya inaad si qoto dheer u baarto waxqabadka barnaamijka kaamil ah. Si kastaba ha ahaatee, waa strace - safka koowaad ee difaaca haddii ay dhibaato ka timaado barnaamijyadayda iyo kuwa kaleba, waxaanan isticmaalaa ugu yaraan laba jeer toddobaadkii.

Marka la soo koobo, haddii aad jeceshahay Unix, akhri man 1 strace xorna u tahay inaad daawato barnaamijyadaada!

Source: www.habr.com

Add a comment