αα αααα»αααααααααααααα·ααααα·ααΆαααΌα ααΌααΈα ααΆαααααΆαααααααααααααααα·ααΈααΆαα½ααα·ααααΆααααα αα·αααααααααααααα·ααααα·ααΆαααΎαα‘αΎαααΆαααααααα»ααα»αααΆαααΌα αα½α - ααΆαα α ααααααααα αααααΆααααααΆαααααΆαααααααααααααΆααααα α»α ααΆα’αΆα ααΆααααααααααααα»αααΆαααααααααΆαααααΎααΆαα α ααααααααααααααα»αααααΎαααΆααααααααΎαααΆαα
α§αααααααααΎααααΆαααα½αα’ααααααα½ααα·αα·ααα "ααΈαα·ααα·ααααα·ααα" αααααααα·ααΈαα
ααΎααΈαα»α
strace
αααααΆαααααΆαααααα’ααααααααα α§ααΆα αααααααΆαααααΎααααΆααα§αααααα
αΆαααααααααΌαααΆαα’αααααααααααα·αααααα strace
αα·αααΆααα·αααααΆα’αααΈααΆααα
ααΆαααααααα·ααΈααααααα
ααΆαα·ααΆ
αααααααΎααααααααααααα α§αααααααΆαααΆααααααααααα Piglet Trace ααΌαααααΆαα ααααΎαααΆααααααα·ααΈααααααα»αααααΎαααΆα ααΌαααααΆαα α αΌααα½αααααΎαααΆαααααΆαα α§ααΆα αααα ααΆαααΆαααΆαααααΎαααΆααα»ααΆα α§ααΆα αααα ααααΌαα―αααΆααααα½αα±ααα ααα»α ααΆα α§ααΆα αααα ααΆαααΆαααΆαααΆαα αΌαααααΎα―αααΆα α§ααΆα αααα αααααα·ααΈαα α»αααα ααααΆααααα ααααΎαααΆαααααα αααα α αααααααα ααααΆααααα ααΆαα αΆαααααα αΌαααα α»α Afterword
αααααααΎααααααααααααα
α ααα»α αααααΆααααααΆαααααΆααααααα·ααΈ αα·αααΊααα OS αα αααα»α Unix ααΊααΆαα α ααΆαααααααααα ααΆαα α ααΆααααααααα, ααα‘αααααα) α’αααααααααααααααα·ααΈααΆαα½ααα·ααααΆααααα ααΎαα‘αΎαααΆαααααα½αααΆα
ααα»αααααα
αααα»αααααααΆααΆαααααααΌαααααΌααΈα (ptrace
.
ptrace ααααΌαβααΆαβαααααΎαβα‘αΎαβααΆβα
ααααβαααααΆααβααΆαβααααΆααβααα α»αβα’αααααααα ααα»ααααβαα
βα
α»αβααααααααβααΈ 80 (αααα»αβααααβααΆαα·ααααααα
trace
ααΈααααα’αΆαα·αααα ααΆααααααΌα αα·αααΎαααααΌαααΆαααααα»ααα»ααααααΆαα SunOS ααα»αααααα
ααααΆα 1994 strace
ααααΌαααΆααααααΌααα
System V, Solaris αα·αααΈαα»α
ααααααα»αααααα·ααα
ααααααααααα strace ααΆααααααααΈαα»α
αα·αααΉαααα’ααααΎααΌα
ααααΆα ptrace
, overgrown ααΆαα½ααααααααααααααΆα
αααΎαα
α’αααααααΆαααααΎα (αα·ααααααααααΆαα) strace
-
ααΆααααααΆααααααααααααΆαα α ααΆααααααααα ptrace αα·αααΆαααΆαααΆααα·ααααααααΌαααΆααα½ααααα αΌααα αααα»α POSIX αααααΈααΆααΆααααααααα· αα·αααΆαα’αα»ααααααααΌααα αααα»α Linux, FreeBSD, OpenBSD αα·α Unix αααααααΈαααααα
α§αααααααΆαααΆααααααααααα Piglet Trace
"α’ααααα·αααααΌαααΆαααααααΉαααΆααΉααααααΈααΏαααααα" (Dennis Ritchie, ααα·ααααααα αααα»ααααα 6 Unix αααααααΌα)
ααΆααααΈαα»ααΆαααΆααα αααα»ααα·αα’αΆα ααααΆαααααααα’αααααα ααΆαααα αααα»ααα·ααααααΆαα½ααααααΆαααααααααααα ααα»ααααααΆαααααΆααΆααααααΈαα ααΆααααααααααααααΆ (ααα»αααααααααααααΎααΆααα "ααΆαα" ααα»αααααα»αααΏα’ααααΆαα’αΆααααα)α αααα ααααΆαααααΆααΌαα ααα»αααααααααααααα ααααΌαααΆαααααααΌααΈαααααΌα αα·αα αααΆαααααααΎαα αα ααααΎαααΊαα αα·ααααα»αα
αααααΆαααααααααααα’αααααααα ααΆαα·αααα ααα»αααααααα»αααΆααα»αααΎααΌαααααααα strace αααααΆαααΎαα‘αΎαααΆαα
αααΎαααααααααααα αΎαα ααα»αααααα·ααα½αααΆαα’αΆααααααΆααα’αααΈαααααααΆααα’αααα’αΆα ααΌα
αααα ααΎααααΈαααα αΆαααΈαααααΆαααααααααα·ααααα·ααΆααααααααα·ααΈ strace αααααα αααα»αααΉαααααααααααΌααααααΆαααααααα·ααΈααΆαααΆαααααΆαααΌα
-
$ gcc examples/piglet-trace.c -o ptr
$ ptr echo test > /dev/null
BRK(12) -> 94744690540544
ACCESS(21) -> 18446744073709551614
ACCESS(21) -> 18446744073709551614
unknown(257) -> 3
FSTAT(5) -> 0
MMAP(9) -> 140694657216512
CLOSE(3) -> 0
ACCESS(21) -> 18446744073709551614
unknown(257) -> 3
READ(0) -> 832
FSTAT(5) -> 0
MMAP(9) -> 140694657208320
MMAP(9) -> 140694650953728
MPROTECT(10) -> 0
MMAP(9) -> 140694655045632
MMAP(9) -> 140694655070208
CLOSE(3) -> 0
unknown(158) -> 0
MPROTECT(10) -> 0
MPROTECT(10) -> 0
MPROTECT(10) -> 0
MUNMAP(11) -> 0
BRK(12) -> 94744690540544
BRK(12) -> 94744690675712
unknown(257) -> 3
FSTAT(5) -> 0
MMAP(9) -> 140694646390784
CLOSE(3) -> 0
FSTAT(5) -> 0
IOCTL(16) -> 18446744073709551591
WRITE(1) -> 5
CLOSE(3) -> 0
CLOSE(3) -> 0
unknown(231)
Tracee terminated
Piglet Trace ααα½αααααΆααα’αααΈααΆαα α
ααααααααααΈαα»α
ααΆαααα (ααΌαααΎαα
ααΌααααα‘ααααΎαααΆαααΆαααααααααΌαααααααΎαα αα
αααα»αααααΈααααΈαα»α
αααααα·ααΈααααΆααααα α»α αα·αα§αααααααΆαααΆαααααΎ ααΌα
αααααΆααααααΆααααΆαααΎ ααΆαα α
αααααααα 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, ®isters) == -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, ®isters) == -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
. αααααΊααΆααΆαααααΆααααα»αααΆαααααΎααΆαααΆαα½αααΆαα α
ααΌααααααααααααααα α
ααα»α
αααααΆαααααα’αααααααααααααα·ααΈααααΎααΆαααΊαα·αααΆαααααααααααΆαααα
ααΉαααΆαα α
ααΆαααααααααααα ααΎαααΈααααα
ααα ααΆααααΆααααααΌαααΆαααααΆααα’αΆαααααααΎααΆαα’αα»αααα αα·ααααα·ααΆα
ααΌαααααΆαα α αΌααα½αααααΎαααΆαααααΆαα
ααααΌααααααααα ptrac α α
αααααΆααααΌαααΆαααΆαααα strace
α’αΆα
ααααΎααΆααααα
αααααααΎαααΆααααααα·ααΈαααα»ααααααα·αααααα»αααααα αααααααααααα’αΆα
ααααΆαααα
ααα ααα»αααα
αααα»ααααααααααα 6 Unix α ααααααααααα ααΆααααααααααααΆαααααα αΎαα αααααααα’αααααααΌααααΎαα’ααααααααα αΆαααααααα·ααΈααΆαααΆαα α§ααΆα αααααααααΆααΊααααΎαααΆααα·ααα
ααΎα
ααα»α
ααΆα α¬αααα»ααααα ααΌα
ααααααααΎα strace
α’αΆα
α
αΌααα½αααααΎαααΆαααΆαααααΆααα
α§ααΆα ααααααααΆαα
int main(int argc, char *argv[])
{
(void) argc; (void) argv;
char str[] = "write men";
write(STDOUT_FILENO, str, sizeof(str));
/* Sleep indefinitely or until a signal arrives */
pause();
write(STDOUT_FILENO, str, sizeof(str));
return EXIT_SUCCESS;
}
ααααααααΎααααααα·ααΈ α αΎαααααΌαααααΆααααΆααΆααΆααααΆααα
$ gcc examples/write-sleep.c -o write-sleep
$ ./write-sleep
./write-sleep
write me
^C
$
α₯α‘αΌαβααΎαβααααΆααΆαβα αΌααα½αβααΆαα½αβααΆα
$ ./write-sleep &
[1] 15329
write me
$ strace -p 15329
strace: Process 15329 attached
pause(
^Cstrace: Process 15329 detached
<detached ...>
αααααα·ααΈααααΌαααΆαααΆααΆαααααααΆαα α
ααΌααααα pause
. αααβααΎαβααΆβααΆαβααΆαβααααα·ααααβαααΆαβααΆβα
ααααβαααααΆβααΆααβαααα
$ strace -o write-sleep.log -p 15329 &
strace: Process 15329 attached
$
$ kill -CONT 15329
$ cat write-sleep.log
pause() = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
pause(
$
$ kill -TERM 15329
$ cat write-sleep.log
pause() = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
pause() = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=14989, si_uid=1001} ---
+++ killed by SIGTERM +++
ααΎαβααΆαβααΎαβααααΎαααΆαβαααααα·ααΈβααααα α αΎαβααΆαβα
αΌααα½αβααΆαα½αβααΆβαααβααααΎ strace
. ααΏαααΈαααΆαααααΆααα
ααΆα
αααΆααα ααΆαα α
ααααααααααα’αΆααα·αα’αΎααΎααΉααααααΆαααααααΆαα§ααααααααααααΆα α αΎαα’αααΈααααα½αα±ααα
αΆααα’αΆααααααααΆαααααα
αααααα strace monitors αα·αααααΉαααα α
ααααααααααα»ααααααα ααα»ααααααααΆααααααΆα
αΌααααααα
α§ααΆα αααα ααΆαααΆαααΆαααααΎαααΆααα»ααΆα
ααααΎααΆαααΆαα½αααααΎαααΆαααΆααααααΆαα α
ααΌαααααα fork
- ααΌαααααΆαααααΌααΈαααΆααα’ααα ααΌαααΎαααΈααααααα strace ααααΎαααΆαααΆαα½ααααααΆαααααΎαααΆααααααααΎα§ααΆα ααααα "ααΆααααααΆαα" ααΆαααα
int main(int argc, char *argv[])
{
pid_t parent_pid = getpid();
pid_t child_pid = fork();
if (child_pid == 0) {
/* A child is born! */
child_pid = getpid();
/* In the end of the day printf is just a call to write(2). */
printf("child (self=%d)n", child_pid);
exit(EXIT_SUCCESS);
}
printf("parent (self=%d, child=%d)n", parent_pid, child_pid);
wait(NULL);
exit(EXIT_SUCCESS);
}
αα ααΈααα ααααΎαααΆαααΎααααααΎαααααΎαααΆααα»ααΆα ααΆααααΆαααααααα αααααααααααααΆαα
$ gcc examples/fork-write.c -o fork-write
$ ./fork-write
parent (self=11274, child=11275)
child (self=11275)
ααΆαααααΆαααΎα ααΎαααΉαααΎαααααΆαα α ααααααααααΈααααΎαααΆαααααα»αααααα
$ strace -e trace=write -ofork-write.log ./fork-write
child (self=22049)
parent (self=22048, child=22049)
$ cat fork-write.log
write(1, "parent (self=22048, child=22049)"..., 33) = 33
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22049, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
ααααα½αα’αααααΆαααΆααααααΆαααααΎαααΆαααΆααααΌα -f
, ααα strace
αααα½ααα·αα·αααααΆαα α
ααΆααααααααααααα»αααααΎαααΆααα»ααΆαα ααααααααααα
αααααΆααααΈαα½αααααα·ααααα pid
ααααΎαααΆαααααααααΎαααααααααααααααα
$ strace -f -e trace=write -ofork-write.log ./fork-write
parent (self=22710, child=22711)
child (self=22711)
$ cat fork-write.log
22710 write(1, "parent (self=22710, child=22711)"..., 33) = 33
22711 write(1, "child (self=22711)n", 19) = 19
22711 +++ exited with 0 +++
22710 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22711, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
22710 +++ exited with 0 +++
αα αααα»αααα·ααααα ααΆαααααααΆααααα»αααααΆαα α ααΆαααααααααα’αΆα ααΆαααααααααα
$ strace -f -e trace=%process -ofork-write.log ./fork-write
parent (self=23610, child=23611)
child (self=23611)
$ cat fork-write.log
23610 execve("./fork-write", ["./fork-write"], 0x7fff696ff720 /* 63 vars */) = 0
23610 arch_prctl(ARCH_SET_FS, 0x7f3d03ba44c0) = 0
23610 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f3d03ba4790) = 23611
23610 wait4(-1, <unfinished ...>
23611 exit_group(0) = ?
23611 +++ exited with 0 +++
23610 <... wait4 resumed> NULL, 0, NULL) = 23611
23610 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=23611, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
23610 exit_group(0) = ?
23610 +++ exited with 0 +++
αα·ααΆαα’αΈααα αΉα ααΎααΆαα α ααααααααα’αααΈααααΌαααααΎααΎααααΈαααααΎαααααΎαααΆαααααΈ?
α§ααΆα αααα ααααΌαα―αααΆααααα½αα±ααα ααα»α ααΆα
ααΆαααΉαααΈα’ααααααααΆα―αααΆααα·αααΆααΆααααααααα ααα»αααααααααα―αααΆαααΆααααΆααααααααααα·ααΈα αΌαααααΎααα’αΆα ααΆααααααααααααααα
αααααΆαα
void do_write(int out_fd)
{
char str[] = "write me to a filen";
if (sizeof(str) != write(out_fd, str, sizeof(str))){
perror("write");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
char tmp_filename_template[] = "/tmp/output_fileXXXXXX";
int out_fd = mkstemp(tmp_filename_template);
if (out_fd == -1) {
perror("mkstemp");
exit(EXIT_FAILURE);
}
do_write(out_fd);
return EXIT_SUCCESS;
}
αααα»αα’αα‘α»ααααα α
ααααααΆα strace
ααΉααααα αΆααααααααααααααααΆαααααΆααααααΌααα
ααΆαα α
ααΆαααααααααα
$ strace -e trace=write -o write-tmp-file.log ./write-tmp-file
$ cat write-tmp-file.log
write(3, "write me to a filen", 20) = 20
+++ exited with 0 +++
ααΆαα½αααΉααααααΆαα· -y
α§αααααααααΎααααΆαααααα αΆαααααΌααα
ααΆααα―αααΆααααα’ααααα·αααααΆααααΌαααααΆα
$ strace -y -e trace=write -o write-tmp-file.log ./write-tmp-file
$ cat write-tmp-file.log
write(3</tmp/output_fileCf5MyW>, "write me to a filen", 20) = 20
+++ exited with 0 +++
α§ααΆα αααα ααΆαααΆαααΆαααΆαα αΌαααααΎα―αααΆα
αα»αααΆαααΆααααααααααα½ααααα αααα αΆαααααΆαα α
αααααααααααααααΆααααΆαα½αα―αααΆαααΆααααΆαααα½αα αααααΆαα
void do_write(int out_fd)
{
char str[] = "write me to a filen";
if (sizeof(str) != write(out_fd, str, sizeof(str))){
perror("write");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
/*
* Path will be provided by the first program argument.
* */
const char *path = argv[1];
/*
* Open an existing file for writing in append mode.
* */
int out_fd = open(path, O_APPEND | O_WRONLY);
if (out_fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
do_write(out_fd);
return EXIT_SUCCESS;
}
ααΆαααααΆαααΎα strace
αααα αΆαααααααΆαααααα·αα
αΆαααΆα
αα
αααΎαα αααααΆαα· -P
ααΆαα½αααΉαα’αΆαα»ααααααααααΆαα±αα strace ααααα»αααααααΆαα α
αα
α―αααΆααααααΆααααααΆαα:
$ strace -y -P/tmp/test_file.log -o write-file.log ./write-file /tmp/test_file.log
$ cat write-file.log
openat(AT_FDCWD, "/tmp/test_file.log", O_WRONLY|O_APPEND) = 3</tmp/test_file.log>
write(3</tmp/test_file.log>, "write me to a filen", 20) = 20
+++ exited with 0 +++
α§ααΆα αααα αααααα·ααΈαα α»αααα
α§αααααααααΎααααΆαα strace
ααα’αΆα
αα½ααα
αααααααΎααΆαααΆαα½ααααααα α»
void *thread(void *arg)
{
(void) arg;
printf("Secondary thread: workingn");
sleep(1);
printf("Secondary thread: donen");
return NULL;
}
int main(int argc, char *argv[])
{
printf("Initial thread: launching a threadn");
pthread_t thr;
if (0 != pthread_create(&thr, NULL, thread, NULL)) {
fprintf(stderr, "Initial thread: failed to create a thread");
exit(EXIT_FAILURE);
}
printf("Initial thread: joining a threadn");
if (0 != pthread_join(thr, NULL)) {
fprintf(stderr, "Initial thread: failed to join a thread");
exit(EXIT_FAILURE);
};
printf("Initial thread: done");
exit(EXIT_SUCCESS);
}
ααΆαααααααΆαα· ααΆααααΌαααααααΌαααΆαα αααααααΆαα½αααΉαααΆαααααΆαααααα·ααααα ααΆααα’αααααααΆαα - ααα -pthread:
$ gcc examples/thread-write.c -pthread -o thread-write
$ ./thread-write
/thread-write
Initial thread: launching a thread
Initial thread: joining a thread
Secondary thread: working
Secondary thread: done
Initial thread: done
$
ααΆααααα -f
ααΌα
αα
αααα»αααααΈααααααΎαααΆαααααααΆ ααΉααααααα pid ααααααΎαααΆααα
ααΎααααααΆααααΈαα½ααα
ααΆαααααααΆαα· ααΎααα·ααα·ααΆαα’αααΈααΆααααααα’ααααααααΆααααααααα‘αΆααααα»ααααααααΆαα’αα»αααααααααααΆα POSIX Threads αα ααα»ααααα’αααΈααααααααααΎααααααααα·ααΈααααααααααΆααα·α αα αα αααα»αααΈαα»α α ααΆαααααααα α»ααααααααα αα·αααΆαααααΎαααΆα α¬αααααααα‘αΆααα - ααΆαααΆααα·α αα αααααααΌαα ααα αΆααααα»αα ααααααααΌααααααΆαααααΆαααααααααΆαααΈαα
αα αααααααΎααΆααα αααα»ααααααααα‘αΆαα αααΎα ααΆαα α ααΆαααααααααααααΆαααΆα αααΎααααα
$ 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 +++
αααα
ααΈααΆαα
αΆαααααα
αΌαααα α»α
Afterword
α§αααααααααΎααααΆαα strace
- α§αααααααΆαααααα·αα’αΆα
αα»αα
α·αααααΆαα ααα»ααααααααααααΈααΎααΆαα α
ααΆααααααααα αα·αααααΆαααααααααααααααα·ααααα·ααΆααααααααα·ααΈ αα·αααααααααααααα·ααααα·ααΆαα’αΆα
ααααΌαααΆαααααΆααααα α»αα α§ααΆα ααα ααΆα’αΆα
ααΆαααΆαααΆαα α
αα
ααΆαααααααΆααααααααααΆαααααααΆαααααα strace
- ααααααΆαααΆαααααΌααααα»αααααΈααΆααααα αΆααΆαα½ααααααα·ααΈααααΆαααααα½α αα·αα’αααααα α αΎααααα»αααααΎααΆαααΆαα αα
ααΆααααΈαααΈαααααα»ααα½ααααααΆα αα
ααα»ααα ααΎαααααΆααααΌααΈα ααΌαα’αΆα man 1 strace
α αΎαααΈαααΆααααα»αααΆαααΎααααααα·ααΈααααα’ααα!
ααααα: www.habr.com