我们在前面分析head.S时借助了GDB进行仿真分析。在使能MMU前,链接地址和运行地址虽然不一样,但是此时没有使能MMU可以直接访问物理地址,我们此时可以使用GDB进行单步等各种调试,链接地址和运行有一个固定偏差所以也可以直接对照反汇编代码。
应对此时的链接地址和运行地址不一致导致的无法使用vmlinux的符号,无法在GDB中同时对应源码和汇编,我们可以使用add-symbol-file加载指定段地址,其实本来前面也都是汇编代码,也不是很复杂,所以也没必要一定要一起layout split对应源码和汇编一起看。单独查看反汇编的s文件也是没问题的,所以这里不处理也没关系。
我们重点关注后面使能mmu后c代码执行过程,后面才是比较复杂的逻辑,我们希望能继续使用gdb调试。现在问题是在使能MMU后会切换到虚拟地址运行,在使能MMU前GDB又访问不了链接地址即虚拟地址,导致无法打断点让CPU在使能MMU后的虚拟地址处停住。所以直接单步运行到使能MMU处后就会无法继续仿真调试。
本文就分享一个小的技巧,来实现让CPU停在使能MMU之后,好让GDB能接着继续仿真调试。
既然无法使用断点停在使能MMU后的地方,那我们是不是能换个思路在代码里人为的停住呢?就按照这个思路我们直接在使能MMU后继续运行的地址,我们前面relocate分析的切换位置加个死循环即可。
我们找到如下位置添加一行代码,
bnez a0,1b在此处死循环
这样我们c全速运行即可直接运行到该处,此时a0不为0,在此死循环,此时已经使能MMU,运行在虚拟地址与链接地址一致了。我们使用GDB停止在此处,再修改a0的值跳过这个死循环即可。后面开始就是使用虚拟地址和链接地址一致,此时加载的Vmlinux符号就可以使用了,可以直接layout split源码和汇编对照了,且各个附后地址都是对的了,不需要再人工去偏移了。
输出汇编
riscv64-unknown-linux-gnu-objdump -l -S output/vmlinux > a.s
找到添加的这条指令的位置
c全速运行,
然后ctrl+c取消全速运行
看到会卡在该处死循环
layout split打开源码和汇编代码
此时看到由于使用虚拟地址和链接地址对应,此时就可以源码和汇编对应了。
查看此时a0不为0,所以会在这里死循环
i r a0
a0 0xffffffe0000010ce -137438949170
(gdb)
我们手动将a0改为0
(gdb) set $a0=0
(gdb)
此时就可以单步运行接着往下走了
此时就可以愉快的仿真调试了。