From 5bb8cffb3a2eb7e1be4d924f530bc61a91d2fc21 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Tue, 26 Nov 2024 11:31:00 +0900 Subject: [PATCH] feat: add many safe wrapper functions (#39) --- src/address.rs | 15 +++++++++ src/data.rs | 36 +++++++++++++++++++- src/filespec.rs | 8 +++++ src/lib.rs | 4 +-- src/module.rs | 49 ++++++++++++++++++++++++++- src/modulespec.rs | 16 +++++++++ src/process.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++-- src/target.rs | 11 ++++++ src/value.rs | 22 ++++++++++++ 9 files changed, 241 insertions(+), 6 deletions(-) diff --git a/src/address.rs b/src/address.rs index 6b5e2acf..0ee0baae 100644 --- a/src/address.rs +++ b/src/address.rs @@ -234,6 +234,21 @@ impl SBAddress { pub fn line_entry(&self) -> Option { SBLineEntry::maybe_wrap(unsafe { sys::SBAddressGetLineEntry(self.raw) }) } + + /// Returns offset of the address in the section + /// + /// See also: + /// - [`get_section`] for getting the section corresponding to this address + /// + /// [`get_section`]: Self::get_section + pub fn get_offset(&self) -> lldb_addr_t { + unsafe { sys::SBAddressGetOffset(self.raw) } + } + + /// Returns the corresponding section of this address. + pub fn get_section(&self) -> Option { + SBSection::maybe_wrap(unsafe { sys::SBAddressGetSection(self.raw) }) + } } impl Clone for SBAddress { diff --git a/src/data.rs b/src/data.rs index 5ca8588a..0c4fee08 100644 --- a/src/data.rs +++ b/src/data.rs @@ -4,7 +4,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::sys; +use crate::{sys, SBError}; /// A block of data. #[derive(Debug)] @@ -32,6 +32,40 @@ impl SBData { pub fn is_valid(&self) -> bool { unsafe { sys::SBDataIsValid(self.raw) } } + + /// Get address of the specified offset in this data region + pub fn get_address(&self, offset: sys::lldb_offset_t) -> Result { + let error = SBError::default(); + let result = unsafe { sys::SBDataGetAddress(self.raw, error.raw, offset) }; + if error.is_success() { + Ok(result) + } else { + Err(error) + } + } + + /// Reads the data at specified offset to the buffer. + pub fn read_raw_data( + &self, + offset: sys::lldb_offset_t, + buffer: &mut [u8], + ) -> Result<(), SBError> { + let error = SBError::default(); + unsafe { + sys::SBDataReadRawData( + self.raw, + error.raw, + offset, + buffer.as_mut_ptr() as *mut _, + buffer.len(), + ); + } + if error.is_success() { + Ok(()) + } else { + Err(error) + } + } } impl Clone for SBData { diff --git a/src/filespec.rs b/src/filespec.rs index 8d3e8a24..d1a844df 100644 --- a/src/filespec.rs +++ b/src/filespec.rs @@ -7,6 +7,7 @@ use crate::{sys, SBStream}; use std::ffi::CStr; use std::fmt; +use std::path::Path; /// A file specification that divides the path into a /// directory and basename. @@ -33,6 +34,13 @@ impl SBFileSpec { } } + /// Create `SBFileSpec` from path + pub fn from_path>(path: P, resolve: bool) -> Self { + let path_cstring = + std::ffi::CString::new(path.as_ref().as_os_str().as_encoded_bytes()).unwrap(); + Self::wrap(unsafe { sys::CreateSBFileSpec3(path_cstring.as_ptr(), resolve) }) + } + /// Check whether or not this is a valid `SBFileSpec` value. pub fn is_valid(&self) -> bool { unsafe { sys::SBFileSpecIsValid(self.raw) } diff --git a/src/lib.rs b/src/lib.rs index 8044bf2f..13426edd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -196,11 +196,11 @@ 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::module::{SBModule, SBModuleSectionIter, SBModuleSymbolsIter}; pub use self::modulespec::SBModuleSpec; pub use self::platform::SBPlatform; pub use self::process::{ - SBProcess, SBProcessEvent, SBProcessEventRestartedReasonIter, SBProcessQueueIter, + ImageToken, SBProcess, SBProcessEvent, SBProcessEventRestartedReasonIter, SBProcessQueueIter, SBProcessThreadIter, }; pub use self::processinfo::SBProcessInfo; diff --git a/src/module.rs b/src/module.rs index 5fc717cb..18233baa 100644 --- a/src/module.rs +++ b/src/module.rs @@ -5,7 +5,8 @@ // except according to those terms. use crate::{ - sys, SBFileSpec, SBSection, SBStream, SBSymbolContextList, SBTypeList, SymbolType, TypeClass, + sys, SBFileSpec, SBSection, SBStream, SBSymbol, SBSymbolContextList, SBTypeList, SymbolType, + TypeClass, }; use std::ffi::CString; use std::fmt; @@ -99,6 +100,14 @@ impl SBModule { pub fn types(&self, type_mask: TypeClass) -> SBTypeList { SBTypeList::wrap(unsafe { sys::SBModuleGetTypes(self.raw, type_mask.bits()) }) } + + /// Get a list of all symbols in the module + pub fn symbols(&self) -> SBModuleSymbolsIter { + SBModuleSymbolsIter { + module: self, + index: 0, + } + } } /// Iterate over the [sections] in a [module]. @@ -133,6 +142,44 @@ impl<'d> Iterator for SBModuleSectionIter<'d> { impl<'d> ExactSizeIterator for SBModuleSectionIter<'d> {} +/// Iterate over the [symbols] in a [module]. +/// +/// [symbols]: SBSymbol +/// [module]: SBModule +pub struct SBModuleSymbolsIter<'d> { + module: &'d SBModule, + index: usize, +} + +impl<'d> Iterator for SBModuleSymbolsIter<'d> { + type Item = SBSymbol; + + fn next(&mut self) -> Option { + self.nth(0) + } + + fn size_hint(&self) -> (usize, Option) { + let size = unsafe { sys::SBModuleGetNumSections(self.module.raw) }; + let len = size - self.index; + (len, Some(len)) + } + + fn nth(&mut self, n: usize) -> Option { + let size = unsafe { sys::SBModuleGetNumSections(self.module.raw) }; + let index = n + self.index; + if index < size { + let symbol = unsafe { sys::SBModuleGetSymbolAtIndex(self.module.raw, index) }; + self.index = index + 1; + Some(SBSymbol { raw: symbol }) + } else { + self.index = self.len(); + None + } + } +} + +impl<'d> ExactSizeIterator for SBModuleSymbolsIter<'d> {} + impl Clone for SBModule { fn clone(&self) -> SBModule { SBModule { diff --git a/src/modulespec.rs b/src/modulespec.rs index 7fa36533..62b48ec9 100644 --- a/src/modulespec.rs +++ b/src/modulespec.rs @@ -14,6 +14,11 @@ pub struct SBModuleSpec { } impl SBModuleSpec { + /// Construct a new `SBModuleSpec`. + pub(crate) fn wrap(raw: sys::SBModuleSpecRef) -> SBModuleSpec { + SBModuleSpec { raw } + } + /// Construct a new `Some(SBModuleSpec)` or `None`. #[allow(dead_code)] pub(crate) fn maybe_wrap(raw: sys::SBModuleSpecRef) -> Option { @@ -29,6 +34,11 @@ impl SBModuleSpec { unsafe { sys::SBModuleSpecIsValid(self.raw) } } + /// Creates new empty `SBModuleSpec` + pub fn new() -> Self { + Self::wrap(unsafe { sys::CreateSBModuleSpec() }) + } + /// The file for the module on the host system that is running LLDB. /// /// This can differ from the path on the platform since we might @@ -110,6 +120,12 @@ impl Clone for SBModuleSpec { } } +impl Default for SBModuleSpec { + fn default() -> Self { + Self::new() + } +} + impl fmt::Debug for SBModuleSpec { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let stream = SBStream::new(); diff --git a/src/process.rs b/src/process.rs index 1e18821b..000a5d25 100644 --- a/src/process.rs +++ b/src/process.rs @@ -6,8 +6,8 @@ use crate::{ lldb_addr_t, lldb_pid_t, lldb_tid_t, sys, Permissions, SBBroadcaster, SBError, SBEvent, - SBMemoryRegionInfo, SBMemoryRegionInfoList, SBProcessInfo, SBQueue, SBStream, SBStructuredData, - SBThread, StateType, + SBFileSpec, SBMemoryRegionInfo, SBMemoryRegionInfoList, SBProcessInfo, SBQueue, SBStream, + SBStructuredData, SBTarget, SBThread, StateType, }; use std::ffi::{CStr, CString}; use std::fmt; @@ -559,6 +559,85 @@ impl SBProcess { pub fn get_memory_regions(&self) -> SBMemoryRegionInfoList { SBMemoryRegionInfoList::wrap(unsafe { sys::SBProcessGetMemoryRegions(self.raw) }) } + + /// Reads the memory at specified address in the process to the `buffer` + pub fn read_memory(&self, addr: lldb_addr_t, buffer: &mut [u8]) -> Result<(), SBError> { + // SBProcessReadMemory will return an error if the memory region is not allowed to read + // and does not cause bad behavior so this method can be safe. + let error = SBError::default(); + unsafe { + sys::SBProcessReadMemory( + self.raw, + addr, + buffer.as_mut_ptr() as *mut _, + buffer.len(), + error.raw, + ); + } + if error.is_success() { + Ok(()) + } else { + Err(error) + } + } + + /// Writes the `buffer` data to the memory at specified address in the process + pub fn write_memory(&self, addr: lldb_addr_t, buffer: &[u8]) -> Result<(), SBError> { + let error = SBError::default(); + unsafe { + sys::SBProcessWriteMemory( + self.raw, + addr, + buffer.as_ptr() as *mut _, + buffer.len(), + error.raw, + ); + } + if error.is_success() { + Ok(()) + } else { + Err(error) + } + } + + /// Returns the byte order of target process + pub fn byte_order(&self) -> crate::ByteOrder { + unsafe { sys::SBProcessGetByteOrder(self.raw) } + } + + /// Loads the specified image into the process. + pub fn load_image(&self, file: &SBFileSpec) -> Result { + let error = SBError::default(); + let image_token = unsafe { sys::SBProcessLoadImage(self.raw, file.raw, error.raw) }; + if error.is_failure() { + Err(error) + } else { + Ok(ImageToken(image_token)) + } + } + + /// Unloads the image loaded with [`load_image`]. + /// + /// [`load_image`]: Self::load_image + pub fn unload_image(&self, image_token: ImageToken) -> Result<(), SBError> { + // the method returns error if image_token is not valid, instead of causing undefined behavior. + let error = SBError::wrap(unsafe { sys::SBProcessUnloadImage(self.raw, image_token.0) }); + if error.is_failure() { + Err(error) + } else { + Ok(()) + } + } + + /// Returns the [`SBTarget`] corresponding to this `SBProcess`. + /// + /// This never return `None` if `self` is [`valid`]. + /// + /// [`SBTarget`]: SBTarget + /// [`valid`]: Self::is_valid + pub fn target(&self) -> Option { + SBTarget::maybe_wrap(unsafe { sys::SBProcessGetTarget(self.raw) }) + } } /// Iterate over the [threads] in a [process]. @@ -621,6 +700,9 @@ impl<'d> Iterator for SBProcessQueueIter<'d> { } } +/// The token to unload image +pub struct ImageToken(pub u32); + impl Clone for SBProcess { fn clone(&self) -> SBProcess { SBProcess { diff --git a/src/target.rs b/src/target.rs index 315e297e..79a9d52f 100644 --- a/src/target.rs +++ b/src/target.rs @@ -10,6 +10,7 @@ use crate::{ SBModule, SBModuleSpec, SBPlatform, SBProcess, SBStream, SBSymbolContextList, SBValue, SBWatchpoint, SymbolType, }; +use lldb_sys::ByteOrder; use std::ffi::{CStr, CString}; use std::fmt; @@ -386,6 +387,16 @@ impl SBTarget { pub fn set_launch_info(&self, launch_info: SBLaunchInfo) { unsafe { sys::SBTargetSetLaunchInfo(self.raw, launch_info.raw) }; } + + /// Returns the byte order of target + pub fn byte_order(&self) -> ByteOrder { + unsafe { sys::SBTargetGetByteOrder(self.raw) } + } + + /// Returns the size of address in bytes + pub fn get_address_byte_size(&self) -> u32 { + unsafe { sys::SBTargetGetAddressByteSize(self.raw) } + } } impl Clone for SBTarget { diff --git a/src/value.rs b/src/value.rs index 3cb8a5e7..c4d81949 100644 --- a/src/value.rs +++ b/src/value.rs @@ -249,6 +249,28 @@ impl SBValue { None } } + + /// Get the value as signed integer + pub fn get_as_signed(&self) -> Result { + let error = SBError::default(); + let result = unsafe { sys::SBValueGetValueAsSigned(self.raw, error.raw, 0) }; + if error.is_success() { + Ok(result) + } else { + Err(error) + } + } + + /// Get the value as unsigned integer + pub fn get_as_unsigned(&self) -> Result { + let error = SBError::default(); + let result = unsafe { sys::SBValueGetValueAsUnsigned(self.raw, error.raw, 0) }; + if error.is_success() { + Ok(result) + } else { + Err(error) + } + } } impl Clone for SBValue {