1use anyhow::{anyhow, bail, Result};
7use libafl::prelude::CmpValues;
8use raw_cstr::AsRawCstr;
9use simics::api::{
10 get_interface, read_phys_memory, sys::instruction_handle_t, Access, ConfObject,
11 CpuInstructionQueryInterface, CpuInstrumentationSubscribeInterface, CycleInterface,
12 IntRegisterInterface, ProcessorInfoV2Interface,
13};
14use std::{ffi::CStr, mem::size_of, slice::from_raw_parts};
15use yaxpeax_arch::{Decoder, U8Reader};
16use yaxpeax_riscv::{Instruction, Opcode, Operand, RiscVDecoder};
17
18use crate::{
19 tracer::{CmpExpr, CmpType, CmpValue, TraceEntry},
20 traits::TracerDisassembler,
21};
22
23use super::ArchitectureOperations;
24
25pub(crate) struct RISCVArchitectureOperations {
26 cpu: *mut ConfObject,
27 disassembler: Disassembler,
28 int_register: IntRegisterInterface,
29 processor_info_v2: ProcessorInfoV2Interface,
30 cpu_instruction_query: CpuInstructionQueryInterface,
31 cpu_instrumentation_subscribe: CpuInstrumentationSubscribeInterface,
32 cycle: CycleInterface,
33}
34
35impl ArchitectureOperations for RISCVArchitectureOperations {
36 const INDEX_SELECTOR_REGISTER: &'static str = "x10";
37
38 const ARGUMENT_REGISTER_0: &'static str = "x11";
39
40 const ARGUMENT_REGISTER_1: &'static str = "x12";
41
42 const ARGUMENT_REGISTER_2: &'static str = "x13";
43
44 fn new(cpu: *mut ConfObject) -> Result<Self> {
45 let mut processor_info_v2: ProcessorInfoV2Interface = get_interface(cpu)?;
46
47 let arch = unsafe { CStr::from_ptr(processor_info_v2.architecture()?) }
48 .to_str()?
49 .to_string();
50
51 if arch == "risc-v" || arch == "riscv" || arch == "riscv32" || arch == "riscv64" {
52 Ok(Self {
53 cpu,
54 disassembler: Disassembler::new(),
55 int_register: get_interface(cpu)?,
56 processor_info_v2,
57 cpu_instruction_query: get_interface(cpu)?,
58 cpu_instrumentation_subscribe: get_interface(cpu)?,
59 cycle: get_interface(cpu)?,
60 })
61 } else {
62 bail!("Architecture {} is not risc-v", arch);
63 }
64 }
65
66 fn new_unchecked(cpu: *mut ConfObject) -> Result<Self>
67 where
68 Self: Sized,
69 {
70 Ok(Self {
71 cpu,
72 disassembler: Disassembler::new(),
73 int_register: get_interface(cpu)?,
74 processor_info_v2: get_interface(cpu)?,
75 cpu_instruction_query: get_interface(cpu)?,
76 cpu_instrumentation_subscribe: get_interface(cpu)?,
77 cycle: get_interface(cpu)?,
78 })
79 }
80
81 fn cpu(&self) -> *mut ConfObject {
82 self.cpu
83 }
84
85 fn disassembler(&mut self) -> &mut dyn TracerDisassembler {
86 &mut self.disassembler
87 }
88
89 fn int_register(&mut self) -> &mut IntRegisterInterface {
90 &mut self.int_register
91 }
92
93 fn processor_info_v2(&mut self) -> &mut ProcessorInfoV2Interface {
94 &mut self.processor_info_v2
95 }
96
97 fn cpu_instruction_query(&mut self) -> &mut CpuInstructionQueryInterface {
98 &mut self.cpu_instruction_query
99 }
100
101 fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface {
102 &mut self.cpu_instrumentation_subscribe
103 }
104
105 fn cycle(&mut self) -> &mut CycleInterface {
106 &mut self.cycle
107 }
108
109 fn trace_pc(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
110 let instruction_bytes = self
111 .cpu_instruction_query
112 .get_instruction_bytes(instruction_query)?;
113
114 self.disassembler.disassemble(unsafe {
115 from_raw_parts(instruction_bytes.data, instruction_bytes.size)
116 })?;
117
118 if self.disassembler.last_was_call()
119 || self.disassembler.last_was_control_flow()
120 || self.disassembler.last_was_ret()
121 {
122 Ok(TraceEntry::builder()
123 .edge(self.processor_info_v2.get_program_counter()?)
124 .build())
125 } else {
126 Ok(TraceEntry::default())
127 }
128 }
129
130 fn trace_cmp(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
131 let instruction_bytes = self
132 .cpu_instruction_query
133 .get_instruction_bytes(instruction_query)?;
134 self.disassembler.disassemble(unsafe {
135 from_raw_parts(instruction_bytes.data, instruction_bytes.size)
136 })?;
137
138 let pc = self.processor_info_v2.get_program_counter()?;
139
140 let mut cmp_values = Vec::new();
141
142 for expr in self.disassembler.cmp() {
143 if let Ok(value) = self.simplify(&expr) {
144 cmp_values.push(value);
145 }
146 }
147
148 let cmp_value = if let (Some(l), Some(r)) = (cmp_values.first(), cmp_values.get(1)) {
149 match (l, r) {
150 (CmpValue::U8(l), CmpValue::U8(r)) => Some(CmpValues::U8((*l, *r))),
151 (CmpValue::I8(l), CmpValue::I8(r)) => Some(CmpValues::U8((
152 u8::from_le_bytes(l.to_le_bytes()),
153 u8::from_le_bytes(r.to_le_bytes()),
154 ))),
155 (CmpValue::U16(l), CmpValue::U16(r)) => Some(CmpValues::U16((*l, *r))),
156 (CmpValue::I16(l), CmpValue::I16(r)) => Some(CmpValues::U16((
157 u16::from_le_bytes(l.to_le_bytes()),
158 u16::from_le_bytes(r.to_le_bytes()),
159 ))),
160 (CmpValue::U32(l), CmpValue::U32(r)) => Some(CmpValues::U32((*l, *r))),
161 (CmpValue::I32(l), CmpValue::I32(r)) => Some(CmpValues::U32((
162 u32::from_le_bytes(l.to_le_bytes()),
163 u32::from_le_bytes(r.to_le_bytes()),
164 ))),
165 (CmpValue::U64(l), CmpValue::U64(r)) => Some(CmpValues::U64((*l, *r))),
166 (CmpValue::I64(l), CmpValue::I64(r)) => Some(CmpValues::U64((
167 u64::from_le_bytes(l.to_le_bytes()),
168 u64::from_le_bytes(r.to_le_bytes()),
169 ))),
170 (CmpValue::Expr(_), CmpValue::Expr(_)) => None,
171 _ => None,
172 }
173 } else {
174 None
175 };
176
177 Ok(TraceEntry::builder()
178 .cmp((
179 pc,
180 self.disassembler.cmp_type(),
181 cmp_value.ok_or_else(|| anyhow!("No cmp value available"))?,
182 ))
183 .build())
184 }
185}
186
187impl RISCVArchitectureOperations {
188 fn simplify(&mut self, expr: &CmpExpr) -> Result<CmpValue> {
189 match expr {
190 CmpExpr::Deref((b, _)) => {
191 let v = self.simplify(b)?;
192 match v {
193 CmpValue::U64(a) => {
194 let address = self
195 .processor_info_v2
196 .logical_to_physical(a, Access::Sim_Access_Read)?;
197 Ok(CmpValue::U64(read_phys_memory(
198 self.cpu,
199 address.address,
200 size_of::<u64>() as i32,
201 )?))
202 }
203 CmpValue::U32(a) => {
204 let address = self
205 .processor_info_v2
206 .logical_to_physical(a as u64, Access::Sim_Access_Read)?;
207 Ok(CmpValue::U64(read_phys_memory(
208 self.cpu,
209 address.address,
210 size_of::<u32>() as i32,
211 )?))
212 }
213 _ => bail!("Invalid dereference size {:?}", v),
214 }
215 }
216 CmpExpr::Reg((n, _)) => {
217 let regno = self.int_register.get_number(n.as_raw_cstr()?)?;
218 let value = self.int_register.read(regno)?;
219 if self.processor_info_v2.get_logical_address_width()? as u32 / u8::BITS == 8 {
220 Ok(CmpValue::U64(value))
221 } else {
222 Ok(CmpValue::U32(value as u32))
223 }
224 }
225 CmpExpr::Add((l, r)) => {
226 let lv = self.simplify(l)?;
227 let rv = self.simplify(r)?;
228
229 match (lv, rv) {
230 (CmpValue::U8(lu), CmpValue::U8(ru)) => Ok(CmpValue::U8(lu.wrapping_add(ru))),
231 (CmpValue::U8(lu), CmpValue::I8(ru)) => {
232 Ok(CmpValue::U8(lu.wrapping_add_signed(ru)))
233 }
234 (CmpValue::U8(lu), CmpValue::U16(ru)) => {
235 Ok(CmpValue::U8((lu as u16).wrapping_add(ru) as u8))
236 }
237 (CmpValue::U8(lu), CmpValue::I16(ru)) => {
238 Ok(CmpValue::U8((lu as u16).wrapping_add_signed(ru) as u8))
239 }
240 (CmpValue::U8(lu), CmpValue::U32(ru)) => {
241 Ok(CmpValue::U8((lu as u32).wrapping_add(ru) as u8))
242 }
243 (CmpValue::U8(lu), CmpValue::I32(ru)) => {
244 Ok(CmpValue::U8((lu as u32).wrapping_add_signed(ru) as u8))
245 }
246 (CmpValue::U8(lu), CmpValue::U64(ru)) => {
247 Ok(CmpValue::U8((lu as u64).wrapping_add(ru) as u8))
248 }
249 (CmpValue::U8(lu), CmpValue::I64(ru)) => {
250 Ok(CmpValue::U8((lu as u64).wrapping_add_signed(ru) as u8))
251 }
252 (CmpValue::I8(lu), CmpValue::U8(ru)) => {
253 Ok(CmpValue::I8(lu.wrapping_add_unsigned(ru)))
254 }
255 (CmpValue::I8(lu), CmpValue::I8(ru)) => Ok(CmpValue::I8(lu.wrapping_add(ru))),
256 (CmpValue::I8(lu), CmpValue::U16(ru)) => {
257 Ok(CmpValue::I8((lu as i16).wrapping_add_unsigned(ru) as i8))
258 }
259 (CmpValue::I8(lu), CmpValue::I16(ru)) => {
260 Ok(CmpValue::I8((lu as i16).wrapping_add(ru) as i8))
261 }
262 (CmpValue::I8(lu), CmpValue::U32(ru)) => {
263 Ok(CmpValue::I8((lu as i32).wrapping_add_unsigned(ru) as i8))
264 }
265 (CmpValue::I8(lu), CmpValue::I32(ru)) => {
266 Ok(CmpValue::I8((lu as i32).wrapping_add(ru) as i8))
267 }
268 (CmpValue::I8(lu), CmpValue::U64(ru)) => {
269 Ok(CmpValue::I8((lu as i64).wrapping_add_unsigned(ru) as i8))
270 }
271 (CmpValue::I8(lu), CmpValue::I64(ru)) => {
272 Ok(CmpValue::I8((lu as i64).wrapping_add(ru) as i8))
273 }
274 (CmpValue::U16(lu), CmpValue::U8(ru)) => {
275 Ok(CmpValue::U16(lu.wrapping_add(ru as u16)))
276 }
277 (CmpValue::U16(lu), CmpValue::I8(ru)) => {
278 Ok(CmpValue::U16(lu.wrapping_add_signed(ru as i16)))
279 }
280 (CmpValue::U16(lu), CmpValue::U16(ru)) => {
281 Ok(CmpValue::U16(lu.wrapping_add(ru)))
282 }
283 (CmpValue::U16(lu), CmpValue::I16(ru)) => {
284 Ok(CmpValue::U16(lu.wrapping_add_signed(ru)))
285 }
286 (CmpValue::U16(lu), CmpValue::U32(ru)) => {
287 Ok(CmpValue::U16((lu as u32).wrapping_add(ru) as u16))
288 }
289 (CmpValue::U16(lu), CmpValue::I32(ru)) => {
290 Ok(CmpValue::U16((lu as u32).wrapping_add_signed(ru) as u16))
291 }
292 (CmpValue::U16(lu), CmpValue::U64(ru)) => {
293 Ok(CmpValue::U16((lu as u64).wrapping_add(ru) as u16))
294 }
295 (CmpValue::U16(lu), CmpValue::I64(ru)) => {
296 Ok(CmpValue::U16((lu as u64).wrapping_add_signed(ru) as u16))
297 }
298 (CmpValue::I16(lu), CmpValue::U8(ru)) => {
299 Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru as u16)))
300 }
301 (CmpValue::I16(lu), CmpValue::I8(ru)) => {
302 Ok(CmpValue::I16(lu.wrapping_add(ru as i16)))
303 }
304 (CmpValue::I16(lu), CmpValue::U16(ru)) => {
305 Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru)))
306 }
307 (CmpValue::I16(lu), CmpValue::I16(ru)) => {
308 Ok(CmpValue::I16(lu.wrapping_add(ru)))
309 }
310 (CmpValue::I16(lu), CmpValue::U32(ru)) => {
311 Ok(CmpValue::I16((lu as i32).wrapping_add_unsigned(ru) as i16))
312 }
313 (CmpValue::I16(lu), CmpValue::I32(ru)) => {
314 Ok(CmpValue::I16((lu as i32).wrapping_add(ru) as i16))
315 }
316 (CmpValue::I16(lu), CmpValue::U64(ru)) => {
317 Ok(CmpValue::I16((lu as i64).wrapping_add_unsigned(ru) as i16))
318 }
319 (CmpValue::I16(lu), CmpValue::I64(ru)) => {
320 Ok(CmpValue::I16((lu as i64).wrapping_add(ru) as i16))
321 }
322 (CmpValue::U32(lu), CmpValue::U8(ru)) => {
323 Ok(CmpValue::U32(lu.wrapping_add(ru as u32)))
324 }
325 (CmpValue::U32(lu), CmpValue::I8(ru)) => {
326 Ok(CmpValue::U32(lu.wrapping_add_signed(ru as i32)))
327 }
328 (CmpValue::U32(lu), CmpValue::U16(ru)) => {
329 Ok(CmpValue::U32(lu.wrapping_add(ru as u32)))
330 }
331 (CmpValue::U32(lu), CmpValue::I16(ru)) => {
332 Ok(CmpValue::U32(lu.wrapping_add_signed(ru as i32)))
333 }
334 (CmpValue::U32(lu), CmpValue::U32(ru)) => {
335 Ok(CmpValue::U32(lu.wrapping_add(ru)))
336 }
337 (CmpValue::U32(lu), CmpValue::I32(ru)) => {
338 Ok(CmpValue::U32(lu.wrapping_add_signed(ru)))
339 }
340 (CmpValue::U32(lu), CmpValue::U64(ru)) => {
341 Ok(CmpValue::U32((lu as u64).wrapping_add(ru) as u32))
342 }
343 (CmpValue::U32(lu), CmpValue::I64(ru)) => {
344 Ok(CmpValue::U32((lu as u64).wrapping_add_signed(ru) as u32))
345 }
346 (CmpValue::I32(lu), CmpValue::U8(ru)) => {
347 Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
348 }
349 (CmpValue::I32(lu), CmpValue::I8(ru)) => {
350 Ok(CmpValue::I32(lu.wrapping_add(ru as i32)))
351 }
352 (CmpValue::I32(lu), CmpValue::U16(ru)) => {
353 Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
354 }
355 (CmpValue::I32(lu), CmpValue::I16(ru)) => {
356 Ok(CmpValue::I32(lu.wrapping_add(ru as i32)))
357 }
358 (CmpValue::I32(lu), CmpValue::U32(ru)) => {
359 Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru)))
360 }
361 (CmpValue::I32(lu), CmpValue::I32(ru)) => {
362 Ok(CmpValue::I32(lu.wrapping_add(ru)))
363 }
364 (CmpValue::I32(lu), CmpValue::U64(ru)) => {
365 Ok(CmpValue::I32((lu as i64).wrapping_add_unsigned(ru) as i32))
366 }
367 (CmpValue::I32(lu), CmpValue::I64(ru)) => {
368 Ok(CmpValue::I32((lu as i64).wrapping_add(ru) as i32))
369 }
370 (CmpValue::U64(lu), CmpValue::U8(ru)) => {
371 Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
372 }
373 (CmpValue::U64(lu), CmpValue::I8(ru)) => {
374 Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
375 }
376 (CmpValue::U64(lu), CmpValue::U16(ru)) => {
377 Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
378 }
379 (CmpValue::U64(lu), CmpValue::I16(ru)) => {
380 Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
381 }
382 (CmpValue::U64(lu), CmpValue::U32(ru)) => {
383 Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
384 }
385 (CmpValue::U64(lu), CmpValue::I32(ru)) => {
386 Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
387 }
388 (CmpValue::U64(lu), CmpValue::U64(ru)) => {
389 Ok(CmpValue::U64(lu.wrapping_add(ru)))
390 }
391 (CmpValue::U64(lu), CmpValue::I64(ru)) => {
392 Ok(CmpValue::U64(lu.wrapping_add_signed(ru)))
393 }
394 (CmpValue::I64(lu), CmpValue::U8(ru)) => {
395 Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
396 }
397 (CmpValue::I64(lu), CmpValue::I8(ru)) => {
398 Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
399 }
400 (CmpValue::I64(lu), CmpValue::U16(ru)) => {
401 Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
402 }
403 (CmpValue::I64(lu), CmpValue::I16(ru)) => {
404 Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
405 }
406 (CmpValue::I64(lu), CmpValue::U32(ru)) => {
407 Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
408 }
409 (CmpValue::I64(lu), CmpValue::I32(ru)) => {
410 Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
411 }
412 (CmpValue::I64(lu), CmpValue::U64(ru)) => {
413 Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru)))
414 }
415 (CmpValue::I64(lu), CmpValue::I64(ru)) => {
416 Ok(CmpValue::I64(lu.wrapping_add(ru)))
417 }
418 _ => bail!("Cannot multiply non-integral types"),
419 }
420 }
421 CmpExpr::I16(i) => Ok(CmpValue::I16(*i)),
422 CmpExpr::U32(u) => Ok(CmpValue::U32(*u)),
423 CmpExpr::I32(i) => Ok(CmpValue::I32(*i)),
424 _ => bail!("Unsupported expression {:?}", expr),
425 }
426 }
427}
428
429pub(crate) struct Disassembler {
430 decoder: RiscVDecoder,
431 last: Option<Instruction>,
432}
433
434impl Disassembler {
435 pub fn new() -> Self {
436 Self {
437 decoder: RiscVDecoder::default(),
438 last: None,
439 }
440 }
441}
442
443impl Default for Disassembler {
444 fn default() -> Self {
445 Self::new()
446 }
447}
448
449impl TracerDisassembler for Disassembler {
450 fn disassemble(&mut self, bytes: &[u8]) -> Result<()> {
451 let mut r = U8Reader::new(bytes);
452
453 if let Ok(insn) = self.decoder.decode(&mut r) {
454 self.last = Some(insn);
455 } else {
456 bail!("Could not disassemble {:?}", bytes);
457 }
458
459 Ok(())
460 }
461
462 fn disassemble_to_string(&mut self, bytes: &[u8]) -> Result<String> {
463 let mut r = U8Reader::new(bytes);
464
465 if let Ok(insn) = self.decoder.decode(&mut r) {
466 Ok(insn.to_string())
467 } else {
468 bail!("Could not disassemble {:?}", bytes);
469 }
470 }
471
472 fn last_was_control_flow(&self) -> bool {
473 if let Some(last) = self.last.as_ref() {
474 if matches!(last.opcode(), |Opcode::BEQ| Opcode::BNE
475 | Opcode::BLT
476 | Opcode::BGE
477 | Opcode::BLTU
478 | Opcode::BGEU)
479 {
480 return true;
481 }
482 }
483
484 false
485 }
486
487 fn last_was_call(&self) -> bool {
492 if let Some(last) = self.last.as_ref() {
493 return matches!(last.opcode(), Opcode::JALR | Opcode::JAL | Opcode::AUIPC);
494 }
495
496 false
497 }
498
499 fn last_was_ret(&self) -> bool {
500 if let Some(last) = self.last.as_ref() {
501 return matches!(last.opcode(), Opcode::JALR | Opcode::JAL | Opcode::AUIPC);
502 }
503
504 false
505 }
506
507 fn last_was_cmp(&self) -> bool {
508 if let Some(last) = self.last.as_ref() {
509 return matches!(
510 last.opcode(),
511 Opcode::SLT
512 | Opcode::SLTI
513 | Opcode::SLTU
514 | Opcode::SLTIU
515 | Opcode::BEQ
516 | Opcode::BNE
517 | Opcode::BGE
518 | Opcode::BLTU
519 | Opcode::BGEU
520 );
521 }
522
523 false
524 }
525
526 fn cmp(&self) -> Vec<CmpExpr> {
527 let mut cmp_exprs = Vec::new();
528 if self.last_was_cmp() {
529 if let Some(last) = self.last.as_ref() {
530 for operand in last.operands() {
531 match operand {
532 Some(Operand::Reg(r)) => {
533 let regname = format!("x{}", r);
534 cmp_exprs.push(CmpExpr::Reg((regname, 0)));
537 }
538 Some(Operand::Imm(i)) => {
539 cmp_exprs.push(CmpExpr::I32(i));
541 }
542 Some(Operand::BaseOffset(b, o)) => {
543 let regname = format!("x{}", b);
544 cmp_exprs.push(CmpExpr::Deref((
545 Box::new(CmpExpr::Add((
546 Box::new(CmpExpr::Reg((regname, 0))),
547 Box::new(CmpExpr::I16(o)),
548 ))),
549 None,
550 )))
551 }
552 Some(Operand::LongImm(u)) => cmp_exprs.push(CmpExpr::U32(u)),
553 _ => {}
554 }
555 }
556 }
557 }
558
559 cmp_exprs
560 }
561
562 fn cmp_type(&self) -> Vec<CmpType> {
563 if self.last_was_cmp() {
564 if let Some(last) = self.last.as_ref() {
565 return match last.opcode() {
566 Opcode::SLT => vec![CmpType::Lesser],
567 Opcode::SLTI => vec![CmpType::Lesser],
568 Opcode::SLTU => vec![CmpType::Lesser],
569 Opcode::SLTIU => vec![CmpType::Lesser],
570 Opcode::BEQ => vec![CmpType::Equal],
571 Opcode::BNE => vec![CmpType::Equal],
572 Opcode::BGE => vec![CmpType::Greater, CmpType::Equal],
573 Opcode::BLTU => vec![CmpType::Lesser],
574 Opcode::BGEU => vec![CmpType::Greater, CmpType::Equal],
575 _ => vec![],
576 };
577 }
578 }
579
580 vec![]
581 }
582}