///|
fn opcode_search_stat_json(stat : FunctionStat) -> Json {
let row : Map[String, Json] = Map([])
row.set("index", int_json(stat.index))
row.set("name", Json::string(stat.name))
row.set("raw_name", path_optional_string(stat.raw_name))
row.set("module_name", Json::string(stat.module_name))
row.set("offset", int_json(stat.offset))
row.set("body_size", int_json(stat.body_size))
row.set("total_size", int_json(stat.total_size))
Json::object(row)
}
///|
pub fn render_opcode_search_json(report : OpcodeSearchReport) -> String {
let root : Map[String, Json] = Map([])
root.set("format", Json::string("moonsize-opcode-search"))
root.set("schema_version", int_json(1))
root.set("query", Json::string(report.query))
root.set("sha256", Json::string(report.sha256))
root.set("matching_rule", Json::string(report.matching_rule))
root.set("scope", Json::string(report.scope))
root.set("file_size", int_json(report.file_size))
root.set("imported_function_count", int_json(report.imported_function_count))
root.set(
"scanned_local_function_count",
int_json(report.scanned_local_function_count),
)
root.set("matched_function_count", int_json(report.matched_function_count))
root.set(
"unmatched_function_count",
int_json(report.unmatched_function_count),
)
root.set("instruction_count", int_json(report.instruction_count))
root.set("instruction_bytes", int_json(report.instruction_bytes))
root.set("match_count", int_json(report.match_count))
root.set("matched_encoded_bytes", int_json(report.matched_encoded_bytes))
root.set("other_instruction_bytes", int_json(report.other_instruction_bytes))
root.set(
"functions",
Json::array(
report.functions.map(fn(f) {
let row : Map[String, Json] = Map([])
row.set("stat", opcode_search_stat_json(f.stat))
row.set("match_count", int_json(f.match_count))
row.set("matched_encoded_bytes", int_json(f.matched_encoded_bytes))
row.set(
"sites",
Json::array(
f.sites.map(fn(site) {
let value : Map[String, Json] = Map([])
value.set("ordinal", int_json(site.ordinal))
value.set("mnemonic", Json::string(site.mnemonic))
value.set("file_offset", int_json(site.file_offset))
value.set(
"body_relative_offset",
int_json(site.body_relative_offset),
)
value.set("encoded_size", int_json(site.encoded_size))
Json::object(value)
}),
),
)
Json::object(row)
}),
),
)
Json::object(root).stringify(indent=2) + "\n"
}
///|
pub fn render_opcode_search(report : OpcodeSearchReport, top : Int) -> String {
let out = StringBuilder()
out.write_string("OPCODE LOCATION SEARCH\n\n")
out.write_string("Query: " + search_terminal_string(report.query) + "\n")
out.write_string("Input: \{report.file_size} B; SHA-256 \{report.sha256}\n")
out.write_string(report.matching_rule + "\n")
out.write_string("Imported functions: \{report.imported_function_count}\n")
out.write_string(
"Scanned local functions: \{report.scanned_local_function_count} = matched \{report.matched_function_count} + unmatched \{report.unmatched_function_count}\n",
)
out.write_string(
"Instructions: \{report.instruction_count}; matches: \{report.match_count}\n",
)
out.write_string(
"Instruction bytes: \{report.instruction_bytes} = matched \{report.matched_encoded_bytes} + other \{report.other_instruction_bytes}\n",
)
let shown = top.max(0).min(report.match_count)
out.write_string(
"\nMATCHES: showing \{shown} of \{report.match_count} (file order)\nFUNCTION INDEX ORDINAL FILE OFFSET BODY OFFSET SIZE NAME\n",
)
if report.scanned_local_function_count == 0 {
out.write_string("No local function definitions to search.\n")
} else if report.match_count == 0 {
out.write_string(
"No matching mnemonic in the decoded local function instructions.\n",
)
}
let mut emitted = 0
for f in report.functions {
if emitted >= shown {
break
}
for site in f.sites {
if emitted >= shown {
break
}
out.write_string(
"\{f.stat.index} \{site.ordinal} \{site.file_offset} \{site.body_relative_offset} \{site.encoded_size} " +
search_terminal_string(f.stat.name) +
"\n",
)
emitted += 1
}
}
out.write_string("\n" + report.scope + "\n")
out.to_string()
}