| Index: fuzzer/go/fuzz/stacktrace.go
|
| diff --git a/fuzzer/go/fuzz/stacktrace.go b/fuzzer/go/fuzz/stacktrace.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..98a5887b7bfa81ac29c03072b8125a5274ec4404
|
| --- /dev/null
|
| +++ b/fuzzer/go/fuzz/stacktrace.go
|
| @@ -0,0 +1,93 @@
|
| +package fuzz
|
| +
|
| +import (
|
| + "bufio"
|
| + "bytes"
|
| + "fmt"
|
| + "regexp"
|
| + "strconv"
|
| + "strings"
|
| +
|
| + "github.com/skia-dev/glog"
|
| +)
|
| +
|
| +type StackTrace struct {
|
| + Frames []StackTraceFrame `json:"frames"`
|
| +}
|
| +
|
| +type StackTraceFrame struct {
|
| + PackageName string `json:"packageName"`
|
| + FileName string `json:"fileName"`
|
| + LineNumber int `json:"lineNumber"`
|
| + FunctionName string `json:"functionName"`
|
| +}
|
| +
|
| +// The `?:` at the beginning of the groups prevent them from being captured
|
| +var stackTraceLine = regexp.MustCompile(`(?:\.\./)+((?:\w+/)+)(.+):(\d+)\(`)
|
| +
|
| +// Given the files of a dump file (created through get_stack_trace [which uses catchsegv], return the stack trace)
|
| +func ParseStackTrace(contents string) StackTrace {
|
| + r := bytes.NewReader([]byte(contents))
|
| + scan := bufio.NewScanner(r)
|
| +
|
| + hasBegun := false
|
| +
|
| + frames := make([]StackTraceFrame, 0, 5)
|
| +
|
| + for scan.Scan() {
|
| + line := scan.Text()
|
| + if strings.Contains(line, "Backtrace") {
|
| + hasBegun = true
|
| + }
|
| + if strings.Contains(line, "Memory map") {
|
| + break
|
| + }
|
| + if !hasBegun {
|
| + continue
|
| + }
|
| +
|
| + if match := stackTraceLine.FindStringSubmatch(line); match != nil {
|
| + // match[0] is the entire matched portion, [1] is the "package", [2] is the file name, [3] is the line number
|
| +
|
| + lineNumber, err := strconv.Atoi(match[3])
|
| + if err != nil {
|
| + glog.Errorf("Could not parse line number from stacktrace line %q: %s", match[0], err)
|
| + continue
|
| + }
|
| + newFrame := BasicStackFrame(match[1], match[2], lineNumber)
|
| + frames = append(frames, newFrame)
|
| + }
|
| + }
|
| +
|
| + return StackTrace{frames}
|
| +}
|
| +
|
| +func BasicStackFrame(packageName, fileName string, lineNumber int) StackTraceFrame {
|
| + return StackTraceFrame{packageName, fileName, lineNumber, ""}
|
| +}
|
| +
|
| +type FindFunctionName func(packageName string, fileName string, lineNumber int) string
|
| +
|
| +// LookUpFunctions will go through all the stacktraces and call the passed in function to find the approximate function name the stacktrace is referring to
|
| +func (st *StackTrace) LookUpFunctions(findFunctionName FindFunctionName) {
|
| + for i, f := range st.Frames {
|
| + // this awkward syntax is required to write to the actual StackTraceFrame, not the copy generated by range
|
| + st.Frames[i].FunctionName = findFunctionName(f.PackageName, f.FileName, f.LineNumber)
|
| + }
|
| +}
|
| +
|
| +func (f *StackTraceFrame) String() string {
|
| + return fmt.Sprintf("%s%s:%d %s", f.PackageName, f.FileName, f.LineNumber, f.FunctionName)
|
| +}
|
| +
|
| +func (st *StackTrace) String() string {
|
| + s := fmt.Sprintf("StackTrace with %d frames:\n", len(st.Frames))
|
| + for _, f := range st.Frames {
|
| + s += fmt.Sprintf("\t%s\n", f.String())
|
| + }
|
| + return s
|
| +}
|
| +
|
| +func (st *StackTrace) IsEmpty() bool {
|
| + return len(st.Frames) == 0
|
| +}
|
|
|