出现Oops消息的大部分错误时因为对NULL指针取值或者因为用了其他不正确的指针值。
Oops如何产生的解释如下:
由于处理器使用的地址几乎都是虚拟地址,这些地址通过一个被称为“页表”的结构被映射为物理地址。当引入一个非法指针的时候,分页机制无法将该地址映射到物理地址,此时处理器就会向操作系统发出一个“页面失效(page fault)”的信号。如果地址非法“换入(page in)”缺失页面;这时,如果处理器恰好处于超级用户模式,系统就会产生一个Oops。
Oops的格式:
更加详细的解释参考下面代码,这里对输出信息做个简要介绍:
arch/arm/mm/fault.c
arch/arm/kernel/traps.c
Unable to handle kernel NULL pointer dereference at virtual address 00000000
//一段文本信息,提示表明是什么错误类型
pgd = 80004000
[00000000] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT//错误序号,中括号中蓝色
last sysfs file:
Modules linked in://被连接进的模块
CPU: 0 Not tainted (2.6.35.3-00054-g8deb747-dirty #1)
//发生错误的CPU序号,蓝色表示编译了10次。
PC is at mutex_lock+0xc/0x28
LR is at alc5633_reg_write+0x20/0x5c
pc : [<80375de8>] lr : [<801ce2d0>] psr: a0000013
sp : 9b029e50 ip : 9b029e60 fp : 9b029e5c
r10: 9b22c2d0 r9 : 9b22c2d0 r8 : 00000000
r7 : 804c0c10 r6 : 9b22c208 r5 : 00000000 r4 : 00000000
r3 : 00000001 r2 : 00000000 r1 : 00000000 r0 : 00000000
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c5387d Table: 90004019 DAC: 00000017
//发生错误时候CPU中各个寄存器的值,即当时CPU寄存器快照
Process swapper (pid: 1, stack limit = 0x9b0282e8)
//当前进程的名字和进程ID。但是这并不表示该进程中发生了该错误,而是表示发生错误时候,当前的进程是它。错误可能发生在内核代码、驱动程序,也可能就是这个进程的错误。
Stack: (0x9b029e50 to 0x9b02a000)
9e40: 9b029e7c 9b029e60 801ce2d0 80375de8
9e60: 804c0c10 00000000 9b22c200 00000000 9b029eac 9b029e80 802c043c 801ce2bc
9e80: 804e6b8c 804c0c10 804c0c44 804e6b8c 804e6b8c 00000000 00000000 00000000
9ea0: 9b029ebc 9b029eb0 801c2cac 802c0328 9b029edc 9b029ec0 801c1c48 801c2c98
9ec0: 804c0c10 804c0c44 804e6b8c 00000000 9b029efc 9b029ee0 801c1d6c 801c1b84
9ee0: 804e6b8c 9b029f00 801c1d04 00000000 9b029f24 9b029f00 801c13ac 801c1d10
9f00: 9b0068b8 9b07f8d0 804e6b8c 9b1ec5a0 804d9670 00000000 9b029f34 9b029f28
9f20: 801c1a8c 801c1364 9b029f64 9b029f38 801c0c78 801c1a78 80452a97 80023f1c
9f40: 804e6b8c 80023f1c 00000001 00000013 00000000 00000000 9b029f8c 9b029f68
9f60: 801c20a0 801c0be0 8001d024 80023f1c 00000001 00000013 00000000 00000000
9f80: 9b029f9c 9b029f90 801c313c 801c1ffc 9b029fac 9b029fa0 8001d038 801c30fc
9fa0: 9b029fdc 9b029fb0 800273b4 8001d030 800515f0 00000013 9b029fdc 9b029fc8
9fc0: 80023e64 80023f1c 800515f0 00000013 9b029ff4 9b029fe0 800084ac 8002735c
9fe0: 00000000 800083f4 00000000 9b029ff8 800515f0 80008400 ffefdb9e db31f16d
//上面是栈信息
Backtrace:
[<80375ddc>] (mutex_lock+0x0/0x28) from [<801ce2d0>] (alc5633_reg_write+0x20/0x5c)
[<801ce2b0>] (alc5633_reg_write+0x0/0x5c) from [<802c043c>] (alc5633_codec_probe+0x120/0x224)
r5:00000000 r4:9b22c200
[<802c031c>] (alc5633_codec_probe+0x0/0x224) from [<801c2cac>] (platform_drv_probe+0x20/0x24)
[<801c2c8c>] (platform_drv_probe+0x0/0x24) from [<801c1c48>] (driver_probe_device+0xd0/0x18c)
[<801c1b78>] (driver_probe_device+0x0/0x18c) from [<801c1d6c>] (__driver_attach+0x68/0x8c)
r7:00000000 r6:804e6b8c r5:804c0c44 r4:804c0c10
[<801c1d04>] (__driver_attach+0x0/0x8c) from [<801c13ac>] (bus_for_each_dev+0x54/0x94)
r7:00000000 r6:801c1d04 r5:9b029f00 r4:804e6b8c
[<801c1358>] (bus_for_each_dev+0x0/0x94) from [<801c1a8c>] (driver_attach+0x20/0x28)
r7:00000000 r6:804d9670 r5:9b1ec5a0 r4:804e6b8c
[<801c1a6c>] (driver_attach+0x0/0x28) from [<801c0c78>] (bus_add_driver+0xa4/0x224)
[<801c0bd4>] (bus_add_driver+0x0/0x224) from [<801c20a0>] (driver_register+0xb0/0x140)
[<801c1ff0>] (driver_register+0x0/0x140) from [<801c313c>] (platform_driver_register+0x4c/0x60)
r9:00000000 r8:00000000 r7:00000013 r6:00000001 r5:80023f1c
r4:8001d024
[<801c30f0>] (platform_driver_register+0x0/0x60) from [<8001d038>] (alc5633_init+0x14/0x1c)
[<8001d024>] (alc5633_init+0x0/0x1c) from [<800273b4>] (do_one_initcall+0x64/0x1bc)
[<80027350>] (do_one_initcall+0x0/0x1bc) from [<800084ac>] (kernel_init+0xb8/0x174)
r7:00000013 r6:800515f0 r5:80023f1c r4:80023e64
[<800083f4>] (kernel_init+0x0/0x174) from [<800515f0>] (do_exit+0x0/0x674)
r5:800083f4 r4:00000000
//上面是栈回溯的信息,可以从中看出调用关系。我们配置CONFIG_FRAME_POINTER这个选项也就是为了出这些信息。
Code: e89dadf0 e1a0c00d e92dd800 e24cb004 (e1903f9f)
//出错指令附近的指令机器码,比如(出错指令在小括号内)。
---[ end trace ae0d0d75681e1941 ]---
上面的内核Oops就是当时调试ALC5633过程中发生的错误,正是通过Oops信息回溯发现了问题点。
明确出错原因
“Unable to handle kernel NULL pointer dereference at virtual address 00000000”可知内核因为非法地址访问出错,使用了空指针。
根据栈回溯信息找出函数调用关系。
内核崩溃时,可以从pc寄存器得知崩溃发生时的函数,出错指令。但是很多情况下是它的调入者引入的,所以找出调用关系很重要,这就是引入栈回溯的目的。
从栈回溯信息我们可以得到清晰的函数调用关系,以及最后在mutex_lock函数内部崩溃。
do_exit()
kernel_init()
do_one_initcall()
alc5633_init()
platform_driver_register()
driver_register()
bus_add_driver()
driver_attach()
bus_for_each_dev()
__driver_attach()
driver_probe_device()
platform_drv_probe()
alc5633_codec_probe()
alc5633_reg_write()
mutex_lock()
根据PC寄存器的值确定出错位置。
PC is at mutex_lock+0xc/0x28
LR is at alc5633_reg_write+0x20/0x5c
pc : [<80375de8>] lr : [<801ce2d0>] psr: a0000013
sp : 9b029e50 ip : 9b029e60 fp : 9b029e5c
r10: 9b22c2d0 r9 : 9b22c2d0 r8 : 00000000
r7 : 804c0c10 r6 : 9b22c208 r5 : 00000000 r4 : 00000000
r3 : 00000001 r2 : 00000000 r1 : 00000000 r0 : 00000000
上面标示出错指令在mutex_lock偏移在0xc处的指令。pc : [<80375de8>]表示出错地址的指令为80375de8
反汇编我们的内核,采用如下指令:
./prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-objdump
-D vmlinux > vmlinux.dis
结合反汇编我们定位到函数:
80375ddc :
80375ddc: e1a0c00d mov ip, sp
80375de0: e92dd800 push {fp, ip, lr, pc}
80375de4: e24cb004 sub fp, ip, #4 ; 0x4
80375de8: e1903f9f ldrex r3, [r0]
80375dec: e2433001 sub r3, r3, #1 ; 0x1
80375df0: e1802f93 strex r2, r3, [r0]
80375df4: e1923003 orrs r3, r2, r3
80375df8: 089da800 ldmeq sp, {fp, sp, pc}
80375dfc: ebffff9f bl 80375c80 <__mutex_lock_slowpath>
80375e00: e89da800 ldm sp, {fp, sp, pc}
上面可以看到r0里面的值为0x00000000。这里知道了我们给mutex_lock传的参数为空指针。
【这里需要知道ARM函数参数传递规则,根据该规则r0存有函数传过来的第一参数,超过4个参数,要进行压栈动作了。】
下面是muetx_lock上一级的调用代码:
96 int alc5633_reg_write(struct alc5633 *alc5633, unsigned short reg,
97 unsigned short val)
98 {
99 int ret;
100
101 mutex_lock(&alc5633->io_lock);
102
103 ret = alc5633_write(alc5633, reg, 2, &val);
104
105 mutex_unlock(&alc5633->io_lock);
106
107 return ret;
108 }
109 EXPORT_SYMBOL_GPL(alc5633_reg_write);
进而发现alc5633->io_lock为空。
在查看再上级的代码,在alc5633_codec_probe()代码如下:
779 static int alc5633_codec_probe(struct platform_device *pdev)
780 {
...
818 alc5633_reg_write(codec->control_data,ALC5633_RESET,0);
...
853 }
蓝色部分我们没有初始化具体的struct alc5633 *类型的值过来,导致了空指针的出现,定位了问题的出处,就好解决了。
from: http://blog.chinaunix.net/uid-27159438-id-3280213.html
- Arm Linux系统调用流程详细解析
Linux系统通过向内核发出系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口. 系统调用是操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的 ...
- ARM Linux 内核 panic 之cache 一致性 ——cci-400 cache一致互联
ARM Linux 内核 panic 之cache 一致性 ——cci-400 cache一致互联 CCI-400 集合了互联和一致性功能,有 2 个 ACE slave 接口和 3 个 ACE-Li ...
- ARM Linux系统调用的原理
转载自:http://blog.csdn.net/hongjiujing/article/details/6831192 ARM Linux系统调用的原理 操作系统为在用户态运行的进程与硬件设备进行交 ...
- 【Qt开发】【VS开发】【Linux开发】OpenCV、Qt-MinGw、Qt-msvc、VS2010、VS2015、Ubuntu Linux、ARM Linux中几个特别容易混淆的内容
[Qt开发][VS开发][Linux开发]OpenCV.Qt-MinGw.Qt-msvc.VS2010.VS2015.Ubuntu Linux.ARM Linux中几个特别容易混淆的内容 标签:[Qt ...
- ARM Linux Qt 5.x.x 无标题栏
/********************************************************************************* * ARM Linux Qt 5. ...
- Linux 常用工具小结:(5) lftp工具使用
Linux 常用工具小结:(1) lftp工具使用. 这里会按照一些比较常用的功能列出,并举一个具体的例子逐一解释功能. 通常使用ftp过程是登陆ftp,浏览ftp内容,下载ftp文件,或者上传ftp ...
- 构建 ARM Linux 4.7.3 嵌入式开发环境 —— BusyBox 构建 RootFS
上一篇我们已经成功将 ARM Linux 4.7.3 的内核利用 U-BOOT 引导了起来.但是细心的你会发现,引导到后面,系统无法启动,出现内核恐慌 (Kernel Panic). 原因是找不到文件 ...
- 构建 ARM Linux 4.7.3 嵌入式开发环境 —— U-BOOT 引导 Kernel
经过若干天的反复测试,搜索.终于成功利用 Qemu 在 u-boot 下引导 ARM Linux 4.7.3 内核.如下详细解释整个构建过程. 准备环境 运行环境:Ubuntu 16.04 需要的虚拟 ...
- ARM Linux 3.x的设备树(Device Tree)
http://blog.csdn.net/21cnbao/article/details/8457546 宋宝华 Barry Song <21cnbao@gmail.com> 1. ...
随机推荐
- 【转】Vmware14安装Centos7无法上网问题的解决
原文链接 1. 选择Net模式 修改配置子网ip. 修改子网的IP不要和本机的IP地址在同一个网段 比如本机IP地址信息: 无线局域网适配器 WLAN: 连接特定的 DNS 后缀 . . . . . ...
- 解锁scott账户方法
装完了数据库,忘了给scott账户解锁.这时可以在sql plus工具里,也可以在控制台通过命令行给scott账户解锁. 在第一种情况下,以system账户+自己安装时设置的密码,登录SQL Plus ...
- Duplicate复制数据库并创建物理StandBy(pfile版本)
1设定环境如下: Primary数据库 IP 172.17.22.16 SID orcl Standby数据库 IP 172.17.22.17 SID orcl 设置提示,以区分操作的位置 prima ...
- 基于Centos搭建Laravel 环境搭建
系统要求:CentOS 7.2 64 位操作系统 安装 Laravel Laravel 简介 Laravel 是一套简洁.优雅的 PHP Web 开发框架.它可以让你从面条一样杂乱的代码中解脱出来:它 ...
- android的activity被杀死后如何重启
最近公司的大屏展示机器人上的程序运行时间长了,比如五天,十天会出现偶尔的崩溃,查日志可能是内存溢出或者是ndk层的错误,这种错误一时也不太好查找,但是产品那边有个要求就是程序退出了一定要能重启,能抓日 ...
- String的split方法支持正则表达式
String的split方法支持正则表达式: 1. 正则表达式\s表示匹配任何空白字符 2. +表示匹配一次或多次
- Gradle环境变量的配置
配置GRADLE_HOME: 找到Android Studio中gradle的位置 E:\Android_Studio\gradle\gradle-2.10 配置GRADLE_USER_HOME: 找 ...
- Selenium:注解@FindBy、@FindBys、@FindAll的用法
方式有3种:@FindBy.@FindBys.@FindAll.下文对3中类型的区别和使用场景进行介绍 1)@FindBy @FindBy(id= "A") private Web ...
- 点云PCL中小细节
计算点与点之间的距离的平局距离 double computeCloudResolution (const pcl::PointCloud<PointType>::ConstPtr & ...
- tronado学习
请求处理程序和请求参数: 原创首发:http://www.cnblogs.com/zxlovenet/p/4128644.html 程序将URL映射到tornado.web.RequestHandle ...