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  }