From 09292f4ae2ccb46130652f6b310ee7a5227326d3 Mon Sep 17 00:00:00 2001 From: Indu Bhagat Date: Tue, 19 Aug 2025 01:08:06 -0700 Subject: [PATCH] binutils: dwarf: fix display of large cfa_offset eh_frame textual dump was not correct when the cfa_offset is a large value. The reason is that the dumping code generally assumes the cfa_offset is an 'int'. cfa_offset values can be updated by various DWARF opcodes, like: - DW_CFA_def_cfa, DW_CFA_def_cfa_offset which bring unsigned leb128 cfa_offset - DW_CFA_def_cfa_sf, DW_CFA_def_cfa_offset_sf which bring signed leb128 cfa_offset Internally, the routines in dwarf.c keep the value as 'uint64_t cfa_offset'. That size of the datatype is expected to work for most of the real-world cases. Care, however, needs to be taken when it comes to the signedness of the value. Fix the buggy behavior by adding an additional field to track whether the value of cfa_offset is signed or unsigned and display accordingly for "frames-interp" output. The display of cfa_offset had issues in both "frames-interp" output (objdump -WF or do_debug_frames_interp) and the "frames" output. Add two new tests: cfi-common-10.s uses a large positive cfa_offset (with "frames output), and cfi-x86_64-2.s uses a negative cfa_offset (with "frames-interp" output). ChangeLog: * binutils/dwarf.c (frame_display_row): Update format string based on signedness. (display_debug_frames): Track signedness. Also fix display of cfa_offset using PRIu64 or PRId64 as applicable. * gas/testsuite/gas/cfi/cfi.exp: Add two new tests. * gas/testsuite/gas/cfi/cfi-common-10.d: New test. * gas/testsuite/gas/cfi/cfi-common-10.s: New test. * gas/testsuite/gas/cfi/cfi-x86_64-2.d: New test. * gas/testsuite/gas/cfi/cfi-x86_64-2.s: New test. --- binutils/dwarf.c | 17 +++++++++++++---- gas/testsuite/gas/cfi/cfi-common-10.d | 19 +++++++++++++++++++ gas/testsuite/gas/cfi/cfi-common-10.s | 5 +++++ gas/testsuite/gas/cfi/cfi-x86_64-2.d | 14 ++++++++++++++ gas/testsuite/gas/cfi/cfi-x86_64-2.s | 5 +++++ gas/testsuite/gas/cfi/cfi.exp | 2 ++ 6 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 gas/testsuite/gas/cfi/cfi-common-10.d create mode 100644 gas/testsuite/gas/cfi/cfi-common-10.s create mode 100644 gas/testsuite/gas/cfi/cfi-x86_64-2.d create mode 100644 gas/testsuite/gas/cfi/cfi-x86_64-2.s diff --git a/binutils/dwarf.c b/binutils/dwarf.c index f4bcb677761..bc5aa2b6b1b 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -8574,6 +8574,7 @@ typedef struct Frame_Chunk uint64_t pc_range; unsigned int cfa_reg; uint64_t cfa_offset; + bool cfa_ofs_signed_p; unsigned int ra; unsigned char fde_encoding; unsigned char cfa_exp; @@ -9071,7 +9072,8 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg if (fc->cfa_exp) strcpy (tmp, "exp"); else - sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), (int) fc->cfa_offset); + sprintf (tmp, (fc->cfa_ofs_signed_p ? "%s%+" PRId64 : "%s+%" PRIu64), + regname (fc->cfa_reg, 1), fc->cfa_offset); printf ("%-8s ", tmp); for (r = 0; r < fc->ncols; r++) @@ -9794,6 +9796,7 @@ display_debug_frames (struct dwarf_section *section, fc->data_factor = cie->data_factor; fc->cfa_reg = cie->cfa_reg; fc->cfa_offset = cie->cfa_offset; + fc->cfa_ofs_signed_p = cie->cfa_ofs_signed_p; fc->ra = cie->ra; if (frame_need_space (fc, max_regs > 0 ? max_regs - 1: 0) < 0) { @@ -10263,6 +10266,7 @@ display_debug_frames (struct dwarf_section *section, printf (" DW_CFA_remember_state\n"); rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); rs->cfa_offset = fc->cfa_offset; + rs->cfa_ofs_signed_p = fc->cfa_ofs_signed_p; rs->cfa_reg = fc->cfa_reg; rs->ra = fc->ra; rs->cfa_exp = fc->cfa_exp; @@ -10285,6 +10289,7 @@ display_debug_frames (struct dwarf_section *section, { remembered_state = rs->next; fc->cfa_offset = rs->cfa_offset; + fc->cfa_ofs_signed_p = rs->cfa_ofs_signed_p; fc->cfa_reg = rs->cfa_reg; fc->ra = rs->ra; fc->cfa_exp = rs->cfa_exp; @@ -10311,10 +10316,11 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa: READ_ULEB (fc->cfa_reg, start, block_end); READ_ULEB (fc->cfa_offset, start, block_end); + fc->cfa_ofs_signed_p = false; fc->cfa_exp = 0; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa: %s ofs %d\n", - regname (fc->cfa_reg, 0), (int) fc->cfa_offset); + printf (" DW_CFA_def_cfa: %s ofs %" PRIu64 "\n", + regname (fc->cfa_reg, 0), fc->cfa_offset); break; case DW_CFA_def_cfa_register: @@ -10327,8 +10333,9 @@ display_debug_frames (struct dwarf_section *section, case DW_CFA_def_cfa_offset: READ_ULEB (fc->cfa_offset, start, block_end); + fc->cfa_ofs_signed_p = false; if (! do_debug_frames_interp) - printf (" DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset); + printf (" DW_CFA_def_cfa_offset: %" PRIu64 "\n", fc->cfa_offset); break; case DW_CFA_nop: @@ -10448,6 +10455,7 @@ display_debug_frames (struct dwarf_section *section, ofs = sofs; ofs *= fc->data_factor; fc->cfa_offset = ofs; + fc->cfa_ofs_signed_p = true; fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_sf: %s ofs %" PRId64 "\n", @@ -10459,6 +10467,7 @@ display_debug_frames (struct dwarf_section *section, ofs = sofs; ofs *= fc->data_factor; fc->cfa_offset = ofs; + fc->cfa_ofs_signed_p = true; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_offset_sf: %" PRId64 "\n", ofs); break; diff --git a/gas/testsuite/gas/cfi/cfi-common-10.d b/gas/testsuite/gas/cfi/cfi-common-10.d new file mode 100644 index 00000000000..826e2364444 --- /dev/null +++ b/gas/testsuite/gas/cfi/cfi-common-10.d @@ -0,0 +1,19 @@ +#objdump: -Wf +#name: CFI common 10 +#... +Contents of the .eh_frame section: + +00000000 0+0014 0+0000 CIE + Version: 1 + Augmentation: "zR" + Code alignment factor: .* + Data alignment factor: .* + Return address column: .* + Augmentation data: [01][abc] +#... + +00000018 0+00(18|1c) 0+001c FDE cie=0+0000 pc=.* +#... + DW_CFA_advance_loc: 4 to 0+0004 + DW_CFA_def_cfa_offset: 1099511627808 +#... diff --git a/gas/testsuite/gas/cfi/cfi-common-10.s b/gas/testsuite/gas/cfi/cfi-common-10.s new file mode 100644 index 00000000000..166f1fc58f4 --- /dev/null +++ b/gas/testsuite/gas/cfi/cfi-common-10.s @@ -0,0 +1,5 @@ + .cfi_sections .eh_frame + .cfi_startproc + .long 0 + .cfi_def_cfa_offset 1099511627808 + .cfi_endproc diff --git a/gas/testsuite/gas/cfi/cfi-x86_64-2.d b/gas/testsuite/gas/cfi/cfi-x86_64-2.d new file mode 100644 index 00000000000..b1f21dcc3a9 --- /dev/null +++ b/gas/testsuite/gas/cfi/cfi-x86_64-2.d @@ -0,0 +1,14 @@ +#objdump: -WF +#name: CFI on x86-64 DW_CFA_def_cfa_offset_sf +#... +Contents of the .eh_frame section: + + +0+0000 0+0014 0+000 CIE "zR" cf=1 df=-8 ra=(16|32) + +LOC +CFA +ra + +0+0000 rsp\+8 +c-8 + + +0+0018 0+0014 0+001c FDE cie=0+0000 pc=0+0000..0+0004 + +LOC +CFA +ra + +0+0000 rsp\+8 +c-8 + +0+0004 rsp-32 +c-8 + diff --git a/gas/testsuite/gas/cfi/cfi-x86_64-2.s b/gas/testsuite/gas/cfi/cfi-x86_64-2.s new file mode 100644 index 00000000000..95c52373539 --- /dev/null +++ b/gas/testsuite/gas/cfi/cfi-x86_64-2.s @@ -0,0 +1,5 @@ + .cfi_sections .eh_frame + .cfi_startproc + .long 0 + .cfi_def_cfa_offset -32 + .cfi_endproc diff --git a/gas/testsuite/gas/cfi/cfi.exp b/gas/testsuite/gas/cfi/cfi.exp index 83d393cab7c..d89a102c885 100644 --- a/gas/testsuite/gas/cfi/cfi.exp +++ b/gas/testsuite/gas/cfi/cfi.exp @@ -42,6 +42,7 @@ if { [istarget "i*86-*-*"] || [istarget "x86_64-*-*"] } then { if { [gas_x86_64_check] } then { set ASFLAGS "$ASFLAGS --64" run_dump_test "cfi-x86_64" + run_dump_test "cfi-x86_64-2" set ASFLAGS "$old_ASFLAGS" } @@ -139,6 +140,7 @@ if { ![istarget "hppa64*-*"] } then { run_dump_test "cfi-common-7" run_dump_test "cfi-common-8" run_dump_test "cfi-common-9" + run_dump_test "cfi-common-10" run_dump_test "cie-version-0" run_dump_test "cie-version-1" -- 2.47.3