use crate::{sys, DisassemblyFlavor, SBAddress, SBInstructionList, SBStream, SBTarget, SymbolType};
use std::ffi::{CStr, CString};
use std::fmt;
use std::os::raw::c_char;
use std::ptr;
pub struct SBSymbol {
pub raw: sys::SBSymbolRef,
}
impl SBSymbol {
pub(crate) fn wrap(raw: sys::SBSymbolRef) -> SBSymbol {
SBSymbol { raw }
}
pub(crate) fn maybe_wrap(raw: sys::SBSymbolRef) -> Option<SBSymbol> {
if unsafe { sys::SBSymbolIsValid(raw) } {
Some(SBSymbol { raw })
} else {
None
}
}
pub fn is_valid(&self) -> bool {
unsafe { sys::SBSymbolIsValid(self.raw) }
}
pub fn name(&self) -> &str {
unsafe {
match CStr::from_ptr(sys::SBSymbolGetName(self.raw)).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
pub fn display_name(&self) -> &str {
unsafe {
match CStr::from_ptr(sys::SBSymbolGetDisplayName(self.raw)).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
pub fn mangled_name(&self) -> Option<&str> {
unsafe { self.check_null_ptr(sys::SBSymbolGetMangledName(self.raw)) }
}
#[allow(missing_docs)]
pub fn get_instructions(
&self,
target: &SBTarget,
flavor: DisassemblyFlavor,
) -> SBInstructionList {
let flavor = match flavor {
DisassemblyFlavor::ATT => CString::new("att").ok(),
DisassemblyFlavor::Default => None,
DisassemblyFlavor::Intel => CString::new("intel").ok(),
};
SBInstructionList::wrap(unsafe {
sys::SBSymbolGetInstructions2(
self.raw,
target.raw,
flavor.map_or(ptr::null(), |s| s.as_ptr()),
)
})
}
pub fn start_address(&self) -> Option<SBAddress> {
SBAddress::maybe_wrap(unsafe { sys::SBSymbolGetStartAddress(self.raw) })
}
pub fn end_address(&self) -> Option<SBAddress> {
SBAddress::maybe_wrap(unsafe { sys::SBSymbolGetEndAddress(self.raw) })
}
pub fn prologue_byte_size(&self) -> u32 {
unsafe { sys::SBSymbolGetPrologueByteSize(self.raw) }
}
pub fn symbol_type(&self) -> SymbolType {
unsafe { sys::SBSymbolGetType(self.raw) }
}
pub fn is_external(&self) -> bool {
unsafe { sys::SBSymbolIsExternal(self.raw) }
}
pub fn is_synthetic(&self) -> bool {
unsafe { sys::SBSymbolIsSynthetic(self.raw) }
}
unsafe fn check_null_ptr(&self, ptr: *const c_char) -> Option<&str> {
if !ptr.is_null() {
match CStr::from_ptr(ptr).to_str() {
Ok(s) => Some(s),
_ => panic!("Invalid string?"),
}
} else {
None
}
}
}
impl Clone for SBSymbol {
fn clone(&self) -> SBSymbol {
SBSymbol {
raw: unsafe { sys::CloneSBSymbol(self.raw) },
}
}
}
impl fmt::Debug for SBSymbol {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let stream = SBStream::new();
unsafe { sys::SBSymbolGetDescription(self.raw, stream.raw) };
write!(fmt, "SBSymbol {{ {} }}", stream.data())
}
}
impl Drop for SBSymbol {
fn drop(&mut self) {
unsafe { sys::DisposeSBSymbol(self.raw) };
}
}
unsafe impl Send for SBSymbol {}
unsafe impl Sync for SBSymbol {}
#[cfg(feature = "graphql")]
#[juniper::graphql_object]
impl SBSymbol {
fn name() -> &str {
self.name()
}
fn display_name() -> &str {
self.display_name()
}
fn mangled_name() -> Option<&str> {
self.mangled_name()
}
fn start_address() -> Option<SBAddress> {
self.start_address()
}
fn end_address() -> Option<SBAddress> {
self.end_address()
}
fn prologue_byte_size() -> i32 {
self.prologue_byte_size() as i32
}
fn is_external() -> bool {
self.is_external()
}
fn is_synthetic() -> bool {
self.is_synthetic()
}
}