I want to customize a GRUB EFI image, and debug it while running on QEMU.
So I'm trying to debug a vanilla GRUB image before customizing it.
I downloaded GRUB2 from http://git.savannah.gnu.org and compiled it:
./autogen.sh
./configure --prefix=`pwd`/local --with-platform=efi --target=i386 CFLAGS=-g
make
make install
Then, generated a trivial EFI image with:
./local/bin/grub-mkstandalone -O i386-efi -o bootIA32.efi
And put it in a disk image file:
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
In order to boot it, I compiled an IA32 OVMF.fd to use it with QEMU:
qemu-system-i386 -bios $UDK_PATH/Build/OvmfIa32/RELEASE_GCC48/FV/OVMF.fd \
-hda hda.img
It boots correctly, giving me a grub shell.
Now, I want to debug GRUB. So I called QEMU with additional parameters:
qemu-system-i386 -bios $UDK_PATH/Build/OvmfIa32/RELEASE_GCC48/FV/OVMF.fd \
-hda hda.img \
-s -S
And attached gdb to QEMU:
cd grub-core/
gdb -x gdb_grub
However, seems that debug symbols are missing:
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)
What am I doing wrong?
@unixsmurf it seems to be loading the debug symbols when I use symbol-file
command. Indeed, gdb says
(gdb) symbol-file ../local/lib/grub/i386-efi/kernel.exec
Reading symbols from ../local/lib/grub/i386-efi/kernel.exec...done.
However, I still cannot step with next
command, which returns
(gdb) n
Single stepping until exit from function grub_disk_cache_table,
which has no line number information.
0xffffff75 in ?? ()
I'd like to, for instance, set a breakpoint in grub_core/kern/main.c:grub_main
function and run it step by step.
But although the breakpoint is set, when I continue
the execution, GRUB reaches the shell without stopping on the breakpoint:
(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.
There are no debug symbols included in your bootIA32.efi
image.
The gdb_grub
script attempts to do this, but since it was designed for BIOS (not UEFI), and appears to basically be included and generated mainly by accident, this does not really function anymore - since the EFI version of GRUB is dynamically to an address decided at runtime.
Now, with a bit of trickery (and an OVMF_CODE.fd
built with -D DEBUG_ON_SERIAL_PORT
), I can see that as long as I don't run any other commands before entering GRUB, I always see:
Loading driver at 0x0003DDE9000 EntryPoint=0x0003DDE9400
So with a horrible hack to gdb_grub
, changing the line near the end:
file kernel.exec
to
add-symbol-file kernel.exec 0x0003DDE9400
I end up with a situation instead of
add symbol table from file "kernel.exec" at
.text_addr = 0x3dde9400
0x0000fff0 in ?? ()
Breakpoint 1 at 0x3ddedddb: file kern/dl.c, line 53.
(gdb)
After this point. And if I then continue, the module symbol loading now works as the script intended:
(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
Not exactly production-ready, but workable.
The accepted answer worked like magic for me.
BTW, I use the following lower-level executable to build the EFI, same as for a full debian qemu image (the command creates a smaller EFI and can be run from any directory.)
MODULES="search iso9660 configfile normal memdisk tar part_msdos part_gpt fat"
$GRUB_PATH/grub-mkimage -O x86_64-efi -d $GRUB_PATH/grub-core -p "" -o ./grub.efi $MODULES
I still have to start the gdb session in the same source directory as kernel.exec because the source file paths are relative to that directory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With