gpt4 book ai didi

debugging - ARM 中 DWARF 信息中的局部变量位置

转载 作者:行者123 更新时间:2023-12-04 02:20:31 27 4
gpt4 key购买 nike

我在文件 delay.c 中有一个 C 程序:

void delay(int num)
{
volatile int i;
for(i=0; i<num; i++);
}

然后我使用命令 gcc -g -O1 -o delay.o delay.c 在 ARM 模拟器(更具体地说是 armel)上用 gcc 4.6.3 编译程序.组装在 delay.o是:
00000000 <delay>:
0: e24dd008 sub sp, sp, #8
4: e3a03000 mov r3, #0
8: e58d3004 str r3, [sp, #4]
c: e59d3004 ldr r3, [sp, #4]
10: e1500003 cmp r0, r3
14: da000005 ble 30 <delay+0x30>
18: e59d3004 ldr r3, [sp, #4]
1c: e2833001 add r3, r3, #1
20: e58d3004 str r3, [sp, #4]
24: e59d3004 ldr r3, [sp, #4]
28: e1530000 cmp r3, r0
2c: bafffff9 blt 18 <delay+0x18>
30: e28dd008 add sp, sp, #8
34: e12fff1e bx lr

我想弄清楚变量 i 在哪里位于函数堆栈 delay 上从调试信息。以下是关于 delay的信息和 i.debug_info部分:
<1><25>: Abbrev Number: 2 (DW_TAG_subprogram)
<26> DW_AT_external : 1
<27> DW_AT_name : (indirect string, offset: 0x19): delay
<2b> DW_AT_decl_file : 1
<2c> DW_AT_decl_line : 1
<2d> DW_AT_prototyped : 1
<2e> DW_AT_low_pc : 0x0
<32> DW_AT_high_pc : 0x38
<36> DW_AT_frame_base : 0x0 (location list)
<3a> DW_AT_sibling : <0x59>
...
<2><4b>: Abbrev Number: 4 (DW_TAG_variable)
<4c> DW_AT_name : i
<4e> DW_AT_decl_file : 1
<4f> DW_AT_decl_line : 3
<50> DW_AT_type : <0x60>
<54> DW_AT_location : 0x20 (location list)

显示 i的位置位于位置列表中。所以我输出位置列表:
Offset   Begin    End      Expression
00000000 00000000 00000004 (DW_OP_breg13 (r13): 0)
00000000 00000004 00000038 (DW_OP_breg13 (r13): 8)
00000000 <End of list>
00000020 0000000c 00000020 (DW_OP_fbreg: -12)
00000020 00000024 00000028 (DW_OP_reg3 (r3))
00000020 00000028 00000038 (DW_OP_fbreg: -12)
00000020 <End of list>

从地址 4 到 38, delay 的框架基址应该是 r13 + 8 .所以从地址c到20,从地址28到38, i的位置是 r13 + 8 -12 = r13 - 4 .

但是,从装配中我们可以知道没有位置 r13 - 4i显然在位置 r13 + 4 .

我错过了一些计算步骤吗?任何人都可以解释 i的区别从调试信息计算和汇编计算之间的位置?

提前致谢!

最佳答案

TL;博士 问题中的分析是正确的,差异是 gcc 组件之一中的错误(GNU Arm Embedded Toolchain 是一个明显的记录位置)。

目前,this other answer是不正确的,因为它错误地将计算位置表达式时的堆栈指针值与函数入口时堆栈指针的较早值混为一谈。

就矮人而言,i的位置因程序计数器而异。例如,考虑文本地址 delay+0x18 .此时,i的位置由 DW_OP_fbreg(-12) 给出,即帧基以下 12 个字节。框架基础由父项 DW_TAG_subprogram 提供的 DW_AT_frame_base在这种情况下,属性也取决于程序计数器:对于 delay+0x18它的表达式是 DW_OP_breg13(8) ,即 r13 + 8 .重要的是,此计算使用 当前 r13 的值,即 r13 的值当程序计数器等于 delay+0x18 .

因此,DWARF 断言,在 delay+0x18 , i位于 r13 + 8 - 12 ,即现有堆栈底部以下 4 个字节。对组件的检查表明,在 delay+018 , i应该找到 4 个字节 以上 堆栈的底部。因此 DWARF 是错误的,无论生成什么都是有缺陷的。

可以使用 gdb 演示该错误在问题中提供的测试用例周围有一个简单的包装器:

$ cat delay.c
void delay(int num)
{
volatile int i;
for(i=0; i<num; i++);
}
$ gcc-4.6 -g -O1 -c delay.c
$ cat main.c
void delay(int);

int main(int argc, char **argv) {
delay(3);
}
$ gcc-4.6 -o test main.c delay.o
$ gdb ./test
.
.
.
(gdb)

delay+0x18 处设置断点并运行到第二次出现(我们预计 i 为 1):
(gdb) break *delay+0x18
Breakpoint 1 at 0x103cc: file delay.c, line 4.
(gdb) run
Starting program: /home/pi/test

Breakpoint 1, 0x000103cc in delay (num=3) at delay.c:4
4 for(i=0; i<num; i++);
(gdb) cont
Continuing.

Breakpoint 1, 0x000103cc in delay (num=3) at delay.c:4
4 for(i=0; i<num; i++);
(gdb)

我们从拆解中得知 i是堆栈指针上方的四个字节。确实,它是:
(gdb) print *((int *)($r13 + 4))
$1 = 1
(gdb)

然而,虚假的 DWARF 意味着 gdb 看起来在错误的地方:
(gdb) print i
$2 = 0
(gdb)

如上所述,DWARF 错误地给出了 i 的位置。在堆栈指针下方的四个字节处。那里有一个零,因此报告的值为 i :
(gdb)  print *((int *)($r13 - 4))
$3 = 0
(gdb)

这不是巧合。当 gdb 时,写入堆栈指针下方这个虚假位置的魔数(Magic Number)再次出现。被要求打印 i :
(gdb) set *((int *)($r13 - 4)) = 42
(gdb) print i
$6 = 42
(gdb)

因此,在 delay+0x18 , DWARF 错误地编码了 i 的位置如 r13 - 4即使它的真实位置是 r13 + 4 .

可以通过手动编辑编译单元并替换 DW_OP_fbreg(-12) 来更进一步。 (字节 0x91 0x74)与 DW_OP_fbreg(-4) (字节 0x91 0x7c)。这给
$ readelf --debug-dump=loc delay.modified.o 
Contents of the .debug_loc section:

Offset Begin End Expression
00000000 00000000 00000004 (DW_OP_breg13 (r13): 0)
0000000c 00000004 00000038 (DW_OP_breg13 (r13): 8)
00000018 <End of list>
00000020 0000000c 00000020 (DW_OP_fbreg: -4)
0000002c 00000024 00000028 (DW_OP_reg3 (r3))
00000037 00000028 00000038 (DW_OP_fbreg: -4)
00000043 <End of list>

$

换句话说,DWARF 已被更正,例如,在 delay+0x18 i的位置给出为 frame base - 4 = r13 + 8 - 4 = r13 + 4 , 匹配程序集。使用修正后的 DWARF 重复 gdb 实验显示预期值 i每次循环:
$ gcc-4.6 -o test.modified main.c delay.modified.o
$ gdb ./test.modified
.
.
.
(gdb) break *delay+0x18
Breakpoint 1 at 0x103cc: file delay.c, line 4.
(gdb) run
Starting program: /home/pi/test.modified

Breakpoint 1, 0x000103cc in delay (num=3) at delay.c:4
4 for(i=0; i<num; i++);
(gdb) print i
$1 = 0
(gdb) cont
Continuing.

Breakpoint 1, 0x000103cc in delay (num=3) at delay.c:4
4 for(i=0; i<num; i++);
(gdb) print i
$2 = 1
(gdb) cont
Continuing.

Breakpoint 1, 0x000103cc in delay (num=3) at delay.c:4
4 for(i=0; i<num; i++);
(gdb) print i
$3 = 2
(gdb) cont
Continuing.
[Inferior 1 (process 30954) exited with code 03]
(gdb)

关于debugging - ARM 中 DWARF 信息中的局部变量位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47359841/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com