Strace Π² Linux: история, Π΄ΠΈΠ·Π°ΠΉΠ½ ΠΈ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅

Strace Π² Linux: история, Π΄ΠΈΠ·Π°ΠΉΠ½ ΠΈ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅

Π’ Unix-ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΈ систСми комуникацията Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°Ρ‚Π° с външния свят ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½Π°Ρ‚Π° систСма сС ΠΎΡΡŠΡ‰Π΅ΡΡ‚Π²ΡΠ²Π° Ρ‡Ρ€Π΅Π· малък Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ - систСмни повиквания. Π’ΠΎΠ²Π° ΠΎΠ·Π½Π°Ρ‡Π°Π²Π°, Ρ‡Π΅ Π·Π° Ρ†Π΅Π»ΠΈΡ‚Π΅ Π½Π° отстраняванСто Π½Π° Π³Ρ€Π΅ΡˆΠΊΠΈ ΠΌΠΎΠΆΠ΅ Π΄Π° бъдС ΠΏΠΎΠ»Π΅Π·Π½ΠΎ Π΄Π° ΡˆΠΏΠΈΠΎΠ½ΠΈΡ€Π°Ρ‚Π΅ систСмнитС повиквания, изпълнявани ΠΎΡ‚ процСси.

ΠŸΠΎΠΌΠΎΡ‰Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° Π²ΠΈ ΠΏΠΎΠΌΠ°Π³Π° Π΄Π° Π½Π°Π±Π»ΡŽΠ΄Π°Π²Π°Ρ‚Π΅ β€žΠΈΠ½Ρ‚ΠΈΠΌΠ½ΠΈΡ ΠΆΠΈΠ²ΠΎΡ‚β€œ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ Π² Linux strace, ΠΊΠΎΠ΅Ρ‚ΠΎ Π΅ ΠΏΡ€Π΅Π΄ΠΌΠ΅Ρ‚ Π½Π° Ρ‚Π°Π·ΠΈ статия. ΠŸΡ€ΠΈΠΌΠ΅Ρ€ΠΈ Π·Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° шпионско ΠΎΠ±ΠΎΡ€ΡƒΠ΄Π²Π°Π½Π΅ са ΠΏΡ€ΠΈΠ΄Ρ€ΡƒΠΆΠ΅Π½ΠΈ с ΠΊΡ€Π°Ρ‚ΠΊΠ° история strace ΠΈ описаниС Π½Π° Π΄ΠΈΠ·Π°ΠΉΠ½Π° Π½Π° Ρ‚Π°ΠΊΠΈΠ²Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ.

Π‘ΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅

ΠŸΡ€ΠΎΠΈΠ·Ρ…ΠΎΠ΄ Π½Π° Π²ΠΈΠ΄ΠΎΠ²Π΅Ρ‚Π΅

ΠžΡΠ½ΠΎΠ²Π½ΠΈΡΡ‚ интСрфСйс ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ ΠΈ ядрото Π½Π° ОБ Π² Unix Π΅ систСмнитС повиквания. систСмни повиквания, систСмни извиквания), взаимодСйствиСто Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ с външния свят сС ΠΎΡΡŠΡ‰Π΅ΡΡ‚Π²ΡΠ²Π° ΠΈΠ·ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»Π½ΠΎ Ρ‡Ρ€Π΅Π· тях.

Но Π² ΠΏΡŠΡ€Π²Π°Ρ‚Π° ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Π° вСрсия Π½Π° Unix (ВСрсия 6 Unix, 1975) Π½Π΅ Π΅ ΠΈΠΌΠ°Π»ΠΎ ΡƒΠ΄ΠΎΠ±Π½ΠΈ Π½Π°Ρ‡ΠΈΠ½ΠΈ Π·Π° прослСдяванС Π½Π° ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅Ρ‚ΠΎ Π½Π° потрСбитСлскитС процСси. Π—Π° Π΄Π° Ρ€Π°Π·Ρ€Π΅ΡˆΠΈ Ρ‚ΠΎΠ·ΠΈ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, Bell Labs Ρ‰Π΅ Π°ΠΊΡ‚ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€Π° Π΄ΠΎ слСдващата вСрсия (ВСрсия 7 Unix, 1979) ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠΈ Π½ΠΎΠ²ΠΎ систСмно ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½Π΅ - ptrace.

ptrace Π΅ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π΅Π½ основно Π·Π° ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΈ Π΄Π΅Π±ΡŠΠ³Π΅Ρ€ΠΈ, Π½ΠΎ Π² края Π½Π° 80-Ρ‚Π΅ Π³ΠΎΠ΄ΠΈΠ½ΠΈ (Π² Π΅Ρ€Π°Ρ‚Π° Π½Π° комСрсиалнитС System V ΠΈΠ·Π΄Π°Π½ΠΈΠ΅ 4) Π½Π° Ρ‚Π°Π·ΠΈ основа сС появиха ΠΈ ΡˆΠΈΡ€ΠΎΠΊΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ΠΈ тясно фокусирани ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ Π·Π° отстраняванС Π½Π° Π³Ρ€Π΅ΡˆΠΊΠΈ - прослСдяващи систСмни повиквания.

ΠŸΡŠΡ€Π²ΠΈ ΡΡŠΡ‰Π°Ρ‚Π° вСрсия Π½Π° strace бСшС ΠΏΡƒΠ±Π»ΠΈΠΊΡƒΠ²Π°Π½Π° ΠΎΡ‚ Paul Cronenburg Π² пощСнския списък comp.sources.sun ΠΏΡ€Π΅Π· 1992 Π³. ΠΊΠ°Ρ‚ΠΎ Π°Π»Ρ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π° Π½Π° Π·Π°Ρ‚Π²ΠΎΡ€Π΅Π½Π° ΠΏΠΎΠΌΠΎΡ‰Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° 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 ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ, Ρ‰Π΅ прСдоставя ΠΊΠΎΠ΄Π° Π·Π° ΠΌΠΈΠ½ΠΈΠ°Ρ‚ΡŽΡ€Π΅Π½ трасиращ - Π‘Π»Π΅Π΄Π° Π½Π° прасСнцС (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 Ρ€Π°Π·ΠΏΠΎΠ·Π½Π°Π²Π° ΠΎΠΊΠΎΠ»ΠΎ стотици систСмни повиквания Π½Π° Linux (Π²ΠΈΠΆΡ‚Π΅. масата) ΠΈ Ρ€Π°Π±ΠΎΡ‚ΠΈ само Π½Π° x86-64 Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°. Π’ΠΎΠ²Π° Π΅ Π΄ΠΎΡΡ‚Π°Ρ‚ΡŠΡ‡Π½ΠΎ Π·Π° ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚Π΅Π»Π½ΠΈ Ρ†Π΅Π»ΠΈ.

НСка Π΄Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° Π½Π° нашия ΠΊΠ»ΠΎΠ½ΠΈΠ½Π³. Π’ случая Π½Π° 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, &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 Π½Π° Linux.

Основи: стартиранС Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°, ΠΈΠ·ΠΏΡŠΠ»Π½ΡΠ²Π°Ρ‰Π° 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 - прост ΠΈ Π½Π°Π΄Π΅ΠΆΠ΄Π΅Π½ инструмСнт. Но Π² допълнСниС към систСмнитС повиквания ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° сС отстраняват Π³Ρ€Π΅ΡˆΠΊΠΈ ΠΈ Π² Π΄Ρ€ΡƒΠ³ΠΈ аспСкти Π½Π° Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½Π°Ρ‚Π° систСма. НапримСр, ΠΌΠΎΠΆΠ΅ Π΄Π° прослСдява повиквания към Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡Π½ΠΎ ΡΠ²ΡŠΡ€Π·Π°Π½ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ. ltrace, Ρ‚Π΅ ΠΌΠΎΠ³Π°Ρ‚ Π΄Π° Ρ€Π°Π·Π³Π»Π΅Π΄Π°Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° Π½Π° ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½Π°Ρ‚Π° систСма SystemTap ΠΈ ftraceΠΈ Π²ΠΈ позволява Π΄Π° ΠΏΡ€ΠΎΡƒΡ‡ΠΈΡ‚Π΅ Π·Π°Π΄ΡŠΠ»Π±ΠΎΡ‡Π΅Π½ΠΎ СфСктивността Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°Ρ‚Π° PERF. Π’ΡŠΠΏΡ€Π΅ΠΊΠΈ Ρ‚ΠΎΠ²Π° Π΅ Ρ‚Π°ΠΊΠ° strace - ΠΏΡŠΡ€Π²Π°Ρ‚Π° линия Π½Π° Π·Π°Ρ‰ΠΈΡ‚Π° Π² случай Π½Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ с ΠΌΠΎΠΈΡ‚Π΅ собствСни ΠΈ Ρ‡ΡƒΠΆΠ΄ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ ΠΈ Π³ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌ ΠΏΠΎΠ½Π΅ няколко ΠΏΡŠΡ‚ΠΈ сСдмично.

Накратко, Π°ΠΊΠΎ ΠΎΠ±ΠΈΡ‡Π°Ρ‚Π΅ Unix, ΠΏΡ€ΠΎΡ‡Π΅Ρ‚Π΅Ρ‚Π΅ man 1 strace ΠΈ Π½Π΅ сС ΠΊΠΎΠ»Π΅Π±Π°ΠΉΡ‚Π΅ Π΄Π° Π½Π°Π΄Π½ΠΈΠΊΠ½Π΅Ρ‚Π΅ Π² ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ си!

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: www.habr.com

ДобавянС Π½Π° Π½ΠΎΠ² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€