1#![deny(missing_docs)]
6#![deny(clippy::all)]
7
8use crt0stack::{Entry, Reader};
9use std::ffi::CStr;
10use std::os::raw::c_char;
11use std::slice::from_raw_parts;
12
13#[cfg(target_pointer_width = "64")]
14mod elf {
15 pub use goblin::elf64::dynamic::*;
16 pub use goblin::elf64::header::*;
17 pub use goblin::elf64::program_header::*;
18 pub use goblin::elf64::section_header::*;
19 pub use goblin::elf64::sym::Sym;
20
21 pub const CLASS: u8 = ELFCLASS64;
22 pub type Word = u64;
23}
24
25#[cfg(target_pointer_width = "32")]
26mod elf {
27 pub use goblin::elf32::dynamic::*;
28 pub use goblin::elf32::header::*;
29 pub use goblin::elf32::program_header::*;
30 pub use goblin::elf32::section_header::*;
31 pub use goblin::elf32::sym::Sym;
32
33 pub const CLASS: u8 = ELFCLASS32;
34 pub type Word = u32;
35}
36
37#[repr(transparent)]
38struct Header(elf::Header);
39
40impl Header {
41 #[allow(clippy::trivially_copy_pass_by_ref)]
42 pub unsafe fn from_ptr(ptr: &()) -> Option<&Self> {
43 let hdr = &*(ptr as *const _ as *const Self);
44
45 if hdr.0.e_ident[..elf::ELFMAG.len()] != elf::ELFMAG[..] {
46 return None;
47 }
48
49 if hdr.0.e_ident[elf::EI_CLASS] != elf::CLASS {
50 return None;
51 }
52
53 Some(hdr)
54 }
55
56 unsafe fn ptr<T>(&self, off: impl Into<elf::Word>) -> *const T {
57 let addr = self as *const _ as *const u8;
58 addr.add(off.into() as usize) as *const T
59 }
60
61 unsafe fn slice<T>(&self, off: impl Into<elf::Word>, len: impl Into<elf::Word>) -> &[T] {
62 from_raw_parts::<u8>(self.ptr(off), len.into() as usize)
63 .align_to()
64 .1
65 }
66
67 unsafe fn shtab(&self) -> &[elf::SectionHeader] {
68 self.slice(self.0.e_shoff, self.0.e_shentsize * self.0.e_shnum)
69 }
70
71 unsafe fn section<T>(&self, kind: u32) -> Option<&[T]> {
72 for sh in self.shtab() {
73 if sh.sh_type == kind {
74 return Some(self.slice(sh.sh_offset, sh.sh_size));
75 }
76 }
77
78 None
79 }
80
81 unsafe fn symbol(&self, name: &str) -> Option<&Symbol> {
82 let symstrtab: &[c_char] = self.section(elf::SHT_STRTAB)?;
83 let symtab: &[elf::Sym] = self.section(elf::SHT_DYNSYM)?;
84
85 for sym in symtab {
90 let cstr = CStr::from_ptr(&symstrtab[sym.st_name as usize]);
91 if let Ok(s) = cstr.to_str() {
92 if s == name {
93 let addr = self.ptr(sym.st_value) as *const Symbol;
94 return Some(&*addr);
95 }
96 }
97 }
98
99 None
100 }
101}
102
103pub enum Symbol {}
108
109pub struct Vdso<'a>(&'a Header);
111
112impl Vdso<'static> {
113 pub fn locate() -> Option<Self> {
115 for aux in Reader::from_environ().done() {
116 if let Entry::SysInfoEHdr(addr) = aux {
117 let hdr = unsafe { Header::from_ptr(&*(addr as *const _))? };
118 return Some(Self(hdr));
119 }
120 }
121
122 None
123 }
124}
125
126impl<'a> Vdso<'a> {
127 pub fn lookup(&self, name: &str) -> Option<&'a Symbol> {
132 unsafe { self.0.symbol(name) }
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use libc::time_t;
140 use std::mem::transmute;
141 use std::ptr::null_mut;
142
143 #[test]
144 fn time() {
145 let vdso = Vdso::locate().unwrap();
146 let func = vdso.lookup("time").unwrap();
147 let func: extern "C" fn(*mut time_t) -> time_t = unsafe { transmute(func) };
148
149 let libc = unsafe { libc::time(null_mut()) };
150 let vdso = func(null_mut());
151 assert!(vdso - libc <= 1);
152 }
153}