39

我是内核开发的新手,我想知道如何使用 QEMU 和 gdb 运行/调试 linux 内核。我实际上正在阅读 Robert Love 的书,但不幸的是它并不能帮助读者了解如何安装适当的工具来运行或调试内核......所以我所做的就是遵循本教程http://opensourceforu.efytimes.com /2011/02/kernel-development-debugging-using-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

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

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

4

6 回答 6

33

我会尝试:

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

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

最好的办法可能是看一个像样的 GDB 教程来了解你正在做的事情。这个看起来很不错。

于 2012-07-10T09:02:57.047 回答
29

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

为了快速从头开始,我在以下位置制作了一个最小的全自动 QEMU + Buildroot 示例:https ://github.com/cirosantilli/linux-kernel-module-cheat/blob/c7bbc6029af7f4fab0a23a380d1607df0b2a3701/gdb-step-debugging.md步骤如下。

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

然后在 Linux 内核上:

git checkout v4.15
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 \
                   -append nokaslr

在另一个终端上,从 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,hbreak需要 GDB 7.7.1,break软件断点被忽略。16.10 不再是这种情况。另见:https ://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944

杂乱无章的disconnect事情以及解决该错误之后的事情是:

Remote 'g' packet reply is too long: 000000000000000017d11000008ef4810120008000000000fdfb8b07000000000d352828000000004040010000000000903fe081ffffffff883fe081ffffffff00000000000e0000ffffffffffe0ffffffffffff07ffffffffffffffff9fffff17d11000008ef4810000000000800000fffffffff8ffffffffff0000ffffffff2ddbf481ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000

相关话题:

已知限制:

也可以看看:

于 2015-10-18T21:46:45.557 回答
3

BjoernID 的回答对我来说并没有真正起作用。在第一次继续之后,没有达到断点并且在中断时,我会看到如下行:

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

我想这与不同的 CPU 模式有关(BIOS 中的实模式与 Linux 启动时的长模式)。无论如何,解决方案是先运行 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
于 2014-03-22T12:15:56.270 回答
2

当您尝试使用 gdb 启动 vmlinux exe 时,gdb 上的第一件事就是发出 cmd:

(gdb) 目标远程 localhost:1234

(gdb) 中断 start_kernel

(继续)

这将在 start_kernel 处破坏内核。

于 2013-08-19T03:27:09.307 回答
1

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

于 2014-03-22T17:12:42.200 回答
1

在 Linux 系统上,vmlinux 是一个静态链接的可执行文件,它包含采用 Linux 支持的目标文件格式之一的 Linux 内核,包括 ELF、COFF 和 a.out。内核调试、符号表生成或其他操作可能需要 vmlinux 文件,但必须在用作操作系统内核之前通过添加多引导标头、引导扇区和设置例程使其可引导。

此初始根文件系统的映像必须存储在 Linux 引导加载程序可访问的计算机引导固件的某个位置。这可以是根文件系统本身、光盘上的引导映像、本地磁盘上的小分区(引导分区,通常使用 ext4 或 FAT 文件系统)或 TFTP 服务器(在可以从以太网引导的系统上) )。

  1. 编译linux内核

    使用此系列构建内核,启用CONFIG_DEBUG_INFO(但不要关闭 CONFIG_DEBUG_INFO_REDUCED)

  2. 安装 GDB 和 Qemu

    sudo pacman -S gdb qemu
    
  3. 创建 initramfs

    #!/bin/bash
    
    # Os     : Arch Linux
    # Kernel : 5.0.3
    
    INIT_DIR=$(pwd)
    BBOX_URL="https://busybox.net/downloads/busybox-1.30.1.tar.bz2"
    BBOX_FILENAME=$(basename ${BBOX_URL})
    BBOX_DIRNAME=$(basename ${BBOX_FILENAME} ".tar.bz2")
    RAM_FILENAME="${INIT_DIR}/initramfs.cpio.gz"
    
    function download_busybox {
        wget -c ${BBOX_URL} 2>/dev/null
    }
    
    function compile_busybox {
        tar xvf ${BBOX_FILENAME} && cd "${INIT_DIR}/${BBOX_DIRNAME}/"
        echo "[*] Settings > Build options > Build static binary (no shared libs)"
        echo "[!] Please enter to continue"
        read tmpvar
        make menuconfig && make -j2 && make install
    }
    
    function config_busybox {
        cd "${INIT_DIR}/${BBOX_DIRNAME}/"
        rm -rf initramfs/ && cp -rf _install/ initramfs/
        rm -f initramfs/linuxrc
        mkdir -p initramfs/{dev,proc,sys}
        sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} initramfs/dev/
    
    cat > "${INIT_DIR}/${BBOX_DIRNAME}/initramfs/init" << EOF
    #!/bin/busybox sh
    mount -t proc none /proc
    mount -t sysfs none /sys
    
    exec /sbin/init
    EOF
    
        chmod a+x initramfs/init
        cd "${INIT_DIR}/${BBOX_DIRNAME}/initramfs/"
        find . -print0 | cpio --null -ov --format=newc | gzip -9 > "${RAM_FILENAME}"
        echo "[*] output: ${RAM_FILENAME}"
    
    }
    
    download_busybox
    compile_busybox
    config_busybox
    
  4. 使用 Qemu 引导 Linux 内核

    #!/bin/bash
    
    KER_FILENAME="/home/debug/Projects/kernelbuild/linux-5.0.3/arch/x86/boot/bzImage"
    RAM_FILENAME="/home/debug/Projects/kerneldebug/initramfs.cpio.gz"
    
    qemu-system-x86_64 -s -kernel "${KER_FILENAME}" -initrd "${RAM_FILENAME}" -nographic -append "console=ttyS0"
    
    $ ./qemuboot_vmlinux.sh
    SeaBIOS (version 1.12.0-20181126_142135-anatol)
    
    
    iPXE (http://ipxe.org) 00:03.0 C980 PCI2.10 PnP PMM+07F92120+07EF2120 C980
    
    
    Booting from ROM...
    Probing EDD (edd=off to disable)... o
    [    0.019814] Spectre V2 : Spectre mitigation: LFENCE not serializing, switching to generic retpoline
    can't run '/etc/init.d/rcS': No such file or directory
    
    Please press Enter to activate this console.
    / #  uname -a
    Linux archlinux 5.0.3 #2 SMP PREEMPT Mon Mar 25 10:27:13 CST 2019 x86_64 GNU/Linux
    / #
    
  5. 使用 GDB 调试 Linux 内核

    ~/Projects/kernelbuild/linux-5.0.3 ➭ gdb vmlinux
    ...
    (gdb) target remote localhost:1234
    Remote debugging using localhost:1234
    0xffffffff89a4b852 in ?? ()
    (gdb) break start_kernel
    Breakpoint 1 at 0xffffffff826ccc08
    (gdb)
    Display all 190 possibilities? (y or n)
    (gdb) info functions
    All defined functions:
    
    Non-debugging symbols:
    0xffffffff81000000  _stext
    0xffffffff81000000  _text
    0xffffffff81000000  startup_64
    0xffffffff81000030  secondary_startup_64
    0xffffffff810000e0  verify_cpu
    0xffffffff810001e0  start_cpu0
    0xffffffff810001f0  __startup_64
    0xffffffff81000410  pvh_start_xen
    0xffffffff81001000  hypercall_page
    0xffffffff81001000  xen_hypercall_set_trap_table
    0xffffffff81001020  xen_hypercall_mmu_update
    0xffffffff81001040  xen_hypercall_set_gdt
    0xffffffff81001060  xen_hypercall_stack_switch
    0xffffffff81001080  xen_hypercall_set_callbacks
    0xffffffff810010a0  xen_hypercall_fpu_taskswitch
    0xffffffff810010c0  xen_hypercall_sched_op_compat
    0xffffffff810010e0  xen_hypercall_platform_op
    
于 2019-03-27T04:57:28.877 回答