use std::fmt;
use std::borrow::Cow;
use std::ffi::CStr;
use std::ops::Deref;
use std::os::raw::{c_char, c_int, c_void};
use std::path::Path;
use errors::Result;
use errors::ErrorKind::ResolverError;
use processor::StackFrame;
use utils;
extern "C" {
fn stack_frame_function_name(frame: *const StackFrame) -> *const c_char;
fn stack_frame_source_file_name(frame: *const StackFrame) -> *const c_char;
fn stack_frame_source_line(frame: *const StackFrame) -> c_int;
fn stack_frame_delete(frame: *mut StackFrame);
fn resolver_new(buffer: *const c_char, buffer_size: usize) -> *mut IResolver;
fn resolver_delete(resolver: *mut IResolver);
fn resolver_is_corrupt(resolver: *const IResolver) -> bool;
fn resolver_resolve_frame(
resolver: *const IResolver,
frame: *const StackFrame,
) -> *mut StackFrame;
}
pub struct ResolvedStackFrame {
internal: *mut StackFrame,
}
impl ResolvedStackFrame {
pub(crate) fn from_ptr(internal: *mut StackFrame) -> ResolvedStackFrame {
ResolvedStackFrame { internal }
}
pub fn function_name(&self) -> Cow<str> {
unsafe {
let ptr = stack_frame_function_name(self.internal);
CStr::from_ptr(ptr).to_string_lossy()
}
}
pub fn source_file_name(&self) -> Cow<str> {
unsafe {
let ptr = stack_frame_source_file_name(self.internal);
CStr::from_ptr(ptr).to_string_lossy()
}
}
pub fn source_line(&self) -> c_int {
unsafe { stack_frame_source_line(self.internal) }
}
}
impl Deref for ResolvedStackFrame {
type Target = StackFrame;
fn deref(&self) -> &StackFrame {
unsafe { &*self.internal }
}
}
impl Drop for ResolvedStackFrame {
fn drop(&mut self) {
unsafe { stack_frame_delete(self.internal) };
}
}
impl fmt::Debug for ResolvedStackFrame {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ResolvedStackFrame")
.field("instruction", &self.instruction())
.field("function_name", &self.function_name())
.field("source_file_name", &self.source_file_name())
.field("source_line", &self.source_line())
.field("trust", &self.trust())
.field("module", &self.module())
.finish()
}
}
type IResolver = c_void;
pub struct Resolver {
internal: *mut IResolver,
}
impl Resolver {
pub fn from_file<P: AsRef<Path>>(file_path: P) -> Result<Resolver> {
let buffer = utils::read_buffer(file_path)?;
Self::from_buffer(buffer.as_slice())
}
pub fn from_buffer(buffer: &[u8]) -> Result<Resolver> {
let internal = unsafe { resolver_new(buffer.as_ptr() as *const c_char, buffer.len()) };
if internal.is_null() {
Err(ResolverError("Could not load symbols".into()).into())
} else {
Ok(Resolver { internal })
}
}
pub fn corrupt(&self) -> bool {
unsafe { resolver_is_corrupt(self.internal) }
}
pub fn resolve_frame(&self, frame: &StackFrame) -> ResolvedStackFrame {
let ptr = unsafe { resolver_resolve_frame(self.internal, frame) };
ResolvedStackFrame::from_ptr(ptr)
}
}
impl Drop for Resolver {
fn drop(&mut self) {
unsafe { resolver_delete(self.internal) };
}
}