4

我正在编写一个 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 tp 打印此结构:

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 并自动打印指针、数组和列表值?

谢谢。

4

1 回答 1

10

struct net_device,struct pci_dev来自 Linux 的目的是供内核使用,而不是用户空间代码。它们甚至没有导出到您使用的经过清理的内核头文件中make headers_install以与 libc 一起使用。

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

核心转储澄清后编辑

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

  • 使用 debuginfo ( CONFIG_DEBUG_INFO ) 获取内核。例如对于 Centos,从http://debuginfo.centos.org/6/x86_64/获取匹配的kernel-debuginfo包。
  • 通过在正常操作下运行驱动程序的系统检查/sys/module/ MY-DRIVER /sections/{.text,.data,.bss}来获取驱动程序模块的.text.data.bss加载地址。

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

$ 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

同时将TEXT-ADDRDATA-ADDRBSS-ADDR替换为 /sys/module/ MY-DRIVER /sections/ 下文件中的地址。(我认为只是撒谎并使用地址 0 在这种情况下可能会起作用)

验证ptype struct net_deviceptype struct pci_devptype my_struct是否有效。然后在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
于 2013-05-28T09:35:46.330 回答