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
r_anal(3), r_asm(3), r_core(3)