diff --git a/src/arch/mod.rs b/src/arch/mod.rs index edbd9e5f..8d9e972f 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -12,6 +12,7 @@ pub mod arm; pub mod mips; pub mod msp430; +pub mod riscv; mod traits; pub mod x86; diff --git a/src/arch/riscv/mod.rs b/src/arch/riscv/mod.rs new file mode 100644 index 00000000..a5a4f780 --- /dev/null +++ b/src/arch/riscv/mod.rs @@ -0,0 +1,33 @@ +//! Support for the [RISC-V](https://riscv.org/) architecture. +//! +//! *Note*: currently only supports integer versions of the ISA. + +use crate::arch::Arch; + +pub mod reg; + +/// Implements `Arch` for 32-bit RISC-V. +#[derive(Eq, PartialEq)] +pub struct Riscv32; + +/// Implements `Arch` for 64-bit RISC-V. +#[derive(Eq, PartialEq)] +pub struct Riscv64; + +impl Arch for Riscv32 { + type Usize = u32; + type Registers = reg::RiscvCoreRegs; + + fn target_description_xml() -> Option<&'static str> { + Some(r#"riscv"#) + } +} + +impl Arch for Riscv64 { + type Usize = u64; + type Registers = reg::RiscvCoreRegs; + + fn target_description_xml() -> Option<&'static str> { + Some(r#"riscv64"#) + } +} diff --git a/src/arch/riscv/reg/mod.rs b/src/arch/riscv/reg/mod.rs new file mode 100644 index 00000000..1ba7c5fd --- /dev/null +++ b/src/arch/riscv/reg/mod.rs @@ -0,0 +1,5 @@ +//! `GdbRegister` structs for RISC-V architectures. + +mod riscv; + +pub use riscv::RiscvCoreRegs; diff --git a/src/arch/riscv/reg/riscv.rs b/src/arch/riscv/reg/riscv.rs new file mode 100644 index 00000000..b20b8d77 --- /dev/null +++ b/src/arch/riscv/reg/riscv.rs @@ -0,0 +1,70 @@ +use crate::arch::Registers; +use crate::internal::LeBytes; +use num_traits::PrimInt; + +/// RISC-V Integer registers. +/// +/// The register width is set to `u32` or `u64` based on the `` 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(Default)] +pub struct RiscvCoreRegs { + /// General purpose registers (x0-x31) + pub x: [U; 32], + /// Program counter + pub pc: U, +} + +impl Registers for RiscvCoreRegs +where + U: PrimInt + LeBytes + Default, +{ + fn gdb_serialize(&self, mut write_byte: impl FnMut(Option)) { + 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::(); + + // 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(()) + } +}