use super::super::remote; use crate::wrapper::Stat; use crate::{Error, ProcessReaderKind, Result}; use core::cell::{Cell, RefCell}; use remote::{transport, wire}; use wire::{Operation, ops}; #[derive(Debug)] pub struct Backend { transport_state: RefCell>, pid: Cell>, max_response_output_len: usize, } #[allow(clippy::large_enum_variant)] #[derive(Debug)] enum TransportState { Ready(T), Poisoned, } impl TransportState { fn expect_ready(&mut self) -> &mut T { match self { TransportState::Ready(transport) => transport, TransportState::Poisoned => panic!("attempted to use poisoned transport"), } } } impl Backend { pub fn new(transport: T) -> Self { let max_response_output_len = transport.max_response_output_len(); Self { transport_state: RefCell::new(TransportState::Ready(transport)), pid: Cell::new(None), max_response_output_len, } } fn empty_request(&self) -> Result where Op: for<'args, 'output> Operation = (), Output<'output> = Out>, Out: 'static, { self.simple_request::(()) } fn simple_request(&self, args: Op::Args<'_>) -> Result where Op: for<'output> Operation = Out>, Out: 'static, { self.mapped_request::(args, Ok) } fn mapped_request(&self, args: Op::Args<'_>, map_fn: F) -> Result where Op: Operation, F: for<'output> FnOnce(Op::Output<'output>) -> Result, { let mut transport_state = self.transport_state.borrow_mut(); let transport = transport_state.expect_ready(); let e = match Op::request(transport, args) { Ok(response) => { let output = response.map_err(Error::Executor)?; return map_fn(output); } Err(e) => e, }; *transport_state = TransportState::Poisoned; Err(Error::Transport(e)) } } impl crate::Backend for Backend { type ProcessReader<'a> = ProcessReader<'a, T> where Self: 'a; type FileReader<'a> = FileReader<'a, T> where Self: 'a; type DirReader<'a> = DirReader<'a, T> where Self: 'a; type MappedModuleMemoryReader<'a> = MappedModuleMemoryReader<'a, T> where Self: 'a; fn pid(&self) -> Result { match self.pid.get() { Some(pid) => Ok(pid), None => { let pid = self.empty_request::()?; self.pid.set(Some(pid)); Ok(pid) } } } fn process_reader<'a>(&'a self) -> Self::ProcessReader<'a> { ProcessReader { backend: self } } fn stop_process(&self) -> Result<()> { self.empty_request::() } fn continue_process(&self) -> Result<()> { self.empty_request::() } fn suspend_thread(&self, tid: libc::pid_t) -> Result<()> { self.simple_request::(tid) } fn resume_thread(&self, tid: libc::pid_t) -> Result<()> { self.simple_request::(tid) } fn map_module_into_memory<'a>( &'a self, path: &core::ffi::CStr, offset: u64, ) -> Result> { self.mapped_request::( wire::MappedModuleMemoryReaderOpenArgs { path: path.into(), offset, }, |handle| { Ok(MappedModuleMemoryReader { backend: self, handle, }) }, ) } fn stat_file(&self, path: &core::ffi::CStr) -> Result { self.simple_request::(path.into()) } fn read_file<'a>(&'a self, path: &core::ffi::CStr) -> Result> { self.mapped_request::(path.into(), |handle| { Ok(FileReader { backend: self, handle, }) }) } fn read_dir<'a>(&'a self, path: &core::ffi::CStr) -> Result> { self.mapped_request::(path.into(), |handle| { Ok(DirReader { backend: self, handle, }) }) } fn read_link(&self, path: &core::ffi::CStr, buf: &mut [u8]) -> Result { self.mapped_request::( wire::ReadLinkArgs { path: path.into(), requested_len: usize::min(buf.len(), self.max_response_output_len), }, |bytes| { buf[0..bytes.len()].copy_from_slice(bytes); Ok(bytes.len()) }, ) } fn get_gen_regs(&self, tid: libc::pid_t) -> Result { self.simple_request::(tid) } fn get_fp_regs(&self, tid: libc::pid_t) -> Result { self.simple_request::(tid) } #[cfg(target_arch = "x86")] fn get_fpx_regs(&self, tid: libc::pid_t) -> Result { self.simple_request::(tid) } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn ptrace_peekuser(&self, addr: usize) -> Result<[u8; crate::PTRACE_DATA_LEN]> { self.simple_request::(addr) } fn force_process_reader_kind(&mut self, kind: ProcessReaderKind) -> Result<()> { self.simple_request::(kind) } #[cfg(feature = "testing")] fn fail_one_syscall_with(&self, errno: core::ffi::c_int) { let _result = self.simple_request::(errno); } } impl Drop for Backend { fn drop(&mut self) { if let Err(e) = self.empty_request::() { report_drop_failed!("failed to drop backend: {e:#?}"); } } } #[derive(Debug)] pub struct ProcessReader<'a, T: transport::Backend> { backend: &'a Backend, } impl<'a, T: transport::Backend> crate::ProcessReader for ProcessReader<'a, T> { fn read_at(&self, address: usize, buf: &mut [u8]) -> Result { self.backend .mapped_request::( wire::ProcessReaderReadAtArgs { address, requested_len: usize::min(buf.len(), self.backend.max_response_output_len), }, |bytes| { buf[0..bytes.len()].copy_from_slice(bytes); Ok(bytes.len()) }, ) } } #[derive(Debug)] pub struct FileReader<'a, T: transport::Backend> { backend: &'a Backend, handle: usize, } impl<'a, T: transport::Backend> crate::FileReader for FileReader<'a, T> { fn read(&mut self, buf: &mut [u8]) -> Result { self.backend.mapped_request::( wire::FileReaderArgs { handle: self.handle, requested_len: usize::min(buf.len(), self.backend.max_response_output_len), }, |bytes| { buf[0..bytes.len()].copy_from_slice(bytes); Ok(bytes.len()) }, ) } } impl<'a, T: transport::Backend> Drop for FileReader<'a, T> { fn drop(&mut self) { if let Err(e) = self .backend .simple_request::(self.handle) { report_drop_failed!("failed to close FileReader: {e:#?}"); } } } #[derive(Debug)] pub struct DirReader<'a, T: transport::Backend> { backend: &'a Backend, handle: usize, } impl<'a, T: transport::Backend> crate::DirReader for DirReader<'a, T> { fn read_next_name(&mut self, buf: &mut [u8]) -> Result { self.backend .mapped_request::(self.handle, |maybe_bytes| { if let Some(bytes) = maybe_bytes { buf[0..bytes.len()].copy_from_slice(bytes); Ok(bytes.len()) } else { Ok(0) } }) } } impl<'a, T: transport::Backend> Drop for DirReader<'a, T> { fn drop(&mut self) { if let Err(e) = self .backend .simple_request::(self.handle) { report_drop_failed!("failed to close DirReader: {e:#?}"); } } } #[derive(Debug)] pub struct MappedModuleMemoryReader<'a, T: transport::Backend> { backend: &'a Backend, handle: usize, } impl<'a, T: transport::Backend> crate::MappedModuleMemoryReader for MappedModuleMemoryReader<'a, T> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { self.backend .mapped_request::( wire::MappedModuleMemoryReaderReadAtArgs { handle: self.handle, offset, requested_len: usize::min(buf.len(), self.backend.max_response_output_len), }, |bytes| { buf[0..bytes.len()].copy_from_slice(bytes); Ok(bytes.len()) }, ) } fn len(&self) -> Result { self.backend .simple_request::(self.handle) } fn is_empty(&self) -> Result { self.len().map(|len| len == 0) } } impl<'a, T: transport::Backend> Drop for MappedModuleMemoryReader<'a, T> { fn drop(&mut self) { if let Err(e) = self .backend .simple_request::(self.handle) { report_drop_failed!("failed to close MappedModuleMemoryReader: {e:#?}"); } } }