Instructions & Operands
Instructions are the lowest level of the Quokka object model. This page covers the Instruction and Operand objects, their attributes, and common instruction-level analysis patterns.
The Instruction Object
func = prog.get_function("main", approximative=False)
entry = func.get_block(func.start)
# Iterate instructions in a block
for addr, inst in entry.items():
print(inst)
# Get by address — from a function or from the program
inst = func.get_instruction(0x401234)
inst = prog.get_instruction(0x401234)
Instruction Attributes
inst = func.get_instruction(0x401234)
inst.address # 0x401234 (virtual address)
inst.size # 3 (bytes)
inst.mnemonic # "mov"
inst.cs_inst # Capstone CsInsn object (full disassembly)
# Capstone gives full detail:
cs = inst.cs_inst
print(f"{cs.mnemonic} {cs.op_str}") # "mov rax, qword ptr [rbx]"
print(f"groups: {cs.groups}") # instruction groups
Export Mode Impact
In LIGHT mode, only block start addresses are stored in the .quokka file. Capstone decodes instructions from the binary bytes at runtime. In FULL mode, mnemonics and operands are stored directly in the file — the binary is not needed at analysis time.
Either way, the Python API is identical:
inst.mnemonic # works in both modes
inst.cs_inst # works in both modes (Capstone is always used)
# To check the current mode:
prog.mode # ExporterMode.LIGHT or ExporterMode.FULL
Operands
from quokka.types import OperandType
inst = func.get_instruction(0x401234)
print(inst.operands) # list of Operand objects
for op in inst.operands:
if op.type == OperandType.REGISTER:
print(f" register: {op.register}")
elif op.type == OperandType.IMMEDIATE:
print(f" value: {op.value:#x}")
elif op.type == OperandType.MEMORY:
print(f" memory reference")
Operand Types
| Type | Meaning | Example |
|---|---|---|
REGISTER |
CPU register | rax, rbx, r8 |
IMMEDIATE |
Constant value | 0x42, -1, 3.14 |
MEMORY |
Memory reference | [rbp-8], [rip+0x10] |
OTHER |
Anything else | FPU stack, implicit operands |
# Filter operands by type
imm_ops = [op for op in inst.operands
if op.type == OperandType.IMMEDIATE]
reg_ops = [op for op in inst.operands
if op.type == OperandType.REGISTER]
String References
An instruction can reference a string literal in the binary:
inst = func.get_instruction(0x401250)
s = inst.string
if s is not None:
print(f"String ref: {repr(s.value)}")
# String ref: b"Error: invalid argument\n"
Call Targets
For call instructions, call_target resolves the callee (thunks are resolved automatically):
call_inst = func.get_instruction(0x4012a0)
target = call_inst.call_target
if target is not None:
print(f"Calls: {target.name}")
else:
print("Indirect call (function pointer)")
Register Access Mode
In FULL export mode, register read/write information is available:
from quokka.types import AccessMode
for op in inst.operands:
if op.type == OperandType.REGISTER:
if AccessMode.READ in op.access:
print(f" reads {op.register}")
if AccessMode.WRITE in op.access:
print(f" writes {op.register}")
Examples
Finding All Call Instructions
import quokka
from quokka.types import FunctionType
prog = quokka.Program("bash.quokka", "bash")
call_sites = []
for func in prog.values():
if func.type != FunctionType.NORMAL:
continue
for block in func.values():
for addr, inst in block.items():
if inst.mnemonic in ("call", "bl", "blx", "jal"):
target = inst.call_target
call_sites.append({
"caller": func.name,
"site": hex(addr),
"callee": target.name if target else "indirect",
})
print(f"Found {len(call_sites)} call sites")
Finding Dangerous Function Calls
DANGEROUS = {"strcpy", "gets", "sprintf", "system",
"strcat", "scanf", "vsprintf"}
hits = []
for func in prog.values():
for block in func.values():
for addr, inst in block.items():
target = inst.call_target
if target and target.name in DANGEROUS:
hits.append((func.name, hex(addr), target.name))
for caller, site, callee in hits:
print(f" [{site}] {caller} → {callee}")
Instruction Cheatsheet
| Attribute / Method | Type | Description |
|---|---|---|
inst.address |
int |
Virtual address |
inst.size |
int |
Size in bytes |
inst.mnemonic |
str |
Mnemonic string |
inst.bytes |
bytes |
Raw instruction bytes |
inst.is_thumb |
bool |
ARM Thumb mode flag |
inst.operands |
list[Operand] |
Decoded operands |
inst.cs_inst |
CsInsn |
Capstone instruction object |
inst.pcode_insts |
list[PcodeOp] |
Lifted P-code operations |
inst.string |
Data \| None |
Referenced string literal |
inst.constants |
list[int] |
Immediate constant values |
inst.comments |
Iterable[str] |
IDA comments on instruction |
inst.call_target |
Function |
Resolved call target (raises if none) |
inst.callees |
list[int] |
Addresses of call targets |
inst.callers |
list[int] |
Addresses of callers |
inst.is_call |
bool |
True if this is a call |
inst.is_jump |
bool |
True if this is a jump |
inst.is_conditional_jump |
bool |
True if conditional jump |
inst.is_dynamic |
bool |
True if indirect call/jump |
inst.data_refs_from |
list |
Data xrefs from this instruction |
inst.data_read_refs_from |
list |
Data read xrefs from this instruction |
inst.data_write_refs_from |
list |
Data write xrefs from this instruction |
inst.data_refs_to |
list |
Data xrefs to this instruction |
inst.code_refs_from |
list[int] |
Code xrefs from (jump/call targets) |
inst.code_refs_to |
list[int] |
Code xrefs to (who jumps/calls here) |
inst.type_refs_from |
list[TypeReference] |
Type xrefs from this instruction |
inst.is_fall_through(addr) |
bool |
Check if addr is the fall-through target |
Operand Cheatsheet
| Attribute / Method | Type | Description |
|---|---|---|
op.type |
OperandType |
REGISTER, IMMEDIATE, MEMORY, OTHER |
op.value |
Any |
Typed value: int (imm), str (reg), mem object |
op.register |
str |
Register name (empty if not a register) |
op.access |
AccessMode |
READ, WRITE, or READ\|WRITE |
op.data_refs_from |
list |
Data objects/functions referenced by this operand |
op.code_refs_from |
list[int] |
Code addresses referenced by this operand |
op.type_refs_from |
list[TypeReference] |
Type references on this operand |
str(op) |
str |
Human-readable operand string |
from quokka.types import OperandType, AccessMode
for op in inst.operands:
match op.type:
case OperandType.REGISTER:
print(f"reg={op.register} access={op.access}")
case OperandType.IMMEDIATE:
print(f"imm={op.value:#x}")
case OperandType.MEMORY:
print(f"mem={op.value} refs={op.data_refs_from}")
See Also
- P-code Lifting — architecture-independent IR via
inst.pcode_insts - Cross-References —
inst.code_refs_from,inst.data_refs_from, etc.