github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/binary_info/binary_info.go (about)

     1  // The MIT License (MIT)
     2  
     3  // Copyright (c) 2014 Derek Parker
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy of
     6  // this software and associated documentation files (the "Software"), to deal in
     7  // the Software without restriction, including without limitation the rights to
     8  // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
     9  // the Software, and to permit persons to whom the Software is furnished to do so,
    10  // subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    17  // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    18  // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    19  // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    20  // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  package binary_info
    23  
    24  import (
    25  	"bytes"
    26  	"compress/zlib"
    27  	"debug/dwarf"
    28  	"debug/elf"
    29  	"encoding/binary"
    30  	"errors"
    31  	"fmt"
    32  	"io"
    33  	"os"
    34  	"path/filepath"
    35  	"runtime"
    36  	"sort"
    37  	"strings"
    38  	"sync"
    39  
    40  	"github.com/Rookout/GoSDK/pkg/logger"
    41  	"github.com/Rookout/GoSDK/pkg/rookoutErrors"
    42  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/frame"
    43  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/godwarf"
    44  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/line"
    45  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/loclist"
    46  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/op"
    47  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/reader"
    48  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/util"
    49  	"github.com/Rookout/GoSDK/pkg/utils"
    50  	"github.com/hashicorp/golang-lru/simplelru"
    51  )
    52  
    53  type Function struct {
    54  	Name       string
    55  	Entry, End uint64 
    56  	Offset     dwarf.Offset
    57  	cu         *compileUnit
    58  
    59  	
    60  	InlinedCalls []InlinedCall
    61  	trampoline   bool
    62  }
    63  
    64  const crosscall2SPOffsetBad = 0x8
    65  
    66  type BinaryInfo struct {
    67  	
    68  	
    69  	
    70  	sigreturnfn *Function
    71  	
    72  	
    73  	
    74  	
    75  	crosscall2fn      *Function
    76  	debugLocBytes     []byte
    77  	debugLoclistBytes []byte
    78  	PointerSize       int
    79  
    80  	debugInfoDirectories []string
    81  
    82  	
    83  	Functions []Function
    84  	
    85  	Sources []string
    86  	
    87  	LookupFunc map[string]*Function
    88  
    89  	
    90  	SymNames map[uint64]*elf.Symbol
    91  
    92  	
    93  	
    94  	Images []*Image
    95  
    96  	ElfDynamicSection ElfDynamicSection
    97  
    98  	
    99  	
   100  	
   101  	
   102  	
   103  	
   104  	
   105  	
   106  	
   107  	PackageMap map[string][]string
   108  
   109  	FrameEntries frame.FrameDescriptionEntries
   110  
   111  	types       map[string]dwarfRef
   112  	packageVars []packageVar 
   113  
   114  	
   115  	
   116  	
   117  	NameOfRuntimeType map[uint64]NameOfRuntimeTypeEntry
   118  
   119  	
   120  	consts constantsMap
   121  
   122  	
   123  	
   124  	
   125  	inlinedCallLines map[fileLine][]uint64
   126  
   127  	Dwarf     *dwarf.Data
   128  	TypeCache sync.Map
   129  }
   130  
   131  type NameOfRuntimeTypeEntry struct {
   132  	Typename string
   133  	Kind     int64
   134  }
   135  
   136  type fileLine struct {
   137  	file string
   138  	line int
   139  }
   140  
   141  
   142  type dwarfRef struct {
   143  	imageIndex int
   144  	offset     dwarf.Offset
   145  }
   146  
   147  
   148  type InlinedCall struct {
   149  	cu            *compileUnit
   150  	LowPC, HighPC uint64 
   151  }
   152  
   153  
   154  
   155  
   156  type packageVar struct {
   157  	name   string
   158  	cu     *compileUnit
   159  	offset dwarf.Offset
   160  	addr   uint64
   161  }
   162  
   163  type buildIDHeader struct {
   164  	Namesz uint32
   165  	Descsz uint32
   166  	Type   uint32
   167  }
   168  
   169  
   170  type ElfDynamicSection struct {
   171  	Addr uint64 
   172  	Size uint64 
   173  }
   174  
   175  
   176  func NewBinaryInfo() *BinaryInfo {
   177  	pointerSize := 4 << (^uintptr(0) >> 63) 
   178  	r := &BinaryInfo{NameOfRuntimeType: make(map[uint64]NameOfRuntimeTypeEntry), PointerSize: pointerSize}
   179  	return r
   180  }
   181  
   182  
   183  func (bi *BinaryInfo) LoadBinaryInfo(path string, entryPoint uint64, debugInfoDirs []string) error {
   184  	bi.debugInfoDirectories = debugInfoDirs
   185  	
   186  
   187  	return bi.AddImage(path, entryPoint)
   188  }
   189  
   190  var dwarfTreeCacheSize = 512 
   191  
   192  
   193  
   194  
   195  
   196  func (bi *BinaryInfo) AddImage(path string, addr uint64) error {
   197  	
   198  	if len(bi.Images) > 0 && !strings.HasPrefix(path, "/") {
   199  		return nil
   200  	}
   201  	for _, image := range bi.Images {
   202  		if image.Path == path && image.addr == addr {
   203  			return nil
   204  		}
   205  	}
   206  
   207  	
   208  	image := &Image{Path: path, addr: addr}
   209  	image.dwarfTreeCache, _ = simplelru.NewLRU(dwarfTreeCacheSize, nil)
   210  
   211  	
   212  	image.Index = len(bi.Images)
   213  	bi.Images = append(bi.Images, image)
   214  	err := loadBinaryInfo(bi, image, path, addr)
   215  	if err != nil {
   216  		bi.Images[len(bi.Images)-1].loadErr = err
   217  	}
   218  	return err
   219  }
   220  
   221  func isSupportedArch(a archID) bool {
   222  	if _, ok := supportedArchs[a]; ok {
   223  		return true
   224  	}
   225  	return false
   226  }
   227  
   228  
   229  
   230  func GetDebugSection(f *File, name string) ([]byte, error) {
   231  	sec := f.Section(getSectionName(name))
   232  	if sec != nil {
   233  		return sec.Data()
   234  	}
   235  	sec = f.Section(getCompressedSectionName(name))
   236  	if sec == nil {
   237  		return nil, fmt.Errorf("could not find .debug_%s section", name)
   238  	}
   239  	b, err := sec.Data()
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  	return decompressMaybe(b)
   244  }
   245  
   246  func decompressMaybe(b []byte) ([]byte, error) {
   247  	if len(b) < 12 || string(b[:4]) != "ZLIB" {
   248  		
   249  		return b, nil
   250  	}
   251  
   252  	dlen := binary.BigEndian.Uint64(b[4:12])
   253  	dbuf := make([]byte, dlen)
   254  	r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	if _, err := io.ReadFull(r, dbuf); err != nil {
   259  		return nil, err
   260  	}
   261  	if err := r.Close(); err != nil {
   262  		return nil, err
   263  	}
   264  	return dbuf, nil
   265  }
   266  
   267  
   268  
   269  
   270  func (bi *BinaryInfo) parseDebugFrame(image *Image, exe *File, debugInfoBytes []byte) error {
   271  	debugFrameData, err := GetDebugSection(exe, "frame")
   272  	ehFrameSection := getEhFrameSection(exe)
   273  	if ehFrameSection == nil && debugFrameData == nil {
   274  		return fmt.Errorf("could not get .debug_frame section and .eh_frame section: %v", err)
   275  	}
   276  	var ehFrameData []byte
   277  	var ehFrameAddr uint64
   278  	if ehFrameSection != nil {
   279  		ehFrameAddr = ehFrameSection.Addr
   280  		ehFrameData, _ = ehFrameSection.Data()
   281  	}
   282  	byteOrder := frame.DwarfEndian(debugInfoBytes)
   283  
   284  	if debugFrameData != nil {
   285  		fe, err := frame.Parse(debugFrameData, byteOrder, image.StaticBase, bi.PointerSize, 0)
   286  		if err != nil {
   287  			return fmt.Errorf("could not parse .debug_frame section: %v", err)
   288  		}
   289  		bi.FrameEntries = bi.FrameEntries.Append(fe)
   290  	}
   291  
   292  	if ehFrameData != nil && ehFrameAddr > 0 {
   293  		fe, err := frame.Parse(ehFrameData, byteOrder, image.StaticBase, bi.PointerSize, ehFrameAddr)
   294  		if err != nil {
   295  			if debugFrameData == nil {
   296  				return fmt.Errorf("could not parse .eh_frame section: %v", err)
   297  			}
   298  			return nil
   299  		}
   300  		bi.FrameEntries = bi.FrameEntries.Append(fe)
   301  	}
   302  
   303  	return nil
   304  }
   305  
   306  func shouldFilterSource(path string) bool {
   307  	if utils.Contains(utils.TrueValues, os.Getenv("ROOKOUT_DONT_FILTER_SOURCES")) {
   308  		return false
   309  	}
   310  
   311  	
   312  	if strings.Contains(path, "shouldrunprologue") || strings.Contains(path, "prepforcallback") {
   313  		return false
   314  	}
   315  
   316  	return strings.Contains(path, "gorook") || strings.Contains(path, "gosdk")
   317  }
   318  
   319  func (bi *BinaryInfo) loadSources(compileUnits []*compileUnit) {
   320  	for _, cu := range compileUnits {
   321  		if cu.lineInfo == nil {
   322  			continue
   323  		}
   324  		for _, fileEntry := range cu.lineInfo.FileNames {
   325  			if shouldFilterSource(fileEntry.Path) {
   326  				continue
   327  			}
   328  			bi.Sources = append(bi.Sources, fileEntry.Path)
   329  		}
   330  	}
   331  	sort.Strings(bi.Sources)
   332  	bi.Sources = uniq(bi.Sources)
   333  }
   334  
   335  func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugInfoBytes, debugLineBytes []byte) error {
   336  	if bi.types == nil {
   337  		bi.types = make(map[string]dwarfRef)
   338  	}
   339  	if bi.consts == nil {
   340  		bi.consts = make(map[dwarfRef]*constantType)
   341  	}
   342  	if bi.PackageMap == nil {
   343  		bi.PackageMap = make(map[string][]string)
   344  	}
   345  	if bi.inlinedCallLines == nil {
   346  		bi.inlinedCallLines = make(map[fileLine][]uint64)
   347  	}
   348  
   349  	image.RuntimeTypeToDIE = make(map[uint64]runtimeTypeDIE)
   350  
   351  	ctxt := newLoadDebugInfoMapsContext(bi, image, util.ReadUnitVersions(debugInfoBytes))
   352  
   353  	reader := image.Dwarf.Reader()
   354  
   355  	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
   356  		if err != nil {
   357  			return errors.New("error reading debug_info")
   358  		}
   359  		switch entry.Tag {
   360  		case dwarf.TagCompileUnit:
   361  			cu := &compileUnit{}
   362  			cu.image = image
   363  			cu.entry = entry
   364  			cu.offset = entry.Offset
   365  			cu.Version = ctxt.offsetToVersion[cu.offset]
   366  			if lang, _ := entry.Val(dwarf.AttrLanguage).(int64); lang == godwarf.DW_LANG_Go {
   367  				cu.IsGo = true
   368  			}
   369  			cu.name, _ = entry.Val(dwarf.AttrName).(string)
   370  			compdir, _ := entry.Val(dwarf.AttrCompDir).(string)
   371  			if compdir != "" {
   372  				cu.name = filepath.Join(compdir, cu.name)
   373  			}
   374  
   375  			if shouldFilterSource(cu.name) {
   376  				continue
   377  			}
   378  
   379  			cu.ranges, _ = image.Dwarf.Ranges(entry)
   380  			for i := range cu.ranges {
   381  				cu.ranges[i][0] += image.StaticBase
   382  				cu.ranges[i][1] += image.StaticBase
   383  			}
   384  			if len(cu.ranges) >= 1 {
   385  				cu.lowPC = cu.ranges[0][0]
   386  			}
   387  			lineInfoOffset, hasLineInfo := entry.Val(dwarf.AttrStmtList).(int64)
   388  			if hasLineInfo && lineInfoOffset >= 0 && lineInfoOffset < int64(len(debugLineBytes)) {
   389  				cu.lineInfo = line.Parse(compdir, bytes.NewBuffer(debugLineBytes[lineInfoOffset:]), image.debugLineStr, nil, image.StaticBase, runtime.GOOS == "windows", bi.PointerSize)
   390  			}
   391  			cu.producer, _ = entry.Val(dwarf.AttrProducer).(string)
   392  			if cu.IsGo && cu.producer != "" {
   393  				semicolon := strings.Index(cu.producer, ";")
   394  				if semicolon < 0 {
   395  					cu.optimized = GoVersionAfterOrEqual(1, 10)
   396  				} else {
   397  					cu.optimized = !strings.Contains(cu.producer[semicolon:], "-N") || !strings.Contains(cu.producer[semicolon:], "-l")
   398  					cu.producer = cu.producer[:semicolon]
   399  				}
   400  			}
   401  			gopkg, _ := entry.Val(godwarf.AttrGoPackageName).(string)
   402  			if cu.IsGo && gopkg != "" {
   403  				bi.PackageMap[gopkg] = append(bi.PackageMap[gopkg], escapePackagePath(strings.Replace(cu.name, "\\", "/", -1)))
   404  			}
   405  			image.compileUnits = append(image.compileUnits, cu)
   406  			if entry.Children {
   407  				err := bi.loadDebugInfoMapsCompileUnit(ctxt, image, reader, cu)
   408  				if err != nil {
   409  					return err
   410  				}
   411  			}
   412  
   413  		case dwarf.TagPartialUnit:
   414  			reader.SkipChildren()
   415  
   416  		default:
   417  			
   418  			reader.SkipChildren()
   419  		}
   420  	}
   421  
   422  	sort.Sort(compileUnitsByOffset(image.compileUnits))
   423  	sort.Sort(functionsDebugInfoByEntry(bi.Functions))
   424  	sort.Sort(packageVarsByAddr(bi.packageVars))
   425  
   426  	bi.LookupFunc = make(map[string]*Function)
   427  	for i := range bi.Functions {
   428  		bi.LookupFunc[bi.Functions[i].Name] = &bi.Functions[i]
   429  	}
   430  	bi.sigreturnfn = bi.LookupFunc["runtime.sigreturn"]
   431  	bi.crosscall2fn = bi.LookupFunc["crosscall2"]
   432  
   433  	bi.loadSources(image.compileUnits)
   434  	return nil
   435  }
   436  
   437  type loadDebugInfoMapsContext struct {
   438  	ardr                *dwarf.Reader
   439  	abstractOriginTable map[dwarf.Offset]int
   440  	knownPackageVars    map[string]struct{}
   441  	offsetToVersion     map[dwarf.Offset]uint8
   442  }
   443  
   444  func newLoadDebugInfoMapsContext(bi *BinaryInfo, image *Image, offsetToVersion map[dwarf.Offset]uint8) *loadDebugInfoMapsContext {
   445  	ctxt := &loadDebugInfoMapsContext{}
   446  
   447  	ctxt.ardr = image.Dwarf.Reader()
   448  	ctxt.abstractOriginTable = make(map[dwarf.Offset]int)
   449  	ctxt.offsetToVersion = offsetToVersion
   450  
   451  	ctxt.knownPackageVars = map[string]struct{}{}
   452  	for _, v := range bi.packageVars {
   453  		ctxt.knownPackageVars[v.name] = struct{}{}
   454  	}
   455  
   456  	return ctxt
   457  }
   458  
   459  
   460  
   461  
   462  func escapePackagePath(pkg string) string {
   463  	slash := strings.Index(pkg, "/")
   464  	if slash < 0 {
   465  		slash = 0
   466  	}
   467  	return pkg[:slash] + strings.Replace(pkg[slash:], ".", "%2e", -1)
   468  }
   469  
   470  type functionsDebugInfoByEntry []Function
   471  
   472  func (v functionsDebugInfoByEntry) Len() int           { return len(v) }
   473  func (v functionsDebugInfoByEntry) Less(i, j int) bool { return v[i].Entry < v[j].Entry }
   474  func (v functionsDebugInfoByEntry) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
   475  
   476  type packageVarsByAddr []packageVar
   477  
   478  func (v packageVarsByAddr) Len() int               { return len(v) }
   479  func (v packageVarsByAddr) Less(i int, j int) bool { return v[i].addr < v[j].addr }
   480  func (v packageVarsByAddr) Swap(i int, j int)      { v[i], v[j] = v[j], v[i] }
   481  
   482  
   483  func (bi *BinaryInfo) loadDebugInfoMapsCompileUnit(ctxt *loadDebugInfoMapsContext, image *Image, reader *dwarf.Reader, cu *compileUnit) error {
   484  	hasAttrGoPkgName := GoVersionAfterOrEqual(1, 13)
   485  
   486  	depth := 0
   487  
   488  	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
   489  		if err != nil {
   490  			return errors.New("error reading debug_info")
   491  		}
   492  		switch entry.Tag {
   493  		case 0:
   494  			if depth == 0 {
   495  				return nil
   496  			} else {
   497  				depth--
   498  			}
   499  		case dwarf.TagImportedUnit:
   500  			err = bi.loadDebugInfoMapsImportedUnit(entry, ctxt, image, cu)
   501  			if err != nil {
   502  				return err
   503  			}
   504  			reader.SkipChildren()
   505  
   506  		case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
   507  			if name, ok := entry.Val(dwarf.AttrName).(string); ok {
   508  				if !cu.IsGo {
   509  					name = "C." + name
   510  				}
   511  				if _, exists := bi.types[name]; !exists {
   512  					bi.types[name] = dwarfRef{image.Index, entry.Offset}
   513  				}
   514  			}
   515  			if cu != nil && cu.IsGo && !hasAttrGoPkgName {
   516  				bi.registerTypeToPackageMap(entry)
   517  			}
   518  			image.registerRuntimeTypeToDIE(entry)
   519  			reader.SkipChildren()
   520  
   521  		case dwarf.TagVariable:
   522  			if n, ok := entry.Val(dwarf.AttrName).(string); ok {
   523  				var addr uint64
   524  				if loc, ok := entry.Val(dwarf.AttrLocation).([]byte); ok {
   525  					if len(loc) == bi.PointerSize+1 && op.Opcode(loc[0]) == op.DW_OP_addr {
   526  						addr, _ = util.ReadUintRaw(bytes.NewReader(loc[1:]), binary.LittleEndian, bi.PointerSize)
   527  					}
   528  				}
   529  				if !cu.IsGo {
   530  					n = "C." + n
   531  				}
   532  				if _, known := ctxt.knownPackageVars[n]; !known {
   533  					bi.packageVars = append(bi.packageVars, packageVar{n, cu, entry.Offset, addr + image.StaticBase})
   534  				}
   535  			}
   536  			reader.SkipChildren()
   537  
   538  		case dwarf.TagConstant:
   539  			name, okName := entry.Val(dwarf.AttrName).(string)
   540  			typ, okType := entry.Val(dwarf.AttrType).(dwarf.Offset)
   541  			val, okVal := entry.Val(dwarf.AttrConstValue).(int64)
   542  			if okName && okType && okVal {
   543  				if !cu.IsGo {
   544  					name = "C." + name
   545  				}
   546  				ct := bi.consts[dwarfRef{image.Index, typ}]
   547  				if ct == nil {
   548  					ct = &constantType{}
   549  					bi.consts[dwarfRef{image.Index, typ}] = ct
   550  				}
   551  				ct.values = append(ct.values, constantValue{name: name, fullName: name, value: val})
   552  			}
   553  			reader.SkipChildren()
   554  
   555  		case dwarf.TagSubprogram:
   556  			inlined := false
   557  			if inval, ok := entry.Val(dwarf.AttrInline).(int64); ok {
   558  				inlined = inval >= 1
   559  			}
   560  
   561  			if inlined {
   562  				err = bi.addAbstractSubprogram(entry, ctxt, reader, cu)
   563  				if err != nil {
   564  					return err
   565  				}
   566  			} else {
   567  				originOffset, hasAbstractOrigin := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
   568  				if hasAbstractOrigin {
   569  					err = bi.addConcreteInlinedSubprogram(entry, originOffset, ctxt, reader, cu)
   570  					if err != nil {
   571  						return err
   572  					}
   573  				} else {
   574  					err = bi.addConcreteSubprogram(entry, ctxt, reader, cu)
   575  					if err != nil {
   576  						return err
   577  					}
   578  				}
   579  			}
   580  
   581  		default:
   582  			if entry.Children {
   583  				depth++
   584  			}
   585  		}
   586  	}
   587  
   588  	return nil
   589  }
   590  
   591  
   592  
   593  func (bi *BinaryInfo) loadDebugInfoMapsImportedUnit(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, image *Image, cu *compileUnit) error {
   594  	off, ok := entry.Val(dwarf.AttrImport).(dwarf.Offset)
   595  	if !ok {
   596  		return nil
   597  	}
   598  	reader := image.Dwarf.Reader()
   599  	reader.Seek(off)
   600  	imentry, err := reader.Next()
   601  	if err != nil {
   602  		return nil
   603  	}
   604  	if imentry.Tag != dwarf.TagPartialUnit {
   605  		return nil
   606  	}
   607  	return bi.loadDebugInfoMapsCompileUnit(ctxt, image, reader, cu)
   608  }
   609  
   610  func (bi *BinaryInfo) registerTypeToPackageMap(entry *dwarf.Entry) {
   611  	if entry.Tag != dwarf.TagTypedef && entry.Tag != dwarf.TagBaseType && entry.Tag != dwarf.TagClassType && entry.Tag != dwarf.TagStructType {
   612  		return
   613  	}
   614  
   615  	typename, ok := entry.Val(dwarf.AttrName).(string)
   616  	if !ok || complexType(typename) {
   617  		return
   618  	}
   619  
   620  	dot := strings.LastIndex(typename, ".")
   621  	if dot < 0 {
   622  		return
   623  	}
   624  	path := typename[:dot]
   625  	slash := strings.LastIndex(path, "/")
   626  	if slash < 0 || slash+1 >= len(path) {
   627  		return
   628  	}
   629  	name := path[slash+1:]
   630  	bi.PackageMap[name] = []string{path}
   631  }
   632  
   633  func (bi *BinaryInfo) addConcreteInlinedSubprogram(entry *dwarf.Entry, originOffset dwarf.Offset, ctxt *loadDebugInfoMapsContext, reader *dwarf.Reader, cu *compileUnit) error {
   634  	lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
   635  	if !ok {
   636  		if entry.Children {
   637  			reader.SkipChildren()
   638  		}
   639  		return nil
   640  	}
   641  
   642  	originIdx, ok := ctxt.abstractOriginTable[originOffset]
   643  	if !ok {
   644  		if entry.Children {
   645  			reader.SkipChildren()
   646  		}
   647  		return nil
   648  	}
   649  
   650  	fn := &bi.Functions[originIdx]
   651  	fn.Offset = entry.Offset
   652  	fn.Entry = lowpc
   653  	fn.End = highpc
   654  
   655  	if entry.Children {
   656  		err := bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
   657  		if err != nil {
   658  			return err
   659  		}
   660  	}
   661  
   662  	return nil
   663  }
   664  
   665  func (bi *BinaryInfo) loadDebugInfoMapsInlinedCalls(ctxt *loadDebugInfoMapsContext, reader *dwarf.Reader, cu *compileUnit) error {
   666  	for {
   667  		entry, err := reader.Next()
   668  		if err != nil {
   669  			return errors.New("error reading debug_info")
   670  		}
   671  		switch entry.Tag {
   672  		case 0:
   673  			return nil
   674  		case dwarf.TagInlinedSubroutine:
   675  			originOffset, ok := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
   676  			if !ok {
   677  				reader.SkipChildren()
   678  				continue
   679  			}
   680  
   681  			originIdx, ok := ctxt.abstractOriginTable[originOffset]
   682  			if !ok {
   683  				reader.SkipChildren()
   684  				continue
   685  			}
   686  			fn := &bi.Functions[originIdx]
   687  
   688  			lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
   689  			if !ok {
   690  				reader.SkipChildren()
   691  				continue
   692  			}
   693  
   694  			callfileidx, ok1 := entry.Val(dwarf.AttrCallFile).(int64)
   695  			callline, ok2 := entry.Val(dwarf.AttrCallLine).(int64)
   696  			if !ok1 || !ok2 {
   697  				reader.SkipChildren()
   698  				continue
   699  			}
   700  			if cu.lineInfo == nil {
   701  				reader.SkipChildren()
   702  				continue
   703  			}
   704  			if int(callfileidx-1) >= len(cu.lineInfo.FileNames) {
   705  				reader.SkipChildren()
   706  				continue
   707  			}
   708  			callfile := cu.lineInfo.FileNames[callfileidx-1].Path
   709  
   710  			fn.InlinedCalls = append(fn.InlinedCalls, InlinedCall{
   711  				cu:     cu,
   712  				LowPC:  lowpc,
   713  				HighPC: highpc,
   714  			})
   715  
   716  			fl := fileLine{callfile, int(callline)}
   717  			bi.inlinedCallLines[fl] = append(bi.inlinedCallLines[fl], lowpc)
   718  		}
   719  		reader.SkipChildren()
   720  	}
   721  }
   722  
   723  func subprogramEntryRange(entry *dwarf.Entry, image *Image) (lowpc, highpc uint64, ok bool) {
   724  	ok = false
   725  	if ranges, _ := image.Dwarf.Ranges(entry); len(ranges) >= 1 {
   726  		ok = true
   727  		lowpc = ranges[0][0] + image.StaticBase
   728  		highpc = ranges[0][1] + image.StaticBase
   729  	}
   730  	return lowpc, highpc, ok
   731  }
   732  
   733  func (bi *BinaryInfo) addConcreteSubprogram(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, reader *dwarf.Reader, cu *compileUnit) error {
   734  	lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
   735  	if !ok {
   736  		if entry.Children {
   737  			reader.SkipChildren()
   738  		}
   739  		return nil
   740  	}
   741  
   742  	name, ok := subprogramEntryName(entry, cu)
   743  	if !ok {
   744  		if entry.Children {
   745  			reader.SkipChildren()
   746  		}
   747  		return nil
   748  	}
   749  
   750  	fn := Function{
   751  		Name:   name,
   752  		Entry:  lowpc,
   753  		End:    highpc,
   754  		Offset: entry.Offset,
   755  		cu:     cu,
   756  	}
   757  	bi.Functions = append(bi.Functions, fn)
   758  
   759  	if entry.Children {
   760  		err := bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
   761  		if err != nil {
   762  			return err
   763  		}
   764  	}
   765  
   766  	return nil
   767  }
   768  
   769  func subprogramEntryName(entry *dwarf.Entry, cu *compileUnit) (string, bool) {
   770  	name, ok := entry.Val(dwarf.AttrName).(string)
   771  	if !ok {
   772  		return "", false
   773  	}
   774  	if !cu.IsGo {
   775  		name = "C." + name
   776  	}
   777  	return name, true
   778  }
   779  
   780  func (bi *BinaryInfo) addAbstractSubprogram(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, reader *dwarf.Reader, cu *compileUnit) error {
   781  	name, ok := subprogramEntryName(entry, cu)
   782  	if !ok {
   783  		if entry.Children {
   784  			reader.SkipChildren()
   785  		}
   786  		return nil
   787  	}
   788  
   789  	fn := Function{
   790  		Name:   name,
   791  		Offset: entry.Offset,
   792  		cu:     cu,
   793  	}
   794  
   795  	if entry.Children {
   796  		err := bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
   797  		if err != nil {
   798  			return err
   799  		}
   800  	}
   801  
   802  	bi.Functions = append(bi.Functions, fn)
   803  	ctxt.abstractOriginTable[entry.Offset] = len(bi.Functions) - 1
   804  	return nil
   805  }
   806  
   807  func (bi *BinaryInfo) getBestMatchingFile(filename string) ([]*compileUnit, string, rookoutErrors.RookoutError) {
   808  	
   809  	var topCu []*compileUnit
   810  	fm := utils.NewFileMatcher()
   811  	for _, image := range bi.Images {
   812  		for _, cu := range image.compileUnits {
   813  			if cu.lineInfo == nil {
   814  				continue
   815  			}
   816  			for _, f := range cu.lineInfo.FileNames {
   817  				matchScore := utils.GetPathMatchingScore(filename, f.Path)
   818  				switch fm.UpdateMatch(matchScore, f.Path) {
   819  				case utils.NewBestMatch:
   820  					logger.Logger().Debugf("NewBestMatch: filepath: %s", f.Path)
   821  					topCu = []*compileUnit{cu}
   822  				case utils.SameBestMatch:
   823  					logger.Logger().Debugf("SameBestMatch: filepath: %s", f.Path)
   824  					topCu = append(topCu, cu)
   825  				}
   826  			}
   827  		}
   828  	}
   829  
   830  	if !fm.AnyMatch() {
   831  		
   832  		return nil, "", rookoutErrors.NewFileNotFound(filename)
   833  	}
   834  	if !fm.IsUnique() {
   835  		
   836  		return nil, "", rookoutErrors.NewMultipleFilesFound(filename)
   837  	}
   838  	
   839  	return topCu, fm.GetBestFile(), nil
   840  }
   841  
   842  
   843  
   844  func (bi *BinaryInfo) PCToInlineFunc(pc uint64) *Function {
   845  	fn := bi.PCToFunc(pc)
   846  	dwarfTree, err := fn.cu.image.GetDwarfTree(fn.Offset)
   847  	if err != nil {
   848  		return fn
   849  	}
   850  	entries := reader.InlineStack(dwarfTree, pc)
   851  	if len(entries) == 0 {
   852  		return fn
   853  	}
   854  
   855  	fnname, okname := entries[0].Val(dwarf.AttrName).(string)
   856  	if !okname {
   857  		return fn
   858  	}
   859  
   860  	return bi.LookupFunc[fnname]
   861  }
   862  
   863  
   864  
   865  func (bi *BinaryInfo) PCToFunc(pc uint64) *Function {
   866  	i := sort.Search(len(bi.Functions), func(i int) bool {
   867  		fn := bi.Functions[i]
   868  		return pc <= fn.Entry || (fn.Entry <= pc && pc < fn.End)
   869  	})
   870  	if i != len(bi.Functions) {
   871  		fn := &bi.Functions[i]
   872  		if fn.Entry <= pc && pc < fn.End {
   873  			return fn
   874  		}
   875  	}
   876  	return nil
   877  }
   878  
   879  func (bi *BinaryInfo) FuncToImage(fn *Function) *Image {
   880  	if fn == nil {
   881  		return bi.Images[0]
   882  	}
   883  
   884  	return fn.cu.image
   885  }
   886  
   887  
   888  func (bi *BinaryInfo) PCToLine(pc uint64) (string, int, *Function) {
   889  	fn := bi.PCToFunc(pc)
   890  	if fn == nil {
   891  		return "", 0, nil
   892  	}
   893  	f, ln := fn.cu.lineInfo.PCToLine(fn.Entry, pc)
   894  	return f, ln, fn
   895  }
   896  
   897  func (bi *BinaryInfo) LocationExpr(entry godwarf.Entry, attr dwarf.Attr, pc uint64) ([]byte, *LocationExpr, error) {
   898  	
   899  	a := entry.Val(attr)
   900  	if a == nil {
   901  		return nil, nil, fmt.Errorf("no location attribute %s", attr)
   902  	}
   903  	if instr, ok := a.([]byte); ok {
   904  		return instr, &LocationExpr{isBlock: true, instr: instr}, nil
   905  	}
   906  	off, ok := a.(int64)
   907  	if !ok {
   908  		return nil, nil, fmt.Errorf("could not interpret location attribute %s", attr)
   909  	}
   910  	instr := bi.loclistEntry(off, pc)
   911  	if instr == nil {
   912  		return nil, nil, fmt.Errorf("could not find loclist entry at %#x for address %#x", off, pc)
   913  	}
   914  	return instr, &LocationExpr{pc: pc, off: off, instr: instr}, nil
   915  }
   916  
   917  type LocationExpr struct {
   918  	isBlock bool
   919  	off     int64
   920  	pc      uint64
   921  	instr   []byte
   922  }
   923  
   924  
   925  
   926  func (bi *BinaryInfo) loclistEntry(off int64, pc uint64) []byte {
   927  	var base uint64
   928  	image := bi.Images[0]
   929  	cu := bi.findCompileUnit(pc)
   930  	if cu != nil {
   931  		base = cu.lowPC
   932  		image = cu.image
   933  	}
   934  	if image == nil {
   935  		return nil
   936  	}
   937  
   938  	var loclist loclist.Reader = bi.newLoclist2Reader()
   939  	var debugAddr *godwarf.DebugAddr
   940  	loclist5 := bi.newLoclist5Reader()
   941  	if cu != nil && cu.Version >= 5 && loclist5 != nil {
   942  		loclist = loclist5
   943  		if addrBase, ok := cu.entry.Val(dwarf.AttrAddrBase).(int64); ok {
   944  			debugAddr = image.debugAddr.GetSubsection(uint64(addrBase))
   945  		}
   946  	}
   947  
   948  	if loclist.Empty() {
   949  		return nil
   950  	}
   951  
   952  	e, err := loclist.Find(int(off), image.StaticBase, base, pc, debugAddr)
   953  	if err != nil {
   954  		logger.Logger().Errorf("error reading loclist section: %v", err)
   955  		return nil
   956  	}
   957  	if e != nil {
   958  		return e.Instr
   959  	}
   960  
   961  	return nil
   962  }
   963  
   964  
   965  func (bi *BinaryInfo) findCompileUnit(pc uint64) *compileUnit {
   966  	for _, image := range bi.Images {
   967  		for _, cu := range image.compileUnits {
   968  			if cu.pcInRange(pc) {
   969  				return cu
   970  			}
   971  		}
   972  	}
   973  	return nil
   974  }
   975  
   976  func (bi *BinaryInfo) newLoclist2Reader() *loclist.Dwarf2Reader {
   977  	return loclist.NewDwarf2Reader(bi.debugLocBytes, bi.PointerSize)
   978  }
   979  
   980  func (bi *BinaryInfo) newLoclist5Reader() *loclist.Dwarf5Reader {
   981  	return loclist.NewDwarf5Reader(bi.debugLoclistBytes)
   982  }
   983  
   984  
   985  func (bi *BinaryInfo) PCToImage(pc uint64) *Image {
   986  	fn := bi.PCToFunc(pc)
   987  	return fn.cu.image
   988  }
   989  
   990  
   991  
   992  
   993  
   994  func (bi *BinaryInfo) Location(entry godwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters) (int64, []op.Piece, *LocationExpr, error) {
   995  	instr, descr, err := bi.LocationExpr(entry, attr, pc)
   996  	if err != nil {
   997  		return 0, nil, nil, err
   998  	}
   999  	addr, pieces, err := op.ExecuteStackProgram(&regs, instr, bi.PointerSize)
  1000  	return addr, pieces, descr, err
  1001  }
  1002  
  1003  
  1004  func (bi *BinaryInfo) FindType(name string) (godwarf.Type, error) {
  1005  	ref, found := bi.types[name]
  1006  	if !found {
  1007  		return nil, errors.New("no type entry found, use 'types' for a list of valid types")
  1008  	}
  1009  	image := bi.Images[ref.imageIndex]
  1010  	return godwarf.ReadType(image.Dwarf, ref.imageIndex, ref.offset, &image.TypeCache)
  1011  }
  1012  
  1013  func (bi *BinaryInfo) GetConst(typ godwarf.Type) *constantType {
  1014  	return bi.consts.Get(typ)
  1015  }
  1016  
  1017  func (bi *BinaryInfo) ReadVariableEntry(entry *godwarf.Tree) (name string, typ godwarf.Type, err error) {
  1018  	name, ok := entry.Val(dwarf.AttrName).(string)
  1019  	if !ok {
  1020  		return "", nil, fmt.Errorf("malformed variable DIE (name)")
  1021  	}
  1022  
  1023  	typ, err = entry.Type(bi.Dwarf, 0, &bi.TypeCache)
  1024  	if err != nil {
  1025  		return "", nil, err
  1026  	}
  1027  
  1028  	return name, typ, nil
  1029  }
  1030  
  1031  func (bi *BinaryInfo) RuntimeTypeTypename() string {
  1032  	if GoVersionAfterOrEqual(1, 21) {
  1033  		return "internal/abi.Type"
  1034  	}
  1035  	return "runtime._type"
  1036  }