Π‘Ρ‚Ρ€Π°Ρ†Π΅ Ρƒ Π›ΠΈΠ½ΡƒΠΊΡƒ: ΠΈΡΡ‚ΠΎΡ€ΠΈΡ˜Π°, дизајн ΠΈ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π°

Π‘Ρ‚Ρ€Π°Ρ†Π΅ Ρƒ Π›ΠΈΠ½ΡƒΠΊΡƒ: ΠΈΡΡ‚ΠΎΡ€ΠΈΡ˜Π°, дизајн ΠΈ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π°

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

УслуТни ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ Π²Π°ΠΌ ΠΏΠΎΠΌΠ°ΠΆΠ΅ Π΄Π° Π½Π°Π΄Π³Π»Π΅Π΄Π°Ρ‚Π΅ β€žΠΈΠ½Ρ‚ΠΈΠΌΠ½ΠΈ ΠΆΠΈΠ²ΠΎΡ‚β€œ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° Π½Π° Π›ΠΈΠ½ΡƒΠΊ-Ρƒ strace, ΡˆΡ‚ΠΎ јС Ρ‚Π΅ΠΌΠ° ΠΎΠ²ΠΎΠ³ Ρ‡Π»Π°Π½ΠΊΠ°. ΠŸΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π΅ ΡˆΠΏΠΈΡ˜ΡƒΠ½ΡΠΊΠ΅ ΠΎΠΏΡ€Π΅ΠΌΠ΅ ΠΏΡ€Π°Ρ‚ΠΈ ΠΊΡ€Π°Ρ‚Π°ΠΊ ΠΈΡΡ‚ΠΎΡ€ΠΈΡ˜Π°Ρ‚ strace ΠΈ опис дизајна Ρ‚Π°ΠΊΠ²ΠΈΡ… ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°.

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

ΠŸΠΎΡ€Π΅ΠΊΠ»ΠΎ врстС

Π“Π»Π°Π²Π½ΠΈ ΠΈΠ½Ρ‚Π΅Ρ€Ρ„Π΅Ρ˜Ρ ΠΈΠ·ΠΌΠ΅Ρ’Ρƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° ΠΈ Ρ˜Π΅Π·Π³Ρ€Π° ОБ Ρƒ Π£Π½ΠΈΠΊ-Ρƒ су систСмски ΠΏΠΎΠ·ΠΈΠ²ΠΈ. систСмски ΠΏΠΎΠ·ΠΈΠ²ΠΈ, сисцаллс), ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ†ΠΈΡ˜Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° са спољним свСтом сС одвија искључиво ΠΏΡ€Π΅ΠΊΠΎ ΡšΠΈΡ….

Али Ρƒ ΠΏΡ€Π²ΠΎΡ˜ јавној Π²Π΅Ρ€Π·ΠΈΡ˜ΠΈ Π£Π½ΠΈΠΊ-Π° (Π’Π΅Ρ€Π·ΠΈΡ˜Π° 6 Π£Π½ΠΈΠΊ, 1975) нијС Π±ΠΈΠ»ΠΎ Π·Π³ΠΎΠ΄Π½ΠΈΡ… Π½Π°Ρ‡ΠΈΠ½Π° Π·Π° ΠΏΡ€Π°Ρ›Π΅ΡšΠ΅ понашања корисничких процСса. Π”Π° Π±ΠΈ Ρ€Π΅ΡˆΠΈΠΎ овај ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, Π‘Π΅Π»Π» Лабс Ρ›Π΅ Π°ΠΆΡƒΡ€ΠΈΡ€Π°Ρ‚ΠΈ Π½Π° слСдСћу Π²Π΅Ρ€Π·ΠΈΡ˜Ρƒ (Π’Π΅Ρ€Π·ΠΈΡ˜Π° 7 Π£Π½ΠΈΠΊ, 1979) ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠΈΠΎ Π½ΠΎΠ²ΠΈ систСмски ΠΏΠΎΠ·ΠΈΠ² - ptrace.

ΠΏΡ‚Ρ€Π°Ρ†Π΅ јС Ρ€Π°Π·Π²ΠΈΡ˜Π΅Π½ првСнствСно Π·Π° ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Π΅ Π΄Π΅Π±Π°Π³Π΅Ρ€Π΅, Π°Π»ΠΈ Π΄ΠΎ ΠΊΡ€Π°Ρ˜Π° 80-ΠΈΡ… (Ρƒ Π΅Ρ€ΠΈ ΠΊΠΎΠΌΠ΅Ρ€Ρ†ΠΈΡ˜Π°Π»Π½ΠΈΡ… БистСм Π’ издањС 4) Π½Π° овој основи, појавили су сС уско фокусирани ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ Π·Π° ΠΎΡ‚ΠΊΠ»Π°ΡšΠ°ΡšΠ΅ Π³Ρ€Π΅ΡˆΠ°ΠΊΠ° β€” Ρ‚Ρ€Π°Π³Π°Ρ‡ΠΈ систСмских ΠΏΠΎΠ·ΠΈΠ²Π° β€” који су постали ΡˆΠΈΡ€ΠΎΠΊΠΎ ΠΊΠΎΡ€ΠΈΡˆΡ›Π΅Π½ΠΈ.

ΠŸΡ€Π²ΠΎ исту Π²Π΅Ρ€Π·ΠΈΡ˜Ρƒ страцС јС објавио ΠŸΠ°ΡƒΠ» Π¦Ρ€ΠΎΠ½Π΅Π½Π±ΡƒΡ€Π³ Π½Π° Ρ†ΠΎΠΌΠΏ.соурцСс.сун ΠΌΠ°ΠΈΠ»ΠΈΠ½Π³ листи 1992. Π³ΠΎΠ΄ΠΈΠ½Π΅ ΠΊΠ°ΠΎ Π°Π»Ρ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Ρƒ Π·Π°Ρ‚Π²ΠΎΡ€Π΅Π½ΠΎΠΌ услуТном ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΡƒ trace ΠΎΠ΄ Π‘ΡƒΠ½Ρ†Π°. И ΠΊΠ»ΠΎΠ½ ΠΈ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π» су Π±ΠΈΠ»ΠΈ намСњСни Π·Π° Π‘ΡƒΠ½ΠžΠ‘, Π°Π»ΠΈ Π΄ΠΎ 1994 strace јС ΠΏΡ€Π΅Π½Π΅Ρ‚ Π½Π° БистСм Π’, Боларис ΠΈ свС ΠΏΠΎΠΏΡƒΠ»Π°Ρ€Π½ΠΈΡ˜ΠΈ Π›ΠΈΠ½ΡƒΠΊ.

Данас страцС ΠΏΠΎΠ΄Ρ€ΠΆΠ°Π²Π° само Π›ΠΈΠ½ΡƒΠΊ ΠΈ ослања сС Π½Π° исти ptrace, обрастао ΠΌΠ½ΠΎΠ³ΠΈΠΌ ΠΏΡ€ΠΎΡˆΠΈΡ€Π΅ΡšΠΈΠΌΠ°.

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

Π’Π°ΠΊΠΎΡ’Π΅ јС Π²Π°ΠΆΠ½ΠΎ Π΄Π° ΠΏΡ‚Ρ€Π°Ρ†Π΅ систСмски ΠΏΠΎΠ·ΠΈΠ² ΠΈ Ρ‚Ρ€Π°Π³Π°Ρ‡ΠΈ Π½ΠΈΠΊΠ°Π΄Π° нису Π±ΠΈΠ»ΠΈ ΡƒΠΊΡ™ΡƒΡ‡Π΅Π½ΠΈ Ρƒ ПОБИКБ, упркос Π΄ΡƒΠ³ΠΎΡ˜ ΠΈΡΡ‚ΠΎΡ€ΠΈΡ˜ΠΈ ΠΈ ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜ΠΈ Ρƒ Π›ΠΈΠ½ΡƒΠΊ, Π€Ρ€Π΅Π΅Π‘Π‘Π”, ΠžΠΏΠ΅Π½Π‘Π‘Π” ΠΈ Ρ‚Ρ€Π°Π΄ΠΈΡ†ΠΈΠΎΠ½Π°Π»Π½ΠΎΠΌ Π£Π½ΠΈΠΊΡƒ.

Π‘Ρ‚Ρ€Π°Ρ†Π΅ ΡƒΡ€Π΅Ρ’Π°Ρ˜ ΡƒΠΊΡ€Π°Ρ‚ΠΊΠΎ: ΠŸΡ€Π°ΡΠ°Π΄ прасад

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

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

Π—Π° ΠΏΠΎΡ‚Ρ€Π΅Π±Π΅ ΠΎΠ²ΠΎΠ³ Ρ‡Π»Π°Π½ΠΊΠ°, Π½Π΅Ρ€Π°Π·ΡƒΠΌΠ½ΠΎ јС растављати ΠΈΠ·Π²ΠΎΡ€Π½ΠΈ ΠΊΠΎΠ΄ страцС-Π°, који јС растао Π΄Π΅Ρ†Π΅Π½ΠΈΡ˜Π°ΠΌΠ°. Али Π·Π° Ρ‡ΠΈΡ‚Π°ΠΎΡ†Π΅ Π½Π΅ Π±ΠΈ Ρ‚Ρ€Π΅Π±Π°Π»ΠΎ Π΄Π° останС Π½ΠΈΠΊΠ°ΠΊΠ²ΠΈΡ… Ρ‚Π°Ρ˜Π½ΠΈ. Π‘Ρ‚ΠΎΠ³Π°, Π΄Π° Π±ΠΈΡ… ΠΏΠΎΠΊΠ°Π·Π°ΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏ Ρ€Π°Π΄Π° Ρ‚Π°ΠΊΠ²ΠΈΡ… ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° Π·Π° ΠΏΡ€Π°Ρ›Π΅ΡšΠ΅, ΠΏΡ€ΡƒΠΆΠΈΡ›Ρƒ ΠΊΠΎΠ΄ Π·Π° ΠΌΠΈΠ½ΠΈΡ˜Π°Ρ‚ΡƒΡ€Π½ΠΈ Ρ‚Ρ€Π°Π³Π°Ρ‡ - ΠŸΡ€Π°ΡΠ°Π΄ Π’Ρ€Π°Ρ†Π΅ (ΠΏΡ‚Ρ€). НС Π·Π½Π° ΠΊΠ°ΠΊΠΎ Π΄Π° ΡƒΡ€Π°Π΄ΠΈ Π½ΠΈΡˆΡ‚Π° посСбно, Π°Π»ΠΈ Π³Π»Π°Π²Π½Π° ствар су систСмски ΠΏΠΎΠ·ΠΈΠ²ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° - ΠΎΠ½ дајС:

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

ΠŸΠΈΠ³Π»Π΅Ρ‚ Π’Ρ€Π°Ρ†Π΅ ΠΏΡ€Π΅ΠΏΠΎΠ·Π½Π°Ρ˜Π΅ стотинС Π›ΠΈΠ½ΡƒΠΊ систСмских ΠΏΠΎΠ·ΠΈΠ²Π° (Π²ΠΈΠ΄ΠΈ. сто) ΠΈ Ρ€Π°Π΄ΠΈ само Π½Π° Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€ΠΈ ΠΊ86-64. Ово јС Π΄ΠΎΠ²ΠΎΡ™Π½ΠΎ Π·Π° ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π½Π΅ сврхС.

Π₯ајдС Π΄Π° ΠΏΠΎΠ³Π»Π΅Π΄Π°ΠΌΠΎ Ρ€Π°Π΄ нашСг ΠΊΠ»ΠΎΠ½Π°. Π£ ΡΠ»ΡƒΡ‡Π°Ρ˜Ρƒ Π›ΠΈΠ½ΡƒΠΊΠ°, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ Π·Π° ΠΎΡ‚ΠΊΠ»Π°ΡšΠ°ΡšΠ΅ Π³Ρ€Π΅ΡˆΠ°ΠΊΠ° ΠΈ Ρ‚Ρ€Π°Π³Π°Ρ‡ΠΈ користС, ΠΊΠ°ΠΎ ΡˆΡ‚ΠΎ јС Π³ΠΎΡ€Π΅ ΠΏΠΎΠΌΠ΅Π½ΡƒΡ‚ΠΎ, систСмски ΠΏΠΎΠ·ΠΈΠ² ΠΏΡ‚Ρ€Π°Ρ†Π΅. Π€ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½ΠΈΡˆΠ΅ Ρ‚Π°ΠΊΠΎ ΡˆΡ‚ΠΎ сС Ρƒ ΠΏΡ€Π²ΠΎΠΌ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρƒ ΠΏΡ€ΠΎΡΠ»Π΅Ρ’ΡƒΡ˜Ρƒ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄ΠΈ, ΠΎΠ΄ ΠΊΠΎΡ˜ΠΈΡ… су Π½Π°ΠΌ само ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΈ PTRACE_TRACEME, PTRACE_SYSCALL ΠΈ PTRACE_GETREGS.

Π’Ρ€Π°Ρ†Π΅Ρ€ ΠΏΠΎΡ‡ΠΈΡšΠ΅ Ρƒ ΡƒΠΎΠ±ΠΈΡ‡Π°Ρ˜Π΅Π½ΠΎΠΌ Π£Π½ΠΈΠΊ стилу: fork(2) ΠΏΠΎΠΊΡ€Π΅Ρ›Π΅ ΠΏΠΎΠ΄Ρ€Π΅Ρ’Π΅Π½ΠΈ процСс, који Π·Π°ΡƒΠ·Π²Ρ€Π°Ρ‚ користи exec(3) ΠΏΠΎΠΊΡ€Π΅Ρ›Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ који сС ΠΏΡ€ΠΎΡƒΡ‡Π°Π²Π°. ЈСдина суптилност ΠΎΠ²Π΄Π΅ јС ΠΈΠ·Π°Π·ΠΎΠ² ptrace(PTRACE_TRACEME) ΠΏΡ€Π΅ exec: ΠŸΠΎΠ΄Ρ€Π΅Ρ’Π΅Π½ΠΈ процСс ΠΎΡ‡Π΅ΠΊΡƒΡ˜Π΅ Π΄Π° Π³Π° Π½Π°Π΄Ρ€Π΅Ρ’Π΅Π½ΠΈ процСс Π½Π°Π΄Π³Π»Π΅Π΄Π°:

pid_t child_pid = fork();
switch (child_pid) {
case -1:
    err(EXIT_FAILURE, "fork");
case 0:
    /* Child here */
    /* A traced mode has to be enabled. A parent will have to wait(2) for it
     * to happen. */
    ptrace(PTRACE_TRACEME, 0, NULL, NULL);
    /* Replace itself with a program to be run. */
    execvp(argv[1], argv + 1);
    err(EXIT_FAILURE, "exec");
}

РодитСљски процСс Π±ΠΈ сада Ρ‚Ρ€Π΅Π±Π°Π»ΠΎ Π΄Π° ΠΏΠΎΠ·ΠΎΠ²Π΅ wait(2) Ρƒ ΠΏΠΎΠ΄Ρ€Π΅Ρ’Π΅Π½ΠΎΠΌ процСсу, Ρ‚ΠΎ Ρ˜Π΅ΡΡ‚, ΡƒΠ²Π΅Ρ€ΠΈΡ‚Π΅ сС Π΄Π° јС дошло Π΄ΠΎ прСласка Π½Π° Ρ€Π΅ΠΆΠΈΠΌ ΠΏΡ€Π°Ρ›Π΅ΡšΠ°:

/* Parent */

/* First we wait for the child to set the traced mode (see
 * ptrace(PTRACE_TRACEME) above) */
if (waitpid(child_pid, NULL, 0) == -1)
    err(EXIT_FAILURE, "traceme -> waitpid");

Π£ ΠΎΠ²ΠΎΠΌ Ρ‚Ρ€Π΅Π½ΡƒΡ‚ΠΊΡƒ, ΠΏΡ€ΠΈΠΏΡ€Π΅ΠΌΠ΅ су Π·Π°Π²Ρ€ΡˆΠ΅Π½Π΅ ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ наставити Π΄ΠΈΡ€Π΅ΠΊΡ‚Π½ΠΎ Π½Π° ΠΏΡ€Π°Ρ›Π΅ΡšΠ΅ систСмских ΠΏΠΎΠ·ΠΈΠ²Π° Ρƒ Π±Π΅ΡΠΊΡ€Π°Ρ˜Π½ΠΎΡ˜ ΠΏΠ΅Ρ‚Ρ™ΠΈ.

Изазов 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);
}

Π’ΠΎ јС Ρ†Π΅ΠΎ Ρ‚Ρ€Π°Π³Π°Ρ‡. Π‘Π°Π΄Π° Π·Π½Π°Ρ‚Π΅ Π³Π΄Π΅ Π΄Π° Π·Π°ΠΏΠΎΡ‡Π½Π΅Ρ‚Π΅ слСдСћС ΠΏΡ€Π΅Π½ΠΎΡˆΠ΅ΡšΠ΅ Π”Π’Ρ€Π°Ρ†Π΅ Π½Π° Π›ΠΈΠ½ΡƒΠΊ-Ρƒ.

ОсновС: ΠΏΠΎΠΊΡ€Π΅Ρ‚Π°ΡšΠ΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° који сС ΠΏΠΎΠΊΡ€Π΅Ρ›Π΅ страцС

Као ΠΏΡ€Π²ΠΈ ΡΠ»ΡƒΡ‡Π°Ρ˜ ΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π΅ 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 ΠΈ ΠΎΠ±ΠΈΡ™Π΅ систСмских ΠΏΠΎΠ·ΠΈΠ²Π° који нас Π½Π΅ Π·Π°Π½ΠΈΠΌΠ°Ρ˜Ρƒ.

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

ΠžΡΡ‚Π°Ρ˜Π΅ Π΄Π° сС ΠΏΠΎΠ·Π°Π±Π°Π²ΠΈΠΌΠΎ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΎΠΌ β€žΠ΄ΠΎΠ΄Π°Ρ‚Π½ΠΈΡ…β€œ ΠΏΠΎΠ·ΠΈΠ²Π°. ΠŸΡ€Π΅Ρ‚ΠΏΠΎΡΡ‚Π°Π²ΠΈΠΌΠΎ Π΄Π° нас Π·Π°Π½ΠΈΠΌΠ°Ρ˜Ρƒ само ΠΏΠΎΠ·ΠΈΠ²ΠΈ 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 +++

ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ ΠΏΠ°ΠΆΡšΡƒ Π½Π° нСискључСни ΡƒΠ·Π²ΠΈΡ‡Π½ΠΈΠΊ Π½Π° листи искључСних ΠΏΠΎΠ·ΠΈΠ²Π°: ΠΎΠ²ΠΎ Π·Π°Ρ…Ρ‚Π΅Π²Π° ΠΊΠΎΠΌΠ°Π½Π΄Π½Π° ΡˆΠΊΠΎΡ™ΠΊΠ°. Π³Ρ€Π°Π½Π°Ρ‚Π°).

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

ОсновС: ΠΏΡ€ΠΈΠ΄Ρ€ΡƒΠΆΠΈΠ²Π°ΡšΠ΅ процСсу Ρƒ Ρ…ΠΎΠ΄Ρƒ

Π£ ΠΏΠΎΡ‡Π΅Ρ‚ΠΊΡƒ, систСмски ΠΏΠΎΠ·ΠΈΠ² ΠΏΡ‚Ρ€Π°Ρ†Π΅ Π½Π° којСм јС ΠΈΠ·Π³Ρ€Π°Ρ’Π΅Π½ strace, ΠΌΠΎΠ³Π°ΠΎ сС користити само ΠΊΠ°Π΄Π° сС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ ΠΏΠΎΠΊΡ€Π΅Ρ›Π΅ Ρƒ посСбном Ρ€Π΅ΠΆΠΈΠΌΡƒ. Ово ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅ΡšΠ΅ јС ΠΌΠΎΠΆΠ΄Π° Π·Π²ΡƒΡ‡Π°Π»ΠΎ Ρ€Π°Π·ΡƒΠΌΠ½ΠΎ Ρƒ Π΄Π°Π½ΠΈΠΌΠ° Π²Π΅Ρ€Π·ΠΈΡ˜Π΅ 6 Π£Π½ΠΈΠΊ-Π°. Данас Ρ‚ΠΎ вишС нијС Π΄ΠΎΠ²ΠΎΡ™Π½ΠΎ: ΠΏΠΎΠ½Π΅ΠΊΠ°Π΄ ΠΌΠΎΡ€Π°Ρ‚Π΅ истраТити ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ΅ Ρ€Π°Π΄Π½ΠΎΠ³ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ°. Π’ΠΈΠΏΠΈΡ‡Π°Π½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ јС процСс Π±Π»ΠΎΠΊΠΈΡ€Π°Π½ Π½Π° Ρ€ΡƒΡ‡ΠΊΠΈ ΠΈΠ»ΠΈ спавањС. Π‘Ρ‚ΠΎΠ³Π° ΠΌΠΎΠ΄Π΅Ρ€Π½ΠΎ strace ΠΌΠΎΠΆΠ΅ Π΄Π° сС ΠΏΡ€ΠΈΠ΄Ρ€ΡƒΠΆΠΈ процСсима Ρƒ Ρ…ΠΎΠ΄Ρƒ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π·Π°ΠΌΡ€Π·Π°Π²Π°ΡšΠ° programi:

int main(int argc, char *argv[])
{
    (void) argc; (void) argv;

    char str[] = "write men";

    write(STDOUT_FILENO, str, sizeof(str));

    /* Sleep indefinitely or until a signal arrives */
    pause();

    write(STDOUT_FILENO, str, sizeof(str));

    return EXIT_SUCCESS;
}

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

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

ΠŸΠΎΠΊΡƒΡˆΠ°Ρ˜ΠΌΠΎ сада Π΄Π° ΠΌΡƒ сС ΠΏΡ€ΠΈΠ΄Ρ€ΡƒΠΆΠΈΠΌΠΎ:

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

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌ Π±Π»ΠΎΠΊΠΈΡ€Π°Π½ ΠΏΠΎΠ·ΠΈΠ²ΠΎΠΌ pause. Π”Π° Π²ΠΈΠ΄ΠΈΠΌΠΎ ΠΊΠ°ΠΊΠΎ ΠΎΠ½Π° Ρ€Π΅Π°Π³ΡƒΡ˜Π΅ Π½Π° сигналС:

$ strace -o write-sleep.log -p 15329 &
strace: Process 15329 attached
$
$ kill -CONT 15329
$ cat write-sleep.log
pause()                                 = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
pause(
$
$ kill -TERM 15329
$ cat write-sleep.log
pause()                                 = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
pause()                                 = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
+++ killed by SIGTERM +++

ΠŸΠΎΠΊΡ€Π΅Π½ΡƒΠ»ΠΈ смо Π·Π°ΠΌΡ€Π·Π½ΡƒΡ‚ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ ΠΈ ΠΏΡ€ΠΈΠ΄Ρ€ΡƒΠΆΠΈΠ»ΠΈ ΠΌΡƒ сС користСћи strace. Π”Π²Π΅ ствари су посталС јаснС: систСмски ΠΏΠΎΠ·ΠΈΠ² ΠΏΠ°ΡƒΠ·Π΅ ΠΈΠ³Π½ΠΎΡ€ΠΈΡˆΠ΅ сигналС Π±Π΅Π· Ρ€ΡƒΠΊΠΎΠ²Π°ΠΎΡ†Π° ΠΈ, ΡˆΡ‚ΠΎ јС још Π·Π°Π½ΠΈΠΌΡ™ΠΈΠ²ΠΈΡ˜Π΅, страцС ΠΏΡ€Π°Ρ‚ΠΈ Π½Π΅ само систСмскС ΠΏΠΎΠ·ΠΈΠ²Π΅, Π²Π΅Ρ› ΠΈ Π΄ΠΎΠ»Π°Π·Π½Π΅ сигналС.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: ΠŸΡ€Π°Ρ›Π΅ΡšΠ΅ Π΄Π΅Ρ‡Ρ˜ΠΈΡ… процСса

Π Π°Π΄ са процСсима ΠΏΡ€Π΅ΠΊΠΎ ΠΏΠΎΠ·ΠΈΠ²Π° fork - основа свих Π£Π½ΠΈΠΊ-ΠΎΠ²Π°. Π₯ајдС Π΄Π° Π²ΠΈΠ΄ΠΈΠΌΠΎ ΠΊΠ°ΠΊΠΎ страцС Ρ€Π°Π΄ΠΈ са процСсним стаблом користСћи ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π½ΠΎΠ³ β€žΡƒΠ·Π³ΠΎΡ˜Π°β€œ programi:

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

Π£Π·Π³Ρ€Π΅Π΄, који систСмски ΠΏΠΎΠ·ΠΈΠ² сС користи Π·Π° ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ Π½ΠΎΠ²ΠΎΠ³ процСса?

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: ΠΏΡƒΡ‚Π°ΡšΠ΅ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° умСсто Ρ€ΡƒΡ‡ΠΈΡ†Π°

ПознавањС дСскриптора Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° јС свакако корисно, Π°Π»ΠΈ ΠΈΠΌΠ΅Π½Π° ΠΎΠ΄Ρ€Π΅Ρ’Π΅Π½ΠΈΡ… Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ° којима ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ приступа Ρ‚Π°ΠΊΠΎΡ’Π΅ ΠΌΠΎΠ³Ρƒ Π±ΠΈΡ‚ΠΈ ΠΎΠ΄ користи.

naredni ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ ΡƒΠΏΠΈΡΡƒΡ˜Π΅ Π»ΠΈΠ½ΠΈΡ˜Ρƒ Ρƒ ΠΏΡ€ΠΈΠ²Ρ€Π΅ΠΌΠ΅Π½Ρƒ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΡƒ:

void do_write(int out_fd)
{
    char str[] = "write me to a filen";

    if (sizeof(str) != write(out_fd, str, sizeof(str))){
        perror("write");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    char tmp_filename_template[] = "/tmp/output_fileXXXXXX";

    int out_fd = mkstemp(tmp_filename_template);
    if (out_fd == -1) {
        perror("mkstemp");
        exit(EXIT_FAILURE);
    }

    do_write(out_fd);

    return EXIT_SUCCESS;
}

Π’ΠΎΠΊΠΎΠΌ Π½ΠΎΡ€ΠΌΠ°Π»Π½ΠΎΠ³ ΠΏΠΎΠ·ΠΈΠ²Π° strace Ρ›Π΅ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΠΈ врСдност Π±Ρ€ΠΎΡ˜Π° дСскриптора који јС прослСђСн систСмском ΠΏΠΎΠ·ΠΈΠ²Ρƒ:

$ strace -e trace=write -o write-tmp-file.log ./write-tmp-file
$ cat write-tmp-file.log
write(3, "write me to a filen", 20)  = 20
+++ exited with 0 +++

Π‘Π° заставом -y УслуТни ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ ΠΏΠΎΠΊΠ°Π·ΡƒΡ˜Π΅ ΠΏΡƒΡ‚Π°ΡšΡƒ Π΄ΠΎ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ΅ којој дСскриптор ΠΎΠ΄Π³ΠΎΠ²Π°Ρ€Π°:

$ strace -y -e trace=write -o write-tmp-file.log ./write-tmp-file
$ cat write-tmp-file.log
write(3</tmp/output_fileCf5MyW>, "write me to a filen", 20) = 20
+++ exited with 0 +++

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: ΠŸΡ€Π°Ρ›Π΅ΡšΠ΅ приступа Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠ°ΠΌΠ°

Још јСдна корисна Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π°: ΠΏΡ€ΠΈΠΊΠ°Π·ΡƒΡ˜Π΅ само систСмскС ΠΏΠΎΠ·ΠΈΠ²Π΅ ΠΏΠΎΠ²Π΅Π·Π°Π½Π΅ са ΠΎΠ΄Ρ€Π΅Ρ’Π΅Π½ΠΎΠΌ Π΄Π°Ρ‚ΠΎΡ‚Π΅ΠΊΠΎΠΌ. Π‘Π»Π΅Π΄Π΅Ρ›ΠΈ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ додајС Π»ΠΈΠ½ΠΈΡ˜Ρƒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΡ™Π½ΠΎΡ˜ Π΄Π°Ρ‚ΠΎΡ‚Π΅Ρ†ΠΈ која јС прослСђСна ΠΊΠ°ΠΎ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚:

void do_write(int out_fd)
{
    char str[] = "write me to a filen";

    if (sizeof(str) != write(out_fd, str, sizeof(str))){
        perror("write");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    /*
     * Path will be provided by the first program argument.
     *  */
    const char *path = argv[1];

    /*
     * Open an existing file for writing in append mode.
     *  */
    int out_fd = open(path, O_APPEND | O_WRONLY);
    if (out_fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    do_write(out_fd);

    return EXIT_SUCCESS;
}

ΠŸΠΎΠ΄Ρ€Π°Π·ΡƒΠΌΠ΅Π²Π°Π½ΠΎ strace ΠΏΡ€ΠΈΠΊΠ°Π·ΡƒΡ˜Π΅ ΠΌΠ½ΠΎΠ³ΠΎ Π½Π΅ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΈΡ… ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ˜Π°. Застава -P са Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠΌ ΡƒΠ·Ρ€ΠΎΠΊΡƒΡ˜Π΅ Π΄Π° страцС ΡˆΡ‚Π°ΠΌΠΏΠ° само ΠΏΠΎΠ·ΠΈΠ²Π΅ навСдСној Π΄Π°Ρ‚ΠΎΡ‚Π΅Ρ†ΠΈ:

$ strace -y -P/tmp/test_file.log -o write-file.log ./write-file /tmp/test_file.log
$ cat write-file.log
openat(AT_FDCWD, "/tmp/test_file.log", O_WRONLY|O_APPEND) = 3</tmp/test_file.log>
write(3</tmp/test_file.log>, "write me to a filen", 20) = 20
+++ exited with 0 +++

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈ са вишС Π½ΠΈΡ‚ΠΈ

ΠšΠΎΡ€ΠΈΡΠ½ΠΎΡΡ‚ 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);
}

Наравно, ΠΌΠΎΡ€Π° сС саставити са посСбним ΠΏΠΎΠ·Π΄Ρ€Π°Π²ΠΎΠΌ Π·Π° Π»ΠΈΠ½ΠΊΠ΅Ρ€ - заставицом -ΠΏΡ‚Ρ…Ρ€Π΅Π°Π΄:

$ 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, ΠΊΠ°ΠΎ ΠΈΡƒ ΡΠ»ΡƒΡ‡Π°Ρ˜Ρƒ Ρ€Π΅Π΄ΠΎΠ²Π½ΠΈΡ… процСса, Π΄ΠΎΠ΄Π°Ρ›Π΅ ΠΏΠΈΠ΄ процСса Π½Π° ΠΏΠΎΡ‡Π΅Ρ‚Π°ΠΊ сваког Ρ€Π΅Π΄Π°.

Наравно, Π½Π΅ Π³ΠΎΠ²ΠΎΡ€ΠΈΠΌΠΎ ΠΎ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρƒ Π½ΠΈΡ‚ΠΈ Ρƒ смислу ΠΈΠΌΠΏΠ»Π΅ΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡ˜Π΅ стандарда ПОБИКБ ВхрСадс, Π²Π΅Ρ› ΠΎ Π±Ρ€ΠΎΡ˜Ρƒ који користи ΠΏΠ»Π°Π½Π΅Ρ€ Π·Π°Π΄Π°Ρ‚Π°ΠΊΠ° Ρƒ Π›ΠΈΠ½ΡƒΠΊΡƒ. Π‘Π° Ρ‚Π°Ρ‡ΠΊΠ΅ Π³Π»Π΅Π΄ΠΈΡˆΡ‚Π° послСдњСг, Π½Π΅ ΠΏΠΎΡΡ‚ΠΎΡ˜Π΅ процСси ΠΈΠ»ΠΈ Π½ΠΈΡ‚ΠΈ - ΠΏΠΎΡΡ‚ΠΎΡ˜Π΅ Π·Π°Π΄Π°Ρ†ΠΈ који Ρ‚Ρ€Π΅Π±Π° Π΄Π° сС распорСдС ΠΈΠ·ΠΌΠ΅Ρ’Ρƒ доступних Ρ˜Π΅Π·Π³Π°Ρ€Π° машинС.

Када Ρ€Π°Π΄ΠΈΡ‚Π΅ Ρƒ вишС Π½ΠΈΡ‚ΠΈ, систСмски ΠΏΠΎΠ·ΠΈΠ²ΠΈ ΠΏΠΎΡΡ‚Π°Ρ˜Ρƒ ΠΏΡ€Π΅Π²ΠΈΡˆΠ΅:

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

Има смисла ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΡ‚ΠΈ сС само Π½Π° ΡƒΠΏΡ€Π°Π²Ρ™Π°ΡšΠ΅ процСсима ΠΈ систСмскС ΠΏΠΎΠ·ΠΈΠ²Π΅ write:

$ strace -f -e trace="%process,write" -othread-write.log ./thread-write
$ cat thread-write.log
18211 execve("./thread-write", ["./thread-write"], 0x7ffc6b8d58f0 /* 64 vars */) = 0
18211 arch_prctl(ARCH_SET_FS, 0x7f38ea3b7740) = 0
18211 write(1, "Initial thread: launching a thre"..., 35) = 35
18211 clone(child_stack=0x7f38e9ba2fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f38e9ba39d0, tls=0x7f38e9ba3700, child_tidptr=0x7f38e9ba39d0) = 18212
18211 write(1, "Initial thread: joining a thread"..., 33) = 33
18212 write(1, "Secondary thread: workingn", 26) = 26
18212 write(1, "Secondary thread: donen", 23) = 23
18212 exit(0)                           = ?
18212 +++ exited with 0 +++
18211 write(1, "Initial thread: done", 20) = 20
18211 exit_group(0)                     = ?
18211 +++ exited with 0 +++

Π£Π·Π³Ρ€Π΅Π΄, ΠΏΠΈΡ‚Π°ΡšΠ°. Који систСмски ΠΏΠΎΠ·ΠΈΠ² сС користи Π·Π° ΠΊΡ€Π΅ΠΈΡ€Π°ΡšΠ΅ Π½ΠΎΠ²Π΅ Π½ΠΈΡ‚ΠΈ? Како сС овај ΠΏΠΎΠ·ΠΈΠ² Π·Π° Π½ΠΈΡ‚ΠΈ Ρ€Π°Π·Π»ΠΈΠΊΡƒΡ˜Π΅ ΠΎΠ΄ ΠΏΠΎΠ·ΠΈΠ²Π° Π·Π° процСсС?

ΠœΠ°ΡΡ‚Π΅Ρ€ класа: процСсни стог Ρƒ Π²Ρ€Π΅ΠΌΠ΅ систСмског ΠΏΠΎΠ·ΠΈΠ²Π°

ЈСдан ΠΎΠ΄ Π½Π΅Π΄Π°Π²Π½ΠΎ појавио strace могућности – ΠΏΡ€ΠΈΠΊΠ°Π·ΠΈΠ²Π°ΡšΠ΅ стСка ΠΏΠΎΠ·ΠΈΠ²Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡ˜Π° Ρƒ Π²Ρ€Π΅ΠΌΠ΅ систСмског ΠΏΠΎΠ·ΠΈΠ²Π°. Π‘ΠΈΠΌΠΏΠ»Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€:

void do_write(void)
{
    char str[] = "write me to stdoutn";
    if (sizeof(str) != write(STDOUT_FILENO, str, sizeof(str))){
        perror("write");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    do_write();
    return EXIT_SUCCESS;
}

Наравно, ΠΈΠ·Π»Π°Π· ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° ΠΏΠΎΡΡ‚Π°Ρ˜Π΅ Π²Π΅ΠΎΠΌΠ° ΠΎΠ±ΠΈΠΌΠ°Π½, ΠΈ ΠΏΠΎΡ€Π΅Π΄ заставС -k (ΠΏΡ€ΠΈΠΊΠ°Π· стСка ΠΏΠΎΠ·ΠΈΠ²Π°), ΠΈΠΌΠ° смисла Ρ„ΠΈΠ»Ρ‚Ρ€ΠΈΡ€Π°Ρ‚ΠΈ систСмскС ΠΏΠΎΠ·ΠΈΠ²Π΅ ΠΏΠΎ ΠΈΠΌΠ΅Π½Ρƒ:

$ gcc examples/write-simple.c -o write-simple
$ strace -k -e trace=write -o write-simple.log ./write-simple
write me to stdout
$ cat write-simple.log
write(1, "write me to stdoutn", 20)  = 20
 > /lib/x86_64-linux-gnu/libc-2.27.so(__write+0x14) [0x110154]
 > /home/vkazanov/projects-my/strace-post/write-simple(do_write+0x50) [0x78a]
 > /home/vkazanov/projects-my/strace-post/write-simple(main+0x14) [0x7d1]
 > /lib/x86_64-linux-gnu/libc-2.27.so(__libc_start_main+0xe7) [0x21b97]
 > /home/vkazanov/projects-my/strace-post/write-simple(_start+0x2a) [0x65a]
+++ exited with 0 +++

ΠœΠ°ΡΡ‚Π΅Ρ€ класа: ΡƒΠ±Ρ€ΠΈΠ·Π³Π°Π²Π°ΡšΠ΅ Π³Ρ€Π΅ΡˆΠΊΠ΅

И још јСдна Π½ΠΎΠ²Π° ΠΈ Π²Π΅ΠΎΠΌΠ° корисна карактСристика: ΡƒΠ±Π°Ρ†ΠΈΠ²Π°ΡšΠ΅ Π³Ρ€Π΅ΡˆΠΊΠ΅. Π•Π²ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌ, ΡƒΠΏΠΈΡΡƒΡ˜ΡƒΡ›ΠΈ Π΄Π²Π° Ρ€Π΅Π΄Π° Ρƒ ΠΈΠ·Π»Π°Π·Π½ΠΈ Ρ‚ΠΎΠΊ:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void do_write(const char *str, ssize_t len)
{
    if (len != write(STDOUT_FILENO, str, (size_t)len)){
        perror("write");
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char *argv[])
{
    (void) argc; (void) argv;

    char str1[] = "write me 1n";
    do_write(str1, sizeof(str1));

    char str2[] = "write me 2n";
    do_write(str2, sizeof(str2));

    return EXIT_SUCCESS;
}

Π₯ајдС Π΄Π° ΠΏΡ€Π°Ρ‚ΠΈΠΌΠΎ ΠΎΠ±Π° писања ΠΏΠΎΠ·ΠΈΠ²Π°:

$ gcc examples/write-twice.c -o write-twice
$ ./write-twice
write me 1
write me 2
$ strace -e trace=write -owrite-twice.log ./write-twice
write me 1
write me 2
$ cat write-twice.log
write(1, "write me 1n", 12)          = 12
write(1, "write me 2n", 12)          = 12
+++ exited with 0 +++

Π‘Π°Π΄Π° користимо ΠΈΠ·Ρ€Π°Π· injectΠ΄Π° бистС ΡƒΠ½Π΅Π»ΠΈ Π³Ρ€Π΅ΡˆΠΊΡƒ EBADF Ρƒ свим ΠΏΠΎΠ·ΠΈΠ²ΠΈΠΌΠ° Π·Π° писањС:

$ strace -e trace=write -e inject=write:error=EBADF -owrite-twice.log ./write-twice
$ cat write-twice.log
write(1, "write me 1n", 12)          = -1 EBADF (Bad file descriptor) (INJECTED)
write(3, "write: Bad file descriptorn", 27) = -1 EBADF (Bad file descriptor) (INJECTED)
+++ exited with 1 +++

Π—Π°Π½ΠΈΠΌΡ™ΠΈΠ²ΠΎ јС којС Π³Ρ€Π΅ΡˆΠΊΠ΅ сС Π²Ρ€Π°Ρ›Π°Ρ˜Ρƒ свС ΠΈΠ·Π°Π·ΠΎΠ²ΠΈ write, ΡƒΠΊΡ™ΡƒΡ‡ΡƒΡ˜ΡƒΡ›ΠΈ ΠΏΠΎΠ·ΠΈΠ² скривСн ΠΈΠ·Π° ΠΏΠ΅Ρ€Ρ€ΠΎΡ€-Π°. Има смисла само Π²Ρ€Π°Ρ‚ΠΈΡ‚ΠΈ Π³Ρ€Π΅ΡˆΠΊΡƒ Π·Π° ΠΏΡ€Π²ΠΈ ΠΎΠ΄ ΠΏΠΎΠ·ΠΈΠ²Π°:

$ strace -e trace=write -e inject=write:error=EBADF:when=1 -owrite-twice.log ./write-twice
write: Bad file descriptor
$ cat write-twice.log
write(1, "write me 1n", 12)          = -1 EBADF (Bad file descriptor) (INJECTED)
write(3, "write: Bad file descriptorn", 27) = 27
+++ exited with 1 +++

Или Π΄Ρ€ΡƒΠ³ΠΈ:

$ strace -e trace=write -e inject=write:error=EBADF:when=2 -owrite-twice.log ./write-twice
write me 1
write: Bad file descriptor
$ cat write-twice.log
write(1, "write me 1n", 12)          = 12
write(1, "write me 2n", 12)          = -1 EBADF (Bad file descriptor) (INJECTED)
write(3, "write: Bad file descriptorn", 27) = 27
+++ exited with 1 +++

НијС ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎ навСсти Ρ‚ΠΈΠΏ Π³Ρ€Π΅ΡˆΠΊΠ΅:

$ strace -e trace=write -e fault=write:when=1 -owrite-twice.log ./write-twice
$ cat write-twice.log
write(1, "write me 1n", 12)          = -1 ENOSYS (Function not implemented) (INJECTED)
write(3, "write: Function not implementedn", 32) = 32
+++ exited with 1 +++

Π£ ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΡ˜ΠΈ са Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΎΠ·Π½Π°ΠΊΠ°ΠΌΠ°, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ β€žΠΏΡ€Π΅ΠΊΠΈΠ½ΡƒΡ‚ΠΈβ€œ приступ ΠΎΠ΄Ρ€Π΅Ρ’Π΅Π½ΠΎΡ˜ Π΄Π°Ρ‚ΠΎΡ‚Π΅Ρ†ΠΈ. ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

$ strace -y -P/tmp/test_file.log -e inject=file:error=ENOENT -o write-file.log ./write-file /tmp/test_file.log
open: No such file or directory
$ cat write-file.log
openat(AT_FDCWD, "/tmp/test_file.log", O_WRONLY|O_APPEND) = -1 ENOENT (No such file or directory) (INJECTED)
+++ exited with 1 +++

ΠŸΠΎΡ€Π΅Π΄ ΡƒΠ±Π°Ρ†ΠΈΠ²Π°ΡšΠ° Π³Ρ€Π΅ΡˆΠΊΠ΅, ΠΌΠΎΠΆΠ΅ сС ΡƒΠ²ΠΎΠ΄Π΅ кашњСња ΠΏΡ€ΠΈΠ»ΠΈΠΊΠΎΠΌ позивања ΠΈΠ»ΠΈ ΠΏΡ€ΠΈΡ˜Π΅ΠΌΠ° сигнала.

АфтСрворд

ΠšΠΎΡ€ΠΈΡΠ½ΠΎΡΡ‚ strace - Ρ˜Π΅Π΄Π½ΠΎΡΡ‚Π°Π²Π°Π½ ΠΈ ΠΏΠΎΡƒΠ·Π΄Π°Π½ Π°Π»Π°Ρ‚. Али ΠΏΠΎΡ€Π΅Π΄ систСмских ΠΏΠΎΠ·ΠΈΠ²Π°, ΠΌΠΎΠ³Ρƒ сС ΠΎΡ‚ΠΊΠ»ΠΎΠ½ΠΈΡ‚ΠΈ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈ аспСкти Ρ€Π°Π΄Π° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° ΠΈ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ систСма. На ΠΏΡ€ΠΈΠΌΠ΅Ρ€, ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΏΡ€Π°Ρ‚ΠΈ ΠΏΠΎΠ·ΠΈΠ²Π΅ ΠΊΠ° Π΄ΠΈΠ½Π°ΠΌΠΈΡ‡ΠΊΠΈ ΠΏΠΎΠ²Π΅Π·Π°Π½ΠΈΠΌ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠ°. Π»Ρ‚Ρ€Π°Ρ†Π΅, ΠΌΠΎΠ³Ρƒ Π΄Π° ΠΈΡΠΏΠΈΡ‚Π°Ρ˜Ρƒ Ρ€Π°Π΄ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ систСма БистСмВап ΠΈ Ρ„Ρ‚Ρ€Π°Ρ†Π΅, ΠΈ ΠΎΠΌΠΎΠ³ΡƒΡ›Π°Π²Π° Π²Π°ΠΌ Π΄Π° Π΄ΡƒΠ±ΠΎΠΊΠΎ истраТитС пСрформансС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° ΠΏΠ΅Ρ€Ρ„. Ипак, Ρ˜Π΅ΡΡ‚Π΅ strace - ΠΏΡ€Π²Π° линија ΠΎΠ΄Π±Ρ€Π°Π½Π΅ Ρƒ ΡΠ»ΡƒΡ‡Π°Ρ˜Ρƒ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° са сопствСним ΠΈ Ρ‚ΡƒΡ’ΠΈΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΈΠΌΠ° ΠΈ користим јС Π±Π°Ρ€ ΠΏΠ°Ρ€ ΠΏΡƒΡ‚Π° Π½Π΅Π΄Π΅Ρ™Π½ΠΎ.

Π£ΠΊΡ€Π°Ρ‚ΠΊΠΎ, Π°ΠΊΠΎ Π²ΠΎΠ»ΠΈΡ‚Π΅ Π£Π½ΠΈΠΊ, Ρ‡ΠΈΡ‚Π°Ρ˜Ρ‚Π΅ man 1 strace ΠΈ слободно Π·Π°Π²ΠΈΡ€ΠΈΡ‚Π΅ Ρƒ својС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ΅!

Π˜Π·Π²ΠΎΡ€: Π²Π²Π².Ρ…Π°Π±Ρ€.Ρ†ΠΎΠΌ

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