gdb单步调试底层实现原理

我,子牙老师,一个手写过操作系统、编程语言、Java虚拟机、docker、Ubuntu系统,玩透Windows内核、Linux内核的...硬核男人

关于gdb调试器,我已经写了三篇硬核文章了《从零手写gdb调试器》《调试器是如何让代码停下来的》《gdb调试器底层实现原理》,今天开启它的第四篇:gdb单步调试代码的底层实现原理

国内关于gdb调试器相关的资料非常少,如果你对调试器底层实现感兴趣,欢迎关注公众号【硬核子牙】,看调试器系列文章。如果你想写一个自己百分百控股的调试器,欢迎学习我的课程《从零手写gdb调试器》

什么是单步调试,就是这三个按钮

从左到右:step over,单步步过。step into,单步步入。step out,单步步出。本篇文章主要谈step into,中间那个。因为step over、step out的实现要依赖step into。step over、step out,后面再写文章细讲

看完本篇文章,你能学到单步步入的全部:

  1. 单步步入的底层实现原理
  2. 实战:不依赖Linux内核自实现单步步入
  3. 调试Linux内核看单步步入在内核层是如何实现的
  4. Linux内核是在何时清除单步标识的
  5. 调试Linux内核论证单步标识清除

以下,enjoy

单步步入底层原理

单步步入的底层实现,是依赖CPU实现的。在CPU内部,有一个寄存器叫状态寄存器:elfags,长这样

其中第8位对研究单步调试非常关键:TF位,单步标志位。记住TF这两个单词,等下看Linux内核源码会看到。

这个TF是如何工作的呢?

当CPU执行完一条机器指令后,会瞄一眼自己的EFLAGS寄存器,如果其中的 TF(Trap Flag)位为1,就会触发一个调试异常(#DB),它是异常向量号1,属于硬件异常,由 CPU自动产生

你可能注意到了EFLAGS中的第9位,IF(Interrupt Flag)位,中断使能控制位。如果这位为0,即关闭中断,会影响单步调试吗?答案是不会。这个位只影响中断,不影响异常。这个位一般是1,因为中断是一直在发生的

所以EFALGS的值如果是0x3**,就表示开启了单步调试功能。接下来咱们实战一下

自实现单步步入

为了实战演示,我给我写的调试器增加了两个功能:开启单步、关闭单步,本质就是修改ELFAGS寄存器的第8位

来看下实战效果。我在main函数处下断点,让程序跑到这个位置停下来,当前的CPU所处位置是0x400542

看下elfags寄存器的值

0x246,没有开启单步调试。我如果现在执行continue,程序就运行结束了。我执行step命令,开启单步调试功能

接下来我执行continue,看它是单步执行还是执行结束

可以看到,是单步执行的。再看下TF位的值

发现还在,所以你现在执行continue,它会一直单步走。但是gdb的单步,你会发现它不是一直生效,它只生效一次,那gdb是何时清除TF位的呢?留个问题,后面会讲到

执行step_del清除TF位,再执行continue,让程序执行结束

一切如我们所愿。自己写的调试器,精准控制程序运行,酷不酷?

Linux内核层实现单步步入

gdb是如何实现单步调试的呢?

使用ptrace函数,request=PTRACE_SINGLESTEP,进入Linux内核做了什么呢?就找重点代码,设置EFLAGS的TF位

最终会执行到这个函数

找到核心代码了!

Linux内核清除单步标识

前面说过,gdb的单步调试是一次性的,言外之意就是执行了一次单步,就会清空EFLAGS中的TF位,这个清空的动作是gdb做的还是Linux内核做的呢?

Linux内核做的!什么时候做的呢?其实研究Linux内核需要一种这样的思维:就是如果这个功能你来实现,你会选择在哪个时机做呢?

答案是,1号#DB硬件异常的处理逻辑里。你仔细想想,是不是这里是最合适的?

至此,gdb调试器的单步调试功能的底层实现原理,就全部讲完了。step over、step out,下篇安排。关注公众号【硬核子牙】,看调试器系列硬核文章

最后再打个小广告,如果你想学习手写操作系统及实战Linux内核,如果你对调试器底层实现感兴趣,同时想写一个自己可以百分百控制的调试器,调试你自己写的操作系统,欢迎去我公众号【硬核子牙】看我之前的文章,了解课程详情。

相关推荐
鲁邦通物联网1 分钟前
充电站底层脱机DLB引擎解构:基于Linux调度的边缘计算网关并发控制实战
linux·运维·人工智能·边缘计算·边缘计算网关·5g数采·工业级边缘计算网关
Zhang~Ling38 分钟前
Linux多线程互斥锁:从现象到原理解析
linux·运维·网络
ambition202423 小时前
操作系统同步:读者-写者问题与读写公平法详解(附每个 PV 操作含义)
linux·开发语言·数据结构·unix
zmzmzmalo3 小时前
Linux ELF文件加载与内存管理揭秘
linux·网络·数据库
三言老师10 小时前
K8s集群运行时自动化运维全覆盖落地实操(下)
linux·运维·服务器·网络
ltl11 小时前
HAProxy HTX 与 HTTP 路径:内部表示、改写落点与协议分叉
linux
ltl11 小时前
可拆分 OS:CXL 内存池化如何动摇本地 DRAM 假设
linux
ltl11 小时前
Tetragon 强制执行:Override 与 SIGKILL 各自保证什么
linux
lengjingzju11 小时前
编译与调试完全指南—第6章 性能分析工具
linux
躺不平的理查德12 小时前
嵌入式 Linux 系统移植与 SD 卡量产镜像制作
linux·运维·服务器