рд▓рд┐рдирдХреНрд╕рдордзреНрдпреЗ рд╕реНрдЯреНрд░реЗрд╕: тАЛтАЛрдЗрддрд┐рд╣рд╛рд╕, рдбрд┐рдЭрд╛рдЗрди рдЖрдгрд┐ рд╡рд╛рдкрд░

рд▓рд┐рдирдХреНрд╕рдордзреНрдпреЗ рд╕реНрдЯреНрд░реЗрд╕: тАЛтАЛрдЗрддрд┐рд╣рд╛рд╕, рдбрд┐рдЭрд╛рдЗрди рдЖрдгрд┐ рд╡рд╛рдкрд░

рдпреБрдирд┐рдХреНрд╕ рд╕рд╛рд░рдЦреНрдпрд╛ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯреАрдордордзреНрдпреЗ, рдкреНрд░реЛрдЧреНрд░рд╛рдордЪрд╛ рдмрд╛рд╣реНрдп рдЬрдЧрд╛рд╢реА рдЖрдгрд┐ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯреАрдорд╢реА рд╕рдВрдкреНрд░реЗрд╖рдг рдлрдВрдХреНрд╢рдиреНрд╕рдЪреНрдпрд╛ рдЫреЛрдЯреНрдпрд╛ рд╕реЗрдЯрджреНрд╡рд╛рд░реЗ рд╣реЛрддреЗ - рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓. рдпрд╛рдЪрд╛ рдЕрд░реНрде рдбреАрдмрдЧрд┐рдВрдЧрдЪреНрдпрд╛ рдЙрджреНрджреЗрд╢рд╛рдиреЗ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдВрджреНрд╡рд╛рд░реЗ рдЪрд╛рд▓рд╡рд▓реНрдпрд╛ рдЬрд╛рдгрд╛рд▒реНрдпрд╛ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓рдЪреА рд╣реЗрд░рдЧрд┐рд░реА рдХрд░рдгреЗ рдЙрдкрдпреБрдХреНрдд рдард░реВ рд╢рдХрддреЗ.

рдпреБрдЯрд┐рд▓рд┐рдЯреА рддреБрдореНрд╣рд╛рд▓рд╛ рд▓рд┐рдирдХреНрд╕рд╡рд░реАрд▓ рдкреНрд░реЛрдЧреНрд░рд╛рдореНрд╕рдЪреНрдпрд╛ "рдЗрдВрдЯрд┐рдореЗрдЯ рд▓рд╛рдИрдл" рдЪреЗ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░рдгреНрдпрд╛рдд рдорджрдд рдХрд░рддреЗ strace, рдЬреЛ рдпрд╛ рд▓реЗрдЦрд╛рдЪрд╛ рд╡рд┐рд╖рдп рдЖрд╣реЗ. рдЧреБрдкреНрддрд╣реЗрд░ рдЙрдкрдХрд░рдгрд╛рдВрдЪреНрдпрд╛ рд╡рд╛рдкрд░рд╛рдЪреА рдЙрджрд╛рд╣рд░рдгреЗ рдереЛрдбрдХреНрдпрд╛рдд рдЗрддрд┐рд╣рд╛рд╕рд╛рд╕рд╣ рдЖрд╣реЗрдд strace рдЖрдгрд┐ рдЕрд╢рд╛ рдХрд╛рд░реНрдпрдХреНрд░рдорд╛рдВрдЪреНрдпрд╛ рдбрд┐рдЭрд╛рдЗрдирдЪреЗ рд╡рд░реНрдгрди.

рд╕рд╛рдордЧреНрд░реА

рдкреНрд░рдЬрд╛рддреАрдВрдЪреЗ рдореВрд│

рдпреБрдирд┐рдХреНрд╕рдордзреАрд▓ рдкреНрд░реЛрдЧреНрд░рд╛рдореНрд╕ рдЖрдгрд┐ рдУрдПрд╕ рдХрд░реНрдирд▓рдордзреАрд▓ рдореБрдЦреНрдп рдЗрдВрдЯрд░рдлреЗрд╕ рдореНрд╣рдгрдЬреЗ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓. рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓, syscalls), рдмрд╛рд╣реНрдп рдЬрдЧрд╛рд╕рд╣ рдХрд╛рд░реНрдпрдХреНрд░рдорд╛рдВрдЪрд╛ рдкрд░рд╕реНрдкрд░рд╕рдВрд╡рд╛рдж рдХреЗрд╡рд│ рддреНрдпрд╛рдВрдЪреНрдпрд╛рджреНрд╡рд╛рд░реЗрдЪ рд╣реЛрддреЛ.

рдкрд░рдВрддреБ рдпреБрдирд┐рдХреНрд╕рдЪреНрдпрд╛ рдкрд╣рд┐рд▓реНрдпрд╛ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдЖрд╡реГрддреНрддреАрдордзреНрдпреЗ (рдЖрд╡реГрддреНрддреА 6 Unix, 1975) рд╡рд╛рдкрд░рдХрд░реНрддрд╛ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдВрдЪреНрдпрд╛ рд╡рд░реНрддрдирд╛рдЪрд╛ рдорд╛рдЧреЛрд╡рд╛ рдШреЗрдгреНрдпрд╛рд╕рд╛рдареА рдХреЛрдгрддреЗрд╣реА рд╕реЛрдпреАрд╕реНрдХрд░ рдорд╛рд░реНрдЧ рдирд╡реНрд╣рддреЗ. рдпрд╛ рд╕рдорд╕реНрдпреЗрдЪреЗ рдирд┐рд░рд╛рдХрд░рдг рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА, рдмреЗрд▓ рд▓реЕрдм рдкреБрдвреАрд▓ рдЖрд╡реГрддреНрддреАрд╡рд░ рдЕрджреНрдпрддрдирд┐рдд рдХрд░рддреАрд▓ (рдЖрд╡реГрддреНрддреА 7 Unix, 1979) рдПрдХ рдирд╡реАрди рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд - ptrace.

ptrace рд╣реЗ рдкреНрд░рд╛рдореБрдЦреНрдпрд╛рдиреЗ рдкрд░рд╕реНрдкрд░ рдбреАрдмрдЧрд░рд╕рд╛рдареА рд╡рд┐рдХрд╕рд┐рдд рдХреЗрд▓реЗ рдЧреЗрд▓реЗ рд╣реЛрддреЗ, рдкрд░рдВрддреБ 80 рдЪреНрдпрд╛ рджрд╢рдХрд╛рдЪреНрдпрд╛ рд╢реЗрд╡рдЯреА (рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рдпреБрдЧрд╛рдд рд╕рд┐рд╕реНрдЯрдо V рдкреНрд░рдХрд╛рд╢рди 4) рдпрд╛ рдЖрдзрд╛рд░рд╛рд╡рд░, рд╕рдВрдХреБрдЪрд┐рддрдкрдгреЗ рдлреЛрдХрд╕ рдХреЗрд▓реЗрд▓реЗ рдбреАрдмрдЧрд░тАФрд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдЯреНрд░реЗрд╕рд░реНрд╕тАФрджрд┐рд╕рд▓реЗ рдЖрдгрд┐ рдореЛрдареНрдпрд╛ рдкреНрд░рдорд╛рдгрд╛рд╡рд░ рд╡рд╛рдкрд░рд▓реЗ рдЬрд╛рдК рд▓рд╛рдЧрд▓реЗ.

рдкрд╣рд┐рд▓рд╛ рд╕реНрдЯреНрд░реЗрд╕рдЪреА рддреАрдЪ рдЖрд╡реГрддреНрддреА рдкреЙрд▓ рдХреНрд░реЛрдирдирдмрд░реНрдЧ рдпрд╛рдВрдиреА 1992 рдордзреНрдпреЗ comp.sources.sun рдореЗрд▓рд┐рдВрдЧ рд▓рд┐рд╕реНрдЯрд╡рд░ рдмрдВрдж рдпреБрдЯрд┐рд▓рд┐рдЯреАрд▓рд╛ рдкрд░реНрдпрд╛рдп рдореНрд╣рдгреВрди рдкреНрд░рдХрд╛рд╢рд┐рдд рдХреЗрд▓реА рд╣реЛрддреА. trace рд╕реВрд░реНрдп рдкрд╛рд╕реВрди. рдХреНрд▓реЛрди рдЖрдгрд┐ рдореВрд│ рджреЛрдиреНрд╣реА SunOS рд╕рд╛рдареА рд╣реЛрддреЗ, рдкрд░рдВрддреБ 1994 рдкрд░реНрдпрдВрдд strace рд╕рд┐рд╕реНрдЯрдо V, рд╕реЛрд▓рд╛рд░рд┐рд╕ рдЖрдгрд┐ рд╡рд╛рдврддреНрдпрд╛ рд▓реЛрдХрдкреНрд░рд┐рдп рд▓рд┐рдирдХреНрд╕рд╡рд░ рдкреЛрд░реНрдЯ рдХреЗрд▓реЗ рдЧреЗрд▓реЗ.

рдЖрдЬ рд╕реНрдЯреНрд░реЗрд╕ рдлрдХреНрдд рд▓рд┐рдирдХреНрд╕рдЪреЗ рд╕рдорд░реНрдерди рдХрд░рддреЗ рдЖрдгрд┐ рддреНрдпрд╛рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдЖрд╣реЗ ptrace, рдЕрдиреЗрдХ рд╡рд┐рд╕реНрддрд╛рд░рд╛рдВрд╕рд╣ рдЕрддрд┐рд╡реГрджреНрдз.

рдЖрдзреБрдирд┐рдХ (рдЖрдгрд┐ рдЕрддрд┐рд╢рдп рд╕рдХреНрд░рд┐рдп) рджреЗрдЦрднрд╛рд▓рдХрд░реНрддрд╛ strace - рджрд┐рдорд┐рддреНрд░реА рд▓реЗрд╡реНрд╣рд┐рди. рддреНрдпрд╛рд▓рд╛ рдзрдиреНрдпрд╡рд╛рдж, рдпреБрдЯрд┐рд▓рд┐рдЯреАрдиреЗ рдкреНрд░рдЧрдд рд╡реИрд╢рд┐рд╖реНрдЯреНрдпреЗ рдкреНрд░рд╛рдкреНрдд рдХреЗрд▓реА рдЬрд╕реЗ рдХреА рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓рдордзреНрдпреЗ рддреНрд░реБрдЯреА рдЗрдВрдЬреЗрдХреНрд╢рди, рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░рдЪреНрдпрд╛ рд╡рд┐рд╕реНрддреГрдд рд╢реНрд░реЗрдгреАрд╕рд╛рдареА рд╕рдорд░реНрдерди рдЖрдгрд┐ рд╕рд░реНрд╡рд╛рдд рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ рдореНрд╣рдгрдЬреЗ, рд╢реБрднрдВрдХрд░. рдЕрдирдзрд┐рдХреГрдд рд╕реНрддреНрд░реЛрддрд╛рдВрдЪрд╛ рдЕрд╕рд╛ рджрд╛рд╡рд╛ рдЖрд╣реЗ рдХреА рд░рд╢рд┐рдпрди рд╢рдмреНрдж "рд╢реБрддреБрд░рдореБрд░реНрдЧ" рдЖрдгрд┐ рдЗрдВрдЧреНрд░рдЬреА рд╢рдмреНрдж "рд╕реНрдЯреНрд░реЗрд╕" рдпрд╛рдВрдЪреНрдпрд╛рддреАрд▓ рдПрдХрд╕рдВрдзрддреЗрдореБрд│реЗ рдирд┐рд╡рдб рд╢рд╣рд╛рдореГрдЧрд╛рд╡рд░ рдкрдбрд▓реА.

рд╣реЗ рджреЗрдЦреАрд▓ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ рдЖрд╣реЗ рдХреА рд▓рд┐рдирдХреНрд╕, рдлреНрд░реАрдмреАрдПрд╕рдбреА, рдУрдкрдирдмреАрдПрд╕рдбреА рдЖрдгрд┐ рдкрд╛рд░рдВрдкрд╛рд░рд┐рдХ рдпреБрдирд┐рдХреНрд╕рдордзреНрдпреЗ рджреАрд░реНрдШ рдЗрддрд┐рд╣рд╛рд╕ рдЖрдгрд┐ рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреА рдЕрд╕реВрдирд╣реА, ptrace рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдЖрдгрд┐ рдЯреНрд░реЗрд╕рд░реНрд╕ рдХрдзреАрд╣реА POSIX рдордзреНрдпреЗ рд╕рдорд╛рд╡рд┐рд╖реНрдЯ рдХреЗрд▓реЗ рдЧреЗрд▓реЗ рдирд╛рд╣реАрдд.

рд╕реНрдЯреНрд░реЗрд╕ рдбрд┐рд╡реНрд╣рд╛рдЗрд╕ рдереЛрдбрдХреНрдпрд╛рдд: рдкрд┐рдЧрд▓реЗрдЯ рдЯреНрд░реЗрд╕

"рддреБрдореНрд╣реА рд╣реЗ рд╕рдордЬреВрди рдШреЗрдгреЗ рдЕрдкреЗрдХреНрд╖рд┐рдд рдирд╛рд╣реА" (рдбреЗрдирд┐рд╕ рд░рд┐рдЪреА, рдЖрд╡реГрддреНрддреА 6 рдпреБрдирд┐рдХреНрд╕ рд╕реНрддреНрд░реЛрдд рдХреЛрдбрдордзреАрд▓ рдЯрд┐рдкреНрдкрдгреА)

рд▓рд╣рд╛рдирдкрдгрд╛рдкрд╛рд╕реВрдирдЪ, рдореА рдмреНрд▓реЕрдХ рдмреЙрдХреНрд╕ рдЙрднреЗ рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реА: рдореА рдЦреЗрд│рдгреНрдпрд╛рдВрд╢реА рдЦреЗрд│рд▓реЛ рдирд╛рд╣реА, рдкрд░рдВрддреБ рддреНрдпрд╛рдВрдЪреА рд░рдЪрдирд╛ рд╕рдордЬреВрди рдШреЗрдгреНрдпрд╛рдЪрд╛ рдкреНрд░рдпрддреНрди рдХреЗрд▓рд╛ (рдкреНрд░реМрдврд╛рдВрдиреА "рдмреНрд░реЗрдХ" рд╣рд╛ рд╢рдмреНрдж рд╡рд╛рдкрд░рд▓рд╛, рдкрд░рдВрддреБ рд╡рд╛рдИрдЯ рднрд╛рд╖рд╛рдВрд╡рд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡реВ рдирдХрд╛). рдХрджрд╛рдЪрд┐рдд рдореНрд╣рдгреВрдирдЪ рдкрд╣рд┐рд▓реНрдпрд╛ рдпреБрдирд┐рдХреНрд╕рдЪреА рдЕрдиреМрдкрдЪрд╛рд░рд┐рдХ рд╕рдВрд╕реНрдХреГрддреА рдЖрдгрд┐ рдЖрдзреБрдирд┐рдХ рдореБрдХреНрдд-рд╕реНрд░реЛрдд рдЪрд│рд╡рд│ рдорд╛рдЭреНрдпрд╛ рдЦреВрдк рдЬрд╡рд│ рдЖрд╣реЗ.

рдпрд╛ рд▓реЗрдЦрд╛рдЪреНрдпрд╛ рд╣реЗрддреВрдВрд╕рд╛рдареА, рд╕реНрдЯреНрд░реЗрд╕рдЪреНрдпрд╛ рд╕реНрддреНрд░реЛрдд рдХреЛрдбрдЪреЗ рдкреГрдердХреНрдХрд░рдг рдХрд░рдгреЗ рдЕрд╡рд╛рд╕реНрддрд╡ рдЖрд╣реЗ, рдЬреЗ рдЕрдиреЗрдХ рджрд╢рдХрд╛рдВрдкрд╛рд╕реВрди рд╡рд╛рдврд▓реЗ рдЖрд╣реЗ. рдкрд░рдВрддреБ рд╡рд╛рдЪрдХрд╛рдВрд╕рд╛рдареА рдХреЛрдгрддреЗрд╣реА рд░рд╣рд╕реНрдп рд╕реЛрдбреВ рдирдпреЗ. рдореНрд╣рдгреВрди, рдЕрд╢рд╛ рд╕реНрдЯреНрд░реЗрд╕ рдкреНрд░реЛрдЧреНрд░рд╛рдордЪреНрдпрд╛ рдСрдкрд░реЗрд╢рдирдЪреЗ рд╕рд┐рджреНрдзрд╛рдВрдд рджрд░реНрд╢рд╡рд┐рдгреНрдпрд╛рд╕рд╛рдареА, рдореА рд▓рдШреБ рдЯреНрд░реЗрд╕рд░рд╕рд╛рдареА рдХреЛрдб рдкреНрд░рджрд╛рди рдХрд░реЗрди - рдкрд┐рдЧрд▓реЗрдЯ рдЯреНрд░реЗрд╕ (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

рдкрд┐рдЧрд▓реЗрдЯ рдЯреНрд░реЗрд╕ рд╕реБрдорд╛рд░реЗ рд╢реЗрдХрдбреЛ рд▓рд┐рдирдХреНрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдУрд│рдЦрддреЗ (рдкрд╣рд╛. рдЯреЗрдмрд▓) рдЖрдгрд┐ рдлрдХреНрдд x86-64 рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░рд╡рд░ рдХрд╛рд░реНрдп рдХрд░рддреЗ. рд╢реИрдХреНрд╖рдгрд┐рдХ рд╣реЗрддреВрдВрд╕рд╛рдареА рд╣реЗ рдкреБрд░реЗрд╕реЗ рдЖрд╣реЗ.

рдЪрд▓рд╛ рдЖрдордЪреНрдпрд╛ рдХреНрд▓реЛрдирдЪреЗ рдХрд╛рдо рдкрд╛рд╣реВ. рд▓рд┐рдирдХреНрд╕рдЪреНрдпрд╛ рдмрд╛рдмрддреАрдд, рдбреАрдмрдЧрд░ рдЖрдгрд┐ рдЯреНрд░реЗрд╕рд░реНрд╕ рд╡рд░ рдирдореВрдж рдХреЗрд▓реНрдпрд╛рдкреНрд░рдорд╛рдгреЗ, ptrace рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рд╡рд╛рдкрд░рддрд╛рдд. рд╣реЗ рдкрд╣рд┐рд▓реНрдпрд╛ рдпреБрдХреНрддрд┐рд╡рд╛рджрд╛рдд рдХрдорд╛рдВрдб рдЖрдпрдбреЗрдВрдЯрд┐рдлрд╛рдпрд░ рдкрд╛рд╕ рдХрд░реВрди рдХрд╛рд░реНрдп рдХрд░рддреЗ, рдЬреНрдпрд╛рдЪреА рдЖрдкрд▓реНрдпрд╛рд▓рд╛ рдлрдХреНрдд рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЖрд╣реЗ 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 рдЖрдгрд┐ рдЖрдореНрд╣рд╛рд▓рд╛ рд╕реНрд╡рд╛рд░рд╕реНрдп рдирд╕рд▓реЗрд▓реНрдпрд╛ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓рдЪреА рд╡рд┐рдкреБрд▓рддрд╛.

рддреБрдореНрд╣реА -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 рдпреБрдирд┐рдХреНрд╕рдЪреНрдпрд╛ рджрд┐рд╡рд╕рд╛рдВрдордзреНрдпреЗ рд╣реА рдорд░реНрдпрд╛рджрд╛ рд╡рд╛рдЬрд╡реА рд╡рд╛рдЯрд▓реА рдЕрд╕реЗрд▓. рдЖрдЬрдХрд╛рд▓, рд╣реЗ рдпрд╛рдкреБрдвреЗ рдкреБрд░реЗрд╕реЗ рдирд╛рд╣реА: рдХрдзреАрдХрдзреА рдЖрдкрд▓реНрдпрд╛рд▓рд╛ рдХрд╛рд░реНрдпрд░рдд рдкреНрд░реЛрдЧреНрд░рд╛рдордЪреНрдпрд╛ рд╕рдорд╕реНрдпрд╛рдВрдЪреА рддрдкрд╛рд╕рдгреА рдХрд░рдгреНрдпрд╛рдЪреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдЕрд╕рддреЗ. рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдЙрджрд╛рд╣рд░рдг рдореНрд╣рдгрдЬреЗ рд╣рдБрдбрд▓ рдХрд┐рдВрд╡рд╛ рд╕реНрд▓реАрдкрд┐рдВрдЧрд╡рд░ рдЕрд╡рд░реЛрдзрд┐рдд рдХреЗрд▓реЗрд▓реА рдкреНрд░рдХреНрд░рд┐рдпрд╛. рддреНрдпрд╛рдореБрд│реЗ рдЖрдзреБрдирд┐рдХ strace рдлреНрд▓рд╛рдпрд╡рд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдВрдордзреНрдпреЗ рд╕рд╛рдореАрд▓ рд╣реЛрдК рд╢рдХрддрд╛рдд.

рдЕрддрд┐рд╢реАрдд рдЙрджрд╛рд╣рд░рдг рдХрд╛рд░реНрдпрдХреНрд░рдо:

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

    char str[] = "write men";

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

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

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

    return EXIT_SUCCESS;
}

рдЪрд▓рд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдо рддрдпрд╛рд░ рдХрд░реВ рдЖрдгрд┐ рддреЗ рдЧреЛрдард▓реЗрд▓реЗ рдЕрд╕рд▓реНрдпрд╛рдЪреА рдЦрд╛рддреНрд░реА рдХрд░рд╛:

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

рдЖрддрд╛ рддреНрдпрд╛рдд рд╕рд╛рдореАрд▓ рд╣реЛрдгреНрдпрд╛рдЪрд╛ рдкреНрд░рдпрддреНрди рдХрд░реВрдпрд╛:

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

рдХреЙрд▓рджреНрд╡рд╛рд░реЗ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдЕрд╡рд░реЛрдзрд┐рдд рдХреЗрд▓рд╛ pause. рддреА рд╕рд┐рдЧреНрдирд▓реНрд╕рд╡рд░ рдХрд╢реА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рджреЗрддреЗ рддреЗ рдкрд╛рд╣реВрдпрд╛:

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

рдЖрдореНрд╣реА рдлреНрд░реЛрдЭрди рдкреНрд░реЛрдЧреНрд░рд╛рдо рд▓рд╛рдБрдЪ рдХреЗрд▓рд╛ рдЖрдгрд┐ рддреНрдпрд╛рдЪрд╛ рд╡рд╛рдкрд░ рдХрд░реВрди рд╕рд╛рдореАрд▓ рдЭрд╛рд▓реЛ strace. рджреЛрди рдЧреЛрд╖реНрдЯреА рд╕реНрдкрд╖реНрдЯ рдЭрд╛рд▓реНрдпрд╛: рдкреЙрдЬ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рд╣рдБрдбрд▓рд░реНрд╕рд╢рд┐рд╡рд╛рдп рд╕рд┐рдЧреНрдирд▓рдХрдбреЗ рджреБрд░реНрд▓рдХреНрд╖ рдХрд░рддреЗ рдЖрдгрд┐ рд╡рд┐рд╢реЗрд╖ рдореНрд╣рдгрдЬреЗ, рд╕реНрдЯреНрд░реЗрд╕ рдореЙрдирд┐рдЯрд░реНрд╕ рдХреЗрд╡рд│ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓рдЪ рдирд╡реНрд╣реЗ рддрд░ рдпреЗрдгрд╛рд░реЗ рд╕рд┐рдЧреНрдирд▓ рджреЗрдЦреАрд▓.

рдЙрджрд╛рд╣рд░рдг: рдмрд╛рд▓ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдВрдЪрд╛ рдорд╛рдЧреЛрд╡рд╛ рдШреЗрдгреЗ

рдХреЙрд▓рджреНрд╡рд╛рд░реЗ рдкреНрд░рдХреНрд░рд┐рдпрд╛рдВрд╕рд╣ рдХрд╛рд░реНрдп рдХрд░рдгреЗ fork - рд╕рд░реНрд╡ рдпреБрдирд┐рдХреНрд╕рдЪрд╛ рдЖрдзрд╛рд░. рд╕реЛрдкреНрдпрд╛ "рдкреНрд░рдЬрдирди" рдЪреЗ рдЙрджрд╛рд╣рд░рдг рд╡рд╛рдкрд░реВрди рд╕реНрдЯреНрд░реЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЭрд╛рдбрд╛рд╕рд╣ рдХрд╕реЗ рдХрд╛рд░реНрдп рдХрд░рддреЗ рддреЗ рдкрд╛рд╣реВрдпрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо:

int main(int argc, char *argv[])
{
    pid_t parent_pid = getpid();
    pid_t child_pid = fork();
    if (child_pid == 0) {
        /* A child is born! */
        child_pid = getpid();

        /* In the end of the day printf is just a call to write(2). */
        printf("child (self=%d)n", child_pid);
        exit(EXIT_SUCCESS);
    }

    printf("parent (self=%d, child=%d)n", parent_pid, child_pid);

    wait(NULL);

    exit(EXIT_SUCCESS);
}

рдпреЗрдереЗ рдореВрд│ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореВрд▓ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рддрдпрд╛рд░ рдХрд░рддреЗ, рджреЛрдиреНрд╣реА рдорд╛рдирдХ рдЖрдЙрдЯрдкреБрдЯрд╡рд░ рд▓рд┐рд╣рд┐рддреЗ:

$ gcc examples/fork-write.c -o fork-write
$ ./fork-write
parent (self=11274, child=11275)
child (self=11275)

рдбреАрдлреЙрд▓реНрдЯрдиреБрд╕рд╛рд░, рдЖрдореНрд╣реА рдлрдХреНрдд рдкрд╛рд▓рдХ рдкреНрд░рдХреНрд░рд┐рдпреЗрддреАрд▓ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдкрд╛рд╣реВ:

$ strace -e trace=write -ofork-write.log ./fork-write
child (self=22049)
parent (self=22048, child=22049)
$ cat fork-write.log
write(1, "parent (self=22048, child=22049)"..., 33) = 33
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22049, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

рдзреНрд╡рдЬ рддреБрдореНрд╣рд╛рд▓рд╛ рд╕рдВрдкреВрд░реНрдг рдкреНрд░рдХреНрд░рд┐рдпреЗрдЪреНрдпрд╛ рдЭрд╛рдбрд╛рдЪрд╛ рдорд╛рдЧреЛрд╡рд╛ рдШреЗрдгреНрдпрд╛рд╕ рдорджрдд рдХрд░рддреЛ -f, рдЬреЗ strace рдЪрд╛рдЗрд▓реНрдб рдкреНрд░реЛрд╕реЗрд╕рдордзреНрдпреЗ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓реНрд╕рдЪреЗ рдирд┐рд░реАрдХреНрд╖рдг рдХрд░рддреЗ. рд╣реЗ рдЖрдЙрдЯрдкреБрдЯрдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рдУрд│реАрдд рдЬреЛрдбрддреЗ pid рд╕рд┐рд╕реНрдЯрдо рдЖрдЙрдЯрдкреБрдЯ рдмрдирд╡рдгрд╛рд░реА рдкреНрд░рдХреНрд░рд┐рдпрд╛:

$ strace -f -e trace=write -ofork-write.log ./fork-write
parent (self=22710, child=22711)
child (self=22711)
$ cat fork-write.log
22710 write(1, "parent (self=22710, child=22711)"..., 33) = 33
22711 write(1, "child (self=22711)n", 19) = 19
22711 +++ exited with 0 +++
22710 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22711, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
22710 +++ exited with 0 +++

рдпрд╛ рд╕рдВрджрд░реНрднрд╛рдд, рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓рдЪреНрдпрд╛ рдЧрдЯрд╛рдиреБрд╕рд╛рд░ рдлрд┐рд▓реНрдЯрд░ рдХрд░рдгреЗ рдЙрдкрдпреБрдХреНрдд рдард░реВ рд╢рдХрддреЗ:

$ strace -f -e trace=%process -ofork-write.log ./fork-write
parent (self=23610, child=23611)
child (self=23611)
$ cat fork-write.log
23610 execve("./fork-write", ["./fork-write"], 0x7fff696ff720 /* 63 vars */) = 0
23610 arch_prctl(ARCH_SET_FS, 0x7f3d03ba44c0) = 0
23610 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f3d03ba4790) = 23611
23610 wait4(-1,  <unfinished ...>
23611 exit_group(0)                     = ?
23611 +++ exited with 0 +++
23610 <... wait4 resumed> NULL, 0, NULL) = 23611
23610 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=23611, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
23610 exit_group(0)                     = ?
23610 +++ exited with 0 +++

рддрд╕реЗ, рдирд╡реАрди рдкреНрд░рдХреНрд░рд┐рдпрд╛ рддрдпрд╛рд░ рдХрд░рдгреНрдпрд╛рд╕рд╛рдареА рдХреЛрдгрддрд╛ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рд╡рд╛рдкрд░рд▓рд╛ рдЬрд╛рддреЛ?

рдЙрджрд╛рд╣рд░рдг: рд╣рдБрдбрд▓рдРрд╡рдЬреА рдлрд╛рдЗрд▓ рдкрде

рдлрд╛рдЗрд▓ рдбрд┐рд╕реНрдХреНрд░рд┐рдкреНрдЯрд░реНрд╕ рдЬрд╛рдгреВрди рдШреЗрдгреЗ рдирдХреНрдХреАрдЪ рдЙрдкрдпреБрдХреНрдд рдЖрд╣реЗ, рдкрд░рдВрддреБ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдЬреНрдпрд╛ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдлрд╛рдЗрд▓реНрд╕рдордзреНрдпреЗ рдкреНрд░рд╡реЗрд╢ рдХрд░рддреЛ рддреНрдпрд╛рдВрдЪреА рдирд╛рд╡реЗ рджреЗрдЦреАрд▓ рдЙрдкрдпреБрдХреНрдд рдард░реВ рд╢рдХрддрд╛рдд.

рдкреБрдвреАрд▓ рдХрд╛рд░реНрдпрдХреНрд░рдо рддрд╛рддреНрдкреБрд░рддреНрдпрд╛ рдлрд╛рдЗрд▓рд╡рд░ рдУрд│ тАЛтАЛрд▓рд┐рд╣рд┐рддреЛ:

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

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

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

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

    do_write(out_fd);

    return EXIT_SUCCESS;
}

рд╕рд╛рдорд╛рдиреНрдп рдХреЙрд▓ рджрд░рдореНрдпрд╛рди strace рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓рд╡рд░ рдкрд╛рд╕ рдХреЗрд▓реЗрд▓реНрдпрд╛ рд╡рд░реНрдгрдирдХ рдХреНрд░рдорд╛рдВрдХрд╛рдЪреЗ рдореВрд▓реНрдп рджрд░реНрд╢рд╡реЗрд▓:

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

рдзреНрд╡рдЬрд╛рд╕рд╣ -y рдпреБрдЯрд┐рд▓рд┐рдЯреА рдлрд╛рдИрд▓рдЪрд╛ рдорд╛рд░реНрдЧ рджрд╛рдЦрд╡рддреЗ рдЬреНрдпрд╛рд╢реА рд╡рд░реНрдгрдирдХрд░реНрддрд╛ рд╕рдВрдмрдВрдзрд┐рдд рдЖрд╣реЗ:

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

рдЙрджрд╛рд╣рд░рдг: рдлрд╛рдЗрд▓ рдНрдХреНрд╕реЗрд╕ рдЯреНрд░реЕрдХрд┐рдВрдЧ

рдЖрдгрдЦреА рдПрдХ рдЙрдкрдпреБрдХреНрдд рд╡реИрд╢рд┐рд╖реНрдЯреНрдп: рд╡рд┐рд╢рд┐рд╖реНрдЯ рдлрд╛рдЗрд▓рд╢реА рд╕рдВрдмрдВрдзрд┐рдд рдлрдХреНрдд рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рд╛. рдкреБрдвреЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рд╡рд┐рддрд░реНрдХ рдореНрд╣рдгреВрди рдкрд╛рд╕ рдХреЗрд▓реЗрд▓реНрдпрд╛ рдЕрдирд┐рдпрдВрддреНрд░рд┐рдд рдлрд╛рдЗрд▓рдордзреНрдпреЗ рдПрдХ рдУрд│ рдЬреЛрдбрддреЗ:

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

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

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

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

    do_write(out_fd);

    return EXIT_SUCCESS;
}

рдореБрд▓рднреВрддрд░рд┐рддреНрдпрд╛ strace рднрд░рдкреВрд░ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдорд╛рд╣рд┐рддреА рджрд╛рдЦрд╡рддреЗ. рдЭреЗрдВрдбрд╛ -P рдпреБрдХреНрддрд┐рд╡рд╛рджрд╛рдиреЗ рд╕реНрдЯреНрд░реЗрд╕ рдХреЗрд╡рд│ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреЗрд▓реЗрд▓реНрдпрд╛ рдлрд╛рдЗрд▓рд╡рд░ рдХреЙрд▓ рдкреНрд░рд┐рдВрдЯ рдХрд░рдгреНрдпрд╛рд╕ рдХрд╛рд░рдгреАрднреВрдд рдард░рддреЗ:

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

рдЙрджрд╛рд╣рд░рдг: рдорд▓реНрдЯреАрдереНрд░реЗрдбреЗрдб рдкреНрд░реЛрдЧреНрд░рд╛рдореНрд╕

рдЙрдкрдпреБрдХреНрддрддрд╛ 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 рдереНрд░реЗрдбреНрд╕ рдорд╛рдирдХрд╛рдВрдЪреНрдпрд╛ рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреАрдЪреНрдпрд╛ рдЕрд░реНрдерд╛рдиреЗ рдереНрд░реЗрдб рдЖрдпрдбреЗрдВрдЯрд┐рдлрд╛рдпрд░рдмрджреНрджрд▓ рдмреЛрд▓рдд рдирд╛рд╣реА, рдкрд░рдВрддреБ рд▓рд┐рдирдХреНрд╕рдордзреАрд▓ рдЯрд╛рд╕реНрдХ рд╢реЗрдбреНрдпреВрд▓рд░рджреНрд╡рд╛рд░реЗ рд╡рд╛рдкрд░рд▓реЗрд▓реНрдпрд╛ рд╕рдВрдЦреНрдпреЗрдмрджреНрджрд▓ рдмреЛрд▓рдд рдЖрд╣реЛрдд. рдирдВрддрд░рдЪреНрдпрд╛ рджреГрд╖реНрдЯрд┐рдХреЛрдирд╛рддреВрди, рдХреЛрдгрддреАрд╣реА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд┐рдВрд╡рд╛ рдереНрд░реЗрдб рдирд╛рд╣реАрдд - рдЕрд╢реА рдХрд╛рд░реНрдпреЗ рдЖрд╣реЗрдд рдЬреА рдорд╢реАрдирдЪреНрдпрд╛ рдЙрдкрд▓рдмреНрдз рдХреЛрд░рдордзреНрдпреЗ рд╡рд┐рддрд░рд┐рдд рдХрд░рдгреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ.

рдПрдХрд╛рдзрд┐рдХ рдереНрд░реЗрдбреНрд╕рдордзреНрдпреЗ рдХрд╛рдо рдХрд░рддрд╛рдирд╛, рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдЦреВрдк рдЬрд╛рд╕реНрдд рд╣реЛрддрд╛рдд:

$ 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, рддреЗ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдордЪреНрдпрд╛ рдСрдкрд░реЗрд╢рдирдХрдбреЗ рд▓рдХреНрд╖ рджреЗрдК рд╢рдХрддрд╛рдд рд╕рд┐рд╕реНрдЯрдордЯреЕрдк ╨╕ ftrace, рдЖрдгрд┐ рддреБрдореНрд╣рд╛рд▓рд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХрд╛рд░реНрдпрдкреНрд░рджрд░реНрд╢рдирд╛рдЪреА рд╕рдЦреЛрд▓ рдЪреМрдХрд╢реА рдХрд░рдгреНрдпрд╛рд╕ рдЕрдиреБрдорддреА рджреЗрддреЗ рдкрд░рдл. рдЕрд╕реЗ рдЕрд╕рд▓реЗ рддрд░реА, рддреЗ рдЖрд╣реЗ strace - рдорд╛рдЭреНрдпрд╛ рд╕реНрд╡рдд: рдЪреНрдпрд╛ рдЖрдгрд┐ рдЗрддрд░ рд▓реЛрдХрд╛рдВрдЪреНрдпрд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдордордзреНрдпреЗ рд╕рдорд╕реНрдпрд╛ рдЕрд╕рд▓реНрдпрд╛рд╕ рд╕рдВрд░рдХреНрд╖рдгрд╛рдЪреА рдкрд╣рд┐рд▓реА рдУрд│ рдЖрдгрд┐ рдореА рдЖрдард╡рдбреНрдпрд╛рддреВрди рдХрд┐рдорд╛рди рджреЛрди рд╡реЗрд│рд╛ рд╡рд╛рдкрд░рддреЛ.

рдереЛрдбрдХреНрдпрд╛рдд, рдЬрд░ рддреБрдореНрд╣рд╛рд▓рд╛ рдпреБрдирд┐рдХреНрд╕ рдЖрд╡рдбрдд рдЕрд╕реЗрд▓ рддрд░ рд╡рд╛рдЪрд╛ man 1 strace рдЖрдгрд┐ рдореЛрдХрд│реНрдпрд╛ рдордирд╛рдиреЗ рддреБрдордЪреЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдкрд╣рд╛!

рд╕реНрддреНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╛