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

相关推荐
用户6135411460163 小时前
OceanBase all-in-one 4.2.0.0 安装教程(CentOS 7/EL7 一键部署详细步骤)
linux
橘子133 小时前
Linux网络(二)——socket编程
linux·网络
lxmyzzs3 小时前
在使用 `resolvconf` 的 Ubuntu 系统上持久化 DNS 设置
linux·运维·ubuntu
nassi_3 小时前
文件属性获取与目录IO操作详解
linux·服务器·网络
User_芊芊君子3 小时前
【LeetCode 经典题解】:队列与栈的双向模拟——从原理到代码详解
linux·redis·leetcode
熊文豪3 小时前
搭建AI资讯早报:AiOnly全球大模型服务+N8N自动化工作流实战
linux·运维·服务器
阿猿收手吧!4 小时前
【C语言】localtime和localtime_r;strftime和strftime_l
linux·c语言·开发语言
yewq-cn4 小时前
海思 SLE 芯片 Linux 烧录
linux·服务器
顾安r4 小时前
11.5 脚本 本地网站收藏(解封归来)
linux·服务器·c语言·python·bash