blob: e64975e0cc4c3bdf073acd0d711ee270c068f10d [file] [log] [blame]
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<NativeEndian>;
type PHdr = ProgramHeader<NativeEndian>;
#[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<Library> {
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
}