Skip to main content

relibc/ld_so/
debug.rs

1use crate::{c_str::CString, platform::types::*};
2use alloc::boxed::Box;
3use core::ptr;
4
5#[repr(C)]
6pub enum RTLDState {
7    /// Mapping change is complete.
8    RtConsistent,
9    /// Beginning to add a new object.
10    RtAdd,
11    /// Beginning to remove an object mapping.
12    RtDelete,
13}
14
15/// Data structure for sharing debugging information from the
16/// run-time dynamic linker for loaded ELF shared objects.
17#[repr(C)]
18pub struct RTLDDebug {
19    /// Version number for this protocol.
20    r_version: i32,
21    /// Head of the chain of loaded objects.
22    r_map: *mut LinkMap,
23    //struct link_map *r_map;
24    /// This is the address of a function internal to the run-time linker,
25    /// that will always be called when the linker begins to map in a
26    /// library or unmap it, and again when the mapping change is complete.
27    /// The debugger can set a breakpoint at this address if it wants to
28    /// notice shared object mapping changes.
29    pub r_brk: extern "C" fn(),
30
31    /// This state value describes the mapping change taking place when
32    /// the `r_brk' address is called.
33    pub state: RTLDState,
34
35    ///  Base address the linker is loaded at.
36    pub r_ldbase: usize,
37}
38
39impl RTLDDebug {
40    const NEW: Self = RTLDDebug {
41        r_version: 1,
42        r_map: ptr::null_mut::<LinkMap>(),
43        r_brk: _dl_debug_state,
44        state: RTLDState::RtConsistent,
45        r_ldbase: 0,
46    };
47
48    pub fn insert(&mut self, l_addr: usize, name: &str, l_ld: usize) {
49        if self.r_map.is_null() {
50            self.r_map = LinkMap::new_with_args(l_addr, name, l_ld);
51        } else {
52            unsafe { (*self.r_map).add_object(l_addr, name, l_ld) };
53        }
54    }
55    pub fn insert_first(&mut self, l_addr: usize, name: &str, l_ld: usize) {
56        if self.r_map.is_null() {
57            self.r_map = LinkMap::new_with_args(l_addr, name, l_ld);
58        } else {
59            let tmp = self.r_map;
60            self.r_map = LinkMap::new_with_args(l_addr, name, l_ld);
61            unsafe { (*self.r_map).link(&mut *tmp) };
62        }
63    }
64}
65
66/// SAFETY: safe as long as caller wraps the instance in a mutex,
67/// or similar structure that guarantees exclusive mutable access.
68/// Separate instances must not contain pointers to the same LinkMap instance.
69unsafe impl Send for RTLDDebug {}
70/// SAFETY: safe as long as caller wraps the instance in a mutex,
71/// or similar structure that guarantees exclusive mutable access.
72/// Separate instances must not contain pointers to the same LinkMap instance.
73unsafe impl Sync for RTLDDebug {}
74
75#[repr(C)]
76struct LinkMap {
77    /* These members are part of the protocol with the debugger.
78    This is the same format used in SVR4.  */
79    /// Difference between the address in the ELF
80    /// file and the addresses in memory.
81    l_addr: usize,
82    /// Absolute file name object was found in.
83    l_name: *const c_char,
84    /// Dynamic section of the shared object.
85    l_ld: usize,
86    l_next: *mut LinkMap,
87    l_prev: *mut LinkMap,
88}
89
90impl LinkMap {
91    fn new() -> *mut Self {
92        let map = Box::new(LinkMap {
93            l_addr: 0,
94            l_name: ptr::null(),
95            l_ld: 0,
96            l_next: ptr::null_mut(),
97            l_prev: ptr::null_mut(),
98        });
99        Box::into_raw(map)
100    }
101    fn link(&mut self, map: &mut LinkMap) {
102        map.l_prev = ptr::from_mut::<LinkMap>(self);
103        self.l_next = ptr::from_mut::<LinkMap>(map);
104    }
105    fn new_with_args(l_addr: usize, name: &str, l_ld: usize) -> *mut Self {
106        let map = LinkMap::new();
107        unsafe {
108            (*map).l_addr = l_addr;
109            (*map).l_ld = l_ld;
110            let c_name = CString::new(name).unwrap();
111            (*map).l_name = c_name.into_raw().cast_const();
112        }
113        map
114    }
115
116    fn add_object(&mut self, l_addr: usize, name: &str, l_ld: usize) {
117        let node = LinkMap::new_with_args(l_addr, name, l_ld);
118        let mut last = self;
119        while !last.l_next.is_null() {
120            last = unsafe { last.l_next.as_mut() }.unwrap();
121        }
122        unsafe {
123            (*node).l_prev = last;
124            last.l_next = node;
125        }
126    }
127}
128
129/*
130 * Gdb may be looking for this fuction with that exact name and set
131 * break point there
132 */
133#[linkage = "weak"]
134#[unsafe(no_mangle)]
135pub extern "C" fn _dl_debug_state() {}
136
137#[unsafe(no_mangle)]
138pub static _r_debug: spin::Mutex<RTLDDebug> = spin::Mutex::new(RTLDDebug::NEW);