github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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.kernelObj != "" { 29 kernelObject = filepath.Join(cfg.kernelObj, cfg.target.KernelObject) 30 var err error 31 symb := symbolizer.NewSymbolizer(cfg.target) 32 symbols, err = symb.ReadTextSymbols(kernelObject) 33 if err != nil { 34 return nil, err 35 } 36 } 37 ctx := &bsd{ 38 config: cfg, 39 oopses: oopses, 40 symbolizeRes: symbolizeRes, 41 kernelObject: kernelObject, 42 symbols: symbols, 43 } 44 return ctx, nil 45 } 46 47 func (ctx *bsd) ContainsCrash(output []byte) bool { 48 return containsCrash(output, ctx.oopses, ctx.ignores) 49 } 50 51 func (ctx *bsd) Parse(output []byte) *Report { 52 return simpleLineParser(output, ctx.oopses, nil, ctx.ignores) 53 } 54 55 func (ctx *bsd) Symbolize(rep *Report) error { 56 symb := symbolizer.NewSymbolizer(ctx.config.target) 57 defer symb.Close() 58 var symbolized []byte 59 prefix := rep.reportPrefixLen 60 for _, line := range bytes.SplitAfter(rep.Report, []byte("\n")) { 61 line := bytes.Clone(line) 62 newLine := ctx.symbolizeLine(symb.Symbolize, line) 63 if prefix > len(symbolized) { 64 prefix += len(newLine) - len(line) 65 } 66 symbolized = append(symbolized, newLine...) 67 } 68 rep.Report = symbolized 69 rep.reportPrefixLen = prefix 70 return nil 71 } 72 73 func (ctx *bsd) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error), 74 line []byte) []byte { 75 var match []int 76 // Check whether the line corresponds to the any of the parts that require symbolization. 77 for _, re := range ctx.symbolizeRes { 78 match = re.FindSubmatchIndex(line) 79 if match != nil { 80 break 81 } 82 } 83 if match == nil { 84 return line 85 } 86 // First part of the matched regex contains the function name. 87 // Second part contains the offset. 88 fn := line[match[2]:match[3]] 89 off, err := strconv.ParseUint(string(line[match[4]:match[5]]), 16, 64) 90 if err != nil { 91 return line 92 } 93 94 // Get the symbol from the list of symbols generated using the kernel object and addr2line. 95 symb := ctx.symbols[string(fn)] 96 if len(symb) == 0 { 97 return line 98 } 99 fnStart := (0xffffffff << 32) | symb[0].Addr 100 101 // Retrieve the frames for the corresponding offset of the function. 102 frames, err := symbFunc(ctx.kernelObject, fnStart+off) 103 if err != nil || len(frames) == 0 { 104 return line 105 } 106 var symbolized []byte 107 // Go through each of the frames and add the corresponding file names and line numbers. 108 for _, frame := range frames { 109 file := frame.File 110 file = strings.TrimPrefix(file, ctx.kernelBuildSrc) 111 file = strings.TrimPrefix(file, "/") 112 info := fmt.Sprintf(" %v:%v", file, frame.Line) 113 modified := append([]byte{}, line...) 114 modified = replace(modified, match[5], match[5], []byte(info)) 115 if frame.Inline { 116 // If frames are marked inline then show that in the report also. 117 end := match[5] + len(info) 118 modified = replace(modified, end, end, []byte(" [inline]")) 119 modified = replace(modified, match[5], match[5], []byte(" "+frame.Func)) 120 } 121 symbolized = append(symbolized, modified...) 122 } 123 return symbolized 124 }