Strace in Linux: historia, consilium et usus

Strace in Linux: historia, consilium et usus

In Unix-similis operandi systemata, communicatio programmatis cum externo et operativa fit per parvas functiones - systema vocat. Hoc significat quod ad debugging usus utiles esse potest explorare systema vocat processibus exequendis.

Utilitas adiuvat te monitorem "vitam intimam" programmatum in Linux stracequod est subiectum huius articuli. Exempla de usu speculatoriae instrumenti brevem historiam comitantur strace et descriptionem consiliorum talium programmatum.

contentus

Origo specierum

Praecipua interfacies inter programmata et OS acinum in Unix est systema vocat. ratio vocat, syscalls) commercium programmatum cum extra mundum fit solum per eos.

Sed in prima versione publica Unix (Version 6 Unix1975) nullae erant opportunae modi ad investigandum processuum usoris moribus. Ad hanc quaestionem solvendam, Bell Labs renovabit ad versionem proximam.Version 7 Unix, 1979 nova ratio vocationis proposuit - ptrace.

ptrace praesertim pro interactive debuggers elaboratum est, sed fine 80s (tempore commerciali Systema V Release 4) hac ratione, anguste debuggers feruntur - systematis vocantis tracatores - apparuit et late usus est.

primus Eadem versio strace a Paulo Cronenburg in comp.sources.sun listarum mailingentium anno 1992 edita est ut jocus ad utilitatem clausam. trace ex Sole; Tam clone quam originale SunOS destinata sunt, sed a 1994 strace ad System V, Solaris et Linux in dies magis populare delatum est.

Strace hodie tantum Linux sustinet et eodem nititur ptracemultis extensionibus obsitus.

Moderni (ac acerrimus) assertor strace - Dmitry Levin. Per eum utilitas quae provectae lineae quaesitae sunt, sicut error iniectio in systematis vocat, subsidium amplis architecturae ac praesertim; terque. Fontes honorarii affirmant electionem struthionis incidisse propter consonantiam inter verbum Russicum "struthocame" et verbum Anglicum "strace".

Gravis etiam est quod ratio vocationis et vestigiorum ptraceas numquam in POSIX comprehendit, quamvis longam historiam et exsecutionem in Linux, FreeBSD, OpenBSD et traditum Unix.

Strace fabrica in a breviter intimatum: Porcelli Trace

"Hoc intellegere non debes" (Dennis Ritchie, commentarium in Versione 6 Unix source code)

Cum prima pueritia, capsellas nigras stare non possum: non lusi cum nugis, sed eorum structuram intellegere conatus sum (adulti verbo "fregerunt", sed malis linguis non credunt. Hac de causa fortasse cultura informalis primae Unix et moderni motus aperti-fontis tam prope me est.

Ad proposita huius articuli, irrationabile est fontem codicem strace disiungere, qui in decenniis crevit. Sed secreta non debent lectoribus relicta. Ut ergo principium operationis talium strorum progressionum exhibeam, signum exigui argumenti dabo. Porcellus Trace (ptr). Nescit facere aliquid speciale, sed summa est ratio vocat progressio - outputs:

$ 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

Porcellus Trace de centenis Linux systematis vocat (vide. mensam) and only works in architectura x86-64. Haec sufficiunt ad proposita scholastica.

Intueamur opus clone nostrae. In Linux, debuggers et tracer, ut supra dictum est, ratio ptrace appellant. In primo argumento praecepti identificatores transeundo operatur, cuius tantum indigemus PTRACE_TRACEME, PTRACE_SYSCALL ΠΈ PTRACE_GETREGS.

In solitum Unix style incipit vestigium: fork(2) puer processum movet, qui rursus utitur exec(3) progressio sub studio movet. Sola subtilitas hic est provocatio ptrace(PTRACE_TRACEME) ante exec: puer processum parentis ad monitorem processum expectat;

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

Parentis processus nunc vocamus wait(2) in puerili processu, id est, fac ut in commutatione ad vestiendi modum inciderit;

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

Hic, praeparationes perfectae sunt et directe procedere potes ad systema tracking vocat in ansa infinita.

voca ptrace(PTRACE_SYSCALL) spondet quod sequens wait parens consummabit vel ante vocationem systematis efficietur vel statim post eam perficiet. Inter duas vocatus quaslibet actiones praestare potes: una cum joco substitue vocationem, argumenta muta vel valorem reditus.

Non solum opus est ad imperium bis ptrace(PTRACE_GETREGS)ut in actis mandare civitatis rax ante vocationem (ratio numeri vocatio) et statim post (retum valorem).

Profecto circulus;

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

Hoc totum est. Nunc scis unde incipias proximam portationem dtrace on Linux.

Basics: currit progressio strace

Ut primum usum causa stracefortasse memorare valet simplicissima via - applicationem currentem deducendi strace.

Ne in indicem nominationum infinitarum programmatis typici imprimamus, scribimus minimum programma circum 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;
}

Rationem aedificemus et opera eius fac;

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

Et tandem eam sub dicione curramus;

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

Valde " verbosus" et non admodum educational. Duae quaestiones hic sunt: ​​programmata output cum output mixta sunt strace ratio et copia vocat quae nobis nihil interest.

Separare potes vexillum programmatis output stream et strace errorum output utens -o switch, quod album rationum vocat ad argumentum lima reducit.

Reliquum est ut de vocat problema "extra". Sumamus nos tantum interesse in vocat write. Clavis -e sino vos exprimere expressiones quibus ratio vocationis percolabitur. Optio popularis conditio naturaliter est; trace=*est, cum qua potes abire, tantum nos id vocat.

Cum eodem tempore usus est -o ΠΈ -e habebimus;

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

Ita vides, multo facilius est legere.

Systema vocatum removere potes, exempli causa quae ad memoriam destinatio et liberatio cognata est;

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

Nota exclamationis nota evasionis in indice vocatorum exclusionum: hoc mandatum testae requiritur. testa).

In mea versione glibc, ratio vocationis processum terminat exit_groupNon traditum _exit. Haec est difficultas operandi cum systemate vocat: interface quod programmator operatur non directe ad systema vocat. Praeterea variat regulariter exsequendum et secundum suggestum.

Basics: iungendum processum in musca

Principio, ratio ptrace vocator, in qua fiebat stracenonnisi speciali modo programma currendo adhiberi potuit. Haec limitatio rationabile in diebus Versionis 6 Unix sonuisse potest. Hodie, hoc iam non est satis: interdum problemata programmatis operarii debes. Typical exemplum est processus clausus in manubrio vel dormienti. ergo moderni strace processus in musca potest iungere.

Mediolanum exemplum programs:

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

Progressionem aedificemus et gelidam eam fac:

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

Nunc iungere conemur:

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

Progressio impedit vocationem pause. Videamus quomodo se ad signa reagit:

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

Propositum congelatum inmisimus et utendo coniunximus strace. Duae res manifestae sunt: ​​mora ratio vocationis neglecta signa sine tracto et, magis interesting, strace monitores non solum ratio vocat, sed etiam signa ineuntium.

Exemplum: Puer Processus mauris

Lorem processibus per vocationem fork β€” Fundamenta omnium Unixes. Videamus quomodo stramen cum arbore processu operatur utens exemplo simplicis "feturae". programs:

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

Hic processus originalis puerum processum creat, utrumque scribens ad output vexillum:

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

Defalta tantum systema vocat videbimus ex processu parentis:

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

Vexillum adiuvat indagare totum lignum -f, quod " strace monitores systematis pueri in processibus vocat. Hoc ad singulas lineas output pid processus quod facit ratio output:

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

Hoc in contextu, eliquare coetus rationum vocat utilis esse potest;

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

Viam, quae ratio vocationis ad novum processum creandum adhibetur?

Exemplum: lima vias pro ansarum

Descriptores fasciculi scientes certe utile est, sed nomina imaginum specificarum quae accessiones programmata etiam in promptu venire possunt.

postero progressio scribit lineam ad tempus file:

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

Per normalis vocatio strace ostendam valorem descriptor numerus ad systema vocationis;

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

Cum a vexillum -y Utilitas ostendit viam tabellae cui descriptor respondet:

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

Exempli gratia: Semita File Access

Aliud utile notam: ostentationem sola ratio vocat cum certo fasciculo coniungendo. deinde progressio lineam apponit ad limam arbitrariam latae pro argumento;

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

per default strace multum necesse ostendit notitia. Flag -P cum argumento facit strace imprimendi solum ad certum file vocat:

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

Exemplum: Multithreaded Programs

utilitas strace Potest etiam auxilium cum opus cum multi-fila progressio. Propositum hoc scribit ut vexillum output a duobus rivis;

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

Naturaliter, cum speciali salutatione iungi debet - pthread vexillum:

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

vexillum -f, ut in processibus regularibus, accessus ad initium cujusque lineae.

Naturaliter de filo identificante non loquimur in sensu exsequendi vexillum sequelarum POSIX, sed de numero schedularum in Linux adhibito. Ex hac consideratione nullae sunt processus vel fili - sunt officia quae inter nucleos apparatus disponendos distribui debent.

Cum in pluribus sequelis operando, ratio vocat nimium multa facta;

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

Sensum efficit ut modum te ad processum administrationis ac systematis solum vocat 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 +++

Viam qq. Quae ratio vocationis adhibetur ad novum linum creare? Quomodo haec vocatio ad fila ab vocationi processuum differt?

Magister ordinis: processus ACERVUS tempore systematis vocatio

Una nuper apparuit strace facultates - vocat acervum functionis ostendit tempore systematis vocationis. Simple exempli gratia:

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

Naturaliter progressio output valde numerosa fit et, praeter vexillum -k (voca ACERVUS ostentus), sensum ad systema colum nominatim vocat;

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

Magister classis: error iniectio

Unum et magis novum et utilissimum: erroris iniectio. Hic progressioduas lineas scribens ad output stream;

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

Uterque scriptorum vestigia lets vocat;

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

Nunc utimur injectut errorem inserere EBADF in omnibus scribe vocat;

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

Suus 'interesting quid errores rediit' omnes challenges writequos vocant perror. Hoc solum facit sensum, ut remittas errorem in primis de vocationibus;

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

Vel secundum:

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

Non est necesse erroris genus denotare;

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

In compositione cum aliis vexillis, "frangere" accessum ad certum fasciculum potes. Exemplum:

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

Praeter errorem iniectio; potes annuit accepto vel vocat moras faciens cum inducere.

afterword

utilitas strace β€” instrumentum simplex et certum. Sed praeter systema vocat, aliae rationes operandi rationes et systema operandi debuggi possunt. Exempli gratia, indagare potest vocat ad bibliothecas dynamice ligatas. ltracepossunt inspicere operationem systematis operantis SystemTap ΠΈ ftraceac permittit ut progressio perficiendi penitus investigetur perfectus. Tamen est strace - Prima defensionis causa in quaestionibus meis propriis et aliorum hominum programmatis, eo utor saltem duobus in hebdomada.

In summa, si Unix amas, lege man 1 strace ac libenter peek at programmata tua!

Source: www.habr.com