1use fugue::ir::{AddressSpace, AddressValue, IntoAddress};
2use fugue::ir::il::Location;
3use fugue::ir::il::pcode::{PCode, PCodeOp};
4
5use std::sync::Arc;
6
7#[derive(Debug, Clone)]
8#[derive(serde::Deserialize, serde::Serialize)]
9pub enum Bound<A: IntoAddress> {
10 Address(A),
11 Steps(usize),
12 AddressOrSteps(A, usize),
13 AddressReachCountOrSteps(A, usize, usize),
14 Unbounded,
15}
16
17impl<A> Bound<A> where A: IntoAddress {
18 pub fn address(address: A) -> Bound<A> {
19 Self::Address(address)
20 }
21 pub fn address_or_steps(address: A, steps: usize) -> Bound<A> {
22 Self::AddressOrSteps(address, steps)
23 }
24 pub fn address_reach_count_or_steps(address: A, addr_reach_count: usize, steps: usize) -> Bound<A> {
25 Self::AddressReachCountOrSteps(address, addr_reach_count, steps)
26 }
27
28 pub fn in_space(self, space: &AddressSpace) -> Bound<AddressValue> {
29 match self {
30 Self::Address(address) => Bound::Address(address.into_address_value(&*space)),
31 Self::Steps(steps) => Bound::Steps(steps),
32 Self::AddressOrSteps(address, steps) => Bound::AddressOrSteps(address.into_address_value(&*space), steps),
33 Self::AddressReachCountOrSteps(address, address_reach_count, steps) => {
34 Bound::AddressReachCountOrSteps(address.into_address_value(&*space), address_reach_count, steps)
35 }
36 Self::Unbounded => Bound::Unbounded,
37 }
38 }
39}
40
41impl Bound<AddressValue> {
42 pub fn steps(steps: usize) -> Bound<AddressValue> {
43 Self::Steps(steps)
44 }
45
46 pub fn unbounded() -> Bound<AddressValue> {
47 Self::Unbounded
48 }
49
50 pub fn deplete(self, address: &AddressValue) -> Self {
53 match self {
54 Self::Steps(steps) => Self::Steps(steps.checked_sub(1).unwrap_or(0)),
55 Self::AddressOrSteps(address, steps) => Self::AddressOrSteps(address, steps.checked_sub(1).unwrap_or(0)),
56 Self::AddressReachCountOrSteps(address_target, addr_reach_count, steps) => {
57 let addr_reach_count_new = if *address == address_target {
58 addr_reach_count.checked_sub(1).unwrap_or(0)
59 } else {
60 addr_reach_count
61 };
62 Self::AddressReachCountOrSteps(
63 address_target,
64 addr_reach_count_new,
65 steps.checked_sub(1).unwrap_or(0)
66 )
67 }
68 _ => self,
69 }
70 }
78
79 pub fn reached(&self, address: &AddressValue) -> bool {
80 match self {
81 Self::Address(ref target) => target == address,
82 Self::Steps(steps) => *steps == 0,
83 Self::AddressOrSteps(ref target, steps) => target == address || *steps == 0,
84 Self::AddressReachCountOrSteps(ref _target, addr_reach_count, steps) => {
85 *addr_reach_count == 0 || *steps == 0
86 }
87 Self::Unbounded => false,
88 }
89 }
90}
91
92#[derive(Debug, Clone)]
93#[derive(serde::Deserialize, serde::Serialize)]
94pub enum Branch {
95 Next,
96 Local(isize),
97 Global(AddressValue),
98}
99
100#[derive(Debug, Clone)]
101#[derive(serde::Deserialize, serde::Serialize)]
102pub enum Outcome<R> {
103 Halt(R),
104 Branch(Branch),
105}
106
107#[derive(Debug, Clone)]
108#[derive(serde::Deserialize, serde::Serialize)]
109pub enum OrOutcome<S, R> {
110 Halt(R),
111 Branch(Location),
112 Continue(S),
113}
114
115impl<T, R> From<T> for OrOutcome<T, R> {
116 fn from(t: T) -> Self {
117 Self::Continue(t)
118 }
119}
120
121#[derive(Debug, Clone)]
122#[derive(serde::Deserialize, serde::Serialize)]
123pub enum StepOutcome<R> {
124 Halt(R),
125 Reached,
126 Branch(AddressValue),
127}
128
129#[derive(Debug, Clone)]
130#[derive(serde::Deserialize, serde::Serialize)]
131pub enum BranchOutcome {
132 Local,
133 Global(AddressValue),
134}
135
136#[derive(Debug, Clone)]
137#[derive(serde::Deserialize, serde::Serialize)]
138pub struct StepState {
139 pcode: Arc<PCode>,
140 position: usize,
141}
142
143impl From<PCode> for StepState {
144 fn from(pcode: PCode) -> Self {
145 Self {
146 pcode: Arc::new(pcode),
147 position: 0,
148 }
149 }
150}
151
152impl StepState {
153 #[inline(always)]
154 pub fn address(&self) -> AddressValue {
155 self.pcode.address()
156 }
157
158 pub fn location(&self) -> Location {
159 Location::new(self.pcode.address(), self.position)
160 }
161
162 pub fn operations(&self) -> &PCode {
163 &*self.pcode
164 }
165
166 pub fn with_location(self, location: &Location) -> Self {
167 assert_eq!(self.pcode.address, *location.address());
168 Self { position: location.position(), ..self }
169 }
170
171 #[inline(always)]
172 pub fn current(&self) -> Option<&PCodeOp> {
173 self.pcode.operations().get(self.position)
174 }
175
176 pub fn fallthrough(&self) -> AddressValue {
177 self.address() + self.pcode.length()
178 }
179
180 pub fn branch(&mut self, action: &Branch) -> BranchOutcome {
181 match action {
182 Branch::Next => {
183 self.position += 1;
184 },
185 Branch::Local(offset) => {
186 if offset.is_negative() {
187 let abs = offset.wrapping_abs() as usize;
188 if abs <= self.position {
189 self.position -= abs;
190 } else {
191 panic!("negative local branch out of range")
192 }
193 } else {
194 self.position += *offset as usize;
195 }
196 },
197 Branch::Global(address) => {
198 return BranchOutcome::Global(address.clone())
199 }
200 }
201
202 if self.position < self.pcode.operations.len() {
203 BranchOutcome::Local
204 } else {
205 BranchOutcome::Global(self.fallthrough())
206 }
207 }
208
209 pub fn branch_location(&self, action: Branch) -> Location {
210 match action {
211 Branch::Next => {
212 if self.position + 1 < self.pcode.operations.len() {
213 Location::new(self.address(), self.position + 1)
214 } else {
215 Location::from(self.fallthrough())
216 }
217 },
218 Branch::Local(offset) => {
219 let npos = if offset.is_negative() {
220 let abs = offset.wrapping_abs() as usize;
221 if abs <= self.position {
222 self.position - abs
223 } else {
224 panic!("negative local branch out of range")
225 }
226 } else {
227 self.position + offset as usize
228 };
229
230 if npos < self.pcode.operations.len() {
231 Location::new(self.address(), npos)
232 } else {
233 Location::from(self.fallthrough())
234 }
235 },
236 Branch::Global(address) => {
237 Location::from(address)
238 }
239 }
240 }
241}