Skip to main content

substrate_wasmtime_runtime/
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::ptr;
6use std::sync::{
7    atomic::{AtomicPtr, Ordering},
8    Mutex,
9};
10
11#[repr(C)]
12struct JITCodeEntry {
13    next_entry: *mut JITCodeEntry,
14    prev_entry: *mut JITCodeEntry,
15    symfile_addr: *const u8,
16    symfile_size: u64,
17}
18
19const JIT_NOACTION: u32 = 0;
20const JIT_REGISTER_FN: u32 = 1;
21const JIT_UNREGISTER_FN: u32 = 2;
22
23lazy_static::lazy_static! {
24    pub static ref JIT_DESCRIPTOR_LOCK: Mutex<()> = Mutex::new(());
25}
26
27#[repr(C)]
28struct JITDescriptor {
29    version: u32,
30    action_flag: u32,
31    relevant_entry: *mut JITCodeEntry,
32    first_entry: *mut JITCodeEntry,
33}
34
35#[no_mangle]
36#[used]
37static mut __jit_debug_descriptor: JITDescriptor = JITDescriptor {
38    version: 1,
39    action_flag: JIT_NOACTION,
40    relevant_entry: ptr::null_mut(),
41    first_entry: ptr::null_mut(),
42};
43
44#[no_mangle]
45#[inline(never)]
46extern "C" fn __jit_debug_register_code() {
47    // Hack to not allow inlining even when Rust wants to do it in release mode.
48    let x = 3;
49    unsafe {
50        std::ptr::read_volatile(&x);
51    }
52}
53
54/// Registeration for JIT image
55pub struct GdbJitImageRegistration {
56    entry: AtomicPtr<JITCodeEntry>,
57    file: Vec<u8>,
58}
59
60impl GdbJitImageRegistration {
61    /// Registers JIT image using __jit_debug_register_code
62    pub fn register(file: Vec<u8>) -> Self {
63        Self {
64            entry: unsafe { register_gdb_jit_image(&file) },
65            file,
66        }
67    }
68
69    /// JIT image used in registration
70    pub fn file(&self) -> &[u8] {
71        &self.file
72    }
73}
74
75impl Drop for GdbJitImageRegistration {
76    fn drop(&mut self) {
77        unsafe {
78            unregister_gdb_jit_image(self.entry.load(Ordering::SeqCst));
79        }
80    }
81}
82
83unsafe fn register_gdb_jit_image(file: &[u8]) -> AtomicPtr<JITCodeEntry> {
84    // Create a code entry for the file, which gives the start and size of the symbol file.
85    let _lock = JIT_DESCRIPTOR_LOCK.lock();
86    let entry = AtomicPtr::new(Box::into_raw(Box::new(JITCodeEntry {
87        next_entry: __jit_debug_descriptor.first_entry,
88        prev_entry: ptr::null_mut(),
89        symfile_addr: file.as_ptr(),
90        symfile_size: file.len() as u64,
91    })));
92    // Add it to the linked list in the JIT descriptor.
93    if !__jit_debug_descriptor.first_entry.is_null() {
94        (*__jit_debug_descriptor.first_entry).prev_entry = entry.load(Ordering::SeqCst);
95    }
96    __jit_debug_descriptor.first_entry = entry.load(Ordering::SeqCst);
97    // Point the relevant_entry field of the descriptor at the entry.
98    __jit_debug_descriptor.relevant_entry = entry.load(Ordering::SeqCst);
99    // Set action_flag to JIT_REGISTER and call __jit_debug_register_code.
100    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
101    __jit_debug_register_code();
102
103    __jit_debug_descriptor.action_flag = JIT_NOACTION;
104    __jit_debug_descriptor.relevant_entry = ptr::null_mut();
105    entry
106}
107
108unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
109    // Remove the code entry corresponding to the code from the linked list.
110    let _lock = JIT_DESCRIPTOR_LOCK.lock();
111    if !(*entry).prev_entry.is_null() {
112        (*(*entry).prev_entry).next_entry = (*entry).next_entry;
113    } else {
114        __jit_debug_descriptor.first_entry = (*entry).next_entry;
115    }
116    if !(*entry).next_entry.is_null() {
117        (*(*entry).next_entry).prev_entry = (*entry).prev_entry;
118    }
119    // Point the relevant_entry field of the descriptor at the code entry.
120    __jit_debug_descriptor.relevant_entry = entry;
121    // Set action_flag to JIT_UNREGISTER and call __jit_debug_register_code.
122    __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
123    __jit_debug_register_code();
124
125    __jit_debug_descriptor.action_flag = JIT_NOACTION;
126    __jit_debug_descriptor.relevant_entry = ptr::null_mut();
127    let _box = Box::from_raw(entry);
128}