diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index 3dc6b8761..6ced77d12 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -40,6 +40,7 @@ cfg_if::cfg_if! { target_os = "macos", target_os = "openbsd", target_os = "solaris", + target_os = "illumos", ))] { #[path = "gimli/mmap_unix.rs"] mod mmap; @@ -359,6 +360,110 @@ cfg_if::cfg_if! { bias: slide, }) } + } else if #[cfg(target_os = "illumos")] { + use mystd::os::unix::prelude::*; + use mystd::ffi::{OsStr, CStr}; + use object::NativeEndian; + + #[cfg(target_pointer_width = "64")] + use object::elf::{ + FileHeader64 as FileHeader, + ProgramHeader64 as ProgramHeader + }; + + type EHdr = FileHeader; + type PHdr = ProgramHeader; + + mod elf; + use self::elf::Object; + + #[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; + } + + 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 = std::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 + } } else if #[cfg(all( any( target_os = "linux",