use std::ffi::CStr;
use std::ffi::CString;
use std::marker::PhantomData;
use std::mem;
use std::os::raw::c_int;
use std::ptr;
use foreign_types::ForeignTypeRef;
use foreign_types::Opaque;
use super::super::elf::Symbol;
use super::Error;
pub struct ModuleRef(Opaque);
unsafe impl ForeignTypeRef for ModuleRef {
type CType = crate::dw_sys::Dwfl_Module;
}
impl ModuleRef {
pub fn name(&self) -> Option<&CStr> {
unsafe {
let name = crate::dw_sys::dwfl_module_info(
self.as_ptr(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
);
if name.is_null() {
None
} else {
Some(CStr::from_ptr(name))
}
}
}
pub fn getsrc(&self, addr: u64) -> Option<SourceLine<'_>> {
unsafe {
let line = crate::dw_sys::dwfl_module_getsrc(self.as_ptr(), addr);
if line.is_null() {
return None;
}
let mut lineno: libc::c_int = 0;
let file = crate::dw_sys::dwfl_lineinfo(
line,
ptr::null_mut(),
&mut lineno,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
);
if file.is_null() {
return None;
}
Some(SourceLine {
file: CStr::from_ptr(file),
line: lineno,
_module: PhantomData,
})
}
}
pub fn addr_name(&self, addr: u64) -> Result<&CStr, Error> {
unsafe {
let ptr = crate::dw_sys::dwfl_module_addrname(self.as_ptr(), addr);
if ptr.is_null() {
Err(Error::new())
} else {
Ok(CStr::from_ptr(ptr))
}
}
}
pub fn addrdie(&self, addr: u64) -> Option<(crate::dw_sys::Dwarf_Die, u64)> {
unsafe {
let mut bias: crate::dw_sys::Dwarf_Addr = 0;
let result = crate::dw_sys::dwfl_module_addrdie(self.as_ptr(), addr, &mut bias);
if result.is_null() {
None
} else {
Some((*result, bias))
}
}
}
pub fn getscopes(
&self,
cudie: &mut crate::dw_sys::Dwarf_Die,
pc: u64,
) -> Option<(*mut crate::dw_sys::Dwarf_Die, c_int)> {
unsafe {
let mut scopes: *mut crate::dw_sys::Dwarf_Die = ptr::null_mut();
let n = crate::dw_sys::dwarf_getscopes(cudie, pc, &mut scopes);
if n <= 0 {
None
} else {
Some((scopes, n))
}
}
}
pub fn find_symbol(&self, name: &str, sym_type: Option<u8>) -> Option<u64> {
let c_name = CString::new(name).ok()?;
let name_bytes = c_name.as_bytes();
let mut fallback = None;
unsafe {
let nsyms = crate::dw_sys::dwfl_module_getsymtab(self.as_ptr());
if nsyms <= 0 {
return None;
}
for i in 0..nsyms {
let mut sym = mem::zeroed::<crate::dw_sys::GElf_Sym>();
let mut addr: crate::dw_sys::GElf_Addr = 0;
let sym_name = crate::dw_sys::dwfl_module_getsym_info(
self.as_ptr(),
i,
&mut sym,
&mut addr,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
);
if sym_name.is_null() {
continue;
}
if (sym.st_info >> 4) == 0 {
continue;
}
if let Some(t) = sym_type {
if (sym.st_info & 0xf) != t {
continue;
}
}
let sym_bytes = CStr::from_ptr(sym_name).to_bytes();
let at_pos = sym_bytes.iter().position(|&b| b == b'@');
let base = &sym_bytes[..at_pos.unwrap_or(sym_bytes.len())];
if base != name_bytes {
continue;
}
match at_pos {
None => return Some(addr),
Some(p) if sym_bytes.get(p + 1) == Some(&b'@') => return Some(addr),
Some(_) => fallback.get_or_insert(addr),
};
}
}
fallback
}
pub fn addr_info(&self, addr: u64) -> Result<AddrInfo<'_>, Error> {
unsafe {
let mut offset = 0;
let mut sym = mem::zeroed::<crate::dw_sys::GElf_Sym>();
let mut bias = 0;
let ptr = crate::dw_sys::dwfl_module_addrinfo(
self.as_ptr(),
addr,
&mut offset,
&mut sym,
ptr::null_mut(),
ptr::null_mut(),
&mut bias,
);
if ptr.is_null() {
Err(Error::new())
} else {
Ok(AddrInfo {
name: ptr,
offset,
sym: Symbol(sym),
bias,
_module: PhantomData,
})
}
}
}
}
pub struct AddrInfo<'a> {
name: *const libc::c_char,
offset: u64,
sym: Symbol,
bias: u64,
_module: PhantomData<&'a ModuleRef>,
}
pub struct SourceLine<'a> {
file: &'a CStr,
line: libc::c_int,
_module: PhantomData<&'a ModuleRef>,
}
impl<'a> SourceLine<'a> {
pub fn file(&self) -> &'a CStr {
self.file
}
pub fn line(&self) -> i32 {
self.line
}
}
impl<'a> AddrInfo<'a> {
pub fn name(&self) -> &'a CStr {
unsafe { CStr::from_ptr(self.name) }
}
pub fn offset(&self) -> u64 {
self.offset
}
pub fn symbol(&self) -> &Symbol {
&self.sym
}
pub fn bias(&self) -> u64 {
self.bias
}
}