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、手写调试器

相关推荐
A小辣椒15 小时前
TShark:基础知识
linux
AlfredZhao17 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
古城小栈2 天前
Unix 与 Linux 异同小叙
linux·服务器·unix