Merge branch 'Debugger_Support' into 'master'
Debugger support See merge request redox-os/relibc!263
This commit is contained in:
@@ -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;
|
||||
+48
-5
@@ -4,9 +4,16 @@ use alloc::{
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{mem, ptr, slice};
|
||||
use core::{
|
||||
mem::{size_of, transmute},
|
||||
ptr, slice,
|
||||
};
|
||||
use goblin::{
|
||||
elf::{program_header, reloc, sym, Elf},
|
||||
elf::{
|
||||
program_header,
|
||||
r#dyn::{Dyn, DT_DEBUG},
|
||||
reloc, sym, Elf,
|
||||
},
|
||||
error::{Error, Result},
|
||||
};
|
||||
|
||||
@@ -19,6 +26,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug},
|
||||
tcb::{Master, Tcb},
|
||||
PAGE_SIZE,
|
||||
};
|
||||
@@ -197,6 +205,8 @@ impl Linker {
|
||||
}
|
||||
|
||||
pub fn link(&mut self, primary_opt: Option<&str>, dso: Option<DSO>) -> Result<Option<usize>> {
|
||||
unsafe { _r_debug.state = RTLDState::RT_ADD };
|
||||
_dl_debug_state();
|
||||
let elfs = {
|
||||
let mut elfs = BTreeMap::new();
|
||||
for (name, data) in self.objects.iter() {
|
||||
@@ -219,7 +229,8 @@ impl Linker {
|
||||
Some(some) => some,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// data for struct LinkMap
|
||||
let mut l_ld = 0;
|
||||
// Calculate virtual memory bounds
|
||||
let bounds = {
|
||||
let mut bounds_opt: Option<(usize, usize)> = None;
|
||||
@@ -230,6 +241,9 @@ impl Linker {
|
||||
((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
|
||||
|
||||
match ph.p_type {
|
||||
program_header::PT_DYNAMIC => {
|
||||
l_ld = ph.p_vaddr;
|
||||
}
|
||||
program_header::PT_LOAD => {
|
||||
if self.verbose {
|
||||
println!(" load {:#x}, {:#x}: {:x?}", vaddr, vsize, ph);
|
||||
@@ -284,6 +298,7 @@ impl Linker {
|
||||
size,
|
||||
sys_mman::PROT_READ | sys_mman::PROT_WRITE,
|
||||
);
|
||||
_r_debug.insert(addr as usize, &elf_name, addr + l_ld as usize);
|
||||
slice::from_raw_parts_mut(addr as *mut u8, size)
|
||||
} else {
|
||||
let ptr = sys_mman::mmap(
|
||||
@@ -301,6 +316,7 @@ impl Linker {
|
||||
return Err(Error::Malformed(format!("failed to map {}", elf_name)));
|
||||
}
|
||||
ptr::write_bytes(ptr as *mut u8, 0, size);
|
||||
_r_debug.insert(ptr as usize, &elf_name, ptr as usize + l_ld as usize);
|
||||
slice::from_raw_parts_mut(ptr as *mut u8, size)
|
||||
}
|
||||
};
|
||||
@@ -541,6 +557,32 @@ impl Linker {
|
||||
}
|
||||
}
|
||||
|
||||
// overwrite DT_DEBUG if exist in .dynamic section
|
||||
for section in &elf.section_headers {
|
||||
// we won't bother with half corrupted elfs.
|
||||
let name = elf.shdr_strtab.get(section.sh_name).unwrap().unwrap();
|
||||
if name != ".dynamic" {
|
||||
continue;
|
||||
}
|
||||
let mmap = match self.mmaps.get_mut(*elf_name) {
|
||||
Some(some) => some,
|
||||
None => continue,
|
||||
};
|
||||
let dyn_start = section.sh_addr as usize;
|
||||
let bytes: [u8; size_of::<Dyn>() / 2] =
|
||||
unsafe { transmute((&_r_debug) as *const RTLDDebug as usize) };
|
||||
if let Some(dynamic) = elf.dynamic.as_ref() {
|
||||
let mut i = 0;
|
||||
for entry in &dynamic.dyns {
|
||||
if entry.d_tag == DT_DEBUG {
|
||||
let start = dyn_start + i * size_of::<Dyn>() + size_of::<Dyn>() / 2;
|
||||
mmap[start..start + size_of::<Dyn>() / 2].clone_from_slice(&bytes);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Protect pages
|
||||
for ph in elf.program_headers.iter() {
|
||||
if ph.p_type == program_header::PT_LOAD {
|
||||
@@ -629,7 +671,7 @@ impl Linker {
|
||||
|
||||
if rel.r_type == reloc::R_X86_64_IRELATIVE {
|
||||
unsafe {
|
||||
let f: unsafe extern "C" fn() -> u64 = mem::transmute(b + a);
|
||||
let f: unsafe extern "C" fn() -> u64 = transmute(b + a);
|
||||
set_u64(f());
|
||||
}
|
||||
}
|
||||
@@ -670,7 +712,8 @@ impl Linker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { _r_debug.state = RTLDState::RT_CONSISTENT };
|
||||
_dl_debug_state();
|
||||
Ok(entry_opt)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,10 +5,10 @@ use crate::start::Stack;
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
|
||||
pub mod debug;
|
||||
pub mod linker;
|
||||
pub mod start;
|
||||
pub mod tcb;
|
||||
|
||||
pub fn static_init(sp: &'static Stack) {
|
||||
let mut phdr_opt = None;
|
||||
let mut phent_opt = None;
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
debug::_r_debug,
|
||||
linker::{Linker, DSO},
|
||||
tcb::Tcb,
|
||||
};
|
||||
@@ -130,6 +131,11 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) ->
|
||||
true
|
||||
};
|
||||
|
||||
// we might need global lock for this kind of stuff
|
||||
unsafe {
|
||||
_r_debug.r_ldbase = ld_entry;
|
||||
}
|
||||
|
||||
// Some variables that will be overridden by environment and auxiliary vectors
|
||||
let library_path = match envs.get("LD_LIBRARY_PATH") {
|
||||
Some(lib_path) => lib_path,
|
||||
|
||||
@@ -8,10 +8,7 @@ mod epoll;
|
||||
|
||||
#[test]
|
||||
fn access() {
|
||||
use crate::header::{
|
||||
errno,
|
||||
unistd,
|
||||
};
|
||||
use crate::header::{errno, unistd};
|
||||
|
||||
//TODO: create test files
|
||||
assert_eq!(Sys::access(c_str!("not a file!"), unistd::F_OK), !0);
|
||||
@@ -44,9 +41,7 @@ fn chdir() {
|
||||
|
||||
#[test]
|
||||
fn clock_gettime() {
|
||||
use crate::header::{
|
||||
time
|
||||
};
|
||||
use crate::header::time;
|
||||
|
||||
{
|
||||
let mut timespec = time::timespec {
|
||||
|
||||
Reference in New Issue
Block a user