Note
Search…
调试原理
1
void run_target(const char* programname)
2
{
3
4
5
/* Allow tracing of this process */
6
if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
7
perror("ptrace");
8
return;
9
}
10
11
/* Replace this process's image with the given program */
12
execl(programname, programname, 0);
13
}
14
15
16
main:
17
18
child_pid = fork();
19
if (child_pid == 0)
20
run_target(argv[1]);
21
else if (child_pid > 0)
22
{
23
wait(&wait_status);
24
check_SIG(WIFSTOPPED(wait_status));
25
do_debug(pid_t child_pid);
26
}
27
else {
28
perror("fork");
29
return -1;
30
}
Copied!
[模拟GDB]
由父进程 fork() 一个子进程,在子进程中调用ptrace(PTRACE_TRACEME, 0, 0, 0),表明这个进程由它的父进程来跟踪,然后执行execl(programname)用新程序替换子进程映像。
子进程被父进程所跟踪时,任何发给这个进程的信号(除了SIGKILL)将导致该进程停止运行,而它的父进程会通过wait()获得通知。另外,该进程之后所有对exec()的调用都将使操作系统产生一个SIGTRAP信号发送给它,这让父进程有机会在新程序开始执行之前获得对子进程的控制权。如果不希望由父进程来跟踪的话,那就不应该使用这个请求。(pid、addr、data被忽略)
一旦子进程开始执行exec调用,它就会停止然后接收到一个SIGTRAP信号。父进程通过第一个wait调用正在等待这个事件发生。一旦子进程停止(如果子进程由于发送的信号而停止运行,WIFSTOPPED就返回true),父进程就去检查这个事件。
父进程 就可以从新程序第一条指令执行前获得控制权,去继续ptrace 操作子进程。
Copy link