结合Yocto Qemu与Eclipse单步调试开发Linux Kernel
Posted TonyHo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结合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.
勾选FRAME POINTER
为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.
在Debugger中选择我们要连接到gdbserver中:
而且gdbserver的连接方式使用TCP, Port为1234:
接下来选择kenrel source code, 注意新版本的Yocto的kernel source code path已经变更:
完成配置后保存.
开启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端口是否已经创建:
上面的图中, 我们可以看到qemu-system-i386, 即runqemu封装的, 开启了端口1234.
然后我们开启Eclipse的Debug, 如果正确的话, 我们可以看到前面图中的gdb那行也是打开了1234端口.
启动调试后, 此时Qemu的vmlinux处于等待status, 我们可以先设定一个breakpoint, 要完成这个设置, 即可在source code中直接设置, 也可以使用命令设置, 例如下面的第一行蓝色字体的就是使用命令设置:
第二行则是加载了要Qemu/gdbserver运行的程序, 当然实际上我们前面已经指定了, 所以这个地方并不需要.
同时可以留意到, 里面使用了vmlinux-gdb.py, 我们前面在内核menuconfig中指定的要生成的script.
因为没有.gdbinit, 所以其实前面的这个gdb init script无效. 如果需要做特殊处理那么可以放在这里面.
开始调试
然后我们自己点击continue按钮, 让内核开始运行, 它会在我们设置的断电处stop:
且自动打开source.
那么如果我们想到某个文件中设置断电该怎么办呢?
我们可以直接使用Eclipse的菜单File中的Open去打开, 然后设置即可:
然后在对应行双击设置即可:
在我们需要查看的地方也可以看变量, dump memory, 查看regs, 效果图如下.
到此就可以愉快的进行调试了. 但是因为我们没有创建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
以上是关于结合Yocto Qemu与Eclipse单步调试开发Linux Kernel的主要内容,如果未能解决你的问题,请参考以下文章
搭建基于qemu + eclipse的kernel调试环境(by quqi99)
Yocto tips (20): Yocto中qemu模拟器的使用,以zynq Cortex-A9为例