Skip to content

Commit 80bb1d6

Browse files
authored
add support for illumos systems (#416)
Uses dlinfo(3C) to access the current link map on illumos systems. From there we can construct a list of program headers for each mapping and get the same unwinding information available on other platforms.
1 parent f76916b commit 80bb1d6

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

src/symbolize/gimli.rs

+105
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ cfg_if::cfg_if! {
4040
target_os = "macos",
4141
target_os = "openbsd",
4242
target_os = "solaris",
43+
target_os = "illumos",
4344
))] {
4445
#[path = "gimli/mmap_unix.rs"]
4546
mod mmap;
@@ -359,6 +360,110 @@ cfg_if::cfg_if! {
359360
bias: slide,
360361
})
361362
}
363+
} else if #[cfg(target_os = "illumos")] {
364+
use mystd::os::unix::prelude::*;
365+
use mystd::ffi::{OsStr, CStr};
366+
use object::NativeEndian;
367+
368+
#[cfg(target_pointer_width = "64")]
369+
use object::elf::{
370+
FileHeader64 as FileHeader,
371+
ProgramHeader64 as ProgramHeader
372+
};
373+
374+
type EHdr = FileHeader<NativeEndian>;
375+
type PHdr = ProgramHeader<NativeEndian>;
376+
377+
mod elf;
378+
use self::elf::Object;
379+
380+
#[repr(C)]
381+
struct LinkMap {
382+
l_addr: libc::c_ulong,
383+
l_name: *const libc::c_char,
384+
l_ld: *const libc::c_void,
385+
l_next: *const LinkMap,
386+
l_prev: *const LinkMap,
387+
l_refname: *const libc::c_char,
388+
}
389+
390+
const RTLD_SELF: *const libc::c_void = -3isize as *const libc::c_void;
391+
const RTLD_DI_LINKMAP: libc::c_int = 2;
392+
393+
extern "C" {
394+
fn dlinfo(
395+
handle: *const libc::c_void,
396+
request: libc::c_int,
397+
p: *mut libc::c_void,
398+
) -> libc::c_int;
399+
}
400+
401+
fn native_libraries() -> Vec<Library> {
402+
let mut libs = Vec::new();
403+
404+
// Request the current link map from the runtime linker:
405+
let map = unsafe {
406+
let mut map: *const LinkMap = std::mem::zeroed();
407+
if dlinfo(
408+
RTLD_SELF,
409+
RTLD_DI_LINKMAP,
410+
(&mut map) as *mut *const LinkMap as *mut libc::c_void
411+
) != 0 {
412+
return libs;
413+
}
414+
map
415+
};
416+
417+
// Each entry in the link map represents a loaded object:
418+
let mut l = map;
419+
while !l.is_null() {
420+
// Fetch the fully qualified path of the loaded object:
421+
let bytes = unsafe { CStr::from_ptr((*l).l_name)}.to_bytes();
422+
let name = OsStr::from_bytes(bytes).to_owned();
423+
424+
// The base address of the object loaded into memory:
425+
let addr = unsafe { (*l).l_addr };
426+
427+
// Use the ELF header for this object to locate the program
428+
// header:
429+
let e: *const EHdr = unsafe { (*l).l_addr as *const EHdr };
430+
let phoff = unsafe { (*e).e_phoff }.get(NativeEndian);
431+
let phnum = unsafe { (*e).e_phnum }.get(NativeEndian);
432+
let etype = unsafe { (*e).e_type }.get(NativeEndian);
433+
434+
let phdr: *const PHdr = (addr + phoff) as *const PHdr;
435+
let phdr = unsafe {
436+
core::slice::from_raw_parts(phdr, phnum as usize)
437+
};
438+
439+
libs.push(Library {
440+
name,
441+
segments: phdr
442+
.iter()
443+
.map(|p| {
444+
let memsz = p.p_memsz.get(NativeEndian);
445+
let vaddr = p.p_vaddr.get(NativeEndian);
446+
LibrarySegment {
447+
len: memsz as usize,
448+
stated_virtual_memory_address: vaddr as usize,
449+
}
450+
})
451+
.collect(),
452+
bias: if etype == object::elf::ET_EXEC {
453+
// Program header addresses for the base executable are
454+
// already absolute.
455+
0
456+
} else {
457+
// Other addresses are relative to the object base.
458+
addr as usize
459+
},
460+
});
461+
462+
l = unsafe { (*l).l_next };
463+
}
464+
465+
libs
466+
}
362467
} else if #[cfg(all(
363468
any(
364469
target_os = "linux",

0 commit comments

Comments
 (0)