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

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

рдпреВрдирд┐рдХреНрд╕ рдЬреИрд╕реЗ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ, рдмрд╛рд╣рд░реА рджреБрдирд┐рдпрд╛ рдФрд░ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╕рд╛рде рдПрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХрд╛ рд╕рдВрдЪрд╛рд░ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдПрдХ рдЫреЛрдЯреЗ рд╕реЗрдЯ - рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣реЛрддрд╛ рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ рдбрд┐рдмрдЧрд┐рдВрдЧ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░рдХреНрд░рд┐рдпрд╛рдУрдВ рджреНрд╡рд╛рд░рд╛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХреА рдЬрд╛рд╕реВрд╕реА рдХрд░рдирд╛ рдЙрдкрдпреЛрдЧреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИред

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

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

рдкреНрд░рдЬрд╛рддрд┐ рдХреА рдЙрддреНрдкрддреНрддрд┐

рдпреВрдирд┐рдХреНрд╕ рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдФрд░ рдУрдПрд╕ рдХрд░реНрдиреЗрд▓ рдХреЗ рдмреАрдЪ рдореБрдЦреНрдп рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рд╣реИред рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓, Syscalls), рдмрд╛рд╣рд░реА рджреБрдирд┐рдпрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдпрдХреНрд░рдореЛрдВ рдХреА рдмрд╛рддрдЪреАрдд рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЙрдирдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣реЛрддреА рд╣реИред

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

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

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

рдЖрдЬ рд╕реНрдЯреНрд░реЗрд╕ рдХреЗрд╡рд▓ рд▓рд┐рдирдХреНрд╕ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЙрд╕реА рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ ptrace, рдЕрдиреЗрдХ рд╡рд┐рд╕реНрддрд╛рд░реЛрдВ рд╕реЗ рдкрд░рд┐рдкреВрд░реНрдгред

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

рдпрд╣ рднреА рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ рд▓рд┐рдирдХреНрд╕, рдлреНрд░реАрдмреАрдПрд╕рдбреА, рдУрдкрдирдмреАрдПрд╕рдбреА рдФрд░ рдкрд╛рд░рдВрдкрд░рд┐рдХ рдпреВрдирд┐рдХреНрд╕ рдореЗрдВ рд▓рдВрдмреЗ рдЗрддрд┐рд╣рд╛рд╕ рдФрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдмрд╛рд╡рдЬреВрдж, рдкреАрдЯреНрд░реЗрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдФрд░ рдЯреНрд░реЗрд╕рд░ рдХреЛ рдХрднреА рднреА POSIX рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред

рд╕реНрдЯреНрд░реЗрд╕ рдбрд┐рд╡рд╛рдЗрд╕ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ: рдкрд┐рдЧрд▓реЗрдЯ рдЯреНрд░реЗрд╕

"рдЖрдкрд╕реЗ рдЗрд╕реЗ рд╕рдордЭрдиреЗ рдХреА рдЙрдореНрдореАрдж рдирд╣реАрдВ рд╣реИ" (рдбреЗрдирд┐рд╕ рд░рд┐рдЪреА, рд╕рдВрд╕реНрдХрд░рдг 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

рдкрд┐рдЧрд▓реЗрдЯ рдЯреНрд░реЗрд╕ рд▓рдЧрднрдЧ рд╕реИрдХрдбрд╝реЛрдВ рд▓рд┐рдирдХреНрд╕ рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХреЛ рдкрд╣рдЪрд╛рдирддрд╛ рд╣реИ (рджреЗрдЦреЗрдВ)ред рдореЗрдЬ) рдФрд░ рдХреЗрд╡рд▓ x86-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);
}

рд╡рд╣ рд╕рдВрдкреВрд░реНрдг рдЕрдиреБрд░реЗрдЦрдХ рд╣реИред рдЕрдм рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдЕрдЧрд▓реА рдкреЛрд░реНрдЯрд┐рдВрдЧ рдХрд╣рд╛рдБ рд╕реЗ рд╢реБрд░реВ рдХрд░рдиреА рд╣реИ DTrace рд▓рд┐рдирдХреНрд╕ рдкрд░.

рдореВрд▓ рдмрд╛рддреЗрдВ: рдПрдХ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдЪрд▓рд╛рдирд╛, рд╕реНрдЯреНрд░реЗрд╕ рдЪрд▓рд╛рдирд╛

рдкрд╣рд▓реЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рдХреЗ рд░реВрдк рдореЗрдВ 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 +++

рдмрд╣рд┐рд╖реНрдХреГрдд рдХреЙрд▓реЛрдВ рдХреА рд╕реВрдЪреА рдореЗрдВ рдЫреВрдЯреЗ рд╣реБрдП рд╡рд┐рд╕реНрдордпрд╛рджрд┐рдмреЛрдзрдХ рдЪрд┐рд╣реНрди рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ: рдпрд╣ рдХрдорд╛рдВрдб рд╢реЗрд▓ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдЦреЛрд▓).

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

рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ, рд╣рдо 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 - рдПрдХ рд╕рд░рд▓ рдФрд░ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рдЙрдкрдХрд░рдг. рд▓реЗрдХрд┐рди рд╕рд┐рд╕реНрдЯрдо рдХреЙрд▓ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдкреНрд░реЛрдЧреНрд░рд╛рдо рдФрд░ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рдЕрдиреНрдп рдкрд╣рд▓реБрдУрдВ рдХреЛ рдбреАрдмрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЬреБрдбрд╝реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдореЗрдВ рдХреЙрд▓ рдХреЛ рдЯреНрд░реИрдХ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдЯреНрд░реЗрд╕, рд╡реЗ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╕рдВрдЪрд╛рд▓рди рдХреЛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рд╕рд┐рд╕реНрдЯрдордЯреИрдк ╨╕ рдлреВрдЯ, рдФрд░ рдЖрдкрдХреЛ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдкреНрд░рджрд░реНрд╢рди рдХреА рдЧрд╣рд░рд╛рдИ рд╕реЗ рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдкрд░реНрдлрд╝. рдлрд┐рд░ рднреА, рдпрд╣ рд╣реИ strace - рдореЗрд░реЗ рдЕрдкрдиреЗ рдФрд░ рдЕрдиреНрдп рд▓реЛрдЧреЛрдВ рдХреЗ рдХрд╛рд░реНрдпрдХреНрд░рдореЛрдВ рдореЗрдВ рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд░рдХреНрд╖рд╛ рдХреА рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐, рдФрд░ рдореИрдВ рдЗрд╕реЗ рд╕рдкреНрддрд╛рд╣ рдореЗрдВ рдХрдо рд╕реЗ рдХрдо рдПрдХ-рджреЛ рдмрд╛рд░ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред

рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдпрджрд┐ рдЖрдкрдХреЛ рдпреВрдирд┐рдХреНрд╕ рдкрд╕рдВрдж рд╣реИ, рддреЛ рдкрдврд╝реЗрдВ man 1 strace рдФрд░ рдмреЗрдЭрд┐рдЭрдХ рдЕрдкрдиреЗ рдХрд╛рд░реНрдпрдХреНрд░рдореЛрдВ рдкрд░ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ!

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

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝реЗрдВ