github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/coveragedb/functions.go (about)

     1  // Copyright 2025 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 coveragedb
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  
    10  	"cloud.google.com/go/spanner"
    11  	"github.com/google/syzkaller/pkg/coveragedb/spannerclient"
    12  	"google.golang.org/api/iterator"
    13  )
    14  
    15  // FuncLines represents the 'functions' table records.
    16  // It could be used to maps 'hitcounts' from 'files' table to the function names.
    17  type FuncLines struct {
    18  	FilePath string
    19  	FuncName string
    20  	Lines    []int64 // List of lines we know belong to this function name according to the addr2line output.
    21  }
    22  
    23  func MakeFuncFinder(ctx context.Context, client spannerclient.SpannerClient, ns string, timePeriod TimePeriod,
    24  ) (*FunctionFinder, error) {
    25  	stmt := spanner.Statement{
    26  		SQL: `select
    27      filepath, funcname, lines
    28  from merge_history
    29    join functions
    30      on merge_history.session = functions.session
    31  where
    32    merge_history.namespace=$1 and dateto=$2 and duration=$3`,
    33  		Params: map[string]interface{}{
    34  			"p1": ns,
    35  			"p2": timePeriod.DateTo,
    36  			"p3": timePeriod.Days,
    37  		},
    38  	}
    39  	iter := client.Single().Query(ctx, stmt)
    40  	defer iter.Stop()
    41  
    42  	ff := &FunctionFinder{}
    43  	for {
    44  		row, err := iter.Next()
    45  		if err == iterator.Done {
    46  			break
    47  		}
    48  		if err != nil {
    49  			return nil, fmt.Errorf("iter.Next(): %w", err)
    50  		}
    51  		var r FuncLines
    52  		if err = row.ToStruct(&r); err != nil {
    53  			return nil, fmt.Errorf("row.ToStruct(): %w", err)
    54  		}
    55  
    56  		for _, val := range r.Lines {
    57  			ff.addLine(r.FilePath, r.FuncName, int(val))
    58  		}
    59  	}
    60  	return ff, nil
    61  }
    62  
    63  type FunctionFinder struct {
    64  	fileLineToFuncName map[string]map[int]string
    65  }
    66  
    67  func (ff *FunctionFinder) addLine(fileName, funcName string, line int) {
    68  	if ff.fileLineToFuncName == nil {
    69  		ff.fileLineToFuncName = map[string]map[int]string{}
    70  	}
    71  	if ff.fileLineToFuncName[fileName] == nil {
    72  		ff.fileLineToFuncName[fileName] = map[int]string{}
    73  	}
    74  	ff.fileLineToFuncName[fileName][line] = funcName
    75  }
    76  
    77  func (ff *FunctionFinder) FileLineToFuncName(filePath string, line int) (string, error) {
    78  	if _, ok := ff.fileLineToFuncName[filePath]; !ok {
    79  		return "", fmt.Errorf("file %s not found", filePath)
    80  	}
    81  	if _, ok := ff.fileLineToFuncName[filePath][line]; !ok {
    82  		return "", fmt.Errorf("file:line %s:%d function not found", filePath, line)
    83  	}
    84  	return ff.fileLineToFuncName[filePath][line], nil
    85  }