本地调试gdb
桌面调试主要是本地调试,以gdb为例。
1.1.1 gdb调试原理
(1) 未执行进程调试
启用gdb调试运行gdb ./test的时候,在操作系统里发生了很多复杂的事情:
系统首先会启动gdb进程,这个进程会调用系统函数fork()来创建一个子进程,这个子进程做两件事情:
1)调用系统函数ptrace(PTRACE_TRACEME,[其他参数]);
2)通过exec来加载、执行可执行程序test,那么test程序就在这个子进程中开始执行了。
(2) 已执行进程调试
如果想对一个已经执行的进程进行调试,那么就要在gdb这个父进程中调用ptrace(PTRACE_ATTACH,[其他参数]),此时,gdb进程会attach(绑定)到已经执行的进程B,gdb把进程B收养成为自己的子进程,而子进程B的行为等同于它进行了一次 PTRACE_TRACEME操作。此时gdb进程会发送SIGSTO信号给子进程B,子进程B接收到SIGSTOP信号后,就会暂停执行进入TASK_STOPED状态,表示自己准备好被调试了。
1.1.2 ptrace系统调用原型
#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控制了,从而达到调试的目的。
如果没有gdb调试,操作系统与目标进程之间是直接交互的;如果使用gdb来调试程序,那么操作系统发送给目标进程的信号就会被gdb截获,gdb根据信号的属性来决定:在继续运行目标程序时是否把当前截获的信号转交给目标程序,如此一来,目标程序就在gdb发来的信号指挥下进行相应的动作。
1.1.3 gdb调试框架
gdb调试不管是本地调试还是远程调试,其原理都是基于ptrace系统调用来实现的。
1.1.4远程调试
调试程序和被调试程序运行在不同的电脑中。
限制:
(1) 宿主机和目标板必须在一个局域网内;
(2) 要在宿主机启用gdbserver;
被调试程序运行在不同的电脑中。
限制:
(1) 宿主机和目标板必须在一个局域网内;
(2) 要在宿主机启用gdbserver;