///|
pub enum FileOffsetDecodeStatus {
NotApplicable
Decoded
} derive(Eq, Debug)
///|
pub enum FileOffsetDecodeDetailKind {
LocalsEncoding
Instruction
} derive(Eq, Debug)
///|
pub struct FileOffsetDecodeDetail {
kind : FileOffsetDecodeDetailKind
file_offset : Int
size : Int
relative_offset : Int
instruction : FunctionInstructionRecord?
}
///|
pub struct FileOffsetDecodedReport {
location : FileOffsetReport
decode_status : FileOffsetDecodeStatus
detail : FileOffsetDecodeDetail?
scope : String
}
///|
pub enum FileOffsetDecodeError {
FileOffsetDecodeLocationError(FileOffsetError)
FileOffsetDecodeInstructionsError(FunctionInstructionsError)
InconsistentFileOffsetDecode(Int, String)
}
///|
pub fn describe_file_offset_decode_error(
error : FileOffsetDecodeError,
) -> String {
match error {
FileOffsetDecodeLocationError(error) => describe_file_offset_error(error)
FileOffsetDecodeInstructionsError(error) =>
describe_function_instructions_error(error)
InconsistentFileOffsetDecode(offset, reason) =>
"inconsistent decoded location for file offset \{offset}: " + reason
}
}
///|
fn file_offset_decode_range(
location : FileOffsetReport,
range : FunctionInstructionRange,
) -> Result[DataByteRange, FileOffsetDecodeError] {
match
file_offset_range(
location.file_size,
range.file_offset,
range.size,
location.offset,
) {
Ok(value) => Ok(value)
Err(_) =>
Err(
InconsistentFileOffsetDecode(
location.offset,
"instruction report range exceeds input",
),
)
}
}
///|
/// Private composition boundary. Both reports must have been produced from
/// the same input in locate_file_offset_decoded, never supplied by a caller.
fn file_offset_decode_detail(
location : FileOffsetReport,
decoded : FunctionInstructionsReport,
) -> Result[FileOffsetDecodeDetail, FileOffsetDecodeError] {
let query = location.offset
let stat = match location.function {
Some(value) => value
None =>
return Err(
InconsistentFileOffsetDecode(query, "body has no function owner"),
)
}
if decoded.file_size != location.file_size ||
decoded.sha256 != location.sha256 ||
decoded.index != stat.index ||
decoded.name != stat.name ||
decoded.raw_name != stat.raw_name {
return Err(
InconsistentFileOffsetDecode(
query, "input identity or function identity differs",
),
)
}
let entry = match file_offset_decode_range(location, decoded.entry) {
Ok(value) => value
Err(error) => return Err(error)
}
let prefix = match file_offset_decode_range(location, decoded.prefix) {
Ok(value) => value
Err(error) => return Err(error)
}
let body = match file_offset_decode_range(location, decoded.body) {
Ok(value) => value
Err(error) => return Err(error)
}
let locals = match
file_offset_decode_range(location, decoded.locals_encoding) {
Ok(value) => value
Err(error) => return Err(error)
}
if location.region.kind != FunctionBodyBytes ||
entry.offset != stat.offset ||
entry.size != stat.total_size ||
prefix.offset != entry.offset ||
prefix.size < 1 ||
prefix.size > entry.size ||
body.offset != prefix.offset + prefix.size ||
body.size != entry.size - prefix.size ||
body.size != stat.body_size ||
body.offset != location.region.file_offset ||
body.size != location.region.size ||
!file_offset_contains(body, query) ||
location.region.relative_offset != query - body.offset ||
locals.offset != body.offset ||
!file_offset_within(locals, body) {
return Err(
InconsistentFileOffsetDecode(
query, "entry, prefix, body or locals ranges differ",
),
)
}
let first = locals.offset + locals.size // checked against input and body
let mut cursor = first
let mut selected : FileOffsetDecodeDetail? = if file_offset_contains(
locals, query,
) {
Some({
kind: LocalsEncoding,
file_offset: locals.offset,
size: locals.size,
relative_offset: query - locals.offset,
instruction: None,
})
} else {
None
}
for ordinal, instruction in decoded.instructions {
let range = match
file_offset_decode_range(location, {
file_offset: instruction.file_offset,
size: instruction.encoded_size,
}) {
Ok(value) => value
Err(error) => return Err(error)
}
if range.offset != cursor ||
range.size <= 0 ||
!file_offset_within(range, body) ||
instruction.ordinal != ordinal ||
instruction.body_relative_offset != range.offset - body.offset {
return Err(
InconsistentFileOffsetDecode(
query, "noncontiguous or inconsistent instruction evidence",
),
)
}
if file_offset_contains(range, query) {
if selected is Some(_) {
return Err(
InconsistentFileOffsetDecode(query, "multiple decoded owners"),
)
}
selected = Some({
kind: Instruction,
file_offset: range.offset,
size: range.size,
relative_offset: query - range.offset,
instruction: Some(instruction),
})
}
cursor = range.offset + range.size // checked before addition
}
if cursor - body.offset != body.size ||
decoded.instruction_bytes != cursor - first ||
decoded.instruction_bytes != body.size - locals.size ||
decoded.instruction_count != decoded.instructions.length() {
return Err(
InconsistentFileOffsetDecode(
query, "decoded body byte ledger does not close",
),
)
}
match selected {
Some(detail) => Ok(detail)
None => Err(InconsistentFileOffsetDecode(query, "no unique decoded owner"))
}
}
///|
/// One base location; only a function-body hit invokes the existing complete
/// single-function decoder, exactly once. A target decode error is never hidden.
pub fn locate_file_offset_decoded(
data : Bytes,
offset : Int,
) -> Result[FileOffsetDecodedReport, FileOffsetDecodeError] {
let location = match locate_file_offset(data, offset) {
Ok(value) => value
Err(error) => return Err(FileOffsetDecodeLocationError(error))
}
let scope = "Optional refinement of one local function body using the existing instruction decoder. Non-body bytes are not_applicable and trigger no instruction decoding. An applicable target must decode completely, even for a locals query; other functions are only range/name checked. Existing entries may repeat structural/name checks and whole-file hashing. Opcode, extended subopcode and immediate bytes belong to their entire instruction; operand fields/values are not identified. No WAT, call-target inference, execution frequency, timing or optimization savings. This does not certify other functions or complete Wasm type, stack or control-flow semantics. All offsets are file bytes, not memory addresses."
if location.region.kind != FunctionBodyBytes {
return Ok({ location, decode_status: NotApplicable, detail: None, scope, })
}
let index = match location.function {
Some(stat) => stat.index
None =>
return Err(
InconsistentFileOffsetDecode(offset, "body has no local function index"),
)
}
let decoded = match inspect_function_instructions(data, index) {
Ok(value) => value
Err(error) => return Err(FileOffsetDecodeInstructionsError(error))
}
let detail = match file_offset_decode_detail(location, decoded) {
Ok(value) => value
Err(error) => return Err(error)
}
Ok({ location, decode_status: Decoded, detail: Some(detail), scope, })
}