67 lines
1.5 KiB
Go
67 lines
1.5 KiB
Go
package fingerprint
|
|
|
|
import (
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// ASan/MSan/TSan/UBSan frame patterns:
|
|
// #0 0x55a3b4 in function_name /path/to/file.c:42:13
|
|
// #0 0x55a3b4 in function_name (/path/to/binary+0x1234)
|
|
// #1 0x55a3b4 (/path/to/binary+0x1234)
|
|
var asanFrameRe = regexp.MustCompile(
|
|
`^\s*#(\d+)\s+(0x[0-9a-fA-F]+)\s+(?:in\s+(\S+)\s+)?(.*)$`,
|
|
)
|
|
|
|
// ASan error header line, e.g.:
|
|
// ==12345==ERROR: AddressSanitizer: heap-buffer-overflow
|
|
var asanHeaderRe = regexp.MustCompile(
|
|
`==\d+==ERROR:\s+(Address|Memory|Thread|Undefined)Sanitizer`,
|
|
)
|
|
|
|
// ParseASan parses AddressSanitizer, MemorySanitizer, ThreadSanitizer,
|
|
// and UndefinedBehaviorSanitizer stack traces.
|
|
func ParseASan(raw string) []Frame {
|
|
if !asanHeaderRe.MatchString(raw) {
|
|
return nil
|
|
}
|
|
|
|
var frames []Frame
|
|
for _, line := range strings.Split(raw, "\n") {
|
|
m := asanFrameRe.FindStringSubmatch(line)
|
|
if m == nil {
|
|
continue
|
|
}
|
|
|
|
idx, _ := strconv.Atoi(m[1])
|
|
addr := m[2]
|
|
fn := m[3]
|
|
location := m[4]
|
|
|
|
var file string
|
|
var lineNo int
|
|
|
|
// Try to extract file:line from location.
|
|
if parts := strings.SplitN(location, ":", 3); len(parts) >= 2 {
|
|
// Could be /path/to/file.c:42 or (/binary+0x1234)
|
|
if !strings.HasPrefix(parts[0], "(") {
|
|
file = parts[0]
|
|
if len(parts) >= 2 {
|
|
lineNo, _ = strconv.Atoi(parts[1])
|
|
}
|
|
}
|
|
}
|
|
|
|
frames = append(frames, Frame{
|
|
Index: idx,
|
|
Address: addr,
|
|
Function: fn,
|
|
File: strings.TrimSpace(file),
|
|
Line: lineNo,
|
|
})
|
|
}
|
|
|
|
return frames
|
|
}
|