gdb调试多线程底层实现原理

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

现实中,我们写的程序一般都是多线程程序。如果多线程程序出问题了,就需要用到gdb的多线程调试功能,非常方便,直接通过thread tid切到可能存在问题的线程,单步执行,看堆栈、寄存器、内存,很快就能找到错误原因

这么强大的功能背后,底层实现原理是什么呢?我们自己写调试器,该如何实现呢?本篇文章为你全方位揭晓!本篇文章看完,gdb远程调试的all,你就过关了!

本篇文章需要前面文章的功底,如果你没看过,建议看看《从零手写gdb调试器》《调试器是如何让代码停下来的》《gdb调试器底层实现原理》《gdb的放过去是如何做到的》

以下,enjoy

Linux内核层面

刚开始接触,难免丈二和尚摸不着头脑,那不妨猜测一下,Linux内核层面会如何实现呢?

那也不能无凭无据的乱猜对吧,根据我们研究调试器的经验+使用gdb调试多线程程序的经验,肯定是Linux内核创建一个线程,就把这个创建线程事件报告给调试器进程。会以何种方式报告呢?信号。什么信号呢?不知道,得看代码找证据。那就开始找证据

研究Linux内核,肯定要借助单步调试环境。那在哪下断点呢?得知道使用pthread_create创建线程,进入内核后,调用的是哪个函数。课程《实战Linux内核》三期讲过,__do_fork函数

通过单步调试Linux内核,跟踪代码执行,发现确实跟我们猜想的一样

那发送的是什么信号呢?进入函数ptrace_event_pid就能找到答案

也是SIGTRAP信号,但是还拼接了点东西。这个要记住,后面写调试器代码会用上。这个event是多少呢?3

用户态实现

如果trace值为0,就不会执行ptrace_event_pid,发送SIGTRAP信号。想想也有道理,如果创建线程,不管三七二十一,都给父进程发SIGTRAP信号,是有点多此一举了。那这个动作肯定是由用户触发了,用户告诉Linux内核:嘿,大兄弟,有线程创建知会我一声

用户怎么告诉内核呢?这样

进入Linux内核后呢?这样

这样,被调试进程的ptrace上就多了很多东西,这个多出来的东西会影响被调试进程创建线程的参数clone_flags(这个环节在pthread库中,偷个懒,不找了)

最终会执行ptrace_event_pid函数,给调试进程发送SIGTRAP信号

妙不妙?反正我研究Linux内核,读Linux内核源码,特别上瘾!

写调试器

来,开干

手写告诉Linux内核:大兄弟,打个桩,有线程创建,告诉我

终于,等了许久,有线程创建了,SIGTRAP信号来了

捕捉到线程创建,完整的操作应该是这样

你在gdb中,使用info threads查看所有的线程信息,通过thread tid能够切换线程,都是以这个代码为基础实现的,来看看完整的代码

至此,gdb调试多线程的底层原理,你应该全部掌握了吧!

如果你也想像我一样,打通所有技术认知,可以随意玩汇编、C语言、Linux用户态、Linux内核态、调试器,欢迎跟我学习。全国唯一一个人做了整个计算机体系课程的人:手写JVM、手写操作系统、实战Linux内核、手写Ubuntu Linux系统、手写编程语言、手写docker、手写调试器

相关推荐
chlk1235 小时前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑5 小时前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件6 小时前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
深紫色的三北六号16 小时前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash20 小时前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI1 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行2 天前
Linux和window共享文件夹
linux
木心月转码ing2 天前
WSL+Cpp开发环境配置
linux
崔小汤呀3 天前
最全的docker安装笔记,包含CentOS和Ubuntu
linux·后端
何中应3 天前
vi编辑器使用
linux·后端·操作系统