Browse Source

Show function names in explore tool instead of only function indices (#8639)

* Implement runtime::Module::function_locations_with_names()

Map the iterator returned by Module::function_locations() to another
one that returns a 3-tuple containing the function name, the offset,
and the length of each function defined in this particular module.

* Show function names in "explore" instead of just the indices

* Address review: Change iterator format

* Address review: use the new iterator struct

* Address review comments
pull/8637/head
L. Pereira 6 months ago
committed by GitHub
parent
commit
f99464727b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      Cargo.lock
  2. 1
      crates/explorer/Cargo.toml
  3. 9
      crates/explorer/src/index.js
  4. 34
      crates/explorer/src/lib.rs
  5. 30
      crates/wasmtime/src/runtime/module.rs

1
Cargo.lock

@ -3683,6 +3683,7 @@ dependencies = [
"target-lexicon",
"wasmprinter",
"wasmtime",
"wasmtime-environ",
]
[[package]]

1
crates/explorer/Cargo.toml

@ -20,3 +20,4 @@ serde_json = { workspace = true }
target-lexicon = { workspace = true, features = ['std'] }
wasmprinter = { workspace = true }
wasmtime = { workspace = true, features = ["cranelift", "runtime"] }
wasmtime-environ = { workspace = true }

9
crates/explorer/src/index.js

@ -191,12 +191,16 @@ const renderInst = (mnemonic, operands) => {
// Render the ASM.
let nthFunc = 0;
for (const func of state.asm.functions) {
const funcElem = document.createElement("div");
const funcHeader = document.createElement("h3");
funcHeader.textContent = `Defined Function ${nthFunc}`;
let func_name =
func.name === null ? `function[${func.func_index}]` : func.name;
let demangled_name =
func.demangled_name !== null ? func.demangled_name : func_name;
funcHeader.textContent = `Disassembly of function <${demangled_name}>:`;
funcHeader.title = `Function ${func.func_index}: ${func_name}`;
funcElem.appendChild(funcHeader);
const bodyElem = document.createElement("pre");
@ -216,7 +220,6 @@ for (const func of state.asm.functions) {
funcElem.appendChild(bodyElem);
asmElem.appendChild(funcElem);
nthFunc++;
}
// Render the WAT.

34
crates/explorer/src/lib.rs

@ -2,6 +2,7 @@ use anyhow::Result;
use capstone::arch::BuildsCapstone;
use serde_derive::Serialize;
use std::{io::Write, str::FromStr};
use wasmtime_environ::demangle_function_name;
pub fn generate(
config: &wasmtime::Config,
@ -83,6 +84,9 @@ struct AnnotatedAsm {
#[derive(Serialize, Debug)]
struct AnnotatedFunction {
func_index: u32,
name: Option<String>,
demangled_name: Option<String>,
instructions: Vec<AnnotatedInstruction>,
}
@ -129,10 +133,9 @@ fn annotate_asm(
};
let functions = module
.function_locations()
.into_iter()
.map(|(start, len)| {
let body = &text[start..][..len];
.functions()
.map(|function| {
let body = &text[function.offset..][..function.len];
let mut cs = match target.architecture {
target_lexicon::Architecture::Aarch64(_) => capstone::Capstone::new()
@ -165,13 +168,13 @@ fn annotate_asm(
cs.set_skipdata(true).unwrap();
let instructions = cs
.disasm_all(body, start as u64)
.disasm_all(body, function.offset as u64)
.map_err(|e| anyhow::anyhow!("{e}"))?;
let instructions = instructions
.iter()
.map(|inst| {
let address = u32::try_from(inst.address()).unwrap();
let wasm_offset = wasm_offset_for_address(start, address);
let wasm_offset = wasm_offset_for_address(function.offset, address);
Ok(AnnotatedInstruction {
wasm_offset,
address,
@ -181,7 +184,24 @@ fn annotate_asm(
})
})
.collect::<Result<Vec<_>>>()?;
Ok(AnnotatedFunction { instructions })
let demangled_name = if let Some(name) = &function.name {
let mut demangled = String::new();
if demangle_function_name(&mut demangled, &name).is_ok() {
Some(demangled)
} else {
None
}
} else {
None
};
Ok(AnnotatedFunction {
func_index: function.index.as_u32(),
name: function.name,
demangled_name,
instructions,
})
})
.collect::<Result<Vec<_>>>()?;

30
crates/wasmtime/src/runtime/module.rs

@ -1017,13 +1017,21 @@ impl Module {
self.code_object().code_memory().text()
}
/// Get the locations of functions in this module's `.text` section.
///
/// Each function's location is a (`.text` section offset, length) pair.
pub fn function_locations<'a>(&'a self) -> impl ExactSizeIterator<Item = (usize, usize)> + 'a {
self.compiled_module().finished_functions().map(|(f, _)| {
let loc = self.compiled_module().func_loc(f);
(loc.start as usize, loc.length as usize)
/// Get information about functions in this module's `.text` section: their
/// index, name, and offset+length.
///
/// Results are yielded in a ModuleFunction struct.
pub fn functions<'a>(&'a self) -> impl ExactSizeIterator<Item = ModuleFunction> + 'a {
let module = self.compiled_module();
module.finished_functions().map(|(idx, _)| {
let loc = module.func_loc(idx);
let idx = module.module().func_index(idx);
ModuleFunction {
index: idx,
name: module.func_name(idx).map(|n| n.to_string()),
offset: loc.start as usize,
len: loc.length as usize,
}
})
}
@ -1032,6 +1040,14 @@ impl Module {
}
}
/// Describes a function for a given module.
pub struct ModuleFunction {
pub index: wasmtime_environ::FuncIndex,
pub name: Option<String>,
pub offset: usize,
pub len: usize,
}
impl ModuleInner {
fn memory_images(&self) -> Result<Option<&ModuleMemoryImages>> {
let images = self

Loading…
Cancel
Save