ืกื˜ืจืึทืกืข ืื™ืŸ ืœื™ื ื•ืงืก: ื’ืขืฉื™ื›ื˜ืข, ืคึผืœืึทืŸ ืื•ืŸ ื ื•ืฆืŸ

ืกื˜ืจืึทืกืข ืื™ืŸ ืœื™ื ื•ืงืก: ื’ืขืฉื™ื›ื˜ืข, ืคึผืœืึทืŸ ืื•ืŸ ื ื•ืฆืŸ

ืื™ืŸ ื™ื•ื ื™ืงืก-ื•ื•ื™ ืึธืคึผืขืจื™ื™ื˜ื™ื ื’ ืกื™ืกื˜ืขืžืขืŸ, ืึท ืคึผืจืึธื’ืจืึทื ืก ืงืึธืžื•ื ื™ืงืึทืฆื™ืข ืžื™ื˜ ื“ื™ ืึทืจื•ื™ืก ื•ื•ืขืœื˜ ืื•ืŸ ื“ื™ ืึธืคึผืขืจื™ื™ื˜ื™ื ื’ ืกื™ืกื˜ืขื ืึทืงืขืจื– ื“ื•ืจืš ืึท ืงืœื™ื™ืŸ ื’ืึทื ื’ ืคื•ืŸ ืคืึทื ื’ืงืฉืึทื ื– - ืกื™ืกื˜ืขื ืจื•ืคื˜. ื“ืขื ืžื™ื˜ืœ ืึทื– ืคึฟืึทืจ ื“ื™ื‘ืึทื’ื™ื ื’ ืฆื•ื•ืขืงืŸ, ืขืก ืงืขืŸ ื–ื™ื™ืŸ ื ื•ืฆื™ืง ืฆื• ืฉืคึผื™ืึธืŸ ืื•ื™ืฃ ืกื™ืกื˜ืขื ืงืึทืœืœืก ื•ื•ืึธืก ื–ืขื ืขืŸ ืขืงืกืึทืงื™ื•ื˜ืึทื“ ื“ื•ืจืš ืคึผืจืึทืกืขืกืึทื–.

ื ื ื•ืฆืŸ ื”ืขืœืคึผืก ืื™ืจ ืžืึธื ื™ื˜ืึธืจ ื“ื™ "ืึธื ื•ื•ื™ื ืงืขืŸ ืœืขื‘ืŸ" ืคื•ืŸ ืžื’ื™ืœื” ืื•ื™ืฃ ืœื™ื ื•ืงืก strace, ื•ื•ืึธืก ืื™ื– ื“ื™ ื˜ืขืžืข ืคื•ืŸ โ€‹โ€‹ื“ืขื ืึทืจื˜ื™ืงืœ. ื‘ื™ื™ืฉืคื™ืœืŸ ืคื•ืŸ ื“ื™ ื ื•ืฆืŸ ืคื•ืŸ ืฉืคึผื™ืึธืŸ ื•ื™ืกืจื™ื›ื˜ ื–ืขื ืขืŸ ื‘ืื’ืœื™ื™ื˜ ื“ื•ืจืš ืึท ืงื•ืจืฅ ื’ืขืฉื™ื›ื˜ืข strace ืื•ืŸ ืึท ื‘ืึทืฉืจื™ื™ึทื‘ื•ื ื’ ืคื•ืŸ ื“ื™ ืคึผืœืึทืŸ ืคื•ืŸ ืึทื–ืึท ืžื’ื™ืœื”.

ืฆื•ืคืจื™ื“ืŸ

ืึธืจื™ื’ื™ืŸ ืคื•ืŸ ืžื™ื ื™ื

ื“ื™ ื”ื•ื™ืคึผื˜ ืฆื•ื‘ื™ื ื“ ืฆื•ื•ื™ืฉืŸ ืžื’ื™ืœื” ืื•ืŸ ื“ื™ ืึทืก ืงืขืจืŸ ืื™ืŸ ื™ื•ื ื™ืงืก ืื™ื– ืกื™ืกื˜ืขื ืงืึทืœืœืก. ืกื™ืกื˜ืขื ืจื•ืคื˜, ืกื™ืกืงืึทืœืœืก), ื“ื™ ื™ื ื˜ืขืจืึทืงืฉืึทืŸ ืคื•ืŸ ืžื’ื™ืœื” ืžื™ื˜ ื“ื™ ืึทืจื•ื™ืก ื•ื•ืขืœื˜ ืึทืงืขืจื– ืื•ื™ืกืฉืœื™ืกืœืขืš ื“ื•ืจืš ื–ื™ื™.

ืึธื‘ืขืจ ืื™ืŸ ื“ืขืจ ืขืจืฉื˜ืขืจ ืขืคื ื˜ืœืขืš ื•ื•ืขืจืกื™ืข ืคื•ืŸ โ€‹โ€‹ื™ื•ื ื™ืงืก (ื•ื•ืขืจืกื™ืข 6 ื™ื•ื ื™ืงืก, 1975) ืขืก ื–ืขื ืขืŸ ื’ืขื•ื•ืขืŸ ืงื™ื™ืŸ ื‘ืึทืงื•ื•ืขื ื•ื•ืขื’ืŸ ืฆื• ืฉืคึผื•ืจ ื“ื™ ื ืึทื˜ื•ืจ ืคื•ืŸ ื‘ืึทื ื™ืฆืขืจ ืคึผืจืึทืกืขืกืึทื–. ืฆื• ืกืึธืœื•ื•ืข ื“ืขื ืึทืจื•ื™ืกื’ืขื‘ืŸ, Bell Labs ื•ื•ืขื˜ ื“ืขืจื”ื™ื™ึทื ื˜ื™ืงืŸ ืฆื• ื“ืขืจ ื•ื•ื™ื™ึทื˜ืขืจ ื•ื•ืขืจืกื™ืข (ื•ื•ืขืจืกื™ืข 7 ื™ื•ื ื™ืงืก, 1979) ืคืืจื’ืขืœื™ื™ื’ื˜ ืึท ื ื™ื™ึทืข ืกื™ืกื˜ืขื ืจื•ืคืŸ - ptrace.

ptrace ืื™ื– ื“ืขื•ื•ืขืœืึธืคึผืขื“ ื‘ืคึฟืจื˜ ืคึฟืึทืจ ื™ื ื˜ืขืจืึทืงื˜ื™ื•ื• ื“ื™ื‘ื•ื’ืขืจื–, ืึธื‘ืขืจ ืื™ืŸ ื“ื™ ืกื•ืฃ ืคื•ืŸ ื“ื™ 80 ืก (ืื™ืŸ ื“ืขืจ ืชืงื•ืคื” ืคื•ืŸ ื’ืขืฉืขืคื˜ ืกื™ืกื˜ืขื V ืžืขืœื“ื•ื ื’ 4) ืื•ื™ืฃ ื“ืขื ื‘ืื–ืข, ืฉืžืึธืœ ืคืึธื•ืงื™ืกื˜ ื“ื™ื‘ื•ื’ืขืจื– - ืกื™ืกื˜ืขื ืจื•ืคืŸ ื˜ืจื™ื™ืกืขืจื– - ืืจื•ื™ืก ืื•ืŸ ื’ืขื•ื•ืืจืŸ ื•ื•ื™ื™ื“ืœื™ ื’ืขื ื™ืฆื˜.

ืขืจืฉื˜ืขืจ ื“ื™ ื–ืขืœื‘ืข ื•ื•ืขืจืกื™ืข ืคื•ืŸ โ€‹โ€‹ืกื˜ืจืึทืกืข ืื™ื– ืืจื•ื™ืก ื“ื•ืจืš Paul Cronenburg ืื•ื™ืฃ ื“ื™ comp.sources.sun ืžื™ื™ืœื™ื ื’ ืจืฉื™ืžื” ืื™ืŸ 1992 ื•ื•ื™ ืึทืŸ ืึธืœื˜ืขืจื ืึทื˜ื™ื•ื• ืฆื• ืึท ืคืืจืžืื›ื˜ ื ื•ืฆืŸ. trace ืคื•ืŸ ื–ื•ืŸ. ื‘ื™ื™ื“ืข ื“ื™ ืงืœืึธื•ืŸ ืื•ืŸ ื“ืขืจ ืึธืจื™ื’ื™ื ืขืœ ื–ืขื ืขืŸ ื‘ื“ืขื” ืคึฟืึทืจ SunOS, ืึธื‘ืขืจ ืื™ืŸ 1994 strace ืื™ื– ื’ืขื•ื•ืขืŸ ืคึผืึธืจื˜ื™ื“ ืฆื• ืกื™ืกื˜ืขื V, ืกืึธืœืึทืจื™ืก ืื•ืŸ ื“ื™ ื™ื ืงืจื™ืกื™ื ื’ืœื™ ืคืึธืœืงืก ืœื™ื ื•ืงืก.

ื”ื™ื™ึทื ื˜ ืกื˜ืจืึทืกืข ืฉื˜ื™ืฆื˜ ื‘ืœื•ื™ื– ืœื™ื ื•ืงืก ืื•ืŸ ืจื™ืœื™ื™ื– ืื•ื™ืฃ ื“ื™ ื–ืขืœื‘ืข ptrace, ืึธื•ื•ื•ืขืจื’ืจืึธื•ืŸ ืžื™ื˜ ืคื™ืœืข ื™ืงืกื˜ืขื ืฉืึทื ื–.

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

ืขืก ืื™ื– ืื•ื™ืš ื•ื•ื™ื›ื˜ื™ืง ืึทื– ื“ื™ ืคื˜ืจืึทืกืข ืกื™ืกื˜ืขื ืจื•ืคืŸ ืื•ืŸ ื˜ืจื™ื™ืกืขืจื– ื–ืขื ืขืŸ ืงื™ื™ื ืžืึธืœ ืึทืจื™ื™ึทื ื’ืขืจืขื›ื ื˜ ืื™ืŸ POSIX, ื˜ืจืึธืฅ ืึท ืœืึทื ื’ ื’ืขืฉื™ื›ื˜ืข ืื•ืŸ ื™ืžืคึผืœืึทืžืขื ื˜ื™ื™ืฉืึทืŸ ืื™ืŸ ืœื™ื ื•ืงืก, ืคืจืขืขื‘ืกื“, ืึธืคึผืขื ื‘ืกื“ ืื•ืŸ ื˜ืจืื“ื™ืฆื™ืื ืขืœืŸ ื™ื•ื ื™ืงืก.

ืกื˜ืจืึทืกืข ืžื™ื˜ืœ ืื™ืŸ ืึท ื ืึทื˜ืฉืขืœ: ืคึผื™ื’ืœืขื˜ ื˜ืจืึทืกืข

"ืื™ืจ ื–ืขื ื˜ ื ื™ืฉื˜ ื“ืขืจื•ื•ืึทืจื˜ ืฆื• ืคึฟืึทืจืฉื˜ื™ื™ืŸ ื“ืขื" (Denis Ritchie, ื‘ืึทืžืขืจืงื•ื ื’ ืื™ืŸ ื•ื•ืขืจืกื™ืข 6 ื™ื•ื ื™ืงืก ืžืงื•ืจ ืงืึธื“)

ื–ื™ื ื˜ ืคืจื™ ืงื™ื ื“ืฉืึทืคื˜, ืื™ืš ืงืขืŸ ื ื™ืฉื˜ ืฉื˜ื™ื™ืŸ ืฉื•ื•ืึทืจืฅ ื‘ืึธืงืกืขืก: ืื™ืš ื”ืื˜ ื ื™ืฉื˜ ืฉืคึผื™ืœืŸ ืžื™ื˜ ืื™ื“ื™ืฉ, ืึธื‘ืขืจ ื’ืขืคืจื•ื•ื•ื˜ ืฆื• ืคึฟืึทืจืฉื˜ื™ื™ืŸ ื–ื™ื™ืขืจ ืกื˜ืจื•ืงื˜ื•ืจ (ืึทื“ืึทืœืฅ ื’ืขื ื™ืฆื˜ ื“ื™ ื•ื•ืึธืจื˜ "ืฆืขื‘ืจืื›ืŸ," ืึธื‘ืขืจ ื˜ืึธืŸ ื ื™ื˜ ื’ืœื•ื™ื‘ืŸ ื“ื™ ื‘ื™ื™ื– ืœืฉื•ื ื•ืช). ื˜ืึธืžืขืจ ื“ืึธืก ืื™ื– ื•ื•ืึธืก ื“ื™ ื™ื ืคืึธืจืžืึทืœ ืงื•ืœื˜ื•ืจ ืคื•ืŸ ื“ืขืจ ืขืจืฉื˜ืขืจ ื™ื•ื ื™ืงืก ืื•ืŸ ื“ื™ ืžืึธื“ืขืจืŸ ืึธืคึฟืŸ-ืžืงื•ืจ ื‘ืึทื•ื•ืขื’ื•ื ื’ ืื™ื– ืึทื–ื•ื™ ื ืึธืขื ื˜ ืฆื• ืžื™ืจ.

ืคึฟืึทืจ ื“ื™ ืฆื•ื•ืขืงืŸ ืคื•ืŸ ื“ืขื ืึทืจื˜ื™ืงืœ, ืขืก ืื™ื– ืงืจื•ื ืฆื• ื“ื™ืกืึทืกืขืžื‘ืึทืœ ื“ื™ ืžืงื•ืจ ืงืึธื“ ืคื•ืŸ ืกื˜ืจืึทืกืข, ื•ื•ืึธืก ืื™ื– ื’ืขื•ื•ืืงืกืŸ ืื™ื‘ืขืจ ื“ืขืงืึทื“ืขืก. ืื‘ืขืจ ืขืก ื–ืึธืœ ื–ื™ื™ืŸ ืงื™ื™ืŸ ืกื™ืงืจื™ืฅ ืคึฟืึทืจ ืœื™ื™ืขื ืขืจ. ื“ืขืจื™ื‘ืขืจ, ืฆื• ื•ื•ื™ื™ึทื–ืŸ ื“ืขื ืคึผืจื™ื ืฆื™ืคึผ ืคื•ืŸ ืึธืคึผืขืจืึทืฆื™ืข ืคื•ืŸ โ€‹โ€‹ืึทื–ืึท ืกื˜ืจืึทืกืข ืžื’ื™ืœื”, ืื™ืš ื•ื•ืขืœ ืฆื•ืฉื˜ืขืœืŸ ื“ื™ ืงืึธื“ ืคึฟืึทืจ ืึท ืžื™ื ื™ืึทื˜ื•ืจืข ื˜ืจื™ื™ืกืขืจ - ืคึผื™ื’ืœืขื˜ ื˜ืจื™ื™ืก (ืคึผื˜ืจ). ืขืก ื˜ื•ื˜ ื ื™ืฉื˜ ื•ื•ื™ืกืŸ ื•ื•ื™ ืฆื• ื˜ืึธืŸ ืขืคึผืขืก ืกืคึผืขืฆื™ืขืœ, ืึธื‘ืขืจ ื“ื™ ื”ื•ื™ืคึผื˜ ื–ืึทืš ืื™ื– ื“ื™ ืกื™ืกื˜ืขื ืงืึทืœืœืก ืคื•ืŸ ื“ื™ ืคึผืจืึธื’ืจืึทื - ืขืก ืึทื•ื˜ืคึผื•ืฅ:

$ 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

ืคึผื™ื’ืœืขื˜ ื˜ืจืึทืกืข ืื ืขืจืงืขื ื˜ ื•ื•ืขื’ืŸ ื”ื•ื ื“ืขืจื˜ืขืจ ืคื•ืŸ ืœื™ื ื•ืงืก ืกื™ืกื˜ืขื ืจื•ืคื˜ (ื–ืขืŸ. ื˜ื™ืฉ) ืื•ืŸ ืึทืจื‘ืขื˜ ื‘ืœื•ื™ื– ืื•ื™ืฃ x86-64 ืึทืจืงืึทื˜ืขืงื˜ืฉืขืจ. ื“ืึธืก ืื™ื– ื’ืขื ื•ื’ ืคึฟืึทืจ ื‘ื™ืœื“ื•ื ื’ืงืจื™ื™ื– ืฆื•ื•ืขืงืŸ.

ื–ืืœ ืก ืงื•ืง ืื™ืŸ ื“ื™ ืึทืจื‘ืขื˜ ืคื•ืŸ ืื•ื ื“ื–ืขืจ ืงืœืึธื•ืŸ. ืื™ืŸ ื“ืขื ืคืึทืœ ืคื•ืŸ ืœื™ื ื•ืงืก, ื“ื™ื‘ืึทื’ืขืจื– ืื•ืŸ ื˜ืจื™ื™ืกืขืจื– ื ื•ืฆืŸ, ื•ื•ื™ ื“ืขืจืžืื ื˜ ืื•ื™ื‘ืŸ, ื“ื™ ืคึผื˜ืจืึทืกืข ืกื™ืกื˜ืขื ืจื•ืคืŸ. ืขืก ืึทืจื‘ืขื˜ ื“ื•ืจืš ืคืึธืจืŸ ืื™ืŸ ื“ืขืจ ืขืจืฉื˜ืขืจ ืึทืจื’ื•ืžืขื ื˜ ื“ื™ ื‘ืึทืคึฟืขืœ ื™ื“ืขื ื˜ื™ืคื™ืขืจืก, ืคื•ืŸ ื•ื•ืึธืก ืžื™ืจ ื ืึธืจ ื“ืึทืจืคึฟืŸ 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");

ืื™ืŸ ื“ืขื ืคื•ื ื˜, ื“ื™ ืคึผืจืขืคึผืขืจื™ื™ืฉืึทื ื– ื–ืขื ืขืŸ ื’ืึทื ืฅ ืื•ืŸ ืื™ืจ ืงืขื ืขืŸ ื’ื™ื™ื  ื•ื•ื™ื™ึทื˜ืขืจ ื’ืœื™ื™ึทืš ืฆื• ื˜ืจืึทืงื™ื ื’ ืกื™ืกื˜ืขื ืจื•ืคื˜ ืื™ืŸ ืึท ืกืึธืฃ ืฉืœื™ื™ืฃ.

Call 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. ื“ืึธืก ืื™ื– ื“ื™ ืฉื•ื•ืขืจื™ืงื™ื™ื˜ ืคื•ืŸ ืืจื‘ืขื˜ืŸ ืžื™ื˜ ืกื™ืกื˜ืขื ืงืึทืœืœืก: ื“ื™ ืฆื•ื‘ื™ื ื“ ืžื™ื˜ ื•ื•ืึธืก ื“ื™ ืคึผืจืึธื’ืจืึทืžื™ืกื˜ ืึทืจื‘ืขื˜ ืื™ื– ื ื™ืฉื˜ ื’ืœื™ื™ึทืš ืฉื™ื™ืš ืฆื• ืกื™ืกื˜ืขื ืงืึทืœืœืก. ื“ืขืจืฆื•, ืขืก ืขื ื“ืขืจื•ื ื’ืขืŸ ืงืขืกื™ื™ื“ืขืจ ื“ื™ืคึผืขื ื“ื™ื ื’ ืื•ื™ืฃ ื“ื™ ื™ืžืคึผืœืึทืžืขื ื˜ื™ื™ืฉืึทืŸ ืื•ืŸ ืคึผืœืึทื˜ืคืึธืจืžืข.

ื‘ืึทืกื™ืงืก: ืคืึทืจื‘ื™ื ื“ืŸ ื“ืขื ืคึผืจืึธืฆืขืก ืื•ื™ืฃ ื“ื™ ืคืœื™ืขืŸ

ื˜ื›ื™ืœืขืก, ื“ื™ ืคึผื˜ืจืึทืกืข ืกื™ืกื˜ืขื ืจื•ืคืŸ ืื•ื™ืฃ ื•ื•ืึธืก ืขืก ืื™ื– ื’ืขื•ื•ืขืŸ ื’ืขื‘ื•ื™ื˜ strace, ืงืขืŸ ื ืึธืจ ื–ื™ื™ืŸ ื’ืขื•ื•ื™ื™ื ื˜ ื•ื•ืขืŸ ืคืœื™ืกื ื“ื™ืง ื“ื™ ืคึผืจืึธื’ืจืึทื ืื™ืŸ ืึท ืกืคึผืขืฆื™ืขืœ ืžืึธื“ืข. ื“ื™ ื‘ืึทื’ืจืขื ืขืฆื•ื ื’ ืงืขืŸ ื”ืึธื‘ืŸ ื’ืขื‘ืœืื–ืŸ ื’ืœื™ื™ึทืš ืื™ืŸ ื“ื™ ื˜ืขื’ ืคื•ืŸ ื•ื•ืขืจืกื™ืข 6 ื™ื•ื ื™ืงืก. ื ืึธื•ื•ืึทื“ื™ื™ึทืก, ื“ืึธืก ืื™ื– ื ื™ื˜ ืžืขืจ ื’ืขื ื•ื’: ืžืืœ ืื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ืคืึธืจืฉืŸ ื“ื™ ืคืจืื‘ืœืขืžืขืŸ ืคื•ืŸ ืึท ืืจื‘ืขื˜ืŸ ืคึผืจืึธื’ืจืึทื. ื ื˜ื™ืคึผื™ืฉ ื‘ื™ื™ึทืฉืคึผื™ืœ ืื™ื– ืึท ืคึผืจืึธืฆืขืก ืืคื’ืขืฉื˜ืขืœื˜ ืื•ื™ืฃ ืึท ืฉืขืคึผืŸ ืึธื“ืขืจ ืกืœื™ืคึผื™ื ื’. ื“ืขืจื™ื‘ืขืจ ืžืึธื“ืขืจืŸ 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. ืฆื•ื•ื™ื™ ื˜ื™ื ื’ื– ื’ืขื•ื•ืืจืŸ ืงืœืึธืจ: ื“ื™ ืคึผื•ื™ื–ืข ืกื™ืกื˜ืขื ืจื•ืคืŸ ื™ื’ื ืึธืจื– ืกื™ื’ื ืึทืœื– ืึธืŸ ื”ืึทื ื“ืœืขืจืก ืื•ืŸ, ืžืขืจ ื™ื ื˜ืขืจืขืกื˜ื™ื ื’ืœื™, ืกื˜ืจืึทืกืข ืžืึธื ื™ื˜ืึธืจืก ื ื™ื˜ ื‘ืœื•ื™ื– ืกื™ืกื˜ืขื ืจื•ืคื˜, ืึธื‘ืขืจ ืื•ื™ืš ื™ื ืงืึทืžื™ื ื’ ืกื™ื’ื ืึทืœื–.

ื‘ื™ื™ึทืฉืคึผื™ืœ: ื˜ืจืึทืงื™ื ื’ ืงื™ื ื“ ืคึผืจืึทืกืขืกืึทื–

ืืจื‘ืขื˜ืŸ ืžื™ื˜ ืคึผืจืึทืกืขืกืึทื– ื“ื•ืจืš ืึท ืจื•ืคืŸ 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 -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 +++

ื‘ื™ื™ึทืฉืคึผื™ืœ: Multithreaded ืžื’ื™ืœื”

ื ื•ืฆืŸ 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
$

Flag -f, ื•ื•ื™ ืื™ืŸ ื“ื™ ืคืึทืœ ืคื•ืŸ ืจืขื’ื•ืœืขืจ ืคึผืจืึทืกืขืกืึทื–, ื•ื•ืขื˜ ืœื™ื™ื’ืŸ ื“ื™ ืคึผื™ื“ ืคื•ืŸ ื“ืขื ืคึผืจืึธืฆืขืก ืฆื• ื“ื™ ืึธื ื”ื™ื™ื‘ ืคื•ืŸ ื™ืขื“ืขืจ ืฉื•ืจื”.

ื’ืขื•ื•ื™ื™ื ื˜ืœืขืš, ืžื™ืจ ื–ืขื ืขืŸ ื ื™ืฉื˜ ื’ืขืจืขื“ื˜ ื•ื•ืขื’ืŸ ืึท ืคืึธื“ืขื ื™ื“ืขื ื˜ื™ืคื™ืขืจ ืื™ืŸ ื“ืขื ื–ื™ื ืขืŸ ืคื•ืŸ ื“ื™ ื™ืžืคึผืœืึทืžืขื ื˜ื™ื™ืฉืึทืŸ ืคื•ืŸ ื“ื™ POSIX ืคึฟืขื“ืขื ื ืึธืจืžืึทืœ, ืึธื‘ืขืจ ื•ื•ืขื’ืŸ ื“ื™ ื ื•ืžืขืจ ื’ืขื ื™ืฆื˜ ื“ื•ืจืš ื“ื™ ืึทืจื‘ืขื˜ ืกืงืขื“ื–ืฉื•ืœืขืจ ืื™ืŸ ืœื™ื ื•ืงืก. ืคึฟื•ืŸ ื“ื™ ืœืขืฆื˜ืข ืคื•ื ื˜ ืคื•ืŸ ืžื™ื™ื ื•ื ื’, ืขืก ื–ืขื ืขืŸ ืงื™ื™ืŸ ืคึผืจืึทืกืขืกืึทื– ืึธื“ืขืจ ืคึฟืขื“ืขื - ืขืก ื–ืขื ืขืŸ ื˜ืึทืกืงืก ื•ื•ืึธืก ื“ืึทืจืคึฟืŸ ืฆื• ื–ื™ื™ืŸ ืคื•ื ืื ื“ืขืจื’ืขื˜ื™ื™ืœื˜ ืฆื•ื•ื™ืฉืŸ ื“ื™ ื‘ื ื™ืžืฆื ืงืึธืจืขืก ืคื•ืŸ ื“ื™ ืžืึทืฉื™ืŸ.

ื•ื•ืขืŸ ืืจื‘ืขื˜ืŸ ืื™ืŸ ืงื™ื™ืคืœ ืคึฟืขื“ืขื, ืกื™ืกื˜ืขื ืจื•ืคื˜ ื•ื•ืขืจืŸ ืฆื• ืคื™ืœืข:

$ 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 - ืึท ืคึผืฉื•ื˜ ืื•ืŸ ืคืึทืจืœืึธื–ืœืขืš ื’ืขืฆื™ื™ึทื’. ืึธื‘ืขืจ ืื™ืŸ ืึทื“ื™ืฉืึทืŸ ืฆื• ืกื™ืกื˜ืขื ืจื•ืคื˜, ืื ื“ืขืจืข ืึทืกืคึผืขืงืฅ ืคื•ืŸ ื“ื™ ืึธืคึผืขืจืึทืฆื™ืข ืคื•ืŸ โ€‹โ€‹ืžื’ื™ืœื” ืื•ืŸ ื“ื™ ืึธืคึผืขืจื™ื™ื˜ื™ื ื’ ืกื™ืกื˜ืขื ืงืขื ืขืŸ ื–ื™ื™ืŸ ื“ื™ื‘ืึทื’ื“. ืคึฟืึทืจ ื‘ื™ื™ึทืฉืคึผื™ืœ, ืขืก ืงืขื ืขืŸ ืฉืคึผื•ืจ ืงืึทืœืœืก ืฆื• ื“ื™ื ืึทืžื™ืงืึทืœืœื™ ืœื™ื ื’ืงื˜ ืœื™ื™ื‘ืจืขืจื™ื–. ืฉืคึผื•ืจ, ื–ื™ื™ ืงืขื ืขืŸ ืงื•ืงืŸ ืื™ืŸ ื“ื™ ืึธืคึผืขืจืึทืฆื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืึธืคึผืขืจื™ื™ื˜ื™ื ื’ ืกื™ืกื˜ืขื ืกื™ืกื˜ืขื ื˜ืึทืคึผ ะธ ืคื˜ืจืึทืกืข, ืื•ืŸ ืึทืœืึทื•ื– ืื™ืจ ืฆื• ื“ื™ืคึผืœื™ ืคืึธืจืฉืŸ ืคึผืจืึธื’ืจืึทื ืคืึธืจืฉื˜ืขืœื•ื ื’ ื’ืื ืฅ. ื“ืืš, ืขืก ืื™ื– strace - ื“ืขืจ ืขืจืฉื˜ืขืจ ืฉื•ืจื” ืคื•ืŸ ืคืึทืจื˜ื™ื™ื“ื™ืงื•ื ื’ ืื™ืŸ ืคืึทืœ ืคื•ืŸ ืคึผืจืึธื‘ืœืขืžืก ืžื™ื˜ ืžื™ื™ืŸ ืื™ื™ื’ืŸ ืื•ืŸ ืื ื“ืขืจืข ืžืขื ื˜ืฉืŸ ืก ืžื’ื™ืœื”, ืื•ืŸ ืื™ืš ื ื•ืฆืŸ ืขืก ื‘ื™ื™ึท ืžื™ื ื“ืกื˜ืขืจ ืึท ืคึผืึธืจ ืคื•ืŸ ืžืืœ ืึท ื•ื•ืึธืš.

ืื™ืŸ ืงื•ืจืฅ, ืื•ื™ื‘ ืื™ืจ ืœื™ื‘ืข ื™ื•ื ื™ืงืก, ืœื™ื™ืขื ืขืŸ man 1 strace ืื•ืŸ ืคื™ืœืŸ ืคืจื™ื™ ืฆื• ืงื•ืง ืื™ืŸ ื“ื™ื™ืŸ ืžื’ื™ืœื”!

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

ืœื™ื™ื’ืŸ ืึท ื‘ืึทืžืขืจืงื•ื ื’