Strace ื‘ืœื™ื ื•ืงืก: ื”ื™ืกื˜ื•ืจื™ื”, ืขื™ืฆื•ื‘ ื•ืฉื™ืžื•ืฉ

Strace ื‘ืœื™ื ื•ืงืก: ื”ื™ืกื˜ื•ืจื™ื”, ืขื™ืฆื•ื‘ ื•ืฉื™ืžื•ืฉ

ื‘ืžืขืจื›ื•ืช ื”ืคืขืœื” ื“ืžื•ื™ื•ืช ื™ื•ื ื™ืงืก, ื”ืชืงืฉื•ืจืช ืฉืœ ืชื•ื›ื ื™ืช ืขื ื”ืขื•ืœื ื”ื—ื™ืฆื•ืŸ ื•ืขื ืžืขืจื›ืช ื”ื”ืคืขืœื” ืžืชื‘ืฆืขืช ื‘ืืžืฆืขื•ืช ืกื˜ ืงื˜ืŸ ืฉืœ ืคื•ื ืงืฆื™ื•ืช - ืงืจื™ืื•ืช ืžืขืจื›ืช. ื”ืžืฉืžืขื•ืช ื”ื™ื ืฉืœืžื˜ืจื•ืช ืื™ืชื•ืจ ื‘ืื’ื™ื, ื–ื” ื™ื›ื•ืœ ืœื”ื™ื•ืช ืฉื™ืžื•ืฉื™ ืœืจื’ืœ ืื—ืจ ืงืจื™ืื•ืช ืžืขืจื›ืช ืฉืžืชื‘ืฆืขื•ืช ืขืœ ื™ื“ื™ ืชื”ืœื™ื›ื™ื.

ื›ืœื™ ืขื–ืจ ืขื•ื–ืจ ืœืš ืœื ื˜ืจ ืืช "ื”ื—ื™ื™ื ื”ืื™ื ื˜ื™ืžื™ื™ื" ืฉืœ ืชื•ื›ื ื™ื•ืช ื‘ืœื™ื ื•ืงืก strace, ืฉื”ื•ื ื ื•ืฉื ื”ืžืืžืจ ื”ื–ื”. ื“ื•ื’ืžืื•ืช ืœืฉื™ืžื•ืฉ ื‘ืฆื™ื•ื“ ืจื™ื’ื•ืœ ืžืœื•ื•ืช ื‘ื”ื™ืกื˜ื•ืจื™ื” ืงืฆืจื” strace ื•ืชื™ืื•ืจ ื”ืขื™ืฆื•ื‘ ืฉืœ ืชื•ื›ื ื™ื•ืช ื›ืืœื”.

ืชื•ื›ืŸ

ืžื•ืฆื ื”ืžื™ื ื™ื

ื”ืžืžืฉืง ื”ืขื™ืงืจื™ ื‘ื™ืŸ ืชื•ื›ื ื™ื•ืช ื•ืœื™ื‘ืช ืžืขืจื›ืช ื”ื”ืคืขืœื” ื‘ื™ื•ื ื™ืงืก ื”ื•ื ืงืจื™ืื•ืช ืžืขืจื›ืช. ืฉื™ื—ื•ืช ืžืขืจื›ืช, ืฉื™ื—ื•ืช ืžืขืจื›ื•ืช), ื”ืื™ื ื˜ืจืืงืฆื™ื” ืฉืœ ืชื•ื›ื ื™ื•ืช ืขื ื”ืขื•ืœื ื”ื—ื™ืฆื•ืŸ ืžืชืจื—ืฉืช ืืš ื•ืจืง ื“ืจื›ืŸ.

ืื‘ืœ ื‘ื’ืจืกื” ื”ืฆื™ื‘ื•ืจื™ืช ื”ืจืืฉื•ื ื” ืฉืœ ื™ื•ื ื™ืงืก (ื’ืจืกื” 6 ื™ื•ื ื™ืงืก, 1975) ืœื ื”ื™ื• ื“ืจื›ื™ื ื ื•ื—ื•ืช ืœืขืงื•ื‘ ืื—ืจ ื”ืชื ื”ื’ื•ืช ืชื”ืœื™ื›ื™ ื”ืžืฉืชืžืฉ. ื›ื“ื™ ืœืคืชื•ืจ ื‘ืขื™ื” ื–ื•, Bell Labs ืชืขื“ื›ืŸ ืœื’ืจืกื” ื”ื‘ืื” (ื’ืจืกื” 7 ื™ื•ื ื™ืงืก, 1979) ื”ืฆื™ืข ืงืจื™ืืช ืžืขืจื›ืช ื—ื“ืฉื” - ptrace.

ptrace ืคื•ืชื—ื” ื‘ืขื™ืงืจ ืขื‘ื•ืจ ืžืืคื™ ื‘ืื’ื™ื ืื™ื ื˜ืจืืงื˜ื™ื‘ื™ื™ื, ืืš ืขื“ ืกื•ืฃ ืฉื ื•ืช ื”-80 (ื‘ืขื™ื“ืŸ ื”ืžืกื—ืจื™ ืžืขืจื›ืช V ืžื”ื“ื•ืจื” 4) ืขืœ ื‘ืกื™ืก ื–ื”, ื ื™ืคื•ื™ ื‘ืื’ื™ื ืžืžื•ืงื“ื™ื - ืžืขืงื‘ื™ ืงืจื™ืื•ืช ืžืขืจื›ืช - ื”ื•ืคื™ืขื• ื•ื”ืคื›ื• ืœืฉื™ืžื•ืฉ ื ืจื—ื‘.

ะŸะตั€ะฒะฐั ืื•ืชื” ื’ืจืกื” ืฉืœ strace ืคื•ืจืกืžื” ืขืœ ื™ื“ื™ ืคื•ืœ ืงืจื•ื ื ื‘ื•ืจื’ ื‘ืจืฉื™ืžืช ื”ืชืคื•ืฆื” comp.sources.sun ื‘ืฉื ืช 1992 ื›ื—ืœื•ืคื” ืœืฉื™ืจื•ืช ืกื’ื•ืจ trace ืž- Sun. ื’ื ื”ืฉื™ื‘ื•ื˜ ื•ื’ื ื”ืžืงื•ืจ ื ื•ืขื“ื• ืขื‘ื•ืจ SunOS, ืืš ืขื“ 1994 strace ื”ื•ืขื‘ืจ ืœ-System V, Solaris ื•ืœื™ื ื•ืงืก ื”ืคื•ืคื•ืœืจื™ ื™ื•ืชืจ ื•ื™ื•ืชืจ.

ื›ื™ื•ื strace ืชื•ืžืš ืจืง ื‘ืœื™ื ื•ืงืก ื•ืžืกืชืžืš ืขืœ ืื•ืชื• ื”ื“ื‘ืจ ptrace, ืžื’ื•ื“ืœ ืขื ื”ืจื—ื‘ื•ืช ืจื‘ื•ืช.

ืžืชื—ื–ืง ืžื•ื“ืจื ื™ (ื•ืืงื˜ื™ื‘ื™ ืžืื•ื“). strace - ื“ืžื™ื˜ืจื™ ืœื•ื™ืŸ. ื”ื•ื“ื•ืช ืœื•, ื›ืœื™ ื”ืฉื™ืจื•ืช ืจื›ืฉ ืชื›ื•ื ื•ืช ืžืชืงื“ืžื•ืช ื›ืžื• ื”ื–ืจืงืช ืฉื’ื™ืื•ืช ืœืฉื™ื—ื•ืช ืžืขืจื›ืช, ืชืžื™ื›ื” ื‘ืžื’ื•ื•ืŸ ืจื—ื‘ ืฉืœ ืืจื›ื™ื˜ืงื˜ื•ืจื•ืช, ื•ื”ื›ื™ ื—ืฉื•ื‘, ืงึธืžึดื™ืขึท. ืžืงื•ืจื•ืช ืœื ืจืฉืžื™ื™ื ื˜ื•ืขื ื™ื ืฉื”ื‘ื—ื™ืจื” ื ืคืœื” ืขืœ ื™ืขืŸ ื‘ื’ืœืœ ื”ืขื™ื“ื•ื“ ื‘ื™ืŸ ื”ืžื™ืœื” ื”ืจื•ืกื™ืช "ื™ืขืŸ" ืœืžื™ืœื” ื”ืื ื’ืœื™ืช "ืกื˜ืจืก".

ื—ืฉื•ื‘ ื’ื ืฉื”ืงืจื™ืื” ืœืžืขืจื›ืช ptrace ื•ื”ืžืขืงื‘ื™ื ืžืขื•ืœื ืœื ื ื›ืœืœื• ื‘-POSIX, ืœืžืจื•ืช ื”ื™ืกื˜ื•ืจื™ื” ืืจื•ื›ื” ื•ื”ื˜ืžืขื” ื‘ืœื™ื ื•ืงืก, FreeBSD, OpenBSD ื•-Unix ื”ืžืกื•ืจืชื™ืช.

ืžื›ืฉื™ืจ Strace ื‘ืงืฆืจื”: Piglet Trace

"ืœื ืžืฆืคื™ื ืžืžืš ืœื”ื‘ื™ืŸ ืืช ื–ื”" (ื“ื ื™ืก ืจื™ืฆ'ื™, ื”ืขืจื” ื‘ืงื•ื“ ื”ืžืงื•ืจ ืฉืœ ื’ืจืกื” 6 Unix)

ืžืื– ื”ื™ืœื“ื•ืช ื”ืžื•ืงื“ืžืช, ืื ื™ ืœื ื™ื›ื•ืœ ืœืกื‘ื•ืœ ืงื•ืคืกืื•ืช ืฉื—ื•ืจื•ืช: ืœื ืฉื™ื—ืงืชื™ ื‘ืฆืขืฆื•ืขื™ื, ืืœื ื ื™ืกื™ืชื™ ืœื”ื‘ื™ืŸ ืืช ื”ืžื‘ื ื” ืฉืœื”ื (ืžื‘ื•ื’ืจื™ื ื”ืฉืชืžืฉื• ื‘ืžื™ืœื” "ื ืฉื‘ืจ", ืื‘ืœ ืœื ืžืืžื™ื ื™ื ืœืœืฉื•ื ื•ืช ื”ืจืขื•ืช). ืื•ืœื™ ื–ื• ื”ืกื™ื‘ื” ืฉื”ืชืจื‘ื•ืช ื”ื‘ืœืชื™ ืคื•ืจืžืœื™ืช ืฉืœ ื™ื•ื ื™ืงืก ื”ืจืืฉื•ืŸ ื•ืชื ื•ืขืช ื”ืงื•ื“ ื”ืคืชื•ื— ื”ืžื•ื“ืจื ื™ืช ื›ืœ ื›ืš ืงืจื•ื‘ื” ืืœื™.

ืœืžื˜ืจื•ืช ืžืืžืจ ื–ื”, ืื™ืŸ ื–ื” ื”ื’ื™ื•ื ื™ ืœืคืจืง ืืช ืงื•ื“ ื”ืžืงื•ืจ ืฉืœ strace, ืฉื’ื“ืœ ื‘ืžืฉืš ืขืฉืจื•ืช ืฉื ื™ื. ืื‘ืœ ืืกื•ืจ ืœื”ืฉืื™ืจ ืกื•ื“ื•ืช ืœืงื•ืจืื™ื. ืœื›ืŸ, ื›ื“ื™ ืœื”ืจืื•ืช ืืช ืขื™ืงืจื•ืŸ ื”ืคืขื•ืœื” ืฉืœ ืชื•ื›ื ื™ื•ืช ืจืฆื•ืขื•ืช ื›ืืœื”, ืื ื™ ืืกืคืง ืืช ื”ืงื•ื“ ืฉืœ ืžืขืงื‘ ืžื™ื ื™ืื˜ื•ืจื™ - ืขืงื‘ื•ืช ื—ื–ืจื–ื™ืจ (ptr). ื–ื” ืœื ื™ื•ื“ืข ืœืขืฉื•ืช ืฉื•ื ื“ื‘ืจ ืžื™ื•ื—ื“, ืื‘ืœ ื”ืขื™ืงืจ ื”ื•ื ืงืจื™ืื•ืช ื”ืžืขืจื›ืช ืฉืœ ื”ืชื•ื›ื ื™ืช - ื”ื™ื ืžื•ืฆื™ืื”:

$ 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 ืžื–ื”ื” ื‘ืขืจืš ืžืื•ืช ืงืจื™ืื•ืช ืžืขืจื›ืช ืœื™ื ื•ืงืก (ืจืื”. ืืช ื”ืฉื•ืœื—ืŸ) ื•ืขื•ื‘ื“ ืจืง ืขืœ ืืจื›ื™ื˜ืงื˜ื•ืจืช x86-64. ื–ื” ืžืกืคื™ืง ืœืžื˜ืจื•ืช ื—ื™ื ื•ื›ื™ื•ืช.

ื‘ื•ืื• ื ืกืชื›ืœ ืขืœ ืขื‘ื•ื“ืช ื”ืฉื™ื‘ื•ื˜ ืฉืœื ื•. ื‘ืžืงืจื” ืฉืœ ืœื™ื ื•ืงืก, ืžืืคื™ ื‘ืื’ื™ื ื•ืžืขืงื‘ื™ื ืžืฉืชืžืฉื™ื, ื›ืืžื•ืจ ืœืขื™ืœ, ื‘ืงืจื™ืื” ืœืžืขืจื›ืช ptrace. ื–ื” ืขื•ื‘ื“ ืขืœ ื™ื“ื™ ื”ืขื‘ืจืช ื‘ืืจื’ื•ืžื ื˜ ื”ืจืืฉื•ืŸ ืืช ืžื–ื”ื™ ื”ืคืงื•ื“ื•ืช, ืฉืื ื—ื ื• ืฆืจื™ื›ื™ื ืจืง ืžื”ื PTRACE_TRACEME, PTRACE_SYSCALL ะธ PTRACE_GETREGS.

ื”ื ื•ืชื‘ ืžืชื—ื™ืœ ื‘ืกื’ื ื•ืŸ ื™ื•ื ื™ืงืก ื”ืจื’ื™ืœ: fork(2) ืžืฉื™ืง ืชื”ืœื™ืš ื™ืœื“, ืืฉืจ ื‘ืชื•ืจื• ืžืฉืชืžืฉ exec(3) ืžืฉื™ืงื” ืืช ื”ืชื•ื›ื ื™ืช ื”ื ื—ืงืจืช. ื”ืขื“ื™ื ื•ืช ื”ื™ื—ื™ื“ื” ื›ืืŸ ื”ื™ื ื”ืืชื’ืจ ptrace(PTRACE_TRACEME) ืœืคื ื™ exec: ืชื”ืœื™ืš ื”ื™ืœื“ ืžืฆืคื” ืžืชื”ืœื™ืš ื”ื”ื•ืจื” ืœืคืงื— ืขืœื™ื•:

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

ืชื”ืœื™ืš ื”ื”ื•ืจื” ืืžื•ืจ ื›ืขืช ืœื”ืชืงืฉืจ wait(2) ื‘ืชื”ืœื™ืš ื”ื™ืœื“, ื›ืœื•ืžืจ, ื•ื“ื ืฉื”ืžืขื‘ืจ ืœืžืฆื‘ ืžืขืงื‘ ื”ืชืจื—ืฉ:

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

ื‘ืฉืœื‘ ื–ื” ื”ื”ื›ื ื•ืช ื”ื•ืฉืœืžื• ื•ื ื™ืชืŸ ืœื”ืžืฉื™ืš ื™ืฉื™ืจื•ืช ืœืžืขืงื‘ ืื—ืจ ืฉื™ื—ื•ืช ื”ืžืขืจื›ืช ื‘ืœื•ืค ืื™ื ืกื•ืคื™.

ะ’ั‹ะทะพะฒ ptrace(PTRACE_SYSCALL) ืžื‘ื˜ื™ื— ื›ื™ ืœืื—ืจ ืžื›ืŸ wait ื”ื”ื•ืจื” ื™ืกืชื™ื™ื ืœืคื ื™ ื‘ื™ืฆื•ืข ืฉื™ื—ืช ื”ืžืขืจื›ืช ืื• ืžื™ื“ ืœืื—ืจ ื”ืฉืœืžืชื”. ื‘ื™ืŸ ืฉืชื™ ืงืจื™ืื•ืช ื ื™ืชืŸ ืœื‘ืฆืข ื›ืœ ืคืขื•ืœื”: ืœื”ื—ืœื™ืฃ ืืช ื”ืงืจื™ืื” ื‘ืื—ืช ื—ืœื•ืคื™ืช, ืœืฉื ื•ืช ืืช ื”ืืจื’ื•ืžื ื˜ื™ื ืื• ืืช ืขืจืš ื”ื”ื—ื–ืจื”.

ืื ื—ื ื• ืจืง ืฆืจื™ื›ื™ื ืœืงืจื•ื ืœืคืงื•ื“ื” ืคืขืžื™ื™ื ptrace(PTRACE_GETREGS)ื›ื“ื™ ืœืงื‘ืœ ืืช ืžืฆื‘ ื”ืจื™ืฉื•ื rax ืœืคื ื™ ื”ืฉื™ื—ื” (ืžืกืคืจ ืฉื™ื—ืช ืžืขืจื›ืช) ื•ืžื™ื“ ืื—ืจื™ื” (ืขืจืš ื”ื—ื–ืจื”).

ืœืžืขืฉื”, ื”ืžื—ื–ื•ืจ:

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

ื–ื” ื›ืœ ื”ื ื•ืชื‘. ืขื›ืฉื™ื• ืืชื” ื™ื•ื“ืข ืื™ืคื” ืœื”ืชื—ื™ืœ ืืช ื”ื”ืขื‘ืจื” ื”ื‘ืื” DTrace ืขืœ ืœื™ื ื•ืงืก.

ื™ืกื•ื“ื•ืช: ื”ืคืขืœืช ืชื•ื›ื ื™ืช ืจืฆื”

ื‘ืชื•ืจ ืžืงืจื” ืฉื™ืžื•ืฉ ืจืืฉื•ืŸ strace, ืื•ืœื™ ื›ื“ืื™ ืœืฆื˜ื˜ ืืช ื”ืฉื™ื˜ื” ื”ืคืฉื•ื˜ื” ื‘ื™ื•ืชืจ - ื”ืคืขืœืช ืืคืœื™ืงืฆื™ื” ื”ืคื•ืขืœืช strace.

ื›ื“ื™ ืœื ืœื”ืชืขืžืง ื‘ืจืฉื™ืžืช ื”ืฉื™ื—ื•ืช ื”ืื™ื ืกื•ืคื™ืช ืฉืœ ืชื•ื›ื ื™ืช ื˜ื™ืคื•ืกื™ืช, ืื ื—ื ื• ื›ื•ืชื‘ื™ื ืชื•ื›ื ื™ืช ืžื™ื ื™ืžื•ื ืžืกื‘ื™ื‘ 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;
}

ื‘ื•ืื• ื ื‘ื ื” ืืช ื”ืชื•ื›ื ื™ืช ื•ื ื•ื•ื“ื ืฉื”ื™ื ืขื•ื‘ื“ืช:

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

ื•ืœื‘ืกื•ืฃ, ื‘ื•ืื• ื ืจื™ืฅ ืืช ื–ื” ืชื—ืช ื‘ืงืจืช ืจืฆื•ืขื•ืช:

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

ืžืื•ื“ "ืจื‘ ืžื™ืœื™ื" ื•ืœื ืžืื•ื“ ื—ื™ื ื•ื›ื™. ื™ืฉ ื›ืืŸ ืฉืชื™ ื‘ืขื™ื•ืช: ืคืœื˜ ื”ืชื•ื›ื ื™ืช ืžืขื•ืจื‘ื‘ ืขื ื”ืคืœื˜ strace ื•ืฉืคืข ืฉืœ ืฉื™ื—ื•ืช ืžืขืจื›ืช ืฉืœื ืžืขื ื™ื™ื ื•ืช ืื•ืชื ื•.

ืืชื” ื™ื›ื•ืœ ืœื”ืคืจื™ื“ ื‘ื™ืŸ ื–ืจื ื”ืคืœื˜ ื”ืกื˜ื ื“ืจื˜ื™ ืฉืœ ื”ืชื•ื›ื ื™ืช ืœื‘ื™ืŸ ืคืœื˜ ื”ืฉื’ื™ืื” ืฉืœ ื”ืชื•ื›ื ื™ืช ื‘ืืžืฆืขื•ืช ืžืชื’ -o, ื”ืžืคื ื” ืืช ืจืฉื™ืžืช ืงืจื™ืื•ืช ื”ืžืขืจื›ืช ืœืงื•ื‘ืฅ ืืจื’ื•ืžื ื˜ื™ื.

ื ื•ืชืจ ืœื”ืชืžื•ื“ื“ ืขื ื”ื‘ืขื™ื” ืฉืœ ืฉื™ื—ื•ืช "ื ื•ืกืคื•ืช". ื‘ื•ื ื ื ื™ื— ืฉืื ื—ื ื• ืžืขื•ื ื™ื™ื ื™ื ืจืง ื‘ืฉื™ื—ื•ืช write. ืžึทืคึฐืชึตื—ึท -e ืžืืคืฉืจ ืœืš ืœืฆื™ื™ืŸ ื‘ื™ื˜ื•ื™ื™ื ืฉืœืคื™ื”ื ืฉื™ื—ื•ืช ื”ืžืขืจื›ืช ื™ืกื•ื ื ื•. ืืคืฉืจื•ืช ื”ืžืฆื‘ ื”ืคื•ืคื•ืœืจื™ืช ื‘ื™ื•ืชืจ ื”ื™ื, ื‘ืื•ืคืŸ ื˜ื‘ืขื™, trace=*, ืื™ืชื ืชื•ื›ืœื• ืœื”ืฉืื™ืจ ืจืง ืืช ื”ืฉื™ื—ื•ืช ืฉืžืขื ื™ื™ื ื•ืช ืื•ืชื ื•.

ื‘ืฉื™ืžื•ืฉ ื‘ื• ื–ืžื ื™ืช -o ะธ -e ืื ื• ื ืงื‘ืœ:

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

ืื–, ืืชื” ืžื‘ื™ืŸ, ื–ื” ื”ืจื‘ื” ื™ื•ืชืจ ืงืœ ืœืงืจื•ื.

ื ื™ืชืŸ ื’ื ืœื”ืกื™ืจ ืฉื™ื—ื•ืช ืžืขืจื›ืช, ืœืžืฉืœ ื›ืืœื” ื”ืงืฉื•ืจื•ืช ืœื”ืงืฆืืช ื–ื™ื›ืจื•ืŸ ื•ืฉื—ืจื•ืจ:

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

ืฉื™ืžื• ืœื‘ ืœืกื™ืžืŸ ื”ืงืจื™ืื” ืฉื ืžืœื˜ ื‘ืจืฉื™ืžืช ื”ืฉื™ื—ื•ืช ืฉืœื ื ื›ืœืœื•: ื–ื” ื ื“ืจืฉ ืขืœ ื™ื“ื™ ืžืขื˜ืคืช ื”ืคืงื•ื“ื”. ืคึผึธื’ึธื–).

ื‘ื’ืจืกื” ืฉืœื™ ืฉืœ glibc, ืงืจื™ืืช ืžืขืจื›ืช ืžืกื™ื™ืžืช ืืช ื”ืชื”ืœื™ืš exit_group, ืœื ืžืกื•ืจืชื™ _exit. ื–ื” ื”ืงื•ืฉื™ ื‘ืขื‘ื•ื“ื” ืขื ืงืจื™ืื•ืช ืžืขืจื›ืช: ื”ืžืžืฉืง ืื™ืชื• ืขื•ื‘ื“ ื”ืžืชื›ื ืช ืื™ื ื• ืงืฉื•ืจ ื™ืฉื™ืจื•ืช ืœืงืจื™ืื•ืช ื”ืžืขืจื›ืช. ื™ืชืจ ืขืœ ื›ืŸ, ื”ื•ื ืžืฉืชื ื” ื‘ืื•ืคืŸ ืงื‘ื•ืข ื‘ื”ืชืื ืœื™ื™ืฉื•ื ื•ืœืคืœื˜ืคื•ืจืžื”.

ื™ืกื•ื“ื•ืช: ื”ืฆื˜ืจืคื•ืช ืœืชื”ืœื™ืš ืชื•ืš ื›ื“ื™ ืชื ื•ืขื”

ื‘ืชื—ื™ืœื”, ืžืขืจื›ืช ptrace call ืขืœื™ื” ื”ื™ื ื ื‘ื ืชื” strace, ื ื™ืชืŸ ืœื”ืฉืชืžืฉ ืจืง ื‘ืขืช ื”ืคืขืœืช ื”ืชื•ื›ื ื™ืช ื‘ืžืฆื‘ ืžื™ื•ื—ื“. ื™ื™ืชื›ืŸ ืฉื”ืžื’ื‘ืœื” ื”ื–ื• ื ืฉืžืขื” ืกื‘ื™ืจื” ื‘ื™ืžื™ ื’ืจืกื” 6 Unix. ื›ื™ื•ื ื–ื” ื›ื‘ืจ ืœื ืžืกืคื™ืง: ืœืคืขืžื™ื ืฆืจื™ืš ืœื—ืงื•ืจ ืืช ื”ื‘ืขื™ื•ืช ืฉืœ ืชื•ื›ื ื™ืช ืขื•ื‘ื“ืช. ื“ื•ื’ืžื” ื˜ื™ืคื•ืกื™ืช ื”ื™ื ืชื”ืœื™ืš ื—ืกื•ื ืขืœ ื™ื“ื™ืช ืื• ืฉื™ื ื”. ืœื›ืŸ ืžื•ื“ืจื ื™ strace ื™ื›ื•ืœ ืœื”ืฆื˜ืจืฃ ืœืชื”ืœื™ื›ื™ื ืชื•ืš ื›ื“ื™ ืชื ื•ืขื”.

ื“ื•ื’ืžื” ืžืงืคื™ืื” ะฟั€ะพะณั€ะฐะผะผั‹:

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

ื‘ื•ืื• ื ื‘ื ื” ืืช ื”ืชื•ื›ื ื™ืช ื•ื ื•ื•ื“ื ืฉื”ื™ื ืงืคื•ืื”:

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

ืขื›ืฉื™ื• ื‘ื•ืื• ื ื ืกื” ืœื”ืฆื˜ืจืฃ ืืœื™ื•:

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

ื”ืชื•ื›ื ื™ืช ื ื—ืกืžื” ื‘ืฉื™ื—ื” pause. ื‘ื•ืื• ื ืจืื” ืื™ืš ื”ื™ื ืžื’ื™ื‘ื” ืœืื•ืชื•ืช:

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

ื”ืฉืงื ื• ืืช ื”ืชื•ื›ื ื™ืช ื”ืงืคื•ืื” ื•ื”ืฆื˜ืจืคื ื• ืืœื™ื” ื‘ืืžืฆืขื•ืช strace. ืฉื ื™ ื“ื‘ืจื™ื ื”ืชื‘ืจืจื•: ืงืจื™ืืช ื”ื”ืฉื”ื™ื” ืฉืœ ื”ืžืขืจื›ืช ืžืชืขืœืžืช ืžืื•ืชื•ืช ืœืœื ืžื˜ืคืœื™ื, ื•ืžืขื ื™ื™ืŸ ื™ื•ืชืจ, ื”-strace ืžื ื˜ืจืช ืœื ืจืง ืงืจื™ืื•ืช ืžืขืจื›ืช, ืืœื ื’ื ืื•ืชื•ืช ื ื›ื ืกื™ื.

ื“ื•ื’ืžื”: ืžืขืงื‘ ืื—ืจ ืชื”ืœื™ื›ื™ ื™ืœื“ื™ื

ืขื‘ื•ื“ื” ืขื ืชื”ืœื™ื›ื™ื ื‘ืืžืฆืขื•ืช ืฉื™ื—ื” fork - ื”ื‘ืกื™ืก ืฉืœ ื›ืœ ื™ื•ื ื™ืงืก. ื‘ื•ื ื ืจืื” ืื™ืš ืกื˜ืจืืก ืขื•ื‘ื“ ืขื ืขืฅ ืชื”ืœื™ืš ืชื•ืš ืฉื™ืžื•ืฉ ื‘ื“ื•ื’ืžื” ืฉืœ "ื’ื™ื“ื•ืœ" ืคืฉื•ื˜ ะฟั€ะพะณั€ะฐะผะผั‹:

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

ื›ืืŸ ื”ืชื”ืœื™ืš ื”ืžืงื•ืจื™ ื™ื•ืฆืจ ืชื”ืœื™ืš ื™ืœื“, ืฉื ื™ื”ื ื›ื•ืชื‘ื™ื ืœืคืœื˜ ืกื˜ื ื“ืจื˜ื™:

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

ื›ื‘ืจื™ืจืช ืžื—ื“ืœ, ื ืจืื” ืจืง ืงืจื™ืื•ืช ืžืขืจื›ืช ืžืชื”ืœื™ืš ื”ืื‘:

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

ื”ื“ื’ืœ ืขื•ื–ืจ ืœืš ืœืขืงื•ื‘ ืื—ืจ ืขืฅ ื”ืชื”ืœื™ืš ื›ื•ืœื• -fืขื ืืฉืจ strace ืขื•ืงื‘ ืื—ืจ ืงืจื™ืื•ืช ืžืขืจื›ืช ื‘ืชื”ืœื™ื›ื™ ืฆืืฆื. ื–ื” ืžื•ืกื™ืฃ ืœื›ืœ ืฉื•ืจืช ืคืœื˜ pid ืชื”ืœื™ืš ืฉื™ื•ืฆืจ ืคืœื˜ ืžืขืจื›ืช:

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

ื‘ื”ืงืฉืจ ื–ื”, ืกื™ื ื•ืŸ ืœืคื™ ืงื‘ื•ืฆืช ืงืจื™ืื•ืช ืžืขืจื›ืช ื™ื›ื•ืœ ืœื”ื™ื•ืช ืฉื™ืžื•ืฉื™:

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

ืื’ื‘, ื‘ืื™ื–ื• ืงืจื™ืืช ืžืขืจื›ืช ืžืฉืชืžืฉื™ื ืœื™ืฆื™ืจืช ืชื”ืœื™ืš ื—ื“ืฉ?

ื“ื•ื’ืžื”: ื ืชื™ื‘ื™ ืงื‘ืฆื™ื ื‘ืžืงื•ื ื™ื“ื™ื•ืช

ื”ื›ืจืช ืžืชืืจื™ ืงื‘ืฆื™ื ื”ื™ื ื‘ื”ื—ืœื˜ ืฉื™ืžื•ืฉื™ืช, ืื‘ืœ ื”ืฉืžื•ืช ืฉืœ ื”ืงื‘ืฆื™ื ื”ืกืคืฆื™ืคื™ื™ื ืฉืชื•ื›ื ื™ืช ื ื™ื’ืฉืช ืืœื™ื”ื ื™ื›ื•ืœื™ื ืœื”ื™ื•ืช ืฉื™ืžื•ืฉื™ื™ื.

ื”ื‘ื ืชื›ื ื™ืช ื›ื•ืชื‘ ืืช ื”ืฉื•ืจื” ืœืงื•ื‘ืฅ ื”ื–ืžื ื™:

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

ื‘ืžื”ืœืš ืฉื™ื—ื” ืจื’ื™ืœื” strace ื™ืฆื™ื’ ืืช ื”ืขืจืš ืฉืœ ืžืกืคืจ ื”ืžืชืืจ ืฉื”ื•ืขื‘ืจ ืœืงืจื™ืืช ื”ืžืขืจื›ืช:

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

ืขื ื“ื’ืœ -y ื›ืœื™ ื”ืฉื™ืจื•ืช ืžืฆื™ื’ ืืช ื”ื ืชื™ื‘ ืœืงื•ื‘ืฅ ืฉืืœื™ื• ืžืชืื™ื ื”ืžืชืืจ:

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

ื“ื•ื’ืžื”: ืžืขืงื‘ ืื—ืจ ื’ื™ืฉื” ืœืงื‘ืฆื™ื

ืชื›ื•ื ื” ืฉื™ืžื•ืฉื™ืช ื ื•ืกืคืช: ื”ืฆื’ ืจืง ืงืจื™ืื•ืช ืžืขืจื›ืช ื”ืžืฉื•ื™ื›ื•ืช ืœืงื•ื‘ืฅ ืกืคืฆื™ืคื™. ื”ึทื‘ึผึธื ืชื›ื ื™ืช ืžื•ืกื™ืฃ ืฉื•ืจื” ืœืงื•ื‘ืฅ ืฉืจื™ืจื•ืชื™ ื”ืžื•ืขื‘ืจ ื›ืืจื’ื•ืžื ื˜:

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

ื‘ืจื™ืจืช ืžื—ื“ืœ strace ืžืฆื™ื’ ื”ืจื‘ื” ืžื™ื“ืข ืžื™ื•ืชืจ. ื“ึถื’ึถืœ -P ืขื ืืจื’ื•ืžื ื˜ ื’ื•ืจื ืœ-strace ืœื”ื“ืคื™ืก ืจืง ืงืจื™ืื•ืช ืœืงื•ื‘ืฅ ืฉืฆื•ื™ืŸ:

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

ื“ื•ื’ืžื”: ืชื•ื›ื ื™ื•ืช ืžืจื•ื‘ื•ืช ื”ืœื™ื›ื™ื

ืฉื™ืจื•ืช strace ื™ื›ื•ืœ ืœืขื–ื•ืจ ื’ื ื‘ืขื‘ื•ื“ื” ืขื ืจื™ื‘ื•ื™ ื—ื•ื˜ื™ื ื”ืชื•ื›ื ื™ืช. ื”ืชื•ื›ื ื™ืช ื”ื‘ืื” ื›ื•ืชื‘ืช ืœืคืœื˜ ืกื˜ื ื“ืจื˜ื™ ืžืฉื ื™ ื–ืจืžื™ื:

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

ื›ืžื•ื‘ืŸ, ื™ืฉ ืœื”ืจื›ื™ื‘ ืื•ืชื• ืขื ื‘ืจื›ื” ืžื™ื•ื—ื“ืช ืœืžืงืฉืจ - ื“ื’ืœ -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
$

ื“ื’ืœ -f, ื›ืžื• ื‘ืžืงืจื” ืฉืœ ืชื”ืœื™ื›ื™ื ืจื’ื™ืœื™ื, ื™ื•ืกื™ืฃ ืืช ื”-pid ืฉืœ ื”ืชื”ืœื™ืš ืœืชื—ื™ืœืช ื›ืœ ืฉื•ืจื”.

ืžื˜ื‘ืข ื”ื“ื‘ืจื™ื, ืื ื—ื ื• ืœื ืžื“ื‘ืจื™ื ืขืœ ืžื–ื”ื” ืฉืจืฉื•ืจ ื‘ืžื•ื‘ืŸ ืฉืœ ื™ื™ืฉื•ื ืชืงืŸ POSIX Threads, ืืœื ืขืœ ื”ืžืกืคืจ ืฉื‘ื• ืžืฉืชืžืฉ ืžืชื–ืžืŸ ื”ืžืฉื™ืžื•ืช ื‘ืœื™ื ื•ืงืก. ืžื ืงื•ื“ืช ื”ืžื‘ื˜ ืฉืœ ื”ืื—ืจื•ืŸ, ืื™ืŸ ืชื”ืœื™ื›ื™ื ืื• ื—ื•ื˜ื™ื - ื™ืฉ ืžืฉื™ืžื•ืช ืฉืฆืจื™ืš ืœื”ืคื™ืฅ ื‘ื™ืŸ ื”ืœื™ื‘ื•ืช ื”ื–ืžื™ื ื•ืช ืฉืœ ื”ืžื›ื•ื ื”.

ื›ืืฉืจ ืขื•ื‘ื“ื™ื ื‘ืžืกืคืจ ืฉืจืฉื•ืจื™ื, ืงืจื™ืื•ืช ื”ืžืขืจื›ืช ื”ื•ืคื›ื•ืช ืœื™ื•ืชืจ ืžื“ื™:

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

ื”ื’ื™ื•ื ื™ ืœื”ื’ื‘ื™ืœ ืืช ืขืฆืžืš ืœื ื™ื”ื•ืœ ืชื”ืœื™ื›ื™ื ื•ืงืจื™ืื•ืช ืžืขืจื›ืช ื‘ืœื‘ื“ 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 +++

ืื’ื‘, ืฉืืœื•ืช. ื‘ืื™ื–ื• ืงืจื™ืืช ืžืขืจื›ืช ืžืฉืชืžืฉื™ื ืœื™ืฆื™ืจืช ืฉืจืฉื•ืจ ื—ื“ืฉ? ื‘ืžื” ืฉื•ื ื” ื”ืงืจื™ืื” ื”ื–ื• ืœืฉืจืฉื•ืจื™ื ืžื”ืงืจื™ืื” ืœืชื”ืœื™ื›ื™ื?

ื›ื™ืชืช ืืžืŸ: ืžื—ืกื ื™ืช ืชื”ืœื™ื›ื™ื ื‘ื–ืžืŸ ืงืจื™ืืช ืžืขืจื›ืช

ืื—ื“ ืžื”ื ื”ื•ืคื™ืข ืœืื—ืจื•ื ื” strace ื™ื›ื•ืœื•ืช - ื”ืฆื’ืช ืขืจื™ืžืช ืงืจื™ืื•ืช ื”ืคื•ื ืงืฆื™ื•ืช ื‘ื–ืžืŸ ืงืจื™ืืช ื”ืžืขืจื›ืช. ืคึผึธืฉืื•ึผื˜ ื“ื•ื’ืžื”:

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

ื‘ืื•ืคืŸ ื˜ื‘ืขื™, ื”ืคืœื˜ ืฉืœ ื”ืชื•ื›ื ื™ืช ื”ื•ืคืš ืœื ืคื— ืžืื•ื“, ื•ื‘ื ื•ืกืฃ ืœื“ื’ืœ -k (ืชืฆื•ื’ืช ืขืจื™ืžืช ืฉื™ื—ื•ืช), ื”ื’ื™ื•ื ื™ ืœืกื ืŸ ืงืจื™ืื•ืช ืžืขืจื›ืช ืœืคื™ ืฉื:

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

ื›ื™ืชืช ืืžืŸ: ื”ื–ืจืงืช ืฉื’ื™ืื”

ื•ืขื•ื“ ืชื›ื•ื ื” ื—ื“ืฉื” ื•ืฉื™ืžื•ืฉื™ืช ืžืื•ื“: ื”ื–ืจืงืช ืฉื’ื™ืื”. ื›ืืŸ ืชื›ื ื™ืช, ื›ืชื™ื‘ืช ืฉืชื™ ืฉื•ืจื•ืช ืœื–ืจื ื”ืคืœื˜:

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

ื‘ื•ืื• ื ืชื—ืงื” ืื—ืจ ืฉืชื™ ื”ืฉื™ื—ื•ืช ืœื›ืชื•ื‘:

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

ื›ืขืช ืื ื• ืžืฉืชืžืฉื™ื ื‘ื‘ื™ื˜ื•ื™ injectื›ื“ื™ ืœื”ื›ื ื™ืก ืฉื’ื™ืื” EBADF ื‘ื›ืœ ืฉื™ื—ื•ืช ื›ืชื™ื‘ื”:

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

ืžืขื ื™ื™ืŸ ืื™ืœื• ืฉื’ื™ืื•ืช ืžื•ื—ื–ืจื•ืช ื›ืœ ืืชื’ืจื™ื write, ื›ื•ืœืœ ื”ืฉื™ื—ื” ื”ืžื•ืกืชืจืช ืžืื—ื•ืจื™ ื˜ืขื•ืช. ื–ื” ืจืง ื”ื’ื™ื•ื ื™ ืœื”ื—ื–ื™ืจ ืฉื’ื™ืื” ืขื‘ื•ืจ ื”ืจืืฉื•ื ื” ืžื”ืฉื™ื—ื•ืช:

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

ืื• ื”ืฉื ื™:

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

ืื™ืŸ ืฆื•ืจืš ืœืฆื™ื™ืŸ ืืช ืกื•ื’ ื”ืฉื’ื™ืื”:

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

ื‘ืฉื™ืœื•ื‘ ืขื ื“ื’ืœื™ื ืื—ืจื™ื, ืืชื” ื™ื›ื•ืœ "ืœืฉื‘ื•ืจ" ื’ื™ืฉื” ืœืงื•ื‘ืฅ ืกืคืฆื™ืคื™. ื“ื•ื’ืžื:

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

ืžืœื‘ื“ ื”ื–ืจืงืช ืฉื’ื™ืื”, ืื—ื“ ื™ื›ื•ืœ ืœื”ืฆื™ื’ ืขื™ื›ื•ื‘ื™ื ื‘ืขืช ื‘ื™ืฆื•ืข ืฉื™ื—ื•ืช ืื• ืงื‘ืœืช ืื•ืชื•ืช.

ืื—ืจื™ืช ื“ื‘ืจ

ืฉื™ืจื•ืช strace - ื›ืœื™ ืคืฉื•ื˜ ื•ืืžื™ืŸ. ืื‘ืœ ื‘ื ื•ืกืฃ ืœืฉื™ื—ื•ืช ืžืขืจื›ืช, ื ื™ืชืŸ ืœืืชืจ ื”ื™ื‘ื˜ื™ื ืื—ืจื™ื ืฉืœ ืคืขื•ืœืช ื”ืชื•ื›ื ื™ื•ืช ื•ืžืขืจื›ืช ื”ื”ืคืขืœื”. ืœื“ื•ื’ืžื”, ื”ื•ื ื™ื›ื•ืœ ืœืขืงื•ื‘ ืื—ืจ ืฉื™ื—ื•ืช ืœืกืคืจื™ื•ืช ืžืงื•ืฉืจื•ืช ื“ื™ื ืžื™ืช. ืขืงื‘ื•ืช, ื”ื ื™ื›ื•ืœื™ื ืœื‘ื“ื•ืง ืืช ืคืขื•ืœืช ืžืขืจื›ืช ื”ื”ืคืขืœื” SystemTap ะธ ftrace, ื•ืžืืคืฉืจ ืœืš ืœื—ืงื•ืจ ืœืขื•ืžืง ืืช ื‘ื™ืฆื•ืขื™ ื”ืชื•ื›ื ื™ืช perf. ืœืžืจื•ืช ื–ืืช, ื–ื” ื›ืŸ strace - ืงื• ื”ื”ื’ื ื” ื”ืจืืฉื•ืŸ ื‘ืžืงืจื” ืฉืœ ื‘ืขื™ื•ืช ื‘ืชื•ื›ื ื™ื•ืช ืฉืœื™ ื•ืฉืœ ืื ืฉื™ื ืื—ืจื™ื, ื•ืื ื™ ืžืฉืชืžืฉ ื‘ื• ืœืคื—ื•ืช ื›ืžื” ืคืขืžื™ื ื‘ืฉื‘ื•ืข.

ื‘ืงื™ืฆื•ืจ, ืื ืืชื” ืื•ื”ื‘ ื™ื•ื ื™ืงืก, ืงืจื man 1 strace ื•ืืœ ืชื”ืกืก ืœื”ืฆื™ืฅ ื‘ืชื•ื›ื ื™ื•ืช ืฉืœืš!

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”