当显示包含动态库函数的调用堆栈时,我想知道函数在库中的调用堆栈中的实际位置-而不是相对于映射地址的地址。
我知道我可以通过运行info shared
为每个调用手动计算该值,然后减去库映射到的偏移量。但是,有没有一种自动的方式来做到这一点?
对我来说,这似乎是一个常见的问题,所以我只是觉得必须有人在此之前曾遇到过此问题,并且已经准备好了方便的解决方法:)。我没有找到执行此操作的脚本,这就是为什么我要发布此脚本。
为说明问题,以防上面的内容不够清楚:
我在write()
中设置了一个断点,然后使用bt
显示了调用堆栈。
Breakpoint 2, 0x00007ffff7eb1790 in write () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff7eb1790 in write () from /usr/lib/libc.so.6
#1 0x00007ffff7e4185d in _IO_new_file_write () from /usr/lib/libc.so.6
#2 0x00007ffff7e40bbf in new_do_write () from /usr/lib/libc.so.6
#3 0x00007ffff7e429d9 in __GI__IO_do_write () from /usr/lib/libc.so.6
#4 0x00007ffff7e42db3 in __GI__IO_file_overflow () from /usr/lib/libc.so.6
#5 0x00007ffff7e37be2 in puts () from /usr/lib/libc.so.6
#6 0x0000555555555050 in main ()
(gdb) info maps
Undefined info command: "maps". Try "help info".
(gdb) info shared
From To Syms Read Shared Object Library
0x00007ffff7fd5000 0x00007ffff7ff3784 Yes (*) /lib64/ld-linux-x86-64.so.2
0x00007ffff7de7450 0x00007ffff7f3083f Yes (*) /usr/lib/libc.so.6
(*): Shared library is missing debugging information.
(gdb)
在这里我想转换例如由于#0 0x00007ffff7eb1790 in write () from /usr/lib/libc.so.6
部分从该库中的0xca340
开始,因此0x22450 + 0xca340
自动或实际上.text
进入0x22450
。
答案 0 :(得分:0)
没有内置方法可以做到这一点。
一种自己实现的方法是用Python编写frame filter。这里的想法是让帧通知来自共享对象的过滤器,在这种情况下,返回具有修改地址的新帧。我不确定是否可以在地址输出中将此打印成0x22450 + 0xca340
格式(如果不是这样的话,似乎值得进行gdb功能请求),但是您可以打印出未经修饰的地址,或将其他信息填充到函数中-或文件名字段。
答案 1 :(得分:0)
汤姆,谢谢你的建议。
这是我想到的过滤器。这有点hacky,因为我找不到一种巧妙的方法来1.以一种不错的方式获取加载的库的起始地址,并且2.必须使用objdump来获取库的.text部分。
import gdb
from gdb.FrameDecorator import FrameDecorator
import subprocess
class SharedFrameFilter():
textOffsets = None
def __init__(self):
self.name = "shared_filter"
self.priority = 100
self.enabled = True
self.textOffsets = {}
# Register this frame filter with the global frame_filters
# dictionary.
gdb.frame_filters[self.name] = self
def getTextOffset(self, libName):
if libName in self.textOffsets:
return self.textOffsets[libName]
out = subprocess.Popen([
"objdump",
"--section-headers",
"--section=.text",
libName
], stdout=subprocess.PIPE).stdout.read()
lines = out.decode("utf-8").split("\n")
for line in lines:
if not ".text" in line:
continue
cols = line.split()
startAddr = int(cols[3], 16)
self.textOffsets[libName] = startAddr
return startAddr
def filter(self, frame_iter):
for frame in frame_iter:
address = frame.address()
libName = gdb.solib_name(address)
if libName == None:
yield frame
continue
absoluteAddress = 0
shared = gdb.execute("info shared", False, True)
for line in shared.split('\n'):
cols = line.split()
try:
int(cols[0], 16)
except:
continue
if cols[4] != libName:
continue
libStart = int(cols[0], 16)
absoluteAddress = address - libStart + \
self.getTextOffset(libName)
break
frame.filename_orig = frame.filename
frame.filename = lambda: "0x%08x in %s" % (
absoluteAddress, frame.filename_orig())
yield frame
SharedFrameFilter()
gdb中的用法:
(gdb) source SharedFrameFilter.py
(gdb) bt
#0 0x00007ffff7eb1790 in write () at 0x000ec790 in /usr/lib/libc.so.6
#1 0x00007ffff7e4185d in _IO_new_file_write () at 0x0007c85d in /usr/lib/libc.so.6
#2 0x00007ffff7e40bbf in new_do_write () at 0x0007bbbf in /usr/lib/libc.so.6
#3 0x00007ffff7e429d9 in __GI__IO_do_write () at 0x0007d9d9 in /usr/lib/libc.so.6
#4 0x00007ffff7e42db3 in __GI__IO_file_overflow ()
at 0x0007ddb3 in /usr/lib/libc.so.6
#5 0x00007ffff7e37be2 in puts () at 0x00072be2 in /usr/lib/libc.so.6
#6 0x0000555555555050 in main ()