gdb add-symbol-file所有节和加载地址

标签 gdb debug-symbols

我正在使用gdb和qemu的gdb-stub调试引导加载程序(syslinux)。在某个时候,主文件会加载一个共享对象ldlinux.elf

我想在gdb中为该文件添加符号。命令add-symbol-file似乎很可行。但是,作为可重定位文件,我必须指定它已加载到的内存地址。问题来了。

尽管我知道LOAD段的加载基地址,但add-symbol-file是分段操作的,希望我指定加载每个段的地址。

如果我指定了内存中文件的基地址,是否可以告诉gdb加载所有节的所有符号?

gdb的行为会引起感觉吗? section标题不用于运行ELF,甚至是可选的。我看不到指定用例的加载地址有用的用例。

例子

这是共享库的程序头和节头。

Elf文件类型为DYN(共用 object 文件)
入口点0x4c60
从偏移量52开始有3个程序头

程序标题:
类型偏移VirtAddr PhysAddr FileSiz MemSiz Flg对齐
负载0x000000 0x00000000 0x00000000 0x1db10 0x20bfc RWE 0x1000
动态0x01d618 0x0001d618 0x0001d618 0x00098 0x00098 RW 0x4
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。动态
02

从偏移量0x78618开始有29个节标题:

节标题:
[Nr]名称类型Addr Off尺寸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凭证00004180 004180 000ae0 04 AX 0 0 16
[7] .text PROGBITS 00004c60 004c60 013816 00 AX 0 0 4
[8] .rodata许可证00018480 018480 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 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程序0001d780 01d780 0002c0 04 WA 0 0 4
[15] .data程序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 PROGBITS 00000000 01ebf8 021ada 00 0 0 1
[20] .debug_abbrev程序00000000 0406d2 009647 00 0 0 1
[21] .debug_line PROGBITS 00000000 049d19 00bd3a 00 0 0 1
[22] .debug_frame PROGBITS 00000000 055a54 004574 00 0 0 4
[23] .debug_str PROGBITS 00000000 059fc8 00538c 01 MS 0 0 1
[24] .debug_loc PROGBITS 00000000 05f354 01312d 00 0 0 1
[25] .debug_ranges PROGBITS 00000000 072481 0005d0 00 0 0 1
[26] .shstrtab STRTAB 00000000 072a51 000101 00 0 0 1
[27] .symtab SYMTAB 00000000 072b54 003530 10 28 504 4
[28] .strtab STRTAB 00000000 076084 002593 00 0 0 1
标志的关键:
W(写),A(分配),X(执行),M(合并),S(字符串)
I(信息),L(链接顺序),G(组),T(TLS),E(排除),x(未知)
O(需要额外的操作系统处理)o(特定于操作系统),p(特定于处理器)

如果我尝试在地址0x7fab000处加载文件,则它将重新定位符号,以便.text节从0x7fab000开始。

(gdb)添加符号文件bios/com32/elflink/ldlinux/ldlinux.elf 0x7fab000
从以下位置添加文件“bios/com32/elflink/ldlinux/ldlinux.elf”中的符号表
.text_addr = 0x7fab000
(y或n)y
从bios/com32/elflink/ldlinux/ldlinux.elf ...完成读取符号。

然后所有符号都关闭0x4c60字节。

最佳答案

因此,最后,我使用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 add-symbol-file所有节和加载地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33049201/

相关文章:

java - 使用调试符号编译 Java 应用程序的各个部分

linux - GDB 不加载调试符号,尽管它们存在

c - 如何使用gdb在for循环中指定计数器的特定值?

c++ - 如何在按下 "stop"按钮时捕获 clion 中捆绑的 GDB 发出的信号?

emacs - GDB 与 emacs 技巧

objective-c - 快速找到 gdb 中断言的线程的方法?

c++ - 即使使用 -g 标志进行编译,gdb 中也没有调试符号

c++ - Oracle 是否为 OCCI/OCI 提供公共(public)符号文件 (PDB)?

c++ - GDB 显示堆栈帧的函数参数不正确

c# - 不要在堆栈跟踪中显示构建机器的文件路径