R_ANAL(3)

πŸ“¦
version 6.2.2 Β· 2 versions
  • 6.2.2 Β· alpine 3.24, arch rolling, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu stonking (latest)
  • 6.0.7 Β· ubuntu resolute
, in alpine 3.24, arch rolling, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu stonking

✨ NAME ✨

okay so this is r_anal β€” the radare2 analysis library, aka the part of radare2 that actually thinks about your binaries bestie πŸ’… (this lives in the R_ANAL(3) manual page, Library Functions Manual, if you were wondering).


🌸 SYNOPSIS 🌸

First things first: include the public header for the analysis API and make yourself an analysis context before you call anything else, k? No context, no vibes 😭

A typical flow is literally:

  1. create an RAnal with r_anal_new
  2. configure architecture and bitness with r_anal_use / r_anal_set_bits
  3. then do operation-level analysis with r_anal_op
  4. and higher-level analysis using the function / block / ESIL APIs
#include <r_anal.h>

πŸ¦‹ DESCRIPTION πŸ¦‹

The r_anal library serves comprehensive binary analysis capabilities for radare2. It's giving main character energy across the whole toolbox: disassembly, function analysis, control flow graph construction, symbolic execution via ESIL (Evaluable Strings Intermediate Language), variable tracking, cross-references, metadata management, and type analysis. Not me casually doing all of that 🫢

The core structure is RAnal, which holds the analysis context β€” architecture configuration, function lists, basic blocks, the ESIL emulator, registers, and various analysis options. She's the whole personality, honestly.


πŸŽ€ INITIALIZATION πŸŽ€

Initialization functions create and tear down the global analysis context used across radare2 components (core, visual, pseudo, etc.).

bestie listen: call r_anal_new once per context and r_anal_free when you're finished. Then bind per-core callbacks with r_anal_bind and pick an architecture plugin with r_anal_use. Clean entry, clean exit, iconic ✨

RAnal * r_anal_new(void)

Creates a new analysis context with default settings. Initializes ESIL, registers, function and block storage, metadata spaces, and loads the built-in plugins. Fr fr it does all of that.

void r_anal_free(RAnal *anal)

Frees all resources associated with the analysis context. Everything. Gone. Slay.

bool r_anal_use(RAnal *anal, const char *name)

Loads and activates an analysis plugin by name (e.g., "x86", "arm"). Pick your fighter πŸ’–


🌈 FUNCTION ANALYSIS 🌈

These APIs manage analyzed functions: creating, querying and iterating them.

In practice libr/core queries functions with r_anal_get_fcn_in / r_anal_get_function_at when displaying or transforming code, and creates new functions with r_anal_create_function when importing symbols or recovering code. Teamwork makes the dream work, no cap.

RAnalFunction * r_anal_create_function(RAnal *anal, const char *name, ut64 addr, int type, RAnalDiff *diff)

Creates and adds a new function to the analysis context. New fcn just dropped πŸ‘‘

RList * r_anal_get_functions_in(RAnal *anal, ut64 addr)

Returns a list of functions containing the given address.

RAnalFunction * r_anal_get_function_at(RAnal *anal, ut64 addr)

Returns the function with the specified entry point address.


πŸ’œ BASIC BLOCK MANAGEMENT πŸ’œ

Basic block helpers let callers construct and manipulate the control-flow graph (CFG).

Typical usage: recover blocks with r_anal_create_block, split or merge blocks while building CFGs, and query blocks from functions when rendering views or computing offsets.

RAnalBlock * r_anal_create_block(RAnal *anal, ut64 addr, ut64 size)

Creates a new basic block at the given address and size.

RAnalBlock * r_anal_block_split(RAnalBlock *bb, ut64 addr)

Splits a basic block at the specified address, returning the new block. It's giving mitosis πŸ’…

bool r_anal_block_merge(RAnalBlock *a, RAnalBlock *b)

Merges block b into block a if they are contiguous and have identical function lists.


⭐ OPERATION ANALYSIS ⭐

Operation-level analysis (r_anal_op) is the entry point for per-instruction work: it disassembles, decodes semantics and fills RAnalOp.

GUI, disassembly and emulation code in libr/core call this repeatedly to render instructions or to feed ESIL emulation. She's getting called in a loop and she's thriving.

int r_anal_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask)

Analyzes a single instruction at the given address, populating the RAnalOp structure with disassembly and analysis information.

char * r_anal_op_tostring(RAnal *anal, RAnalOp *op)

Converts an analyzed operation to its string representation.


πŸ“ VARIABLES πŸ“

Variable and type APIs are used to track function-local variables, arguments and their types.

r_anal_function_set_var is commonly used when recovering stack or register variables; callers can rename variables or set types to improve pseudocode and decompilation results. Basically: glow-up your decompilation 🫢

RAnalVar * r_anal_function_set_var(RAnalFunction *fcn, int delta, char kind, const char *type, int size, bool isarg, const char *name)

Creates or updates a variable in a function.

bool r_anal_var_rename(RAnal *anal, RAnalVar *var, const char *new_name)

Renames a variable. Name change era.

void r_anal_var_set_type(RAnal *anal, RAnalVar *var, const char *type)

Sets the type of a variable.


🧚 CROSS-REFERENCES 🧚

Xref APIs record references between addresses (calls, jumps, data references).

The core UI and analysis logic use r_anal_xrefs_set and r_anal_xrefs_get to display callers and to propagate dataflow information; set references when you discover a target during disassembly or relocation processing. Keeping receipts on who called who, iykyk.

bool r_anal_xrefs_set(RAnal *anal, ut64 from, ut64 to, RAnalRefType type)

Creates a cross-reference from one address to another.

bool r_anal_xrefs_setf(RAnal *anal, RAnalFunction *fcn, ut64 from, ut64 to, RAnalRefType type)

Like r_anal_xrefs_set, but takes the calling function to skip hash lookups. Speedrun strats ⚑

RVecAnalRef * r_anal_xrefs_get(RAnal *anal, ut64 to)

Returns all cross-references pointing to the given address.


πŸ”₯ METADATA πŸ”₯

Metadata routines attach arbitrary typed information to addresses (names, comments, function prototypes, etc.).

Use r_meta_set / r_meta_get_at to persist and query additional annotations discovered during analysis or imported from debug info. Your little annotation diary πŸ““

bool r_meta_set(RAnal *a, RAnalMetaType type, ut64 addr, ut64 size, const char *str)

Sets metadata at the specified address and size.

RAnalMetaItem * r_meta_get_at(RAnal *a, ut64 addr, RAnalMetaType type, ut64 *size)

Retrieves metadata at the given address.


πŸ¦„ HINTS πŸ¦„

Hints let you provide the analyzer with guidance (bitness, architecture, alignment).

libr/core often sets hints derived from sections, relocations or user commands so the analysis chooses the correct decoding and emulation models. Basically: sliding the analyzer a little note so it doesn't guess wrong 😌

void r_anal_hint_set_bits(RAnal *a, ut64 addr, int bits)

Sets a bitness hint at the specified address.

void r_anal_hint_set_arch(RAnal *a, ut64 addr, const char *arch)

Sets an architecture hint at the specified address.


πŸ’– ESIL πŸ’–

ESIL (the Evaluable Strings Intermediate Language) provides symbolic execution and emulation.

Use r_anal_esil_parse / r_anal_esil_run to evaluate instruction effects, and r_anal_esil_cfg_expr to build a small CFG from ESIL expressions when you need to simulate sequences or compute register/stack deltas. Yes bestie, we're simulating β€” stay with me πŸ’…

bool r_anal_esil_parse(REsil *esil, const char *expr)

Parses and executes an ESIL expression.

bool r_anal_esil_run(REsil *esil, ut64 addr, const char *str, int len, REsilInterrupt *intr, int *paddr)

Runs ESIL emulation starting from the given address.

RAnalEsilCFG * r_anal_esil_cfg_expr(RAnalEsilCFG *cfg, RAnal *anal, ut64 off, char *expr)

Builds a control flow graph from an ESIL expression.


🌟 TYPES 🌟

Type and base-type helpers are used by the type parser and by UI commands to store and query type information for variables and globals.

Use r_anal_type_new and the type lookup helpers when importing or constructing type metadata.

RAnalType * r_anal_type_new(void)

Creates a new type structure.

RAnalBaseType * r_anal_get_base_type(RAnal *anal, const char *name)

Retrieves a base type by name.


πŸ‘‘ CLASSES πŸ‘‘

Class and method APIs are used to model OO constructs and method dispatch when available from type information or debug info.

They are typically used together with the type system to provide richer decompilation results. OOP girlies, this one's for you ✨

void r_anal_class_create(RAnal *anal, const char *name)

Creates a new class in the analysis context.

RAnalClassErr r_anal_class_method_set(RAnal *anal, const char *class_name, RAnalMethod *meth)

Adds a method to a class.


🌸 GLOBALS 🌸

Global variable helpers let analysis record statically allocated symbols with types and names.

The core loader sets globals when parsing symbol tables or relocations so UI and analysis code can resolve references to static data.

bool r_anal_global_add(RAnal *anal, ut64 addr, const char *type_name, const char *name)

Adds a global variable at the specified address.


✨ EXAMPLES ✨

okay bestie, this is the part where it all comes together πŸ’… These snippets are the actual practical patterns that live in libr/core β€” like, the real recipes. They show you how to spin up an analysis context, do per-instruction analysis with r_anal_op, register or look up functions, record cross-references and metadata, and how ESIL gets used through the r_esil API (fun fact: ESIL itself lives over in libr/esil, not here πŸ¦‹).


πŸŽ€ Initialization / core-style setup

/* Initialization / core-style setup */
RAnal *anal = r_anal_new ();
/* select architecture plugin (e.g. "x86", "arm") and bitness */
r_anal_use (anal, "x86");
r_anal_set_bits (anal, 64);
/* optionally bind callbacks or a host object (core sets a user pointer) */
r_anal_set_user_ptr (anal, core);
r_anal_bind (anal, &core->rasm->analb);

so first you birth a fresh RAnal with r_anal_new (), then you tell it who it is β€” pick the architecture plugin (like "x86" or "arm", iykyk) and set the bitness with r_anal_set_bits (anal, 64). And optionally, if you want, you can bind callbacks or a host object β€” the comment notes that core sets a user pointer (r_anal_set_user_ptr) and binds (r_anal_bind). all vibes ✨

πŸ¦‹ Analyzing a single instruction

/* Analyze a single instruction (typical loop uses r_anal_op repeatedly) */
unsigned char buf[64];
RAnalOp op;
r_anal_op_init (&op);
int n = anal->iob.read_at (anal->iob.io, 0x1000, buf, sizeof (buf));
if (n > 0 && r_anal_op (anal, &op, 0x1000, buf, n, R_ANAL_OP_MASK_BASIC) > 0) {
    /* inspect op.size, op.type, op.jump, op.fail, op.mnemonic, op.esil, ... */
}
r_anal_op_fini (&op);

this one's the main-character move 🫢 you grab a RAnalOp, r_anal_op_init it, read the bytes at 0x1000 into buf, and if the read actually returned something and r_anal_op came back > 0, you can go peek at op.size, op.type, op.jump, op.fail, op.mnemonic, op.esil, and friends. then r_anal_op_fini to clean up, because we're respectful like that πŸ’… (and yes, the typical loop calls r_anal_op over and over, no cap.)

πŸ’– Registering (declaring) a function

/* Register (declare) a function vs. finding a function that contains an address */
RAnalFunction *decl = r_anal_create_function (anal, "sym_main", 0x401000,
    R_ANAL_FCN_TYPE_SYM, NULL); /* registers a function entry (not a full recover) */

RAnalFunction *f = r_anal_get_fcn_in (anal, 0x401123, 0); /* lookup containing function */

not me needing to point this out β€” there's a difference here bestie, and it matters. r_anal_create_function registers (declares) a function: name "sym_main", address 0x401000, type R_ANAL_FCN_TYPE_SYM, and NULL for the last arg. but heads up, the comment is clear: that registers a function entry, it is not a full recovery πŸ“ Meanwhile r_anal_get_fcn_in is the lookup β€” it finds the function that contains an address (0x401123 here, with 0 as the last arg). two completely different energies.

πŸ”₯ Walking a function range & recording xrefs

/* Walk a function range, record xrefs discovered while decoding instructions */
RAnalOp aop;
r_anal_op_init (&aop);
for (ut64 pc = f->addr; pc < r_anal_function_max_addr (f); pc += aop.size) {
    int len = anal->iob.read_at (anal->iob.io, pc, buf, sizeof (buf));
    if (r_anal_op (anal, &aop, pc, buf, len, R_ANAL_OP_MASK_BASIC) < 1) {
        break;
    }
    if (aop.jump != UT64_MAX) {
        r_anal_xrefs_set (anal, pc, aop.jump, R_ANAL_REF_TYPE_CALL);
    }
}
r_anal_op_fini (&aop);

this loop literally walks the function's range, stepping by aop.size each time, from f->addr up to r_anal_function_max_addr (f) πŸ‘‘ At each pc it reads into buf, and if r_anal_op returns < 1 it bails. Otherwise, if aop.jump != UT64_MAX, it records the xref with r_anal_xrefs_set (anal, pc, aop.jump, R_ANAL_REF_TYPE_CALL) β€” discovering xrefs right there while decoding. so slay. then r_anal_op_fini (&aop) because again, we clean up 🌸

πŸ’œ Local variables + comment metadata

/* Set a local variable for a function and add a comment metadata entry */
r_anal_function_set_var (f, -8, 'b', "int", 4, false, "local_var");
r_meta_set (anal, R_META_TYPE_COMMENT, f->addr, 0, "Recovered function entry");

two lines, two vibes: r_anal_function_set_var sets a local variable on the function (-8, 'b', "int", 4, false, "local_var"), and r_meta_set drops a metadata entry β€” specifically an R_META_TYPE_COMMENT at f->addr with size 0 and the text "Recovered function entry" πŸŽ€

🧚 ESIL usage

/* ESIL usage: ESIL emulation/parsing is provided by libr/esil; r_anal exposes an
 * `esil` instance on the analyzer but evaluation uses r_esil_* helpers. */
/* Example: parse an ESIL expression into the ESIL VM attached to the analyzer */
/* r_esil_parse (anal->esil, "rax,8,+,rbx,="); */

ngl this is the part where people get confused, so let's be so clear: ESIL emulation and parsing is provided by libr/esil. r_anal exposes an esil instance on the analyzer, but the actual evaluation happens through the r_esil_* helpers. the example, which is commented out, shows parsing an ESIL expression into the ESIL VM attached to the analyzer:

r_esil_parse (anal->esil, "rax,8,+,rbx,=");

that's the vibe. ESIL lives elsewhere, r_anal just holds the handle πŸ’«


πŸ¦‹ SEE ALSO πŸ¦‹


and that's a wrap on R_ANAL(3), bestie 🫢 this page ships as part of Debian, dated September 20, 2025 β€” go forth and analyze, you absolute icon πŸ‘‘βœ¨

πŸ“¦ where this page comes from