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