850dfd971b
This fixes a regression in gdb where sometimes it decides to ignore the first entry in the list.
131 lines
3.8 KiB
Rust
131 lines
3.8 KiB
Rust
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;
|
|
}
|
|
pub fn insert_first(&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 {
|
|
let tmp = self.r_map;
|
|
self.r_map = LinkMap::new_with_args(l_addr, name, l_ld);
|
|
unsafe { (*self.r_map).link(&mut *tmp) };
|
|
}
|
|
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 link(&mut self, map: &mut LinkMap) {
|
|
map.l_prev = self as *mut LinkMap;
|
|
self.l_next = map as *mut LinkMap;
|
|
}
|
|
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;
|