aboutsummaryrefslogtreecommitdiff
path: root/src/riscv/reg/riscv.rs
blob: 15075f22418542f4d5e79486c9661481054ddde0 (plain)
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
use num_traits::PrimInt;

use gdbstub::arch::Registers;
use gdbstub::internal::LeBytes;

/// RISC-V Integer registers.
///
/// The register width is set to `u32` or `u64` based on the `<U>` type.
///
/// Useful links:
/// * [GNU binutils-gdb XML descriptions](https://github.com/bminor/binutils-gdb/blob/master/gdb/features/riscv)
/// * [riscv-tdep.h](https://github.com/bminor/binutils-gdb/blob/master/gdb/riscv-tdep.h)
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct RiscvCoreRegs<U> {
    /// General purpose registers (x0-x31)
    pub x: [U; 32],
    /// Program counter
    pub pc: U,
}

impl<U> Registers for RiscvCoreRegs<U>
where
    U: PrimInt + LeBytes + Default + core::fmt::Debug,
{
    type ProgramCounter = U;

    fn pc(&self) -> Self::ProgramCounter {
        self.pc
    }

    fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
        macro_rules! write_le_bytes {
            ($value:expr) => {
                let mut buf = [0; 16];
                // infallible (unless digit is a >128 bit number)
                let len = $value.to_le_bytes(&mut buf).unwrap();
                let buf = &buf[..len];
                for b in buf {
                    write_byte(Some(*b));
                }
            };
        }

        // Write GPRs
        for reg in self.x.iter() {
            write_le_bytes!(reg);
        }

        // Program Counter is regnum 33
        write_le_bytes!(&self.pc);
    }

    fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
        let ptrsize = core::mem::size_of::<U>();

        // ensure bytes.chunks_exact(ptrsize) won't panic
        if bytes.len() % ptrsize != 0 {
            return Err(());
        }

        let mut regs = bytes
            .chunks_exact(ptrsize)
            .map(|c| U::from_le_bytes(c).unwrap());

        // Read GPRs
        for reg in self.x.iter_mut() {
            *reg = regs.next().ok_or(())?
        }
        self.pc = regs.next().ok_or(())?;

        if regs.next().is_some() {
            return Err(());
        }

        Ok(())
    }
}