From f99464727b69b3f7bfcdd334e0f1624526ed0b8c Mon Sep 17 00:00:00 2001 From: "L. Pereira" Date: Tue, 21 May 2024 10:27:52 -0700 Subject: [PATCH] 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 --- Cargo.lock | 1 + crates/explorer/Cargo.toml | 1 + crates/explorer/src/index.js | 9 ++++--- crates/explorer/src/lib.rs | 34 +++++++++++++++++++++------ crates/wasmtime/src/runtime/module.rs | 30 +++++++++++++++++------ 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f611936b81cf..49aaa7f4b79b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3683,6 +3683,7 @@ dependencies = [ "target-lexicon", "wasmprinter", "wasmtime", + "wasmtime-environ", ] [[package]] diff --git a/crates/explorer/Cargo.toml b/crates/explorer/Cargo.toml index 7a0a80f074bc..ba315ddd50b8 100644 --- a/crates/explorer/Cargo.toml +++ b/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 } diff --git a/crates/explorer/src/index.js b/crates/explorer/src/index.js index afcfac9e5bdc..254c86abc6c1 100644 --- a/crates/explorer/src/index.js +++ b/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. diff --git a/crates/explorer/src/lib.rs b/crates/explorer/src/lib.rs index 0b92aae71412..cd9c4e3fc4ad 100644 --- a/crates/explorer/src/lib.rs +++ b/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, + demangled_name: Option, instructions: Vec, } @@ -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::>>()?; - 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::>>()?; diff --git a/crates/wasmtime/src/runtime/module.rs b/crates/wasmtime/src/runtime/module.rs index 0a6b42ae064a..70c0e3fb3dd8 100644 --- a/crates/wasmtime/src/runtime/module.rs +++ b/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 + '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 + '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, + pub offset: usize, + pub len: usize, +} + impl ModuleInner { fn memory_images(&self) -> Result> { let images = self