ptrace是gdb实现的基石,本文简要介绍一下ptrace.
ptrace
linux提供的系统调用ptrace,使得一个进程可以attach到另一个进程并进而完整的控制被attach上的进程。
被控制的内容包括但不局限于下述所列
- 文件描述符
- 内存
- 寄存器
- 信号
能够观察到被控制进程的单步执行指令,能够设置断点,等等。
ptrace调用接口定义如下所示
#include <sys/ptrace.h> long int ptrace(enum __ptrace_request request, pid_t pid, void * addr, void * data)
每个参数的具体含义就不作解释了,可以参考相应的manpage.
与接口相对应的是内核在process最重要的数据结构task_struct中定义了一个ptrace成员变量。这样通过ptrace系统调用接口与相应的进程数据结构挂起钩来。
struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; atomic_t usage; unsigned int flags; /* per process flags, defined below */ unsigned int ptrace; int lock_depth; /* BKL lock depth */
Demo
我们可以写一个小的demo程序来演示如何使用ptrace.
#include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <sys/user.h> /* For constants ORIG_EAX etc */ int main() { pid_t child; long orig_eax; child = fork(); if(child == 0) { ptrace(PTRACE_TRACEME, 0, NULL, NULL); execl("/bin/ls", "ls", NULL); } else { wait(NULL); orig_eax = ptrace(PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL); printf("The child made a " "system call %ld ", orig_eax); ptrace(PTRACE_CONT, child, NULL, NULL); } return 0; }
执行结果为
The child made a system call 11
参考资料
- playing with ptrace http://www.linuxjournal.com/article/6100?page=0,0
- process tracing using ptrace http://linuxgazette.net/issue81/sandeep.html
- gdb的基本工作原理 http://www.spongeliu.com/240.html