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  }