1pub mod address;
2pub mod r#async;
3mod breakpoint;
4pub mod call;
5mod code;
6mod debugee;
7mod error;
8pub mod process;
9pub mod register;
10pub mod rust;
11mod step;
12mod utils;
13pub mod variable;
14mod watchpoint;
15
16pub use breakpoint::BreakpointView;
17pub use breakpoint::BreakpointViewOwned;
18pub use breakpoint::CreateTransparentBreakpointRequest;
19use call::CallCache;
20pub use debugee::FrameInfo;
21pub use debugee::FunctionAssembly;
22pub use debugee::FunctionRange;
23pub use debugee::RegionInfo;
24pub use debugee::ThreadSnapshot;
25pub use debugee::dwarf::Symbol;
26pub use debugee::dwarf::r#type::TypeDeclaration;
27pub use debugee::dwarf::unit::FunctionDie;
28pub use debugee::dwarf::unit::PlaceDescriptor;
29pub use debugee::dwarf::unit::PlaceDescriptorOwned;
30pub use debugee::dwarf::unwind;
31pub use debugee::tracee::Tracee;
32pub use error::Error;
33pub use watchpoint::WatchpointView;
34pub use watchpoint::WatchpointViewOwned;
35
36use crate::debugger::Error::Syscall;
37use crate::debugger::address::{Address, GlobalAddress, RelocatedAddress};
38use crate::debugger::breakpoint::{Breakpoint, BreakpointRegistry, BrkptType, UninitBreakpoint};
39use crate::debugger::debugee::dwarf::DwarfUnwinder;
40use crate::debugger::debugee::dwarf::r#type::TypeCache;
41use crate::debugger::debugee::dwarf::unwind::Backtrace;
42use crate::debugger::debugee::tracer::{StopReason, TraceContext};
43use crate::debugger::debugee::{Debugee, ExecutionStatus, Location};
44use crate::debugger::error::Error::{
45 FrameNotFound, Hook, ProcessNotStarted, Ptrace, RegisterNameNotFound, UnwindNoContext,
46};
47use crate::debugger::process::{Child, Installed};
48use crate::debugger::register::debug::BreakCondition;
49use crate::debugger::register::{DwarfRegisterMap, Register, RegisterMap};
50use crate::debugger::step::StepResult;
51use crate::debugger::variable::dqe::{Dqe, Selector};
52use crate::debugger::variable::execute::QueryResult;
53use crate::debugger::variable::value::Value;
54use crate::debugger::watchpoint::WatchpointRegistry;
55use crate::oracle::Oracle;
56use crate::{print_warns, weak_error};
57use indexmap::IndexMap;
58use log::debug;
59use nix::libc::{c_void, uintptr_t};
60use nix::sys;
61use nix::sys::signal;
62use nix::sys::signal::{SIGKILL, Signal};
63use nix::sys::wait::{WaitStatus, waitpid};
64use nix::unistd::Pid;
65use object::Object;
66use regex::Regex;
67use std::cell::RefCell;
68use std::cell::RefMut;
69use std::ffi::c_long;
70use std::path::{Path, PathBuf};
71use std::str::FromStr;
72use std::sync::Arc;
73use std::{fs, mem};
74
75pub trait EventHook {
77 fn on_breakpoint(
86 &self,
87 pc: RelocatedAddress,
88 num: u32,
89 place: Option<PlaceDescriptor>,
90 function: Option<&FunctionDie>,
91 ) -> anyhow::Result<()>;
92
93 #[allow(clippy::too_many_arguments)]
106 fn on_watchpoint(
107 &self,
108 pc: RelocatedAddress,
109 num: u32,
110 place: Option<PlaceDescriptor>,
111 condition: BreakCondition,
112 dqe_string: Option<&str>,
113 old_value: Option<&Value>,
114 new_value: Option<&Value>,
115 end_of_scope: bool,
116 ) -> anyhow::Result<()>;
117
118 fn on_step(
126 &self,
127 pc: RelocatedAddress,
128 place: Option<PlaceDescriptor>,
129 function: Option<&FunctionDie>,
130 ) -> anyhow::Result<()>;
131
132 fn on_async_step(
142 &self,
143 pc: RelocatedAddress,
144 place: Option<PlaceDescriptor>,
145 function: Option<&FunctionDie>,
146 task_id: u64,
147 task_completed: bool,
148 ) -> anyhow::Result<()>;
149
150 fn on_signal(&self, signal: Signal);
156
157 fn on_exit(&self, code: i32);
163
164 fn on_process_install(&self, pid: Pid, object: Option<&object::File>);
170}
171
172pub struct NopHook {}
173
174impl EventHook for NopHook {
175 fn on_breakpoint(
176 &self,
177 _: RelocatedAddress,
178 _: u32,
179 _: Option<PlaceDescriptor>,
180 _: Option<&FunctionDie>,
181 ) -> anyhow::Result<()> {
182 Ok(())
183 }
184
185 fn on_watchpoint(
186 &self,
187 _: RelocatedAddress,
188 _: u32,
189 _: Option<PlaceDescriptor>,
190 _: BreakCondition,
191 _: Option<&str>,
192 _: Option<&Value>,
193 _: Option<&Value>,
194 _: bool,
195 ) -> anyhow::Result<()> {
196 Ok(())
197 }
198
199 fn on_step(
200 &self,
201 _: RelocatedAddress,
202 _: Option<PlaceDescriptor>,
203 _: Option<&FunctionDie>,
204 ) -> anyhow::Result<()> {
205 Ok(())
206 }
207
208 fn on_async_step(
209 &self,
210 _: RelocatedAddress,
211 _: Option<PlaceDescriptor>,
212 _: Option<&FunctionDie>,
213 _: u64,
214 _: bool,
215 ) -> anyhow::Result<()> {
216 Ok(())
217 }
218
219 fn on_signal(&self, _: Signal) {}
220
221 fn on_exit(&self, _: i32) {}
222
223 fn on_process_install(&self, _: Pid, _: Option<&object::File>) {}
224}
225
226#[macro_export]
227macro_rules! disable_when_not_stared {
228 ($this: expr) => {
229 if !$this.debugee.is_in_progress() {
230 return Err($crate::debugger::error::Error::ProcessNotStarted);
231 }
232 };
233}
234
235#[derive(Clone, Debug)]
239pub struct ExplorationContext {
240 focus_location: Location,
241 focus_frame: u32,
242}
243
244impl ExplorationContext {
245 pub fn new_non_running(pid: Pid) -> ExplorationContext {
252 Self {
253 focus_location: Location {
254 pc: 0_u64.into(),
255 global_pc: 0_u64.into(),
256 pid,
257 },
258 focus_frame: 0,
259 }
260 }
261
262 pub fn new(location: Location, frame_num: u32) -> Self {
264 Self {
265 focus_location: location,
266 focus_frame: frame_num,
267 }
268 }
269
270 #[inline(always)]
271 pub fn location(&self) -> Location {
272 self.focus_location
273 }
274
275 #[inline(always)]
276 pub fn frame_num(&self) -> u32 {
277 self.focus_frame
278 }
279
280 #[inline(always)]
281 pub fn pid_on_focus(&self) -> Pid {
282 self.location().pid
283 }
284}
285
286#[derive(Default)]
288pub struct DebuggerBuilder<H: EventHook + 'static = NopHook> {
289 oracles: Vec<Arc<dyn Oracle>>,
290 hooks: Option<H>,
291}
292
293impl<H: EventHook + 'static> DebuggerBuilder<H> {
294 pub fn new() -> Self {
296 Self {
297 oracles: vec![],
298 hooks: None,
299 }
300 }
301
302 pub fn with_oracles(self, oracles: Vec<Arc<dyn Oracle>>) -> Self {
308 Self { oracles, ..self }
309 }
310
311 pub fn with_hooks(self, hooks: H) -> Self {
317 Self {
318 hooks: Some(hooks),
319 ..self
320 }
321 }
322
323 pub fn oracles(&self) -> impl Iterator<Item = &dyn Oracle> {
325 self.oracles.iter().map(|oracle| oracle.as_ref())
326 }
327
328 pub fn build(self, process: Child<Installed>) -> Result<Debugger, Error> {
334 if let Some(hooks) = self.hooks {
335 Debugger::new(process, hooks, self.oracles)
336 } else {
337 Debugger::new(process, NopHook {}, self.oracles)
338 }
339 }
340}
341
342pub struct Debugger {
344 process: Child<Installed>,
346 debugee: Debugee,
348 breakpoints: BreakpointRegistry,
350 watchpoints: WatchpointRegistry,
352 type_cache: RefCell<TypeCache>,
354 hooks: Box<dyn EventHook>,
356 expl_context: ExplorationContext,
358 oracles: IndexMap<&'static str, (Arc<dyn Oracle>, bool)>,
360 call_cache: RefCell<CallCache>,
362}
363
364impl Debugger {
365 fn new(
366 process: Child<Installed>,
367 hooks: impl EventHook + 'static,
368 oracles: impl IntoIterator<Item = Arc<dyn Oracle>>,
369 ) -> Result<Self, Error> {
370 let program_path = Path::new(process.program());
371
372 let file = fs::File::open(program_path)?;
373 let mmap = unsafe { memmap2::Mmap::map(&file)? };
374 let object = object::File::parse(&*mmap)?;
375
376 let entry_point = GlobalAddress::from(object.entry());
377 let mut breakpoints = BreakpointRegistry::default();
378 breakpoints.add_uninit(UninitBreakpoint::new_entry_point(
379 None::<PathBuf>,
380 Address::Global(entry_point),
381 process.pid(),
382 ));
383
384 let process_id = process.pid();
385 hooks.on_process_install(process_id, Some(&object));
386
387 let debugee = if process.is_external() {
388 Debugee::new_from_external_process(program_path, &process, &object)?
389 } else {
390 Debugee::new_non_running(program_path, &process, &object)?
391 };
392
393 Ok(Self {
394 debugee,
395 process,
396 breakpoints,
397 watchpoints: WatchpointRegistry::default(),
398 hooks: Box::new(hooks),
399 type_cache: RefCell::default(),
400 call_cache: RefCell::default(),
401 expl_context: ExplorationContext::new_non_running(process_id),
402 oracles: oracles
403 .into_iter()
404 .map(|oracle| (oracle.name(), (oracle, false)))
405 .collect(),
406 })
407 }
408
409 pub fn get_oracle(&self, name: &str) -> Option<&dyn Oracle> {
415 self.oracles
416 .get(name)
417 .and_then(|(oracle, install)| install.then_some(oracle.as_ref()))
418 }
419
420 pub fn get_oracle_arc(&self, name: &str) -> Option<Arc<dyn Oracle>> {
422 self.oracles
423 .get(name)
424 .and_then(|(oracle, install)| install.then_some(oracle.clone()))
425 }
426
427 pub fn all_oracles(&self) -> impl Iterator<Item = &dyn Oracle> {
429 self.oracles.values().map(|(oracle, _)| oracle.as_ref())
430 }
431
432 pub fn all_oracles_arc(&self) -> impl Iterator<Item = Arc<dyn Oracle>> + '_ {
434 self.oracles.values().map(|(oracle, _)| oracle.clone())
435 }
436
437 pub fn process(&self) -> &Child<Installed> {
438 &self.process
439 }
440
441 pub fn set_hook(&mut self, hooks: impl EventHook + 'static) {
442 self.hooks = Box::new(hooks);
443 }
444
445 #[inline(always)]
447 pub fn exploration_ctx(&self) -> &ExplorationContext {
448 &self.expl_context
449 }
450
451 fn expl_ctx_update_location(&mut self) -> Result<&ExplorationContext, Error> {
453 let old_ctx = self.exploration_ctx();
454 self.expl_context = ExplorationContext::new(
455 self.debugee
456 .get_tracee_ensure(old_ctx.pid_on_focus())
457 .location(&self.debugee)?,
458 0,
459 );
460 Ok(&self.expl_context)
461 }
462
463 fn expl_ctx_swap(&mut self, new: ExplorationContext) {
464 self.expl_context = new;
465 }
466
467 fn expl_ctx_restore_frame(&mut self) -> Result<&ExplorationContext, Error> {
469 self.expl_ctx_update_location()
470 }
471
472 fn expl_ctx_switch_thread(&mut self, pid: Pid) -> Result<&ExplorationContext, Error> {
478 self.expl_context = ExplorationContext::new(
479 self.debugee
480 .get_tracee_ensure(pid)
481 .location(&self.debugee)?,
482 0,
483 );
484 Ok(&self.expl_context)
485 }
486
487 fn continue_execution(&mut self) -> Result<StopReason, Error> {
492 if let Some(sign_or_wp) = self.step_over_breakpoint()? {
493 match sign_or_wp {
494 StopReason::Watchpoint(pid, current_pc, ty) => {
495 self.execute_on_watchpoint_hook(pid, current_pc, &ty)?;
496 return Ok(StopReason::Watchpoint(pid, current_pc, ty));
497 }
498 StopReason::SignalStop(pid, sign) => {
499 self.hooks.on_signal(sign);
500 return Ok(StopReason::SignalStop(pid, sign));
501 }
502 _ => {
503 unreachable!("unexpected reason")
504 }
505 }
506 }
507
508 let stop_reason = loop {
509 let event = self.debugee.trace_until_stop(TraceContext::new(
510 &self.breakpoints.active_breakpoints(),
511 &self.watchpoints,
512 ))?;
513 match event {
514 StopReason::DebugeeExit(code) => {
515 _ = self.watchpoints.clear_local_disable_global(
517 self.debugee.tracee_ctl(),
518 &mut self.breakpoints,
519 );
520 _ = self.breakpoints.disable_all_breakpoints(&self.debugee);
522 self.hooks.on_exit(code);
523 break event;
524 }
525 StopReason::DebugeeStart => {
526 self.breakpoints.enable_entry_breakpoint(&self.debugee)?;
527 }
529 StopReason::NoSuchProcess(_) => {
530 return Err(ProcessNotStarted);
531 }
532 StopReason::Breakpoint(pid, current_pc) => {
533 self.expl_ctx_switch_thread(pid)?;
534
535 if let Some(bp) = self.breakpoints.get_enabled(current_pc) {
536 match bp.r#type() {
537 BrkptType::EntryPoint => {
538 print_warns!(
539 self.breakpoints.enable_all_breakpoints(&self.debugee)
540 );
541 print_warns!(self.watchpoints.refresh(&self.debugee));
542
543 let brk = self.debugee.rendezvous().r_brk();
545 self.breakpoints.add_and_enable(Breakpoint::new_linker_map(
546 brk,
547 self.process.pid(),
548 ))?;
549
550 let oracles = self.oracles.clone();
552 self.oracles = oracles.into_iter().map(|(key, (oracle, _))| {
553 let ready = oracle.ready_for_install(self);
554 if !ready {
555 debug!(target: "oracle", "oracle `{}` is disabled", oracle.name());
556 }
557
558 (key, (oracle, ready))
559 }).collect();
560
561 let oracles = self.oracles.clone();
562 let ready_oracles = oracles.into_values().filter(|(_, a)| *a);
563 for (oracle, _) in ready_oracles {
564 let spy_points = oracle.spy_points();
565 for request in spy_points {
566 weak_error!(self.set_transparent_breakpoint(request));
567 }
568 }
569
570 while self.step_over_breakpoint()?.is_some() {}
572 continue;
573 }
574 BrkptType::LinkerMapFn => {
575 while self.step_over_breakpoint()?.is_some() {}
577 print_warns!(self.refresh_deferred());
578 continue;
579 }
580 BrkptType::UserDefined => {
581 let pc = current_pc.into_global(&self.debugee)?;
582 let dwarf = self
583 .debugee
584 .debug_info(self.exploration_ctx().location().pc)?;
585 let place = weak_error!(dwarf.find_place_from_pc(pc)).flatten();
586 let func = weak_error!(dwarf.find_function_by_pc(pc))
587 .flatten()
588 .map(|f| f.die);
589 self.hooks
590 .on_breakpoint(current_pc, bp.number(), place, func)
591 .map_err(Hook)?;
592 break event;
593 }
594 BrkptType::WatchpointCompanion(_) => {
595 unreachable!("should not coming from tracer directly");
596 }
597 BrkptType::Temporary | BrkptType::TemporaryAsync => {
598 break event;
599 }
600 BrkptType::Transparent(callback) => {
601 callback.clone()(self);
602
603 match self.step_over_breakpoint()? {
604 Some(StopReason::SignalStop(pid, sign)) => {
605 self.hooks.on_signal(sign);
606 return Ok(StopReason::SignalStop(pid, sign));
607 }
608 Some(StopReason::Watchpoint(pid, addr, ty)) => {
609 self.execute_on_watchpoint_hook(pid, addr, &ty)?;
610 return Ok(StopReason::Watchpoint(pid, current_pc, ty));
611 }
612 _ => continue,
613 }
614 }
615 }
616 }
617 }
618 StopReason::SignalStop(pid, sign) => {
619 if !self.debugee.is_in_progress() {
620 continue;
621 }
622
623 self.expl_ctx_switch_thread(pid)?;
624 self.hooks.on_signal(sign);
625 break event;
626 }
627 StopReason::Watchpoint(pid, current_pc, ref ty) => {
628 self.expl_ctx_switch_thread(pid)?;
629 self.execute_on_watchpoint_hook(pid, current_pc, ty)?;
630 break event;
631 }
632 }
633 };
634
635 Ok(stop_reason)
636 }
637
638 pub fn restart_debugee(&mut self) -> Result<Pid, Error> {
643 match self.debugee.execution_status() {
644 ExecutionStatus::Unload => {
645 }
647 ExecutionStatus::InProgress => {
648 print_warns!(
649 self.watchpoints.clear_local_disable_global(
650 self.debugee.tracee_ctl(),
651 &mut self.breakpoints
652 )
653 );
654 print_warns!(self.breakpoints.disable_all_breakpoints(&self.debugee)?);
655 }
656 ExecutionStatus::Exited => {
657 }
660 }
661
662 if !self.debugee.is_exited() {
663 let proc_pid = self.process.pid();
664 signal::kill(proc_pid, SIGKILL).map_err(|e| Syscall("kill", e))?;
665 _ = self
666 .debugee
667 .tracer_mut()
668 .resume(TraceContext::new(&[], &self.watchpoints));
669 }
670
671 self.process = self.process.install()?;
672
673 let new_debugee = self.debugee.extend(self.process.pid());
674 _ = mem::replace(&mut self.debugee, new_debugee);
675
676 self.breakpoints.update_pid(self.process.pid());
678
679 self.hooks.on_process_install(self.process.pid(), None);
680 self.expl_context = ExplorationContext::new_non_running(self.process.pid());
681 self.continue_execution()?;
682 Ok(self.process.pid())
683 }
684
685 fn start_debugee_inner(&mut self, force: bool, dry_start: bool) -> Result<(), Error> {
686 if dry_start {
687 if (self.debugee.is_in_progress() || self.debugee.is_exited()) && !force {
688 return Err(Error::AlreadyRun);
689 }
690 return Ok(());
691 }
692
693 match self.debugee.execution_status() {
694 ExecutionStatus::Unload => {
695 self.continue_execution()?;
696 }
697 ExecutionStatus::InProgress | ExecutionStatus::Exited if force => {
698 self.restart_debugee()?;
699 }
700 ExecutionStatus::InProgress | ExecutionStatus::Exited => return Err(Error::AlreadyRun),
701 };
702
703 Ok(())
704 }
705
706 pub fn start_debugee(&mut self) -> Result<(), Error> {
713 self.start_debugee_inner(false, false)
714 }
715
716 pub fn start_debugee_force(&mut self) -> Result<(), Error> {
719 self.start_debugee_inner(true, false)
720 }
721
722 pub fn dry_start_debugee(&mut self) -> Result<(), Error> {
728 self.start_debugee_inner(false, true)
729 }
730
731 pub fn continue_debugee(&mut self) -> Result<(), Error> {
733 disable_when_not_stared!(self);
734 self.continue_execution()?;
735 Ok(())
736 }
737
738 pub fn get_symbols(&self, regex: &str) -> Result<Vec<&Symbol>, Error> {
744 let regex = Regex::new(regex)?;
745
746 Ok(self
747 .debugee
748 .debug_info_all()
749 .iter()
750 .flat_map(|dwarf| dwarf.find_symbols(®ex))
751 .collect())
752 }
753
754 pub fn frame_info(&self) -> Result<FrameInfo, Error> {
756 disable_when_not_stared!(self);
757 self.debugee.frame_info(self.exploration_ctx())
758 }
759
760 pub fn set_frame_into_focus(&mut self, num: u32) -> Result<u32, Error> {
766 disable_when_not_stared!(self);
767 let ctx = self.exploration_ctx();
768 let backtrace = self.debugee.unwind(ctx.pid_on_focus())?;
769 let frame = backtrace.get(num as usize).ok_or(FrameNotFound(num))?;
770 self.expl_context = ExplorationContext::new(
771 Location {
772 pc: frame.ip,
773 global_pc: frame.ip.into_global(&self.debugee)?,
774 pid: ctx.pid_on_focus(),
775 },
776 num,
777 );
778 Ok(num)
779 }
780
781 fn execute_on_step_hook(&self) -> Result<(), Error> {
783 let ctx = self.exploration_ctx();
784 let pc = ctx.location().pc;
785 let global_pc = ctx.location().global_pc;
786 let dwarf = self.debugee.debug_info(pc)?;
787 let place = weak_error!(dwarf.find_place_from_pc(global_pc)).flatten();
788 let func = weak_error!(dwarf.find_function_by_pc(global_pc))
789 .flatten()
790 .map(|f| f.die);
791 self.hooks.on_step(pc, place, func).map_err(Hook)
792 }
793
794 fn execute_on_async_step_hook(&self, task_id: u64, task_completed: bool) -> Result<(), Error> {
796 let ctx = self.exploration_ctx();
797 let pc = ctx.location().pc;
798 let global_pc = ctx.location().global_pc;
799 let dwarf = self.debugee.debug_info(pc)?;
800 let place = weak_error!(dwarf.find_place_from_pc(global_pc)).flatten();
801 let func = weak_error!(dwarf.find_function_by_pc(global_pc))
802 .flatten()
803 .map(|f| f.die);
804 self.hooks
805 .on_async_step(pc, place, func, task_id, task_completed)
806 .map_err(Hook)
807 }
808
809 pub fn step_into(&mut self) -> Result<(), Error> {
813 disable_when_not_stared!(self);
814 self.expl_ctx_restore_frame()?;
815
816 match self.step_in()? {
817 StepResult::Done => self.execute_on_step_hook(),
818 StepResult::SignalInterrupt { signal, quiet } if !quiet => {
819 self.hooks.on_signal(signal);
820 Ok(())
821 }
822 StepResult::WatchpointInterrupt {
823 pid,
824 addr,
825 ref ty,
826 quiet,
827 } if !quiet => self.execute_on_watchpoint_hook(pid, addr, ty),
828 _ => Ok(()),
829 }
830 }
831
832 pub fn stepi(&mut self) -> Result<(), Error> {
836 disable_when_not_stared!(self);
837 self.expl_ctx_restore_frame()?;
838
839 match self.single_step_instruction()? {
840 Some(StopReason::SignalStop(_, sign)) => {
841 self.hooks.on_signal(sign);
842 Ok(())
843 }
844 Some(StopReason::Watchpoint(pid, addr, ref ty)) => {
845 self.execute_on_watchpoint_hook(pid, addr, ty)
846 }
847 _ => self.execute_on_step_hook(),
848 }
849 }
850
851 pub fn thread_state(&self) -> Result<Vec<ThreadSnapshot>, Error> {
853 disable_when_not_stared!(self);
854 self.debugee.thread_state(self.exploration_ctx())
855 }
856
857 pub fn set_thread_into_focus(&mut self, num: u32) -> Result<Tracee, Error> {
863 disable_when_not_stared!(self);
864 let tracee = self.debugee.get_tracee_by_num(num)?;
865 self.expl_ctx_switch_thread(tracee.pid)?;
866 Ok(tracee)
867 }
868
869 pub fn backtrace(&self, pid: Pid) -> Result<Backtrace, Error> {
875 disable_when_not_stared!(self);
876 self.debugee.unwind(pid)
877 }
878
879 pub fn read_memory(&self, addr: usize, read_n: usize) -> Result<Vec<u8>, Error> {
886 disable_when_not_stared!(self);
887 read_memory_by_pid(self.debugee.tracee_ctl().proc_pid(), addr, read_n).map_err(Ptrace)
888 }
889
890 pub fn write_memory(&self, addr: uintptr_t, value: uintptr_t) -> Result<(), Error> {
898 disable_when_not_stared!(self);
899 unsafe {
900 sys::ptrace::write(
901 self.debugee.tracee_ctl().proc_pid(),
902 addr as *mut c_void,
903 value as *mut c_void,
904 )
905 .map_err(Ptrace)
906 }
907 }
908
909 pub fn step_out(&mut self) -> Result<(), Error> {
911 disable_when_not_stared!(self);
912 self.expl_ctx_restore_frame()?;
913 self.step_out_frame()?;
914 self.execute_on_step_hook()
915 }
916
917 pub fn step_over(&mut self) -> Result<(), Error> {
919 disable_when_not_stared!(self);
920 self.expl_ctx_restore_frame()?;
921 match self.step_over_any()? {
922 StepResult::Done => self.execute_on_step_hook(),
923 StepResult::SignalInterrupt { signal, quiet } if !quiet => {
924 self.hooks.on_signal(signal);
925 Ok(())
926 }
927 StepResult::WatchpointInterrupt {
928 pid,
929 addr,
930 ref ty,
931 quiet,
932 } if !quiet => self.execute_on_watchpoint_hook(pid, addr, ty),
933 _ => Ok(()),
934 }
935 }
936
937 pub fn read_local_variables(&self) -> Result<Vec<QueryResult<'_>>, Error> {
939 disable_when_not_stared!(self);
940
941 let executor = variable::execute::DqeExecutor::new(self);
942 let eval_result = executor.query(&Dqe::Variable(Selector::Any))?;
943 Ok(eval_result)
944 }
945
946 pub fn read_variable(&self, select_expr: Dqe) -> Result<Vec<QueryResult<'_>>, Error> {
953 disable_when_not_stared!(self);
954 let executor = variable::execute::DqeExecutor::new(self);
955 let eval_result = executor.query(&select_expr)?;
956 Ok(eval_result)
957 }
958
959 pub fn read_variable_names(&self, select_expr: Dqe) -> Result<Vec<String>, Error> {
966 disable_when_not_stared!(self);
967 let executor = variable::execute::DqeExecutor::new(self);
968 executor.query_names(&select_expr)
969 }
970
971 pub fn read_argument(&self, select_expr: Dqe) -> Result<Vec<QueryResult<'_>>, Error> {
978 disable_when_not_stared!(self);
979 let executor = variable::execute::DqeExecutor::new(self);
980 let eval_result = executor.query_arguments(&select_expr)?;
981 Ok(eval_result)
982 }
983
984 pub fn read_argument_names(&self, select_expr: Dqe) -> Result<Vec<String>, Error> {
991 disable_when_not_stared!(self);
992 let executor = variable::execute::DqeExecutor::new(self);
993 executor.query_arguments_names(&select_expr)
994 }
995
996 pub fn get_register_value(&self, register_name: &str) -> Result<u64, Error> {
1002 disable_when_not_stared!(self);
1003
1004 let r = Register::from_str(register_name)
1005 .map_err(|_| RegisterNameNotFound(register_name.into()))?;
1006 Ok(RegisterMap::current(self.exploration_ctx().pid_on_focus())?.value(r))
1007 }
1008
1009 pub fn current_thread_registers_at_pc(
1015 &self,
1016 pc: RelocatedAddress,
1017 ) -> Result<DwarfRegisterMap, Error> {
1018 disable_when_not_stared!(self);
1019 let unwinder = DwarfUnwinder::new(&self.debugee);
1020 let location = Location {
1021 pc,
1022 global_pc: pc.into_global(&self.debugee)?,
1023 pid: self.exploration_ctx().pid_on_focus(),
1024 };
1025 Ok(unwinder
1026 .context_for(&ExplorationContext::new(location, 0))?
1030 .ok_or(UnwindNoContext)?
1031 .registers())
1032 }
1033
1034 pub fn set_register_value(&self, register_name: &str, val: u64) -> Result<(), Error> {
1041 disable_when_not_stared!(self);
1042
1043 let in_focus_pid = self.exploration_ctx().pid_on_focus();
1044 let mut map = RegisterMap::current(in_focus_pid)?;
1045 map.update(
1046 Register::try_from(register_name)
1047 .map_err(|_| RegisterNameNotFound(register_name.into()))?,
1048 val,
1049 );
1050 map.persist(in_focus_pid)
1051 }
1052
1053 pub fn known_files(&self) -> impl Iterator<Item = &PathBuf> {
1055 self.debugee
1056 .debug_info_all()
1057 .into_iter()
1058 .filter_map(|dwarf| dwarf.known_files().ok())
1059 .flatten()
1060 }
1061
1062 pub fn shared_libs(&self) -> Vec<RegionInfo> {
1064 self.debugee.dump_mapped_regions()
1065 }
1066
1067 pub fn disasm(&self) -> Result<FunctionAssembly, Error> {
1069 disable_when_not_stared!(self);
1070 self.debugee.disasm(
1071 self.exploration_ctx(),
1072 &self.breakpoints.active_breakpoints(),
1073 )
1074 }
1075
1076 pub fn current_function_range(&self) -> Result<FunctionRange<'_>, Error> {
1078 disable_when_not_stared!(self);
1079 self.debugee.function_range(self.exploration_ctx())
1080 }
1081
1082 fn call_cache(&self) -> RefMut<'_, CallCache> {
1084 self.call_cache.borrow_mut()
1085 }
1086}
1087
1088impl Drop for Debugger {
1089 fn drop(&mut self) {
1090 if self.process.is_external() {
1091 _ = self.breakpoints.disable_all_breakpoints(&self.debugee);
1092 self.watchpoints
1094 .clear_all(self.debugee.tracee_ctl(), &mut self.breakpoints);
1095
1096 let current_tids: Vec<Pid> = self
1097 .debugee
1098 .tracee_ctl()
1099 .tracee_iter()
1100 .map(|t| t.pid)
1101 .collect();
1102
1103 if !current_tids.is_empty() {
1104 current_tids.iter().for_each(|tid| {
1105 sys::ptrace::detach(*tid, None).expect("detach debugee");
1106 });
1107
1108 signal::kill(self.debugee.tracee_ctl().proc_pid(), Signal::SIGCONT)
1109 .expect("kill debugee");
1110 }
1111
1112 return;
1113 }
1114
1115 match self.debugee.execution_status() {
1116 ExecutionStatus::Unload => {
1117 signal::kill(self.debugee.tracee_ctl().proc_pid(), Signal::SIGKILL)
1118 .expect("kill debugee");
1119 waitpid(self.debugee.tracee_ctl().proc_pid(), None).expect("waiting child");
1120 }
1121 ExecutionStatus::InProgress => {
1122 _ = self.breakpoints.disable_all_breakpoints(&self.debugee);
1124 self.watchpoints
1126 .clear_all(self.debugee.tracee_ctl(), &mut self.breakpoints);
1127
1128 let current_tids: Vec<Pid> = self
1129 .debugee
1130 .tracee_ctl()
1131 .tracee_iter()
1132 .map(|t| t.pid)
1133 .collect();
1134
1135 let prepare_stopped: Vec<_> = current_tids
1138 .into_iter()
1139 .filter(|&tid| sys::ptrace::cont(tid, Signal::SIGSTOP).is_ok())
1140 .collect();
1141 let stopped: Vec<_> = prepare_stopped
1142 .into_iter()
1143 .filter(|&tid| waitpid(tid, None).is_ok())
1144 .collect();
1145 stopped.into_iter().for_each(|tid| {
1147 sys::ptrace::detach(tid, None).expect("detach tracee");
1148 });
1149 signal::kill(self.debugee.tracee_ctl().proc_pid(), Signal::SIGKILL)
1151 .expect("kill debugee");
1152 let wait_result = loop {
1153 let wait_result = waitpid(Pid::from_raw(-1), None).expect("waiting debugee");
1154 if wait_result.pid() == Some(self.debugee.tracee_ctl().proc_pid()) {
1155 break wait_result;
1156 }
1157 };
1158
1159 debug_assert!(matches!(
1160 wait_result,
1161 WaitStatus::Signaled(_, Signal::SIGKILL, _)
1162 ));
1163 }
1164 ExecutionStatus::Exited => {}
1165 }
1166 }
1167}
1168
1169pub fn read_memory_by_pid(pid: Pid, addr: usize, read_n: usize) -> Result<Vec<u8>, nix::Error> {
1171 let mut read_reminder = read_n as isize;
1172 let mut result = Vec::with_capacity(read_n);
1173
1174 let single_read_size = mem::size_of::<c_long>();
1175
1176 let mut addr = addr as *mut c_long;
1177 while read_reminder > 0 {
1178 let value = sys::ptrace::read(pid, addr as *mut c_void)?;
1179 result.extend(value.to_ne_bytes().into_iter().take(read_reminder as usize));
1180
1181 read_reminder -= single_read_size as isize;
1182 addr = unsafe { addr.offset(1) };
1183 }
1184
1185 debug_assert!(result.len() == read_n);
1186
1187 Ok(result)
1188}