完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
程序跑着跑着打印一串奇奇怪怪没见过的打印,就像下面的打印一样? CPU Exception: NO.2 r0: 0x00000014 r1: 0x18a70124 r2: 0x00001111 r3: 0x10020000 r4: 0x00000000 r5: 0x00000001 r6: 0x00000002 r7: 0x07070707 r8: 0x00000000 r9: 0x09090909 r10: 0x10101010 r11: 0x11111111 r12: 0x40000000 r13: 0x00000000 r14: 0x18b166a8 r15: 0x186d9c0a r16: 0x16161616 r17: 0x47000000 r18: 0x3f800000 r19: 0x00000000 r20: 0xc0000000 r21: 0x40000000 r22: 0x00000000 r23: 0x00000000 r24: 0x40400000 r25: 0x12345678 r26: 0x12345678 r27: 0x12345678 r28: 0x12345678 r29: 0x12345678 r30: 0x12345678 r31: 0x12345678 vr0: 0x12345678 vr1: 0x00000000 vr2: 0x00000000 vr3: 0x00000000 vr4: 0x00000000 vr5: 0x00000000 vr6: 0x00000000 vr7: 0x00000000 vr8: 0x00000000 vr9: 0x00000000 vr10: 0x00000000 vr11: 0x00000000 vr12: 0x00000000 vr13: 0x00000000 vr14: 0x00000000 vr15: 0x00000000 vr16: 0x00000000 vr17: 0x00000000 vr18: 0x00000000 vr19: 0x00000000 vr20: 0x00000000 vr21: 0x00000000 vr22: 0x00000000 vr23: 0x00000000 vr24: 0x00000000 vr25: 0x00000000 vr26: 0x00000000 vr27: 0x00000000 vr28: 0x00000000 vr29: 0x00000000 vr30: 0x00000000 vr31: 0x00000000 vr32: 0x00000000 vr33: 0x00000000 vr34: 0x00000000 vr35: 0x00000000 vr36: 0x00000000 vr37: 0x00000000 vr38: 0x00000000 vr39: 0x00000000 vr40: 0x00000000 vr41: 0x00000000 vr42: 0x00000000 vr43: 0x00000000 vr44: 0x00000000 vr45: 0x00000000 vr46: 0x00000000 vr47: 0x00000000 vr48: 0x00000000 vr49: 0x00000000 vr50: 0x00000000 vr51: 0x00000000 vr52: 0x00000000 vr53: 0x00000000 vr54: 0x00000000 vr55: 0x00000000 vr56: 0x00000000 vr57: 0x00000000 vr58: 0x00000000 vr59: 0x00000000 vr60: 0x00000000 vr61: 0x00000000 vr62: 0x00000000 vr63: 0x00000000 epsr: 0xe4000341 epc : 0x186d9c12 不用紧张,你没有把板子搞坏了,只是程序跑挂了。下面我们就来一步一步的分析,我们掉进了什么坑里,怎么跳出来? 你需要知道的基础知识 下面介绍一些基础知识,如果你已经是老鸟,可以不用看这些。 几个重要的寄存器
这几个重要的寄存器都在上面的异常打印中打印出来了。 几个重要的文件
其中:
在我们的ck cpu架构里,不同的cpu异常会有不同的异常号,我们往往需要通过异常号来判断可能出现的问题。
这些异常中,出现最多的是 1、2 号异常,4、7 偶尔也会被触发,3号异常比较好确认,其余基本不会出现。 开始填坑 了解完基础知识,我们就要开始填坑了,不管是谁挖的坑,总还是要填回去的。 连上GDB 如何连接GDB可以参考上一篇文章的内容 恢复现场 在GDB 使用 set 命令 将异常的现场的通用寄存器和 PC 寄存器设置回CPU中,便可以看到崩溃异常的程序位置了 (cskygdb)set $r0=0x00000014 (cskygdb)set $r1=0x18a70124 (cskygdb)set $r2=0x00001111 (cskygdb)set $r3=0x10020000 ... (cskygdb)set $r14=0x18b166a8 (cskygdb)set $r15=0x186d9c0a ... (cskygdb)set $r30=0x12345678 (cskygdb)set $r31=0x12345678 (cskygdb)set $pc=$epc 不同的CPU 通用寄存器的个数有可能不相同,一般有 16个通用寄存器、32个通用寄存器,两种版本,我们只需要把通用寄存器,即 r 开头的寄存器 设置回CPU即可。 PC 寄存器 需要设置成 EPC, r14 r15 分别是 sp 寄存器和 lr寄存器。pc r14 r15 三个寄存器 是找回现场的关键寄存器,其余的通用寄存器是一些函数传参和函数内的局部变量。 设置完成以后可以通过 GDB bt 命令可以查看异常现场的栈 (cskygdb) bt #0 0x186d9c12 in board_yoc_init () at vendor/tg6100n/board/init.c:202 #1 0x186d9684 in sys_init_func () at vendor/tg6100n/aos/aos.c:102 #2 0x186dfc14 in krhino_task_info_get (task= at kernel/kernel/rhino/k_task.c:1081 Backtrace stopped: frame did not save the PC 从 bt 命令 打印出来的栈信息,我们可以看到 异常点在 init.c 的 202 行上,board_yoc_init 函数内。 到这里,对于一些比较简单的错误,基本能判断出了什么问题。 如果没法一眼看出问题点,那我们就需要通过异常号来对应找BUG了。 通过异常号找BUG 程序崩溃后,异常打印的第一行就是CPU异常号。 CPU Exception: NO.2 如上,我们示例中的打印是 2号异常。 2号异常是最为常见的异常,1号异常也较为常见。4号、7号一般是程序跑飞了,运行到了一个不是程序段的地方。3号异常就是除法除零了,比较好确认。其余的异常基本不会出现,出现了大概率也是芯片问题或者某个驱动问题,不是应用程序问题。 CPU Exception: NO.1 一号异常是访问未对齐异常,一般是一个多字节的变量从一个没有对齐的地址赋值或者被赋值。 例如: uint32_t temp; uint8_t data[12]; temp = *((uint32_t*)&data[1]); 如上代码,一个 4字节的变量 temp 从 一个单字节的数组中取4个字节内容,这种代码就容易出现地址未对齐异常。这种操作在一些流数据的拆包组包过程比较常见,这个时候就需要谨慎小心了。 有些CPU 可以开启不对齐访问设置,让CPU可以支持从不对齐的地址去取多字节,这样就不会出现一号异常。但是为了平台兼容性,我们还是尽量不要出现这样的代码。 当然一号异常的出现也有可能是一个变量、一片内存被踩了导致的内存地址不对齐。 CPU Exception: NO.2 二号异常是访问错误异常,一般是访问了一个不存在的地址空间。 例如: uint32_t *temp; *temp = 1; 如上代码,temp 指针未初始化,如果直接给 temp指针指向的地址赋值,有可能导致二号异常,因为temp指向的地址是个随机值,该地址可能并不存在,或者不可以被写入。 二号异常也是最经常出现的异常,例如常见的错误有:
请注意你代码里的 memset、memcpy、malloc、free 、strcpy等调用。 大部分2号异常和1号异常的问题,异常的时候都不是第一现场了,也就是说异常点之前就已经出问题了。 比如之前就出现了 memcpy的 内存访问越界,内存拷贝超出变量区域了。memcpy的时候是不会异常的,只有当程序使用了这些被memcpy 踩了内存时,才会出现一号或二号异常。 这个时候异常点已经不是那个坑的地方了,属于“前人埋坑,后人遭殃”型问题。 如果是一些很快就复现的问题,我们可以通过GDB watch命令,watch那些被踩的内存或变量来快速的定位是哪段代码踩了内存。 如果是一些压测出现的问题,压测了2天,出了一个2号异常,恭喜你,碰到大坑了。类似这种,比较难复现的问题,watch已经不现实了。 结合异常现场GDB查看变量、内存信息和reiview代码逻辑,倒推出内存踩踏点,是比较正确的途径。 再有,就是在可疑的代码中加 log日志,增加压测的机器,构造缩短复现时间的case等一些技巧来加快BUG解决的速度。 CPU Exception: NO.4 CPU Exception: NO.7 四号异常是指令非法,即这个地址上的内容并不是一条CPU机器指令,不能被执行。 七号异常是断点异常,也就是这个指令是断点指令,即 bktp 指令,这是调试指令,一般代码不会编译生成这种指令。 这两种异常大概率是 指针函数没有赋值就直接跳转了,或者是代码段被踩了 例如: typedef void (*func_t)(void *argv); func_t f; void *priv = NULL; if (f != NULL) { f(priv); } 如上代码,f 是一个 函数指针,没有被赋值,是一个随机值。直接进行跳转,程序就肯定跑飞了。 这种异常,一般epc地址,都不在反汇编文件 yoc.asm 中。 CPU Exception: NO.3 3号异常是除零异常,也是最简单、最直接的一种异常。 例如: int a = 100; int b = 0; int c = a / b; 如上代码,b 变量位 0,除零就会出现 三号异常。 不用GDB也能找到异常点 有些时候无法使用GDB去查看异常点,或者搭环境不是很方便怎么办? 这个时候我们可以通过 反汇编文件和epc地址来查看,异常的函数。 打开yoc.asm 反汇编文件,在文件内搜索epc地址,就可以找到对应的函数,只是找不到对应的行号。 例如: 186d9b14 186d9b14: 14d3 push r4-r6, r15 186d9b16: 1430 subi r14, r14, 64 186d9b18: e3ffffc6 bsr 0x186d9aa4 // 186d9aa4 186d9b1c: 3001 movi r0, 1 186d9b1e: e3fe3221 bsr 0x1869ff60 // 1869ff60 186d9b22: e3fe4ca9 bsr 0x186a3474 // 186a3474 186d9b26: e3fffe7d bsr 0x186d9820 // 186d9820 ... 186d9bfc: 1010 lrw r0, 0x188d1a50 // 186d9c3c 186d9bfe: e00c6aeb bsr 0x188671d4 // 188671d4 186d9c02: ea231002 movih r3, 4098 186d9c06: ea021111 movi r2, 4369 186d9c0a: b340 st.w r2, (r3, 0x0) 186d9c0c: 1410 addi r14, r14, 64 186d9c0e: 1493 pop r4-r6, r15 186d9c12: 9821 ld.w r1, (r14, 0x4) 186d9c14: 07a4 br 0x186d9b5a // 186d9b5a 186d9c14: 188d19c0 .long 0x188d19c0 如上的汇编代码,根据异常的epc地址0x186d9c12,我们可以确认异常的函数发生在 board_yoc_init内。 使用 addr2line 命令可以找到程序代码位置。 addr2line -e yoc.elf 0x186d9c12 vendor/tg6100n/board/init.c:202 文章转载自:平头哥芯片开放社区 作者:小黄 本帖被以下淘专辑推荐:
|
|
相关推荐 |
|
只有小组成员才能发言,加入小组>>
【平头哥Sipeed LicheeRV 86开发板试用体验】Waft初体验
15642 浏览 1 评论
13692 浏览 4 评论
【平头哥Sipeed LicheeRV 86开发板试用体验】四、烧写waft系统&搭建waft测试环境
19609 浏览 2 评论
59000 浏览 19 评论
【限时福利】加入芯片开发社区,领100G电子工程师资料大礼包
87556 浏览 121 评论
邀请函 | 3月2日 来上海参加平头哥“玄铁RISC-V生态大会”
732浏览 0评论
读书分享会 | 玄铁RISC-V处理器入门与实战电子书免费下载!
620浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 05:10 , Processed in 0.640432 second(s), Total 46, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号