热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

GDB多线程调试分析

0x00:在Linux系统上Gdb提供了一组多线程调试命令,如表所示:多线程调试的主要任务是准确及时地捕捉被调试程序线程状态的变化的事件,并且GDB针对根据捕捉到的事件做出相应的操作,其实最终的

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观察者模式)我们就应做初始化多线程调试功能。

 


推荐阅读
  • 在过去,我曾使用过自建MySQL服务器中的MyISAM和InnoDB存储引擎(也曾尝试过Memory引擎)。今年初,我开始转向阿里云的关系型数据库服务,并深入研究了其高效的压缩存储引擎TokuDB。TokuDB在数据压缩和处理大规模数据集方面表现出色,显著提升了存储效率和查询性能。通过实际应用,我发现TokuDB不仅能够有效减少存储成本,还能显著提高数据处理速度,特别适用于高并发和大数据量的场景。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • C#实现文件的压缩与解压
    2019独角兽企业重金招聘Python工程师标准一、准备工作1、下载ICSharpCode.SharpZipLib.dll文件2、项目中引用这个dll二、文件压缩与解压共用类 ... [详细]
  • 2022年2月 微信小程序 app.json 配置详解:启用调试模式
    本文将详细介绍如何在微信小程序的 app.json 文件中启用调试模式(debug),并通过实际案例展示其配置方法和应用场景。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 在分析Android的Audio系统时,我们对mpAudioPolicy->get_input进行了详细探讨,发现其背后涉及的机制相当复杂。本文将详细介绍这一过程及其背后的实现细节。 ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 本文提出了一种基于栈结构的高效四则运算表达式求值方法。该方法能够处理包含加、减、乘、除运算符以及十进制整数和小括号的算术表达式。通过定义和实现栈的基本操作,如入栈、出栈和判空等,算法能够准确地解析并计算输入的表达式,最终输出其计算结果。此方法不仅提高了计算效率,还增强了对复杂表达式的处理能力。 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • 开发日志:201521044091 《Java编程基础》第11周学习心得与总结
    开发日志:201521044091 《Java编程基础》第11周学习心得与总结 ... [详细]
  • 在PHP的设计中,预定义了9个超级全局变量、8个魔术变量和13个魔术函数,这些变量和函数无需声明即可在脚本的任意位置使用。这些特性在PHP开发中极为常见,能够显著提升开发效率和代码的灵活性。相比之下,Java并没有类似的内置机制,但通过其他方式如上下文对象和反射机制,也可以实现类似的功能。本文将详细探讨这两种语言中这些特殊变量和函数的使用方法及其应用场景。 ... [详细]
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
author-avatar
吕小布
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有