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