github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/integration_test/engine/dwarf_test.go (about)

     1  package adhoc
     2  
     3  import (
     4  	"bufio"
     5  	_ "embed"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/tetratelabs/wazero"
    10  	"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
    11  	"github.com/tetratelabs/wazero/internal/platform"
    12  	"github.com/tetratelabs/wazero/internal/testing/dwarftestdata"
    13  	"github.com/tetratelabs/wazero/internal/testing/require"
    14  )
    15  
    16  var dwarfTests = map[string]testCase{
    17  	"tinygo": {f: testTinyGoDWARF},
    18  	"zig":    {f: testZigDWARF},
    19  	"cc":     {f: testCCDWARF},
    20  	"rust":   {f: testRustDWARF},
    21  }
    22  
    23  func TestEngineCompiler_DWARF(t *testing.T) {
    24  	if !platform.CompilerSupported() {
    25  		t.Skip()
    26  	}
    27  	runAllTests(t, dwarfTests, wazero.NewRuntimeConfigCompiler(), false)
    28  }
    29  
    30  func TestEngineInterpreter_DWARF(t *testing.T) {
    31  	runAllTests(t, dwarfTests, wazero.NewRuntimeConfigInterpreter(), false)
    32  }
    33  
    34  func testTinyGoDWARF(t *testing.T, r wazero.Runtime) {
    35  	runDWARFTest(t, r, dwarftestdata.TinyGoWasm, `module[] function[_start] failed: wasm error: unreachable
    36  wasm stack trace:
    37  	.runtime._panic(i32)
    38  		0x18f3: /runtime_tinygowasm.go:70:6
    39  	.main.c()
    40  		0x2ff9: /main.go:16:7
    41  	.main.b()
    42  		0x2f97: /main.go:12:3
    43  	.main.a()
    44  		0x2f39: /main.go:8:3
    45  	.main.main()
    46  		0x2149: /main.go:4:3
    47  	.runtime.run$1()
    48  		0x1fcb: /scheduler_any.go:25:11
    49  	.runtime.run$1$gowrapper(i32)
    50  		0x6f0: /scheduler_any.go:23:2
    51  	.tinygo_launch(i32)
    52  		0x23: /task_asyncify_wasm.S:59
    53  	.runtime.scheduler()
    54  		0x1ec4: /task_asyncify.go:109:17 (inlined)
    55  		        /scheduler.go:236:11
    56  	.runtime.run()
    57  		0x1d92: /scheduler_any.go:28:11
    58  	._start()
    59  		0x1d12: /runtime_wasm_wasi.go:21:5`)
    60  }
    61  
    62  func testZigDWARF(t *testing.T, r wazero.Runtime) {
    63  	runDWARFTest(t, r, dwarftestdata.ZigWasm, `module[] function[_start] failed: wasm error: unreachable
    64  wasm stack trace:
    65  	.builtin.default_panic(i32,i32,i32,i32)
    66  		0x63: /builtin.zig:889:17
    67  	.main.main() i32
    68  		0x25: /main.zig:10:5 (inlined)
    69  		      /main.zig:6:5 (inlined)
    70  		      /main.zig:2:5
    71  	._start()
    72  		0x6a: /start.zig:609:37 (inlined)
    73  		      /start.zig:224:5`)
    74  }
    75  
    76  func testCCDWARF(t *testing.T, r wazero.Runtime) {
    77  	runDWARFTest(t, r, dwarftestdata.ZigCCWasm, `module[] function[_start] failed: wasm error: unreachable
    78  wasm stack trace:
    79  	.a()
    80  		0x312: /main.c:7:18
    81  	.__original_main() i32
    82  		0x47c: /main.c:11:3
    83  	._start()
    84  	._start.command_export()`)
    85  }
    86  
    87  func testRustDWARF(t *testing.T, r wazero.Runtime) {
    88  	runDWARFTest(t, r, dwarftestdata.RustWasm, `module[] function[_start] failed: wasm error: unreachable
    89  wasm stack trace:
    90  	.__rust_start_panic(i32) i32
    91  		0xc474: /index.rs:286:39 (inlined)
    92  		        /const_ptr.rs:870:18 (inlined)
    93  		        /index.rs:286:39 (inlined)
    94  		        /mod.rs:1630:46 (inlined)
    95  		        /mod.rs:405:20 (inlined)
    96  		        /mod.rs:1630:46 (inlined)
    97  		        /mod.rs:1548:18 (inlined)
    98  		        /iter.rs:1478:30 (inlined)
    99  		        /count.rs:74:18
   100  	.rust_panic(i32,i32)
   101  		0xa3f8: /validations.rs:57:19 (inlined)
   102  		        /validations.rs:57:19 (inlined)
   103  		        /iter.rs:140:15 (inlined)
   104  		        /iter.rs:140:15 (inlined)
   105  		        /iterator.rs:330:13 (inlined)
   106  		        /iterator.rs:377:9 (inlined)
   107  		        /mod.rs:1455:35
   108  	.std::panicking::rust_panic_with_hook::h93e119628869d575(i32,i32,i32,i32,i32)
   109  		0x42df: /alloc.rs:244:22 (inlined)
   110  		        /alloc.rs:244:22 (inlined)
   111  		        /alloc.rs:342:9 (inlined)
   112  		        /mod.rs:487:1 (inlined)
   113  		        /mod.rs:487:1 (inlined)
   114  		        /mod.rs:487:1 (inlined)
   115  		        /mod.rs:487:1 (inlined)
   116  		        /mod.rs:487:1 (inlined)
   117  		        /panicking.rs:292:17 (inlined)
   118  		        /panicking.rs:292:17
   119  	.std::panicking::begin_panic_handler::{{closure}}::h2b8c0798e533b227(i32,i32,i32)
   120  		0xaa8c: /mod.rs:362:12 (inlined)
   121  		        /mod.rs:1257:22 (inlined)
   122  		        /mod.rs:1235:21 (inlined)
   123  		        /mod.rs:1214:26
   124  	.std::sys_common::backtrace::__rust_end_short_backtrace::h030a533bc034da65(i32)
   125  		0xc144: /mod.rs:188:26
   126  	.rust_begin_unwind(i32)
   127  		0xb7df: /mod.rs:1629:9 (inlined)
   128  		        /builders.rs:199:17 (inlined)
   129  		        /result.rs:1352:22 (inlined)
   130  		        /builders.rs:187:23
   131  	.core::panicking::panic_fmt::hb1bfc4175f838eff(i32,i32)
   132  		0xbd3d: /mod.rs:1384:17
   133  	.main::main::hfd44f54575e6bfdf()
   134  		0xad2c: /memchr.rs
   135  	.core::ops::function::FnOnce::call_once::h87e5f77996df3e28(i32)
   136  		0xbd61: /mod.rs
   137  	.std::sys_common::backtrace::__rust_begin_short_backtrace::h7ca17eb6aa97f768(i32)
   138  		0xbd95: /mod.rs:1504:35 (inlined)
   139  		        /mod.rs:1407:36
   140  	.std::rt::lang_start::{{closure}}::he4aa401e76315dfe(i32) i32
   141  		0xae9a: /location.rs:196:6
   142  	.std::rt::lang_start_internal::h3c39e5d3c278a90f(i32,i32,i32,i32) i32
   143  	.std::rt::lang_start::h779801844bd22a3c(i32,i32,i32) i32
   144  		0xab94: /mod.rs:1226:2
   145  	.__original_main() i32
   146  		0xc0ae: /methods.rs:1677:13 (inlined)
   147  		        /mod.rs:165:24 (inlined)
   148  		        /mod.rs:165:24
   149  	._start()
   150  		0xc10f: /mod.rs:187
   151  	._start.command_export()
   152  		0xc3de: /iterator.rs:2414:21 (inlined)
   153  		        /map.rs:124:9 (inlined)
   154  		        /accum.rs:42:17 (inlined)
   155  		        /iterator.rs:3347:9 (inlined)
   156  		        /count.rs:135:5 (inlined)
   157  		        /count.rs:135:5 (inlined)
   158  		        /count.rs:71:21`)
   159  }
   160  
   161  func runDWARFTest(t *testing.T, r wazero.Runtime, bin []byte, exp string) {
   162  	if len(bin) == 0 {
   163  		t.Skip() // Skip if the binary is empty which can happen when xz is not installed on the system
   164  	}
   165  
   166  	_, err := wasi_snapshot_preview1.Instantiate(testCtx, r)
   167  	require.NoError(t, err)
   168  	_, err = r.Instantiate(testCtx, bin)
   169  	require.Error(t, err)
   170  
   171  	errStr := err.Error()
   172  
   173  	// Since stack traces change where the binary is compiled, we sanitize each line
   174  	// so that it doesn't contain any file system dependent info.
   175  	scanner := bufio.NewScanner(strings.NewReader(errStr))
   176  	scanner.Split(bufio.ScanLines)
   177  	var sanitizedLines []string
   178  	for scanner.Scan() {
   179  		line := scanner.Text()
   180  		start, last := strings.Index(line, "/"), strings.LastIndex(line, "/")
   181  		if start >= 0 {
   182  			l := len(line) - last
   183  			buf := []byte(line)
   184  			copy(buf[start:], buf[last:])
   185  			line = string(buf[:start+l])
   186  		}
   187  		sanitizedLines = append(sanitizedLines, line)
   188  	}
   189  
   190  	sanitizedTraces := strings.Join(sanitizedLines, "\n")
   191  	require.Equal(t, exp, sanitizedTraces)
   192  }