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