efi: Provide an easy way to debug with gdb

Add a Kconfig option to easily enable debugging of the app using the
recommended method. Provide some docs too.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2025-05-17 14:46:09 +02:00
parent 538deb46b7
commit 21ae2207d5
3 changed files with 86 additions and 1 deletions

View File

@@ -338,6 +338,45 @@ Additionally something like (sda is assumed as disk device):
append root=/dev/sda2 console=tty0 console=ttyS0,115200n8 rootwait rw
Debugging
---------
Debugging the app is not straightforward since it is relocated by the UEFI
firmware before it is run.
See
`Debugging UEFI applications with GDB <https://wiki.osdev.org/Debugging_UEFI_applications_with_GDB>`_
for details.
Within U-Boot, enable `CONFIG_EFI_APP_DEBUG` which will cause U-Boot to write
deadbeef to address `10000` which you can catch with gdb.
In gdb the procedure is something like this, for a 64-bit machine::
# Enable CONFIG_EFI_APP_DEBUG in the build
$ grep CONFIG_EFI_APP_DEBUG .config
CONFIG_EFI_APP_DEBUG=y
$ gdb u-boot
# Connect to the target; here we assume 'qemu -Ss' has been started
(gdb) target remote localhost:1234
# Set a watchpoint for the marker write
(gdb) watch *(unsigned long *)0x10000 == 0xdeadbeef
(gdb) continue
# Execution will break as soon as the marker is written.
# Now, fetch the relocated base address:
(gdb) set $base = *(unsigned long long *)0x10008
(gdb) add-symbol-file u-boot -o $base
# Now you can set other breakpoints as needed
For a 32-bit machine, use `unsigned long` for the cast when setting `$base`
The address of 0x10000 is defined by `GDB_ADDR` which you can change in the
code if needed.
Future work
-----------

View File

@@ -70,9 +70,10 @@ config EFI_STUB_64BIT
endchoice
if EFI_APP
config EFI_RAM_SIZE
hex "Amount of EFI RAM for U-Boot"
depends on EFI_APP
default 0x10000000
help
Set the amount of EFI RAM which is claimed by U-Boot for its own
@@ -80,4 +81,13 @@ config EFI_RAM_SIZE
other smaller amounts) and it can never be increased after that.
It is used as the RAM size in with U-Boot.
config EFI_APP_DEBUG
bool "Enable GDB debugging"
help
Enable this to allow GDB to stop the app at an early stage, so it is
possible to set the symbol offset. Since the app is relocated to an
unknown address, breakpoints will only work if this is done.
endif # EFI_APP
endmenu

View File

@@ -18,6 +18,31 @@
#include <efi.h>
#include <efi_api.h>
enum {
/* magic number to trigger gdb breakpoint */
GDB_MAGIC = 0xdeadbeef,
/* breakpoint address */
GDB_ADDR = 0x10000,
};
/**
* struct gdb_marker - structure to simplify debugging with gdb
*
* This struct is placed in memory and accessed to trigger a breakpoint in
* gdb.
*
* @magic: Magic number (GDB_MAGIC)
* @base: Base address of the app
*/
struct gdb_marker {
union {
u32 magic;
u64 space;
};
void *base;
};
static struct efi_priv *global_priv;
struct efi_priv *efi_get_priv(void)
@@ -116,6 +141,17 @@ int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image,
priv->loaded_image = loaded_image;
priv->image_data_type = loaded_image->image_data_type;
if (IS_ENABLED(CONFIG_EFI_APP_DEBUG)) {
struct gdb_marker *marker = (struct gdb_marker *)GDB_ADDR;
char buf[64];
marker->base = priv->loaded_image->image_base;
snprintf(buf, sizeof(buf), "\ngdb marker at %p base %p\n",
marker, marker->base);
efi_puts(priv, buf);
marker->magic = 0xdeadbeef;
}
return 0;
}