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 }