Можно ли показать абсолютные адреса в разделяемых библиотеках в обратной трассировке в GDB? - PullRequest
0 голосов
/ 26 августа 2018

При отображении стека вызовов, который содержит динамические библиотечные функции, я хочу знать фактическое расположение функций в стеке вызовов в библиотеках, а не адреса относительно сопоставленного адреса.

Я знаю, чтоЯ могу вручную вычислить это для каждого вызова, выполнив 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 голосов
/ 28 августа 2018

Спасибо за ваше предложение, Том.

Вот фильтр, который я придумал. Это немного странно, так как я не смог найти изящный способ 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 ()
0 голосов
/ 26 августа 2018

Нет встроенного способа сделать это.

Один из возможных способов реализовать это для себя - написать frame filter на Python.Идея состоит в том, чтобы иметь уведомление фильтра, когда фрейм приходит от общего объекта, и в этих случаях возвращать новый фрейм с измененным адресом.Я не уверен, что вы можете сделать так, чтобы вы печатали форму 0x22450 + 0xca340 в выводе адреса (если это не похоже на запрос функции gdb), но вы можете напечатать неукрашенный адрес или добавить дополнительную информацию в функцию - илиполе имени файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...