0x00: 在Linux系统上Gdb提供了一组多线程调试命令,如表所示:

多线程调试的主要任务是准确及时地捕捉被调试程序线程状态的变化的事件,并且GDB针对根据捕捉到的事件做出相应的操作,其实最终的结果就是维护一根叫thread list的链表。上面的调试命令都是基于thread list链表来实现的,后面会有讲到。

0x01:Gdb在linux平台多线程调试实现主要依赖下面三个文件

thread.c:文件它的任务非常简单,就是多线程调试命令子集的实现,比如info threads。
当用户在gdb命令行敲入多线程调试命令子集中的命令时,就会调用thread.c中对应的函数。Thread.c中的实现都是基于thread list的。而gdb对于thread list的维护工作主要在另外两个文件中实现。
Linux-nat.c:它实现了通常的调试功能,比如读写寄存器、读写内存、resume程序、wait程序、attach、detach等功能。更重要的是,在linux-nat.c中会维护一个lwp_list链表,表示当前进程所有的内核线程。

linux-thread-db.c:基于thread_db库的一组功能函数,用在多线程调试环境下的函数,比如to_get_thread_local_address。这些函数的任务就是获取用户态线程的产生、消亡事件,双及获取用户态线程相关的数据。Linux-thread-db.c获取用户线程的发生的事件和获取的信息、结合linux-nat.c中维护的lwp_list内核线程链表中提供的信息,以此维护一个完整的thread_list,该链表存放线程所有的信息。

0x02:Gdb功能函数分层:

Gdb中的功能函数使用struct target_ops数据结构来组织。不同功能的函数集抽象成不同的target_ops。比如用于处理coredump文件的”core” target_ops,而linux-nat.c中实现的linux应用程序本地调试功能也抽象成一个ops”child” target_ops,linux-thread-db.c中实现的基于libpthread库的调试功能抽象成”multi-thread”target_ops。
整个linux多线程应用程序本地调试的结构框架如下:

从上图可以看到当调试linux多线程程序时,就会使用thread_db_ops中的相应的函数。那么问题来了,对于resume和wait这些Linux_ops中也实现的函数,会调用哪个呢?Gdb中实现了很多的target_ops,有功能相近也有完全不同功能的,比如linux_ops和file_ops。那么对于功能相近的target_ops怎样使用呢?功能不同的target_ops之间又有怎样的关系呢?这些问题gdb分层机制能解释。
Gdb中把target_ops分为了7层,每一层负责不同的功能。如图所示:

0x03:GDB调试多线程

调试进程建立具体的流程下图所示:

在创建好被调试进程之后,gdb通过ptrace(PTRACE_SETOPTIONS)设置PTRACE_O_TRACECLONE,设置过后,当被调试进程创建线程的时候,就会给自己发送一个SIGTRAP信号,让被调试进程进入stop状态,使得gdb能够捕捉到这些事件,获取tid添加到lwp_list中后,gdb会让程序继续运行,直到被调试程序发生一些需要通知gdb用户的事件,比如触发了用户设置的断点,下面是流程图

Lwp_list链表
被调试进程创建线程最终是通过clone()系统调用实现的。要捕捉子线程的创建和死亡事件,这个捕捉事件由ptrace提供的机制实现。具体机制如下图所示。

Thread_list链表:
Thread_list是struct thread_info类型的一个链表,记录的是被调试进程的所有线程的信息,里面包含线程用户态和内核态的一些信息。线程用户态信息的捕获基于libthread_db库,该库提供了一组调试接口。这么一组libpthread_db调试接口在gdb中使用struct thread_db_info进行管理,该数据主要结构的具体信息如下表:

在被调试进程加载libpthread库时,会为该进程创建这么一个struct thread_db_info记录该进程要使用到的libthread_db提供的调试接口。其中比较重要的是:
td_create_bp_addr和td_death_bp_addr。这两个地址是对应libpthread库中的某个位置。当调用libpthread库创建线程或者线程死亡时,一定会分别调用这么两个addr处的代码。Gdb通过在这两个位置设置断点来捕获libpthread库的线程创建和死亡事件,断点的类型为bp_thread_event.
被调试程序创建子进程或者子进程死亡,会执行到libpthread库的td_create_bp_addr或td_death_bp_addr地址处,触发断点。线程进入stop状态
gdb 通过waitpid()监测到被调试进程的状态改变,分析子进程发生的事件,判断为bp_thread_event的断点触发。如果是create,获取新创建线程struct thread_info的相关的信息,并且加入到thread_list中;如果是death,从thread_list中删除该线程。

0x04:总结

GDB确定我们调试的程序是否为多线程, 通过判断被调试程序是否加载libpthread库来判断的。(捕捉装载libpthread库这个事件)也就是一旦被调试程序装在libpthread库,( Observer观察者模式)我们就应做初始化多线程调试功能。

GDB多线程调试分析的更多相关文章

  1. gdb 多线程调试

    gdb 多线程调试 http://hi.baidu.com/hcq11/blog/item/9f5bfc6e696209d680cb4a25.html  http://hi.baidu.com/lit ...

  2. GDB 多线程调试:只停止断点的线程,其他线程任然执行; 或只运行某些线程 其他线程中断

    多线程调试之痛 调试器(如VS2008和老版GDB)往往只支持all-stop模式,调试多线程程序时,如果某个线程断在一个断点上,你的调试器会让整个程序freeze,直到你continue这个线程,程 ...

  3. [skill][gdb] gdb 多线程调试

    中文快速入门: http://coolshell.cn/articles/3643.html (关于多线程的部署说的并不太对) 进阶: 多进程相关概念: inferiors 是什么? http://m ...

  4. GDB多线程调试

    一.多线程调试1. 多线程调试,最重要的几个命令:info threads                        查看当前进程的线程.                              ...

  5. gdbserver 移植与多线程调试

    在嵌入式linux平台使用gdb调试进行远程调试需要安装gdbserver,gdbserver工作在目标板上,通过串口或者网线与主机上的gdb互联实现远程调试. Gdbserver需要根据不同的嵌入式 ...

  6. Linux学习——Gdb基本调试方法&&多线程调试

    1.Gdb的基本调试 示例代码 //e.c #include <stdio.h> void debug(char *str) { printf("debug info :%s\n ...

  7. 通过gdb调试分析Linux内核的启动过程

    作者:吴乐 山东师范大学 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验流程 1.打开环境 执 ...

  8. 利用GDB进行多线程调试

    一.多线程调试 多线程调试重要就是下面几个命令: info thread 查看当前进程的线程. thread <ID> 切换调试的线程为指定ID的线程. break file.c:100 ...

  9. gdb的多线程调试

    info threads 可以查看当前进程有哪些线程 thread ID 可以切换到线程ID bt 查看当前线程堆栈 set scheduler-locking on多线程调试过程中, 线程会来回切换 ...

随机推荐

  1. P1630 求和

    题意:求$\sum_{i=1}^a i^b,a,b\le 10^9$ 暴力只有30分QAQ(本数学蒟蒻当然想不到正解啦) 正解:模数很小,不难(?)想到$i^a%10000=(i+b)^a %1000 ...

  2. luogu1900 自我数

    分享一个非正解的做法 本题解内存最低(\(\le1\rm MiB\)) 但是不开O2会tle 思路:每个数字仅会更新出1个新的数字,而且这个新数字比旧数字最多也就大70多.所以这里还是利用" ...

  3. 牛客寒假算法基础集训营1 D 小a与黄金街道

    链接:https://ac.nowcoder.com/acm/contest/317/D 首先被数学题吓到了.gcd(n,x)==1 那么必定有 gcd(n,n-x)==1 证明略. 并且两个人的对答 ...

  4. Educational Codeforces Round 13 C

    Description Little Joty has got a task to do. She has a line of n tiles indexed from 1 to n. She has ...

  5. 如何避免遗漏bug

    bug遗漏,我想这个是很多公司很多人头痛的一个问题.众所周知,bug是不可能被完全消灭的,当然也就意味着在发布前不能被全部找出来.于是乎当项目发布后,或多或少都会出现bug遗漏的现象,即使发布初期没有 ...

  6. Photoshop入门教程(三):图层

    学习心得:图层可以说是Photoshop的核心,看似简单,但是对于图像的各种编辑都是基于图层.他就像一层透明的.没有厚度的玻璃纸,每张玻璃纸设置不同的效果,层层叠加,最后显现出绚烂的效果. 在进行图像 ...

  7. 转 windows下安装pycharm并连接Linux的python环境 以及 windows 下notepad ++编辑 linux 的文件

    ######sample 1:windows下安装pycharm并连接Linux的python环境 https://www.cnblogs.com/junxun/p/8287998.html wind ...

  8. 使用 Charles 获取 https 的数据

    1. 配置 Charles 根证书 首先打开 Charles: 然后如下图操作: 之后会弹出钥匙串,如果不弹出,请自行打开钥匙串,如下图: 系统默认是不信任 Charles 的证书的,此时对证书右键, ...

  9. Windows 10家庭版升级到专业版,系统蓝屏

    Log Name: SystemSource: Microsoft-Windows-DistributedCOMDate: 9/9/2018 7:56:57 PMEvent ID: 10016Task ...

  10. 牛客网Java刷题知识点之什么是进程、什么是线程、什么是多线程、多线程的好处和弊端、多线程的创建方式、JVM中的多线程解析、多线程运行图解

    不多说,直接上干货! 什么是进程? 正在进行中的程序(直译). 什么是线程? 就是进程中一个负责程序执行的控制单元(执行路径). 见 牛客网Java刷题知识点之进程和线程的区别 什么是多线程? 一个进 ...