77//! and debugging and such.
88
99#![ deny( missing_docs) ]
10+ #![ cfg_attr( docsrs, feature( doc_auto_cfg) ) ]
1011
1112use anyhow:: { Context , Result , anyhow, bail} ;
1213use operator:: { OpPrinter , OperatorSeparator , OperatorState , PrintOperator , PrintOperatorFolded } ;
@@ -25,6 +26,12 @@ const MAX_WASM_FUNCTION_SIZE: u32 = 128 * 1024;
2526
2627#[ cfg( feature = "component-model" ) ]
2728mod component;
29+ #[ cfg( feature = "validate" ) ]
30+ mod operand_stack;
31+ #[ cfg( not( feature = "validate" ) ) ]
32+ mod operand_stack_disabled;
33+ #[ cfg( not( feature = "validate" ) ) ]
34+ use operand_stack_disabled as operand_stack;
2835mod operator;
2936mod print;
3037
@@ -57,6 +64,7 @@ pub struct Config {
5764 name_unnamed : bool ,
5865 fold_instructions : bool ,
5966 indent_text : String ,
67+ print_operand_stack : bool ,
6068}
6169
6270impl Default for Config {
@@ -67,6 +75,7 @@ impl Default for Config {
6775 name_unnamed : false ,
6876 fold_instructions : false ,
6977 indent_text : " " . to_string ( ) ,
78+ print_operand_stack : false ,
7079 }
7180 }
7281}
@@ -246,6 +255,30 @@ impl Config {
246255 self
247256 }
248257
258+ /// Print the operand stack types within function bodies,
259+ /// flagging newly pushed operands when color output is enabled. E.g.:
260+ ///
261+ /// ```wasm
262+ /// (module
263+ /// (type (;0;) (func))
264+ /// (func (;0;) (type 0)
265+ /// i32.const 4
266+ /// ;; [i32]
267+ /// i32.const 5
268+ /// ;; [i32 i32]
269+ /// i32.add
270+ /// ;; [i32]
271+ /// drop
272+ /// ;; []
273+ /// )
274+ /// )
275+ /// ```
276+ #[ cfg( feature = "validate" ) ]
277+ pub fn print_operand_stack ( & mut self , enable : bool ) -> & mut Self {
278+ self . print_operand_stack = enable;
279+ self
280+ }
281+
249282 /// Select the string to use when indenting.
250283 ///
251284 /// The indent allowed here are arbitrary and unchecked. You should enter
@@ -415,6 +448,12 @@ impl Printer<'_, '_> {
415448 #[ cfg( feature = "component-model" ) ]
416449 let mut parsers = Vec :: new ( ) ;
417450
451+ let mut validator = if self . config . print_operand_stack {
452+ operand_stack:: Validator :: new ( )
453+ } else {
454+ None
455+ } ;
456+
418457 loop {
419458 let payload = match parser. parse ( bytes, true ) ? {
420459 Chunk :: NeedMoreData ( _) => unreachable ! ( ) ,
@@ -423,6 +462,15 @@ impl Printer<'_, '_> {
423462 payload
424463 }
425464 } ;
465+ if let Some ( validator) = & mut validator {
466+ match validator. payload ( & payload) {
467+ Ok ( ( ) ) => { }
468+ Err ( e) => {
469+ self . newline_unknown_pos ( ) ?;
470+ write ! ( self . result, ";; module or component is invalid: {e}" ) ?;
471+ }
472+ }
473+ }
426474 match payload {
427475 Payload :: Version { encoding, .. } => {
428476 if let Some ( e) = expected {
@@ -605,7 +653,11 @@ impl Printer<'_, '_> {
605653 Self :: ensure_module ( & states) ?;
606654 }
607655 Payload :: CodeSectionEntry ( body) => {
608- self . print_code_section_entry ( states. last_mut ( ) . unwrap ( ) , & body) ?;
656+ self . print_code_section_entry (
657+ states. last_mut ( ) . unwrap ( ) ,
658+ & body,
659+ validator. as_mut ( ) . and_then ( |v| v. next_func ( ) ) ,
660+ ) ?;
609661 self . update_custom_section_place ( & mut states, "after code" ) ;
610662 }
611663 Payload :: DataCountSection { .. } => {
@@ -699,6 +751,7 @@ impl Printer<'_, '_> {
699751 }
700752 }
701753 parser = parsers. pop ( ) . unwrap ( ) ;
754+
702755 continue ;
703756 }
704757 }
@@ -1328,6 +1381,7 @@ impl Printer<'_, '_> {
13281381 & mut self ,
13291382 state : & mut State ,
13301383 body : & FunctionBody < ' _ > ,
1384+ validator : Option < operand_stack:: FuncValidator > ,
13311385 ) -> Result < ( ) > {
13321386 self . newline ( body. get_binary_reader ( ) . original_position ( ) ) ?;
13331387 self . start_group ( "func " ) ?;
@@ -1355,7 +1409,7 @@ impl Printer<'_, '_> {
13551409 if self . config . print_skeleton {
13561410 self . result . write_str ( " ..." ) ?;
13571411 } else {
1358- self . print_func_body ( state, func_idx, params, & body, & hints) ?;
1412+ self . print_func_body ( state, func_idx, params, & body, & hints, validator ) ?;
13591413 }
13601414
13611415 self . end_group ( ) ?;
@@ -1370,6 +1424,7 @@ impl Printer<'_, '_> {
13701424 params : u32 ,
13711425 body : & FunctionBody < ' _ > ,
13721426 branch_hints : & [ ( usize , BranchHint ) ] ,
1427+ mut validator : Option < operand_stack:: FuncValidator > ,
13731428 ) -> Result < ( ) > {
13741429 let mut first = true ;
13751430 let mut local_idx = 0 ;
@@ -1400,6 +1455,14 @@ impl Printer<'_, '_> {
14001455 }
14011456 locals. finish ( self ) ?;
14021457
1458+ if let Some ( f) = & mut validator {
1459+ if let Err ( e) = f. read_locals ( body. get_binary_reader ( ) ) {
1460+ validator = None ;
1461+ self . newline_unknown_pos ( ) ?;
1462+ write ! ( self . result, ";; locals are invalid: {e}" ) ?;
1463+ }
1464+ }
1465+
14031466 let nesting_start = self . nesting ;
14041467 let fold_instructions = self . config . fold_instructions ;
14051468 let mut operator_state = OperatorState :: new ( self , OperatorSeparator :: Newline ) ;
@@ -1408,11 +1471,22 @@ impl Printer<'_, '_> {
14081471 let mut folded_printer = PrintOperatorFolded :: new ( self , state, & mut operator_state) ;
14091472 folded_printer. set_offset ( func_start) ;
14101473 folded_printer. begin_function ( func_idx) ?;
1411- Self :: print_operators ( & mut reader, branch_hints, func_start, & mut folded_printer) ?;
1412- folded_printer. finalize ( ) ?;
1474+ Self :: print_operators (
1475+ & mut reader,
1476+ branch_hints,
1477+ func_start,
1478+ & mut folded_printer,
1479+ validator,
1480+ ) ?;
14131481 } else {
14141482 let mut flat_printer = PrintOperator :: new ( self , state, & mut operator_state) ;
1415- Self :: print_operators ( & mut reader, branch_hints, func_start, & mut flat_printer) ?;
1483+ Self :: print_operators (
1484+ & mut reader,
1485+ branch_hints,
1486+ func_start,
1487+ & mut flat_printer,
1488+ validator,
1489+ ) ?;
14161490 }
14171491
14181492 // If this was an invalid function body then the nesting may not
@@ -1433,12 +1507,24 @@ impl Printer<'_, '_> {
14331507 mut branch_hints : & [ ( usize , BranchHint ) ] ,
14341508 func_start : usize ,
14351509 op_printer : & mut O ,
1510+ mut validator : Option < operand_stack:: FuncValidator > ,
14361511 ) -> Result < ( ) > {
14371512 let mut ops = OperatorsReader :: new ( body. clone ( ) ) ;
14381513 while !ops. eof ( ) {
14391514 if ops. is_end_then_eof ( ) {
1515+ let mut annotation = None ;
1516+ if let Some ( f) = & mut validator {
1517+ match f. visit_operator ( & ops, true ) {
1518+ Ok ( ( ) ) => { }
1519+ Err ( _) => {
1520+ annotation = Some ( String :: from ( "type mismatch at end of expression" ) )
1521+ }
1522+ }
1523+ }
1524+
14401525 ops. read ( ) ?; // final "end" opcode terminates instruction sequence
14411526 ops. finish ( ) ?;
1527+ op_printer. finalize ( annotation. as_deref ( ) ) ?;
14421528 return Ok ( ( ) ) ;
14431529 }
14441530
@@ -1450,9 +1536,22 @@ impl Printer<'_, '_> {
14501536 op_printer. branch_hint ( * hint_offset, hint. taken ) ?;
14511537 }
14521538 }
1453-
1539+ let mut annotation = None ;
1540+ if let Some ( f) = & mut validator {
1541+ let result = f
1542+ . visit_operator ( & ops, false )
1543+ . map_err ( anyhow:: Error :: from)
1544+ . and_then ( |( ) | f. visualize_operand_stack ( op_printer. use_color ( ) ) ) ;
1545+ match result {
1546+ Ok ( s) => annotation = Some ( s) ,
1547+ Err ( _) => {
1548+ validator = None ;
1549+ annotation = Some ( String :: from ( "(invalid)" ) ) ;
1550+ }
1551+ }
1552+ }
14541553 op_printer. set_offset ( ops. original_position ( ) ) ;
1455- op_printer. visit_operator ( & mut ops) ?;
1554+ op_printer. visit_operator ( & mut ops, annotation . as_deref ( ) ) ?;
14561555 }
14571556 ops. finish ( ) ?; // for the error message
14581557 bail ! ( "unexpected end of operators" ) ;
@@ -1726,12 +1825,10 @@ impl Printer<'_, '_> {
17261825 if fold {
17271826 let mut folded_printer = PrintOperatorFolded :: new ( self , state, & mut operator_state) ;
17281827 folded_printer. begin_const_expr ( ) ;
1729- Self :: print_operators ( & mut reader, & [ ] , 0 , & mut folded_printer) ?;
1730- folded_printer. finalize ( ) ?;
1828+ Self :: print_operators ( & mut reader, & [ ] , 0 , & mut folded_printer, None ) ?;
17311829 } else {
17321830 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) ?;
1831+ Self :: print_operators ( & mut reader, & [ ] , 0 , & mut op_printer, None ) ?;
17351832 }
17361833
17371834 Ok ( ( ) )
0 commit comments