1use crate::abi::Abi;
8use crate::sys::{RED_ZONE_SIZE, Result};
9
10#[cfg(target_arch = "x86_64")]
11mod arch {
12 use super::super::ptrace;
13 use crate::abi::Abi;
14 use crate::sys::Result;
15
16 pub type Raw = libc::user_regs_struct;
17
18 pub fn fetch(pid: i32) -> Result<Raw> {
19 ptrace::getregs(pid)
20 }
21
22 pub fn store(pid: i32, cur: &Raw, _orig: &Raw) -> Result<()> {
23 ptrace::setregs(pid, cur)
24 }
25
26 pub fn abi(r: &Raw) -> Abi {
28 if r.cs == 0x23 { Abi::I386 } else { Abi::X86_64 }
29 }
30
31 pub fn sysnum(r: &Raw) -> i64 {
32 r.orig_rax as i64
33 }
34
35 pub fn set_sysnum(r: &mut Raw, nr: i64) {
36 r.orig_rax = nr as u64;
37 }
38
39 pub fn set_ret(r: &mut Raw, v: i64) {
41 r.rax = v as u64;
42 }
43
44 pub fn arg(r: &Raw, i: usize) -> u64 {
45 match abi(r) {
46 Abi::I386 => {
47 (match i {
48 0 => r.rbx,
49 1 => r.rcx,
50 2 => r.rdx,
51 3 => r.rsi,
52 4 => r.rdi,
53 _ => r.rbp,
54 }) & 0xffff_ffff
55 }
56 _ => match i {
57 0 => r.rdi,
58 1 => r.rsi,
59 2 => r.rdx,
60 3 => r.r10,
61 4 => r.r8,
62 _ => r.r9,
63 },
64 }
65 }
66
67 pub fn set_arg(r: &mut Raw, i: usize, v: u64) {
68 match abi(r) {
69 Abi::I386 => {
70 let v = v & 0xffff_ffff;
71 match i {
72 0 => r.rbx = v,
73 1 => r.rcx = v,
74 2 => r.rdx = v,
75 3 => r.rsi = v,
76 4 => r.rdi = v,
77 _ => r.rbp = v,
78 }
79 }
80 _ => match i {
81 0 => r.rdi = v,
82 1 => r.rsi = v,
83 2 => r.rdx = v,
84 3 => r.r10 = v,
85 4 => r.r8 = v,
86 _ => r.r9 = v,
87 },
88 }
89 }
90
91 pub fn sp(r: &Raw) -> u64 {
92 r.rsp
93 }
94
95 pub fn ip(r: &Raw) -> u64 {
96 r.rip
97 }
98
99 pub fn same(a: &Raw, b: &Raw) -> bool {
100 let n = std::mem::size_of::<Raw>();
101 unsafe {
102 std::slice::from_raw_parts(a as *const _ as *const u8, n)
103 == std::slice::from_raw_parts(b as *const _ as *const u8, n)
104 }
105 }
106}
107
108#[cfg(target_arch = "aarch64")]
109mod arch {
110 use super::super::ptrace;
111 use crate::abi::Abi;
112 use crate::sys::Result;
113
114 #[repr(C)]
117 #[derive(Clone, Copy, PartialEq)]
118 pub struct Raw {
119 pub regs: [u64; 31],
120 pub sp: u64,
121 pub pc: u64,
122 pub pstate: u64,
123 pub compat: bool,
125 pub sysnum_override: Option<i32>,
127 }
128
129 const NT_PRSTATUS: u32 = 1;
130 const NT_ARM_SYSTEM_CALL: u32 = 0x404;
131 const REGS64_LEN: usize = 34 * 8;
132 const REGS32_LEN: usize = 18 * 4;
133
134 pub fn fetch(pid: i32) -> Result<Raw> {
135 let mut r = Raw {
136 regs: [0; 31],
137 sp: 0,
138 pc: 0,
139 pstate: 0,
140 compat: false,
141 sysnum_override: None,
142 };
143 let mut buf = [0u8; REGS64_LEN];
144 let n = ptrace::getregset(pid, NT_PRSTATUS, buf.as_mut_ptr(), REGS64_LEN)?;
145 if n == REGS32_LEN {
146 r.compat = true;
147 for (i, w) in buf[..REGS32_LEN].as_chunks::<4>().0.iter().enumerate() {
148 r.regs[i] = u32::from_ne_bytes(*w) as u64;
149 }
150 r.sp = r.regs[13];
151 r.pc = r.regs[15];
152 r.pstate = r.regs[16];
153 } else {
154 for (i, w) in buf[..31 * 8].as_chunks::<8>().0.iter().enumerate() {
155 r.regs[i] = u64::from_ne_bytes(*w);
156 }
157 r.sp = u64::from_ne_bytes(buf[248..256].try_into().unwrap());
158 r.pc = u64::from_ne_bytes(buf[256..264].try_into().unwrap());
159 r.pstate = u64::from_ne_bytes(buf[264..272].try_into().unwrap());
160 }
161 Ok(r)
162 }
163
164 pub fn store(pid: i32, cur: &Raw, orig: &Raw) -> Result<()> {
165 if let Some(nr) = cur.sysnum_override {
166 let mut v = nr;
167 ptrace::setregset(pid, NT_ARM_SYSTEM_CALL, &mut v as *mut i32 as *mut u8, 4)?;
168 }
169 if cur.regs != orig.regs || cur.sp != orig.sp || cur.pc != orig.pc {
170 if cur.compat {
171 let mut buf = [0u8; REGS32_LEN];
172 for i in 0..18 {
173 buf[i * 4..i * 4 + 4].copy_from_slice(&(cur.regs[i] as u32).to_ne_bytes());
174 }
175 ptrace::setregset(pid, NT_PRSTATUS, buf.as_mut_ptr(), REGS32_LEN)?;
176 } else {
177 let mut buf = [0u8; REGS64_LEN];
178 for i in 0..31 {
179 buf[i * 8..i * 8 + 8].copy_from_slice(&cur.regs[i].to_ne_bytes());
180 }
181 buf[248..256].copy_from_slice(&cur.sp.to_ne_bytes());
182 buf[256..264].copy_from_slice(&cur.pc.to_ne_bytes());
183 buf[264..272].copy_from_slice(&cur.pstate.to_ne_bytes());
184 ptrace::setregset(pid, NT_PRSTATUS, buf.as_mut_ptr(), REGS64_LEN)?;
185 }
186 }
187 Ok(())
188 }
189
190 pub fn abi(r: &Raw) -> Abi {
191 if r.compat { Abi::Arm } else { Abi::Aarch64 }
192 }
193
194 pub fn sysnum(r: &Raw) -> i64 {
196 if let Some(n) = r.sysnum_override {
197 return n as i64;
198 }
199 if r.compat {
200 r.regs[7] as i64
201 } else {
202 r.regs[8] as i64
203 }
204 }
205
206 pub fn set_sysnum(r: &mut Raw, nr: i64) {
207 r.sysnum_override = Some(nr as i32);
208 }
209
210 pub fn set_ret(r: &mut Raw, v: i64) {
212 r.regs[0] = if r.compat {
213 v as u64 & 0xffff_ffff
214 } else {
215 v as u64
216 };
217 }
218
219 pub fn arg(r: &Raw, i: usize) -> u64 {
221 let v = r.regs[i.min(5)];
222 if r.compat { v & 0xffff_ffff } else { v }
223 }
224
225 pub fn set_arg(r: &mut Raw, i: usize, v: u64) {
226 r.regs[i.min(5)] = if r.compat { v & 0xffff_ffff } else { v };
227 if r.compat && i == 0 {
228 r.regs[17] = v & 0xffff_ffff;
230 }
231 }
232
233 pub fn sp(r: &Raw) -> u64 {
234 r.sp
235 }
236
237 pub fn ip(r: &Raw) -> u64 {
238 r.pc
239 }
240
241 pub fn same(a: &Raw, b: &Raw) -> bool {
242 a == b
243 }
244}
245
246#[derive(Clone)]
248pub struct Regs {
249 pid: i32,
250 orig: arch::Raw,
251 cur: arch::Raw,
252 scratch_used: u64,
254}
255
256impl Regs {
257 pub fn fetch(pid: i32) -> Result<Regs> {
259 let r = arch::fetch(pid)?;
260 Ok(Regs {
261 pid,
262 orig: r,
263 cur: r,
264 scratch_used: 0,
265 })
266 }
267
268 pub fn pid(&self) -> i32 {
270 self.pid
271 }
272
273 pub fn abi(&self) -> Abi {
275 arch::abi(&self.cur)
276 }
277
278 pub fn sysnum(&self) -> i64 {
280 arch::sysnum(&self.cur)
281 }
282
283 pub fn fail(&mut self, errno: i32) {
288 arch::set_sysnum(&mut self.cur, -1);
289 arch::set_ret(&mut self.cur, -i64::from(errno));
290 }
291
292 pub fn arg(&self, i: usize) -> u64 {
294 arch::arg(&self.cur, i)
295 }
296
297 pub fn set_arg(&mut self, i: usize, v: u64) {
299 arch::set_arg(&mut self.cur, i, v);
300 }
301
302 pub fn sp(&self) -> u64 {
304 arch::sp(&self.cur)
305 }
306
307 pub fn ip(&self) -> u64 {
309 arch::ip(&self.cur)
310 }
311
312 pub fn alloc_stack(&mut self, size: u64) -> u64 {
326 let sp = self.sp();
327 let base = sp.saturating_sub(RED_ZONE_SIZE + self.scratch_used);
328 let addr = base.saturating_sub(size) & !0xf;
329 self.scratch_used = sp - addr;
330 addr
331 }
332
333 pub fn commit(&self) -> Result<()> {
335 if arch::same(&self.cur, &self.orig) {
336 return Ok(());
337 }
338 arch::store(self.pid, &self.cur, &self.orig)
339 }
340}