1use crate::decode::*;
4use crate::imms::*;
5use crate::regs::*;
6use alloc::string::String;
7use core::fmt::Write;
8
9pub struct Disassembler<'a> {
17 raw_bytecode: &'a [u8],
18 bytecode: SafeBytecodeStream<'a>,
19 disas: String,
20 start_offset: usize,
21 start: usize,
22 temp: String,
23 offsets: bool,
24 hexdump: bool,
25 br_tables: bool,
26}
27
28impl<'a> Disassembler<'a> {
29 pub fn disassemble_all(bytecode: &'a [u8]) -> Result<String> {
31 let mut disas = Self::new(bytecode);
32 Decoder::decode_all(&mut disas)?;
33 Ok(disas.disas)
34 }
35
36 pub fn new(bytecode: &'a [u8]) -> Self {
39 Self {
40 raw_bytecode: bytecode,
41 bytecode: SafeBytecodeStream::new(bytecode),
42 disas: String::new(),
43 start: 0,
44 start_offset: 0,
45 temp: String::new(),
46 offsets: true,
47 hexdump: true,
48 br_tables: true,
49 }
50 }
51
52 pub fn offsets(&mut self, offsets: bool) -> &mut Self {
56 self.offsets = offsets;
57 self
58 }
59
60 pub fn hexdump(&mut self, hexdump: bool) -> &mut Self {
64 self.hexdump = hexdump;
65 self
66 }
67
68 pub fn br_tables(&mut self, enable: bool) -> &mut Self {
72 self.br_tables = enable;
73 self
74 }
75
76 pub fn start_offset(&mut self, offset: usize) -> &mut Self {
82 self.start_offset = offset;
83 self
84 }
85
86 pub fn disas(&self) -> &str {
88 &self.disas
89 }
90
91 fn disas_op(&mut self, mnemonic: &str, operands: &[&dyn Disas]) {
92 write!(&mut self.temp, "{mnemonic}").unwrap();
93 for (i, val) in operands.iter().enumerate() {
94 if i > 0 {
95 write!(&mut self.temp, ",").unwrap();
96 }
97 write!(&mut self.temp, " ").unwrap();
98 val.disas(self.start + self.start_offset, &mut self.temp);
99 }
100 }
101
102 fn disas_br_table32(&mut self, reg: XReg, amt: u32) {
103 self.disas_op("br_table32", &[®, &amt]);
104 for _ in 0..amt {
105 self.after_visit();
106 self.start = self.bytecode.position();
107 if let Ok(offset) = PcRelOffset::decode(self.bytecode()) {
108 if self.br_tables {
109 offset.disas(self.start + self.start_offset, &mut self.temp);
110 }
111 }
112 }
113 }
114}
115
116trait Disas {
119 fn disas(&self, position: usize, disas: &mut String);
120}
121
122impl Disas for XReg {
123 fn disas(&self, _position: usize, disas: &mut String) {
124 write!(disas, "{self}").unwrap();
125 }
126}
127
128impl Disas for FReg {
129 fn disas(&self, _position: usize, disas: &mut String) {
130 write!(disas, "{self}").unwrap();
131 }
132}
133
134impl Disas for VReg {
135 fn disas(&self, _position: usize, disas: &mut String) {
136 write!(disas, "{self}").unwrap();
137 }
138}
139
140impl Disas for i8 {
141 fn disas(&self, _position: usize, disas: &mut String) {
142 write!(disas, "{self}").unwrap();
143 }
144}
145
146impl Disas for i16 {
147 fn disas(&self, _position: usize, disas: &mut String) {
148 write!(disas, "{self}").unwrap();
149 }
150}
151
152impl Disas for i32 {
153 fn disas(&self, _position: usize, disas: &mut String) {
154 write!(disas, "{self}").unwrap();
155 }
156}
157
158impl Disas for i64 {
159 fn disas(&self, _position: usize, disas: &mut String) {
160 write!(disas, "{self}").unwrap();
161 }
162}
163
164impl Disas for i128 {
165 fn disas(&self, _position: usize, disas: &mut String) {
166 write!(disas, "{self}").unwrap();
167 }
168}
169
170impl Disas for u8 {
171 fn disas(&self, _position: usize, disas: &mut String) {
172 write!(disas, "{self}").unwrap();
173 }
174}
175
176impl Disas for u16 {
177 fn disas(&self, _position: usize, disas: &mut String) {
178 write!(disas, "{self}").unwrap();
179 }
180}
181
182impl Disas for u32 {
183 fn disas(&self, _position: usize, disas: &mut String) {
184 write!(disas, "{self}").unwrap();
185 }
186}
187
188impl Disas for u64 {
189 fn disas(&self, _position: usize, disas: &mut String) {
190 write!(disas, "{self}").unwrap();
191 }
192}
193
194impl Disas for u128 {
195 fn disas(&self, _position: usize, disas: &mut String) {
196 write!(disas, "{self}").unwrap();
197 }
198}
199
200impl Disas for PcRelOffset {
201 fn disas(&self, position: usize, disas: &mut String) {
202 let offset = i64::from(i32::from(*self));
203 let target = (position as u64).wrapping_add(offset as u64);
204 let (prefix, offset) = if offset < 0 {
205 ("-", -offset)
206 } else {
207 ("", offset)
208 };
209 write!(disas, "{prefix}{offset:#x} // target = {target:#x}").unwrap()
210 }
211}
212
213impl Disas for U6 {
214 fn disas(&self, _position: usize, disas: &mut String) {
215 write!(disas, "{}", u8::from(*self)).unwrap();
216 }
217}
218
219fn disas_list<T: Disas>(position: usize, disas: &mut String, iter: impl IntoIterator<Item = T>) {
220 let mut iter = iter.into_iter();
221 let Some(first) = iter.next() else { return };
222 first.disas(position, disas);
223
224 for item in iter {
225 write!(disas, ", ").unwrap();
226 item.disas(position, disas);
227 }
228}
229
230impl<D, S1, S2> Disas for BinaryOperands<D, S1, S2>
231where
232 D: Reg + Disas,
233 S1: Reg + Disas,
234 S2: Reg + Disas,
235{
236 fn disas(&self, position: usize, disas: &mut String) {
237 self.dst.disas(position, disas);
238 write!(disas, ", ").unwrap();
239 self.src1.disas(position, disas);
240 write!(disas, ", ").unwrap();
241 self.src2.disas(position, disas);
242 }
243}
244
245impl<D, S1> Disas for BinaryOperands<D, S1, U6>
246where
247 D: Reg + Disas,
248 S1: Reg + Disas,
249{
250 fn disas(&self, position: usize, disas: &mut String) {
251 self.dst.disas(position, disas);
252 write!(disas, ", ").unwrap();
253 self.src1.disas(position, disas);
254 write!(disas, ", ").unwrap();
255 self.src2.disas(position, disas);
256 }
257}
258
259impl<R: Reg + Disas> Disas for UpperRegSet<R> {
260 fn disas(&self, position: usize, disas: &mut String) {
261 disas_list(position, disas, *self)
262 }
263}
264
265macro_rules! impl_disas {
266 (
267 $(
268 $( #[$attr:meta] )*
269 $snake_name:ident = $name:ident $( {
270 $(
271 $( #[$field_attr:meta] )*
272 $field:ident : $field_ty:ty
273 ),*
274 } )? ;
275 )*
276 ) => {
277 $(
278 impl_disas!(@one $snake_name = $name $( { $($field: $field_ty),* } )?);
279 )*
280 };
281
282 (
285 @one br_table32 = BrTable32 $( {
286 $(
287 $field:ident : $field_ty:ty
288 ),*
289 } )?
290 ) => {
291 fn br_table32(&mut self $( $( , $field : $field_ty )* )? ) {
292 self.disas_br_table32($($($field),*)?)
293 }
294 };
295
296 (
298 @one $snake_name:ident = $name:ident $( {
299 $(
300 $field:ident : $field_ty:ty
301 ),*
302 } )?
303 ) => {
304 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) {
305 self.disas_op(stringify!($snake_name), &[$($(&$field),*)?])
306 }
307 };
308}
309
310impl<'a> OpVisitor for Disassembler<'a> {
311 type BytecodeStream = SafeBytecodeStream<'a>;
312
313 fn bytecode(&mut self) -> &mut Self::BytecodeStream {
314 &mut self.bytecode
315 }
316
317 type Return = ();
318
319 fn before_visit(&mut self) {
320 self.start = self.bytecode.position();
321 }
322
323 fn after_visit(&mut self) {
324 if self.offsets {
325 write!(&mut self.disas, "{:8x}: ", self.start + self.start_offset).unwrap();
326 }
327 if self.hexdump {
328 let size = self.bytecode.position() - self.start;
329 let mut need_space = false;
330 for byte in &self.raw_bytecode[self.start..][..size] {
331 let space = if need_space { " " } else { "" };
332 write!(&mut self.disas, "{space}{byte:02x}").unwrap();
333 need_space = true;
334 }
335 for _ in 0..12_usize.saturating_sub(size) {
336 write!(&mut self.disas, " ").unwrap();
337 }
338 }
339 self.disas.push_str(&self.temp);
340 self.temp.clear();
341
342 self.disas.push('\n');
343 }
344
345 for_each_op!(impl_disas);
346}
347
348impl ExtendedOpVisitor for Disassembler<'_> {
349 for_each_extended_op!(impl_disas);
350}