Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ jobs:
os: ubuntu-latest
test: >
cargo check -p wasmtime --no-default-features --features runtime,component-model &&
cargo check -p wasmtime --no-default-features --features runtime,gc,component-model,async &&
cargo check -p wasmtime --no-default-features --features runtime,gc,component-model,async,debug-builtins &&
cargo check -p cranelift-control --no-default-features &&
cargo check -p pulley-interpreter --features encode,decode,disas,interp &&
cargo check -p wasmtime-wasi-io --no-default-features
Expand Down
3 changes: 2 additions & 1 deletion crates/jit-debug/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ wasmtime-versioned-export-macros = { workspace = true }
rustix = { workspace = true, features = ["mm", "time"], optional = true }

[features]
std = []
gdb_jit_int = []
perf_jitdump = ["rustix", "object"]
perf_jitdump = ["rustix", "object", "std"]
76 changes: 65 additions & 11 deletions crates/jit-debug/src/gdb_jit_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
//! the __jit_debug_register_code() and __jit_debug_descriptor to register
//! or unregister generated object images with debuggers.

use std::pin::Pin;
use std::ptr;
use std::sync::Mutex;
extern crate alloc;

use alloc::{boxed::Box, vec::Vec};
use core::{pin::Pin, ptr};
use wasmtime_versioned_export_macros::versioned_link;

#[repr(C)]
Expand Down Expand Up @@ -33,13 +34,66 @@ unsafe extern "C" {
fn __jit_debug_register_code();
}

/// The process controls access to the __jit_debug_descriptor by itself --
/// the GDB/LLDB accesses this structure and its data at the process startup
/// and when paused in __jit_debug_register_code.
#[cfg(feature = "std")]
mod gdb_registration {
use std::sync::{Mutex, MutexGuard};

/// The process controls access to the __jit_debug_descriptor by itself --
/// the GDB/LLDB accesses this structure and its data at the process startup
/// and when paused in __jit_debug_register_code.
///
/// The GDB_REGISTRATION lock is needed for GdbJitImageRegistration to protect
/// access to the __jit_debug_descriptor within this process.
pub static GDB_REGISTRATION: Mutex<()> = Mutex::new(());

/// The lock guard for the GDB registration lock.
#[expect(
dead_code,
reason = "field used to hold the lock until the end of the scope"
)]
pub struct LockGuard<'a>(MutexGuard<'a, ()>);

pub fn lock() -> LockGuard<'static> {
LockGuard(GDB_REGISTRATION.lock().unwrap())
}
}

/// For no_std there's no access to synchronization primitives so a primitive
/// fallback for now is to panic-on-contention which is, in theory, rare to come
/// up as threads are rarer in no_std mode too.
///
/// The GDB_REGISTRATION lock is needed for GdbJitImageRegistration to protect
/// access to the __jit_debug_descriptor within this process.
static GDB_REGISTRATION: Mutex<()> = Mutex::new(());
/// This provides the guarantee that the debugger will see consistent state at
/// least, but if this panic is hit in practice it'll require some sort of
/// no_std synchronization mechanism one way or another.
#[cfg(not(feature = "std"))]
mod gdb_registration {
use core::sync::atomic::{AtomicBool, Ordering};

/// Whether or not a lock is held or not.
pub static GDB_REGISTRATION: AtomicBool = AtomicBool::new(false);

/// The lock guard for the GDB registration lock.
pub struct LockGuard;

/// When the `LockGuard` is dropped, it releases the lock by setting
/// `GDB_REGISTRATION` to false.
impl Drop for LockGuard {
fn drop(&mut self) {
GDB_REGISTRATION.store(false, Ordering::Release);
}
}

/// Locks the GDB registration lock. If the lock is already held, it panics
pub fn lock() -> LockGuard {
if GDB_REGISTRATION
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
panic!("GDB JIT registration lock contention detected in no_std mode");
}
LockGuard
}
}

/// Registration for JIT image
pub struct GdbJitImageRegistration {
Expand Down Expand Up @@ -87,7 +141,7 @@ unsafe impl Sync for GdbJitImageRegistration {}

unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) {
unsafe {
let _lock = GDB_REGISTRATION.lock().unwrap();
let _lock = gdb_registration::lock();
let desc = &mut *wasmtime_jit_debug_descriptor();

// Add it to the linked list in the JIT descriptor.
Expand All @@ -109,7 +163,7 @@ unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) {

unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
unsafe {
let _lock = GDB_REGISTRATION.lock().unwrap();
let _lock = gdb_registration::lock();
let desc = &mut *wasmtime_jit_debug_descriptor();

// Remove the code entry corresponding to the code from the linked list.
Expand Down
4 changes: 4 additions & 0 deletions crates/jit-debug/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
//! > you're interested in using this feel free to file an issue on the
//! > Wasmtime repository to start a discussion about doing so, but otherwise
//! > be aware that your usage of this crate is not supported.
#![no_std]

#[cfg(feature = "std")]
extern crate std;

#[cfg(feature = "gdb_jit_int")]
pub mod gdb_jit_int;
Expand Down
2 changes: 2 additions & 0 deletions crates/jit-debug/src/perf_jitdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use std::io;
use std::io::Write;
use std::path::Path;
use std::ptr;
use std::string::String;
use std::vec::Vec;
use std::{mem, process};

/// Defines jitdump record types
Expand Down
9 changes: 6 additions & 3 deletions crates/wasmtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ all-features = true
[dependencies]
wasmtime-asm-macros = { workspace = true, optional = true }
wasmtime-environ = { workspace = true }
wasmtime-jit-debug = { workspace = true, features = ["gdb_jit_int", "perf_jitdump"], optional = true }
wasmtime-jit-debug = { workspace = true, optional = true }
wasmtime-jit-icache-coherence = { workspace = true, optional = true }
wasmtime-cache = { workspace = true, optional = true }
wasmtime-fiber = { workspace = true, optional = true }
Expand Down Expand Up @@ -175,12 +175,12 @@ incremental-cache = ["wasmtime-cranelift?/incremental-cache", "std"]
# Enables support for profiling guest modules.
profiling = [
"dep:fxprof-processed-profile",
"dep:wasmtime-jit-debug",
"dep:ittapi",
"dep:rustix",
"rustix/thread",
"dep:serde_json",
"std",
"wasmtime-jit-debug/perf_jitdump",
]

# Enables parallel compilation of WebAssembly code.
Expand Down Expand Up @@ -243,7 +243,9 @@ coredump = ["dep:wasm-encoder", "runtime", "std"]

# Export some symbols from the final binary to assist in debugging
# Cranelift-generated code with native debuggers like GDB and LLDB.
debug-builtins = ["dep:wasmtime-jit-debug", "std"]
debug-builtins = [
"wasmtime-jit-debug/gdb_jit_int",
]

# Enable support for executing compiled Wasm modules.
runtime = [
Expand Down Expand Up @@ -334,6 +336,7 @@ std = [
'addr2line?/std',
"dep:rustix",
"wasmtime-jit-icache-coherence",
"wasmtime-jit-debug?/std",
]

# Enables support for the `Store::call_hook` API which enables injecting custom
Expand Down
6 changes: 3 additions & 3 deletions crates/wasmtime/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ fn main() {
custom_cfg("has_virtual_memory", has_virtual_memory);
custom_cfg("has_host_compiler_backend", has_host_compiler_backend);

// If this OS isn't supported or if Cranelift doesn't support the host then
// there's no need to build these helpers.
// If this OS isn't supported and no debug-builtins or if Cranelift doesn't support
// the host or there's no need to build these helpers.
#[cfg(feature = "runtime")]
if supported_os && has_host_compiler_backend {
if has_host_compiler_backend && (supported_os || cfg!(feature = "debug-builtins")) {
build_c_helpers();
}

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 @@ -109,7 +109,7 @@ impl Engine {
#[cfg(has_native_signals)]
crate::runtime::vm::init_traps(config.macos_use_mach_ports);
if !cfg!(miri) {
#[cfg(all(has_host_compiler_backend, feature = "debug-builtins"))]
#[cfg(feature = "debug-builtins")]
crate::runtime::vm::debug_builtins::init();
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/runtime/vm/debug_builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ static mut VMCTX_AND_MEMORY: (NonNull<VMContext>, usize) = (NonNull::dangling(),
#[versioned_export]
pub unsafe extern "C" fn resolve_vmctx_memory_ptr(p: *const u32) -> *const u8 {
unsafe {
let ptr = std::ptr::read(p);
let ptr = core::ptr::read(p);
assert!(
VMCTX_AND_MEMORY.0 != NonNull::dangling(),
"must call `__vmctx->set()` before resolving Wasm pointers"
Expand Down