如何解释内核中的地址oops

我有一个内核哎呀在我写的Linux设备驱动程序。 我想确定哪一行负责哎呀。 我有以下输出,但我不知道如何解释它。

这是否意味着我的代码在write_func + 0x63的指令处崩溃了? 我如何将EIP中的价值与我自己的function联系起来? 反斜杠之后的值是什么意思?

[10991.880354] BUG: unable to handle kernel NULL pointer dereference at (null) [10991.880359] IP: [<c06969d4>] iret_exc+0x7d0/0xa59 [10991.880365] *pdpt = 000000002258a001 *pde = 0000000000000000 [10991.880368] Oops: 0002 [#1] PREEMPT SMP [10991.880371] last sysfs file: /sys/devices/platform/coretemp.3/temp1_input [10991.880374] Modules linked in: nfs lockd fscache nfs_acl auth_rpcgss sunrpc hdrdmod(F) coretemp(F) af_packet fuse edd cpufreq_conservative cpufreq_userspace cpufreq_powersave acpi_cpufreq mperf microcode dm_mod ppdev sg og3 ghes i2c_i801 igb hed pcspkr iTCO_wdt dca iTCO_vendor_support parport_pc floppy parport ext4 jbd2 crc16 i915 drm_kms_helper drm i2c_algo_bit video button fan processor thermal thermal_sys [last unloaded: preloadtrace] [10991.880400] [10991.880402] Pid: 4487, comm: python Tainted: GF 2.6.37.1-1.2-desktop #1 To be filled by OEM To be filled by OEM/To be filled by OEM [10991.880408] EIP: 0060:[<c06969d4>] EFLAGS: 00210246 CPU: 0 [10991.880411] EIP is at iret_exc+0x7d0/0xa59 [10991.880413] EAX: 00000000 EBX: 00000000 ECX: 0000018c EDX: b7837000 [10991.880415] ESI: b7837000 EDI: 00000000 EBP: b7837000 ESP: e2a81ee0 [10991.880417] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [10991.880420] Process python (pid: 4487, ti=e2a80000 task=df940530 task.ti=e2a80000) [10991.880422] Stack: [10991.880423] 00000000 0000018c 00000000 0000018c e5e903dc e4616353 00000009 df99735c [10991.880428] df900a7c df900a7c b7837000 df80ad80 df99735c 00000009 e46182a4 e2a81f70 [10991.880433] e28cd800 e09fc840 e28cd800 fffffffb e09fc888 c03718c1 e4618290 0000018c [10991.880438] Call Trace: [10991.882006] Inexact backtrace: [10991.882006] [10991.882012] [<e4616353>] ? write_func+0x63/0x160 [mymod] [10991.882017] [<c03718c1>] ? proc_file_write+0x71/0xa0 [10991.882020] [<c0371850>] ? proc_file_write+0x0/0xa0 [10991.882023] [<c036c971>] ? proc_reg_write+0x61/0x90 [10991.882026] [<c036c910>] ? proc_reg_write+0x0/0x90 [10991.882031] [<c0323060>] ? vfs_write+0xa0/0x160 [10991.882034] [<c03243c6>] ? fget_light+0x96/0xb0 [10991.882037] [<c0323331>] ? sys_write+0x41/0x70 [10991.882040] [<c0202f0c>] ? sysenter_do_call+0x12/0x22 [10991.882044] [<c069007b>] ? _lock_kernel+0xab/0x180 [10991.882046] Code: f3 aa 58 59 e9 5a f9 d7 ff 8d 0c 88 e9 12 fa d7 ff 01 d9 e9 7b fa d7 ff 8d 0c 8b e9 73 fa d7 ff 01 d9 eb 03 8d 0c 8b 51 50 31 c0 <f3> aa 58 59 e9 cf fa d7 ff 01 d9 e9 38 fb d7 ff 8d 0c 8b e9 30 [10991.882069] EIP: [<c06969d4>] iret_exc+0x7d0/0xa59 SS:ESP 0068:e2a81ee0 [10991.882072] CR2: 0000000000000000 [10991.889660] ---[ end trace 26fe339b54b2ea3e ]--- 

所有你需要的信息就在那里:

 [10991.880354] BUG: unable to handle kernel NULL pointer dereference at (null) 

这就是原因。

 [10991.880359] IP: [<c06969d4>] iret_exc+0x7d0/0xa59 

这是故障发生时的指示指针。 我们会马上回来。

 [10991.880365] *pdpt = 000000002258a001 *pde = 0000000000000000 

这些是物理页表项。 描述符表和页面描述符条目。 自然,后者是NULL,因为它是一个NULL指针。 上述值很少有用(仅在需要物理内存映射的情况下)

 [10991.880368] Oops: 0002 [#1] PREEMPT SMP 

这是哎呀代码。 PREEMPT SMP显示内核是可抢占的,并为SMP而不是UP编译。 这对于那些错误来自某种竞争条件的情况很重要

 [10991.880371] last sysfs file: /sys/devices/platform/coretemp.3/temp1_input 

这不一定是罪魁祸首,但往往是。 sys文件由各种内核模块导出,并且sys文件上的I / O操作通常会导致错误的模块代码执行。

 [10991.880374] modulees linked in: ... [last unloaded: preloadtrace] 

内核不一定知道哪个模块是责任,所以它给你所有的人。 另外,最近卸载的模块很可能没有清理干净,在内核中留下了一些残留(如某些定时器或回调) – 这是oops或panic的典型情况。 所以内核也会报告最后一个被卸载的内核。

 [10991.880402] Pid: 4487, comm: python Tainted: GF 2.6.37.1-1.2-desktop #1 To be filled by OEM To be filled by OEM/To be filled by OEM 

如果故障线程是一个用户模式线程,则会得到PID和命令行。 “感染”标志是内核说它不是内核故障的方式(内核源是开放的,“纯”的)。“Taint”来自亵渎的非GPL模块等等。

 [10991.880408] EIP: 0060:[<c06969d4>] EFLAGS: 00210246 CPU: 0 [10991.880411] EIP is at iret_exc+0x7d0/0xa59 

这给你错误的指令指针,直接和符号+偏移量形式。 斜杠后的部分是函数的大小。

 [10991.880413] EAX: 00000000 EBX: 00000000 ECX: 0000018c EDX: b7837000 [10991.880415] ESI: b7837000 EDI: 00000000 EBP: b7837000 ESP: e2a81ee0 [10991.880417] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 

寄存器显示在这里。 您的NULL可能是EAX。

 [10991.880420] Process python (pid: 4487, ti=e2a80000 task=df940530 task.ti=e2a80000) [10991.880422] Stack: [10991.880423] 00000000 0000018c 00000000 0000018c e5e903dc e4616353 00000009 df99735c [10991.880428] df900a7c df900a7c b7837000 df80ad80 df99735c 00000009 e46182a4 e2a81f70 [10991.880433] e28cd800 e09fc840 e28cd800 fffffffb e09fc888 c03718c1 e4618290 0000018c 

显示堆栈指针附近的区域。 内核不知道这些值是什么意思,但是它们与从gdb显示$ rsp得到的结果是一样的。 所以这是由你来确定他们是什么。 (例如,c03718c1是一个内核返回地址,可能 – 所以你可以去/ proc / kallsyms找出它,或者依靠它在跟踪中,因为它,下一步)。 这告诉你,所有的数据是堆栈帧

现在,因为你有堆栈调用跟踪,你可以把碎片放在一起:

 [10991.880423] 00000000 0000018c 00000000 0000018c e5e903dc e4616353 --> back to write_func [ ] ..................................................... 00000009 df99735c [10991.880428] df900a7c df900a7c b7837000 df80ad80 df99735c 00000009 e46182a4 e2a81f70 [10991.880433] e28cd800 e09fc840 e28cd800 fffffffb e09fc888 c03718c1 --> back to proc_file_write [10991.882046] Code: f3 aa 58 59 e9 5a f9 d7 ff 8d 0c 88 e9 12 fa d7 ff 01 d9 e9 7b fa d7 ff 8d 0c 8b e9 73 fa d7 ff 01 d9 eb 03 8d 0c 8b 51 50 31 c0 <f3> aa 58 59 e9 cf fa d7 ff 01 d9 e9 38 fb d7 ff 8d 0c 8b e9 30 

再一次,内核不能为你分解(这是糟糕的,可能非常恐慌,给它一个休息!)。 但是你可以使用gdb来反汇编这些值。

所以,现在你知道一切。 你实际上可以反汇编你自己的模块,并找出在write_func中的NULL指针被解引用的地方。 (你可能将它作为参数传递给某个函数)。