DWARF DIE变量跟踪异常求助(GDB调试报错)
问题背景
自研编译器生成DWARF DIE时遭遇变量跟踪异常:变量实际存储在汇编的-8(%rbp)位置,DWARF中DW_AT_location使用DW_OP_fbreg: -24描述,但GDB设置观察点后执行报错,提示无法访问内存地址0x1。尝试调整偏移无效,环境为GDB 15.2、gcc 14.2.1编译AT&T语法汇编、DWARF版本5。
相关DWARF信息
变量条目缩写
DW_AT_name DW_FORM_string DW_AT_decl_file DW_FORM_data1 DW_AT_decl_line DW_FORM_data1 DW_AT_decl_column DW_FORM_data1 DW_AT_type DW_FORM_ref4 DW_AT_location DW_FORM_exprloc
对应debug_info内容
DW_AT_name : x DW_AT_decl_file : 1 DW_AT_decl_line : 2 DW_AT_decl_column : 24 DW_AT_type : <0x65> DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24)
GDB报错日志
(gdb) start ........ Not important (gdb) watch x Hardware watchpoint 2: x (gdb) step Warning: Cannot insert breakpoint -1. Cannot access memory at address 0x1 Command aborted.
编译器生成的汇编示例
.file "main.zu" .text globl main .file 0 "main.zu" .Ltext0: .weak .Ltext0 .loc 0 1 6 .Ldie1_debug_start: .type main, @function main: .loc 0 1 17 .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 movq %rsp, %rbp .cfi_def_cfa_register 6 .loc 0 1 26 # Variable declaration for 'stinky' movq $415, -8(%rbp) # End of variable declaration for 'stinky' movq $913, -8(%rbp) movq $69, %rdi movq $60, %rax syscall # SYS_EXIT ret .Ldie1_debug_end: .cfi_endproc .size main, .-main .Ldebug_text0: .section .debug_info,"",@progbits .long .Ldebug_end - .Ldebug_info .Ldebug_info: .weak .Ldebug_info .word 0x5 .byte 0x1 .byte 0x8 .long .Ldebug_abbrev .uleb128 1 .long .Ldebug_producer_string .byte 0x8042 .long .Ldebug_file_string .long .Ldebug_file_dir .quad .Ltext0 .quad .Ldebug_text0 - .Ltext0 .long .Ldebug_line0 .uleb128 2 .long .Ldie1_string .byte 0 .byte 1 .byte 17 .long .Lint_debug_type .quad .Ldie1_debug_start .quad .Ldie1_debug_end - .Ldie1_debug_start .uleb128 0x01 .byte 0x9c .uleb128 7 .long .Ldie2_string .byte 0 .byte 2 .byte 7 .long .Lint_debug_type .uleb128 0x02 .byte 0x91 .sleb128 -24 .byte 0 .Lint_debug_type: .uleb128 8 .byte 8 .byte 5 .string "int" .Lfloat_debug_type: .uleb128 8 .byte 4 .byte 4 .string "float" .Lstr_debug_type: .uleb128 9 .byte 8 .long .Lchar_debug_type .Lchar_debug_type: .uleb128 8 .byte 1 .byte 6 .string "char" .byte 0 .Ldebug_end: .section .debug_abbrev,"",@progbits .Ldebug_abbrev: .uleb128 1 .uleb128 0x11 # TAG_compile_unit .byte 0x1 # No children .uleb128 0x25 # AT_producer .uleb128 0xe # FORM_strp .uleb128 0x13 # AT_language .uleb128 0xb # FORM_data1 .uleb128 0x3 # AT_name .uleb128 0x1f # FORM_line_strp .uleb128 0x1b # AT_comp_dir .uleb128 0x1f # FORM_line_strp .uleb128 0x11 # AT_low_pc .uleb128 0x1 # FORM_addr .uleb128 0x12 # AT_high_pc .uleb128 0x7 # FORM_data8 .uleb128 0x10 # AT_stmt_list .uleb128 0x17 # FORM_sec_offset .byte 0 .byte 0 .uleb128 2 .uleb128 0x2e # TAG_subprogram - FunctionNoParams, non-void .byte 0x1 # Has children .uleb128 0x3f # AT_external .uleb128 0x19 # FORM_flag_present .uleb128 0x3 # AT_name .uleb128 0xe # FORM_strp .uleb128 0x3a # AT_decl_file .uleb128 0xb # FORM_data1 .uleb128 0x3b # AT_decl_line .uleb128 0xb # FORM_data1 .uleb128 0x39 # AT_decl_column .uleb128 0xb # FORM_data1 .uleb128 0x49 # AT_type .uleb128 0x13 # FORM_ref4 .uleb128 0x11 # AT_low_pc .uleb128 0x1 # FORM_addr .uleb128 0x12 # AT_high_pc .uleb128 0x7 # FORM_data8 .uleb128 0x40 # AT_frame_base .uleb128 0x18 # FORM_exprloc .uleb128 0x7a # AT_call_all_calls .uleb128 0x19 # FORM_flag_present .byte 0 .byte 0 .uleb128 7 .uleb128 0x34 # TAG_variable .byte 0 # No children .uleb128 0x3 # AT_name .uleb128 0xe # FORM_strp .uleb128 0x3a # AT_decl_file .uleb128 0xb # FORM_data1 .uleb128 0x3b # AT_decl_line .uleb128 0xb # FORM_data1 .uleb128 0x39 # AT_decl_column .uleb128 0xb # FORM_data1 .uleb128 0x49 # AT_type .uleb128 0x13 # FORM_ref4 .uleb128 0x2 # AT_location .uleb128 0x18 # FORM_exprloc .byte 0 .byte 0 .uleb128 8 .uleb128 0x24 # TAG_base_type .byte 0 # no children .uleb128 0xb # AT_byte_size .uleb128 0xb # FORM_data1 .uleb128 0x3e # AT_encoding .uleb128 0xb # FORM_data1 .uleb128 0x3 # AT_name .uleb128 0x8 # FORM_string .byte 0 .byte 0 .uleb128 9 .uleb128 0xF # TAG_pointer_type .byte 0 # No children .uleb128 0xB # AT_byte_size .uleb128 0xb # FORM_data1 .uleb128 0x49 # AT_type .uleb128 0x13 # FORM_ref4 .byte 0 .byte 0 .byte 0 .byte 0 .section .debug_aranges,"",@progbits .Ldebug_aranges: .long .Ldebug_aranges_end - 4 - .Ldebug_aranges .value 0x5 .long .Ldebug_text0 .byte 0x8 .byte 0x0 .value 0 .value 0 .quad .Ltext0 .quad .Ldebug_text0-.Ltext0 .quad 0 .quad 0 .Ldebug_aranges_end: .section .debug_line,"",@progbits .Ldebug_line0: .section .debug_str,"MS",@progbits,1 .Ldebug_producer_string: .string "Zura compiler v0.1.25" .Ldie1_string: .string "main" .Ldie2_string: .string "stinky" .section .debug_line_str,"MS",@progbits,1 .Ldebug_file_string: .string "main.zu" .Ldebug_file_dir: .string "zura_files"
排查方向
帧基地址定义错误
当前TAG_subprogram的AT_frame_base使用0x9c(对应DW_OP_call_frame_cfa),但x86-64下函数帧基地址应绑定到rbp,正确表达式应为DW_OP_breg6, 0(即rbp+0)。DW_OP_fbreg的偏移是相对于帧基地址计算的,若帧基地址与实际栈布局不匹配,会直接导致变量地址计算错误。偏移值逻辑错误
变量实际存储在-8(%rbp),若帧基地址设为rbp,DW_OP_fbreg的偏移应直接写-8而非-24。C语言中用-16偏移是因为其帧基地址绑定到CFA(rsp+16),计算后得到-8(%rbp),但你的帧基地址规则与C语言不一致,不能直接套用该偏移。函数地址范围异常
TAG_subprogram的AT_low_pc指向.Ldie1_debug_start(位于main:标签之前),导致函数地址范围包含了函数定义前的无关代码,可能让GDB误解变量的有效作用域,应将.Ldie1_debug_start移至main:标签之后、.cfi_startproc之前。DWARF条目嵌套与作用域
确认TAG_variable是否正确嵌套在对应TAG_subprogram的子节点下,且变量的生命周期与代码范围匹配,避免GDB在变量未生效的阶段尝试访问其地址。
内容的提问来源于stack exchange,提问作者Connor

