找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

460

积分

0

好友

58

主题
发表于 10 小时前 | 查看: 1| 回复: 0

.debug_info 节是 ELF (可执行与可链接格式) 文件中存储 DWARF 调试信息的核心节区,它包含了程序的调试信息条目,为调试器提供了源代码与机器代码之间的精确映射关系,是进行源代码级调试的基石。

.debug_info节详解

.debug_info 节,即调试信息节,是 ELF 文件中存储 DWARF (带属性记录格式的调试信息) 调试信息的主要节区。它以编译单元为基本组织单位,每个单元都包含一棵完整的调试信息树。

1. DWARF格式概述

.debug_info 节采用 DWARF 格式来存储调试信息,其核心特征包括:

  • 树形结构:调试信息以树形结构组织,每个节点称为一个调试信息条目。节点之间通过父子、兄弟关系连接。
  • 编译单元:每个源代码文件通常对应一个或多个编译单元,它是调试信息在 .debug_info 节中的顶层组织单位。

2. 调试信息条目

.debug_info 节的核心是调试信息条目:

// DIE的基本结构
typedef struct {
    // 标签(Tag)标识条目类型
    // 属性列表(Attributes)
} DebugInfoEntry;

常见的DIE标签类型:

  • DW_TAG_compile_unit:编译单元,表示一个源文件的调试信息。
  • DW_TAG_subprogram:子程序,表示函数或方法。
  • DW_TAG_variable:变量,表示局部或全局变量。
  • DW_TAG_base_type:基本类型,如 int、char 等。
  • DW_TAG_structure_type:结构体类型。
  • DW_TAG_pointer_type:指针类型。

3. 数据结构

.debug_info 节内部通过特定的数据结构进行组织:

// 编译单元头部
typedef struct {
    Elf32_Word length;        // 编译单元长度
    Elf32_Half version;       // DWARF版本
    Elf32_Word abbrev_offset; // 缩写表偏移
    Elf32_Byte address_size;  // 地址大小
} DWARF_CU_Header;

// 调试信息条目(DIE)
typedef struct {
    Elf32_Word abbrev_code;   // 缩写码
    // 属性值列表(根据缩写表确定)
} DWARF_DIE;

4. 与其它调试节的关系

.debug_info 节并非孤立存在,它与 ELF 文件中的其他调试节紧密协作:

  • .debug_abbrev 节:存储 DIE 的缩写信息,定义了 DIE 的标签和属性格式。
  • .debug_str 节:集中存储调试信息中用到的字符串,DIE 中的字符串属性通过偏移引用此节。
  • .debug_line 节:存储源代码行号信息,与 .debug_info 中的函数和变量条目关联。
  • .debug_loc 节:存储变量的位置描述信息,详细说明变量在不同代码段的存储位置(如在寄存器或栈中)。

5. 编译单元结构

一个编译单元在 .debug_info 节中的典型结构如下:

  1. 编译单元头部:包含该单元的基本信息,并指向 .debug_abbrev 节的偏移以解析后续 DIE。
  2. 根 DIE:标签为 DW_TAG_compile_unit,包含源文件名、编译目录、编译器版本等全局信息。
  3. 子 DIEs:在根 DIE 之下,按树形结构组织着描述函数、变量、类型等实体的子 DIE。

6. 属性类型

DIE 通过属性来描述实体的具体细节,常见属性包括:

  • DW_AT_name:名称属性,如函数名、变量名、类型名。
  • DW_AT_type:类型属性,指向另一个描述类型的 DIE。
  • DW_AT_location:位置属性,通过表达式描述变量在内存或寄存器中的存储位置。
  • DW_AT_low_pc / DW_AT_high_pc:地址范围属性,描述函数代码在内存中的起始和结束地址。
  • DW_AT_decl_file / DW_AT_decl_line:声明位置属性,描述实体在源代码中的文件和行号。

7. 实际应用示例

我们可以使用 readelf 工具来查看 .debug_info 节的具体内容:

# 查看.debug_info节信息
$ readelf -S program | grep debug_info
[28] .debug_info       PROGBITS        00000000 000aa8 00016b 00      0   0  1

# 查看.debug_info详细内容
$ readelf --debug-dump=info program

Contents of the .debug_info section:

  Compilation Unit @ offset 0x0:
   Length:        0x167 (32-bit)
   Version:       4
   Abbrev Offset: 0x0
   Pointer Size:  8
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
 <c>   DW_AT_producer    : (indirect string, offset: 0x0): GNU C11 9.3.0 -mtune=generic -march=x86-64 -g
 <10>   DW_AT_language    : 12 (ANSI C99)
 <11>   DW_AT_name        : (indirect string, offset: 0x44): main.c
 <15>   DW_AT_comp_dir    : (indirect string, offset: 0x4c): /home/user/project
 <19>   DW_AT_low_pc      : 0x1129
 <21>   DW_AT_high_pc     : 0x1145
 <29>   DW_AT_stmt_list   : 0x0
 <1><31>: Abbrev Number: 2 (DW_TAG_subprogram)
 <32>   DW_AT_external    : 1
 <33>   DW_AT_name        : (indirect string, offset: 0x5f): main
 <37>   DW_AT_decl_file   : 1
 <38>   DW_AT_decl_line   : 8
 <39>   DW_AT_type        : <0x7a>
 <3d>   DW_AT_low_pc      : 0x1129
 <45>   DW_AT_high_pc     : 0x1145
 <4d>   DW_AT_frame_base  : 1 byte block: 56 (DW_OP_reg6)
 <4f>   DW_AT_GNU_all_call_sites: 1
 <50>   DW_AT_sibling     : <0x7a>

从输出可以看到一个编译单元(来自 main.c)及其内部的 main 函数的详细信息,包括地址范围、声明行号等。

8. 存储的调试信息内容

.debug_info 节承载了丰富的调试信息,主要包括:

  • 源文件信息:源文件名、完整路径、编译目录以及编译器版本信息。
  • 函数信息:函数名称、在内存中的起始地址和大小、参数列表及其类型、局部变量信息。
  • 变量信息:全局变量和局部变量的名称、类型,以及在不同程序点上的存储位置。
  • 类型信息:从基本类型(int, char)到复杂的复合类型(结构体、联合体、数组)和派生类型(指针、引用)的定义。

9. 调试器如何使用

调试器(如 GDB)依赖 .debug_info 节工作:

  1. 信息解析:加载可执行文件时,解析 .debug_info 节中的编译单元和 DIE 树,建立源代码符号(函数名、变量名)到机器代码地址的映射表。
  2. 符号查找:当用户输入 break main 时,调试器查找标签为 DW_TAG_subprogramDW_AT_name 为 “main” 的 DIE,从中获取 DW_AT_low_pc 地址并设置断点。
  3. 类型信息查询:当用户要求打印一个复杂结构体变量时,调试器通过变量的 DW_AT_type 属性找到类型定义 DIE,从而知道该结构的成员布局并正确显示。

10. 优化与剥离

由于调试信息会显著增加文件体积,因此存在相关的优化和剥离操作:

  • 调试信息优化:GCC 等编译器提供 -g1-g2-g3 等不同级别的调试选项,控制生成信息的详细程度,在体积和调试能力间取得平衡。
  • 调试信息剥离:使用 strip 工具可以移除调试节,包括 .debug_info,以减小发布版本的文件大小。
    
    # 移除所有调试信息和符号表
    $ strip program

只移除调试信息(.debug_*节),保留普通符号表

$ strip --strip-debug program



### 总结
.debug_info 节作为 DWARF 调试信息生态的核心,通过编译单元和调试信息条目构成的树形结构,为调试器建立了从源代码到机器指令的完整映射。它使得设置断点、查看变量、回溯调用栈等高级调试功能成为可能,是现代软件开发与 [逆向工程](https://yunpan.plus/f/17-1) 中不可或缺的基础设施。理解其结构,对于深层次调试、性能分析或安全研究都至关重要。如果你想深入了解编译、调试等计算机系统知识,可以访问 [云栈社区](https://yunpan.plus) 探索更多相关内容。



上一篇:深入解析 C# RestClient 与 HttpClient:.NET 中 HTTP 客户端的选择策略
下一篇:Spring事务管理的6种进阶方案,解决@Transactional的局限性
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-18 18:12 , Processed in 0.422616 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表