在内核崩溃转储期间分析CPU寄存器

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

<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: PW --------------- 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. 我可以从导致崩溃的崩溃转储知道variables值或数据结构值吗?

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

Solutions Collecting From Web of "在内核崩溃转储期间分析CPU寄存器"

你必须明白,你正在检查(不调试)在汇编级别(而不是源代码)。 在检查崩溃转储时,这一点很重要。

你必须仔细阅读你的崩溃转储报告,因为它包含大量的信息,这也是你所得到的。

当你的代码崩溃的时候,你必须弄清楚为什么发生崩溃转储报告和反汇编。

崩溃转储报告中的第一行告诉你

 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十六进制= 25十二月)并环顾四周。 与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指针下的内存内容。

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

看到这里 …这有良好的文档,如何调试内核崩溃..请参阅Objdump部分

它告诉你可以在vmlinux映像上使用objdump反汇编你的内核镜像。 这个命令会输出你的内核源代码的一个大的文本文件。然后,你可以在先前创建的输出文件中找到导致EIP的问题。

PS:我会建议在vmlinux上做objdump并保存在本地。

  1. 和2 .:很难找出CPU寄存器如何与参数和变量值相关。

3:该代码是汇编代码。 你可以在你的反汇编程序中找到它,并找出发生问题的位置。 注意有<48> 8b 01 48 … – 和AFAIK陷阱发生在这个汇编程序命令。 这意味着您需要通过反汇编代码来进行调试。 如果你用debuggig符号编译你的程序(模块),你可以找到问题发生的地方。