|
| 1 | +pr 地址 https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=a4b1ac7f1f3b5eb05d35226017f9b7cc8bc94ac3 |
| 2 | +# 1 解析标题 |
| 3 | +``` |
| 4 | +gdb: LoongArch: Record correct frame base address |
| 5 | +``` |
| 6 | +可以理解这是为了记录正确的栈基地址,说明在提交之前 gdb 反馈的栈基地址是错误的 |
| 7 | + |
| 8 | +# 2 解析摘要 |
| 9 | +## 问题描述 |
| 10 | +``` |
| 11 | + |
| 12 | +Description of Problem: |
| 13 | +The frame_base structure is defined in gdb/frame-base.h, a typical |
| 14 | +implementation of frame_base is return the same value for frame base, |
| 15 | +locals base and args base. When debugging following code on LoongArch, |
| 16 | +the outputs of locals base and args base are not equal to frame base |
| 17 | +address in frame base register. The frame base register is sp(r3) or |
| 18 | +fp(r22) on LoongArch. This problem only occurs when frame base register |
| 19 | +is sp, there is no problem when fp is used as frame base register. When |
| 20 | +using gcc option -fomit-frame-pointer or writing asm code without using |
| 21 | +fp, the frame base register is sp. |
| 22 | +``` |
| 23 | +frame base address 栈帧基地址: 整个栈帧的关键地址,固定指向一点 |
| 24 | +locals base address 局部变量基地址: gdb定位局部变量的基地址 |
| 25 | +args base addrss 参数变量基地址:gdb定位参数变量的基地址 |
| 26 | +LoongArch 的函数栈帧可以用两种寄存器定义“基地址”: |
| 27 | +帧指针 (fp):寄存器 $r22 |
| 28 | +栈指针 (sp):寄存器 $r3 |
| 29 | + |
| 30 | +此处可以知道基地址的数据结构在frame-bash文件中定义,且说明了gdb调试过程中每个函数均有对应的栈帧,存储着frame base(基地址)、locals base(当前地址)和args base (参数基地址) |
| 31 | +当在la机器上进行debug时,涉及一个简单文件,预想local base和arg base与frame base address 相同,但是在使用-fomit-frame-pointer 指定不使用fp作为基地址时,问题出现了,frame base与其他两者地址不同。 |
| 32 | + |
| 33 | +## 测试代码及结果 |
| 34 | +``` |
| 35 | +$ cat test.c |
| 36 | +int main() |
| 37 | +{ |
| 38 | + unsigned long a= 1, b = 1; |
| 39 | + a = 2; |
| 40 | + b = 2; |
| 41 | + return 0; |
| 42 | +} |
| 43 | +$ gcc -g -fomit-frame-pointer test.c -o test |
| 44 | +$ gdb test |
| 45 | +... |
| 46 | +(gdb) start |
| 47 | +... |
| 48 | +Temporary breakpoint 1, main () at test.c:4 |
| 49 | +4 unsigned long a= 1, b = 1; |
| 50 | +(gdb) disas |
| 51 | +Dump of assembler code for function main: |
| 52 | + 0x0000555555554740 <+0>: addi.d $sp, $sp, -16 |
| 53 | +=> 0x0000555555554744 <+4>: li.w $t0, 1 |
| 54 | + 0x0000555555554748 <+8>: st.d $t0, $sp, 8 |
| 55 | + 0x000055555555474c <+12>: li.w $t0, 1 |
| 56 | + 0x0000555555554750 <+16>: stptr.d $t0, $sp, 0 |
| 57 | + 0x0000555555554754 <+20>: li.w $t0, 2 |
| 58 | + 0x0000555555554758 <+24>: st.d $t0, $sp, 8 |
| 59 | + 0x000055555555475c <+28>: li.w $t0, 2 |
| 60 | + 0x0000555555554760 <+32>: stptr.d $t0, $sp, 0 |
| 61 | + 0x0000555555554764 <+36>: move $t0, $zero |
| 62 | + 0x0000555555554768 <+40>: move $a0, $t0 |
| 63 | + 0x000055555555476c <+44>: addi.d $sp, $sp, 16 |
| 64 | + 0x0000555555554770 <+48>: ret |
| 65 | +End of assembler dump. |
| 66 | +(gdb) p $sp |
| 67 | +$1 = (void *) 0x7ffffffeb130 |
| 68 | +(gdb) info frame |
| 69 | +Stack level 0, frame at 0x7ffffffeb140: |
| 70 | + pc = 0x555555554744 in main (test.c:4); saved pc = 0x7ffff7e3d874 |
| 71 | + source language c. |
| 72 | + Arglist at 0x7ffffffeb140, args: |
| 73 | + Locals at 0x7ffffffeb140, Previous frame's sp is 0x7ffffffeb140 |
| 74 | + ``` |
| 75 | +通过上述栈帧可以看到: |
| 76 | +``` |
| 77 | +$sp = 0x7ffffffeb130 |
| 78 | +args base address = 0x7ffffffeb140 |
| 79 | +locals base address = 0x7ffffffeb140 |
| 80 | +``` |
| 81 | +为了对照,我们再运行一组使用fp作为基地址的情况 |
| 82 | +``` |
| 83 | +(gdb) disas |
| 84 | +Dump of assembler code for function main: |
| 85 | + 0x0000555555554758 <+0>: addi.d $sp, $sp, -16 |
| 86 | +=> 0x000055555555475c <+4>: li.w $t0, 1 |
| 87 | + 0x0000555555554760 <+8>: st.d $t0, $sp, 8 |
| 88 | + 0x0000555555554764 <+12>: li.w $t0, 1 |
| 89 | + 0x0000555555554768 <+16>: stptr.d $t0, $sp, 0 |
| 90 | + 0x000055555555476c <+20>: li.w $t0, 2 |
| 91 | + 0x0000555555554770 <+24>: st.d $t0, $sp, 8 |
| 92 | + 0x0000555555554774 <+28>: li.w $t0, 2 |
| 93 | + 0x0000555555554778 <+32>: stptr.d $t0, $sp, 0 |
| 94 | + 0x000055555555477c <+36>: move $t0, $zero |
| 95 | + 0x0000555555554780 <+40>: move $a0, $t0 |
| 96 | + 0x0000555555554784 <+44>: addi.d $sp, $sp, 16 |
| 97 | + 0x0000555555554788 <+48>: ret |
| 98 | +End of assembler dump. |
| 99 | +(gdb) p $sp |
| 100 | +$1 = (void *) 0x7ffffffeec40 |
| 101 | +(gdb) info frame |
| 102 | +Stack level 0, frame at 0x7ffffffeec50: |
| 103 | + pc = 0x55555555475c in main (test.c:3); saved pc = 0x7ffff7e22208 |
| 104 | + source language c. |
| 105 | + Arglist at 0x7ffffffeec50, args: |
| 106 | + Locals at 0x7ffffffeec50, Previous frame's sp is 0x7ffffffeec50 |
| 107 | +``` |
| 108 | +可以看到此时frame address == args address == locals address |
| 109 | + |
| 110 | +## 解决方案 |
| 111 | +(3) Solution: |
| 112 | + |
| 113 | +Implement loongarch_frame_base structure and loongarch_frame_base_address() |
| 114 | +to record the correct frame base address stored in sp or fp register. It can |
| 115 | +be calculated by subtracting the framebase_offset from the prev_sp recorded |
| 116 | +in loongarch_frame_cache. And locals base and args base here are equal to |
| 117 | +frame base. |
| 118 | +不使用默认的frame_base_address函数,引入loongarch_frame_base 自定义的结构体以及loongarch_frame_base_address函数去记录正确的sp/fp地址。 |
| 119 | +可以通过prev_sp(上一个栈帧的sp/fp)减去framebase_offset(偏移量)来修正 |
| 120 | + |
| 121 | +具体代码: |
| 122 | +自己思考一下实现思路: |
| 123 | +首先不再使用默认的frame_base_address获取frame地址 |
| 124 | +其次 查看默认的frame_base_address结构体可以看到: |
| 125 | +``` |
| 126 | +struct frame_base { |
| 127 | + frame_unwind_func *unwind_func; |
| 128 | + frame_base_addr_func *frame_base_address; |
| 129 | + frame_base_addr_func *locals_base_address; |
| 130 | + frame_base_addr_func *args_base_address; |
| 131 | +}; |
| 132 | +``` |
| 133 | +首先,使用同一个默认函数,因此需要将他们拆分开来 |
| 134 | +其次,需要实现一个获取frame地址的函数,计算方式是上一个栈帧的地址-offset,具体实现如下: |
| 135 | + |
| 136 | +``` |
| 137 | +index f88fb5f0b09ef9439e039560041c5693f4f83815..e94b88bc010aebd408f1d6670fbb1e99fcf95895 100644 (file) |
| 138 | +--- a/gdb/loongarch-tdep.c |
| 139 | ++++ b/gdb/loongarch-tdep.c |
| 140 | +@@ -22,6 +22,7 @@ |
| 141 | + #include "dwarf2/frame.h" |
| 142 | + #include "elf-bfd.h" |
| 143 | + #include "extract-store-integer.h" |
| 144 | ++#include "frame-base.h" |
| 145 | + #include "frame-unwind.h" |
| 146 | + #include "gdbcore.h" |
| 147 | + #include "linux-record.h" |
| 148 | +@@ -787,6 +788,26 @@ static const struct frame_unwind_legacy loongarch_frame_unwind ( |
| 149 | + /*.prev_arch =*/nullptr |
| 150 | + ); |
| 151 | + |
| 152 | ++/* Return the frame base address of *THIS_FRAME. */ |
| 153 | ++ |
| 154 | ++static CORE_ADDR |
| 155 | ++loongarch_frame_base_address (const frame_info_ptr &this_frame, void **this_cache) |
| 156 | ++{ |
| 157 | ++ struct loongarch_frame_cache *cache |
| 158 | ++ = loongarch_frame_cache (this_frame, this_cache); |
| 159 | ++ |
| 160 | ++ return cache->prev_sp - cache->framebase_offset; |
| 161 | ++} |
| 162 | ++ |
| 163 | ++/* LoongArch default frame base information. */ |
| 164 | ++static frame_base loongarch_frame_base = |
| 165 | ++{ |
| 166 | ++ &loongarch_frame_unwind, |
| 167 | ++ loongarch_frame_base_address, |
| 168 | ++ loongarch_frame_base_address, |
| 169 | ++ loongarch_frame_base_address |
| 170 | ++}; |
| 171 | ++ |
| 172 | + /* Write the contents of buffer VAL into the general-purpose argument |
| 173 | + register defined by GAR in REGCACHE. GAR indicates the available |
| 174 | + general-purpose argument registers which should be a value in the |
| 175 | +@@ -2207,6 +2228,8 @@ loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) |
| 176 | + dwarf2_append_unwinders (gdbarch); |
| 177 | + frame_unwind_append_unwinder (gdbarch, &loongarch_frame_unwind); |
| 178 | + |
| 179 | ++ frame_base_set_default (gdbarch, &loongarch_frame_base); |
| 180 | ++ |
| 181 | + /* Hook in OS ABI-specific overrides, if they have been registered. */ |
| 182 | + gdbarch_init_osabi (info, gdbarch); |
| 183 | + set_gdbarch_register_reggroup_p (gdbarch, loongarch_register_reggroup_p); |
| 184 | +``` |
0 commit comments