本文以一个简单的实例介绍RISC-V指令异常的调试过程,思路都是一样的,遇到其他情况时分析过程也类似。
相关内容参考《riscv-privileged-20211203.pdf》
现象是程序执行后进入了异常中断,可以通过GDB的bt命令看到
#12 0x02002e9c in exception () at src/lib/riscv/src/exception.c:55
#13 0x02002b40 in is_exception ()
Backtrace stopped: frame did not save the PC
(gdb)
既然是进入了异常中断,那么就需要确认到底是什么异常,
这可以通过mcause寄存器查看
(gdb) info reg mcause
mcause 0x2 0x2
(gdb)
可以看到是非法指令异常
那么我们就搜索文档的Illegal instruction可以查看到所有可能导致Illegal instruction的原因。
我们搜到以下信息,即mtval寄存器保存了异常指令,mepc指向了异常指令
可以看到mepc的内容是0,那么猜测应该是函数指针未初始化直接调用导致的
(gdb) info reg mtval
mtval 0x0 0x0
(gdb) info reg mepc
mepc 0x0 0x0
(gdb)
到这里基本就确认了方向了,可以重点看哪些地方有函数指针,或者逐步注释函数,或者逐步断点定位即可。
这里很快就确认了是
是如下代码导致
int xxx_ioctl(unsigned int dev_id, unsigned int cmd, void *data)
{
if (dev_id >= xxx_drv.dev_num)
return -1;
return xxx_drv.ops.ioctl(&(xxx_drv.dev[dev_id]), cmd, data);
}
查看函数指针正好是0
(gdb) p xxx_drv.ops.ioctl
$1 = (int (*)(struct xxx_dev_s *, unsigned int, void *)) 0x0
(gdb)
回溯代码确认了是某个外设没有初始化成功则这个回调函数没有初始化。原因就定位了。
对于异常的调试可以参考手册《riscv-privileged-20211203.pdf》,从异常原因入手,逐渐反推,确认异常触发点然后确定原因。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !