根据epc 定位linux kernel panic 位置

韩大卫@吉林师范大学

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, 打开源代码, 根据分析汇编代码得到的信息进行定位.

希望以上信息对您有帮助.

时间: 2024-08-03 17:35:44

根据epc 定位linux kernel panic 位置的相关文章

如何快速定位 Linux Panic 出错的代码行

问题描述 内核调试中最常见的一个问题是:内核Panic后,如何快速定位到出错的代码行? 就是这样一个常见的问题,面试过的大部分同学都未能很好地回答,这里希望能够做很彻底地解答. 问题分析 内核Panic时,一般会打印回调,并打印出当前出错的地址: kernel/panic.c:panic(): #ifdef CONFIG_DEBUG_BUGVERBOSE /* * Avoid nested stack-dumping if a panic occurs during oops processin

kernel panic

Linux kernel panic是很难定位和排查的重大故障,一旦系统发生了kernel panic,相关的日志信息非常少,而一种常见的排查方法-重现法–又很难实现,因此遇到kernel panic的问题,一般比较头疼.没有一个万能和完美的方法来解决所有的kernel panic问题,这篇文章仅仅只是给出一些思路,一来如何解决kernel panic的问题,二来可以尽可能减少发生kernel panic的机会.什么是kernel panic 就像名字所暗示的那样,它表示Linux kernel

linux加载rootfs 根文件系统 kernel panic - not

环境:linux内核加载自己的制作的文件系统. 错误信息有以下几种: 错误信息1: Root-NFS: Server returned error -5 while mounting /mini2440/rootfs VFS: Unable to mount root fs via NFS, trying floppy. VFS: Cannot open root device "nfs" or unknown-block(2,0) Please append a correct &q

linux 内核启动错误和selinux参数 Kernel panic -not syncing:Attempted to kill init

今天在装某个软件的时候,修改了selinux参数.修改selinux 的某个参数值为Disable.导致 linux系统不能启动.出现如下错误 Kernel panic -not syncing:Attempted to kill init! 后经过向群友请教和自己操作和互联网搜索,终于找到了解决办法. 在linux启动界面出现时,按f2进入如下界面: 按e进入如下界面 移动到第2个选项,再按e进入编辑 在后面输入 selinux=0 按回车. 返回到原来界面, 再按b,就可以启动了. 以下为转

linux启动报错:kernel panic - not attempted to kill init

系统类型:CentOS 6.4(x64) 启动提示:Kernel panic - not syncing: Attempted to kill init 解决办法: 系统启动的时候,按下‘e’键进入grub编辑界面,编辑grub菜单,选择“kernel /vmlinuz-XXXXro root=/dev/vogroup00/logvol00 rhgb quiet” 一栏,按‘e’键进入编辑,在末尾增加enforcing=0,即:kernel /vmlinuz-XXXXro root=/dev/v

Linux Kernel - Debug Guide (Linux内核调试指南 )

http://blog.csdn.net/blizmax6/article/details/6747601 linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 建立调试环境 发行版的选择和安装 安装交叉编译工具 bin工具集的使用 qemu的使用 initrd.img的原理与制作 x86虚拟调试环境的建立 arm虚拟调试环境的建立 arm开发板调试环

ARM Linux 内核 panic 之cache 一致性 ——cci-400 cache一致互联

ARM Linux 内核 panic 之cache 一致性 ——cci-400 cache一致互联 CCI-400 集合了互联和一致性功能,有 2 个 ACE slave 接口和 3 个 ACE-Lite slave 接口,有 3 个 AXI master 接口.2 个 ACE slave 接口可以相互 snoop 对方,ACE-Lite slave 接口可以 snoop 这 2 个 ACE slave 接口.本文首先介绍cci-400相关结构,然后以内核的panic为引子,最后给出导致内核pa

深入 kernel panic 流程【转】

一.前言 我们在项目开发过程中,很多时候会出现由于某种原因经常会导致手机系统死机重启的情况(重启分Android重启跟kernel重启,而我们这里只讨论kernel重启也就是 kernel panic 的情况),死机重启基本算是影响最严重的系统问题了,有稳定复现的,也有概率出现的,解题难度也千差万别,出现问题后,通常我们会拿到类似这样的kernel log信息(下面log仅以调用BUG()为例,其它异常所致的死机log信息会有一些不同之处): [ 2.052157] <2>-(2)[1:swa

挂载文件系统出现&quot;kernel panic...&quot; 史上最全解决方案

问:挂载自己制作的文件系统卡在这里: NET: Registered protocol family 1 NET: Registered protocol family 17 VFS: Mounted root (cramfs filesystem) readonly. Freeing init memory: 116K Failed to execute /linuxrc. Attempting defaults... Kernel panic - not syncing: No init f