use std::ptr;
use std::sync::{
atomic::{AtomicPtr, Ordering},
Mutex,
};
#[repr(C)]
struct JITCodeEntry {
next_entry: *mut JITCodeEntry,
prev_entry: *mut JITCodeEntry,
symfile_addr: *const u8,
symfile_size: u64,
}
const JIT_NOACTION: u32 = 0;
const JIT_REGISTER_FN: u32 = 1;
const JIT_UNREGISTER_FN: u32 = 2;
lazy_static::lazy_static! {
pub static ref JIT_DESCRIPTOR_LOCK: Mutex<()> = Mutex::new(());
}
#[repr(C)]
struct JITDescriptor {
version: u32,
action_flag: u32,
relevant_entry: *mut JITCodeEntry,
first_entry: *mut JITCodeEntry,
}
#[no_mangle]
#[used]
static mut __jit_debug_descriptor: JITDescriptor = JITDescriptor {
version: 1,
action_flag: JIT_NOACTION,
relevant_entry: ptr::null_mut(),
first_entry: ptr::null_mut(),
};
#[no_mangle]
#[inline(never)]
extern "C" fn __jit_debug_register_code() {
let x = 3;
unsafe {
std::ptr::read_volatile(&x);
}
}
pub struct GdbJitImageRegistration {
entry: AtomicPtr<JITCodeEntry>,
file: Vec<u8>,
}
impl GdbJitImageRegistration {
pub fn register(file: Vec<u8>) -> Self {
Self {
entry: unsafe { register_gdb_jit_image(&file) },
file,
}
}
pub fn file(&self) -> &[u8] {
&self.file
}
}
impl Drop for GdbJitImageRegistration {
fn drop(&mut self) {
unsafe {
unregister_gdb_jit_image(self.entry.load(Ordering::SeqCst));
}
}
}
unsafe fn register_gdb_jit_image(file: &[u8]) -> AtomicPtr<JITCodeEntry> {
let _lock = JIT_DESCRIPTOR_LOCK.lock();
let entry = AtomicPtr::new(Box::into_raw(Box::new(JITCodeEntry {
next_entry: __jit_debug_descriptor.first_entry,
prev_entry: ptr::null_mut(),
symfile_addr: file.as_ptr(),
symfile_size: file.len() as u64,
})));
if !__jit_debug_descriptor.first_entry.is_null() {
(*__jit_debug_descriptor.first_entry).prev_entry = entry.load(Ordering::SeqCst);
}
__jit_debug_descriptor.first_entry = entry.load(Ordering::SeqCst);
__jit_debug_descriptor.relevant_entry = entry.load(Ordering::SeqCst);
__jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
__jit_debug_register_code();
__jit_debug_descriptor.action_flag = JIT_NOACTION;
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
entry
}
unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
let _lock = JIT_DESCRIPTOR_LOCK.lock();
if !(*entry).prev_entry.is_null() {
(*(*entry).prev_entry).next_entry = (*entry).next_entry;
} else {
__jit_debug_descriptor.first_entry = (*entry).next_entry;
}
if !(*entry).next_entry.is_null() {
(*(*entry).next_entry).prev_entry = (*entry).prev_entry;
}
__jit_debug_descriptor.relevant_entry = entry;
__jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
__jit_debug_register_code();
__jit_debug_descriptor.action_flag = JIT_NOACTION;
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
let _box = Box::from_raw(entry);
}