Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add (partial) support for RISC-V #21

Merged
merged 2 commits into from Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/arch/mod.rs
Expand Up @@ -12,6 +12,7 @@
pub mod arm;
pub mod mips;
pub mod msp430;
pub mod riscv;
mod traits;
pub mod x86;

Expand Down
33 changes: 33 additions & 0 deletions 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<u32>;

fn target_description_xml() -> Option<&'static str> {
Some(r#"<target version="1.0"><architecture>riscv</architecture></target>"#)
}
}

impl Arch for Riscv64 {
type Usize = u64;
type Registers = reg::RiscvCoreRegs<u64>;

fn target_description_xml() -> Option<&'static str> {
Some(r#"<target version="1.0"><architecture>riscv64</architecture></target>"#)
}
}
5 changes: 5 additions & 0 deletions src/arch/riscv/reg/mod.rs
@@ -0,0 +1,5 @@
//! `GdbRegister` structs for RISC-V architectures.

mod riscv;

pub use riscv::RiscvCoreRegs;
70 changes: 70 additions & 0 deletions 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 `<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(Default)]
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,
{
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(())
daniel5151 marked this conversation as resolved.
Show resolved Hide resolved
}
}