angr.analyses.decompiler.edits¶
Knowledge-base edits for decompilation output: renaming, retyping, and commenting.
This layer is deliberately free of any UI or transport dependency so both the headless MCP server and angr-management drive the same code. It is not thread-safe: locking belongs to whoever owns the knowledge base’s lifetime.
- exception angr.analyses.decompiler.edits.AmbiguousFunctionError
Bases:
DecompilationEditErrorMore than one function matches the given name. Renames make this reachable.
- exception angr.analyses.decompiler.edits.DecompilationEditError
Bases:
AngrErrorBase class for every failure raised by the decompilation edit layer.
- class angr.analyses.decompiler.edits.EditHooks
Bases:
ProtocolNotifications fired immediately before each mutation, while the old value is still readable from the knowledge base.
The method set mirrors angr-management’s plugin hooks one-for-one so its adapter is a pure forwarder. Firing before the mutation matches what the GUI’s own edit dialogs do, and is what lets a handler snapshot pre-edit state.
- before_function_renamed(func, old_name, new_name)
- before_stack_var_renamed(func, offset, old_name, new_name)
- before_func_arg_renamed(func, arg_index, old_name, new_name)
- before_global_var_renamed(addr, old_name, new_name)
- before_stack_var_retyped(func, offset, old_type, new_type)
- before_func_arg_retyped(func, arg_index, old_type, new_type)
- before_global_var_retyped(addr, old_type, new_type)
- before_other_var_retyped(var, old_type, new_type)
- Return type:
- Parameters:
var (SimVariable)
old_type (SimType | None)
new_type (SimType)
- before_function_retyped(func, old_proto, new_proto)
- Return type:
- Parameters:
func (Function)
old_proto (SimTypeFunction | None)
new_proto (SimTypeFunction)
- before_comment_changed(addr, old, new, created, decomp)
- __init__(*args, **kwargs)
- class angr.analyses.decompiler.edits.EditResult
Bases:
objectThe outcome of a single edit.
changedis False when the edit was a no-op.- changed: bool
- kind: str
- refresh: Refresh
- exception angr.analyses.decompiler.edits.FunctionNotFoundError
Bases:
DecompilationEditErrorNo function matches the given address or name.
- exception angr.analyses.decompiler.edits.InvalidNameError
Bases:
DecompilationEditErrorThe requested name is not a usable identifier.
- exception angr.analyses.decompiler.edits.NameCollisionError
Bases:
DecompilationEditErrorThe requested name is already bound to a different function, variable, or label.
- exception angr.analyses.decompiler.edits.NotDecompiledError
Bases:
DecompilationEditErrorThe function has no cached decompilation, so there is nothing to edit.
- class angr.analyses.decompiler.edits.NullEditHooks
Bases:
objectA concrete no-op implementation. Subclass it so an adapter only overrides what it needs.
- before_function_renamed(func, old_name, new_name)
- before_stack_var_renamed(func, offset, old_name, new_name)
- before_func_arg_renamed(func, arg_index, old_name, new_name)
- before_global_var_renamed(addr, old_name, new_name)
- before_stack_var_retyped(func, offset, old_type, new_type)
- before_func_arg_retyped(func, arg_index, old_type, new_type)
- before_global_var_retyped(addr, old_type, new_type)
- before_other_var_retyped(var, old_type, new_type)
- Return type:
- Parameters:
var (SimVariable)
old_type (SimType | None)
new_type (SimType)
- before_function_retyped(func, old_proto, new_proto)
- Return type:
- Parameters:
func (Function)
old_proto (SimTypeFunction | None)
new_proto (SimTypeFunction)
- class angr.analyses.decompiler.edits.Refresh
Bases:
objectWhat a caller has to redo after an edit.
Lets a UI pick between re-rendering text, rebuilding the codegen AST, and a full re-decompilation instead of guessing.
text_stale_allmeans every cached decompilation’s rendered text is stale (a function rename changes call sites everywhere), but the caller should re-render lazily: eagerly re-rendering the whole cache would thrash its LRU.- __init__(text_stale=frozenset({}), text_stale_all=False, reanalyze=frozenset({}), redecompile=frozenset({}), function_list_dirty=False, disassembly_dirty=False)
- class angr.analyses.decompiler.edits.ResolvedVariable
Bases:
objectA pseudocode display name resolved to the objects an edit needs.
variableis the concrete/SSA variable thatset_variable_typeexpects;unifiedis the unified variable that a rename mutates (None for globals, which have no unified form).- kind: Literal['argument', 'local', 'global']
- variable: SimVariable
- unified: SimVariable | None
- property storage: str
- detail()
- Return type:
- __init__(kind, variable, unified, cvar=None, arg_index=None, stack_offset=None, global_addr=None, ambiguous=False)
- Parameters:
kind (Literal['argument', 'local', 'global'])
variable (SimVariable)
unified (SimVariable | None)
cvar (CVariable | None)
arg_index (int | None)
stack_offset (int | None)
global_addr (int | None)
ambiguous (bool)
- Return type:
None
- exception angr.analyses.decompiler.edits.TypeParseError
Bases:
DecompilationEditErrorA C type declaration or function signature could not be parsed.
- exception angr.analyses.decompiler.edits.UnsupportedEditError
Bases:
DecompilationEditErrorThe requested edit is not supported for this kind of target.
- exception angr.analyses.decompiler.edits.VariableNotFoundError
Bases:
DecompilationEditErrorNo variable in the decompilation matches the given display name.
candidatescarries the names that are available, so a caller that failed can correct itself without a second round trip.
- angr.analyses.decompiler.edits.concrete_variables(varman, resolved)
Every SSA variable sharing the resolved variable’s unified form.
Retyping applies to all of them. Computed here rather than relying on
set_variable_type(all_unified=True), which silently does nothing when the variable it is handed is not a key in the SSA-to-unified map.- Return type:
- Parameters:
resolved (ResolvedVariable)
- angr.analyses.decompiler.edits.get_cache(kb, func_addr, flavor='pseudocode')
Return the cached decompilation for a function, or None if there is none.
- Return type:
- Parameters:
kb (KnowledgeBase)
func_addr (int)
flavor (str)
- angr.analyses.decompiler.edits.global_variable_at(kb, addr)
The global SimVariable recorded at an address, if variable recovery produced one.
- Parameters:
kb (KnowledgeBase)
addr (int)
- angr.analyses.decompiler.edits.invalidate(kb, func_addr, *, flavors=None, drop_variables=False)
Drop cached decompilations for a function.
- Parameters:
flavors (
Iterable[str] |None) – Flavors to drop; None drops every flavor currently cached. A prototype change must drop all of them, or a non-pseudocode flavor silently retains the old signature.drop_variables (
bool) – Also dropkb.dec_variables[func_addr]. Required for new argument names to take effect, but it discards every rename and manual type for the function – seesnapshot_user_edits().kb (KnowledgeBase)
func_addr (int)
- Return type:
- angr.analyses.decompiler.edits.list_variable_names(codegen, kb=None, func_addr=None)
Every display name addressable in this decompilation, for error messages.
- Return type:
- Parameters:
kb (KnowledgeBase | None)
func_addr (int | None)
- angr.analyses.decompiler.edits.parse_address(value)
Parse an address given as an int or a string. Accepts 0x-prefixed hex and decimal.
- angr.analyses.decompiler.edits.reflow_types(project, func, *, kb=None, flavor='pseudocode', rerender=True)
Re-run type inference over the cached constraints and refresh the rendered code.
Separate from
set_variable_type()so a batch can retype many variables and reflow once; per-variable reflow would re-run Typehoon N times.This is not a re-decompilation: the AST is untouched, so a retype that should change how an access renders (a struct field, an array index) needs a full re-decompilation instead.
- Parameters:
project (Project)
func (Function)
kb (KnowledgeBase | None)
flavor (str)
rerender (bool)
- angr.analyses.decompiler.edits.rename_function(project, func, new_name, *, kb=None, hooks=None, flavor='pseudocode', allow_overwrite=True, strict_names=True, rerender=True)
Rename a function.
Nothing is invalidated: other functions’ cached ASTs reference the same Function object, so only their rendered text goes stale. That is reported through
Refresh.text_stale_allfor the caller to act on lazily.- Return type:
- Parameters:
- angr.analyses.decompiler.edits.rename_global(project, addr, new_name, *, kb=None, hooks=None, allow_overwrite=True, strict_names=True)
Rename a global by address, without needing a function whose decompilation shows it.
- Return type:
- Parameters:
- angr.analyses.decompiler.edits.rename_variable(project, func, variable_name, new_name, *, kb=None, hooks=None, flavor='pseudocode', allow_overwrite=True, strict_names=True, rerender=True, codegen=None)
Rename a local, an argument, or a global as it appears in a function’s decompilation.
Sets
renamedon the variable, without which a later re-decompilation overwrites the name.
- angr.analyses.decompiler.edits.require_cache(kb, func_addr, flavor='pseudocode')
Return the cached decompilation, raising NotDecompiledError if it is missing or empty.
- Return type:
- Parameters:
kb (KnowledgeBase)
func_addr (int)
flavor (str)
- angr.analyses.decompiler.edits.resolve_function(kb, *, address=None, name=None, containing=True)
Find a function by address or by name.
- angr.analyses.decompiler.edits.resolve_variable(kb, func_addr, display_name, *, codegen=None, flavor='pseudocode')
Resolve a name as it appears in the pseudocode to the underlying variable.
Precedence is argument > local > global. A name matching more than one variable within the same bucket resolves deterministically and sets
ambiguous, rather than failing – a batch edit should be able to report the collision and continue.- Return type:
- Parameters:
kb (KnowledgeBase)
func_addr (int)
display_name (str)
flavor (str)
- angr.analyses.decompiler.edits.restore_user_edits(kb, func_addr, snapshot)
Re-apply a
snapshot_user_edits()result after re-decompilation.Best-effort: idents can change across a re-decompile, so the unmatched ones are returned rather than silently dropped.
- angr.analyses.decompiler.edits.set_comment(project, addr, comment, *, kind=None, kb=None, hooks=None, flavor='pseudocode', mirror_to_pseudocode=True, snap=True, rerender=True)
Set the comment at an address, or clear it with an empty string or None.
The comment goes into kb.comments, which the disassembly renders and which the decompiler reads for the function header. Per-statement pseudocode comments live in codegen.stmt_comments instead, so both are written – except at the function entry, where kb.comments is already what the header renders and mirroring would show the comment twice.
kindsets the comment’s display kind; None keeps whatever kind the comment already has. Clearing a comment always clears its kind.- Return type:
- Parameters:
project (Project)
addr (int)
comment (str | None)
kind (CommentKind | None)
kb (KnowledgeBase | None)
hooks (EditHooks | None)
flavor (str)
mirror_to_pseudocode (bool)
snap (bool)
rerender (bool)
- angr.analyses.decompiler.edits.set_function_prototype(project, func, prototype, *, kb=None, hooks=None, flavor='pseudocode', invalidate_cache=True, preserve_user_edits=True, redecompile=False)
Set a function’s prototype.
The function name inside the signature is ignored; use
rename_function()to rename.Dropping kb.dec_variables is what makes new argument names take effect, but it also discards every rename and manual type for the function. Those are snapshotted and, when this function re-decompiles, restored. Otherwise the snapshot is returned in
detail["user_edits"]so a caller that decompiles asynchronously can restore it once its own job finishes.- Return type:
- Parameters:
project (Project)
func (Function)
prototype (str | SimTypeFunction)
kb (KnowledgeBase | None)
hooks (EditHooks | None)
flavor (str)
invalidate_cache (bool)
preserve_user_edits (bool)
redecompile (bool)
- angr.analyses.decompiler.edits.set_global_type(project, addr, c_type, *, kb=None, hooks=None)
Set the type of a global by address.
- Return type:
- Parameters:
- angr.analyses.decompiler.edits.set_variable_type(project, func, variable_name, c_type, *, kb=None, hooks=None, flavor='pseudocode', reflow=True, rerender=True, allow_prototype_change=True, codegen=None)
Change the type of a local, an argument, or a global.
Arguments are retyped by rewriting the function prototype, which requires a re-decompilation – the returned Refresh says so. Pass
allow_prototype_change=Falseto refuse instead.
- angr.analyses.decompiler.edits.snapshot_user_edits(kb, func_addr)
Capture user renames and manual types for a function, keyed by
SimVariable.ident.Used to survive the
dec_variablesdrop that a prototype change requires.
- angr.analyses.decompiler.edits.validate_name(name, *, strict=True)
Reject names that cannot be used as identifiers.
strictrequires a C identifier. Without it only whitespace-free names are required, which still admits things likeint;that render as uncompilable C – so strict is the default.
Submodules