Documentation Index
Fetch the complete documentation index at: https://mintlify.com/angr/angr/llms.txt
Use this file to discover all available pages before exploring further.
The VariableManager plugin manages variables across the entire binary, including local variables, stack variables, registers, and global variables. It provides per-function variable tracking and type information.
VariableManager Class
class VariableManager(KnowledgeBasePlugin):
"""Manages variables across functions and globally."""
Constructor
The knowledge base instance this manager belongs to
Properties
Variable manager for global scope (variables not tied to a specific function)
function_managers
dict[int, VariableManagerInternal]
Dictionary mapping function addresses to their VariableManagerInternal instances
Accessing Variable Managers
The VariableManager acts as a container for function-specific variable managers:
# Access global variable manager
global_vars = kb.variables['global']
# Access function-specific variable manager
func_addr = 0x401000
func_vars = kb.variables[func_addr]
# Check if function has variable manager
if func_addr in kb.variables:
print("Function has variables tracked")
# Access via get_manager (same as dict access)
func_vars = kb.variables.get_manager(func_addr)
VariableManagerInternal
Each function has its own VariableManagerInternal instance that manages variables within that function’s scope.
Properties
Address of the function this manager belongs to (None for global manager)
Type information store for this function’s variables
variable_to_types
dict[SimVariable, SimType]
Mapping from variables to their types
variables_with_manual_types
Set of variables with manually-assigned types
Variable Access
get_variables
func_vars.get_variables(
sort: Literal['stack', 'reg'] | None = None,
collapse_same_ident: bool = False
) -> list[SimVariable]
Get all variables in the function.
Filter by variable type: 'stack' for stack variables, 'reg' for register variables, None for all
Whether to collapse variables with same identifier (not yet implemented)
Returns: List of variables
# Get all variables
all_vars = func_vars.get_variables()
# Get only stack variables
stack_vars = func_vars.get_variables(sort='stack')
# Get only register variables
reg_vars = func_vars.get_variables(sort='reg')
for var in stack_vars:
print(f"Stack var: {var.name} at offset {var.offset}")
get_unified_variables
func_vars.get_unified_variables(
sort: Literal['stack', 'reg'] | None = None
) -> list[SimVariable]
Get unified variables (SSA variables merged into single representations).
Filter by variable type: 'stack', 'reg', or None for all
Returns: List of unified variables
# Get all unified variables
unified = func_vars.get_unified_variables()
# Get unified stack variables
unified_stack = func_vars.get_unified_variables(sort='stack')
for var in unified:
print(f"{var.name}: {var}")
get_global_variables
func_vars.get_global_variables(addr: int) -> set[SimVariable]
Get global variables at a specific address.
Address of the global variable
Returns: Set of variables at that address
Finding Variables
find_variables_by_insn
func_vars.find_variables_by_insn(
ins_addr: int,
sort: Literal['memory', 'register']
) -> list[tuple[SimVariable, int | None]] | None
Find variables accessed at a specific instruction address.
Type of variables to find: 'memory' or 'register'
Returns: List of (variable, offset) tuples, or None if no variables found
# Find memory variables at instruction
mem_vars = func_vars.find_variables_by_insn(0x401234, 'memory')
if mem_vars:
for var, offset in mem_vars:
print(f"{var.name} at offset {offset}")
# Find register variables
reg_vars = func_vars.find_variables_by_insn(0x401234, 'register')
find_variables_by_stmt
func_vars.find_variables_by_stmt(
block_addr: int,
stmt_idx: int,
sort: Literal['memory', 'register', 'constant'],
block_idx: int | None = None
) -> list[tuple[SimVariable, int | None]]
Find variables accessed at a specific statement.
Address of the block containing the statement
Index of the statement within the block
Type: 'memory', 'register', or 'constant'
Optional block index for blocks with same address
Returns: List of (variable, offset) tuples
# Find variables at statement
vars = func_vars.find_variables_by_stmt(0x401000, 5, 'memory')
for var, offset in vars:
print(f"{var.name} ({offset})")
find_variables_by_atom
func_vars.find_variables_by_atom(
block_addr: int,
stmt_idx: int,
atom: ailment.expression.Expression,
block_idx: int | None = None
) -> set[tuple[SimVariable, int | None]]
Find variables represented by a specific AIL atom.
atom
ailment.expression.Expression
required
AIL expression atom to search for
Returns: Set of (variable, offset) tuples
find_variables_by_stack_offset
func_vars.find_variables_by_stack_offset(offset: int) -> set[SimVariable]
Find all variables at a specific stack offset.
# Find variables at stack offset -0x10
vars = func_vars.find_variables_by_stack_offset(-0x10)
for var in vars:
print(f"{var.name}: {var.size} bytes")
find_variables_by_register
func_vars.find_variables_by_register(reg: str | int) -> set[SimVariable]
Find all variables stored in a specific register.
Register name (e.g., 'rax') or register offset
# Find variables in rax
vars = func_vars.find_variables_by_register('rax')
for var in vars:
print(f"{var.name} in rax")
Variable Accesses
get_variable_accesses
func_vars.get_variable_accesses(
variable: SimVariable,
same_name: bool = False
) -> list[VariableAccess]
Get all accesses (reads/writes) to a variable.
If True, include accesses to all variables with the same name
Returns: List of VariableAccess objects
var = stack_vars[0]
accesses = func_vars.get_variable_accesses(var)
for access in accesses:
access_type = 'READ' if access.access_type == VariableAccessSort.READ else 'WRITE'
print(f"{access_type} at {hex(access.location.ins_addr)}")
func_vars.input_variables(exclude_specials: bool = True) -> list[SimVariable]
Get all input variables (variables that are read but never written).
Exclude special variables (like stack pointer)
Returns: List of input variables
# Find function arguments and external inputs
inputs = func_vars.input_variables()
for var in inputs:
print(f"Input: {var.name}")
get_variables_without_writes
func_vars.get_variables_without_writes() -> list[SimVariable]
Get all variables that have never been written to.
Returns: List of variables without write accesses
Variable Recording
write_to / read_from / reference_at
func_vars.write_to(
variable: SimVariable,
offset: int | None,
location: CodeLocation,
overwrite: bool = False,
atom: ailment.expression.Atom | None = None
)
func_vars.read_from(
variable: SimVariable,
offset: int | None,
location: CodeLocation,
overwrite: bool = False,
atom: ailment.expression.Atom | None = None
)
func_vars.reference_at(
variable: SimVariable,
offset: int | None,
location: CodeLocation,
overwrite: bool = False,
atom: ailment.expression.Atom | None = None
)
Record variable accesses. These are typically used internally by analyses.
Offset within the variable
Replace existing accesses at this location
atom
ailment.expression.Atom
default:"None"
AIL atom representing this access
Type Management
set_variable_type
func_vars.set_variable_type(
var: SimVariable,
ty: SimType,
name: str | None = None,
override_bot: bool = True,
all_unified: bool = False,
mark_manual: bool = False
) -> None
Set the type of a variable.
Optional type name for named types
Replace bottom types with default integer types
Apply type to all unified variables
Mark as manually set (won’t be overridden by analysis)
from angr.sim_type import SimTypeInt, SimTypePointer
# Set variable type to int
var = stack_vars[0]
func_vars.set_variable_type(var, SimTypeInt())
# Set pointer type
ptr_type = SimTypePointer(SimTypeInt())
func_vars.set_variable_type(var, ptr_type, mark_manual=True)
# Apply to all unified variables
func_vars.set_variable_type(var, SimTypeInt(), all_unified=True)
get_variable_type
func_vars.get_variable_type(var: SimVariable) -> SimType | None
Get the type of a variable.
Returns: SimType instance or None if no type is set
var_type = func_vars.get_variable_type(var)
if var_type:
print(f"{var.name} has type: {var_type}")
remove_types
func_vars.remove_types() -> None
Clear all type information.
Phi Variables
Phi variables represent merged SSA variables at control flow join points.
make_phi_node
func_vars.make_phi_node(
block_addr: int,
*variables: SimVariable
) -> SimVariable
Create or get a phi variable for the given variables at a block.
Address of the block where phi occurs
Returns: The phi variable
is_phi_variable
func_vars.is_phi_variable(var: SimVariable) -> bool
Check if a variable is a phi variable.
get_phi_subvariables
func_vars.get_phi_subvariables(var: SimVariable) -> set[SimVariable]
Get the sub-variables that a phi variable represents.
if func_vars.is_phi_variable(var):
subvars = func_vars.get_phi_subvariables(var)
print(f"Phi variable {var.name} merges:")
for subvar in subvars:
print(f" - {subvar.name}")
get_phi_variables
func_vars.get_phi_variables(block_addr: int) -> dict[SimVariable, set[SimVariable]]
Get all phi variables at a block.
Returns: Dictionary mapping phi variables to their sub-variables
Variable Unification
unify_variables
func_vars.unify_variables(
interference: networkx.Graph[int] | None = None
) -> None
Unify SSA variables into single representations based on phi nodes and interference.
interference
networkx.Graph[int]
default:"None"
Variable interference graph
unified_variable
func_vars.unified_variable(variable: SimVariable) -> SimVariable | None
Get the unified variable for an SSA variable.
ssa_var = stack_vars[0]
unified = func_vars.unified_variable(ssa_var)
if unified:
print(f"{ssa_var.name} unifies to {unified.name}")
set_unified_variable
func_vars.set_unified_variable(
variable: SimVariable,
unified: SimVariable
) -> None
Manually set the unified variable for an SSA variable.
Variable Naming
assign_variable_names
func_vars.assign_variable_names(
labels: dict | None = None,
types: list[type] | None = None
) -> None
Assign default names to all variables.
Known labels in the binary
Variable types to name (None for all)
# Assign default names to all variables
func_vars.assign_variable_names()
# Only assign names to stack variables
from angr.sim_variable import SimStackVariable
func_vars.assign_variable_names(types=[SimStackVariable])
assign_unified_variable_names
func_vars.assign_unified_variable_names(
labels: dict | None = None,
arg_names: list[str] | None = None,
reset: bool = False,
func_blocks: list[ailment.Block] | None = None
) -> None
Assign names to unified variables.
func_blocks
list[ailment.Block]
default:"None"
Function blocks for optimization
# Assign names with custom argument names
func_vars.assign_unified_variable_names(
arg_names=['argc', 'argv', 'envp']
)
Usage Examples
Basic Variable Analysis
# Get function variable manager
func = kb.functions[0x401000]
var_mgr = kb.variables[func.addr]
# Analyze stack variables
stack_vars = var_mgr.get_variables(sort='stack')
print(f"Found {len(stack_vars)} stack variables")
for var in stack_vars:
accesses = var_mgr.get_variable_accesses(var)
reads = sum(1 for a in accesses if a.access_type == VariableAccessSort.READ)
writes = sum(1 for a in accesses if a.access_type == VariableAccessSort.WRITE)
print(f"{var.name}: {reads} reads, {writes} writes")
Type Assignment
from angr.sim_type import SimTypeInt, SimTypePointer, SimTypeChar
var_mgr = kb.variables[0x401000]
# Assign types to arguments
args = [v for v in var_mgr.get_variables() if v.ident.startswith('arg_')]
if len(args) >= 2:
# argc: int
var_mgr.set_variable_type(args[0], SimTypeInt(), mark_manual=True)
# argv: char**
var_mgr.set_variable_type(
args[1],
SimTypePointer(SimTypePointer(SimTypeChar())),
mark_manual=True
)
func_addr = 0x401000
var_mgr = kb.variables[func_addr]
# Get input variables (likely function arguments)
input_vars = var_mgr.input_variables()
print(f"Function {hex(func_addr)} has {len(input_vars)} inputs:")
for var in input_vars:
var_type = var_mgr.get_variable_type(var)
type_str = str(var_type) if var_type else 'unknown'
print(f" {var.name} ({type_str})")
VariableType Constants
class VariableType:
REGISTER = 0
MEMORY = 1
These constants are used in some methods for filtering variable types.