Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add many safe wrapper functions #39

Merged
merged 10 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,21 @@ impl SBAddress {
pub fn line_entry(&self) -> Option<SBLineEntry> {
SBLineEntry::maybe_wrap(unsafe { sys::SBAddressGetLineEntry(self.raw) })
}

/// Returns offset of the address in the section
///
/// See also:
/// - [`get_section`] for get the section corresponding to this address
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"for getting the"

///
/// [`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> {
SBSection::maybe_wrap(unsafe { sys::SBAddressGetSection(self.raw) })
}
}

impl Clone for SBAddress {
Expand Down
32 changes: 31 additions & 1 deletion src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -32,6 +32,36 @@ 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<sys::lldb_addr_t, SBError> {
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 {
Expand Down
6 changes: 6 additions & 0 deletions src/filespec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ impl SBFileSpec {
}
}

/// Create SBFileSpec from path
pub fn from_path(path: &str, resolve: bool) -> Self {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense for this to be generic on something like:

pub fn from_path<P: AsRef<Path>>(path: P, resolve: bool) -> Self

?

let path_cstring = std::ffi::CString::new(path).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) }
Expand Down
65 changes: 64 additions & 1 deletion src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -99,6 +100,11 @@ 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) -> ModuleSymbols {
ModuleSymbols { module: self }
}
}

/// Iterate over the [sections] in a [module].
Expand Down Expand Up @@ -133,6 +139,63 @@ impl<'d> Iterator for SBModuleSectionIter<'d> {

impl<'d> ExactSizeIterator for SBModuleSectionIter<'d> {}

/// The list of symbols in the module
pub struct ModuleSymbols<'d> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this just be a SBModuleSymbolsIter like the other iterators?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should have direct indexed accessor and length access so I made it have intermediate struct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious to know why... but not going to block on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I want to get first library (excluding exexutable), I think it should be possible to access 1th element without accessing 0th element, but I came up with implementing nth of iterator is enough so I'll do this instead of intermediate struct.

module: &'d SBModule,
}

impl<'d> ModuleSymbols<'d> {
pub fn len(&self) -> usize {
unsafe { sys::SBModuleGetNumSymbols(self.module.raw) }
}

pub fn get(&self, index: usize) -> Option<SBSymbol> {
if index < self.len() {
let symbol = unsafe { sys::SBModuleGetSymbolAtIndex(self.module.raw, index) };
Some(SBSymbol { raw: symbol })
} else {
None
}
}
}

impl<'a> IntoIterator for ModuleSymbols<'a> {
type Item = SBSymbol;
type IntoIter = ModuleSymbolsIter<'a>;

fn into_iter(self) -> Self::IntoIter {
ModuleSymbolsIter {
module: self,
index: 0,
}
}
}

pub struct ModuleSymbolsIter<'d> {
module: ModuleSymbols<'d>,
index: usize,
}

impl<'d> Iterator for ModuleSymbolsIter<'d> {
type Item = SBSymbol;

fn next(&mut self) -> Option<Self::Item> {
if self.index < self.module.len() {
self.index += 1;
self.module.get(self.index - 1)
} else {
None
}
}

fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.module.len() - self.index;
(len, Some(len))
}
}

impl<'d> ExactSizeIterator for ModuleSymbolsIter<'d> {}

impl Clone for SBModule {
fn clone(&self) -> SBModule {
SBModule {
Expand Down
10 changes: 10 additions & 0 deletions src/modulespec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<SBModuleSpec> {
Expand All @@ -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
Expand Down
83 changes: 81 additions & 2 deletions src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 error the memory region is not allowed to read
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"will return an error if the" (2 missing words)

// 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 to the process
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"into the" and a missing period at the end.

pub fn load_image(&self, file: &SBFileSpec) -> Result<u32, SBError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably make a quick pub struct ImageToken(u32) to hide the image_token rather than just allowing any u32 to be used.

let error = SBError::default();
let image_token = unsafe { sys::SBProcessLoadImage(self.raw, file.raw, error.raw) };
if error.is_failure() {
Err(error)
} else {
Ok(image_token)
}
}

/// Unloads the image loaded with [`load_image`]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing period at the end.

///
/// [`load_image`]: Self::load_image
pub fn unload_image(&self, image_token: u32) -> Result<(), SBError> {
// the method returns error if image_token is not valid, instead of cause undefined behavior
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"instead of causing"

let error = SBError::wrap(unsafe { sys::SBProcessUnloadImage(self.raw, image_token) });
if error.is_failure() {
Err(error)
} else {
Ok(())
}
}

/// Returns the [`SBTarget`] corresponds to this SBProcess.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"corresponding" and missing backticks on SBProcess and None (below)

///
/// This never return None if `self` is [`valid`].
///
/// [`SBTarget`]: SBTarget
/// [`valid`]: Self::is_valid
pub fn target(&self) -> Option<SBTarget> {
SBTarget::maybe_wrap(unsafe { sys::SBProcessGetTarget(self.raw) })
}
}

/// Iterate over the [threads] in a [process].
Expand Down
11 changes: 11 additions & 0 deletions src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down
22 changes: 22 additions & 0 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,28 @@ impl SBValue {
None
}
}

/// Get the value as signed integer
pub fn get_as_signed(&self) -> Result<i64, SBError> {
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<u64, SBError> {
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 {
Expand Down
Loading