gdb-python:解析结构的每个字段并用正确的值打印它们(如果存在)

2023-12-12

我正在编写一个 python 脚本来自动调试 gdb 的核心转储。我正在尝试打印数据结构,其中包括内核数据结构和列表(例如struct list_head)。例如,结构是这样的:

struct my_struct {
  struct my_hardware_context ahw;
  struct net_device *netdev;
  struct pci_dev *pdev;
  struct list_head mac_list;
  ....
  ....
};

我正在使用以下 API 来打印此结构:

gdb.execute('p (*(struct my_struct *)dev_base->priv)')

所以我可以自动打印 'struct my_struct' 、 struct my_hardware_context ahw 的内容,但不能自动打印指针和列表的内容(例如 struct net_device *netdev、struct pci_dev *pdev、struct list_head mac_list)(仅打印地址)。那么如何使用gdb-python脚本打印*netdev、*pdev和mac_list的内容呢?

编辑:让我的问题更清楚

我正在编写一个 python 脚本来自动调试 gdb 的核心转储。我正在尝试打印数据结构,其中包括内核数据结构和列表(例如struct list_head)。例如,结构是这样的:

struct my_struct {
   struct my_hardware_context ahw;
   struct net_device *netdev;
   struct pci_dev *pdev;
   struct list_head mac_list;
   ....
   ....
};

我正在使用以下 API 来打印此结构:(可以假设我有正确的核心转储并添加了正确的符号。

main_struct = gdb.execute('p (*(struct my_struct *)dev_base->priv)')

print main_struct

现在它将打印 struct my_struct 所有成员的值,但最多打印一级,这意味着它将打印 struct my_hardware_context ahw 的全部内容,因为它是一个实例,但不会打印 struct net_device *netdev、struct pci_dev *pdev 的内容、 struct list_head mac_list 等,所以现在我需要手动执行如下操作:

netdev = gdb.parse_and_eval('*(*(struct my_struct *)dev_base->next->priv).netdev')

print netdev

pdev = gdb.parse_and_eval('*(*(struct my_struct *)dev_base->next->priv).pdev')

print pdev

所以我想自动化这些步骤。是否有任何 gdb-python API 或方法可以迭代 struct my_struct 并自动打印指针、数组和列表值?

Thanks.


struct net_device, struct pci_devLinux 中的代码旨在由内核而不是用户空间代码使用。它们甚至没有导出到您获得的经过清理的内核标头中make headers_install与 libc 一起使用。

GDB无法打印struct net_device, struct pci_dev因为它没有描述这些结构定义的调试信息。您的用户空间struct my_struct被声明为具有指向这些结构的不透明指针。我认为你一开始就不应该这样做。

核心转储澄清后编辑

诀窍是将调试信息从内核和驱动程序模块加载到 GDB 中:

  • 使用 debuginfo 获取内核(配置调试信息)。例如对于 Centos,获取匹配的内核调试信息包裹来自http://debuginfo.centos.org/6/x86_64/.
  • Get the .text, .data and .bss通过检查加载驱动程序模块的地址/系统/模块/我的司机/sections/{.text,.data,.bss}来自在正常操作下运行驱动程序的系统。

假设带有调试信息的内核位于/usr/lib/debug/lib/modules/3.9.4-200.fc18.x86_64/vmlinux, run:

$ gdb /usr/lib/debug/lib/modules/3.9.4-200.fc18.x86_64/vmlinux vmcore
(gdb) add-symbol-file MY-DRIVER.ko TEXT-ADDR -s .data DATA-ADDR -s .bss BSS-ADDR

更换时文本地址, 数据地址 and BSS-ADDR使用 /sys/module/ 下文件的地址我的司机/部分/。 (我认为在这种情况下,只是撒谎并使用地址 0 可能会起作用)

验证一下ptype 结构体net_device, ptype 结构 pci_dev, ptype my_struct工作。然后得到a的地址后struct *my_struct就像您之前所做的那样,您应该能够打印其内容。

跟随指针遍历结构体

打印结构跟随指针.py

import gdb

def is_container(v):
    c = v.type.code
    return (c == gdb.TYPE_CODE_STRUCT or c == gdb.TYPE_CODE_UNION)

def is_pointer(v):
    return (v.type.code == gdb.TYPE_CODE_PTR)

def print_struct_follow_pointers(s, level_limit = 3, level = 0):
    indent = ' ' * level

    if not is_container(s):
        gdb.write('%s\n' % (s,))
        return

    if level >= level_limit:
        gdb.write('%s { ... },\n' % (s.type,))
        return

    gdb.write('%s {\n' % (s.type,))
    for k in s.type.keys():
        v = s[k]
        if is_pointer(v):
            gdb.write('%s %s: %s' % (indent, k, v))
            try:
                v1 = v.dereference()
                v1.fetch_lazy()
            except gdb.error:
                gdb.write(',\n')
                continue
            else:
                gdb.write(' -> ')
            print_struct_follow_pointers(v1, level_limit, level + 1)
        elif is_container(v):
            gdb.write('%s %s: ' % (indent, k))
            print_struct_follow_pointers(v, level_limit, level + 1)
        else:
            gdb.write('%s %s: %s,\n' % (indent, k, v))
    gdb.write('%s},\n' % (indent,))

class PrintStructFollowPointers(gdb.Command):
    '''
    print-struct-follow-pointers [/LEVEL_LIMIT] STRUCT-VALUE
    '''
    def __init__(self): 
        super(PrintStructFollowPointers, self).__init__(
            'print-struct-follow-pointers',
            gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, False)

    def invoke(self, arg, from_tty):
        s = arg.find('/')
        if s == -1:
            (expr, limit) = (arg, 3)
        else:
            if arg[:s].strip():
                (expr, limit) = (arg, 3)
            else:
                i = s + 1
                for (i, c) in enumerate(arg[s+1:], s + 1):
                    if not c.isdigit():
                        break
                end = i
                digits = arg[s+1:end]
                try:
                    limit = int(digits)
                except ValueError:
                    raise gdb.GdbError(PrintStructFollowPointers.__doc__)
                (expr, limit) = (arg[end:], limit)
        try:
            v = gdb.parse_and_eval(expr)
        except gdb.error, e:
            raise gdb.GdbError(e.message)

        print_struct_follow_pointers(v, limit)

PrintStructFollowPointers()

示例会话

(gdb) source print-struct-follow-pointers.py
(gdb) print-struct-follow-pointers *p

您可以限制打印的嵌入结构的级别:

(gdb) print-struct-follow-pointers/4 *p
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

gdb-python:解析结构的每个字段并用正确的值打印它们(如果存在) 的相关文章

随机推荐