From 9c515d4208d46378430bb7818d884eb2c86f6caf Mon Sep 17 00:00:00 2001 From: starfleetcadet75 Date: Sat, 2 Jan 2021 18:04:33 -0500 Subject: [PATCH 1/7] Implement `RegId` for MIPS --- src/arch/mips/mod.rs | 25 ++---- src/arch/mips/reg/id.rs | 178 +++++++++++++++++++++++++++++++++++++- src/arch/mips/reg/mips.rs | 45 ++++++++++ src/arch/mips/reg/mod.rs | 2 - 4 files changed, 227 insertions(+), 23 deletions(-) diff --git a/src/arch/mips/mod.rs b/src/arch/mips/mod.rs index c13640d2..cf5a9bc7 100644 --- a/src/arch/mips/mod.rs +++ b/src/arch/mips/mod.rs @@ -1,42 +1,29 @@ //! Implementations for the MIPS architecture. use crate::arch::Arch; -use crate::arch::RegId; pub mod reg; /// Implements `Arch` for 32-bit MIPS. -/// -/// Check out the [module level docs](../index.html#whats-with-regidimpl) for -/// more info about the `RegIdImpl` type parameter. -pub enum Mips { - #[doc(hidden)] - _Marker(core::marker::PhantomData), -} +pub enum Mips {} /// Implements `Arch` for 64-bit MIPS. -/// -/// Check out the [module level docs](../index.html#whats-with-regidimpl) for -/// more info about the `RegIdImpl` type parameter. -pub enum Mips64 { - #[doc(hidden)] - _Marker(core::marker::PhantomData), -} +pub enum Mips64 {} -impl Arch for Mips { +impl Arch for Mips { type Usize = u32; type Registers = reg::MipsCoreRegs; - type RegId = RegIdImpl; + type RegId = reg::id::MipsRegId; fn target_description_xml() -> Option<&'static str> { Some(r#"mips"#) } } -impl Arch for Mips64 { +impl Arch for Mips64 { type Usize = u64; type Registers = reg::MipsCoreRegs; - type RegId = RegIdImpl; + type RegId = reg::id::Mips64RegId; fn target_description_xml() -> Option<&'static str> { Some(r#"mips64"#) diff --git a/src/arch/mips/reg/id.rs b/src/arch/mips/reg/id.rs index 85f7a53c..cab9a710 100644 --- a/src/arch/mips/reg/id.rs +++ b/src/arch/mips/reg/id.rs @@ -1,2 +1,176 @@ -// TODO: Add proper `RegId` implementation. See [issue #29](https://github.com/daniel5151/gdbstub/issues/29) -// pub enum MipsRegId {} +use crate::arch::RegId; + +/// 32-bit MIPS register identifier. +#[derive(Debug, Clone, Copy)] +#[non_exhaustive] +pub enum MipsRegId { + /// General purpose registers (R0-R31) + Gpr(u8), + /// Status register + Status, + /// Low register + Lo, + /// High register + Hi, + /// Bad Virtual Address register + Badvaddr, + /// Exception Cause register + Cause, + /// Program Counter + Pc, + /// Floating point registers (F0-F31) + Fpr(u8), + /// Floating-point Control Status register + Fcsr, + /// Floating-point Implementation Register + Fir, + /// High 1 register + Hi1, + /// Low 1 register + Lo1, + /// High 2 register + Hi2, + /// Low 2 register + Lo2, + /// High 3 register + Hi3, + /// Low 3 register + Lo3, + /// DSP Control register + Dspctl, + /// Restart register + Restart, +} + +/// 64-bit MIPS register identifier. +#[derive(Debug, Clone, Copy)] +#[non_exhaustive] +pub enum Mips64RegId { + /// General purpose registers (R0-R31) + Gpr(u8), + /// Status register + Status, + /// Low register + Lo, + /// High register + Hi, + /// Bad Virtual Address register + Badvaddr, + /// Exception Cause register + Cause, + /// Program Counter + Pc, + /// Floating point registers (F0-F31) + Fpr(u8), + /// Floating-point Control Status register + Fcsr, + /// Floating-point Implementation Register + Fir, + /// High 1 register + Hi1, + /// Low 1 register + Lo1, + /// High 2 register + Hi2, + /// Low 2 register + Lo2, + /// High 3 register + Hi3, + /// Low 3 register + Lo3, + /// DSP Control register + Dspctl, + /// Restart register + Restart, +} + +impl RegId for MipsRegId { + fn from_raw_id(id: usize) -> Option<(Self, usize)> { + let reg = match id { + 0..=31 => Self::Gpr(id as u8), + 32 => Self::Status, + 33 => Self::Lo, + 34 => Self::Hi, + 35 => Self::Badvaddr, + 36 => Self::Cause, + 37 => Self::Pc, + 38..=69 => Self::Fpr((id as u8) - 38), + 70 => Self::Fcsr, + 71 => Self::Fir, + 72 => Self::Hi1, + 73 => Self::Lo1, + 74 => Self::Hi2, + 75 => Self::Lo2, + 76 => Self::Hi3, + 77 => Self::Lo3, + 78 => Self::Dspctl, + 79 => Self::Restart, + _ => return None, + }; + Some((reg, 4)) + } +} + +impl RegId for Mips64RegId { + fn from_raw_id(id: usize) -> Option<(Self, usize)> { + let reg = match id { + 0..=31 => Self::Gpr(id as u8), + 32 => Self::Status, + 33 => Self::Lo, + 34 => Self::Hi, + 35 => Self::Badvaddr, + 36 => Self::Cause, + 37 => Self::Pc, + 38..=69 => Self::Fpr((id as u8) - 38), + 70 => Self::Fcsr, + 71 => Self::Fir, + 72 => Self::Hi1, + 73 => Self::Lo1, + 74 => Self::Hi2, + 75 => Self::Lo2, + 76 => Self::Hi3, + 77 => Self::Lo3, + 78 => Self::Dspctl, + 79 => Self::Restart, + _ => return None, + }; + Some((reg, 8)) + } +} + +#[cfg(test)] +mod tests { + use crate::arch::traits::RegId; + use crate::arch::traits::Registers; + + fn test() { + // Obtain the data length written by `gdb_serialize` by passing a custom closure. + let mut serialized_data_len = 0; + let counter = |b: Option| { + if b.is_some() { + serialized_data_len += 1; + } + }; + Rs::default().gdb_serialize(counter); + + // Accumulate register sizes returned by `from_raw_id`. + let mut i = 0; + let mut sum_reg_sizes = 0; + while let Some((_, size)) = RId::from_raw_id(i) { + sum_reg_sizes += size; + i += 1; + } + + assert_eq!(serialized_data_len, sum_reg_sizes); + } + + #[test] + fn test_mips32() { + test::, crate::arch::mips::reg::id::MipsRegId>() + } + + #[test] + fn test_mips64() { + test::, crate::arch::mips::reg::id::Mips64RegId>() + } +} diff --git a/src/arch/mips/reg/mips.rs b/src/arch/mips/reg/mips.rs index 5b328b06..e412ca25 100644 --- a/src/arch/mips/reg/mips.rs +++ b/src/arch/mips/reg/mips.rs @@ -22,6 +22,8 @@ pub struct MipsCoreRegs { pub cp0: MipsCp0Regs, /// FPU registers pub fpu: MipsFpuRegs, + /// DSP registers + pub dsp: MipsDspRegs, } /// MIPS CP0 (coprocessor 0) registers. @@ -50,6 +52,29 @@ pub struct MipsFpuRegs { pub fir: U, } +/// MIPS DSP registers. +/// +/// Source: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/mips-dsp.xml +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct MipsDspRegs { + /// High 1 register (regnum 72) + pub hi1: U, + /// Low 1 register (regnum 73) + pub lo1: U, + /// High 2 register (regnum 74) + pub hi2: U, + /// Low 2 register (regnum 75) + pub lo2: U, + /// High 3 register (regnum 76) + pub hi3: U, + /// Low 3 register (regnum 77) + pub lo3: U, + /// DSP Control register (regnum 78) + pub dspctl: U, + /// Restart register (regnum 79) + pub restart: U, +} + impl Registers for MipsCoreRegs where U: PrimInt + LeBytes + Default + core::fmt::Debug, @@ -94,6 +119,16 @@ where // Write FCSR and FIR registers write_le_bytes!(&self.fpu.fcsr); write_le_bytes!(&self.fpu.fir); + + // Write DSP registers + write_le_bytes!(&self.dsp.hi1); + write_le_bytes!(&self.dsp.lo1); + write_le_bytes!(&self.dsp.hi2); + write_le_bytes!(&self.dsp.lo2); + write_le_bytes!(&self.dsp.hi3); + write_le_bytes!(&self.dsp.lo3); + write_le_bytes!(&self.dsp.dspctl); + write_le_bytes!(&self.dsp.restart); } fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> { @@ -136,6 +171,16 @@ where self.fpu.fcsr = regs.next().ok_or(())?; self.fpu.fir = regs.next().ok_or(())?; + // Read DSP registers + self.dsp.hi1 = regs.next().ok_or(())?; + self.dsp.lo1 = regs.next().ok_or(())?; + self.dsp.hi2 = regs.next().ok_or(())?; + self.dsp.lo2 = regs.next().ok_or(())?; + self.dsp.hi3 = regs.next().ok_or(())?; + self.dsp.lo3 = regs.next().ok_or(())?; + self.dsp.dspctl = regs.next().ok_or(())?; + self.dsp.restart = regs.next().ok_or(())?; + if regs.next().is_some() { return Err(()); } diff --git a/src/arch/mips/reg/mod.rs b/src/arch/mips/reg/mod.rs index 5d0bc03c..e7cdef7d 100644 --- a/src/arch/mips/reg/mod.rs +++ b/src/arch/mips/reg/mod.rs @@ -6,5 +6,3 @@ pub mod id; mod mips; pub use mips::MipsCoreRegs; -pub use mips::MipsCp0Regs; -pub use mips::MipsFpuRegs; From 58f0605d99cc393e76b6d658be8c1079c5cd7132 Mon Sep 17 00:00:00 2001 From: starfleetcadet75 Date: Sat, 2 Jan 2021 18:28:33 -0500 Subject: [PATCH 2/7] Implement `RegId` for MSP430 --- src/arch/msp430/mod.rs | 13 ++------ src/arch/msp430/reg/id.rs | 69 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/arch/msp430/mod.rs b/src/arch/msp430/mod.rs index 7d9b2b66..a5fe773a 100644 --- a/src/arch/msp430/mod.rs +++ b/src/arch/msp430/mod.rs @@ -1,23 +1,16 @@ //! Implementations for the TI-MSP430 family of MCUs. use crate::arch::Arch; -use crate::arch::RegId; pub mod reg; /// Implements `Arch` for standard 16-bit TI-MSP430 MCUs. -/// -/// Check out the [module level docs](../index.html#whats-with-regidimpl) for -/// more info about the `RegIdImpl` type parameter. -pub enum Msp430 { - #[doc(hidden)] - _Marker(core::marker::PhantomData), -} +pub enum Msp430 {} -impl Arch for Msp430 { +impl Arch for Msp430 { type Usize = u32; type Registers = reg::Msp430Regs; - type RegId = RegIdImpl; + type RegId = reg::id::Msp430RegId; fn target_description_xml() -> Option<&'static str> { Some(r#"msp430"#) diff --git a/src/arch/msp430/reg/id.rs b/src/arch/msp430/reg/id.rs index 7ada07cd..698f0662 100644 --- a/src/arch/msp430/reg/id.rs +++ b/src/arch/msp430/reg/id.rs @@ -1,2 +1,67 @@ -// TODO: Add proper `RegId` implementation. See [issue #29](https://github.com/daniel5151/gdbstub/issues/29) -// pub enum Msp430RegId {} +use crate::arch::RegId; + +/// TI-MSP430 register identifier. +#[derive(Debug, Clone, Copy)] +#[non_exhaustive] +pub enum Msp430RegId { + /// Program Counter (R0) + Pc, + /// Stack Pointer (R1) + Sp, + /// Status Register (R2) + Sr, + /// Constant Generator (R3) + Cg, + /// General Purpose Registers (R4-R15) + Gpr(u8), +} + +impl RegId for Msp430RegId { + fn from_raw_id(id: usize) -> Option<(Self, usize)> { + let reg = match id { + 0 => Self::Pc, + 1 => Self::Sp, + 2 => Self::Sr, + 3 => Self::Cg, + 4..=15 => Self::Gpr(id as u8), + _ => return None, + }; + Some((reg, 2)) + } +} + +#[cfg(test)] +mod tests { + use crate::arch::traits::RegId; + use crate::arch::traits::Registers; + + fn test() { + // Obtain the data length written by `gdb_serialize` by passing a custom closure. + let mut serialized_data_len = 0; + let counter = |b: Option| { + if b.is_some() { + serialized_data_len += 1; + } + }; + Rs::default().gdb_serialize(counter); + + // The `Msp430Regs` implementation does not increment the size for + // the CG register since it will always be the constant zero. + serialized_data_len += 4; + + // Accumulate register sizes returned by `from_raw_id`. + let mut i = 0; + let mut sum_reg_sizes = 0; + while let Some((_, size)) = RId::from_raw_id(i) { + sum_reg_sizes += size; + i += 1; + } + + assert_eq!(serialized_data_len, sum_reg_sizes); + } + + #[test] + fn test_msp430() { + test::() + } +} From 3945ae927dbd0fcfdd07ef0a169cf5e41175774b Mon Sep 17 00:00:00 2001 From: starfleetcadet75 Date: Sat, 2 Jan 2021 19:19:47 -0500 Subject: [PATCH 3/7] Implement `RegId` for PPC --- src/arch/ppc/mod.rs | 13 ++----- src/arch/ppc/reg/id.rs | 87 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/arch/ppc/mod.rs b/src/arch/ppc/mod.rs index bdb9465a..79fb3a7f 100644 --- a/src/arch/ppc/mod.rs +++ b/src/arch/ppc/mod.rs @@ -1,23 +1,16 @@ //! Implementations for various PowerPC architectures. use crate::arch::Arch; -use crate::arch::RegId; pub mod reg; /// Implements `Arch` for 32-bit PowerPC + AltiVec SIMD. -/// -/// Check out the [module level docs](../index.html#whats-with-regidimpl) for -/// more info about the `RegIdImpl` type parameter. -pub enum PowerPcAltivec32 { - #[doc(hidden)] - _Marker(core::marker::PhantomData), -} +pub enum PowerPcAltivec32 {} -impl Arch for PowerPcAltivec32 { +impl Arch for PowerPcAltivec32 { type Usize = u32; type Registers = reg::PowerPcCommonRegs; - type RegId = RegIdImpl; + type RegId = reg::id::PowerPc32RegId; fn target_description_xml() -> Option<&'static str> { Some( diff --git a/src/arch/ppc/reg/id.rs b/src/arch/ppc/reg/id.rs index 97ccfea3..7efb564e 100644 --- a/src/arch/ppc/reg/id.rs +++ b/src/arch/ppc/reg/id.rs @@ -1,2 +1,85 @@ -// TODO: Add proper `RegId` implementation. See [issue #29](https://github.com/daniel5151/gdbstub/issues/29) -// pub enum PowerPc32RegId {} +use crate::arch::RegId; + +/// 32-bit PowerPC register identifier. +#[derive(Debug, Clone, Copy)] +#[non_exhaustive] +pub enum PowerPc32RegId { + /// General purpose registers (R0-R31) + Gpr(u8), + /// Floating point registers (F0-F31) + Fpr(u8), + /// Program Counter + Pc, + /// Machine state + Msr, + /// Condition register + Cr, + /// Link register + Lr, + /// Count register + Ctr, + /// Integer exception register + Xer, + /// Floating-point status and control register + Fpscr, + /// Vector registers + Vr(u8), + /// Vector status and control register + Vscr, + /// Vector context save register + Vrsave, +} + +impl RegId for PowerPc32RegId { + fn from_raw_id(id: usize) -> Option<(Self, usize)> { + let reg = match id { + 0..=31 => (Self::Gpr(id as u8), 4), + 32..=63 => (Self::Fpr((id as u8) - 32), 8), + 64 => (Self::Pc, 4), + 65 => (Self::Msr, 4), + 66 => (Self::Cr, 4), + 67 => (Self::Lr, 4), + 68 => (Self::Ctr, 4), + 69 => (Self::Xer, 4), + 70 => (Self::Fpscr, 4), + 71..=102 => (Self::Vr((id as u8) - 71), 16), + 103 => (Self::Vscr, 4), + 104 => (Self::Vrsave, 4), + _ => return None, + }; + + Some(reg) + } +} + +#[cfg(test)] +mod tests { + use crate::arch::traits::RegId; + use crate::arch::traits::Registers; + + fn test() { + // Obtain the data length written by `gdb_serialize` by passing a custom closure. + let mut serialized_data_len = 0; + let counter = |b: Option| { + if b.is_some() { + serialized_data_len += 1; + } + }; + Rs::default().gdb_serialize(counter); + + // Accumulate register sizes returned by `from_raw_id`. + let mut i = 0; + let mut sum_reg_sizes = 0; + while let Some((_, size)) = RId::from_raw_id(i) { + sum_reg_sizes += size; + i += 1; + } + + assert_eq!(serialized_data_len, sum_reg_sizes); + } + + #[test] + fn test_powerpc() { + test::() + } +} From eb4d82768951639175de05bd24a4cc019c1bdb8e Mon Sep 17 00:00:00 2001 From: starfleetcadet75 Date: Mon, 4 Jan 2021 17:45:57 -0500 Subject: [PATCH 4/7] Fix clippy warnings --- src/arch/mips/reg/id.rs | 3 ++- src/arch/msp430/reg/id.rs | 3 ++- src/arch/ppc/reg/id.rs | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/arch/mips/reg/id.rs b/src/arch/mips/reg/id.rs index cab9a710..7c60e724 100644 --- a/src/arch/mips/reg/id.rs +++ b/src/arch/mips/reg/id.rs @@ -144,7 +144,8 @@ mod tests { use crate::arch::traits::Registers; fn test() { - // Obtain the data length written by `gdb_serialize` by passing a custom closure. + // Obtain the data length written by `gdb_serialize` by passing a custom + // closure. let mut serialized_data_len = 0; let counter = |b: Option| { if b.is_some() { diff --git a/src/arch/msp430/reg/id.rs b/src/arch/msp430/reg/id.rs index 698f0662..411bbf58 100644 --- a/src/arch/msp430/reg/id.rs +++ b/src/arch/msp430/reg/id.rs @@ -36,7 +36,8 @@ mod tests { use crate::arch::traits::Registers; fn test() { - // Obtain the data length written by `gdb_serialize` by passing a custom closure. + // Obtain the data length written by `gdb_serialize` by passing a custom + // closure. let mut serialized_data_len = 0; let counter = |b: Option| { if b.is_some() { diff --git a/src/arch/ppc/reg/id.rs b/src/arch/ppc/reg/id.rs index 7efb564e..d38d219f 100644 --- a/src/arch/ppc/reg/id.rs +++ b/src/arch/ppc/reg/id.rs @@ -54,11 +54,13 @@ impl RegId for PowerPc32RegId { #[cfg(test)] mod tests { + use crate::arch::ppc::reg; use crate::arch::traits::RegId; use crate::arch::traits::Registers; fn test() { - // Obtain the data length written by `gdb_serialize` by passing a custom closure. + // Obtain the data length written by `gdb_serialize` by passing a custom + // closure. let mut serialized_data_len = 0; let counter = |b: Option| { if b.is_some() { @@ -80,6 +82,6 @@ mod tests { #[test] fn test_powerpc() { - test::() + test::() } } From 085b779ec5543fdd96dfebcef247c23ea124d454 Mon Sep 17 00:00:00 2001 From: starfleetcadet75 Date: Sat, 9 Jan 2021 15:15:09 -0500 Subject: [PATCH 5/7] Requested changes for Mips/Msp430 --- src/arch/mips/mod.rs | 58 +++++++++++++++-- src/arch/mips/reg/id.rs | 132 ++++++++++++-------------------------- src/arch/mips/reg/mips.rs | 114 +++++++++++++++++++++++++------- src/arch/mips/reg/mod.rs | 1 + src/arch/msp430/mod.rs | 13 +++- src/arch/msp430/reg/id.rs | 5 +- src/arch/ppc/mod.rs | 13 +++- src/arch/ppc/reg/id.rs | 89 +------------------------ 8 files changed, 212 insertions(+), 213 deletions(-) diff --git a/src/arch/mips/mod.rs b/src/arch/mips/mod.rs index cf5a9bc7..35df1334 100644 --- a/src/arch/mips/mod.rs +++ b/src/arch/mips/mod.rs @@ -1,31 +1,77 @@ //! Implementations for the MIPS architecture. use crate::arch::Arch; +use crate::arch::RegId; pub mod reg; /// Implements `Arch` for 32-bit MIPS. -pub enum Mips {} +/// +/// Check out the [module level docs](../index.html#whats-with-regidimpl) for +/// more info about the `RegIdImpl` type parameter. +pub enum Mips> { + #[doc(hidden)] + _Marker(core::marker::PhantomData), +} /// Implements `Arch` for 64-bit MIPS. -pub enum Mips64 {} +pub enum Mips64> { + #[doc(hidden)] + _Marker(core::marker::PhantomData), +} -impl Arch for Mips { +/// Implements `Arch` for 32-bit MIPS with the DSP feature enabled. +pub enum MipsWithDsp> { + #[doc(hidden)] + _Marker(core::marker::PhantomData), +} + +/// Implements `Arch` for 64-bit MIPS with the DSP feature enabled. +pub enum Mips64WithDsp> { + #[doc(hidden)] + _Marker(core::marker::PhantomData), +} + +impl Arch for Mips { type Usize = u32; type Registers = reg::MipsCoreRegs; - type RegId = reg::id::MipsRegId; + type RegId = RegIdImpl; fn target_description_xml() -> Option<&'static str> { Some(r#"mips"#) } } -impl Arch for Mips64 { +impl Arch for Mips64 { type Usize = u64; type Registers = reg::MipsCoreRegs; - type RegId = reg::id::Mips64RegId; + type RegId = RegIdImpl; fn target_description_xml() -> Option<&'static str> { Some(r#"mips64"#) } } + +impl Arch for MipsWithDsp { + type Usize = u32; + type Registers = reg::MipsCoreRegsWithDsp; + type RegId = RegIdImpl; + + fn target_description_xml() -> Option<&'static str> { + Some( + r#"mips"#, + ) + } +} + +impl Arch for Mips64WithDsp { + type Usize = u64; + type Registers = reg::MipsCoreRegsWithDsp; + type RegId = RegIdImpl; + + fn target_description_xml() -> Option<&'static str> { + Some( + r#"mips64"#, + ) + } +} diff --git a/src/arch/mips/reg/id.rs b/src/arch/mips/reg/id.rs index 7c60e724..424cb299 100644 --- a/src/arch/mips/reg/id.rs +++ b/src/arch/mips/reg/id.rs @@ -1,9 +1,9 @@ use crate::arch::RegId; -/// 32-bit MIPS register identifier. +/// MIPS register identifier. #[derive(Debug, Clone, Copy)] #[non_exhaustive] -pub enum MipsRegId { +pub enum MipsRegId { /// General purpose registers (R0-R31) Gpr(u8), /// Status register @@ -40,101 +40,47 @@ pub enum MipsRegId { Dspctl, /// Restart register Restart, + #[doc(hidden)] + _Size(U), } -/// 64-bit MIPS register identifier. -#[derive(Debug, Clone, Copy)] -#[non_exhaustive] -pub enum Mips64RegId { - /// General purpose registers (R0-R31) - Gpr(u8), - /// Status register - Status, - /// Low register - Lo, - /// High register - Hi, - /// Bad Virtual Address register - Badvaddr, - /// Exception Cause register - Cause, - /// Program Counter - Pc, - /// Floating point registers (F0-F31) - Fpr(u8), - /// Floating-point Control Status register - Fcsr, - /// Floating-point Implementation Register - Fir, - /// High 1 register - Hi1, - /// Low 1 register - Lo1, - /// High 2 register - Hi2, - /// Low 2 register - Lo2, - /// High 3 register - Hi3, - /// Low 3 register - Lo3, - /// DSP Control register - Dspctl, - /// Restart register - Restart, +fn from_raw_id(id: usize) -> Option<(MipsRegId, usize)> { + let reg = match id { + 0..=31 => MipsRegId::Gpr(id as u8), + 32 => MipsRegId::Status, + 33 => MipsRegId::Lo, + 34 => MipsRegId::Hi, + 35 => MipsRegId::Badvaddr, + 36 => MipsRegId::Cause, + 37 => MipsRegId::Pc, + 38..=69 => MipsRegId::Fpr((id as u8) - 38), + 70 => MipsRegId::Fcsr, + 71 => MipsRegId::Fir, + 72 => MipsRegId::Hi1, + 73 => MipsRegId::Lo1, + 74 => MipsRegId::Hi2, + 75 => MipsRegId::Lo2, + 76 => MipsRegId::Hi3, + 77 => MipsRegId::Lo3, + // `MipsRegId::Dspctl` is the only register that will always be 4 bytes wide + 78 => return Some((MipsRegId::Dspctl, 4)), + 79 => MipsRegId::Restart, + _ => return None, + }; + + let ptrsize = core::mem::size_of::(); + Some((reg, ptrsize)) } -impl RegId for MipsRegId { +impl RegId for MipsRegId { fn from_raw_id(id: usize) -> Option<(Self, usize)> { - let reg = match id { - 0..=31 => Self::Gpr(id as u8), - 32 => Self::Status, - 33 => Self::Lo, - 34 => Self::Hi, - 35 => Self::Badvaddr, - 36 => Self::Cause, - 37 => Self::Pc, - 38..=69 => Self::Fpr((id as u8) - 38), - 70 => Self::Fcsr, - 71 => Self::Fir, - 72 => Self::Hi1, - 73 => Self::Lo1, - 74 => Self::Hi2, - 75 => Self::Lo2, - 76 => Self::Hi3, - 77 => Self::Lo3, - 78 => Self::Dspctl, - 79 => Self::Restart, - _ => return None, - }; - Some((reg, 4)) + from_raw_id::(id) } } -impl RegId for Mips64RegId { +impl RegId for MipsRegId { fn from_raw_id(id: usize) -> Option<(Self, usize)> { - let reg = match id { - 0..=31 => Self::Gpr(id as u8), - 32 => Self::Status, - 33 => Self::Lo, - 34 => Self::Hi, - 35 => Self::Badvaddr, - 36 => Self::Cause, - 37 => Self::Pc, - 38..=69 => Self::Fpr((id as u8) - 38), - 70 => Self::Fcsr, - 71 => Self::Fir, - 72 => Self::Hi1, - 73 => Self::Lo1, - 74 => Self::Hi2, - 75 => Self::Lo2, - 76 => Self::Hi3, - 77 => Self::Lo3, - 78 => Self::Dspctl, - 79 => Self::Restart, - _ => return None, - }; - Some((reg, 8)) + from_raw_id::(id) } } @@ -167,11 +113,17 @@ mod tests { #[test] fn test_mips32() { - test::, crate::arch::mips::reg::id::MipsRegId>() + test::< + crate::arch::mips::reg::MipsCoreRegsWithDsp, + crate::arch::mips::reg::id::MipsRegId, + >() } #[test] fn test_mips64() { - test::, crate::arch::mips::reg::id::Mips64RegId>() + test::< + crate::arch::mips::reg::MipsCoreRegsWithDsp, + crate::arch::mips::reg::id::MipsRegId, + >() } } diff --git a/src/arch/mips/reg/mips.rs b/src/arch/mips/reg/mips.rs index e412ca25..b79a674e 100644 --- a/src/arch/mips/reg/mips.rs +++ b/src/arch/mips/reg/mips.rs @@ -1,5 +1,6 @@ use crate::arch::Registers; use crate::internal::LeBytes; +use std::convert::TryInto; use num_traits::PrimInt; @@ -10,7 +11,7 @@ use num_traits::PrimInt; /// Source: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/mips-cpu.xml #[derive(Debug, Default, Clone, Eq, PartialEq)] pub struct MipsCoreRegs { - /// General purpose registers (R0-R32) + /// General purpose registers (R0-R31) pub r: [U; 32], /// Low register (regnum 33) pub lo: U, @@ -22,8 +23,6 @@ pub struct MipsCoreRegs { pub cp0: MipsCp0Regs, /// FPU registers pub fpu: MipsFpuRegs, - /// DSP registers - pub dsp: MipsDspRegs, } /// MIPS CP0 (coprocessor 0) registers. @@ -44,7 +43,7 @@ pub struct MipsCp0Regs { /// Source: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/mips-fpu.xml #[derive(Debug, Default, Clone, Eq, PartialEq)] pub struct MipsFpuRegs { - /// FP registers (F0-F32) starting at regnum 38 + /// FP registers (F0-F31) starting at regnum 38 pub r: [U; 32], /// Floating-point Control Status register pub fcsr: U, @@ -70,11 +69,24 @@ pub struct MipsDspRegs { /// Low 3 register (regnum 77) pub lo3: U, /// DSP Control register (regnum 78) - pub dspctl: U, + /// Note: This register will always be 32-bit regardless of the target + /// https://sourceware.org/gdb/current/onlinedocs/gdb/MIPS-Features.html#MIPS-Features + pub dspctl: u32, /// Restart register (regnum 79) pub restart: U, } +/// MIPS core and DSP registers. +/// +/// Source: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/mips-dsp-linux.xml +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct MipsCoreRegsWithDsp { + /// Core registers + pub core: MipsCoreRegs, + /// DSP registers + pub dsp: MipsDspRegs, +} + impl Registers for MipsCoreRegs where U: PrimInt + LeBytes + Default + core::fmt::Debug, @@ -119,26 +131,17 @@ where // Write FCSR and FIR registers write_le_bytes!(&self.fpu.fcsr); write_le_bytes!(&self.fpu.fir); - - // Write DSP registers - write_le_bytes!(&self.dsp.hi1); - write_le_bytes!(&self.dsp.lo1); - write_le_bytes!(&self.dsp.hi2); - write_le_bytes!(&self.dsp.lo2); - write_le_bytes!(&self.dsp.hi3); - write_le_bytes!(&self.dsp.lo3); - write_le_bytes!(&self.dsp.dspctl); - write_le_bytes!(&self.dsp.restart); } 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 { + // Ensure bytes contains enough data for all 72 registers + if bytes.len() < ptrsize * 72 { return Err(()); } + // All core registers are the same size let mut regs = bytes .chunks_exact(ptrsize) .map(|c| U::from_le_bytes(c).unwrap()); @@ -171,19 +174,84 @@ where self.fpu.fcsr = regs.next().ok_or(())?; self.fpu.fir = regs.next().ok_or(())?; - // Read DSP registers + Ok(()) + } +} + +impl Registers for MipsCoreRegsWithDsp +where + U: PrimInt + LeBytes + Default + core::fmt::Debug, +{ + 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)); + } + }; + } + + // Serialize the core registers first + self.core.gdb_serialize(&mut write_byte); + + // Write the DSP registers + write_le_bytes!(&self.dsp.hi1); + write_le_bytes!(&self.dsp.lo1); + write_le_bytes!(&self.dsp.hi2); + write_le_bytes!(&self.dsp.lo2); + write_le_bytes!(&self.dsp.hi3); + write_le_bytes!(&self.dsp.lo3); + + for b in &self.dsp.dspctl.to_le_bytes() { + write_byte(Some(*b)); + } + + write_le_bytes!(&self.dsp.restart); + } + + fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> { + // Deserialize the core registers first + self.core.gdb_deserialize(bytes)?; + + // Ensure bytes contains enough data for all 79 registers of target-width + // and the dspctl register which is always 4 bytes + let ptrsize = core::mem::size_of::(); + if bytes.len() < (ptrsize * 79) + 4 { + return Err(()); + } + + // Calculate the offsets to the DSP registers based on the ptrsize + let dspregs_start = ptrsize * 72; + let dspctl_start = ptrsize * 78; + + // Read up until the dspctl register + let mut regs = bytes[dspregs_start..dspctl_start] + .chunks_exact(ptrsize) + .map(|c| U::from_le_bytes(c).unwrap()); + self.dsp.hi1 = regs.next().ok_or(())?; self.dsp.lo1 = regs.next().ok_or(())?; self.dsp.hi2 = regs.next().ok_or(())?; self.dsp.lo2 = regs.next().ok_or(())?; self.dsp.hi3 = regs.next().ok_or(())?; self.dsp.lo3 = regs.next().ok_or(())?; - self.dsp.dspctl = regs.next().ok_or(())?; - self.dsp.restart = regs.next().ok_or(())?; - if regs.next().is_some() { - return Err(()); - } + // Dspctl will always be a u32 + self.dsp.dspctl = + u32::from_le_bytes(bytes[dspctl_start..dspctl_start + 4].try_into().unwrap()); + + // Only 4 or 8 bytes should remain to be read + self.dsp.restart = U::from_le_bytes( + bytes[dspctl_start + 4..] + .chunks_exact(ptrsize) + .next() + .ok_or(())?, + ) + .unwrap(); Ok(()) } diff --git a/src/arch/mips/reg/mod.rs b/src/arch/mips/reg/mod.rs index e7cdef7d..b101e4c5 100644 --- a/src/arch/mips/reg/mod.rs +++ b/src/arch/mips/reg/mod.rs @@ -6,3 +6,4 @@ pub mod id; mod mips; pub use mips::MipsCoreRegs; +pub use mips::MipsCoreRegsWithDsp; diff --git a/src/arch/msp430/mod.rs b/src/arch/msp430/mod.rs index a5fe773a..9baf44dd 100644 --- a/src/arch/msp430/mod.rs +++ b/src/arch/msp430/mod.rs @@ -1,16 +1,23 @@ //! Implementations for the TI-MSP430 family of MCUs. use crate::arch::Arch; +use crate::arch::RegId; pub mod reg; /// Implements `Arch` for standard 16-bit TI-MSP430 MCUs. -pub enum Msp430 {} +/// +/// Check out the [module level docs](../index.html#whats-with-regidimpl) for +/// more info about the `RegIdImpl` type parameter. +pub enum Msp430 { + #[doc(hidden)] + _Marker(core::marker::PhantomData), +} -impl Arch for Msp430 { +impl Arch for Msp430 { type Usize = u32; type Registers = reg::Msp430Regs; - type RegId = reg::id::Msp430RegId; + type RegId = RegIdImpl; fn target_description_xml() -> Option<&'static str> { Some(r#"msp430"#) diff --git a/src/arch/msp430/reg/id.rs b/src/arch/msp430/reg/id.rs index 411bbf58..eec70620 100644 --- a/src/arch/msp430/reg/id.rs +++ b/src/arch/msp430/reg/id.rs @@ -1,6 +1,9 @@ use crate::arch::RegId; /// TI-MSP430 register identifier. +/// +/// GDB does not provide a XML file for the MSP430. +/// The best file to reference is [msp430-tdep.c](https://github.com/bminor/binutils-gdb/blob/master/gdb/msp430-tdep.c). #[derive(Debug, Clone, Copy)] #[non_exhaustive] pub enum Msp430RegId { @@ -23,7 +26,7 @@ impl RegId for Msp430RegId { 1 => Self::Sp, 2 => Self::Sr, 3 => Self::Cg, - 4..=15 => Self::Gpr(id as u8), + 4..=15 => Self::Gpr((id as u8) - 4), _ => return None, }; Some((reg, 2)) diff --git a/src/arch/ppc/mod.rs b/src/arch/ppc/mod.rs index 79fb3a7f..bdb9465a 100644 --- a/src/arch/ppc/mod.rs +++ b/src/arch/ppc/mod.rs @@ -1,16 +1,23 @@ //! Implementations for various PowerPC architectures. use crate::arch::Arch; +use crate::arch::RegId; pub mod reg; /// Implements `Arch` for 32-bit PowerPC + AltiVec SIMD. -pub enum PowerPcAltivec32 {} +/// +/// Check out the [module level docs](../index.html#whats-with-regidimpl) for +/// more info about the `RegIdImpl` type parameter. +pub enum PowerPcAltivec32 { + #[doc(hidden)] + _Marker(core::marker::PhantomData), +} -impl Arch for PowerPcAltivec32 { +impl Arch for PowerPcAltivec32 { type Usize = u32; type Registers = reg::PowerPcCommonRegs; - type RegId = reg::id::PowerPc32RegId; + type RegId = RegIdImpl; fn target_description_xml() -> Option<&'static str> { Some( diff --git a/src/arch/ppc/reg/id.rs b/src/arch/ppc/reg/id.rs index d38d219f..97ccfea3 100644 --- a/src/arch/ppc/reg/id.rs +++ b/src/arch/ppc/reg/id.rs @@ -1,87 +1,2 @@ -use crate::arch::RegId; - -/// 32-bit PowerPC register identifier. -#[derive(Debug, Clone, Copy)] -#[non_exhaustive] -pub enum PowerPc32RegId { - /// General purpose registers (R0-R31) - Gpr(u8), - /// Floating point registers (F0-F31) - Fpr(u8), - /// Program Counter - Pc, - /// Machine state - Msr, - /// Condition register - Cr, - /// Link register - Lr, - /// Count register - Ctr, - /// Integer exception register - Xer, - /// Floating-point status and control register - Fpscr, - /// Vector registers - Vr(u8), - /// Vector status and control register - Vscr, - /// Vector context save register - Vrsave, -} - -impl RegId for PowerPc32RegId { - fn from_raw_id(id: usize) -> Option<(Self, usize)> { - let reg = match id { - 0..=31 => (Self::Gpr(id as u8), 4), - 32..=63 => (Self::Fpr((id as u8) - 32), 8), - 64 => (Self::Pc, 4), - 65 => (Self::Msr, 4), - 66 => (Self::Cr, 4), - 67 => (Self::Lr, 4), - 68 => (Self::Ctr, 4), - 69 => (Self::Xer, 4), - 70 => (Self::Fpscr, 4), - 71..=102 => (Self::Vr((id as u8) - 71), 16), - 103 => (Self::Vscr, 4), - 104 => (Self::Vrsave, 4), - _ => return None, - }; - - Some(reg) - } -} - -#[cfg(test)] -mod tests { - use crate::arch::ppc::reg; - use crate::arch::traits::RegId; - use crate::arch::traits::Registers; - - fn test() { - // Obtain the data length written by `gdb_serialize` by passing a custom - // closure. - let mut serialized_data_len = 0; - let counter = |b: Option| { - if b.is_some() { - serialized_data_len += 1; - } - }; - Rs::default().gdb_serialize(counter); - - // Accumulate register sizes returned by `from_raw_id`. - let mut i = 0; - let mut sum_reg_sizes = 0; - while let Some((_, size)) = RId::from_raw_id(i) { - sum_reg_sizes += size; - i += 1; - } - - assert_eq!(serialized_data_len, sum_reg_sizes); - } - - #[test] - fn test_powerpc() { - test::() - } -} +// TODO: Add proper `RegId` implementation. See [issue #29](https://github.com/daniel5151/gdbstub/issues/29) +// pub enum PowerPc32RegId {} From bd376188954e44a930a86ced24b74ae86f5b0ed7 Mon Sep 17 00:00:00 2001 From: starfleetcadet75 Date: Sat, 9 Jan 2021 15:25:12 -0500 Subject: [PATCH 6/7] use non-std version of TryInto --- src/arch/mips/reg/mips.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/mips/reg/mips.rs b/src/arch/mips/reg/mips.rs index b79a674e..d6738462 100644 --- a/src/arch/mips/reg/mips.rs +++ b/src/arch/mips/reg/mips.rs @@ -1,6 +1,6 @@ use crate::arch::Registers; use crate::internal::LeBytes; -use std::convert::TryInto; +use core::convert::TryInto; use num_traits::PrimInt; From 427b9067b4bb09b5753dfde822dc82e79c4269df Mon Sep 17 00:00:00 2001 From: starfleetcadet75 Date: Sat, 9 Jan 2021 17:50:08 -0500 Subject: [PATCH 7/7] Small changes for Mips --- src/arch/mips/mod.rs | 21 +++++++++------------ src/arch/mips/reg/mips.rs | 5 +++-- src/arch/mips/reg/mod.rs | 2 ++ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/arch/mips/mod.rs b/src/arch/mips/mod.rs index 35df1334..2bd8362d 100644 --- a/src/arch/mips/mod.rs +++ b/src/arch/mips/mod.rs @@ -15,22 +15,19 @@ pub enum Mips> { } /// Implements `Arch` for 64-bit MIPS. +/// +/// Check out the [module level docs](../index.html#whats-with-regidimpl) for +/// more info about the `RegIdImpl` type parameter. pub enum Mips64> { #[doc(hidden)] _Marker(core::marker::PhantomData), } /// Implements `Arch` for 32-bit MIPS with the DSP feature enabled. -pub enum MipsWithDsp> { - #[doc(hidden)] - _Marker(core::marker::PhantomData), -} +pub enum MipsWithDsp {} /// Implements `Arch` for 64-bit MIPS with the DSP feature enabled. -pub enum Mips64WithDsp> { - #[doc(hidden)] - _Marker(core::marker::PhantomData), -} +pub enum Mips64WithDsp {} impl Arch for Mips { type Usize = u32; @@ -52,10 +49,10 @@ impl Arch for Mips64 { } } -impl Arch for MipsWithDsp { +impl Arch for MipsWithDsp { type Usize = u32; type Registers = reg::MipsCoreRegsWithDsp; - type RegId = RegIdImpl; + type RegId = reg::id::MipsRegId; fn target_description_xml() -> Option<&'static str> { Some( @@ -64,10 +61,10 @@ impl Arch for MipsWithDsp { } } -impl Arch for Mips64WithDsp { +impl Arch for Mips64WithDsp { type Usize = u64; type Registers = reg::MipsCoreRegsWithDsp; - type RegId = RegIdImpl; + type RegId = reg::id::MipsRegId; fn target_description_xml() -> Option<&'static str> { Some( diff --git a/src/arch/mips/reg/mips.rs b/src/arch/mips/reg/mips.rs index d6738462..6d86b439 100644 --- a/src/arch/mips/reg/mips.rs +++ b/src/arch/mips/reg/mips.rs @@ -1,9 +1,10 @@ -use crate::arch::Registers; -use crate::internal::LeBytes; use core::convert::TryInto; use num_traits::PrimInt; +use crate::arch::Registers; +use crate::internal::LeBytes; + /// MIPS registers. /// /// The register width is set to `u32` or `u64` based on the `` type. diff --git a/src/arch/mips/reg/mod.rs b/src/arch/mips/reg/mod.rs index b101e4c5..3cafbd19 100644 --- a/src/arch/mips/reg/mod.rs +++ b/src/arch/mips/reg/mod.rs @@ -7,3 +7,5 @@ mod mips; pub use mips::MipsCoreRegs; pub use mips::MipsCoreRegsWithDsp; +pub use mips::MipsCp0Regs; +pub use mips::MipsFpuRegs;