linux - 如何解释内核 oops 中的地址

标签 linux kernel linux-device-driver

我写的 linux 设备驱动程序中有一个内核 oops。我想确定哪条线是造成 oops 的原因。我有以下输出,但我不知道如何解释它。

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

[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 O.E.M. To be filled by O.E.M./To be filled by O.E.M.
[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] Modules 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 O.E.M. To be filled by O.E.M./To be filled by O.E.M.

如果故障线程是用户模式线程,您将获得 PID 和命令行。 “污染”标志是内核表示它不是内核错误的方式(内核源代码是开放且“纯净”的)。“污染”来自亵渎神明的非 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

显示堆栈指针附近的区域。内核不知道这些值的含义,但它们与您从显示 $rsp 的 gdb 获得的输出相同。因此,由您决定它们是什么。 (例如,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

同样,内核无法为您反汇编(它正在崩溃,并且很可能会 panic ,让它休息一下!)。但是您可以使用 gdb 来反汇编这些值。

所以现在你什么都知道了。您实际上可以反汇编您自己的模块并找出在 write_func 中 NULL 指针被取消引用的确切位置。 (您可能将其作为参数传递给某个函数)。

关于linux - 如何解释内核 oops 中的地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16731570/

相关文章:

linux - 如何编写循环遍历相似字符以执行函数的脚本?

linux - 异步管道

c - 汇编相当于函数指针数组?

c - Linux 内核 3.16 上的 Moxa RealTTY 模块编译错误

c - Linux 内核如何知道将输入事件写入哪个文件描述符?

linux-kernel - Linux 用户空间中通过/dev/mem 与 PCIe 设备进行双向通信?

linux - 系统启动时自动挂载文件系统到/etc/fstab

linux - ldapsearch 获取特定 AD 组中的用户 (samAccountName) 列表

c++ - 如何用C/C++获取硬盘的运行时间

linux-kernel - DEFINE_IDA 是什么意思?