gdb到底是怎样实现的?

gdb这个debug工具 , 应该无人不知吧 。服务器开发和客户端开发人员应该都或多或少的通过这个工具排查问题 。但有没有想过它的实现原理 , 为什么打断点能够在断点处停止运行?为什么能查看cpu寄存器?等等 。我们就带着这些疑问接着往下看 。
知识铺垫
我们都听说过系统调用 , 这里简单的解释下系统调用的含义 。操作系统提供了一种标准的服务来让程序员实现对底层的硬件和服务的控制 , 比如申请、释放内存 , 打开、关闭文件等等 , 这就叫做系统调用(system calls) 。
系统调用的过程比较复杂 , 大致流程是这样的:将相关参数放进系统调用的相关寄存器中 , 然后调用软中断(0x80) , 这个中断作用就是让一个程序从用户态陷入到内核态执行 , 程序将参数和系统调用号交给内核 , 内核来执行 。
看完这个知识铺垫 , 估计心里猜测跟系统调用有关系了 。确实不是特别高大上的技术 , 只是利用了linux提供的非常优雅的方式:ptrace系统调用 , 用man查看以下这个系统调用 。ptrace可以让父进程观察和控制其子进程的检查、执行 , 改变其寄存器和内存的内容 。主要的作用就是大家常用的打断点的功能了 , 还有一个功能是打印系统调用的轨迹信息 。
我们先来看下这个ptrace函数的原型:

  •  
#include <sys/ptrace.h>long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);第一个参数决定了ptrace的行为与其他参数的使用方法 。可取的值有:
  •  
PTRACE_MEPTRACE_PEEKTEXTPTRACE_PEEKDATAPTRACE_PEEKUSERPTRACE_POKETEXTPTRACE_POKEDATAPTRACE_POKEUSERPTRACE_GETREGSPTRACE_GETFPREGS,PTRACE_SETREGSPTRACE_SETFPREGSPTRACE_CONTPTRACE_SYSCALL,PTRACE_SINGLESTEPPTRACE_DETACH 
下面对常用的几种模式进行说明 。
  1. PTRACE_ME(跟踪我):这是相对父进程而言的 。功能是指示父进程 , 对其进行跟踪 。trace工具的实现就是用这个模式 。
  2. PTRACE_GETREGS:读取寄存器的值 。如果你想在系统调用或者进程停止前读取它的寄存器 。这就回答了文章开头的第二个问题 。
  3. PTRACE_SINGLESTEP:单步 。会使内核在子进程的每一条指令执行前先将其阻塞 , 然后控制权交给父进程 。
  4. PTRACE_PEEKDATA:设置断点 。调试器怎么设置断点的呢?通常情况下 , 将当前需要执行的指令替换成trap指令 , 于是就会停在当前位置 。被调试程序恢复运行以后调试器将原指令放回来就可以了 。具体实现过程请接着往下看!


    推荐阅读