Debug GRUB2 EFI image running on QEMU
Asked Answered
R

2

11

What I want to achieve

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.

What I have done so far

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.


Where I got stuck

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?


After adding symbols

@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.
Roaring answered 9/5, 2017 at 14:7 Comment(0)
S
10

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.

Skaw answered 10/5, 2017 at 15:53 Comment(6)
It still doesn't let me debug... I added in the question informations about what happened after loading kernel.execRoaring
So, digging a bit deeper, this functionality was clearly implemented pre-EFI - so the basic functionality is a bit ... clunky here. Updating the answer accordingly.Skaw
Great! It worked fine :-) I think you meant add-symbol-file kernel.exec 0x0003DDE9400.Roaring
Ah, yes, whoops. Edited.Skaw
I think you can avoid adding debugging to EFI and use the value from the "gdbinfo" grub command assuming the value is fairly stable. I think this was introduced in 2.12Cardiomegaly
@Cardiomegaly ah, yes, that will definitely be more useful for the majority of users. Although hackery still needed to debug before command line is available.Skaw
H
2

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.

Hyrup answered 6/10, 2020 at 22:17 Comment(1)
The MODULES list I used above is a sufficient set to boot up. For full features, I pulled in all the grub modules with something like (cd $GRUB_PATH/grub-core; find . -name "*.mod") > grubmods.lst and then use that to generate the (much larger) image.Hyrup

© 2022 - 2024 — McMap. All rights reserved.