大家写驱动的时候不知道有没有发现,当我们驱动写错了,发生内核奔溃时,会打印一大堆的报错信息,
如果再返回我们的程序中一行一行代码的检查,既耗费时间,并且有些逻辑上的错误,我们是很难看的出来的,
那我们能不能再这一大堆的报错信息中发现问题的所在呢?
此处我们来模拟一个错误,还是沿用上一篇文章中的驱动代码err_led.c的驱动程序中的代码修改错误,当然大家用其他的驱动代码做测试也可以.
1 40 static int key_open(struct inode *inode, struct file *file)
2 41 {
3 42 printk('<0>function open!nn');
4 43
5 44 base_iomux = 0x43FAC000;
6 45 MUX_CTL &= ~(0x07 << 0);
7 46 MUX_CTL |= (0X05 << 0); //设置为ALT5 GPIO3_23 ERR_LED
8 47
9 48 //MUX_CTL
10 49 return 0;
11 50 }
直接让base_iomux = 实际的物理地址,肯定会报错的.
加载编译,如我们所愿,成功的打印出了内核奔溃信息:
接下来我们来分析分析是否可以从这些信息中寻得蛛丝马迹呢?让我们一起见证奇迹的时刻.
1 root@EasyARM-iMX257 ~# echo 1 > /dev/err_led_dev
2 function open!
3
4 Unable to handle kernel paging request at virtual address 43fac060
5 //无法访问虚拟地址43fac060,因为驱动访问的都是虚拟地址,而恰恰43fac060这个地址是没有映射的,以无法访问
6
7 pgd = c3b8c000
8 [43fac060] *pgd=00000000
9 Internal error: Oops: 5 [#2] PREEMPT
10 Modules linked in: err_led mymsg gpio [ Tainted: G D (2.6.31-207-g7286c01 #692)
11 //发生错误时,系统加载的模块有err_led mymsg gpio 这几个
12
13 PC is at key_open+0x18/0x54 [err_led]
14 //PC就是发生错误的指令地址,发生错误的函数为 key_open,偏移0x18,其实这里已经很明显了
15
16 LR is at key_open+0x10/0x54 [err_led]
17 //LR寄存器的值
18
19 pc : [ 20 //发生错误时pc指针的值: bf010128 21 22 sp : c32c3e70 ip : c046708f fp : 00095ab0 23 r10: c3b9aae0 r9 : c320 r4 : 00000001 24 r3 : 00000000 r2 : 00000000 r1 : 43facfff r0 : 43fac000 25 //执行这条错误导致错误时各个寄存器的值 26 27 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user 28 Control: 0005317f Table: 83b8c000 DAC: 000000 limit = 0xc32c2270) 29 30 //发生错误时,堆栈的信息 31 32 Stack: (0xc32c2000 c00bb9d0 0000000b c3 c31790c8 00000000 c00bb7fc c380f0a0 c31b6398 c00b66b4 33 3ea0: c32c3ef8 c3b9aae0 c3885660 c32c3e0b76d4 34 3ec0: 00000000 c3885660 c32c3ef0 00000000 c32c3ef0 c00c4288 00000000 000001b6 35 3ee0: 00020241 00000000 00000000 00000000000b 36 3f00: c3b91005 c380f2200000 00005402 00000036 37 3f20: 00000000 c00c5698 c31498a0 fffffff7 be880704 c00c5d34 c32c3f84 00 c3879d60 00000003 c380f0a0 c31b6398 00000000 00020241 38 3f60: 000001b6 ffffff9c 00000000 c0029f24 c3b91000 00000003 00095ab0 c00b6444 39 3f80: 00000022 00000000 000001b6 000932ac 00000001 00000005 c0029f24 c32c2000 40 3fa0: 40138000 c0029da0 000001b6 000932000000 41 3fc0: 000001b6 000932ac 00000001 00000005 00000000 000933f8 40138000 00095ab0 42 3fe0: 000903ac be8803d8 00035c28 400d110x18/0x54 [err_led]) from [ 43 [ 44 [ 45 [ 46 [ 47 [114) from [ 48 Code: e24dd004 eb40e05c e59f1030 e59f0030 (e5113f9f) 49 ---[ end trace c4bb5578ca399f8a ]--- 50 process '/sbin/getty -L ttymxc0 115200 vt100' (pid 1832) exited. Scheduling for restart. 51 starting pid 1833, tty '': '/sbin/getty -L ttymxc0 115200 vt100' 52 CC) 4.1.2 53 root filesystem built on Tue, 13 Aug 2013 02:31:56 -0700 54 Freescale Semiconductor, Inc. 55 56 57 //如果内核的配置选项选择了kernel 的FRAME_POINTER 的话 58 -->kernel hacking 59 - - → - - > kernel debuging (DEBUG_KERNEL) 60 //这儿会打印粗回溯信息,即一系列的内核指针调用信息. 61 Backtrace: 有的时候pc值只会给出列出一个地址,不会说是在那个函数里面 1.根据上面的PC值,找到出错误的地址: System.map 先判断是否属于内核的地址: 看源代码目录下的linux-2.6.31/System.map 1 root@Lover雪:/home/study/nfs_home/system/linux-2.6.31# vi System.map 2 1 c0004000 A swapper_pg_dir 3 2 c0008000 T __init_begin 4 3 c0008000 T _sinittext 5 4 c0008000 T stext 6 5 c0008000 T _stext 7 6 c0008034 t __enable_mmu 8 .......... 9 32128 c04a0d64 b ratelimit.21298 10 32129 c04a0d68 b pipe_version_lock 11 32130 c04a0d68 b pipe_version_rpc_waitqueue 12 32131 c04a0db4 b rsc_table 13 32132 c04a1db4 b rsi_table 14 32133 c04a1eb8 B krb5_seq_lock 15 32134 c04a1ec0 b i.21559 16 32135 c04a1ec8 b wireless_nlevent_queue 17 32136 c04a1ed4 B __bss_stop 18 32137 c04a1ed4 B _end 可以发现内核的地址范围为c0004000 ~ c04a1ed4 ,如果属于这个范围则为内核错误. 如果不属于System.map 里的范围,则它属于insmod加载的程序.] 因为我们的PC值为 bf010128,肯定不属于内核啊, 2.假设它是加载的驱动程序引入的错误,怎么确定是哪一个驱动程序呢? /proc/kallsyms 先看看加载的驱动程序的函数的地址范围.cat /proc/kallsyms > 1.txt 在开发板上运行cat /proc/kallsyms > 1.txt 在1.txt中查看PC = bf010128 相近的值 28484 bf0100ec t key_read [err_led] 28485 bf0100ec t $a [err_led] 28486 bf01010c t $d [err_led] 28487 bf010110 t key_open [err_led] 28488 bf010110 t $a [err_led] 28489 bf010154 t $d [err_led] 28490 bf010164 t $a [err_led] 28491 bf010248 t $d [err_led] 28492 bf01024c t key_irq_exit [err_led] 28493 bf01024c t $a [err_led] 28494 bf0102ac t $d [err_led] 可以发现:我们这个程序所有的程序的地址, 我们找到与PC值项相近并且小于它的地方,可以发现,我们除错的程序再key_open 里面. t: 静态函数 T: 全局函数 然后利用这个找到的地址再加上我们的偏移地址,就找到了我们的错误所在. 3.找到了我们的驱动程序err_led.ko反汇编 1 root@Lover雪:/home/study/nfs_home/module/36_my_proc_prink/test# 2 arm-none-linux-gnueabi-objdump -D err_led.ko > err_led.txt 3 root@Lover雪:/home/study/nfs_home/module/36_my_proc_prink/test# 4 vi err_led.txt 5 下面就是我们err_led.ko 的反汇编代码: 6 再反汇编代码中找到key_open函数然后在加上偏移0x18 7 8 84 00000110 9 85 110: e52de004 str lr, [sp, #-4]! 10 86 114: e59f0038 ldr r0, [pc, #56] ; 154 <.text+0x154> 11 87 118: e24dd004 sub sp, sp, #4 ; 0x4 12 88 11c: ebfffffe bl 0 13 89 120: e59f1030 ldr r1, [pc, #48] ; 158 <.text+0x158> 14 90 124: e59f0030 ldr r0, [pc, #48] ; 15c <.text+0x15c> 15 91 128: e5113f9f ldr r3, [r1, #-3999] 16 92 12c: e3c33007 bic r3, r3, #7 ; 0x7 //R3 &= ~(0x07) 17 93 130: e5013f9f str r3, [r1, #-3999] 18 94 134: e5112f9f ldr r2, [r1, #-3999] 19 95 138: e59f3020 ldr r3, [pc, #32] ; 160 <.text+0x160> 20 96 13c: e3822005 orr r2, r2, #5 ; 0x5 //R3 |= 0x05 21 97 140: e5830000 str r0, [r3] 22 98 144: e3a00000 mov r0, #0 ; 0x0 如上面代码所示,很容易就找到了了错误地址. 分析汇编代码: 接下来就是考察汇编功底的时刻了, 根据汇编代码来推出C语言代码: 从上面推出的 R3 &= ~(0x07) 和 R3 |= 0x05,再与程序中匹配: 1 40 static int key_open(struct inode *inode, struct file *file) 2 41 { 3 42 printk('<0>function open!nn'); 4 43 5 44 base_iomux = 0x43FAC000; 6 45 MUX_CTL &= ~(0x07 << 0); 7 46 MUX_CTL |= (0X05 << 0); //设置为ALT5 GPIO3_23 ERR_LED 8 47 9 48 //MUX_CTL 10 49 return 0; 11 50 } 可以发现,一模一样,有没有.所以我们就得到了MUX_CTL这儿有错误. 根据MUX_CTL自然就可以得到base_iomux这个有错误. 附上驱动程序:err_led.c 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include 14 15 #define Driver_NAME 'err_led_dev' 16 #define DEVICE_NAME 'err_led_dev' 17 18 static int major = 0; 19 20 //auto to create device node 21 static struct class *drv_class = NULL; 22 static struct class_device *drv_class_dev = NULL; 23 24 //寄存器基址; 25 static unsigned long base_iomux; //iomux基址 0X 43FA C000 - 0X 43FA FFFF 26 static unsigned long base_gpio3; //gpio3 0X 53FA 4000 - 0X 53FA 7FFF 27 // MUX_CTL模式选择 配置寄存器 28 #define MUX_CTL (*(volatile unsigned long *)(base_iomux + 0x0060)) 29 // PAD_CTL GPIO常用功能设置 30 #define PAD_CTL (*(volatile unsigned long *)(base_iomux + 0x0270)) 31 // GPIO DR 数据寄存器 DR 32 #define DR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0000)) 33 // GPIO GDIR 方向控制寄存器 GDIR 34 #define GDIR_GPIO3 (*(volatile unsigned long *)(base_gpio3 + 0x0004)) 35 36 37 extern int printk(const char *fmt, ...); 38 39 static int key_open(struct inode *inode, struct file *file) 40 { 41 printk('<0>function open!nn'); 42 43 base_iomux = 0x43FAC000; 44 MUX_CTL &= ~(0x07 << 0); 45 MUX_CTL |= (0X05 << 0); //设置为ALT5 GPIO3_23 ERR_LED 46 47 //MUX_CTL 48 return 0;
上一篇:调试分析之 根据内核报错信息栈信息分析错误
下一篇:调试分析之 imx257中proc下mymsg及myprintk的实现
推荐阅读最新更新时间:2024-11-02 17:11
设计资源 培训 开发板 精华推荐
- 理想中的开发板、万用表,好用不贵? e络盟11.11抢购,给你机会!
- 学习有礼,分享也有礼!跟着小梅哥,一起intel SoC FPGA走起!
- #Micropython大作战#第二弹:发表mciropython原创教程赢好礼!
- 是德感恩月|天天抽示波器,推荐同享,百余份礼品等你拿!
- Mentor线上研讨会 | 教你在设计工具中进行DFM分析,轻松兼顾效率、成本和质量
- EEWORLD下载中心热力上线!
- 看视频赢50元京东卡|泰享实测之水哥秘籍第四期
- Microchip电源评估板促销,还有红包送!
- 下载有礼|精华课件汇编:泰克半导体器件的表征及可靠性研究交流会暨吉时利测试测量年度研讨会
- MPS探索营 “正经玩技术”!创意征集 | 解锁锂电池充电的无限玩法!
- MIT研究人员为家用机器人开发新语义解析器 以色列推出新仓储机器人
- 对号入座 看看未来几年机器人是否会取代你的工作
- 首例立体高密度机器人智能仓启用
- OpenAI推出强化学习项目Spinning Up 为通用人工智能铺路
- 技术拆解:Apple苹果 Lightning与USB-C to 3.5mm转换器
- Pixel 2/3a/4 XL不幸中招!更新安卓11之后相机崩溃
- 错误Bug不少 Surface Duo首个系统级更新或在10月发布
- iPhone 12 mimi诸多细节曝光:电容太小 后置镜头被缩水
- 上市涨185%,信号链芯片第一股芯海科技成功登陆科创板
- 韩半导体材料、组件和设备供应商反对专利诉讼“发现制