1use anyhow::Result;
2use std::fmt::Write as _;
3use std::io::Write;
4use wasmparser::*;
5
6pub fn dump_wasm(bytes: &[u8]) -> Result<String> {
7 let mut dst = vec![];
8 {
9 let mut d = Dump::new(bytes, &mut dst);
10 d.run()?;
11 }
12 Ok(String::from_utf8(dst).unwrap())
13}
14
15pub fn dump_wasm_into(bytes: &[u8], into: impl Write) -> Result<()> {
16 let mut d = Dump::new(bytes, into);
17 d.run()?;
18 Ok(())
19}
20
21struct Dump<'a> {
22 bytes: &'a [u8],
23 cur: usize,
24 state: String,
25 dst: Box<dyn Write + 'a>,
26 nesting: u32,
27 offset_width: usize,
28}
29
30#[derive(Default)]
31struct Indices {
32 core_types: u32,
34 core_funcs: u32,
35 core_globals: u32,
36 core_tables: u32,
37 core_memories: u32,
38 core_tags: u32,
39 core_modules: u32,
40 core_instances: u32,
41
42 types: u32,
44 funcs: u32,
45 components: u32,
46 instances: u32,
47 values: u32,
48}
49
50enum ComponentTypeKind {
51 Func,
52 Component,
53 Instance,
54 DefinedType,
55}
56
57const NBYTES: usize = 4;
58
59impl<'a> Dump<'a> {
60 fn new(bytes: &'a [u8], dst: impl Write + 'a) -> Dump<'a> {
61 Dump {
62 bytes,
63 cur: 0,
64 nesting: 0,
65 state: String::new(),
66 dst: Box::new(dst) as _,
67 offset_width: format!("{:x}", bytes.len()).len() + 1,
68 }
69 }
70
71 fn run(&mut self) -> Result<()> {
72 self.print_module()?;
73 assert_eq!(self.cur, self.bytes.len());
74 Ok(())
75 }
76
77 fn print_module(&mut self) -> Result<()> {
78 let mut stack = Vec::new();
79 let mut i = Indices::default();
80 let mut component_types = Vec::new();
81 self.nesting += 1;
82
83 for item in Parser::new(0).parse_all(self.bytes) {
84 match item? {
85 Payload::Version {
86 num,
87 encoding,
88 range,
89 } => {
90 write!(self.state, "version {} ({:?})", num, encoding)?;
91 self.print(range.end)?;
92 }
93 Payload::TypeSection(s) => self.section(s, "type", |me, end, t| {
94 write!(me.state, "[type {}] {:?}", inc(&mut i.core_types), t)?;
95 me.print(end)
96 })?,
97 Payload::ImportSection(s) => self.section(s, "import", |me, end, imp| {
98 write!(me.state, "import ")?;
99 match imp.ty {
100 TypeRef::Func(_) => write!(me.state, "[func {}]", inc(&mut i.core_funcs))?,
101 TypeRef::Memory(_) => {
102 write!(me.state, "[memory {}]", inc(&mut i.core_memories))?
103 }
104 TypeRef::Tag(_) => write!(me.state, "[tag {}]", inc(&mut i.core_tags))?,
105 TypeRef::Table(_) => {
106 write!(me.state, "[table {}]", inc(&mut i.core_tables))?
107 }
108 TypeRef::Global(_) => {
109 write!(me.state, "[global {}]", inc(&mut i.core_globals))?
110 }
111 }
112 write!(me.state, " {:?}", imp)?;
113 me.print(end)
114 })?,
115 Payload::FunctionSection(s) => {
116 let mut cnt = i.core_funcs;
117 self.section(s, "func", |me, end, f| {
118 write!(me.state, "[func {}] type {:?}", inc(&mut cnt), f)?;
119 me.print(end)
120 })?
121 }
122 Payload::TableSection(s) => self.section(s, "table", |me, end, t| {
123 write!(me.state, "[table {}] {:?}", inc(&mut i.core_tables), t)?;
124 me.print(end)
125 })?,
126 Payload::MemorySection(s) => self.section(s, "memory", |me, end, m| {
127 write!(me.state, "[memory {}] {:?}", inc(&mut i.core_memories), m)?;
128 me.print(end)
129 })?,
130 Payload::TagSection(s) => self.section(s, "tag", |me, end, m| {
131 write!(me.state, "[tag {}] {:?}", inc(&mut i.core_tags), m)?;
132 me.print(end)
133 })?,
134 Payload::ExportSection(s) => self.section(s, "export", |me, end, e| {
135 write!(me.state, "export {:?}", e)?;
136 me.print(end)
137 })?,
138 Payload::GlobalSection(s) => self.section(s, "global", |me, _end, g| {
139 write!(me.state, "[global {}] {:?}", inc(&mut i.core_globals), g.ty)?;
140 me.print(g.init_expr.get_binary_reader().original_position())?;
141 me.print_ops(g.init_expr.get_operators_reader())
142 })?,
143 Payload::StartSection { func, range } => {
144 write!(self.state, "start section")?;
145 self.print(range.start)?;
146 write!(self.state, "start function {}", func)?;
147 self.print(range.end)?;
148 }
149 Payload::DataCountSection { count, range } => {
150 write!(self.state, "data count section")?;
151 self.print(range.start)?;
152 write!(self.state, "data count {}", count)?;
153 self.print(range.end)?;
154 }
155 Payload::ElementSection(s) => self.section(s, "element", |me, _end, i| {
156 write!(me.state, "element {:?}", i.ty)?;
157 let item_count = match &i.items {
158 ElementItems::Functions(reader) => reader.count(),
159 ElementItems::Expressions(reader) => reader.count(),
160 };
161 match i.kind {
162 ElementKind::Passive => {
163 write!(me.state, " passive, {} items", item_count)?;
164 }
165 ElementKind::Active {
166 table_index,
167 offset_expr,
168 } => {
169 write!(me.state, " table[{}]", table_index)?;
170 me.print(offset_expr.get_binary_reader().original_position())?;
171 me.print_ops(offset_expr.get_operators_reader())?;
172 write!(me.state, "{} items", item_count)?;
173 }
174 ElementKind::Declared => {
175 write!(me.state, " declared {} items", item_count)?;
176 }
177 }
178 match i.items {
179 ElementItems::Functions(reader) => {
180 let mut iter = reader.into_iter();
181 me.print(iter.original_position())?;
182 while let Some(item) = iter.next() {
183 write!(me.state, "item {:?}", item?)?;
184 me.print(iter.original_position())?;
185 }
186 }
187 ElementItems::Expressions(reader) => {
188 let mut iter = reader.into_iter();
189 me.print(iter.original_position())?;
190 while let Some(item) = iter.next() {
191 write!(me.state, "item {:?}", item?)?;
192 me.print(iter.original_position())?;
193 }
194 }
195 }
196 Ok(())
197 })?,
198
199 Payload::DataSection(s) => self.section(s, "data", |me, end, i| {
200 match i.kind {
201 DataKind::Passive => {
202 write!(me.state, "data passive")?;
203 me.print(end - i.data.len())?;
204 }
205 DataKind::Active {
206 memory_index,
207 offset_expr,
208 } => {
209 write!(me.state, "data memory[{}]", memory_index)?;
210 me.print(offset_expr.get_binary_reader().original_position())?;
211 me.print_ops(offset_expr.get_operators_reader())?;
212 }
213 }
214 me.print_byte_header()?;
215 for _ in 0..NBYTES {
216 write!(me.dst, "---")?;
217 }
218 writeln!(me.dst, "-| ... {} bytes of data", i.data.len())?;
219 me.cur = end;
220 Ok(())
221 })?,
222
223 Payload::CodeSectionStart { count, range, size } => {
224 write!(self.state, "code section")?;
225 self.print(range.start)?;
226 write!(self.state, "{} count", count)?;
227 self.print(range.end - size as usize)?;
228 }
229
230 Payload::CodeSectionEntry(body) => {
231 writeln!(
232 self.dst,
233 "============== func {} ====================",
234 inc(&mut i.core_funcs),
235 )?;
236 write!(self.state, "size of function")?;
237 self.print(body.get_binary_reader().original_position())?;
238 let mut locals = body.get_locals_reader()?;
239 write!(self.state, "{} local blocks", locals.get_count())?;
240 self.print(locals.original_position())?;
241 for _ in 0..locals.get_count() {
242 let (amt, ty) = locals.read()?;
243 write!(self.state, "{} locals of type {:?}", amt, ty)?;
244 self.print(locals.original_position())?;
245 }
246 self.print_ops(body.get_operators_reader()?)?;
247 }
248
249 Payload::ModuleSection { range, .. } => {
251 write!(
252 self.state,
253 "[core module {}] inline size",
254 inc(&mut i.core_modules)
255 )?;
256 self.print(range.start)?;
257 self.nesting += 1;
258 stack.push(i);
259 i = Indices::default();
260 }
261
262 Payload::InstanceSection(s) => self.section(s, "core instance", |me, end, e| {
263 write!(
264 me.state,
265 "[core instance {}] {:?}",
266 inc(&mut i.core_instances),
267 e
268 )?;
269 me.print(end)
270 })?,
271
272 Payload::CoreTypeSection(s) => self.section(s, "core type", |me, end, t| {
273 write!(me.state, "[core type {}] {:?}", inc(&mut i.core_types), t)?;
274 me.print(end)
275 })?,
276
277 Payload::ComponentSection { range, .. } => {
278 write!(
279 self.state,
280 "[component {}] inline size",
281 inc(&mut i.components)
282 )?;
283 self.print(range.start)?;
284 self.nesting += 1;
285 stack.push(i);
286 i = Indices::default();
287 }
288
289 Payload::ComponentInstanceSection(s) => {
290 self.section(s, "component instance", |me, end, e| {
291 write!(me.state, "[instance {}] {:?}", inc(&mut i.instances), e)?;
292 me.print(end)
293 })?
294 }
295
296 Payload::ComponentAliasSection(s) => {
297 self.section(s, "component alias", |me, end, a| {
298 let (kind, num) = match a {
299 ComponentAlias::InstanceExport {
300 kind: ComponentExternalKind::Module,
301 ..
302 }
303 | ComponentAlias::Outer {
304 kind: ComponentOuterAliasKind::CoreModule,
305 ..
306 } => ("module", inc(&mut i.core_modules)),
307 ComponentAlias::Outer {
308 kind: ComponentOuterAliasKind::CoreType,
309 ..
310 } => ("core type", inc(&mut i.core_types)),
311 ComponentAlias::InstanceExport {
312 kind: ComponentExternalKind::Func,
313 ..
314 } => ("func", inc(&mut i.funcs)),
315 ComponentAlias::InstanceExport {
316 kind: ComponentExternalKind::Value,
317 ..
318 } => ("value", inc(&mut i.values)),
319 ComponentAlias::InstanceExport {
320 kind: ComponentExternalKind::Type,
321 ..
322 }
323 | ComponentAlias::Outer {
324 kind: ComponentOuterAliasKind::Type,
325 ..
326 } => ("type", inc(&mut i.types)),
327 ComponentAlias::InstanceExport {
328 kind: ComponentExternalKind::Instance,
329 ..
330 } => ("instance", inc(&mut i.instances)),
331 ComponentAlias::InstanceExport {
332 kind: ComponentExternalKind::Component,
333 ..
334 }
335 | ComponentAlias::Outer {
336 kind: ComponentOuterAliasKind::Component,
337 ..
338 } => ("component", inc(&mut i.components)),
339 ComponentAlias::CoreInstanceExport { kind, .. } => match kind {
340 ExternalKind::Func => ("core func", inc(&mut i.core_funcs)),
341 ExternalKind::Table => ("core table", inc(&mut i.core_tables)),
342 ExternalKind::Memory => ("core memory", inc(&mut i.core_memories)),
343 ExternalKind::Global => ("core global", inc(&mut i.core_globals)),
344 ExternalKind::Tag => ("core tag", inc(&mut i.core_tags)),
345 },
346 };
347
348 write!(me.state, "alias [{} {}] {:?}", kind, num, a)?;
349 me.print(end)
350 })?
351 }
352
353 Payload::ComponentTypeSection(s) => {
354 self.section(s, "component type", |me, end, t| {
355 write!(me.state, "[type {}] {:?}", inc(&mut i.types), t)?;
356 component_types.push(match t {
357 ComponentType::Defined(_) => ComponentTypeKind::DefinedType,
358 ComponentType::Func(_) => ComponentTypeKind::Func,
359 ComponentType::Component(_) => ComponentTypeKind::Component,
360 ComponentType::Instance(_) => ComponentTypeKind::Instance,
361 });
362 me.print(end)
363 })?
364 }
365
366 Payload::ComponentImportSection(s) => {
367 self.section(s, "component import", |me, end, item| {
368 let (desc, idx) = match item.ty {
369 ComponentTypeRef::Module(..) => ("module", inc(&mut i.core_modules)),
370 ComponentTypeRef::Func(..) => ("func", inc(&mut i.funcs)),
371 ComponentTypeRef::Value(..) => ("value", inc(&mut i.values)),
372 ComponentTypeRef::Type(..) => ("type", inc(&mut i.types)),
373 ComponentTypeRef::Instance(..) => ("instance", inc(&mut i.instances)),
374 ComponentTypeRef::Component(..) => {
375 ("component", inc(&mut i.components))
376 }
377 };
378 write!(me.state, "[{desc} {idx}] {item:?}")?;
379 me.print(end)
380 })?
381 }
382
383 Payload::ComponentCanonicalSection(s) => {
384 self.section(s, "canonical function", |me, end, f| {
385 let (name, col) = match &f {
386 CanonicalFunction::Lift { .. } => ("func", &mut i.funcs),
387 CanonicalFunction::Lower { .. } => ("core func", &mut i.core_funcs),
388 };
389
390 write!(me.state, "[{} {}] {:?}", name, inc(col), f)?;
391 me.print(end)
392 })?
393 }
394
395 Payload::ComponentExportSection(s) => {
396 self.section(s, "component export", |me, end, e| {
397 write!(me.state, "export {:?}", e)?;
398 me.print(end)
399 })?
400 }
401
402 Payload::ComponentStartSection { start, range } => {
403 write!(self.state, "start section")?;
404 self.print(range.start)?;
405 write!(self.state, "{:?}", start)?;
406 self.print(range.end)?;
407 }
408
409 Payload::CustomSection(c) => {
410 write!(self.state, "custom section")?;
411 self.print(c.range().start)?;
412 write!(self.state, "name: {:?}", c.name())?;
413 self.print(c.data_offset())?;
414 if c.name() == "name" {
415 let mut iter = NameSectionReader::new(c.data(), c.data_offset());
416 while let Some(section) = iter.next() {
417 self.print_custom_name_section(section?, iter.original_position())?;
418 }
419 } else if c.name() == "component-name" {
420 let mut iter = ComponentNameSectionReader::new(c.data(), c.data_offset());
421 while let Some(section) = iter.next() {
422 self.print_custom_component_name_section(
423 section?,
424 iter.original_position(),
425 )?;
426 }
427 } else {
428 self.print_byte_header()?;
429 for _ in 0..NBYTES {
430 write!(self.dst, "---")?;
431 }
432 writeln!(self.dst, "-| ... {} bytes of data", c.data().len())?;
433 self.cur += c.data().len();
434 }
435 }
436 Payload::UnknownSection {
437 id,
438 range,
439 contents,
440 } => {
441 write!(self.state, "unknown section: {}", id)?;
442 self.print(range.start)?;
443 self.print_byte_header()?;
444 for _ in 0..NBYTES {
445 write!(self.dst, "---")?;
446 }
447 writeln!(self.dst, "-| ... {} bytes of data", contents.len())?;
448 self.cur += contents.len();
449 }
450 Payload::End(_) => {
451 self.nesting -= 1;
452 if self.nesting > 0 {
453 i = stack.pop().unwrap();
454 }
455 }
456 }
457 }
458
459 Ok(())
460 }
461
462 fn print_name_map(&mut self, thing: &str, n: NameMap<'_>) -> Result<()> {
463 self.section(n, thing, |me, end, naming| {
464 write!(me.state, "{:?}", naming)?;
465 me.print(end)
466 })
467 }
468
469 fn print_indirect_name_map(
470 &mut self,
471 thing_a: &str,
472 thing_b: &str,
473 n: IndirectNameMap<'_>,
474 ) -> Result<()> {
475 self.section(n, thing_b, |me, _end, naming| {
476 write!(me.state, "{} {} ", thing_a, naming.index)?;
477 me.print_name_map(thing_b, naming.names)
478 })
479 }
480
481 fn print_custom_name_section(&mut self, name: Name<'_>, end: usize) -> Result<()> {
482 match name {
483 Name::Module { name, name_range } => {
484 write!(self.state, "module name")?;
485 self.print(name_range.start)?;
486 write!(self.state, "{:?}", name)?;
487 self.print(name_range.end)?;
488 }
489 Name::Function(n) => self.print_name_map("function", n)?,
490 Name::Local(n) => self.print_indirect_name_map("function", "local", n)?,
491 Name::Label(n) => self.print_indirect_name_map("function", "label", n)?,
492 Name::Type(n) => self.print_name_map("type", n)?,
493 Name::Table(n) => self.print_name_map("table", n)?,
494 Name::Memory(n) => self.print_name_map("memory", n)?,
495 Name::Global(n) => self.print_name_map("global", n)?,
496 Name::Element(n) => self.print_name_map("element", n)?,
497 Name::Data(n) => self.print_name_map("data", n)?,
498 Name::Unknown { ty, range, .. } => {
499 write!(self.state, "unknown names: {}", ty)?;
500 self.print(range.start)?;
501 self.print(end)?;
502 }
503 }
504 Ok(())
505 }
506
507 fn print_custom_component_name_section(
508 &mut self,
509 name: ComponentName<'_>,
510 end: usize,
511 ) -> Result<()> {
512 match name {
513 ComponentName::Component { name, name_range } => {
514 write!(self.state, "component name")?;
515 self.print(name_range.start)?;
516 write!(self.state, "{:?}", name)?;
517 self.print(name_range.end)?;
518 }
519 ComponentName::CoreFuncs(n) => self.print_name_map("core func", n)?,
520 ComponentName::CoreTables(n) => self.print_name_map("core table", n)?,
521 ComponentName::CoreGlobals(n) => self.print_name_map("core global", n)?,
522 ComponentName::CoreMemories(n) => self.print_name_map("core memory", n)?,
523 ComponentName::CoreInstances(n) => self.print_name_map("core instance", n)?,
524 ComponentName::CoreModules(n) => self.print_name_map("core module", n)?,
525 ComponentName::CoreTypes(n) => self.print_name_map("core type", n)?,
526 ComponentName::Types(n) => self.print_name_map("type", n)?,
527 ComponentName::Instances(n) => self.print_name_map("instance", n)?,
528 ComponentName::Components(n) => self.print_name_map("component", n)?,
529 ComponentName::Funcs(n) => self.print_name_map("func", n)?,
530 ComponentName::Values(n) => self.print_name_map("value", n)?,
531 ComponentName::Unknown { ty, range, .. } => {
532 write!(self.state, "unknown names: {}", ty)?;
533 self.print(range.start)?;
534 self.print(end)?;
535 }
536 }
537 Ok(())
538 }
539
540 fn section<'b, T>(
541 &mut self,
542 iter: SectionLimited<'b, T>,
543 name: &str,
544 print: impl FnMut(&mut Self, usize, T) -> Result<()>,
545 ) -> Result<()>
546 where
547 T: FromReader<'b>,
548 {
549 write!(self.state, "{} section", name)?;
550 self.print(iter.range().start)?;
551 self.print_iter(iter, print)
552 }
553
554 fn print_iter<'b, T>(
555 &mut self,
556 iter: SectionLimited<'b, T>,
557 mut print: impl FnMut(&mut Self, usize, T) -> Result<()>,
558 ) -> Result<()>
559 where
560 T: FromReader<'b>,
561 {
562 write!(self.state, "{} count", iter.count())?;
563 let mut iter = iter.into_iter();
564 self.print(iter.original_position())?;
565 while let Some(item) = iter.next() {
566 print(self, iter.original_position(), item?)?;
567 }
568 Ok(())
569 }
570
571 fn print_ops(&mut self, mut i: OperatorsReader) -> Result<()> {
572 while !i.eof() {
573 match i.visit_operator(self) {
574 Ok(()) => {}
575 Err(_) => write!(self.state, "??")?,
576 }
577 self.print(i.original_position())?;
578 }
579 Ok(())
580 }
581
582 fn print(&mut self, end: usize) -> Result<()> {
583 assert!(
584 self.cur < end,
585 "{:#x} >= {:#x}\ntrying to print: {}",
586 self.cur,
587 end,
588 self.state,
589 );
590 let bytes = &self.bytes[self.cur..end];
591 self.print_byte_header()?;
592 for (i, chunk) in bytes.chunks(NBYTES).enumerate() {
593 if i > 0 {
594 for _ in 0..self.nesting - 1 {
595 write!(self.dst, " ")?;
596 }
597 for _ in 0..self.offset_width {
598 write!(self.dst, " ")?;
599 }
600 write!(self.dst, " |")?;
601 }
602 for j in 0..NBYTES {
603 match chunk.get(j) {
604 Some(b) => write!(self.dst, " {:02x}", b)?,
605 None => write!(self.dst, " ")?,
606 }
607 }
608 if i == 0 {
609 write!(self.dst, " | ")?;
610 write!(self.dst, "{}", &self.state)?;
611 self.state.truncate(0);
612 }
613 writeln!(self.dst)?;
614 }
615 self.cur = end;
616 Ok(())
617 }
618
619 fn print_byte_header(&mut self) -> Result<()> {
620 for _ in 0..self.nesting - 1 {
621 write!(self.dst, " ")?;
622 }
623 write!(
624 self.dst,
625 "{:#width$x} |",
626 self.cur,
627 width = self.offset_width + 2
628 )?;
629 Ok(())
630 }
631}
632
633fn inc(spot: &mut u32) -> u32 {
634 let ret = *spot;
635 *spot += 1;
636 ret
637}
638
639macro_rules! define_visit_operator {
640 ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
641 $(
642 fn $visit(&mut self $($(,$arg: $argty)*)?) {
643 write!(
644 self.state,
645 concat!(
646 "{}"
647 $( $(, " ", stringify!($arg), ":{:?}")* )?
648 ),
649 stringify!($visit).strip_prefix("visit_").unwrap(),
650 $( $($arg,)* )?
651 ).unwrap();
652 }
653 )*
654 }
655}
656
657impl<'a> VisitOperator<'a> for Dump<'_> {
658 type Output = ();
659
660 wasmparser::for_each_operator!(define_visit_operator);
661}