当前位置:   article > 正文

qemu单步调试arm64 linux kernel_qemu 调试内核

qemu 调试内核

一、背景和目的

qemu搭建arm64 linux kernel环境-CSDN博客

之前介绍了qemu启动kernel的配置步骤和方法,现在开始我们的调试,这篇文章主要讲解如何单步调试内核,所有的实验还是基于ARM64;

二、环境准备

需要准备host=x86 target = arm64的gdb, 有三种方式:一种是sudo apt install gdb-multiarch;

另外一种是用ARM官网下载交叉编译工具链,其中自带gdb(目前我使用的方式Arm GNU Toolchain Downloads – Arm Developer); 还有一种是下载gdb源码并编译;

不同的方式有些差异,用apt安装的如果ubuntu比较老,可能存在部分特性不支持(比如ARMv8.5的PAC,BTI等,之前用ubuntu18.04就遇到了);

注意:使用ARM 官网gdb的伙伴启动时可能会遇到缺少库和python3.8的报错(依赖libncurses5 ,libncursesw5及python3.8),可以参考下面解决(偷懒可以直接安装gdb-multiarch)

三、kernel debug

单步调试kernel 只需要三步:

第一步:qemu启动内核并暂停等待(暂停是可选的,如果不调启动,可以去掉),同时需要建立网络端口等待gdb attach;

第二步:启动gdb(target=arm64)加载对应kernel Image的vmlinux, attach到指定端口即可;

第三步:如果是启动是挂起,直接设置断点即可调试,如果未选择启动暂停,ctrl + c会触发挂起,然后就可以和前面一样,正常设置断点。

qemu启动调试脚本(注意这里有个小坑,直接调试的伙伴直接跳转到最后拷贝即可

  1. qemu-system-aarch64 \
  2. -machine virt,virtualization=true,gic-version=3 \
  3. -nographic \
  4. -m size=1024M \
  5. -cpu cortex-a72 \
  6. -smp 2 \
  7. -kernel Image \
  8. -drive format=raw,file=rootfs.img \
  9. -append "root=/dev/vda rw" \
  10. -s \
  11. -S
  12. 可以看到对比之前的启动参数也就是增加了-s 和-S,具体含义如下:
  13. # -s 是-gdb tcp::1234 的简写,如果需要换端口可以用-gdb tcp::1234替换-s参数
  14. # -S 是freeze cpu at startup的指令,也就是kernel 启动时就挂起,等待调试连接,如果不需要调试内核启动,这个参数也
  15. 可以去掉

gdb启动
找到vmlinux所在目录(最好在linux编译的根目录,不要拷贝出来,这样调试源码可以直接显示,不然还要在gdb中设置src path),
geek@geek-virtual-machine:~/workspace/linux/linux-6.6.1$ aarch64-none-linux-gnu-gdb vmlinux

  1. (gdb) target remote :1234
  2. Remote debugging using :1234
  3. 0x0000000040000000 in ?? ()
  4. (gdb) b start_kerne
  5. 然后continue即可停在指定断点,后面就可以step 单步调试了,实际调试时会发现设置的断点start_kernel停不住,ctrl+c 触发挂起时会出现bt无法显示相关符号等问题
  6. (gdb) bt
  7. #0 0xffffd43266a17f6c in ?? ()
  8. #1 0xffffd43265ad7ad0 in ?? ()
  9. #2 0x0000000000000002 in ?? ()
  10. Backtrace stopped: previous frame identical to this frame (corrupt stack?)

这里的原因也是经常会遇到和遗忘的,查看kernel log可以看到KASLR字样

  1. [ 0.000000] KASLR enabled
  2. [ 0.000000] CPU features: kernel page table isolation forced ON by KASLR

KASLR是内核启动添加随机地址保护,启动后实际运行地址和vmlinux 有一个随机偏移值,在gdb中设置断点是基于vmlinux的(这个是不带偏移值的),实际qemu中运行的内核是在这个地址 + 随机偏移值,所以断点无法触发,出现上面的问题;

上面的问题有两种解决方法:

1、是重新编译内核,在arch/arm64/configs/defconfig 中将CONFIG_RANDOMIZE_BASE=y修改成CONFIG_RANDOMIZE_BASE=n

2、是在qemu启动的cmdline中增加nokaslr 参数,通过参数方式关闭

      -append "root=/dev/vda rw nokaslr" \

修改正常后,断点能正确停止,bt调用栈显示正常

  1. (gdb) bt
  2. #0 cpu_do_idle () at arch/arm64/kernel/idle.c:32
  3. #1 0xffff800081017f80 in arch_cpu_idle () at arch/arm64/kernel/idle.c:44
  4. #2 0xffff800081018bcc in default_idle_call () at kernel/sched/idle.c:97
  5. #3 0xffff8000800d7ad0 in cpuidle_idle_call () at kernel/sched/idle.c:170
  6. #4 do_idle () at kernel/sched/idle.c:282
  7. #5 0xffff8000800d7d48 in cpu_startup_entry (state=CPUHP_ONLINE) at kernel/sched/idle.c:380
  8. #6 0xffff800081018eac in rest_init () at init/main.c:726
  9. #7 0xffff800081aa08bc in arch_call_rest_init () at init/main.c:823
  10. Backtrace stopped: previous frame identical to this frame (corrupt stack?)

四、总结

qemu内核调试时需要注意关闭kaslr,更新正确的脚本,也不依赖kenerl config是否开启kaslr

qemu启动脚本(最终版本):

  1. qemu-system-aarch64 \
  2. -machine virt,virtualization=true,gic-version=3 \
  3. -nographic \
  4. -m size=1024M \
  5. -cpu cortex-a72 \
  6. -smp 2 \
  7. -kernel Image \
  8. -drive format=raw,file=rootfs.img \
  9. -append "root=/dev/vda rw nokaslr" \
  10. -s \
  11. -S

关于kaslr原理相关的知识,有兴趣的伙伴参考 文章 kaslr原理分析

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/973391
推荐阅读
相关标签
  

闽ICP备14008679号

        
cppcmd=keepalive&