Add a Kconfig option to easily enable debugging of the app using the recommended method. Provide some docs too.
Signed-off-by: Simon Glass <s...@chromium.org> --- doc/develop/uefi/u-boot_on_efi.rst | 39 ++++++++++++++++++++++++++++++ lib/efi_client/Kconfig | 12 ++++++++- lib/efi_client/efi.c | 36 +++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index f1f9113b01f..d20d5b00ec6 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -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 ----------- diff --git a/lib/efi_client/Kconfig b/lib/efi_client/Kconfig index fec5b7e004c..7ac6497ec09 100644 --- a/lib/efi_client/Kconfig +++ b/lib/efi_client/Kconfig @@ -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 diff --git a/lib/efi_client/efi.c b/lib/efi_client/efi.c index bb1d9e24f84..8b825c7a66e 100644 --- a/lib/efi_client/efi.c +++ b/lib/efi_client/efi.c @@ -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; } -- 2.43.0