Skip to content
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
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/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