github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/report/bsd.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package report 5 6 import ( 7 "bytes" 8 "fmt" 9 "path/filepath" 10 "regexp" 11 "strconv" 12 "strings" 13 14 "github.com/google/syzkaller/pkg/symbolizer" 15 ) 16 17 type bsd struct { 18 *config 19 oopses []*oops 20 symbolizeRes []*regexp.Regexp 21 kernelObject string 22 symbols map[string][]symbolizer.Symbol 23 } 24 25 func ctorBSD(cfg *config, oopses []*oops, symbolizeRes []*regexp.Regexp) (reporterImpl, error) { 26 var symbols map[string][]symbolizer.Symbol 27 kernelObject := "" 28 if cfg.kernelDirs.Obj != "" { 29 kernelObject = filepath.Join(cfg.kernelDirs.Obj, cfg.target.KernelObject) 30 var err error 31 symbols, err = symbolizer.ReadTextSymbols(kernelObject) 32 if err != nil { 33 return nil, err 34 } 35 } 36 ctx := &bsd{ 37 config: cfg, 38 oopses: oopses, 39 symbolizeRes: symbolizeRes, 40 kernelObject: kernelObject, 41 symbols: symbols, 42 } 43 return ctx, nil 44 } 45 46 func (ctx *bsd) ContainsCrash(output []byte) bool { 47 return containsCrash(output, ctx.oopses, ctx.ignores) 48 } 49 50 func (ctx *bsd) Parse(output []byte) *Report { 51 return simpleLineParser(output, ctx.oopses, nil, ctx.ignores) 52 } 53 54 func (ctx *bsd) Symbolize(rep *Report) error { 55 symb := symbolizer.Make(ctx.config.target) 56 defer symb.Close() 57 var symbolized []byte 58 prefix := rep.reportPrefixLen 59 for _, line := range bytes.SplitAfter(rep.Report, []byte("\n")) { 60 line := bytes.Clone(line) 61 newLine := ctx.symbolizeLine(symb.Symbolize, line) 62 if prefix > len(symbolized) { 63 prefix += len(newLine) - len(line) 64 } 65 symbolized = append(symbolized, newLine...) 66 } 67 rep.Report = symbolized 68 rep.reportPrefixLen = prefix 69 return nil 70 } 71 72 func (ctx *bsd) symbolizeLine(symbFunc func(string, ...uint64) ([]symbolizer.Frame, error), 73 line []byte) []byte { 74 var match []int 75 // Check whether the line corresponds to the any of the parts that require symbolization. 76 for _, re := range ctx.symbolizeRes { 77 match = re.FindSubmatchIndex(line) 78 if match != nil { 79 break 80 } 81 } 82 if match == nil { 83 return line 84 } 85 // First part of the matched regex contains the function name. 86 // Second part contains the offset. 87 fn := line[match[2]:match[3]] 88 off, err := strconv.ParseUint(string(line[match[4]:match[5]]), 16, 64) 89 if err != nil { 90 return line 91 } 92 93 // Get the symbol from the list of symbols generated using the kernel object and addr2line. 94 symb := ctx.symbols[string(fn)] 95 if len(symb) == 0 { 96 return line 97 } 98 fnStart := (0xffffffff << 32) | symb[0].Addr 99 100 // Retrieve the frames for the corresponding offset of the function. 101 frames, err := symbFunc(ctx.kernelObject, fnStart+off) 102 if err != nil || len(frames) == 0 { 103 return line 104 } 105 var symbolized []byte 106 // Go through each of the frames and add the corresponding file names and line numbers. 107 for _, frame := range frames { 108 file := frame.File 109 file = strings.TrimPrefix(file, ctx.kernelDirs.BuildSrc) 110 file = strings.TrimPrefix(file, "/") 111 info := fmt.Sprintf(" %v:%v", file, frame.Line) 112 modified := append([]byte{}, line...) 113 modified = replace(modified, match[5], match[5], []byte(info)) 114 if frame.Inline { 115 // If frames are marked inline then show that in the report also. 116 end := match[5] + len(info) 117 modified = replace(modified, end, end, []byte(" [inline]")) 118 modified = replace(modified, match[5], match[5], []byte(" "+frame.Func)) 119 } 120 symbolized = append(symbolized, modified...) 121 } 122 return symbolized 123 }