github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wasmdebug/dwarf_test.go (about) 1 package wasmdebug_test 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/wasilibs/wazerox/api" 9 "github.com/wasilibs/wazerox/internal/testing/dwarftestdata" 10 "github.com/wasilibs/wazerox/internal/testing/hammer" 11 "github.com/wasilibs/wazerox/internal/testing/require" 12 "github.com/wasilibs/wazerox/internal/wasm" 13 "github.com/wasilibs/wazerox/internal/wasm/binary" 14 ) 15 16 func TestDWARFLines_Line_Zig(t *testing.T) { 17 mod, err := binary.DecodeModule(dwarftestdata.ZigWasm, api.CoreFeaturesV2, wasm.MemoryLimitPages, false, true, false) 18 require.NoError(t, err) 19 require.NotNil(t, mod.DWARFLines) 20 21 // codeSecStart is the beginning of the code section in the Wasm binary. 22 // If dwarftestdata.ZigWasm has been changed, we need to inspect by `wasm-tools objdump`. 23 const codeSecStart = 0x46 24 25 // These cases are crafted by matching the stack trace result from wasmtime. To verify, run: 26 // 27 // WASMTIME_BACKTRACE_DETAILS=1 wasmtime run internal/testing/dwarftestdata/testdata/zig/main.wasm 28 // 29 // And this should produce the output as: 30 // 31 // Caused by: 32 // 0: failed to invoke command default 33 // 1: error while executing at wasm backtrace: 34 // 0: 0xa9 - builtin.default_panic 35 // at /Users/adrian/Downloads/zig-macos-aarch64-0.11.0-dev.3334+cd1417dbd/lib/std/builtin.zig:889:17 36 // 1: 0x6b - main.inlined_b 37 // at /Users/adrian/oss/wazero/internal/testing/dwarftestdata/testdata/zig/main.zig:10:5 - main.inlined_a 38 // at /Users/adrian/oss/wazero/internal/testing/dwarftestdata/testdata/zig/main.zig:6:5 - main.main 39 // at /Users/adrian/oss/wazero/internal/testing/dwarftestdata/testdata/zig/main.zig:2:5 40 // 2: 0xb0 - start.callMain 41 // at /Users/adrian/Downloads/zig-macos-aarch64-0.11.0-dev.3334+cd1417dbd/lib/std/start.zig:609:37 - _start 42 // at /Users/adrian/Downloads/zig-macos-aarch64-0.11.0-dev.3334+cd1417dbd/lib/std/start.zig:224:5 43 // 2: wasm trap: wasm `unreachable` instruction executed 44 for _, tc := range []struct { 45 offset uint64 46 exp []string 47 }{ 48 {offset: 0xa9 - codeSecStart, exp: []string{ 49 "lib/std/builtin.zig:889:17", 50 }}, 51 {offset: 0x6b - codeSecStart, exp: []string{ 52 "zig/main.zig:10:5 (inlined)", 53 "zig/main.zig:6:5 (inlined)", 54 "zig/main.zig:2:5", 55 }}, 56 {offset: 0xb0 - codeSecStart, exp: []string{ 57 "lib/std/start.zig:609:37 (inlined)", 58 "lib/std/start.zig:224:5", 59 }}, 60 } { 61 tc := tc 62 t.Run(fmt.Sprintf("%#x/%s", tc.offset, tc.exp), func(t *testing.T) { 63 // Ensures that DWARFLines.Line is goroutine-safe. 64 hammer.NewHammer(t, 100, 5).Run(func(name string) { 65 actual := mod.DWARFLines.Line(tc.offset) 66 require.Equal(t, len(tc.exp), len(actual)) 67 for i := range tc.exp { 68 require.Contains(t, actual[i], tc.exp[i]) 69 } 70 }, nil) 71 }) 72 } 73 } 74 75 func TestDWARFLines_Line_Rust(t *testing.T) { 76 if len(dwarftestdata.RustWasm) == 0 { 77 t.Skip() 78 } 79 mod, err := binary.DecodeModule(dwarftestdata.RustWasm, api.CoreFeaturesV2, wasm.MemoryLimitPages, false, true, false) 80 require.NoError(t, err) 81 require.NotNil(t, mod.DWARFLines) 82 83 // codeSecStart is the beginning of the code section in the Wasm binary. 84 // If dwarftestdata.RustWasm has been changed, we need to inspect by `wasm-tools objdump`. 85 const codeSecStart = 0x309 86 87 // These cases are crafted by matching the stack trace result from wasmtime. To verify, run: 88 // 89 // WASMTIME_BACKTRACE_DETAILS=1 wasmtime run internal/testing/dwarftestdata/testdata/rust/main.wasm 90 // 91 // And this should produce the output as: 92 // Caused by: 93 // 0: failed to invoke command default 94 // 1: error while executing at wasm backtrace: 95 // 0: 0xc77d - core::ptr::const_ptr::<impl *const T>::offset::ha55096d7e14d75d8 96 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/slice/index.rs:286:39 - core::ptr::const_ptr::<impl *const T>::add::h089d5a72f68a4291 97 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/ptr/const_ptr.rs:870:18 - <core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::get_unchecked::h29ddcf1882fa0f66 98 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/slice/index.rs:286:39 - <core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::get_unchecked::h75ebc890f16858ff 99 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/slice/mod.rs:1630:46 - core::slice::<impl [T]>::get_unchecked::h6278e5a065ea078a 100 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/slice/mod.rs:405:20 - core::slice::<impl [T]>::split_at_unchecked::h88a6f1e7c576a79c 101 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/slice/mod.rs:1630:46 - core::slice::<impl [T]>::split_at::h68e6904057100aef 102 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/slice/mod.rs:1548:18 - <core::slice::iter::Chunks<T> as core::iter::traits::iterator::Iterator>::next::h9e3ea1e50ad1cfcf 103 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/slice/iter.rs:1478:30 - core::str::count::do_count_chars::h124622240ac1fb8b 104 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/str/count.rs:74:18 105 // 1: 0xa701 - core::str::validations::utf8_acc_cont_byte::hb47c34b8c4cbf06b 106 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/str/validations.rs:57:19 - core::str::validations::next_code_point::hbb42fe8b8fcbddc3 107 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/str/validations.rs:57:19 - <core::str::iter::Chars as core::iter::traits::iterator::Iterator>::next::h2dc4678e3c0bda18 108 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/str/iter.rs:140:15 - <core::str::iter::CharIndices as core::iter::traits::iterator::Iterator>::next::h430b9a1b0d2fcfcd 109 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/str/iter.rs:140:15 - core::iter::traits::iterator::Iterator::advance_by::hadbf2e62b9ea873e 110 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/iter/traits/iterator.rs:330:13 - core::iter::traits::iterator::Iterator::nth::h68978ac344a2c26f 111 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/iter/traits/iterator.rs:377:9 - core::fmt::Formatter::pad::hc91f9fb3fb51f81f 112 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1455:35 113 // 2: 0x45e8 - alloc::alloc::dealloc::hde3d57428722ee9b 114 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/alloc/src/alloc.rs:244:22 - <alloc::alloc::Global as core::alloc::Allocator>::deallocate::h9c672f23742d6fbc 115 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/alloc/src/alloc.rs:244:22 - alloc::alloc::box_free::hd090040c59659308 116 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/alloc/src/alloc.rs:342:9 - core::ptr::drop_in_place<alloc::boxed::Box<std::io::error::Custom>>::h3d2c76e2b4a26668 117 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/ptr/mod.rs:487:1 - core::ptr::drop_in_place<std::io::error::ErrorData<alloc::boxed::Box<std::io::error::Custom>>>::hcaa143fc963fdc85 118 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/ptr/mod.rs:487:1 - core::ptr::drop_in_place<std::io::error::repr_unpacked::Repr>::hf8eda15dbd953cd1 119 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/ptr/mod.rs:487:1 - core::ptr::drop_in_place<std::io::error::Error>::ha50d906acd95a768 120 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/ptr/mod.rs:487:1 - core::ptr::drop_in_place<core::result::Result<(),std::io::error::Error>>::h1a246d5cbc0481cf 121 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/ptr/mod.rs:487:1 - core::mem::drop::h37b541d3c993930c 122 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/std/src/panicking.rs:292:17 - std::panicking::default_hook::{{closure}}::h78d75d30689791e7 123 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/std/src/panicking.rs:292:17 124 // 3: 0xad95 - core::fmt::ArgumentV1::as_usize::h1da6b057d1a7dc54 125 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:362:12 - core::fmt::getcount::h8c5d6b3aea75a2d3 126 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1257:22 - core::fmt::run::h78a98448d78ecec3 127 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1235:21 - core::fmt::write::h5471a2341ce22f17 128 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1214:26 129 // 4: 0xc44d - core::fmt::Write::write_fmt::h4a7e084f8beacf08 130 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:188:26 131 // 5: 0xbae8 - core::fmt::Formatter::write_str::hc634aaecc183d175 132 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1629:9 - core::fmt::builders::DebugStruct::finish_non_exhaustive::{{closure}}::h51dc89dce87b7120 133 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/builders.rs:199:17 - core::result::Result<T,E>::and_then::hea34a5d4dd616ad6 134 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/result.rs:1352:22 - core::fmt::builders::DebugStruct::finish_non_exhaustive::h87daf5524c71dda9 135 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/builders.rs:187:23 136 // 6: 0xc046 - core::fmt::Formatter::pad_integral::ha8bb3db77298fecc 137 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1384:17 138 // 7: 0xb035 - core::slice::memchr::memchr_general_case::hb481b2edf3b1871e 139 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/slice/memchr.rs 140 // 8: 0xc06a - core::fmt::Formatter::pad_integral::ha8bb3db77298fecc 141 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs 142 // 9: 0xc09e - core::fmt::Formatter::padding::h4b882ffb39d00a12 143 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1504:35 - core::fmt::Formatter::pad_integral::ha8bb3db77298fecc 144 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1407:36 145 // 10: 0xb1a3 - <core::panic::location::Location as core::fmt::Display>::fmt::hf3870c0af6a67fac 146 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/panic/location.rs:196:6 147 // 11: 0x8ee0 - <unknown>!std::rt::lang_start_internal::h3c39e5d3c278a90f 148 // 12: 0xae9d - core::fmt::write::h5471a2341ce22f17 149 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:1226:2 150 // 13: 0xc3b7 - core::char::methods::encode_utf8_raw::h700e7a293d6eb2b7 151 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/char/methods.rs:1677:13 - core::char::methods::<impl char>::encode_utf8::h641f2d1d001008d5 152 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:165:24 - core::fmt::Write::write_char::ha951e2975b9730c3 153 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:165:24 154 // 14: 0xc418 - core::fmt::Write::write_fmt::h4a7e084f8beacf08 155 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/fmt/mod.rs:187 156 // 15: 0xc6e7 - core::iter::traits::iterator::Iterator::fold::h99ed29c108afc948 157 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/iter/traits/iterator.rs:2414:21 - <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold::ha5be3bb1eeeaf8fe 158 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/iter/adapters/map.rs:124:9 - <usize as core::iter::traits::accum::Sum>::sum::h00b4d0c0300e94a9 159 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/iter/traits/accum.rs:42:17 - core::iter::traits::iterator::Iterator::sum::h04374b17d4abbea5 160 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/iter/traits/iterator.rs:3347:9 - <core::iter::adapters::filter::Filter<I,P> as core::iter::traits::iterator::Iterator>::count::h5c8b4c5e67e6831c 161 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/str/count.rs:135:5 - core::str::count::char_count_general_case::hfffa06842344b9fe 162 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/str/count.rs:135:5 - core::str::count::do_count_chars::h124622240ac1fb8b 163 // at /rustc/c396bb3b8a16b1f2762b7c6078dc3e023f6a2493/library/core/src/str/count.rs:71:21 164 for _, tc := range []struct { 165 offset uint64 166 exp []string 167 }{ 168 {offset: 0xc77d - codeSecStart, exp: []string{ 169 "/library/core/src/slice/index.rs:286:39", 170 "/library/core/src/ptr/const_ptr.rs:870:18", 171 "/library/core/src/slice/index.rs:286:39", 172 "/library/core/src/slice/mod.rs:1630:46", 173 "/library/core/src/slice/mod.rs:405:20", 174 "/library/core/src/slice/mod.rs:1630:46", 175 "/library/core/src/slice/mod.rs:1548:18", 176 "/library/core/src/slice/iter.rs:1478:30", 177 "/library/core/src/str/count.rs:74:18", 178 }}, 179 {offset: 0xc06a - codeSecStart, exp: []string{"/library/core/src/fmt/mod.rs"}}, 180 {offset: 0xc6e7 - codeSecStart, exp: []string{ 181 "/library/core/src/iter/traits/iterator.rs:2414:21", 182 "/library/core/src/iter/adapters/map.rs:124:9", 183 "/library/core/src/iter/traits/accum.rs:42:17", 184 "/library/core/src/iter/traits/iterator.rs:3347:9", 185 "/library/core/src/str/count.rs:135:5", 186 "/library/core/src/str/count.rs:135:5", 187 "/library/core/src/str/count.rs:71:21", 188 }}, 189 } { 190 tc := tc 191 t.Run(fmt.Sprintf("%#x/%s", tc.offset, tc.exp), func(t *testing.T) { 192 actual := mod.DWARFLines.Line(tc.offset) 193 194 require.Equal(t, len(tc.exp), len(actual)) 195 for i := range tc.exp { 196 require.Contains(t, actual[i], tc.exp[i]) 197 } 198 }) 199 } 200 } 201 202 func TestDWARFLines_Line_TinyGo(t *testing.T) { 203 mod, err := binary.DecodeModule(dwarftestdata.TinyGoWasm, api.CoreFeaturesV2, wasm.MemoryLimitPages, false, true, false) 204 require.NoError(t, err) 205 require.NotNil(t, mod.DWARFLines) 206 207 // codeSecStart is the beginning of the code section in the Wasm binary. 208 // If dwarftestdata.TinyGoWasm has been changed, we need to inspect by `wasm-tools objdump`. 209 const codeSecStart = 0x16f 210 211 // These cases are crafted by matching the stack trace result from wasmtime. To verify, run: 212 // 213 // WASMTIME_BACKTRACE_DETAILS=1 wasmtime run internal/testing/dwarftestdata/testdata/tinygo/main.wasm 214 // 215 // And this should produce the output as: 216 // 217 // Caused by: 218 // 0: failed to invoke command default 219 // 1: error while executing at wasm backtrace: 220 // 0: 0x1a62 - runtime.abort 221 // at /Users/mathetake/Downloads/tinygo/src/runtime/runtime_tinygowasm.go:70:6 - runtime._panic 222 // at /Users/mathetake/Downloads/tinygo/src/runtime/panic.go:52:7 223 // 1: 0x3168 - main.c 224 // at /Users/mathetake/Downloads/tinygo/tmo/main.go:16:7 225 // 2: 0x3106 - main.b 226 // at /Users/mathetake/Downloads/tinygo/tmo/main.go:12:3 227 // 3: 0x30a8 - main.a 228 // at /Users/mathetake/Downloads/tinygo/tmo/main.go:8:3 229 // 4: 0x22b8 - main.main 230 // at /Users/mathetake/Downloads/tinygo/tmo/main.go:4:3 231 // 5: 0x213a - runtime.run$1 232 // at /Users/mathetake/Downloads/tinygo/src/runtime/scheduler_any.go:25:11 233 // 6: 0x85f - <goroutine wrapper> 234 // at /Users/mathetake/Downloads/tinygo/src/runtime/scheduler_any.go:23:2 235 // 7: 0x192 - tinygo_launch 236 // at /Users/mathetake/Downloads/tinygo/src/internal/task/task_asyncify_wasm.S:59 237 // 8: 0x2033 - (*internal/task.Task).Resume 238 // at /Users/mathetake/Downloads/tinygo/src/internal/task/task_asyncify.go:109:17 - runtime.scheduler 239 // at /Users/mathetake/Downloads/tinygo/src/runtime/scheduler.go:236:11 240 // 9: 0x1f01 - runtime.run 241 // at /Users/mathetake/Downloads/tinygo/src/runtime/scheduler_any.go:28:11 242 // 10: 0x1e81 - _start 243 // at /Users/mathetake/Downloads/tinygo/src/runtime/runtime_wasm_wasi.go:21:5 244 for _, tc := range []struct { 245 offset uint64 246 exp []string 247 }{ 248 {offset: 0x1e81 - codeSecStart, exp: []string{"runtime/runtime_wasm_wasi.go:21:5"}}, 249 {offset: 0x1f01 - codeSecStart, exp: []string{"runtime/scheduler_any.go:28:11"}}, 250 {offset: 0x2033 - codeSecStart, exp: []string{ 251 "internal/task/task_asyncify.go:109:17", 252 "runtime/scheduler.go:236:11", 253 }}, 254 {offset: 0x192 - codeSecStart, exp: []string{"internal/task/task_asyncify_wasm.S:59"}}, 255 {offset: 0x85f - codeSecStart, exp: []string{"runtime/scheduler_any.go:23:2"}}, 256 {offset: 0x213a - codeSecStart, exp: []string{"runtime/scheduler_any.go:25:11"}}, 257 {offset: 0x22b8 - codeSecStart, exp: []string{"main.go:4:3"}}, 258 {offset: 0x30a8 - codeSecStart, exp: []string{"main.go:8:3"}}, 259 {offset: 0x3106 - codeSecStart, exp: []string{"main.go:12:3"}}, 260 {offset: 0x3168 - codeSecStart, exp: []string{"main.go:16:7"}}, 261 // Note(important): this case is different from the output of Wasmtime, which produces the incorrect inline info (panic.go:52:7). 262 // Actually, "runtime_tinygowasm.go:70:6" invokes trap() which is translated as "unreachable" instruction by LLVM, so there won't be 263 // any inlined function invocation here. 264 {offset: 0x1a62 - codeSecStart, exp: []string{"runtime/runtime_tinygowasm.go:70:6"}}, 265 } { 266 tc := tc 267 t.Run(fmt.Sprintf("%#x/%s", tc.offset, tc.exp), func(t *testing.T) { 268 actual := mod.DWARFLines.Line(tc.offset) 269 require.Equal(t, len(tc.exp), len(actual), "\nexp: %s\ngot: %s", strings.Join(tc.exp, "\n"), strings.Join(actual, "\n")) 270 for i := range tc.exp { 271 require.Contains(t, actual[i], tc.exp[i]) 272 } 273 }) 274 } 275 }