metaemu_arch_additional/c166/
observers.rs

1// use muexe_core::machine::observer::{
2//     ClonableObserver, ObservationKind, Observer, RegisterPreRead, RegisterWrite,
3// };
4// use muexe_core::pcode::{Operand, Register};
5// use muexe_core::state::pcode::PCodeState;
6// use muexe_core::state::{AsState, State};
7// use muexe_core::types::int::U24;
8// use muexe_core::types::word::traits::*;
9// use muexe_core::types::{Address, O};
10
11use 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; // 2 bytes (16-bits) for each GPR (0..15)
21
22#[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// CP is 16bit , but the program is written for 24 bit, check if this will cause any problem
33#[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) // default CP to value at reset
64    }
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(&register, 0u16).unwrap();
118            // state.state_mut().write_register_value::<O, u16>(register, 0)?;
119            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 { // MDL + MDH
131            register.offset().into()
132        } else {
133            // NOTE: for now, we just memory map the GPR range
134            return Ok(HookAction::Pass.into())// operand.offset().into()
135        };
136
137		// let reg_size = register.size();
138		// let value = state.view_values(address, reg_size).unwrap().clon;
139		// state.registers_mut().set_register_values(register, value).unwrap();
140
141        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 { // MDL + MDH
176            register.offset().into()
177        } else {
178            // NOTE: for now, we just memory map the GPR range
179            return Ok(HookAction::Pass.into()) // operand.offset().into()
180            // operand.offset().into()
181        };
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	{}