1use ustr::Ustr;
2
3use crate::compiler::{self, CallFixup, Specification};
4use crate::deserialise::error::Error as DeserialiseError;
5use crate::disassembly::VarnodeData;
6use crate::register::RegisterNames;
7use crate::space::AddressSpace;
8use crate::space_manager::SpaceManager;
9
10use std::sync::Arc;
11
12#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
13pub enum PrototypeOperand {
14 Register {
15 name: Ustr,
16 varnode: VarnodeData,
17 },
18 RegisterJoin {
19 first_name: Ustr,
20 first_varnode: VarnodeData,
21 second_name: Ustr,
22 second_varnode: VarnodeData,
23 },
24 StackRelative(u64),
25}
26
27impl PrototypeOperand {
28 pub fn from_spec(
29 spec: &compiler::PrototypeOperand,
30 registers: &RegisterNames,
31 ) -> Result<Self, DeserialiseError> {
32 match spec {
33 compiler::PrototypeOperand::Register(ref name) => {
34 let (name, offset, size) = registers.get_by_name(&**name).ok_or_else(|| {
35 DeserialiseError::Invariant("register for prototype operand invalid")
36 })?;
37 Ok(Self::Register {
38 name: name.clone(),
39 varnode: VarnodeData::new(registers.register_space(), offset, size),
40 })
41 }
42 compiler::PrototypeOperand::RegisterJoin(ref first_name, ref second_name) => {
43 let (first_name, foffset, fsize) =
44 registers.get_by_name(&**first_name).ok_or_else(|| {
45 DeserialiseError::Invariant("register for prototype operand invalid")
46 })?;
47
48 let (second_name, soffset, ssize) =
49 registers.get_by_name(&**second_name).ok_or_else(|| {
50 DeserialiseError::Invariant("register for prototype operand invalid")
51 })?;
52
53 Ok(Self::RegisterJoin {
54 first_name: first_name.clone(),
55 first_varnode: VarnodeData::new(registers.register_space(), foffset, fsize),
56 second_name: second_name.clone(),
57 second_varnode: VarnodeData::new(registers.register_space(), soffset, ssize),
58 })
59 }
60 compiler::PrototypeOperand::StackRelative(offset) => Ok(Self::StackRelative(*offset)),
61 }
62 }
63}
64
65#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
66pub struct PrototypeEntry {
67 min_size: usize,
68 max_size: usize,
69 alignment: u64,
70 meta_type: Option<String>,
71 extension: Option<String>,
72 operand: PrototypeOperand,
73}
74
75impl PrototypeEntry {
76 pub fn from_spec(
77 spec: &compiler::PrototypeEntry,
78 registers: &RegisterNames,
79 ) -> Result<Self, DeserialiseError> {
80 Ok(Self {
81 min_size: spec.min_size,
82 max_size: spec.max_size,
83 alignment: spec.alignment,
84 meta_type: spec.meta_type.clone(),
85 extension: spec.extension.clone(),
86 operand: PrototypeOperand::from_spec(&spec.operand, registers)?,
87 })
88 }
89
90 pub fn min_size(&self) -> usize {
91 self.min_size
92 }
93
94 pub fn max_size(&self) -> usize {
95 self.max_size
96 }
97
98 pub fn alignment(&self) -> u64 {
99 self.alignment
100 }
101
102 pub fn meta_type(&self) -> &Option<String> {
103 &self.meta_type
104 }
105
106 pub fn extension(&self) -> &Option<String> {
107 &self.extension
108 }
109
110 pub fn operand(&self) -> &PrototypeOperand {
111 &self.operand
112 }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
116pub struct Prototype {
117 name: String,
118 extra_pop: u64,
119 stack_shift: u64,
120 inputs: Vec<PrototypeEntry>,
121 outputs: Vec<PrototypeEntry>,
122 unaffected: Vec<PrototypeOperand>,
123 killed_by_call: Vec<PrototypeOperand>,
124 likely_trashed: Vec<PrototypeOperand>,
125}
126
127impl Prototype {
128 pub fn from_spec(
129 spec: &compiler::Prototype,
130 registers: &RegisterNames,
131 ) -> Result<Self, DeserialiseError> {
132 Ok(Self {
133 name: spec.name.clone(),
134 extra_pop: spec.extra_pop,
135 stack_shift: spec.stack_shift,
136 inputs: spec
137 .inputs
138 .iter()
139 .map(|input| PrototypeEntry::from_spec(input, registers))
140 .collect::<Result<_, _>>()?,
141 outputs: spec
142 .outputs
143 .iter()
144 .map(|output| PrototypeEntry::from_spec(output, registers))
145 .collect::<Result<_, _>>()?,
146 unaffected: spec
147 .unaffected
148 .iter()
149 .map(|unaffected| PrototypeOperand::from_spec(unaffected, registers))
150 .collect::<Result<_, _>>()?,
151 killed_by_call: spec
152 .killed_by_call
153 .iter()
154 .map(|killed| PrototypeOperand::from_spec(killed, registers))
155 .collect::<Result<_, _>>()?,
156 likely_trashed: spec
157 .likely_trashed
158 .iter()
159 .map(|trashed| PrototypeOperand::from_spec(trashed, registers))
160 .collect::<Result<_, _>>()?,
161 })
162 }
163
164 pub fn name(&self) -> &str {
165 &self.name
166 }
167
168 pub fn extra_pop(&self) -> u64 {
169 self.extra_pop
170 }
171
172 pub fn stack_shift(&self) -> u64 {
173 self.stack_shift
174 }
175
176 pub fn inputs(&self) -> &[PrototypeEntry] {
177 &self.inputs
178 }
179
180 pub fn outputs(&self) -> &[PrototypeEntry] {
181 &self.outputs
182 }
183
184 pub fn unaffected(&self) -> &[PrototypeOperand] {
185 &self.unaffected
186 }
187
188 pub fn killed_by_call(&self) -> &[PrototypeOperand] {
189 &self.killed_by_call
190 }
191
192 pub fn likely_trashed(&self) -> &[PrototypeOperand] {
193 &self.likely_trashed
194 }
195}
196
197#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
198pub enum ReturnAddress {
199 Register { name: Ustr, varnode: VarnodeData },
200 StackRelative { offset: u64, size: usize },
201}
202
203impl ReturnAddress {
204 pub fn from_spec(
205 spec: &compiler::ReturnAddress,
206 registers: &RegisterNames,
207 ) -> Result<Self, DeserialiseError> {
208 match spec {
209 compiler::ReturnAddress::Register(ref name) => {
210 let (name, offset, size) = registers.get_by_name(&**name).ok_or_else(|| {
211 DeserialiseError::Invariant("register for return address invalid")
212 })?;
213 Ok(Self::Register {
214 name: name.clone(),
215 varnode: VarnodeData::new(registers.register_space(), offset, size),
216 })
217 }
218 compiler::ReturnAddress::StackRelative { offset, size } => Ok(Self::StackRelative {
219 offset: *offset,
220 size: *size,
221 }),
222 }
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
227pub struct StackPointer {
228 name: Ustr,
229 varnode: VarnodeData,
230 space: Arc<AddressSpace>,
231}
232
233impl StackPointer {
234 pub fn from_spec(
235 spec: &compiler::StackPointer,
236 registers: &RegisterNames,
237 manager: &SpaceManager,
238 ) -> Result<Self, DeserialiseError> {
239 let space = manager.space_by_name(&spec.space).ok_or_else(|| {
240 DeserialiseError::Invariant("stack pointer space for convention invalid")
241 })?;
242 let (name, offset, size) = registers
243 .get_by_name(&*spec.register)
244 .ok_or_else(|| DeserialiseError::Invariant("named stack pointer invalid"))?;
245
246 Ok(Self {
247 name: name.clone(),
248 varnode: VarnodeData::new(registers.register_space(), offset, size),
249 space,
250 })
251 }
252
253 pub fn varnode(&self) -> &VarnodeData {
254 &self.varnode
255 }
256}
257
258#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
259pub struct Convention {
260 name: String,
261 data_organisation: Option<compiler::DataOrganisation>,
262 stack_pointer: StackPointer,
263 return_address: ReturnAddress,
264 default_prototype: Prototype,
265 additional_prototypes: Vec<Prototype>,
266 call_fixups: Vec<CallFixup>,
267}
268
269impl Convention {
270 pub fn from_spec(
271 spec: &Specification,
272 registers: &RegisterNames,
273 manager: &SpaceManager,
274 ) -> Result<Self, DeserialiseError> {
275 Ok(Self {
276 name: spec.name.clone(),
277 data_organisation: spec.data_organisation.clone(),
278 stack_pointer: StackPointer::from_spec(&spec.stack_pointer, registers, manager)?,
279 return_address: ReturnAddress::from_spec(&spec.return_address, registers)?,
280 default_prototype: Prototype::from_spec(&spec.default_prototype, registers)?,
281 additional_prototypes: spec
282 .additional_prototypes
283 .iter()
284 .map(|prototype| Prototype::from_spec(prototype, registers))
285 .collect::<Result<_, _>>()?,
286 call_fixups: spec.call_fixups.clone(),
287 })
288 }
289
290 pub fn name(&self) -> &str {
291 &self.name
292 }
293
294 pub fn stack_pointer(&self) -> &StackPointer {
295 &self.stack_pointer
296 }
297
298 pub fn return_address(&self) -> &ReturnAddress {
299 &self.return_address
300 }
301
302 pub fn default_prototype(&self) -> &Prototype {
303 &self.default_prototype
304 }
305
306 pub fn additional_prototypes(&self) -> &[Prototype] {
307 &self.additional_prototypes
308 }
309
310 pub fn prototypes(&self) -> impl Iterator<Item = &Prototype> {
311 std::iter::once(&self.default_prototype).chain(self.additional_prototypes.iter())
312 }
313
314 pub fn call_fixups(&self) -> &[CallFixup] {
315 &self.call_fixups
316 }
317}