рд▓рд┐рдирдХреНрд╕рдорд╛ рд╕реНрдЯреНрд░реЗрд╕: тАЛтАЛрдЗрддрд┐рд╣рд╛рд╕, рдбрд┐рдЬрд╛рдЗрди рд░ рдкреНрд░рдпреЛрдЧ

рд▓рд┐рдирдХреНрд╕рдорд╛ рд╕реНрдЯреНрд░реЗрд╕: тАЛтАЛрдЗрддрд┐рд╣рд╛рд╕, рдбрд┐рдЬрд╛рдЗрди рд░ рдкреНрд░рдпреЛрдЧ

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

рдПрдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛рд▓реЗ рддрдкрд╛рдИрдВрд▓рд╛рдИ рд▓рд┐рдирдХреНрд╕рдорд╛ рдХрд╛рд░реНрдпрдХреНрд░рдорд╣рд░реВрдХреЛ "рдЕрдиреНрддрд░рдВрдЧ рдЬреАрд╡рди" рдирд┐рдЧрд░рд╛рдиреА рдЧрд░реНрди рдорджреНрджрдд рдЧрд░реНрджрдЫ strace, рдЬреБрди рдпрд╕ рд▓реЗрдЦрдХреЛ рд╡рд┐рд╖рдп рд╣реЛред рдЬрд╛рд╕реВрд╕ рдЙрдкрдХрд░рдгрдХреЛ рдкреНрд░рдпреЛрдЧрдХрд╛ рдЙрджрд╛рд╣рд░рдгрд╣рд░реВ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдЗрддрд┐рд╣рд╛рд╕рдХреЛ рд╕рд╛рдердорд╛ рдЫрдиреН strace рд░ рддреНрдпрд╕реНрддрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдорд╣рд░реВрдХреЛ рдбрд┐рдЬрд╛рдЗрдирдХреЛ рд╡рд┐рд╡рд░рдгред

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

рдкреНрд░рдЬрд╛рддрд┐рд╣рд░реВрдХреЛ рдЙрддреНрдкрддреНрддрд┐

рдпреБрдирд┐рдХреНрд╕рдорд╛ рдкреНрд░реЛрдЧреНрд░рд╛рдорд╣рд░реВ рд░ рдУрдПрд╕ рдХрд░реНрдиреЗрд▓ рдмреАрдЪрдХреЛ рдореБрдЦреНрдп рдЗрдиреНрдЯрд░рдлреЗрд╕ рдкреНрд░рдгрд╛рд▓реА рдХрд▓рд╣рд░реВ рд╣реЛред рдкреНрд░рдгрд╛рд▓реА рдХрд▓рд╣рд░реВ, syscalls), рдмрд╛рд╣рд┐рд░реА рд╕рдВрд╕рд╛рд░рд╕рдБрдЧ рдХрд╛рд░реНрдпрдХреНрд░рдорд╣рд░реВрдХреЛ рдЕрдиреНрддрд░рдХреНрд░рд┐рдпрд╛ рддрд┐рдиреАрд╣рд░реВ рдорд╛рд░реНрдлрдд рдорд╛рддреНрд░ рд╣реБрдиреНрдЫред

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

ptrace рдореБрдЦреНрдпрддрдпрд╛ рдЕрдиреНрддрд░рдХреНрд░рд┐рдпрд╛рддреНрдордХ рдбрд┐рдмрдЧрд░рд╣рд░реВрдХреЛ рд▓рд╛рдЧрд┐ рд╡рд┐рдХрд╕рд┐рдд рдЧрд░рд┐рдПрдХреЛ рдерд┐рдпреЛ, рддрд░ 80s рдХреЛ рдЕрдиреНрддреНрдпрдорд╛ (рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рдпреБрдЧрдорд╛ рдкреНрд░рдгрд╛рд▓реА V рд░рд┐рд▓реАрдЬ 4) рдпрд╕ рдЖрдзрд╛рд░рдорд╛, рд╕рдВрдХреБрдЪрд┐рдд рд░реВрдкрдорд╛ рдХреЗрдиреНрджреНрд░рд┐рдд рдбрд┐рдмрдЧрд░рд╣рд░реВ-рдкреНрд░рдгрд╛рд▓реА рдХрд▓ рдЯреНрд░реЗрд╕рд░рд╣рд░реВ- рджреЗрдЦрд╛ рдкрд░реНтАНрдпреЛ рд░ рд╡реНрдпрд╛рдкрдХ рд░реВрдкрдорд╛ рдкреНрд░рдпреЛрдЧ рднрдпреЛред

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

рдЖрдЬ рд╕реНрдЯреНрд░реЗрд╕рд▓реЗ рд▓рд┐рдирдХреНрд╕рд▓рд╛рдИ рдорд╛рддреНрд░ рд╕рдорд░реНрдерди рдЧрд░реНрджрдЫ рд░ рддреНрдпрд╕реИрдорд╛ рдирд┐рд░реНрднрд░ рдЧрд░реНрджрдЫ ptrace, рдзреЗрд░реИ рд╡рд┐рд╕реНрддрд╛рд░рд╣рд░реБ рд╕рдВрдЧ overgrownред

рдЖрдзреБрдирд┐рдХ (рд░ рдзреЗрд░реИ рд╕рдХреНрд░рд┐рдп) рд░рдЦрд░рдЦрд╛рд╡рдХрд░реНрддрд╛ 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, рд╕рд╛рдпрдж рдпреЛ рд╕рд░рд▓ рд╡рд┐рдзрд┐ рдЙрджреНрдзреГрдд рдЧрд░реНрди рд▓рд╛рдпрдХ рдЫ - рдЪрд▓рд┐рд░рд╣реЗрдХреЛ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╕реБрд░реВ рдЧрд░реНрджреИ 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ред рджреБрдИ рдЪреАрдЬрд╣рд░реВ рд╕реНрдкрд╖реНрдЯ рднрдП: рдкрдЬ рдкреНрд░рдгрд╛рд▓реА рдХрд▓рд▓реЗ рд╣реНрдпрд╛рдиреНрдбрд▓рд░рд╣рд░реВ рдмрд┐рдирд╛ рд╕рдВрдХреЗрддрд╣рд░реВрд▓рд╛рдИ рдмреЗрд╡рд╛рд╕реНрддрд╛ рдЧрд░реНрджрдЫ рд░, рдЕрдЭ рдЪрд╛рдЦрд▓рд╛рдЧреНрджреЛ рдХреБрд░рд╛, рд╕реНрдЯреНрд░реЗрд╕ рдореЛрдирд┐рдЯрд░рд╣рд░реВрд▓реЗ рдкреНрд░рдгрд╛рд▓реА рдХрд▓рд╣рд░реВ рдорд╛рддреНрд░ рд╣реЛрдЗрди, рдЖрдЧрдорди рд╕рдВрдХреЗрддрд╣рд░реВ рдкрдирд┐ред

рдЙрджрд╛рд╣рд░рдг: рдмрд╛рд▓ рдкреНрд░рдХреНрд░рд┐рдпрд╛рд╣рд░реВ рдЯреНрд░реНрдпрд╛рдХ рдЧрд░реНрджреИ

рдХрд▓ рдорд╛рд░реНрдлрдд рдкреНрд░рдХреНрд░рд┐рдпрд╛рд╣рд░реВрд╕рдБрдЧ рдХрд╛рдо рдЧрд░реНрджреИ 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 -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, рддрд┐рдиреАрд╣рд░реВрд▓реЗ рдЕрдкрд░реЗрдЯрд┐рдЩ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рд╕рдЮреНрдЪрд╛рд▓рди рдорд╛ рд╣реЗрд░реНрди рд╕рдХреНрдЫрдиреН SystemTap ╨╕ ftrace, рд░ рддрдкрд╛рдЗрдБрд▓рд╛рдИ рдХрд╛рд░реНрдпрдХреНрд░рдо рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдЧрд╣рд┐рд░реЛ рдЕрдиреБрд╕рдиреНрдзрд╛рди рдЧрд░реНрди рдЕрдиреБрдорддрд┐ рджрд┐рдиреНрдЫ perfред рддреИрдкрдирд┐, рдпреЛ рдЫ strace - рдореЗрд░реЛ рдЖрдлреНрдиреИ рд░ рдЕрдиреНрдп рд╡реНрдпрдХреНрддрд┐рдХрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдорд╣рд░реВрдорд╛ рд╕рдорд╕реНрдпрд╛ рднрдПрдорд╛ рд░рдХреНрд╖рд╛рдХреЛ рдкрд╣рд┐рд▓реЛ рд░реЗрдЦрд╛, рд░ рдо рдпрд╕рд▓рд╛рдИ рд╣рдкреНрддрд╛рдорд╛ рдХрдореНрддрд┐рдорд╛ рджреБрдИ рдкрдЯрдХ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдЫреБред

рдЫреЛрдЯрдХрд░реАрдорд╛, рдпрджрд┐ рддрдкрд╛рдЗрдБ рдпреБрдирд┐рдХреНрд╕рд▓рд╛рдИ рдорд╛рдпрд╛ рдЧрд░реНрдиреБрд╣реБрдиреНрдЫ рднрдиреЗ, рдкрдвреНрдиреБрд╣реЛрд╕реН man 1 strace рд░ рддрдкрд╛рдЗрдБрдХрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдорд╣рд░реВ рд╣реЗрд░реНрди рд╕реНрд╡рддрдиреНрддреНрд░ рдорд╣рд╕реБрд╕ рдЧрд░реНрдиреБрд╣реЛрд╕реН!

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

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдердкреНрди