libsdb/
process.rs

1use super::bit::to_byte_span;
2
3use super::breakpoint::Breakpoint;
4
5use super::bit::from_bytes;
6use super::breakpoint_site::BreakpointSite;
7use super::breakpoint_site::IdType;
8use super::pipe::Pipe;
9use super::register_info::RegisterId;
10use super::register_info::register_info_by_id;
11use super::registers::Registers;
12use super::sdb_error::SdbError;
13use super::stoppoint_collection::StoppointCollection;
14use super::target::Target;
15use super::traits::StoppointTrait;
16use super::types::StoppointMode;
17use super::types::VirtualAddress;
18use super::utils::ResultLogExt;
19use super::watchpoint::WatchPoint;
20use bytemuck::Pod;
21use bytemuck::bytes_of_mut;
22use byteorder::NativeEndian;
23use byteorder::ReadBytesExt;
24use nix::libc::AT_NULL;
25use nix::libc::PTRACE_EVENT_CLONE;
26use nix::libc::PTRACE_GETFPREGS;
27use nix::libc::ptrace;
28use nix::sys::personality::Persona;
29use nix::sys::personality::set as set_personality;
30use nix::sys::ptrace::AddressType;
31use nix::sys::ptrace::Options;
32use nix::sys::ptrace::cont;
33use nix::sys::ptrace::getsiginfo;
34use nix::sys::ptrace::setoptions;
35use nix::sys::ptrace::step;
36use nix::sys::ptrace::syscall;
37use nix::sys::ptrace::write;
38use nix::sys::signal::Signal;
39use nix::sys::signal::Signal::SIGSTOP;
40use nix::sys::signal::Signal::SIGTRAP;
41use nix::sys::signal::kill;
42use nix::sys::uio::RemoteIoVec;
43use nix::sys::uio::process_vm_readv;
44use nix::unistd::dup2;
45use nix::{
46    errno::Errno,
47    libc::{
48        PTRACE_SETFPREGS, PTRACE_SETREGS, SI_KERNEL, TRAP_HWBKPT, TRAP_TRACE, setpgid,
49        user_fpregs_struct, user_regs_struct,
50    },
51    sys::{
52        ptrace::{attach as nix_attach, detach, getregs, read_user, write_user},
53        wait::{WaitPidFlag, WaitStatus, waitpid},
54    },
55};
56use nix::{
57    sys::ptrace::traceme,
58    unistd::{ForkResult, Pid, execvp, fork},
59};
60use std::any::Any;
61use std::cell::Ref;
62use std::cell::RefMut;
63use std::cmp::min;
64use std::collections::HashMap;
65use std::ffi::c_long;
66use std::fs::File;
67use std::io::IoSliceMut;
68use std::os::fd::AsRawFd;
69use std::rc::Weak;
70use std::{cell::RefCell, ffi::CString, os::raw::c_void, path::Path, process::exit, rc::Rc};
71use typed_builder::TypedBuilder;
72#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
73pub enum ProcessState {
74    #[default]
75    Stopped,
76    Running,
77    Exited,
78    Terminated,
79}
80
81#[derive(Debug, Clone, Copy, TypedBuilder)]
82pub struct StopReason {
83    #[builder(default)]
84    pub reason: ProcessState,
85    #[builder(default)]
86    pub info: i32,
87    #[builder(default)]
88    pub trap_reason: Option<TrapType>,
89    #[builder(default)]
90    pub syscall_info: Option<SyscallInfo>,
91    #[builder(default = Pid::from_raw(0))]
92    pub tid: Pid,
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub enum TrapType {
97    SingleStep,
98    SoftwareBreak,
99    HardwareBreak,
100    Syscall,
101    Clone,
102    Unknown,
103}
104
105impl StopReason {
106    pub fn new(tid: Pid, status: WaitStatus) -> Result<Self, SdbError> {
107        if let WaitStatus::Exited(_, info) = status {
108            return Ok(StopReason {
109                reason: ProcessState::Exited,
110                info,
111                trap_reason: None,
112                syscall_info: None,
113                tid,
114            });
115        } else if let WaitStatus::Signaled(_, info, _) = status {
116            return Ok(StopReason {
117                reason: ProcessState::Terminated,
118                info: info as i32,
119                trap_reason: None,
120                syscall_info: None,
121                tid,
122            });
123        } else if let WaitStatus::Stopped(_, info) = status {
124            return Ok(StopReason {
125                reason: ProcessState::Stopped,
126                info: info as i32,
127                trap_reason: None,
128                syscall_info: None,
129                tid,
130            });
131        } else if let WaitStatus::PtraceEvent(_, info, event) = status {
132            return Ok(StopReason {
133                reason: ProcessState::Stopped,
134                info: info as i32,
135                // Implementation is different
136                trap_reason: if event == PTRACE_EVENT_CLONE {
137                    Some(TrapType::Clone)
138                } else {
139                    None
140                },
141                syscall_info: None,
142                tid,
143            });
144        } else if let WaitStatus::PtraceSyscall(_) = status {
145            return Ok(StopReason {
146                reason: ProcessState::Stopped,
147                info: SIGTRAP as i32,
148                trap_reason: Some(TrapType::Syscall),
149                syscall_info: None,
150                tid,
151            });
152        }
153
154        SdbError::err(&format!("Unhandled wait status {status:?}"))
155    }
156
157    pub fn is_step(&self) -> bool {
158        self.reason == ProcessState::Stopped
159            && self.info == SIGTRAP as i32
160            && self.trap_reason == Some(TrapType::SingleStep)
161    }
162
163    pub fn is_breakpoint(&self) -> bool {
164        self.reason == ProcessState::Stopped
165            && self.info == SIGTRAP as i32
166            && (self.trap_reason == Some(TrapType::SoftwareBreak)
167                || self.trap_reason == Some(TrapType::HardwareBreak))
168    }
169}
170
171fn set_ptrace_options(pid: Pid) -> Result<(), SdbError> {
172    setoptions(
173        pid,
174        Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACECLONE,
175    )
176    .map_err(|errno| {
177        SdbError::new_errno("Failed to set TRACESYSGOOD and TRACECLONE options", errno)
178    })
179}
180
181#[derive(Debug, PartialEq, Eq, Default)]
182pub enum SyscallCatchPolicy {
183    #[default]
184    None,
185    Some(Vec<i32>),
186    All,
187}
188
189#[derive(Debug, Clone, Copy)]
190pub struct SyscallInfo {
191    pub id: u16,
192    pub data: SyscallData,
193}
194
195#[derive(Debug, Clone, Copy)]
196pub enum SyscallData {
197    Args([u64; 6]),
198    Ret(i64),
199}
200
201type HitHandler = Option<Box<dyn Fn(&StopReason)>>;
202
203pub struct Process {
204    pid: Pid,
205    terminate_on_end: bool,       // true
206    state: RefCell<ProcessState>, // Stopped
207    is_attached: bool,            // true
208    registers: Rc<RefCell<Registers>>,
209    breakpoint_sites: Rc<RefCell<StoppointCollection>>,
210    watchpoints: Rc<RefCell<StoppointCollection>>,
211    syscall_catch_policy: RefCell<SyscallCatchPolicy>,
212    expecting_syscall_exit: RefCell<bool>,
213    target: RefCell<Option<Weak<Target>>>,
214    threads: RefCell<HashMap<Pid, Rc<RefCell<ThreadState>>>>,
215    current_thread: RefCell<Pid>,
216    thread_lifecycle_callback: RefCell<HitHandler>,
217}
218
219impl Process {
220    pub fn cleanup_exited_threads(self: &Rc<Self>, main_stop_tid: Pid) -> Option<StopReason> {
221        let mut to_remove = Vec::new();
222        let mut to_report = None;
223        for (tid, thread) in self.threads.borrow().iter() {
224            if *tid != main_stop_tid
225                && (thread.borrow().state == ProcessState::Exited
226                    || thread.borrow().state == ProcessState::Terminated)
227            {
228                self.report_thread_lifecycle_event(&thread.borrow().reason);
229                to_remove.push(*tid);
230                if *tid == self.pid {
231                    to_report = Some(thread.borrow().reason);
232                }
233            }
234        }
235        for tid in to_remove {
236            self.threads.borrow_mut().remove(&tid);
237        }
238        to_report
239    }
240
241    pub fn report_thread_lifecycle_event(self: &Rc<Self>, reason: &StopReason) {
242        if let Some(callback) = self.thread_lifecycle_callback.borrow().as_ref() {
243            callback(reason);
244        }
245        if let Some(target) = self.target.borrow().as_ref() {
246            target
247                .upgrade()
248                .unwrap()
249                .notify_thread_lifecycle_event(reason);
250        }
251    }
252
253    pub fn stop_running_threads(self: &Rc<Self>) -> Result<(), SdbError> {
254        let threads = self.threads.borrow().clone();
255        for (tid, thread) in threads.iter() {
256            if thread.borrow().state == ProcessState::Running {
257                if !thread.borrow().pending_sigstop {
258                    unsafe {
259                        let ret = nix::libc::syscall(
260                            nix::libc::SYS_tgkill,
261                            self.pid.as_raw() as nix::libc::c_long,
262                            tid.as_raw() as nix::libc::c_long,
263                            SIGSTOP as nix::libc::c_long,
264                        );
265                        if ret == -1 {
266                            return SdbError::errno("tgkill failed", Errno::last());
267                        }
268                    }
269                }
270
271                let wait_status =
272                    waitpid(*tid, None).map_err(|e| SdbError::new_errno("Failed to waitpid", e))?;
273                let mut thread_reason = StopReason::new(*tid, wait_status)?;
274
275                if thread_reason.reason == ProcessState::Stopped {
276                    if thread_reason.info != SIGSTOP as i32 {
277                        thread.borrow_mut().pending_sigstop = true;
278                    } else if thread.borrow().pending_sigstop {
279                        thread.borrow_mut().pending_sigstop = false;
280                    }
281                }
282
283                thread_reason = self
284                    .handle_signal(thread_reason, false)?
285                    .unwrap_or(thread_reason);
286
287                let mut temp_mut = self.threads.borrow_mut();
288                let mut temp_mut = temp_mut.get_mut(tid).unwrap().borrow_mut();
289                temp_mut.reason = thread_reason;
290                temp_mut.state = thread_reason.reason;
291            }
292        }
293        Ok(())
294    }
295
296    pub fn step_instruction(
297        self: &Rc<Self>,
298        otid: Option<Pid>, /* None */
299    ) -> Result<StopReason, SdbError> {
300        let tid = otid.unwrap_or(self.current_thread());
301        let mut to_reenable: Option<_> = None;
302        let pc = self.get_pc(Some(tid));
303        let breakpoint_sites = &self.breakpoint_sites.borrow();
304        if breakpoint_sites.enabled_breakpoint_at_address(pc) {
305            let bp = breakpoint_sites.get_by_address(pc).unwrap();
306            bp.borrow_mut().disable()?;
307            to_reenable = Some(bp);
308        }
309        self.swallow_pending_sigstop(tid)?;
310        step(tid, None).map_err(|errno| SdbError::new_errno("Could not single step", errno))?;
311        let reason = self.wait_on_signal(tid)?;
312        if let Some(to_reenable) = to_reenable {
313            to_reenable.borrow_mut().enable()?;
314        }
315        Ok(reason)
316    }
317
318    pub fn wait_on_signal(
319        self: &Rc<Self>,
320        to_await: Pid, /* -1 */
321    ) -> Result<StopReason, SdbError> {
322        let options = WaitPidFlag::__WALL;
323        let wait_status = waitpid(to_await, Some(options));
324
325        let (tid, status) = match wait_status {
326            Err(errno) => return SdbError::errno("waitpid failed", errno),
327            Ok(status) => {
328                let tid = match status {
329                    WaitStatus::Exited(pid, _) => pid,
330                    WaitStatus::Signaled(pid, _, _) => pid,
331                    WaitStatus::Stopped(pid, _) => pid,
332                    WaitStatus::PtraceEvent(pid, _, _) => pid,
333                    WaitStatus::PtraceSyscall(pid) => pid,
334                    WaitStatus::Continued(pid) => pid,
335                    WaitStatus::StillAlive => {
336                        return SdbError::err("Unexpected WaitStatus::StillAlive");
337                    }
338                };
339                (tid, status)
340            }
341        };
342
343        let mut reason = StopReason::new(tid, status)?;
344        let final_reason = self.handle_signal(reason, true)?;
345
346        if final_reason.is_none() {
347            self.resume(Some(tid))?;
348            return self.wait_on_signal(to_await);
349        }
350
351        reason = final_reason.unwrap();
352        // Implementation difference: add empty check
353        if let Some(thread) = self.threads.borrow().get(&tid) {
354            let thread = thread.clone();
355            let mut thread_state = thread.borrow_mut();
356            thread_state.reason = reason;
357            thread_state.state = reason.reason;
358        }
359
360        if reason.reason == ProcessState::Exited || reason.reason == ProcessState::Terminated {
361            self.report_thread_lifecycle_event(&reason);
362            if tid == self.pid {
363                *self.state.borrow_mut() = reason.reason;
364                return Ok(reason);
365            } else {
366                return self.wait_on_signal(Pid::from_raw(-1));
367            }
368        }
369
370        self.stop_running_threads()?;
371        reason = self.cleanup_exited_threads(tid).unwrap_or(reason);
372
373        *self.state.borrow_mut() = reason.reason;
374        self.set_current_thread(tid);
375
376        Ok(reason)
377    }
378
379    pub fn handle_signal(
380        self: &Rc<Self>,
381        mut reason: StopReason,
382        is_main_stop: bool,
383    ) -> Result<Option<StopReason>, SdbError> {
384        let tid = reason.tid;
385
386        if reason.trap_reason == Some(TrapType::Clone) && is_main_stop {
387            return Ok(None);
388        }
389
390        if self.is_attached && reason.reason == ProcessState::Stopped {
391            if !self.threads.borrow().contains_key(&tid) {
392                let thread_state = Rc::new(RefCell::new(
393                    ThreadState::builder()
394                        .tid(tid)
395                        .regs(Rc::new(RefCell::new(Registers::new(
396                            &Rc::downgrade(self),
397                            tid,
398                        ))))
399                        .build(),
400                ));
401                self.threads.borrow_mut().insert(tid, thread_state);
402                self.report_thread_lifecycle_event(&reason);
403                if is_main_stop {
404                    return Ok(None);
405                }
406            }
407
408            let thread = self.threads.borrow().get(&tid).unwrap().clone();
409            if thread.borrow().pending_sigstop && reason.info == SIGSTOP as i32 {
410                thread.borrow_mut().pending_sigstop = false;
411                return Ok(None);
412            }
413
414            self.read_all_registers(tid)?;
415            self.augment_stop_reason(&mut reason)?;
416
417            if reason.info == SIGTRAP as i32 {
418                let instr_begin = VirtualAddress::from(self.get_pc(Some(tid)).addr() - 1);
419
420                if reason.trap_reason == Some(TrapType::SoftwareBreak)
421                    && self.breakpoint_sites.borrow().contains_address(instr_begin)
422                    && self
423                        .breakpoint_sites
424                        .borrow()
425                        .get_by_address(instr_begin)?
426                        .borrow()
427                        .is_enabled()
428                {
429                    self.set_pc(instr_begin, Some(tid))?;
430
431                    let bp = self.breakpoint_sites.borrow().get_by_address(instr_begin)?;
432                    let bp = bp.borrow() as Ref<dyn Any>;
433                    let bp = bp.downcast_ref::<BreakpointSite>().unwrap();
434                    if let Some(parent) = &bp.parent.upgrade() {
435                        let should_restart = parent.borrow().notify_hit()?;
436                        if should_restart && is_main_stop {
437                            return Ok(None);
438                        }
439                    }
440                } else if reason.trap_reason == Some(TrapType::HardwareBreak) {
441                    let id = self.get_current_hardware_stoppoint(Some(tid))?;
442                    if let StoppointId::Watchpoint(watchpoint_id) = id {
443                        if let Ok(wp) = self.watchpoints.borrow().get_by_id(watchpoint_id) {
444                            let mut wp = wp.borrow_mut() as RefMut<dyn Any>;
445                            let wp = wp.downcast_mut::<WatchPoint>().unwrap();
446                            wp.update_data()?;
447                        }
448                    }
449                } else if reason.trap_reason == Some(TrapType::Syscall)
450                    && is_main_stop
451                    && self.should_resume_from_syscall(&reason)
452                {
453                    return Ok(None);
454                }
455            }
456
457            if let Some(target_weak) = self.target.borrow().as_ref() {
458                target_weak.upgrade().unwrap().notify_stop(&reason)?;
459            }
460        }
461
462        Ok(Some(reason))
463    }
464
465    pub fn populate_existing_threads(self: &Rc<Self>) {
466        let path = format!("/proc/{}/task", self.pid);
467        let entries = std::fs::read_dir(path).unwrap();
468        for entry in entries {
469            let entry = entry.unwrap();
470            let path = entry.path();
471            let tid = Pid::from_raw(
472                path.file_name()
473                    .unwrap()
474                    .to_str()
475                    .unwrap()
476                    .parse::<i32>()
477                    .unwrap(),
478            );
479            self.threads.borrow_mut().insert(
480                tid,
481                Rc::new(RefCell::new(
482                    ThreadState::builder()
483                        .tid(tid)
484                        .regs(Rc::new(RefCell::new(Registers::new(
485                            &Rc::downgrade(self),
486                            tid,
487                        ))))
488                        .build(),
489                )),
490            );
491        }
492    }
493
494    pub fn create_breakpoint_site(
495        self: &Rc<Self>,
496        address: VirtualAddress,
497        hardware: bool, // false
498        internal: bool, // false
499    ) -> Result<Weak<RefCell<BreakpointSite>>, SdbError> {
500        if self.breakpoint_sites.borrow().contains_address(address) {
501            return SdbError::err(&format!(
502                "Breakpoint site already created at address {}",
503                address.addr()
504            ));
505        }
506        let bs = Rc::new(RefCell::new(BreakpointSite::new(
507            self, address, hardware, internal,
508        )));
509        self.breakpoint_sites.borrow_mut().push_strong(bs.clone());
510        Ok(Rc::downgrade(&bs))
511    }
512
513    pub fn create_breakpoint_site_from_breakpoint(
514        self: &Rc<Self>,
515        parent: &Rc<RefCell<Breakpoint>>,
516        id: IdType,
517        address: VirtualAddress,
518        hardware: bool,
519        internal: bool,
520    ) -> Result<Weak<RefCell<BreakpointSite>>, SdbError> {
521        if self.breakpoint_sites.borrow().contains_address(address) {
522            return SdbError::err(&format!(
523                "Breakpoint site already created at address {}",
524                address.addr()
525            ));
526        }
527        let bs = Rc::new(RefCell::new(BreakpointSite::from_breakpoint(
528            parent, id, self, address, hardware, internal,
529        )));
530        self.breakpoint_sites.borrow_mut().push_strong(bs.clone());
531        Ok(Rc::downgrade(&bs))
532    }
533
534    pub fn create_watchpoint(
535        self: &Rc<Self>,
536        address: VirtualAddress,
537        mode: StoppointMode,
538        size: usize,
539    ) -> Result<Weak<RefCell<WatchPoint>>, SdbError> {
540        if self.watchpoints.borrow().contains_address(address) {
541            return SdbError::err(&format!(
542                "Watchpoint already created at address {}",
543                address.addr()
544            ));
545        }
546        let wp = Rc::new(RefCell::new(WatchPoint::new(self, address, mode, size)?));
547        self.watchpoints.borrow_mut().push_strong(wp.clone());
548        Ok(Rc::downgrade(&wp))
549    }
550
551    pub fn inferior_call(
552        self: &Rc<Self>,
553        func_addr: VirtualAddress,
554        return_addr: VirtualAddress,
555        regs_to_restore: Registers,
556        otid: Option<Pid>, /* None */
557    ) -> Result<Registers, SdbError> {
558        let tid = otid.unwrap_or(self.current_thread());
559        let regs = self.get_registers(Some(tid));
560
561        regs.borrow_mut()
562            .write_by_id(RegisterId::rip, func_addr.addr(), true)?;
563
564        let mut rsp = regs.borrow().read_by_id_as::<u64>(RegisterId::rsp)?;
565
566        rsp -= 8;
567        self.write_memory(VirtualAddress::new(rsp), to_byte_span(&return_addr.addr()))?;
568        regs.borrow_mut().write_by_id(RegisterId::rsp, rsp, true)?;
569
570        self.resume(Some(tid))?;
571        let reason = self.wait_on_signal(tid)?;
572        if reason.reason != ProcessState::Stopped {
573            return SdbError::err("Function call failed");
574        }
575
576        let new_regs = regs.borrow().clone();
577        *regs.borrow_mut() = regs_to_restore.clone();
578        regs.borrow_mut().flush()?;
579        if let Some(target) = self.target.borrow().as_ref()
580            && let Some(target) = target.upgrade()
581        {
582            target.notify_stop(&reason)?;
583        }
584
585        Ok(new_regs)
586    }
587
588    pub fn read_string(&self, address: VirtualAddress) -> Result<String, SdbError> {
589        let mut ret = String::new();
590        loop {
591            let data = self.read_memory(address, 1024)?;
592            for c in data {
593                if c == 0 {
594                    return Ok(ret);
595                }
596                ret.push(c as char);
597            }
598        }
599    }
600
601    pub fn install_thread_lifecycle_callback<T: Fn(&StopReason) + 'static>(&self, callback: T) {
602        *self.thread_lifecycle_callback.borrow_mut() = Some(Box::new(callback));
603    }
604
605    pub fn resume_all_threads(&self) -> Result<(), SdbError> {
606        let tids = self.threads.borrow().keys().copied().collect::<Vec<_>>();
607        for tid in tids.iter() {
608            self.step_over_breakpoint(*tid)?;
609        }
610        for tid in tids.iter() {
611            self.send_continue(*tid)?;
612        }
613        Ok(())
614    }
615
616    fn send_continue(&self, tid: Pid) -> Result<(), SdbError> {
617        let request: fn(Pid, Option<Signal>) -> Result<(), Errno> =
618            if *self.syscall_catch_policy.borrow() == SyscallCatchPolicy::None {
619                cont::<Option<Signal>>
620            } else {
621                syscall::<Option<Signal>>
622            };
623        if let Err(errno) = request(tid, None) {
624            return SdbError::errno("Could not resume", errno);
625        }
626        self.threads
627            .borrow_mut()
628            .get_mut(&tid)
629            .unwrap()
630            .borrow_mut()
631            .state = ProcessState::Running;
632        *self.state.borrow_mut() = ProcessState::Running;
633        Ok(())
634    }
635
636    fn swallow_pending_sigstop(&self, tid: Pid) -> Result<(), SdbError> {
637        let thread = self.threads.borrow().get(&tid).unwrap().clone();
638        if thread.borrow().pending_sigstop {
639            cont(tid, None).map_err(|errno| SdbError::new_errno("Failed to continue", errno))?;
640            waitpid(tid, None).map_err(|errno| SdbError::new_errno("Waitpid failed", errno))?;
641            thread.borrow_mut().pending_sigstop = false;
642        }
643        Ok(())
644    }
645
646    fn step_over_breakpoint(&self, tid: Pid) -> Result<(), SdbError> {
647        let pc = self.get_pc(Some(tid));
648        if self
649            .breakpoint_sites
650            .borrow()
651            .enabled_breakpoint_at_address(pc)
652        {
653            let bp = self.breakpoint_sites.borrow().get_by_address(pc)?;
654            bp.borrow_mut().disable()?;
655            self.swallow_pending_sigstop(tid)?;
656            step(tid, None).map_err(|errno| SdbError::new_errno("Failed to single step", errno))?;
657            waitpid(tid, None).map_err(|errno| SdbError::new_errno("Waitpid failed", errno))?;
658            bp.borrow_mut().enable()?;
659        }
660        Ok(())
661    }
662
663    pub fn set_current_thread(&self, tid: Pid) {
664        *self.current_thread.borrow_mut() = tid;
665    }
666
667    pub fn current_thread(&self) -> Pid {
668        *self.current_thread.borrow()
669    }
670
671    pub fn thread_states(&self) -> &RefCell<HashMap<Pid, Rc<RefCell<ThreadState>>>> {
672        &self.threads
673    }
674
675    pub fn set_syscall_catch_policy(&self, info: SyscallCatchPolicy) {
676        *self.syscall_catch_policy.borrow_mut() = info;
677    }
678
679    fn new(pid: Pid, terminate_on_end: bool, is_attached: bool) -> Rc<Self> {
680        let ret = Rc::new_cyclic(|weak_self| Self {
681            pid,
682            terminate_on_end,
683            state: RefCell::new(ProcessState::Stopped),
684            is_attached,
685            registers: Rc::new(RefCell::new(Registers::new(weak_self, pid))),
686            breakpoint_sites: Rc::new(RefCell::new(StoppointCollection::default())),
687            watchpoints: Rc::new(RefCell::new(StoppointCollection::default())),
688            syscall_catch_policy: RefCell::new(SyscallCatchPolicy::default()),
689            expecting_syscall_exit: RefCell::new(false),
690            target: RefCell::new(None),
691            threads: RefCell::new(HashMap::new()),
692            current_thread: RefCell::new(pid),
693            thread_lifecycle_callback: RefCell::new(None),
694        });
695        ret.populate_existing_threads();
696        ret
697    }
698
699    pub fn pid(&self) -> Pid {
700        self.pid
701    }
702
703    pub fn resume(&self, otid: Option<Pid> /* None */) -> Result<(), SdbError> {
704        let tid = otid.unwrap_or(self.current_thread());
705        self.step_over_breakpoint(tid)?;
706        self.send_continue(tid)?;
707        Ok(())
708    }
709
710    pub fn state(&self) -> ProcessState {
711        *self.state.borrow()
712    }
713
714    fn exit_with_error(channel: &Pipe, msg: &str, errno: Errno) -> ! {
715        let err_str = errno.desc();
716        channel
717            .write(format!("{msg}: {err_str}").as_bytes())
718            .unwrap();
719        exit(-1)
720    }
721
722    pub fn launch(
723        path: &Path,
724        debug: bool, /*true*/
725        stdout_replacement: Option<i32>,
726    ) -> Result<Rc<Process>, SdbError> {
727        let fork_res;
728        let mut channel = Pipe::new(true)?;
729        let mut pid = Pid::from_raw(0);
730        unsafe {
731            // unsafe in signal handler context
732            fork_res = fork();
733        }
734        let path_str = CString::new(path.to_str().unwrap()).unwrap();
735        if let Ok(ForkResult::Child) = fork_res {
736            unsafe {
737                if setpgid(0, 0) < 0 {
738                    Process::exit_with_error(&channel, "Could not set pgid", Errno::last());
739                }
740            }
741            let res = set_personality(Persona::ADDR_NO_RANDOMIZE);
742            if let Err(errno) = res {
743                Process::exit_with_error(&channel, "Subprocess set peronality failed", errno);
744            }
745            channel.close_read();
746            if let Some(fd) = stdout_replacement
747                && let Err(errno) = dup2(fd, std::io::stdout().as_raw_fd())
748            {
749                Process::exit_with_error(&channel, "Stdout replacement failed", errno);
750            }
751            if debug && let Err(errno) = traceme() {
752                Process::exit_with_error(&channel, "Tracing failed", errno);
753            }
754            if execvp(&path_str, &[&path_str]).is_err() {
755                Process::exit_with_error(&channel, "Exec failed", Errno::from_raw(0));
756            }
757        } else if let Ok(ForkResult::Parent { child }) = fork_res {
758            pid = child;
759            channel.close_write();
760            let data = channel.read();
761            channel.close_read();
762            if let Ok(msg) = data {
763                if !msg.is_empty() {
764                    waitpid(pid, WaitPidFlag::from_bits(0)).map_err(|errno| {
765                        SdbError::new_err(&format!("Waitpid child failed, errno: {errno}"))
766                    })?;
767                    return SdbError::err(std::str::from_utf8(&msg).unwrap());
768                }
769            }
770        } else {
771            return SdbError::err("Fork failed");
772        }
773
774        let proc = Process::new(pid, true, debug);
775        if debug {
776            proc.wait_on_signal(Pid::from_raw(-1))?;
777            set_ptrace_options(pid)?;
778        }
779        return Ok(proc);
780    }
781
782    pub fn attach(pid: Pid) -> Result<Rc<Process>, SdbError> {
783        if pid.as_raw() <= 0 {
784            return SdbError::err("Invalid pid");
785        }
786        if let Err(errno) = nix_attach(pid) {
787            return SdbError::errno("Could not attach", errno);
788        }
789        let proc = Process::new(pid, false, true);
790        proc.wait_on_signal(Pid::from_raw(-1))?;
791        set_ptrace_options(pid)?;
792        return Ok(proc);
793    }
794
795    pub fn write_user_area(
796        &self,
797        offset: usize,
798        data: u64,
799        otid: Option<Pid>, /* None */
800    ) -> Result<(), SdbError> {
801        let tid = otid.unwrap_or(self.current_thread());
802        match write_user(tid, offset as AddressType, data.try_into().unwrap()) {
803            Ok(_) => Ok(()),
804            Err(errno) => SdbError::errno("Could not write user area", errno),
805        }
806    }
807
808    pub fn get_registers(&self, otid: Option<Pid> /* None */) -> Rc<RefCell<Registers>> {
809        let tid = otid.unwrap_or(self.current_thread());
810        self.threads
811            .borrow()
812            .get(&tid)
813            .unwrap()
814            .borrow()
815            .regs
816            .clone()
817    }
818
819    pub fn read_all_registers(&self, tid: Pid) -> Result<(), SdbError> {
820        let regs = getregs(tid);
821        match regs {
822            Ok(data) => {
823                self.get_registers(Some(tid)).borrow_mut().data.0.regs = data;
824                Ok(())
825            }
826            Err(errno) => SdbError::errno("Could not read GPR registers", errno),
827        }?;
828
829        unsafe {
830            if ptrace(
831                PTRACE_GETFPREGS,
832                tid,
833                std::ptr::null_mut::<c_void>(),
834                &mut self.get_registers(Some(tid)).borrow_mut().data.0.i387 as *mut _
835                    as *mut c_void,
836            ) < 0
837            {
838                return SdbError::errno("Could not read FPR registers", Errno::last());
839            }
840        }
841        for i in 0..8 {
842            let id = RegisterId::dr0 as i32 + i;
843            let info = register_info_by_id(RegisterId::try_from(id).unwrap())?;
844
845            match read_user(tid, info.offset as *mut c_void) {
846                Ok(data) => {
847                    self.get_registers(Some(tid)).borrow_mut().data.0.u_debugreg[i as usize] =
848                        data as u64;
849                }
850                Err(errno) => SdbError::errno("Could not read debug register", errno)?,
851            };
852        }
853
854        Ok(())
855    }
856
857    pub fn write_gprs(
858        &self,
859        gprs: &mut user_regs_struct,
860        otid: Option<Pid>, /* None */
861    ) -> Result<(), SdbError> {
862        let tid = otid.unwrap_or(self.current_thread());
863        unsafe {
864            if ptrace(
865                PTRACE_SETREGS,
866                tid,
867                std::ptr::null_mut::<c_void>(),
868                gprs as *mut _ as *mut c_void,
869            ) < 0
870            {
871                return SdbError::errno("Could not write GPR registers", Errno::last());
872            }
873            Ok(())
874        }
875    }
876
877    pub fn write_fprs(
878        &self,
879        fprs: &mut user_fpregs_struct,
880        otid: Option<Pid>, /* None */
881    ) -> Result<(), SdbError> {
882        let tid = otid.unwrap_or(self.current_thread());
883        unsafe {
884            if ptrace(
885                PTRACE_SETFPREGS,
886                tid,
887                std::ptr::null_mut::<c_void>(),
888                fprs as *mut _ as *mut c_void,
889            ) < 0
890            {
891                return SdbError::errno("Could not write FPR registers", Errno::last());
892            }
893            Ok(())
894        }
895    }
896
897    pub fn get_pc(&self, otid: Option<Pid> /* None */) -> VirtualAddress {
898        self.get_registers(otid)
899            .borrow()
900            .read_by_id_as::<u64>(RegisterId::rip)
901            .unwrap()
902            .into()
903    }
904
905    pub fn breakpoint_sites(&self) -> Rc<RefCell<StoppointCollection>> {
906        self.breakpoint_sites.clone()
907    }
908
909    pub fn set_pc(
910        &self,
911        address: VirtualAddress,
912        otid: Option<Pid>, /* None */
913    ) -> Result<(), SdbError> {
914        self.get_registers(otid)
915            .borrow_mut()
916            .write_by_id(RegisterId::rip, address.addr(), true)?;
917        Ok(())
918    }
919
920    pub fn read_memory(
921        &self,
922        mut address: VirtualAddress,
923        mut amount: usize,
924    ) -> Result<Vec<u8>, SdbError> {
925        let mut ret = vec![0u8; amount];
926        let local_desc = IoSliceMut::new(&mut ret);
927        let mut remote_descs = Vec::<RemoteIoVec>::new();
928        while amount > 0 {
929            let up_to_next_stage = 0x1000 - (address.addr() & 0xfff) as usize;
930            let chunk_size = min(amount, up_to_next_stage);
931            remote_descs.push(RemoteIoVec {
932                base: address.addr() as usize,
933                len: chunk_size,
934            });
935            amount -= chunk_size;
936            address += chunk_size as i64;
937        }
938        process_vm_readv(self.pid, &mut [local_desc], &remote_descs)
939            .map_err(|errno| SdbError::new_errno("Could not read process memory", errno))?;
940        Ok(ret)
941    }
942
943    pub fn write_memory(&self, address: VirtualAddress, data: &[u8]) -> Result<(), SdbError> {
944        let mut written = 0usize;
945        while written < data.len() {
946            let remaing = data.len() - written;
947            let mut word = 0u64;
948            if remaing >= 8 {
949                word = from_bytes(&data[written..]);
950            } else {
951                let read = self.read_memory(address + written as i64, 8)?;
952                let word_data = bytes_of_mut(&mut word);
953                word_data[..remaing].copy_from_slice(&data[written..written + remaing]);
954                word_data[remaing..].copy_from_slice(&read[remaing..8]);
955            }
956            write(
957                self.pid,
958                (address + written as i64).addr() as AddressType,
959                word as c_long,
960            )
961            .map_err(|errno| SdbError::new_errno("Failed to write memory", errno))?;
962            written += 8;
963        }
964        Ok(())
965    }
966
967    pub fn read_memory_as<T: Pod>(&self, address: VirtualAddress) -> Result<T, SdbError> {
968        let data = self.read_memory(address, size_of::<T>())?;
969        Ok(from_bytes(&data))
970    }
971
972    pub fn read_memory_without_trap(
973        &self,
974        address: VirtualAddress,
975        amount: usize,
976    ) -> Result<Vec<u8>, SdbError> {
977        let mut memory = self.read_memory(address, amount)?;
978        let sites = self
979            .breakpoint_sites
980            .borrow()
981            .get_in_region(address, address + amount as i64);
982        for site in sites.iter() {
983            let site = site.borrow() as Ref<dyn Any>;
984            let site = site.downcast_ref::<BreakpointSite>().unwrap();
985            if !site.is_enabled() || site.is_hardware() {
986                continue;
987            }
988            let offset = site.address() - address.addr() as i64;
989            memory[offset.addr() as usize] = site.saved_data();
990        }
991        Ok(memory)
992    }
993
994    pub fn set_hardware_breakpoint(
995        &self,
996        _id: i32,
997        address: VirtualAddress,
998    ) -> Result<i32, SdbError> {
999        self._set_hardware_breakpoint(address, StoppointMode::Execute, 1)
1000    }
1001
1002    fn _set_hardware_breakpoint(
1003        &self,
1004        address: VirtualAddress,
1005        mode: StoppointMode,
1006        size: usize,
1007    ) -> Result<i32, SdbError> {
1008        let owned_regs = self.get_registers(None);
1009        let mut regs = owned_regs.borrow_mut();
1010        let control: u64 = regs.read_by_id_as(RegisterId::dr7)?;
1011
1012        let free_space = Process::find_free_stoppoint_register(control)?;
1013        let id = RegisterId::dr0 as i32 + free_space as i32;
1014        regs.write_by_id(RegisterId::try_from(id).unwrap(), address.addr(), true)?;
1015
1016        let mode_flag = Process::encode_hardware_stoppoint_mode(mode);
1017        let size_flag = Process::encode_hardware_stoppoint_size(size)?;
1018
1019        let enable_bit = 1 << (free_space * 2);
1020        let mode_bits = mode_flag << (free_space * 4 + 16);
1021        let size_bits = size_flag << (free_space * 4 + 18);
1022        let clear_mask = (0b11 << (free_space * 2)) | (0b1111 << (free_space * 4 + 16));
1023        let mut masked = control & !clear_mask;
1024        masked |= enable_bit | mode_bits | size_bits;
1025        regs.write_by_id(RegisterId::dr7, masked, true)?;
1026        for (tid, _) in self.threads.borrow().iter() {
1027            if *tid == *self.current_thread.borrow() {
1028                continue;
1029            }
1030            let other_regs = self.get_registers(Some(*tid));
1031            let mut other_regs = other_regs.borrow_mut();
1032            other_regs.write_by_id(RegisterId::try_from(id).unwrap(), address.addr(), true)?;
1033            other_regs.write_by_id(RegisterId::dr7, masked, true)?;
1034        }
1035        return Ok(free_space as i32);
1036    }
1037
1038    pub fn clear_hardware_stoppoint(&self, index: i32) -> Result<(), SdbError> {
1039        let id = RegisterId::try_from(RegisterId::dr0 as i32 + index).unwrap();
1040        let owned_registers = self.get_registers(None);
1041        {
1042            let mut regs = owned_registers.borrow_mut();
1043            regs.write_by_id(id, 0, true)?;
1044        }
1045        let masked: u64;
1046        {
1047            let regs = owned_registers.borrow();
1048            let control: u64 = regs.read_by_id_as(RegisterId::dr7)?;
1049            let clear_mask = (0b11 << (index * 2)) | (0b1111 << (index * 4 + 16));
1050            masked = control & !clear_mask;
1051        }
1052        let mut regs = owned_registers.borrow_mut();
1053        regs.write_by_id(RegisterId::dr7, masked, true)?;
1054
1055        for (tid, _) in self.threads.borrow().iter() {
1056            if *tid == *self.current_thread.borrow() {
1057                continue;
1058            }
1059            let other_regs = self.get_registers(Some(*tid));
1060            let mut other_regs = other_regs.borrow_mut();
1061            other_regs.write_by_id(id, 0, true)?;
1062            other_regs.write_by_id(RegisterId::dr7, masked, true)?;
1063        }
1064        Ok(())
1065    }
1066
1067    fn find_free_stoppoint_register(control_register: u64) -> Result<u64, SdbError> {
1068        for i in 0..4 {
1069            if (control_register & (0b11 << (i * 2))) == 0 {
1070                return Ok(i);
1071            }
1072        }
1073        return SdbError::err("No remaining hardware debug registers");
1074    }
1075
1076    fn encode_hardware_stoppoint_mode(mode: StoppointMode) -> u64 {
1077        match mode {
1078            StoppointMode::Write => 0b01,
1079            StoppointMode::ReadWrite => 0b11,
1080            StoppointMode::Execute => 0b00,
1081        }
1082    }
1083
1084    fn encode_hardware_stoppoint_size(size: usize) -> Result<u64, SdbError> {
1085        match size {
1086            1 => Ok(0b00),
1087            2 => Ok(0b01),
1088            4 => Ok(0b11),
1089            8 => Ok(0b10),
1090            _ => SdbError::err("Invalid stoppoint size"),
1091        }
1092    }
1093
1094    pub fn set_watchpoint(
1095        &self,
1096        _id: IdType,
1097        address: VirtualAddress,
1098        mode: StoppointMode,
1099        size: usize,
1100    ) -> Result<i32, SdbError> {
1101        return self._set_hardware_breakpoint(address, mode, size);
1102    }
1103
1104    pub fn watchpoints(&self) -> Rc<RefCell<StoppointCollection>> {
1105        self.watchpoints.clone()
1106    }
1107
1108    fn augment_stop_reason(&self, reason: &mut StopReason) -> Result<(), SdbError> {
1109        let tid = reason.tid;
1110        let info = getsiginfo(tid)
1111            .map_err(|errno| SdbError::new_errno("Failed to get signal info", errno))?;
1112
1113        // Implementation is different
1114        if reason.trap_reason == Some(TrapType::Syscall) {
1115            let regs = self.get_registers(Some(tid));
1116            let regs = regs.borrow();
1117            let expecting_syscall_exit = *self.expecting_syscall_exit.borrow();
1118            if expecting_syscall_exit {
1119                reason.syscall_info = Some(SyscallInfo {
1120                    id: regs.read_by_id_as::<u64>(RegisterId::orig_rax)? as u16,
1121                    data: SyscallData::Ret(regs.read_by_id_as::<u64>(RegisterId::rax)? as i64),
1122                });
1123                *self.expecting_syscall_exit.borrow_mut() = false;
1124            } else {
1125                let register_ids = [
1126                    RegisterId::rdi,
1127                    RegisterId::rsi,
1128                    RegisterId::rdx,
1129                    RegisterId::r10,
1130                    RegisterId::r8,
1131                    RegisterId::r9,
1132                ];
1133                let mut data = [0u64; 6];
1134                for (idx, id) in register_ids.iter().enumerate() {
1135                    data[idx] = regs.read_by_id_as::<u64>(*id)?;
1136                }
1137                reason.syscall_info = Some(SyscallInfo {
1138                    id: regs.read_by_id_as::<u64>(RegisterId::orig_rax)? as u16,
1139                    data: SyscallData::Args(data),
1140                });
1141
1142                *self.expecting_syscall_exit.borrow_mut() = true;
1143            }
1144
1145            reason.info = SIGTRAP as i32;
1146            return Ok(());
1147        }
1148
1149        *self.expecting_syscall_exit.borrow_mut() = false;
1150        reason.trap_reason = Some(TrapType::Unknown);
1151        if reason.info == SIGTRAP as i32 {
1152            match info.si_code {
1153                TRAP_TRACE => reason.trap_reason = Some(TrapType::SingleStep),
1154                SI_KERNEL => reason.trap_reason = Some(TrapType::SoftwareBreak),
1155                TRAP_HWBKPT => reason.trap_reason = Some(TrapType::HardwareBreak),
1156                _ => {}
1157            }
1158        }
1159        Ok(())
1160    }
1161
1162    fn should_resume_from_syscall(&self, reason: &StopReason) -> bool {
1163        if let SyscallCatchPolicy::Some(to_catch) = &*self.syscall_catch_policy.borrow() {
1164            if !to_catch.iter().any(|id| {
1165                if let Some(info) = reason.syscall_info {
1166                    return *id == info.id as i32;
1167                }
1168                return false;
1169            }) {
1170                return true;
1171            }
1172        }
1173        false
1174    }
1175
1176    pub fn get_current_hardware_stoppoint(
1177        &self,
1178        otid: Option<Pid>, /* None */
1179    ) -> Result<StoppointId, SdbError> {
1180        let regs = self.get_registers(otid);
1181        let regs = regs.borrow();
1182        let status: u64 = regs.read_by_id_as(RegisterId::dr6)?;
1183        let index = status.trailing_zeros();
1184
1185        let id = RegisterId::try_from(RegisterId::dr0 as i32 + index as i32).unwrap();
1186        let addr = VirtualAddress::from(regs.read_by_id_as::<u64>(id)?);
1187        let breapoint_sites = self.breakpoint_sites.borrow();
1188        if breapoint_sites.contains_address(addr) {
1189            let site_id = breapoint_sites.get_by_address(addr)?.borrow().id();
1190            Ok(StoppointId::BreakpointSite(site_id))
1191        } else {
1192            let watch_id = self
1193                .watchpoints
1194                .borrow()
1195                .get_by_address(addr)?
1196                .borrow()
1197                .id();
1198            Ok(StoppointId::Watchpoint(watch_id))
1199        }
1200    }
1201
1202    pub fn get_auxv(&self) -> HashMap<i32, u64> {
1203        let path = format!("/proc/{}/auxv", self.pid);
1204        let mut file = File::open(path).unwrap();
1205        let mut auxv = HashMap::new();
1206        loop {
1207            let id = file.read_u64::<NativeEndian>().unwrap();
1208            if id == AT_NULL {
1209                break;
1210            }
1211            let value = file.read_u64::<NativeEndian>().unwrap();
1212            auxv.insert(id as i32, value);
1213        }
1214        auxv
1215    }
1216
1217    pub fn set_target(&self, target: &Rc<Target>) {
1218        *self.target.borrow_mut() = Some(Rc::downgrade(target));
1219    }
1220}
1221
1222pub enum StoppointId {
1223    BreakpointSite(IdType),
1224    Watchpoint(IdType),
1225}
1226
1227impl Drop for Process {
1228    fn drop(&mut self) {
1229        if self.pid.as_raw() != 0 {
1230            if self.is_attached {
1231                if *self.state.borrow() == ProcessState::Running {
1232                    kill(self.pid, Signal::SIGSTOP).log_error();
1233                    waitpid(self.pid, WaitPidFlag::from_bits(0)).log_error();
1234                }
1235                detach(self.pid, None).log_error();
1236                kill(self.pid, Signal::SIGCONT).log_error();
1237            }
1238            if self.terminate_on_end {
1239                kill(self.pid, Signal::SIGKILL).log_error();
1240                waitpid(self.pid, WaitPidFlag::from_bits(0)).log_error();
1241            }
1242        }
1243    }
1244}
1245
1246#[derive(TypedBuilder)]
1247pub struct ThreadState {
1248    tid: Pid,
1249    regs: Rc<RefCell<Registers>>,
1250    #[builder(default = StopReason::builder().build())]
1251    pub reason: StopReason,
1252    #[builder(default = ProcessState::Stopped)]
1253    state: ProcessState,
1254    #[builder(default = false)]
1255    pending_sigstop: bool,
1256}
1257
1258#[cfg(test)]
1259mod tests {
1260    use nix::sys::signal::kill;
1261    use nix::unistd::Pid;
1262    use serial_test::serial;
1263    use std::path::Path;
1264
1265    fn process_exists(pid: Pid) -> bool {
1266        return kill(pid, None).is_ok();
1267    }
1268
1269    #[test]
1270    #[serial]
1271    fn process_launch_success() {
1272        let proc = super::Process::launch(Path::new("yes"), true, None);
1273        assert!(process_exists(proc.unwrap().pid()));
1274    }
1275
1276    #[test]
1277    #[serial]
1278    fn process_launch_no_such_program() {
1279        let proc = super::Process::launch(Path::new("you_do_not_have_to_be_good"), true, None);
1280        assert!(proc.is_err());
1281    }
1282}