50行straceもどき
すこし前に、straceコマンドもどきを50行くらいで書いてみたことがあるので、それを貼ってみまーす。いきなりコード。あ、C99です。
// strace_modoki.c: Linux/x86専用です。x86_64カーネルでは-m32でコンパイルしても動きません。 #include <stdio.h> #include <unistd.h> #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <asm/user.h> #include <asm/ptrace.h> int main() { int i; static const char* syscallstr[1000] = {0}; for(i = 0; i < 1000; ++i) syscallstr[i] = "???"; syscallstr[0] = "restart_syscall"; syscallstr[1] = "exit"; syscallstr[2] = "fork"; /* 略 */ syscallstr[321] = "signalfd"; syscallstr[322] = "timerfd"; syscallstr[323] = "eventfd"; if (!fork()) { // child ptrace(PTRACE_TRACEME, 0, 0, 0); execve("/bin/echo", (char *const []){ "/bin/echo", "123", NULL }, (char *const []){ NULL }); _exit(-1); } else { int st, in_syscall = 1; // うまく動かなかったら1を0にしてみてください :-) if (in_syscall) printf("enter execve() "); wait(&st); // wait for exec while (ptrace(PTRACE_SYSCALL, p, 0, 0) == 0) { // cont until syscall enter/leave wait(&st); // wait for syscall enter/leave if(WIFEXITED(st)) { puts("= ?"); break; } long orig_eax = ptrace(PTRACE_PEEKUSER, p, 4 * ORIG_EAX, 0); struct user_regs_struct regs; ptrace(PTRACE_GETREGS, p, 0, ®s); if (in_syscall == 0) { in_syscall = 1; printf("enter %s(0x%lx) ", (orig_eax >= 0 && orig_eax < 1000) ? syscallstr[orig_eax] : "???", regs.ebx); } else { in_syscall = 0; printf("= %ld\n", regs.eax); } fflush(stdout); } } return 0; }
冒頭の syscallstr[nnn] = "xxx"; の部分は、/usr/include/asm/unistd.h をもとに、適当に変形して生成してください。余談ですがこのファイルをたまにのぞくと新規に追加されたシステムコールがわかって楽しいです。signalfdとか。エラーチェック他全部省略の手抜きコードです。うまく動かなかったらゴメンナサイ。
これを実行すると、まずfork()して子プロセスで /bin/echo 123 を実行し、親プロセスがその子の様子をptraceで観察します。出力はこんな感じになります。
% gcc -Wall -W strace_modoki.c % ./a.out enter execve() = 0 enter brk(0x0) = 164818944 enter access(0x4bee8f) = -2 enter open(0x4bf077) = 3 enter fstat64(0x3) = 0 enter mmap2(0x0) = -1208172544 enter close(0x3) = 0 enter open(0xb7fd7a08) = 3 enter read(0x3) = 512 enter fstat64(0x3) = 0 enter mmap2(0x0) = -1208176640 enter mmap2(0x4c5000) = 5001216 enter mmap2(0x5ff000) = 6287360 enter mmap2(0x602000) = 6299648 enter close(0x3) = 0 enter mmap2(0x0) = -1208180736 enter set_thread_area(0xbfac95c4) = 0 enter mprotect(0x5ff000) = 0 enter mprotect(0x4c1000) = 0 enter munmap(0xb7fcc000) = 0 enter brk(0x0) = 164818944 enter brk(0x9d50000) = 164954112 enter fstat64(0x1) = 0 enter mmap2(0x0) = -1208119296 enter write(0x1) 123 = 4 enter close(0x1) = 0 enter munmap(0xb7fd9000) = 0 enter exit_group(0x0) = ? %
全くpretty printされていませんが、一応straceっぽい出力が得られています。ptraceの詳細については、man 2 ptraceや、2002年のこの記事あたりが参考になると思います。