驱动从PC指针分析段错误

我们将驱动程序故意改一句话  我们都知道寄存器要ioremap之后才能用。在驱动程序里面不能使用物理地址 或者对那种没有初始化指针的时候你操作也会出错。我现在故意引入这个错误 我们修改以前的LED代码用来说明

我们将以前的驱动程序改成下面这种


然后加载并运行测试程序


我们现在就根据这一大堆错我来找问题


[  181.105729] Unable to handle kernel paging request at virtual address e0200280

第一句话 无法处理对内核的也请求在虚拟地址e0200280,驱动程序是把所有的地址当中虚拟地址访问的,它这里无法识别或者处理你这个虚拟地址,因为根本 没有这个虚拟地址,因为你还没有建立映射,

[  181.105801] pgd = cf4fc000
[  181.105827] [e0200280] *pgd=00000000
[  181.105865] Internal error: Oops: 805 [#1] PREEMPT

Internal error: Oops: 805 [#1] PREEMPT  内部错误OOPS

[  181.105907] last sysfs file: /sys/devices/virtual/led_class/led_driver/dev

[  181.108524] Modules linked in: led humidity ov9650 timer_irq second buzzer_drv adc_drv snd_soc_gec210_wm8960 snd_soc_wm8960

 Modules linked in: led 表示是在led模块发生了这个错误

[  181.119619] CPU: 0    Not tainted  (2.6.35.7-GEC210 #1)
[  181.124824] PC is at led_open+0x30/0x50 [led]

PC就是发送错误的指令的地址,我执行了某条机器码发送了错误,PC就是这条指令码的地址
[  181.129159] LR is at chrdev_open+0x18c/0x1b8

LR是LR寄存器而已
[  181.133398] pc : [<bf0380fc>]    lr : [<c0120154>]    psr: a0000013
[  181.133403] sp : cf4f7dc8  ip : 00001111  fp : cf4f7ddc
[  181.144834] r10: cf4ba700  r9 : c011ffc8  r8 : 00000001
[  181.150034] r7 : 00000000  r6 : bf0383c4  r5 : cf4c6d80  r4 : bf0383b8
[  181.156533] r3 : e0200280  r2 : 00000000  r1 : 00000004  r0 : e0200284

执行这条导致错误的执行时,各个寄存器的值
[  181.163034] Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
[  181.170139] Control: 10c5387d  Table: 3f4fc019  DAC: 00000015

[ 1317.590588] Process led_test (pid: 127, stack limit = 0xcf4f62f0)

Process表示发送错误时当前进程的名称是led_test

[ 1317.596654] Stack: (0xcf4f7dc8 to 0xcf4f8000)
[ 1317.600991] 7dc0:                   bf0380cc cf4ba700 cf4f7e0c cf4f7de0 c0120154 bf0380d8
[ 1317.609137] 7de0: c05726f4 c02349d8 cf4f7e0c cff49980 cf9be090 c0577ee0 00000000 cf4c6840
[ 1317.617283] 7e00: cf4f7e3c cf4f7e10 c011b230 c011ffd4 00000000 cf4c6840 00000000 00000666
[ 1317.625429] 7e20: 00000000 0000002e beea5c4c cf4c6840 cf4f7e54 cf4f7e40 c011c114 c011b0c0
[ 1317.633574] 7e40: 00002000 cf4f7ec8 cf4f7e8c cf4f7e58 c0128388 c011c0f0 c08603a0 00000000
[ 1317.641720] 7e60: cf4f7e8c cf4f7ec8 00000666 cf4f7f28 00000000 cf4f6000 00000000 0000002e
[ 1317.649866] 7e80: cf4f7f5c cf4f7e90 c0128644 c0127f30 beea5c4c c05726ac 00000071 cf4f7fb0
[ 1317.658012] 7ea0: cfec9180 400ef420 ffffff9c cf46e000 cf4f7edc beea5c4c cf4f7efc 00000000
[ 1317.666158] 7ec0: 00000667 c00d2c00 cff49980 cf9be090 f764bd4e 0000000a cf46e005 cff49480
[ 1317.674303] 7ee0: cf804240 00000301 00000000 00000000 cf4f7fac 00000000 cf4c6cc0 cf4c6ce4
[ 1317.682449] 7f00: 00000000 00000666 00000000 cf4c6cc8 cf4f7f2c 00000667 beea5c4c cf4c6840
[ 1317.690595] 7f20: cf4f7f5c cf4f7f30 cff49980 cf9be090 beea5c4c 00000000 00000003 00000666
[ 1317.698741] 7f40: beea5c4c cf46e000 cf4f6000 ffffff9c cf4f7f94 cf4f7f60 c011c18c c01284e0
[ 1317.706886] 7f60: 00000000 cf4f7f70 c01123e0 00000000 00000000 00000000 00000005 c008f168
[ 1317.715032] 7f80: cf4f6000 00000000 cf4f7fa4 cf4f7f98 c011c26c c011c134 00000000 cf4f7fa8
[ 1317.723178] 7fa0: c008efc0 c011c250 00000000 00000000 0000860c 00000666 beea5c4c 000084ac
[ 1317.731324] 7fc0: 00000000 00000000 00000000 00000005 00000000 00000000 40025000 beea5af4
[ 1317.739470] 7fe0: 00000000 beea5ae0 000084cc 400ef43c 60000010 0000860c 30a97021 30a97421

栈,这个非常有用,我们以后可以根据这个推出函数的调用关系

[ 1317.747610] Backtrace: 
[ 1317.750048] [<bf0380cc>] (led_open+0x0/0x50 [led]) from [<c0120154>] (chrdev_open+0x18c/0x1b8)
[ 1317.758617]  r4:cf4ba700 r3:bf0380cc
[ 1317.762177] [<c011ffc8>] (chrdev_open+0x0/0x1b8) from [<c011b230>] (__dentry_open.clone.13+0x17c/0x294)
[ 1317.771528]  r8:cf4c6840 r7:00000000 r6:c0577ee0 r5:cf9be090 r4:cff49980
[ 1317.778207] [<c011b0b4>] (__dentry_open.clone.13+0x0/0x294) from [<c011c114>] (nameidata_to_filp+0x30/0x44)
[ 1317.787916] [<c011c0e4>] (nameidata_to_filp+0x0/0x44) from [<c0128388>] (do_last.clone.29+0x464/0x5b0)
[ 1317.797179]  r4:cf4f7ec8 r3:00002000
[ 1317.800738] [<c0127f24>] (do_last.clone.29+0x0/0x5b0) from [<c0128644>] (do_filp_open+0x170/0x4d4)
[ 1317.809664] [<c01284d4>] (do_filp_open+0x0/0x4d4) from [<c011c18c>] (do_sys_open+0x64/0x11c)
[ 1317.818069] [<c011c128>] (do_sys_open+0x0/0x11c) from [<c011c26c>] (sys_open+0x28/0x2c)
[ 1317.826045] [<c011c244>] (sys_open+0x0/0x2c) from [<c008efc0>] (ret_fast_syscall+0x0/0x30)
[ 1317.834274] Code: e301c111 e3a01004 e3a02000 e59f0018 (e583c000) 
[ 1317.843379] ---[ end trace 8b8c2943c58e57b7 ]---
Segmentation fault

Backtarce表示回溯。回溯是什么意思呢,你可以倒过来看,sys_open函数调用do_sys_open函数调用do_filp_ope,这么一层一层调用

你想要这个回溯信息的话,必须要把内核中的一个开关打开

在内核里面叫做 FRAME_POINT


这里就会把这个回溯打印上去,有时候为了减少内核的体积,这里就没有打印上去,

我们先来看PC值,

[ 1316.984165] PC is at led_open+0x30/0x50 [led]

这里是说PC在led_open+0x30的地方发送了错误,0x30表示该指令的偏移 0x50表示该函数指令的总大小

大多时候PC只会给出一个地址,不会指示他在那个地址里面

[ 1316.992739] pc : [<bf0380fc>]    lr : [<c0120154>]    psr: a0000013

我们根据上面这个可以知道PC=bf0380fc。它属于什么地址。是内核还是通过insmod加载的驱动程序

先判断是否属于内核的地址,去看Sysmap确定内核的函数的地址范围,如果sysmap中包含这个bf0380fc,表示当前发生错误的指令是属于内核函数

否则,如果不属于Sysmap里的函数,则它属于insmod驱动程序,

假设它是加载的驱动程序引入的错误,怎么确定是哪一个驱动程序

[ 1316.978094] CPU: 0    Tainted: G      D      (2.6.35.7-GEC210 #1)
[ 1316.984165] PC is at led_open+0x30/0x50 [led]
[ 1316.988500] LR is at chrdev_open+0x18c/0x1b8

如果有这些信息就可以看出,如果没有的话,只得到一个PC值,怎么办

我们下面来说根据PC值去找到是那个驱动程序

进入内核的目录

我们来看看Sysmap


内核是从C0004006开始,到最后一行44020 c087f648 A _end    C087f648结束

你前面的PC=bf0380f不属于这个范围,所以肯定是外面加进来的驱动程序,

既然知道是外面加进来的驱动程序发生了错误,怎么知道是哪一个呢,先看看加载的驱动程序的函数的地址范围,

怎么看,使用下面这条指令


K代表内核,all所有的,symsfuhao   内核的函数,加载函数的地址,所有的东西都有,变量也有

我们把这个放到一个文件里面去  cat /proc/kallsyms  > 1.txt

从这些信息里找到一个相近的地址 这个地址<=bf0380fc这个值


这里有个接近的

这里led_open表示驱动程序里面有个open函数,led表示驱动程序,这个led_open是属于这个驱动程序的,这个led_open函数的地址是0xbf0380cc

这个地址就属于PC is at led_open+0x30的地方 算出来就是0xbf0380cc+30刚好等于我们的0xbf0380fc

找到了这个驱动,然后反汇编它

在PC上使用反汇编命令arm-none-linux-gnueabi-objdump -D led.ko > led.dis

在反汇编文件里面找到led_open这个东西


然后我们PC就等于000000CC+30= 000000fc

   000000cc <led_open>:
   cc:   e1a0c00d    mov ip, sp
   d0:   e92dd818    push    {r3, r4, fp, ip, lr, pc}
   d4   e24cb004    sub fp, ip, #4
   d8:   e59f4030    ldr r4, [pc, #48]   ; 110 <led_open+0x44>
   dc:   e59f3030    ldr r3, [pc, #48]   ; 114 <led_open+0x48>
   e0:   e5843048    str r3, [r4, #72]   ; 0x48
   e4:   f57ff04f    dsb sy
   e8:   e5943048    ldr r3, [r4, #72]   ; 0x48
   ec:   e301c111    movw    ip, #4369   ; 0x1111

   f0:   e3a01004    mov r1, #4

   f4:   e3a02000    mov r2, #0

   f8:   e59f0018    ldr r0, [pc, #24]   ; 118 <led_open+0x4c>

   fc:   e583c000    str ip, [r3]

就是这一句出错

这计划的意思是将IP的值压入【R3】寄存器 对应C语言中的写的过程

R3寄存器根据我们内核的输出信息可以看到

r3 : e0200280,所以是这里出错,这个地址是非法的

这是外加的模块


如果你是直接编译进内核的话

你需要去System.map的地址有没有包括你的

然后反汇编内核

arm-linux-objdump -D vmlinux > vmlinux.dis

反汇编之后查找




  








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值