Arm Community
Arm Community
  • Site
  • User
  • Site
  • Search
  • User
Arm Community blogs
Arm Community blogs
Tools, Software and IDEs blog UEFI Debug Made Easy
  • Blogs
  • Mentions
  • Sub-Groups
  • Tags
  • Jump...
  • Cancel
More blogs in Arm Community blogs
  • AI blog

  • Announcements

  • Architectures and Processors blog

  • Automotive blog

  • Embedded and Microcontrollers blog

  • Internet of Things (IoT) blog

  • Laptops and Desktops blog

  • Mobile, Graphics, and Gaming blog

  • Operating Systems blog

  • Servers and Cloud Computing blog

  • SoC Design and Simulation blog

  • Tools, Software and IDEs blog

Tags
  • Software
  • UEFI
  • DS-5 Debugger
  • Debugger
Actions
  • RSS
  • More
  • Cancel
Related blog posts
Related forum threads

UEFI Debug Made Easy

Stephen Theobald
Stephen Theobald
September 11, 2013
6 minute read time.

Unified Extensible Firmware Interface (UEFI) is a well-established specification that defines a software interface to control the start-up of complex microprocessor systems, including initializing firmware, loading drivers and applications, all the way through to launching an operating system. UEFI on ARM is an excellent solution to control the booting of ARM-based servers and client computing devices, as it is small, fast and offers remote access capabilities.

Porting and debugging UEFI with ARM

Porting and debugging this flexible and powerful interface, however, is not a trivial task if you are not well geared for it. This blog shows step-by-step how to build the UEFI software and debug it at source level, including all dynamically loaded modules (DLLs), using the ARM Development Studio 5 (DS-5) toolchain.

UEFI has been developed by a community of companies, and ARM has been actively contributing to this initiative for several years. The "Tianocore" project offers Open Source implementations of the UEFI specification, and ARM ports are available to users under the BSD license.  In addition, Linaro is maintaining a UEFI tree based on the Tianocore git tree.

The toolchains supported for compiling UEFI for ARM include the ARM Compiler (a rebranded version of the RealView Compilation Tools a.k.a RVCT) as supplied in DS-5 Professional and DS-5 Ultimate Editions, GCC and XCode.

UEFI is quite a large package of source code, and porting this to your own ARM-based platform can be a daunting task. Thankfully, ready-made example ports for ARM-based systems, BeagleBoard and Samsung Origen are already available. DS-5 Professional and Ultimate Editions provide a complete UEFI development environment that enables you to:

  • fetch the UEFI source code via the Eclipse git plug-in
  • build the source code using the ARM Compiler
  • download the executables to a software model (a model of the Cortex-A9 is provided with DS-5) or to a hardware target (available separately)
  • run/debug the code at source-level using DS-5 Debugger

The DS-5 Debugger component in ARM DS-5 toolchain allows you to debug all phases of the UEFI control flow, including SEC (Security - Set up Temp memory), PEI (Pre-EFI - Initialize Memory), DXE (Driver Execution - Dispatch list of UEFI / DXE drivers) and BDS (Boot Device Selection - Run Setup) phases.

Let's get started

First launch DS-5 on a host machine. If you do not have the DS-5 toolchain installed on your machine, you can download a free 30-day evaluation license. Then set up DS-5 for UEFI development as described on GitHub, including creating a debug launch configuration that loads the UEFI firmware RTSM_VE_CORTEX-A9_EFI.fd .
 
Establish a connection to the Cortex-A9x4 software model by double-clicking on your debug launch configuration.  After connecting to the model and loading the UEFI firmware, DS-5 Debugger shows you something like this:

DS-5 Debugger screen views UEFI

DS-5 Debugger screen views after connecting to the model and loading the UEFI firmware

The first few instructions are 32-bit ARM assembler that performs some essential CPU initialization and sets up a basic C run-time environment (e.g. stack). You can single-step through this assembler, but the more interesting C code sections come fairly soon after, compiled as 16-/32-bit Thumb.

UEFI is modular, and is structured as a set of DLLs that are loaded into memory at run time. The addresses at which the modules are loaded are stored in tables in memory. The DLLs are compiled by the ARM Compiler into ELF files containing DWARF debug data. These are converted into PECOFF as required by the UEFI Specification. UEFI loads the PECOFF DLLs at run-time, and DS-5 Debugger loads the DWARF debug data from the ELF files at debug time.

Debug UEFI at source-level

To debug UEFI at source-level, a Jython script is provided in the ArmPlatformPkg. This script (cmd_load_symbols.py) handles all the complexities of searching memory for loaded modules, and calculating offset addresses to load debug information for symbols. In the Command field, enter:

source C:\git\edk2/ArmPlatformPkg/Scripts/Ds5/cmd_load_symbols.py -f (0x08000000,0x00280000) -m (0x80000000,0x40000000) -a

This will load all the debug symbols for the platform with firmware at 0x08000000 and DRAM at 0x80000000, for all currently loaded modules.  At this stage, only ArmPlatformSec.dll has been loaded, so only debug symbols for this will be loaded. The full list of symbols for this module then appears in the Functions view, including CEntryPoint. Set a breakpoint on CEntryPoint with: break CEntryPoint

Then run to this breakpoint by clicking on the Continue button (or pressing F8). Program execution will stop at CEntryPoint in Sec.c:

Debugging UEFI's C entry point at source level

Debugging UEFI's C entry point at source level


Now that debugging information has been loaded into DS-5 Debugger, you can now debug the code in ArmPlatformSec.dll at source level.  You can run, stop, set breakpoints, view variables, view registers, view disassembly, view memory, and so on in the normal way.

Resume program execution (Continue/F8), and stop it after a few seconds (Interrupt/F9).  UEFI will have started loading other modules, as shown in its serial console output:

Log of UEFI module loading activity
The log of UEFi's module loading activity

This output shows which DLLs have been loaded at which addresses, and (as an alternative to using cmd_load_symbols.py) which add-symbol-file command to use to debug them at source level.

DS-5's Jython scripting capabilities provide powerful ways to execute scripts and visualise system states.  For example, you can drag'n'drop cmd_load_symbols.py from the file system into the Scripts view. You can also associate parameters with the script, for example, the parameters "-f (0x08000000,0x00280000) -m (0x80000000,0x40000000) -a" mentioned earlier, by clicking on the "(...)" button on the Scripts view menu bar:

Associating parameters in Scripts view

Associating parameters with a script in the Scripts view

Having done that, you can then simply double-click on the script in the Scripts view to execute it with its parameters. Debug symbols will now be loaded into DS-5 Debugger for the other loaded modules.To see which DLLs have symbols loaded by the cmd_load_symbols.py script, add the "-v" switch to the list of parameters. You will then see the loaded DLLs listed in the Commands view:

UEFI loaded DLLs Commands view
UEFI's loaded DLLs listed in the Commands view

Resume program execution (Continue/F8), and let UEFI continue to load all the modules, and complete its count-down before attempting to launch an OS. UEFI's command-line boot loader output appears in the model's simulated display:

UEFI's boot loader

UEFI boot loader
The platform's timer is ticking, generating Interrupts at regular intervals. To debug the interrupt handler, set a breakpoint with: break IrqInterruptHandler

and run to this breakpoint (Continue/F8). Program execution will stop at IrqInterruptHandler in PL390GicDxe.c. You can now single-step through the interrupt handler, with full source-level symbols, and view Variables, Memory, Registers, etc.

Debugging UEFI's interrupt handler

Debugging UEFI's interrupt handler

Summary

To summarize, the DS-5 toolchain provides a complete UEFI development environment that enables you to fetch, build, download and run the UEFI software, and to debug its loaded DLLs at source-level, using the powerful Jython scripting features of DS-5 Debugger. It is also possible to debug the UEFI Self Certification Test (SCT) with DS-5, using the same Jython scripts. 

The Self Certification Test is not easy to debug but, thanks to DS-5, this process can be made much easier. More advanced UEFI implementations are already available, for example, UEFI for the ARMv8 (AArch64) architecture, and DS-5 Debugger is able to debug this too, including its loaded DLLs, using its flexible Jython scripting!

Anonymous
  • onepiece
    onepiece over 9 years ago

    Hi, Theobald:

    I am debug UEFI through you provide method, only ArmPlatformSec.dll has loaded, other modules has not loaded, and show following log:

    "Add symbols of z:\win10\uefi\edk2\Build\XxxxBoard\DEBUG_ARMGCC\ARM\XxxxBoardPkg\Sec\Sec\DEBUG\ArmPlatformSec.dll at 0x180

    Note: no symbols have been found in System Memory (possible cause: the UEFI permanent memory has been installed yet)"

    when other modules is loaded? only ArmPlatformSec.dll can source level debug current.

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
  • Olivier Martin
    Olivier Martin over 9 years ago

    You can break into the Linux and Windows 10 UEFI boot application with ARM DS-5.

    But if you want to step through the Linux/Windows UEFI code then you will need the source code and the debug symbols of the UEFI application.

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
  • Jerome Decamps - 杜尚杰
    Jerome Decamps - 杜尚杰 over 10 years ago

    Hi,

    Is this the way to break the windows 10 UEFI ?
    Or just a way to be able to consider the same solution for linux ?

    Regards,

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
  • Stephen Theobald
    Stephen Theobald over 10 years ago

    Hi onepiece,

    To be able to debug a UEFI module at source level, it must first be compiled with debug information (e.g. with “-g”).  After the debug information for a module has been loaded into DS-5 Debugger using the cmd_load_symbols.py Jython script, DS-5 Debugger can then show you all the names of C/C++ functions and assembler labels used in the module.  These will appear in the Functions view in DS-5 Debugger.  You can then set a breakpoint on any function or label, referring to it directly by name, for example “break CEntryPoint”, and run to it, and then debug the module at source level.  If you do not see function names appearing in the Functions view, check that you have compiled the module for source level debug (“-g”).

    I hope this helps to clarify my explanation, and I hope you are now able to debug your project successfully!

    Best regards,

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
  • onepiece
    onepiece over 10 years ago

    hi,Mr.Theobald

    what mean is

    “The full list of symbols for this module then appears in the Functions view, including CEntryPoint.  Set a breakpoint on CEntryPoint with:

    break CEntryPoint”


    Thanks

    Best Regards

    onepiece

    • Cancel
    • Up 0 Down
    • Reply
    • More
    • Cancel
>
Tools, Software and IDEs blog
  • Python on Arm: 2025 Update

    Diego Russo
    Diego Russo
    Python powers applications across Machine Learning (ML), automation, data science, DevOps, web development, and developer tooling.
    • August 21, 2025
  • Product update: Arm Development Studio 2025.0 now available

    Stephen Theobald
    Stephen Theobald
    Arm Development Studio 2025.0 now available with Arm Toolchain for Embedded Professional.
    • July 18, 2025
  • GCC 15: Continuously Improving

    Tamar Christina
    Tamar Christina
    GCC 15 brings major Arm optimizations: enhanced vectorization, FP8 support, Neoverse tuning, and 3–5% performance gains on SPEC CPU 2017.
    • June 26, 2025