Skip to content

Commit

Permalink
Show function names in explore tool instead of only function indices (
Browse files Browse the repository at this point in the history
…#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
  • Loading branch information
lpereira authored May 21, 2024
1 parent 3c8bb26 commit f994647
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/explorer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 6 additions & 3 deletions crates/explorer/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -216,7 +220,6 @@ for (const func of state.asm.functions) {
funcElem.appendChild(bodyElem);

asmElem.appendChild(funcElem);
nthFunc++;
}

// Render the WAT.
Expand Down
34 changes: 27 additions & 7 deletions crates/explorer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -83,6 +84,9 @@ struct AnnotatedAsm {

#[derive(Serialize, Debug)]
struct AnnotatedFunction {
func_index: u32,
name: Option<String>,
demangled_name: Option<String>,
instructions: Vec<AnnotatedInstruction>,
}

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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,
Expand All @@ -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<_>>>()?;

Expand Down
30 changes: 23 additions & 7 deletions crates/wasmtime/src/runtime/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
})
}

Expand All @@ -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
Expand Down

0 comments on commit f994647

Please sign in to comment.