结合Yocto Qemu与Eclipse单步调试开发Linux Kernel

使用说明

在以前的博客中说明过使用Qemu + BuildRoot来构建一个虚拟的嵌入式开发平台, 还写过使用Yocto + Qemu来构建一个Cortex-A9的嵌入式开发调试平台. 同时在很久以前也写过使用Eclipse + JLINK来调试ARM9. 而在工作学习中,有时候, 对内核源码的研究中, 需要单步对linux内核跟踪调试, 且大部分是关注与内核中某些组件的实现, 例如MM, Binder驱动, 这个时候直接使用Qemu + Eclipse来调试与开发就比使用硬件方便快捷得多了.

那么这篇文章中将使用: Yocto + Qemu + Eclipse来调试与开发kernel.


准备

获取Yocto的layers, 即metas, 然后构建一个MACHINE为qemux86的rootfs, 使用core-image-minimal为bitbake target构建对应的rootfs. 构建完成后就可以直接启动Yocto构建出来的Qemu来模拟调试了.

内核的准备

开启debug info, 以及Provide  GDB scripts.

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第1张图片

勾选FRAME POINTER

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第2张图片

为gdb准备还需要开启KGDB.

关于如何开启与编译, 可以参考以前的Yocto的专栏文章.

编译完成后, 得到的vmlinux将会非常庞大, 因为包含了debug info. 而这个vmlinux将会在Eclipse中使用.

在Eclipse中准备调试配置

在Eclipse的Debug Configurations中新建一个C/C++ Attach to Application, 为什么是这个? 这是因为我们在Kernle中配置了KGDB, 配合Qemu的参数, 那么相当于开启了一个gdbserver在等待gdb的连接.

在Main Tab中选择要添加时候加载的文件, 为带有调试信息的vmlinux.

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第3张图片


在Debugger中选择我们要连接到gdbserver中:

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第4张图片

而且gdbserver的连接方式使用TCP, Port为1234:

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第5张图片

接下来选择kenrel source code, 注意新版本的Yocto的kernel source code path已经变更:

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第6张图片

完成配置后保存.


开启Qemu等待EClipse gdb调试

可使用runqemu来完成, 例如下面是一个例子:

$ runqemu qemux86 qemuparams="-s -S " serial
runqemu - INFO - Assuming MACHINE = qemux86
runqemu - INFO - Running MACHINE=qemux86 bitbake -e...
runqemu - INFO - MACHINE: qemux86
runqemu - INFO - DEPLOY_DIR_IMAGE: /ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/deploy/images/qemux86
runqemu - INFO - Running ls -t /ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/deploy/images/qemux86/*.qemuboot.conf...
runqemu - INFO - CONFFILE: /ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/deploy/images/qemux86/core-image-minimal-qemux86-20170327033520.qemuboot.conf
runqemu - INFO - Continuing with the following parameters:

KERNEL: [/ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/deploy/images/qemux86/bzImage]
MACHINE: [qemux86]
FSTYPE: [ext4]
ROOTFS: [/ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/deploy/images/qemux86/core-image-minimal-qemux86-20170327033520.rootfs.ext4]
CONFFILE: [/ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/deploy/images/qemux86/core-image-minimal-qemux86-20170327033520.qemuboot.conf]

runqemu - INFO - Running /sbin/ip link...
runqemu - INFO - Setting up tap interface under sudo
runqemu - INFO - Acquiring lockfile /tmp/qemu-tap-locks/tap0.lock...
runqemu - INFO - Created tap: tap0
runqemu - INFO - Running ldd /ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/sysroots/x86_64-linux/usr/bin/qemu-system-i386...
runqemu - INFO - Interrupt character is '^]'
runqemu - INFO - Running /ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/sysroots/x86_64-linux/usr/bin/qemu-system-i386 -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:02 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no  -s -S   -cpu qemu32 -m 256 -drive file=/ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/deploy/images/qemux86/core-image-minimal-qemux86-20170327033520.rootfs.ext4,if=virtio,format=raw -vga vmware -show-cursor -usb -usbdevice tablet -device virtio-rng-pci -serial mon:vc -serial mon:stdio -serial null -kernel /ExtDisk/Projects/Yocto_Rpi3_Morty/x86_build/tmp/deploy/images/qemux86/bzImage -append 'root=/dev/vda rw highres=off  console=ttyS0 mem=256M ip=192.168.7.2::192.168.7.1:255.255.255.0 vga=0 uvesafb.mode_option=640x480-32 oprofile.timer=1 uvesafb.task_timeout=-1'

Poky (Yocto Project Reference Distro) 2.2 qemux86 /dev/ttyS1

qemux86 login: root

这里说明一下命令的作用:

$ runqemu qemux86 qemuparams="-s -S " serial

即qemuparams中的参数, 其中-S是停下运行:

-S  Do not start CPU at startup (you must type 'c' in the monitor).

然后-s则是开启kgdb端口, 即相当于使用gdbserver加载了内核, 同时这个端口是默认的1234

而serial则表示将console=stdio, 即将Guest OS中的串口output到这个Terminal的stdout, 即我们的终端中.


使用

在准备好后, 我们确定一下Qemu中的kernel的gdbserver是否已经准备好, 使用netstat查看对应TCP端口是否已经创建:

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第7张图片

上面的图中, 我们可以看到qemu-system-i386, 即runqemu封装的, 开启了端口1234.

然后我们开启Eclipse的Debug, 如果正确的话, 我们可以看到前面图中的gdb那行也是打开了1234端口. 


启动调试后, 此时Qemu的vmlinux处于等待status, 我们可以先设定一个breakpoint, 要完成这个设置, 即可在source code中直接设置, 也可以使用命令设置, 例如下面的第一行蓝色字体的就是使用命令设置:

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第8张图片


第二行则是加载了要Qemu/gdbserver运行的程序, 当然实际上我们前面已经指定了, 所以这个地方并不需要.

同时可以留意到, 里面使用了vmlinux-gdb.py, 我们前面在内核menuconfig中指定的要生成的script.

因为没有.gdbinit, 所以其实前面的这个gdb init script无效. 如果需要做特殊处理那么可以放在这里面.

开始调试

然后我们自己点击continue按钮, 让内核开始运行, 它会在我们设置的断电处stop:

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第9张图片

且自动打开source.

那么如果我们想到某个文件中设置断电该怎么办呢?

我们可以直接使用Eclipse的菜单File中的Open去打开, 然后设置即可:

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第10张图片

然后在对应行双击设置即可:

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第11张图片

在我们需要查看的地方也可以看变量, dump memory, 查看regs, 效果图如下.

结合Yocto Qemu与Eclipse单步调试开发Linux Kernel_第12张图片


到此就可以愉快的进行调试了. 但是因为我们没有创建Project, 所以无法对Kernel Source Code进行index, 因此大家还可以添加kernel code进行index从而更好的调试.


问题与解决

使用过程中, 因为Host CPU是Intel的支持虚拟化, 因此我一开始尝试使用了KVM, 结果发现无法单步调试, 因此在使用qemu来调试的时候不要开启KVM.


参考

http://www.yonch.com/tech/84-debugging-the-linux-kernel-with-qemu-and-eclipse

http://www.sw-at.com/blog/2011/02/11/linux-kernel-development-and-debugging-using-eclipse-cdt/

http://issaris.blogspot.jp/2007/12/download-linux-kernel-sourcecode-from.html

你可能感兴趣的:(Linux,eclipse,qemu,arm,linux,kernel,调试)