【问题标题】:Analyzing CPU registers during kernel crash dump在内核崩溃转储期间分析 CPU 寄存器
【发布时间】:2014-02-18 10:18:31
【问题描述】:

我在调试一个问题时遇到了下面的内核崩溃以及正在生成的崩溃转储。在某种程度上我确实知道,如何使用 gdb (l *(debug_fucntion+0x19)) 命令到达代码中发生问题的确切行。

<1>BUG: unable to handle kernel paging request at ffffc90028213000
<1>IP: [<ffffffffa0180279>] debug_fucntion+0x19/0x160 [dise]
<4>PGD 103febe067 PUD 103febf067 PMD fd54e1067 PTE 0
<4>Oops: 0000 [#1] SMP
<4>last sysfs file: /sys/kernel/mm/ksm/run
<4>CPU 7
<4>Modules linked in: dise(P)(U) ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat xt_CHECKSUM iptable_mangle bridge autofs4 8021q garp stp llc ipt_REJECT nf_conntrack_ipv4 nf_defrag_ipv4 iptable_filter ip_tables ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables ipv6 vhost_net macvtap macvlan tun kvm uinput ipmi_devintf power_meter microcode iTCO_wdt iTCO_vendor_support dcdbas sg ses enclosure serio_raw lpc_ich mfd_core i7core_edac edac_core bnx2 ext4 jbd2 mbcache sr_mod cdrom sd_mod crc_t10dif pata_acpi ata_generic ata_piix megaraid_sas dm_mirror dm_region_hash dm_log dm_mod [last unloaded: dise]
<4>
<4>Pid: 1126, comm: diseproc Tainted: P        W  ---------------    2.6.32-431.el6.x86_64 #1 Dell Inc. PowerEdge R710/0MD99X
<4>RIP: 0010:[<ffffffffa0180279>]  [<ffffffffa0180279>] debug_fucntion+0x19/0x160 [dise]
<4>RSP: 0018:ffff880435fc5b88  EFLAGS: 00010282
<4>RAX: 0000000000000000 RBX: 0000000000010000 RCX: ffffc90028213000
<4>RDX: 0000000000010040 RSI: 0000000000010000 RDI: ffff880fe36a0000
<4>RBP: ffff880435fc5b88 R08: ffffffffa025d8a3 R09: 0000000000000000
<4>R10: 0000000000000004 R11: 0000000000000004 R12: 0000000000010040
<4>R13: 000000000000b101 R14: ffffc90028213010 R15: ffff880fe36a0000
<4>FS:  00007fbe6040b700(0000) GS:ffff8800618e0000(0000) knlGS:0000000000000000
<4>CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
<4>CR2: ffffc90028213000 CR3: 0000000fc965b000 CR4: 00000000000007e0
<4>DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
<4>DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
<4>Process diseproc (pid: 1126, threadinfo ffff880435fc4000, task ffff8807f8be8ae0)
<4>Stack:
<4> ffff880435fc5be8 ffffffffa0180498 0000000081158f46 00000c200000fd26
<4><d> ffffc90028162000 0000fec635fc5bc8 0000000000000018 ffff881011d80000
<4><d> ffffc90028162000 ffff8802f18fe440 ffff880fc80b4000 ffff880435fc5cec
<4>Call Trace:
<4> [<ffffffffa0180498>] cmd_dump+0x1c8/0x360 [dise]
<4> [<ffffffffa01978e1>] debug_log_show+0x91/0x160 [dise]
<4> [<ffffffffa013afb9>] process_debug+0x5a9/0x990 [dise]
<4> [<ffffffff810792c7>] ? current_fs_time+0x27/0x30
<4> [<ffffffffa013bc38>] dise_ioctl+0xd8/0x300 [dise]
<4> [<ffffffff8105a501>] ? hotplug_hrtick+0x21/0x60
<4> [<ffffffff8119db42>] vfs_ioctl+0x22/0xa0
<4> [<ffffffff8119dce4>] do_vfs_ioctl+0x84/0x580
<4> [<ffffffff8119e261>] sys_ioctl+0x81/0xa0
<4> [<ffffffff810e1e5e>] ? __audit_syscall_exit+0x25e/0x290
<4> [<ffffffff8100b072>] system_call_fastpath+0x16/0x1b
<4>Code: be c4 10 e1 48 8b 5d d8 44 01 f0 4c 8b 65 e0 4c 8b 6d e8 4c 8b 75 f0 4c 8b 7d f8 c9 c3 0f 1f 44 00 00 55 48 89 e5 0f 1f 44 00 00 <48> 8b 01 48 c1 e8 3c 83 f8 08 76 0b e8 f6 fb ff ff c9 c3 0f 1f
<1>RIP  [<ffffffffa0180279>] debug_fucntion+0x19/0x160 [dise]
<4> RSP <ffff880435fc5b88>
<4>CR2: ffffc90028213000

我的问题是

  1. 打印出来的CPU寄存器内容能否提供更多信息?我如何解码它们?

  2. 我可以从导致崩溃的崩溃转储中了解变量值或数据结构值吗?

  3. “代码:be c4 10 e1 48 8b 5d ...”在这里告诉我什么?

【问题讨论】:

    标签: linux linux-kernel crash-dumps


    【解决方案1】:

    您必须了解您是在汇编级别(不是源代码)进行检查(而不是调试)。在检查故障转储时,您必须牢记这一点。

    您必须逐行仔细阅读故障转储报告,因为它包含大量信息,而这就是您所获得的全部信息。

    当您的代码崩溃时,您必须通过阅读崩溃转储报告和反汇编来找出发生这种情况的原因。

    故障转储报告中的第一行告诉您

    BUG: unable to handle kernel paging request at ffffc90028213000
    

    这意味着你使用了无效的内存。

    线

    Process diseproc (pid: 1126, threadinfo ffff880435fc4000, task ffff8807f8be8ae0)
    

    告诉你崩溃时用户空间发生了什么。似乎用户空间进程diseproc 向您的驱动程序发出了一些导致崩溃的命令。

    非常重要的一行是

    IP: [<ffffffffa0180279>] debug_fucntion+0x19/0x160 [dise]
    

    尝试发出dis debug_function 命令来反汇编debug_function,找到debug_function+25(0x19 hex = 25 dec) 并环顾四周。与 debug_function 的 C 源代码一起阅读。通常你可以通过比较callq指令在C代码中找到崩溃的地方——反汇编会显示被调用函数的可打印名称。

    接下来也是最重要的是调用跟踪:

    Call Trace:
     [<ffffffffa0180498>] cmd_dump+0x1c8/0x360 [dise]
     [<ffffffffa01978e1>] debug_log_show+0x91/0x160 [dise]
     [<ffffffffa013afb9>] process_debug+0x5a9/0x990 [dise]
     [<ffffffff810792c7>] ? current_fs_time+0x27/0x30
     [<ffffffffa013bc38>] dise_ioctl+0xd8/0x300 [dise]
     [<ffffffff8105a501>] ? hotplug_hrtick+0x21/0x60
     [<ffffffff8119db42>] vfs_ioctl+0x22/0xa0
     [<ffffffff8119dce4>] do_vfs_ioctl+0x84/0x580
     [<ffffffff8119e261>] sys_ioctl+0x81/0xa0
     [<ffffffff810e1e5e>] ? __audit_syscall_exit+0x25e/0x290
     [<ffffffff8100b072>] system_call_fastpath+0x16/0x1b
    

    从下往上阅读:内核得到了 ioctl(来自 diseproc,很明显),内核在 dise 模块中调用了 ioctl 处理程序 dise_ioctl,然后是 current_fs_timeprocess_debugdebug_log_show,最后是cmd_dump.

    现在你知道了:

    • 代码路径:dise_ioctl -> current_fs_time -> process_debug -> debug_log_show -> cmd_dump -> 不知何故到debug_function
    • C 代码中导致崩溃的大致位置
    • 崩溃原因:访问无效内存

    有了这些信息,你必须使用你最后也是最强大的方法——思考。尝试了解导致崩溃的变量/结构。也许他们中的一些人在您到达debug_function 时已被释放?也许你在指针运算中打错了?

    问题的答案:

    1. 大多数时候 CPU 寄存器值是没有意义的,因为它与您的 C 代码无关。只是一些值,指向一些记忆 - 无论如何。是的,有一些非常有用的寄存器,比如 RIP/EIP 和 RSP/ESP,但它们中的大多数都太脱离上下文了。

    2. 不太可能。您实际上没有在调试 - 您正在检查您的转储 - 您没有任何调试上下文。

    3. 我同意@user2699113 的观点,它只是在 RIP 的指针下存储内容。

    记住 - 最好的调试工具是你的大脑。

    【讨论】:

    • @pkumarn 您还可以在带有内核映像的故障转储中使用崩溃实用程序,以从中获取更多调试信息。
    • 感谢您的回复。在崩溃实用程序中,它们是一种在崩溃时查看结构值或变量的方法吗?在崩溃实用程序中尝试了 mod -S 然后 p *(结构名称),它抛出错误说找不到。我错过了什么吗?
    • 从 EIP 我了解了正在执行的代码行,我可以看看其他一些寄存器,它们告诉我崩溃行中的变量值是什么?这样做的原因是,一些错误需要很多小时才能重现,并且最好知道导致崩溃的“坏值”,以便在分析代码时有用。
    • @pkumarn 在崩溃时打印结构值你使用struct 命令,但你必须给它虚拟地址。要获取虚拟地址,您可以使用bt -F 检查堆栈帧,其中-F 选项显示带有符号名称解析的堆栈帧内容。
    • @pkumarn 变量存储在内存中,并在计算时进行注册。所以检查寄存器大多是没有意义的,因为在崩溃的那一刻,他们有来自内核崩溃例程的变量,比如panic
    【解决方案2】:

    请参阅here... 这有很好的文档说明如何调试内核崩溃。请参阅Objdump 部分

    它告诉它您可以在 vmlinux 映像上使用 objdump 反汇编您的内核映像。此命令将输出一个包含内核源代码的大文本文件...然后您可以grep 解决在先前创建的输出文件中导致EIP 的问题。

    PS:我建议在 vmlinux 上执行 objdump 并将其保存在本地。

    【讨论】:

      【解决方案3】:
      1. 和 2.:很难找出 cpu 寄存器与参数和变量值的关系。

      3:该代码是汇编代码。您可能会在反汇编程序中找到它并找出问题发生的位置。请注意,有 8b 01 48 ... - 并且AFAIK陷阱发生在此汇编程序命令处。这意味着您需要通过反汇编代码来调试它。如果你用调试符号编译你的程序(模块),你可以找出出现问题的数字行。

      【讨论】:

        猜你喜欢
        • 2017-02-08
        • 2023-01-12
        • 2014-03-01
        • 2020-07-23
        • 2012-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多