GDB add-symbol-file все разделы и адрес загрузки

Я отлаживаю загрузчик (syslinux) с помощью gdb и заглушки gdb из qemu. В какой-то момент основной файл загружает общий объект ldlinux.elf,

Я хотел бы добавить символы в GDB для этого файла. Команда add-symbol-file кажется, путь. Однако, как перемещаемый файл, я должен указать адрес памяти, в который он был загружен. И тут возникает проблема.

Хотя я знаю базовый адрес, по которому LOAD сегмент был загружен в, add-symbol-file работает по разделам и хочет, чтобы я указал адрес, по которому каждый раздел был загружен.

Могу ли я сказать gdb загрузить все символы всех разделов, если я укажу базовый адрес файла в памяти?

Имеет ли смысл поведение GDB? Заголовки разделов не используются для запуска ELF и даже являются необязательными. Я не вижу варианта использования, в котором было бы полезно указать адрес загрузки разделов.


пример

Вот заголовки программ и заголовки разделов общего объекта.

Тип файла elf: DYN (общий объектный файл). Точка входа 0x4c60. Имеется 3 заголовка программы, начиная со смещения. 52 Заголовки программы: Тип смещения. VirtAddr   PhysAddr   FileSiz MemSiz  Flg. GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10 Отображение разделов на сегменты: сегменты сегментов...
   00     .gnu.hash .dynsym .dynstr .rel.dyn .rel.plt .plt .text .rodata .ctors .dtors .data.rel.ro .dynamic .got .got.plt .data .bss 
   01     .dynamic 
   02 
Существует 29 заголовков разделов, начиная со смещения 0x78618: Заголовки разделов:
  [Nr] Имя Тип Адреса Выкл. Размер ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .gnu.hash         GNU_HASH        00000094 000094 0007e0 04   A  2   0  4
  [ 2] .dynsym           DYNSYM          00000874 000874 0015c0 10   A  3   1  4
  [ 3] .dynstr           STRTAB          00001e34 001e34 0010f4 00   A  0   0  1
  [ 4] .rel.dyn          REL             00002f28 002f28 000ce8 08   A  2   0  4
  [ 5] .rel.plt          REL             00003c10 003c10 000568 08  AI  2   6  4
  [ 6] .plt              PROGBITS        00004180 004180 000ae0 04  AX  0   0 16
  [ 7] .text             PROGBITS        00004c60 004c60 013816 00  AX  0   0  4
  [ 8] .rodata           PROGBITS        00018480 0184 00462f 00   A  0   0 32
  [ 9] .ctors            INIT_ARRAY      0001cab0 01cab0 000010 00  WA  0   0  4
  [10] .dtors            FINI_ARRAY      0001cac0 01cac0 000004 00  WA  0   0  4
  [11] .data.rel.ro ПРОБИТЫ 0001cae0 01cae0 000b38 00 WA 0 32 [12].dynamic DYNAMIC 0001d618 01d618 000098 08 WA 3 0 4 [13] .got              PROGBITS        0001d6b0 01d6b0 0000d0 04  WA  0   0  4
  [14] .got.plt              PROGBITS        0001d780 01d780 0002c0 04  WA  0   0  4
  [15]. данные PROGBITS 0001da40 01da40 0000d0 00 WA 0 0 32 [16].bss NOBITS 0001db20 01db10 0030dc 00 WA 0 0 32 [17].comment PROGBITS        00000000 01db10 000026 01 MS 0 0 1 [18] .debug_aranges PROGBITS        00000000 01db38 0010c0 00 0 0 8 [19] .debug_info PROGB 01ebf8 021ada 00      0   0  1
  [20] .debug_abbrev     PROGBITS        00000000 0406d2 009647 00      0   0  1
  [21] .debug_line       PROGBITS        00000000 049d19 00bd3a 00      0   0  1 22 [. PROGBITS        00000000 059fc8 00538c 01 MS 0 0 1 [24] .debug_loc PROGBITS        00000000 05f354 01312d 00      0   0  1
  [25] .debug_ranges ] .symtab           SYMTAB          00000000 072b54 003530 10     28 504  4
  [28] .strtab           STRTAB          00000000 076084 002593 00      0   0  1 Ключ к флагам:
  W (запись), A (alloc), X (выполнение), M (объединение), S (строки)
  I (информация), L (порядок ссылок), G (группа), T (TLS), E (исключить), x (неизвестно)
  O (требуется дополнительная обработка ОС) o (зависит от ОС), p (зависит от процессора)

Если я попытаюсь загрузить файл по адресу 0x7fab000 тогда он будет перемещать символы так, чтобы .text раздел начинается с 0x7fab000.

(gdb) add-symbol-file bios / com32 / elflink / ldlinux / ldlinux.elf 0x7fab000
добавить таблицу символов из файла "bios/com32/elflink/ldlinux/ldlinux.elf" в.text_addr = 0x7fab000
(у или н) у
Чтение символов из bios/com32/elflink/ldlinux/ldlinux.elf... сделано.

И тогда все символы отключены на 0x4c60 байтов.

2 ответа

Итак, наконец, я сделал свою собственную команду с Python и readelf инструмент. Это не очень чисто, так как работает readelf в подпроцессе и анализируйте его выход вместо анализа файла ELF напрямую, но это работает (только для 32-битного ELF).

Он использует заголовки разделов для генерации и запуска add-symbol-file Команда со всеми разделами правильно перемещены. Использование довольно простое, вы указываете ему файл elf и базовый адрес файла. И так как remove-symbol-file не работает должным образом, просто давая ему имя файла, я сделал remove-symbol-file-all которые генерируют и работают правильно remove-symbol-file -a address команда.

(gdb) add-symbol-file-all bios/com32/elflink/ldlinux/ldlinux.elf 0x7fab000
add symbol table from file "bios/com32/elflink/ldlinux/ldlinux.elf" at
        .text_addr = 0x7fafc50
        .gnu.hash_addr = 0x7fab094
        .dynsym_addr = 0x7fab874
        .dynstr_addr = 0x7face34
        .rel.dyn_addr = 0x7fadf28
        .rel.plt_addr = 0x7faec08
        .plt_addr = 0x7faf170
        .rodata_addr = 0x7fc34e0
        .ctors_addr = 0x7fc7af0
        .dtors_addr = 0x7fc7b00
        .data.rel.ro_addr = 0x7fc7b20
        .dynamic_addr = 0x7fc8658
        .got_addr = 0x7fc86f0
        .got.plt_addr = 0x7fc87bc
        .data_addr = 0x7fc8a80
        .bss_addr = 0x7fc8b60
(gdb) remove-symbol-file-all bios/com32/elflink/ldlinux/ldlinux.elf 0x7fab000

Вот код, который будет добавлен в .gdbinit файл.

python
import subprocess
import re

def relocatesections(filename, addr):
    p = subprocess.Popen(["readelf", "-S", filename], stdout = subprocess.PIPE)

    sections = []
    textaddr = '0'
    for line in p.stdout.readlines():
        line = line.decode("utf-8").strip()
        if not line.startswith('[') or line.startswith('[Nr]'):
            continue

        line = re.sub(r' +', ' ', line)
        line = re.sub(r'\[ *(\d+)\]', '\g<1>', line)
        fieldsvalue = line.split(' ')
        fieldsname = ['number', 'name', 'type', 'addr', 'offset', 'size', 'entsize', 'flags', 'link', 'info', 'addralign']
        sec = dict(zip(fieldsname, fieldsvalue))

        if sec['number'] == '0':
            continue

        sections.append(sec)

        if sec['name'] == '.text':
            textaddr = sec['addr']

    return (textaddr, sections)


class AddSymbolFileAll(gdb.Command):
    """The right version for add-symbol-file"""

    def __init__(self):
        super(AddSymbolFileAll, self).__init__("add-symbol-file-all", gdb.COMMAND_USER)
        self.dont_repeat()

    def invoke(self, arg, from_tty):
        argv = gdb.string_to_argv(arg)
        filename = argv[0]

        if len(argv) > 1:
            offset = int(str(gdb.parse_and_eval(argv[1])), 0)
        else:
            offset = 0

        (textaddr, sections) = relocatesections(filename, offset)

        cmd = "add-symbol-file %s 0x%08x" % (filename, int(textaddr, 16) + offset)

        for s in sections:
            addr = int(s['addr'], 16)
            if s['name'] == '.text' or addr == 0:
                continue

            cmd += " -s %s 0x%08x" % (s['name'], addr + offset)

        gdb.execute(cmd)

class RemoveSymbolFileAll(gdb.Command):
    """The right version for remove-symbol-file"""

    def __init__(self):
        super(RemoveSymbolFileAll, self).__init__("remove-symbol-file-all", gdb.COMMAND_USER)
        self.dont_repeat()

    def invoke(self, arg, from_tty):
        argv = gdb.string_to_argv(arg)
        filename = argv[0]

        if len(argv) > 1:
            offset = int(str(gdb.parse_and_eval(argv[1])), 0)
        else:
            offset = 0

        (textaddr, _) = relocatesections(filename, offset)

        cmd = "remove-symbol-file -a 0x%08x" % (int(textaddr, 16) + offset)
        gdb.execute(cmd)


AddSymbolFileAll()
RemoveSymbolFileAll()
end

Могу ли я сказать gdb загрузить все символы всех разделов, если я укажу базовый адрес файла в памяти?

Да, но вам нужно предоставить адрес .text раздел, т.е. 0x7fab000+0x00004c60 Вот. Я согласен: это довольно раздражает, чтобы выловить адрес .textи я хотел это исправить много раз, так что, например,

(gdb) add-symbol-file foo.so @0x7abc0000

просто работает. Не стесняйтесь подать запрос на функцию в GDB bugzilla.

Имеет ли смысл поведение GDB?

Я предполагаю, что это основано на том, как GDB использовался для отладки встроенных ПЗУ, где каждый раздел может быть по произвольному адресу памяти.

Другие вопросы по тегам