wasmtime_jit_debug/
gdb_jit_int.rs

1//! The GDB's JIT compilation interface. The low level module that exposes
2//! the __jit_debug_register_code() and __jit_debug_descriptor to register
3//! or unregister generated object images with debuggers.
4
5use std::pin::Pin;
6use std::ptr;
7use std::sync::Mutex;
8use wasmtime_versioned_export_macros::versioned_link;
9
10#[repr(C)]
11struct JITCodeEntry {
12    next_entry: *mut JITCodeEntry,
13    prev_entry: *mut JITCodeEntry,
14    symfile_addr: *const u8,
15    symfile_size: u64,
16}
17
18const JIT_NOACTION: u32 = 0;
19const JIT_REGISTER_FN: u32 = 1;
20const JIT_UNREGISTER_FN: u32 = 2;
21
22#[repr(C)]
23struct JITDescriptor {
24    version: u32,
25    action_flag: u32,
26    relevant_entry: *mut JITCodeEntry,
27    first_entry: *mut JITCodeEntry,
28}
29
30unsafe extern "C" {
31    #[versioned_link]
32    fn wasmtime_jit_debug_descriptor() -> *mut JITDescriptor;
33    fn __jit_debug_register_code();
34}
35
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.
42static GDB_REGISTRATION: Mutex<()> = Mutex::new(());
43
44/// Registration for JIT image
45pub struct GdbJitImageRegistration {
46    entry: Pin<Box<JITCodeEntry>>,
47    file: Pin<Box<[u8]>>,
48}
49
50impl GdbJitImageRegistration {
51    /// Registers JIT image using __jit_debug_register_code
52    pub fn register(file: Vec<u8>) -> Self {
53        let file = Pin::new(file.into_boxed_slice());
54
55        // Create a code entry for the file, which gives the start and size
56        // of the symbol file.
57        let mut entry = Pin::new(Box::new(JITCodeEntry {
58            next_entry: ptr::null_mut(),
59            prev_entry: ptr::null_mut(),
60            symfile_addr: file.as_ptr(),
61            symfile_size: file.len() as u64,
62        }));
63
64        unsafe {
65            register_gdb_jit_image(&mut *entry);
66        }
67
68        Self { entry, file }
69    }
70
71    /// JIT image used in registration
72    pub fn file(&self) -> &[u8] {
73        &self.file
74    }
75}
76
77impl Drop for GdbJitImageRegistration {
78    fn drop(&mut self) {
79        unsafe {
80            unregister_gdb_jit_image(&mut *self.entry);
81        }
82    }
83}
84
85unsafe impl Send for GdbJitImageRegistration {}
86unsafe impl Sync for GdbJitImageRegistration {}
87
88unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) {
89    unsafe {
90        let _lock = GDB_REGISTRATION.lock().unwrap();
91        let desc = &mut *wasmtime_jit_debug_descriptor();
92
93        // Add it to the linked list in the JIT descriptor.
94        (*entry).next_entry = desc.first_entry;
95        if !desc.first_entry.is_null() {
96            (*desc.first_entry).prev_entry = entry;
97        }
98        desc.first_entry = entry;
99        // Point the relevant_entry field of the descriptor at the entry.
100        desc.relevant_entry = entry;
101        // Set action_flag to JIT_REGISTER and call __jit_debug_register_code.
102        desc.action_flag = JIT_REGISTER_FN;
103        __jit_debug_register_code();
104
105        desc.action_flag = JIT_NOACTION;
106        desc.relevant_entry = ptr::null_mut();
107    }
108}
109
110unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
111    unsafe {
112        let _lock = GDB_REGISTRATION.lock().unwrap();
113        let desc = &mut *wasmtime_jit_debug_descriptor();
114
115        // Remove the code entry corresponding to the code from the linked list.
116        if !(*entry).prev_entry.is_null() {
117            (*(*entry).prev_entry).next_entry = (*entry).next_entry;
118        } else {
119            desc.first_entry = (*entry).next_entry;
120        }
121        if !(*entry).next_entry.is_null() {
122            (*(*entry).next_entry).prev_entry = (*entry).prev_entry;
123        }
124        // Point the relevant_entry field of the descriptor at the code entry.
125        desc.relevant_entry = entry;
126        // Set action_flag to JIT_UNREGISTER and call __jit_debug_register_code.
127        desc.action_flag = JIT_UNREGISTER_FN;
128        __jit_debug_register_code();
129
130        desc.action_flag = JIT_NOACTION;
131        desc.relevant_entry = ptr::null_mut();
132    }
133}