1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use crate::ptrace_control::*;
use crate::statemachine::*;
use nix::unistd::Pid;
use nix::{Error, Result};
use std::collections::HashMap;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
const INT: u64 = 0xCC;
#[derive(Debug)]
pub struct Breakpoint {
pub pc: u64,
data: u8,
shift: u64,
is_running: HashMap<Pid, bool>,
}
impl Breakpoint {
pub fn new(pid: Pid, pc: u64) -> Result<Breakpoint> {
let aligned = pc & !0x7u64;
let data = read_address(pid, aligned)?;
let shift = 8 * (pc - aligned);
let data = ((data >> shift) & 0xFF) as u8;
let mut b = Breakpoint {
pc,
data,
shift,
is_running: HashMap::new(),
};
match b.enable(pid) {
Ok(_) => Ok(b),
Err(e) => Err(e),
}
}
pub fn jump_to(&mut self, pid: Pid) -> Result<()> {
set_instruction_pointer(pid, self.pc).map(|_| ())
}
pub fn enable(&mut self, pid: Pid) -> Result<()> {
let data = read_address(pid, self.aligned_address())?;
self.is_running.insert(pid, true);
let mut intdata = data & (!(0xFFu64 << self.shift) as i64);
intdata |= (INT << self.shift) as i64;
if data == intdata {
Err(Error::UnsupportedOperation)
} else {
write_to_address(pid, self.aligned_address(), intdata)
}
}
fn disable(&self, pid: Pid) -> Result<()> {
let data = read_address(pid, self.aligned_address())?;
let mut orgdata = data & (!(0xFFu64 << self.shift) as i64);
orgdata |= i64::from(self.data) << self.shift;
write_to_address(pid, self.aligned_address(), orgdata)
}
pub fn process(
&mut self,
pid: Pid,
reenable: bool,
) -> Result<(bool, TracerAction<ProcessInfo>)> {
let is_running = match self.is_running.get(&pid) {
Some(r) => *r,
None => true,
};
if is_running {
let _ = self.enable(pid);
self.step(pid)?;
self.is_running.insert(pid, false);
Ok((true, TracerAction::Step(pid.into())))
} else {
self.disable(pid)?;
if reenable {
self.enable(pid)?;
}
self.is_running.insert(pid, true);
Ok((false, TracerAction::Continue(pid.into())))
}
}
pub fn thread_killed(&mut self, pid: Pid) {
self.is_running.remove(&pid);
}
fn step(&mut self, pid: Pid) -> Result<()> {
self.disable(pid)?;
self.jump_to(pid)?;
Ok(())
}
fn aligned_address(&self) -> u64 {
self.pc & !0x7u64
}
}