VS2005通过指令地址查找其所在函数的方法

本文介绍两种定位程序崩溃位置的方法:通过分析map文件找到与崩溃地址最接近的代码位置,以及利用反汇编文件直接查找崩溃指令的具体上下文。

方法一: map文件

1、记录地址。例如崩溃的位置是0x0047de39;

2、配置生成Map文件。属性页---->链接器---->调试---->生成映射文件选“是(/MAP)”---->映射文件名选编辑,然后点击右下角的宏,选择$(ProjectName),添加后缀.map,即$(ProjectName).map。

3、map文件中找到距离指令地址最近的地址。例如:

 

0002:00008df0       ?test2@@YAHHH@Z            0047ddf0 f   gtest_LogFileAnalysisTool.obj

 0002:00008e20       ?test@@YAXXZ               0047de20 f   gtest_LogFileAnalysisTool.obj

 0002:00008e50       ?TestBody@test_backtrace_havefun_Test@@EAEXXZ 0047de50 f   gtest_LogFileAnalysisTool.obj

 

 

方法二: 反汇编

在反汇编文件中查找指令地址。例如:

 

void test()

{

0047DE20  push        ebp 

0047DE21  mov         ebp,esp

......

     s /= 0;

0047DE33  mov         eax,dword ptr [s]

0047DE36  cdq             

0047DE37  xor         ecx,ecx

0047DE39  idiv        eax,ecx           //在这!

0047DE3B  mov         dword ptr [s],eax

     s++;

0047DE3E  mov         edx,dword ptr [s]

0047DE41  add         edx,1

0047DE44  mov         dword ptr [s],edx

}

0047DE47  mov         esp,ebp

0047DE49  pop         ebp 

0047DE4A  ret 

 

 

 

<think> 我们正在讨论使用GDB通过地址打印函数地址的方法。根据用户提供的引用和问题,用户希望了解如何在GDB调试器中通过地址来打印函数地址(即函数指针的值)或函数名。然而,需要注意的是,用户的问题可能有些歧义。通常,我们有两种理解: 1. 我们有一个地址(可能是某个函数指针变量的值,或者是从堆栈中得到的返回地址等),我们想打印这个地址对应的函数名(如果该地址确实指向某个函数的入口)。 2. 我们有一个函数的地址(比如通过函数名得到的地址),我们想打印这个地址的值(即十六进制表示)。 根据引用内容,特别是引用[2]和[3],GDB提供了强大的功能来打印内存地址处的数据以及堆栈信息。 结合用户的问题“使用gdb通过地址打印出函数地址的方法”,我理解为:我们有一个地址(比如0x4004a0),我们想打印这个地址对应的函数名(如果它是个函数入口地址)或者仅仅打印这个地址的值(但这样直接打印地址值不需要GDB,用print命令即可)。实际上,在GDB中,我们通常更关心如何将地址转换为函数名。 因此,我将重点放在如何将一个地址解析为函数名(如果可能的话)以及如何打印函数地址(十六进制形式)上。 步骤: 1. 打印地址的十六进制值(简单,直接使用print命令) 2. 将地址解析为函数名(使用GDB的符号解析功能) 以下详细步骤: ### 方法1:直接打印地址的十六进制值(如果已知函数名,想得到其地址) 如果你在GDB中有一个函数名,想得到它的地址,可以直接使用`print`命令打印函数名,它会显示函数的地址。 例如,要打印函数`main`的地址: ```bash (gdb) print main $1 = {int (int, char **)} 0x4004ed <main> ``` 这里,0x4004ed就是main函数的地址。 如果你已经有一个地址,比如0x4004ed,想以十六进制形式打印它,同样可以用print: ```bash (gdb) print /x 0x4004ed $2 = 0x4004ed ``` ### 方法2:通过地址解析函数名(反向符号查找) 如果你有一个地址(例如0x4004ed),想知道它对应哪个函数,可以使用GDB的`info symbol`命令。 例如: ```bash (gdb) info symbol 0x4004ed main in section .text of /path/to/your/program ``` 这将告诉你该地址对应的符号名(函数名)以及它所在的节。 另外,也可以使用`x`命令(examine)来查看该地址处的汇编指令,从而判断是否是函数入口: ```bash (gdb) x/i 0x4004ed 0x4004ed <main>: push %rbp ``` 这里,我们可以看到该地址处是main函数的开始(通常有push %rbp这样的序言)。 ### 方法3:在函数堆栈中打印地址对应的函数名(参考引用[3]) 引用[3]提到了打印函数堆栈帧信息。在GDB中,我们可以使用`backtrace`命令(或简写`bt`)来打印当前的调用堆栈,其中会显示每个函数调用对应的地址和函数名。 但是,如果我们有一个特定的地址(比如从程序崩溃时的寄存器中得到的地址),我们可以用方法2的`info symbol`。 ### 方法4:使用`disassemble`命令 如果你有一个地址,并且想查看该地址附近的汇编代码(包括函数名),可以使用`disassemble`命令: ```bash (gdb) disassemble 0x4004ed Dump of assembler code for function main: 0x00000000004004ed <+0>: push %rbp 0x00000000004004ee <+1>: mov %rsp,%rbp ... ``` 注意:以上方法都要求程序包含调试符号(使用-g编译)。如果程序被剥离(strip)了,那么函数名将无法显示。 ### 示例步骤(参考引用[3]的代码) 假设我们有如下代码(与引用[3]类似): ```c #include <stdio.h> void func(int a, int b) { int c = a * b; printf("c = %d\n", c); } int main (int argc, char *argv[]) { func(1, 2); return 0; } ``` 编译并启动GDB: ```bash gcc -g test.c -o test gdb ./test ``` 在GDB中,我们可以: 1. 获取函数`func`的地址: ```bash (gdb) print func $1 = {void (int, int)} 0x40052d <func> ``` 2. 假设我们有一个地址0x40052d,我们可以用`info symbol`来解析: ```bash (gdb) info symbol 0x40052d func in section .text of /path/to/test ``` 3. 或者,在程序运行到func函数内部时,我们可以打印当前函数的地址: ```bash (gdb) break func (gdb) run Breakpoint 1, func (a=1, b=2) at test.c:3 (gdb) print $pc # 打印程序计数器(当前指令地址),这个地址会在func函数内部 $2 = (void (*)()) 0x400531 <func+4> (gdb) info symbol $pc func + 4 in section .text of /path/to/test ``` 4. 我们也可以打印函数的返回地址(即调用该函数的指令的下一条指令地址): 在func函数中,我们可以查看返回地址(它保存在栈上)。在x86_64上,返回地址在栈顶(rsp指向的位置)。我们可以用: ```bash (gdb) x /g $rsp 0x7fffffffe3e8: 0x0000000000400560 (gdb) info symbol 0x0000000000400560 main + 23 in section .text of /path/to/test ``` 这里,我们看到返回地址在main函数中(具体是main+23)。 ### 总结 - 要打印函数的地址(十六进制形式),使用`print 函数名`。 - 要将一个地址解析为函数名(如果该地址是一个函数的入口),使用`info symbol 地址`。 - 要查看某个地址处的汇编代码(从而判断是否为函数),使用`x/i 地址`或`disassemble 地址`。 以上方法均在GDB中完成,且需要调试信息(编译时加-g)才能正确解析函数名。 注意:如果地址不在函数的入口(比如在函数中间),`info symbol`会显示函数名+偏移量(例如`func+4`)。 §§相关问题§§ 1. 如何在GDB中打印当前函数的地址? 2. 如何在没有调试符号的情况下解析地址对应的函数名? 3. GDB的`info symbol`命令和`info address`命令有什么区别? 4. 如何在GDB中通过函数地址设置断点? 5. 如何查看GDB中某个函数的反汇编代码? </think> ### 使用GDB通过地址打印函数地址的方法 在GDB调试器中,通过地址打印函数地址主要有以下方法,结合您提供的引用内容[1][2][3]逐步说明: #### 方法1:直接打印函数指针地址 ```bash (gdb) p function_name # 示例:打印main函数地址 (gdb) p main $1 = {int (int, char **)} 0x4004ed <main> [^1][^3] ``` **说明**: 1. 使用`p`(print)命令+函数名 2. 输出格式:`{函数签名} 十六进制地址 <函数名>` 3. 适用于已知函数名的场景 #### 方法2:通过内存地址解析函数 ```bash # 示例:解析地址0x40063c处的函数 (gdb) info symbol 0x40063c func_name in section .text of /path/to/binary [^2] # 查看地址对应的代码 (gdb) x/i 0x40063c 0x40063c <func_name+4>: push %rbp [^2][^3] ``` **说明**: 1. `info symbol <地址>` 解析地址对应的符号名 2. `x/i <地址>` 反汇编地址处的指令 3. 适用于动态获取地址的场景(如寄存器/内存值) #### 方法3:打印堆栈帧中的函数地址 ```bash # 打印当前堆栈帧信息 (gdb) bt #0 func (a=1, b=2) at test.c:4 #1 0x40052a in main (argc=1, argv=0x7fffffffe3f8) at test.c:9 [^3] # 打印特定帧的返回地址 (gdb) frame 1 (gdb) p $pc $2 = (void (*)()) 0x40052a <main+23> [^3] ``` **说明**: 1. `bt` 显示调用堆栈,包含函数地址偏移量 2. `frame N` 选择堆栈帧后,`p $pc` 打印程序计数器值 3. 适用于调试函数调用链的场景 #### 方法4:通过函数指针打印 ```c // 示例代码 void (*func_ptr)() = some_function; ``` ```bash (gdb) p func_ptr $3 = (void (*)()) 0x400540 <some_function> [^1] # 直接打印地址值 (gdb) p/x func_ptr $4 = 0x400540 ``` ### 关键点总结 1. **符号解析依赖调试信息**:需用`gcc -g`编译程序[^1] 2. **地址格式**: - 绝对地址:`0x4004ed` - 偏移地址:`<main+23>` 3. **特殊寄存器**: - `$pc`:当前指令地址 - `$sp`:栈指针地址 4. **反汇编验证**:使用`disassemble`命令确认函数地址范围 > **注意**:地址随机化(ASLR)可能导致每次运行地址不同,调试时可用`set disable-randomization on`禁用[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值