如何用GDB和QEMUdebuggingLinux内核?

我是内核开发的新手,我想知道如何使用QEMU和gdb运行/debuggingLinux内核。 我其实读罗伯特·爱的书,但不幸的是,它不能帮助读者如何安装适当的工具来运行或debugging内核…所以我所做的是遵循本教程http://opensourceforu.efytimes.com / 2011/02 / kernel-development-debugging-eclipse / 。 我使用eclipse作为IDE在内核上开发,但是我想首先在QEMU / gdb下运行。 所以我到目前为止做的是:

1)编译内核:

make defconfig (then setting the CONFIG_DEBUG_INFO=y in the .config) make -j4 

2)一旦编译完成,我运行Qemu使用:

 qemu-system-x86_64 -s -S /dev/zero -kernel /arch/x86/boot/bzImage 

在“停止”状态下启动内核

3)因此我必须使用gdb,我尝试下面的命令:

 gdb ./vmlinux 

它正确运行,但是…现在我不知道该怎么做…我知道我必须使用远程debugging端口1234(Qemu使用的默认端口),使用vmlinux作为符号表文件debugging。

所以我的问题是:我应该怎么做才能在Qemu上运行内核,将debugging器附加到它上面,从而让它们一起工作,通过内核开发使我的生活更轻松。

我会尝试:

 (gdb) target remote localhost:1234 (gdb) continue 

使用'-s'选项可以让qemu监听端口tcp :: 1234,如果你在同一台机器上,你可以连接到localhost:1234。 Qemu的“-S”选项会使Qemu停止执行,直到您执行continue命令。

最好的事情可能是看看一个体面的GDB教程,以配合你正在做的事情。 这个看起来相当不错。

在Ubuntu 16.10主机上测试的分步过程

为了快速入门,我已经在https://github.com/cirosantilli/linux-kernel-module-cheat上做了一个最小化的完全自动化的QEMU + Buildroot示例。主要步骤如下。

首先得到rootfs.cpio.gz文件系统rootfs.cpio.gz 。 如果您需要,请考虑:

  • 一个最小的init唯一可执行映像: https : //unix.stackexchange.com/questions/122717/custom-linux-distro-that-runs-just-one-program-nothing-else/238579#238579
  • Busybox交互式系统: https : //unix.stackexchange.com/questions/2692/what-is-the-smallest-possible-linux-implementation/203902#203902

然后在Linux内核上:

 git checkout v4.9 make mrproper make x86_64_defconfig cat <<EOF >.config-fragment CONFIG_DEBUG_INFO=y CONFIG_DEBUG_KERNEL=y CONFIG_GDB_SCRIPTS=y EOF ./scripts/kconfig/merge_config.sh .config .config-fragment make -j"$(nproc)" qemu-system-x86_64 -kernel arch/x86/boot/bzImage \ -initrd rootfs.cpio.gz -S -s 

在另一个终端上,从Linux内核树中,假设你想从start_kernel开始调试:

 gdb \ -ex "add-auto-load-safe-path $(pwd)" \ -ex "file vmlinux" \ -ex 'set arch i386:x86-64:intel' \ -ex 'target remote localhost:1234' \ -ex 'break start_kernel' \ -ex 'continue' \ -ex 'disconnect' \ -ex 'set arch i386:x86-64' \ -ex 'target remote localhost:1234' 

我们完成了!

有关内核模块,请参阅: 如何使用QEMU调试Linux内核模块?

对于Ubuntu 14.04,GDB 7.7.1,需要hbreakbreak软件断点被忽略。 在16.10中不再是这种情况。 另见: https : //bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944

凌乱的disconnect ,然后是解决错误:

 Remote 'g' packet reply is too long: 

相关线程:

已知的限制:

  • 如果使用-O0 ,Linux内核不支持(甚至无需编译补丁): 如何使用-O0 来优化Linux内核并编译它?
  • 即使在max-completions修正之后,GDB 7.11也会在某些类型的选项卡完成上留下内存: 大型二进制文件的选项卡完成中断有可能是该补丁没有涉及的一些特殊情况。 所以一个ulimit -Sv 500000是一个明智的行动前调试。 当我为sys_execvefilename参数选项卡完成的file<tab>时,特意sys_execve : https : sys_execve

也可以看看:

BjoernID的答案并不适合我。 第一次继续之后,没有断点,在中断时,我会看到如下行:

 0x0000000000000000 in ?? () (gdb) break rapl_pmu_init Breakpoint 1 at 0xffffffff816631e7 (gdb) c Continuing. ^CRemote 'g' packet reply is too long: 08793000000000002988d582000000002019[..] 

我想这与不同的CPU模式有关(在Linux启动时B​​IOS中的实模式与长模式)。 无论如何,解决方案是先运行QEMU而不用等待(即没有-S ):

 qemu-system-x86_64 -enable-kvm -kernel arch/x86/boot/bzImage -cpu SandyBridge -s 

在我的情况下,我需要在引导过程中断开某些东西,所以在几十秒后,我运行了gdb命令。 如果你有更多的时间(例如,你需要调试一个手动加载的模块),那么时间并不重要。

gdb允许你指定启动时应该运行的命令。 这使自动化更容易一些。 要连接到QEMU(现在应该已经启动了),请打开一个函数并继续执行,使用:

 gdb -ex 'target remote localhost:1234' -ex 'break rapl_pmu_init' -ex c ./vmlinux 

当你尝试使用gdb启动vmlinux exe时,那么gdb上的第一件事就是发布cmds:

(gdb)目标远程本地主机:1234

(gdb)break start_kernel

(继续)

这将在start_kernel中破坏内核。

至于我调试内核的最佳解决方案 – 就是从Eclipse环境中使用gdb。 您应该在远程调试部分为gdb设置适当的端口(必须与您在qemu启动字符串中指定的端口相同)。 这里是手册: http : //www.sw-at.com/blog/2011/02/11/linux-kernel-development-and-debugging-using-eclipse-cdt/