【发布时间】:2020-03-12 06:23:21
【问题描述】:
我正在尝试实现一种方法,将我的程序的调用堆栈记录到一个文件中,然后再显示它。 步骤如下:
- 将 /proc/self/maps 的内容写入日志文件。
- 在本例中,/proc/self/maps 的内容为:
00400000-05cdc000 r-xp 00000000 00:51 12974779926 helloworld- 也就是说
helloworld程序的基地址是0x400000。
- 在程序中,每当感兴趣的代码需要记录其调用堆栈时,我使用函数
backtrace()获取调用堆栈的地址,然后写入日志文件。假设这个例子中的调用栈是:- 0x400001
- 0x400003
- 稍后,在一个单独的日志查看器程序中,日志文件被打开并解析。调用堆栈中的地址将被程序的基地址减去。在这种情况下:
0x400001 - 0x400000 = 1
- 然后我使用 addr2line 程序使用这个扣除的偏移量来获取行号:
addr2line -fCe hellowork 0x1- 但是这会产生
???结果,即无效的偏移量。
- 但是如果我不扣除调用堆栈的地址,而是将实际值传递给 add2line 命令:
-
addr2line -fCe hellowork 0x400001,则返回正确的文件和行号。
-
问题是如果地址在共享对象中,那么绝对地址将不起作用,而扣除的偏移量将起作用。
为什么主可执行文件和共享对象的地址映射方式存在如此大的差异?或者这可能是 backtrace 实现特定的,这样它总是返回主可执行文件中函数的绝对地址?
【问题讨论】:
-
addr2line 仅识别 VMA 地址。就像您已经发现的那样,对于共享库,VMA 地址从 @ 0 开始,但对于 EXE,它们可以从 @ 0x400000 开始。这是另一种带有图纸的解释。 stackoverflow.com/questions/4636456/…