4

gdb からのコア ダンプのデバッグを自動化する Python スクリプトを作成しています。カーネル データ構造とリスト (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 print this structureを使用しています:

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 の内容を出力するにはどうすればよいでしょうか?

編集済み:私の質問をより明確にするために

gdb からのコア ダンプのデバッグを自動化する Python スクリプトを作成しています。カーネル データ構造とリスト (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 のすべてのメンバーの値が 1 つのレベルまで出力されます。つまり、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

だから私はこれらのステップを自動化したい。構造体 my_struct を反復処理し、ポインター、配列、およびリストの値も自動的に出力できる gdb-python API または方法はありますか?

ありがとう。

4

1 に答える 1

10

struct net_deviceLinux の は、struct pci_devユーザー空間コードではなく、カーネルによって使用されることを意図しています。make headers_installそれらは、libc で使用するために取得するサニタイズされたカーネル ヘッダーでさえエクスポートされません。

これらの構造の定義を説明するデバッグ情報がないためstruct net_device、GDB は を出力できません。struct pci_devユーザー空間struct my_structは、これらの構造への不透明なポインターを持つように宣言されています。最初からやるべきではないと思います。

コアダンプの明確化後に編集

コツは、カーネルとドライバー モジュールの両方からデバッグ情報を GDB にロードすることです。

  • debuginfo ( CONFIG_DEBUG_INFO ) でカーネルを取得します。たとえば、Centos の場合、一致するkernel-debuginfoパッケージをhttp://debuginfo.centos.org/6/x86_64/から取得します。
  • 通常の操作でドライバーを実行しているシステムから/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-ADDR、およびBSS-ADDRを /sys/module/ MY-DRIVER /sections/の下のファイルのアドレスに置き換えます。(この場合、嘘をついてアドレス0を使用するだけでおそらくうまくいくと思います)

ptype struct net_deviceptype struct pci_devptype my_structが機能することを確認します。次に、以前と同じ方法で a のアドレスを取得した後、struct *my_structその内容を印刷できるはずです。

ポインターをたどりながら構造体をトラバースする

print-struct-follow-pointers.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 に答える