一、GDB调试工具的原理
1.1 未执行进程调试
启用gdb调试运行gdb ./test的时候,在操作系统里发生了很多复杂的事情,系统首先会启动gdb进程,这个进程会调用系统函数fork()来创建一个子进程,这个子进程做两件事情:
•调用系统函数ptrace(PTRACE_TRACEME,[其他参数]);
•通过exec来加载、执行可执行程序test,那么test程序就在这个子进程中开始执行了。
1.2 执行中进程调试
如果想对一个已经执行的进程进行调试,那么就要在gdb这个父进程中调用ptrace(PTRACE_ATTACH,[其他参数]),此时,gdb进程会attach(绑定)到已经执行的进程B,gdb把进程B收养成为自己的子进程,而子进程B的行为等同于它进行了一次 PTRACE_TRACEME操作。
此时gdb进程会发送SIGSTO信号给子进程B,子进程B接收到SIGSTOP信号后,就会暂停执行进入TASK_STOPED状态,表示自己准备好被调试了。
1.3 gdb系统调用原型介绍
#include < sys/ptrace.h >
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
ptrace系统函数是Linux内核提供的一个用于进程跟踪的系统调用,通过它,一个进程(gdb)可以读写另外一个进程(test)的指令空间、数据空间、堆栈和寄存器的值。
而且gdb进程接管了test进程的所有信号,也就是说系统向test进程发送的所有信号,都被gdb进程接收到,这样一来,test进程的执行就被gdb控制了,从而达到调试的目的。
下面对各个参数进行解释:
2. pid_t pid: 是一个整数类型,表示要操作的目标进程的进程ID(PID)。pid指定了要对哪个进程进行跟踪操作,可以是当前进程、正在运行的其他进程或子进程等。
3. void addr: 是一个指针类型,用于指定内存地址,具体用途根据不同的request *参数而定。例如,对于一些读写内存的请求,addr指定了要读取或写入的内存地址。
4. void data: 是一个指针类型,用于传递数据,具体用途也根据不同的request *参数而定。对于一些读写内存或寄存器的请求,data指定了要读取或写入的数据存储位置。
ptrace函数返回一个long类型值,表示操作的结果或错误码。通常情况下,返回值大于等于0表示成功,小于0表示发生错误。
如果没有gdb调试,操作系统与目标进程之间是直接交互的;如果使用gdb来调试程序,那么操作系统发送给目标进程的信号就会被gdb截获,gdb根据信号的属性来决定:在继续运行目标程序时是否把当前截获的信号转交给目标程序,如此一来,目标程序就在gdb发来的信号指挥下进行相应的动作。
全部0条评论
快来发表一下你的评论吧 !