- unstable 6.0.4+dfsg-1
R_ARCH(3) | Library Functions Manual | R_ARCH(3) |
NAME¶
r_arch
—
Architecture abstraction library for radare2
SYNOPSIS¶
The primary functions and types provided by the r_arch API are used to select architecture plugins, configure decoding/encoding behaviour and create per-plugin sessions for advanced callbacks (for example to fetch register profiles or run ESIL hooks). Use `r_arch_config_new` to create a configuration and `r_arch_use` to activate an architecture plugin.
#include <r_arch.h>
DESCRIPTION¶
r_arch implements a thin, stable interface that core consumers (such as `libr/core` and `libr/anal`) use to perform disassembly, assembly and to access plugin-specific capabilities. The API exposes helpers to query plugin limits (e.g. maximum opcode size), run the generic decode/encode paths and to wrap plugin sessions when direct access to plugin callbacks is required.
Key concepts and why they matter in practice:
- `RArch` — holds available arch plugins and an active session; most clients keep a single `RArch` per `RCore` or `RAnal` instance so the arch state (current plugin, esil, reg profile) is shared.
- `RArchConfig` — describes desired architecture parameters (name, bits, endianness, syntax). Set this before calling `r_arch_use` so the right plugin variant is selected.
- `RAnalOp` — the container for decoded instruction information. Decoders fill `op.size`, `op.mnemonic`, `op.esil` and other fields depending on the decode mask. Consumers such as the ESIL executor rely on `op.esil` to obtain instruction semantics.
- `RArchSession` — per-plugin state allowing callers to directly invoke plugin callbacks (for example, `plugin->regs` to obtain a register profile). Use a session when you need functionality not exposed by the generic decode/encode wrappers.
INITIALIZATION¶
Before decoding or encoding, create an `RArch` instance and
configure the plugin you want to use. The configuration controls bits,
syntax and other plugin-specific options. Pp RArch *
r_arch_new
(void)
RArchConfig *
r_arch_config_new
(void)
void
r_arch_config_free
(RArchConfig
*cfg)
bool
r_arch_use
(RArch
*arch, RArchConfig *config,
const char *name)
void
r_arch_free
(RArch
*arch)
Typical initialization steps used across core components:
- Create an arch object with `r_arch_new` and a configuration with `r_arch_config_new`.
- Set desired options (`cfg->arch`, `cfg->bits`, `cfg->endian`, `cfg->syntax`) and call `r_arch_use (arch, cfg, name)` to activate the plugin.
- Query plugin capabilities via `r_arch_info` (for example `R_ARCH_INFO_MAXOP_SIZE`), or create an `RArchSession` with `r_arch_session` when you need plugin callbacks, such as `regs()`.
Example (typical init):
RArch *arch = r_arch_new(); RArchConfig *cfg = r_arch_config_new(); strcpy (cfg->arch, "x86"); cfg->bits = 64; cfg->syntax = R_ARCH_SYNTAX_INTEL; if (!r_arch_use (arch, cfg, "x86")) { // handle error: requested plugin not available } // later r_arch_config_free (cfg); // r_arch_free (arch) when done
DECODING (DISASSEMBLING)¶
Decoding converts raw bytes to a populated `RAnalOp`. The API
supports masks to control what information the plugin should fill —
for example basic fields, ESIL semantics or value operands. Real-world
clients first query the plugin for its maximum opcode length so they read
enough bytes from IO. Pp int
r_arch_info
(RArch
*arch, int query)
bool
r_arch_decode
(RArch
*a, RAnalOp *op, RArchDecodeMask
mask)
void
r_anal_op_init
(RAnalOp
*op)
bool
r_anal_op_set_bytes
(RAnalOp
*op, ut64 addr, const ut8
*data, int size)
void
r_anal_op_fini
(RAnalOp
*op)
Practical sequence used in `r_core_esil_single_step`:
- Query maximum opcode size: `r_arch_info (arch, R_ARCH_INFO_MAXOP_SIZE)`.
- Read up to `max_op_size` bytes from the IO layer into a buffer.
- Initialize and populate an `RAnalOp` with `r_anal_op_init` and `r_anal_op_set_bytes`.
- Call `r_arch_decode (arch, &op, mask)` with masks such as `R_ARCH_OP_MASK_BASIC | R_ARCH_OP_MASK_ESIL` to obtain decoding and ESIL semantics.
- On success inspect `op.size`, `op.esil`, `op.mnemonic` and other fields and clean up with `r_anal_op_fini`.
Minimal decode example (pattern taken from `r_core_esil_single_step`):
int max_op = r_arch_info (arch, R_ARCH_INFO_MAXOP_SIZE); if (max_op < 1) { max_op = 32; } ut8 buf[64]; if (!r_io_read_at (io, pc, buf, max_op)) { // read failure } RAnalOp op; r_anal_op_init (&op); r_anal_op_set_bytes (&op, pc, buf, max_op); if (!r_arch_decode (arch, &op, R_ARCH_OP_MASK_BASIC | R_ARCH_OP_MASK_ESIL)) { r_anal_op_fini (&op); // decode failed } // use op.size, op.esil, op.mnemonic ... r_anal_op_fini (&op);
Notes and gotchas:
- Always ensure you read at least `R_ARCH_INFO_MAXOP_SIZE` bytes (or a safe fallback) before calling `r_arch_decode`; plugins may require several bytes to decide instruction length.
- Check `op.size` and `op.type` after decoding. The core implementation uses hints (`r_anal_hint_get`) to override `op.size` or `op.esil` when available.
- When decoding for emulation (ESIL) prefer to request ESIL with the `R_ARCH_OP_MASK_ESIL` mask so the plugin fills `op.esil` with the instruction semantics.
ENCODING (ASSEMBLING)¶
Encoding converts textual mnemonics to machine code and populates
the `RAnalOp` bytes. The common workflow in `libr/anal` (see `r_anal_opasm`)
first tries the encoder callback provided by the active plugin/session and
falls back to other encoders when necessary. Pp bool
r_arch_encode
(RArch
*a, RAnalOp *op, RArchEncodeMask
mask)
RAnalOp *
r_anal_op_new
(void)
void
r_anal_op_free
(void
*op)
bool
r_anal_op_set_mnemonic
(RAnalOp
*op, ut64 addr, const char
*s)
Key points:
- Prepare an `RAnalOp` with the mnemonic (for example using `r_anal_op_set_mnemonic`) and call `r_arch_encode` to attempt encoding.
- If the plugin cannot encode the instruction, query `r_arch_info` for fallback sizes: `R_ARCH_INFO_INVOP_SIZE` (size of an invalid instruction placeholder) or `R_ARCH_INFO_CODE_ALIGN` to choose a reasonable number of bytes to reserve.
Encoding example (conceptual):
RAnalOp *op = r_anal_op_new (); r_anal_op_set_mnemonic (op, 0, "mov rax, 42"); if (r_arch_encode (arch, op, 0)) { // op->bytes and op->size now contain encoded data } else { int sz = r_arch_info (arch, R_ARCH_INFO_INVOP_SIZE); if (sz < 1) sz = r_arch_info (arch, R_ARCH_INFO_CODE_ALIGN); if (sz < 1) sz = 1; // reserve `sz` bytes as fallback } r_anal_op_free (op);
SESSIONS¶
When you need direct access to plugin callbacks (for example to
obtain a register profile string or to use plugin-specific preludes), create
a session with `r_arch_session`. Sessions wrap a `RArchPlugin` and expose
`session->plugin` which contains callbacks such as `regs()` or
`esilcb()`. Pp RArchSession *
r_arch_session
(RArch
*arch, RArchConfig *cfg,
RArchPlugin *ap)
int
r_arch_session_info
(RArchSession
*as, int q)
RList *
r_arch_session_preludes
(RArchSession
*as)
Real usage example from `r_core_esil_load_arch`:
// after activating arch and creating core->anal->arch->session char *rp = core->anal->arch->session->plugin->regs (core->anal->arch->session); if (rp) { r_reg_set_profile_string (core->esil.reg, rp); free (rp); } // the plugin may also register ESIL callbacks via session->plugin->esilcb
Other session helpers:
- `r_arch_session_info(session, q)` — query plugin-specific values.
- `r_arch_session_preludes(session)` — obtain RList of preludes injected by plugins (used by disassemblers/emitters to add prologue code, etc.).
CONFIGURATION¶
`RArchConfig` and its helpers let you specify architecture
attributes before loading a plugin. Use `r_arch_config_set_bits`,
`r_arch_config_set_cpu` and `r_arch_config_set_syntax` to set common
options. Plugins can read these fields when `r_arch_use` is called to select
appropriate variants. Pp bool
r_arch_config_set_bits
(RArchConfig
*c, int bits)
void
r_arch_config_set_cpu
(RArchConfig
*config, const char *cpu)
bool
r_arch_config_set_syntax
(RArchConfig
*config, int syntax)
RArchConfig *
r_arch_config_new
(void)
void
r_arch_config_free
(RArchConfig
*cfg)
Example: set CPU and syntax before calling `r_arch_use`:
r_arch_config_set_bits(cfg, 32); r_arch_config_set_cpu(cfg, "cortex-a53"); r_arch_config_set_syntax(cfg, R_ARCH_SYNTAX_ATT); r_arch_use(arch, cfg, NULL);
ARCHITECTURES¶
The architecture plugins are located under `libr/arch/p/*` and provide implementations for decoders/encoders and ESIL callbacks. `r_arch_find` and `r_arch_use` select and activate a plugin by name (plugins often use short names such as `x86`, `arm`, `mips`).
To discover which plugins were built inspect the `libr/arch/p` directory or call `r_arch_platform_list` at runtime.
SYNTAX MODES¶
Some plugins support multiple syntax modes (for x86 this is commonly Intel or AT&T). The syntax influences disassembly formatting and sometimes encoding. Set `cfg->syntax` with `r_arch_config_set_syntax` before calling `r_arch_use`.
Common syntax constants are `R_ARCH_SYNTAX_INTEL`, `R_ARCH_SYNTAX_ATT` and `R_ARCH_SYNTAX_MASM`. Use `R_ARCH_SYNTAX_REGNUM` to request register numbers instead of names when supported.
EXAMPLES¶
Below are practical snippets adapted from core components to show how decoding, ESIL integration and session usage combine to solve real tasks.
Example 1 — ESIL single-step (short sequence based on `r_core_esil_single_step`):
// 1. get max opcode size int max_op = r_arch_info (arch, R_ARCH_INFO_MAXOP_SIZE); if (max_op < 1) { max_op = 32; } // 2. read bytes from IO ut8 buf[64]; if (!r_io_read_at (io, pc, buf, max_op)) { /* read error */ } // 3. decode requesting ESIL RAnalOp op; r_anal_op_init (&op); r_anal_op_set_bytes (&op, pc, buf, max_op); if (!r_arch_decode (arch, &op, R_ARCH_OP_MASK_BASIC | R_ARCH_OP_MASK_ESIL)) { r_anal_op_fini (&op); // decode failed or unknown instruction } // 4. check op.size and apply hints if needed (core uses r_anal_hint_get) if (op.size < 1 || op.type == R_ANAL_OP_TYPE_ILL) { /* trap handling */ } // 5. run ESIL expression (op.esil) in the REsil context char *esil_expr = r_strbuf_drain_nofree (&op.esil); // r_esil_parse(core_esil, esil_expr); free (esil_expr); r_anal_op_fini (&op);
Example 2 — load architecture register profile into core ESIL (from `r_core_esil_load_arch`):
// after arch/plugin/session are initialized if (core->anal->arch->session && core->anal->arch->session->plugin && core->anal->arch->session->plugin->regs) { char *reg_profile = core->anal->arch->session->plugin->regs ( core->anal->arch->session); if (reg_profile) { r_reg_set_profile_string (core->esil.reg, reg_profile); free (reg_profile); } }
SEE ALSO¶
September 21, 2025 | Debian |