内核Oops小结
出现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 *类型的值过来,导致了空指针的出现,定位了问题的出处,就好解决了。
arm-linux-objdump  -m arm  -D  xxx.o  >  err
通过这个命令能够得到反汇编文件

linux oops相关推荐

  1. 初步认识Linux oops 消息

    oops是英语口语"糟糕"的意思,当LINUX 内核发生严重错误时,比如内存段错误时,将会提示一大段信息.     Oops提示信息相当多,包括出问题时的,各个常用寄存器的值,调用 ...

  2. linux oops产生原理,kernel panic , Oops 等cpu异常的分析与定位

    一.kernel panic 二.mips异常机制 三.linuxkernel 对mips异常的处理 四.kernel panic 实例分析 Kernel  panic 内核代码,相比用户层代码更难以 ...

  3. 一次linux oops分析

    移植microarrayfp指纹模块,在probe进行spi写.读操作时内核出现oops的崩溃问题. [ 18.404728] Unable to handle kernel paging reque ...

  4. linux oops定位问题

    注意分析pc is at系统挂死的行号,结合反汇编定位.以及关键寄存器的值,还有dump_stack()打印出来的调用堆栈关系. oops的原因,也就是报告出错的原因: OOP信息序号: 出错时内核已 ...

  5. 依据linux Oops信息准确定位错误代码所在行

    在linux下调tvp5150am1的过程中,遇到了一kernel oops,内容如下: [   66.714603] Unable to handle kernel paging request a ...

  6. 嵌入式Linux——oops:根据oops信息,找到错误的产生位置以及函数的调用关系

    简介: 本文主要介绍通过oops信息找到程序中出错位置的方法.并结合自己代码中的错误来讲解如何找到出错位置.同时还会介绍使用栈信息来推到函数间的调用关系.  Linux内核:linux-2.6.22. ...

  7. linux oops问题调试

    36.Linux驱动调试-根据oops定位错误代码行 1.当驱动有误时,比如,访问的内存地址是非法的,便会打印一大串的oops出来 1.1以LED驱动为例 将open()函数里的ioremap()屏蔽 ...

  8. linux oops产生原理,linux oops产生过程之dump_backtrace

    什么是Oops?从语言学的角度说,Oops应该是一个拟声词.当出了点小事故,或者做了比较尴尬的事之后,你可以说"Oops",翻译成中国话就叫做"哎呦".&quo ...

  9. Android linux Oops 信息

    项目调试中碰见过多次,之前不懂是 Oops,下面记录下 linux中经常遇到下面情况出现空指针,导致 linux 死掉: linux sys 创建的节点中 store 函数返回值不是 return c ...

  10. arm linux oops 5,ARM Linux Oops使用小结

    内核Oops小结 出现Oops消息的大部分错误时因为对NULL指针取值或者因为用了其他不正确的指针值. Oops如何产生的解释如下: 由于处理器使用的地址几乎都是虚拟地址,这些地址通过一个被称为&qu ...

最新文章

  1. linux常用命令简介- 用户管理及文件属性
  2. 如何在div中将绝对定位的元素居中?
  3. Android处理崩溃的一些实践
  4. 北斗导航 | GPS原理与接收机设计——青冥剑(金码、C/A码、P码)
  5. 百度交易中台之账房系统架构浅析
  6. redis 槽点重新分配 集群_redis集群高可用部署-cluster-槽点的迁移查看
  7. python自动化第三周---文件读写
  8. linux 热拔插硬盘,带电热插拔硬盘造成硬盘故障
  9. 容器编排技术 -- 本地运行Kubrenetes v1.0
  10. Android如何判断输入框是否为空
  11. 用python做一个搜索引擎(Pylucene)
  12. java移位操作示例
  13. 今日头条阅读量怎么刷_自动刷今日头条阅读量 头条号自己刷阅读量
  14. 基于多任务深度学习的时空网络流量预测
  15. 采用参数服务器的分布式机器学习
  16. 【专题5: 硬件设计】 之 【30.案例三:碎纸机,DC-DC降压方法(电容降压原理)】
  17. 免费配音软件哪个好?快把这些软件收好
  18. 青你3倒奶,蒙牛装小白花?
  19. 2021年终总结暨2022年计划安排
  20. SQL修改表的基本操作

热门文章

  1. Windows7服务一览
  2. RK3588 EVB1蓝牙休眠唤醒调试
  3. BZOJ2851 极限满月
  4. ValueError: tf.function-decorated function tried to create variables on non-
  5. 信息爆炸时代,海量信息占据了你我大部分时间。与其这样,不如看看我推荐的几个公众号。...
  6. 实时系统vxWorks - 虚拟机环境搭建
  7. 浅谈 IOC 什么是 IOC?
  8. leetcode 会议室系列
  9. V.24 V.35 ISDN E1 POS这些常见的广域网接口
  10. 3万6千字爆肝,前端进阶不得不了解的函数式编程开发,含大量实例,手写案例,所有案例均可运行