Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a compilation section to disable address maps #3598

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions crates/c-api/src/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ pub extern "C" fn wasmtime_frame_module_name(frame: &wasm_frame_t) -> Option<&wa

#[no_mangle]
pub extern "C" fn wasm_frame_func_offset(frame: &wasm_frame_t) -> usize {
frame.trap.trace()[frame.idx].func_offset()
frame.trap.trace()[frame.idx]
.func_offset()
.unwrap_or(usize::MAX)
}

#[no_mangle]
Expand All @@ -167,7 +169,9 @@ pub extern "C" fn wasm_frame_instance(_arg1: *const wasm_frame_t) -> *mut wasm_i

#[no_mangle]
pub extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t) -> usize {
frame.trap.trace()[frame.idx].module_offset()
frame.trap.trace()[frame.idx]
.module_offset()
.unwrap_or(usize::MAX)
}

#[no_mangle]
Expand Down
42 changes: 26 additions & 16 deletions crates/cranelift/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl Compiler {
context: &Context,
data: &FunctionBodyData<'_>,
body_len: u32,
tunables: &Tunables,
) -> FunctionAddressMap {
// Generate artificial srcloc for function start/end to identify boundary
// within module.
Expand All @@ -75,17 +76,21 @@ impl Compiler {

// New-style backend: we have a `MachCompileResult` that will give us `MachSrcLoc` mapping
// tuples.
let instructions = collect_address_maps(
body_len,
context
.mach_compile_result
.as_ref()
.unwrap()
.buffer
.get_srclocs_sorted()
.into_iter()
.map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start))),
);
let instructions = if tunables.generate_address_map {
collect_address_maps(
body_len,
context
.mach_compile_result
.as_ref()
.unwrap()
.buffer
.get_srclocs_sorted()
.into_iter()
.map(|&MachSrcLoc { start, end, loc }| (loc, start, (end - start))),
)
} else {
Vec::new()
};

FunctionAddressMap {
instructions: instructions.into(),
Expand Down Expand Up @@ -179,7 +184,7 @@ impl wasmtime_environ::Compiler for Compiler {
.map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?;

let address_transform =
self.get_function_address_map(&context, &input, code_buf.len() as u32);
self.get_function_address_map(&context, &input, code_buf.len() as u32, tunables);

let ranges = if tunables.generate_native_debuginfo {
Some(
Expand Down Expand Up @@ -221,7 +226,7 @@ impl wasmtime_environ::Compiler for Compiler {
translation: &ModuleTranslation,
types: &TypeTables,
funcs: PrimaryMap<DefinedFuncIndex, Box<dyn Any + Send>>,
emit_dwarf: bool,
tunables: &Tunables,
obj: &mut Object<'static>,
) -> Result<(PrimaryMap<DefinedFuncIndex, FunctionInfo>, Vec<Trampoline>)> {
let funcs: crate::CompiledFunctions = funcs
Expand All @@ -244,7 +249,9 @@ impl wasmtime_environ::Compiler for Compiler {
let mut func_starts = Vec::with_capacity(funcs.len());
for (i, func) in funcs.iter() {
let range = builder.func(i, func);
addrs.push(range.clone(), &func.address_map.instructions);
if tunables.generate_address_map {
addrs.push(range.clone(), &func.address_map.instructions);
}
traps.push(range.clone(), &func.traps);
func_starts.push(range.start);
if self.linkopts.padding_between_functions > 0 {
Expand All @@ -266,7 +273,7 @@ impl wasmtime_environ::Compiler for Compiler {

builder.unwind_info();

if emit_dwarf && funcs.len() > 0 {
if tunables.generate_native_debuginfo && funcs.len() > 0 {
let ofs = VMOffsets::new(
self.isa
.triple()
Expand Down Expand Up @@ -297,7 +304,10 @@ impl wasmtime_environ::Compiler for Compiler {
}

builder.finish()?;
addrs.append_to(obj);

if tunables.generate_address_map {
addrs.append_to(obj);
}
traps.append_to(obj);

Ok((
Expand Down
2 changes: 1 addition & 1 deletion crates/environ/src/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ pub trait Compiler: Send + Sync {
module: &ModuleTranslation,
types: &TypeTables,
funcs: PrimaryMap<DefinedFuncIndex, Box<dyn Any + Send>>,
emit_dwarf: bool,
tunables: &Tunables,
obj: &mut Object<'static>,
) -> Result<(PrimaryMap<DefinedFuncIndex, FunctionInfo>, Vec<Trampoline>)>;

Expand Down
5 changes: 5 additions & 0 deletions crates/environ/src/tunables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ pub struct Tunables {
/// Whether or not linear memory allocations will have a guard region at the
/// beginning of the allocation in addition to the end.
pub guard_before_linear_memory: bool,

/// Indicates whether an address map from compiled native code back to wasm
/// offsets in the original file is generated.
pub generate_address_map: bool,
}

impl Default for Tunables {
Expand Down Expand Up @@ -86,6 +90,7 @@ impl Default for Tunables {
consume_fuel: false,
static_memory_bound_is_maximum: false,
guard_before_linear_memory: true,
generate_address_map: true,
}
}
}
18 changes: 16 additions & 2 deletions crates/jit/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,16 +297,21 @@ impl CompiledModule {
};

let mut ret = Self {
meta: info.meta,
module: Arc::new(info.module),
funcs: info.funcs,
trampolines: info.trampolines,
wasm_data: subslice_range(section(ELF_WASM_DATA)?, code.mmap),
address_map_data: subslice_range(section(ELF_WASMTIME_ADDRMAP)?, code.mmap),
address_map_data: code
.obj
.section_by_name(ELF_WASMTIME_ADDRMAP)
.and_then(|s| s.data().ok())
.map(|slice| subslice_range(slice, code.mmap))
.unwrap_or(0..0),
trap_data: subslice_range(section(ELF_WASMTIME_TRAPS)?, code.mmap),
code: subslice_range(code.text, code.mmap),
dbg_jit_registration: None,
code_memory,
meta: info.meta,
};
ret.register_debug_and_profiling(profiler)?;

Expand Down Expand Up @@ -500,6 +505,15 @@ impl CompiledModule {
pub fn has_unparsed_debuginfo(&self) -> bool {
self.meta.has_unparsed_debuginfo
}

/// Indicates whether this module came with n address map such that lookups
/// via `wasmtime_environ::lookup_file_pos` will succeed.
///
/// If this function returns `false` then `lookup_file_pos` will always
/// return `None`.
pub fn has_address_map(&self) -> bool {
!self.address_map_data().is_empty()
}
}

type Addr2LineContext<'a> = addr2line::Context<gimli::EndianSlice<'a, gimli::LittleEndian>>;
Expand Down
14 changes: 14 additions & 0 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,20 @@ impl Config {
self
}

/// Configures whether compiled artifacts will contain information to map
/// native program addresses back to the original wasm module.
///
/// This configuration option is `true` by default and, if enables,
/// generates the appropriate tables in compiled modules to map from native
/// address back to wasm source addresses. This is used for displaying wasm
/// program counters in backtraces as well as generating filenames/line
/// numbers if so configured as well (and the original wasm module has DWARF
/// debugging information present).
pub fn generate_address_map(&mut self, generate: bool) -> &mut Self {
self.tunables.generate_address_map = generate;
self
}

pub(crate) fn build_allocator(&self) -> Result<Box<dyn InstanceAllocator>> {
#[cfg(feature = "async")]
let stack_size = self.async_stack_size;
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl Engine {
// Ensure that wasmtime_runtime's signal handlers are configured. This
// is the per-program initialization required for handling traps, such
// as configuring signals, vectored exception handlers, etc.
wasmtime_runtime::init_traps(crate::module::GlobalModuleRegistry::is_wasm_pc);
wasmtime_runtime::init_traps(crate::module::GlobalModuleRegistry::is_wasm_trap_pc);
debug_builtins::ensure_exported();

let registry = SignatureRegistry::new();
Expand Down
11 changes: 4 additions & 7 deletions crates/wasmtime/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,13 +398,10 @@ impl Module {
.collect();

let mut obj = engine.compiler().object()?;
let (funcs, trampolines) = engine.compiler().emit_obj(
&translation,
&types,
funcs,
tunables.generate_native_debuginfo,
&mut obj,
)?;
let (funcs, trampolines) =
engine
.compiler()
.emit_obj(&translation, &types, funcs, tunables, &mut obj)?;

// If configured, attempt to use paged memory initialization
// instead of the default mode of memory initialization
Expand Down
40 changes: 25 additions & 15 deletions crates/wasmtime/src/module/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,12 @@ pub struct GlobalModuleRegistry(BTreeMap<usize, GlobalRegisteredModule>);
impl GlobalModuleRegistry {
/// Returns whether the `pc`, according to globally registered information,
/// is a wasm trap or not.
pub(crate) fn is_wasm_pc(pc: usize) -> bool {
pub(crate) fn is_wasm_trap_pc(pc: usize) -> bool {
let modules = GLOBAL_MODULES.read().unwrap();

match modules.module(pc) {
Some((entry, text_offset)) => {
wasmtime_environ::lookup_file_pos(entry.module.address_map_data(), text_offset)
.is_some()
wasmtime_environ::lookup_trap_code(entry.module.trap_data(), text_offset).is_some()
}
None => false,
}
Expand Down Expand Up @@ -275,14 +274,15 @@ impl GlobalRegisteredModule {
// the function, because otherwise something is buggy along the way and
// not accounting for all the instructions. This isn't super critical
// though so we can omit this check in release mode.
//
// Note that if the module doesn't even have an address map due to
// compilation settings then it's expected that `instr` is `None`.
debug_assert!(
instr.is_some(),
instr.is_some() || !self.module.has_address_map(),
"failed to find instruction for {:#x}",
text_offset
);

let instr = instr.unwrap_or(info.start_srcloc);

// Use our wasm-relative pc to symbolize this frame. If there's a
// symbolication context (dwarf debug info) available then we can try to
// look this up there.
Expand All @@ -294,7 +294,7 @@ impl GlobalRegisteredModule {
let mut symbols = Vec::new();

if let Some(s) = &self.module.symbolize_context().ok().and_then(|c| c) {
if let Some(offset) = instr.file_offset() {
if let Some(offset) = instr.and_then(|i| i.file_offset()) {
let to_lookup = u64::from(offset) - s.code_section_offset();
if let Ok(mut frames) = s.addr2line().find_frames(to_lookup) {
while let Ok(Some(frame)) = frames.next() {
Expand Down Expand Up @@ -344,7 +344,7 @@ pub struct FrameInfo {
func_index: u32,
func_name: Option<String>,
func_start: FilePos,
instr: FilePos,
instr: Option<FilePos>,
symbols: Vec<FrameSymbol>,
}

Expand Down Expand Up @@ -393,8 +393,14 @@ impl FrameInfo {
///
/// The offset here is the offset from the beginning of the original wasm
/// module to the instruction that this frame points to.
pub fn module_offset(&self) -> usize {
self.instr.file_offset().unwrap_or(u32::MAX) as usize
///
/// Note that `None` may be returned if the original module was not
/// compiled with mapping information to yield this information. This is
/// controlled by the
/// [`Config::generate_address_map`](crate::Config::generate_address_map)
/// configuration option.
pub fn module_offset(&self) -> Option<usize> {
Some(self.instr?.file_offset()? as usize)
}

/// Returns the offset from the original wasm module's function to this
Expand All @@ -403,11 +409,15 @@ impl FrameInfo {
/// The offset here is the offset from the beginning of the defining
/// function of this frame (within the wasm module) to the instruction this
/// frame points to.
pub fn func_offset(&self) -> usize {
match self.instr.file_offset() {
Some(i) => (i - self.func_start.file_offset().unwrap()) as usize,
None => u32::MAX as usize,
}
///
/// Note that `None` may be returned if the original module was not
/// compiled with mapping information to yield this information. This is
/// controlled by the
/// [`Config::generate_address_map`](crate::Config::generate_address_map)
/// configuration option.
pub fn func_offset(&self) -> Option<usize> {
let instr_offset = self.instr?.file_offset()?;
Some((instr_offset - self.func_start.file_offset()?) as usize)
}

/// Returns the debug symbols found, if any, for this function frame.
Expand Down
6 changes: 6 additions & 0 deletions crates/wasmtime/src/module/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,12 @@ impl<'a> SerializedModule<'a> {

// This doesn't affect compilation, it's just a runtime setting.
dynamic_memory_growth_reserve: _,

// This does technically affect compilation but modules with/without
// trap information can be loaded into engines with the opposite
// setting just fine (it's just a section in the compiled file and
// whether it's present or not)
generate_address_map: _,
} = self.metadata.tunables;

Self::check_int(
Expand Down
6 changes: 5 additions & 1 deletion crates/wasmtime/src/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,11 @@ impl fmt::Display for Trap {
writeln!(f, "\nwasm backtrace:")?;
for (i, frame) in self.trace().iter().enumerate() {
let name = frame.module_name().unwrap_or("<unknown>");
write!(f, " {:>3}: {:#6x} - ", i, frame.module_offset())?;
write!(f, " {:>3}: ", i)?;

if let Some(offset) = frame.module_offset() {
write!(f, "{:#6x} - ", offset)?;
}

let demangle =
|f: &mut fmt::Formatter<'_>, name: &str| match rustc_demangle::try_demangle(name) {
Expand Down
Loading