当您执行“break function-name"时,GDB 如何确定要中断的地址? [英] How does GDB determine the address to break at when you do "break function-name"?

查看:16
本文介绍了当您执行“break function-name"时,GDB 如何确定要中断的地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个演示我的问题的简单示例:

//test.c#include <stdio.h>int foo1(int i) {我 = 我 * 2;返回我;}无效 foo2(int i) {printf("来自 foo 的问候!i = %i", i);}int main() {诠释 i = 7;foo1(i);foo2(i);返回0;}

<块引用>

$ clang -o test -O0 -Wall -g test.c

在 GDB 中,我执行以下操作并开始执行:

(gdb) b foo1(gdb) b foo2

到达第一个断点后,我反汇编:

(gdb) 反汇编函数 foo1 的汇编代码转储:0x0000000000400530 <+0>:推送%rbp0x0000000000400531 <+1>: mov %rsp,%rbp0x0000000000400534 <+4>: mov %edi,-0x4(%rbp)=>0x0000000000400537 <+7>: mov -0x4(%rbp),%edi0x000000000040053a <+10>: shl $0x1,%edi0x000000000040053d <+13>: mov %edi,-0x4(%rbp)0x0000000000400540 <+16>: mov -0x4(%rbp),%eax0x0000000000400543 <+19>: 弹出 %rbp0x0000000000400544 <+20>: retq汇编程序转储结束.

到达第二个断点后我也这样做:

(gdb) 反汇编函数 foo2 的汇编代码转储:0x0000000000400550 <+0>:推送%rbp0x0000000000400551 <+1>: mov %rsp,%rbp0x0000000000400554 <+4>: sub $0x10,%rsp0x0000000000400558 <+8>: lea 0x400644,%rax0x0000000000400560 <+16>: mov %edi,-0x4(%rbp)=>0x0000000000400563 <+19>: mov -0x4(%rbp),%esi0x0000000000400566 <+22>: mov %rax,%rdi0x0000000000400569 <+25>: 移动 $0x0,%al0x000000000040056b <+27>: callq 0x400410 <printf@plt>0x0000000000400570 <+32>: mov %eax,-0x8(%rbp)0x0000000000400573<+35>:加$0x10,%rsp0x0000000000400577 <+39>: 弹出 %rbp0x0000000000400578 <+40>: retq汇编程序转储结束.

GDB 显然在设置断点时相对于函数的开头使用了不同的偏移量(foo1 中的 +7 和 foo2 中的 +19).如何在不使用 GDB 的情况下自行确定此偏移量?

解决方案

gdb 使用几种方法来决定这些信息.

首先,最好的方法是编译器发出 DWARF 来描述函数.然后 gdb 可以解码 DWARF 以找到序言的结尾.

但是,这并不总是可用的.GCC 会发出它,但 IIRC 仅在使用优化时发出.

我相信还有一个约定,如果一个函数的第一个行号在行表中重复,那么第二个实例的地址被用作序言的结尾.也就是说,如果线条看起来像:

<代码><函数f>第 23 行 0xffff0000第 23 行 0xffff0010

然后 gdb 将假定函数 f 的序言在 0xfff0010 完成.

我认为这是gcc在不优化时使用的模式.

最后,gdb 有一些序言解码器,它们知道如何在许多平台上编写常见序言.这些在 debuginfo 不可用时使用,尽管我不记得这样做的目的是什么.

A simple example that demonstrates my issue:

// test.c
#include <stdio.h>

int foo1(int i) {
    i = i * 2;
    return i;
}

void foo2(int i) {
    printf("greetings from foo! i = %i", i);
}

int main() {
    int i = 7;
    foo1(i);
    foo2(i);
    return 0;
}

$ clang -o test -O0 -Wall -g test.c

Inside GDB I do the following and start the execution:

(gdb) b foo1  
(gdb) b foo2

After reaching the first breakpoint, I disassemble:

(gdb) disassemble 
Dump of assembler code for function foo1:
   0x0000000000400530 <+0>:     push   %rbp
   0x0000000000400531 <+1>:     mov    %rsp,%rbp
   0x0000000000400534 <+4>:     mov    %edi,-0x4(%rbp)
=> 0x0000000000400537 <+7>:     mov    -0x4(%rbp),%edi
   0x000000000040053a <+10>:    shl    $0x1,%edi
   0x000000000040053d <+13>:    mov    %edi,-0x4(%rbp)
   0x0000000000400540 <+16>:    mov    -0x4(%rbp),%eax
   0x0000000000400543 <+19>:    pop    %rbp
   0x0000000000400544 <+20>:    retq   
End of assembler dump.

I do the same after reaching the second breakpoint:

(gdb) disassemble 
Dump of assembler code for function foo2:
   0x0000000000400550 <+0>:     push   %rbp
   0x0000000000400551 <+1>:     mov    %rsp,%rbp
   0x0000000000400554 <+4>:     sub    $0x10,%rsp
   0x0000000000400558 <+8>:     lea    0x400644,%rax
   0x0000000000400560 <+16>:    mov    %edi,-0x4(%rbp)
=> 0x0000000000400563 <+19>:    mov    -0x4(%rbp),%esi
   0x0000000000400566 <+22>:    mov    %rax,%rdi
   0x0000000000400569 <+25>:    mov    $0x0,%al
   0x000000000040056b <+27>:    callq  0x400410 <printf@plt>
   0x0000000000400570 <+32>:    mov    %eax,-0x8(%rbp)
   0x0000000000400573 <+35>:    add    $0x10,%rsp
   0x0000000000400577 <+39>:    pop    %rbp
   0x0000000000400578 <+40>:    retq   
End of assembler dump.

GDB obviously uses different offsets (+7 in foo1 and +19 in foo2), with respect to the beginning of the function, when setting the breakpoint. How can I determine this offset by myself without using GDB?

解决方案

gdb uses a few methods to decide this information.

First, the very best way is if your compiler emits DWARF describing the function. Then gdb can decode the DWARF to find the end of the prologue.

However, this isn't always available. GCC emits it, but IIRC only when optimization is used.

I believe there's also a convention that if the first line number of a function is repeated in the line table, then the address of the second instance is used as the end of the prologue. That is if the lines look like:

< function f >
line 23  0xffff0000
line 23  0xffff0010

Then gdb will assume that the function f's prologue is complete at 0xfff0010.

I think this is the mode used by gcc when not optimizing.

Finally gdb has some prologue decoders that know how common prologues are written on many platforms. These are used when debuginfo isn't available, though offhand I don't recall what the purpose of that is.

这篇关于当您执行“break function-name"时,GDB 如何确定要中断的地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆