...
1
2
3
4 package wasmdebug
5
6 import (
7 "fmt"
8 "runtime"
9 "runtime/debug"
10 "strconv"
11 "strings"
12
13 "github.com/tetratelabs/wazero/api"
14 "github.com/tetratelabs/wazero/internal/wasmruntime"
15 "github.com/tetratelabs/wazero/sys"
16 )
17
18
19
20
21
22
23
24
25
26
27 func FuncName(moduleName, funcName string, funcIdx uint32) string {
28 var ret strings.Builder
29
30
31 ret.WriteString(moduleName)
32 ret.WriteByte('.')
33 if funcName == "" {
34 ret.WriteByte('$')
35 ret.WriteString(strconv.Itoa(int(funcIdx)))
36 } else {
37 ret.WriteString(funcName)
38 }
39
40 return ret.String()
41 }
42
43
44
45
46
47
48 func signature(funcName string, paramTypes []api.ValueType, resultTypes []api.ValueType) string {
49 var ret strings.Builder
50 ret.WriteString(funcName)
51
52
53 ret.WriteByte('(')
54 paramCount := len(paramTypes)
55 switch paramCount {
56 case 0:
57 case 1:
58 ret.WriteString(api.ValueTypeName(paramTypes[0]))
59 default:
60 ret.WriteString(api.ValueTypeName(paramTypes[0]))
61 for _, vt := range paramTypes[1:] {
62 ret.WriteByte(',')
63 ret.WriteString(api.ValueTypeName(vt))
64 }
65 }
66 ret.WriteByte(')')
67
68
69 resultCount := len(resultTypes)
70 switch resultCount {
71 case 0:
72 case 1:
73 ret.WriteByte(' ')
74 ret.WriteString(api.ValueTypeName(resultTypes[0]))
75 default:
76 ret.WriteByte(' ')
77 ret.WriteByte('(')
78 ret.WriteString(api.ValueTypeName(resultTypes[0]))
79 for _, vt := range resultTypes[1:] {
80 ret.WriteByte(',')
81 ret.WriteString(api.ValueTypeName(vt))
82 }
83 ret.WriteByte(')')
84 }
85
86 return ret.String()
87 }
88
89
90
91
92 type ErrorBuilder interface {
93
94
95
96
97
98
99
100
101 AddFrame(funcName string, paramTypes, resultTypes []api.ValueType, sources []string)
102
103
104 FromRecovered(recovered interface{}) error
105 }
106
107 func NewErrorBuilder() ErrorBuilder {
108 return &stackTrace{}
109 }
110
111 type stackTrace struct {
112 frames []string
113 }
114
115
116
117 const GoRuntimeErrorTracePrefix = "Go runtime stack trace:"
118
119 func (s *stackTrace) FromRecovered(recovered interface{}) error {
120 if false {
121 debug.PrintStack()
122 }
123
124 if exitErr, ok := recovered.(*sys.ExitError); ok {
125 return exitErr
126 }
127
128 stack := strings.Join(s.frames, "\n\t")
129
130
131 if wasmErr, ok := recovered.(*wasmruntime.Error); ok {
132 return fmt.Errorf("wasm error: %w\nwasm stack trace:\n\t%s", wasmErr, stack)
133 }
134
135
136
137 if runtimeErr, ok := recovered.(runtime.Error); ok {
138 return fmt.Errorf("%w (recovered by wazero)\nwasm stack trace:\n\t%s\n\n%s\n%s",
139 runtimeErr, stack, GoRuntimeErrorTracePrefix, debug.Stack())
140 }
141
142
143 if runtimeErr, ok := recovered.(error); ok {
144 return fmt.Errorf("%w (recovered by wazero)\nwasm stack trace:\n\t%s", runtimeErr, stack)
145 } else {
146 return fmt.Errorf("%v (recovered by wazero)\nwasm stack trace:\n\t%s", recovered, stack)
147 }
148 }
149
150
151 func (s *stackTrace) AddFrame(funcName string, paramTypes, resultTypes []api.ValueType, sources []string) {
152 sig := signature(funcName, paramTypes, resultTypes)
153 s.frames = append(s.frames, sig)
154 for _, source := range sources {
155 s.frames = append(s.frames, "\t"+source)
156 }
157 }
158
View as plain text