Strace kwi Linux: imbali, uyilo kunye nokusetyenziswa

Strace kwi Linux: imbali, uyilo kunye nokusetyenziswa

Kwiinkqubo zokusebenza ezifana ne-Unix, unxibelelwano lweprogram kunye nehlabathi langaphandle kunye nenkqubo yokusebenza kwenzeka ngeseti encinci yemisebenzi - iifowuni zenkqubo. Oku kuthetha ukuba ngeenjongo zokulungisa ingxaki kunokuba luncedo ukuhlola iminxeba yenkqubo eyenziwa ngeenkqubo.

Into eluncedo ikunceda ukuba ujonge "ubomi obusondeleyo" beenkqubo kwiLinux strace, ngumxholo weli nqaku. Imizekelo yokusetyenziswa kwezixhobo zobuntlola ikhatshwa yimbali emfutshane strace kunye nenkcazo yoyilo lweenkqubo ezinjalo.

Iziqulatho

Imvelaphi yeentlobo

Ujongano oluphambili phakathi kweenkqubo kunye ne-OS kernel kwi-Unix ziifowuni zenkqubo. inkqubo iminxeba, iisyscalls), unxibelelwano lweenkqubo kunye nelizwe langaphandle lwenzeka ngokukodwa ngabo.

Kodwa kwinguqulelo yokuqala yoluntu ye-Unix (Uguqulelo 6 Unix, 1975) bekungekho ndlela zilungileyo zokulandelela ukuziphatha kweenkqubo zabasebenzisi. Ukusombulula lo mba, iiLabhu zeBell ziyakuhlaziya kuguqulelo olulandelayo (Uguqulelo 7 Unix, 1979) ucebise umnxeba wenkqubo entsha - ptrace.

i-ptrace yaphuhliswa ikakhulu kubalungisi abasebenzisanayo, kodwa ekupheleni kweminyaka yee-80s (ngexesha lorhwebo. Inkqubo V Ukukhutshwa 4) ngokwesi siseko, ii-debuggers ezigxile emxinwaβ€”ii-system call tracersβ€”zavela zaza zasetyenziswa ngokubanzi.

Okokuqala inguqulelo efanayo yomtya yapapashwa nguPaul Cronenburg kuluhlu lokuposa lwe-com.sources.sun ngo-1992 njengenye indlela yosetyenziso oluvaliweyo. trace ukusuka eLangeni. Zombini i-clone kunye neyokuqala zenzelwe i-SunOS, kodwa ngo-1994 strace yafakwa kwiSistim V, iSolaris kunye neLinux eyandayo.

Namhlanje umtya uxhasa iLinux kuphela kwaye uxhomekeke kwinto enye ptrace, ikhule ngezongezo ezininzi.

Umlondolozi wangoku (kwaye usebenza kakhulu). strace - NguDmitry Levin. Enkosi kuye, into eluncedo ifumene izinto eziphambili ezifana nenaliti yempazamo kwiifowuni zenkqubo, inkxaso yoluhlu olubanzi lwezakhiwo kwaye, okona kubaluleke kakhulu, imascot. Imithombo engekho semthethweni ithi ukhetho lwawela kwinciniba ngenxa ye-consonance phakathi kwegama lesiRashiya elithi "inciniba" kunye negama lesiNgesi elithi "strace".

Kwakhona kubalulekile ukuba ifowuni ye-ptrace kunye ne-tracers ayizange ifakwe kwi-POSIX, ngaphandle kwembali ende kunye nokuphunyezwa kwi-Linux, i-FreeBSD, i-OpenBSD kunye ne-Unix yendabuko.

Isixhobo sobuchule ngokufutshane: I-Piglet Trace

"Akulindelekanga ukuba uyiqonde le nto" (uDennis Ritchie, izimvo kwiNguqulelo yesi-6 yekhowudi yomthombo we-Unix)

Ukususela ebuntwaneni, andinakukwazi ukuma iibhokisi ezimnyama: Andizange ndidlale ngamathoyizi, kodwa ndazama ukuqonda isakhiwo sabo (abadala basebenzisa igama elithi "ukuphuka," kodwa musa ukukholelwa kwiilwimi ezimbi). Mhlawumbi kungenxa yoko le nto inkcubeko engekho sikweni ye-Unix yokuqala kunye nentshukumo yanamhlanje yomthombo ovulekileyo isondele kum.

Ngenjongo yeli nqaku, akukho ngqiqweni ukuqhawula ikhowudi yomthombo we-strace, ekhulile kwiminyaka emashumi. Kodwa akufuneki kubekho zimfihlo zishiyelwa abafundi. Ke ngoko, ukubonisa umgaqo wokusebenza kweenkqubo zomtya, ndiya kubonelela ngekhowudi yetracer encinci - Ihagu Trace (ptr). Akwazi ukwenza nantoni na ekhethekileyo, kodwa eyona nto iphambili kukufowuna kwenkqubo yenkqubo - ikhupha:

$ 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

I-Piglet Trace ibona malunga namakhulu eefowuni zeLinux (bona. itafile) kwaye isebenza kuphela kuyilo lwe-x86-64. Oku kwanele kwiinjongo zemfundo.

Makhe sijonge umsebenzi weclone yethu. Kwimeko yeLinux, iidebuggers kunye netracers zisebenzisa, njengoko kukhankanyiwe ngasentla, inkqubo ye ptrace call. Isebenza ngokugqithisa kwingxoxo yokuqala izazisi zomyalelo, esizidingayo kuphela PTRACE_TRACEME, PTRACE_SYSCALL ΠΈ PTRACE_GETREGS.

Itracer iqala ngendlela eqhelekileyo ye-Unix: fork(2) iqalisa inkqubo yomntwana, ethi yona isebenzise exec(3) isungula inkqubo ephantsi kwesifundo. Ubuqili kuphela apha ngumngeni ptrace(PTRACE_TRACEME) ngaphambili exec: Inkqubo yomntwana ilindele ukuba inkqubo yomzali iyibeke iliso:

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

Inkqubo yomzali kufuneka ngoku ifowune wait(2) kwinkqubo yomntwana, oko kukuthi, qiniseka ukuba ukutshintshela kwindlela yokulandela umkhondo kwenzekile:

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

Ngeli xesha, amalungiselelo agqityiwe kwaye unokuqhubeka ngokuthe ngqo ekulandeleni iifowuni zenkqubo kwi-loop engapheliyo.

Mngeni ptrace(PTRACE_SYSCALL) iqinisekisa ukuba okulandelayo wait umzali uya kugqiba nokuba ngaphambi kokuba inkqubo yokufowuna yenziwe okanye ngokukhawuleza emva kokuba igqityiwe. Phakathi kweefowuni ezimbini ungenza naziphi na iintshukumo: buyisela ifowuni ngenye indlela, tshintsha iimpikiswano okanye ixabiso lokubuyisela.

Sidinga nje ukubiza umyalelo kabini ptrace(PTRACE_GETREGS)ukufumana imeko yokubhalisa rax phambi kokufowuna (inombolo yokufowuna yesixokelelwano) kwaye ngokukhawuleza emva koko (ixabiso lokubuyisela).

Ngokwenyani, umjikelo:

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

Yiyo yonke loo mkhondo. Ngoku uyazi ukuba ungaqala phi ukuhambisa okulandelayo DTrace kwi Linux.

Izinto ezisisiseko: ukuqhuba inkqubo eqhuba umtya

Njengemeko yokuqala yokusetyenziswa strace, mhlawumbi kufanelekile ukukhankanya eyona ndlela ilula - ukuqaliswa kwesicelo esisebenzayo strace.

Ukuze ungangeni kuluhlu olungapheliyo lweefowuni zeprogram eqhelekileyo, sibhala ubuncinane benkqubo ngeenxa zonke 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;
}

Masakhe inkqubo kwaye siqinisekise ukuba iyasebenza:

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

Kwaye ekugqibeleni, masiyiqhube phantsi kolawulo lomtya:

$ 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)                           = ?

"Amagama" kakhulu kwaye ayifundisi kakhulu. Kukho iingxaki ezimbini apha: imveliso yenkqubo ixutywe nemveliso strace kunye nentaphane yeefowuni zenkqubo ezingasiniki mdla.

Unokwahlula ujelo lwemveliso esemgangathweni kunye nesiphumo semposiso yomtya usebenzisa i -o switsha, ephinda iqondise uluhlu lweefowuni zenkqubo kwifayile yengxabano.

Kuhlala ukujongana nengxaki yeefowuni "zongezelelweyo". Makhe sicinge ukuba sinomdla kuphela kwiifowuni write. Isitshixo -e ikuvumela ukuba ukhankanye iintetho zendlela yokufowuna ezakuhluzwa. Olona khetho ludumileyo lwemeko kukuba, ngokwendalo, trace=*, apho unokushiya kuphela iifowuni ezinomdla kuthi.

Xa isetyenziswa ngaxeshanye -o ΠΈ -e siya kufumana:

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

Ke, uyabona, kulula kakhulu ukufunda.

Unako kwakhona ukususa iifowuni zesistim, umzekelo ezo zinxulumene nolwabiwo lwememori kunye nokukhulula:

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

Qaphela isikhuzo esisindileyo kuluhlu lweefowuni ezingabandakanywanga: oku kufunwa liqokobhe lomyalelo. iqokobhe).

Kwinguqulelo yam ye-glibc, umnxeba wenkqubo uphelisa inkqubo exit_group, hayi ngokwesithethe _exit. Obu bubunzima bokusebenza ngeefowuni zesistim: ujongano apho umdwebi wenkqubo asebenza khona alunxulumananga ngokuthe ngqo neefowuni zesistim. Ngaphezu koko, itshintsha rhoqo ngokuxhomekeke ekuphunyezweni kunye neqonga.

Izinto ezisisiseko: ukujoyina inkqubo kwi-fly

Ekuqaleni, inkqubo ye-ptrace ibiza apho yayakhiwe khona strace, ingasetyenziswa kuphela xa uqhuba inkqubo ngendlela ekhethekileyo. Oku kusikelwa umda kwakuvakala kusengqiqweni ngeentsuku zenguqulelo yesi-6 ye-Unix. Namhlanje, oku akusekho ngokwaneleyo: ngamanye amaxesha kufuneka uphande iingxaki zenkqubo yokusebenza. Umzekelo oqhelekileyo yinkqubo evaliweyo kwisibambo okanye ukulala. Ngoko ke namhlanje strace inokujoyina iinkqubo kubhabho.

Umzekelo wokukhenkceza kwenkqubo:

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

Masakhe inkqubo kwaye siqinisekise ukuba ingumkhenkce:

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

Ngoku makhe sizame ukuyidibanisa:

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

Inkqubo ivaliwe ngomnxeba pause. Makhe sibone indlela asabela ngayo kwimiqondiso:

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

Siphehlelele inkqubo ekhenkcezisiweyo kwaye siyidibanise sisebenzisa strace. Izinto ezimbini ziye zacaca: umnxeba wenkqubo yokumisa ikhefu ayihoyi imiqondiso ngaphandle kwabaphathi kwaye, ngakumbi umdla, abaqapheli bomda kungekuphela nje umnxeba wenkqubo, kodwa kunye nemiqondiso engenayo.

Umzekelo: Ukulandelela iinkqubo zabantwana

Ukusebenza kunye neenkqubo ngokufowuna fork - isiseko sazo zonke ii-Unixes. Makhe sibone ukuba umtya osebenza njani nomthi wenkqubo usebenzisa umzekelo β€œwokufuya” olula. kwenkqubo:

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

Apha inkqubo yoqobo idala inkqubo yomntwana, zombini zibhala kwimveliso eqhelekileyo:

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

Ngokungagqibekanga, siya kubona kuphela iminxeba yenkqubo esuka kwinkqubo yabazali:

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

Iflegi ikunceda ulandele umthi wenkqubo yonke -f, leyo strace esweni inkqubo iminxeba kwiinkqubo umntwana. Oku kongeza kumgca ngamnye wemveliso pid inkqubo eyenza imveliso yenkqubo:

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

Kulo mxholo, ukuhluza ngeqela leefowuni zesixokelelwano kunokuba luncedo:

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

Ngendlela, yeyiphi inkqubo yokufowuna esetyenziselwa ukudala inkqubo entsha?

Umzekelo: iindlela zefayile endaweni yeziphatho

Ukwazi izichazi zefayile ngokuqinisekileyo kuluncedo, kodwa amagama eefayile ezithile ezifikelelwa yinkqubo nazo zinokuza luncedo.

Olandelayo kwenkqubo ubhala umgca kwifayile yethutyana:

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

Ngexesha lomnxeba oqhelekileyo strace izakubonisa ixabiso lenombolo yesichazi egqithiselwe kumnxeba wesixokelelwano:

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

Ngeflegi -y Into eluncedo ibonisa indlela eya kwifayile apho inkcazo ihambelana khona:

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

Umzekelo: UkuKhangela ngokuFikelela kwiFayile

Olunye uphawu oluluncedo: bonisa kuphela iifowuni zesixokelelwano ezinxulumene nefayile ethile. Okulandelayo kwenkqubo ifakela umgca kwifayile engenamkhethe egqithiswe njengengxoxo:

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

Ukungagqibeki strace ibonisa ulwazi oluninzi olungeyomfuneko. Iflegi -P ngengxoxo ibangela umtya ukuprinta kuphela iminxeba eya kwifayile ekhankanyiweyo:

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

Umzekelo: Iinkqubo ezinemisonto emininzi

Uncedo strace inokunceda xa usebenza ngemisonto emininzi inkqubo. Le nkqubo ilandelayo ibhala kwimveliso eqhelekileyo ukusuka kwimijelo emibini:

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

Ngokwemvelo, kufuneka ihlanganiswe ngombuliso okhethekileyo kumnxibelelanisi - iflegi ye-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
$

Iflegi -f, njengakwimeko yeenkqubo eziqhelekileyo, ziya kongeza i-pid yenkqubo ekuqaleni komgca ngamnye.

Ngokwendalo, asithethi ngesichongi somsonto ngengqiqo yokuphunyezwa komgangatho wePOSIX weMisonto, kodwa malunga nenani elisetyenziswe ngumcwangcisi womsebenzi kwiLinux. Ukususela kumbono wokugqibela, akukho nkqubo okanye imicu - kukho imisebenzi efuna ukuhanjiswa phakathi kwee-cores ezikhoyo zomatshini.

Xa usebenza kwimisonto emininzi, iifowuni zesistim ziba ninzi kakhulu:

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

Iyavakala ukuzibekela umda ekuqhubeni ulawulo kunye neefowuni zenkqubo kuphela 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 +++

Kakade ke, imibuzo. Yeyiphi inkqubo yokufowuna esetyenziselwa ukwenza umsonto omtsha? Lo mnxeba wemisonto wahluke njani kwikhwelo leenkqubo?

Iklasi ye-Master: inkqubo yokupakisha ngexesha lomnxeba wenkqubo

Omnye wabasanda kuvela strace ubunakho - ukubonisa isitakhi seefowuni zokusebenza ngexesha lenkqubo yokufowuna. Elula mzekelo:

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

Ngokwemvelo, imveliso yeprogram iba yi-voluminous kakhulu, kwaye, ngaphezu kweflegi -k (umboniso womnxeba wokufowuna), iyavakala ukuhluza iminxeba yenkqubo ngegama:

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

Iklasi ye-Master: inaliti yempazamo

Kwaye enye into entsha kwaye iluncedo kakhulu: inaliti yempazamo. Apha kwenkqubo, ukubhala imigca emibini kumsinga wemveliso:

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

Masilandele zombini iifowuni ezibhalayo:

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

Ngoku sisebenzisa igama injectukufaka imposiso EBADF kuzo zonke bhala iminxeba:

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

Inika umdla ukuba zeziphi iimpazamo ezibuyiswayo zonke imingeni write, kuquka umnxeba ofihliweyo emva koloyiko. Iyavakala kuphela ukubuyisela impazamo kwiminxeba yokuqala:

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

Okanye owesibini:

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

Akuyomfuneko ukukhankanya uhlobo lwemposiso:

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

Ngokudibanisa nezinye iiflegi, unako "ukuqhawula" ukufikelela kwifayile ethile. Umzekelo:

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

Ngaphandle kwesitofu sempazamo, unako yazisa ulibaziseko xa ufowuna okanye ufumana iimpawu.

Emva kwegama

Uncedo strace - isixhobo esilula nesithembekileyo. Kodwa ukongeza kwiifowuni zenkqubo, ezinye iinkalo zokusebenza kweenkqubo kunye nenkqubo yokusebenza inokulungiswa. Umzekelo, inokulandelela iminxeba ukuya kumathala eencwadi aqhagamshelwe ngamandla. i-ltrace, banokujonga ekusebenzeni kwenkqubo yokusebenza SystemTap ΠΈ intambo, kwaye ikuvumela ukuba uphande ngokunzulu ukusebenza kwenkqubo Isitshisi. Nangona kunjalo, kunjalo strace -umgca wokuqala wokukhusela kwimeko yeengxaki ngeyam kunye neenkqubo zabanye abantu, kwaye ndiyisebenzisa ubuncinane amaxesha ambalwa ngeveki.

Ngamafutshane, ukuba uyayithanda i-Unix, funda man 1 strace kwaye uzive ukhululekile ukujonga iinkqubo zakho!

umthombo: www.habr.com

Yongeza izimvo