Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debug GRUB2 EFI image running on QEMU

Tags:

qemu

gdb

uefi

grub2

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.
like image 474
lseki Avatar asked May 09 '17 14:05

lseki


2 Answers

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.

like image 123
unixsmurf Avatar answered Oct 22 '22 22:10

unixsmurf


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.

like image 2
dturvene Avatar answered Oct 22 '22 22:10

dturvene