Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: fuzzer/go/frontend/data/stacktrace.go

Issue 1691893002: Fuzzer now deduplicates on the analysis side instead of the download side (Closed) Base URL: https://skia.googlesource.com/buildbot@metrics
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « fuzzer/go/frontend/data/result.go ('k') | fuzzer/go/frontend/data/stacktrace_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 package data
2
3 import (
4 "bufio"
5 "bytes"
6 "fmt"
7 "regexp"
8 "strconv"
9 "strings"
10
11 "github.com/skia-dev/glog"
12 "go.skia.org/infra/fuzzer/go/common"
13 )
14
15 type StackTrace struct {
16 Frames []StackTraceFrame `json:"frames"`
17 }
18
19 type StackTraceFrame struct {
20 PackageName string `json:"packageName"`
21 FileName string `json:"fileName"`
22 LineNumber int `json:"lineNumber"`
23 FunctionName string `json:"functionName"`
24 }
25
26 // The `?:` at the beginning of the groups prevent them from being captured
27 // \1 is the "package", \2 is the file name, \3 is the line number, \4 is the fu nction symbol string
28 var segvStackTraceLine = regexp.MustCompile(`(?:\.\./)+(?P<package>(?:\w+/)+)(?P <file>.+):(?P<line>\d+).*\(_(?P<symbol>.*)\)`)
29
30 // parseCatchsegvStackTrace takes the contents of a dump file of a catchsegv run , and returns the
31 // parsed stacktrace
32 func parseCatchsegvStackTrace(contents string) StackTrace {
33 r := bytes.NewBufferString(contents)
34 scan := bufio.NewScanner(r)
35
36 hasBegun := false
37
38 frames := make([]StackTraceFrame, 0, 5)
39
40 for scan.Scan() {
41 line := scan.Text()
42 if strings.Contains(line, "Backtrace") {
43 hasBegun = true
44 }
45 if strings.Contains(line, "Memory map") {
46 break
47 }
48 if !hasBegun {
49 continue
50 }
51
52 if match := segvStackTraceLine.FindStringSubmatch(line); match ! = nil {
53 // match[0] is the entire matched portion, [1] is the "p ackage", [2] is the file name,
54 // [3] is the line number and [4] is the encoded functio n symbol string.
55 newFrame := FullStackFrame(match[1], match[2], catchsegv FunctionName(match[4]), safeParseInt(match[3]))
56 frames = append(frames, newFrame)
57 }
58 }
59 return StackTrace{Frames: frames}
60 }
61
62 // safeParseInt parses a string that is known to contain digits into an int.
63 // It may fail if the number is larger than MAX_INT, but it is unlikely those
64 // numbers would come up in the stacktraces.
65 func safeParseInt(n string) int {
66 if i, err := strconv.Atoi(n); err != nil {
67 glog.Errorf("Could not parse number from known digits %q: %v", n , err)
68 return 0
69 } else {
70 return i
71 }
72 }
73
74 var staticStart = regexp.MustCompile(`^ZL(\d+)`)
75 var nonstaticStart = regexp.MustCompile(`^Z(\d+)`)
76
77 var methodStart = regexp.MustCompile(`^(ZNK?)(\d+)`)
78 var methodName = regexp.MustCompile(`^(\d+)`)
79
80 // catchsegvFunctionName parses the symbol string from a stacktrace to
81 // get the name of the related function.
82 //TODO(kjlubick) parse arguments if that helps the readability of the stacktrace s
83 // Here are some examples of symbol strings and what the various chars mean:
84 // (Parameters are after the names, but are unparsed as of yet)
85 // ZL12convert_to_8 -> ZL12 -> static function 12 long "convert_to_8"
86 // Z9tool_mainiPPc -> non-static function, 9 long "tool_main"
87 // ZN14SkBmpMaskCodec10decodeRows -> ZN14 -> type is 14 long, method name is 10 long "decodeRows"
88 // ZNK2DM6SKPSrc4drawEP8SkCanvas -> ZNK2 -> type is 2 long (method is konstant) "DM" ->
89 // 6 -> Sub type is 6 long "SKPSrc" -> 4 -> method is 4 long "draw"
90 // (since there is no number directly after the 3rd step, we have found the p aram boundary).
91 func catchsegvFunctionName(s string) string {
92 if match := methodStart.FindStringSubmatch(s); match != nil {
93 length := safeParseInt(match[2])
94 // ZNK? is 2-3 chars, so slice (num letters + num digits + numbe r of spaces) chars off
95 // the beginning.
96 s = s[len(match[1])+len(match[2])+length:]
97 f := ""
98 // We look at the beginning of our trimmed string for numbers.
99 // if there are numbers, we pull off a piece of the name and sca n again.
100 // If there is more than one piece, we separate it with ::, beca use it is a nested type
101 // or enum thing.
102 for match := methodName.FindStringSubmatch(s); match != nil; mat ch = methodName.FindStringSubmatch(s) {
103 if f != "" {
104 f += "::"
105 }
106 length = safeParseInt(match[1])
107 start := len(match[1])
108 f += s[start : start+length]
109 s = s[start+length:]
110 }
111 return f
112 }
113 if match := staticStart.FindStringSubmatch(s); match != nil {
114 length := safeParseInt(match[1])
115 // ZL is 2 chars, so advance 2 spaces + how many digits there ar e
116 start := 2 + len(match[1])
117 return s[start : start+length]
118 }
119 if match := nonstaticStart.FindStringSubmatch(s); match != nil {
120 length := safeParseInt(match[1])
121 // Z is 1 char, so advance 1 space + how many digits there are
122 start := 1 + len(match[1])
123 return s[start : start+length]
124 }
125 return common.UNKNOWN_FUNCTION
126 }
127
128 // The `?:` at the beginning of the groups prevent them from being captured
129 // \1 is the (hopefully symbolized) function name, \2 is the "package", \3 is th e file name,
130 // \4 is the line number
131 var asanStackTraceLine = regexp.MustCompile(`in (?P<function>[a-zA-Z0-9_:]+).*(? :\.\./)+(?P<package>(?:\w+/)+)(?P<file>.+?):(?P<line>\d+)`)
132
133 // parseCatchsegvStackTrace takes the output of an AddressSanitizer crash, and r eturns the parsed
134 // StackTrace, if it is able to find one. If the result is not symbolized, this will return
135 // an empty StackTrace.
136 func parseASANStackTrace(contents string) StackTrace {
137 r := bytes.NewBufferString(contents)
138 scan := bufio.NewScanner(r)
139
140 hasBegun := false
141
142 frames := make([]StackTraceFrame, 0, 5)
143
144 for scan.Scan() {
145 line := scan.Text()
146 if strings.Contains(line, "ERROR: AddressSanitizer:") {
147 hasBegun = true
148 continue
149 }
150 if hasBegun && line == "" {
151 break
152 }
153 if !hasBegun {
154 continue
155 }
156
157 line = strings.Replace(line, "(anonymous namespace)::", "", -1)
158
159 if match := asanStackTraceLine.FindStringSubmatch(line); match ! = nil {
160 // match[0] is the entire matched portion, [1] is the fu nction name [2] is the
161 // "package", [3] is the file name, [4] is the line numb er
162 newFrame := FullStackFrame(match[2], match[3], match[1], safeParseInt(match[4]))
163 frames = append(frames, newFrame)
164 }
165 }
166 return StackTrace{Frames: frames}
167 }
168
169 // FullStackFrame creates a StackTraceFrame with all components
170 func FullStackFrame(packageName, fileName, functionName string, lineNumber int) StackTraceFrame {
171 return StackTraceFrame{
172 PackageName: packageName,
173 FileName: fileName,
174 LineNumber: lineNumber,
175 FunctionName: functionName,
176 }
177 }
178
179 func (f *StackTraceFrame) String() string {
180 return fmt.Sprintf("%s%s:%d %s", f.PackageName, f.FileName, f.LineNumber , f.FunctionName)
181 }
182
183 func (st *StackTrace) String() string {
184 s := fmt.Sprintf("StackTrace with %d frames:\n", len(st.Frames))
185 for _, f := range st.Frames {
186 s += fmt.Sprintf("\t%s\n", f.String())
187 }
188 return s
189 }
190
191 func (st *StackTrace) IsEmpty() bool {
192 return len(st.Frames) == 0
193 }
OLDNEW
« no previous file with comments | « fuzzer/go/frontend/data/result.go ('k') | fuzzer/go/frontend/data/stacktrace_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698