107 lines
1.8 KiB
Go
107 lines
1.8 KiB
Go
package fingerprint
|
|
|
|
import (
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
const maxFrames = 8
|
|
|
|
var (
|
|
hexAddrRe = regexp.MustCompile(`0x[0-9a-fA-F]+`)
|
|
templateParamRe = regexp.MustCompile(`<[^>]*>`)
|
|
abiTagRe = regexp.MustCompile(`\[abi:[^\]]*\]`)
|
|
)
|
|
|
|
// runtimePrefixes are function prefixes for runtime/library frames to filter out.
|
|
var runtimePrefixes = []string{
|
|
"__libc_",
|
|
"__GI_",
|
|
"_start",
|
|
"__clone",
|
|
"start_thread",
|
|
"__pthread_",
|
|
"__sigaction",
|
|
"_dl_",
|
|
"__tls_",
|
|
// glibc allocator internals
|
|
"__libc_malloc",
|
|
"__libc_free",
|
|
"malloc",
|
|
"free",
|
|
"realloc",
|
|
"calloc",
|
|
// ASan runtime
|
|
"__asan_",
|
|
"__sanitizer_",
|
|
"__interceptor_",
|
|
"__interception::",
|
|
// Zig std runtime
|
|
"std.debug.",
|
|
"std.start.",
|
|
"std.os.linux.",
|
|
"posixCallNative",
|
|
}
|
|
|
|
// Normalize applies stability-oriented transformations to parsed frames.
|
|
func Normalize(frames []Frame) []NormalizedFrame {
|
|
var result []NormalizedFrame
|
|
|
|
for _, f := range frames {
|
|
// Skip inline frames.
|
|
if f.Inline {
|
|
continue
|
|
}
|
|
|
|
fn := f.Function
|
|
|
|
// Skip runtime/library frames.
|
|
if isRuntimeFrame(fn) {
|
|
continue
|
|
}
|
|
|
|
// Strip hex addresses.
|
|
fn = hexAddrRe.ReplaceAllString(fn, "")
|
|
|
|
// Strip C++ template parameters.
|
|
fn = templateParamRe.ReplaceAllString(fn, "<>")
|
|
|
|
// Strip ABI tags.
|
|
fn = abiTagRe.ReplaceAllString(fn, "")
|
|
|
|
// Clean up whitespace.
|
|
fn = strings.TrimSpace(fn)
|
|
|
|
// Strip paths to just filename.
|
|
file := f.File
|
|
if file != "" {
|
|
file = filepath.Base(file)
|
|
}
|
|
|
|
if fn == "" {
|
|
continue
|
|
}
|
|
|
|
result = append(result, NormalizedFrame{
|
|
Function: fn,
|
|
File: file,
|
|
})
|
|
|
|
if len(result) >= maxFrames {
|
|
break
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func isRuntimeFrame(fn string) bool {
|
|
for _, prefix := range runtimePrefixes {
|
|
if strings.HasPrefix(fn, prefix) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|