use super::mystd::borrow::ToOwned; use super::mystd::ffi::{CStr, OsStr}; use super::mystd::os::unix::prelude::*; use super::{Library, LibrarySegment, Vec}; use core::mem; use object::NativeEndian; #[cfg(target_pointer_width = "64")] use object::elf::{FileHeader64 as FileHeader, ProgramHeader64 as ProgramHeader}; type EHdr = FileHeader; type PHdr = ProgramHeader; #[repr(C)] struct LinkMap { l_addr: libc::c_ulong, l_name: *const libc::c_char, l_ld: *const libc::c_void, l_next: *const LinkMap, l_prev: *const LinkMap, l_refname: *const libc::c_char, } const RTLD_SELF: *const libc::c_void = -3isize as *const libc::c_void; const RTLD_DI_LINKMAP: libc::c_int = 2; extern "C" { fn dlinfo( handle: *const libc::c_void, request: libc::c_int, p: *mut libc::c_void, ) -> libc::c_int; } pub(super) fn native_libraries() -> Vec { let mut libs = Vec::new(); // Request the current link map from the runtime linker: let map = unsafe { let mut map: *const LinkMap = mem::zeroed(); if dlinfo( RTLD_SELF, RTLD_DI_LINKMAP, (&mut map) as *mut *const LinkMap as *mut libc::c_void, ) != 0 { return libs; } map }; // Each entry in the link map represents a loaded object: let mut l = map; while !l.is_null() { // Fetch the fully qualified path of the loaded object: let bytes = unsafe { CStr::from_ptr((*l).l_name) }.to_bytes(); let name = OsStr::from_bytes(bytes).to_owned(); // The base address of the object loaded into memory: let addr = unsafe { (*l).l_addr }; // Use the ELF header for this object to locate the program // header: let e: *const EHdr = unsafe { (*l).l_addr as *const EHdr }; let phoff = unsafe { (*e).e_phoff }.get(NativeEndian); let phnum = unsafe { (*e).e_phnum }.get(NativeEndian); let etype = unsafe { (*e).e_type }.get(NativeEndian); let phdr: *const PHdr = (addr + phoff) as *const PHdr; let phdr = unsafe { core::slice::from_raw_parts(phdr, phnum as usize) }; libs.push(Library { name, segments: phdr .iter() .map(|p| { let memsz = p.p_memsz.get(NativeEndian); let vaddr = p.p_vaddr.get(NativeEndian); LibrarySegment { len: memsz as usize, stated_virtual_memory_address: vaddr as usize, } }) .collect(), bias: if etype == object::elf::ET_EXEC { // Program header addresses for the base executable are // already absolute. 0 } else { // Other addresses are relative to the object base. addr as usize }, }); l = unsafe { (*l).l_next }; } libs }