github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/integration_test/engine/dwarf_test.go (about)

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