use crate::{
lldb_addr_t, lldb_pid_t, lldb_tid_t, sys, Permissions, SBBroadcaster, SBError, SBEvent,
SBProcessInfo, SBQueue, SBStream, SBStructuredData, SBThread, StateType,
};
use libc::size_t;
use std::ffi::{CStr, CString};
use std::fmt;
pub struct SBProcess {
pub raw: sys::SBProcessRef,
}
impl SBProcess {
pub(crate) fn wrap(raw: sys::SBProcessRef) -> SBProcess {
SBProcess { raw }
}
#[allow(dead_code)]
pub(crate) fn maybe_wrap(raw: sys::SBProcessRef) -> Option<SBProcess> {
if unsafe { sys::SBProcessIsValid(raw) } {
Some(SBProcess { raw })
} else {
None
}
}
pub fn is_valid(&self) -> bool {
unsafe { sys::SBProcessIsValid(self.raw) }
}
#[allow(missing_docs)]
pub fn broadcaster_class_name() -> &'static str {
unsafe {
match CStr::from_ptr(sys::SBProcessGetBroadcasterClassName()).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
pub fn state(&self) -> StateType {
unsafe { sys::SBProcessGetState(self.raw) }
}
pub fn is_alive(&self) -> bool {
matches!(
self.state(),
StateType::Attaching
| StateType::Launching
| StateType::Stopped
| StateType::Running
| StateType::Stepping
| StateType::Crashed
| StateType::Suspended
)
}
pub fn is_running(&self) -> bool {
matches!(self.state(), StateType::Running | StateType::Stepping)
}
pub fn is_stopped(&self) -> bool {
matches!(
self.state(),
StateType::Stopped | StateType::Crashed | StateType::Suspended
)
}
pub fn exit_status(&self) -> i32 {
unsafe { sys::SBProcessGetExitStatus(self.raw) }
}
pub fn exit_description(&self) -> &str {
unsafe {
match CStr::from_ptr(sys::SBProcessGetExitDescription(self.raw)).to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
}
}
pub fn process_id(&self) -> lldb_pid_t {
unsafe { sys::SBProcessGetProcessID(self.raw) }
}
pub fn unique_id(&self) -> u32 {
unsafe { sys::SBProcessGetUniqueID(self.raw) }
}
pub fn address_byte_size(&self) -> u32 {
unsafe { sys::SBProcessGetAddressByteSize(self.raw) }
}
pub fn destroy(&self) -> Result<(), SBError> {
let error = SBError::wrap(unsafe { sys::SBProcessDestroy(self.raw) });
if error.is_success() {
Ok(())
} else {
Err(error)
}
}
#[allow(missing_docs)]
pub fn continue_execution(&self) -> Result<(), SBError> {
let error = SBError::wrap(unsafe { sys::SBProcessContinue(self.raw) });
if error.is_success() {
Ok(())
} else {
Err(error)
}
}
#[allow(missing_docs)]
pub fn stop(&self) -> Result<(), SBError> {
let error = SBError::wrap(unsafe { sys::SBProcessStop(self.raw) });
if error.is_success() {
Ok(())
} else {
Err(error)
}
}
pub fn kill(&self) -> Result<(), SBError> {
let error = SBError::wrap(unsafe { sys::SBProcessKill(self.raw) });
if error.is_success() {
Ok(())
} else {
Err(error)
}
}
#[allow(missing_docs)]
pub fn detach(&self) -> Result<(), SBError> {
let error = SBError::wrap(unsafe { sys::SBProcessDetach(self.raw) });
if error.is_success() {
Ok(())
} else {
Err(error)
}
}
pub fn signal(&self, signal: i32) -> Result<(), SBError> {
let error = SBError::wrap(unsafe { sys::SBProcessSignal(self.raw, signal) });
if error.is_success() {
Ok(())
} else {
Err(error)
}
}
#[allow(missing_docs)]
pub fn broadcaster(&self) -> SBBroadcaster {
SBBroadcaster::wrap(unsafe { sys::SBProcessGetBroadcaster(self.raw) })
}
pub fn get_extended_crash_information(&self) -> SBStructuredData {
SBStructuredData::wrap(unsafe { sys::SBProcessGetExtendedCrashInformation(self.raw) })
}
#[allow(missing_docs)]
pub fn get_num_supported_hardware_watchpoints(&self) -> Result<u32, SBError> {
let error = SBError::default();
let num = unsafe { sys::SBProcessGetNumSupportedHardwareWatchpoints(self.raw, error.raw) };
if error.is_success() {
Ok(num)
} else {
Err(error)
}
}
pub fn threads(&self) -> SBProcessThreadIter {
SBProcessThreadIter {
process: self,
idx: 0,
}
}
pub fn queues(&self) -> SBProcessQueueIter {
SBProcessQueueIter {
process: self,
idx: 0,
}
}
pub fn thread_by_id(&self, thread_id: lldb_tid_t) -> Option<SBThread> {
SBThread::maybe_wrap(unsafe { sys::SBProcessGetThreadByID(self.raw, thread_id) })
}
pub fn thread_by_index_id(&self, thread_index_id: u32) -> Option<SBThread> {
SBThread::maybe_wrap(unsafe { sys::SBProcessGetThreadByIndexID(self.raw, thread_index_id) })
}
pub fn selected_thread(&self) -> SBThread {
SBThread::wrap(unsafe { sys::SBProcessGetSelectedThread(self.raw) })
}
pub fn set_selected_thread(&self, thread: &SBThread) -> bool {
unsafe { sys::SBProcessSetSelectedThread(self.raw, thread.raw) }
}
pub fn set_selected_thread_by_id(&self, thread_id: lldb_tid_t) -> bool {
unsafe { sys::SBProcessSetSelectedThreadByID(self.raw, thread_id) }
}
pub fn set_selected_thread_by_index_id(&self, thread_index_id: u32) -> bool {
unsafe { sys::SBProcessSetSelectedThreadByIndexID(self.raw, thread_index_id) }
}
#[allow(missing_docs)]
pub fn event_as_process_event(event: &SBEvent) -> Option<SBProcessEvent> {
if unsafe { sys::SBProcessEventIsProcessEvent(event.raw) } {
Some(SBProcessEvent::new(event))
} else {
None
}
}
pub fn save_core(&self, file_name: &str) -> Result<(), SBError> {
let f = CString::new(file_name).unwrap();
let error = SBError::wrap(unsafe { sys::SBProcessSaveCore(self.raw, f.as_ptr()) });
if error.is_success() {
Ok(())
} else {
Err(error)
}
}
#[allow(missing_docs)]
pub fn process_info(&self) -> SBProcessInfo {
SBProcessInfo::wrap(unsafe { sys::SBProcessGetProcessInfo(self.raw) })
}
pub fn allocate_memory(
&self,
size: size_t,
permissions: Permissions,
) -> Result<lldb_addr_t, SBError> {
let error = SBError::default();
let addr =
unsafe { sys::SBProcessAllocateMemory(self.raw, size, permissions.bits(), error.raw) };
if error.is_success() {
Ok(addr)
} else {
Err(error)
}
}
pub unsafe fn deallocate_memory(&self, ptr: lldb_addr_t) -> Result<(), SBError> {
let error = SBError::wrap(sys::SBProcessDeallocateMemory(self.raw, ptr));
if error.is_success() {
Ok(())
} else {
Err(error)
}
}
}
pub struct SBProcessThreadIter<'d> {
process: &'d SBProcess,
idx: usize,
}
impl<'d> Iterator for SBProcessThreadIter<'d> {
type Item = SBThread;
fn next(&mut self) -> Option<SBThread> {
if self.idx < unsafe { sys::SBProcessGetNumThreads(self.process.raw) as usize } {
let r = Some(SBThread::wrap(unsafe {
sys::SBProcessGetThreadAtIndex(self.process.raw, self.idx)
}));
self.idx += 1;
r
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let sz = unsafe { sys::SBProcessGetNumThreads(self.process.raw) } as usize;
(sz - self.idx, Some(sz))
}
}
pub struct SBProcessQueueIter<'d> {
process: &'d SBProcess,
idx: usize,
}
impl<'d> Iterator for SBProcessQueueIter<'d> {
type Item = SBQueue;
fn next(&mut self) -> Option<SBQueue> {
if self.idx < unsafe { sys::SBProcessGetNumQueues(self.process.raw) as usize } {
let r = Some(SBQueue::wrap(unsafe {
sys::SBProcessGetQueueAtIndex(self.process.raw, self.idx)
}));
self.idx += 1;
r
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let sz = unsafe { sys::SBProcessGetNumQueues(self.process.raw) } as usize;
(sz - self.idx, Some(sz))
}
}
impl Clone for SBProcess {
fn clone(&self) -> SBProcess {
SBProcess {
raw: unsafe { sys::CloneSBProcess(self.raw) },
}
}
}
impl fmt::Debug for SBProcess {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let stream = SBStream::new();
unsafe { sys::SBProcessGetDescription(self.raw, stream.raw) };
write!(fmt, "SBProcess {{ {} }}", stream.data())
}
}
impl Drop for SBProcess {
fn drop(&mut self) {
unsafe { sys::DisposeSBProcess(self.raw) };
}
}
unsafe impl Send for SBProcess {}
unsafe impl Sync for SBProcess {}
#[allow(missing_docs)]
pub struct SBProcessEvent<'e> {
event: &'e SBEvent,
}
#[allow(missing_docs)]
impl<'e> SBProcessEvent<'e> {
pub fn new(event: &'e SBEvent) -> Self {
SBProcessEvent { event }
}
pub fn process_state(&self) -> StateType {
unsafe { sys::SBProcessGetStateFromEvent(self.event.raw) }
}
pub fn process(&self) -> SBProcess {
SBProcess::wrap(unsafe { sys::SBProcessGetProcessFromEvent(self.event.raw) })
}
pub fn interrupted(&self) -> bool {
unsafe { sys::SBProcessGetInterruptedFromEvent(self.event.raw) }
}
pub fn restarted(&self) -> bool {
unsafe { sys::SBProcessGetRestartedFromEvent(self.event.raw) }
}
pub fn restarted_reasons(&self) -> SBProcessEventRestartedReasonIter {
SBProcessEventRestartedReasonIter {
event: self,
idx: 0,
}
}
}
pub struct SBProcessEventRestartedReasonIter<'d> {
event: &'d SBProcessEvent<'d>,
idx: usize,
}
impl<'d> Iterator for SBProcessEventRestartedReasonIter<'d> {
type Item = &'d str;
fn next(&mut self) -> Option<&'d str> {
let raw = self.event.event.raw;
if self.idx < unsafe { sys::SBProcessGetNumRestartedReasonsFromEvent(raw) } {
let r = unsafe {
let s = CStr::from_ptr(sys::SBProcessGetRestartedReasonAtIndexFromEvent(
raw, self.idx,
));
match s.to_str() {
Ok(s) => s,
_ => panic!("Invalid string?"),
}
};
self.idx += 1;
Some(r)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let sz = unsafe { sys::SBProcessGetNumRestartedReasonsFromEvent(self.event.event.raw) };
(sz - self.idx, Some(sz))
}
}
impl<'d> ExactSizeIterator for SBProcessEventRestartedReasonIter<'d> {}
#[cfg(feature = "graphql")]
#[graphql_object]
impl SBProcess {
fn is_alive() -> bool {
self.is_alive()
}
fn is_running() -> bool {
self.is_running()
}
fn is_stopped() -> bool {
self.is_stopped()
}
fn exit_status() -> i32 {
self.exit_status()
}
fn exit_description() -> &str {
self.exit_description()
}
fn process_id() -> i32 {
self.process_id() as i32
}
fn unique_id() -> i32 {
self.unique_id() as i32
}
fn address_byte_size() -> i32 {
self.address_byte_size() as i32
}
fn threads() -> Vec<SBThread> {
self.threads().collect()
}
fn queues() -> Vec<SBQueue> {
self.queues().collect()
}
fn selected_thread() -> SBThread {
self.selected_thread()
}
fn process_info() -> SBProcessInfo {
self.process_info()
}
}