oops_根据epc定位linux_kernel_panic位置

本文介绍了一种针对Linux内核中出现的“Unable to handle kernel paging request at virtual address”错误的定位方法。通过分析异常程序计数器(epc)的具体位置及调用堆栈,结合System.map和vmlinux.o文件,可以精确找到导致问题的代码位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

韩大卫@吉林师范大学

2014.12.10

转载请表明出处

*****************************************************

    关于内核报错 “Unable to handle kernel paging request at virtual address” 的问题, 绝大多数都是由于程序使用了不可用的指针而引起的, 定位这类问题的办法很简单,也希望我的描述足够简单实用. 

以我下面的一个实例说明:

 

epc :exception program counter  , 异常程序计数器,  ra : return address 返回地址

我们可以根据 “CPU 0 Unable to handle kernel paging request at virtual address 0000000000000078, epc == ffffffff805e96e8, ra == ffffffff80ec73d0”  找到epc的具体位置,  再根据具体的汇编程序定位出引起epc的具体原因, 另外, 如有必须知道全部的调用路径. 那么重复定位epc的方法,根据call trace 逐步定位即可. 

在编译linux 的时候, 会产生一个System.map, vmlinux, 以及vmlinux.o

我们使用System.map 和vmlinux.o 即可. 因为vmlinux可能是被特定压缩工具压缩过的(根据您的makefile), 无法使用objdump工具做反汇编. 

先打开System.map:

将 epc == ffffffff805e96e8 里的 ffffffff805e96e8 地址拷贝下来,  直接在System.map 里面查找, 如果没有找到, 那么将ffffffff805e96e8 最后两位删掉, 即ffffffff805e96,  查找这个地址, 绝大多数情况都可以找到, 我的如下:  


看来问题是出在 add_mtd_device 这个函数里面. 

epc 的位置是在ffffffff805e96e8,  add_mtd_device 的地址是在ffffffff805e96c0 , 那么应该是在add_mtd_device里的ffffffff805e96e8 - ffffffff805e96c0 = 0x28 这个偏移位置出了问题. 

 现在我们需要观察 vmlinux.o 的汇编代码, 找到 add_mtd_device 函数的汇编,  观察 0x28 位置的汇编语言. 

先使用xxx-objdump(xxx为具体的交叉编译工具前缀)  将vmlinux.o 反汇编出来, 我的做法是:

mips64-octeon-linux-gnu-objdump -dr vmlinux.o >> linux-dr

之后打开linux-dr 这个文件,  找到 add_mtd_device 的定义处: 

可以看到, 0x28 位置的汇编:

28:   dc820078    ld  v0,120(a0)

ld v0, 120(a0) 的含义是:

先取寄存器a0的数值的地址, 再将该地址后120字节处的数值加载到v0 寄存器.

(a0)是取a0寄存器的地址, a0是负责传递函数的第一个参数的寄存器.

dc820078  就是ld v0, 120(a0) 对应的机器码.  

根据CPU 0 Unable to handle kernel paging request at virtual address 0000000000000078 这句话的提示可以知道,  

是在对a0的0x78(120) 地址取值的时候发生了错误,  很可能是a0地址本身不可用. 如果能确认的话, 就可以证明add_mtd_device的第一个参数使用一个不可用的指针.  

这时候就可以检查源代码,  相信您有能力很快到定位问题. 

但如果该函数很大,  不容易定位,  那么我们可以通过120这个信息定位到该函数里具体的语句. 

我的实例:

打开linux内核源代码,  计算120字节在add_mtd_device() 第一个参数类型里的位置, 得到参数成员:

vi -t  add_mtd_device

如下图: 

 


找到第一个参数的类型struct mtd_info 定义, 通过逐步计算每个成员偏移(注意填充字节),  

可以算出第120字节的成员为backing_dev_info. 那么, 在代码里, 出现epc的程序就是第一个出现该成员的地方. 

如果这个偏移太大, 很难计算的话, 不妨在代码里, 在调用该函数前自定义一个该参数类型的变量, 

估计一个大概的成员, 计算他们的偏移, 在知道这个成员偏移量的基础上, 再计算120的成员位置. 会容易一些. 

 

我的做法是:

struct mtd_info my = {0};  

unsigned long len = (unsigned long)&(my.backing_dev_info) - (unsigned long)&my;

printk("sizeof is = 0x%lu\n", len);

当然, 这需要重启设备, 并load新编译的linux. 

 

关于定位epc 位置, 总结一下:

1, 打开System.map, 找到epc之前的最近函数的地址.计算出epc距离该函数的偏移值. 

2, 使用objdump 找到该函数, 分析 epc 偏移处的汇编代码. 

3, 打开源代码, 根据分析汇编代码得到的信息进行定位. 

 

转自:https://blog.youkuaiyun.com/han_dawei/article/details/41846055

我有多台运行openwrt 12的AP设备,在运行四天之后发生设备异常重启,1.两台笔记本,一台连LAN口,一台连无线,双向PING包,AP设备发生重启 CPU 0 Unable to handle kernel paging request at virtual address e79190a0, epc == 800eca00, ra == 800cff34 [347296.030000] Call Trace: [347296.030000] [<800eca00>] sync_supers+0x44/0x124 [347296.030000] [<800cff34>] bdi_sync_supers+0x34/0x58 [347296.030000] [<8008ea08>] kthread+0x90/0x98 [347296.030000] [<80066950>] kernel_thread_helper+0x10/0x18 2. 两台笔记本,一台连LAN口,一台连无线,双向PING包,AP设备发生重启 Unhandled kernel unaligned access[#1]: [347296.020000] Call Trace: [347296.020000] [<800eca00>] sync_supers+0x44/0x124 [347296.020000] [<800cff34>] bdi_sync_supers+0x34/0x58 [347296.020000] [<8008ea08>] kthread+0x90/0x98 [347296.020000] [<80066950>] kernel_thread_helper+0x10/0x18 3.两台笔记本,一台连LAN口,一台连无线,双向PING包,AP设备发生重启 Unhandled kernel unaligned access[#1]: [347296.020000] Call Trace: [347296.020000] [<800eca00>] sync_supers+0x44/0x124 [347296.020000] [<800cff34>] bdi_sync_supers+0x34/0x58 [347296.020000] [<8008ea08>] kthread+0x90/0x98 [347296.020000] [<80066950>] kernel_thread_helper+0x10/0x18 4.两台笔记本,一台连LAN口,一台连无线,双向PING包,AP设备发生重启 Data bus error, epc == 8006ad60, ra == 8006af14 [347296.020000] Call Trace: [347296.020000] [<8006ad60>] emulate_load_store_insn+0x220/0x2f8 [347296.020000] [<8006af14>] do_ade+0xdc/0x158 [347296.020000] [<80064e20>] ret_from_exception+0x0/0xc [347296.020000] [<800eca00>] sync_supers+0x44/0x124 [347296.020000] [<800cff34>] bdi_sync_supers+0x34/0x58 [347296.020000] [<8008ea08>] kthread+0x90/0x98 [347296.020000] [<80066950>] kernel_thread_helper+0x10/0x18 5.两台笔记本,一台连LAN口,一台连无线,双向PING包,AP设备发生重启 Data bus error, epc == 8006ad60, ra == 8006af14 [347296.020000] Call Trace: [347296.020000] [<8006ad60>] emulate_load_store_insn+0x220/0x2f8 [347296.020000] [<8006af14>] do_ade+0xdc/0x158 [347296.020000] [<80064e20>] ret_from_exception+0x0/0xc [347296.020000] [<800eca00>] sync_supers+0x44/0x124 [347296.020000] [<800cff34>] bdi_sync_supers+0x34/0x58 [347296.020000] [<8008ea08>] kthread+0x90/0x98 [347296.020000] [<80066950>] kernel_thread_helper+0x10/0x18 6.未连无线挂机,访问WEB界面重启 CPU 0 Unable to handle kernel paging request at virtual address eea005a0, epc == 8007de74, ra == 80133614 [389773.160000] Call Trace: [389773.160000] [<8007de74>] __sysctl_head_next+0x3c/0x108 [389773.160000] [<80133614>] proc_sys_lookup+0x10c/0x13c [389773.160000] [<800f350c>] d_alloc_and_lookup+0x54/0x90 [389773.160000] [<800f3a80>] do_lookup+0x2a8/0x390 [389773.160000] [<800f5808>] path_lookupat+0x148/0x708 [389773.160000] [<800f5df8>] do_path_lookup+0x30/0xa4 [389773.160000] [<800f751c>] user_path_at_empty+0x60/0xa8 [389773.160000] [<800f7574>] user_path_at+0x10/0x1c [389773.160000] [<800e8a0c>] sys_faccessat+0xb4/0x1cc [389773.160000] [<8006c584>] stack_done+0x20/0x40 7.未连无线挂机,访问WEB界面重启 CPU 0 Unable to handle kernel paging request at virtual address e9a3088c, epc == 8007de74, ra == 80133614 [393501.240000] Call Trace: [393501.240000] [<8007de74>] __sysctl_head_next+0x3c/0x108 [393501.240000] [<80133614>] proc_sys_lookup+0x10c/0x13c [393501.240000] [<800f350c>] d_alloc_and_lookup+0x54/0x90 [393501.240000] [<800f3a80>] do_lookup+0x2a8/0x390 [393501.240000] [<800f5808>] path_lookupat+0x148/0x708 [393501.240000] [<800f5df8>] do_path_lookup+0x30/0xa4 [393501.240000] [<800f751c>] user_path_at_empty+0x60/0xa8 [393501.240000] [<800f7574>] user_path_at+0x10/0x1c [393501.240000] [<800e8a0c>] sys_faccessat+0xb4/0x1cc [393501.240000] [<8006c584>] stack_done+0x20/0x40 8.输入cat /proc/sys/fs/file补全命令时重启 [502416.700000] Unhandled kernel unaligned access[#1]: [502416.700000] Call Trace: [502416.700000] [<8007de74>] __sysctl_head_next+0x3c/0x108 [502416.700000] [<801333ec>] proc_sys_readdir+0x118/0x234 [502416.700000] [<800f9f7c>] vfs_readdir+0xb4/0xdc [502416.700000] [<800fa16c>] sys_getdents64+0x74/0xe8 [502416.700000] [<8006c584>] stack_done+0x20/0x40 9.运行四天,访问WEB界面重启 [357658.830000] Unhandled kernel unaligned access[#1]: [357658.830000] Call Trace: [357658.830000] [<8007de74>] __sysctl_head_next+0x3c/0x108 [357658.830000] [<80133614>] proc_sys_lookup+0x10c/0x13c [357658.830000] [<800f350c>] d_alloc_and_lookup+0x54/0x90 [357658.830000] [<800f3a80>] do_lookup+0x2a8/0x390 [357658.830000] [<800f5808>] path_lookupat+0x148/0x708 [357658.830000] [<800f5df8>] do_path_lookup+0x30/0xa4 [357658.830000] [<800f751c>] user_path_at_empty+0x60/0xa8 [357658.830000] [<800f7574>] user_path_at+0x10/0x1c [357658.830000] [<800e8a0c>] sys_faccessat+0xb4/0x1cc [357658.830000] [<8006c584>] stack_done+0x20/0x40
06-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值