可以在GDB的反向跟踪中显示共享库中的绝对地址吗?

时间:2018-08-26 00:53:29

标签: gdb

当显示包含动态库函数的调用堆栈时,我想知道函数在库中的调用堆栈中的实际位置-而不是相对于映射地址的地址。

我知道我可以通过运行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

2 个答案:

答案 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 ()