2012-02-01 100 views
1

我有下面的代码:nm和addr2line函数地址不匹配

#include <stdio.h> 
#include <execinfo.h> 

#define BACKTRACE_SIZE 10 

void log() 
{ 
    void *array[BACKTRACE_SIZE]; 
    int s =0; 
    s = backtrace(array, BACKTRACE_SIZE); 
    for (int j=1; j<s; j++) 
     fprintf(stdout," %p ", array[j]); 
    fprintf(stdout,"\n"); 
} 
void show_1() 
{ 
    log(); 
} 
void show_2() 
{ 
    log(); 
} 
void show_3() 
{ 
    log(); 
} 
void show_4() 
{ 
    log(); 
} 
int main (void) 
{ 
    show_1(); 
    show_2(); 
    show_3(); 
    show_4(); 
} 

当我编译并运行它,我得到了以下的输出:

~ 1064> a.out 
0x4006dd 0x4006e9 0x2ab130eec994 0x400599 
0x4006d1 0x4006ee 0x2ab130eec994 0x400599 
0x4006c5 0x4006f3 0x2ab130eec994 0x400599 
0x4006b9 0x4006f8 0x2ab130eec994 0x400599 

然而,当我使用纳米实用程序转储功能地址说'show_1()'我得到:

~ 1070> nm -S a.out | grep show_1 | c++filt 
00000000004006d4 000000000000000b T show_1() 
~ 1071> 

但是从程序的stdout转储我得到的以下输出和在其上运行addr2line效用:

~ 1067> addr2line -Cfe ./a.out 0x4006dd 0x4006e9 0x2ab130eec994 0x400599 
show_1() 
??:0 
main 
??:0 
?? 
??:0 
_start 
??:0 

此外:

~ 1072> addr2line -Cfe ./a.out 0X4006d4 0x4006dd 
show_1() 
??:0 
show_1() 
??:0 

第一输出是由从程序nm和其他。

现在实际上我有一个更大的代码面临同样的问题。后退是巨大的(数据明智),我不能去所有后退转储addr2line输出。我需要一个特定的函数地址来搜索生成的回溯日志,然后在它发生时使用addr2line。

如何获得与由backtrace()/ nm system/binutils call/utility生成的地址相匹配的特定函数地址?

回答

2

回溯中的地址不是函数的入口点;他们是通话网站(所以他们的地址之内)。这只是回溯的本质。

nm所示的地址是函数名称符号的地址,它是函数的入口点。

+0

是否有一种方法可以使用回溯生成的呼叫站点地址来查找入口点地址?即使使用__cyg_profile_func_enter,__builtin_return_address(x)打印函数地址也无济于事。它们与nm的输出不同。 – Prakash 2012-02-01 03:02:13

+0

@Prakash:好的,如果函数线性排列,而不是内联等,那么调用该函数内的站点将位于函数入口点和下一个函数入口点之间。但是如果你想要一个通用的工作解决方案,那么你应该用'addr2line()'处理整个回溯,并在输出中搜索你感兴趣的函数。 – caf 2012-02-01 03:06:37

+0

我发现的一个快速方法是在nm实用程序中使用--print-size选项。添加到我在nm工具中没有选项的输出中 - 我得到函数的开始/结束地址。接下来,获取两个输出之间的第一个公共地址字符,并在大回溯文件中搜索它。当我发现每个事件时,我都会对每个事件执行addr2line(),直到找到所需的东西。虽然这是一段辛勤工作的时间,但我仍在寻找更好的选择。谢谢。 – Prakash 2012-02-01 03:56:34