Π Unix-ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½ΠΈ ΡΠΈΡΡΠ΅ΠΌΠΈ ΠΊΠΎΠΌΡΠ½ΠΈΠΊΠ°ΡΠΈΡΡΠ° Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°ΡΠ° Ρ Π²ΡΠ½ΡΠ½ΠΈΡ ΡΠ²ΡΡ ΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½Π°ΡΠ° ΡΠΈΡΡΠ΅ΠΌΠ° ΡΠ΅ ΠΎΡΡΡΠ΅ΡΡΠ²ΡΠ²Π° ΡΡΠ΅Π· ΠΌΠ°Π»ΡΠΊ Π½Π°Π±ΠΎΡ ΠΎΡ ΡΡΠ½ΠΊΡΠΈΠΈ - ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½ΠΈΡ. Π’ΠΎΠ²Π° ΠΎΠ·Π½Π°ΡΠ°Π²Π°, ΡΠ΅ Π·Π° ΡΠ΅Π»ΠΈΡΠ΅ Π½Π° ΠΎΡΡΡΡΠ°Π½ΡΠ²Π°Π½Π΅ΡΠΎ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΏΠΎΠ»Π΅Π·Π½ΠΎ Π΄Π° ΡΠΏΠΈΠΎΠ½ΠΈΡΠ°ΡΠ΅ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΠ΅ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½ΠΈΡ, ΠΈΠ·ΠΏΡΠ»Π½ΡΠ²Π°Π½ΠΈ ΠΎΡ ΠΏΡΠΎΡΠ΅ΡΠΈ.
ΠΠΎΠΌΠΎΡΠ½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ° Π²ΠΈ ΠΏΠΎΠΌΠ°Π³Π° Π΄Π° Π½Π°Π±Π»ΡΠ΄Π°Π²Π°ΡΠ΅ βΠΈΠ½ΡΠΈΠΌΠ½ΠΈΡ ΠΆΠΈΠ²ΠΎΡβ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ΅ Π² Linux strace
, ΠΊΠΎΠ΅ΡΠΎ Π΅ ΠΏΡΠ΅Π΄ΠΌΠ΅Ρ Π½Π° ΡΠ°Π·ΠΈ ΡΡΠ°ΡΠΈΡ. ΠΡΠΈΠΌΠ΅ΡΠΈ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° ΡΠΏΠΈΠΎΠ½ΡΠΊΠΎ ΠΎΠ±ΠΎΡΡΠ΄Π²Π°Π½Π΅ ΡΠ° ΠΏΡΠΈΠ΄ΡΡΠΆΠ΅Π½ΠΈ Ρ ΠΊΡΠ°ΡΠΊΠ° ΠΈΡΡΠΎΡΠΈΡ strace
ΠΈ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π½Π° Π΄ΠΈΠ·Π°ΠΉΠ½Π° Π½Π° ΡΠ°ΠΊΠΈΠ²Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈ.
Π‘ΡΠ΄ΡΡΠΆΠ°Π½ΠΈΠ΅
ΠΡΠΎΠΈΠ·Ρ ΠΎΠ΄ Π½Π° Π²ΠΈΠ΄ΠΎΠ²Π΅ΡΠ΅ Π£ΡΡΡΠΎΠΉΡΡΠ²ΠΎ Strace Π½Π°ΠΊΡΠ°ΡΠΊΠΎ: Piglet Trace ΠΡΠ½ΠΎΠ²ΠΈ: ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°, ΠΈΠ·ΠΏΡΠ»Π½ΡΠ²Π°ΡΠ° strace ΠΡΠ½ΠΎΠ²ΠΈ: ΠΏΡΠΈΡΡΠ΅Π΄ΠΈΠ½ΡΠ²Π°Π½Π΅ ΠΊΡΠΌ ΠΏΡΠΎΡΠ΅ΡΠ° Π² Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΠΡΠΈΠΌΠ΅Ρ: ΠΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ Π½Π° Π΄ΡΡΠ΅ΡΠ½ΠΈ ΠΏΡΠΎΡΠ΅ΡΠΈ ΠΡΠΈΠΌΠ΅Ρ: ΡΠ°ΠΉΠ»ΠΎΠ²ΠΈ ΠΏΡΡΠΈΡΠ° Π²ΠΌΠ΅ΡΡΠΎ ΠΌΠ°Π½ΠΈΠΏΡΠ»Π°ΡΠΎΡΠΈ ΠΡΠΈΠΌΠ΅Ρ: ΠΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ Π½Π° Π΄ΠΎΡΡΡΠΏ Π΄ΠΎ ΡΠ°ΠΉΠ»ΠΎΠ²Π΅ ΠΡΠΈΠΌΠ΅Ρ: ΠΠ½ΠΎΠ³ΠΎΠ½ΠΈΡΠΊΠΎΠ²ΠΈ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈ ΠΠ°ΠΉΡΡΠΎΡΡΠΊΠΈ ΠΊΠ»Π°Ρ: ΠΏΡΠΎΡΠ΅Ρ ΡΡΠ΅ΠΊ ΠΏΠΎ Π²ΡΠ΅ΠΌΠ΅ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ½ΠΎ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½Π΅ ΠΠ°ΠΉΡΡΠΎΡΡΠΊΠΈ ΠΊΠ»Π°Ρ: ΠΈΠ½ΠΆΠ΅ΠΊΡΠΈΡΠ°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ ΠΏΠΎΡΠ»Π΅ΡΠ»ΠΎΠ²
ΠΡΠΎΠΈΠ·Ρ ΠΎΠ΄ Π½Π° Π²ΠΈΠ΄ΠΎΠ²Π΅ΡΠ΅
ΠΡΠ½ΠΎΠ²Π½ΠΈΡΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ΅ ΠΈ ΡΠ΄ΡΠΎΡΠΎ Π½Π° ΠΠ‘ Π² Unix Π΅ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΠ΅ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½ΠΈΡ. ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½ΠΈΡ, ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½ΠΈΡ), Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ΡΠΎ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ΅ Ρ Π²ΡΠ½ΡΠ½ΠΈΡ ΡΠ²ΡΡ ΡΠ΅ ΠΎΡΡΡΠ΅ΡΡΠ²ΡΠ²Π° ΠΈΠ·ΠΊΠ»ΡΡΠΈΡΠ΅Π»Π½ΠΎ ΡΡΠ΅Π· ΡΡΡ .
ΠΠΎ Π² ΠΏΡΡΠ²Π°ΡΠ° ΠΏΡΠ±Π»ΠΈΡΠ½Π° Π²Π΅ΡΡΠΈΡ Π½Π° Unix (ptrace
.
ptrace Π΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠ΅Π½ ΠΎΡΠ½ΠΎΠ²Π½ΠΎ Π·Π° ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΠ²Π½ΠΈ Π΄Π΅Π±ΡΠ³Π΅ΡΠΈ, Π½ΠΎ Π² ΠΊΡΠ°Ρ Π½Π° 80-ΡΠ΅ Π³ΠΎΠ΄ΠΈΠ½ΠΈ (Π² Π΅ΡΠ°ΡΠ° Π½Π° ΠΊΠΎΠΌΠ΅ΡΡΠΈΠ°Π»Π½ΠΈΡΠ΅
trace
ΠΎΡ Π‘Π»ΡΠ½ΡΠ΅. Π ΠΊΠ»ΠΎΠ½ΠΈΠ½Π³ΡΡ, ΠΈ ΠΎΡΠΈΠ³ΠΈΠ½Π°Π»ΡΡ Π±ΡΡ
Π° ΠΏΡΠ΅Π΄Π½Π°Π·Π½Π°ΡΠ΅Π½ΠΈ Π·Π° SunOS, Π½ΠΎ Π΄ΠΎ 1994Π³ strace
Π±Π΅ΡΠ΅ ΠΏΡΠ΅Π½Π΅ΡΠ΅Π½ ΠΊΡΠΌ System V, Solaris ΠΈ Π²ΡΠ΅ ΠΏΠΎ-ΠΏΠΎΠΏΡΠ»ΡΡΠ½ΠΈΡ Linux.
ΠΠ½Π΅Ρ strace ΠΏΠΎΠ΄Π΄ΡΡΠΆΠ° ΡΠ°ΠΌΠΎ Linux ΠΈ ΡΠ°Π·ΡΠΈΡΠ° Π½Π° ΡΡΡΠΎΡΠΎ ptrace
, ΠΎΠ±ΡΠ°ΡΠ»ΠΎ Ρ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ ΡΠ°Π·ΡΠΈΡΠ΅Π½ΠΈΡ.
ΠΠΎΠ΄Π΅ΡΠ΅Π½ (ΠΈ ΠΌΠ½ΠΎΠ³ΠΎ Π°ΠΊΡΠΈΠ²Π΅Π½) ΠΏΠΎΠ΄Π΄ΡΡΠΆΠ°Ρ strace
-
Π‘ΡΡΠΎ ΡΠ°ΠΊΠ° Π΅ Π²Π°ΠΆΠ½ΠΎ, ΡΠ΅ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΎΡΠΎ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅ Π½Π° ptrace ΠΈ ΡΡΠ°ΡΠΈΡΠ°ΡΠΈΡΠ΅ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈ Π½ΠΈΠΊΠΎΠ³Π° Π½Π΅ ΡΠ° Π±ΠΈΠ»ΠΈ Π²ΠΊΠ»ΡΡΠ΅Π½ΠΈ Π² POSIX, Π²ΡΠΏΡΠ΅ΠΊΠΈ Π΄ΡΠ»Π³Π°ΡΠ° ΠΈΡΡΠΎΡΠΈΡ ΠΈ Π²Π½Π΅Π΄ΡΡΠ²Π°Π½Π΅ Π² Linux, FreeBSD, OpenBSD ΠΈ ΡΡΠ°Π΄ΠΈΡΠΈΠΎΠ½Π½ΠΈΡ Unix.
Π£ΡΡΡΠΎΠΉΡΡΠ²ΠΎ Strace Π½Π°ΠΊΡΠ°ΡΠΊΠΎ: Piglet Trace
βΠΠ΅ ΡΠ΅ ΠΎΡΠ°ΠΊΠ²Π° Π΄Π° ΡΠ°Π·Π±Π΅ΡΠ΅ΡΠ΅ ΡΠΎΠ²Π°β (ΠΠ΅Π½ΠΈΡ Π ΠΈΡΠΈ, ΠΊΠΎΠΌΠ΅Π½ΡΠ°Ρ Π²ΡΠ² Π²Π΅ΡΡΠΈΡ 6 Unix ΠΈΠ·Ρ ΠΎΠ΄Π΅Π½ ΠΊΠΎΠ΄)
ΠΡ ΡΠ°Π½Π½ΠΎ Π΄Π΅ΡΡΡΠ²ΠΎ Π½Π΅ ΠΌΠΎΠ³Π° Π΄Π° ΠΏΠΎΠ½Π°ΡΡΠΌ ΡΠ΅ΡΠ½ΠΈ ΠΊΡΡΠΈΠΈ: Π½Π΅ ΡΠΈ ΠΈΠ³ΡΠ°Π΅Ρ Ρ ΠΈΠ³ΡΠ°ΡΠΊΠΈ, Π½ΠΎ ΡΠ΅ ΠΎΠΏΠΈΡΠ²Π°Ρ Π΄Π° ΡΠ°Π·Π±Π΅ΡΠ° ΡΡΡΡΠΊΡΡΡΠ°ΡΠ° ΠΈΠΌ (Π²ΡΠ·ΡΠ°ΡΡΠ½ΠΈΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ Π° Π΄ΡΠΌΠ°ΡΠ° βΡΡΡΠΏΠ΅Π½ΠΈβ, Π½ΠΎ Π½Π΅ Π²ΡΡΠ²Π°ΠΉΡΠ΅ Π½Π° Π·Π»ΠΈΡΠ΅ Π΅Π·ΠΈΡΠΈ). ΠΠΎΠΆΠ΅ Π±ΠΈ Π·Π°ΡΠΎΠ²Π° Π½Π΅ΡΠΎΡΠΌΠ°Π»Π½Π°ΡΠ° ΠΊΡΠ»ΡΡΡΠ° Π½Π° ΠΏΡΡΠ²ΠΈΡ Unix ΠΈ ΠΌΠΎΠ΄Π΅ΡΠ½ΠΎΡΠΎ Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ Ρ ΠΎΡΠ²ΠΎΡΠ΅Π½ ΠΊΠΎΠ΄ Π΅ ΡΠΎΠ»ΠΊΠΎΠ²Π° Π±Π»ΠΈΠ·ΠΊΠ° Π΄ΠΎ ΠΌΠ΅Π½.
ΠΠ° ΡΠ΅Π»ΠΈΡΠ΅ Π½Π° ΡΠ°Π·ΠΈ ΡΡΠ°ΡΠΈΡ Π΅ Π½Π΅ΡΠ°Π·ΡΠΌΠ½ΠΎ Π΄Π° ΡΠ΅ ΡΠ°Π·Π³Π»ΠΎΠ±ΡΠ²Π° ΠΈΠ·Ρ
ΠΎΠ΄Π½ΠΈΡΡ ΠΊΠΎΠ΄ Π½Π° strace, ΠΊΠΎΠΉΡΠΎ ΡΠ΅ ΡΠ°Π·ΡΠ°ΡΡΠ²Π° Ρ Π΄Π΅ΡΠ΅ΡΠΈΠ»Π΅ΡΠΈΡ. ΠΠΎ Π½Π΅ ΡΡΡΠ±Π²Π° Π΄Π° ΠΎΡΡΠ°Π²Π°Ρ ΡΠ°ΠΉΠ½ΠΈ Π·Π° ΡΠΈΡΠ°ΡΠ΅Π»ΠΈΡΠ΅. ΠΡΠΎ Π·Π°ΡΠΎ, Π·Π° Π΄Π° ΠΏΠΎΠΊΠ°ΠΆΠ° ΠΏΡΠΈΠ½ΡΠΈΠΏΠ° Π½Π° ΡΠ°Π±ΠΎΡΠ° Π½Π° ΡΠ°ΠΊΠΈΠ²Π° strace ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈ, ΡΠ΅ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Ρ ΠΊΠΎΠ΄Π° Π·Π° ΠΌΠΈΠ½ΠΈΠ°ΡΡΡΠ΅Π½ ΡΡΠ°ΡΠΈΡΠ°Ρ -
$ 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 ΡΠ°Π·ΠΏΠΎΠ·Π½Π°Π²Π° ΠΎΠΊΠΎΠ»ΠΎ ΡΡΠΎΡΠΈΡΠΈ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½ΠΈΡ Π½Π° Linux (Π²ΠΈΠΆΡΠ΅.
ΠΠ΅ΠΊΠ° Π΄Π° ΡΠ°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΡΠ°Π±ΠΎΡΠ°ΡΠ° Π½Π° Π½Π°ΡΠΈΡ ΠΊΠ»ΠΎΠ½ΠΈΠ½Π³. Π ΡΠ»ΡΡΠ°Ρ Π½Π° Linux, ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ΅ Π·Π° ΠΎΡΡΡΡΠ°Π½ΡΠ²Π°Π½Π΅ Π½Π° Π³ΡΠ΅ΡΠΊΠΈ ΠΈ ΠΏΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ, ΠΊΠ°ΠΊΡΠΎ Π±Π΅ΡΠ΅ ΡΠΏΠΎΠΌΠ΅Π½Π°ΡΠΎ ΠΏΠΎ-Π³ΠΎΡΠ΅, ΡΠΈΡΡΠ΅ΠΌΠ½ΠΎΡΠΎ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅ ptrace. Π Π°Π±ΠΎΡΠΈ, ΠΊΠ°ΡΠΎ Π² ΠΏΡΡΠ²ΠΈΡ Π°ΡΠ³ΡΠΌΠ΅Π½Ρ ΠΏΡΠ΅Π΄Π°Π²Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΠΈΡΠ΅ Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ°, ΠΎΡ ΠΊΠΎΠΈΡΠΎ ΡΠ΅ Π½ΡΠΆΠ΄Π°Π΅ΠΌ ΡΠ°ΠΌΠΎ PTRACE_TRACEME
, PTRACE_SYSCALL
ΠΈ PTRACE_GETREGS
.
ΠΡΠΎΡΠ»Π΅Π΄ΡΠ²Π°Π½Π΅ΡΠΎ Π·Π°ΠΏΠΎΡΠ²Π° Π² ΠΎΠ±ΠΈΡΠ°ΠΉΠ½ΠΈΡ Unix ΡΡΠΈΠ»: 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
parent ΡΠ΅ Π·Π°Π²ΡΡΡΠΈ ΠΈΠ»ΠΈ ΠΏΡΠ΅Π΄ΠΈ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΎΡΠΎ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½Π΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΎ, ΠΈΠ»ΠΈ Π²Π΅Π΄Π½Π°Π³Π° ΡΠ»Π΅Π΄ ΠΊΠ°ΡΠΎ Π·Π°Π²ΡΡΡΠΈ. ΠΠ΅ΠΆΠ΄Ρ Π΄Π²Π΅ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½ΠΈΡ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΈΠ·Π²ΡΡΡΠ²Π°ΡΠ΅ Π²ΡΡΠΊΠ°ΠΊΠ²ΠΈ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ: Π΄Π° Π·Π°ΠΌΠ΅Π½ΠΈΡΠ΅ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½Π΅ΡΠΎ Ρ Π°Π»ΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π½ΠΎ, Π΄Π° ΠΏΡΠΎΠΌΠ΅Π½ΠΈΡΠ΅ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΈΡΠ΅ ΠΈΠ»ΠΈ Π²ΡΡΠ½Π°ΡΠ°ΡΠ° ΡΡΠΎΠΉΠ½ΠΎΡΡ.
ΠΡΠΎΡΡΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΠΈΠ·Π²ΠΈΠΊΠ°ΠΌΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΡΠ° Π΄Π²Π° ΠΏΡΡΠΈ 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, ®isters) == -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, ®isters) == -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);
}
Π’ΠΎΠ²Π° Π΅ ΡΠ΅Π»ΠΈΡΡ ΡΡΠ°ΠΉΡΠ΅Ρ. Π‘Π΅Π³Π° Π·Π½Π°Π΅ΡΠ΅ ΠΎΡΠΊΡΠ΄Π΅ Π΄Π° Π·Π°ΠΏΠΎΡΠ½Π΅ΡΠ΅ ΡΠ»Π΅Π΄Π²Π°ΡΠΎΡΠΎ ΠΏΡΠ΅Π½Π°ΡΡΠ½Π΅
ΠΡΠ½ΠΎΠ²ΠΈ: ΡΡΠ°ΡΡΠΈΡΠ°Π½Π΅ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°, ΠΈΠ·ΠΏΡΠ»Π½ΡΠ²Π°ΡΠ° strace
ΠΠ°ΡΠΎ ΠΏΡΡΠ²ΠΈ ΡΠ»ΡΡΠ°ΠΉ Π½Π° ΡΠΏΠΎΡΡΠ΅Π±Π° 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 ΠΊΠΎΠ½ΡΡΠΎΠ»:
$ 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
ΠΈ ΠΈΠ·ΠΎΠ±ΠΈΠ»ΠΈΠ΅ ΠΎΡ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½ΠΈΡ, ΠΊΠΎΠΈΡΠΎ Π½Π΅ Π½ΠΈ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΡΠ²Π°Ρ.
ΠΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΡΠ°Π·Π΄Π΅Π»ΠΈΡΠ΅ ΡΡΠ°Π½Π΄Π°ΡΡΠ½ΠΈΡ ΠΈΠ·Ρ ΠΎΠ΄Π΅Π½ ΠΏΠΎΡΠΎΠΊ Π½Π° ΠΏΡΠΎΠ³ΡΠ°ΠΌΠ°ΡΠ° ΠΈ ΠΈΠ·Ρ ΠΎΠ΄Π° Π·Π° Π³ΡΠ΅ΡΠΊΠ° Π½Π° 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, Π²ΡΡΡ
Ρ ΠΊΠΎΠ΅ΡΠΎ Π΅ ΠΈΠ·Π³ΡΠ°Π΄Π΅Π½ΠΎ 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
- ΠΎΡΠ½ΠΎΠ²Π°ΡΠ° Π½Π° Π²ΡΠΈΡΠΊΠΈ Unix-ΠΈ. ΠΠ΅ΠΊΠ° Π΄Π° Π²ΠΈΠ΄ΠΈΠΌ ΠΊΠ°ΠΊ strace ΡΠ°Π±ΠΎΡΠΈ Ρ Π΄ΡΡΠ²ΠΎ Π½Π° ΠΏΡΠΎΡΠ΅ΡΠ°, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΠΊΠΈ ΠΏΡΠΈΠΌΠ΅ΡΠ° Π½Π° ΠΏΡΠΎΡΡΠΎ βΡΠ°Π·ΠΌΠ½ΠΎΠΆΠ°Π²Π°Π½Π΅β
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, Π° Π·Π° Π½ΠΎΠΌΠ΅ΡΠ°, ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ ΠΎΡ ΠΏΠ»Π°Π½ΠΈΡΠΎΠ²ΡΠΈΠΊΠ° Π½Π° Π·Π°Π΄Π°ΡΠΈ Π² Linux. ΠΡ Π³Π»Π΅Π΄Π½Π° ΡΠΎΡΠΊΠ° Π½Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡ Π½ΡΠΌΠ° ΠΏΡΠΎΡΠ΅ΡΠΈ ΠΈΠ»ΠΈ Π½ΠΈΡΠΊΠΈ - ΠΈΠΌΠ° Π·Π°Π΄Π°ΡΠΈ, ΠΊΠΎΠΈΡΠΎ ΡΡΡΠ±Π²Π° Π΄Π° Π±ΡΠ΄Π°Ρ ΡΠ°Π·ΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈ ΠΌΠ΅ΠΆΠ΄Ρ Π½Π°Π»ΠΈΡΠ½ΠΈΡΠ΅ ΡΠ΄ΡΠ° Π½Π° ΠΌΠ°ΡΠΈΠ½Π°ΡΠ°.
ΠΠΎΠ³Π°ΡΠΎ ΡΠ°Π±ΠΎΡΠΈΡΠ΅ Π² ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ Π½ΠΈΡΠΊΠΈ, ΡΠΈΡΡΠ΅ΠΌΠ½ΠΈΡΠ΅ ΠΈΠ·Π²ΠΈΠΊΠ²Π°Π½ΠΈΡ ΡΡΠ°Π²Π°Ρ ΡΠ²ΡΡΠ΄Π΅ ΠΌΠ½ΠΎΠ³ΠΎ:
$ 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
- ΠΏΡΡΠ²Π°ΡΠ° Π»ΠΈΠ½ΠΈΡ Π½Π° Π·Π°ΡΠΈΡΠ° Π² ΡΠ»ΡΡΠ°ΠΉ Π½Π° ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ Ρ ΠΌΠΎΠΈΡΠ΅ ΡΠΎΠ±ΡΡΠ²Π΅Π½ΠΈ ΠΈ ΡΡΠΆΠ΄ΠΈ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈ ΠΈ Π³ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌ ΠΏΠΎΠ½Π΅ Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΠΏΡΡΠΈ ΡΠ΅Π΄ΠΌΠΈΡΠ½ΠΎ.
ΠΠ°ΠΊΡΠ°ΡΠΊΠΎ, Π°ΠΊΠΎ ΠΎΠ±ΠΈΡΠ°ΡΠ΅ Unix, ΠΏΡΠΎΡΠ΅ΡΠ΅ΡΠ΅ man 1 strace
ΠΈ Π½Π΅ ΡΠ΅ ΠΊΠΎΠ»Π΅Π±Π°ΠΉΡΠ΅ Π΄Π° Π½Π°Π΄Π½ΠΈΠΊΠ½Π΅ΡΠ΅ Π² ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΈΡΠ΅ ΡΠΈ!
ΠΠ·ΡΠΎΡΠ½ΠΈΠΊ: www.habr.com