use super::mystd::borrow::ToOwned; use super::mystd::env; use super::mystd::ffi::{CStr, OsStr}; use super::mystd::io::Error; use super::mystd::os::unix::prelude::*; use super::xcoff; use super::{Library, LibrarySegment, Vec}; use alloc::vec; use core::mem; const EXE_IMAGE_BASE: u64 = 0x100000000; /// On AIX, we use `loadquery` with `L_GETINFO` flag to query libraries mmapped. /// See https://www.ibm.com/docs/en/aix/7.2?topic=l-loadquery-subroutine for /// detailed information of `loadquery`. pub(super) fn native_libraries() -> Vec { let mut ret = Vec::new(); unsafe { let mut buffer = vec![mem::zeroed::(); 64]; loop { if libc::loadquery( libc::L_GETINFO, buffer.as_mut_ptr().cast::(), (mem::size_of::() * buffer.len()) as u32, ) != -1 { break; } else { match Error::last_os_error().raw_os_error() { Some(libc::ENOMEM) => { buffer.resize(buffer.len() * 2, mem::zeroed::()); } Some(_) => { // If other error occurs, return empty libraries. return Vec::new(); } _ => unreachable!(), } } } let mut current = buffer.as_mut_ptr(); loop { let text_base = (*current).ldinfo_textorg as usize; let filename_ptr: *const libc::c_char = &(*current).ldinfo_filename[0]; let bytes = CStr::from_ptr(filename_ptr).to_bytes(); let member_name_ptr = filename_ptr.offset((bytes.len() + 1) as isize); let mut filename = OsStr::from_bytes(bytes).to_owned(); if text_base == EXE_IMAGE_BASE as usize { if let Ok(exe) = env::current_exe() { filename = exe.into_os_string(); } } let bytes = CStr::from_ptr(member_name_ptr).to_bytes(); let member_name = OsStr::from_bytes(bytes).to_owned(); if let Some(image) = xcoff::parse_image(filename.as_ref(), &member_name) { ret.push(Library { name: filename, member_name, segments: vec![LibrarySegment { stated_virtual_memory_address: image.base as usize, len: image.size, }], bias: (text_base + image.offset).wrapping_sub(image.base as usize), }); } if (*current).ldinfo_next == 0 { break; } current = current .cast::() .offset((*current).ldinfo_next as isize) .cast::(); } } return ret; }