Backend.S
The backend interface.
The backend is a simple automaton that disassembles instructions and pushes them into the queue. It runs until it either hits an instruction that matches with one of the previously set predicates or if it either hits an invalid instruction or runs out of the bounds of the specified memory region. On the high level the algorithm of the run
function can be described with the following pseudocode.
1. disassemble instruction 2. push result into the queue 3. update the offset 4. if exists predicate p such that p(insn) or off >= length(data) then stop else goto 1.
If it is impossible to decode the given sequence of bytes, then an invalid instruction is pushed into the queue and disassembling continues on the next offset.
Predicates enables fine control over the behavior of the disassembler. For example, the Is_true
predicate is always true
disassembler will stop after each instruction. The backend is not required to support all predicates, only Is_true
and Is_invalid
are required.
The state of the disassembler includes the queue of disassembled instructions, the last disassembled instruction, the set of predicates, and the current offset. At the beginning, the queue and the set of predicates are empty, the offset is zero, and the last disassembled instruction is invalid.
To minimize allocations, opcodes and register names are represented as offsets in the corresponding string tables.
val delete : t -> unit
delete d
is called when the disassembler is no longer needed.
It is safe now to free any data related with the disassembler.
val set_memory :
t ->
int64 ->
Core_kernel.Bigstring.t ->
off:int ->
len:int ->
unit
set_memory dis addr data ~off ~len
sets the current memory region.
Sets the memory region accessible by disassembler to a substring of data
starting at the offset off
and having the length len
with the first byte at off
having the address addr
.
Parameters off
and len
must be non-negative numbers. The offset dis
shall be equal to 0
after this function is executed.
val store_predicates : t -> bool -> unit
store_predicates dis on_off
turns predicate storage on or off.
When it is off
it is not required to store semantic predicates for each instruction in the queue, only for the last disassembled one. It is off
by default.
val store_asm_string : t -> bool -> unit
store_asm_string dis on_off
turns assembly string storage on or off.
When it is off
it is not required to store assembly strings for each instruction in the queue, only for the last disassembled one.
It is off
by default.
val insn_table : t -> Core_kernel.Bigstring.t
insn_table dis
returns a string table for opcodes.
The table contains a sequence of null-terminated strings.
val reg_table : t -> Core_kernel.Bigstring.t
reg_table dis
returns a string table for register names.
The table contains a sequence of null-terminated strings.
val predicates_clear : t -> unit
predicates_clear dis
clears the set of predicates.
predicates_push dis p
adds p
to the set of predicates.
precondition: is_supported dis p
.
val set_offset : t -> int -> unit
set_offset dis off
sets the current offset to off
.
val offset : t -> int
offset dis
is the current offset.
val run : t -> unit
run dis
runs the disassembler.
The disassembler runs until it hits an instruction that matches one of the predicates in the disassemblers current set of predicates or it runs out of the boundaries of the currently specified memory region.
See the module description for the more detailed description of the backend algorithm.
val insns_clear : t -> unit
insns_clear dis
clears the disassembler instructions queue.
val insns_size : t -> int
insns_size dis
the length of the instruction queue.
val insn_size : t -> insn:int -> int
insn_size dis ~insn:n
the n
th instruction length.
val insn_name : t -> insn:int -> int
insn_name dis ~insn:n
the n
th instruction name.
val insn_code : t -> insn:int -> int
insn_name dis ~insn:n
the n
th instruction opcode.
The opcode name is represented as an offset to the insn_table dis
string table in which each element is a null-terminated string.
val insn_offset : t -> insn:int -> int
insn_offset dis ~insn:n
the offset of n
th instruction.
val insn_asm_size : t -> insn:int -> int
insn_offset dis ~insn:n
the n
th instruction assembly string length.
val insn_asm_copy : t -> insn:int -> Regular.Std.Bytes.t -> unit
insn_asm_copy dis ~insn:n data
copies the assembly string of the n
th instruction.
insn_satisfies dis ~insn:n p
is true
if the n
th instruction satisfies the predicate p
.
val insn_ops_size : t -> insn:int -> int
insn_ops_size dis ~insn:n
the number of operands.
insn_op_type dis ~insn:n ~oper:m
the m
th operand type.
val insn_op_reg_name : t -> insn:int -> oper:int -> int
insn_op_reg_name dis ~insn:n ~oper:m
the register name.
Returns the register name of the operand m
. The name is represented as an offset to the reg_table dis
, which is a string table of null-terminated strings.
Precondition: insn_op_type dis ~insn:n ~oper:m = Reg
val insn_op_reg_code : t -> insn:int -> oper:int -> int
insn_op_reg_name dis ~insn:n ~oper:m
the register code.
Returns the register code of the operand m
. The code is a unique number identifying the register (could be the same as insn_op_reg_name
.
Precondition: insn_op_type dis ~insn:n ~oper:m = Reg
val insn_op_imm_value : t -> insn:int -> oper:int -> int64
insn_op_imm_value dis ~insn:n ~oper:m
the immediate value.
Returns the value of the operand m
.
Precondition: insn_op_type dis ~insn:n ~oper:m = Imm
val insn_op_imm_small_value : t -> insn:int -> oper:int -> int
insn_op_imm_small_value dis ~insn:n ~oper:m
the immediate value.
If the value v
of the operand m
is strictly greater than Int.min_val
and is strictly less than Int.max_val
then returns v
otherwise returns Int.min_val
or Int.max_val
.
Precondition: insn_op_type dis ~insn:n ~oper:m = Imm
val insn_op_fmm_value : t -> insn:int -> oper:int -> float
insn_op_fmm_value
the floating-point immediate value.
Returns the value of the operand m
.
Precondition: insn_op_type dis ~insn:n ~oper:m = Fmm