[binutils-gdb] gdb/dwarf: fix internal error in dwarf2_fetch_cfa_info for FDEs without a CFA rule

Simon Marchi via Gdb-cvs <[email protected]>
Newsgroups gmane.comp.gdb.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=38e1f10568dc62a9c7fb1fb2f508595d787d0171

commit 38e1f10568dc62a9c7fb1fb2f508595d787d0171
Author: Simon Marchi <[email protected]>
Date:   Thu Apr 23 13:37:06 2026 -0400

    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 <[email protected]>

Diff:
---
 gdb/dwarf2/frame.c                              |  3 +++
 gdb/testsuite/gdb.dwarf2/debug-frame-no-cfa.exp | 36 +++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

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"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.