1use crate::{Instruction, Operand, Result, Routine, Vip};
2use std::io;
3
4pub fn dump_instr(buffer: &mut dyn io::Write, instr: &Instruction) -> Result<()> {
6 if instr.vip != Vip::invalid() {
7 write!(buffer, "[{:08x}] ", instr.vip.0)?;
8 } else {
9 write!(buffer, "[ PSEUDO ] ")?;
10 }
11
12 if instr.sp_reset {
13 write!(
14 buffer,
15 ">{}{:>#4x} ",
16 if instr.sp_offset >= 0 { '+' } else { '-' },
17 instr.sp_offset.abs()
18 )?;
19 } else {
20 write!(
21 buffer,
22 " {}{:>#4x} ",
23 if instr.sp_offset >= 0 { '+' } else { '-' },
24 instr.sp_offset.abs()
25 )?;
26 }
27
28 write!(buffer, "{:<8} ", instr.op.name())?;
29
30 for op in instr.op.operands() {
31 match op {
32 Operand::RegisterDesc(r) => {
33 write!(buffer, "{:<12}", format!("{}", r))?;
34 }
35 Operand::ImmediateDesc(i) => {
36 if i.i64() < 0 {
37 write!(buffer, "-{:<#12x}", -i.i64())?;
38 } else {
39 write!(buffer, "{:<#12x}", i.i64())?;
40 }
41 }
42 }
43 }
44
45 Ok(())
46}
47
48pub fn dump_routine(buffer: &mut dyn io::Write, routine: &Routine) -> Result<()> {
50 for (_, basic_block) in &routine.explored_blocks {
51 writeln!(buffer, "Entry point VIP: {:#x}", basic_block.vip.0)?;
52 write!(buffer, "Stack pointer: ")?;
53 if basic_block.sp_offset < 0 {
54 writeln!(buffer, "-{:#x}", -basic_block.sp_offset)?;
55 } else {
56 writeln!(buffer, "{:#x}", basic_block.sp_offset)?;
57 }
58
59 for instr in &basic_block.instructions {
60 dump_instr(buffer, instr)?;
61 writeln!(buffer)?;
62 }
63 }
64
65 Ok(())
66}