use crate::utils::debug::GDBDebug;
use elf_loader::elf::abi::{DT_DEBUG, DT_NULL, PT_DYNAMIC, PT_PHDR};
use elf_loader::elf::{ElfDyn, ElfHeader, ElfPhdr};
cfg_if::cfg_if! {
if #[cfg(feature = "use-syscall")] {
mod linux;
pub(crate) use linux::*;
} else if #[cfg(unix)] {
mod unix;
pub(crate) use unix::*;
} else {
pub(crate) fn read_file(_path: &str) -> crate::Result<alloc::boxed::Box<[u8]>> {
Err(crate::Error::Unsupported)
}
pub(crate) fn read_file_limit(_path: &str, _limit: usize) -> crate::Result<alloc::boxed::Box<[u8]>> {
Err(crate::Error::Unsupported)
}
pub(crate) unsafe fn get_r_debug() -> *mut GDBDebug {
core::ptr::null_mut()
}
}
}
pub(crate) unsafe fn find_r_debug(
phdr_addr: usize,
phnum: usize,
interpreter_base: usize,
) -> *mut GDBDebug {
if phdr_addr == 0 || phnum == 0 {
return core::ptr::null_mut();
}
let phdrs = unsafe { core::slice::from_raw_parts(phdr_addr as *const ElfPhdr, phnum) };
let mut load_bias = None;
let mut dynamic_phdr = None;
for phdr in phdrs {
if phdr.p_type == PT_PHDR {
load_bias = Some(phdr_addr.wrapping_sub(phdr.p_vaddr as usize));
} else if phdr.p_type == PT_DYNAMIC {
dynamic_phdr = Some(phdr);
}
}
if load_bias.is_none() {
for phdr in phdrs {
if phdr.p_type == 1 && phdr.p_offset == 0 {
let linked_phdr_addr = phdr.p_vaddr as usize + 64;
load_bias = Some(phdr_addr.wrapping_sub(linked_phdr_addr));
break;
}
}
}
if let (Some(bias), Some(phdr)) = (load_bias, dynamic_phdr) {
let mut cur = (bias.wrapping_add(phdr.p_vaddr as usize)) as *const ElfDyn;
while !cur.is_null() && unsafe { (*cur).d_tag } != DT_NULL {
if unsafe { (*cur).d_tag } == DT_DEBUG {
let ptr = unsafe { (*cur).d_un as *mut GDBDebug };
if !ptr.is_null() && unsafe { (*ptr).version } != 0 {
return ptr;
}
}
cur = unsafe { cur.add(1) };
}
}
if interpreter_base != 0 {
let ehdr = unsafe { &*(interpreter_base as *const ElfHeader) };
let phdrs = unsafe {
core::slice::from_raw_parts(
(interpreter_base + ehdr.e_phoff as usize) as *const ElfPhdr,
ehdr.e_phnum as usize,
)
};
if let Some(phdr) = phdrs.iter().find(|p| p.p_type == PT_DYNAMIC) {
let mut cur = (interpreter_base.wrapping_add(phdr.p_vaddr as usize)) as *const ElfDyn;
while !cur.is_null() && unsafe { (*cur).d_tag } != DT_NULL {
if unsafe { (*cur).d_tag } == DT_DEBUG {
let ptr = unsafe { (*cur).d_un as *mut GDBDebug };
if !ptr.is_null() && unsafe { (*ptr).version } != 0 {
return ptr;
}
}
cur = unsafe { cur.add(1) };
}
}
}
core::ptr::null_mut()
}