我正在调试一个问题,并在生成崩溃转储时遇到了下面的内核崩溃。在某种程度上,我知道,如何使用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
我的问题是
CPU注册打印的内容能提供更多信息吗?我如何解码它们?
我可以从崩溃转储中了解导致崩溃的变量值或数据结构值吗?
“代码:c4 10 e1 48 8b 5d ......”在这里告诉我什么?
答案 0 :(得分:8)
您必须了解您正在组装级别(而不是源代码)检查(而不是调试)。在检查故障转储时,必须牢记这一点。
您必须逐行仔细阅读崩溃转储报告,因为它包含大量信息,而且这就是您所有的信息。
当你的代码崩溃时到位 - 你必须通过阅读崩溃转储报告和反汇编来找出发生这种情况的原因。
崩溃转储报告中的第一行告诉您
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 handler dise_ioctl
,然后current_fs_time
,process_debug
,debug_log_show
,最后是cmd_dump
。
现在你知道了:
dise_ioctl
- &gt; current_fs_time
- &gt; process_debug
- &gt; debug_log_show
- &gt; cmd_dump
- &gt;以某种方式debug_function
。有了这些信息,你必须使用你最后一个也是最强大的方法 - 思考。尝试了解导致崩溃的变量/结构。也许有些人在你到达debug_function
时被释放了?也许你在指针算术中输错了?
问题答案:
大多数情况下,CPU寄存器值毫无意义,因为它与您的C代码无关。只是一些价值观,指向一些记忆 - 无论如何。是的,有一些非常有用的寄存器,如RIP / EIP和RSP / ESP,但大多数寄存器过于偏离上下文。
非常不可能。您实际上没有调试 - 您正在检查转储 - 您没有任何调试上下文。
我同意@ user2699113它只是RIP指针下的内存内容。
请记住 - 最好的调试工具是你的大脑。
答案 1 :(得分:1)
请参阅here ...这里有关于如何调试内核崩溃的良好文档。请参阅Objdump
它告诉您可以使用vmlinux映像上的objdump
来反汇编内核映像。此命令将输出内核源代码的大型文本文件...然后,您可以grep
查找先前创建的输出文件中导致EIP
的问题。
PS:我建议在vmlinux上进行objdump
并在本地保存。
答案 2 :(得分:0)
3:该代码是汇编代码。您可以在反汇编程序中找到它并找出问题发生的位置。注意,有&lt; 48&gt; 8b 01 48 ... - 和AFAIK陷阱发生在这个汇编命令中。这意味着您需要通过反汇编代码来调试它。如果使用debuggig符号编译程序(模块),可以找到出现问题的数字行。