1use super::bit::from_bytes;
2use super::bit::to_byte128;
3use super::process::Process;
4use super::register_info::RegisterFormat;
5use super::register_info::RegisterId;
6use super::register_info::RegisterInfo;
7use super::register_info::RegisterType;
8use super::register_info::register_info_by_id;
9use super::sdb_error::SdbError;
10use super::types::VirtualAddress;
11use super::types::{Byte64, Byte128};
12use bytemuck::Pod;
13use bytemuck::Zeroable;
14use extended::Extended;
15use nix::libc::user;
16use nix::unistd::Pid;
17use std::fmt::Display;
18use std::fmt::Write;
19use std::rc::Weak;
20use typed_builder::TypedBuilder;
21
22#[repr(transparent)]
23#[derive(Clone, Copy, Debug)]
24pub struct User(pub user);
25
26unsafe impl Zeroable for User {}
27
28#[repr(transparent)]
29#[derive(Clone, Copy, PartialEq, Debug)]
30pub struct F80(pub Extended);
31
32impl Display for F80 {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 write!(f, "{}", self.0.to_f64())
35 }
36}
37
38unsafe impl Pod for F80 {}
39
40unsafe impl Zeroable for F80 {}
41
42impl F80 {
43 pub fn new(value: f64) -> Self {
44 Self(Extended::from(value))
45 }
46}
47
48#[derive(Debug, Clone, TypedBuilder)]
49pub struct Registers {
50 #[builder(default = User::zeroed())]
51 pub data: User,
52 process: Weak<Process>,
53 #[builder(default)]
54 undefined: Vec<usize>,
55 #[builder(default)]
56 cfa: VirtualAddress,
57 tid: Pid,
58}
59
60pub enum RegisterValue {
61 U8(u8),
62 U16(u16),
63 U32(u32),
64 U64(u64),
65 I8(i8),
66 I16(i16),
67 I32(i32),
68 I64(i64),
69 Float(f32),
70 Double(f64),
71 LongDouble(F80), Byte64(Byte64),
73 Byte128(Byte128),
74}
75
76macro_rules! format_register_value {
77 ($this:ident,
78 {
79 $($int_enum:ident => $int_ty:ty );+ $(;)?
80 },
81 {
82 $($float_enum:ident);+ $(;)?
83 },
84 {
85 $($vec_enum:ident);+ $(;)?
86 }
87 ) => {
88 match $this {
89 $(
90 RegisterValue::$int_enum(v) => {
91 let width = std::mem::size_of::<$int_ty>() * 2 + 2;
92 format!("{:#0width$x}", v, width = width)
93 }
94 )+
95 $(
96 RegisterValue::$float_enum(v) => format!("{v}"),
97 )+
98 $(
99 RegisterValue::$vec_enum(v) => {
100 let mut out = String::with_capacity(v.len() * 6 + 2);
101 out.push('[');
102 for (i, v) in v.iter().enumerate() {
103 if i != 0 {
104 out.push(',');
105 }
106 write!(out, "{:#04x}", v).unwrap();
107 }
108 out.push(']');
109 out
110 }
111 )+
112 }
113 };
114}
115
116impl Display for RegisterValue {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 let v = format_register_value!(self, {
119 U8 => u8;
120 U16 => u16;
121 U32 => u32;
122 U64 => u64;
123 I8 => i8;
124 I16 => i16;
125 I32 => i32;
126 I64 => i64;
127 },
128 { Float; Double; LongDouble},
129 { Byte64; Byte128 });
130 write!(f, "{v}")
131 }
132}
133
134macro_rules! impl_register_value_conversion {
136 ($t:ty, $p:ident) => {
137 impl From<RegisterValue> for $t {
138 fn from(val: RegisterValue) -> Self {
139 match val {
140 RegisterValue::$p(inner) => inner as $t,
141 _ => panic!("Unkown RegisterValue"),
142 }
143 }
144 }
145
146 impl From<$t> for RegisterValue {
147 #[inline]
148 fn from(val: $t) -> Self {
149 RegisterValue::$p(val)
150 }
151 }
152 };
153}
154
155impl_register_value_conversion!(u8, U8);
156impl_register_value_conversion!(u16, U16);
157impl_register_value_conversion!(u32, U32);
158impl_register_value_conversion!(u64, U64);
159impl_register_value_conversion!(i8, I8);
160impl_register_value_conversion!(i16, I16);
161impl_register_value_conversion!(i32, I32);
162impl_register_value_conversion!(i64, I64);
163impl_register_value_conversion!(f32, Float);
164impl_register_value_conversion!(f64, Double);
165impl_register_value_conversion!(F80, LongDouble);
166impl_register_value_conversion!(Byte64, Byte64);
167impl_register_value_conversion!(Byte128, Byte128);
168
169macro_rules! write_cases {
170 ( $src:ident, $dest:ident, $info:ident, $( $variant:ident => $ty:ty ),+ $(,)? ) => {
171 match $src {
172 $(
173 RegisterValue::$variant(v)
174 if size_of::<$ty>() <= $info.size => {
175 $dest.copy_from_slice(&to_byte128(v)[..$info.size]);
176 }
177 )+
178 _ => panic!("register::write called with mismatched register and value sizes"),
179 }
180 };
181}
182
183impl Registers {
184 pub fn new(proc: &Weak<Process>, tid: Pid) -> Self {
185 Self {
186 data: User::zeroed(),
187 process: proc.clone(),
188 undefined: Vec::new(),
189 cfa: VirtualAddress::default(),
190 tid,
191 }
192 }
193 pub fn read(&self, info: &RegisterInfo) -> Result<RegisterValue, SdbError> {
194 if self.is_undefined(info.id)? {
195 return SdbError::err("Register is undefined");
196 }
197 let bytes = unsafe {
198 core::slice::from_raw_parts(
199 &self.data as *const _ as *const u8,
200 std::mem::size_of_val(&self.data),
201 )
202 };
203 match info.format {
204 RegisterFormat::UInt => match info.size {
205 1 => Ok(RegisterValue::U8(from_bytes::<u8>(&bytes[info.offset..]))),
206 2 => Ok(RegisterValue::U16(from_bytes::<u16>(&bytes[info.offset..]))),
207 4 => Ok(RegisterValue::U32(from_bytes::<u32>(&bytes[info.offset..]))),
208 8 => Ok(RegisterValue::U64(from_bytes::<u64>(&bytes[info.offset..]))),
209 _ => SdbError::err("Unexpected register size"),
210 },
211 RegisterFormat::DoubleFloat => Ok(RegisterValue::Double(from_bytes::<f64>(
212 &bytes[info.offset..],
213 ))),
214 RegisterFormat::LongDouble => Ok(RegisterValue::LongDouble(from_bytes::<F80>(
215 &bytes[info.offset..],
216 ))),
217 RegisterFormat::Vector if info.size == 8 => {
218 Ok(RegisterValue::Byte64(from_bytes::<Byte64>(
219 &bytes[info.offset..],
220 )))
221 }
222 _ => Ok(RegisterValue::Byte128(from_bytes::<Byte128>(
223 &bytes[info.offset..],
224 ))),
225 }
226 }
227
228 pub fn write(
229 &mut self,
230 info: &RegisterInfo,
231 value: RegisterValue,
232 commit: bool, ) -> Result<(), SdbError> {
234 let bytes: &mut [u8] = unsafe {
235 core::slice::from_raw_parts_mut(
236 &mut self.data as *mut _ as *mut u8,
237 std::mem::size_of_val(&self.data),
238 )
239 };
240 let dest = &mut bytes[info.offset..info.offset + info.size];
241
242 write_cases!(
243 value, dest, info,
244 U8 => u8, U16 => u16, U32 => u32, U64 => u64,
245 I8 => i8, I16 => i16, I32 => i32, I64 => i64,
246 Float => f32, Double => f64, LongDouble => F80,
247 Byte64 => Byte64, Byte128 => Byte128,
248 );
249 let proc = self.process.upgrade().unwrap();
250 if commit {
251 if info.type_ == RegisterType::Fpr {
252 proc.write_fprs(&mut self.data.0.i387, Some(self.tid))?;
253 } else {
254 let aligned_offset = info.offset & !0b111;
255 proc.write_user_area(
256 info.offset,
257 from_bytes::<u64>(&bytes[aligned_offset..]),
258 Some(self.tid),
259 )?;
260 }
261 }
262
263 Ok(())
264 }
265
266 pub fn read_by_id_as<T: From<RegisterValue>>(&self, id: RegisterId) -> Result<T, SdbError> {
267 let info = register_info_by_id(id)?;
268 let value = self.read(&info)?;
269 Ok(T::from(value))
270 }
271
272 pub fn write_by_id<T: Into<RegisterValue>>(
273 &mut self,
274 id: RegisterId,
275 value: T,
276 commit: bool, ) -> Result<(), SdbError> {
278 let info = register_info_by_id(id)?;
279 self.write(&info, value.into(), commit)?;
280 Ok(())
281 }
282
283 pub fn undefine(&mut self, id: RegisterId) -> Result<(), SdbError> {
284 let canonical_offset = register_info_by_id(id)?.offset >> 1;
285 self.undefined.push(canonical_offset);
286 Ok(())
287 }
288
289 pub fn is_undefined(&self, id: RegisterId) -> Result<bool, SdbError> {
290 let canonical_offset = register_info_by_id(id)?.offset >> 1;
291 Ok(self.undefined.contains(&canonical_offset))
292 }
293
294 pub fn flush(&mut self) -> Result<(), SdbError> {
295 let proc = self.process.upgrade().unwrap();
296 proc.write_fprs(&mut self.data.0.i387, Some(self.tid))?;
297 proc.write_gprs(&mut self.data.0.regs, Some(self.tid))?;
298 let info = register_info_by_id(RegisterId::dr0)?;
299 for i in 0..8 {
300 if i == 4 || i == 5 {
301 continue;
302 }
303 let reg_offset = info.offset + std::mem::size_of::<u64>() * i;
304 let bytes = self.data.0.u_debugreg[i];
305 proc.write_user_area(reg_offset, bytes, Some(self.tid))?;
306 }
307 Ok(())
308 }
309
310 pub fn set_cfa(&mut self, addr: VirtualAddress) {
311 self.cfa = addr;
312 }
313
314 pub fn cfa(&self) -> VirtualAddress {
315 self.cfa
316 }
317}