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 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, state: RefCell<ProcessState>, is_attached: bool, 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>, ) -> 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, ) -> 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 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, internal: bool, ) -> 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>, ) -> 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> ) -> 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, 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 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>, ) -> 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> ) -> 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>, ) -> 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>, ) -> 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> ) -> 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>, ) -> 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 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>, ) -> 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}