Skip to content

Commit 5a06855

Browse files
authored
学习gdb-从pr开始
Add detailed analysis and solution for frame base address issue in GDB on LoongArch architecture.
1 parent d0f528c commit 5a06855

File tree

1 file changed

+184
-0
lines changed

1 file changed

+184
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
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

Comments
 (0)