本文由霸气的菠萝原创,转载请注明出处: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(这个词实在不知道咋翻译了……但是程序员应该都懂@_@)。该行为以及后续操作是线程独立的:在一个多线程的进程中,每一个线程可以被一个独立的(可能是不同的)追踪者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,...)即可,如下图说明:

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

  1. gdb调试原理及qemu中的gdbserver

    (一)gdb调试原理 此部分转自:https://blog.csdn.net/u012658346/article/details/51159971     https://www.cnblogs.c ...

  2. Linux高级调试与优化——gdb调试命令

    番外 2019年7月26日至27日,公司邀请<软件调试>和<格蠹汇编——软件调试案例集锦>两本书的作者张银奎老师进行<Linux高级调试与优化>培训,有幸聆听张老师 ...

  3. GDB调试系列之了解GDB

    想要熟练利用GDB进行程序调试,首先要了解什么是GDB. 1. 什么是GDB GDB (the GNU Project Debugger) 是一个可以运行在大多数常见的UNIX架构.Windows.M ...

  4. GDB调试-从入门到实践

    你好,我是雨乐! 在上篇文章中,我们分析了线上coredump产生的原因,其中用到了coredump分析工具gdb,这几天一直有读者在问,能不能写一篇关于gdb调试方面的文章,今天借助此文,分享一些工 ...

  5. GDB的原理

    gdb调试不管是本地调试还是远程调试,都是基于ptrace系统调用来实现. ptrace系统调用提供了一种方法,让父进程可以观察和控制其它进程的执行,检查和改变其核心映像及寄存器.主要用来实现断点调试 ...

  6. 20145314郑凯杰《信息安全系统设计基础》GDB调试32位汇编堆栈分析

    20145314郑凯杰<信息安全系统设计基础>GDB调试32位汇编堆栈分析 本篇博客将对第五周博客中的GDB调试32位汇编堆栈进行分析 首先放上以前环境配置的图: 图1: 测试代码: #i ...

  7. nginx模块_使用gdb调试nginx源码

    工欲善其事必先利其器,如何使用调试工具gdb一步步调试nginx是了解nginx的重要手段. ps:本文的目标人群是像我这样初接触Unix编程的同学,如果有什么地方错误请指正. 熟悉gdb的使用 这里 ...

  8. GDB调试总结__1

    该博客旨在分享IT技术心得和实际工作中遇到问题的解决方法,下面是新浪博客地址http://blog.sina.com.cn/qianyumolu,则为分享经济.行业趋势.心灵文章等,有兴趣的朋友能够踩 ...

  9. 比较全面的gdb调试命令 (转载)

    转自http://blog.csdn.net/dadalan/article/details/3758025 用GDB调试程序 GDB是一个强大的命令行调试工具.大家知道命令行的强大就是在于,其可以形 ...

随机推荐

  1. sql中的left join以及on、where关键字的区别

    创建两张表并插入一些数据 create table class( class_id int, class_name ), class_grade ) ); ,'语文','A'); ,'数学','B') ...

  2. ELK & ElasticSearch 5.1 基础概念及配置文件详解【转】

    转自:https://blog.csdn.net/zxf_668899/article/details/54582849 配置文件 基本概念 接近实时NRT 集群cluster 索引index 文档d ...

  3. mongodb常用查询语法

    一.查询 find方法 db.collection_name.find(); 查询所有的结果: select * from users; db.users.find(); 指定返回那些列(键): se ...

  4. bootstrap动态添加Tab标签页

    好久没有写博客了(主要是懒),工作中用到一个动态添加Tab的功能,众所周知,bootstrap没有动态添加Tab的功能,网上又没找到什么好用的,那咱就自己写呗?(因为懒,所以只写了添加的方法.(๑&g ...

  5. 通过灰度线性映射增强图像对比度实现PS中的色阶

    通过灰度线性映射增强图像对比度 Halcon中如何通过灰度线性映射增强图片对比度呢?不急,我先讲点其他的. 如果你用过Photoshop,那么想必对增强图像的对比度很熟悉.在Photoshop中,我们 ...

  6. android9.0适配HTTPS:not permitted by network security policy'

    app功能接口正常,其他手机运行OK,但是在Android9.0的手机上报错 CLEARTEXT communication to 192.168.1.xx not permitted by netw ...

  7. 使用Go语言操作MySQL数据库的思路与步骤

    最近在做注册登录服务时,学习用Go语言操作MySQL数据库实现用户数据的增删改查,现将个人学习心得总结如下,另外附有代码仓库地址,欢迎各位有兴趣的fork. 软件环境:Goland.Navicat f ...

  8. Redis 数据结构的实现

    Redis 数据结构的实现 先看个对照关系: Redis数据结构 实现一 实现二 string 整数(如果value能够表示为整数) 字符串 hash 压缩列表(只包含少量键值对, 并且每个键值对的键 ...

  9. 用scrapy框架爬取映客直播用户头像

    1. 创建项目 scrapy startproject yingke cd yingke 2. 创建爬虫  scrapy genspider live 3. 分析http://www.inke.cn/ ...

  10. js中的运算符优先级

    运算符有何很多,基本的可能都比较熟,单有些优先级很难记住.建议使用“()”将复杂的运算表达式区分好优先级. 我给运算符优先级做了一首小打油诗. 括号成员new函数 直new后置累计数 单目幂算乘除模 ...