Strace Π²ΠΎ Linux: ΠΈΡΡ‚ΠΎΡ€ΠΈΡ˜Π°, дизајн ΠΈ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π°

Strace Π²ΠΎ Linux: ΠΈΡΡ‚ΠΎΡ€ΠΈΡ˜Π°, дизајн ΠΈ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π°

Π’ΠΎ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΈΡ‚Π΅ систСми слични Π½Π° Unix, ΠΊΠΎΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΡ˜Π°Ρ‚Π° Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°Ρ‚Π° со Π½Π°Π΄Π²ΠΎΡ€Π΅ΡˆΠ½ΠΈΠΎΡ‚ свСт ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΈΠΎΡ‚ систСм сС случува ΠΏΡ€Π΅ΠΊΡƒ ΠΌΠ°Π» сСт Π½Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ - систСмски ΠΏΠΎΠ²ΠΈΡ†ΠΈ. Ова Π·Π½Π°Ρ‡ΠΈ Π΄Π΅ΠΊΠ° Π·Π° Ρ†Π΅Π»ΠΈΡ‚Π΅ Π½Π° Π΄Π΅Π±Π°Π³ΠΈΡ€Π°ΡšΠ΅ ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΠΈΠ΄Π΅ корисно Π΄Π° сС ΡˆΠΏΠΈΠΎΠ½ΠΈΡ€Π°Π°Ρ‚ систСмскитС ΠΏΠΎΠ²ΠΈΡ†ΠΈ ΡˆΡ‚ΠΎ сС ΠΈΠ·Π²Ρ€ΡˆΡƒΠ²Π°Π°Ρ‚ ΠΎΠ΄ процСситС.

Алатката Π²ΠΈ ΠΏΠΎΠΌΠ°Π³Π° Π΄Π° Π³ΠΎ слСдитС β€žΠΈΠ½Ρ‚ΠΈΠΌΠ½ΠΈΠΎΡ‚ ΠΆΠΈΠ²ΠΎΡ‚β€œ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ Π½Π° Linux strace, ΡˆΡ‚ΠΎ Π΅ Ρ‚Π΅ΠΌΠ° Π½Π° овој напис. ΠŸΡ€ΠΈΠΌΠ΅Ρ€ΠΈΡ‚Π΅ Π·Π° ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π° Π½Π° шпионска ΠΎΠΏΡ€Π΅ΠΌΠ° сС ΠΏΡ€ΠΈΠ΄Ρ€ΡƒΠΆΠ΅Π½ΠΈ со ΠΊΡ€Π°Ρ‚ΠΊΠ° ΠΈΡΡ‚ΠΎΡ€ΠΈΡ˜Π° strace ΠΈ опис Π½Π° Π΄ΠΈΠ·Π°Ρ˜Π½ΠΎΡ‚ Π½Π° Ρ‚Π°ΠΊΠ²ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ.

содрТина

ΠŸΠΎΡ‚Π΅ΠΊΠ»ΠΎ Π½Π° Π²ΠΈΠ΄ΠΎΠ²ΠΈΡ‚Π΅

Π“Π»Π°Π²Π½ΠΈΠΎΡ‚ ΠΈΠ½Ρ‚Π΅Ρ€Ρ„Π΅Ρ˜Ρ ΠΏΠΎΠΌΠ΅Ρ“Ρƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ ΠΈ ΠΊΠ΅Ρ€Π½Π΅Π»ΠΎΡ‚ Π½Π° ОБ Π²ΠΎ Unix сС систСмскитС ΠΏΠΎΠ²ΠΈΡ†ΠΈ. систСмски ΠΏΠΎΠ²ΠΈΡ†ΠΈ, syscals), ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ†ΠΈΡ˜Π°Ρ‚Π° Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ со Π½Π°Π΄Π²ΠΎΡ€Π΅ΡˆΠ½ΠΈΠΎΡ‚ свСт сС случува исклучиво ΠΏΡ€Π΅ΠΊΡƒ Π½ΠΈΠ².

Но, Π²ΠΎ ΠΏΡ€Π²Π°Ρ‚Π° јавна Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π½Π° Unix (Π’Π΅Ρ€Π·ΠΈΡ˜Π° 6 Unix, 1975) нСмашС ΠΏΡ€ΠΈΠ³ΠΎΠ΄Π½ΠΈ Π½Π°Ρ‡ΠΈΠ½ΠΈ Π·Π° слСдСњС Π½Π° ΠΎΠ΄Π½Π΅ΡΡƒΠ²Π°ΡšΠ΅Ρ‚ΠΎ Π½Π° корисничкитС процСси. Π—Π° Π΄Π° сС Ρ€Π΅ΡˆΠΈ овој ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, Bell Labs ќС сС Π°ΠΆΡƒΡ€ΠΈΡ€Π° Π½Π° слСдната Π²Π΅Ρ€Π·ΠΈΡ˜Π° (Π’Π΅Ρ€Π·ΠΈΡ˜Π° 7 Unix, 1979) ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠΈ Π½ΠΎΠ² систСмски ΠΏΠΎΠ²ΠΈΠΊ - ptrace.

ptrace бСшС Ρ€Π°Π·Π²ΠΈΠ΅Π½ првСнствСно Π·Π° ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΈ Π΄Π΅Π±Π°Π³Π΅Ρ€ΠΈ, Π½ΠΎ Π΄ΠΎ ΠΊΡ€Π°Ρ˜ΠΎΡ‚ Π½Π° 80-Ρ‚ΠΈΡ‚Π΅ (Π²ΠΎ Π΅Ρ€Π°Ρ‚Π° Π½Π° ΠΊΠΎΠΌΠ΅Ρ€Ρ†ΠΈΡ˜Π°Π»Π½ΠΈ БистСм V ΠΈΠ·Π΄Π°Π½ΠΈΠ΅ 4) Π½Π° ΠΎΠ²Π°Π° основа, сС појавија ΠΈ станаа ΡˆΠΈΡ€ΠΎΠΊΠΎ користСни Π΄Π΅Π±Π°Π³Π΅Ρ€ΠΈ со тСсно Ρ„ΠΎΠΊΡƒΡΠΈΡ€Π°ΡšΠ΅ - систСмски ΠΏΠΎΠ²ΠΈΡ†ΠΈ Π·Π° слСдСњС.

ΠŸΡ€Π²ΠΈΠΎΡ‚ истата Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π½Π° strace бСшС објавСна ΠΎΠ΄ Пол ΠšΡ€ΠΎΠ½Π΅Π½Π±ΡƒΡ€Π³ Π½Π° мСјлинг листата comp.sources.sun Π²ΠΎ 1992 Π³ΠΎΠ΄ΠΈΠ½Π° ΠΊΠ°ΠΊΠΎ Π°Π»Ρ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π° Π½Π° Π·Π°Ρ‚Π²ΠΎΡ€Π΅Π½Π° Π°Π»Π°Ρ‚ΠΊΠ° trace ΠΎΠ΄ Π‘ΠΎΠ½Ρ†Π΅Ρ‚ΠΎ. И ΠΊΠ»ΠΎΠ½ΠΎΡ‚ ΠΈ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΠΎΡ‚ Π±Π΅Π° Π½Π°ΠΌΠ΅Π½Π΅Ρ‚ΠΈ Π·Π° SunOS, Π½ΠΎ Π΄ΠΎ 1994 Π³ΠΎΠ΄ΠΈΠ½Π° strace бСшС прСнСсСн Π½Π° System V, Solaris ΠΈ сè ΠΏΠΎΠΏΠΎΠΏΡƒΠ»Π°Ρ€Π½ΠΈΠΎΡ‚ Linux.

ДСнСс strace ΠΏΠΎΠ΄Π΄Ρ€ΠΆΡƒΠ²Π° само Linux ΠΈ сС ΠΏΠΎΡ‚ΠΏΠΈΡ€Π° Π½Π° истото ptrace, обраснат со ΠΌΠ½ΠΎΠ³Ρƒ ΠΏΡ€ΠΎΡˆΠΈΡ€ΡƒΠ²Π°ΡšΠ°.

ΠœΠΎΠ΄Π΅Ρ€Π΅Π½ (ΠΈ ΠΌΠ½ΠΎΠ³Ρƒ Π°ΠΊΡ‚ΠΈΠ²Π΅Π½) ΠΎΠ΄Ρ€ΠΆΡƒΠ²Π°Ρ‡ strace - Π”ΠΌΠΈΡ‚Ρ€ΠΈΡ˜ Π›Π΅Π²ΠΈΠ½. Π‘Π»Π°Π³ΠΎΠ΄Π°Ρ€Π΅Π½ΠΈΠ΅ Π½Π° Π½Π΅Π³ΠΎ, Π°Π»Π°Ρ‚ΠΊΠ°Ρ‚Π° Π΄ΠΎΠ±ΠΈ Π½Π°ΠΏΡ€Π΅Π΄Π½ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΊΠ°ΠΊΠΎ ΡˆΡ‚ΠΎ сС Π²Π±Ρ€ΠΈΠ·Π³ΡƒΠ²Π°ΡšΠ΅ Π½Π° Π³Ρ€Π΅ΡˆΠΊΠΈ Π²ΠΎ систСмскитС ΠΏΠΎΠ²ΠΈΡ†ΠΈ, ΠΏΠΎΠ΄Π΄Ρ€ΡˆΠΊΠ° Π·Π° ΡˆΠΈΡ€ΠΎΠΊ опсСг Π½Π° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ΠΈ ΠΈ ΡˆΡ‚ΠΎ Π΅ најваТно, маскота. ΠΠ΅ΠΎΡ„ΠΈΡ†ΠΈΡ˜Π°Π»Π½ΠΈ ΠΈΠ·Π²ΠΎΡ€ΠΈ Ρ‚Π²Ρ€Π΄Π°Ρ‚ Π΄Π΅ΠΊΠ° ΠΈΠ·Π±ΠΎΡ€ΠΎΡ‚ ΠΏΠ°Π΄Π½Π°Π» Π½Π° Π½ΠΎΡ˜ΠΎΡ‚ ΠΏΠΎΡ€Π°Π΄ΠΈ согласката ΠΏΠΎΠΌΠ΅Ρ“Ρƒ рускиот Π·Π±ΠΎΡ€ β€žΠ½ΠΎΡ˜β€œ ΠΈ англискиот Π·Π±ΠΎΡ€ β€žΡΡ‚Ρ€Π°Ρ˜Ρβ€œ.

Π˜ΡΡ‚ΠΎ Ρ‚Π°ΠΊΠ°, Π²Π°ΠΆΠ½ΠΎ Π΅ ΡˆΡ‚ΠΎ систСмскиот ΠΏΠΎΠ²ΠΈΠΊ ptrace ΠΈ трасСритС никогаш Π½Π΅ Π±ΠΈΠ»Π΅ Π²ΠΊΠ»ΡƒΡ‡Π΅Π½ΠΈ Π²ΠΎ POSIX, ΠΈ ΠΏΠΎΠΊΡ€Π°Ρ˜ Π΄ΠΎΠ»Π³Π°Ρ‚Π° ΠΈΡΡ‚ΠΎΡ€ΠΈΡ˜Π° ΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π° Π²ΠΎ Linux, FreeBSD, OpenBSD ΠΈ Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π°Π»Π½ΠΈΠΎΡ‚ Unix.

Π£Ρ€Π΅Π΄ Π·Π° ΡˆΡ‚Ρ€Π°Ρ˜Ρ Π½Π°ΠΊΡ€Π°Ρ‚ΠΊΠΎ: Piglet Trace

β€žΠΠ΅ сС ΠΎΡ‡Π΅ΠΊΡƒΠ²Π° Π΄Π° Π³ΠΎ Ρ€Π°Π·Π±Π΅Ρ€Π΅Ρ‚Π΅ ΠΎΠ²Π°β€œ (ДСнис Π ΠΈΡ‡ΠΈ, ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€ Π²ΠΎ ΠΈΠ·Π²ΠΎΡ€Π½ΠΈΠΎΡ‚ ΠΊΠΎΠ΄ Π½Π° Unix Π²Π΅Ρ€Π·ΠΈΡ˜Π° 6)

Од Ρ€Π°Π½ΠΎΡ‚ΠΎ дСтство, Π½Π΅ ΠΌΠΎΠΆΠ°ΠΌ Π΄Π° поднСсам Ρ†Ρ€Π½ΠΈ ΠΊΡƒΡ‚ΠΈΠΈ: Π½Π΅ си ΠΈΠ³Ρ€Π°Π² со ΠΈΠ³Ρ€Π°Ρ‡ΠΊΠΈ, Ρ‚ΡƒΠΊΡƒ сС ΠΎΠ±ΠΈΠ΄ΠΎΠ² Π΄Π° ја Ρ€Π°Π·Π±Π΅Ρ€Π°ΠΌ Π½ΠΈΠ²Π½Π°Ρ‚Π° структура (возраснитС Π³ΠΎ користСа Π·Π±ΠΎΡ€ΠΎΡ‚ β€žΡΠΊΡ€ΡˆΠΈβ€œ, Π½ΠΎ Π½Π΅ ΠΈΠΌ Π²Π΅Ρ€ΡƒΠ²Π°Π°Ρ‚ Π½Π° Π·Π»ΠΈΡ‚Π΅ Ρ˜Π°Π·ΠΈΡ†ΠΈ). МоТСби Π·Π°Ρ‚ΠΎΠ° Π½Π΅Ρ„ΠΎΡ€ΠΌΠ°Π»Π½Π°Ρ‚Π° ΠΊΡƒΠ»Ρ‚ΡƒΡ€Π° Π½Π° ΠΏΡ€Π²ΠΈΠΎΡ‚ Unix ΠΈ ΠΌΠΎΠ΄Π΅Ρ€Π½ΠΎΡ‚ΠΎ двиТСњС Π·Π° ΠΎΡ‚Π²ΠΎΡ€Π΅Π½ ΠΊΠΎΠ΄ ΠΌΠΈ Π΅ Ρ‚ΠΎΠ»ΠΊΡƒ блиску.

Π—Π° Ρ†Π΅Π»ΠΈΡ‚Π΅ Π½Π° овој напис, Π½Π΅Ρ€Π°Π·ΡƒΠΌΠ½ΠΎ Π΅ Π΄Π° сС расклопи ΠΈΠ·Π²ΠΎΡ€Π½ΠΈΠΎΡ‚ ΠΊΠΎΠ΄ Π½Π° strace, кој Ρ€Π°ΡΡ‚Π΅ΡˆΠ΅ со Π΄Π΅Ρ†Π΅Π½ΠΈΠΈ. Но, Π½Π΅ Ρ‚Ρ€Π΅Π±Π° Π΄Π° останат Ρ‚Π°Ρ˜Π½ΠΈ Π·Π° Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π»ΠΈΡ‚Π΅. Π—Π°Ρ‚ΠΎΠ°, Π·Π° Π΄Π° Π³ΠΎ ΠΏΠΎΠΊΠ°ΠΆΠ°ΠΌ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΎΡ‚ Π½Π° Ρ€Π°Π±ΠΎΡ‚Π° Π½Π° Ρ‚Π°ΠΊΠ²ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ Π·Π° Ρ‚Ρ€Π°Π³Π°, ќС Π³ΠΎ Π΄Π°Π΄Π°ΠΌ ΠΊΠΎΠ΄ΠΎΡ‚ Π·Π° ΠΌΠΈΠ½ΠΈΡ˜Π°Ρ‚ΡƒΡ€Π΅Π½ трасСр - ΠŸΡ€Π°ΡΠ΅ прасС (ptr). НС Π·Π½Π°Π΅ ΠΊΠ°ΠΊΠΎ Π΄Π° Π½Π°ΠΏΡ€Π°Π²ΠΈ Π½ΠΈΡˆΡ‚ΠΎ посСбно, Π½ΠΎ Π³Π»Π°Π²Π½Π°Ρ‚Π° Ρ€Π°Π±ΠΎΡ‚Π° Π΅ систСмскитС ΠΏΠΎΠ²ΠΈΡ†ΠΈ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°Ρ‚Π° - Ρ‚Π°Π° ΠΈΠ·Π»Π΅Π³ΡƒΠ²Π°:

$ gcc examples/piglet-trace.c -o ptr
$ ptr echo test > /dev/null
BRK(12) -> 94744690540544
ACCESS(21) -> 18446744073709551614
ACCESS(21) -> 18446744073709551614
unknown(257) -> 3
FSTAT(5) -> 0
MMAP(9) -> 140694657216512
CLOSE(3) -> 0
ACCESS(21) -> 18446744073709551614
unknown(257) -> 3
READ(0) -> 832
FSTAT(5) -> 0
MMAP(9) -> 140694657208320
MMAP(9) -> 140694650953728
MPROTECT(10) -> 0
MMAP(9) -> 140694655045632
MMAP(9) -> 140694655070208
CLOSE(3) -> 0
unknown(158) -> 0
MPROTECT(10) -> 0
MPROTECT(10) -> 0
MPROTECT(10) -> 0
MUNMAP(11) -> 0
BRK(12) -> 94744690540544
BRK(12) -> 94744690675712
unknown(257) -> 3
FSTAT(5) -> 0
MMAP(9) -> 140694646390784
CLOSE(3) -> 0
FSTAT(5) -> 0
IOCTL(16) -> 18446744073709551591
WRITE(1) -> 5
CLOSE(3) -> 0
CLOSE(3) -> 0
unknown(231)
Tracee terminated

Piglet Trace ΠΏΡ€Π΅ΠΏΠΎΠ·Π½Π°Π²Π° ΠΎΠΊΠΎΠ»Ρƒ стотици систСмски ΠΏΠΎΠ²ΠΈΡ†ΠΈ Π½Π° 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 Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π» ќС Π·Π°Π²Ρ€ΡˆΠΈ ΠΈΠ»ΠΈ ΠΏΡ€Π΅Π΄ Π΄Π° сС ΠΈΠ·Π²Ρ€ΡˆΠΈ систСмскиот ΠΏΠΎΠ²ΠΈΠΊ ΠΈΠ»ΠΈ вСднаш ΠΎΡ‚ΠΊΠ°ΠΊΠΎ ќС Π·Π°Π²Ρ€ΡˆΠΈ. ΠŸΠΎΠΌΠ΅Ρ“Ρƒ Π΄Π²Π° ΠΏΠΎΠ²ΠΈΡ†ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΈΠ·Π²Ρ€ΡˆΠΈΡ‚Π΅ ΠΊΠ°ΠΊΠ²ΠΈ Π±ΠΈΠ»ΠΎ Π΄Π΅Ρ˜ΡΡ‚Π²Π°: Π·Π°ΠΌΠ΅Π½Π΅Ρ‚Π΅ Π³ΠΎ ΠΏΠΎΠ²ΠΈΠΊΠΎΡ‚ со Π°Π»Ρ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π΅Π½, смСнСтС Π³ΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΈΡ‚Π΅ ΠΈΠ»ΠΈ ΠΏΠΎΠ²Ρ€Π°Ρ‚Π½Π°Ρ‚Π° врСдност.

Π’Ρ€Π΅Π±Π° само Π΄Π²Π°ΠΏΠ°Ρ‚ΠΈ Π΄Π° ја ΠΏΠΎΠ²ΠΈΠΊΠ°ΠΌΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ‚Π° 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.

Π—Π° Π΄Π° Π½Π΅ Π½Π°Π²Π»Π΅Π³ΡƒΠ²Π°ΠΌΠ΅ Π²ΠΎ Π±Π΅ΡΠΊΡ€Π°Ρ˜Π½Π°Ρ‚Π° листа Π½Π° ΠΏΠΎΠ²ΠΈΡ†ΠΈ Π½Π° Ρ‚ΠΈΠΏΠΈΡ‡Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°, ΠΏΠΈΡˆΡƒΠ²Π°ΠΌΠ΅ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° ΠΎΠΊΠΎΠ»Ρƒ write:

int main(int argc, char *argv[])
{
    char str[] = "write me to stdoutn";
    /* write(2) is a simple wrapper around a syscall so it should be easy to
     * find in the syscall trace. */
    if (sizeof(str) != write(STDOUT_FILENO, str, sizeof(str))){
        perror("write");
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

АјдС Π΄Π° ја ΠΈΠ·Π³Ρ€Π°Π΄ΠΈΠΌΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°Ρ‚Π° ΠΈ Π΄Π° сС ΡƒΠ²Π΅Ρ€ΠΈΠΌΠ΅ Π΄Π΅ΠΊΠ° Ρ€Π°Π±ΠΎΡ‚ΠΈ:

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

И, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ајдС Π΄Π° Π³ΠΎ Π²ΠΎΠ΄ΠΈΠΌΠ΅ ΠΏΠΎΠ΄ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π°:

$ strace ./write-simple
pexecve("./write", ["./write"], 0x7ffebd6145b0 /* 71 vars */) = 0
brk(NULL)                               = 0x55ff5489e000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=197410, ...}) = 0
mmap(NULL, 197410, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7a2a633000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF21133>1260342"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7a2a631000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7a2a04c000
mprotect(0x7f7a2a233000, 2097152, PROT_NONE) = 0
mmap(0x7f7a2a433000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f7a2a433000
mmap(0x7f7a2a439000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7a2a439000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f7a2a6324c0) = 0
mprotect(0x7f7a2a433000, 16384, PROT_READ) = 0
mprotect(0x55ff52b52000, 4096, PROT_READ) = 0
mprotect(0x7f7a2a664000, 4096, PROT_READ) = 0
munmap(0x7f7a2a633000, 197410)          = 0
write(1, "write me to stdoutn", 20write me to stdout
)  = 20
exit_group(0)                           = ?

ΠœΠ½ΠΎΠ³Ρƒ β€žΠ·Π±ΠΎΡ€ΡƒΠ²Π°Π½β€œ ΠΈ Π½Π΅ ΠΌΠ½ΠΎΠ³Ρƒ Π΅Π΄ΡƒΠΊΠ°Ρ‚ΠΈΠ²Π΅Π½. Π’ΡƒΠΊΠ° ΠΈΠΌΠ° Π΄Π²Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ: ΠΈΠ·Π»Π΅Π·ΠΎΡ‚ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°Ρ‚Π° сС мСша со ΠΈΠ·Π»Π΅Π·ΠΎΡ‚ strace ΠΈ изобилство систСмски ΠΏΠΎΠ²ΠΈΡ†ΠΈ ΠΊΠΎΠΈ Π½Π΅ Π½Γ¨ интСрСсираат.

ΠœΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π³ΠΎ Ρ€Π°Π·Π΄Π²ΠΎΠΈΡ‚Π΅ стандардниот ΠΈΠ·Π»Π΅Π·Π΅Π½ Ρ‚Π΅ΠΊ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°Ρ‚Π° ΠΈ ΠΈΠ·Π»Π΅Π·ΠΎΡ‚ Π½Π° Π³Ρ€Π΅ΡˆΠΊΠ° Π²ΠΎ трасата ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Π³ΠΎ ΠΏΡ€Π΅ΠΊΠΈΠ½ΡƒΠ²Π°Ρ‡ΠΎΡ‚ -o, кој ја прСнасочува листата Π½Π° систСмски ΠΏΠΎΠ²ΠΈΡ†ΠΈ Π΄ΠΎ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° со Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΈ.

ΠžΡΡ‚Π°Π½ΡƒΠ²Π° Π΄Π° сС справимС со ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΎΡ‚ со β€žΠ΅ΠΊΡΡ‚Ρ€Π°β€œ ΠΏΠΎΠ²ΠΈΡ†ΠΈ. Π”Π° прСтпоставимС Π΄Π΅ΠΊΠ° смС заинтСрСсирани само Π·Π° ΠΏΠΎΠ²ΠΈΡ†ΠΈ write. ΠšΠ»ΡƒΡ‡ -e Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π° ΠΎΠ΄Ρ€Π΅Π΄ΠΈΡ‚Π΅ ΠΈΠ·Ρ€Π°Π·ΠΈ спорСд ΠΊΠΎΠΈ систСмскитС ΠΏΠΎΠ²ΠΈΡ†ΠΈ ќС сС Ρ„ΠΈΠ»Ρ‚Ρ€ΠΈΡ€Π°Π°Ρ‚. ΠΠ°Ρ˜ΠΏΠΎΠΏΡƒΠ»Π°Ρ€Π½Π°Ρ‚Π° ΠΎΠΏΡ†ΠΈΡ˜Π° Π·Π° ΡΠΎΡΡ‚ΠΎΡ˜Π±Π° Π΅, ΠΏΡ€ΠΈΡ€ΠΎΠ΄Π½ΠΎ, trace=*, со кој ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° Π³ΠΈ оставитС само ΠΏΠΎΠ²ΠΈΡ†ΠΈΡ‚Π΅ ΠΊΠΎΠΈ Π½Π΅ интСрСсираат.

Кога сС користи истоврСмСно -o ΠΈ -e ќС Π΄ΠΎΠ±ΠΈΠ΅ΠΌΠ΅:

$ strace -e trace=write -owrite-simple.log ./write-simple
write me to stdout
$ cat write-simple.log
write(1, "write me to stdoutn", 20
)  = 20
+++ exited with 0 +++

Π—Π½Π°Ρ‡ΠΈ, Π³Π»Π΅Π΄Π°Ρ‚Π΅, ΠΌΠ½ΠΎΠ³Ρƒ Π΅ полСсно Π΄Π° сС ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°.

ΠœΠΎΠΆΠ΅Ρ‚Π΅ исто Ρ‚Π°ΠΊΠ° Π΄Π° Π³ΠΈ отстранитС систСмскитС ΠΏΠΎΠ²ΠΈΡ†ΠΈ, Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΎΠ½ΠΈΠ΅ ΠΏΠΎΠ²Ρ€Π·Π°Π½ΠΈ со распрСдСлба ΠΈ ΠΎΡΠ»ΠΎΠ±ΠΎΠ΄ΡƒΠ²Π°ΡšΠ΅ ΠΌΠ΅ΠΌΠΎΡ€ΠΈΡ˜Π°:

$ strace -e trace=!brk,mmap,mprotect,munmap -owrite-simple.log ./write-simple
write me to stdout
$ cat write-simple.log
execve("./write-simple", ["./write-simple"], 0x7ffe9972a498 /* 69 vars */) = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=124066, ...}) = 0
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "177ELF21133>1260342"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030544, ...}) = 0
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f00f0be74c0) = 0
write(1, "write me to stdoutn", 20)  = 20
exit_group(0)                           = ?
+++ exited with 0 +++

Π—Π°Π±Π΅Π»Π΅ΠΆΠ΅Ρ‚Π΅ Π³ΠΎ ΠΈΠ·Π²ΠΈΡ‡Π½ΠΈΠΊΠΎΡ‚ кој ΠΈΠ·Π±Π΅Π³Π½Π° Π²ΠΎ списокот со исклучСни ΠΏΠΎΠ²ΠΈΡ†ΠΈ: Ρ‚ΠΎΠ° Π³ΠΎ Π±Π°Ρ€Π° ΠΊΠΎΠΌΠ°Π½Π΄Π½Π°Ρ‚Π° школка. школка).

Π’ΠΎ ΠΌΠΎΡ˜Π°Ρ‚Π° Π²Π΅Ρ€Π·ΠΈΡ˜Π° Π½Π° glibc, систСмскиот ΠΏΠΎΠ²ΠΈΠΊ Π³ΠΎ ΠΏΡ€Π΅ΠΊΠΈΠ½ΡƒΠ²Π° процСсот exit_group, Π½Π΅ Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π°Π»Π΅Π½ _exit. Ова Π΅ Ρ‚Π΅ΡˆΠΊΠΎΡ‚ΠΈΡ˜Π°Ρ‚Π° Π·Π° Ρ€Π°Π±ΠΎΡ‚Π° со систСмски ΠΏΠΎΠ²ΠΈΡ†ΠΈ: ΠΈΠ½Ρ‚Π΅Ρ€Ρ„Π΅Ρ˜ΡΠΎΡ‚ со кој Ρ€Π°Π±ΠΎΡ‚ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ΅Ρ€ΠΎΡ‚ Π½Π΅ Π΅ Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ ΠΏΠΎΠ²Ρ€Π·Π°Π½ со систСмскитС ΠΏΠΎΠ²ΠΈΡ†ΠΈ. ΠŸΠΎΠΊΡ€Π°Ρ˜ Ρ‚ΠΎΠ°, Ρ‚Π°Π° сС ΠΌΠ΅Π½ΡƒΠ²Π° Ρ€Π΅Π΄ΠΎΠ²Π½ΠΎ Π²ΠΎ зависност ΠΎΠ΄ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π°Ρ‚Π° ΠΈ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π°.

Основи: ΠΏΡ€ΠΈΠΊΠ»ΡƒΡ‡ΡƒΠ²Π°ΡšΠ΅ Π½Π° процСсот Π²ΠΎ Π»Π΅Ρ‚

ΠŸΡ€Π²ΠΈΡ‡Π½ΠΎ, систСмот ptrace ΠΏΠΎΠ²ΠΈΠΊ Π½Π° кој Π΅ ΠΈΠ·Π³Ρ€Π°Π΄Π΅Π½ 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 - основата Π½Π° ситС Unixes. АјдС Π΄Π° Π²ΠΈΠ΄ΠΈΠΌΠ΅ ΠΊΠ°ΠΊΠΎ ΡΡ‚Ρ€Π΅Ρ˜ΡΠΎΡ‚ Ρ€Π°Π±ΠΎΡ‚ΠΈ со процСсно Π΄Ρ€Π²ΠΎ ΠΊΠΎΡ€ΠΈΡΡ‚Π΅Ρ˜ΡœΠΈ Π³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΡ‚ Π½Π° Сдноставно β€žΡ€Π°Π·ΠΌΠ½ΠΎΠΆΡƒΠ²Π°ΡšΠ΅β€œ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ:

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 - Сдноставна ΠΈ сигурна Π°Π»Π°Ρ‚ΠΊΠ°. Но, ΠΏΠΎΠΊΡ€Π°Ρ˜ систСмскитС ΠΏΠΎΠ²ΠΈΡ†ΠΈ, ΠΌΠΎΠΆΠ΅ Π΄Π° сС Π΄Π΅Π±Π°Π³ΠΈΡ€Π°Π°Ρ‚ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈ аспСкти ΠΎΠ΄ Ρ€Π°Π±ΠΎΡ‚Π΅ΡšΠ΅Ρ‚ΠΎ Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΡ‚Π΅ ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΈΠΎΡ‚ систСм. На ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΌΠΎΠΆΠ΅ Π΄Π° Π³ΠΈ слСди ΠΏΠΎΠ²ΠΈΡ†ΠΈΡ‚Π΅ Π΄ΠΎ Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡ΠΊΠΈ ΠΏΠΎΠ²Ρ€Π·Π°Π½ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ. Ρ‚Ρ€Π°Π³Π°, Ρ‚ΠΈΠ΅ ΠΌΠΎΠΆΠ°Ρ‚ Π΄Π° ја Ρ€Π°Π·Π³Π»Π΅Π΄Π°Π°Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚Π° Π½Π° ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΈΠΎΡ‚ систСм SystemTap ΠΈ Ρ„Ρ‚Ρ€Π°Ρ†Π΅, ΠΈ Π²ΠΈ ΠΎΠ²ΠΎΠ·ΠΌΠΎΠΆΡƒΠ²Π° Π΄Π»Π°Π±ΠΎΠΊΠΎ Π΄Π° Π³ΠΈ истраТитС пСрформанситС Π½Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°Ρ‚Π° ΠΏΠ΅Ρ€Ρ„. Π‘Π΅ΠΏΠ°ΠΊ, Ρ‚ΠΎΠ° Π΅ strace - ΠΏΡ€Π²Π° линија Π½Π° ΠΎΠ΄Π±Ρ€Π°Π½Π° Π²ΠΎ ΡΠ»ΡƒΡ‡Π°Ρ˜ Π½Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΈ со ΠΌΠΎΠΈΡ‚Π΅ ΠΈ Ρ‚ΡƒΡ“ΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ ΠΈ ја користам Π±Π°Ρ€Π΅ΠΌ Π½Π΅ΠΊΠΎΠ»ΠΊΡƒ ΠΏΠ°Ρ‚ΠΈ Π½Π΅Π΄Π΅Π»Π½ΠΎ.

Накратко, Π°ΠΊΠΎ Π³ΠΎ сакатС Unix, ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ man 1 strace ΠΈ слободно Ρ•ΠΈΡ€Π½Π΅Ρ‚Π΅ Π²ΠΎ Π²Π°ΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ!

Π˜Π·Π²ΠΎΡ€: www.habr.com

Π”ΠΎΠ΄Π°Π΄Π΅Ρ‚Π΅ ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€