diff options
author | 2025-03-09 17:47:56 +0100 | |
---|---|---|
committer | 2025-03-10 01:59:49 +0100 | |
commit | 3ac1ee16f377d31a0fb80c8dae28b6239ac4229e (patch) | |
tree | f61faa581feaaeaba2542b9f2b8234a590684413 /vendor/github.com/tetratelabs/wazero/internal/wasmdebug | |
parent | [chore] update URLs to forked source (diff) | |
download | gotosocial-3ac1ee16f377d31a0fb80c8dae28b6239ac4229e.tar.xz |
[chore] remove vendor
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/wasmdebug')
-rw-r--r-- | vendor/github.com/tetratelabs/wazero/internal/wasmdebug/debug.go | 170 | ||||
-rw-r--r-- | vendor/github.com/tetratelabs/wazero/internal/wasmdebug/dwarf.go | 225 |
2 files changed, 0 insertions, 395 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasmdebug/debug.go b/vendor/github.com/tetratelabs/wazero/internal/wasmdebug/debug.go deleted file mode 100644 index ff0e0cccc..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasmdebug/debug.go +++ /dev/null @@ -1,170 +0,0 @@ -// Package wasmdebug contains utilities used to give consistent search keys between stack traces and error messages. -// Note: This is named wasmdebug to avoid conflicts with the normal go module. -// Note: This only imports "api" as importing "wasm" would create a cyclic dependency. -package wasmdebug - -import ( - "fmt" - "runtime" - "runtime/debug" - "strconv" - "strings" - - "github.com/tetratelabs/wazero/api" - "github.com/tetratelabs/wazero/internal/wasmruntime" - "github.com/tetratelabs/wazero/sys" -) - -// FuncName returns the naming convention of "moduleName.funcName". -// -// - moduleName is the possibly empty name the module was instantiated with. -// - funcName is the name in the Custom Name section. -// - funcIdx is the position in the function index, prefixed with -// imported functions. -// -// Note: "moduleName.$funcIdx" is used when the funcName is empty, as commonly -// the case in TinyGo. -func FuncName(moduleName, funcName string, funcIdx uint32) string { - var ret strings.Builder - - // Start module.function - ret.WriteString(moduleName) - ret.WriteByte('.') - if funcName == "" { - ret.WriteByte('$') - ret.WriteString(strconv.Itoa(int(funcIdx))) - } else { - ret.WriteString(funcName) - } - - return ret.String() -} - -// signature returns a formatted signature similar to how it is defined in Go. -// -// * paramTypes should be from wasm.FunctionType -// * resultTypes should be from wasm.FunctionType -// TODO: add paramNames -func signature(funcName string, paramTypes []api.ValueType, resultTypes []api.ValueType) string { - var ret strings.Builder - ret.WriteString(funcName) - - // Start params - ret.WriteByte('(') - paramCount := len(paramTypes) - switch paramCount { - case 0: - case 1: - ret.WriteString(api.ValueTypeName(paramTypes[0])) - default: - ret.WriteString(api.ValueTypeName(paramTypes[0])) - for _, vt := range paramTypes[1:] { - ret.WriteByte(',') - ret.WriteString(api.ValueTypeName(vt)) - } - } - ret.WriteByte(')') - - // Start results - resultCount := len(resultTypes) - switch resultCount { - case 0: - case 1: - ret.WriteByte(' ') - ret.WriteString(api.ValueTypeName(resultTypes[0])) - default: // As this is used for errors, don't panic if there are multiple returns, even if that's invalid! - ret.WriteByte(' ') - ret.WriteByte('(') - ret.WriteString(api.ValueTypeName(resultTypes[0])) - for _, vt := range resultTypes[1:] { - ret.WriteByte(',') - ret.WriteString(api.ValueTypeName(vt)) - } - ret.WriteByte(')') - } - - return ret.String() -} - -// ErrorBuilder helps build consistent errors, particularly adding a WASM stack trace. -// -// AddFrame should be called beginning at the frame that panicked until no more frames exist. Once done, call Format. -type ErrorBuilder interface { - // AddFrame adds the next frame. - // - // * funcName should be from FuncName - // * paramTypes should be from wasm.FunctionType - // * resultTypes should be from wasm.FunctionType - // * sources is the source code information for this frame and can be empty. - // - // Note: paramTypes and resultTypes are present because signature misunderstanding, mismatch or overflow are common. - AddFrame(funcName string, paramTypes, resultTypes []api.ValueType, sources []string) - - // FromRecovered returns an error with the wasm stack trace appended to it. - FromRecovered(recovered interface{}) error -} - -func NewErrorBuilder() ErrorBuilder { - return &stackTrace{} -} - -type stackTrace struct { - // frameCount is the number of stack frame currently pushed into lines. - frameCount int - // lines contains the stack trace and possibly the inlined source code information. - lines []string -} - -// GoRuntimeErrorTracePrefix is the prefix coming before the Go runtime stack trace included in the face of runtime.Error. -// This is exported for testing purpose. -const GoRuntimeErrorTracePrefix = "Go runtime stack trace:" - -func (s *stackTrace) FromRecovered(recovered interface{}) error { - if false { - debug.PrintStack() - } - - if exitErr, ok := recovered.(*sys.ExitError); ok { // Don't wrap an exit error! - return exitErr - } - - stack := strings.Join(s.lines, "\n\t") - - // If the error was internal, don't mention it was recovered. - if wasmErr, ok := recovered.(*wasmruntime.Error); ok { - return fmt.Errorf("wasm error: %w\nwasm stack trace:\n\t%s", wasmErr, stack) - } - - // If we have a runtime.Error, something severe happened which should include the stack trace. This could be - // a nil pointer from wazero or a user-defined function from HostModuleBuilder. - if runtimeErr, ok := recovered.(runtime.Error); ok { - return fmt.Errorf("%w (recovered by wazero)\nwasm stack trace:\n\t%s\n\n%s\n%s", - runtimeErr, stack, GoRuntimeErrorTracePrefix, debug.Stack()) - } - - // At this point we expect the error was from a function defined by HostModuleBuilder that intentionally called panic. - if runtimeErr, ok := recovered.(error); ok { // e.g. panic(errors.New("whoops")) - return fmt.Errorf("%w (recovered by wazero)\nwasm stack trace:\n\t%s", runtimeErr, stack) - } else { // e.g. panic("whoops") - return fmt.Errorf("%v (recovered by wazero)\nwasm stack trace:\n\t%s", recovered, stack) - } -} - -// MaxFrames is the maximum number of frames to include in the stack trace. -const MaxFrames = 30 - -// AddFrame implements ErrorBuilder.AddFrame -func (s *stackTrace) AddFrame(funcName string, paramTypes, resultTypes []api.ValueType, sources []string) { - if s.frameCount == MaxFrames { - return - } - s.frameCount++ - sig := signature(funcName, paramTypes, resultTypes) - s.lines = append(s.lines, sig) - for _, source := range sources { - s.lines = append(s.lines, "\t"+source) - } - if s.frameCount == MaxFrames { - s.lines = append(s.lines, "... maybe followed by omitted frames") - } -} diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasmdebug/dwarf.go b/vendor/github.com/tetratelabs/wazero/internal/wasmdebug/dwarf.go deleted file mode 100644 index 50ba7b2b3..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasmdebug/dwarf.go +++ /dev/null @@ -1,225 +0,0 @@ -package wasmdebug - -import ( - "debug/dwarf" - "errors" - "fmt" - "io" - "sort" - "strings" - "sync" -) - -// DWARFLines is used to retrieve source code line information from the DWARF data. -type DWARFLines struct { - // d is created by DWARF custom sections. - d *dwarf.Data - // linesPerEntry maps dwarf.Offset for dwarf.Entry to the list of lines contained by the entry. - // The value is sorted in the increasing order by the address. - linesPerEntry map[dwarf.Offset][]line - mux sync.Mutex -} - -type line struct { - addr uint64 - pos dwarf.LineReaderPos -} - -// NewDWARFLines returns DWARFLines for the given *dwarf.Data. -func NewDWARFLines(d *dwarf.Data) *DWARFLines { - if d == nil { - return nil - } - return &DWARFLines{d: d, linesPerEntry: map[dwarf.Offset][]line{}} -} - -// isTombstoneAddr returns true if the given address is invalid a.k.a tombstone address which was made no longer valid -// by linker. According to the DWARF spec[1], the value is encoded as 0xffffffff for Wasm (as 32-bit target), -// but some tools encode it either in -1, -2 [2] or 1<<32 (This might not be by tools, but by debug/dwarf package's bug). -// -// [1] https://dwarfstd.org/issues/200609.1.html -// [2] https://github.com/WebAssembly/binaryen/blob/97178d08d4a20d2a5e3a6be813fc6a7079ef86e1/src/wasm/wasm-debug.cpp#L651-L660 -// [3] https://reviews.llvm.org/D81784 -func isTombstoneAddr(addr uint64) bool { - addr32 := int32(addr) - return addr32 == -1 || addr32 == -2 || - addr32 == 0 // This covers 1 <<32. -} - -// Line returns the line information for the given instructionOffset which is an offset in -// the code section of the original Wasm binary. Returns empty string if the info is not found. -func (d *DWARFLines) Line(instructionOffset uint64) (ret []string) { - if d == nil { - return - } - - // DWARFLines is created per Wasm binary, so there's a possibility that multiple instances - // created from a same binary face runtime error at the same time, and that results in - // concurrent access to this function. - d.mux.Lock() - defer d.mux.Unlock() - - r := d.d.Reader() - - var inlinedRoutines []*dwarf.Entry - var cu *dwarf.Entry - var inlinedDone bool -entry: - for { - ent, err := r.Next() - if err != nil || ent == nil { - break - } - - // If we already found the compilation unit and relevant inlined routines, we can stop searching entries. - if cu != nil && inlinedDone { - break - } - - switch ent.Tag { - case dwarf.TagCompileUnit, dwarf.TagInlinedSubroutine: - default: - // Only CompileUnit and InlinedSubroutines are relevant. - continue - } - - // Check if the entry spans the range which contains the target instruction. - ranges, err := d.d.Ranges(ent) - if err != nil { - continue - } - for _, pcs := range ranges { - start, end := pcs[0], pcs[1] - if isTombstoneAddr(start) || isTombstoneAddr(end) { - continue - } - if start <= instructionOffset && instructionOffset < end { - switch ent.Tag { - case dwarf.TagCompileUnit: - cu = ent - case dwarf.TagInlinedSubroutine: - inlinedRoutines = append(inlinedRoutines, ent) - // Search inlined subroutines until all the children. - inlinedDone = !ent.Children - // Not that "children" in the DWARF spec is defined as the next entry to this entry. - // See "2.3 Relationship of Debugging Information Entries" in https://dwarfstd.org/doc/DWARF4.pdf - } - continue entry - } - } - } - - // If the relevant compilation unit is not found, nothing we can do with this DWARF info. - if cu == nil { - return - } - - lineReader, err := d.d.LineReader(cu) - if err != nil || lineReader == nil { - return - } - var lines []line - var ok bool - var le dwarf.LineEntry - // Get the lines inside the entry. - if lines, ok = d.linesPerEntry[cu.Offset]; !ok { - // If not found, we create the list of lines by reading all the LineEntries in the Entry. - // - // Note that the dwarf.LineEntry.SeekPC API shouldn't be used because the Go's dwarf package assumes that - // all the line entries in an Entry are sorted in increasing order which *might not* be true - // for some languages. Such order requirement is not a part of DWARF specification, - // and in fact Zig language tends to emit interleaved line information. - // - // Thus, here we read all line entries here, and sort them in the increasing order wrt addresses. - for { - pos := lineReader.Tell() - err = lineReader.Next(&le) - if errors.Is(err, io.EOF) { - break - } else if err != nil { - return - } - // TODO: Maybe we should ignore tombstone addresses by using isTombstoneAddr, - // but not sure if that would be an issue in practice. - lines = append(lines, line{addr: le.Address, pos: pos}) - } - sort.Slice(lines, func(i, j int) bool { return lines[i].addr < lines[j].addr }) - d.linesPerEntry[cu.Offset] = lines // Caches for the future inquiries for the same Entry. - } - - // Now we have the lines for this entry. We can find the corresponding source line for instructionOffset - // via binary search on the list. - n := len(lines) - index := sort.Search(n, func(i int) bool { return lines[i].addr >= instructionOffset }) - - if index == n { // This case the address is not found. See the doc sort.Search. - return - } - - ln := lines[index] - if ln.addr != instructionOffset { - // If the address doesn't match exactly, the previous entry is the one that contains the instruction. - // That can happen anytime as the DWARF spec allows it, and other tools can handle it in this way conventionally - // https://github.com/gimli-rs/addr2line/blob/3a2dbaf84551a06a429f26e9c96071bb409b371f/src/lib.rs#L236-L242 - // https://github.com/kateinoigakukun/wasminspect/blob/f29f052f1b03104da9f702508ac0c1bbc3530ae4/crates/debugger/src/dwarf/mod.rs#L453-L459 - if index-1 < 0 { - return - } - ln = lines[index-1] - } - - // Advance the line reader for the found position. - lineReader.Seek(ln.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") - } - - // In the inlined case, the line info is the innermost inlined function call. - inlined := len(inlinedRoutines) != 0 - prefix := fmt.Sprintf("%#x: ", instructionOffset) - ret = append(ret, formatLine(prefix, le.File.Name, int64(le.Line), int64(le.Column), inlined)) - - if inlined { - prefix = strings.Repeat(" ", len(prefix)) - 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 := files[fileIndex] - line, _ := inlined.Val(dwarf.AttrCallLine).(int64) - col, _ := inlined.Val(dwarf.AttrCallColumn).(int64) - ret = append(ret, formatLine(prefix, fileName.Name, line, col, - // Last one is the origin of the inlined function calls. - i != 0)) - } - } - return -} - -func formatLine(prefix, fileName string, line, col int64, inlined bool) string { - builder := strings.Builder{} - builder.WriteString(prefix) - builder.WriteString(fileName) - - if line != 0 { - builder.WriteString(fmt.Sprintf(":%d", line)) - if col != 0 { - builder.WriteString(fmt.Sprintf(":%d", col)) - } - } - - if inlined { - builder.WriteString(" (inlined)") - } - return builder.String() -} |