Expand description
Patina Debugger
This crate provides a debugger implementation that will install itself in the exception handlers and communicate with debugger software using the GDB Remote protocol. The debugger is intended to be used in the boot phase cores.
This crate is under construction and may be missing functionality, documentation, and testing.
§Getting Started
For more details on using the debugger on a device, see the readme.
§Examples and Usage
The debugger consists of the static access routines and the underlying debugger
struct. The top level platform code should initialize the static PatinaDebugger
struct with the appropriate serial transport and default configuration. The
platform has the option of setting static configuration, or enabling the
debugger in runtime code based on platform policy. During entry, the platform
should use the set_debugger routine to set the global instance of the debugger.
Core code should use the static routines to interact with the debugger. If the debugger is either not set or not enabled, the static routines will be no-ops.
extern crate patina;
static DEBUGGER: patina_debugger::PatinaDebugger<patina::serial::uart::UartNull> =
patina_debugger::PatinaDebugger::new(patina::serial::uart::UartNull{})
.with_timeout(30); // Set initial break timeout to 30 seconds.
fn entry() {
// Configure the debugger. This is used for dynamic configuration of the debugger.
DEBUGGER.enable(true);
// Set the global debugger instance. This can only be done once.
patina_debugger::set_debugger(&DEBUGGER);
// Setup a custom monitor command for this platform.
patina_debugger::add_monitor_command("my_command", "Description of my_command", |args, writer| {
// Parse the arguments from _args, which is a SplitWhitespace iterator.
let _ = write!(writer, "Executed my_command with args: {:?}", args);
});
// Call the core entry. The core can then initialize and access the debugger
// through the static routines.
start();
}
fn start() {
// Initialize the debugger. This will cause a debug break because of the
// initial break configuration set above.
patina_debugger::initialize(&mut Interrupts::default(), Some(&ExampleTimer));
// Notify the debugger of a module load.
patina_debugger::notify_module_load("module.efi", 0x420000, 0x10000);
// Poll the debugger for any pending interrupts.
patina_debugger::poll_debugger();
// Break into the debugger if the debugger is enabled and initialized.
patina_debugger::breakpoint();
// Cause a debug break unconditionally. This will crash the system
// if the debugger is not enabled or initialized. This should be used with extreme caution.
patina_debugger::breakpoint_unchecked();
}
The debugger can be further configured by using various functions on the
initialization of the debugger struct. See the definition for debugger::PatinaDebugger
for more details. Notably, if the device is using the same transport for
logging and debugger, it is advisable to use .without_log_init().
§Features
alloc - Uses allocated buffers rather than static buffers for all memory. This provides additional functionality
but prevents debugging prior to allocations being available. This is intended for use by the core crate, and not
for platform use.
§License
Copyright (C) Microsoft Corporation.
SPDX-License-Identifier: Apache-2.0
Structs§
- Patina
Debugger - Patina Debugger
Enums§
- Debugger
Logging Policy - Policy for how the debugger will handle logging on the system.
Functions§
- add_
monitor_ command - Adds a monitor command to the debugger. This may be called before initialization, but should not be called before memory allocations are available. See MonitorCommandFn for more details on the callback function expectations.
- breakpoint
- Invokes a debug break instruction if the debugger is enabled and initialized. This will cause the debugger to break in. If the debugger is not enabled and initialized, this routine will have no effect.
- breakpoint_
unchecked - Invokes a debug break instruction unconditionally. If this routine is invoked when the debugger is not enabled and initialized, it will cause an unhandled exception.
- enabled
- Checks if the debugger is enabled.
- initialize
- Initializes the debugger. This will install the debugger into the exception handlers using the provided interrupt manager. This routine may invoke a debug break depending on configuration.
- initialized
- Checks if the debugger is initialized.
- notify_
module_ load - Notifies the debugger of a module load at the provided address and length. This should be invoked before the module has begun execution.
- poll_
debugger - Polls the debugger for any pending interrupts. The routine may cause a debug break.
- set_
debugger - Sets the global instance of the debugger.
Type Aliases§
- Monitor
Command Fn - Type for monitor command functions. This will be invoked by the debugger when the associated monitor command is invoked.