转载自gdb的工作原理
一、gdb简介
gdb:GNU debugger UNIX及UNIX-like下一个强大的命令行的调试工具 gdb调试的整体架构如下图所示:
可以发现gdb调试不管是本地调试还是远程调试,都是基于ptrace系统调用来实现的
二、ptrace
ptrace系统调用的原型:
long ptrace(enum __ptrace_request request, \
pid_t pid,void *addr,void *data);
ptrace系统调用提供了一种方法,让父进程可以观察和控制其它进程的执行,检查和改变其核心映像及寄存器。主要用来实现断点调试和系统调用跟踪 可通过man手册查看具体使用:man ptrace request参数的主要选项: PTRACE_TRACEME:由子进程调用,表示本进程将被其父进程跟踪,交付给这个进程的所有信号,即使信号是忽略处理的(除SIGKILL之外),都将使其停止,父进程将通过wait()获知这一情况。
PTRACE_ATTACH: attach到一个指定的进程,使其成为当前进程跟踪的子进程,而子进程的行为等同于它进行了一次PTRACE_TRACEME操作。但是,需要注意的是,虽然当前进程成为被跟踪进程的父进程,但是子进程使用getppid()的到的仍将是其原始父进程的pid。 这下子gdb的attach功能也就明朗了。当你在gdb中使用attach命令来跟踪一个指定进程/线程的时候,gdb就自动成为改进程的父进程,而被跟踪的进程则使用了一次PTRACE_TRACEME,gdb也就顺理成章的接管了这个进程。
PTRACE_CONT:继续运行之前停止的子进程。可同时向子进程交付指定的信号。
三、gdb三种调试方式
1)attach并调试一个已经运行的进程: 确定需要进行调试的进程id 运行gdb,输入attch pid,如:gdb 12345。gdb将对指定进行执行如下操作:ptrace(PTRACE_ATTACH,pid,0,0) 2)运行并调试一个新的进程 运行gdb,通过命令行参数或file指定目标调试程序,如gdb ./test 输入run命令,gdb执行下述操作: 通过fork()系统调用创建一个新进程 在新创建的子进程中调用ptrace(PTRACE_TRACEME,0,0,0) 在子进程中通过execv()系统调用加载用户指定的可执行文件 3)远程调试目标主机上新创建的进程 gdb运行在调试机,gdbserver运行在目标机,通过二者之间定义的数据格式进行通信
四、gdb调试的基础—信号
gdb调试的实现都是建立在信号的基础上的,在使用参数为PTRACE_TRACEME或PTRACE_ATTACH的ptrace系统调用建立调试关系后,交付给目标程序的任何信号首先都会被gdb截获。 因此gdb可以先行对信号进行相应处理,并根据信号的属性决定是否要将信号交付给目标程序。 1、设置断点: 信号是实现断点的基础,当用breakpoint 设置一个断点后,gdb会在=找到该位置对应的具体地址,然后向该地址写入断点指令INT3,即0xCC。 目标程序运行到这条指令时,就会触发SIGTRAP信号,gdb会首先捕获到这个信号。然后根据目标程序当前停止的位置在gdb维护的断点链表中查询,若存在,则可判定为命中断点。 gdb暂停目标程序运行的方法是想起发送SIGSTOP信号。 2、next单步调试: next指令可以实现单步调试,即每次只执行一行语句。一行语句可能对应多条及其指令,当执行next指令时,gdb会计算下一条语句对应的第一条指令的地址,然后控制目标程序走到该位置停止。
参考: http://www.spongeliu.com/240.html http://www.docin.com/p-18618736.html |