metaemu_arch_additional/c166/
observers.rs1use std::marker::PhantomData;
12
13use fugue::{ir::{il::pcode::{Register, Operand}, Address, PCode}, bytes::Order};
14use metaemu::{state::{pcode::PCodeState, AsState, StateOps}, concrete::hooks::{HookConcrete, ClonableHookConcrete}, hooks::HookAction};
15use metaemu::hooks::types::{HookStepAction, HookOutcome, Error as HookError};
16use metaemu::state::pcode::Error as PCodeError;
17use thiserror::Error;
18use ux::u24;
19
20const GPR_RANGE: usize = 0x20; #[derive(Debug, Error)]
23pub enum Error {
24 #[error("cannot obtain reference to context pointer (CP)")]
25 ContextMissing,
26 #[error("cannot read from context pointer: {0}")]
27 ContextRead(PCodeError),
28 #[error("register `{}` is not a GPR register", _0.name())]
29 InvalidOperand(Register),
30}
31
32#[derive(Debug, Clone)]
34pub struct RegisterMapper<O, ErrorType> {
35 cp: Register,
36 cp_default: u16,
37 ones: Register,
38 zeros: Register,
39 marker: PhantomData<O>,
40 error_type: PhantomData<ErrorType>,
41}
42
43impl<O, ErrorType> RegisterMapper<O, ErrorType>
44where
45 O: Order,
46 ErrorType: std::error::Error + Send + Sync + 'static + Clone,
47{
48 pub fn new_with(
49 state: &PCodeState<u8, O>,
50 default: u16,
51 ) -> Result<Self, Error> {
52 Ok(Self {
53 cp: state.registers().register_by_name("CP").unwrap().clone(),
54 cp_default: default.into(),
55 ones: state.registers().register_by_name("ONES").unwrap().clone(),
56 zeros: state.registers().register_by_name("ZEROS").unwrap().clone(),
57 marker: PhantomData,
58 error_type: PhantomData,
59 })
60 }
61
62 pub fn new(state: &PCodeState<u8, O>) -> Result<Self, Error> {
63 Self::new_with(state, 0xFC00u16) }
65
66 pub fn is_gpr(&self, operand: &Register) -> bool {
67 let cp = u64::from(self.cp_default);
68 let offset = operand.offset();
69 let size = operand.size() as u64;
70
71 offset >= cp && offset + size < cp + GPR_RANGE as u64
72 }
73
74 pub fn is_one(&self, operand: &Register) -> bool {
75 *operand == self.ones
76 }
77
78 pub fn is_zero(&self, operand: &Register) -> bool {
79 *operand == self.zeros
80 }
81
82 pub fn gpr_in_bank(
83 &self,
84 state: &PCodeState<u8, O>,
85 operand: &Register,
86 ) -> Result<Address, Error> {
87 if !self.is_gpr(operand) {
88 return Err(Error::InvalidOperand(operand.clone()).into());
89 }
90
91 let offset = (operand.offset() as u16).wrapping_sub(self.cp_default);
92
93 let context: u16 = state.registers().get_register(&self.cp).unwrap();
94
95 let address = u32::from(context.wrapping_add(offset));
96
97 Ok(address.into())
98 }
99}
100
101impl<O, ErrorType> HookConcrete for RegisterMapper<O, ErrorType>
102where
103 O: Order,
104 ErrorType: std::error::Error + Send + Sync + 'static + Clone,
105{
106 type State = PCodeState<u8, O>;
107 type Error = ErrorType;
108 type Outcome = String;
109
110 fn hook_register_read(
111 &mut self,
112 state: &mut Self::State,
113 register: &Register,
114 ) -> Result<HookOutcome<HookAction<Self::Outcome>>, HookError<Self::Error>> {
115 if self.is_zero(register) {
116 log::debug!("ZEROS read; writing 0 to register");
117 state.registers_mut().set_register(®ister, 0u16).unwrap();
118 return Ok(HookAction::Pass.into())
120 }
121
122 if self.is_one(register) {
123 log::debug!("ONES read; writing 1 to register");
124 state.registers_mut().set_register(register, 1).unwrap();
125 return Ok(HookAction::Pass.into())
126 }
127
128 let address = if self.is_gpr(register) {
129 self.gpr_in_bank(state, register).unwrap()
130 } else if register.offset() == 0xfe0e || register.offset() == 0xfe0c { register.offset().into()
132 } else {
133 return Ok(HookAction::Pass.into())};
136
137 match register.size() {
142 1 => {
143 let state = state.state_mut();
144 let mut value = [0u8; 1];
145 state.get_values(address, &mut value).unwrap();
146 state.registers_mut().set_register_values(register, &value).unwrap();
147 }
148 2 => {
149 let state = state.state_mut();
150 let mut value = [0u8; 2];
151 state.get_values(address, &mut value).unwrap();
152 state.registers_mut().set_register_values(register, &value).unwrap();
153
154 }
155 3 => {
156 let state = state.state_mut();
157 let mut value = [0u8; 3];
158 state.get_values(address, &mut value).unwrap();
159 state.registers_mut().set_register_values(register, &value).unwrap();
160 }
161 n => panic!("unexpected operand size: {}", n),
162 }
163
164 Ok(HookAction::Pass.into())
165 }
166
167 fn hook_register_write(
168 &mut self,
169 state: &mut Self::State,
170 register: &Register,
171 value: &[<Self::State as StateOps>::Value],
172 ) -> Result<HookOutcome<HookAction<Self::Outcome>>, HookError<Self::Error>>{
173 let address = if self.is_gpr(register) {
174 self.gpr_in_bank(state, register).unwrap()
175 } else if register.offset() == 0xfe0e || register.offset() == 0xfe0c { register.offset().into()
177 } else {
178 return Ok(HookAction::Pass.into()) };
182
183 log::debug!("memory wrapped write to {} (address: {}, value: {:02x?})", register.name(), address, value);
184
185 state.state_mut().set_values(address, value).unwrap();
186
187 Ok(HookAction::Pass.into())
188 }
189}
190
191impl<O, ErrorType> ClonableHookConcrete for RegisterMapper<O, ErrorType>
192where O: Order,
193 ErrorType: std::error::Error + Send + Sync + 'static + Clone,
194 {}