1#[repr(C)]
7pub struct DlInfo {
8 pub dli_fname: *const c_char,
9 pub dli_fbase: *mut c_void,
10 pub dli_sname: *const c_char,
11 pub dli_saddr: *mut c_void,
12}
13
14#[repr(C)]
15pub struct DlPhdrInfo {
16 pub dlpi_addr: u64,
17 pub dlpi_name: *const c_char,
18 pub dlpi_phdr: *const u8,
19 pub dlpi_phnum: u16,
20 __pad0: u16,
21 __pad1: u32,
22 pub dlpi_adds: u64,
23 pub dlpi_subs: u64,
24 pub dlpi_tls_modid: usize,
25 pub dlpi_tls_data: *mut c_void,
26}
27
28type DlIterateCb = unsafe extern "C" fn(*mut DlPhdrInfo, usize, *mut c_void) -> c_int;
29type LdsoIterateFn = unsafe extern "C" fn(Option<DlIterateCb>, *mut c_void) -> c_int;
30type LdsoDlinfoFn = unsafe extern "C" fn(*mut c_void, c_int, *mut c_void) -> c_int;
31
32static mut LDSO_ITERATE: Option<LdsoIterateFn> = None;
33static mut LDSO_DLINFO: Option<LdsoDlinfoFn> = None;
34
35#[no_mangle]
36pub unsafe extern "C" fn __ldso_register_dl_iterate(f: LdsoIterateFn) {
37 LDSO_ITERATE = Some(f);
38}
39
40#[no_mangle]
41pub unsafe extern "C" fn __ldso_register_dlinfo(f: LdsoDlinfoFn) {
42 LDSO_DLINFO = Some(f);
43}
44
45static mut MAPS_PATH: [c_char; PATH_MAX_V] = [0; PATH_MAX_V];
50static mut MAPS_LINE: *mut c_char = core::ptr::null_mut();
51static mut MAPS_LINE_CAP: usize = 0;
52
53unsafe fn maps_parse_hex(p: *const u8) -> (u64, *const u8) {
54 let mut v: u64 = 0;
55 let mut q = p;
56 loop {
57 let c = *q;
58 let d = if c >= b'0' && c <= b'9' {
59 (c - b'0') as u64
60 } else if c >= b'a' && c <= b'f' {
61 (c - b'a' + 10) as u64
62 } else if c >= b'A' && c <= b'F' {
63 (c - b'A' + 10) as u64
64 } else {
65 break;
66 };
67 v = (v << 4) | d;
68 q = q.add(1);
69 }
70 (v, q)
71}
72
73unsafe fn maps_lookup(addr: usize) -> (u64, u64, *const c_char, bool) {
76 MAPS_PATH[0] = 0;
77 let f = crate::fopen(b"/proc/self/maps\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
78 if f.is_null() { return (0, 0, MAPS_PATH.as_ptr(), false); }
79 let mut start_out = 0u64;
80 let mut off_out = 0u64;
81 let mut found = false;
82 while crate::getline(&raw mut MAPS_LINE, &raw mut MAPS_LINE_CAP, f) >= 0 {
83 let p = MAPS_LINE as *const u8;
84 let (start, after) = maps_parse_hex(p);
85 if *after != b'-' { continue; }
86 let (end, after2) = maps_parse_hex(after.add(1));
87 if (addr as u64) < start || (addr as u64) >= end { continue; }
88 let mut q = after2;
90 while *q == b' ' { q = q.add(1); }
91 while *q != 0 && *q != b' ' { q = q.add(1); }
92 while *q == b' ' { q = q.add(1); }
93 let (off, after_off) = maps_parse_hex(q);
94 start_out = start;
95 off_out = off;
96 let mut q2 = after_off;
97 for _ in 0..2 {
98 while *q2 == b' ' { q2 = q2.add(1); }
99 while *q2 != 0 && *q2 != b' ' { q2 = q2.add(1); }
100 }
101 while *q2 == b' ' { q2 = q2.add(1); }
102 if *q2 != 0 {
103 let mut i = 0usize;
104 while *q2 != 0 && *q2 != b'\n' && i + 1 < MAPS_PATH.len() {
105 MAPS_PATH[i] = *q2 as c_char;
106 i += 1;
107 q2 = q2.add(1);
108 }
109 MAPS_PATH[i] = 0;
110 }
111 found = true;
112 break;
113 }
114 crate::fclose(f);
115 (start_out, off_out, MAPS_PATH.as_ptr(), found)
116}
117
118unsafe fn elf_bias_for(path: *const c_char, start: u64, off: u64) -> u64 {
122 let fd = crate::open(path, 0, 0);
123 if fd < 0 { return start.wrapping_sub(off); }
124 let mut eh = [0u8; 64];
125 if crate::pread(fd, eh.as_mut_ptr() as *mut c_void, 64, 0) != 64 || eh[0] != 0x7f {
126 crate::close(fd);
127 return start.wrapping_sub(off);
128 }
129 let e_phoff = rd64(eh.as_ptr().add(0x20));
130 let e_phentsize = rd16(eh.as_ptr().add(0x36)) as usize;
131 let e_phnum = rd16(eh.as_ptr().add(0x38)) as usize;
132 if e_phentsize != 56 || e_phnum == 0 || e_phnum > 512 {
133 crate::close(fd);
134 return start.wrapping_sub(off);
135 }
136 let total = e_phnum * e_phentsize;
137 let ph = crate::malloc(total) as *mut u8;
138 if ph.is_null() {
139 crate::close(fd);
140 return start.wrapping_sub(off);
141 }
142 let got = crate::pread(fd, ph as *mut c_void, total, e_phoff as i64);
143 crate::close(fd);
144 if got != total as isize {
145 crate::free(ph as *mut c_void);
146 return start.wrapping_sub(off);
147 }
148 let mut bias = start.wrapping_sub(off);
149 for i in 0..e_phnum {
150 let p = ph.add(i * e_phentsize);
151 let p_type = rd32(p);
152 if p_type != 1 { continue; }
153 let p_offset = rd64(p.add(8));
154 let p_vaddr = rd64(p.add(0x10));
155 let map_off = p_offset.wrapping_sub(p_vaddr & 0xfff);
157 if off == map_off {
158 bias = start.wrapping_sub(off).wrapping_sub(p_vaddr.wrapping_sub(p_offset));
159 break;
160 }
161 }
162 crate::free(ph as *mut c_void);
163 bias
164}
165
166static mut DLADDR_NAME: [c_char; PATH_MAX_V] = [0; PATH_MAX_V];
171
172unsafe fn rd16(p: *const u8) -> u16 { core::ptr::read_unaligned(p as *const u16) }
173unsafe fn rd32(p: *const u8) -> u32 { core::ptr::read_unaligned(p as *const u32) }
174unsafe fn rd64(p: *const u8) -> u64 { core::ptr::read_unaligned(p as *const u64) }
175
176unsafe fn elf_symbol_lookup(path: *const c_char, addr: u64) -> (bool, u64) {
177 let fd = crate::open(path, 0, 0);
178 if fd < 0 { return (false, 0); }
179 let mut eh = [0u8; 64];
180 if crate::pread(fd, eh.as_mut_ptr() as *mut c_void, 64, 0) != 64 {
181 crate::close(fd);
182 return (false, 0);
183 }
184 if eh[0] != 0x7f || eh[1] != b'E' || eh[2] != b'L' || eh[3] != b'F' {
185 crate::close(fd);
186 return (false, 0);
187 }
188 let e_shoff = rd64(eh.as_ptr().add(0x28));
189 let e_shentsize = rd16(eh.as_ptr().add(0x3a)) as usize;
190 let e_shnum = rd16(eh.as_ptr().add(0x3c)) as usize;
191 if e_shoff == 0 || e_shentsize < 64 || e_shnum == 0 || e_shnum > 4096 {
192 crate::close(fd);
193 return (false, 0);
194 }
195 let shtotal = e_shnum * e_shentsize;
196 let sh = crate::malloc(shtotal) as *mut u8;
197 if sh.is_null() { crate::close(fd); return (false, 0); }
198 if crate::pread(fd, sh as *mut c_void, shtotal, e_shoff as i64) != shtotal as isize {
199 crate::free(sh as *mut c_void);
200 crate::close(fd);
201 return (false, 0);
202 }
203 let mut best: u64 = 0;
204 let mut have = false;
205 for i in 0..e_shnum {
206 let sec = sh.add(i * e_shentsize);
207 let sh_type = rd32(sec.add(4));
208 if sh_type != 2 && sh_type != 11 { continue; }
209 let sh_offset = rd64(sec.add(0x18));
210 let sh_size = rd64(sec.add(0x20)) as usize;
211 let sh_link = rd32(sec.add(0x28)) as usize;
212 let sh_entsize = rd64(sec.add(0x38)) as usize;
213 if sh_size == 0 || sh_entsize < 24 || sh_link >= e_shnum { continue; }
214 let syms = crate::malloc(sh_size) as *mut u8;
215 if syms.is_null() { continue; }
216 let got = crate::pread(fd, syms as *mut c_void, sh_size, sh_offset as i64);
217 if got != sh_size as isize {
218 crate::free(syms as *mut c_void);
219 continue;
220 }
221 let strsec = sh.add(sh_link * e_shentsize);
222 let str_off = rd64(strsec.add(0x18));
223 let str_size = rd64(strsec.add(0x20)) as usize;
224 if str_size == 0 || str_size > (1 << 24) {
225 crate::free(syms as *mut c_void);
226 continue;
227 }
228 let strs = crate::malloc(str_size) as *mut u8;
229 if strs.is_null() {
230 crate::free(syms as *mut c_void);
231 continue;
232 }
233 if crate::pread(fd, strs as *mut c_void, str_size, str_off as i64) != str_size as isize {
234 crate::free(strs as *mut c_void);
235 crate::free(syms as *mut c_void);
236 continue;
237 }
238 let count = sh_size / sh_entsize;
239 for j in 0..count {
240 let sym = syms.add(j * sh_entsize);
241 let st_name = rd32(sym) as usize;
242 let st_value = rd64(sym.add(8));
243 let st_size = rd64(sym.add(16));
244 let st_shndx = rd16(sym.add(6));
245 if st_name == 0 || st_name >= str_size || st_shndx == 0 { continue; }
246 if st_value > addr { continue; }
247 if st_size != 0 && addr >= st_value + st_size { continue; }
248 if !have || st_value > best {
249 best = st_value;
250 have = true;
251 let s = strs.add(st_name);
252 let mut k = 0usize;
253 while *s.add(k) != 0 && k + 1 < DLADDR_NAME.len() {
254 DLADDR_NAME[k] = *s.add(k) as c_char;
255 k += 1;
256 }
257 DLADDR_NAME[k] = 0;
258 }
259 }
260 crate::free(strs as *mut c_void);
261 crate::free(syms as *mut c_void);
262 }
263 crate::free(sh as *mut c_void);
264 crate::close(fd);
265 (have, best)
266}
267
268#[no_mangle]
269pub unsafe extern "C" fn dladdr(addr: *const c_void, info: *mut DlInfo) -> c_int {
270 if info.is_null() { ERRNO!() = EINVAL; return 0; }
271 (*info).dli_fname = core::ptr::null();
272 (*info).dli_fbase = core::ptr::null_mut();
273 (*info).dli_sname = core::ptr::null();
274 (*info).dli_saddr = core::ptr::null_mut();
275 if addr.is_null() { return 0; }
276 let (start, off, path, found) = maps_lookup(addr as usize);
277 if !found { return 0; }
278 let base = if MAPS_PATH[0] != 0 && MAPS_PATH[0] != b'[' as c_char {
279 elf_bias_for(path, start, off)
280 } else {
281 start.wrapping_sub(off)
282 };
283 (*info).dli_fname = path;
284 (*info).dli_fbase = base as *mut c_void;
285 if MAPS_PATH[0] == 0 || MAPS_PATH[0] == b'[' as c_char { return 1; }
286 let off = addr as u64 - base;
287 let (have, value) = elf_symbol_lookup(path, off);
288 if have {
289 (*info).dli_sname = DLADDR_NAME.as_ptr();
290 (*info).dli_saddr = (base + value) as *mut c_void;
291 }
292 1
293}
294
295static mut EXE_PATH: [c_char; PATH_MAX_V] = [0; PATH_MAX_V];
300
301unsafe fn read_exe_path() -> *const c_char {
302 let n = crate::readlink(
303 b"/proc/self/exe\0".as_ptr() as *const c_char,
304 EXE_PATH.as_mut_ptr(),
305 EXE_PATH.len() - 1,
306 );
307 if n < 0 {
308 EXE_PATH[0] = 0;
309 } else {
310 EXE_PATH[n as usize] = 0;
311 }
312 EXE_PATH.as_ptr()
313}
314
315unsafe fn main_program_info() -> (u64, *const u8, u16) {
317 let exe = read_exe_path();
318 if *exe != 0 {
319 let f = crate::fopen(b"/proc/self/maps\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
320 if !f.is_null() {
321 while crate::getline(&raw mut MAPS_LINE, &raw mut MAPS_LINE_CAP, f) >= 0 {
322 let p = MAPS_LINE as *const u8;
323 let (start, after) = maps_parse_hex(p);
324 if *after != b'-' { continue; }
325 let (_end, after2) = maps_parse_hex(after.add(1));
326 let mut q = after2;
327 while *q == b' ' { q = q.add(1); }
328 while *q != 0 && *q != b' ' { q = q.add(1); }
329 while *q == b' ' { q = q.add(1); }
330 let (off, after_off) = maps_parse_hex(q);
331 if off != 0 { continue; }
332 let mut q2 = after_off;
333 for _ in 0..2 {
334 while *q2 == b' ' { q2 = q2.add(1); }
335 while *q2 != 0 && *q2 != b' ' { q2 = q2.add(1); }
336 }
337 while *q2 == b' ' { q2 = q2.add(1); }
338 if *q2 == 0 { continue; }
339 let mut path = [0 as c_char; PATH_MAX_V];
340 let mut i = 0usize;
341 while *q2 != 0 && *q2 != b'\n' && i + 1 < path.len() {
342 path[i] = *q2 as c_char;
343 i += 1;
344 q2 = q2.add(1);
345 }
346 path[i] = 0;
347 if crate::strcmp(path.as_ptr() as *const u8, exe as *const u8) != 0 { continue; }
348 let base = start;
349 let eh = base as *const u8;
350 if *eh == 0x7f && *eh.add(1) == b'E' && *eh.add(2) == b'L' && *eh.add(3) == b'F' {
351 let e_phoff = rd64(eh.add(32));
352 let e_phentsize = rd16(eh.add(54));
353 let e_phnum = rd16(eh.add(56));
354 if e_phentsize as usize == 56 {
355 crate::fclose(f);
356 return (base, (base + e_phoff) as *const u8, e_phnum);
357 }
358 }
359 crate::fclose(f);
360 return (base, core::ptr::null(), 0);
361 }
362 crate::fclose(f);
363 }
364 }
365 let phdr = crate::getauxval(3);
366 let phnum = crate::getauxval(5) as u16;
367 if phdr != 0 && phnum != 0 {
368 let (start, off, path, _f) = maps_lookup(phdr as usize);
369 let base = elf_bias_for(path, start, off);
370 return (base, phdr as *const u8, phnum);
371 }
372 (0, core::ptr::null(), 0)
373}
374
375#[no_mangle]
376pub unsafe extern "C" fn dl_iterate_phdr(
377 callback: Option<unsafe extern "C" fn(*mut DlPhdrInfo, usize, *mut c_void) -> c_int>,
378 data: *mut c_void,
379) -> c_int {
380 let cb = match callback { Some(c) => c, None => return 0 };
381 let (base, phdr, phnum) = main_program_info();
382 if !phdr.is_null() && phnum != 0 {
383 let info = DlPhdrInfo {
384 dlpi_addr: base,
385 dlpi_name: b"\0".as_ptr() as *const c_char,
386 dlpi_phdr: phdr,
387 dlpi_phnum: phnum,
388 __pad0: 0,
389 __pad1: 0,
390 dlpi_adds: 0,
391 dlpi_subs: 0,
392 dlpi_tls_modid: 0,
393 dlpi_tls_data: core::ptr::null_mut(),
394 };
395 let r = cb(&info as *const DlPhdrInfo as *mut DlPhdrInfo, core::mem::size_of::<DlPhdrInfo>(), data);
396 if r != 0 { return r; }
397 }
398 if let Some(f) = LDSO_ITERATE {
399 return f(Some(cb), data);
400 }
401 0
402}
403
404#[no_mangle]
405pub unsafe extern "C" fn dlinfo(handle: *mut c_void, request: c_int, info: *mut c_void) -> c_int {
406 if let Some(f) = LDSO_DLINFO {
407 return f(handle, request, info);
408 }
409 ERRNO!() = 95; -1
411}