angr.analyses.decompiler.known_patterns

Known code patterns: context-aware, declarative descriptions of library/macro idioms that compilers inline, plus machinery (KnownPatternFinder) to find them in Clinic AIL graphs and outline them back into calls.

Each idiom is defined once as a KnownPatternTemplate that instantiates itself into a concrete KnownPattern for the target’s PatternContext (architecture / platform / C++ runtime), so a single definition covers 32- and 64-bit, libstdc++ and MSVC, etc.

class angr.analyses.decompiler.known_patterns.PITE

Bases: PatternExpr

Matches an ITE (ternary) expression cond ? iftrue : iffalse.

Needed because ITERegionConverter (AFTER_GLOBAL_SIMPLIFICATION) collapses if (c) x = a; else x = b; diamonds into a single ITE assignment before the KnownPatternOutliner runs, so a two-armed value-select idiom reaches the outliner as an expression, not as a PGraphPat region. (A triangle, with one arm empty as in the MSVC std::string::c_str SSO select, is not converted, which is why that idiom is still a PGraphPat.)

cond: PatternExpr
iftrue: PatternExpr
iffalse: PatternExpr
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(cond, iftrue, iffalse, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.AllOf

Bases: PatternGate

Opens when every sub-gate opens.

gates: tuple[PatternGate, ...]
opens(gctx)
Return type:

bool

Parameters:

gctx (GateContext)

property requires_evidence: bool

Whether this gate can only be decided once the function’s matches are known. Such gates are evaluated a second time by the finder.

property label: str
__init__(gates=<factory>)
Parameters:

gates (tuple[PatternGate, ...])

Return type:

None

class angr.analyses.decompiler.known_patterns.AnyOf

Bases: PatternGate

Opens when any sub-gate opens.

gates: tuple[PatternGate, ...]
opens(gctx)
Return type:

bool

Parameters:

gctx (GateContext)

property requires_evidence: bool

Whether this gate can only be decided once the function’s matches are known. Such gates are evaluated a second time by the finder.

property label: str
__init__(gates=<factory>)
Parameters:

gates (tuple[PatternGate, ...])

Return type:

None

class angr.analyses.decompiler.known_patterns.CorroboratedBy

Bases: PatternGate

Opens in a function where at least one of witnesses already matched.

Witnesses are given as template ``name``s or ``call_name``s; the finder puts both spellings of every established pattern into the evidence set.

witnesses: frozenset[str]
opens(gctx)
Return type:

bool

Parameters:

gctx (GateContext)

property requires_evidence: bool

Whether this gate can only be decided once the function’s matches are known. Such gates are evaluated a second time by the finder.

property label: str
__init__(witnesses)
Parameters:

witnesses (frozenset[str])

Return type:

None

class angr.analyses.decompiler.known_patterns.CppRef

Bases: object

A reference to a C++ class type registered in the cpp::std SimTypeCollection, keyed by its unique (mangled-style) name.

unique_name: str
ptr: bool = True
resolve(arch)
Return type:

SimType | None

Parameters:

arch (Arch)

__init__(unique_name, ptr=True)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.GateContext

Bases: object

Everything a gate may look at.

Variables:
  • ctx – The target’s PatternContext (arch, platform, C++ runtime, and the binary-evidence facts).

  • project – The Project, for gates that need to look past the context.

  • evidence – Names and call names of the patterns established in the function currently being matched: both the patterns that matched in the first stage and the known-pattern calls already present in the graph (outlined by an earlier round). Empty when gates are evaluated outside a function.

ctx: PatternContext
project: Project | None = None
evidence: frozenset[str] = frozenset({})
with_evidence(evidence)
Return type:

GateContext

Parameters:

evidence (Iterable[str])

__init__(ctx, project=None, evidence=frozenset({}))
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.KnownPattern

Bases: object

A known code idiom, described declaratively.

Variables:
  • name – Identifier, e.g. "std_string_length".

  • display_name – Human-readable name, e.g. "std::string::length".

  • call_name – Target name of the synthesized Call.

  • pattern – The structural pattern to match.

  • params – Ordered parameters; their captures become the call arguments, in order.

  • returnty – Return type of the synthesized call.

  • returnty_factory – Optional callable building a call-site-specific return type from the values of the constant extra_args captures (e.g. CONTAINING_RECORD returns a pointer to a record whose layout depends on the matched field offset). Falls back to returnty when it returns None or when the constant values are unavailable.

  • extra_args – Names of (typically constant) captures appended to the call arguments after params.

  • arches – Allowed archinfo.Arch.name values; None = any.

  • platforms – Allowed OS names (project.simos.name, lowercased); None = any.

  • where – Optional cross-capture predicate evaluated on the bindings after a structural match.

  • collapse_capture – Optional capture name identifying the idiom that a match belongs to: within one function, matches binding it to the same virtual variable all describe one source-level idiom, and only the one with the largest collapse_max_capture constant is kept. The compiler folds CONTAINING_RECORD’s subtraction into every field displacement, so one source idiom otherwise emits a call per field, each naming a different (and mostly wrong) record base.

  • collapse_max_capture – Capture whose constant value orders the collapsing; required when collapse_capture is set.

  • binary_guard – Optional predicate on the Project; the pattern is only used when it returns True (e.g. require C++ evidence for STL patterns to avoid false positives on plain C binaries).

  • default_enabled – Whether the pattern is used when the caller does not explicitly select patterns. Generic patterns prone to false positives should set this False.

name: str
display_name: str
call_name: str
pattern: PatternExpr | PatternStmt | PGraphPat
params: tuple[PatternParam, ...]
returnty: str | CppRef | None = None
returnty_factory: Callable[[Arch, dict[str, int]], SimType | None] | None = None
extra_args: tuple[str, ...] = ()
arches: tuple[str, ...] | None = None
platforms: tuple[str, ...] | None = None
where: Callable[[dict[str, Expression]], bool] | None = None
collapse_capture: str | None = None
collapse_max_capture: str | None = None
binary_guard: Callable[[Project], bool] | None = None
default_enabled: bool = True
suppressed_by: tuple[str, str, str] | None = None

Drop a match of this pattern when a pattern whose name matches the regex matched on the same object: (name regex, my capture, their capture). The two captures must bind .likes()-equal expressions. This is how a generic accessor yields to a specific one on the same base: a bare Load(s + 8) is std::string::length on a string and _M_finish on a vector, and the vector’s other fields say which. Judged against every match of the suppressing family, selected or not, so it cannot interact with largest-match selection.

claims_only: bool = False

Match only to claim a base for suppressed_by purposes; never outlined, never rewritten, never reported. For shapes that identify an object beyond doubt but are not worth naming: a vector’s capacity check says “this is a vector” and nothing a reader wants a call for.

pure_calls: frozenset[str] = frozenset({})

Callees this pattern reads through PCallResult whose only effect is their result: once the pattern has consumed that result and nothing else does, the call goes too. Naming a callee in a pattern is already a claim about what it computes; this is the claim that it computes nothing else. __ctype_b_loc returns a table pointer, and a bare __ctype_b_loc(); left behind after isspace(c) is noise.

applicable(arch_name, platform)
Return type:

bool

Parameters:
  • arch_name (str)

  • platform (str | None)

const_args_of_call(call)

Recover the extra_args constant values from a synthesized call’s trailing arguments. Returns None when the call does not carry them.

Return type:

dict[str, int] | None

Parameters:

call (Call)

prototype(arch, const_args=None)

Build the synthesized call’s prototype. const_args (the values of the constant extra_args captures, see const_args_of_call()) enables call-site-specific return types via returnty_factory. Returns None if any declared type fails to resolve.

Return type:

SimTypeFunction | None

Parameters:
__init__(name, display_name, call_name, pattern, params, returnty=None, returnty_factory=None, extra_args=(), arches=None, platforms=None, where=None, collapse_capture=None, collapse_max_capture=None, binary_guard=None, default_enabled=True, suppressed_by=None, claims_only=False, pure_calls=frozenset({}))
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.KnownPatternFinder

Bases: Analysis

Finds occurrences of KnownPatterns in a Clinic AIL graph.

The graph to match on is the final (SSA-form) Clinic graph, i.e. decompiler.ail_graph / clinic.cc_graph. Matches are reported in self.matches; outline() turns a match into a synthesized call by invoking the Outliner analysis on a copy of the graph.

MAX_REMOTE_CHASE_DEPTH = 6
__init__(func, ail_graph, patterns=None, chase_defs=True, chase_remote_defs=True, skip_conversions=True, vvar_id_start=48879, block_addr_start=2864381952, ail_manager=None, force_patterns=None)

patterns may be pattern templates (KnownPatternTemplate) and/or already-concrete KnownPatterns; templates are instantiated for this binary’s PatternContext. When None, the registry is used, filtered down to the templates that are enabled for this target: default-on ones, ones named by force_patterns, and ones whose gate opens (see gating).

force_patterns is the user’s force-enable selection, "all" or an iterable of template names / call names, and is only consulted when patterns is None (an explicit pattern list is already a selection).

Parameters:
matches: list[KnownPatternMatch]
call_target_names(call)

Public face of _resolve_call_target(), for the outliner’s clean-up of calls a pattern declared pure.

Return type:

frozenset[str]

Parameters:

call (Call)

apply_matches(matches, ail_graph)

Apply as many of matches as possible, batching where it matters.

Applying one match at a time is fine until several of them interleave in one block, which is exactly what consecutive field swaps do:

t1 = x->b; t2 = y->b; y->b = t1; x->b = t2;

^ the next field’s load sits in this one’s gap

Rewrite the first and the second’s statements have moved; rewrite it anyway and the third now has an opaque call sitting in its gap, which no disjointness test will let it move across. So the void statement-span matches of a block, which the finder has already checked do not conflict, are spliced in together, against the statement indices they were found at. Everything else keeps the one-at-a-time path.

Returns the new graph and the ids of the matches that were applied.

Return type:

tuple[DiGraph, set[int]]

Parameters:
outline(match, ail_graph=None)

Outline one match: split the anchor block so the matched span forms its own block, invoke the Outliner analysis on it, and rewrite the synthesized callsite into the pattern’s call. Operates on (and returns) a copy; neither self._graph nor ail_graph is mutated.

Return type:

OutlineResult

Parameters:
MAX_LIFTED_EXPR_NODES = 8

Node budget for a lifted parameter expression; see _is_liftable.

outline_at(location, pattern, ail_graph)

Find pattern at location ((block_addr, block_idx) or (block_addr, block_idx, stmt_idx)) in ail_graph and outline it.

Return type:

OutlineResult

Parameters:
class angr.analyses.decompiler.known_patterns.KnownPatternMatch

Bases: object

One occurrence of a KnownPattern in an AIL graph.

For expression-level matches, the boundary is consumed_stmt_idxs (statements wholly owned by the match, e.g. chased definitions) plus expr_path (the location of the matched sub-expression inside the anchor statement). For statement-sequence matches, stmt_span holds the ordered matched statement indices (the anchor is the first) and matched_expr is None.

duplicated_stmt_idxs holds chased definitions that are copied into the outlined region instead of moved: the originals stay where they are (other code still uses them) and the copies make the pattern’s captured values the region’s live-ins. It is always disjoint from consumed_stmt_idxs.

recomputed_defs does the same for definitions that live in another block (a CSE’d value, possibly reaching the anchor through a phi): the expression is pure, so the region recomputes it from the captured operands.

pattern: KnownPattern
block_loc: tuple[int, int | None]
anchor_stmt_idx: int
expr_path: tuple[tuple[str, int | None], ...]
consumed_stmt_idxs: frozenset[int]
captures: dict[str, Expression]
matched_expr: Expression | None
duplicated_stmt_idxs: frozenset[int] = frozenset({})
recomputed_defs: tuple[tuple[int, Expression], ...] = ()
base_aliases: tuple[tuple[int, int, int], ...] = ()
stmt_span: tuple[int, ...] | None = None
block_map: dict[str, tuple[int, int | None]] | None = None
consumed_by_block: dict[tuple[int, int | None], frozenset[int]] | None = None
frontier_locs: frozenset[tuple[int, int | None]] | None = None
__init__(pattern, block_loc, anchor_stmt_idx, expr_path, consumed_stmt_idxs, captures, matched_expr, duplicated_stmt_idxs=frozenset({}), recomputed_defs=(), base_aliases=(), stmt_span=None, block_map=None, consumed_by_block=None, frontier_locs=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.KnownPatternTemplate

Bases: object

A context-aware pattern definition.

Variables:
  • call_name – The synthesized call name (unique across templates).

  • buildbuild(ctx) -> KnownPattern | None; emits the concrete pattern for ctx (None if it cannot).

  • arches – Allowed Arch.name values; None = any.

  • languages – Allowed languages ({“c”,”cpp”}); None = any.

  • runtimes – Allowed C++ runtimes ({“libstdcxx”,”msvc”}); None = any.

  • platforms – Allowed platforms ({“linux”,”windows”}); None = any.

  • default_enabled – Whether the template is used when the caller does not explicitly select patterns.

  • gate – Optional PatternGate that turns an opt-in template on for targets (or functions) where the evidence says the idiom is real; see gating. A gate can only open a template, never close a default-on one.

call_name: str
build: Callable[[PatternContext], KnownPattern | None]
arches: frozenset[str] | None = None
languages: frozenset[str] | None = None
runtimes: frozenset[str] | None = None
platforms: frozenset[str] | None = None
default_enabled: bool = False
name: str = ''
gate: PatternGate | None = None
enabled_for(gate_ctx)
Return type:

bool

Parameters:

gate_ctx (GateContext)

applicable(ctx)
Return type:

bool

Parameters:

ctx (PatternContext)

instantiate(ctx)

The concrete pattern for ctx, or None if this template does not apply there. Memoized: a KnownPattern is a frozen tree that depends on nothing but the context, and callers treat it read-only.

Return type:

KnownPattern | None

Parameters:

ctx (PatternContext)

__init__(call_name, build, arches=None, languages=None, runtimes=None, platforms=None, default_enabled=False, name='', gate=None, _cache=<factory>)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.OutlineResult

Bases: object

The outcome of outlining one KnownPatternMatch.

graph: DiGraph
match: KnownPatternMatch
call_stmt: Statement
child_func: Function | None
child_graph: DiGraph | None
child_funcargs: list[VirtualVariable]
__init__(graph, match, call_stmt, child_func, child_graph, child_funcargs)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PAny

Bases: PatternExpr

Matches any expression.

name: str | None = None
bits: int | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(name=None, bits=None)
Parameters:
  • name (str | None)

  • bits (int | None)

Return type:

None

class angr.analyses.decompiler.known_patterns.PAssign

Bases: PatternStmt

Matches an Assignment statement.

dst: PatternExpr
src: PatternExpr
match(stmt, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(dst, src)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PBinOp

Bases: PatternExpr

Matches a BinaryOp. op may be a single op string or a set of acceptable ops. Commutative ops try both operand orders unless commutative is explicitly False.

op: str | frozenset[str]
operands: tuple[PatternExpr, PatternExpr]
commutative: bool | None = None
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(op, operands, commutative=None, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PBlockPat

Bases: PatternNode

A labeled block of statements in a multi-block pattern graph. An empty stmts sequence matches any block (structure alone identifies it).

label: str
stmts: PStmtSeq
__init__(label, stmts)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PCall

Bases: PatternExpr

Matches a Call whose callee is one of names.

The callee is what makes a pattern containing this node self-guarding: an idiom spelled around a named runtime function (operator delete in the std::string destructor, __ctype_b_loc in isspace) cannot be confused with arithmetic that happens to look alike, because no other code calls that function to do something else.

names is matched against every spelling the callee is known by (the raw symbol and its demangled form), so a pattern may name either. Prefer the mangled spelling: it is exact, while a demangled one carries the argument list and varies with the demangler.

args=None leaves the arguments unconstrained; a tuple constrains them positionally, with None in a slot meaning “any expression”.

names: frozenset[str]
args: tuple[PatternExpr | None, ...] | None = None
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(names, args=None, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PCallResult

Bases: PatternExpr

The value a call to one of names returned.

A call’s result is rarely used where it is produced: the compiler assigns it to a register and reads that register, often in another block. __ctype_b_loc() is called once per function and its table indexed at every predicate. So this node matches the virtual variable and looks up its definition read-only. Nothing is consumed, moved or recomputed; the call stays where the compiler put it.

An inline Call expression is matched too, for the case where the value is used at its definition.

names: frozenset[str]
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(names, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PCallStmt

Bases: PatternStmt

Matches a statement whose effect is a call.

Ailment has no Call statement: a call whose result is discarded is a SideEffectStatement wrapping the Call expression, and one whose result is kept is an ordinary Assignment. Both spellings are the same idiom, so both match; dst, when given, also constrains the assigned destination, which requires the assignment form.

call: PCall
dst: PatternExpr | None = None
match(stmt, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(call, dst=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PChoice

Bases: PatternExpr

Ordered alternation: matches the first alternative that succeeds.

alternatives: tuple[PatternExpr, ...]
__init__(*alternatives)
Parameters:

alternatives (PatternExpr)

match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
class angr.analyses.decompiler.known_patterns.PCondJump

Bases: PatternStmt

Matches a ConditionalJump, matching its condition expression.

condition: PatternExpr
match(stmt, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(condition)
Parameters:

condition (PatternExpr)

Return type:

None

class angr.analyses.decompiler.known_patterns.PConst

Bases: PatternExpr

Matches a Const, by exact value or by predicate. Width is ignored unless bits is given (e.g. shift amounts are often 8-bit).

value: int | None = None
pred: Callable[[int], bool] | None = None
bits: int | None = None
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(value=None, pred=None, bits=None, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PConv

Bases: PatternExpr

Matches a Convert explicitly (never skipped).

operand: PatternExpr
from_bits: int | None = None
to_bits: int | None = None
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(operand, from_bits=None, to_bits=None, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PDefOf

Bases: PatternExpr

inner, or a virtual variable whose reaching definition is inner.

The compiler is free to compute a value once and use it twice, and it does so exactly where an idiom uses one value twice. if (_M_p != &_M_local_buf) operator delete(_M_p, ...) reads _M_p in the compare and in the call, so gcc loads it into a register and the pattern sees Load(s) in neither place; it sees the same virtual variable in both.

Reading that variable’s definition is read-only. Nothing is consumed, moved or recomputed, and the identification stays accurate even if memory changes afterwards: the variable holds what the load produced at the definition, which is what the idiom meant. That is why this is not peek_fn, whose contract (“can be recomputed at the use”) a load cannot satisfy.

The unconsumed definition is left where it was, so a region that matches through this node keeps it as residue. That is harmless, and dead-code elimination removes it once the idiom’s other uses are gone.

inner: PatternExpr
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(inner, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PExtract

Bases: PatternExpr

Matches an Extract, a bit-slice of a wider value.

This is how a scalar reaches integer code out of a vector register when the 128-bit op did not get narrowed away: movq %xmm2,%rax on a value that came from maxsd/mulsd lifts to Extract(vvar_128, 64bits@0) rather than to a Convert. Without a node for it, every libm bit-twiddle whose operand is a computed double rather than an incoming argument is unmatchable.

bits/offset default to unconstrained; offset is in bits.

operand: PatternExpr
bits: int | None = None
offset: int | None = None
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(operand, bits=None, offset=None, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PField

Bases: PatternExpr

The address of the field at offset inside the object bound to base.

Spelling a container’s fields as PLoad(PVVar("v")) / PLoad(PVVar("v") + 8) requires the object to sit at the very address held in a virtual variable. That is the minority case: measured over the benchmark corpus, only 10-25% of the DWARF sites for a std::vector accessor read the container through a bare pointer; the rest reach it as a field of something else (this->tokens.size()), which lifts to Load(this + 56) / Load(this + 64) and cannot bind v at all.

PField matches such an address and binds base to the object’s own address: root when the object is at offset 0, else root + K. Two fields of one object therefore unify on K, which is what keeps the node honest: it replaces the constraint “this displacement is exactly 8” with “these two displacements differ by exactly 8”.

Only use it in patterns that reference at least two fields. With a single field there is no second displacement to constrain, so PLoad(PField("s", 8)) degenerates into “any load through a pointer plus a non-negative constant” and matches essentially everything.

root must be a virtual variable: the outliner materializes tmp = root + K ahead of the region so the synthesized call still takes a variable.

base: str
offset: int
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(base, offset, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PGraphPat

Bases: PatternNode

A multi-block pattern: labeled blocks connected by edges.

blocks maps a label to its PBlockPat. edges are (src_label, dst_label) pairs; a destination label that does not appear in blocks denotes an external successor, a region exit that becomes the Outliner frontier. entry is the label of the single entry block. Captures unify across all blocks (one bindings environment).

blocks: dict[str, PBlockPat]
edges: Sequence[tuple[str, str]]
entry: str
property external_labels: set[str]
__init__(blocks, edges, entry)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PLoad

Bases: PatternExpr

Matches a memory Load. size is in bytes.

addr: PatternExpr
size: int | None = None
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(addr, size=None, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PPhi

Bases: PatternExpr

Matches a Phi expression, capturing it whole (its individual sources are not matched). Useful for loop-header blocks, whose statements are phi assignments.

name: str | None = None
bits: int | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(name=None, bits=None)
Parameters:
  • name (str | None)

  • bits (int | None)

Return type:

None

class angr.analyses.decompiler.known_patterns.PStackField

Bases: PatternExpr

A field of a container that lives on the stack.

A stack object never reaches the matcher as an object at all: variable recovery has already split it into one virtual variable per slot, so std::string s; is a handful of independent vvar{s-112}, vvar{s-96} and there is no Load(s) to match and no s + 16 to compare against. Measured over the benchmark corpus (kp-eval/stack_share.py), stack objects are 40-54% of the DWARF sites for std::string::length and 15-35% for std::vector<T>::size.

This node matches the slot of the field at offset and binds base to the object’s own stack offset, so two fields of one object unify on it exactly as PField’s two displacements do. as_address matches the address form (&slot, which lifts to UnaryOp("Reference", vvar)) rather than the value form; std::string::capacity needs both, since it compares the data pointer against the address of the local buffer.

The binding is a StackBaseOffset, the object’s own address. That is both the thing two fields must agree on and, directly, the argument the synthesized call takes, so nothing has to be materialized for it.

Matching is only half the problem, and the other half is why a pattern using this node is never outlined: the region for a stack container reads N independent slots, so its live-ins are N values rather than one pointer and there is nothing for a synthesized callee to take. Such a match is instead rewritten in place: the matched expression, or the whole region, is replaced by call(&s), whose argument the binding already is. See KnownPatternFinder._rewrite_in_place and _rewrite_graph_in_place.

base: str
offset: int
as_address: bool = False
size: int | None = None
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(base, offset, as_address=False, size=None, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PStmtSeq

Bases: PatternStmt

Matches a group of statements within one block. When ordered (the default), the statement patterns must match in order; with allow_gaps, unrelated statements may sit between the matched ones. When ordered is False, the statement patterns match statements of the block in any order (each pattern to a distinct statement), which suits idioms whose statement order the compiler chooses freely (e.g. list-link stores).

stmts: tuple[PatternStmt, ...]
allow_gaps: bool = True
ordered: bool = True
max_gap: int = 8

How many unmatched statements may sit between two matched ones. Without a bound the scan runs to the end of the block from every statement it could start at, quadratic per block per template, and finds nothing: an idiom’s statements are adjacent apart from what the scheduler interleaved, which is a handful of instructions rather than a basic block.

__init__(stmts, allow_gaps=True, ordered=True, max_gap=8)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PStore

Bases: PatternStmt

Matches a Store statement. size is in bytes.

addr: PatternExpr
value: PatternExpr
size: int | None = None
match(stmt, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(addr, value, size=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PUnaryOp

Bases: PatternExpr

Matches a UnaryOp.

op: str | frozenset[str]
operand: PatternExpr
name: str | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(op, operand, name=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.PVVar

Bases: PatternExpr

Matches a VirtualVariable.

name: str | None = None
bits: int | None = None
categories: frozenset[VirtualVariableCategory] | None = None
match(expr, state, ctx)
Return type:

MatchState | None

Parameters:
__init__(name=None, bits=None, categories=None)
Parameters:
  • name (str | None)

  • bits (int | None)

  • categories (frozenset[VirtualVariableCategory] | None)

Return type:

None

class angr.analyses.decompiler.known_patterns.PatternContext

Bases: object

Target facts used to instantiate pattern templates.

The last two fields are binary evidence: facts about what kind of program this is, used by gating to switch whole pattern families on for targets where the idioms are certain to appear and off everywhere else.

arch_name: str
bits: int
ptr_size: int
platform: str | None
cxx_runtime: str | None
is_cpp: bool
is_linux_kernel_object: bool = False
is_windows_kernel_driver: bool = False
classmethod from_project(project)
Return type:

PatternContext

Parameters:

project (Project)

word(n)

Byte offset of the n-th pointer-word field.

Return type:

int

Parameters:

n (int)

property word_size: int

Load size (bytes) of a pointer / size_t field.

property language: str
__init__(arch_name, bits, ptr_size, platform, cxx_runtime, is_cpp, is_linux_kernel_object=False, is_windows_kernel_driver=False)
Parameters:
  • arch_name (str)

  • bits (int)

  • ptr_size (int)

  • platform (str | None)

  • cxx_runtime (str | None)

  • is_cpp (bool)

  • is_linux_kernel_object (bool)

  • is_windows_kernel_driver (bool)

Return type:

None

class angr.analyses.decompiler.known_patterns.PatternGate

Bases: object

Base class for template gates. Instances are callables so that a gate can be used anywhere a Callable[[GateContext], bool] is expected.

opens(gctx)
Return type:

bool

Parameters:

gctx (GateContext)

property requires_evidence: bool

Whether this gate can only be decided once the function’s matches are known. Such gates are evaluated a second time by the finder.

property label: str
__init__()
Return type:

None

exception angr.analyses.decompiler.known_patterns.PatternGenerationError

Bases: Exception

Raised when a selection cannot be turned into a KnownPattern (ambiguous, unsupported, or inconsistent with the given arguments).

class angr.analyses.decompiler.known_patterns.PatternGenerator

Bases: object

Generate a KnownPattern from a text selection in codegen.text.

Parameters:
  • codegen – the Decompiler.codegen (a CStructuredCodeGenerator).

  • ail_graph (DiGraph | None) – the graph the generated pattern will be matched against (Decompiler.ail_graph). Required for multi-block (control-flow-spanning) selections; optional otherwise.

__init__(codegen, ail_graph=None)
Parameters:

ail_graph (DiGraph | None)

vvar_id_at(offset)

The AIL vvar id of the variable rendered at offset, or None.

Return type:

int | None

Parameters:

offset (int)

offset_of(needle, start=0)

Convenience: the offset of needle in the rendered text.

Return type:

int

Parameters:
generate(start_offset, end_offset, call_name, arg_offsets, *, name=None, display_name=None, returnty=None, param_types=None, const_arg_offsets=(), arches=None, platforms=None, binary_guard=None, default_enabled=False)
Return type:

KnownPattern

Parameters:
class angr.analyses.decompiler.known_patterns.PatternParam

Bases: object

One parameter of the synthesized call.

Variables:
  • capture – Name of the pattern capture bound to this parameter.

  • type – Argument type for the synthesized call’s prototype; flows into Typehoon as a per-argument subtype constraint.

  • type_hint – Optional cpp::std unique name emitted as a direct vvar type hint (for by-value captures where the vvar is the object rather than a pointer to it).

capture: str
type: str | CppRef | None = None
type_hint: str | None = None
__init__(capture, type=None, type_hint=None)
Parameters:
Return type:

None

class angr.analyses.decompiler.known_patterns.TargetGate

Bases: PatternGate

Opens when a predicate over the target’s PatternContext holds.

The predicate reads facts that were derived once from the loaded binary, so evaluating it is free and its result is the same for every function.

name: str
predicate: Callable[[PatternContext], bool]
opens(gctx)
Return type:

bool

Parameters:

gctx (GateContext)

property label: str
__init__(name, predicate)
Parameters:
Return type:

None

exception angr.analyses.decompiler.known_patterns.UnknownPatternError

Bases: ValueError

Raised when a pattern selection names a template that is not registered.

exception angr.analyses.decompiler.known_patterns.UnsupportedOutlineError

Bases: Exception

Raised when a match cannot be safely outlined (e.g. side-effecting statements interleave with the matched span, or the recovered callee interface does not agree with the pattern’s declared parameters).

angr.analyses.decompiler.known_patterns.all_of(*gates)
Return type:

AllOf

Parameters:

gates (PatternGate)

angr.analyses.decompiler.known_patterns.any_of(*gates)
Return type:

AnyOf

Parameters:

gates (PatternGate)

angr.analyses.decompiler.known_patterns.corroborated_by(*witnesses)

A gate that opens in a function where one of witnesses matched.

Return type:

CorroboratedBy

Parameters:

witnesses (str)

angr.analyses.decompiler.known_patterns.exact_div_magic(elt_size, bits)

(shift, magic) of the exact-division-by-elt_size idiom.

Return type:

tuple[int, int]

Parameters:
angr.analyses.decompiler.known_patterns.make_std_vector_size_exactdiv_template(elt_name, elt_size)

A non-power-of-two std::vector<elt_name>::size template.

Parameters:
  • elt_name (str)

  • elt_size (int)

angr.analyses.decompiler.known_patterns.make_std_vector_size_template(elt_name, log2_elt_size)

A power-of-two std::vector<elt_name>::size template.

Parameters:
  • elt_name (str)

  • log2_elt_size (int)

angr.analyses.decompiler.known_patterns.make_template(call_name, build, *, arches=None, languages=None, runtimes=None, platforms=None, default_enabled=False, name='', gate=None)
Return type:

KnownPatternTemplate

Parameters:
angr.analyses.decompiler.known_patterns.partition_templates(gate_ctx, forced=(), templates=None)

Split templates into (enabled, deferred) for one target.

enabled are the templates to match with right away: default-on ones, ones the caller force-enabled, and ones whose gate already opens on target evidence alone. deferred are the ones whose gate needs per-function evidence (see CorroboratedBy) and must be re-evaluated by the finder once the first matching stage has run.

Return type:

tuple[list[KnownPatternTemplate], list[KnownPatternTemplate]]

Parameters:
angr.analyses.decompiler.known_patterns.patterns_for(ctx, templates=None, *, enabled_only=False)

Instantiate the applicable templates for ctx into concrete KnownPatterns. templates defaults to the whole registry; with enabled_only only default-enabled templates are used.

Return type:

list[KnownPattern]

Parameters:
angr.analyses.decompiler.known_patterns.register_pattern_template(template)

Register a KnownPatternTemplate. Call names are unique across templates (the architecture / runtime conditionals live inside each template’s build).

Return type:

None

Parameters:

template (KnownPatternTemplate)

angr.analyses.decompiler.known_patterns.resolve_pattern_selection(selection)

Resolve a user’s force-enable selection into templates.

selection is one of:

  • None / empty: nothing is force-enabled (returns an empty list);

  • "all": every registered template, opt-in ones included;

  • an iterable of template ``name``s and/or ``call_name``s (a comma-separated string is accepted too, for the string-valued decompilation option).

An unrecognized name raises UnknownPatternError rather than silently selecting nothing.

Return type:

list[KnownPatternTemplate]

Parameters:

selection (str | Iterable[str] | None)

Submodules

apply

Apply call-site information (prototypes) for known-pattern calls.

block_split

Utilities for splitting an AIL block into consecutive blocks within a graph.

containing_record

The CONTAINING_RECORD macro (Windows drivers) / container_of (Linux kernel):

context

PatternContext: the architecture / platform / language facts a KnownPattern template needs to instantiate itself for a given binary.

ctype_tables

The glibc ctype macros: isspace, isdigit, .

dsl

Declarative pattern-AST for describing known AIL code idioms (KnownPatterns).

finder

KnownPatternFinder: find occurrences of KnownPatterns in a Clinic AIL graph and outline them into calls via the Outliner analysis.

gating

Criteria gates: per-target (and per-function) enablement for pattern templates.

generator

PatternGenerator: build a KnownPattern from a decompilation text selection.

kernel_err

Linux kernel <linux/err.h> error-pointer idioms.

layouts

Runtime-specific struct layout offsets for the STL container patterns.

libm_bits

libm floating-point bit-twiddling idioms (fabs / -x / copysign / isnan / isinf).

linked_list

Doubly-linked-list idioms shared by Windows LIST_ENTRY (Flink/Blink) and Linux kernel list_head (next/prev): the same two-pointer layout, so one set of templates matches both WDK drivers and kernel/Boost-intrusive code.

pattern

KnownPattern: declarative metadata around a pattern-AST.

posix_macros

Single-expression glibc/POSIX macros that the preprocessor inlines into every caller, so they survive into decompiled output as bare bit arithmetic.

protobuf_hasbits

protobuf has-bits accessors (protoc output for optional fields):

registry

The template registry: every KnownPatternTemplate the package defines, keyed by call name and by human name, plus the helpers that turn a user's selection or a target's gates into the list of templates to match with.

std_string_cstr

Inlined MSVC std::string::c_str() / data(): the small-string optimization (SSO) select.

std_string_dtor

The inlined std::string destructor.

std_string_internals

libstdc++ std::string internals that are not accessors: the SSO test and the two length-setting idioms.

std_string_length

Inlined std::string::length() / size() and empty().

std_swap

Inlined std::swap, the three-move exchange of two memory locations.

std_vector_size

Inlined std::vector<T>::size() and capacity().

stl_accessors2

C++ STL accessors, round two: std::string capacity/back/front and std::vector<T>::back().

stl_containers

C++ STL std::vector accessors beyond size()/capacity(): empty / operator[].

templates

KnownPatternTemplate: a single, context-parameterized definition of an idiom that instantiates itself into a concrete KnownPattern for a target's PatternContext.

vector_claims

Claims-only std::vector fingerprints: shapes that identify a vector beyond doubt but are not worth a call of their own.

vector_math

3-component float vector math (glm / DirectXMath / game-graphics code).

wdk_shared_data

Reads of KUSER_SHARED_DATA, the page Windows maps read-only at the fixed virtual address 0x7FFE0000 in every user-mode process (x86, x64 and ARM64 alike). ntdll, kernel32 and countless drivers read its fields through the SharedUserData macro of ntddk.h/wdm.h, which compiles to a bare load from an absolute constant address::.