From 8b5e85233436026ac56928c0450f6af53822a599 Mon Sep 17 00:00:00 2001 From: tetenpapier Date: Tue, 14 Jun 2022 09:54:22 +0200 Subject: [PATCH 1/6] add basic creation for breakpoints --- src/target.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/target.rs b/src/target.rs index 83eb9f9c..d5ccf101 100644 --- a/src/target.rs +++ b/src/target.rs @@ -232,6 +232,26 @@ impl SBTarget { unsafe { sys::SBTargetDeleteAllBreakpoints(self.raw) }; } + #[allow(missing_docs)] + pub fn breakpoint_create_by_location(&self, file: &str, line: u32) -> SBBreakpoint { + let file = CString::new(file).unwrap(); + SBBreakpoint::from(unsafe { + sys::SBTargetBreakpointCreateByLocation(self.raw, file.as_ptr(), line) + }) + } + + #[allow(missing_docs)] + pub fn breakpoint_create_by_address(&self, address: lldb_addr_t) -> SBBreakpoint { + SBBreakpoint::from(unsafe { sys::SBTargetBreakpointCreateByAddress(self.raw, address) }) + } + + #[allow(missing_docs)] + pub fn breakpoint_create_by_sbaddress(&self, address: SBAddress) -> SBBreakpoint { + SBBreakpoint::from(unsafe { + sys::SBTargetBreakpointCreateBySBAddress(self.raw, address.raw) + }) + } + #[allow(missing_docs)] pub fn breakpoints(&self) -> SBTargetBreakpointIter { SBTargetBreakpointIter { From a6a68b94972d86be77393bc9233910d914a117cf Mon Sep 17 00:00:00 2001 From: tetenpapier Date: Tue, 14 Jun 2022 09:55:34 +0200 Subject: [PATCH 2/6] handle nullptr for SBValue --- src/value.rs | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/src/value.rs b/src/value.rs index f6461cd6..ef3c6305 100644 --- a/src/value.rs +++ b/src/value.rs @@ -10,6 +10,7 @@ use crate::{ }; use std::ffi::CStr; use std::fmt; +use std::os::raw::c_char; /// The value of a variable, register or expression. pub struct SBValue { @@ -18,6 +19,17 @@ pub struct SBValue { } impl SBValue { + 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 + } + } + /// Construct a new `Some(SBValue)` or `None`. pub fn maybe_wrap(raw: sys::SBValueRef) -> Option { if unsafe { sys::SBValueIsValid(raw) } { @@ -48,33 +60,18 @@ impl SBValue { } #[allow(missing_docs)] - pub fn name(&self) -> &str { - unsafe { - match CStr::from_ptr(sys::SBValueGetName(self.raw)).to_str() { - Ok(s) => s, - _ => panic!("Invalid string?"), - } - } + pub fn name(&self) -> Option<&str> { + unsafe { self.check_null_ptr(sys::SBValueGetName(self.raw)) } } #[allow(missing_docs)] - pub fn type_name(&self) -> &str { - unsafe { - match CStr::from_ptr(sys::SBValueGetTypeName(self.raw)).to_str() { - Ok(s) => s, - _ => panic!("Invalid string?"), - } - } + pub fn type_name(&self) -> Option<&str> { + unsafe { self.check_null_ptr(sys::SBValueGetTypeName(self.raw)) } } #[allow(missing_docs)] - pub fn display_type_name(&self) -> &str { - unsafe { - match CStr::from_ptr(sys::SBValueGetDisplayTypeName(self.raw)).to_str() { - Ok(s) => s, - _ => panic!("Invalid string?"), - } - } + pub fn display_type_name(&self) -> Option<&str> { + unsafe { self.check_null_ptr(sys::SBValueGetDisplayTypeName(self.raw)) } } #[allow(missing_docs)] @@ -98,13 +95,8 @@ impl SBValue { } #[allow(missing_docs)] - pub fn value(&self) -> &str { - unsafe { - match CStr::from_ptr(sys::SBValueGetValue(self.raw)).to_str() { - Ok(s) => s, - _ => panic!("Invalid string?"), - } - } + pub fn value(&self) -> Option<&str> { + unsafe { self.check_null_ptr(sys::SBValueGetValue(self.raw)) } } #[allow(missing_docs)] From d6d8b52d6c1184b7a63c5fa787172488984cffe8 Mon Sep 17 00:00:00 2001 From: tetenpapier Date: Tue, 14 Jun 2022 09:56:15 +0200 Subject: [PATCH 3/6] add basic childs methods for SBValue --- src/value.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/value.rs b/src/value.rs index ef3c6305..b29b9d8b 100644 --- a/src/value.rs +++ b/src/value.rs @@ -99,6 +99,16 @@ impl SBValue { unsafe { self.check_null_ptr(sys::SBValueGetValue(self.raw)) } } + #[allow(missing_docs)] + pub fn get_child_at_index(&self, id: u32) -> Option { + SBValue::maybe_wrap(unsafe { sys::SBValueGetChildAtIndex(self.raw, id) }) + } + + #[allow(missing_docs)] + pub fn get_num_children(&self) -> u32 { + unsafe { sys::SBValueGetNumChildren(self.raw) } + } + #[allow(missing_docs)] pub fn dereference(&self) -> Option { SBValue::maybe_wrap(unsafe { sys::SBValueDereference(self.raw) }) From 5c1b6b28f7cda797d0a9ceb57f226c6c6b107103 Mon Sep 17 00:00:00 2001 From: tetenpapier Date: Tue, 14 Jun 2022 09:57:02 +0200 Subject: [PATCH 4/6] add basic change value for SBValue --- src/value.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/value.rs b/src/value.rs index b29b9d8b..b8b94230 100644 --- a/src/value.rs +++ b/src/value.rs @@ -8,7 +8,7 @@ use crate::{ lldb_addr_t, lldb_user_id_t, sys, Format, SBAddress, SBData, SBError, SBFrame, SBProcess, SBStream, SBTarget, SBThread, SBWatchpoint, }; -use std::ffi::CStr; +use std::ffi::{CStr, CString}; use std::fmt; use std::os::raw::c_char; @@ -109,6 +109,18 @@ impl SBValue { unsafe { sys::SBValueGetNumChildren(self.raw) } } + #[allow(missing_docs)] + pub fn set_value_from_cstring(&self, val: &str) -> Result<(), SBError> { + let error = SBError::default(); + let val = CString::new(val).unwrap(); + + if unsafe { sys::SBValueSetValueFromCString2(self.raw, val.as_ptr(), error.raw) } { + Ok(()) + } else { + Err(error) + } + } + #[allow(missing_docs)] pub fn dereference(&self) -> Option { SBValue::maybe_wrap(unsafe { sys::SBValueDereference(self.raw) }) From b464f24f56b065fdab1ff7d65190e73b9204ac0a Mon Sep 17 00:00:00 2001 From: tetenpapier Date: Mon, 20 Jun 2022 11:01:05 +0200 Subject: [PATCH 5/6] add steps over and out --- src/thread.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/thread.rs b/src/thread.rs index bd6236fa..35b6f184 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -9,6 +9,7 @@ use crate::{ }; use std::ffi::CStr; use std::fmt; +use RunMode; /// A thread of execution. /// @@ -223,6 +224,28 @@ impl SBThread { SBProcess::from(unsafe { sys::SBThreadGetProcess(self.raw) }) } + #[allow(missing_docs)] + pub fn step_out(&self) -> Result<(), SBError> { + let error = SBError::default(); + unsafe { sys::SBThreadStepOut(self.raw, error.raw) } + if error.is_success() { + Ok(()) + } else { + Err(error) + } + } + + #[allow(missing_docs)] + pub fn step_over(&self, stop_other_threads: RunMode) -> Result<(), SBError> { + let error = SBError::default(); + unsafe { sys::SBThreadStepOver(self.raw, stop_other_threads, error.raw) } + if error.is_success() { + Ok(()) + } else { + Err(error) + } + } + /// If the given event is a thread event, return it as an /// `SBThreadEvent`. Otherwise, return `None`. pub fn event_as_thread_event(event: &SBEvent) -> Option { From 56874982cb51bb128805a4d030e721aa7e0a645a Mon Sep 17 00:00:00 2001 From: tetenpapier Date: Mon, 20 Jun 2022 15:45:47 +0200 Subject: [PATCH 6/6] add Memory region info item and list --- src/lib.rs | 4 ++ src/memoryregioninfo.rs | 98 +++++++++++++++++++++++++++++++++ src/memoryregioninfolist.rs | 106 ++++++++++++++++++++++++++++++++++++ src/process.rs | 28 +++++++++- 4 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 src/memoryregioninfo.rs create mode 100644 src/memoryregioninfolist.rs diff --git a/src/lib.rs b/src/lib.rs index 7357cb21..a46508be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,6 +145,8 @@ mod instructionlist; mod launchinfo; mod lineentry; mod listener; +mod memoryregioninfo; +mod memoryregioninfolist; mod module; mod modulespec; mod platform; @@ -191,6 +193,8 @@ pub use self::instructionlist::{SBInstructionList, SBInstructionListIter}; pub use self::launchinfo::SBLaunchInfo; pub use self::lineentry::SBLineEntry; pub use self::listener::SBListener; +pub use self::memoryregioninfo::SBMemoryRegionInfo; +pub use self::memoryregioninfolist::{SBMemoryRegionInfoList, SBMemoryRegionInfoListIter}; pub use self::module::{SBModule, SBModuleSectionIter}; pub use self::modulespec::SBModuleSpec; pub use self::platform::SBPlatform; diff --git a/src/memoryregioninfo.rs b/src/memoryregioninfo.rs new file mode 100644 index 00000000..f6f0e73c --- /dev/null +++ b/src/memoryregioninfo.rs @@ -0,0 +1,98 @@ +use crate::sys; +use lldb_addr_t; +use std::ffi::CStr; + +#[allow(missing_docs)] +#[derive(Debug)] +pub struct SBMemoryRegionInfo { + pub raw: sys::SBMemoryRegionInfoRef, +} + +impl SBMemoryRegionInfo { + #[allow(missing_docs)] + pub fn new() -> Self { + SBMemoryRegionInfo::from(unsafe { sys::CreateSBMemoryRegionInfo() }) + } + + #[allow(missing_docs)] + pub fn clear(&self) { + unsafe { sys::SBMemoryRegionInfoClear(self.raw) }; + } + + /* + pub fn get_description(&self, description: SBStream) -> SBStream { + } + */ + + #[allow(missing_docs)] + pub fn is_executable(&self) -> bool { + unsafe { sys::SBMemoryRegionInfoIsExecutable(self.raw) } + } + + #[allow(missing_docs)] + pub fn is_mapped(&self) -> bool { + unsafe { sys::SBMemoryRegionInfoIsMapped(self.raw) } + } + + #[allow(missing_docs)] + pub fn is_readable(&self) -> bool { + unsafe { sys::SBMemoryRegionInfoIsReadable(self.raw) } + } + + #[allow(missing_docs)] + pub fn is_writable(&self) -> bool { + unsafe { sys::SBMemoryRegionInfoIsWritable(self.raw) } + } + + #[allow(missing_docs)] + pub fn get_name(&self) -> Option { + unsafe { + let ptr = sys::SBMemoryRegionInfoGetName(self.raw); + + if !ptr.is_null() { + match CStr::from_ptr(ptr).to_str() { + Ok(s) => Some(s.to_owned()), + _ => panic!("No MemoryRegionInfo name string?"), + } + } else { + None + } + } + } + + #[allow(missing_docs)] + pub fn get_region_base(&self) -> lldb_addr_t { + unsafe { sys::SBMemoryRegionInfoGetRegionBase(self.raw) } + } + + #[allow(missing_docs)] + pub fn get_region_end(&self) -> lldb_addr_t { + unsafe { sys::SBMemoryRegionInfoGetRegionEnd(self.raw) } + } +} + +impl Clone for SBMemoryRegionInfo { + fn clone(&self) -> Self { + Self { + raw: unsafe { sys::CloneSBMemoryRegionInfo(self.raw) }, + } + } +} + +impl Default for SBMemoryRegionInfo { + fn default() -> Self { + Self::new() + } +} + +impl Drop for SBMemoryRegionInfo { + fn drop(&mut self) { + unsafe { sys::DisposeSBMemoryRegionInfo(self.raw) }; + } +} + +impl From for SBMemoryRegionInfo { + fn from(raw: sys::SBMemoryRegionInfoRef) -> Self { + Self { raw } + } +} diff --git a/src/memoryregioninfolist.rs b/src/memoryregioninfolist.rs new file mode 100644 index 00000000..ec64cac2 --- /dev/null +++ b/src/memoryregioninfolist.rs @@ -0,0 +1,106 @@ +use crate::sys; +use crate::SBMemoryRegionInfo; + +#[allow(missing_docs)] +#[derive(Debug)] +pub struct SBMemoryRegionInfoList { + pub raw: sys::SBMemoryRegionInfoListRef, +} + +impl SBMemoryRegionInfoList { + #[allow(missing_docs)] + pub fn new() -> Self { + SBMemoryRegionInfoList::from(unsafe { sys::CreateSBMemoryRegionInfoList() }) + } + + #[allow(missing_docs)] + pub fn append(&self, region: SBMemoryRegionInfo) { + unsafe { sys::SBMemoryRegionInfoListAppend(self.raw, region.raw) }; + } + + #[allow(missing_docs)] + pub fn append_list(&self, region_list: SBMemoryRegionInfoList) { + unsafe { sys::SBMemoryRegionInfoListAppendList(self.raw, region_list.raw) }; + } + + #[allow(missing_docs)] + pub fn clear(&self) { + unsafe { sys::SBMemoryRegionInfoListClear(self.raw) }; + } + + #[allow(missing_docs)] + pub fn get_memory_region(&self, index: u32) -> Option { + let tmp = SBMemoryRegionInfo::default(); + if unsafe { sys::SBMemoryRegionInfoListGetMemoryRegionAtIndex(self.raw, index, tmp.raw) } { + Some(tmp) + } else { + None + } + } + + #[allow(missing_docs)] + pub fn get_size(&self) -> u32 { + unsafe { sys::SBMemoryRegionInfoListGetSize(self.raw) } + } + + #[allow(missing_docs)] + pub fn iter(&self) -> SBMemoryRegionInfoListIter { + SBMemoryRegionInfoListIter { + memory_list: self, + idx: 0, + } + } +} + +impl Clone for SBMemoryRegionInfoList { + fn clone(&self) -> Self { + Self { + raw: unsafe { sys::CloneSBMemoryRegionInfoList(self.raw) }, + } + } +} + +impl Default for SBMemoryRegionInfoList { + fn default() -> Self { + Self::new() + } +} + +impl Drop for SBMemoryRegionInfoList { + fn drop(&mut self) { + unsafe { sys::DisposeSBMemoryRegionInfoList(self.raw) }; + } +} + +impl From for SBMemoryRegionInfoList { + fn from(raw: sys::SBMemoryRegionInfoListRef) -> Self { + Self { raw } + } +} + +#[allow(missing_docs)] +pub struct SBMemoryRegionInfoListIter<'d> { + memory_list: &'d SBMemoryRegionInfoList, + idx: u32, +} + +impl<'d> Iterator for SBMemoryRegionInfoListIter<'d> { + type Item = SBMemoryRegionInfo; + + #[allow(missing_docs)] + fn next(&mut self) -> Option { + if self.idx < self.memory_list.get_size() { + let r = self.memory_list.get_memory_region(self.idx); + self.idx += 1; + r + } else { + None + } + } + + #[allow(missing_docs)] + fn size_hint(&self) -> (usize, Option) { + let sz = self.memory_list.get_size() as usize; + (sz - self.idx as usize, Some(sz)) + } +} diff --git a/src/process.rs b/src/process.rs index b96ec47f..90fa34d5 100644 --- a/src/process.rs +++ b/src/process.rs @@ -5,10 +5,10 @@ // except according to those terms. use crate::{ - lldb_pid_t, lldb_tid_t, sys, SBBroadcaster, SBError, SBEvent, SBProcessInfo, SBQueue, SBStream, - SBThread, StateType, + lldb_addr_t, lldb_pid_t, lldb_tid_t, sys, SBBroadcaster, SBError, SBEvent, SBMemoryRegionInfo, + SBMemoryRegionInfoList, SBProcessInfo, SBQueue, SBStream, SBThread, StateType, }; -use std::ffi::{CStr, CString}; +use std::ffi::{c_void, CStr, CString}; use std::fmt; /// The process associated with the target program. @@ -338,6 +338,28 @@ impl SBProcess { pub fn process_info(&self) -> SBProcessInfo { SBProcessInfo::from(unsafe { sys::SBProcessGetProcessInfo(self.raw) }) } + + #[allow(missing_docs)] + pub fn get_memory_region_info( + &self, + load_addr: lldb_addr_t, + ) -> Result { + let region_info = SBMemoryRegionInfo::default(); + let error = SBError::from(unsafe { + sys::SBProcessGetMemoryRegionInfo(self.raw, load_addr, region_info.raw) + }); + + if error.is_success() { + Ok(region_info) + } else { + Err(error) + } + } + + #[allow(missing_docs)] + pub fn get_memory_regions(&self) -> SBMemoryRegionInfoList { + SBMemoryRegionInfoList::from(unsafe { sys::SBProcessGetMemoryRegions(self.raw) }) + } } /// Iterate over the [threads] in a [process].