The*_*mad 2 c debugging static-analysis debug-symbols dwarf
给定变量访问(不是声明)的行号,我如何确定它的类型(或它在.info树中的声明 DIE )?
看下面的代码:
void foo()
{
{
struct A *b;
}
{
struct B *b;
b = malloc(sizeof(struct B));
}
}
Run Code Online (Sandbox Code Playgroud)
假设我有这个源代码,它是用DWARF格式的调试信息编译的。如何使用源代码和调试信息确定变量b的类型struct B *?
我的意思是如何离线自动化?问题是在源代码(例如,行号)和范围信息之间没有映射的.info部分DWARF。在上面的示例中,使用调试信息,我们可以确定存在一个类型struct A * 为 的子代的foo()变量和一个类型struct B *为 的另一个子代的变量foo()。解析源代码有助于确定发生访问的嵌套级别,但无法将访问的变量映射到其类型。因为在同一级别有两种类型b被访问。
如果有办法强制编译器在调试信息中包含更多的信息,问题就可以解决。例如,将DW_AT_high_pc和添加DW_AT_low_pc到 DIE 类型的调试信息DW_TAG_lexical_block将有所帮助。
你已经回答了几乎所有你自己的问题;只缺少两件事。
首先,文件名/行号和程序计数器之间的关系被编码为.debug_line,而不是.debug_info。
其次,变量不是 的孩子foo():每个都是词法块的孩子。程序结构的相关部分看起来像
DW_TAG_compile_unit
DW_TAG_subprogram
DW_TAG_lexical_block
DW_TAG_variable
DW_TAG_lexical_block
DW_TAG_variable
Run Code Online (Sandbox Code Playgroud)
词法块应与地址范围相关联,但这可能会使用DW_AT_ranges代替DW_AT_low_pc/进行编码DW_AT_high_pc;如果是这种情况,那么您需要解释.debug_ranges.
为了说明手头的案例,我使用cc -g(Oracle Linux 上的 gcc 4.8.5)编译了以下内容...
1 #include <stdlib.h>
2
3 struct A { int a; };
4 struct B { int b; };
5
6 void foo()
7 {
8 {
9 struct A *b;
10 }
11
12 {
13 struct B *b;
14 b = malloc(sizeof (struct B));
15 }
16 }
Run Code Online (Sandbox Code Playgroud)
...并使用 'readelf -w' 解码 DWARF。第 14 行出现在行号表中:
[0x00000032] Special opcode 124: advance Address by 8 to 0x8 and Line by 7 to 14
Run Code Online (Sandbox Code Playgroud)
这意味着我们对地址 0x8 感兴趣。DIE 层次结构包括
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<1><96>: Abbrev Number: 6 (DW_TAG_subprogram)
<9d> DW_AT_low_pc : 0x0
<a5> DW_AT_high_pc : 0x18
<2><b3>: Abbrev Number: 7 (DW_TAG_lexical_block)
<b4> DW_AT_low_pc : 0x8
<bc> DW_AT_high_pc : 0xe
<3><c4>: Abbrev Number: 8 (DW_TAG_variable)
<c5> DW_AT_name : b
<c7> DW_AT_decl_file : 1
<c8> DW_AT_decl_line : 13
<c9> DW_AT_type : <0xd2>
Run Code Online (Sandbox Code Playgroud)
0xb3 处的 DIE 不包含任何进一步的词法块,因此它代表地址 0x8 处的最紧密范围。因此,此时名称“b”必须指代 DIE 的 0xc4 子节点。该变量的类型由
<1><d2>: Abbrev Number: 9 (DW_TAG_pointer_type)
<d3> DW_AT_byte_size : 8
<d4> DW_AT_type : <0x81>
<1><81>: Abbrev Number: 4 (DW_TAG_structure_type)
<82> DW_AT_name : B
<84> DW_AT_byte_size : 4
<2><8b>: Abbrev Number: 5 (DW_TAG_member)
<8c> DW_AT_name : b
<90> DW_AT_type : <0x34>
<94> DW_AT_data_member_location: 0
<1><34>: Abbrev Number: 3 (DW_TAG_base_type)
<35> DW_AT_byte_size : 4
<36> DW_AT_encoding : 5 (signed)
<37> DW_AT_name : int
Run Code Online (Sandbox Code Playgroud)
编辑:
在您自己的回答中,您给出了 mplayer 的反例,其中存在没有相应地址范围的词法块。这样的 DWARF 不符合标准:DWARF 2 的 §3.4 指出词法块条目具有 DW_AT_low_pc 和 DW_AT_high_pc 属性,并没有暗示这些是可选的。假设您使用 gcc,此错误的一个可能候选者是“内联词法块缺失范围的 DWARF 调试信息”。默认的 mplayer 配置包括 -O2 优化,它打开内联;您将看到这反映在父DW_TAG_subprogramfor 中draw_vertices(),从中获取示例代码。该错误的解决方法是添加-fno-inline到编译器选项;这似乎并没有抑制所有内联,因此您可能希望完全禁用优化。