GDB调试原理——ptrace系统调用

本文由霸气的菠萝原创,转载请注明出处:http://www.cnblogs.com/xsln/p/ptrace.html

全部关于gdb的文章索引请点这里

引子:

  1. gdb基本上大家都在用,你有没有想过它的实现原理是什么?为什么它可以控制程序执行、中断、访问内存甚至直接使程序流程改变?
  2. 在使用gdb调试程序时,程序的进程状态是”T”,但又似乎并非接到了SIGSTOP信号,那么这个”T”是什么呢?

追根溯源,我们今天来研究一下Linux下这个强大的系统调用:ptrace()

首先,linux的进程状态大体分为以下几种:

  1. D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态。
  2. R (TASK_RUNNING),进程执行中。
  3. S (TASK_INTERRUPTIBLE),可中断的睡眠状态。
  4. T (TASK_STOPPED),暂停状态。
  5. t (TASK_TRACED),进程被追踪。
  6. w (TASK_PAGING),进程调页中,2.6以上版本的内核中已经被移除。
  7. X (TASK_DEAD – EXIT_DEAD),退出状态,进程即将被销毁。
  8. Z (TASK_DEAD – EXIT_ZOMBIE),退出状态,进程成为僵尸进程。

(以上内容来自ps命令的manual手册,原文请看↓)

其中上面的5就是我们要讨论的,gdb调试程序时的t状态,程序被追踪。(关于进程的其他状态请自行百度)。

请看ptrace系统调用手册↓

ptrace的原型可以看到是:

long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);

4个参数的含义分别为:

  1. enum __ptrace_request request:指示了ptrace要执行的命令。
  2. pid_t pid: 指示ptrace要跟踪的进程。
  3. void *addr: 指示要监控的内存地址。
  4. void *data: 存放读取出的或者要写入的数据。

描述译文如下:

ptrace()系统调用提供了一个方法,该方法使一个程序(追踪者)可以观察和控制另外一个程序(被追踪者)的执行,并检查和改变被追踪者的内存及寄存器。它主要用于实现断点调试和追踪系统调用。

被追踪者首先需要被追踪者attach(这个词实在不知道咋翻译了……但是程序员应该都懂@[email protected])。该行为以及后续操作是线程独立的:在一个多线程的进程中,每一个线程可以被一个独立的(可能是不同的)追踪者attach,或者干脆不理会。因此,被追踪者永远是“一个线程”,而不是一个(可能是多线程的)进程。使用ptrace命令的方法是追踪程序发送如下命令给被追踪程序:

ptrace(PTRACE_foo, pid, …)

pid即linux系统分配的线程号。

当被追踪时,被追踪线程在接收信号时会被停止,即使那个信号是被忽略的也是如此(SIGKILL除外)。追踪程序会在一个调用waitpid(或者其他类wait系统调用)时收到通知,该调用会返回一个包含被追踪线程停止的原因的状态值。当被追踪线程停止时,追踪程序可以使用多种ptrace请求来检查和编辑被追踪线程。追踪程序可以让被追踪线程继续运行,有选择地忽略发过来的信号(甚至可以发送一个完全不同的信号给被追踪线程)。

可以看到,ptrace确实是一个强大的系统调用;gdb就是基于ptrace这个系统调用来做的。其原理是利用ptrace系统调用,在被调试程序和gdb之间建立追踪关系。然后所有发送给被调试程序(被追踪线程)的信号(除SIGKILL)都会被gdb截获,gdb根据截获的信号,查看被调试程序相应的内存地址,并控制被调试的程序继续运行。GDB常用的使用方法有断点设置和单步调试,接下来我们来分析一下他们是如何实现的。

1.建立调试关系:

用gdb调试程序有2种模式,包括使用gdb启动程序,以及attach到现有进程。分别对应下面2种建立调试关系的方法:

1)  fork: 利用fork+execve执行被测试的程序,子进程在执行execve之前调用ptrace(PTRACE_TRACEME),建立了与父进程(debugger)的跟踪关系。

2)  attach: debugger可以调用ptrace(PTRACE_ATTACH,pid,...),建立自己与进程号为pid的进程间的跟踪关系。即利用PTRACE_ATTACH,使自己变成被调试程序的父进程(用ps可以看到)。用attach建立起来的跟踪关系,可以调用ptrace(PTRACE_DETACH,pid,...)来解除。注意attach进程时的权限问题,如一个非root权限的进程是不能attach到一个root进程上的。

2.断点原理:

1)    断点的实现原理,就是在指定的位置插入断点指令,当被调试的程序运行到断点的时候,产生SIGTRAP信号。该信号被gdb捕获并进行断点命中判定,当gdb判断出这次SIGTRAP是断点命中之后就会转入等待用户输入进行下一步处理,否则继续。

2)    断点的设置原理: 在程序中设置断点,就是先将该位置的原来的指令保存,然后向该位置写入int 3。当执行到int 3的时候,发生软中断,内核会给子进程发出SIGTRAP信号,当然这个信号会被转发给父进程。然后用保存的指令替换int3,等待恢复运行。

3)    断点命中判定:gdb把所有的断点位置都存放在一个链表中,命中判定即把被调试程序当前停止的位置和链表中的断点位置进行比较,看是断点产生的信号,还是无关信号。

4)    条件断点的判定:原理同3),只是恢复断点处的指令后,再多加一步条件判断。若表达式为真,则触发断点。由于需要判断一次,因此加入条件断点后,不管有没有触发到条件断点,都会影响性能。在x86平台,某些硬件支持硬件断点,在条件断点处不插入int    3,而是插入一个其他指令,当程序走到这个地址的时候,不发出int 3信号,而是先去比较一下特定寄存器和某个地址的内容,再决定是否发送int 3。因此,当你的断点的位置会被程序频繁地“路过”时,尽量使用硬件断点,会对提高性能有帮助

3.单步跟踪原理:

这个最简单,因为ptrace本身支持单步功能,调用ptrace(PTRACE_SINGLESTEP,pid,...)即可,如下图说明:

时间: 2024-10-09 18:47:15

GDB调试原理——ptrace系统调用的相关文章

gdb调试原理及qemu中的gdbserver

(一)gdb调试原理 此部分转自:https://blog.csdn.net/u012658346/article/details/51159971     https://www.cnblogs.com/xsln/p/ptrace.html gdb调试的原理是基于ptrace系统调用,ptrace()系统调用提供了一个方法,该方法使一个程序(追踪者)可以观察和控制另外一个程序(被追踪者)的执行,并检查和改变被追踪者的内存及寄存器.它主要用于实现断点调试和追踪系统调用. 当被追踪时,被追踪线程在

GDB调试系列之了解GDB

想要熟练利用GDB进行程序调试,首先要了解什么是GDB. 1. 什么是GDB GDB (the GNU Project Debugger) 是一个可以运行在大多数常见的UNIX架构.Windows.Mac OSX等系统上的跨平台调试器,允许我们查看另一个程序在运行过程中内部发生了什么——或者另一个程序崩溃时在做什么. 具体而言,GDB能做以下四种事情[1],以帮助我们定位运行中的Bug: 让程序开始运行,指定任何可能影响其行为的内容. 让程序在特定条件下停止运行. 检查程序停止运行时发生了什么.

gdb调试命令

本篇摘自互联网,纯属自己学习笔记,然分享给看到我的博客的人们. 用GDB调试程序 GDB是一个强大的命令行调试工具.大家知道命令行的强大就是在于,其可以形成执行序列,形成脚本.UNIX下的软件全是命令行的,这给程序开发提代供了极大的便利,命令行软件的优势在于,它们可以非常容易的集成在一起,使用几个简单的已有工具的命令,就可以做出一个非常强大的功能. 于是UNIX下的软件比Windows下的软件更能有机地结合,各自发挥各自的长处,组合成更为强劲的功能.而Windows下的图形软件基本上是各自为营,

从NDK在非Root手机上的调试原理探讨Android的安全机制(转载)

从NDK在非Root手机上的调试原理探讨Android的安全机制 最近都在忙着研究Android的安全攻防技术,好长一段时间没有写博客了,准备回归老本行中--Read the funcking android source code.这两天在看NDK文档的时候,看到一句话"Native debugging ... does not require root or privileged access, aslong as your application is debuggable".咦

GDB调试总结__1

该博客旨在分享IT技术心得和实际工作中遇到问题的解决方法,下面是新浪博客地址http://blog.sina.com.cn/qianyumolu,则为分享经济.行业趋势.心灵文章等,有兴趣的朋友能够踩踩,讨论分享    也欢迎来群里一起学习交流http://url.cn/LJhxoQ -----------------------------------------------------------------------------------------------------------

第七课 GDB调试 (下)

1序言: 通过前面一节第六课 GDB调试 (下)文章,可以掌握理解了gdb调试:怎么启动.运行,打断点.查看变量.甚至改变变量等的知识,今天来大概讲解下调试bug的类型. 2知识点: 2.1 就像之前所说的没有任何一个程序员敢打包票自己写的代码是没任何bug,bug总会有意无意的出现在我们眼前,当程序运行结果于我们预期结果不一样的时候这时候我们就应该调试,总的来说bug分为:语法错误.逻辑错误.硬件异常: 3原理: 3.1 语法错误:一般情况下出现在编译的时候会有提示编译错误这时候我们就可以马上

GDB 调试 C/C++ Project

平时做算法题目, 没少用到 GDB, 但今天才意识到 Project 的调试方法与单个 cpp 文件的不同之处, 比如 gdb list 命令, 在单个 cpp 文件中列出的是源代码, 但在 project 中却什么都不显示 Project Debug 时, file 参数的使用 [1] 有讲解, UP 主问的问题和我遇到的一样, 只不过, 没能解决我的问题(我的问题更2B一些). 出现的错误 1. 执行命令, make, gdb test, gdb l No symbol table is l

Linux下交叉编译gdb,gdbserver+gdb的使用以及通过gdb调试core文件

交叉编译gdb和gdbserver 1.下载gdb:下载地址为:http://ftp.gnu.org/gnu/gdb/按照一般的想法,最新版本越好,因此下载7.2这个版本.当然,凡事无绝对.我们以gdb-7.2.tar.bz2 这个文件为例.2.解压缩: $ tar jxvf gdb-7.2.tar.bz2 注:小技巧:Linux下一般压缩文件后缀为.tar.bz2和.tar.gz,它们解压命令有两三个选项是一致的: xf(v),前者再加上j选项,后者再加上z选项. 3.进入该目录 $ cd g

实验作业:使gdb跟踪分析一个系统调用内核函数

实验作业:使gdb跟踪分析一个系统调用内核函数(我使用的是getuid) 20135313吴子怡.北京电子科技学院 [第一部分] 根据视频演示的步骤,先做第一部分,步骤如下 ①更新menu代码到最新版 ②在代码中加入C函数.汇编函数 ③在main函数中加入makeconfig ④make rootfs ⑤可以看到qemu中增加了我们先前添加的命令: ⑥分别执行新增的命令 [第二部分]gdb跟踪分析一个系统调用内核函数 ①进入gdb调试 ②设置断点,继续执行: ③相对应的得到这样的结果: ④查看我