Linux内核调试之Oops信息



http://blog.sina.com.cn/s/blog_703f58b101015mat.html

http://blog.chinaunix.net/uid-23046336-id-3220727.html

常在河边走,哪能不湿鞋。用Linux,总有死机的时候,如果运气好,会看到一些所谓”Oops”信息(在屏幕上或系统日志中),比如:

Unable to handle kernel paging request at virtual address f899b670

Oops这个英文单词的意思是“哎呀”,当内核出错时(比如访问非法地址),输出的信息就成为Oops信息,

Oops可以看成是内核级的Segmentation Fault。应用程序如果进行了非法内存访问或执行了非法指令,会得到Segfault信号,一般的行为是coredump,应用程序也可以自己截获Segfault信号,自行处理。如果内核自己犯了这样的错误,则会打出Oops信息。


出现Oops消息的大部分错误时因为对NULL指针取值或者因为用了其他不正确的指针值。

Oops如何产生的解释如下:

    由于处理器使用的地址几乎都是虚拟地址,这些地址通过一个被称为“页表”的结构被映射为物理地址。当引入一个非法指针的时候,分页机制无法将该地址映射到物理地址,此时处理器就会向操作系统发出一个“页面失效(page fault)”的信号。如果地址非法“换入(page in)”缺失页面;这时,如果处理器恰好处于超级用户模式,系统就会产生一个Oops。


Oops 信息来源及格式
Oops 这个单词含义为“惊讶”
,当内核出错时(比如访问非法地址)打印出来的信息被
称为 Oops 信息。
Oops 信息包含以下几部分内容。
1 一段文本描述信息。
比如类似“Unable to handle kernel NULL pointer dereference at virtual address 00000000”
的信息,它说明了发生的是哪类错误。
2 Oops 信息的序号。
比如是第 1 次、第 2 次等。这些信息与下面类似,中括号内的数据表示序号。
Internal error: Oops: 805 [#1]
3 内核中加载的模块名称,也可能没有,以下面字样开头。
Modules linked in:
4 发生错误的 CPU 的序号,对于单处理器的系统,序号为 0,比如:
CPU: 0
Not tainted (2.6.22.6 #36)
5 发生错误时 CPU 的各个寄存器值。
6 当前进程的名字及进程 ID,比如:
Process swapper (pid: 1, stack limit = 0xc0480258)
这并不是说发生错误的是这个进程,而是表示发生错误时,当前进程是它。错误可能发
生在内核代码、驱动程序,也可能就是这个进程的错误。
7 栈信息。
8 栈回溯信息,可以从中看出函数调用关系,形式如下:
Backtrace:
[<c001a6f4>] (s3c2410fb_probe+0x0/0x560) from [<c01bf4e8>] (platform_drv_
probe+0x20/0x24)
...
9 出错指令附近的指令的机器码,比如(出错指令在小括号里)
:
Code: e24cb004 e24dd010 e59f34e0 e3a07000 (e5873000)

配置内核使 Oops 信息的栈回溯信息更直观
Linux 2.6.22 自身具备的调试功能,可以使得打印出的 Oops 信息更直观。通过 Oops 信
息中 PC 寄存器的值可以知道出错指令的地址,通过栈回溯信息可以知道出错时的函数调用
关系,根据这两点可以很快定位错误。
要让内核出错时能够打印栈回溯信息,编译内核时要增加“-fno-omit-frame-pointer”选
项,这可以通过配置 CONFIG_FRAME_POINTER 来实现。查看内核目录下的配置文件.config,
确保 CONFIG_FRAME_POINTER 已经被定义,如果没有,执行“make menuconfig”命令重
新配置内核。CONFIG_FRAME_POINTER 有可能被其他配置项自动选上。

1.首先,编译时打开complie with debug info选项,步则如下

make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- menuconfig

进入 Kernel hacking

选择 Compile the kernel with debug info

然后,保存,退出。

接着 make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

编译, 等编译完成。

2.利用arm-none-linux-gnueabi-gdb 调试,如下:

arm-none-linux-gnueabi-gdb vmlinux


对应着Oops 消息里面的这一行

[ 1023.520000] LR is at atmel_tasklet_func+0x10/0x690

在gdb下键入命令 : l *atmel_tasklet_func+0x10(注意:这里的‘l’是字母“L”,由于字体的原因看起来像‘1’)


这样就找到了出错的代码行。在这里鄙视一下atmel提供的内核,竟然还有bug!

从这里可以看出是由于串口的dma导致Oops的,于是我去掉了串口的dma传输。方法如下:


去掉之后还没有发现上述的Oops出现。


其中 lr 值为 c01bd5a8,表示函数 platform_drv_probe 执行完后的返回地址,它是上一级
调用函数中的地址。使用 lr 值,重复本步骤的查找过程,直到栈信息分析完毕或者再也无法
分析,这样就可以找出所有的函数调用关系。


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值