2020-02-18 17:31:12 -08:00
|
|
|
//! Code for interacting with the
|
2020-02-21 14:33:32 -08:00
|
|
|
//! [GDB JIT interface](https://sourceware.org/gdb/current/onlinedocs/gdb.html#JIT-Interface).
|
2020-02-18 17:31:12 -08:00
|
|
|
|
2020-02-21 14:33:32 -08:00
|
|
|
use lazy_static::lazy_static;
|
|
|
|
|
|
|
|
use std::os::raw::c_char;
|
2020-02-03 16:01:23 -08:00
|
|
|
use std::ptr;
|
2020-02-21 14:33:32 -08:00
|
|
|
use std::sync::{Arc, Mutex};
|
2020-02-03 16:01:23 -08:00
|
|
|
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Entrypoint that the debugger will use to trigger a read from the
|
|
|
|
/// [`__jit_debug_descriptor`] global variable.
|
|
|
|
///
|
|
|
|
/// The debugger will wait for this function to be called and then take
|
|
|
|
/// control to read the data we prepared.
|
2020-02-20 13:06:50 -08:00
|
|
|
// Implementation of this function is derived from wasmtime and is licensed under
|
2020-02-18 17:31:12 -08:00
|
|
|
// the Apache 2.0 license. See ATTRIBUTIONS.md for full license and more
|
|
|
|
// information.
|
2020-02-26 18:32:40 -08:00
|
|
|
#[cfg(not(feature = "generate-debug-information-no-export-symbols"))]
|
2020-02-11 09:52:21 -08:00
|
|
|
#[no_mangle]
|
2020-02-03 16:01:23 -08:00
|
|
|
#[inline(never)]
|
2020-02-11 09:52:21 -08:00
|
|
|
extern "C" fn __jit_debug_register_code() {
|
2020-02-18 17:31:12 -08:00
|
|
|
// This code exists to prevent optimization of this function so that the
|
|
|
|
// GDB JIT interface behaves as expected
|
2020-02-21 14:33:32 -08:00
|
|
|
let x = 42;
|
2020-02-11 09:52:21 -08:00
|
|
|
unsafe {
|
|
|
|
std::ptr::read_volatile(&x);
|
|
|
|
}
|
2020-02-03 16:01:23 -08:00
|
|
|
}
|
|
|
|
|
2020-02-18 17:31:12 -08:00
|
|
|
/// The operation that the debugger should perform with the entry that we gave it.
|
2020-02-03 16:01:23 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
#[repr(u32)]
|
2020-02-21 14:33:32 -08:00
|
|
|
enum JitAction {
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Do nothing.
|
2020-02-21 14:33:32 -08:00
|
|
|
NoAction = 0,
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Register the given code.
|
2020-02-21 14:33:32 -08:00
|
|
|
RegisterFn = 1,
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Unregister the given code.
|
2020-02-21 14:33:32 -08:00
|
|
|
UnregisterFn = 2,
|
2020-02-11 09:52:21 -08:00
|
|
|
}
|
2020-02-03 16:01:23 -08:00
|
|
|
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Node of the doubly linked list that the GDB JIT interface reads from.
|
2020-02-03 16:01:23 -08:00
|
|
|
#[repr(C)]
|
2020-02-21 14:33:32 -08:00
|
|
|
struct JitCodeEntry {
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Next entry in the linked list.
|
2020-02-21 14:33:32 -08:00
|
|
|
next: *mut Self,
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Previous entry in the linked list.
|
2020-02-21 14:33:32 -08:00
|
|
|
prev: *mut Self,
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Pointer to the data we want the debugger to read.
|
2020-02-21 14:33:32 -08:00
|
|
|
symfile_addr: *const c_char,
|
2020-02-18 17:31:12 -08:00
|
|
|
/// The amount of data at the `symfile_addr` pointer.
|
2020-02-03 16:01:23 -08:00
|
|
|
symfile_size: u64,
|
|
|
|
}
|
|
|
|
|
2020-02-21 14:33:32 -08:00
|
|
|
impl Default for JitCodeEntry {
|
2020-02-03 16:01:23 -08:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
next: ptr::null_mut(),
|
|
|
|
prev: ptr::null_mut(),
|
2020-02-21 14:33:32 -08:00
|
|
|
symfile_addr: ptr::null(),
|
2020-02-03 16:01:23 -08:00
|
|
|
symfile_size: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Head node of the doubly linked list that the GDB JIT interface expects.
|
2020-02-03 16:01:23 -08:00
|
|
|
#[no_mangle]
|
|
|
|
#[repr(C)]
|
2020-02-21 14:33:32 -08:00
|
|
|
struct JitDebugDescriptor {
|
|
|
|
/// The version of the JIT interface to use.
|
2020-02-03 16:01:23 -08:00
|
|
|
version: u32,
|
2020-02-21 14:33:32 -08:00
|
|
|
/// Which action to perform.
|
|
|
|
action_flag: JitAction,
|
2020-02-18 17:31:12 -08:00
|
|
|
/// The entry in the list that the `action_flag` applies to.
|
2020-02-21 14:33:32 -08:00
|
|
|
relevant_entry: *mut JitCodeEntry,
|
2020-02-18 17:31:12 -08:00
|
|
|
/// The first entry in the doubly linked list.
|
2020-02-21 14:33:32 -08:00
|
|
|
first_entry: *mut JitCodeEntry,
|
2020-02-03 16:01:23 -08:00
|
|
|
}
|
|
|
|
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Global variable that the GDB JIT interface will read the data from.
|
2020-02-21 14:33:32 -08:00
|
|
|
/// The data is in the form of a doubly linked list. This global variable acts
|
2020-02-18 17:31:12 -08:00
|
|
|
/// as a head node with extra information about the operation that we want the
|
|
|
|
/// debugger to perform.
|
2020-02-26 18:32:40 -08:00
|
|
|
#[cfg(not(feature = "generate-debug-information-no-export-symbols"))]
|
2020-02-03 16:01:23 -08:00
|
|
|
#[no_mangle]
|
|
|
|
#[allow(non_upper_case_globals)]
|
2020-02-21 14:33:32 -08:00
|
|
|
static mut __jit_debug_descriptor: JitDebugDescriptor = JitDebugDescriptor {
|
2020-02-03 16:01:23 -08:00
|
|
|
version: 1,
|
2020-02-21 14:33:32 -08:00
|
|
|
action_flag: JitAction::NoAction,
|
2020-02-03 16:01:23 -08:00
|
|
|
relevant_entry: ptr::null_mut(),
|
|
|
|
first_entry: ptr::null_mut(),
|
|
|
|
};
|
|
|
|
|
2020-02-26 18:32:40 -08:00
|
|
|
#[cfg(feature = "generate-debug-information-no-export-symbols")]
|
|
|
|
extern "C" {
|
2020-02-27 14:22:26 -08:00
|
|
|
#[no_mangle]
|
2020-02-26 18:32:40 -08:00
|
|
|
static mut __jit_debug_descriptor: JitDebugDescriptor;
|
2020-02-27 14:22:26 -08:00
|
|
|
#[no_mangle]
|
2020-02-26 18:32:40 -08:00
|
|
|
fn __jit_debug_register_code();
|
|
|
|
}
|
|
|
|
|
2020-02-21 14:33:32 -08:00
|
|
|
lazy_static! {
|
|
|
|
/// Global lock on [`__jit_debug_descriptor`]. Acquire this lock when
|
|
|
|
/// reading or writing to the global variable. This includes calls to
|
|
|
|
/// [`__jit_debug_register_code`] which may cause a debugger to read from
|
|
|
|
/// the global variable.
|
|
|
|
static ref JIT_DEBUG_DESCRIPTOR_LOCK: Mutex<()> = Mutex::new(());
|
|
|
|
}
|
|
|
|
|
2020-02-03 16:01:23 -08:00
|
|
|
/// Prepend an item to the front of the `__jit_debug_descriptor` entry list
|
|
|
|
///
|
|
|
|
/// # Safety
|
2020-02-21 14:33:32 -08:00
|
|
|
/// - Access to underlying global variable is unsynchronized: acquire a lock on
|
|
|
|
/// [`JIT_DEBUG_DESCRIPTOR_LOCK`] before calling this function.
|
|
|
|
/// - Pointer to [`JitCodeEntry`] must point to a valid entry.
|
|
|
|
unsafe fn push_front(jce: *mut JitCodeEntry) {
|
2020-02-03 16:01:23 -08:00
|
|
|
if __jit_debug_descriptor.first_entry.is_null() {
|
|
|
|
__jit_debug_descriptor.first_entry = jce;
|
|
|
|
} else {
|
|
|
|
let old_first = __jit_debug_descriptor.first_entry;
|
2020-02-21 14:33:32 -08:00
|
|
|
assert!((*old_first).prev.is_null());
|
2020-02-03 16:01:23 -08:00
|
|
|
(*jce).next = old_first;
|
|
|
|
(*old_first).prev = jce;
|
|
|
|
__jit_debug_descriptor.first_entry = jce;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-18 16:51:02 -08:00
|
|
|
/// Removes an entry from the doubly linked list, updating both nodes that it's
|
|
|
|
/// connected to.
|
|
|
|
///
|
|
|
|
/// # Safety
|
2020-02-21 14:33:32 -08:00
|
|
|
/// - Access to underlying global variable is unsynchronized: acquire a lock on
|
|
|
|
/// [`JIT_DEBUG_DESCRIPTOR_LOCK`] before calling this function.
|
|
|
|
/// - Pointer to [`JitCodeEntry`] must point to a valid entry.
|
|
|
|
unsafe fn remove_node(jce: *mut JitCodeEntry) {
|
2020-02-18 16:51:02 -08:00
|
|
|
if __jit_debug_descriptor.first_entry == jce {
|
2020-02-21 14:33:32 -08:00
|
|
|
assert!((*jce).prev.is_null());
|
2020-02-18 16:51:02 -08:00
|
|
|
__jit_debug_descriptor.first_entry = (*jce).next;
|
|
|
|
}
|
|
|
|
if !(*jce).prev.is_null() {
|
|
|
|
(*(*jce).prev).next = (*jce).next;
|
|
|
|
}
|
|
|
|
if !(*jce).next.is_null() {
|
|
|
|
(*(*jce).next).prev = (*jce).prev;
|
|
|
|
}
|
|
|
|
}
|
2020-02-11 09:52:21 -08:00
|
|
|
|
2020-02-18 16:51:02 -08:00
|
|
|
/// Type for implementing Drop on the memory shared with the debugger.
|
|
|
|
#[derive(Debug)]
|
2020-02-21 14:33:32 -08:00
|
|
|
struct JitCodeDebugInfoEntryHandleInner(*mut JitCodeEntry);
|
2020-02-11 09:52:21 -08:00
|
|
|
|
2020-02-21 14:52:28 -08:00
|
|
|
// this is safe because the pointer is never mutated directly and then
|
|
|
|
// [`JIT_DEBUG_DESCRIPTOR_LOCK`] should always be held whenever any mutation
|
|
|
|
// can happen.
|
|
|
|
unsafe impl Send for JitCodeDebugInfoEntryHandleInner {}
|
|
|
|
unsafe impl Sync for JitCodeDebugInfoEntryHandleInner {}
|
|
|
|
|
2020-02-18 16:51:02 -08:00
|
|
|
/// Handle to debug info about JIT code registered with a debugger
|
|
|
|
#[derive(Debug, Clone)]
|
2020-02-21 14:33:32 -08:00
|
|
|
pub(crate) struct JitCodeDebugInfoEntryHandle(Arc<JitCodeDebugInfoEntryHandleInner>);
|
2020-02-03 16:01:23 -08:00
|
|
|
|
2020-02-21 14:33:32 -08:00
|
|
|
impl Drop for JitCodeDebugInfoEntryHandleInner {
|
2020-02-18 16:51:02 -08:00
|
|
|
fn drop(&mut self) {
|
2020-02-21 14:33:32 -08:00
|
|
|
let _guard = JIT_DEBUG_DESCRIPTOR_LOCK.lock().unwrap();
|
2020-02-18 16:51:02 -08:00
|
|
|
unsafe {
|
|
|
|
// unregister the function when dropping the JIT code entry
|
|
|
|
__jit_debug_descriptor.relevant_entry = self.0;
|
2020-02-21 14:33:32 -08:00
|
|
|
__jit_debug_descriptor.action_flag = JitAction::UnregisterFn;
|
2020-02-18 16:51:02 -08:00
|
|
|
__jit_debug_register_code();
|
|
|
|
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
2020-02-21 14:33:32 -08:00
|
|
|
__jit_debug_descriptor.action_flag = JitAction::NoAction;
|
2020-02-18 16:51:02 -08:00
|
|
|
remove_node(self.0);
|
2020-02-21 14:33:32 -08:00
|
|
|
let entry: Box<JitCodeEntry> = Box::from_raw(self.0);
|
2020-02-18 16:51:02 -08:00
|
|
|
Vec::from_raw_parts(
|
2020-02-21 14:33:32 -08:00
|
|
|
entry.symfile_addr as *mut u8,
|
2020-02-18 16:51:02 -08:00
|
|
|
entry.symfile_size as _,
|
|
|
|
entry.symfile_size as _,
|
|
|
|
);
|
|
|
|
}
|
2020-02-03 16:01:23 -08:00
|
|
|
}
|
2020-02-18 16:51:02 -08:00
|
|
|
}
|
2020-02-03 16:01:23 -08:00
|
|
|
|
2020-02-18 16:51:02 -08:00
|
|
|
/// Manager of debug info registered with the debugger.
|
2020-02-26 18:32:40 -08:00
|
|
|
#[derive(Debug, Clone)]
|
2020-02-21 14:33:32 -08:00
|
|
|
pub(crate) struct JitCodeDebugInfoManager {
|
|
|
|
inner: Vec<JitCodeDebugInfoEntryHandle>,
|
2020-02-18 16:51:02 -08:00
|
|
|
}
|
|
|
|
|
2020-02-26 18:32:40 -08:00
|
|
|
impl Default for JitCodeDebugInfoManager {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 14:33:32 -08:00
|
|
|
impl JitCodeDebugInfoManager {
|
2020-02-26 18:32:40 -08:00
|
|
|
pub(crate) fn new() -> Self {
|
|
|
|
unsafe {
|
|
|
|
// ensure we set the version, even if externally linked
|
|
|
|
__jit_debug_descriptor.version = 1;
|
|
|
|
}
|
2020-02-26 19:41:53 -08:00
|
|
|
Self { inner: vec![] }
|
2020-02-26 18:32:40 -08:00
|
|
|
}
|
2020-02-26 19:41:53 -08:00
|
|
|
|
2020-02-18 17:31:12 -08:00
|
|
|
/// Register debug info relating to JIT code with the debugger.
|
2020-02-18 16:51:02 -08:00
|
|
|
pub(crate) fn register_new_jit_code_entry(
|
|
|
|
&mut self,
|
|
|
|
bytes: &[u8],
|
2020-02-21 14:33:32 -08:00
|
|
|
) -> JitCodeDebugInfoEntryHandle {
|
2020-02-18 16:51:02 -08:00
|
|
|
let mut owned_bytes = bytes.iter().cloned().collect::<Vec<u8>>();
|
|
|
|
// ensure length == capacity to simplify memory freeing code
|
|
|
|
owned_bytes.shrink_to_fit();
|
|
|
|
let ptr = owned_bytes.as_mut_ptr();
|
|
|
|
let len = owned_bytes.len();
|
|
|
|
|
|
|
|
std::mem::forget(owned_bytes);
|
|
|
|
|
2020-02-21 14:33:32 -08:00
|
|
|
let entry: *mut JitCodeEntry = Box::into_raw(Box::new(JitCodeEntry {
|
|
|
|
symfile_addr: ptr as *const _,
|
2020-02-18 16:51:02 -08:00
|
|
|
symfile_size: len as _,
|
2020-02-21 14:33:32 -08:00
|
|
|
..JitCodeEntry::default()
|
2020-02-18 16:51:02 -08:00
|
|
|
}));
|
|
|
|
|
|
|
|
unsafe {
|
2020-02-21 14:33:32 -08:00
|
|
|
let _guard = JIT_DEBUG_DESCRIPTOR_LOCK.lock().unwrap();
|
2020-02-18 16:51:02 -08:00
|
|
|
push_front(entry);
|
|
|
|
__jit_debug_descriptor.relevant_entry = entry;
|
2020-02-21 14:33:32 -08:00
|
|
|
__jit_debug_descriptor.action_flag = JitAction::RegisterFn;
|
2020-02-18 16:51:02 -08:00
|
|
|
__jit_debug_register_code();
|
|
|
|
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
2020-02-21 14:33:32 -08:00
|
|
|
__jit_debug_descriptor.action_flag = JitAction::NoAction;
|
2020-02-18 16:51:02 -08:00
|
|
|
}
|
|
|
|
|
2020-02-21 14:33:32 -08:00
|
|
|
let handle = JitCodeDebugInfoEntryHandle(Arc::new(JitCodeDebugInfoEntryHandleInner(entry)));
|
2020-02-18 16:51:02 -08:00
|
|
|
self.inner.push(handle.clone());
|
|
|
|
|
|
|
|
handle
|
|
|
|
}
|
2020-02-03 16:01:23 -08:00
|
|
|
}
|