我们知道在内核里面不能够处理指向0地址的指针,我们故意引入这样一个指针,并根据打印的出错信息来进行分析,下面是我们的程序:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
int *i;
static int first_drv_init(void)
{
         i=0;
        *i=2;
        return 0;
}
static void first_drv_exit(void)
{
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");
当我们加载的时候会打印出错信息,出错信息如下:
//第一行就指出了出错的原因是由于无法处理指向0地址的指针
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c3e4c000
[00000000] *pgd=33c90031, *pte=00000000, *ppte=00000000
Internal error: Oops: 817 [#1]
Modules linked in: test  
CPU: 0    Not tainted  (2.6.22.6 #12)
//PC指明发生错误的指令的地址
//0x1c:该指令的偏移,0x28 :该函数的大小
//大多时候PC值只会是一个地址,不会指示说在哪个函数里面
//当然这里是给出了函数了
PC is at first_drv_init+0x1c/0x28 [test]
//指明LR寄存器的值
LR is at sys_init_module+0x1424/0x1514
//执行这条导致错误的指令时各个寄存器的值
pc : [<bf00001c>]    lr : [<c006285c>]    psr: a0000013
sp : c3e25ec8  ip : c3e25ed8  fp : c3e25ed4
r10: c486e000  r9 : c3e29d14  r8 : 00000018
r7 : c48795b8  r6 : bf000360  r5 : bf000360  r4 : 00000000
r3 : 00000002  r2 : c0357028  r1 : 00000001  r0 : 00000000
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  Segment user
Control: c000717f  Table: 33e4c000  DAC: 00000015
Process insmod (pid: 751, stack limit = 0xc3e24258)
//发生错误时当前进程的名称是insmod
Stack: (0xc3e25ec8 to 0xc3e26000)
5ec0:                   c3e25fa4 c3e25ed8 c006285c bf000010 00000000 00000398 
5ee0: c02a9f60 c02a9f60 000000fc 0000001c 00000018 c3c13370 c3e25f18 00000000 
5f00: 00000028 00000028 0000005c 00000058 00000014 c3e24000 00000000 00000000 
5f20: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
5f40: 00000003 00000000 00000005 00000000 00000000 00000000 00000017 00000016 
5f60: c487cd48 c3e0db80 c48794e4 000cb060 beb46918 000c7f7c c3e25f9c 0000eddb 
5f80: 000ca1b0 000cb050 00000080 c002b044 c3e24000 000c7f7c 00000000 c3e25fa8 
5fa0: c002aea0 c0061448 000ca1b0 000cb050 00900080 000cb248 0000eddb 000cb070 
5fc0: 0000eddb 000ca1b0 000cb050 00000000 000cb060 beb46918 000c7f7c 00000002 
5fe0: beb44fb8 beb44fac 00052354 401b7a00 60000010 00900080 00000000 00000000 
//这里从出错位置回溯出了函数的调用关系
Backtrace: 
[<bf000000>] (first_drv_init+0x0/0x28 [test]) from [<c006285c>] (sys_init_module+0x1424/0x1514)
[<c0061438>] (sys_init_module+0x0/0x1514) from [<c002aea0>] (ret_fast_syscall+0x0/0x2c)
Code: e59f3010 e3a00000 e5830000 e3a03002 (e5803000) 
Segmentation fault

分析:
1、根据pc值确定该指令属于内核还是外加的模块
先判断是否属于内核的地址: 看System.map确定内核的函数的地址范围:c0004000~c03be254
而本PC值为bf00001c,并不属于内核模块,而是属于加载模块
该System.map文件位于编译内核后的根目录
2、根据pc确定错误出在哪一个加载的内核模块
cat /proc/kallsyms  (内核函数、加载的函数的地址)
从这些信息中找出一个跟bf00001c相近的地址
我们找到如下信息:
bf000000 t first_drv_init[test]
这行表示first_drv_init地址是bf000000 ,显然出错位置就在0xbf000000 + 0x1c处,且对应的加载模块式test.ko
我们根据打印信息:PC is at first_drv_init+0x1c/0x28 [test]
看出确实是如此!
3、找到了test.ko
在PC上反汇编它: arm-linux-objdump -D test.ko > test.dis
在dis文件里找到地址:bf00001c,即:  
1c:e5803000  strr3, [r0]
根据对应的反汇编找到对应的c函数对应的位置
总结一下就是:
1、首先我们在出错信息中找到出错的地址
2、然后查看:System.map,判断出错位置是属于内核模块还是加载模块
3、如果是在加载模块的话,我们可以用命令:cat /proc/kallsyms > /kallsyms.txt来查看距离出错pc最近的一个函数是什么,并查看它属于哪一个模块。
最后我们反汇编该模块,并找到我们上面找到的那个函数,根据偏移地址找到出错pc的位置,根据该位置的汇编代码来判断出错位置对应c语言的位置。
上面的错误位置是出现在加载模块,那么如果出现在内核模块又怎么做呢?其实方法是完全一样的:
比如我们将上面的文件命名为test.c,然后将其放入内核的drivers/char/目录下面,然后将drivers/char/目录下的Makefile里面加上这么一句:
obj-y    +=test.o
重新编译内核:make uImage
用新内核启动
启动过程中崩溃了,打印出如下错误信息:
//看!无法处理0指针处的操作
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 805 [#1]
Modules linked in:
CPU: 0    Not tainted  (2.6.22.6 #15)
PC is at first_drv_init+0x1c/0x28
LR is at kernel_init+0xd4/0x28c
pc : [<c019ad88>]    lr : [<c0008a94>]    psr: 60000013
sp : c0471f74  ip : c0471f84  fp : c0471f80
r10: 00000000  r9 : c0023864  r8 : c0022838
r7 : c0470000  r6 : 00000000  r5 : 00000000  r4 : 00000000
r3 : 00000002  r2 : c002292c  r1 : 00000000  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  Segment kernel
Control: c000717f  Table: 30004000  DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc0470258)
Stack: (0xc0471f74 to 0xc0472000)
1f60:                                              c0471ff4 c0471f84 c0008a94 
1f80: c019ad7c 0a00002e e5943000 00000000 00000001 e59f10fc 00000000 00000000 
1fa0: 00000000 c0471fb0 c002af24 c0040330 00000000 00000000 c00089c0 c00466f0 
1fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
1fe0: 00000000 00000000 00000000 c0471ff8 c00466f0 c00089d0 e5840058 15803024 
Backtrace: 
[<c019ad6c>] (first_drv_init+0x0/0x28) from [<c0008a94>] (kernel_init+0xd4/0x28c)
[<c00089c0>] (kernel_init+0x0/0x28c) from [<c00466f0>] (do_exit+0x0/0x760)
Code: e59f3010 e3a00000 e5830000 e3a03002 (e5803000) 
Kernel panic - not syncing: Attempted to kill init!
分析:
1、我们找到pc值:c019ad88
2、然后:cat System.map,查看错误位置是否在内核模块
     我们发现内核模块函数的地址范围是:c0004000~c03bd168
     所以是属于内核模块的。
3、接下来我们反汇编内核:arm-linux-objdump -D vmlinux > vmlinux.dis
4、在dis文件里搜c014e6c0
      vi vmlinux.dis
我们找到如下信息:
c019ad6c <first_drv_init>:
c019ad6c:       e1a0c00d        mov     ip, sp
c019ad70:       e92dd800        stmdb   sp!, {fp, ip, lr, pc}
c019ad74:       e24cb004        sub     fp, ip, #4      ; 0x4
c019ad78:       e59f3010        ldr     r3, [pc, #16]   ; c019ad90 <.text+0x170d90>
c019ad7c:       e3a00000        mov     r0, #0  ; 0x0
c019ad80:       e5830000        str     r0, [r3]
c019ad84:       e3a03002        mov     r3, #2  ; 0x2
c019ad88:       e5803000        str     r3, [r0]
c019ad8c:       e89da800        ldmia   sp, {fp, sp, pc}
c019ad90:       c03b33d8        ldrgtsb r3, [fp], -r8
OK!根据  函数名  以及  c019ad88:       e5803000        str     r3, [r0]就可以找到对应的c程序的位置了!

http://liu1227787871.blog.163.com/blog/static/20536319720126101202205/

linux驱动调试之段错误分析_根据pc值确定出错的代码位置相关推荐

  1. Linux驱动调试中的Debugfs的使用简介

    Linux驱动调试中的Debugfs的使用简介 (2012-03-31 14:14) 在调试linux驱动的时候,可以用debugfs来调试,debugfs类似字符设备驱动一样,甚至更简单,不需要主设 ...

  2. Linux驱动调试中的Debugfs的使用简介 CONFIG_DEBUG_FS 的功能与配置

    Linux驱动调试中的Debugfs的使用简介 (2012-03-31 14:14) 在调试linux驱动的时候,可以用debugfs来调试,debugfs类似字符设备驱动一样,甚至更简单,不需要主设 ...

  3. linux驱动调试--段错误之oops信息分析

    原文地址 http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29401328&id=4923447 发生段错误原因就是访问 ...

  4. Linux驱动段错误,linux驱动调试--段错误之oops信息分析

    下面根据Oops信息来分析一下段错误 first_drv.c 点击(此处)折叠或打开 #include #include #include #include #include #include #in ...

  5. 37.Linux驱动调试-根据oops的栈信息,确定函数调用过程

    上章链接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我们分析了oops的PC值在哪个函数出错的 本章便通过栈信息来分析函数调用过程 1. ...

  6. linux驱动调试--段错误之栈信息分析

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29401328&id=4923529 接着上一篇来分析一下Oop ...

  7. linux驱动获取函数失败信息,linux驱动调试--段错误之栈信息分析

    接着上一篇来分析一下Oops的栈 s3c2440平台 关于调试源码和整个Oops信息请参考上一篇博文,这里只再次贴出关于栈的信息 Stack: (0xc3a61e30 to 0xc3a62000) 1 ...

  8. linux驱动调试--oops信息

    在移植dm9000 时被一个错误困扰了很久,当时手里只有printk调试手段,觉得自己应该升级下了,先学习了根据oops信息来调试. 先构造一个错误,insmod后抛出如下信息 我们着重看这几句 PC ...

  9. Linux驱动调试之修改系统时钟中断定位系统僵死问题

    目录 1 将驱动程序改错 2 调试 1 将驱动程序改错 我们在点灯的函数里面增加一个死循环, 编译完之后,加载,测试,发现系统卡死. 2 调试 我们的系统不管在做什么事情,系统时钟中断是永远都在进行的 ...

最新文章

  1. TypeError: sequence item 1: expected str instance, int found
  2. 谷歌大脑提出对智能体进行「正向-反向」强化学习训练,加速训练过程
  3. 从前端角度来看网页设计
  4. 通道抠图--火焰,背景颜色统一为黑色
  5. 深入学习SAP UI5框架代码系列之五:SAP UI5控件的实例数据修改和读取逻辑
  6. 大一大学计算机考试难吗,新生必看!大一期间必考的3个证书,不考后悔,越拖越难考!...
  7. 倒计时css和js html代码,手把手教你利用CSS和JS创建一个倒数计时器
  8. OpenWares | Open Source and Free Matters » 为rm命令增加回收站功能
  9. 制作并使用9-patch图像
  10. 求解线性方程组(SVD,QR,Gauss,LU)
  11. mysql5.7下载与安装(windows10)
  12. C语言有符号和无符号数
  13. 身份证验证Java代码
  14. 文本特征提取之TF-IDF算法(原理+Python代码)
  15. 人工神经网络概念梳理与实例演示
  16. 两数相加(有序/无序) 时间复杂度小于 O(n2)做题心得
  17. hdu4939思维DP
  18. 阿里云服务器上海地域和杭州节点区别对比
  19. css3 background简写,background-size简写背景属性(CSS3)
  20. Smart3D(ContextCapture)跑三维到底要啥配置?!40000元来组建建模集群

热门文章

  1. 自学SQL网之学习笔记(题目+答案)
  2. android卡点视频教程,手机自动卡点视频软件-卡点视频制作-自动卡点神器v1.1.0 安卓版-腾牛安卓网...
  3. 计算机毕业生的简历,计算机系毕业生的个人简历
  4. GEE获取京津冀区域面积
  5. 由浅入深,内容详实《Python爬虫开发与项目实战》 豆瓣评分[7.10]
  6. 龙泉农商银行计算机类考什么,农商行都考什么啊?
  7. 一款体积小使用的截屏取色小工具推荐——Faststone Capture
  8. ASP简体转繁体函数
  9. 华为鲲鹏认证怎么样?值得考吗
  10. 海南之行--绝望之行