Skip to content
Open
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
12 changes: 6 additions & 6 deletions crates/cranelift/src/compiled_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use cranelift_codegen::{
isa::unwind::CfaUnwindInfo, isa::unwind::UnwindInfo,
};
use wasmtime_environ::{
FilePos, FrameStateSlotBuilder, InstructionAddressMap, PrimaryMap, TrapInformation,
FilePos, FrameStateSlotBuilder, InstructionAddressMap, ModulePC, PrimaryMap, TrapInformation,
};

#[derive(Debug, Clone, PartialEq, Eq, Default)]
Expand Down Expand Up @@ -67,8 +67,8 @@ pub struct CompiledFunction {
metadata: CompiledFunctionMetadata,
/// Debug metadata for the top-level function's state slot.
pub debug_slot_descriptor: Option<FrameStateSlotBuilder>,
/// Debug breakpoint patches: Wasm PC, offset range in buffer.
pub breakpoint_patch_points: Vec<(u32, Range<u32>)>,
/// Debug breakpoint patches: module-relative Wasm PC, offset range in buffer.
pub breakpoint_patch_points: Vec<(ModulePC, Range<u32>)>,
}

impl CompiledFunction {
Expand Down Expand Up @@ -120,15 +120,15 @@ impl CompiledFunction {
// second-to-last tag will get the innermost Wasm PC (if
// there are multiple nested frames due to inlining).
assert!(tag.tags.len() >= 3);
let ir::DebugTag::User(wasm_pc) = tag.tags[tag.tags.len() - 2] else {
let ir::DebugTag::User(wasm_pc_raw) = tag.tags[tag.tags.len() - 2] else {
panic!("invalid tag")
};

let patchable_start = patchable_callsite.ret_addr - patchable_callsite.len;
let patchable_end = patchable_callsite.ret_addr;

self.breakpoint_patch_points
.push((wasm_pc, patchable_start..patchable_end));
.push((ModulePC::new(wasm_pc_raw), patchable_start..patchable_end));

tags.next();
patchable_callsites.next();
Expand Down Expand Up @@ -218,7 +218,7 @@ impl CompiledFunction {
/// Returns an iterator over breakpoint patches for this function.
///
/// Each tuple is (wasm PC, buffer offset range).
pub fn breakpoint_patches(&self) -> impl Iterator<Item = (u32, Range<u32>)> + '_ {
pub fn breakpoint_patches(&self) -> impl Iterator<Item = (ModulePC, Range<u32>)> + '_ {
self.breakpoint_patch_points.iter().cloned()
}
}
Expand Down
12 changes: 6 additions & 6 deletions crates/cranelift/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use wasmtime_environ::{
Abi, AddressMapSection, BuiltinFunctionIndex, CacheStore, CompileError, CompiledFunctionBody,
DefinedFuncIndex, FlagValue, FrameInstPos, FrameStackShape, FrameStateSlotBuilder,
FrameTableBuilder, FuncKey, FunctionBodyData, FunctionLoc, HostCall, InliningCompiler,
ModuleTranslation, ModuleTypesBuilder, PtrSize, StackMapSection, StaticModuleIndex,
ModulePC, ModuleTranslation, ModuleTypesBuilder, PtrSize, StackMapSection, StaticModuleIndex,
TrapEncodingBuilder, TrapSentinel, TripleExt, Tunables, WasmFuncType, WasmValType, prelude::*,
};
use wasmtime_unwinder::ExceptionTableBuilder;
Expand Down Expand Up @@ -520,7 +520,7 @@ impl wasmtime_environ::Compiler for Compiler {
}
}

let mut breakpoint_table = Vec::new();
let mut breakpoint_table: Vec<(ModulePC, Range<u32>)> = Vec::new();
let mut nop_units = None;

let mut ret = Vec::with_capacity(funcs.len());
Expand Down Expand Up @@ -1623,7 +1623,7 @@ fn clif_to_env_frame_tables<'a>(
for frame_tags in tag_site.tags.chunks_exact(3) {
let &[
ir::DebugTag::StackSlot(slot),
ir::DebugTag::User(wasm_pc),
ir::DebugTag::User(wasm_pc_raw),
ir::DebugTag::User(stack_shape),
] = frame_tags
else {
Expand All @@ -1645,7 +1645,7 @@ fn clif_to_env_frame_tables<'a>(
});

frames.push((
wasm_pc,
ModulePC::new(wasm_pc_raw),
frame_descriptor,
FrameStackShape::from_raw(stack_shape),
));
Expand All @@ -1669,8 +1669,8 @@ fn clif_to_env_frame_tables<'a>(
/// Wasmtime's serialized metadata.
fn clif_to_env_breakpoints(
range: Range<u64>,
breakpoint_patches: impl Iterator<Item = (u32, Range<u32>)>,
patch_table: &mut Vec<(u32, Range<u32>)>,
breakpoint_patches: impl Iterator<Item = (ModulePC, Range<u32>)>,
patch_table: &mut Vec<(ModulePC, Range<u32>)>,
) -> Result<()> {
patch_table.extend(breakpoint_patches.map(|(wasm_pc, offset_range)| {
let start = offset_range.start + u32::try_from(range.start).unwrap();
Expand Down
30 changes: 22 additions & 8 deletions crates/cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ use std::mem;
use wasmparser::{FuncValidator, Operator, WasmFeatures, WasmModuleResources};
use wasmtime_core::math::f64_cvt_to_int_bounds;
use wasmtime_environ::{
BuiltinFunctionIndex, DataIndex, DefinedFuncIndex, ElemIndex, EngineOrModuleTypeIndex,
FrameStateSlotBuilder, FrameValType, FuncIndex, FuncKey, GlobalConstValue, GlobalIndex,
IndexType, Memory, MemoryIndex, Module, ModuleInternedTypeIndex, ModuleTranslation,
ModuleTypesBuilder, PtrSize, Table, TableIndex, TagIndex, Tunables, TypeConvert, TypeIndex,
VMOffsets, WasmCompositeInnerType, WasmFuncType, WasmHeapTopType, WasmHeapType, WasmRefType,
WasmResult, WasmValType,
BuiltinFunctionIndex, ComponentPC, DataIndex, DefinedFuncIndex, ElemIndex,
EngineOrModuleTypeIndex, FrameStateSlotBuilder, FrameValType, FuncIndex, FuncKey,
GlobalConstValue, GlobalIndex, IndexType, Memory, MemoryIndex, Module, ModuleInternedTypeIndex,
ModuleTranslation, ModuleTypesBuilder, PtrSize, Table, TableIndex, TagIndex, Tunables,
TypeConvert, TypeIndex, VMOffsets, WasmCompositeInnerType, WasmFuncType, WasmHeapTopType,
WasmHeapType, WasmRefType, WasmResult, WasmValType,
};
use wasmtime_environ::{FUNCREF_INIT_BIT, FUNCREF_MASK};

Expand Down Expand Up @@ -137,6 +137,11 @@ pub struct FuncEnvironment<'module_environment> {
needs_gc_heap: bool,
entities: WasmEntities,

/// The byte offset of the module's wasm binary within the outer
/// binary (e.g. a component). Used to make source locations in
/// guest-debug frame tables module-relative.
pub(crate) wasm_module_offset: u64,

/// Translation state at the given point.
pub(crate) stacks: FuncTranslationStacks,

Expand Down Expand Up @@ -291,6 +296,7 @@ impl<'module_environment> FuncEnvironment<'module_environment> {

state_slot: None,
next_srcloc: ir::SourceLoc::default(),
wasm_module_offset: translation.wasm_module_offset,
}
}

Expand Down Expand Up @@ -1318,10 +1324,18 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
.last()
.map(|s| s.raw())
.unwrap_or(u32::MAX);
let pc = srcloc.bits();
// Convert component-relative srcloc to module-relative
// Wasm PC for the frame table. The srcloc on the builder
// remains component-relative for native DWARF and other
// purposes, but the frame table must be module-relative
// because the guest-debug API presents a purely core-Wasm
// view of the world where components are deconstructed
// into core Wasm modules.
let component_pc = ComponentPC::new(srcloc.bits());
let module_pc = component_pc.to_module_pc(self.wasm_module_offset);
vec![
ir::DebugTag::StackSlot(*slot),
ir::DebugTag::User(pc),
ir::DebugTag::User(module_pc.raw()),
ir::DebugTag::User(stack_shape),
]
} else {
Expand Down
6 changes: 3 additions & 3 deletions crates/debugger/src/host/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ impl<T: Send + 'static> OpaqueDebugger for crate::Debuggee<T> {
.wasm_function_index_and_pc(&mut store)
.map_err(|_| wit::Error::InvalidFrame)?
.ok_or(wit::Error::NonWasmFrame)?;
Ok((func.as_u32(), pc))
Ok((func.as_u32(), pc.raw()))
})
.await?
}
Expand Down Expand Up @@ -556,7 +556,7 @@ impl<T: Send + 'static> OpaqueDebugger for crate::Debuggee<T> {
store
.edit_breakpoints()
.expect("guest debugging is enabled")
.add_breakpoint(&module, pc)
.add_breakpoint(&module, wasmtime::ModulePC::new(pc))
.map_err(|_| wit::Error::InvalidPc)?;
Ok(())
})
Expand All @@ -568,7 +568,7 @@ impl<T: Send + 'static> OpaqueDebugger for crate::Debuggee<T> {
store
.edit_breakpoints()
.expect("guest debugging is enabled")
.remove_breakpoint(&module, pc)
.remove_breakpoint(&module, wasmtime::ModulePC::new(pc))
.map_err(|_| wit::Error::InvalidPc)?;
Ok(())
})
Expand Down
12 changes: 8 additions & 4 deletions crates/debugger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,8 @@ mod test {
.wasm_function_index_and_pc(&mut store)
.unwrap()
.unwrap()
.1,
.1
.raw(),
36
);
assert_eq!(frame.num_locals(&mut store).unwrap(), 2);
Expand Down Expand Up @@ -618,7 +619,8 @@ mod test {
.wasm_function_index_and_pc(&mut store)
.unwrap()
.unwrap()
.1,
.1
.raw(),
38
);
assert_eq!(frame.num_locals(&mut store).unwrap(), 2);
Expand Down Expand Up @@ -651,7 +653,8 @@ mod test {
.wasm_function_index_and_pc(&mut store)
.unwrap()
.unwrap()
.1,
.1
.raw(),
40
);
assert_eq!(frame.num_locals(&mut store).unwrap(), 2);
Expand Down Expand Up @@ -685,7 +688,8 @@ mod test {
.wasm_function_index_and_pc(&mut store)
.unwrap()
.unwrap()
.1,
.1
.raw(),
41
);
assert_eq!(frame.num_locals(&mut store).unwrap(), 2);
Expand Down
80 changes: 80 additions & 0 deletions crates/environ/src/address_map.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Data structures to provide transformation of the source

use core::fmt;
use object::{Bytes, LittleEndian, U32};
use serde_derive::{Deserialize, Serialize};

Expand Down Expand Up @@ -61,6 +62,85 @@ impl Default for FilePos {
}
}

/// A Wasm bytecode offset relative to the start of a component (or
/// top-level module) binary.
///
/// When compiling a component, the Wasm parser returns source
/// positions relative to the entire component binary. This type
/// captures that convention. Use
/// [`ComponentPC::to_module_pc`] to convert to a
/// [`ModulePC`] given the byte offset of the module within the
/// component.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ComponentPC(u32);

impl ComponentPC {
/// Create a new component-relative PC from a raw offset.
pub fn new(offset: u32) -> Self {
Self(offset)
}

/// Get the raw u32 offset.
pub fn raw(self) -> u32 {
self.0
}

/// Convert to a module-relative PC by subtracting the byte offset
/// of the module within the component binary.
pub fn to_module_pc(self, wasm_module_offset: u64) -> ModulePC {
let offset = u32::try_from(wasm_module_offset).unwrap();
ModulePC(self.0 - offset)
}
}

impl fmt::Debug for ComponentPC {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ComponentPC({:#x})", self.0)
}
}

impl fmt::Display for ComponentPC {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#x}", self.0)
}
}

/// A Wasm bytecode offset relative to the start of a core Wasm
/// module binary.
///
/// In the guest-debug system, PCs are always module-relative because
/// the debugger presents a core-Wasm view of the world where
/// components are deconstructed into individual core Wasm modules.
///
/// For standalone (non-component) modules, `ModulePC` and
/// [`ComponentPC`] values are numerically identical.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModulePC(u32);

impl ModulePC {
/// Create a new module-relative PC from a raw offset.
pub fn new(offset: u32) -> Self {
Self(offset)
}

/// Get the raw u32 offset.
pub fn raw(self) -> u32 {
self.0
}
}

impl fmt::Debug for ModulePC {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ModulePC({:#x})", self.0)
}
}

impl fmt::Display for ModulePC {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#x}", self.0)
}
}

/// Parse an `ELF_WASMTIME_ADDRMAP` section, returning the slice of code offsets
/// and the slice of associated file positions for each offset.
fn parse_address_map(section: &[u8]) -> Option<(&[U32<LittleEndian>], &[U32<LittleEndian>])> {
Expand Down
25 changes: 16 additions & 9 deletions crates/environ/src/compile/frame_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use crate::{
FrameInstPos, FrameStackShape, FrameStateSlotOffset, FrameTableDescriptorIndex, FrameValType,
FuncKey, WasmHeapTopType, WasmValType, prelude::*,
FuncKey, ModulePC, WasmHeapTopType, WasmValType, prelude::*,
};
use object::{LittleEndian, U32};
use std::collections::{HashMap, hash_map::Entry};
Expand Down Expand Up @@ -278,9 +278,9 @@ impl FrameTableBuilder {
&mut self,
native_pc: u32,
pos: FrameInstPos,
// For each frame: Wasm PC, frame descriptor, stack shape
// within the frame descriptor.
frames: &[(u32, FrameTableDescriptorIndex, FrameStackShape)],
// For each frame: module-relative Wasm PC, frame descriptor,
// stack shape within the frame descriptor.
frames: &[(ModulePC, FrameTableDescriptorIndex, FrameStackShape)],
) {
let pc_and_pos = FrameInstPos::encode(native_pc, pos);
// If we already have a program point record at this PC,
Expand All @@ -300,11 +300,12 @@ impl FrameTableBuilder {
.push(U32::new(LittleEndian, start));

for (i, &(wasm_pc, frame_descriptor, stack_shape)) in frames.iter().enumerate() {
debug_assert!(wasm_pc < 0x8000_0000);
let wasm_pc_raw = wasm_pc.raw();
debug_assert!(wasm_pc_raw < 0x8000_0000);
let not_last = i < (frames.len() - 1);
let wasm_pc = wasm_pc | if not_last { 0x8000_0000 } else { 0 };
let wasm_pc_raw = wasm_pc_raw | if not_last { 0x8000_0000 } else { 0 };
self.progpoint_descriptor_data
.push(U32::new(LittleEndian, wasm_pc));
.push(U32::new(LittleEndian, wasm_pc_raw));
self.progpoint_descriptor_data
.push(U32::new(LittleEndian, frame_descriptor.0));
self.progpoint_descriptor_data
Expand All @@ -313,8 +314,14 @@ impl FrameTableBuilder {
}

/// Add one breakpoint patch.
pub fn add_breakpoint_patch(&mut self, wasm_pc: u32, patch_start_native_pc: u32, patch: &[u8]) {
self.breakpoint_pcs.push(U32::new(LittleEndian, wasm_pc));
pub fn add_breakpoint_patch(
&mut self,
wasm_pc: ModulePC,
patch_start_native_pc: u32,
patch: &[u8],
) {
self.breakpoint_pcs
.push(U32::new(LittleEndian, wasm_pc.raw()));
self.breakpoint_patch_offsets
.push(U32::new(LittleEndian, patch_start_native_pc));
self.breakpoint_patch_data.extend(patch.iter().cloned());
Expand Down
7 changes: 7 additions & 0 deletions crates/environ/src/compile/module_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ pub struct ModuleTranslation<'data> {
/// themselves.
pub wasm: &'data [u8],

/// The byte offset of this module's Wasm binary within the outer
/// binary (e.g. a component). For standalone modules this is 0.
/// This is used to convert component-relative source locations to
/// module-relative source locations.
pub wasm_module_offset: u64,

/// References to the function bodies.
pub function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,

Expand Down Expand Up @@ -118,6 +124,7 @@ impl<'data> ModuleTranslation<'data> {
Self {
module: Module::new(module_index),
wasm: &[],
wasm_module_offset: 0,
function_body_inputs: PrimaryMap::default(),
known_imported_functions: SecondaryMap::default(),
exported_signatures: Vec::default(),
Expand Down
Loading
Loading