From: Hui Li Date: Wed, 17 Sep 2025 08:39:06 +0000 (+0800) Subject: gdb: LoongArch: Record correct frame base address X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a4b1ac7f1f3b5eb05d35226017f9b7cc8bc94ac3;p=thirdparty%2Fbinutils-gdb.git gdb: LoongArch: Record correct frame base address (1) Description of Problem: The frame_base structure is defined in gdb/frame-base.h, a typical implementation of frame_base is return the same value for frame base, locals base and args base. When debugging following code on LoongArch, the outputs of locals base and args base are not equal to frame base address in frame base register. The frame base register is sp(r3) or fp(r22) on LoongArch. This problem only occurs when frame base register is sp, there is no problem when fp is used as frame base register. When using gcc option -fomit-frame-pointer or writing asm code without using fp, the frame base register is sp. $ cat test.c int main() { unsigned long a= 1, b = 1; a = 2; b = 2; return 0; } $ gcc -g -fomit-frame-pointer test.c -o test $ gdb test ... (gdb) start ... Temporary breakpoint 1, main () at test.c:4 4 unsigned long a= 1, b = 1; (gdb) disas Dump of assembler code for function main: 0x0000555555554740 <+0>: addi.d $sp, $sp, -16 => 0x0000555555554744 <+4>: li.w $t0, 1 0x0000555555554748 <+8>: st.d $t0, $sp, 8 0x000055555555474c <+12>: li.w $t0, 1 0x0000555555554750 <+16>: stptr.d $t0, $sp, 0 0x0000555555554754 <+20>: li.w $t0, 2 0x0000555555554758 <+24>: st.d $t0, $sp, 8 0x000055555555475c <+28>: li.w $t0, 2 0x0000555555554760 <+32>: stptr.d $t0, $sp, 0 0x0000555555554764 <+36>: move $t0, $zero 0x0000555555554768 <+40>: move $a0, $t0 0x000055555555476c <+44>: addi.d $sp, $sp, 16 0x0000555555554770 <+48>: ret End of assembler dump. (gdb) p $sp $1 = (void *) 0x7ffffffeb130 (gdb) info frame Stack level 0, frame at 0x7ffffffeb140: pc = 0x555555554744 in main (test.c:4); saved pc = 0x7ffff7e3d874 source language c. Arglist at 0x7ffffffeb140, args: Locals at 0x7ffffffeb140, Previous frame's sp is 0x7ffffffeb140 (2) Root Cause Analysis: When we use the info frame command, the addresses of previous frame's sp, arglist and locals will be printed, the arglist and locals addresses are calculated by member function of frame_base. Because LoongArch does not implement its own frame_base, a default_frame_base will be used, it will return stack address of the frame ID for frame base, locals base and args base. However, on LoongArch or other architectures, the frame base address does not always equal the stack address of the frame ID. (3) Solution: Implement loongarch_frame_base structure and loongarch_frame_base_address() to record the correct frame base address stored in sp or fp register. It can be calculated by subtracting the framebase_offset from the prev_sp recorded in loongarch_frame_cache. And locals base and args base here are equal to frame base. (4) Test: (gdb) p $sp $1 = (void *) 0x7ffffffeb130 (gdb) info frame Stack level 0, frame at 0x7ffffffeb140: pc = 0x555555554744 in main (test.c:4); saved pc = 0x7ffff7e3d874 source language c. Arglist at 0x7ffffffeb130, args: Locals at 0x7ffffffeb130, Previous frame's sp is 0x7ffffffeb140 This modification only change the output of the info frame command when sp is used as frame base register, and has no affect other functions of gdb on LoongArch. Signed-off-by: Hui Li Signed-off-by: Tiezhu Yang --- diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c index f88fb5f0b09..e94b88bc010 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -22,6 +22,7 @@ #include "dwarf2/frame.h" #include "elf-bfd.h" #include "extract-store-integer.h" +#include "frame-base.h" #include "frame-unwind.h" #include "gdbcore.h" #include "linux-record.h" @@ -787,6 +788,26 @@ static const struct frame_unwind_legacy loongarch_frame_unwind ( /*.prev_arch =*/nullptr ); +/* Return the frame base address of *THIS_FRAME. */ + +static CORE_ADDR +loongarch_frame_base_address (const frame_info_ptr &this_frame, void **this_cache) +{ + struct loongarch_frame_cache *cache + = loongarch_frame_cache (this_frame, this_cache); + + return cache->prev_sp - cache->framebase_offset; +} + +/* LoongArch default frame base information. */ +static frame_base loongarch_frame_base = +{ + &loongarch_frame_unwind, + loongarch_frame_base_address, + loongarch_frame_base_address, + loongarch_frame_base_address +}; + /* Write the contents of buffer VAL into the general-purpose argument register defined by GAR in REGCACHE. GAR indicates the available general-purpose argument registers which should be a value in the @@ -2207,6 +2228,8 @@ loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) dwarf2_append_unwinders (gdbarch); frame_unwind_append_unwinder (gdbarch, &loongarch_frame_unwind); + frame_base_set_default (gdbarch, &loongarch_frame_base); + /* Hook in OS ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); set_gdbarch_register_reggroup_p (gdbarch, loongarch_register_reggroup_p);