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

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

问题描述

一个简单的例子说明了我的问题:

  // test.c 
#include
int foo1(int i){
i = i * 2;
返回i;
}

void foo2(int i){
printf(来自foo的问候!i =%i,i);
}

int main(){
int 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> ;: push%rbp
0x0000000000400531< + 1> ;: mov%rsp,%rbp
0x0000000000400534< + 4> ;: mov%edi ,-0×4(%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
汇编器转储结束。

在达到第二个断点后,我做同样的事情:

 (gdb)反汇编
函数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
汇编程序转储结束。

GDB明显使用不同的偏移量(foo1中的+7和foo2中的+19)在设置断点时,函数的开始。如何在不使用GDB的情况下自行确定这个偏移量?

解决方案

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

>

首先,如果您的编译器发出描述函数的DWARF,最好的方法是。然后gdb可以解码DWARF以查找序言的结尾。



然而,这并不总是可用的。 GCC发射它,但只有在使用优化时才会发生IIRC。



我相信还有一个约定,如果函数的第一个行号在行表中重复,那么第二个实例的地址被用作序言的结尾。这就是说,如果线条如下所示:

 <函数f> 
line 23 0xffff0000
line 23 0xffff0010

然后gdb会假定函数f的序幕完成在0xfff0010。



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



最后gdb有一些序言解码器,它们知道在很多平台上如何编写常见的序言。这些在调试信息不​​可用的情况下使用,尽管我不记得那是什么目的。


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.

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

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