1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! The GDB's JIT compilation interface. The low level module that exposes
//! the __jit_debug_register_code() and __jit_debug_descriptor to register
//! or unregister generated object images with debuggers.

use alloc::boxed::Box;
use alloc::vec::Vec;
use core::ptr;

#[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;

#[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() {
    // Hack to not allow inlining even when Rust wants to do it in release mode.
    let x = 3;
    unsafe {
        core::ptr::read_volatile(&x);
    }
}

/// Registeration for JIT image
pub struct GdbJitImageRegistration {
    entry: *mut JITCodeEntry,
    file: Vec<u8>,
}

impl GdbJitImageRegistration {
    /// Registers JIT image using __jit_debug_register_code
    pub fn register(file: Vec<u8>) -> Self {
        Self {
            entry: unsafe { register_gdb_jit_image(&file) },
            file,
        }
    }

    /// JIT image used in registration
    pub fn file(&self) -> &[u8] {
        &self.file
    }
}

impl Drop for GdbJitImageRegistration {
    fn drop(&mut self) {
        unsafe {
            unregister_gdb_jit_image(self.entry);
        }
    }
}

unsafe fn register_gdb_jit_image(file: &[u8]) -> *mut JITCodeEntry {
    // Create a code entry for the file, which gives the start and size of the symbol file.
    let entry = 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,
    }));
    // Add it to the linked list in the JIT descriptor.
    if !__jit_debug_descriptor.first_entry.is_null() {
        (*__jit_debug_descriptor.first_entry).prev_entry = entry;
    }
    __jit_debug_descriptor.first_entry = entry;
    // Point the relevant_entry field of the descriptor at the entry.
    __jit_debug_descriptor.relevant_entry = entry;
    // Set action_flag to JIT_REGISTER and call __jit_debug_register_code.
    __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) {
    // Remove the code entry corresponding to the code from the linked list.
    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;
    }
    // Point the relevant_entry field of the descriptor at the code entry.
    __jit_debug_descriptor.relevant_entry = entry;
    // Set action_flag to JIT_UNREGISTER and call __jit_debug_register_code.
    __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);
}