调试在QEMU上运行的GRUB2 EFI映像

lse*_*eki 5 gdb qemu uefi grub2

我想实现的目标

我想自定义GRUB EFI映像,并在QEMU上运行时对其进行调试。

因此,我尝试在自定义之前调试原始GRUB图像。

到目前为止我做了什么

我从http://git.savannah.gnu.org下载GRUB2 并进行了编译:

./autogen.sh
./configure --prefix=`pwd`/local --with-platform=efi --target=i386 CFLAGS=-g
make
make install
Run Code Online (Sandbox Code Playgroud)

然后,生成具有以下内容的普通EFI图像:

./local/bin/grub-mkstandalone -O i386-efi -o bootIA32.efi
Run Code Online (Sandbox Code Playgroud)

并将其放在磁盘映像文件中:

qemu-img create -f raw hda.img 1G
mkfs.fat hda.img
sudo mount -o uid=$UID hda.img /mnt
mkdir -p /mnt/efi/boot/
mv bootIA32.efi /mnt/efi/boot/
sudo umount /mnt
Run Code Online (Sandbox Code Playgroud)

为了启动它,我编译了一个IA32 OVMF.fd使其与QEMU一起使用:

qemu-system-i386 -bios $UDK_PATH/Build/OvmfIa32/RELEASE_GCC48/FV/OVMF.fd \
                 -hda hda.img
Run Code Online (Sandbox Code Playgroud)

它可以正确启动,给我一个g壳。


我被困在那里

现在,我想调试GRUB。所以我用其他参数调用了QEMU:

qemu-system-i386 -bios $UDK_PATH/Build/OvmfIa32/RELEASE_GCC48/FV/OVMF.fd \
                 -hda hda.img \
                 -s -S
Run Code Online (Sandbox Code Playgroud)

并将gdb附加到QEMU:

cd grub-core/
gdb -x gdb_grub
Run Code Online (Sandbox Code Playgroud)

但是,似乎缺少调试符号:

GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1
(...)
For help, type "help".
Type "apropos word" to search for commands related to "word".
0x0000fff0 in grub_disk_cache_table ()
Breakpoint 1 at 0x49b1: file kern/dl.c, line 53.
(gdb) n
Single stepping until exit from function grub_disk_cache_table,
which has no line number information.
0xffffff75 in ?? ()
(gdb)
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?


添加符号后

@unixsmurf,当我使用symbol-file命令时,似乎正在加载调试符号。确实,gdb说

(gdb) symbol-file ../local/lib/grub/i386-efi/kernel.exec
Reading symbols from ../local/lib/grub/i386-efi/kernel.exec...done.
Run Code Online (Sandbox Code Playgroud)

但是,我仍然无法next执行命令,该命令返回

(gdb) n
Single stepping until exit from function grub_disk_cache_table,
which has no line number information.
0xffffff75 in ?? ()
Run Code Online (Sandbox Code Playgroud)

例如,我想在grub_core/kern/main.c:grub_main函数中设置一个断点并逐步运行它。

但是,尽管设置了断点,但是continue在执行时,GRUB到达了外壳而没有在断点上停止:

(gdb) b main.c:grub_main
Note: breakpoint 2 also set at pc 0x6082.
Breakpoint 3 at 0x6082: file kern/main.c, line 266.
(gdb) c
Continuing.
Run Code Online (Sandbox Code Playgroud)

uni*_*urf 8

您的bootIA32.efi图像中不包含调试符号。该gdb_grub脚本尝试执行此操作,但由于它是为 BIOS(而非 UEFI)设计的,并且似乎主要是偶然包含和生成的,因此它不再真正起作用 - 因为 GRUB 的 EFI 版本是动态地确定的地址在运行时。

现在,通过一些技巧(和OVMF_CODE.fd内置-D DEBUG_ON_SERIAL_PORT),我可以看到只要在进入 GRUB 之前不运行任何其他命令,我总是看到:

Loading driver at 0x0003DDE9000 EntryPoint=0x0003DDE9400
Run Code Online (Sandbox Code Playgroud)

所以用一个可怕的 hack to gdb_grub,改变接近尾声的行:

file kernel.exec
Run Code Online (Sandbox Code Playgroud)

add-symbol-file kernel.exec 0x0003DDE9400
Run Code Online (Sandbox Code Playgroud)

我最终遇到了一个情况而不是

add symbol table from file "kernel.exec" at
.text_addr = 0x3dde9400
0x0000fff0 in ?? ()
Breakpoint 1 at 0x3ddedddb: file kern/dl.c, line 53.
(gdb)
Run Code Online (Sandbox Code Playgroud)

在这点之后。如果我再继续,模块符号加载现在按脚本预期工作:

(gdb) cont
Continuing.
add symbol table from file "memdisk.module" at
    .text_addr = 0x3bf75cb0
    .rodata.str1.1_addr = 0x3bf75e77
    .data_addr = 0x3bf75ee0
    .module_license_addr = 0x3bf75f00
    .bss_addr = 0x3bf75f10
add symbol table from file "archelp.module" at
    .text_addr = 0x3b885ef0
    .rodata.str1.1_addr = 0x3b8864d6
    .module_license_addr = 0x3b88653c
Run Code Online (Sandbox Code Playgroud)

不完全适合生产,但可行。