从DWARF调试信息获取结构体成员内存地址的两类疑问咨询
DWARF调试信息解析疑问解答
问题1:DW_AT_location解析与变量地址匹配问题
你的DW_AT_location值为[3, 192, 63, 2, 128],这里的第一个字节3对应DWARF标准中的DW_OP_addr操作码(编码0x03),该操作码的作用是直接指定变量的内存地址,后续字节是地址的原始字节序列(而非你误以为的无符号LEB128编码),且遵循目标嵌入式平台的字节序(小端)。
具体解析步骤:
- 忽略操作码
3,取后续4个字节[192, 63, 2, 128] - 按小端字节序反转字节顺序,得到
[128, 2, 63, 192] - 将每个字节转换为十六进制:
0x80, 0x02, 0x3F, 0xC0 - 拼接后得到地址
0x80023FC0,与第三方工具结果完全一致
使用Python elftools解析时,库会自动识别DW_OP_addr操作码,并根据目标平台的地址长度(此处为32位)和字节序解析后续字节,无需手动处理LEB128。你之前的误解在于混淆了DW_OP_addr与其他使用LEB128编码的操作码(如DW_OP_plus_uconst)的格式。
相关DIE信息:
DIE DW_TAG_variable, size=37, has_children=False |DW_AT_name : AttributeValue(name='DW_AT_name', form='DW_FORM_string', value=b'apCalVariant_Appl_LCS', raw_value=b'apCalVariant_Appl_LCS', offset=26734224) |DW_AT_decl_file : AttributeValue(name='DW_AT_decl_file', form='DW_FORM_udata', value=38, raw_value=38, offset=26734246) |DW_AT_decl_line : AttributeValue(name='DW_AT_decl_line', form='DW_FORM_udata', value=8, raw_value=8, offset=26734247) |DW_AT_decl_column : AttributeValue(name='DW_AT_decl_column', form='DW_FORM_udata', value=24, raw_value=24, offset=26734248) |DW_AT_type : AttributeValue(name='DW_AT_type', form='DW_FORM_ref_addr', value=6023079, raw_value=6023079, offset=26734249) |DW_AT_external : AttributeValue(name='DW_AT_external', form='DW_FORM_flag', value=True, raw_value=1, offset=26734253) |DW_AT_location : AttributeValue(name='DW_AT_location', form='DW_FORM_block', value=[3, 192, 63, 2, 128], raw_value=[3, 192, 63, 2, 128], offset=26734254)
问题2:DW_AT_data_member_location的含义与结构体成员地址计算
DW_AT_data_member_location用于描述结构体成员相对于结构体起始地址的偏移,其值是一个DWARF表达式(而非直接的十进制偏移)。你的两个成员的属性值第一个字节都是35,对应DW_OP_plus_uconst操作码(编码0x23),该操作码的作用是将后续无符号LEB128编码的偏移量加到结构体起始地址上,得到成员的实际地址。
第一个成员解析([35, 196, 1]):
- 操作码
35(DW_OP_plus_uconst),后续字节是无符号LEB128编码的偏移 - 解析LEB128:
- 第一个字节
196(0xC4),最高位为1,说明需要继续读取下一个字节 - 取低7位:
196 & 0x7F = 68 - 第二个字节
1(0x01),最高位为0,结束解析 - 总偏移:
68 + (1 << 7) = 68 + 128 = 196
- 第一个字节
- 成员地址 = 结构体起始地址(0x80023FC0) + 196,与你观察到的结果一致
第二个成员解析([35, 144, 2]):
- 操作码
35(DW_OP_plus_uconst),后续字节是无符号LEB128编码的偏移 - 解析LEB128:
- 第一个字节
144(0x90),最高位为1,继续读取下一个字节 - 取低7位:
144 & 0x7F = 16 - 第二个字节
2(0x02),最高位为0,结束解析 - 总偏移:
16 + (2 << 7) = 16 + 256 = 272
- 第一个字节
- 成员地址 = 结构体起始地址(0x80023FC0) + 272,而非你之前误以为的+144
相关DIE信息:
DIE DW_TAG_member, size=36, has_children=False |DW_AT_name : AttributeValue(name='DW_AT_name', form='DW_FORM_string', value=b'k_u16_LCS_VarStrTq_1En2Nm', raw_value=b'k_u16_LCS_VarStrTq_1En2Nm', offset=5215310) |DW_AT_type : AttributeValue(name='DW_AT_type', form='DW_FORM_ref4', value=312, raw_value=312, offset=5215336) |DW_AT_byte_size : AttributeValue(name='DW_AT_byte_size', form='DW_FORM_udata', value=2, raw_value=2, offset=5215340) |DW_AT_data_member_location: AttributeValue(name='DW_AT_data_member_location', form='DW_FORM_block', value=[35, 196, 1], raw_value=[35, 196, 1], offset=5215341)
DIE DW_TAG_member, size=57, has_children=False |DW_AT_name : AttributeValue(name='DW_AT_name', form='DW_FORM_string', value=b'k_s16_LCS_LacDeActvLatestCtrlLine_LCHold_1En3m', raw_value=b'k_s16_LCS_LacDeActvLatestCtrlLine_LCHold_1En3m', offset=5216696) |DW_AT_type : AttributeValue(name='DW_AT_type', form='DW_FORM_ref4', value=283, raw_value=283, offset=26734249) |DW_AT_byte_size : AttributeValue(name='DW_AT_byte_size', form='DW_FORM_udata', value=2, raw_value=2, offset=5216747) |DW_AT_data_member_location: AttributeValue(name='DW_AT_data_member_location', form='DW_FORM_block', value=[35, 144, 2], raw_value=[35, 144, 2], offset=5216748)
内容的提问来源于stack exchange,提问作者SangYoon
相关产品推荐
相关产品推荐

