1#![deny(missing_docs)]
10
11use anyhow::{anyhow, bail, Context, Result};
12use operator::{OpPrinter, OperatorSeparator, OperatorState, PrintOperator, PrintOperatorFolded};
13use std::collections::{HashMap, HashSet};
14use std::fmt;
15use std::io;
16use std::marker;
17use std::mem;
18use std::path::Path;
19use wasmparser::*;
20
21const MAX_LOCALS: u32 = 50000;
22const MAX_NESTING_TO_PRINT: u32 = 50;
23const MAX_WASM_FUNCTIONS: u32 = 1_000_000;
24const MAX_WASM_FUNCTION_SIZE: u32 = 128 * 1024;
25
26#[cfg(feature = "component-model")]
27mod component;
28mod operator;
29mod print;
30
31pub use self::print::*;
32
33pub fn print_file(file: impl AsRef<Path>) -> Result<String> {
36 let file = file.as_ref();
37 let contents = std::fs::read(file).context(format!("failed to read `{}`", file.display()))?;
38 print_bytes(contents)
39}
40
41pub fn print_bytes(wasm: impl AsRef<[u8]>) -> Result<String> {
44 let mut dst = String::new();
45 Config::new().print(wasm.as_ref(), &mut PrintFmtWrite(&mut dst))?;
46 Ok(dst)
47}
48
49#[derive(Debug)]
54pub struct Config {
55 print_offsets: bool,
56 print_skeleton: bool,
57 name_unnamed: bool,
58 fold_instructions: bool,
59 indent_text: String,
60}
61
62impl Default for Config {
63 fn default() -> Self {
64 Self {
65 print_offsets: false,
66 print_skeleton: false,
67 name_unnamed: false,
68 fold_instructions: false,
69 indent_text: " ".to_string(),
70 }
71 }
72}
73
74struct Printer<'cfg, 'env> {
76 config: &'cfg Config,
77 result: &'cfg mut (dyn Print + 'env),
78 nesting: u32,
79 line: usize,
80 group_lines: Vec<usize>,
81 code_section_hints: Vec<(u32, Vec<(usize, BranchHint)>)>,
82}
83
84#[derive(Default)]
85struct CoreState {
86 types: Vec<Option<SubType>>,
87 funcs: u32,
88 func_to_type: Vec<Option<u32>>,
89 memories: u32,
90 tags: u32,
91 tag_to_type: Vec<Option<u32>>,
92 globals: u32,
93 tables: u32,
94 #[cfg(feature = "component-model")]
95 modules: u32,
96 #[cfg(feature = "component-model")]
97 instances: u32,
98 func_names: NamingMap<u32, NameFunc>,
99 local_names: NamingMap<(u32, u32), NameLocal>,
100 label_names: NamingMap<(u32, u32), NameLabel>,
101 type_names: NamingMap<u32, NameType>,
102 field_names: NamingMap<(u32, u32), NameField>,
103 tag_names: NamingMap<u32, NameTag>,
104 table_names: NamingMap<u32, NameTable>,
105 memory_names: NamingMap<u32, NameMemory>,
106 global_names: NamingMap<u32, NameGlobal>,
107 element_names: NamingMap<u32, NameElem>,
108 data_names: NamingMap<u32, NameData>,
109 #[cfg(feature = "component-model")]
110 module_names: NamingMap<u32, NameModule>,
111 #[cfg(feature = "component-model")]
112 instance_names: NamingMap<u32, NameInstance>,
113}
114
115struct NamingMap<T, K> {
125 index_to_name: HashMap<T, Naming>,
126 _marker: marker::PhantomData<K>,
127}
128
129impl<T, K> Default for NamingMap<T, K> {
130 fn default() -> NamingMap<T, K> {
131 NamingMap {
132 index_to_name: HashMap::new(),
133 _marker: marker::PhantomData,
134 }
135 }
136}
137
138#[derive(Default)]
139#[cfg(feature = "component-model")]
140struct ComponentState {
141 types: u32,
142 funcs: u32,
143 instances: u32,
144 components: u32,
145 values: u32,
146 type_names: NamingMap<u32, NameType>,
147 func_names: NamingMap<u32, NameFunc>,
148 component_names: NamingMap<u32, NameComponent>,
149 instance_names: NamingMap<u32, NameInstance>,
150 value_names: NamingMap<u32, NameValue>,
151}
152
153struct State {
154 encoding: Encoding,
155 name: Option<Naming>,
156 core: CoreState,
157 #[cfg(feature = "component-model")]
158 component: ComponentState,
159 custom_section_place: Option<&'static str>,
160}
161
162impl State {
163 fn new(encoding: Encoding) -> Self {
164 Self {
165 encoding,
166 name: None,
167 core: CoreState::default(),
168 #[cfg(feature = "component-model")]
169 component: ComponentState::default(),
170 custom_section_place: None,
171 }
172 }
173}
174
175struct Naming {
176 name: String,
177 kind: NamingKind,
178}
179
180enum NamingKind {
181 DollarName,
182 DollarQuotedName,
183 SyntheticPrefix(String),
184}
185
186impl Config {
187 pub fn new() -> Self {
190 Self::default()
191 }
192
193 pub fn print_offsets(&mut self, print: bool) -> &mut Self {
196 self.print_offsets = print;
197 self
198 }
199
200 pub fn print_skeleton(&mut self, print: bool) -> &mut Self {
203 self.print_skeleton = print;
204 self
205 }
206
207 pub fn name_unnamed(&mut self, enable: bool) -> &mut Self {
218 self.name_unnamed = enable;
219 self
220 }
221
222 pub fn fold_instructions(&mut self, enable: bool) -> &mut Self {
238 self.fold_instructions = enable;
239 self
240 }
241
242 pub fn indent_text(&mut self, text: impl Into<String>) -> &mut Self {
249 self.indent_text = text.into();
250 self
251 }
252
253 pub fn print(&self, wasm: &[u8], result: &mut impl Print) -> Result<()> {
258 Printer {
259 config: self,
260 result,
261 code_section_hints: Vec::new(),
262 group_lines: Vec::new(),
263 line: 0,
264 nesting: 0,
265 }
266 .print_contents(wasm)
267 }
268
269 pub fn offsets_and_lines<'a>(
272 &self,
273 wasm: &[u8],
274 storage: &'a mut String,
275 ) -> Result<impl Iterator<Item = (Option<usize>, &'a str)> + 'a> {
276 struct TrackingPrint<'a> {
277 dst: &'a mut String,
278 lines: Vec<usize>,
279 line_offsets: Vec<Option<usize>>,
280 }
281
282 impl Print for TrackingPrint<'_> {
283 fn write_str(&mut self, s: &str) -> io::Result<()> {
284 self.dst.push_str(s);
285 Ok(())
286 }
287 fn start_line(&mut self, offset: Option<usize>) {
288 self.lines.push(self.dst.len());
289 self.line_offsets.push(offset);
290 }
291 }
292
293 let mut output = TrackingPrint {
294 dst: storage,
295 lines: Vec::new(),
296 line_offsets: Vec::new(),
297 };
298 self.print(wasm, &mut output)?;
299
300 let TrackingPrint {
301 dst,
302 lines,
303 line_offsets,
304 } = output;
305 let end = dst.len();
306 let dst = &dst[..];
307 let mut offsets = line_offsets.into_iter();
308 let mut lines = lines.into_iter().peekable();
309
310 Ok(std::iter::from_fn(move || {
311 let offset = offsets.next()?;
312 let i = lines.next()?;
313 let j = lines.peek().copied().unwrap_or(end);
314 let line = &dst[i..j];
315 Some((offset, line))
316 }))
317 }
318}
319
320impl Printer<'_, '_> {
321 fn read_names<'a>(
322 &mut self,
323 mut bytes: &'a [u8],
324 mut parser: Parser,
325 state: &mut State,
326 ) -> Result<()> {
327 loop {
328 let payload = match parser.parse(bytes, true)? {
329 Chunk::NeedMoreData(_) => unreachable!(),
330 Chunk::Parsed { payload, consumed } => {
331 bytes = &bytes[consumed..];
332 payload
333 }
334 };
335
336 match payload {
337 Payload::CodeSectionStart { size, .. } => {
338 if size as usize > bytes.len() {
339 bail!("invalid code section size");
340 }
341 bytes = &bytes[size as usize..];
342 parser.skip_section();
343 }
344 #[cfg(feature = "component-model")]
345 Payload::ModuleSection {
346 unchecked_range: range,
347 ..
348 }
349 | Payload::ComponentSection {
350 unchecked_range: range,
351 ..
352 } => {
353 let offset = range.end - range.start;
354 if offset > bytes.len() {
355 bail!("invalid module or component section range");
356 }
357 bytes = &bytes[offset..];
358 }
359
360 Payload::CustomSection(c) => {
361 match c.as_known() {
363 KnownCustom::Name(reader) => {
364 drop(self.register_names(state, reader));
365 }
366 #[cfg(feature = "component-model")]
367 KnownCustom::ComponentName(reader) => {
368 drop(self.register_component_names(state, reader));
369 }
370 KnownCustom::BranchHints(reader) => {
371 drop(self.register_branch_hint_section(reader));
372 }
373 _ => {}
374 }
375 }
376
377 Payload::End(_) => break,
378 _ => {}
379 }
380 }
381
382 Ok(())
383 }
384
385 fn ensure_module(states: &[State]) -> Result<()> {
386 if !matches!(states.last().unwrap().encoding, Encoding::Module) {
387 bail!("a module section was encountered when parsing a component");
388 }
389
390 Ok(())
391 }
392
393 #[cfg(feature = "component-model")]
394 fn ensure_component(states: &[State]) -> Result<()> {
395 if !matches!(states.last().unwrap().encoding, Encoding::Component) {
396 bail!("a component section was encountered when parsing a module");
397 }
398
399 Ok(())
400 }
401
402 fn print_contents(&mut self, mut bytes: &[u8]) -> Result<()> {
403 self.result.start_line(Some(0));
404
405 let mut expected = None;
406 let mut states: Vec<State> = Vec::new();
407 let mut parser = Parser::new(0);
408 #[cfg(feature = "component-model")]
409 let mut parsers = Vec::new();
410
411 loop {
412 let payload = match parser.parse(bytes, true)? {
413 Chunk::NeedMoreData(_) => unreachable!(),
414 Chunk::Parsed { payload, consumed } => {
415 bytes = &bytes[consumed..];
416 payload
417 }
418 };
419 match payload {
420 Payload::Version { encoding, .. } => {
421 if let Some(e) = expected {
422 if encoding != e {
423 bail!("incorrect encoding for nested module or component");
424 }
425 expected = None;
426 }
427
428 assert!(states.last().map(|s| s.encoding) != Some(Encoding::Module));
429
430 match encoding {
431 Encoding::Module => {
432 states.push(State::new(Encoding::Module));
433 states.last_mut().unwrap().custom_section_place = Some("before first");
434 if states.len() > 1 {
435 self.start_group("core module")?;
436 } else {
437 self.start_group("module")?;
438 }
439
440 #[cfg(feature = "component-model")]
441 if states.len() > 1 {
442 let parent = &states[states.len() - 2];
443 self.result.write_str(" ")?;
444 self.print_name(&parent.core.module_names, parent.core.modules)?;
445 }
446 }
447 Encoding::Component => {
448 #[cfg(feature = "component-model")]
449 {
450 states.push(State::new(Encoding::Component));
451 self.start_group("component")?;
452
453 if states.len() > 1 {
454 let parent = &states[states.len() - 2];
455 self.result.write_str(" ")?;
456 self.print_name(
457 &parent.component.component_names,
458 parent.component.components,
459 )?;
460 }
461 }
462 #[cfg(not(feature = "component-model"))]
463 {
464 bail!(
465 "support for printing components disabled \
466 at compile-time"
467 );
468 }
469 }
470 }
471
472 let len = states.len();
473 let state = states.last_mut().unwrap();
474
475 self.read_names(bytes, parser.clone(), state)?;
478
479 if len == 1 {
480 if let Some(name) = state.name.as_ref() {
481 self.result.write_str(" ")?;
482 name.write(self)?;
483 }
484 }
485 }
486 Payload::CustomSection(c) => {
487 let printed =
490 self.result
491 .print_custom_section(c.name(), c.data_offset(), c.data())?;
492 if printed {
493 continue;
494 }
495
496 let state = states.last().unwrap();
501 let start = self.nesting;
502 let err = match self.print_custom_section(state, c.clone()) {
503 Ok(()) => continue,
504 Err(e) if !e.is::<BinaryReaderError>() => return Err(e),
505 Err(e) => e,
506 };
507
508 while self.nesting > start {
515 self.end_group()?;
516 }
517 let msg = format!("failed to parse custom section `{}`: {err}", c.name());
518 for line in msg.lines() {
519 self.newline(c.data_offset())?;
520 write!(self.result, ";; {line}")?;
521 }
522 self.newline(c.range().end)?;
523 }
524 Payload::TypeSection(s) => {
525 self.update_custom_section_place(&mut states, "after type");
526 self.print_types(states.last_mut().unwrap(), s)?;
527 }
528 Payload::ImportSection(s) => {
529 self.update_custom_section_place(&mut states, "after import");
530 Self::ensure_module(&states)?;
531 self.print_imports(states.last_mut().unwrap(), s)?
532 }
533 Payload::FunctionSection(reader) => {
534 self.update_custom_section_place(&mut states, "after func");
535 Self::ensure_module(&states)?;
536 if reader.count() > MAX_WASM_FUNCTIONS {
537 bail!(
538 "module contains {} functions which exceeds the limit of {}",
539 reader.count(),
540 MAX_WASM_FUNCTIONS
541 );
542 }
543 for ty in reader {
544 states.last_mut().unwrap().core.func_to_type.push(Some(ty?))
545 }
546 }
547 Payload::TableSection(s) => {
548 self.update_custom_section_place(&mut states, "after table");
549 Self::ensure_module(&states)?;
550 self.print_tables(states.last_mut().unwrap(), s)?
551 }
552 Payload::MemorySection(s) => {
553 self.update_custom_section_place(&mut states, "after memory");
554 Self::ensure_module(&states)?;
555 self.print_memories(states.last_mut().unwrap(), s)?
556 }
557 Payload::TagSection(s) => {
558 self.update_custom_section_place(&mut states, "after tag");
559 Self::ensure_module(&states)?;
560 self.print_tags(states.last_mut().unwrap(), s)?
561 }
562 Payload::GlobalSection(s) => {
563 self.update_custom_section_place(&mut states, "after global");
564 Self::ensure_module(&states)?;
565 self.print_globals(states.last_mut().unwrap(), s)?
566 }
567 Payload::ExportSection(s) => {
568 self.update_custom_section_place(&mut states, "after export");
569 Self::ensure_module(&states)?;
570 self.print_exports(states.last().unwrap(), s)?
571 }
572 Payload::StartSection { func, range } => {
573 self.update_custom_section_place(&mut states, "after start");
574 Self::ensure_module(&states)?;
575 self.newline(range.start)?;
576 self.start_group("start ")?;
577 self.print_idx(&states.last().unwrap().core.func_names, func)?;
578 self.end_group()?;
579 }
580 Payload::ElementSection(s) => {
581 self.update_custom_section_place(&mut states, "after element");
582 Self::ensure_module(&states)?;
583 self.print_elems(states.last_mut().unwrap(), s)?;
584 }
585 Payload::CodeSectionStart { .. } => {
586 self.update_custom_section_place(&mut states, "after code");
587 Self::ensure_module(&states)?;
588 }
589 Payload::CodeSectionEntry(body) => {
590 self.print_code_section_entry(states.last_mut().unwrap(), &body)?
591 }
592 Payload::DataCountSection { .. } => {
593 Self::ensure_module(&states)?;
594 }
596 Payload::DataSection(s) => {
597 self.update_custom_section_place(&mut states, "after data");
598 Self::ensure_module(&states)?;
599 self.print_data(states.last_mut().unwrap(), s)?;
600 }
601
602 #[cfg(feature = "component-model")]
603 Payload::ModuleSection {
604 parser: inner,
605 unchecked_range: range,
606 } => {
607 Self::ensure_component(&states)?;
608 expected = Some(Encoding::Module);
609 parsers.push(parser);
610 parser = inner;
611 self.newline(range.start)?;
612 }
613 #[cfg(feature = "component-model")]
614 Payload::InstanceSection(s) => {
615 Self::ensure_component(&states)?;
616 self.print_instances(states.last_mut().unwrap(), s)?;
617 }
618 #[cfg(feature = "component-model")]
619 Payload::CoreTypeSection(s) => self.print_core_types(&mut states, s)?,
620 #[cfg(feature = "component-model")]
621 Payload::ComponentSection {
622 parser: inner,
623 unchecked_range: range,
624 } => {
625 Self::ensure_component(&states)?;
626 expected = Some(Encoding::Component);
627 parsers.push(parser);
628 parser = inner;
629 self.newline(range.start)?;
630 }
631 #[cfg(feature = "component-model")]
632 Payload::ComponentInstanceSection(s) => {
633 Self::ensure_component(&states)?;
634 self.print_component_instances(states.last_mut().unwrap(), s)?;
635 }
636 #[cfg(feature = "component-model")]
637 Payload::ComponentAliasSection(s) => {
638 Self::ensure_component(&states)?;
639 self.print_component_aliases(&mut states, s)?;
640 }
641 #[cfg(feature = "component-model")]
642 Payload::ComponentTypeSection(s) => {
643 Self::ensure_component(&states)?;
644 self.print_component_types(&mut states, s)?;
645 }
646 #[cfg(feature = "component-model")]
647 Payload::ComponentCanonicalSection(s) => {
648 Self::ensure_component(&states)?;
649 self.print_canonical_functions(states.last_mut().unwrap(), s)?;
650 }
651 #[cfg(feature = "component-model")]
652 Payload::ComponentStartSection { start, range } => {
653 Self::ensure_component(&states)?;
654 self.print_component_start(states.last_mut().unwrap(), range.start, start)?;
655 }
656 #[cfg(feature = "component-model")]
657 Payload::ComponentImportSection(s) => {
658 Self::ensure_component(&states)?;
659 self.print_component_imports(states.last_mut().unwrap(), s)?;
660 }
661 #[cfg(feature = "component-model")]
662 Payload::ComponentExportSection(s) => {
663 Self::ensure_component(&states)?;
664 self.print_component_exports(states.last_mut().unwrap(), s)?;
665 }
666
667 Payload::End(offset) => {
668 self.end_group()?; #[cfg(feature = "component-model")]
671 {
672 let state = states.pop().unwrap();
673 if let Some(parent) = states.last_mut() {
674 match state.encoding {
675 Encoding::Module => {
676 parent.core.modules += 1;
677 }
678 Encoding::Component => {
679 parent.component.components += 1;
680 }
681 }
682 parser = parsers.pop().unwrap();
683 continue;
684 }
685 }
686 self.newline(offset)?;
687 if self.config.print_offsets {
688 self.result.newline()?;
689 }
690 break;
691 }
692
693 other => match other.as_section() {
694 Some((id, _)) => bail!("found unknown section `{}`", id),
695 None => bail!("found unknown payload"),
696 },
697 }
698 }
699
700 Ok(())
701 }
702
703 fn update_custom_section_place(&self, states: &mut Vec<State>, place: &'static str) {
704 if let Some(last) = states.last_mut() {
705 if let Some(prev) = &mut last.custom_section_place {
706 *prev = place;
707 }
708 }
709 }
710
711 fn start_group(&mut self, name: &str) -> Result<()> {
712 write!(self.result, "(")?;
713 self.result.start_keyword()?;
714 write!(self.result, "{name}")?;
715 self.result.reset_color()?;
716 self.nesting += 1;
717 self.group_lines.push(self.line);
718 Ok(())
719 }
720
721 fn end_group(&mut self) -> Result<()> {
722 self.nesting -= 1;
723 if let Some(line) = self.group_lines.pop() {
724 if line != self.line {
725 self.newline_unknown_pos()?;
726 }
727 }
728 self.result.write_str(")")?;
729 Ok(())
730 }
731
732 fn register_names(&mut self, state: &mut State, names: NameSectionReader<'_>) -> Result<()> {
733 fn indirect_name_map<K>(
734 into: &mut NamingMap<(u32, u32), K>,
735 names: IndirectNameMap<'_>,
736 name: &str,
737 ) -> Result<()> {
738 for indirect in names {
739 let indirect = indirect?;
740 let mut used = match name {
741 "label" => None,
743 "local" | "field" => Some(HashSet::new()),
744 _ => unimplemented!("{name} is an unknown type of indirect names"),
745 };
746 for naming in indirect.names {
747 let naming = naming?;
748 into.index_to_name.insert(
749 (indirect.index, naming.index),
750 Naming::new(naming.name, naming.index, name, used.as_mut()),
751 );
752 }
753 }
754 Ok(())
755 }
756
757 for section in names {
758 match section? {
759 Name::Module { name, .. } => {
760 let name = Naming::new(name, 0, "module", None);
761 state.name = Some(name);
762 }
763 Name::Function(n) => name_map(&mut state.core.func_names, n, "func")?,
764 Name::Local(n) => indirect_name_map(&mut state.core.local_names, n, "local")?,
765 Name::Label(n) => indirect_name_map(&mut state.core.label_names, n, "label")?,
766 Name::Type(n) => name_map(&mut state.core.type_names, n, "type")?,
767 Name::Table(n) => name_map(&mut state.core.table_names, n, "table")?,
768 Name::Memory(n) => name_map(&mut state.core.memory_names, n, "memory")?,
769 Name::Global(n) => name_map(&mut state.core.global_names, n, "global")?,
770 Name::Element(n) => name_map(&mut state.core.element_names, n, "elem")?,
771 Name::Data(n) => name_map(&mut state.core.data_names, n, "data")?,
772 Name::Field(n) => indirect_name_map(&mut state.core.field_names, n, "field")?,
773 Name::Tag(n) => name_map(&mut state.core.tag_names, n, "tag")?,
774 Name::Unknown { .. } => (),
775 }
776 }
777 Ok(())
778 }
779
780 fn print_rec(
781 &mut self,
782 state: &mut State,
783 offset: Option<usize>,
784 rec: RecGroup,
785 is_component: bool,
786 ) -> Result<()> {
787 if rec.is_explicit_rec_group() {
788 if is_component {
789 self.start_group("core rec")?;
790 } else {
791 self.start_group("rec")?;
792 }
793 for ty in rec.into_types() {
794 match offset {
795 Some(offset) => self.newline(offset + 2)?,
796 None => self.newline_unknown_pos()?,
797 }
798 self.print_type(state, ty, false)?;
799 }
800 self.end_group()?; } else {
802 assert_eq!(rec.types().len(), 1);
803 let ty = rec.into_types().next().unwrap();
804 self.print_type(state, ty, is_component)?;
805 }
806 Ok(())
807 }
808
809 fn print_type(&mut self, state: &mut State, ty: SubType, is_component: bool) -> Result<()> {
810 if is_component {
811 self.start_group("core type ")?;
812 } else {
813 self.start_group("type ")?;
814 }
815 let ty_idx = state.core.types.len() as u32;
816 self.print_name(&state.core.type_names, ty_idx)?;
817 self.result.write_str(" ")?;
818 self.print_sub(state, &ty, ty_idx)?;
819 self.end_group()?; state.core.types.push(Some(ty));
821 Ok(())
822 }
823
824 fn print_sub(&mut self, state: &State, ty: &SubType, ty_idx: u32) -> Result<u32> {
825 let r = if !ty.is_final || !ty.supertype_idx.is_none() {
826 self.start_group("sub")?;
827 self.print_sub_type(state, ty)?;
828 let r = self.print_composite(state, &ty.composite_type, ty_idx)?;
829 self.end_group()?; r
831 } else {
832 self.print_composite(state, &ty.composite_type, ty_idx)?
833 };
834 Ok(r)
835 }
836
837 fn print_composite(&mut self, state: &State, ty: &CompositeType, ty_idx: u32) -> Result<u32> {
838 if ty.shared {
839 self.start_group("shared")?;
840 self.result.write_str(" ")?;
841 }
842 let r = match &ty.inner {
843 CompositeInnerType::Func(ty) => {
844 self.start_group("func")?;
845 let r = self.print_func_type(state, ty, None)?;
846 self.end_group()?; r
848 }
849 CompositeInnerType::Array(ty) => {
850 self.start_group("array")?;
851 let r = self.print_array_type(state, ty)?;
852 self.end_group()?; r
854 }
855 CompositeInnerType::Struct(ty) => {
856 self.start_group("struct")?;
857 let r = self.print_struct_type(state, ty, ty_idx)?;
858 self.end_group()?; r
860 }
861 CompositeInnerType::Cont(ty) => {
862 self.start_group("cont")?;
863 let r = self.print_cont_type(state, ty)?;
864 self.end_group()?; r
866 }
867 };
868 if ty.shared {
869 self.end_group()?; }
871 Ok(r)
872 }
873
874 fn print_types(&mut self, state: &mut State, parser: TypeSectionReader<'_>) -> Result<()> {
875 for ty in parser.into_iter_with_offsets() {
876 let (offset, rec_group) = ty?;
877 self.newline(offset)?;
878 self.print_rec(state, Some(offset), rec_group, false)?;
879 }
880 Ok(())
881 }
882
883 fn print_core_functype_idx(
884 &mut self,
885 state: &State,
886 idx: u32,
887 names_for: Option<u32>,
888 ) -> Result<Option<u32>> {
889 self.print_core_type_ref(state, idx)?;
890
891 match state.core.types.get(idx as usize) {
892 Some(Some(SubType {
893 composite_type:
894 CompositeType {
895 inner: CompositeInnerType::Func(ty),
896 shared: false,
897 },
898 ..
899 })) => self.print_func_type(state, ty, names_for).map(Some),
900 Some(Some(_)) | Some(None) | None => Ok(None),
901 }
902 }
903
904 fn print_func_type(
907 &mut self,
908 state: &State,
909 ty: &FuncType,
910 names_for: Option<u32>,
911 ) -> Result<u32> {
912 if !ty.params().is_empty() {
913 self.result.write_str(" ")?;
914 }
915
916 let mut params = NamedLocalPrinter::new("param");
917 for (i, param) in ty.params().iter().enumerate() {
921 params.start_local(names_for, i as u32, self, state)?;
922 self.print_valtype(state, *param)?;
923 params.end_local(self)?;
924 }
925 params.finish(self)?;
926 if !ty.results().is_empty() {
927 self.result.write_str(" ")?;
928 self.start_group("result")?;
929 for result in ty.results().iter() {
930 self.result.write_str(" ")?;
931 self.print_valtype(state, *result)?;
932 }
933 self.end_group()?;
934 }
935 Ok(ty.params().len() as u32)
936 }
937
938 fn print_field_type(
939 &mut self,
940 state: &State,
941 ty: &FieldType,
942 ty_field_idx: Option<(u32, u32)>,
943 ) -> Result<u32> {
944 self.result.write_str(" ")?;
945 if let Some(idxs @ (_, field_idx)) = ty_field_idx {
946 match state.core.field_names.index_to_name.get(&idxs) {
947 Some(name) => {
948 name.write_identifier(self)?;
949 self.result.write_str(" ")?;
950 }
951 None if self.config.name_unnamed => write!(self.result, "$#field{field_idx} ")?,
952 None => {}
953 }
954 }
955 if ty.mutable {
956 self.result.write_str("(mut ")?;
957 }
958 self.print_storage_type(state, ty.element_type)?;
959 if ty.mutable {
960 self.result.write_str(")")?;
961 }
962 Ok(0)
963 }
964
965 fn print_array_type(&mut self, state: &State, ty: &ArrayType) -> Result<u32> {
966 self.print_field_type(state, &ty.0, None)
967 }
968
969 fn print_struct_type(&mut self, state: &State, ty: &StructType, ty_idx: u32) -> Result<u32> {
970 for (field_index, field) in ty.fields.iter().enumerate() {
971 self.result.write_str(" (field")?;
972 self.print_field_type(state, field, Some((ty_idx, field_index as u32)))?;
973 self.result.write_str(")")?;
974 }
975 Ok(0)
976 }
977
978 fn print_cont_type(&mut self, state: &State, ct: &ContType) -> Result<u32> {
979 self.result.write_str(" ")?;
980 self.print_idx(&state.core.type_names, ct.0.as_module_index().unwrap())?;
981 Ok(0)
982 }
983
984 fn print_sub_type(&mut self, state: &State, ty: &SubType) -> Result<u32> {
985 self.result.write_str(" ")?;
986 if ty.is_final {
987 self.result.write_str("final ")?;
988 }
989 if let Some(idx) = ty.supertype_idx {
990 self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
991 self.result.write_str(" ")?;
992 }
993 Ok(0)
994 }
995
996 fn print_storage_type(&mut self, state: &State, ty: StorageType) -> Result<()> {
997 match ty {
998 StorageType::I8 => self.result.write_str("i8")?,
999 StorageType::I16 => self.result.write_str("i16")?,
1000 StorageType::Val(val_type) => self.print_valtype(state, val_type)?,
1001 }
1002 Ok(())
1003 }
1004
1005 fn print_valtype(&mut self, state: &State, ty: ValType) -> Result<()> {
1006 match ty {
1007 ValType::I32 => self.print_type_keyword("i32")?,
1008 ValType::I64 => self.print_type_keyword("i64")?,
1009 ValType::F32 => self.print_type_keyword("f32")?,
1010 ValType::F64 => self.print_type_keyword("f64")?,
1011 ValType::V128 => self.print_type_keyword("v128")?,
1012 ValType::Ref(rt) => self.print_reftype(state, rt)?,
1013 }
1014 Ok(())
1015 }
1016
1017 fn print_reftype(&mut self, state: &State, ty: RefType) -> Result<()> {
1018 if ty.is_nullable() {
1019 match ty.as_non_null() {
1020 RefType::FUNC => self.print_type_keyword("funcref")?,
1021 RefType::EXTERN => self.print_type_keyword("externref")?,
1022 RefType::I31 => self.print_type_keyword("i31ref")?,
1023 RefType::ANY => self.print_type_keyword("anyref")?,
1024 RefType::NONE => self.print_type_keyword("nullref")?,
1025 RefType::NOEXTERN => self.print_type_keyword("nullexternref")?,
1026 RefType::NOFUNC => self.print_type_keyword("nullfuncref")?,
1027 RefType::EQ => self.print_type_keyword("eqref")?,
1028 RefType::STRUCT => self.print_type_keyword("structref")?,
1029 RefType::ARRAY => self.print_type_keyword("arrayref")?,
1030 RefType::EXN => self.print_type_keyword("exnref")?,
1031 RefType::NOEXN => self.print_type_keyword("nullexnref")?,
1032 _ => {
1033 self.start_group("ref")?;
1034 self.result.write_str(" null ")?;
1035 self.print_heaptype(state, ty.heap_type())?;
1036 self.end_group()?;
1037 }
1038 }
1039 } else {
1040 self.start_group("ref ")?;
1041 self.print_heaptype(state, ty.heap_type())?;
1042 self.end_group()?;
1043 }
1044 Ok(())
1045 }
1046
1047 fn print_heaptype(&mut self, state: &State, ty: HeapType) -> Result<()> {
1048 match ty {
1049 HeapType::Concrete(i) => {
1050 self.print_idx(&state.core.type_names, i.as_module_index().unwrap())?;
1051 }
1052 HeapType::Abstract { shared, ty } => {
1053 use AbstractHeapType::*;
1054 if shared {
1055 self.start_group("shared ")?;
1056 }
1057 match ty {
1058 Func => self.print_type_keyword("func")?,
1059 Extern => self.print_type_keyword("extern")?,
1060 Any => self.print_type_keyword("any")?,
1061 None => self.print_type_keyword("none")?,
1062 NoExtern => self.print_type_keyword("noextern")?,
1063 NoFunc => self.print_type_keyword("nofunc")?,
1064 Eq => self.print_type_keyword("eq")?,
1065 Struct => self.print_type_keyword("struct")?,
1066 Array => self.print_type_keyword("array")?,
1067 I31 => self.print_type_keyword("i31")?,
1068 Exn => self.print_type_keyword("exn")?,
1069 NoExn => self.print_type_keyword("noexn")?,
1070 Cont => self.print_type_keyword("cont")?,
1071 NoCont => self.print_type_keyword("nocont")?,
1072 }
1073 if shared {
1074 self.end_group()?;
1075 }
1076 }
1077 }
1078 Ok(())
1079 }
1080
1081 fn print_type_keyword(&mut self, keyword: &str) -> Result<()> {
1082 self.result.start_type()?;
1083 self.result.write_str(keyword)?;
1084 self.result.reset_color()?;
1085 Ok(())
1086 }
1087
1088 fn print_imports(&mut self, state: &mut State, parser: ImportSectionReader<'_>) -> Result<()> {
1089 for import in parser.into_iter_with_offsets() {
1090 let (offset, import) = import?;
1091 self.newline(offset)?;
1092 self.print_import(state, &import, true)?;
1093 match import.ty {
1094 TypeRef::Func(idx) => {
1095 debug_assert!(state.core.func_to_type.len() == state.core.funcs as usize);
1096 state.core.funcs += 1;
1097 state.core.func_to_type.push(Some(idx))
1098 }
1099 TypeRef::Table(_) => state.core.tables += 1,
1100 TypeRef::Memory(_) => state.core.memories += 1,
1101 TypeRef::Tag(TagType {
1102 kind: _,
1103 func_type_idx: idx,
1104 }) => {
1105 debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1106 state.core.tags += 1;
1107 state.core.tag_to_type.push(Some(idx))
1108 }
1109 TypeRef::Global(_) => state.core.globals += 1,
1110 }
1111 }
1112 Ok(())
1113 }
1114
1115 fn print_import(&mut self, state: &State, import: &Import<'_>, index: bool) -> Result<()> {
1116 self.start_group("import ")?;
1117 self.print_str(import.module)?;
1118 self.result.write_str(" ")?;
1119 self.print_str(import.name)?;
1120 self.result.write_str(" ")?;
1121 self.print_import_ty(state, &import.ty, index)?;
1122 self.end_group()?;
1123 Ok(())
1124 }
1125
1126 fn print_import_ty(&mut self, state: &State, ty: &TypeRef, index: bool) -> Result<()> {
1127 match ty {
1128 TypeRef::Func(f) => {
1129 self.start_group("func ")?;
1130 if index {
1131 self.print_name(&state.core.func_names, state.core.funcs)?;
1132 self.result.write_str(" ")?;
1133 }
1134 self.print_core_type_ref(state, *f)?;
1135 }
1136 TypeRef::Table(f) => self.print_table_type(state, f, index)?,
1137 TypeRef::Memory(f) => self.print_memory_type(state, f, index)?,
1138 TypeRef::Tag(f) => self.print_tag_type(state, f, index)?,
1139 TypeRef::Global(f) => self.print_global_type(state, f, index)?,
1140 }
1141 self.end_group()?;
1142 Ok(())
1143 }
1144
1145 fn print_table_type(&mut self, state: &State, ty: &TableType, index: bool) -> Result<()> {
1146 self.start_group("table ")?;
1147 if index {
1148 self.print_name(&state.core.table_names, state.core.tables)?;
1149 self.result.write_str(" ")?;
1150 }
1151 if ty.shared {
1152 self.print_type_keyword("shared ")?;
1153 }
1154 if ty.table64 {
1155 self.print_type_keyword("i64 ")?;
1156 }
1157 self.print_limits(ty.initial, ty.maximum)?;
1158 self.result.write_str(" ")?;
1159 self.print_reftype(state, ty.element_type)?;
1160 Ok(())
1161 }
1162
1163 fn print_memory_type(&mut self, state: &State, ty: &MemoryType, index: bool) -> Result<()> {
1164 self.start_group("memory ")?;
1165 if index {
1166 self.print_name(&state.core.memory_names, state.core.memories)?;
1167 self.result.write_str(" ")?;
1168 }
1169 if ty.memory64 {
1170 self.print_type_keyword("i64 ")?;
1171 }
1172 self.print_limits(ty.initial, ty.maximum)?;
1173 if ty.shared {
1174 self.print_type_keyword(" shared")?;
1175 }
1176 if let Some(p) = ty.page_size_log2 {
1177 let p = 1_u64
1178 .checked_shl(p)
1179 .ok_or_else(|| anyhow!("left shift overflow").context("invalid page size"))?;
1180
1181 self.result.write_str(" ")?;
1182 self.start_group("pagesize ")?;
1183 write!(self.result, "{p:#x}")?;
1184 self.end_group()?;
1185 }
1186 Ok(())
1187 }
1188
1189 fn print_tag_type(&mut self, state: &State, ty: &TagType, index: bool) -> Result<()> {
1190 self.start_group("tag ")?;
1191 if index {
1192 self.print_name(&state.core.tag_names, state.core.tags)?;
1193 self.result.write_str(" ")?;
1194 }
1195 self.print_core_functype_idx(state, ty.func_type_idx, None)?;
1196 Ok(())
1197 }
1198
1199 fn print_limits<T>(&mut self, initial: T, maximum: Option<T>) -> Result<()>
1200 where
1201 T: fmt::Display,
1202 {
1203 self.result.start_literal()?;
1204 write!(self.result, "{}", initial)?;
1205 if let Some(max) = maximum {
1206 write!(self.result, " {}", max)?;
1207 }
1208 self.result.reset_color()?;
1209 Ok(())
1210 }
1211
1212 fn print_global_type(&mut self, state: &State, ty: &GlobalType, index: bool) -> Result<()> {
1213 self.start_group("global ")?;
1214 if index {
1215 self.print_name(&state.core.global_names, state.core.globals)?;
1216 self.result.write_str(" ")?;
1217 }
1218 if ty.shared || ty.mutable {
1219 self.result.write_str("(")?;
1220 if ty.shared {
1221 self.print_type_keyword("shared ")?;
1222 }
1223 if ty.mutable {
1224 self.print_type_keyword("mut ")?;
1225 }
1226 self.print_valtype(state, ty.content_type)?;
1227 self.result.write_str(")")?;
1228 } else {
1229 self.print_valtype(state, ty.content_type)?;
1230 }
1231 Ok(())
1232 }
1233
1234 fn print_tables(&mut self, state: &mut State, parser: TableSectionReader<'_>) -> Result<()> {
1235 for table in parser.into_iter_with_offsets() {
1236 let (offset, table) = table?;
1237 self.newline(offset)?;
1238 self.print_table_type(state, &table.ty, true)?;
1239 match &table.init {
1240 TableInit::RefNull => {}
1241 TableInit::Expr(expr) => {
1242 self.result.write_str(" ")?;
1243 self.print_const_expr(state, expr, self.config.fold_instructions)?;
1244 }
1245 }
1246 self.end_group()?;
1247 state.core.tables += 1;
1248 }
1249 Ok(())
1250 }
1251
1252 fn print_memories(&mut self, state: &mut State, parser: MemorySectionReader<'_>) -> Result<()> {
1253 for memory in parser.into_iter_with_offsets() {
1254 let (offset, memory) = memory?;
1255 self.newline(offset)?;
1256 self.print_memory_type(state, &memory, true)?;
1257 self.end_group()?;
1258 state.core.memories += 1;
1259 }
1260 Ok(())
1261 }
1262
1263 fn print_tags(&mut self, state: &mut State, parser: TagSectionReader<'_>) -> Result<()> {
1264 for tag in parser.into_iter_with_offsets() {
1265 let (offset, tag) = tag?;
1266 self.newline(offset)?;
1267 self.print_tag_type(state, &tag, true)?;
1268 self.end_group()?;
1269 debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1270 state.core.tags += 1;
1271 state.core.tag_to_type.push(Some(tag.func_type_idx));
1272 }
1273 Ok(())
1274 }
1275
1276 fn print_globals(&mut self, state: &mut State, parser: GlobalSectionReader<'_>) -> Result<()> {
1277 for global in parser.into_iter_with_offsets() {
1278 let (offset, global) = global?;
1279 self.newline(offset)?;
1280 self.print_global_type(state, &global.ty, true)?;
1281 self.result.write_str(" ")?;
1282 self.print_const_expr(state, &global.init_expr, self.config.fold_instructions)?;
1283 self.end_group()?;
1284 state.core.globals += 1;
1285 }
1286 Ok(())
1287 }
1288
1289 fn print_code_section_entry(
1290 &mut self,
1291 state: &mut State,
1292 body: &FunctionBody<'_>,
1293 ) -> Result<()> {
1294 let mut body = body.get_binary_reader();
1295 let offset = body.original_position();
1296 self.newline(offset)?;
1297 self.start_group("func ")?;
1298 let func_idx = state.core.funcs;
1299 self.print_name(&state.core.func_names, func_idx)?;
1300 self.result.write_str(" ")?;
1301 let ty = match state.core.func_to_type.get(func_idx as usize) {
1302 Some(Some(x)) => *x,
1303 _ => panic!("invalid function type"),
1304 };
1305 let params = self
1306 .print_core_functype_idx(state, ty, Some(func_idx))?
1307 .unwrap_or(0);
1308
1309 let hints = match self.code_section_hints.last() {
1312 Some((f, _)) if *f == func_idx => {
1313 let (_, hints) = self.code_section_hints.pop().unwrap();
1314 hints
1315 }
1316 _ => Vec::new(),
1317 };
1318
1319 if self.config.print_skeleton {
1320 self.result.write_str(" ...")?;
1321 } else {
1322 self.print_func_body(state, func_idx, params, &mut body, &hints)?;
1323 }
1324
1325 self.end_group()?;
1326 state.core.funcs += 1;
1327 Ok(())
1328 }
1329
1330 fn print_func_body(
1331 &mut self,
1332 state: &mut State,
1333 func_idx: u32,
1334 params: u32,
1335 body: &mut BinaryReader<'_>,
1336 branch_hints: &[(usize, BranchHint)],
1337 ) -> Result<()> {
1338 let mut first = true;
1339 let mut local_idx = 0;
1340 let mut locals = NamedLocalPrinter::new("local");
1341 let func_start = body.original_position();
1342 for _ in 0..body.read_var_u32()? {
1343 let offset = body.original_position();
1344 let cnt = body.read_var_u32()?;
1345 let ty = body.read()?;
1346 if MAX_LOCALS
1347 .checked_sub(local_idx)
1348 .and_then(|s| s.checked_sub(cnt))
1349 .is_none()
1350 {
1351 bail!("function exceeds the maximum number of locals that can be printed");
1352 }
1353 for _ in 0..cnt {
1354 if first {
1355 self.newline(offset)?;
1356 first = false;
1357 }
1358 locals.start_local(Some(func_idx), params + local_idx, self, state)?;
1359 self.print_valtype(state, ty)?;
1360 locals.end_local(self)?;
1361 local_idx += 1;
1362 }
1363 }
1364 locals.finish(self)?;
1365
1366 let nesting_start = self.nesting;
1367 let fold_instructions = self.config.fold_instructions;
1368 let mut operator_state = OperatorState::new(self, OperatorSeparator::Newline);
1369
1370 if fold_instructions {
1371 let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1372 folded_printer.set_offset(func_start);
1373 folded_printer.begin_function(func_idx)?;
1374 Self::print_operators(body, branch_hints, func_start, &mut folded_printer)?;
1375 folded_printer.finalize()?;
1376 } else {
1377 let mut flat_printer = PrintOperator::new(self, state, &mut operator_state);
1378 Self::print_operators(body, branch_hints, func_start, &mut flat_printer)?;
1379 }
1380
1381 if self.nesting != nesting_start {
1387 self.nesting = nesting_start;
1388 self.newline(body.original_position())?;
1389 }
1390
1391 Ok(())
1392 }
1393
1394 fn print_operators<'a, O: OpPrinter>(
1395 body: &mut BinaryReader<'a>,
1396 mut branch_hints: &[(usize, BranchHint)],
1397 func_start: usize,
1398 op_printer: &mut O,
1399 ) -> Result<()> {
1400 while !body.is_end_then_eof() {
1401 if let Some(((hint_offset, hint), rest)) = branch_hints.split_first() {
1404 if hint.func_offset == (body.original_position() - func_start) as u32 {
1405 branch_hints = rest;
1406 op_printer.branch_hint(*hint_offset, hint.taken)?;
1407 }
1408 }
1409
1410 op_printer.set_offset(body.original_position());
1411 op_printer.visit_operator(body)?;
1412 }
1413 Ok(())
1414 }
1415
1416 fn newline(&mut self, offset: usize) -> Result<()> {
1417 self.print_newline(Some(offset))
1418 }
1419
1420 fn newline_unknown_pos(&mut self) -> Result<()> {
1421 self.print_newline(None)
1422 }
1423
1424 fn print_newline(&mut self, offset: Option<usize>) -> Result<()> {
1425 self.result.newline()?;
1426 self.result.start_line(offset);
1427
1428 if self.config.print_offsets {
1429 match offset {
1430 Some(offset) => write!(self.result, "(;@{offset:<6x};)")?,
1431 None => self.result.write_str(" ")?,
1432 }
1433 }
1434 self.line += 1;
1435
1436 for _ in 0..self.nesting.min(MAX_NESTING_TO_PRINT) {
1440 self.result.write_str(&self.config.indent_text)?;
1441 }
1442 Ok(())
1443 }
1444
1445 fn print_exports(&mut self, state: &State, data: ExportSectionReader) -> Result<()> {
1446 for export in data.into_iter_with_offsets() {
1447 let (offset, export) = export?;
1448 self.newline(offset)?;
1449 self.print_export(state, &export)?;
1450 }
1451 Ok(())
1452 }
1453
1454 fn print_export(&mut self, state: &State, export: &Export) -> Result<()> {
1455 self.start_group("export ")?;
1456 self.print_str(export.name)?;
1457 self.result.write_str(" ")?;
1458 self.print_external_kind(state, export.kind, export.index)?;
1459 self.end_group()?; Ok(())
1461 }
1462
1463 fn print_external_kind(&mut self, state: &State, kind: ExternalKind, index: u32) -> Result<()> {
1464 match kind {
1465 ExternalKind::Func => {
1466 self.start_group("func ")?;
1467 self.print_idx(&state.core.func_names, index)?;
1468 }
1469 ExternalKind::Table => {
1470 self.start_group("table ")?;
1471 self.print_idx(&state.core.table_names, index)?;
1472 }
1473 ExternalKind::Global => {
1474 self.start_group("global ")?;
1475 self.print_idx(&state.core.global_names, index)?;
1476 }
1477 ExternalKind::Memory => {
1478 self.start_group("memory ")?;
1479 self.print_idx(&state.core.memory_names, index)?;
1480 }
1481 ExternalKind::Tag => {
1482 self.start_group("tag ")?;
1483 write!(self.result, "{index}")?;
1484 }
1485 }
1486 self.end_group()?;
1487 Ok(())
1488 }
1489
1490 fn print_core_type_ref(&mut self, state: &State, idx: u32) -> Result<()> {
1491 self.start_group("type ")?;
1492 self.print_idx(&state.core.type_names, idx)?;
1493 self.end_group()?;
1494 Ok(())
1495 }
1496
1497 fn print_idx<K>(&mut self, names: &NamingMap<u32, K>, idx: u32) -> Result<()>
1498 where
1499 K: NamingNamespace,
1500 {
1501 self._print_idx(&names.index_to_name, idx, K::desc())
1502 }
1503
1504 fn _print_idx(&mut self, names: &HashMap<u32, Naming>, idx: u32, desc: &str) -> Result<()> {
1505 self.result.start_name()?;
1506 match names.get(&idx) {
1507 Some(name) => name.write_identifier(self)?,
1508 None if self.config.name_unnamed => write!(self.result, "$#{desc}{idx}")?,
1509 None => write!(self.result, "{idx}")?,
1510 }
1511 self.result.reset_color()?;
1512 Ok(())
1513 }
1514
1515 fn print_local_idx(&mut self, state: &State, func: u32, idx: u32) -> Result<()> {
1516 self.result.start_name()?;
1517 match state.core.local_names.index_to_name.get(&(func, idx)) {
1518 Some(name) => name.write_identifier(self)?,
1519 None if self.config.name_unnamed => write!(self.result, "$#local{idx}")?,
1520 None => write!(self.result, "{}", idx)?,
1521 }
1522 self.result.reset_color()?;
1523 Ok(())
1524 }
1525
1526 fn print_field_idx(&mut self, state: &State, ty: u32, idx: u32) -> Result<()> {
1527 self.result.start_name()?;
1528 match state.core.field_names.index_to_name.get(&(ty, idx)) {
1529 Some(name) => name.write_identifier(self)?,
1530 None if self.config.name_unnamed => write!(self.result, "$#field{idx}")?,
1531 None => write!(self.result, "{}", idx)?,
1532 }
1533 self.result.reset_color()?;
1534 Ok(())
1535 }
1536
1537 fn print_name<K>(&mut self, names: &NamingMap<u32, K>, cur_idx: u32) -> Result<()>
1538 where
1539 K: NamingNamespace,
1540 {
1541 self._print_name(&names.index_to_name, cur_idx, K::desc())
1542 }
1543
1544 fn _print_name(
1545 &mut self,
1546 names: &HashMap<u32, Naming>,
1547 cur_idx: u32,
1548 desc: &str,
1549 ) -> Result<()> {
1550 self.result.start_name()?;
1551 match names.get(&cur_idx) {
1552 Some(name) => {
1553 name.write(self)?;
1554 self.result.write_str(" ")?;
1555 }
1556 None if self.config.name_unnamed => {
1557 write!(self.result, "$#{desc}{cur_idx} ")?;
1558 }
1559 None => {}
1560 }
1561 write!(self.result, "(;{cur_idx};)")?;
1562 self.result.reset_color()?;
1563 Ok(())
1564 }
1565
1566 fn print_elems(&mut self, state: &mut State, data: ElementSectionReader) -> Result<()> {
1567 for (i, elem) in data.into_iter_with_offsets().enumerate() {
1568 let (offset, mut elem) = elem?;
1569 self.newline(offset)?;
1570 self.start_group("elem ")?;
1571 self.print_name(&state.core.element_names, i as u32)?;
1572 match &mut elem.kind {
1573 ElementKind::Passive => {}
1574 ElementKind::Declared => self.result.write_str(" declare")?,
1575 ElementKind::Active {
1576 table_index,
1577 offset_expr,
1578 } => {
1579 if let Some(table_index) = *table_index {
1580 self.result.write_str(" ")?;
1581 self.start_group("table ")?;
1582 self.print_idx(&state.core.table_names, table_index)?;
1583 self.end_group()?;
1584 }
1585 self.result.write_str(" ")?;
1586 self.print_const_expr_sugar(state, offset_expr, "offset")?;
1587 }
1588 }
1589 self.result.write_str(" ")?;
1590
1591 if self.config.print_skeleton {
1592 self.result.write_str("...")?;
1593 } else {
1594 match elem.items {
1595 ElementItems::Functions(reader) => {
1596 self.result.write_str("func")?;
1597 for idx in reader {
1598 self.result.write_str(" ")?;
1599 self.print_idx(&state.core.func_names, idx?)?
1600 }
1601 }
1602 ElementItems::Expressions(ty, reader) => {
1603 self.print_reftype(state, ty)?;
1604 for expr in reader {
1605 self.result.write_str(" ")?;
1606 self.print_const_expr_sugar(state, &expr?, "item")?
1607 }
1608 }
1609 }
1610 }
1611 self.end_group()?;
1612 }
1613 Ok(())
1614 }
1615
1616 fn print_data(&mut self, state: &mut State, data: DataSectionReader) -> Result<()> {
1617 for (i, data) in data.into_iter_with_offsets().enumerate() {
1618 let (offset, data) = data?;
1619 self.newline(offset)?;
1620 self.start_group("data ")?;
1621 self.print_name(&state.core.data_names, i as u32)?;
1622 self.result.write_str(" ")?;
1623 match &data.kind {
1624 DataKind::Passive => {}
1625 DataKind::Active {
1626 memory_index,
1627 offset_expr,
1628 } => {
1629 if *memory_index != 0 {
1630 self.start_group("memory ")?;
1631 self.print_idx(&state.core.memory_names, *memory_index)?;
1632 self.end_group()?;
1633 self.result.write_str(" ")?;
1634 }
1635 self.print_const_expr_sugar(state, offset_expr, "offset")?;
1636 self.result.write_str(" ")?;
1637 }
1638 }
1639 if self.config.print_skeleton {
1640 self.result.write_str("...")?;
1641 } else {
1642 self.print_bytes(data.data)?;
1643 }
1644 self.end_group()?;
1645 }
1646 Ok(())
1647 }
1648
1649 fn print_const_expr_sugar(
1653 &mut self,
1654 state: &mut State,
1655 expr: &ConstExpr,
1656 explicit: &str,
1657 ) -> Result<()> {
1658 self.start_group("")?;
1659 let mut reader = expr.get_operators_reader();
1660
1661 if reader.read().is_ok() && !reader.is_end_then_eof() {
1662 write!(self.result, "{explicit} ")?;
1663 self.print_const_expr(state, expr, self.config.fold_instructions)?;
1664 } else {
1665 self.print_const_expr(state, expr, false)?;
1666 }
1667
1668 self.end_group()?;
1669 Ok(())
1670 }
1671
1672 fn print_const_expr(&mut self, state: &mut State, expr: &ConstExpr, fold: bool) -> Result<()> {
1674 let mut reader = expr.get_binary_reader();
1675 let mut operator_state = OperatorState::new(self, OperatorSeparator::NoneThenSpace);
1676
1677 if fold {
1678 let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1679 folded_printer.begin_const_expr();
1680 Self::print_operators(&mut reader, &[], 0, &mut folded_printer)?;
1681 folded_printer.finalize()?;
1682 } else {
1683 let mut op_printer = PrintOperator::new(self, state, &mut operator_state);
1684 Self::print_operators(&mut reader, &[], 0, &mut op_printer)?;
1685 }
1686
1687 Ok(())
1688 }
1689
1690 fn print_str(&mut self, name: &str) -> Result<()> {
1691 self.result.start_literal()?;
1692 self.result.write_str("\"")?;
1693 self.print_str_contents(name)?;
1694 self.result.write_str("\"")?;
1695 self.result.reset_color()?;
1696 Ok(())
1697 }
1698
1699 fn print_str_contents(&mut self, name: &str) -> Result<()> {
1700 for c in name.chars() {
1701 let v = c as u32;
1702 if (0x20..0x7f).contains(&v) && c != '"' && c != '\\' && v < 0xff {
1703 write!(self.result, "{c}")?;
1704 } else {
1705 write!(self.result, "\\u{{{v:x}}}",)?;
1706 }
1707 }
1708 Ok(())
1709 }
1710
1711 fn print_bytes(&mut self, bytes: &[u8]) -> Result<()> {
1712 self.result.start_literal()?;
1713 self.result.write_str("\"")?;
1714 for byte in bytes {
1715 if *byte >= 0x20 && *byte < 0x7f && *byte != b'"' && *byte != b'\\' {
1716 write!(self.result, "{}", *byte as char)?;
1717 } else {
1718 self.hex_byte(*byte)?;
1719 }
1720 }
1721 self.result.write_str("\"")?;
1722 self.result.reset_color()?;
1723 Ok(())
1724 }
1725
1726 fn hex_byte(&mut self, byte: u8) -> Result<()> {
1727 write!(self.result, "\\{byte:02x}")?;
1728 Ok(())
1729 }
1730
1731 fn print_custom_section(
1732 &mut self,
1733 state: &State,
1734 section: CustomSectionReader<'_>,
1735 ) -> Result<()> {
1736 match section.as_known() {
1737 KnownCustom::Producers(s) => {
1741 self.newline(section.range().start)?;
1742 self.print_producers_section(s)
1743 }
1744 KnownCustom::Dylink0(s) => {
1745 self.newline(section.range().start)?;
1746 self.print_dylink0_section(s)
1747 }
1748
1749 KnownCustom::Name(_) | KnownCustom::BranchHints(_) => Ok(()),
1752 #[cfg(feature = "component-model")]
1753 KnownCustom::ComponentName(_) => Ok(()),
1754
1755 _ => self.print_raw_custom_section(state, section),
1758 }
1759 }
1760
1761 fn print_raw_custom_section(
1762 &mut self,
1763 state: &State,
1764 section: CustomSectionReader<'_>,
1765 ) -> Result<()> {
1766 self.newline(section.range().start)?;
1767 self.start_group("@custom ")?;
1768 self.print_str(section.name())?;
1769 if let Some(place) = state.custom_section_place {
1770 write!(self.result, " ({place})")?;
1771 }
1772 self.result.write_str(" ")?;
1773 if self.config.print_skeleton {
1774 self.result.write_str("...")?;
1775 } else {
1776 self.print_bytes(section.data())?;
1777 }
1778 self.end_group()?;
1779 Ok(())
1780 }
1781
1782 fn print_producers_section(&mut self, section: ProducersSectionReader<'_>) -> Result<()> {
1783 self.start_group("@producers")?;
1784 for field in section {
1785 let field = field?;
1786 for value in field.values.into_iter_with_offsets() {
1787 let (offset, value) = value?;
1788 self.newline(offset)?;
1789 self.start_group(field.name)?;
1790 self.result.write_str(" ")?;
1791 self.print_str(value.name)?;
1792 self.result.write_str(" ")?;
1793 self.print_str(value.version)?;
1794 self.end_group()?;
1795 }
1796 }
1797 self.end_group()?;
1798 Ok(())
1799 }
1800
1801 fn print_dylink0_section(&mut self, mut section: Dylink0SectionReader<'_>) -> Result<()> {
1802 self.start_group("@dylink.0")?;
1803 loop {
1804 let start = section.original_position();
1805 let next = match section.next() {
1806 Some(Ok(next)) => next,
1807 Some(Err(e)) => return Err(e.into()),
1808 None => break,
1809 };
1810 match next {
1811 Dylink0Subsection::MemInfo(info) => {
1812 self.newline(start)?;
1813 self.start_group("mem-info")?;
1814 if info.memory_size > 0 || info.memory_alignment > 0 {
1815 write!(
1816 self.result,
1817 " (memory {} {})",
1818 info.memory_size, info.memory_alignment
1819 )?;
1820 }
1821 if info.table_size > 0 || info.table_alignment > 0 {
1822 write!(
1823 self.result,
1824 " (table {} {})",
1825 info.table_size, info.table_alignment
1826 )?;
1827 }
1828 self.end_group()?;
1829 }
1830 Dylink0Subsection::Needed(needed) => {
1831 self.newline(start)?;
1832 self.start_group("needed")?;
1833 for s in needed {
1834 self.result.write_str(" ")?;
1835 self.print_str(s)?;
1836 }
1837 self.end_group()?;
1838 }
1839 Dylink0Subsection::ExportInfo(info) => {
1840 for info in info {
1841 self.newline(start)?;
1842 self.start_group("export-info ")?;
1843 self.print_str(info.name)?;
1844 self.print_dylink0_flags(info.flags)?;
1845 self.end_group()?;
1846 }
1847 }
1848 Dylink0Subsection::ImportInfo(info) => {
1849 for info in info {
1850 self.newline(start)?;
1851 self.start_group("import-info ")?;
1852 self.print_str(info.module)?;
1853 self.result.write_str(" ")?;
1854 self.print_str(info.field)?;
1855 self.print_dylink0_flags(info.flags)?;
1856 self.end_group()?;
1857 }
1858 }
1859 Dylink0Subsection::Unknown { ty, .. } => {
1860 bail!("don't know how to print dylink.0 subsection id {ty}");
1861 }
1862 }
1863 }
1864 self.end_group()?;
1865 Ok(())
1866 }
1867
1868 fn print_dylink0_flags(&mut self, mut flags: SymbolFlags) -> Result<()> {
1869 macro_rules! print_flag {
1870 ($($name:ident = $text:tt)*) => ({$(
1871 if flags.contains(SymbolFlags::$name) {
1872 flags.remove(SymbolFlags::$name);
1873 write!(self.result, concat!(" ", $text))?;
1874 }
1875 )*})
1876 }
1877 print_flag! {
1879 BINDING_WEAK = "binding-weak"
1880 BINDING_LOCAL = "binding-local"
1881 VISIBILITY_HIDDEN = "visibility-hidden"
1882 UNDEFINED = "undefined"
1883 EXPORTED = "exported"
1884 EXPLICIT_NAME = "explicit-name"
1885 NO_STRIP = "no-strip"
1886 TLS = "tls"
1887 ABSOLUTE = "absolute"
1888 }
1889 if !flags.is_empty() {
1890 write!(self.result, " {:#x}", flags)?;
1891 }
1892 Ok(())
1893 }
1894
1895 fn register_branch_hint_section(&mut self, section: BranchHintSectionReader<'_>) -> Result<()> {
1896 self.code_section_hints.clear();
1897 for func in section {
1898 let func = func?;
1899 if self.code_section_hints.len() >= MAX_WASM_FUNCTIONS as usize {
1900 bail!("found too many hints");
1901 }
1902 if func.hints.count() >= MAX_WASM_FUNCTION_SIZE {
1903 bail!("found too many hints");
1904 }
1905 let hints = func
1906 .hints
1907 .into_iter_with_offsets()
1908 .collect::<wasmparser::Result<Vec<_>>>()?;
1909 self.code_section_hints.push((func.func, hints));
1910 }
1911 self.code_section_hints.reverse();
1912 Ok(())
1913 }
1914}
1915
1916struct NamedLocalPrinter {
1917 group_name: &'static str,
1918 in_group: bool,
1919 end_group_after_local: bool,
1920 first: bool,
1921}
1922
1923impl NamedLocalPrinter {
1924 fn new(group_name: &'static str) -> NamedLocalPrinter {
1925 NamedLocalPrinter {
1926 group_name,
1927 in_group: false,
1928 end_group_after_local: false,
1929 first: true,
1930 }
1931 }
1932
1933 fn start_local(
1934 &mut self,
1935 func: Option<u32>,
1936 local: u32,
1937 dst: &mut Printer,
1938 state: &State,
1939 ) -> Result<()> {
1940 let name = state
1941 .core
1942 .local_names
1943 .index_to_name
1944 .get(&(func.unwrap_or(u32::MAX), local));
1945
1946 if name.is_some() && self.in_group {
1949 dst.end_group()?;
1950 self.in_group = false;
1951 }
1952
1953 if self.first {
1954 self.first = false;
1955 } else {
1956 dst.result.write_str(" ")?;
1957 }
1958
1959 if !self.in_group {
1962 dst.start_group(self.group_name)?;
1963 dst.result.write_str(" ")?;
1964 self.in_group = true;
1965 }
1966
1967 match name {
1969 Some(name) => {
1970 name.write(dst)?;
1971 dst.result.write_str(" ")?;
1972 self.end_group_after_local = true;
1973 }
1974 None if dst.config.name_unnamed && func.is_some() => {
1975 write!(dst.result, "$#local{local} ")?;
1976 self.end_group_after_local = true;
1977 }
1978 None => {
1979 self.end_group_after_local = false;
1980 }
1981 }
1982 Ok(())
1983 }
1984
1985 fn end_local(&mut self, dst: &mut Printer) -> Result<()> {
1986 if self.end_group_after_local {
1987 dst.end_group()?;
1988 self.end_group_after_local = false;
1989 self.in_group = false;
1990 }
1991 Ok(())
1992 }
1993 fn finish(self, dst: &mut Printer) -> Result<()> {
1994 if self.in_group {
1995 dst.end_group()?;
1996 }
1997 Ok(())
1998 }
1999}
2000
2001macro_rules! print_float {
2002 ($name:ident $float:ident $uint:ident $sint:ident $exp_bits:tt) => {
2003 fn $name(&mut self, mut bits: $uint) -> Result<()> {
2004 let int_width = mem::size_of::<$uint>() * 8;
2006 let exp_width = $exp_bits;
2007 let mantissa_width = int_width - 1 - exp_width;
2008 let bias = (1 << (exp_width - 1)) - 1;
2009 let max_exp = (1 as $sint) << (exp_width - 1);
2010 let min_exp = -max_exp + 1;
2011
2012 let f = $float::from_bits(bits);
2014 if bits >> (int_width - 1) != 0 {
2015 bits ^= 1 << (int_width - 1);
2016 self.result.write_str("-")?;
2017 }
2018 if f.is_infinite() {
2019 self.result.start_literal()?;
2020 self.result.write_str("inf ")?;
2021 self.result.start_comment()?;
2022 write!(self.result, "(;={f};)")?;
2023 self.result.reset_color()?;
2024 return Ok(());
2025 }
2026 if f.is_nan() {
2027 let payload = bits & ((1 << mantissa_width) - 1);
2028 self.result.start_literal()?;
2029 if payload == 1 << (mantissa_width - 1) {
2030 self.result.write_str("nan ")?;
2031 self.result.start_comment()?;
2032 write!(self.result, "(;={f};)")?;
2033 } else {
2034 write!(self.result, "nan:{:#x} ", payload)?;
2035 self.result.start_comment()?;
2036 write!(self.result, "(;={f};)")?;
2037 }
2038 self.result.reset_color()?;
2039 return Ok(());
2040 }
2041
2042 let mut exponent = (((bits << 1) as $sint) >> (mantissa_width + 1)).wrapping_sub(bias);
2058 exponent = (exponent << (int_width - exp_width)) >> (int_width - exp_width);
2059 let mut fraction = bits & ((1 << mantissa_width) - 1);
2060 self.result.start_literal()?;
2061 self.result.write_str("0x")?;
2062 if bits == 0 {
2063 self.result.write_str("0p+0")?;
2064 } else {
2065 self.result.write_str("1")?;
2066 if fraction > 0 {
2067 fraction <<= (int_width - mantissa_width);
2068
2069 if exponent == min_exp {
2073 let leading = fraction.leading_zeros();
2074 if (leading as usize) < int_width - 1 {
2075 fraction <<= leading + 1;
2076 } else {
2077 fraction = 0;
2078 }
2079 exponent -= leading as $sint;
2080 }
2081
2082 self.result.write_str(".")?;
2083 while fraction > 0 {
2084 write!(self.result, "{:x}", fraction >> (int_width - 4))?;
2085 fraction <<= 4;
2086 }
2087 }
2088 write!(self.result, "p{:+}", exponent)?;
2089 }
2090 self.result.start_comment()?;
2091 write!(self.result, " (;={};)", f)?;
2092 self.result.reset_color()?;
2093 Ok(())
2094 }
2095 };
2096}
2097
2098impl Printer<'_, '_> {
2099 print_float!(print_f32 f32 u32 i32 8);
2100 print_float!(print_f64 f64 u64 i64 11);
2101}
2102
2103impl Naming {
2104 fn new<'a>(
2105 name: &'a str,
2106 index: u32,
2107 group: &str,
2108 used: Option<&mut HashSet<&'a str>>,
2109 ) -> Naming {
2110 let mut kind = NamingKind::DollarName;
2111 if name.chars().any(|c| !is_idchar(c)) {
2112 kind = NamingKind::DollarQuotedName;
2113 }
2114
2115 if name.is_empty()
2134 || name.starts_with('#')
2135 || used.map(|set| !set.insert(name)).unwrap_or(false)
2136 {
2137 kind = NamingKind::SyntheticPrefix(format!("#{group}{index}"));
2138 }
2139 return Naming {
2140 kind,
2141 name: name.to_string(),
2142 };
2143
2144 fn is_idchar(c: char) -> bool {
2146 matches!(
2147 c,
2148 '0'..='9'
2149 | 'a'..='z'
2150 | 'A'..='Z'
2151 | '!'
2152 | '#'
2153 | '$'
2154 | '%'
2155 | '&'
2156 | '\''
2157 | '*'
2158 | '+'
2159 | '-'
2160 | '.'
2161 | '/'
2162 | ':'
2163 | '<'
2164 | '='
2165 | '>'
2166 | '?'
2167 | '@'
2168 | '\\'
2169 | '^'
2170 | '_'
2171 | '`'
2172 | '|'
2173 | '~'
2174 )
2175 }
2176 }
2177
2178 fn write_identifier(&self, printer: &mut Printer<'_, '_>) -> Result<()> {
2179 match &self.kind {
2180 NamingKind::DollarName => {
2181 printer.result.write_str("$")?;
2182 printer.result.write_str(&self.name)?;
2183 }
2184 NamingKind::DollarQuotedName => {
2185 printer.result.write_str("$\"")?;
2186 printer.print_str_contents(&self.name)?;
2187 printer.result.write_str("\"")?;
2188 }
2189 NamingKind::SyntheticPrefix(prefix) => {
2190 printer.result.write_str("$\"")?;
2191 printer.result.write_str(&prefix)?;
2192 printer.result.write_str(" ")?;
2193 printer.print_str_contents(&self.name)?;
2194 printer.result.write_str("\"")?;
2195 }
2196 }
2197 Ok(())
2198 }
2199
2200 fn write(&self, dst: &mut Printer<'_, '_>) -> Result<()> {
2201 self.write_identifier(dst)?;
2202 match &self.kind {
2203 NamingKind::DollarName | NamingKind::DollarQuotedName => {}
2204
2205 NamingKind::SyntheticPrefix(_) => {
2206 dst.result.write_str(" ")?;
2207 dst.start_group("@name \"")?;
2208 dst.print_str_contents(&self.name)?;
2209 dst.result.write_str("\"")?;
2210 dst.end_group()?;
2211 }
2212 }
2213 Ok(())
2214 }
2215}
2216
2217trait NamingNamespace {
2219 fn desc() -> &'static str;
2220}
2221
2222macro_rules! naming_namespaces {
2223 ($(struct $name:ident => $desc:tt)*) => ($(
2224 struct $name;
2225
2226 impl NamingNamespace for $name {
2227 fn desc() -> &'static str { $desc }
2228 }
2229 )*)
2230}
2231
2232naming_namespaces! {
2233 struct NameFunc => "func"
2234 struct NameGlobal => "global"
2235 struct NameMemory => "memory"
2236 struct NameLocal => "local"
2237 struct NameLabel => "label"
2238 struct NameTable => "table"
2239 struct NameType => "type"
2240 struct NameField => "field"
2241 struct NameData => "data"
2242 struct NameElem => "elem"
2243 struct NameTag => "tag"
2244}
2245
2246#[cfg(feature = "component-model")]
2247naming_namespaces! {
2248 struct NameModule => "module"
2249 struct NameInstance => "instance"
2250 struct NameValue => "value"
2251 struct NameComponent => "component"
2252}
2253
2254fn name_map<K>(into: &mut NamingMap<u32, K>, names: NameMap<'_>, name: &str) -> Result<()> {
2255 let mut used = HashSet::new();
2256 for naming in names {
2257 let naming = naming?;
2258 into.index_to_name.insert(
2259 naming.index,
2260 Naming::new(naming.name, naming.index, name, Some(&mut used)),
2261 );
2262 }
2263 Ok(())
2264}