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    let _lock = GDB_REGISTRATION.lock().unwrap();
90    let desc = &mut *wasmtime_jit_debug_descriptor();
91
92    // Add it to the linked list in the JIT descriptor.
93    (*entry).next_entry = desc.first_entry;
94    if !desc.first_entry.is_null() {
95        (*desc.first_entry).prev_entry = entry;
96    }
97    desc.first_entry = entry;
98    // Point the relevant_entry field of the descriptor at the entry.
99    desc.relevant_entry = entry;
100    // Set action_flag to JIT_REGISTER and call __jit_debug_register_code.
101    desc.action_flag = JIT_REGISTER_FN;
102    __jit_debug_register_code();
103
104    desc.action_flag = JIT_NOACTION;
105    desc.relevant_entry = ptr::null_mut();
106}
107
108unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
109    let _lock = GDB_REGISTRATION.lock().unwrap();
110    let desc = &mut *wasmtime_jit_debug_descriptor();
111
112    // Remove the code entry corresponding to the code from the linked list.
113    if !(*entry).prev_entry.is_null() {
114        (*(*entry).prev_entry).next_entry = (*entry).next_entry;
115    } else {
116        desc.first_entry = (*entry).next_entry;
117    }
118    if !(*entry).next_entry.is_null() {
119        (*(*entry).next_entry).prev_entry = (*entry).prev_entry;
120    }
121    // Point the relevant_entry field of the descriptor at the code entry.
122    desc.relevant_entry = entry;
123    // Set action_flag to JIT_UNREGISTER and call __jit_debug_register_code.
124    desc.action_flag = JIT_UNREGISTER_FN;
125    __jit_debug_register_code();
126
127    desc.action_flag = JIT_NOACTION;
128    desc.relevant_entry = ptr::null_mut();
129}