xref: /wasmtime-44.0.1/pulley/src/interp/debug.rs (revision 1d1c06f3)
1 //! Primitive support for debugging Pulley
2 //!
3 //! This `Debug` visitor defined in this module is what's actually used as part
4 //! of the interpreter loop in Pulley. Due to the code size impact of always
5 //! including this and the runtime overhead of always checking a flag this is
6 //! enabled/disabled via a `const DEBUG` below. This is currently only really
7 //! suitable for one-off debugging while developing locally.
8 //!
9 //! The hope is that this'll eventually evolve into something more useful, but
10 //! for now it's a quick-and-easy way to dump all the instructions that are
11 //! executed as well as the values in various registers.
12 //!
13 //! If debugging is disabled, or in `#[no_std]` mode, then this module should
14 //! compile away (e.g. a "zero cost abstraction").
15 
16 use super::Interpreter;
17 use crate::decode::{ExtendedOpVisitor, OpVisitor};
18 use crate::imms::*;
19 use crate::regs::*;
20 use alloc::string::ToString;
21 
22 // Whether or not debugging is enabled at all.
23 const DEBUG: bool = false;
24 
25 // Whether or not these registers are dumped between each instruction.
26 const DEBUG_X_REGS: bool = true;
27 const DEBUG_F_REGS: bool = false;
28 
29 #[cfg(not(feature = "std"))]
30 macro_rules! print {
31     ($($t:tt)*) => ({ let _ = format_args!($($t)*); })
32 }
33 #[cfg(not(feature = "std"))]
34 macro_rules! println {
35     () => ();
36     ($($t:tt)*) => ({ let _ = format_args!($($t)*); })
37 }
38 
39 #[repr(transparent)]
40 pub(super) struct Debug<'a>(pub Interpreter<'a>);
41 
42 macro_rules! debug_then_delegate {
43     (
44         $(
45             $( #[$attr:meta] )*
46                 $snake_name:ident = $name:ident $( {
47                 $(
48                     $( #[$field_attr:meta] )*
49                     $field:ident : $field_ty:ty
50                 ),*
51             } )? ;
52         )*
53     ) => {
54         $(
55             $( #[$attr] )*
56             fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
57                 if DEBUG {
58                     println!(
59                         concat!(
60                             stringify!($snake_name),
61                             $(
62                                 $(
63                                     " ",
64                                     stringify!($field),
65                                     "={:?}",
66                                 )*
67                             )?
68                         ),
69                         $($($field),*)?
70                     );
71                 }
72                 self.0.$snake_name($( $($field),* )?)
73             }
74         )*
75     }
76 }
77 
78 impl<'a> OpVisitor for Debug<'a> {
79     type BytecodeStream = <Interpreter<'a> as OpVisitor>::BytecodeStream;
80     type Return = <Interpreter<'a> as OpVisitor>::Return;
81 
bytecode(&mut self) -> &mut Self::BytecodeStream82     fn bytecode(&mut self) -> &mut Self::BytecodeStream {
83         self.0.bytecode()
84     }
85 
before_visit(&mut self)86     fn before_visit(&mut self) {
87         self.0.record_executing_pc_for_profiling();
88         if !DEBUG {
89             return;
90         }
91         print!("\t{:?}\t", self.bytecode().as_ptr());
92     }
93 
after_visit(&mut self)94     fn after_visit(&mut self) {
95         if !DEBUG {
96             return;
97         }
98         if DEBUG_X_REGS {
99             for (i, regs) in self.0.state.x_regs.chunks(4).enumerate() {
100                 print!("\t\t");
101                 for (j, reg) in regs.iter().enumerate() {
102                     let n = i * 4 + j;
103                     let val = reg.get_u64();
104                     let reg = XReg::new(n as u8).unwrap().to_string();
105                     print!(" {reg:>3}={val:#018x}");
106                 }
107                 println!();
108             }
109         }
110         if DEBUG_F_REGS {
111             for (i, regs) in self.0.state.f_regs.chunks(4).enumerate() {
112                 print!("\t\t");
113                 for (j, reg) in regs.iter().enumerate() {
114                     let n = i * 4 + j;
115                     let val = reg.get_f64().to_bits();
116                     let reg = FReg::new(n as u8).unwrap().to_string();
117                     print!(" {reg:>3}={val:#018x}");
118                 }
119                 println!();
120             }
121         }
122     }
123 
124     for_each_op!(debug_then_delegate);
125 }
126 
127 impl<'a> ExtendedOpVisitor for Debug<'a> {
128     for_each_extended_op!(debug_then_delegate);
129 }
130