pub struct Context<'str> {
pub shared: Shared<'str>,
pub interfaces: Registry<FunctionId, FunctionInterface<'str>>,
pub bodies: Registry<FunctionId, FunctionBody<'str>>,
}Expand description
The central arena that owns all IR state.
Context is the single source of truth for every value (instructions,
varnodes, literals, blocks, functions), every memory space, and the
bidirectional maps that let you look up values by name or by machine
address.
§Usage
Create a context with Context::new and pass &mut references to a
Builder when constructing IR, or to analysis
passes when transforming it.
use qcode::context::Context;
let ctx = Context::new();
// `ctx.shared.default_space` is the RAM space created by `new`.
let _ram = ctx.shared.default_space;§Lifetime parameter 'str
The 'str lifetime is the lifetime of interned string data used for names
and space identifiers. When names are owned (e.g. generated names), they
are stored as Cow::Owned; when they are borrowed from source data they are
Cow::Borrowed and must outlive the context.
Fields§
Module-shared IR state: everything that is not per-function interface
or body storage (regimes 1–3 of the context-split design — architecture,
interners, module maps, truths). Reached today behind &mut Context;
Context::split() (stage 5b-ii c.2) will hand it out as a frozen
&Shared view while the bodies registry is borrowed mutably.
interfaces: Registry<FunctionId, FunctionInterface<'str>>Per-function interface storage — the caller-reasoning surface (name,
address, kind, external-ness, signature) held in lockstep with
bodies under the same FunctionId space. Never checked
out: a co-checked-out callee answers interface queries from here.
bodies: Registry<FunctionId, FunctionBody<'str>>Per-function body storage. Each function owns its instruction/block/param/
edge arenas; the composite-ID accessors (Context::instruction etc.)
route through here. A checked-out function’s body is moved out of its slot
(leaving an empty body); its interface stays put, so
callers always read the real interface.
Implementations§
Source§impl<'str> Context<'str>
impl<'str> Context<'str>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new, empty context with a single default RAM space.
The default space has a word size of 1 byte and an address size of 8
bytes (suitable for 64-bit architectures). Its SpaceId is stored in
Context::default_space.
Sourcepub fn try_get_space(&self, name: &str) -> Option<SpaceId>
pub fn try_get_space(&self, name: &str) -> Option<SpaceId>
Returns the SpaceId for the named space, or None if it has not
been registered.
Sourcepub fn get_or_make_named_space(&mut self, name: &str) -> SpaceId
pub fn get_or_make_named_space(&mut self, name: &str) -> SpaceId
Resolve a space by name for textual lowering: an already-registered named
space, the default space when its name matches (the default ram space is
not in named_spaces), or a freshly-registered RAM space otherwise. Used
by the canonical load(space:size, ptr) / store(...) lowering.
Sourcepub fn add_space(&mut self, space: Space) -> SpaceId
pub fn add_space(&mut self, space: Space) -> SpaceId
Adds a space to the context, registering its name, and returns its ID.
Sourcepub fn space_count(&self) -> usize
pub fn space_count(&self) -> usize
Returns the number of spaces registered in this context.
pub fn set_primary_entrypoint(&mut self, entrypoint: Option<u64>)
pub fn primary_entrypoint(&self) -> Option<u64>
Sourcepub fn set_ignored_functions(&mut self, addrs: HashSet<u64>)
pub fn set_ignored_functions(&mut self, addrs: HashSet<u64>)
Record the set of function entry addresses whose optimization the user
asked to skip (--ignore). Per-function passes consult
Context::is_function_ignored and skip these functions.
Sourcepub fn ignored_functions(&self) -> &HashSet<u64>
pub fn ignored_functions(&self) -> &HashSet<u64>
The function entry addresses whose optimization is being skipped.
Sourcepub fn is_function_ignored(&self, addr: Option<u64>) -> bool
pub fn is_function_ignored(&self, addr: Option<u64>) -> bool
Whether the function at addr was marked ignored (--ignore). A None
address (synthetic functions with no entry) is never ignored.
Sourcepub fn set_target_os(&mut self, os: TargetOs)
pub fn set_target_os(&mut self, os: TargetOs)
Records the loaded binary’s operating system (set by the loader from the container format).
Sourcepub fn target_os(&self) -> TargetOs
pub fn target_os(&self) -> TargetOs
The loaded binary’s operating system, or TargetOs::Unknown.
Sourcepub fn set_linked_libraries(&mut self, libs: Vec<String>)
pub fn set_linked_libraries(&mut self, libs: Vec<String>)
Records the library names the binary links against (set by the loader
from the container format, or by --assume-libs).
Sourcepub fn linked_libraries(&self) -> &[String]
pub fn linked_libraries(&self) -> &[String]
Library names the loaded binary links against (ELF DT_NEEDED sonames,
PE import DLL names). Empty when unknown.
Sourcepub fn load_spaces(&mut self, spaces: Registry<SpaceId, Space>)
pub fn load_spaces(&mut self, spaces: Registry<SpaceId, Space>)
Replaces the spaces registry wholesale. Intended for initialization from a pre-built spec.
Sourcepub fn mark_protections_known(&mut self)
pub fn mark_protections_known(&mut self)
Mark the binary’s memory protections as established (the
memory_protections pass has run), so executability checks narrow from the
permissive default to the real per-segment flags.
Sourcepub fn protections_known(&self) -> bool
pub fn protections_known(&self) -> bool
Whether the binary’s per-segment protection flags are authoritative.
Sourcepub fn assume_executable(
&mut self,
binary: &dyn BinaryFormat,
addr: u64,
) -> bool
pub fn assume_executable( &mut self, binary: &dyn BinaryFormat, addr: u64, ) -> bool
The lifter’s pre-decode executability gate, modeling executability as a
Proposition::ExecutableMemory. Returns whether addr should be lifted:
- protections not yet established → optimistic default r/x (
true); the binary’s segment flags are not consulted in this case; - protections known and the region is executable →
true; - protections known and the region is non-executable (or unmapped) →
false(skip), recording the proven factExecutableMemory{start, end} = falsefor the whole containing segment of a mapped-but-non-executable target.
The proposition is keyed by the containing segment, not the individual address, so repeated skips in the same non-executable region collapse to a single truth-map entry rather than one per byte.
A known value for the containing region (a proven fact, or a user override seeded as known) wins over the raw segment flags, so the user can force a region executable or non-executable from the Assumptions panel.
Sourcepub fn discover(&mut self, discovery: Discovery) -> bool
pub fn discover(&mut self, discovery: Discovery) -> bool
Record a discovered code address (typed: a new function or a block within
an existing function) for the lift_new_addresses pass to lift.
Sourcepub fn discover_code(&mut self, func_entry: u64, source_block: u64, target: u64)
pub fn discover_code(&mut self, func_entry: u64, source_block: u64, target: u64)
Convenience for the common case: the jump-table pass resolved a branch in
the function at func_entry to target, a block within that function.
source_block is the address of the block ending in the indirect branch,
so the lifter can connect a real CFG edge from it to target in the clean
IR (the resolution is otherwise only reflected in the disposable optimized
clone, which would leave the target an orphan that function-splitting and
reachability cannot follow).
Sourcepub fn drain_discoveries(&mut self) -> Vec<Discovery>
pub fn drain_discoveries(&mut self) -> Vec<Discovery>
Remove and return every pending discovery, leaving the queue empty.
Sourcepub fn discoveries(&self) -> impl Iterator<Item = &Discovery> + '_
pub fn discoveries(&self) -> impl Iterator<Item = &Discovery> + '_
Iterate pending discoveries without consuming them.
Sourcepub fn has_no_discoveries(&self) -> bool
pub fn has_no_discoveries(&self) -> bool
True if there are no pending discoveries.
Sourcepub fn lifted_code_seeds(&self) -> Vec<CodeSeed>
pub fn lifted_code_seeds(&self) -> Vec<CodeSeed>
Every code address lifted in this context, as portable CodeSeeds. Used
to export a “code map” that pre-seeds a later run of the same binary.
Sourcepub fn seed_code(&mut self, seeds: impl IntoIterator<Item = CodeSeed>)
pub fn seed_code(&mut self, seeds: impl IntoIterator<Item = CodeSeed>)
Enqueue exported CodeSeeds as pending discoveries so the lifter reaches
them in its first pass. Call before lifting begins; seeds whose key already
has a terminal outcome are ignored by the queue.
pub fn mark_discovery_lifted(&mut self, key: DiscoveryKey)
pub fn mark_discovery_failed( &mut self, key: DiscoveryKey, reason: impl Into<String>, )
pub fn mark_discovery_skipped( &mut self, key: DiscoveryKey, reason: impl Into<String>, )
Sourcepub fn get_or_make_block(&mut self, addr: u64, func: FunctionId) -> BlockId
pub fn get_or_make_block(&mut self, addr: u64, func: FunctionId) -> BlockId
Returns the BlockId for a block at addr, creating one if needed.
The newly created block is named after the address in hex and registered in the address map.
Sourcepub fn get_or_make_block_indexed(
&mut self,
addresses: &mut AddressIndex,
addr: u64,
func: FunctionId,
) -> BlockId
pub fn get_or_make_block_indexed( &mut self, addresses: &mut AddressIndex, addr: u64, func: FunctionId, ) -> BlockId
Indexed construction variant of get_or_make_block.
The caller owns addresses for the duration of its lifting/lowering
operation and threads it through every address-bearing mutation.
Sourcepub fn split_block_at_address(
&mut self,
addresses: &mut AddressIndex,
block: BlockId,
addr: u64,
) -> BlockId
pub fn split_block_at_address( &mut self, addresses: &mut AddressIndex, block: BlockId, addr: u64, ) -> BlockId
Re-establishes addr as the start of a block of its own, when it is
currently interior to block — one of the addresses block absorbed.
§Why this discards code instead of moving it
The obvious split copies the instructions from addr onward into the
new block. That is only sound while a block’s instructions still
correspond, one run at a time, to the guest instructions they came from
— and they do not: a discovered block is optimized in place, so stores
have been forwarded and dead computation removed across the guest
instruction boundaries. There is no longer an instruction that “is” the
start of addr.
So neither half’s code survives the split. Both blocks are emptied and
keep only their place in the graph: block keeps its identity, so every
branch already targeting it stays valid, and the new block takes addr.
An empty block carrying an address is already this module’s request to
lift it, so the code comes back from the guest bytes — which are the
only faithful source for it — the next time control reaches either half.
Sourcepub fn builder(&mut self, block: BlockId) -> Builder<'str, '_>
pub fn builder(&mut self, block: BlockId) -> Builder<'str, '_>
Borrows one function body and creates the concrete body-local builder
positioned at block.
Sourcepub fn builder_at(&mut self, address: u64) -> Builder<'str, '_>
pub fn builder_at(&mut self, address: u64) -> Builder<'str, '_>
Test/API convenience for preparing a machine-address block before narrowing construction to its body-local builder.
Sourcepub fn bytes_display(&self, id: BytesId) -> BytesDisplay
pub fn bytes_display(&self, id: BytesId) -> BytesDisplay
The forced rendering mode for a Bytes blob, or
BytesDisplay::Auto if unset.
Sourcepub fn set_bytes_display(&mut self, id: BytesId, mode: BytesDisplay)
pub fn set_bytes_display(&mut self, id: BytesId, mode: BytesDisplay)
Force how a Bytes blob renders as a b"..." literal everywhere.
Setting BytesDisplay::Auto clears
any existing override.
Sourcepub fn block_ids(&self) -> Vec<BlockId>
pub fn block_ids(&self) -> Vec<BlockId>
Returns a list of all live blocks in the context (across all functions).
Sourcepub fn instruction_ids(&self) -> Vec<InstructionId>
pub fn instruction_ids(&self) -> Vec<InstructionId>
Returns all live instructions across all functions in stable logical-ID order. Function arenas iterate in dense physical order, so this explicit sort preserves the observable whole-context order across compaction.
Sourcepub fn function_ids(&self) -> Vec<FunctionId>
pub fn function_ids(&self) -> Vec<FunctionId>
Returns a list of all functions in the context.
Sourcepub fn anon_function(&mut self) -> FunctionId
pub fn anon_function(&mut self) -> FunctionId
Mints a fresh, uniquely-named anonymous function and returns its id.
A block must be born into some function’s arena; this hands out a host for standalone blocks (tests, the raw-hex/bare-block lift paths, and the pyqcode API that build a block without an enclosing function).
Sourcepub fn instruction_arena_stats(&self) -> (usize, usize)
pub fn instruction_arena_stats(&self) -> (usize, usize)
(issued_ids, removed_ids) across every function’s instruction arena.
Sourcepub fn body_arena_stats(&self) -> BodyArenaStats
pub fn body_arena_stats(&self) -> BodyArenaStats
Aggregate issued/live/dead and structural capacity for every body arena.
This is the stable reporting surface used by the Stage 7 before/after probe. Keeping the aggregation here avoids exposing arena internals to measurement binaries.
Sourcepub fn shrink_bodies_to_fit(&mut self)
pub fn shrink_bodies_to_fit(&mut self)
Releases body-arena capacity retained from peak analysis churn in every
function (see FunctionBody::shrink_to_fit).
Purely an allocator hint: IDs, ordering, and rendered IR are unchanged. Called once at explicit end-of-mutation boundaries such as pipeline convergence; nothing depends on it running.
Sourcepub fn instructions(
&self,
) -> impl Iterator<Item = InstructionRef<'str, '_>> + '_
pub fn instructions( &self, ) -> impl Iterator<Item = InstructionRef<'str, '_>> + '_
Iterates over all the (live) instructions in the context.
Sourcepub fn blocks(&self) -> impl Iterator<Item = BlockRef<'str, '_>> + '_
pub fn blocks(&self) -> impl Iterator<Item = BlockRef<'str, '_>> + '_
Iterates over all the (live) blocks in the context.
Sourcepub fn functions(&self) -> FunctionIter<'str, '_> ⓘ
pub fn functions(&self) -> FunctionIter<'str, '_> ⓘ
Iterates over all the functions in the context
Sourcepub fn iter(&self) -> FunctionIter<'str, '_> ⓘ
pub fn iter(&self) -> FunctionIter<'str, '_> ⓘ
Iterates over all the functions in the context
alias for functions()
pub fn varnodes(&self) -> impl Iterator<Item = VarnodeRef<'str, '_>> + '_
Sourcepub fn varnode_count(&self) -> usize
pub fn varnode_count(&self) -> usize
Number of varnodes in the context. The varnode registry is append-only, so
this is monotonic and an unchanged value means an unchanged varnode set —
used to validate caches keyed on the register/varnode layout (e.g. the
alias RegisterBase in the analysis layer).
Sourcepub fn remove_cfg_edge(&mut self, func: FunctionId, edge_id: EdgeId)
pub fn remove_cfg_edge(&mut self, func: FunctionId, edge_id: EdgeId)
Removes a CFG edge, unlinking it from both incident blocks’ edge sets and
physically dropping its payload. The module-path (function-qualified)
spelling of FunctionBody::remove_cfg_edge.
Sourcepub fn rehome_owned_blocks(
&mut self,
addresses: &mut AddressIndex,
target: FunctionId,
olds: &[BlockId],
) -> HashMap<BlockId, BlockId>
pub fn rehome_owned_blocks( &mut self, addresses: &mut AddressIndex, target: FunctionId, olds: &[BlockId], ) -> HashMap<BlockId, BlockId>
Relocate every block in olds into target’s own arena. The originals
remain owned by their source functions until deletion; only the clones are
rostered in target, so ownership and storage never diverge. This is the storage
mover split_function_at uses to make a split-off
tail self-stored.
A pure storage move: the resulting IR is semantically identical. Every
relocated block is deep-cloned into target (preserving instruction types,
machine addresses, and labels), all intra-set value/block references are
remapped to the clones, the incident CFG edges are rebuilt between the new
blocks (and their unmoved neighbours), the block addresses and the function
root are re-pointed, and the originals are deleted. target’s reverse-use
map is rebuilt from its live instructions afterwards.
Assumes the relocated set is closed (the caller strips every cross-function
CFG edge and rewrites foreign terminator targets to TailCalls first): every
reference from a relocated block resolves to another relocated block, an
unmoved block of target, or a shared value; a reference into a third
function is a bug upstream, and debug builds assert against it.
Sourcepub fn split_function_at(&mut self, block: BlockId) -> FunctionId
pub fn split_function_at(&mut self, block: BlockId) -> FunctionId
Split at block, returning the function G whose entry is block. This is
the strict-locality construction verb (context-split ruling 2): a control
transfer that lands mid-function is modelled as a function split — never a
foreign block reference.
Concretely it: (i) reuses the function already registered at block’s address
(a stub minted by a call, which may already have adopted block as its
root) or mints a conventional fn_<addr> (synthesized interface, unknown ABI
— the optimization pipeline derives its purity/clobber/ABI facts later);
(ii) extracts the tail reachable from block, stopping at other function
entries (split_tail), and reassigns it to G (an
absorbed tail may currently be owned by the function that absorbed it);
(iii) rewrites every terminator that statically targeted block — in the
absorbing function and in any already-lifted caller — into a function-level
TailCall (G for an unconditional Branch;
a fresh intra-function trampoline block ending in a TailCall for a
conditional CBranch arm), strips every cross-function CFG edge incident to
the moved tail, and rewrites any foreign back-edge out of the tail the same
way; (iv) relocates the tail into G’s own arena
(rehome_owned_blocks) so G is self-stored.
Afterwards no foreign block reference and no cross-function edge survives.
block must carry a machine address.
Sourcepub fn split_function_at_indexed(
&mut self,
addresses: &mut AddressIndex,
block: BlockId,
) -> FunctionId
pub fn split_function_at_indexed( &mut self, addresses: &mut AddressIndex, block: BlockId, ) -> FunctionId
Indexed construction variant of
split_function_at.
Sourcepub fn assume_true(&mut self, prop: Proposition) -> bool
pub fn assume_true(&mut self, prop: Proposition) -> bool
Assumes prop is true. Returns false (and records nothing) if the
proposition is already assumed or known false; returns true if it was
recorded or already held with the same polarity (idempotent). The
recording pass is taken from pass_scope.
Sourcepub fn assume_false(&mut self, prop: Proposition) -> bool
pub fn assume_false(&mut self, prop: Proposition) -> bool
Assumes prop is false. Mirror of assume_true.
Sourcepub fn set_known(&mut self, prop: Proposition, value: bool) -> bool
pub fn set_known(&mut self, prop: Proposition, value: bool) -> bool
Records prop = value as proven, overriding any assumption. If this
contradicts an existing assumption, a Violation is recorded — the
checkpoint+replay driver’s signal to discard this working copy.
Contradicting an existing known fact is a logic error.
Returns true if the fact is novel (no prior truth, or it overturned
an assumption): the driver replays when a round produced novel facts.
Sourcepub fn seed_known(&mut self, prop: Proposition, value: bool, pass: PassName)
pub fn seed_known(&mut self, prop: Proposition, value: bool, pass: PassName)
Seeds a proven fact carried over from an earlier checkpoint+replay
round. Unlike set_known this is not “novel”: it
must not retrigger a replay, and seeding over an existing entry is a
logic error (seed before any pass runs).
pass is the identity of the pass that originally proved the fact (as
harvested from known_facts), preserved across the
round boundary so the converged context still names the proving pass
rather than the re-seeding driver.
Sourcepub fn set_assumed_call_convention(&mut self, effect: Option<AssumedCallEffect>)
pub fn set_assumed_call_convention(&mut self, effect: Option<AssumedCallEffect>)
Install (or clear) the cached effect backing the opt-in
AssumeCallingConvention hypothesis — see
Shared::assumed_call_convention.
The assume_calling_convention pass calls this alongside recording
Proposition::AssumeCallingConvention.
Sourcepub fn assumed_call_convention(&self) -> Option<&AssumedCallEffect>
pub fn assumed_call_convention(&self) -> Option<&AssumedCallEffect>
The cached AssumedCallEffect, if
the hypothesis is active this round. Mirror of
Shared::assumed_call_convention.
Sourcepub fn known(&self, prop: Proposition) -> Option<bool>
pub fn known(&self, prop: Proposition) -> Option<bool>
The proven value of prop: Some only for known entries.
Sourcepub fn truths(&self) -> impl Iterator<Item = (Proposition, Truth)> + '_
pub fn truths(&self) -> impl Iterator<Item = (Proposition, Truth)> + '_
Iterates over every recorded truth (assumed and known).
Sourcepub fn known_facts(
&self,
) -> impl Iterator<Item = (Proposition, bool, PassName)> + '_
pub fn known_facts( &self, ) -> impl Iterator<Item = (Proposition, bool, PassName)> + '_
Iterates over the proven facts, for the replay driver to harvest into
the next round’s seed_known calls.
Sourcepub fn violations(&self) -> &[Violation]
pub fn violations(&self) -> &[Violation]
The violations recorded this round (proven facts that contradicted an assumption). Non-empty means derived IR may be wrong: replay.
Sourcepub fn known_contradictions(&self) -> &[KnownContradiction]
pub fn known_contradictions(&self) -> &[KnownContradiction]
Facts proven this round that contradicted an existing known fact (e.g. a user override the analysis disproved). Non-empty means the analysis cannot honor the forced value; the driver surfaces this as a hard error.
Sourcepub fn get_literal_value(&self, id: LiteralId) -> u64
pub fn get_literal_value(&self, id: LiteralId) -> u64
Returns the raw u64 backing value of the literal id.
Sourcepub fn get_insn(&self, id: InstructionId) -> InstructionRef<'str, '_>
pub fn get_insn(&self, id: InstructionId) -> InstructionRef<'str, '_>
Returns an immutable reference to the instruction identified by id.
Sourcepub fn body(&self, fid: FunctionId) -> &FunctionBody<'str>
pub fn body(&self, fid: FunctionId) -> &FunctionBody<'str>
The function body fid (context-split stage 5a bridging accessor).
Names the owning function explicitly so IR reads route through the body’s
function-local raw accessors — ctx.body(fid).block(id) in place of the
globally routed BasicBlock::from_id(ctx, id). This is the module-scope
(&Context) obtain-form; a function pass reaches the same body accessors
through its checked-out host. After the stage-4 func-strip only this
obtain step changes (the caller already holds &FunctionBody); the
.block(id) call on the result is unchanged.
Sourcepub fn body_mut(&mut self, fid: FunctionId) -> &mut FunctionBody<'str>
pub fn body_mut(&mut self, fid: FunctionId) -> &mut FunctionBody<'str>
The function body fid, mutably (see Context::body).
Sourcepub fn push_insn(
&mut self,
func: FunctionId,
insn: Instruction<'str>,
) -> InstructionId
pub fn push_insn( &mut self, func: FunctionId, insn: Instruction<'str>, ) -> InstructionId
Appends an instruction to func’s body and records all its operands in the
users map.
§Immutability invariant
Instructions are considered immutable after this call. If you alter the
operands of an instruction after insertion the users map will be stale.
Rewrite operands through replace_all_uses_with
instead.
Sourcepub fn instruction(&self, id: InstructionId) -> &Instruction<'str>
pub fn instruction(&self, id: InstructionId) -> &Instruction<'str>
Borrows the instruction id, routing through its owning function’s arena.
Sourcepub fn instruction_mut(&mut self, id: InstructionId) -> &mut Instruction<'str>
pub fn instruction_mut(&mut self, id: InstructionId) -> &mut Instruction<'str>
Mutably borrows the instruction id.
Sourcepub fn contains_instruction(&self, id: InstructionId) -> bool
pub fn contains_instruction(&self, id: InstructionId) -> bool
Whether id currently names a live instruction payload.
Sourcepub fn block(&self, id: BlockId) -> &BasicBlock<'str>
pub fn block(&self, id: BlockId) -> &BasicBlock<'str>
Borrows the basic block id.
Sourcepub fn block_mut(&mut self, id: BlockId) -> &mut BasicBlock<'str>
pub fn block_mut(&mut self, id: BlockId) -> &mut BasicBlock<'str>
Mutably borrows the basic block id.
Sourcepub fn contains_block(&self, id: BlockId) -> bool
pub fn contains_block(&self, id: BlockId) -> bool
Whether id currently names a live block payload.
Sourcepub fn block_param(&self, id: BlockParamId) -> &BlockParam<'str>
pub fn block_param(&self, id: BlockParamId) -> &BlockParam<'str>
Borrows the block parameter id.
Sourcepub fn block_param_mut(&mut self, id: BlockParamId) -> &mut BlockParam<'str>
pub fn block_param_mut(&mut self, id: BlockParamId) -> &mut BlockParam<'str>
Mutably borrows the block parameter id.
Sourcepub fn contains_block_param(&self, id: BlockParamId) -> bool
pub fn contains_block_param(&self, id: BlockParamId) -> bool
Whether id currently names a live block-parameter payload.
Sourcepub fn edge(&self, func: FunctionId, id: EdgeId) -> &EdgeData
pub fn edge(&self, func: FunctionId, id: EdgeId) -> &EdgeData
Borrows the CFG edge id, stored in function func’s edge arena.
Sourcepub fn edge_mut(&mut self, func: FunctionId, id: EdgeId) -> &mut EdgeData
pub fn edge_mut(&mut self, func: FunctionId, id: EdgeId) -> &mut EdgeData
Mutably borrows the CFG edge id, stored in function func’s edge arena.
Sourcepub fn users_of(&self, value: ValueId) -> Vec<InstructionId>
pub fn users_of(&self, value: ValueId) -> Vec<InstructionId>
Returns the instructions that use value as an operand, read from
value’s owning function. For an SSA def (instruction/param) that is the
complete user set (all uses are intra-function). For a shared value
(literal/bytes/varnode) there is no single owner, so this returns &[].
Sourcepub fn has_users(&self, value: ValueId) -> bool
pub fn has_users(&self, value: ValueId) -> bool
Whether anything uses value, without building the user list to ask.
pub fn push_block( &mut self, func: FunctionId, block: BasicBlock<'str>, ) -> BlockId
pub fn push_block_param( &mut self, func: FunctionId, param: BlockParam<'str>, ) -> BlockParamId
pub fn push_edge(&mut self, func: FunctionId, edge: EdgeData) -> EdgeId
Sourcepub fn push_function(
&mut self,
interface: FunctionInterface<'str>,
body: FunctionBody<'str>,
) -> FunctionId
pub fn push_function( &mut self, interface: FunctionInterface<'str>, body: FunctionBody<'str>, ) -> FunctionId
Push a function’s interface and body in lockstep, returning the shared
FunctionId. Both registries must always grow together.
Sourcepub fn get_register(&self, id: RegisterId) -> VarnodeRef<'str, '_>
pub fn get_register(&self, id: RegisterId) -> VarnodeRef<'str, '_>
Returns an immutable reference to the varnode mapped to the named
register id.
Sourcepub fn get_const(&self, value: u64, size: usize) -> LiteralRef<'str, '_>
pub fn get_const(&self, value: u64, size: usize) -> LiteralRef<'str, '_>
Creates a Value representing an integer constant of the given byte width.
Sourcepub fn get_bool_const(&self, value: bool) -> LiteralRef<'str, '_>
pub fn get_bool_const(&self, value: bool) -> LiteralRef<'str, '_>
Creates a bool-typed constant (true/false), byte-stored with value
1/0. This is the only way to mint a bool literal.
Sourcepub fn get_poison(&self, type_id: TypeId) -> ValueId
pub fn get_poison(&self, type_id: TypeId) -> ValueId
Sourcepub fn get_typed_const(
&self,
value: u64,
type_id: TypeId,
) -> LiteralRef<'str, '_>
pub fn get_typed_const( &self, value: u64, type_id: TypeId, ) -> LiteralRef<'str, '_>
Sourcepub fn get_bytes(&self, data: Vec<u8>) -> BytesRef<'str, '_>
pub fn get_bytes(&self, data: Vec<u8>) -> BytesRef<'str, '_>
Creates an opaque byte-blob constant from a little-endian, memory-order byte vector.
The blob is typed as an Array(i8, data.len()). Unlike numeric literals,
byte blobs are not interned: every call produces a fresh
BytesId. Use this for constants wider than a
u64 (SSE/AVX pools, wide stack/memory reads, coalesced constant stores).
Sourcepub fn get_typed_bytes(
&self,
data: Vec<u8>,
type_id: TypeId,
) -> BytesRef<'str, '_>
pub fn get_typed_bytes( &self, data: Vec<u8>, type_id: TypeId, ) -> BytesRef<'str, '_>
Like get_bytes but stamps the blob with an explicit
array/sequence TypeId instead of the default Array(i8, len). Mints
through the &self append path (no post-hoc type_id write), so a
checked-out function pass reading through a BodyView can materialize a
typed constant array without mutable access to the shared registry.
Sourcepub fn stored_type_of(&self, id: ValueId) -> Option<TypeId>
pub fn stored_type_of(&self, id: ValueId) -> Option<TypeId>
Returns the stored TypeId for value kinds that carry one directly.
Unlike Context::type_of, this never interns fallback integer types,
so it works from immutable formatting and parsing paths. Varnodes,
blocks, and functions return None.
Sourcepub fn set_varnode_type(&mut self, varnode: VarnodeId, type_id: TypeId)
pub fn set_varnode_type(&mut self, varnode: VarnodeId, type_id: TypeId)
Gives varnode a global type override, replacing the default
Int(size). Used to type ambient register globals — e.g. the FS_OFFSET
segment base as PtrTo<TEB> — so every use across all functions reads the
richer type. Pass a type whose size matches the varnode’s width.
Sourcepub fn users(&self, value: impl Into<ValueId>) -> Vec<InstructionId>
pub fn users(&self, value: impl Into<ValueId>) -> Vec<InstructionId>
Return all instructions that use value as an operand.
For an SSA value (instruction result or block param) this is the complete
user set, read from its owning function. For a shared value
(literal/bytes/varnode) it is &[] — those have no owning function and
their uses are tracked per using-function; use
users_across_functions to find them.
Sourcepub fn users_across_functions(
&self,
value: impl Into<ValueId>,
) -> Vec<InstructionId>
pub fn users_across_functions( &self, value: impl Into<ValueId>, ) -> Vec<InstructionId>
Sourcepub fn view(&self) -> ModuleView<'_, 'str>
pub fn view(&self) -> ModuleView<'_, 'str>
A Copy read view over the whole module (for the mutation refs’ reads).
Sourcepub fn shr(&self) -> &Shared<'str>
pub fn shr(&self) -> &Shared<'str>
The module’s shared IR state (Shared) — the module-path twin of
ModuleView::shared/BodyMut::shr, so a &mut Context module walker and
a checked-out pass spell shared-data reads identically (context-split
stage 5b-ii item #1).
Sourcepub fn function(&self, f: FunctionId) -> &FunctionBody<'str>
pub fn function(&self, f: FunctionId) -> &FunctionBody<'str>
The owning function’s storage (read). Alias of body.
Sourcepub fn function_mut(&mut self, f: FunctionId) -> &mut FunctionBody<'str>
pub fn function_mut(&mut self, f: FunctionId) -> &mut FunctionBody<'str>
The owning function’s storage (write). Alias of body_mut.
Sourcepub fn block_ref(&self, id: BlockId) -> BlockRef<'str, '_, ModuleView<'_, 'str>>
pub fn block_ref(&self, id: BlockId) -> BlockRef<'str, '_, ModuleView<'_, 'str>>
A read BlockRef over id, module-routed.
Sourcepub fn insn_ref(
&self,
id: InstructionId,
) -> InstructionRef<'str, '_, ModuleView<'_, 'str>>
pub fn insn_ref( &self, id: InstructionId, ) -> InstructionRef<'str, '_, ModuleView<'_, 'str>>
A read InstructionRef over id, module-routed.
Sourcepub fn param_ref(
&self,
id: BlockParamId,
) -> BlockParamRef<'str, '_, ModuleView<'_, 'str>>
pub fn param_ref( &self, id: BlockParamId, ) -> BlockParamRef<'str, '_, ModuleView<'_, 'str>>
A read BlockParamRef over id.
Sourcepub fn function_ref(
&self,
id: FunctionId,
) -> FunctionRef<'str, '_, ModuleView<'_, 'str>>
pub fn function_ref( &self, id: FunctionId, ) -> FunctionRef<'str, '_, ModuleView<'_, 'str>>
A read FunctionRef over id, module-routed.
Sourcepub fn push_mnemonic(
&mut self,
func: FunctionId,
mnemonic: Mnemonic,
size: usize,
) -> InstructionId
pub fn push_mnemonic( &mut self, func: FunctionId, mnemonic: Mnemonic, size: usize, ) -> InstructionId
Mint an Int(size)-typed instruction with mnemonic into func’s arena.
Sourcepub fn push_mnemonic_with_type(
&mut self,
func: FunctionId,
mnemonic: Mnemonic,
type_id: TypeId,
) -> InstructionId
pub fn push_mnemonic_with_type( &mut self, func: FunctionId, mnemonic: Mnemonic, type_id: TypeId, ) -> InstructionId
Mint an instruction with mnemonic and explicit result type_id into
func’s arena.
Sourcepub fn make_block(&mut self, func: FunctionId) -> BlockId
pub fn make_block(&mut self, func: FunctionId) -> BlockId
Mint a fresh empty block into func’s arena, owned (arena membership) and
rostered. The module-scope mint of a fresh empty block.
Sourcepub fn register_local_name(
&mut self,
id: ValueId,
name: Cow<'str, str>,
old_name: Option<&str>,
) -> Result<()>
pub fn register_local_name( &mut self, id: ValueId, name: Cow<'str, str>, old_name: Option<&str>, ) -> Result<()>
Register name for id in the table that owns its kind (function-local
for block/insn/param/Temp, global otherwise).
Sourcepub fn update_name(
&mut self,
name: Cow<'str, str>,
id: ValueId,
old_name: Option<&str>,
) -> Result<()>
pub fn update_name( &mut self, name: Cow<'str, str>, id: ValueId, old_name: Option<&str>, ) -> Result<()>
Changes the name of a value, in the name table that owns its kind (function-local for block/instruction/param/Temp, global otherwise).
Sourcepub fn get_named_in_scope(&self, id: ValueId, name: &str) -> Option<ValueId>
pub fn get_named_in_scope(&self, id: ValueId, name: &str) -> Option<ValueId>
Resolve name in the table that owns id’s kind (function-local for
block/instruction/param/Temp, global otherwise). Used by the rename path to
check for a conflict in the correct namespace, and by passes that mint a
unique name for a known SSA value.
Sourcepub fn get_named(&self, name: &str) -> Option<ValueId>
pub fn get_named(&self, name: &str) -> Option<ValueId>
Remove name from the name map, keeping the get_unique_name suffix
hint exact: if name is a generated base_<n> suffix, lower base’s hint
so the freed suffix is reconsidered on the next call (a naive first-free
scan would reuse it, and the hint must not skip it). Un-suffixed names are
Attempts to get a value ID by its global name (function/varnode/space/
p-code/bytes). Block/instruction/param/Temp names are function-scoped and are
resolved through their owning FunctionBody (see NameTable); this
returns None for them.
Sourcepub fn get_unique_name(&mut self, name: Cow<'str, str>) -> Cow<'str, str>
pub fn get_unique_name(&mut self, name: Cow<'str, str>) -> Cow<'str, str>
Gets a unique global name (functions, varnodes, spaces, …), appending
a numeric suffix until free. For a block/instruction/param/Temp name, use
get_unique_name_in so uniqueness is checked
against the owning function’s table.
Sourcepub fn get_unique_name_in(
&mut self,
func: FunctionId,
name: Cow<'str, str>,
) -> Cow<'str, str>
pub fn get_unique_name_in( &mut self, func: FunctionId, name: Cow<'str, str>, ) -> Cow<'str, str>
Gets a unique name within func’s function-local name table (for block,
instruction, block-param, and Temp names). Two functions may thus reuse the same
name independently.
Trait Implementations§
Source§impl<'de, 'str> Deserialize<'de> for Context<'str>
impl<'de, 'str> Deserialize<'de> for Context<'str>
Source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
Source§impl<'str, 'ctx> IntoIterator for &'ctx Context<'str>
impl<'str, 'ctx> IntoIterator for &'ctx Context<'str>
Source§impl<'str> QCodeMut<'str> for Context<'str>
impl<'str> QCodeMut<'str> for Context<'str>
Source§type View<'v> = ModuleView<'v, 'str>
where
Self: 'v,
'str: 'v
type View<'v> = ModuleView<'v, 'str> where Self: 'v, 'str: 'v
Source§fn function_mut(&mut self, id: FunctionId) -> &mut FunctionBody<'str>
fn function_mut(&mut self, id: FunctionId) -> &mut FunctionBody<'str>
id (write). The checked-out host panics if
id is not its own function.Source§fn body(&self, id: FunctionId) -> &FunctionBody<'str>
fn body(&self, id: FunctionId) -> &FunctionBody<'str>
id (read), tied to &self. The
borrow-friendly read primitive for host-generic ref code: a fully
generic H cannot prove 'str outlives a view GAT
borrow, but a plain &self-tied borrow needs no such proof.Source§fn interfaces(&self) -> &Registry<FunctionId, FunctionInterface<'str>>
fn interfaces(&self) -> &Registry<FunctionId, FunctionInterface<'str>>
Source§fn view(&self) -> ModuleView<'_, 'str>
fn view(&self) -> ModuleView<'_, 'str>
Source§fn instruction_mut(&mut self, id: InstructionId) -> &mut Instruction<'str>
fn instruction_mut(&mut self, id: InstructionId) -> &mut Instruction<'str>
id from its owning function’s arena.Source§fn block_mut(&mut self, id: BlockId) -> &mut BasicBlock<'str>
fn block_mut(&mut self, id: BlockId) -> &mut BasicBlock<'str>
id from its owning function’s arena.Source§fn block_param_mut(&mut self, id: BlockParamId) -> &mut BlockParam<'str>
fn block_param_mut(&mut self, id: BlockParamId) -> &mut BlockParam<'str>
id from its owning function’s arena.Source§fn register_body_name(
&mut self,
id: ValueId,
name: Cow<'str, str>,
old_name: Option<&str>,
) -> Result<()>
fn register_body_name( &mut self, id: ValueId, name: Cow<'str, str>, old_name: Option<&str>, ) -> Result<()>
name for the function-scoped id (block/instruction/param/
Temp) in its owning function’s local name table. Panics on a
global-scoped id — shared-name registration is a module-only operation
outside this trait’s body-local contract. Errors only on a duplicate
name.Source§fn remove_block_param(&mut self, id: BlockParamId)
fn remove_block_param(&mut self, id: BlockParamId)
Source§fn insert_insn_before(
&mut self,
block: BlockId,
before: InstructionId,
insn: InstructionId,
)
fn insert_insn_before( &mut self, block: BlockId, before: InstructionId, insn: InstructionId, )
insn immediately before before in block, setting its parent.Source§fn move_insn_before(&mut self, insn: InstructionId, before: InstructionId)
fn move_insn_before(&mut self, insn: InstructionId, before: InstructionId)
insn immediately before the arbitrary live instruction before,
preserving the moved instruction’s stable ID. Both instructions must
belong to the same function; the destination block is inferred from the
anchor.Source§fn replace_all_uses_with(
&mut self,
old: impl Into<ValueId>,
new: impl Into<ValueId>,
)
fn replace_all_uses_with( &mut self, old: impl Into<ValueId>, new: impl Into<ValueId>, )
old with new across old’s owning function and
update the reverse use-map (SSA defs only; all uses are intra-function).Source§fn remove_instruction(&mut self, id: InstructionId)
fn remove_instruction(&mut self, id: InstructionId)
id from its block, unlink its outgoing CFG edges if
a terminator, clear its name, prune its operand use-lists, and
physically drop its payload.Source§fn replace_instruction(&mut self, id: InstructionId, new: impl Into<ValueId>)
fn replace_instruction(&mut self, id: InstructionId, new: impl Into<ValueId>)
id with new, then remove id —
the standard “rewrite to a cheaper value” epilogue
(replace_all_uses_with +
remove_instruction).Source§fn remove_instructions(&mut self, dead: &FxHashSet<InstructionId>)
fn remove_instructions(&mut self, dead: &FxHashSet<InstructionId>)
Source§fn rehome_outgoing_edges(&mut self, keep: BlockId, remove: BlockId)
fn rehome_outgoing_edges(&mut self, keep: BlockId, remove: BlockId)
remove’s outgoing CFG edges onto keep. The direct edge and
keep’s forwarding terminator have already been removed by the caller.Source§fn replace_instruction_mnemonic(
&mut self,
id: InstructionId,
mnemonic: Mnemonic,
)
fn replace_instruction_mnemonic( &mut self, id: InstructionId, mnemonic: Mnemonic, )
Source§fn unroster_block(&mut self, block: BlockId)
fn unroster_block(&mut self, block: BlockId)
block from its function’s ownership roster. Ownership is derived
from the storing arena (block.func); the arena slot is untouched.Source§fn delete_block(&mut self, block: BlockId)
fn delete_block(&mut self, block: BlockId)
block from its function: unlink every incident CFG edge, remove
its instructions and params, clear ownership metadata, then drop its
payload.