From: Simon Marchi Date: Thu, 23 Apr 2026 17:37:06 +0000 (-0400) Subject: gdb/dwarf: fix internal error in dwarf2_fetch_cfa_info for FDEs without a CFA rule X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=38e1f10568dc62a9c7fb1fb2f508595d787d0171;p=thirdparty%2Fbinutils-gdb.git gdb/dwarf: fix internal error in dwarf2_fetch_cfa_info for FDEs without a CFA rule Commit a910478f65a5 ("gdb/dwarf: fix internal error when FDEs do not describe the CFA") fixed the switch on cfa_how in dwarf2_frame_cache, but there is a very similar switch in dwarf2_fetch_cfa_info that has the same issue. If the unwind info does not set a rule for the CFA, fs.regs.cfa_how is left as CFA_UNSET and we hit the default case, triggering an internal error. dwarf2_fetch_cfa_info is called from two places, both while compiling a DWARF expression that contains DW_OP_call_frame_cfa: - dwarf2_compile_expr_to_ax, when compiling to agent-expression bytecode - do_compile_dwarf_expr_to_c, when compiling to C source (used by the "compile" commands). Unlike dwarf2_frame_cache, where we can degrade gracefully by setting undefined_retaddr, the callers of dwarf2_fetch_cfa_info need a concrete CFA to generate code, so we can't continue. Throw an error with the same message used a few lines above, when the FDE itself cannot be found. Extend the debug-frame-no-cfa.exp test to reproduce this case: add a compile unit describing the "main" function and with a DW_AT_frame_base that uses DW_OP_call_frame_cfa and a local variable "x" that uses DW_OP_fbreg (the evaluation of which requires the CFA). Then, try to translate the location of "x" to agent-expression bytecode with "maint" agent. This hits the internal error without the corresponding fix. Change-Id: I82349e3d9259c8f943eabee5c2fce360876feee8 Approved-by: Kevin Buettner --- diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c index 2301d914637..70895e90696 100644 --- a/gdb/dwarf2/frame.c +++ b/gdb/dwarf2/frame.c @@ -793,6 +793,9 @@ dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc, /* Calculate the CFA. */ switch (fs.regs.cfa_how) { + case CFA_UNSET: + error (_("Could not compute CFA; needed to translate this expression")); + case CFA_REG_OFFSET: { int regnum = dwarf_reg_to_regnum_or_error (gdbarch, fs.regs.cfa_reg); diff --git a/gdb/testsuite/gdb.dwarf2/debug-frame-no-cfa.exp b/gdb/testsuite/gdb.dwarf2/debug-frame-no-cfa.exp index 8442b5c3ddb..3f7d77cf074 100644 --- a/gdb/testsuite/gdb.dwarf2/debug-frame-no-cfa.exp +++ b/gdb/testsuite/gdb.dwarf2/debug-frame-no-cfa.exp @@ -26,6 +26,36 @@ set asm_file [standard_output_file $srcfile2] Dwarf::assemble $asm_file { get_func_info main + cu { version 5 } { + DW_TAG_compile_unit { + DW_AT_name debug-frame-no-cfa.c + DW_AT_comp_dir /tmp + } { + declare_labels int_type_label + + int_type_label: DW_TAG_base_type { + DW_AT_name "int" + DW_AT_encoding @DW_ATE_signed + DW_AT_byte_size 4 DW_FORM_sdata + } + + DW_TAG_subprogram { + MACRO_AT_func { main } + DW_AT_frame_base { + DW_OP_call_frame_cfa + } SPECIAL_expr + } { + DW_TAG_variable { + DW_AT_name x + DW_AT_type :$int_type_label + DW_AT_location { + DW_OP_fbreg 0 + } SPECIAL_expr + } + } + } + } + frame { declare_labels cie_label @@ -52,3 +82,9 @@ if { ![runto_main] } { # Make sure to match a single line, so that the test fails if an error # about stack unwind is printed after frame 0. gdb_test "backtrace" "^#0 \[^\r\n\]* main \[^\r\n\]*" + +# Translating the location of "x" to an agent expression requires +# evaluating its frame base, which uses DW_OP_call_frame_cfa. This would +# cause an internal error in dwarf2_fetch_cfa_info. +gdb_test "maint agent x" \ + "Could not compute CFA; needed to translate this expression"