From 45aa798a557f23137282a4f53cfdf1a29cc5791f Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Mon, 12 Dec 2022 11:20:14 +0900 Subject: [PATCH] dwarf: include inlined function calls in stack traces (#912) Signed-off-by: Takeshi Yoneda --- experimental/dwarf_test.go | 72 ++++++++---- internal/engine/compiler/engine.go | 6 +- internal/engine/interpreter/interpreter.go | 6 +- .../dwarftestdata/testdata/zig/main.wasm | Bin 87325 -> 87634 bytes .../dwarftestdata/testdata/zig/main.zig | 12 +- internal/wasmdebug/debug.go | 12 +- internal/wasmdebug/debug_test.go | 15 +-- internal/wasmdebug/dwarf.go | 103 +++++++++++++++--- internal/wasmdebug/dwarf_test.go | 60 ++++++---- 9 files changed, 212 insertions(+), 74 deletions(-) diff --git a/experimental/dwarf_test.go b/experimental/dwarf_test.go index a46e3167..80313891 100644 --- a/experimental/dwarf_test.go +++ b/experimental/dwarf_test.go @@ -1,8 +1,10 @@ package experimental_test import ( + "bufio" "context" _ "embed" + "strings" "testing" "github.com/tetratelabs/wazero" @@ -37,37 +39,50 @@ func TestWithDWARFBasedStackTrace(t *testing.T) { t.Run(tc.name, func(t *testing.T) { r := tc.r defer r.Close(ctx) // This closes everything this Runtime created. - wasi_snapshot_preview1.MustInstantiate(ctx, r) for _, lang := range []struct { name string bin []byte - exps []string + exp string }{ { name: "tinygo", bin: dwarftestdata.TinyGoWasm, - exps: []string{ - "src/runtime/runtime_tinygowasm.go:73:6", - "wazero/internal/testing/dwarftestdata/testdata/main.go:19:7", - "wazero/internal/testing/dwarftestdata/testdata/main.go:14:3", - "wazero/internal/testing/dwarftestdata/testdata/main.go:9:3", - "wazero/internal/testing/dwarftestdata/testdata/main.go:4:3", - "wazero/internal/testing/dwarftestdata/testdata/main.go:4:3", - "src/runtime/scheduler_none.go:26:10", - "src/runtime/runtime_wasm_wasi.go:22:5", - }, + exp: `module[] function[_start] failed: wasm error: unreachable +wasm stack trace: + .runtime._panic(i32) + 0x16e2: /runtime_tinygowasm.go:73:6 (inlined) + /panic.go:52:7 + .c() + 0x1919: /main.go:19:7 + .b() + 0x1901: /main.go:14:3 + .a() + 0x18f7: /main.go:9:3 + .main.main() + 0x18ed: /main.go:4:3 + .runtime.run() + 0x18cc: /scheduler_none.go:26:10 + ._start() + 0x18b6: /runtime_wasm_wasi.go:22:5`, }, { name: "zig", bin: dwarftestdata.ZigWasm, - exps: []string{ - "lib/std/os.zig:552:9", - "lib/std/builtin.zig:787:25", - "main.zig:1:23", - "lib/std/start.zig:614:37", - }, + exp: `module[] function[_start] failed: wasm error: unreachable +wasm stack trace: + .os.abort() + 0x1b3: /os.zig:552:9 + .builtin.default_panic(i32,i32,i32,i32) + 0x86: /builtin.zig:787:25 + .main.main() i32 + 0x2d: main.zig:10:5 (inlined) + main.zig:6:5 (inlined) + main.zig:2:5 + ._start() + 0x1c6: /start.zig:614:37 (inlined) + /start.zig:240:42`, }, } { t.Run(lang.name, func(t *testing.T) { @@ -79,9 +94,26 @@ func TestWithDWARFBasedStackTrace(t *testing.T) { require.Error(t, err) errStr := err.Error() - for _, exp := range lang.exps { - require.Contains(t, errStr, exp) + + // Since stack traces change where the binary is compiled, we sanitize each line + // so that it doesn't contain any file system dependent info. + scanner := bufio.NewScanner(strings.NewReader(errStr)) + scanner.Split(bufio.ScanLines) + var sanitizedLines []string + for scanner.Scan() { + line := scanner.Text() + start, last := strings.Index(line, "/"), strings.LastIndex(line, "/") + if start >= 0 { + l := len(line) - last + buf := []byte(line) + copy(buf[start:], buf[last:]) + line = string(buf[:start+l]) + } + sanitizedLines = append(sanitizedLines, line) } + + sanitizedTraces := strings.Join(sanitizedLines, "\n") + require.Equal(t, sanitizedTraces, lang.exp) }) } }) diff --git a/internal/engine/compiler/engine.go b/internal/engine/compiler/engine.go index dde3397f..207d9074 100644 --- a/internal/engine/compiler/engine.go +++ b/internal/engine/compiler/engine.go @@ -735,14 +735,14 @@ func (ce *callEngine) deferredOnCall(recovered interface{}) (err error) { // sourceInfo holds the source code information corresponding to the frame. // It is not empty only when the DWARF is enabled. - var sourceInfo string + var sources []string if p := fn.parent; p.codeSegment != nil { if p.sourceOffsetMap != nil { offset := fn.getSourceOffsetInWasmBinary(pc) - sourceInfo = p.sourceModule.DWARFLines.Line(offset) + sources = p.sourceModule.DWARFLines.Line(offset) } } - builder.AddFrame(def.DebugName(), def.ParamTypes(), def.ResultTypes(), sourceInfo) + builder.AddFrame(def.DebugName(), def.ParamTypes(), def.ResultTypes(), sources) callFrameOffset := callFrameOffset(source.Type) if stackBasePointer != 0 { diff --git a/internal/engine/interpreter/interpreter.go b/internal/engine/interpreter/interpreter.go index ff2d1ef3..04b831c6 100644 --- a/internal/engine/interpreter/interpreter.go +++ b/internal/engine/interpreter/interpreter.go @@ -840,11 +840,11 @@ func (ce *callEngine) recoverOnCall(v interface{}) (err error) { for i := 0; i < frameCount; i++ { frame := ce.popFrame() def := frame.f.source.Definition - var sourceInfo string + var sources []string if frame.f.body != nil { - sourceInfo = frame.f.parent.source.DWARFLines.Line(frame.f.body[frame.pc].sourcePC) + sources = frame.f.parent.source.DWARFLines.Line(frame.f.body[frame.pc].sourcePC) } - builder.AddFrame(def.DebugName(), def.ParamTypes(), def.ResultTypes(), sourceInfo) + builder.AddFrame(def.DebugName(), def.ParamTypes(), def.ResultTypes(), sources) } err = builder.FromRecovered(v) diff --git a/internal/testing/dwarftestdata/testdata/zig/main.wasm b/internal/testing/dwarftestdata/testdata/zig/main.wasm index 055e03189142dc95807f6ecf53b6d12dd10bbb56..6504e652de81fbd4afe8f7fb5f15fcd9807cd39c 100755 GIT binary patch delta 14100 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 D%>>zX delta 13986 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 instructionOffset }) if index == n { // This case the address is not found. See the doc sort.Search. - return "" + return } // Advance the line reader for the found position. lineReader.Seek(lines[index].pos) err = lineReader.Next(&le) + if err != nil { // If we reach this block, that means there's a bug in the []line creation logic above. panic("BUG: stored dwarf.LineReaderPos is invalid") } - return fmt.Sprintf("%#x: %s:%d:%d", le.Address, le.File.Name, le.Line, le.Column) + + if len(inlinedRoutines) == 0 { + // Do early return for non-inlined case. + ret = []string{fmt.Sprintf("%#x: %s:%d:%d", le.Address, le.File.Name, le.Line, le.Column)} + return + } + + // In the inlined case, the line info is the innermost inlined function call. + addr := fmt.Sprintf("%#x: ", le.Address) + ret = append(ret, fmt.Sprintf("%s%s:%d:%d (inlined)", addr, le.File.Name, le.Line, le.Column)) + + files := lineReader.Files() + // inlinedRoutines contain the inlined call information in the reverse order (children is higher than parent), + // so we traverse the reverse order and emit the inlined calls. + for i := len(inlinedRoutines) - 1; i >= 0; i-- { + inlined := inlinedRoutines[i] + fileIndex, ok := inlined.Val(dwarf.AttrCallFile).(int64) + if !ok { + return + } else if fileIndex >= int64(len(files)) { + // This in theory shouldn't happen according to the spec, but guard against ill-formed DWARF info. + return + } + fileName, line, col := files[fileIndex], inlined.Val(dwarf.AttrCallLine), inlined.Val(dwarf.AttrCallColumn) + if i == 0 { + // Last one is the origin of the inlined function calls. + ret = append(ret, fmt.Sprintf("%s%s:%d:%d", strings.Repeat(" ", len(addr)), fileName.Name, line, col)) + } else { + ret = append(ret, fmt.Sprintf("%s%s:%d:%d (inlined)", strings.Repeat(" ", len(addr)), fileName.Name, line, col)) + } + } + return } diff --git a/internal/wasmdebug/dwarf_test.go b/internal/wasmdebug/dwarf_test.go index 84797c2c..18de9bfc 100644 --- a/internal/wasmdebug/dwarf_test.go +++ b/internal/wasmdebug/dwarf_test.go @@ -13,12 +13,12 @@ import ( "github.com/tetratelabs/wazero/internal/wasm/binary" ) -func TestDWARFLines_Line_TinyGO(t *testing.T) { +func TestDWARFLines_Line_TinyGo(t *testing.T) { mod, err := binary.DecodeModule(dwarftestdata.TinyGoWasm, api.CoreFeaturesV2, wasm.MemoryLimitPages, false, true, false) require.NoError(t, err) require.NotNil(t, mod.DWARFLines) - // Get the offsets of functions named "a", "b" and "c" in dwarftestdata.DWARFWasm. + // Get the offsets of functions named "a", "b" and "c" in dwarftestdata.TinyGoWasm. var a, b, c uint64 for _, exp := range mod.ExportSection { switch exp.Name { @@ -32,19 +32,20 @@ func TestDWARFLines_Line_TinyGO(t *testing.T) { } tests := []struct { + name string offset uint64 - exp string + exp []string }{ // Unknown offset returns empty string. - {offset: math.MaxUint64, exp: ""}, + {offset: math.MaxUint64}, // The first instruction should point to the first line of each function in internal/testing/dwarftestdata/testdata/tinygo.go - {offset: a, exp: "wazero/internal/testing/dwarftestdata/testdata/main.go:9:3"}, - {offset: b, exp: "wazero/internal/testing/dwarftestdata/testdata/main.go:14:3"}, - {offset: c, exp: "wazero/internal/testing/dwarftestdata/testdata/main.go:19:7"}, + {offset: a, exp: []string{"wazero/internal/testing/dwarftestdata/testdata/main.go:9:3"}}, + {offset: b, exp: []string{"wazero/internal/testing/dwarftestdata/testdata/main.go:14:3"}}, + {offset: c, exp: []string{"wazero/internal/testing/dwarftestdata/testdata/main.go:19:7"}}, } for _, tc := range tests { - t.Run(tc.exp, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { // Ensures that DWARFLines.Line is goroutine-safe. const concurrent = 100 var wg sync.WaitGroup @@ -54,7 +55,11 @@ func TestDWARFLines_Line_TinyGO(t *testing.T) { go func() { defer wg.Done() actual := mod.DWARFLines.Line(tc.offset) - require.Contains(t, actual, tc.exp) + + require.Equal(t, len(tc.exp), len(actual)) + for i := range tc.exp { + require.Contains(t, actual[i], tc.exp[i]) + } }() } wg.Wait() @@ -69,7 +74,7 @@ func TestDWARFLines_Line_Zig(t *testing.T) { // codeSecStart is the beginning of the first code entry in the Wasm binary. // If dwarftestdata.ZigWasm has been changed, we need to inspect by `wasm-tools dump`. - const codeSecStart = 0x0109 + const codeSecStart = 0x108 // These cases are crafted by matching the stack trace result from wasmtime. To verify, run: // @@ -84,25 +89,40 @@ func TestDWARFLines_Line_Zig(t *testing.T) { // at /Users/mathetake/zig-macos-aarch64-0.11.0-dev.618+096d3efae/lib/std/os.zig:552:9 // 1: 0x18e - builtin.default_panic // at /Users/mathetake/zig-macos-aarch64-0.11.0-dev.618+096d3efae/lib/std/builtin.zig:787:25 - // 2: 0x12d - main.main - // at ././main.zig:1:23 + // 2: 0x12d - main.inlined_b + // at ././main.zig:10:5 - main.inlined_a + // at ././main.zig:6:5 - main.main + // at ././main.zig:2:5 // 3: 0x2ce - start.callMain - // at /Users/mathetake/zig-macos-aarch64-0.11.0-dev.618+096d3efae/lib/std/start.zig:614:37 - // - _start + // at /Users/mathetake/zig-macos-aarch64-0.11.0-dev.618+096d3efae/lib/std/start.zig:614:37 - _start // at /Users/mathetake/zig-macos-aarch64-0.11.0-dev.618+096d3efae/lib/std/start.zig:240:42 + // 2: wasm trap: wasm `unreachable` instruction executed for _, tc := range []struct { offset uint64 - exp string + exp []string }{ - {offset: 0x2bb - codeSecStart, exp: "lib/std/os.zig:552:9"}, - {offset: 0x18e - codeSecStart, exp: "lib/std/builtin.zig:787:25"}, - {offset: 0x12d - codeSecStart, exp: "main.zig:1:23"}, - {offset: 0x2ce - codeSecStart, exp: "lib/std/start.zig:614:37"}, + {offset: 0x2bb - codeSecStart, exp: []string{"lib/std/os.zig:552:9"}}, + {offset: 0x18e - codeSecStart, exp: []string{"lib/std/builtin.zig:787:25"}}, + {offset: 0x12d - codeSecStart, exp: []string{ + "main.zig:10:5 (inlined)", + "main.zig:6:5 (inlined)", + "main.zig:2:5", + }}, + {offset: 0x2ce - codeSecStart, exp: []string{ + "lib/std/start.zig:614:37 (inlined)", + "lib/std/start.zig:240:42", + }}, } { tc := tc t.Run(fmt.Sprintf("%#x/%s", tc.offset, tc.exp), func(t *testing.T) { actual := mod.DWARFLines.Line(tc.offset) - require.Contains(t, actual, tc.exp) + + t.Log(actual) + + require.Equal(t, len(tc.exp), len(actual)) + for i := range tc.exp { + require.Contains(t, actual[i], tc.exp[i]) + } }) } }