Bootstrap

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

;