libsdb/
registers.rs

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), // 80 bit extended precision
72    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
134/* --- blanket impls for the primitive types you actually care about --- */
135macro_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, /* true */
233    ) -> 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            /* unsigned  */ U8 => u8,   U16 => u16, U32 => u32, U64 => u64,
245            /* signed    */ I8 => i8,   I16 => i16, I32 => i32, I64 => i64,
246            /* floats    */ Float => f32, Double => f64, LongDouble => F80,
247            /* vectors   */ 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, /* true */
277    ) -> 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}