Unix áá²á·ááá¯á·áá±á¬ áááºáááºááŸá¯á áá áºáá»á¬ážááœááºá áááá¯ááááºáá áºáá¯á ááŒááºáááá¹áá¬ááŸáá·áº áááºááœááºááŸá¯ááŸáá·áº áááºáááºááŸá¯á áá áºááẠáá±ážáááºáá±á¬áá¯ááºáá±á¬ááºáá»ááºáá»á¬áž - á áá áºáá±á«áºááá¯ááŸá¯áá»á¬ážááŸáá áºááá·áº ááŒá áºáá±á«áºáááºá ááá¯ááá¯áááºááŸá¬ á¡ááŸá¬ážááŸá¬ááŒááºááŒááºáž áááºááœááºáá»ááºáá»á¬ážá¡ááœáẠáááºážááẠáá¯ááºáááºážá ááºáá»á¬ážááŒáá·áº áá¯ááºáá±á¬ááºáá±ááá·áº á áá áºáá±á«áºááá¯ááŸá¯áá»á¬ážááᯠá á°ážá ááºážááẠá¡áá¯á¶ážáááºááá¯ááºáááºáᯠááá¯ááá¯áááºá
á¡áá¯á¶ážáááºááŸá¯áá
áºáá¯ááẠLinux ááŸá áááá¯ááááºáá»á¬ážá "áááºážááŸá®ážáá±á¬áá" ááᯠá
á±á¬áá·áºááŒáá·áºááẠáá°áá®áá±ážáááºá strace
á€áá±á¬ááºážáá«ážáá¡ááŒá±á¬ááºážá¡áá¬ááŒá
áºáááºá áá°áá»áŸáá¯áááááá¬áá»á¬ážá¡áá¯á¶ážááŒá¯ááŸá¯ááá°áá¬áá»á¬ážááᯠááŸááºáááºážá¡áá»ááºážááŒáá·áº ááœá²áá¬ážáááºá strace
ááŸáá·áºááá¯áá²á·ááá¯á·áá±á¬áááá¯ááááºáá»á¬ážááá®ááá¯ááºážáá±á¬áºááŒáá»ááºá
á¡ááŒá±á¬ááºážá¡áá¬
áá»áá¯ážá áááºáá»á¬ážááá°áá¡á á¡ááá¯áá»á¯ááºá¡á¬ážááŒáá·áº ááŒá±áá¬áá¶áááááá¬- Piglet Trace á¡ááŒá±áá¶áá»á¬áž- ááŒá±ážáá±áá±á¬ áááá¯ááááºáá áºáá¯ááᯠááŒá±ážááŒááºážá á¡ááŒá±áá¶á¡áá»ááºáá»á¬áž- áá¯ááºáááºážá ááºááœáẠáá«áááºááŒááºáž á¥ááá¬- ááá±ážáá¯ááºáááºážá ááºáá»á¬ážááᯠááŒá±áá¬áá¶ááŒááºážá á¥ááá¬- áááºááá¯ááºáá»á¬ážá¡á á¬áž ááá¯ááºáááºážááŒá±á¬ááºážáá»á¬áž á¥ááá¬- ááá¯ááºáááºáá±á¬ááºááŸá¯ ááŒá±áá¬áá¶ááŒááºážá á¥ááá¬- Multithreaded áááá¯ááááºáá»á¬áž áá¬á áá¬á¡áááºážá¡á á¬áž- á áá áºáá±á«áºááá¯ááŸá¯ááŒá¯áá¯ááºááá·áºá¡áá»áááºááœáẠáá¯ááºáááºážá ááºá á¥áº áá¬á áá¬á¡áááºážá¡á á¬áž- ááŸá¬ážááœááºážááá¯ážááœááºážááŒááºážá afterword
áá»áá¯ážá áááºáá»á¬ážááá°áá¡á
Unix ááŸá áááá¯ááááºáá»á¬ážááŸáá·áº OS kernel á¡ááŒá¬áž á¡ááá interface ááẠá áá áºáá±á«áºááá¯ááŸá¯áá»á¬ážááŒá áºáááºá á áá áºáá±á«áºááá¯ááŸá¯áá»á¬áž, áá±ááŒááºáá±á¬áº) ááŒááºáááá¹áá¬ááŸáá·áº áááá¯ááááºáá»á¬ážá á¡ááŒááºá¡ááŸáẠáááºáá±á¬ááºááŸá¯ááẠáááºážááá¯á·ááŸáááá·áº áá®ážááá·áºááŒá áºáá±á«áºáááºá
áá«áá±ááá·áº Unix áá²á· ááááá¯á¶áž á¡áá»á¬ážáá°ááŸá¬ áá¬ážááŸááºáž (ptrace
.
ptrace ááá¯á¡ááŒááºá¡ááŸááºáá¯á¶á·ááŒááºááá·áºá¡ááŸá¬ážááŸá¬áá°áá»á¬ážá¡ááœááºá¡áááá¡á¬ážááŒáá·áºáá®ááœááºáá²á·áááºá ááá¯á·áá±á¬áº 80s ááŸá±á¬ááºážááá¯ááºáž (á
á®ážááœá¬ážááŒá
áºáá±ááºááœááºá
trace
áá±. clone ááŸáá·áº áá°áááºážááŸá
áºáá¯áá¯á¶ážááᯠSunOS á¡ááœáẠáááºááœááºáá¬ážáá±á¬áºáááºáž áááá ááœááºááŒá
áºáááºá strace
System Vá Solaris ááŸáá·áº ááá¯ááá¯áá±áááºážá
á¬ážáá±á¬ Linux ááá¯á· ááá¯á·áá¬ážáááºá
ááá±á· strace ááẠLinux ááá¯áᬠáá±á¬ááºáá¶á·áá±ážááŒá®áž áá°áá®áá±á¬á¡áá±á«áºááœáẠááŸá®ááá¯áá±áá«áááºá ptrace
áá»á¬ážá
áœá¬áá±á¬ extensions áá»á¬ážááŒáá·áº ááŒá®ážááœá¬ážáá¬áááºá
áá±ááºáá® (á¡ááœááºáááºááŒáœáá±á¬) ááááºážááááºážáá° strace
-
Linuxá FreeBSDá OpenBSD ááŸáá·áº ááá¬ážááá¯ážáá» Unix ááœáẠááŸááºáá»á¬ážáá±á¬áááá¯ááºážááŒá±á¬ááºážááŸáá·áº á¡áá±á¬ááºá¡áááºáá±á¬áºáá±áá±á¬áºáááºáž ptrace á áá áºáá±á«áºááá¯ááŸá¯ááŸáá·áº ááŒá±áá¬áá¶áááááá¬áá»á¬ážááẠPOSIX ááœáẠáááºáá±á¬á¡áá«á០ááá«áááºáááºáááºáž á¡áá±ážááŒá®ážáá«áááºá
á¡ááá¯áá»á¯ááºá¡á¬ážááŒáá·áº ááŒá±áá¬áá¶áááááá¬- Piglet Trace
"ááẠáá«ááᯠáá¬ážáááºááá¯á· áá»áŸá±á¬áºááá·áºááá¬ážáá«áá°áž" (Dennis Ritchieá Version 6 Unix á¡áááºážá¡ááŒá áºáá¯ááºááœáẠááŸááºáá»ááº)
áááºá ááºááá±ážááááááºážá áá±á¬ááºá áºáá±áá¹áá¬ááœá±ááᯠáááºážááá¶ááá¯ááºáá±á¬á·áá² á¡áá¯ááºááœá±áá²á· ááá á¬ážáá²á·áá±ááá·áº áá°ááá¯á·áá²á·ááœá²á·á ááºážáá¯á¶ááᯠáá¬ážáááºááá¯á· ááŒáá¯ážá á¬ážáá²á·ááẠ(áá°ááŒá®ážááœá±á âáá»áá¯ážáá²á·â ááá¯áá²á· á áá¬ážáá¯á¶ážááᯠáá¯á¶ážáá±ááá·áº ááá±á¬ááºážááá¯ážáá«áž áá»áŸá¬ááœá±ááᯠááá¯á¶ááŒáá°ážá áá«á ááááá¯á¶áž Unix áá²á· á¡ááœááºááá±á¬ áááºáá»á±ážááŸá¯áá²á· áá±ááºáá® ááœáá·áºáááºážáá²á· á¡áááºážá¡ááŒá ẠááŸá¯ááºááŸá¬ážááŸá¯á áá«á·áá²á· á¡áááºážáá®ážá ááºááá¯á· ááŒá áºáá±á¬ááºážááŒá áºááá¯ááºáááºá
á€áá±á¬ááºážáá«ážááááºááœááºáá»ááºá¡ááœááºá áááºá
á¯ááŸá
áºáá»á¬ážááŒá¬áá¬áá²á·ááá·áº 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 ááẠáá¬ááŸáá·áºáá»á®áá±á¬ Linux á
áá
áºáá±á«áºááá¯ááŸá¯áá»á¬ážá¡ááŒá±á¬ááºáž á¡ááá¡ááŸááºááŒá¯ááẠ(ááŒáá·áºáá«á
áá»áœááºá¯ááºááá¯á·áááá¯ááºááœá¬ážááᯠááŒáá·áºááŒáá«á
áá¯á·á Linux ááœááºá debugger ááŸáá·áº tracers áá»á¬ážááẠá¡áááºáá±á¬áºááŒáá«á¡ááá¯ááºáž ptrace system call ááá¯á¡áá¯á¶ážááŒá¯áááºá áááºážáááºáá»áœááºá¯ááºááá¯á·áá¬ááá¯á¡ááºáá±á¬ command identifiers ááá¯áááá¡ááŒááºážá¡áá¯á¶ááœááºááŒááºáááºážááŒááºážááŒáá·áºá¡áá¯ááºáá¯ááºáááºá PTRACE_TRACEME
, PTRACE_SYSCALL
О PTRACE_GETREGS
.
ááŒá±áá¬áá¶ááẠáá¯á¶ááŸáẠUnix á
ááá¯ááºááŒáá·áº á
áááºáááº- 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
á
áá
áºáá±á«áºááá¯ááŸá¯ááᯠááá¯ááºáá±á¬ááºáá® ááá¯á·ááá¯áẠááŒá®ážááŒá®ážáá»ááºážááœáẠáááá ááŒá®ážááŒá±á¬ááºáááºááŒá
áºáááºá áá±á«áºááá¯ááŸá¯ááŸá
áºáá¯ááŒá¬ážááœáẠáááºááẠáááºááá·áºáá¯ááºáá±á¬ááºáá»ááºáá»á¬ážááá¯áááᯠáá¯ááºáá±á¬ááºááá¯ááºáááº- áá±á«áºááá¯ááŸá¯ááᯠá¡ááŒá¬ážáá
áºáá¯ááŒáá·áº á¡á
á¬ážááá¯ážáá«á á¡ááŒá±á¬ááºážááŒáá»ááºáá»á¬áž ááá¯á·ááá¯áẠááŒááºáááºááá¯ážááᯠááŒá±á¬ááºážáá²áá«á
áá»áœááºá¯ááºááá¯á·ááẠcommand ááá¯ááŸá
áºááŒáááºáá±á«áºááá¯áááºáá¬ááá¯á¡ááºáááºá 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);
}
á¡á²áá«á ááŒá±áá¬áá¶áá
áºáá¯áá¯á¶ážáá«á ááá¯áááºááẠáá±á¬ááºáá¬ááá·áº porting ááá¯áááºááŸá¬á
áááºááááºáááºážá
á¡ááŒá±áá¶áá»á¬áž- ááŒá±ážáá±áá±á¬ áááá¯ááááºáá áºáá¯ááᯠááŒá±ážááŒááºážá
áááá¡áá¯á¶ážá¡ááŒá
Ạ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
áá±á¬ááºáá¯á¶ážá¡áá±áá²á·á áááºážááŒá±á¬ááºážááááºážáá»á¯ááºááŸá¯á¡á±á¬ááºááŸá¬ run ááŒáá«á áá¯á·á
$ 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 +++
áááºáá¯ááºáá¬ážáá±á¬áá±á«áºááá¯ááŸá¯áá»á¬ážá á¬áááºážááœáẠááœááºáá±áá±á¬ á¡á¬áá±ááááºá¡ááŸááºá¡áá¬ážááᯠááŸááºáá¬ážáá¬ážáá«- áááºážááᯠcommand shell á០ááá¯á¡ááºáá«áááºá á¡ááœá¶).
áá»áœááºá¯ááºá glibc áá¬ážááŸááºážááœááºá á
áá
áºáá±á«áºááá¯ááŸá¯ááẠáá¯ááºáááºážá
ááºááᯠáááºááá·áºá
á±áááºá exit_group
ááá¯ážáá¬ááá¯ááºáá°ážá _exit
. á€áááºááŸá¬ á
áá
áºáá±á«áºááá¯ááŸá¯áá»á¬ážááŸáá·áº áá¯ááºáá±á¬ááºááẠá¡áááºá¡áá²ááŒá
áºáááº- áááá¯ááááºáᬠá¡áá¯ááºáá¯ááºááá·áº áá»ááºááŸá¬ááŒááºááẠá
áá
áºáá±á«áºááá¯ááŸá¯áá»á¬ážááŸáá·áº ááá¯ááºááá¯ááºáááºááá¯ááºááŒááºážáááŸááá«á ááá¯á·á¡ááŒááºá á¡áá±á¬ááºá¡áááºáá±á¬áºááŸá¯ááŸáá·áº ááááºáá±á¬ááºážáá±á«áº áá°áááºá áá¯á¶ááŸááºááŒá±á¬ááºážáá²áááºá
á¡ááŒá±áá¶á¡áá»ááºáá»á¬áž- áá¯ááºáááºážá ááºááœáẠáá«áááºááŒááºáž
á¡á
ááá¯ááºážááŸá¬áá±á¬á· prace system ááᯠáááºáá±á¬ááºáá²á·áᬠááŒá
áºáá«áááºá 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
- Unix á¡á¬ážáá¯á¶ážáá¡ááŒá±áá¶á ááá¯ážááŸááºážáá±á¬ "ááœá±ážááŒá°ááŒááºáž" á¥ááá¬ááᯠá¡áá¯á¶ážááŒá¯á strace ááẠprocess tree ááŸáá·áº áááºááá¯á·á¡áá¯ááºáá¯ááºáááºááᯠááŒáá·áºááŒáá«á
áá¯á·á
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
system output ááá¯ááŒá
áºá
á±ááá·áº áá¯ááºáááºážá
ááº
$ 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
utility ááẠáá±á¬áºááŒáá»ááºááŸáá·áº ááá¯ááºáá®ááá·áº ááá¯ááºáá®ááá¯á· áááºážááŒá±á¬ááºážááᯠááŒáááº-
$ 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 +++
á¥ááá¬- Multithreaded áááá¯ááááºáá»á¬áž
á¡áá¯á¶ážáááºááẠstrace
Multi-threaded ááŒáá·áºá¡áá¯ááºáá¯ááºáá±á¬á¡áá«ááœááºáááºážáá°áá®ááá¯ááºáááºá
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);
}
áá¯á¶ááŸááºá¡á¬ážááŒáá·áºá áááºážááᯠlinker ááá¯á· á¡áá°ážááŸá¯ááºááœááºážáááºá áá¬ážááŒáá·áº á á¯á ááºážáá¬ážáááẠ- 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 á á¶ááŸá¯ááºážááᯠá¡áá±á¬ááºá¡áááºáá±á¬áºááŒááºážááá±á¬á¡á thread identifier á¡ááŒá±á¬ááºážááŒá±á¬áá±ááŒááºážááá¯ááºáá² Linux ááœáẠtask scheduler ááŸá¡áá¯á¶ážááŒá¯áá±á¬ á¡áá±á¡ááœááºááŸáá·áºáááºáááºáá«áááºá áá±á¬ááºáá¯á¶ážá¡ááŒááºá¡áá áá¯ááºáááºážá ááºáá»á¬áž ááá¯á·ááá¯áẠthread áá»á¬ážáááŸááá« - á ááºááááŸáááá¯ááºáá±á¬ cores áá»á¬ážááŒá¬ážááœáẠááŒáá·áºáá±ááẠááá¯á¡ááºáá±á¬á¡áá¯ááºáá»á¬ážááŸááá«áááºá
á á¬ááœá²áá»á¬ážá áœá¬ááœáẠá¡áá¯ááºáá¯ááºáá±á¬á¡áá«á á áá áºáá±á«áºááá¯ááŸá¯áá»á¬áž á¡ááœááºáá»á¬ážáá¬áááº-
$ 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
á
áœááºážáááºáá»á¬áž - á
áá
áºáá±á«áºááá¯áá»áááºááœáẠáá¯ááºáá±á¬ááºáá»ááºáá±á«áºááá¯ááŸá¯áá»á¬ážá stack ááá¯ááŒáááŒááºážá ááá¯ážááá¯ážááŸááºážááŸááºáž
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
(call stack display)á áááºážááẠá
áá
áºáá±á«áºááá¯ááŸá¯áá»á¬ážááᯠá¡áááºááŒáá·áº á
á
áºáá¯ááºááẠá¡áááá¹áá¬ááºááŸááááº-
$ 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 +++
error injection á¡ááŒááºá
afterword
á¡áá¯á¶ážáááºááẠstrace
- ááá¯ážááŸááºážááŒá®áž áá¯á¶ááŒááºá
áááºáá»ááá±á¬ tool áá
áºáá¯á ááá¯á·áá±á¬áº á
áá
áºáá±á«áºááá¯ááŸá¯áá»á¬ážá¡ááŒáẠáááá¯ááááºáá»á¬ážá áá¯ááºáá±á¬ááºáá»ááºááŸáá·áº áááºáááºááŸá¯á
áá
áºá á¡ááŒá¬ážááŸá¯áá±á¬áá·áºáá»á¬ážááᯠá¡ááŸá¬ážááŸá¬ááá¯ááºáááºá á¥ááá¬á¡á¬ážááŒáá·áºá áááºážááẠááá¯ááºážááá
áºáá»áááºáááºáá¬ážáá±á¬ á
á¬ááŒáá·áºááá¯ááºáá»á¬ážááá¯á· áá±á«áºááá¯ááŸá¯áá»á¬ážááᯠááŒá±áá¬áá¶ááá¯ááºáááºá strace
- áá»áœááºá¯ááºáááá¯ááºááá¯ááºááŸáá·áºá¡ááŒá¬ážáá°áá»á¬ážááááá¯ááááºáá»á¬ážááŸáá·áºááŒá¿áá¬áá»á¬ážááŸááá«ááá¬ááœááºáá±ážáááááá»ááºážááŒá
áºááŒá®ážá áá
áºáááºáá»áŸááºá¡áááºážáá¯á¶ážááŸá
áºááŒáááºá¡áá¯á¶ážááŒá¯áá«á
ááá¯ááá¯ááŒá±á¬áááẠUnix ááá¯áá»á
áºáááºáááºáá«á man 1 strace
áááºááááá¯ááááºáá»á¬ážááᯠááœááºáááºá
áœá¬ááŒáá·áºááŸá¯ááá¯ááºáá«á
á±á
source: www.habr.com