Skip to content

Commit 6bb53bf

Browse files
committed
Allow compiling debug-builtins in no_std environment to enable gdb jit
- Make jit-debug crate #![no_std] when `std` feature is not enabled - Make gdb_jit_int module build in no_std environment - Use std when perf_jitdebug is enabled because the perf_jitdebug module does not run in no_std environment - Change debug-builtins feature to only enable gdb_jit_int - The perf_jitdebug feature is enabled in profiling mode only Signed-off-by: Doru Blânzeanu <[email protected]>
1 parent 88079b4 commit 6bb53bf

File tree

8 files changed

+86
-21
lines changed

8 files changed

+86
-21
lines changed

crates/jit-debug/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ wasmtime-versioned-export-macros = { workspace = true }
2626
rustix = { workspace = true, features = ["mm", "time"], optional = true }
2727

2828
[features]
29+
std = []
2930
gdb_jit_int = []
30-
perf_jitdump = ["rustix", "object"]
31+
perf_jitdump = ["rustix", "object", "std"]

crates/jit-debug/src/gdb_jit_int.rs

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
//! the __jit_debug_register_code() and __jit_debug_descriptor to register
33
//! or unregister generated object images with debuggers.
44
5-
use std::pin::Pin;
6-
use std::ptr;
7-
use std::sync::Mutex;
5+
#[cfg(not(feature = "std"))]
6+
use alloc::{boxed::Box, vec::Vec};
7+
#[cfg(not(feature = "std"))]
8+
use core::{pin::Pin, ptr};
9+
#[cfg(feature = "std")]
10+
use std::{boxed::Box, pin::Pin, ptr, vec::Vec};
811
use wasmtime_versioned_export_macros::versioned_link;
912

1013
#[repr(C)]
@@ -33,13 +36,60 @@ unsafe extern "C" {
3336
fn __jit_debug_register_code();
3437
}
3538

36-
/// The process controls access to the __jit_debug_descriptor by itself --
37-
/// the GDB/LLDB accesses this structure and its data at the process startup
38-
/// and when paused in __jit_debug_register_code.
39-
///
40-
/// The GDB_REGISTRATION lock is needed for GdbJitImageRegistration to protect
41-
/// access to the __jit_debug_descriptor within this process.
42-
static GDB_REGISTRATION: Mutex<()> = Mutex::new(());
39+
#[cfg(feature = "std")]
40+
mod gdb_registration {
41+
use std::sync::Mutex;
42+
43+
/// The process controls access to the __jit_debug_descriptor by itself --
44+
/// the GDB/LLDB accesses this structure and its data at the process startup
45+
/// and when paused in __jit_debug_register_code.
46+
///
47+
/// The GDB_REGISTRATION lock is needed for GdbJitImageRegistration to protect
48+
/// access to the __jit_debug_descriptor within this process.
49+
pub static GDB_REGISTRATION: Mutex<()> = Mutex::new(());
50+
51+
/// The lock guard for the GDB registration lock.
52+
/// The field is not used directly, but it is needed to ensure that the lock
53+
/// is held until the `LockGuard` is dropped.
54+
#[allow(dead_code, reason = "field used to hold the lock until the end of the scope")]
55+
pub struct LockGuard<'a>(std::sync::MutexGuard<'a, ()>);
56+
57+
pub fn lock() -> LockGuard<'static> {
58+
LockGuard(GDB_REGISTRATION.lock().unwrap())
59+
}
60+
}
61+
62+
#[cfg(not(feature = "std"))]
63+
mod gdb_registration {
64+
use core::sync::atomic::{AtomicBool, Ordering};
65+
66+
/// In no_std mode, we use an atomic boolean to control access to the
67+
/// __jit_debug_descriptor. This is a simple lock mechanism.
68+
pub static GDB_REGISTRATION: AtomicBool = AtomicBool::new(false);
69+
70+
/// The lock guard for the GDB registration lock.
71+
pub struct LockGuard;
72+
73+
/// When the `LockGuard` is dropped, it releases the lock by setting
74+
/// `GDB_REGISTRATION` to false.
75+
impl Drop for LockGuard {
76+
fn drop(&mut self) {
77+
GDB_REGISTRATION.store(false, Ordering::Release);
78+
}
79+
}
80+
81+
/// Locks the GDB registration lock. If the lock is already held, it panics
82+
pub fn lock() -> LockGuard {
83+
// Try to acquire the lock. If already held, panic as per PR feedback.
84+
if GDB_REGISTRATION
85+
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
86+
.is_err()
87+
{
88+
panic!("GDB JIT registration lock contention detected in no_std mode");
89+
}
90+
LockGuard
91+
}
92+
}
4393

4494
/// Registration for JIT image
4595
pub struct GdbJitImageRegistration {
@@ -87,7 +137,7 @@ unsafe impl Sync for GdbJitImageRegistration {}
87137

88138
unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) {
89139
unsafe {
90-
let _lock = GDB_REGISTRATION.lock().unwrap();
140+
let _lock = gdb_registration::lock();
91141
let desc = &mut *wasmtime_jit_debug_descriptor();
92142

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

110160
unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
111161
unsafe {
112-
let _lock = GDB_REGISTRATION.lock().unwrap();
162+
let _lock = gdb_registration::lock();
113163
let desc = &mut *wasmtime_jit_debug_descriptor();
114164

115165
// Remove the code entry corresponding to the code from the linked list.

crates/jit-debug/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
//! > you're interested in using this feel free to file an issue on the
55
//! > Wasmtime repository to start a discussion about doing so, but otherwise
66
//! > be aware that your usage of this crate is not supported.
7+
#![no_std]
8+
9+
#[cfg(all(feature = "gdb_jit_int", not(feature = "std")))]
10+
extern crate alloc;
11+
#[cfg(feature = "std")]
12+
extern crate std;
713

814
#[cfg(feature = "gdb_jit_int")]
915
pub mod gdb_jit_int;

crates/jit-debug/src/perf_jitdump.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use std::io;
1616
use std::io::Write;
1717
use std::path::Path;
1818
use std::ptr;
19+
use std::string::String;
20+
use std::vec::Vec;
1921
use std::{mem, process};
2022

2123
/// Defines jitdump record types

crates/wasmtime/Cargo.toml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ all-features = true
1919
[dependencies]
2020
wasmtime-asm-macros = { workspace = true, optional = true }
2121
wasmtime-environ = { workspace = true }
22-
wasmtime-jit-debug = { workspace = true, features = ["gdb_jit_int", "perf_jitdump"], optional = true }
22+
wasmtime-jit-debug = { workspace = true, features = [], optional = true }
2323
wasmtime-jit-icache-coherence = { workspace = true, optional = true }
2424
wasmtime-cache = { workspace = true, optional = true }
2525
wasmtime-fiber = { workspace = true, optional = true }
@@ -139,6 +139,8 @@ default = [
139139
'addr2line',
140140
'coredump',
141141
'debug-builtins',
142+
'wasmtime-jit-debug/perf_jitdump',
143+
'wasmtime-jit-debug/std',
142144
'runtime',
143145
'component-model',
144146
'threads',
@@ -175,12 +177,14 @@ incremental-cache = ["wasmtime-cranelift?/incremental-cache", "std"]
175177
# Enables support for profiling guest modules.
176178
profiling = [
177179
"dep:fxprof-processed-profile",
178-
"dep:wasmtime-jit-debug",
179180
"dep:ittapi",
180181
"dep:rustix",
181182
"rustix/thread",
182183
"dep:serde_json",
183184
"std",
185+
"wasmtime-jit-debug/gdb_jit_int",
186+
"wasmtime-jit-debug/perf_jitdump",
187+
"wasmtime-jit-debug/std",
184188
]
185189

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

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

248254
# Enable support for executing compiled Wasm modules.
249255
runtime = [

crates/wasmtime/build.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ fn main() {
2727
custom_cfg("has_virtual_memory", has_virtual_memory);
2828
custom_cfg("has_host_compiler_backend", has_host_compiler_backend);
2929

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

crates/wasmtime/src/engine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl Engine {
109109
#[cfg(has_native_signals)]
110110
crate::runtime::vm::init_traps(config.macos_use_mach_ports);
111111
if !cfg!(miri) {
112-
#[cfg(all(has_host_compiler_backend, feature = "debug-builtins"))]
112+
#[cfg(feature = "debug-builtins")]
113113
crate::runtime::vm::debug_builtins::init();
114114
}
115115
}

crates/wasmtime/src/runtime/vm/debug_builtins.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ static mut VMCTX_AND_MEMORY: (NonNull<VMContext>, usize) = (NonNull::dangling(),
1414
#[versioned_export]
1515
pub unsafe extern "C" fn resolve_vmctx_memory_ptr(p: *const u32) -> *const u8 {
1616
unsafe {
17-
let ptr = std::ptr::read(p);
17+
let ptr = core::ptr::read(p);
1818
assert!(
1919
VMCTX_AND_MEMORY.0 != NonNull::dangling(),
2020
"must call `__vmctx->set()` before resolving Wasm pointers"

0 commit comments

Comments
 (0)