Provided by: radare2_6.0.4+dfsg-1_amd64 

NAME
r_debug — radare2 debugger library
SYNOPSIS
#include <r_debug.h>
DESCRIPTION
The r_debug library provides debugging capabilities for radare2, supporting process attachment, stepping,
breakpoints, register manipulation, memory inspection, and various debugging operations across different
platforms and architectures.
The core structure is RDebug, which manages debugger state, plugins, breakpoints, registers, and process
information.
INITIALIZATION
RDebug * r_debug_new(int hard)
Creates and returns a new debugger context. Use this as the first step when writing code that drives the
debugger programmatically. The optional `hard` parameter enables hardware-specific debugging features
(when available) such as hardware breakpoints. Typical usage is to create the context with `r_debug_new
()`, configure the `RDebug` fields (for example setting the core pointer or event hooks), then call
`r_debug_start ()` or `r_debug_attach ()` to begin debugging.
Always free the returned object with `r_debug_free ()` once debugging is finished to avoid leaking
resources.
void r_debug_free(RDebug *dbg)
Frees all resources associated with the debugger context and its substructures. After calling this
function the `RDebug *` must not be used. Typical pattern:
RDebug *dbg = r_debug_new (0);
// configure dbg->coreb.core, dbg->anal, etc.
// attach or start target
// debug loop
r_debug_free (dbg);
PROCESS CONTROL
bool r_debug_attach(RDebug *dbg, int pid)
Attach to an existing process and prepare the internal plugin and IO callbacks for controlling the
target. After a successful attach you usually call `r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false)` to
populate register state and `r_debug_bp_update (dbg)` if breakpoints need to be resolved against symbol
expressions. When attaching to remote backends the plugin selected (the `dbg->current->plugin`)
determines the behaviour of `r_debug_attach ()` and subsequent I/O.
bool r_debug_detach(RDebug *dbg, int pid)
Detach the debugger from the target process. Use this when you want to leave the debuggee running under
its own control. After detaching you may still call `r_debug_info ()` to read cached information, but
most control functions will no longer be available.
bool r_debug_start(RDebug *dbg, const char *cmd)
Start and spawn a new process for debugging with the given command. This sets up the debugging plugin's
process creation flow (for example using `fork/exec` on native backends or a remote protocol for remote
backends). After `r_debug_start ()` the usual flow is to call `r_debug_wait ()` to observe the initial
stop event, then set breakpoints and continue.
EXECUTION CONTROL
int r_debug_step(RDebug *dbg, int steps)
Perform one or more single instruction steps on the selected thread. Use `r_debug_step ()` for
instruction-level stepping. For higher-level stepping that steps over function calls use
`r_debug_step_over ()`. If you need to execute until a given address use `r_debug_continue_until ()`.
When stepping after hitting a software breakpoint, the library handles the "recoil" process (clearing the
breakpoint, stepping once, restoring the breakpoint). Callers do not normally need to implement recoiling
themselves but should be aware that `r_debug_step ()` may return a value less than requested when a
breakpoint was involved.
int r_debug_step_over(RDebug *dbg, int steps)
Step over function calls for `steps` instructions. This is useful when implementing source-level stepping
or when the caller wants to skip stepping into library code.
int r_debug_continue(RDebug *dbg)
Resume execution until the debuggee stops due to a breakpoint, signal or other event. Before calling
`r_debug_continue ()` ensure that software breakpoints are properly restored by calling
`r_debug_bp_update ()` if you modified breakpoint expressions, and sync registers if you modified them
locally. For multi-threaded targets prefer using the `continue_all_threads` flag on `RDebug` when
supported by the backend.
bool r_debug_continue_until(RDebug *dbg, ut64 addr)
Resume execution and stop when the program counter reaches `addr`. This is convenient for implementing
temporary range stepping: add a temporary breakpoint with `r_debug_bp_add ()` and then call
`r_debug_continue ()`, or use `r_debug_continue_until ()` to avoid explicit breakpoint management when
supported by the plugin.
WAITING AND REASONS
RDebugReasonType r_debug_wait(RDebug *dbg, RBreakpointItem **bp)
Block until the debuggee stops and return the reason (an `RDebugReasonType`). `r_debug_wait ()` is the
canonical way to implement a debugging loop: call it after `r_debug_continue ()` or `r_debug_step ()` and
inspect the returned reason via `r_debug_stop_reason ()` or by testing the return value. If `bp` is non-
NULL and the stop reason involves a breakpoint, `*bp` will be set to the `RBreakpointItem *` that was
hit.
Typical usage pattern:
r_debug_continue (dbg);
RBreakpointItem *bp = NULL;
RDebugReasonType why = r_debug_wait (dbg, &bp);
if (why == R_DEBUG_REASON_BREAKPOINT && bp) {
// inspect registers and memory here
}
RDebugReasonType r_debug_stop_reason(RDebug *dbg)
Return the last stop reason stored in `dbg->reason`. This is useful when you cannot block on
`r_debug_wait ()` (for example when integrating with an event loop) and need to poll the current state.
const char * r_debug_reason_tostring(int type)
Return a human-readable string for the given reason code. Useful for logging or user-facing messages when
reporting why a debuggee stopped.
REGISTER MANAGEMENT
bool r_debug_reg_sync(RDebug *dbg, int type, int write)
Synchronize registers between the local `RReg` view and the debuggee. Call with `write == false` to read
registers from the debuggee into the local `RReg` and with `write == true` to push local register values
into the debuggee. Always call `r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false)` after attaching to ensure
that `r_debug_reg_get ()` returns meaningful values.
ut64 r_debug_reg_get(RDebug *dbg, const char *name)
Return the value of the register named `name` using the local `RReg` cache. This value is only as up-to-
date as the last `r_debug_reg_sync ()`.
bool r_debug_reg_set(RDebug *dbg, const char *name, ut64 num)
Set a register locally. After calling `r_debug_reg_set ()` call `r_debug_reg_sync (dbg, R_REG_TYPE_GPR,
true)` to write the change to the debuggee. Common pattern: read PC with `r_debug_reg_get ()`, update a
register, write back with `r_debug_reg_sync ()`, then `r_debug_continue ()`.
bool r_debug_reg_list(RDebug *dbg, int type, int size, PJ *pj, int rad, const char *use_color)
Produce a formatted list of registers suitable for printing. Useful for implementing `info registers`
style commands in front-ends.
BREAKPOINTS
RBreakpointItem * r_debug_bp_add(RDebug *dbg, ut64 addr, int hw, bool watch, int rw, char *module, st64
m_delta)
Add a breakpoint at `addr`. Use `hw` to request a hardware breakpoint when supported by the backend,
`watch` to indicate a watchpoint and `rw` to specify read/write conditions for watchpoints. `module` and
`m_delta` are used for module-relative expressions. After adding breakpoints call `r_debug_bp_update ()`
to resolve expression-based breakpoints and make sure the plugin has the correct breakpoint list loaded.
The library distinguishes software and hardware breakpoints: software breakpoints are typically
implemented by writing a trap instruction to the target process and therefore must be temporarily removed
when the debugger needs to execute target code (for example when implementing recoil). Hardware
breakpoints do not require patching memory but are usually limited in number.
void r_debug_bp_update(RDebug *dbg)
Resolve breakpoint expressions and update the internal breakpoint addresses. Call this after adding
breakpoints by name/expression. The implementation calls `r_bp_get_at ()` and `r_bp_restore ()`
internally to manage software breakpoints; front-ends should not duplicate that logic.
MEMORY MANAGEMENT
RList * r_debug_map_list_new(void)
Create an empty list used to store memory map entries (the same format used by `r_debug_map_get ()`). Use
this to enumerate memory regions when implementing memory listing or to build a synthetic map for
analysis.
RDebugMap * r_debug_map_get(RDebug *dbg, ut64 addr)
Return the `RDebugMap` corresponding to the memory region that contains `addr`. The returned map is owned
by the `RDebug` internals; callers should not free it directly. Use `r_debug_map_protect ()` to change
memory protections for writable patching or to make a region executable for `r_debug_execute ()`.
bool r_debug_map_protect(RDebug *dbg, ut64 addr, int size, int perms)
Change memory protection for a region starting at `addr`. This is useful when you want to write code into
the target and execute it (for example for trampolines). Many backends require cooperation with the
plugin, and the call will fail if the underlying OS does not permit the kind of change requested.
PROCESS INFORMATION
RDebugInfo * r_debug_info(RDebug *dbg, const char *arg)
Query miscellaneous information about the debugged process, such as its current working directory,
command line and executable path. Backends populate this structure from platform-specific sources; it is
convenient for front-ends that need to show process metadata.
void r_debug_info_free(RDebugInfo *rdi)
Free the `RDebugInfo` structure returned by `r_debug_info ()`.
THREADS AND PROCESSES
RList * r_debug_pids(RDebug *dbg, int pid)
Return a list of process/thread identifiers that the backend knows about. Use this to implement thread
list UIs. Each list element is typically an `RDebugPid` or similar structure depending on the plugin.
bool r_debug_select(RDebug *dbg, int pid, int tid)
Select a specific process and thread (if supported) for subsequent operations. After selecting a thread,
calls like `r_debug_step ()` or `r_debug_reg_sync ()` operate on the selected thread. Remember to call
`r_debug_reg_sync ()` after switching threads to refresh register state.
SIGNALS
int r_debug_signal_send(RDebug *dbg, int num)
Send the signal `num` to the debuggee. This can be used to emulate user actions such as `SIGINT` or to
forward signals from a front-end.
int r_debug_signal_resolve(RDebug *dbg, const char *signame)
Resolve a textual signal name like "SIGINT" to its numeric value.
const char * r_debug_signal_resolve_i(RDebug *dbg, int signum)
Return the canonical name for `signum` (for example, `SIGSEGV`). Useful for logging and user messages.
TRACING
RDebugTrace * r_debug_trace_new(void)
Create and initialize a trace context used by the tracing facilities in the debugger. The trace APIs
provide a way to record program execution history (PCs, memory snapshots) for later analysis.
void r_debug_trace_free(RDebugTrace *dbg)
Free a trace context created with `r_debug_trace_new ()`.
RDebugTracepointItem * r_debug_trace_add(RDebug *dbg, ut64 addr, int size)
Add a tracepoint at `addr`. When the tracepoint is hit the tracer may record state according to the trace
configuration.
PLUGINS
bool r_debug_plugin_add(RDebug *dbg, RDebugPlugin *plugin)
Register a debugger plugin implementation with the `RDebug` instance. Plugins implement architecture/OS-
specific behaviour such as process control, register IO and memory access. The built-in backends (native,
gdb, etc.) are provided as plugins; front-ends can add custom plugins to support additional transports.
bool r_debug_plugin_remove(RDebug *dbg, RDebugPlugin *plugin)
Unregister a previously added plugin. Removing the current plugin while debugging is not supported and
will typically fail.
EXECUTION
bool r_debug_execute(RDebug *dbg, const ut8 *buf, int len, ut64 *ret, bool restore, bool ignore_stack)
Execute the machine code in `buf` of length `len` inside the debugged process and optionally return a
value via `ret`. If `restore` is true the original memory contents and registers are restored after
execution. The `ignore_stack` flag lets the plugin adjust stack-related safety checks when injecting
code. This function is useful to evaluate small snippets in the target process for dynamic analysis or
for implementing functions that need to run in the target context.
DEBUG REASONS
The library defines various reasons why a debuggee might stop:
R_DEBUG_REASON_BREAKPOINT Hit a breakpoint
R_DEBUG_REASON_SIGNAL Received a signal
R_DEBUG_REASON_STEP Completed a step
R_DEBUG_REASON_SEGFAULT Segmentation fault
EXAMPLES
The examples below show common real-world sequences found in radare2's front-ends and plugins. They
assume a native backend but the same patterns apply to remote backends via their plugin implementations.
Minimal attach-and-continue loop:
RDebug *dbg = r_debug_new (0);
// attach and populate registers
if (!r_debug_attach (dbg, pid)) {
// handle error
}
if (!r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false)) {
// cannot read registers
}
// set a breakpoint at a symbol or address
RBreakpointItem *bp = r_debug_bp_add (dbg, 0x400000, 0, false, 0, NULL, 0);
r_debug_bp_update (dbg);
// resume and wait for events
r_debug_continue (dbg);
RBreakpointItem *hit = NULL;
RDebugReasonType why = r_debug_wait (dbg, &hit);
if (why == R_DEBUG_REASON_BREAKPOINT && hit) {
ut64 pc = r_debug_reg_get (dbg, "PC");
// inspect/modify registers or memory
}
Step-and-inspect example (useful for implementing a step debugger):
RDebug *dbg = r_debug_new (0);
// start or attach
r_debug_step (dbg, 1);
if (r_debug_wait (dbg, NULL) == R_DEBUG_REASON_STEP) {
// make sure registers are synced
r_debug_reg_sync (dbg, R_REG_TYPE_GPR, false);
ut64 sp = r_debug_reg_get (dbg, "SP");
// read memory via dbg->iob.read_at or use r_debug_map_get to find protections
}
Executing injected snippets safely:
// prepare the small machine code to run (architecture dependent)
const ut8 code[] = { 0x90, 0x90 }; // nop; nop
ut64 ret = 0;
if (r_debug_execute (dbg, code, sizeof (code), &ret, true, false)) {
// result available in ret
}
SEE ALSO
r_bp(3), r_reg(3), r_anal(3)
Debian September 20, 2025 R_DEBUG(3)