use crate::{
lldb_addr_t, sys, SBAddress, SBBlock, SBCompileUnit, SBExpressionOptions, SBFunction,
SBLineEntry, SBModule, SBStream, SBSymbol, SBSymbolContext, SBThread, SBValue, SBValueList,
SBVariablesOptions,
};
use std::ffi::{CStr, CString};
use std::fmt;
pub struct SBFrame {
pub raw: sys::SBFrameRef,
}
impl SBFrame {
pub(crate) fn wrap(raw: sys::SBFrameRef) -> SBFrame {
SBFrame { raw }
}
pub(crate) fn maybe_wrap(raw: sys::SBFrameRef) -> Option<SBFrame> {
if unsafe { sys::SBFrameIsValid(raw) } {
Some(SBFrame { raw })
} else {
None
}
}
pub fn is_valid(&self) -> bool {
unsafe { sys::SBFrameIsValid(self.raw) }
}
pub fn frame_id(&self) -> u32 {
unsafe { sys::SBFrameGetFrameID(self.raw) }
}
pub fn cfa(&self) -> Option<lldb_addr_t> {
let cfa = unsafe { sys::SBFrameGetCFA(self.raw) };
if cfa != u64::max_value() {
Some(cfa)
} else {
None
}
}
pub fn pc(&self) -> lldb_addr_t {
unsafe { sys::SBFrameGetPC(self.raw) }
}
#[allow(missing_docs)]
pub fn set_pc(&self, new_pc: lldb_addr_t) -> bool {
unsafe { sys::SBFrameSetPC(self.raw, new_pc) }
}
pub fn sp(&self) -> lldb_addr_t {
unsafe { sys::SBFrameGetSP(self.raw) }
}
pub fn fp(&self) -> lldb_addr_t {
unsafe { sys::SBFrameGetFP(self.raw) }
}
pub fn pc_address(&self) -> SBAddress {
SBAddress::wrap(unsafe { sys::SBFrameGetPCAddress(self.raw) })
}
pub fn symbol_context(&self, resolve_scope: u32) -> SBSymbolContext {
SBSymbolContext::wrap(unsafe { sys::SBFrameGetSymbolContext(self.raw, resolve_scope) })
}
pub fn module(&self) -> SBModule {
SBModule::wrap(unsafe { sys::SBFrameGetModule(self.raw) })
}
pub fn compile_unit(&self) -> SBCompileUnit {
SBCompileUnit::wrap(unsafe { sys::SBFrameGetCompileUnit(self.raw) })
}
pub fn function(&self) -> SBFunction {
SBFunction::wrap(unsafe { sys::SBFrameGetFunction(self.raw) })
}
pub fn symbol(&self) -> SBSymbol {
SBSymbol::wrap(unsafe { sys::SBFrameGetSymbol(self.raw) })
}
pub fn block(&self) -> SBBlock {
SBBlock::wrap(unsafe { sys::SBFrameGetBlock(self.raw) })
}
pub fn function_name(&self) -> Option<&str> {
unsafe {
match CStr::from_ptr(sys::SBFrameGetFunctionName(self.raw).as_ref()?).to_str() {
Ok(s) => Some(s),
_ => None,
}
}
}
#[allow(missing_docs)]
pub fn display_function_name(&self) -> Option<&str> {
unsafe {
match CStr::from_ptr(sys::SBFrameGetDisplayFunctionName(self.raw)).to_str() {
Ok(s) => Some(s),
_ => None,
}
}
}
pub fn is_inlined(&self) -> bool {
unsafe { sys::SBFrameIsInlined(self.raw) }
}
pub fn evaluate_expression(&self, expression: &str, options: &SBExpressionOptions) -> SBValue {
let expression = CString::new(expression).unwrap();
SBValue::wrap(unsafe {
sys::SBFrameEvaluateExpression(self.raw, expression.as_ptr(), options.raw)
})
}
pub fn frame_block(&self) -> SBBlock {
SBBlock::wrap(unsafe { sys::SBFrameGetFrameBlock(self.raw) })
}
pub fn line_entry(&self) -> Option<SBLineEntry> {
SBLineEntry::maybe_wrap(unsafe { sys::SBFrameGetLineEntry(self.raw) })
}
pub fn thread(&self) -> SBThread {
SBThread::wrap(unsafe { sys::SBFrameGetThread(self.raw) })
}
pub fn disassemble(&self) -> &str {
unsafe {
match CStr::from_ptr(sys::SBFrameDisassemble(self.raw)).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
pub fn variables(&self, options: &SBVariablesOptions) -> SBValueList {
SBValueList::wrap(unsafe { sys::SBFrameGetVariables(self.raw, options.raw) })
}
pub fn all_variables(&self) -> SBValueList {
let options = SBVariablesOptions::new();
options.set_include_arguments(true);
options.set_include_locals(true);
options.set_include_statics(true);
options.set_in_scope_only(true);
self.variables(&options)
}
pub fn arguments(&self) -> SBValueList {
let options = SBVariablesOptions::new();
options.set_include_arguments(true);
options.set_include_locals(false);
options.set_include_statics(false);
options.set_in_scope_only(false);
self.variables(&options)
}
pub fn locals(&self) -> SBValueList {
let options = SBVariablesOptions::new();
options.set_include_arguments(false);
options.set_include_locals(true);
options.set_include_statics(false);
options.set_in_scope_only(false);
self.variables(&options)
}
pub fn statics(&self) -> SBValueList {
let options = SBVariablesOptions::new();
options.set_include_arguments(false);
options.set_include_locals(false);
options.set_include_statics(true);
options.set_in_scope_only(false);
self.variables(&options)
}
pub fn registers(&self) -> SBValueList {
SBValueList::wrap(unsafe { sys::SBFrameGetRegisters(self.raw) })
}
pub fn find_register(&self, name: &str) -> Option<SBValue> {
let name = CString::new(name).unwrap();
SBValue::maybe_wrap(unsafe { sys::SBFrameFindRegister(self.raw, name.as_ptr()) })
}
pub fn parent_frame(&self) -> Option<SBFrame> {
let thread = self.thread();
let parent_idx = self.frame_id() + 1;
if parent_idx < unsafe { sys::SBThreadGetNumFrames(thread.raw) } {
SBFrame::maybe_wrap(unsafe { sys::SBThreadGetFrameAtIndex(thread.raw, parent_idx) })
} else {
None
}
}
}
impl Clone for SBFrame {
fn clone(&self) -> SBFrame {
SBFrame {
raw: unsafe { sys::CloneSBFrame(self.raw) },
}
}
}
impl fmt::Debug for SBFrame {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let stream = SBStream::new();
unsafe { sys::SBFrameGetDescription(self.raw, stream.raw) };
write!(fmt, "SBFrame {{ {} }}", stream.data())
}
}
impl Drop for SBFrame {
fn drop(&mut self) {
unsafe { sys::DisposeSBFrame(self.raw) };
}
}
unsafe impl Send for SBFrame {}
unsafe impl Sync for SBFrame {}
#[cfg(feature = "graphql")]
#[graphql_object]
impl SBFrame {
fn frame_id() -> i32 {
self.frame_id() as i32
}
fn cfa() -> Option<i32> {
self.cfa().map(|i| i as i32)
}
fn pc() -> i32 {
self.pc() as i32
}
fn sp() -> i32 {
self.sp() as i32
}
fn fp() -> i32 {
self.fp() as i32
}
fn pc_address() -> SBAddress {
self.pc_address()
}
fn module() -> SBModule {
self.module()
}
fn compile_unit() -> SBCompileUnit {
self.compile_unit()
}
fn function() -> SBFunction {
self.function()
}
fn symbol() -> SBSymbol {
self.symbol()
}
fn block() -> SBBlock {
self.block()
}
fn function_name() -> Option<&str> {
self.function_name()
}
fn display_function_name() -> Option<&str> {
self.display_function_name()
}
fn is_inlined() -> bool {
self.is_inlined()
}
fn frame_block() -> SBBlock {
self.frame_block()
}
fn line_entry() -> Option<SBLineEntry> {
self.line_entry()
}
fn thread() -> SBThread {
self.thread()
}
}