1 use super::PpcVector; 2 use core::convert::TryInto; 3 use gdbstub::arch::Registers; 4 5 /// 32-bit PowerPC core registers, FPU registers, and AltiVec SIMD registers. 6 /// 7 /// Sources: 8 /// * <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/rs6000/powerpc-altivec32.xml> 9 /// * <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/rs6000/power-core.xml> 10 /// * <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/rs6000/power-fpu.xml> 11 /// * <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/rs6000/power-altivec.xml> 12 #[derive(Debug, Default, Clone, PartialEq)] 13 pub struct PowerPcCommonRegs { 14 /// General purpose registers 15 pub r: [u32; 32], 16 /// Floating Point registers 17 pub f: [f64; 32], 18 /// Program counter 19 pub pc: u32, 20 /// Machine state 21 pub msr: u32, 22 /// Condition register 23 pub cr: u32, 24 /// Link register 25 pub lr: u32, 26 /// Count register 27 pub ctr: u32, 28 /// Integer exception register 29 pub xer: u32, 30 /// Floating-point status and control register 31 pub fpscr: u32, 32 /// Vector registers 33 pub vr: [PpcVector; 32], 34 /// Vector status and control register 35 pub vscr: u32, 36 /// Vector context save register 37 pub vrsave: u32, 38 } 39 40 impl Registers for PowerPcCommonRegs { 41 type ProgramCounter = u32; 42 pc(&self) -> Self::ProgramCounter43 fn pc(&self) -> Self::ProgramCounter { 44 self.pc 45 } 46 gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>))47 fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) { 48 macro_rules! write_bytes { 49 ($bytes:expr) => { 50 for b in $bytes { 51 write_byte(Some(*b)) 52 } 53 }; 54 } 55 56 macro_rules! write_regs { 57 ($($reg:ident),*) => { 58 $( 59 write_bytes!(&self.$reg.to_be_bytes()); 60 )* 61 } 62 } 63 64 for reg in &self.r { 65 write_bytes!(®.to_be_bytes()); 66 } 67 68 for reg in &self.f { 69 write_bytes!(®.to_be_bytes()); 70 } 71 72 write_regs!(pc, msr, cr, lr, ctr, xer, fpscr); 73 74 for ® in &self.vr { 75 let reg: u128 = reg; 76 write_bytes!(®.to_be_bytes()); 77 } 78 79 write_regs!(vscr, vrsave); 80 } 81 gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()>82 fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> { 83 if bytes.len() < 0x3a4 { 84 return Err(()); 85 } 86 87 let mut regs = bytes[0..0x80] 88 .chunks_exact(4) 89 .map(|x| u32::from_be_bytes(x.try_into().unwrap())); 90 91 for reg in &mut self.r { 92 *reg = regs.next().ok_or(())?; 93 } 94 95 let mut regs = bytes[0x80..0x180] 96 .chunks_exact(8) 97 .map(|x| f64::from_be_bytes(x.try_into().unwrap())); 98 99 for reg in &mut self.f { 100 *reg = regs.next().ok_or(())?; 101 } 102 103 macro_rules! parse_regs { 104 ($start:literal..$end:literal, $($reg:ident),*) => { 105 let mut regs = bytes[$start..$end] 106 .chunks_exact(4) 107 .map(|x| u32::from_be_bytes(x.try_into().unwrap())); 108 $( 109 self.$reg = regs.next().ok_or(())?; 110 )* 111 } 112 } 113 114 parse_regs!(0x180..0x19c, pc, msr, cr, lr, ctr, xer, fpscr); 115 116 let mut regs = bytes[0x19c..0x39c] 117 .chunks_exact(0x10) 118 .map(|x| u128::from_be_bytes(x.try_into().unwrap())); 119 120 for reg in &mut self.vr { 121 *reg = regs.next().ok_or(())?; 122 } 123 124 parse_regs!(0x39c..0x3a4, vscr, vrsave); 125 126 Ok(()) 127 } 128 } 129 130 #[cfg(test)] 131 mod tests { 132 use super::*; 133 134 #[test] ppc_core_round_trip()135 fn ppc_core_round_trip() { 136 let regs_before = PowerPcCommonRegs { 137 r: [1; 32], 138 pc: 2, 139 msr: 3, 140 cr: 4, 141 lr: 5, 142 ctr: 6, 143 xer: 7, 144 fpscr: 8, 145 f: [9.0; 32], 146 vr: [52; 32], 147 vrsave: 10, 148 vscr: 11, 149 }; 150 151 let mut data = vec![]; 152 153 regs_before.gdb_serialize(|x| { 154 data.push(x.unwrap_or(b'x')); 155 }); 156 157 assert_eq!(data.len(), 0x3a4); 158 159 let mut regs_after = PowerPcCommonRegs::default(); 160 regs_after.gdb_deserialize(&data).unwrap(); 161 162 assert_eq!(regs_before, regs_after); 163 } 164 } 165