|
@@ -0,0 +1,117 @@
|
|
|
+use crate::{c_str::CString, platform::types::*};
|
|
|
+use alloc::boxed::Box;
|
|
|
+
|
|
|
+#[repr(C)]
|
|
|
+pub enum RTLDState {
|
|
|
+ /// Mapping change is complete.
|
|
|
+ RT_CONSISTENT,
|
|
|
+ /// Beginning to add a new object.
|
|
|
+ RT_ADD,
|
|
|
+ /// Beginning to remove an object mapping.
|
|
|
+ RT_DELETE,
|
|
|
+}
|
|
|
+
|
|
|
+/// Data structure for sharing debugging information from the
|
|
|
+/// run-time dynamic linker for loaded ELF shared objects.
|
|
|
+#[repr(C)]
|
|
|
+pub struct RTLDDebug {
|
|
|
+ /// Version number for this protocol.
|
|
|
+ r_version: i32,
|
|
|
+ /// Head of the chain of loaded objects.
|
|
|
+ r_map: *mut LinkMap,
|
|
|
+ //struct link_map *r_map;
|
|
|
+ /// This is the address of a function internal to the run-time linker,
|
|
|
+ /// that will always be called when the linker begins to map in a
|
|
|
+ /// library or unmap it, and again when the mapping change is complete.
|
|
|
+ /// The debugger can set a breakpoint at this address if it wants to
|
|
|
+ /// notice shared object mapping changes.
|
|
|
+ pub r_brk: extern "C" fn(),
|
|
|
+
|
|
|
+ /// This state value describes the mapping change taking place when
|
|
|
+ /// the `r_brk' address is called.
|
|
|
+ pub state: RTLDState,
|
|
|
+
|
|
|
+ /// Base address the linker is loaded at.
|
|
|
+ pub r_ldbase: usize,
|
|
|
+}
|
|
|
+
|
|
|
+impl RTLDDebug {
|
|
|
+ const NEW: Self = RTLDDebug {
|
|
|
+ r_version: 1,
|
|
|
+ r_map: 0 as *mut LinkMap,
|
|
|
+ r_brk: _dl_debug_state,
|
|
|
+ state: RTLDState::RT_CONSISTENT,
|
|
|
+ r_ldbase: 0,
|
|
|
+ };
|
|
|
+
|
|
|
+ pub fn insert(&mut self, l_addr: usize, name: &str, l_ld: usize) {
|
|
|
+ if self.r_map.is_null() {
|
|
|
+ self.r_map = LinkMap::new_with_args(l_addr, name, l_ld);
|
|
|
+ } else {
|
|
|
+ unsafe { (*self.r_map).add_object(l_addr, name, l_ld) };
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[repr(C)]
|
|
|
+struct LinkMap {
|
|
|
+ /* These members are part of the protocol with the debugger.
|
|
|
+ This is the same format used in SVR4. */
|
|
|
+ /// Difference between the address in the ELF
|
|
|
+ /// file and the addresses in memory.
|
|
|
+ l_addr: usize,
|
|
|
+ /// Absolute file name object was found in.
|
|
|
+ l_name: *const c_char,
|
|
|
+ /// Dynamic section of the shared object.
|
|
|
+ l_ld: usize,
|
|
|
+ l_next: *mut LinkMap,
|
|
|
+ l_prev: *mut LinkMap,
|
|
|
+}
|
|
|
+
|
|
|
+impl LinkMap {
|
|
|
+ fn new() -> *mut Self {
|
|
|
+ let map = Box::new(LinkMap {
|
|
|
+ l_addr: 0,
|
|
|
+ l_name: 0 as *const c_char,
|
|
|
+ l_ld: 0,
|
|
|
+ l_next: 0 as *mut LinkMap,
|
|
|
+ l_prev: 0 as *mut LinkMap,
|
|
|
+ });
|
|
|
+ Box::into_raw(map)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn new_with_args(l_addr: usize, name: &str, l_ld: usize) -> *mut Self {
|
|
|
+ let map = LinkMap::new();
|
|
|
+ unsafe {
|
|
|
+ (*map).l_addr = l_addr;
|
|
|
+ (*map).l_ld = l_ld;
|
|
|
+ let c_name = CString::new(name).unwrap();
|
|
|
+ (*map).l_name = c_name.into_raw() as *const c_char;
|
|
|
+ }
|
|
|
+ map
|
|
|
+ }
|
|
|
+
|
|
|
+ fn add_object(&mut self, l_addr: usize, name: &str, l_ld: usize) {
|
|
|
+ let node = LinkMap::new_with_args(l_addr, name, l_ld);
|
|
|
+ let mut last = self;
|
|
|
+ while !last.l_next.is_null() {
|
|
|
+ last = unsafe { last.l_next.as_mut() }.unwrap();
|
|
|
+ }
|
|
|
+ unsafe {
|
|
|
+ (*node).l_prev = last;
|
|
|
+ (*last).l_next = node;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Gdb may be looking for this fuction with that exact name and set
|
|
|
+ * break point there
|
|
|
+ */
|
|
|
+#[linkage = "weak"]
|
|
|
+#[no_mangle]
|
|
|
+pub extern "C" fn _dl_debug_state() {}
|
|
|
+
|
|
|
+#[no_mangle]
|
|
|
+pub static mut _r_debug: RTLDDebug = RTLDDebug::NEW;
|