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 once_cell::sync::Lazy;
6use std::pin::Pin;
7use std::ptr;
8use std::sync::Mutex;
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
30extern "C" {
31    fn wasmtime_jit_debug_descriptor() -> *mut JITDescriptor;
32    fn __jit_debug_register_code();
33}
34
35/// The process controls access to the __jit_debug_descriptor by itself --
36/// the GDB/LLDB accesses this structure and its data at the process startup
37/// and when paused in __jit_debug_register_code.
38///
39/// The GDB_REGISTRATION lock is needed for GdbJitImageRegistration to protect
40/// access to the __jit_debug_descriptor within this process.
41static GDB_REGISTRATION: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(Default::default()));
42
43/// Registeration for JIT image
44pub struct GdbJitImageRegistration {
45    entry: Pin<Box<JITCodeEntry>>,
46    file: Pin<Box<[u8]>>,
47}
48
49impl GdbJitImageRegistration {
50    /// Registers JIT image using __jit_debug_register_code
51    pub fn register(file: Vec<u8>) -> Self {
52        let file = Pin::new(file.into_boxed_slice());
53
54        // Create a code entry for the file, which gives the start and size
55        // of the symbol file.
56        let mut entry = Pin::new(Box::new(JITCodeEntry {
57            next_entry: ptr::null_mut(),
58            prev_entry: ptr::null_mut(),
59            symfile_addr: file.as_ptr(),
60            symfile_size: file.len() as u64,
61        }));
62
63        unsafe {
64            register_gdb_jit_image(&mut *entry);
65        }
66
67        Self { entry, file }
68    }
69
70    /// JIT image used in registration
71    pub fn file(&self) -> &[u8] {
72        &self.file
73    }
74}
75
76impl Drop for GdbJitImageRegistration {
77    fn drop(&mut self) {
78        unsafe {
79            unregister_gdb_jit_image(&mut *self.entry);
80        }
81    }
82}
83
84unsafe impl Send for GdbJitImageRegistration {}
85unsafe impl Sync for GdbJitImageRegistration {}
86
87unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) {
88    let _lock = GDB_REGISTRATION.lock().unwrap();
89    let desc = &mut *wasmtime_jit_debug_descriptor();
90
91    // Add it to the linked list in the JIT descriptor.
92    (*entry).next_entry = desc.first_entry;
93    if !desc.first_entry.is_null() {
94        (*desc.first_entry).prev_entry = entry;
95    }
96    desc.first_entry = entry;
97    // Point the relevant_entry field of the descriptor at the entry.
98    desc.relevant_entry = entry;
99    // Set action_flag to JIT_REGISTER and call __jit_debug_register_code.
100    desc.action_flag = JIT_REGISTER_FN;
101    __jit_debug_register_code();
102
103    desc.action_flag = JIT_NOACTION;
104    desc.relevant_entry = ptr::null_mut();
105}
106
107unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
108    let _lock = GDB_REGISTRATION.lock().unwrap();
109    let desc = &mut *wasmtime_jit_debug_descriptor();
110
111    // Remove the code entry corresponding to the code from the linked list.
112    if !(*entry).prev_entry.is_null() {
113        (*(*entry).prev_entry).next_entry = (*entry).next_entry;
114    } else {
115        desc.first_entry = (*entry).next_entry;
116    }
117    if !(*entry).next_entry.is_null() {
118        (*(*entry).next_entry).prev_entry = (*entry).prev_entry;
119    }
120    // Point the relevant_entry field of the descriptor at the code entry.
121    desc.relevant_entry = entry;
122    // Set action_flag to JIT_UNREGISTER and call __jit_debug_register_code.
123    desc.action_flag = JIT_UNREGISTER_FN;
124    __jit_debug_register_code();
125
126    desc.action_flag = JIT_NOACTION;
127    desc.relevant_entry = ptr::null_mut();
128}