gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/bininfo.go (about)

     1  package proc
     2  
     3  import (
     4  	"bytes"
     5  	"debug/dwarf"
     6  	"debug/elf"
     7  	"debug/macho"
     8  	"debug/pe"
     9  	"encoding/binary"
    10  	"encoding/hex"
    11  	"errors"
    12  	"fmt"
    13  	"go/ast"
    14  	"go/token"
    15  	"hash/crc32"
    16  	"io"
    17  	"os"
    18  	"path/filepath"
    19  	"sort"
    20  	"strconv"
    21  	"strings"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/hashicorp/golang-lru/simplelru"
    26  	pdwarf "gitlab.com/Raven-IO/raven-delve/pkg/dwarf"
    27  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/frame"
    28  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/godwarf"
    29  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/line"
    30  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/loclist"
    31  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/op"
    32  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/reader"
    33  	"gitlab.com/Raven-IO/raven-delve/pkg/goversion"
    34  	"gitlab.com/Raven-IO/raven-delve/pkg/internal/gosym"
    35  	"gitlab.com/Raven-IO/raven-delve/pkg/logflags"
    36  	"gitlab.com/Raven-IO/raven-delve/pkg/proc/debuginfod"
    37  )
    38  
    39  const (
    40  	dwarfGoLanguage    = 22   // DW_LANG_Go (from DWARF v5, section 7.12, page 231)
    41  	dwarfAttrAddrBase  = 0x74 // debug/dwarf.AttrAddrBase in Go 1.14, defined here for compatibility with Go < 1.14
    42  	dwarfTreeCacheSize = 512  // size of the dwarfTree cache of each image
    43  )
    44  
    45  // BinaryInfo holds information on the binaries being executed (this
    46  // includes both the executable and also any loaded libraries).
    47  type BinaryInfo struct {
    48  	// Architecture of this binary.
    49  	Arch *Arch
    50  
    51  	// GOOS operating system this binary is executing on.
    52  	GOOS string
    53  
    54  	DebugInfoDirectories []string
    55  
    56  	// BuildID of this binary.
    57  	BuildID string
    58  
    59  	// Functions is a list of all DW_TAG_subprogram entries in debug_info, sorted by entry point
    60  	Functions []Function
    61  	// Sources is a list of all source files found in debug_line.
    62  	Sources []string
    63  	// lookupFunc maps function names to a description of the function.
    64  	lookupFunc map[string][]*Function
    65  	// lookupGenericFunc maps function names, with their type parameters removed, to functions.
    66  	// Functions that are not generic are not added to this map.
    67  	lookupGenericFunc map[string][]*Function
    68  
    69  	// SymNames maps addr to a description *elf.Symbol of this addr.
    70  	SymNames map[uint64]*elf.Symbol
    71  
    72  	// Images is a list of loaded shared libraries (also known as
    73  	// shared objects on linux or DLLs on windows).
    74  	Images []*Image
    75  
    76  	ElfDynamicSection ElfDynamicSection
    77  
    78  	lastModified time.Time // Time the executable of this process was last modified
    79  
    80  	// PackageMap maps package names to package paths, needed to lookup types inside DWARF info.
    81  	// On Go1.12 this mapping is determined by using the last element of a package path, for example:
    82  	//   gitlab.com/Raven-IO/raven-delve
    83  	// will map to 'delve' because it ends in '/delve'.
    84  	// Starting with Go1.13 debug_info will contain a special attribute
    85  	// (godwarf.AttrGoPackageName) containing the canonical package name for
    86  	// each package.
    87  	// If multiple packages have the same name the map entry will have more
    88  	// than one item in the slice.
    89  	PackageMap map[string][]string
    90  
    91  	frameEntries frame.FrameDescriptionEntries
    92  
    93  	types       map[string]dwarfRef
    94  	packageVars []packageVar // packageVars is a list of all global/package variables in debug_info, sorted by address
    95  
    96  	gStructOffset      uint64
    97  	gStructOffsetIsPtr bool
    98  
    99  	// consts[off] lists all the constants with the type defined at offset off.
   100  	consts constantsMap
   101  
   102  	// inlinedCallLines maps a file:line pair, corresponding to the header line
   103  	// of a function to a list of PC addresses where an inlined call to that
   104  	// function starts.
   105  	inlinedCallLines map[fileLine][]uint64
   106  
   107  	// dwrapUnwrapCache caches unwrapping of defer wrapper functions (dwrap)
   108  	dwrapUnwrapCache map[uint64]*Function
   109  
   110  	// Go 1.17 register ABI is enabled.
   111  	regabi bool
   112  
   113  	logger logflags.Logger
   114  }
   115  
   116  var (
   117  	// ErrCouldNotDetermineRelocation is an error returned when Delve could not determine the base address of a
   118  	// position independent executable.
   119  	ErrCouldNotDetermineRelocation = errors.New("could not determine the base address of a PIE")
   120  
   121  	// ErrNoDebugInfoFound is returned when Delve cannot open the debug_info
   122  	// section or find an external debug info file.
   123  	ErrNoDebugInfoFound = errors.New("could not open debug info")
   124  )
   125  
   126  var (
   127  	supportedLinuxArch = map[elf.Machine]bool{
   128  		elf.EM_X86_64:  true,
   129  		elf.EM_AARCH64: true,
   130  		elf.EM_386:     true,
   131  		elf.EM_PPC64:   true,
   132  	}
   133  
   134  	supportedWindowsArch = map[_PEMachine]bool{
   135  		_IMAGE_FILE_MACHINE_AMD64: true,
   136  		_IMAGE_FILE_MACHINE_ARM64: true,
   137  	}
   138  
   139  	supportedDarwinArch = map[macho.Cpu]bool{
   140  		macho.CpuAmd64: true,
   141  		macho.CpuArm64: true,
   142  	}
   143  )
   144  
   145  // ErrFunctionNotFound is returned when failing to find the
   146  // function named 'FuncName' within the binary.
   147  type ErrFunctionNotFound struct {
   148  	FuncName string
   149  }
   150  
   151  func (err *ErrFunctionNotFound) Error() string {
   152  	return fmt.Sprintf("could not find function %s\n", err.FuncName)
   153  }
   154  
   155  // FindFileLocation returns the PC for a given file:line.
   156  // Assumes that `file` is normalized to lower case and '/' on Windows.
   157  func FindFileLocation(p Process, filename string, lineno int) ([]uint64, error) {
   158  	// A single file:line can appear in multiple concrete functions, because of
   159  	// generics instantiation as well as multiple inlined calls into other
   160  	// concrete functions.
   161  
   162  	// 1. Find all instructions assigned in debug_line to filename:lineno.
   163  
   164  	bi := p.BinInfo()
   165  
   166  	fileFound := false
   167  	pcs := []line.PCStmt{}
   168  	for _, image := range bi.Images {
   169  		for _, cu := range image.compileUnits {
   170  			if cu.lineInfo == nil || cu.lineInfo.Lookup[filename] == nil {
   171  				continue
   172  			}
   173  
   174  			fileFound = true
   175  			pcs = append(pcs, cu.lineInfo.LineToPCs(filename, lineno)...)
   176  		}
   177  	}
   178  
   179  	if len(pcs) == 0 {
   180  		// Check if the line contained a call to a function that was inlined, in
   181  		// that case it's possible for the line itself to not appear in debug_line
   182  		// at all, but it will still be in debug_info as the call site for an
   183  		// inlined subroutine entry.
   184  		for _, pc := range bi.inlinedCallLines[fileLine{filename, lineno}] {
   185  			pcs = append(pcs, line.PCStmt{PC: pc, Stmt: true})
   186  		}
   187  	}
   188  
   189  	if len(pcs) == 0 {
   190  		return nil, &ErrCouldNotFindLine{fileFound, filename, lineno}
   191  	}
   192  
   193  	// 2. assign all occurrences of filename:lineno to their containing function
   194  
   195  	pcByFunc := map[*Function][]line.PCStmt{}
   196  	sort.Slice(pcs, func(i, j int) bool { return pcs[i].PC < pcs[j].PC })
   197  	var fn *Function
   198  	for _, pcstmt := range pcs {
   199  		if fn == nil || (pcstmt.PC < fn.Entry) || (pcstmt.PC >= fn.End) {
   200  			fn = p.BinInfo().PCToFunc(pcstmt.PC)
   201  		}
   202  		if fn != nil {
   203  			pcByFunc[fn] = append(pcByFunc[fn], pcstmt)
   204  		}
   205  	}
   206  
   207  	selectedPCs := []uint64{}
   208  
   209  	for fn, pcs := range pcByFunc {
   210  
   211  		// 3. for each concrete function split instruction between the inlined functions it contains
   212  
   213  		if strings.Contains(fn.Name, "·dwrap·") || fn.trampoline {
   214  			// skip autogenerated functions
   215  			continue
   216  		}
   217  
   218  		dwtree, err := fn.cu.image.getDwarfTree(fn.offset)
   219  		if err != nil {
   220  			return nil, fmt.Errorf("loading DWARF for %s@%#x: %v", fn.Name, fn.offset, err)
   221  		}
   222  		inlrngs := allInlineCallRanges(dwtree)
   223  
   224  		// findInlRng returns the DWARF offset of the inlined call containing pc.
   225  		// If multiple nested inlined calls contain pc the deepest one is returned
   226  		// (since allInlineCallRanges returns inlined call by decreasing depth
   227  		// this is the first matching entry of the slice).
   228  		findInlRng := func(pc uint64) dwarf.Offset {
   229  			for _, inlrng := range inlrngs {
   230  				if inlrng.rng[0] <= pc && pc < inlrng.rng[1] {
   231  					return inlrng.off
   232  				}
   233  			}
   234  			return fn.offset
   235  		}
   236  
   237  		pcsByOff := map[dwarf.Offset][]line.PCStmt{}
   238  
   239  		for _, pc := range pcs {
   240  			off := findInlRng(pc.PC)
   241  			pcsByOff[off] = append(pcsByOff[off], pc)
   242  		}
   243  
   244  		// 4. pick the first instruction with stmt set for each inlined call as
   245  		//    well as the main body of the concrete function. If nothing has
   246  		//    is_stmt set pick the first instruction instead.
   247  
   248  		for off, pcs := range pcsByOff {
   249  			sort.Slice(pcs, func(i, j int) bool { return pcs[i].PC < pcs[j].PC })
   250  
   251  			var selectedPC uint64
   252  			for _, pc := range pcs {
   253  				if pc.Stmt {
   254  					selectedPC = pc.PC
   255  					break
   256  				}
   257  			}
   258  
   259  			if selectedPC == 0 && len(pcs) > 0 {
   260  				selectedPC = pcs[0].PC
   261  			}
   262  
   263  			if selectedPC == 0 {
   264  				continue
   265  			}
   266  
   267  			// 5. if we picked the entry point of the function, skip it
   268  
   269  			if off == fn.offset && fn.Entry == selectedPC {
   270  				selectedPC, _ = FirstPCAfterPrologue(p, fn, true)
   271  			}
   272  
   273  			selectedPCs = append(selectedPCs, selectedPC)
   274  		}
   275  	}
   276  
   277  	sort.Slice(selectedPCs, func(i, j int) bool { return selectedPCs[i] < selectedPCs[j] })
   278  
   279  	return selectedPCs, nil
   280  }
   281  
   282  // inlRange is the range of an inlined call
   283  type inlRange struct {
   284  	off   dwarf.Offset
   285  	depth uint32
   286  	rng   [2]uint64
   287  }
   288  
   289  // allInlineCallRanges returns all inlined calls contained inside 'tree' in
   290  // reverse nesting order (i.e. the most nested calls are returned first).
   291  // Note that a single inlined call might not have a continuous range of
   292  // addresses and therefore appear multiple times in the returned slice.
   293  func allInlineCallRanges(tree *godwarf.Tree) []inlRange {
   294  	r := []inlRange{}
   295  
   296  	var visit func(*godwarf.Tree, uint32)
   297  	visit = func(n *godwarf.Tree, depth uint32) {
   298  		if n.Tag == dwarf.TagInlinedSubroutine {
   299  			for _, rng := range n.Ranges {
   300  				r = append(r, inlRange{off: n.Offset, depth: depth, rng: rng})
   301  			}
   302  		}
   303  		for _, child := range n.Children {
   304  			visit(child, depth+1)
   305  		}
   306  	}
   307  	visit(tree, 0)
   308  
   309  	sort.SliceStable(r, func(i, j int) bool { return r[i].depth > r[j].depth })
   310  	return r
   311  }
   312  
   313  // FindFunction returns the functions with name funcName.
   314  func (bi *BinaryInfo) FindFunction(funcName string) ([]*Function, error) {
   315  	if fns := bi.LookupFunc()[funcName]; fns != nil {
   316  		return fns, nil
   317  	}
   318  	fns := bi.LookupGenericFunc()[funcName]
   319  	if len(fns) == 0 {
   320  		return nil, &ErrFunctionNotFound{funcName}
   321  	}
   322  	return fns, nil
   323  }
   324  
   325  // FindFunctionLocation finds address of a function's line
   326  // If lineOffset is passed FindFunctionLocation will return the address of that line
   327  func FindFunctionLocation(p Process, funcName string, lineOffset int) ([]uint64, error) {
   328  	bi := p.BinInfo()
   329  	origfns, err := bi.FindFunction(funcName)
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  
   334  	if lineOffset > 0 {
   335  		fn := origfns[0]
   336  		filename, lineno := bi.EntryLineForFunc(fn)
   337  		return FindFileLocation(p, filename, lineno+lineOffset)
   338  	}
   339  
   340  	r := make([]uint64, 0, len(origfns[0].InlinedCalls)+len(origfns))
   341  
   342  	for _, origfn := range origfns {
   343  		if origfn.Entry > 0 {
   344  			// add concrete implementation of the function
   345  			pc, err := FirstPCAfterPrologue(p, origfn, false)
   346  			if err != nil {
   347  				return nil, err
   348  			}
   349  			r = append(r, pc)
   350  		}
   351  		// add inlined calls to the function
   352  		for _, call := range origfn.InlinedCalls {
   353  			r = append(r, call.LowPC)
   354  		}
   355  		if len(r) == 0 {
   356  			return nil, &ErrFunctionNotFound{funcName}
   357  		}
   358  	}
   359  	sort.Slice(r, func(i, j int) bool { return r[i] < r[j] })
   360  	return r, nil
   361  }
   362  
   363  // FirstPCAfterPrologue returns the address of the first
   364  // instruction after the prologue for function fn.
   365  // If sameline is set FirstPCAfterPrologue will always return an
   366  // address associated with the same line as fn.Entry.
   367  func FirstPCAfterPrologue(p Process, fn *Function, sameline bool) (uint64, error) {
   368  	if fn.cu.lineInfo != nil {
   369  		pc, _, line, ok := fn.cu.lineInfo.PrologueEndPC(fn.Entry, fn.End)
   370  		if ok {
   371  			if !sameline {
   372  				return pc, nil
   373  			}
   374  			_, entryLine := p.BinInfo().EntryLineForFunc(fn)
   375  			if entryLine == line {
   376  				return pc, nil
   377  			}
   378  		}
   379  	}
   380  
   381  	pc, err := firstPCAfterPrologueDisassembly(p, fn, sameline)
   382  	if err != nil {
   383  		return fn.Entry, err
   384  	}
   385  
   386  	if pc == fn.Entry && fn.cu.lineInfo != nil {
   387  		// Look for the first instruction with the stmt flag set, so that setting a
   388  		// breakpoint with file:line and with the function name always result on
   389  		// the same instruction being selected.
   390  		if pc2, _, _, ok := fn.cu.lineInfo.FirstStmtForLine(fn.Entry, fn.End); ok {
   391  			return pc2, nil
   392  		}
   393  	}
   394  
   395  	return pc, nil
   396  }
   397  
   398  func findRetPC(t *Target, name string) ([]uint64, error) {
   399  	fn := t.BinInfo().lookupOneFunc(name)
   400  	if fn == nil {
   401  		return nil, fmt.Errorf("could not find %s", name)
   402  	}
   403  	text, err := Disassemble(t.Memory(), nil, t.Breakpoints(), t.BinInfo(), fn.Entry, fn.End)
   404  	if err != nil {
   405  		return nil, err
   406  	}
   407  	r := []uint64{}
   408  	for _, instr := range text {
   409  		if instr.IsRet() {
   410  			r = append(r, instr.Loc.PC)
   411  		}
   412  	}
   413  	if len(r) == 0 {
   414  		return nil, fmt.Errorf("could not find return instruction in %s", name)
   415  	}
   416  	return r, nil
   417  }
   418  
   419  // cpuArch is a stringer interface representing CPU architectures.
   420  type cpuArch interface {
   421  	String() string
   422  }
   423  
   424  // ErrUnsupportedArch is returned when attempting to debug a binary compiled for an unsupported architecture.
   425  type ErrUnsupportedArch struct {
   426  	os      string
   427  	cpuArch cpuArch
   428  }
   429  
   430  func (e *ErrUnsupportedArch) Error() string {
   431  	var supportArchs []cpuArch
   432  	switch e.os {
   433  	case "linux":
   434  		for linuxArch := range supportedLinuxArch {
   435  			supportArchs = append(supportArchs, linuxArch)
   436  		}
   437  	case "windows":
   438  		for windowArch := range supportedWindowsArch {
   439  			supportArchs = append(supportArchs, windowArch)
   440  		}
   441  	case "darwin":
   442  		for darwinArch := range supportedDarwinArch {
   443  			supportArchs = append(supportArchs, darwinArch)
   444  		}
   445  	}
   446  
   447  	errStr := "unsupported architecture of " + e.os + "/" + e.cpuArch.String()
   448  	errStr += " - only"
   449  	for _, arch := range supportArchs {
   450  		errStr += " " + e.os + "/" + arch.String() + " "
   451  	}
   452  	if len(supportArchs) == 1 {
   453  		errStr += "is supported"
   454  	} else {
   455  		errStr += "are supported"
   456  	}
   457  
   458  	return errStr
   459  }
   460  
   461  type compileUnit struct {
   462  	name    string // univocal name for non-go compile units
   463  	Version uint8  // DWARF version of this compile unit
   464  	lowPC   uint64
   465  	ranges  [][2]uint64
   466  
   467  	entry     *dwarf.Entry        // debug_info entry describing this compile unit
   468  	isgo      bool                // true if this is the go compile unit
   469  	lineInfo  *line.DebugLineInfo // debug_line segment associated with this compile unit
   470  	optimized bool                // this compile unit is optimized
   471  	producer  string              // producer attribute
   472  
   473  	offset dwarf.Offset // offset of the entry describing the compile unit
   474  
   475  	image *Image // parent image of this compilation unit.
   476  }
   477  
   478  type fileLine struct {
   479  	file string
   480  	line int
   481  }
   482  
   483  // dwarfRef is a reference to a Debug Info Entry inside a shared object.
   484  type dwarfRef struct {
   485  	imageIndex int
   486  	offset     dwarf.Offset
   487  }
   488  
   489  // InlinedCall represents a concrete inlined call to a function.
   490  type InlinedCall struct {
   491  	cu            *compileUnit
   492  	LowPC, HighPC uint64 // Address range of the generated inlined instructions
   493  }
   494  
   495  // Function describes a function in the target program.
   496  type Function struct {
   497  	Name       string
   498  	Entry, End uint64 // same as DW_AT_lowpc and DW_AT_highpc
   499  	offset     dwarf.Offset
   500  	cu         *compileUnit
   501  
   502  	trampoline bool // DW_AT_trampoline attribute set to true
   503  
   504  	// InlinedCalls lists all inlined calls to this function
   505  	InlinedCalls []InlinedCall
   506  	// closureStructType is the cached struct type for closures for this function
   507  	closureStructTypeCached *godwarf.StructType
   508  }
   509  
   510  // instRange returns the indexes in fn.Name of the type parameter
   511  // instantiation, which is the position of the outermost '[' and ']'.
   512  // If fn is not an instantiated function both returned values will be len(fn.Name)
   513  func (fn *Function) instRange() [2]int {
   514  	d := len(fn.Name)
   515  	inst := [2]int{d, d}
   516  	if strings.HasPrefix(fn.Name, "type..") {
   517  		return inst
   518  	}
   519  	inst[0] = strings.Index(fn.Name, "[")
   520  	if inst[0] < 0 {
   521  		inst[0] = d
   522  		return inst
   523  	}
   524  	inst[1] = strings.LastIndex(fn.Name, "]")
   525  	if inst[1] < 0 {
   526  		inst[0] = d
   527  		inst[1] = d
   528  		return inst
   529  	}
   530  	return inst
   531  }
   532  
   533  // PackageName returns the package part of the symbol name,
   534  // or the empty string if there is none.
   535  // Borrowed from $GOROOT/debug/gosym/symtab.go
   536  func (fn *Function) PackageName() string {
   537  	inst := fn.instRange()
   538  	return packageName(fn.Name[:inst[0]])
   539  }
   540  
   541  func packageName(name string) string {
   542  	pathend := strings.LastIndex(name, "/")
   543  	if pathend < 0 {
   544  		pathend = 0
   545  	}
   546  
   547  	if i := strings.Index(name[pathend:], "."); i != -1 {
   548  		return name[:pathend+i]
   549  	}
   550  	return ""
   551  }
   552  
   553  // ReceiverName returns the receiver type name of this symbol,
   554  // or the empty string if there is none.
   555  // Borrowed from $GOROOT/debug/gosym/symtab.go
   556  func (fn *Function) ReceiverName() string {
   557  	inst := fn.instRange()
   558  	pathend := strings.LastIndex(fn.Name[:inst[0]], "/")
   559  	if pathend < 0 {
   560  		pathend = 0
   561  	}
   562  	l := strings.Index(fn.Name[pathend:], ".")
   563  	if l == -1 {
   564  		return ""
   565  	}
   566  	if r := strings.LastIndex(fn.Name[inst[1]:], "."); r != -1 && pathend+l != inst[1]+r {
   567  		return fn.Name[pathend+l+1 : inst[1]+r]
   568  	} else if r := strings.LastIndex(fn.Name[pathend:inst[0]], "."); r != -1 && l != r {
   569  		return fn.Name[pathend+l+1 : pathend+r]
   570  	}
   571  	return ""
   572  }
   573  
   574  // BaseName returns the symbol name without the package or receiver name.
   575  // Borrowed from $GOROOT/debug/gosym/symtab.go
   576  func (fn *Function) BaseName() string {
   577  	inst := fn.instRange()
   578  	if i := strings.LastIndex(fn.Name[inst[1]:], "."); i != -1 {
   579  		return fn.Name[inst[1]+i+1:]
   580  	} else if i := strings.LastIndex(fn.Name[:inst[0]], "."); i != -1 {
   581  		return fn.Name[i+1:]
   582  	}
   583  	return fn.Name
   584  }
   585  
   586  // NameWithoutTypeParams returns the function name without instantiation parameters
   587  func (fn *Function) NameWithoutTypeParams() string {
   588  	inst := fn.instRange()
   589  	if inst[0] == inst[1] {
   590  		return fn.Name
   591  	}
   592  	return fn.Name[:inst[0]] + fn.Name[inst[1]+1:]
   593  }
   594  
   595  // Optimized returns true if the function was optimized by the compiler.
   596  func (fn *Function) Optimized() bool {
   597  	return fn.cu.optimized
   598  }
   599  
   600  // PrologueEndPC returns the PC just after the function prologue
   601  func (fn *Function) PrologueEndPC() uint64 {
   602  	pc, _, _, ok := fn.cu.lineInfo.PrologueEndPC(fn.Entry, fn.End)
   603  	if !ok {
   604  		return fn.Entry
   605  	}
   606  	return pc
   607  }
   608  
   609  func (fn *Function) AllPCs(excludeFile string, excludeLine int) ([]uint64, error) {
   610  	if !fn.cu.image.Stripped() {
   611  		return fn.cu.lineInfo.AllPCsBetween(fn.Entry, fn.End-1, excludeFile, excludeLine)
   612  	}
   613  	var pcs []uint64
   614  	fnFile, lastLine, _ := fn.cu.image.symTable.PCToLine(fn.Entry - fn.cu.image.StaticBase)
   615  	for pc := fn.Entry - fn.cu.image.StaticBase; pc < fn.End-fn.cu.image.StaticBase; pc++ {
   616  		f, line, pcfn := fn.cu.image.symTable.PCToLine(pc)
   617  		if pcfn == nil {
   618  			continue
   619  		}
   620  		if f == fnFile && line > lastLine {
   621  			lastLine = line
   622  			pcs = append(pcs, pc+fn.cu.image.StaticBase)
   623  		}
   624  	}
   625  	return pcs, nil
   626  }
   627  
   628  // From $GOROOT/src/runtime/traceback.go:597
   629  // exportedRuntime reports whether the function is an exported runtime function.
   630  // It is only for runtime functions, so ASCII A-Z is fine.
   631  func (fn *Function) exportedRuntime() bool {
   632  	name := fn.Name
   633  	const n = len("runtime.")
   634  	return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
   635  }
   636  
   637  // unexportedRuntime reports whether the function is a private runtime function.
   638  func (fn *Function) privateRuntime() bool {
   639  	name := fn.Name
   640  	const n = len("runtime.")
   641  	return len(name) > n && name[:n] == "runtime." && !('A' <= name[n] && name[n] <= 'Z')
   642  }
   643  
   644  func (fn *Function) closureStructType(bi *BinaryInfo) *godwarf.StructType {
   645  	if fn.closureStructTypeCached != nil {
   646  		return fn.closureStructTypeCached
   647  	}
   648  	dwarfTree, err := fn.cu.image.getDwarfTree(fn.offset)
   649  	if err != nil {
   650  		return nil
   651  	}
   652  	st := &godwarf.StructType{
   653  		Kind: "struct",
   654  	}
   655  	vars := reader.Variables(dwarfTree, 0, 0, reader.VariablesNoDeclLineCheck|reader.VariablesSkipInlinedSubroutines)
   656  	for _, v := range vars {
   657  		off, ok := v.Val(godwarf.AttrGoClosureOffset).(int64)
   658  		if ok {
   659  			n, _ := v.Val(dwarf.AttrName).(string)
   660  			typ, err := v.Type(fn.cu.image.dwarf, fn.cu.image.index, fn.cu.image.typeCache)
   661  			if err == nil {
   662  				sz := typ.Common().ByteSize
   663  				st.Field = append(st.Field, &godwarf.StructField{
   664  					Name:       n,
   665  					Type:       typ,
   666  					ByteOffset: off,
   667  					ByteSize:   sz,
   668  					BitOffset:  off * 8,
   669  					BitSize:    sz * 8,
   670  				})
   671  			}
   672  		}
   673  	}
   674  
   675  	if len(st.Field) > 0 {
   676  		lf := st.Field[len(st.Field)-1]
   677  		st.ByteSize = lf.ByteOffset + lf.Type.Common().ByteSize
   678  	}
   679  	fn.closureStructTypeCached = st
   680  	return st
   681  }
   682  
   683  type constantsMap map[dwarfRef]*constantType
   684  
   685  type constantType struct {
   686  	initialized bool
   687  	values      []constantValue
   688  }
   689  
   690  type constantValue struct {
   691  	name      string
   692  	fullName  string
   693  	value     int64
   694  	singleBit bool
   695  }
   696  
   697  // packageVar represents a package-level variable (or a C global variable).
   698  // If a global variable does not have an address (for example it's stored in
   699  // a register, or non-contiguously) addr will be 0.
   700  type packageVar struct {
   701  	name   string
   702  	cu     *compileUnit
   703  	offset dwarf.Offset
   704  	addr   uint64
   705  }
   706  
   707  type buildIDHeader struct {
   708  	Namesz uint32
   709  	Descsz uint32
   710  	Type   uint32
   711  }
   712  
   713  // ElfDynamicSection describes the .dynamic section of an ELF executable.
   714  type ElfDynamicSection struct {
   715  	Addr uint64 // relocated address of where the .dynamic section is mapped in memory
   716  	Size uint64 // size of the .dynamic section of the executable
   717  }
   718  
   719  // NewBinaryInfo returns an initialized but unloaded BinaryInfo struct.
   720  func NewBinaryInfo(goos, goarch string) *BinaryInfo {
   721  	r := &BinaryInfo{GOOS: goos, logger: logflags.DebuggerLogger()}
   722  
   723  	// TODO: find better way to determine proc arch (perhaps use executable file info).
   724  	switch goarch {
   725  	case "386":
   726  		r.Arch = I386Arch(goos)
   727  	case "amd64":
   728  		r.Arch = AMD64Arch(goos)
   729  	case "arm64":
   730  		r.Arch = ARM64Arch(goos)
   731  	case "ppc64le":
   732  		r.Arch = PPC64LEArch(goos)
   733  	}
   734  	return r
   735  }
   736  
   737  // LoadBinaryInfo will load and store the information from the binary at 'path'.
   738  func (bi *BinaryInfo) LoadBinaryInfo(path string, entryPoint uint64, debugInfoDirs []string) error {
   739  	fi, err := os.Stat(path)
   740  	if err == nil {
   741  		bi.lastModified = fi.ModTime()
   742  	}
   743  
   744  	bi.DebugInfoDirectories = debugInfoDirs
   745  
   746  	return bi.AddImage(path, entryPoint)
   747  }
   748  
   749  func loadBinaryInfo(bi *BinaryInfo, image *Image, path string, entryPoint uint64) error {
   750  	var wg sync.WaitGroup
   751  	defer wg.Wait()
   752  
   753  	switch bi.GOOS {
   754  	case "linux", "freebsd":
   755  		return loadBinaryInfoElf(bi, image, path, entryPoint, &wg)
   756  	case "windows":
   757  		return loadBinaryInfoPE(bi, image, path, entryPoint, &wg)
   758  	case "darwin":
   759  		return loadBinaryInfoMacho(bi, image, path, entryPoint, &wg)
   760  	}
   761  	return errors.New("unsupported operating system")
   762  }
   763  
   764  // GStructOffset returns the offset of the G
   765  // struct in thread local storage.
   766  func (bi *BinaryInfo) GStructOffset(mem MemoryReadWriter) (uint64, error) {
   767  	offset := bi.gStructOffset
   768  	if bi.gStructOffsetIsPtr {
   769  		// The G struct offset from the TLS section is a pointer
   770  		// and the address must be dereferenced to find to actual G struct offset.
   771  		var err error
   772  		offset, err = readUintRaw(mem, offset, int64(bi.Arch.PtrSize()))
   773  		if err != nil {
   774  			return 0, err
   775  		}
   776  	}
   777  	return offset, nil
   778  }
   779  
   780  // LastModified returns the last modified time of the binary.
   781  func (bi *BinaryInfo) LastModified() time.Time {
   782  	return bi.lastModified
   783  }
   784  
   785  // DwarfReader returns a reader for the dwarf data
   786  func (so *Image) DwarfReader() *reader.Reader {
   787  	if so.dwarf == nil {
   788  		return nil
   789  	}
   790  	return reader.New(so.dwarf)
   791  }
   792  
   793  // Types returns list of types present in the debugged program.
   794  func (bi *BinaryInfo) Types() ([]string, error) {
   795  	types := make([]string, 0, len(bi.types))
   796  	for k := range bi.types {
   797  		types = append(types, k)
   798  	}
   799  	return types, nil
   800  }
   801  
   802  func (bi *BinaryInfo) EntryLineForFunc(fn *Function) (string, int) {
   803  	return bi.pcToLine(fn, fn.Entry)
   804  }
   805  
   806  func (bi *BinaryInfo) pcToLine(fn *Function, pc uint64) (string, int) {
   807  	if fn.cu.lineInfo == nil {
   808  		f, l, _ := fn.cu.image.symTable.PCToLine(pc - fn.cu.image.StaticBase)
   809  		return f, l
   810  	}
   811  	f, l := fn.cu.lineInfo.PCToLine(fn.Entry, pc)
   812  	return f, l
   813  }
   814  
   815  // PCToLine converts an instruction address to a file/line/function.
   816  func (bi *BinaryInfo) PCToLine(pc uint64) (string, int, *Function) {
   817  	fn := bi.PCToFunc(pc)
   818  	if fn == nil {
   819  		return "", 0, nil
   820  	}
   821  	f, ln := bi.pcToLine(fn, pc)
   822  	return f, ln, fn
   823  }
   824  
   825  type ErrCouldNotFindLine struct {
   826  	fileFound bool
   827  	filename  string
   828  	lineno    int
   829  }
   830  
   831  func (err *ErrCouldNotFindLine) Error() string {
   832  	if err.fileFound {
   833  		return fmt.Sprintf("could not find statement at %s:%d, please use a line with a statement", err.filename, err.lineno)
   834  	}
   835  	return fmt.Sprintf("could not find file %s", err.filename)
   836  }
   837  
   838  // AllPCsForFileLines returns a map providing all PC addresses for filename and each line in linenos
   839  func (bi *BinaryInfo) AllPCsForFileLines(filename string, linenos []int) map[int][]uint64 {
   840  	r := make(map[int][]uint64)
   841  	for _, line := range linenos {
   842  		r[line] = make([]uint64, 0, 1)
   843  	}
   844  	for _, image := range bi.Images {
   845  		for _, cu := range image.compileUnits {
   846  			if cu.lineInfo != nil && cu.lineInfo.Lookup[filename] != nil {
   847  				cu.lineInfo.AllPCsForFileLines(filename, r)
   848  			}
   849  		}
   850  	}
   851  	return r
   852  }
   853  
   854  // PCToFunc returns the concrete function containing the given PC address.
   855  // If the PC address belongs to an inlined call it will return the containing function.
   856  func (bi *BinaryInfo) PCToFunc(pc uint64) *Function {
   857  	i := sort.Search(len(bi.Functions), func(i int) bool {
   858  		fn := bi.Functions[i]
   859  		return pc <= fn.Entry || (fn.Entry <= pc && pc < fn.End)
   860  	})
   861  	if i != len(bi.Functions) {
   862  		fn := &bi.Functions[i]
   863  		if fn.Entry <= pc && pc < fn.End {
   864  			return fn
   865  		}
   866  	}
   867  	return nil
   868  }
   869  
   870  // PCToImage returns the image containing the given PC address.
   871  func (bi *BinaryInfo) PCToImage(pc uint64) *Image {
   872  	fn := bi.PCToFunc(pc)
   873  	return bi.funcToImage(fn)
   874  }
   875  
   876  // Image represents a loaded library file (shared object on linux, DLL on windows).
   877  type Image struct {
   878  	Path       string
   879  	StaticBase uint64
   880  	addr       uint64
   881  
   882  	index int // index of this object in BinaryInfo.SharedObjects
   883  
   884  	closer         io.Closer
   885  	sepDebugCloser io.Closer
   886  
   887  	dwarf        *dwarf.Data
   888  	dwarfReader  *dwarf.Reader
   889  	loclist2     *loclist.Dwarf2Reader
   890  	loclist5     *loclist.Dwarf5Reader
   891  	debugAddr    *godwarf.DebugAddrSection
   892  	debugLineStr []byte
   893  
   894  	symTable *gosym.Table
   895  
   896  	typeCache map[dwarf.Offset]godwarf.Type
   897  
   898  	compileUnits []*compileUnit // compileUnits is sorted by increasing DWARF offset
   899  
   900  	dwarfTreeCache  *simplelru.LRU
   901  	workaroundCache map[dwarf.Offset]*godwarf.Tree
   902  
   903  	// runtimeTypeToDIE maps between the offset of a runtime._type in
   904  	// runtime.moduledata.types and the offset of the DIE in debug_info. This
   905  	// map is filled by using the extended attribute godwarf.AttrGoRuntimeType
   906  	// which was added in go 1.11.
   907  	runtimeTypeToDIE map[uint64]runtimeTypeDIE
   908  
   909  	loadErrMu sync.Mutex
   910  	loadErr   error
   911  }
   912  
   913  func (image *Image) registerRuntimeTypeToDIE(entry *dwarf.Entry, ardr *reader.Reader) {
   914  	if off, ok := entry.Val(godwarf.AttrGoRuntimeType).(uint64); ok {
   915  		if _, ok := image.runtimeTypeToDIE[off]; !ok {
   916  			image.runtimeTypeToDIE[off] = runtimeTypeDIE{entry.Offset, -1}
   917  		}
   918  	}
   919  }
   920  
   921  func (image *Image) Stripped() bool {
   922  	return image.dwarf == nil
   923  }
   924  
   925  // AddImage adds the specified image to bi, loading data asynchronously.
   926  // Addr is the relocated entry point for the executable and staticBase (i.e.
   927  // the relocation offset) for all other images.
   928  // The first image added must be the executable file.
   929  func (bi *BinaryInfo) AddImage(path string, addr uint64) error {
   930  	// Check if the image is already present.
   931  	if len(bi.Images) > 0 && !strings.HasPrefix(path, "/") {
   932  		return nil
   933  	}
   934  	for _, image := range bi.Images {
   935  		if image.Path == path && image.addr == addr {
   936  			return nil
   937  		}
   938  	}
   939  
   940  	// Actually add the image.
   941  	image := &Image{Path: path, addr: addr, typeCache: make(map[dwarf.Offset]godwarf.Type)}
   942  	image.dwarfTreeCache, _ = simplelru.NewLRU(dwarfTreeCacheSize, nil)
   943  
   944  	// add Image regardless of error so that we don't attempt to re-add it every time we stop
   945  	image.index = len(bi.Images)
   946  	bi.Images = append(bi.Images, image)
   947  	err := loadBinaryInfo(bi, image, path, addr)
   948  	if err != nil {
   949  		bi.Images[len(bi.Images)-1].loadErr = err
   950  	}
   951  	bi.macOSDebugFrameBugWorkaround()
   952  	return err
   953  }
   954  
   955  // moduleDataToImage finds the image corresponding to the given module data object.
   956  func (bi *BinaryInfo) moduleDataToImage(md *moduleData) *Image {
   957  	fn := bi.PCToFunc(md.text)
   958  	if fn != nil {
   959  		return bi.funcToImage(fn)
   960  	}
   961  	// Try searching for the image with the closest address preceding md.text
   962  	var so *Image
   963  	for i := range bi.Images {
   964  		if int64(bi.Images[i].StaticBase) > int64(md.text) {
   965  			continue
   966  		}
   967  		if so == nil || int64(bi.Images[i].StaticBase) > int64(so.StaticBase) {
   968  			so = bi.Images[i]
   969  		}
   970  	}
   971  	return so
   972  }
   973  
   974  // imageToModuleData finds the module data in mds corresponding to the given image.
   975  func (bi *BinaryInfo) imageToModuleData(image *Image, mds []moduleData) *moduleData {
   976  	for _, md := range mds {
   977  		im2 := bi.moduleDataToImage(&md)
   978  		if im2 != nil && im2.index == image.index {
   979  			return &md
   980  		}
   981  	}
   982  	return nil
   983  }
   984  
   985  // typeToImage returns the image containing the give type.
   986  func (bi *BinaryInfo) typeToImage(typ godwarf.Type) *Image {
   987  	return bi.Images[typ.Common().Index]
   988  }
   989  
   990  func (bi *BinaryInfo) runtimeTypeTypename() string {
   991  	if goversion.ProducerAfterOrEqual(bi.Producer(), 1, 21) {
   992  		return "internal/abi.Type"
   993  	}
   994  	return "runtime._type"
   995  }
   996  
   997  var errBinaryInfoClose = errors.New("multiple errors closing executable files")
   998  
   999  // Close closes all internal readers.
  1000  func (bi *BinaryInfo) Close() error {
  1001  	var errs []error
  1002  	for _, image := range bi.Images {
  1003  		if err := image.Close(); err != nil {
  1004  			errs = append(errs, err)
  1005  		}
  1006  	}
  1007  	switch len(errs) {
  1008  	case 0:
  1009  		return nil
  1010  	case 1:
  1011  		return errs[0]
  1012  	default:
  1013  		return errBinaryInfoClose
  1014  	}
  1015  }
  1016  
  1017  func (image *Image) Close() error {
  1018  	var err1, err2 error
  1019  	if image.sepDebugCloser != nil {
  1020  		err := image.sepDebugCloser.Close()
  1021  		if err != nil {
  1022  			err1 = fmt.Errorf("closing shared object %q (split dwarf): %v", image.Path, err)
  1023  		}
  1024  	}
  1025  	if image.closer != nil {
  1026  		err := image.closer.Close()
  1027  		if err != nil {
  1028  			err2 = fmt.Errorf("closing shared object %q: %v", image.Path, err)
  1029  		}
  1030  	}
  1031  	if err1 != nil && err2 != nil {
  1032  		return errBinaryInfoClose
  1033  	}
  1034  	if err1 != nil {
  1035  		return err1
  1036  	}
  1037  	return err2
  1038  }
  1039  
  1040  func (image *Image) setLoadError(logger logflags.Logger, fmtstr string, args ...interface{}) {
  1041  	image.loadErrMu.Lock()
  1042  	image.loadErr = fmt.Errorf(fmtstr, args...)
  1043  	image.loadErrMu.Unlock()
  1044  	if logger != nil {
  1045  		logger.Errorf("error loading binary %q: %v", image.Path, image.loadErr)
  1046  	}
  1047  }
  1048  
  1049  // LoadError returns any error incurred while loading this image.
  1050  func (image *Image) LoadError() error {
  1051  	return image.loadErr
  1052  }
  1053  
  1054  func (image *Image) getDwarfTree(off dwarf.Offset) (*godwarf.Tree, error) {
  1055  	if image.workaroundCache[off] != nil {
  1056  		return image.workaroundCache[off], nil
  1057  	}
  1058  	if r, ok := image.dwarfTreeCache.Get(off); ok {
  1059  		return r.(*godwarf.Tree), nil
  1060  	}
  1061  	r, err := godwarf.LoadTree(off, image.dwarf, image.StaticBase)
  1062  	if err != nil {
  1063  		return nil, err
  1064  	}
  1065  	image.dwarfTreeCache.Add(off, r)
  1066  	return r, nil
  1067  }
  1068  
  1069  type nilCloser struct{}
  1070  
  1071  func (c *nilCloser) Close() error { return nil }
  1072  
  1073  // LoadImageFromData creates a new Image, using the specified data, and adds it to bi.
  1074  // This is used for debugging BinaryInfo, you should use LoadBinary instead.
  1075  func (bi *BinaryInfo) LoadImageFromData(dwdata *dwarf.Data, debugFrameBytes, debugLineBytes, debugLocBytes []byte) {
  1076  	image := &Image{}
  1077  	image.closer = (*nilCloser)(nil)
  1078  	image.sepDebugCloser = (*nilCloser)(nil)
  1079  	image.dwarf = dwdata
  1080  	image.typeCache = make(map[dwarf.Offset]godwarf.Type)
  1081  	image.dwarfTreeCache, _ = simplelru.NewLRU(dwarfTreeCacheSize, nil)
  1082  
  1083  	if debugFrameBytes != nil {
  1084  		bi.frameEntries, _ = frame.Parse(debugFrameBytes, frame.DwarfEndian(debugFrameBytes), 0, bi.Arch.PtrSize(), 0)
  1085  	}
  1086  
  1087  	image.loclist2 = loclist.NewDwarf2Reader(debugLocBytes, bi.Arch.PtrSize())
  1088  
  1089  	bi.loadDebugInfoMaps(image, nil, debugLineBytes, nil, nil)
  1090  
  1091  	bi.Images = append(bi.Images, image)
  1092  }
  1093  
  1094  func (bi *BinaryInfo) locationExpr(entry godwarf.Entry, attr dwarf.Attr, pc uint64) ([]byte, *locationExpr, error) {
  1095  	//TODO(aarzilli): handle DW_FORM_loclistx attribute form new in DWARFv5
  1096  	a := entry.Val(attr)
  1097  	if a == nil {
  1098  		return nil, nil, fmt.Errorf("no location attribute %s", attr)
  1099  	}
  1100  	if instr, ok := a.([]byte); ok {
  1101  		return instr, &locationExpr{isBlock: true, instr: instr, regnumToName: bi.Arch.RegnumToString}, nil
  1102  	}
  1103  	off, ok := a.(int64)
  1104  	if !ok {
  1105  		return nil, nil, fmt.Errorf("could not interpret location attribute %s", attr)
  1106  	}
  1107  	instr := bi.loclistEntry(off, pc)
  1108  	if instr == nil {
  1109  		return nil, nil, fmt.Errorf("could not find loclist entry at %#x for address %#x", off, pc)
  1110  	}
  1111  	return instr, &locationExpr{pc: pc, off: off, instr: instr, regnumToName: bi.Arch.RegnumToString}, nil
  1112  }
  1113  
  1114  type locationExpr struct {
  1115  	isBlock   bool
  1116  	isEscaped bool
  1117  	off       int64
  1118  	pc        uint64
  1119  	instr     []byte
  1120  
  1121  	regnumToName func(uint64) string
  1122  }
  1123  
  1124  func (le *locationExpr) String() string {
  1125  	if le == nil {
  1126  		return ""
  1127  	}
  1128  	var descr bytes.Buffer
  1129  
  1130  	if le.isBlock {
  1131  		fmt.Fprintf(&descr, "[block] ")
  1132  		op.PrettyPrint(&descr, le.instr, le.regnumToName)
  1133  	} else {
  1134  		fmt.Fprintf(&descr, "[%#x:%#x] ", le.off, le.pc)
  1135  		op.PrettyPrint(&descr, le.instr, le.regnumToName)
  1136  	}
  1137  
  1138  	if le.isEscaped {
  1139  		fmt.Fprintf(&descr, " (escaped)")
  1140  	}
  1141  	return descr.String()
  1142  }
  1143  
  1144  // LocationCovers returns the list of PC addresses that is covered by the
  1145  // location attribute 'attr' of entry 'entry'.
  1146  func (bi *BinaryInfo) LocationCovers(entry *dwarf.Entry, attr dwarf.Attr) ([][2]uint64, error) {
  1147  	a := entry.Val(attr)
  1148  	if a == nil {
  1149  		return nil, fmt.Errorf("attribute %s not found", attr)
  1150  	}
  1151  	if _, isblock := a.([]byte); isblock {
  1152  		return [][2]uint64{{0, ^uint64(0)}}, nil
  1153  	}
  1154  
  1155  	off, ok := a.(int64)
  1156  	if !ok {
  1157  		return nil, fmt.Errorf("attribute %s of unsupported type %T", attr, a)
  1158  	}
  1159  	cu := bi.Images[0].findCompileUnitForOffset(entry.Offset)
  1160  	if cu == nil {
  1161  		return nil, errors.New("could not find compile unit")
  1162  	}
  1163  	if cu.Version >= 5 && cu.image.loclist5 != nil {
  1164  		return nil, errors.New("LocationCovers does not support DWARFv5")
  1165  	}
  1166  
  1167  	image := cu.image
  1168  	base := cu.lowPC
  1169  	if image == nil || image.loclist2.Empty() {
  1170  		return nil, errors.New("malformed executable")
  1171  	}
  1172  
  1173  	r := [][2]uint64{}
  1174  	var e loclist.Entry
  1175  	image.loclist2.Seek(int(off))
  1176  	for image.loclist2.Next(&e) {
  1177  		if e.BaseAddressSelection() {
  1178  			base = e.HighPC
  1179  			continue
  1180  		}
  1181  		r = append(r, [2]uint64{e.LowPC + base, e.HighPC + base})
  1182  	}
  1183  	return r, nil
  1184  }
  1185  
  1186  // Location returns the location described by attribute attr of entry.
  1187  // This will either be an int64 address or a slice of Pieces for locations
  1188  // that don't correspond to a single memory address (registers, composite
  1189  // locations).
  1190  func (bi *BinaryInfo) Location(entry godwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters, mem MemoryReadWriter) (int64, []op.Piece, *locationExpr, error) {
  1191  	instr, descr, err := bi.locationExpr(entry, attr, pc)
  1192  	if err != nil {
  1193  		return 0, nil, nil, err
  1194  	}
  1195  	readMemory := op.ReadMemoryFunc(nil)
  1196  	if mem != nil {
  1197  		readMemory = mem.ReadMemory
  1198  	}
  1199  	addr, pieces, err := op.ExecuteStackProgram(regs, instr, bi.Arch.PtrSize(), readMemory)
  1200  	return addr, pieces, descr, err
  1201  }
  1202  
  1203  // loclistEntry returns the loclist entry in the loclist starting at off,
  1204  // for address pc.
  1205  func (bi *BinaryInfo) loclistEntry(off int64, pc uint64) []byte {
  1206  	var base uint64
  1207  	image := bi.Images[0]
  1208  	cu := bi.findCompileUnit(pc)
  1209  	if cu != nil {
  1210  		base = cu.lowPC
  1211  		image = cu.image
  1212  	}
  1213  	if image == nil {
  1214  		return nil
  1215  	}
  1216  
  1217  	var loclist loclist.Reader = image.loclist2
  1218  	var debugAddr *godwarf.DebugAddr
  1219  	if cu != nil && cu.Version >= 5 && image.loclist5 != nil {
  1220  		loclist = image.loclist5
  1221  		if addrBase, ok := cu.entry.Val(dwarfAttrAddrBase).(int64); ok {
  1222  			debugAddr = image.debugAddr.GetSubsection(uint64(addrBase))
  1223  		}
  1224  	}
  1225  
  1226  	if loclist.Empty() {
  1227  		return nil
  1228  	}
  1229  
  1230  	e, err := loclist.Find(int(off), image.StaticBase, base, pc, debugAddr)
  1231  	if err != nil {
  1232  		bi.logger.Errorf("error reading loclist section: %v", err)
  1233  		return nil
  1234  	}
  1235  	if e != nil {
  1236  		return e.Instr
  1237  	}
  1238  
  1239  	return nil
  1240  }
  1241  
  1242  // findCompileUnit returns the compile unit containing address pc.
  1243  func (bi *BinaryInfo) findCompileUnit(pc uint64) *compileUnit {
  1244  	for _, image := range bi.Images {
  1245  		for _, cu := range image.compileUnits {
  1246  			for _, rng := range cu.ranges {
  1247  				if pc >= rng[0] && pc < rng[1] {
  1248  					return cu
  1249  				}
  1250  			}
  1251  		}
  1252  	}
  1253  	return nil
  1254  }
  1255  
  1256  func (bi *Image) findCompileUnitForOffset(off dwarf.Offset) *compileUnit {
  1257  	i := sort.Search(len(bi.compileUnits), func(i int) bool {
  1258  		return bi.compileUnits[i].offset >= off
  1259  	})
  1260  	if i > 0 {
  1261  		i--
  1262  	}
  1263  	return bi.compileUnits[i]
  1264  }
  1265  
  1266  // Producer returns the value of DW_AT_producer.
  1267  func (bi *BinaryInfo) Producer() string {
  1268  	for _, cu := range bi.Images[0].compileUnits {
  1269  		if cu.isgo && cu.producer != "" {
  1270  			return cu.producer
  1271  		}
  1272  	}
  1273  	return ""
  1274  }
  1275  
  1276  // Type returns the Dwarf type entry at `offset`.
  1277  func (image *Image) Type(offset dwarf.Offset) (godwarf.Type, error) {
  1278  	return godwarf.ReadType(image.dwarf, image.index, offset, image.typeCache)
  1279  }
  1280  
  1281  // funcToImage returns the Image containing function fn, or the
  1282  // executable file as a fallback.
  1283  func (bi *BinaryInfo) funcToImage(fn *Function) *Image {
  1284  	if fn == nil {
  1285  		return bi.Images[0]
  1286  	}
  1287  	return fn.cu.image
  1288  }
  1289  
  1290  // parseDebugFrameGeneral parses a debug_frame and a eh_frame section.
  1291  // At least one of the two must be present and parsed correctly, if
  1292  // debug_frame is present it must be parsable correctly.
  1293  func (bi *BinaryInfo) parseDebugFrameGeneral(image *Image, debugFrameBytes []byte, debugFrameName string, debugFrameErr error, ehFrameBytes []byte, ehFrameAddr uint64, ehFrameName string, byteOrder binary.ByteOrder) {
  1294  	if debugFrameBytes == nil && ehFrameBytes == nil {
  1295  		image.setLoadError(bi.logger, "could not get %s section: %v", debugFrameName, debugFrameErr)
  1296  		return
  1297  	}
  1298  
  1299  	if debugFrameBytes != nil {
  1300  		fe, err := frame.Parse(debugFrameBytes, byteOrder, image.StaticBase, bi.Arch.PtrSize(), 0)
  1301  		if err != nil {
  1302  			image.setLoadError(bi.logger, "could not parse %s section: %v", debugFrameName, err)
  1303  			return
  1304  		}
  1305  		bi.frameEntries = bi.frameEntries.Append(fe)
  1306  	}
  1307  
  1308  	if ehFrameBytes != nil && ehFrameAddr > 0 {
  1309  		fe, err := frame.Parse(ehFrameBytes, byteOrder, image.StaticBase, bi.Arch.PtrSize(), ehFrameAddr)
  1310  		if err != nil {
  1311  			if debugFrameBytes == nil {
  1312  				image.setLoadError(bi.logger, "could not parse %s section: %v", ehFrameName, err)
  1313  				return
  1314  			}
  1315  			bi.logger.Warnf("could not parse %s section: %v", ehFrameName, err)
  1316  			return
  1317  		}
  1318  		bi.frameEntries = bi.frameEntries.Append(fe)
  1319  	}
  1320  }
  1321  
  1322  // ELF ///////////////////////////////////////////////////////////////
  1323  
  1324  // openSeparateDebugInfo searches for a file containing the separate
  1325  // debug info for the binary using the "build ID" method as described
  1326  // in GDB's documentation [1], and if found returns two handles, one
  1327  // for the bare file, and another for its corresponding elf.File.
  1328  // [1] https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
  1329  //
  1330  // Alternatively, if the debug file cannot be found be the build-id, Delve
  1331  // will look in directories specified by the debug-info-directories config value.
  1332  func (bi *BinaryInfo) openSeparateDebugInfo(image *Image, exe *elf.File, debugInfoDirectories []string) (*os.File, *elf.File, error) {
  1333  	exePath := image.Path
  1334  	exeName := filepath.Base(image.Path)
  1335  	if strings.HasPrefix(image.Path, "/proc") {
  1336  		var err error
  1337  		exePath, err = filepath.EvalSymlinks(image.Path)
  1338  		if err == nil {
  1339  			exeName = filepath.Base(exePath)
  1340  		}
  1341  	}
  1342  
  1343  	var debugFilePath string
  1344  
  1345  	check := func(potentialDebugFilePath string) bool {
  1346  		_, err := os.Stat(potentialDebugFilePath)
  1347  		if err == nil {
  1348  			debugFilePath = potentialDebugFilePath
  1349  			return true
  1350  		}
  1351  		return false
  1352  	}
  1353  
  1354  	find := func(f func(string) bool, suffix string) {
  1355  		for _, dir := range debugInfoDirectories {
  1356  			if f != nil && !f(dir) {
  1357  				continue
  1358  			}
  1359  			if check(fmt.Sprintf("%s/%s", dir, suffix)) {
  1360  				break
  1361  			}
  1362  		}
  1363  	}
  1364  
  1365  	if debugFilePath == "" && len(bi.BuildID) > 2 {
  1366  		// Build ID method: look for a file named .build-id/nn/nnnnnnnn.debug in
  1367  		// every debug info directory.
  1368  		find(nil, fmt.Sprintf(".build-id/%s/%s.debug", bi.BuildID[:2], bi.BuildID[2:]))
  1369  	}
  1370  
  1371  	if debugFilePath == "" {
  1372  		// Debug link: method if the executable contains a .gnu_debuglink section
  1373  		// it will look for the file named in the same directory of the
  1374  		// executable, then in a subdirectory named .debug and finally in each
  1375  		// debug info directory in a subdirectory with the same path as the
  1376  		// directory of the executable
  1377  		debugLink, crc := bi.getDebugLink(exe)
  1378  
  1379  		if debugLink != "" {
  1380  			check(filepath.Join(filepath.Dir(exePath), debugLink))
  1381  			if debugFilePath == "" {
  1382  				check(filepath.Join(filepath.Dir(exePath), ".debug", debugLink))
  1383  			}
  1384  			if debugFilePath == "" {
  1385  				suffix := filepath.Join(filepath.Dir(exePath)[1:], debugLink)
  1386  				find(nil, suffix)
  1387  			}
  1388  			if debugFilePath == "" {
  1389  				bi.logger.Warnf("gnu_debuglink link %q not found in any debug info directory", debugLink)
  1390  			}
  1391  		}
  1392  
  1393  		if debugFilePath != "" {
  1394  			// CRC check
  1395  			buf, err := os.ReadFile(debugFilePath)
  1396  			if err == nil {
  1397  				computedCRC := crc32.ChecksumIEEE(buf)
  1398  				if crc != computedCRC {
  1399  					bi.logger.Errorf("gnu_debuglink CRC check failed for %s (want %x got %x)", debugFilePath, crc, computedCRC)
  1400  					debugFilePath = ""
  1401  				}
  1402  
  1403  			}
  1404  		}
  1405  	}
  1406  
  1407  	if debugFilePath == "" && len(bi.BuildID) > 2 {
  1408  		// Previous versions of delve looked for the build id in every debug info
  1409  		// directory that contained the build-id substring. This behavior deviates
  1410  		// from the ones specified by GDB but we keep it for backwards compatibility.
  1411  		find(func(dir string) bool { return strings.Contains(dir, "build-id") }, fmt.Sprintf("%s/%s.debug", bi.BuildID[:2], bi.BuildID[2:]))
  1412  	}
  1413  
  1414  	if debugFilePath == "" {
  1415  		// Previous versions of delve looked for the executable filename (with
  1416  		// .debug extension) in every debug info directory.  This behavior also
  1417  		// deviates from the ones specified by GDB, but we keep it for backwards
  1418  		// compatibility.
  1419  		find(func(dir string) bool { return !strings.Contains(dir, "build-id") }, fmt.Sprintf("%s.debug", exeName))
  1420  	}
  1421  
  1422  	// We cannot find the debug information locally on the system. Try and see if we're on a system that
  1423  	// has debuginfod so that we can use that in order to find any relevant debug information.
  1424  	if debugFilePath == "" {
  1425  		var err error
  1426  		debugFilePath, err = debuginfod.GetDebuginfo(bi.BuildID)
  1427  		if err != nil {
  1428  			return nil, nil, ErrNoDebugInfoFound
  1429  		}
  1430  	}
  1431  
  1432  	sepFile, err := os.OpenFile(debugFilePath, 0, os.ModePerm)
  1433  	if err != nil {
  1434  		return nil, nil, errors.New("can't open separate debug file: " + err.Error())
  1435  	}
  1436  
  1437  	elfFile, err := elf.NewFile(sepFile)
  1438  	if err != nil {
  1439  		sepFile.Close()
  1440  		return nil, nil, fmt.Errorf("can't open separate debug file %q: %v", debugFilePath, err.Error())
  1441  	}
  1442  
  1443  	if !supportedLinuxArch[elfFile.Machine] {
  1444  		sepFile.Close()
  1445  		return nil, nil, fmt.Errorf("can't open separate debug file %q: %v", debugFilePath, &ErrUnsupportedArch{os: "linux", cpuArch: elfFile.Machine})
  1446  	}
  1447  
  1448  	return sepFile, elfFile, nil
  1449  }
  1450  
  1451  // loadBinaryInfoElf specifically loads information from an ELF binary.
  1452  func loadBinaryInfoElf(bi *BinaryInfo, image *Image, path string, addr uint64, wg *sync.WaitGroup) error {
  1453  	exe, err := os.OpenFile(path, 0, os.ModePerm)
  1454  	if err != nil {
  1455  		return err
  1456  	}
  1457  	image.closer = exe
  1458  	elfFile, err := elf.NewFile(exe)
  1459  	if err != nil {
  1460  		return err
  1461  	}
  1462  	if !supportedLinuxArch[elfFile.Machine] {
  1463  		return &ErrUnsupportedArch{os: "linux", cpuArch: elfFile.Machine}
  1464  	}
  1465  
  1466  	if image.index == 0 {
  1467  		// adding executable file:
  1468  		// - addr is entryPoint therefore staticBase needs to be calculated by
  1469  		//   subtracting the entry point specified in the executable file from addr.
  1470  		// - memory address of the .dynamic section needs to be recorded in
  1471  		//   BinaryInfo so that we can find loaded libraries.
  1472  		if addr != 0 {
  1473  			image.StaticBase = addr - elfFile.Entry
  1474  		} else if elfFile.Type == elf.ET_DYN {
  1475  			return ErrCouldNotDetermineRelocation
  1476  		}
  1477  		if dynsec := elfFile.Section(".dynamic"); dynsec != nil {
  1478  			bi.ElfDynamicSection.Addr = dynsec.Addr + image.StaticBase
  1479  			bi.ElfDynamicSection.Size = dynsec.Size
  1480  		}
  1481  	} else {
  1482  		image.StaticBase = addr
  1483  	}
  1484  
  1485  	dwarfFile := elfFile
  1486  
  1487  	bi.loadBuildID(image, elfFile)
  1488  	var debugInfoBytes []byte
  1489  	var dwerr error
  1490  	image.dwarf, dwerr = elfFile.DWARF()
  1491  	if dwerr != nil {
  1492  		var sepFile *os.File
  1493  		var serr error
  1494  		sepFile, dwarfFile, serr = bi.openSeparateDebugInfo(image, elfFile, bi.DebugInfoDirectories)
  1495  		if serr != nil {
  1496  			if len(bi.Images) <= 1 {
  1497  				fmt.Fprintln(os.Stderr, "Warning: no debug info found, some functionality will be missing such as stack traces and variable evaluation.")
  1498  			}
  1499  			err := loadBinaryInfoGoRuntimeElf(bi, image, path, elfFile)
  1500  			if err != nil {
  1501  				return fmt.Errorf("could not read debug info (%v) and could not read go symbol table (%v)", dwerr, err)
  1502  			}
  1503  			return nil
  1504  		}
  1505  		image.sepDebugCloser = sepFile
  1506  		image.dwarf, err = dwarfFile.DWARF()
  1507  		if err != nil {
  1508  			return err
  1509  		}
  1510  	}
  1511  
  1512  	debugInfoBytes, err = godwarf.GetDebugSectionElf(dwarfFile, "info")
  1513  	if err != nil {
  1514  		return err
  1515  	}
  1516  
  1517  	image.dwarfReader = image.dwarf.Reader()
  1518  
  1519  	debugLineBytes, err := godwarf.GetDebugSectionElf(dwarfFile, "line")
  1520  	if err != nil {
  1521  		return err
  1522  	}
  1523  	debugLocBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "loc")
  1524  	image.loclist2 = loclist.NewDwarf2Reader(debugLocBytes, bi.Arch.PtrSize())
  1525  	debugLoclistBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "loclists")
  1526  	image.loclist5 = loclist.NewDwarf5Reader(debugLoclistBytes)
  1527  	debugAddrBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "addr")
  1528  	image.debugAddr = godwarf.ParseAddr(debugAddrBytes)
  1529  	debugLineStrBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "line_str")
  1530  	image.debugLineStr = debugLineStrBytes
  1531  
  1532  	wg.Add(3)
  1533  	go bi.parseDebugFrameElf(image, dwarfFile, elfFile, debugInfoBytes, wg)
  1534  	go bi.loadDebugInfoMaps(image, debugInfoBytes, debugLineBytes, wg, nil)
  1535  	go bi.loadSymbolName(image, elfFile, wg)
  1536  	if image.index == 0 {
  1537  		// determine g struct offset only when loading the executable file
  1538  		wg.Add(1)
  1539  		go bi.setGStructOffsetElf(image, dwarfFile, wg)
  1540  	}
  1541  	return nil
  1542  }
  1543  
  1544  func findGoFuncVal(moduleData []byte, roDataAddr uint64, ptrsize int) (uint64, error) {
  1545  	buf := new(bytes.Buffer)
  1546  	err := binary.Write(buf, binary.LittleEndian, &roDataAddr)
  1547  	if err != nil {
  1548  		return 0, err
  1549  	}
  1550  	// Here we search for the value of `go.func.*` by searching through the raw bytes of the
  1551  	// runtime.moduledata structure. Since we don't know the value that we are looking for,
  1552  	// we use a known value, in this case the address of the .rodata section.
  1553  	// This is because in the layout of the struct, the rodata member is right next to
  1554  	// the value we need, making the math trivial once we find that member.
  1555  	// We use `bytes.LastIndex` specifically because the `types` struct member can also
  1556  	// contain the address of the .rodata section, so this pointer can appear multiple times
  1557  	// in the raw bytes.
  1558  	// Yes, this is very ill-advised low-level hackery but it works fine until
  1559  	// https://github.com/golang/go/issues/58474#issuecomment-1785681472 happens.
  1560  	// This code path also only runs in stripped binaries, so the whole implementation is
  1561  	// best effort anyways.
  1562  	rodata := bytes.LastIndex(moduleData, buf.Bytes()[:ptrsize])
  1563  	if rodata == -1 {
  1564  		return 0, errors.New("could not find rodata struct member")
  1565  	}
  1566  	// Layout of struct members is:
  1567  	// type moduledata struct {
  1568  	// 	...
  1569  	// 	rodata uintptr
  1570  	// 	gofunc uintptr
  1571  	// 	...
  1572  	// }
  1573  	// So do some pointer arithmetic to get the value we need.
  1574  	gofuncval := binary.LittleEndian.Uint64(moduleData[rodata+(1*ptrsize) : rodata+(2*ptrsize)])
  1575  	return gofuncval, nil
  1576  }
  1577  
  1578  func parseModuleData(dataSection []byte, tableAddr uint64) ([]byte, error) {
  1579  	buf := new(bytes.Buffer)
  1580  	err := binary.Write(buf, binary.LittleEndian, &tableAddr)
  1581  	if err != nil {
  1582  		return nil, err
  1583  	}
  1584  	off := bytes.Index(dataSection, buf.Bytes()[:4])
  1585  	if off == -1 {
  1586  		return nil, errors.New("could not find moduledata")
  1587  	}
  1588  	return dataSection[off : off+0x300], nil
  1589  }
  1590  
  1591  // _STT_FUNC is a code object, see /usr/include/elf.h for a full definition.
  1592  const _STT_FUNC = 2
  1593  
  1594  func (bi *BinaryInfo) loadSymbolName(image *Image, file *elf.File, wg *sync.WaitGroup) {
  1595  	defer wg.Done()
  1596  	if bi.SymNames == nil {
  1597  		bi.SymNames = make(map[uint64]*elf.Symbol)
  1598  	}
  1599  	symSecs, _ := file.Symbols()
  1600  	for _, symSec := range symSecs {
  1601  		if symSec.Info == _STT_FUNC { // TODO(chainhelen), need to parse others types.
  1602  			s := symSec
  1603  			bi.SymNames[symSec.Value+image.StaticBase] = &s
  1604  		}
  1605  	}
  1606  }
  1607  
  1608  func (bi *BinaryInfo) loadBuildID(image *Image, file *elf.File) {
  1609  	buildid := file.Section(".note.gnu.build-id")
  1610  	if buildid == nil {
  1611  		return
  1612  	}
  1613  
  1614  	br := buildid.Open()
  1615  	bh := new(buildIDHeader)
  1616  	if err := binary.Read(br, binary.LittleEndian, bh); err != nil {
  1617  		bi.logger.Warnf("can't read build-id header: %v", err)
  1618  		return
  1619  	}
  1620  
  1621  	name := make([]byte, bh.Namesz)
  1622  	if err := binary.Read(br, binary.LittleEndian, name); err != nil {
  1623  		bi.logger.Warnf("can't read build-id name: %v", err)
  1624  		return
  1625  	}
  1626  
  1627  	if strings.TrimSpace(string(name)) != "GNU\x00" {
  1628  		bi.logger.Warn("invalid build-id signature")
  1629  		return
  1630  	}
  1631  
  1632  	descBinary := make([]byte, bh.Descsz)
  1633  	if err := binary.Read(br, binary.LittleEndian, descBinary); err != nil {
  1634  		bi.logger.Warnf("can't read build-id desc: %v", err)
  1635  		return
  1636  	}
  1637  	bi.BuildID = hex.EncodeToString(descBinary)
  1638  }
  1639  
  1640  func (bi *BinaryInfo) getDebugLink(exe *elf.File) (debugLink string, crc uint32) {
  1641  	gnuDebugLink := exe.Section(".gnu_debuglink")
  1642  	if gnuDebugLink == nil {
  1643  		return
  1644  	}
  1645  
  1646  	br := gnuDebugLink.Open()
  1647  	buf, err := io.ReadAll(br)
  1648  	if err != nil {
  1649  		bi.logger.Warnf("can't read .gnu_debuglink: %v", err)
  1650  		return
  1651  	}
  1652  	zero := bytes.Index(buf, []byte{0})
  1653  	if zero <= 0 || len(buf[zero+1:]) < 4 {
  1654  		bi.logger.Warnf("wrong .gnu_debuglink format: %q", buf)
  1655  		return
  1656  	}
  1657  	debugLink = string(buf[:zero])
  1658  	crc = binary.LittleEndian.Uint32(buf[len(buf)-4:])
  1659  	return
  1660  }
  1661  
  1662  func (bi *BinaryInfo) parseDebugFrameElf(image *Image, dwarfFile, exeFile *elf.File, debugInfoBytes []byte, wg *sync.WaitGroup) {
  1663  	defer wg.Done()
  1664  
  1665  	debugFrameData, debugFrameErr := godwarf.GetDebugSectionElf(dwarfFile, "frame")
  1666  	ehFrameSection := exeFile.Section(".eh_frame")
  1667  	var ehFrameData []byte
  1668  	var ehFrameAddr uint64
  1669  	if ehFrameSection != nil {
  1670  		ehFrameAddr = ehFrameSection.Addr
  1671  		// Workaround for go.dev/cl/429601
  1672  		if ehFrameSection.Type == elf.SHT_NOBITS {
  1673  			ehFrameData = make([]byte, ehFrameSection.Size)
  1674  		} else {
  1675  			ehFrameData, _ = ehFrameSection.Data()
  1676  		}
  1677  	}
  1678  
  1679  	bi.parseDebugFrameGeneral(image, debugFrameData, ".debug_frame", debugFrameErr, ehFrameData, ehFrameAddr, ".eh_frame", frame.DwarfEndian(debugInfoBytes))
  1680  }
  1681  
  1682  func (bi *BinaryInfo) setGStructOffsetElf(image *Image, exe *elf.File, wg *sync.WaitGroup) {
  1683  	defer wg.Done()
  1684  
  1685  	// This is a bit arcane. Essentially:
  1686  	// - If the program is pure Go, it can do whatever it wants, and puts the G
  1687  	//   pointer at %fs-8 on 64 bit.
  1688  	// - %Gs is the index of private storage in GDT on 32 bit, and puts the G
  1689  	//   pointer at -4(tls).
  1690  	// - Otherwise, Go asks the external linker to place the G pointer by
  1691  	//   emitting runtime.tlsg, a TLS symbol, which is relocated to the chosen
  1692  	//   offset in libc's TLS block.
  1693  	// - On ARM64 (but really, any architecture other than i386 and 86x64) the
  1694  	//   offset is calculated using runtime.tls_g and the formula is different.
  1695  
  1696  	var tls *elf.Prog
  1697  	for _, prog := range exe.Progs {
  1698  		if prog.Type == elf.PT_TLS {
  1699  			tls = prog
  1700  			break
  1701  		}
  1702  	}
  1703  
  1704  	switch exe.Machine {
  1705  	case elf.EM_X86_64, elf.EM_386:
  1706  		tlsg := getSymbol(image, bi.logger, exe, "runtime.tlsg")
  1707  		if tlsg == nil || tls == nil {
  1708  			bi.gStructOffset = ^uint64(bi.Arch.PtrSize()) + 1 //-ptrSize
  1709  			return
  1710  		}
  1711  
  1712  		// According to https://reviews.llvm.org/D61824, linkers must pad the actual
  1713  		// size of the TLS segment to ensure that (tlsoffset%align) == (vaddr%align).
  1714  		// This formula, copied from the lld code, matches that.
  1715  		// https://github.com/llvm-mirror/lld/blob/9aef969544981d76bea8e4d1961d3a6980980ef9/ELF/InputSection.cpp#L643
  1716  		memsz := tls.Memsz + (-tls.Vaddr-tls.Memsz)&(tls.Align-1)
  1717  
  1718  		// The TLS register points to the end of the TLS block, which is
  1719  		// tls.Memsz long. runtime.tlsg is an offset from the beginning of that block.
  1720  		bi.gStructOffset = ^(memsz) + 1 + tlsg.Value // -tls.Memsz + tlsg.Value
  1721  
  1722  	case elf.EM_AARCH64:
  1723  		tlsg := getSymbol(image, bi.logger, exe, "runtime.tls_g")
  1724  		if tlsg == nil || tls == nil {
  1725  			bi.gStructOffset = 2 * uint64(bi.Arch.PtrSize())
  1726  			return
  1727  		}
  1728  
  1729  		bi.gStructOffset = tlsg.Value + uint64(bi.Arch.PtrSize()*2) + ((tls.Vaddr - uint64(bi.Arch.PtrSize()*2)) & (tls.Align - 1))
  1730  
  1731  	case elf.EM_PPC64:
  1732  		_ = getSymbol(image, bi.logger, exe, "runtime.tls_g")
  1733  
  1734  	default:
  1735  		// we should never get here
  1736  		panic("architecture not supported")
  1737  	}
  1738  }
  1739  
  1740  func getSymbol(image *Image, logger logflags.Logger, exe *elf.File, name string) *elf.Symbol {
  1741  	symbols, err := exe.Symbols()
  1742  	if err != nil {
  1743  		image.setLoadError(logger, "could not parse ELF symbols: %v", err)
  1744  		return nil
  1745  	}
  1746  
  1747  	for _, symbol := range symbols {
  1748  		if symbol.Name == name {
  1749  			s := symbol
  1750  			return &s
  1751  		}
  1752  	}
  1753  	return nil
  1754  }
  1755  
  1756  // PE ////////////////////////////////////////////////////////////////
  1757  
  1758  const _IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040
  1759  
  1760  // loadBinaryInfoPE specifically loads information from a PE binary.
  1761  func loadBinaryInfoPE(bi *BinaryInfo, image *Image, path string, entryPoint uint64, wg *sync.WaitGroup) error {
  1762  	peFile, closer, err := openExecutablePathPE(path)
  1763  	if err != nil {
  1764  		return err
  1765  	}
  1766  	image.closer = closer
  1767  	cpuArch := _PEMachine(peFile.Machine)
  1768  	if !supportedWindowsArch[cpuArch] {
  1769  		return &ErrUnsupportedArch{os: "windows", cpuArch: cpuArch}
  1770  	}
  1771  	image.dwarf, err = peFile.DWARF()
  1772  	if err != nil {
  1773  		return err
  1774  	}
  1775  	debugInfoBytes, err := godwarf.GetDebugSectionPE(peFile, "info")
  1776  	if err != nil {
  1777  		return err
  1778  	}
  1779  	opth := peFile.OptionalHeader.(*pe.OptionalHeader64)
  1780  	if entryPoint != 0 {
  1781  		image.StaticBase = entryPoint - opth.ImageBase
  1782  	} else {
  1783  		if opth.DllCharacteristics&_IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE != 0 {
  1784  			return ErrCouldNotDetermineRelocation
  1785  		}
  1786  	}
  1787  
  1788  	image.dwarfReader = image.dwarf.Reader()
  1789  
  1790  	debugLineBytes, err := godwarf.GetDebugSectionPE(peFile, "line")
  1791  	if err != nil {
  1792  		return err
  1793  	}
  1794  	debugLocBytes, _ := godwarf.GetDebugSectionPE(peFile, "loc")
  1795  	image.loclist2 = loclist.NewDwarf2Reader(debugLocBytes, bi.Arch.PtrSize())
  1796  	debugLoclistBytes, _ := godwarf.GetDebugSectionPE(peFile, "loclists")
  1797  	image.loclist5 = loclist.NewDwarf5Reader(debugLoclistBytes)
  1798  	debugAddrBytes, _ := godwarf.GetDebugSectionPE(peFile, "addr")
  1799  	image.debugAddr = godwarf.ParseAddr(debugAddrBytes)
  1800  	debugLineStrBytes, _ := godwarf.GetDebugSectionPE(peFile, "line_str")
  1801  	image.debugLineStr = debugLineStrBytes
  1802  
  1803  	wg.Add(2)
  1804  	go bi.parseDebugFramePE(image, peFile, debugInfoBytes, wg)
  1805  	go bi.loadDebugInfoMaps(image, debugInfoBytes, debugLineBytes, wg, func() {
  1806  		// setGStructOffsetPE requires the image compile units to be loaded,
  1807  		// so it can't be called concurrently with loadDebugInfoMaps.
  1808  		if image.index == 0 {
  1809  			// determine g struct offset only when loading the executable file.
  1810  			bi.setGStructOffsetPE(entryPoint, peFile)
  1811  		}
  1812  	})
  1813  	return nil
  1814  }
  1815  
  1816  func (bi *BinaryInfo) setGStructOffsetPE(entryPoint uint64, peFile *pe.File) {
  1817  	readtls_g := func() uint64 {
  1818  		for _, s := range peFile.Symbols {
  1819  			if s.Name == "runtime.tls_g" {
  1820  				i := int(s.SectionNumber) - 1
  1821  				if 0 <= i && i < len(peFile.Sections) {
  1822  					sect := peFile.Sections[i]
  1823  					if s.Value < sect.VirtualSize {
  1824  						return entryPoint + uint64(sect.VirtualAddress) + uint64(s.Value)
  1825  					}
  1826  				}
  1827  				break
  1828  			}
  1829  		}
  1830  		return 0
  1831  	}
  1832  	switch _PEMachine(peFile.Machine) {
  1833  	case _IMAGE_FILE_MACHINE_AMD64:
  1834  		producer := bi.Producer()
  1835  		if producer != "" && goversion.ProducerAfterOrEqual(producer, 1, 20) {
  1836  			// Use runtime.tls_g as pointer to offset from GS to G struct:
  1837  			// https://golang.org/src/runtime/sys_windows_amd64.s
  1838  			bi.gStructOffset = readtls_g()
  1839  			bi.gStructOffsetIsPtr = true
  1840  		} else {
  1841  			// Use ArbitraryUserPointer (0x28) as pointer to pointer
  1842  			// to G struct per:
  1843  			// https://golang.org/src/runtime/cgo/gcc_windows_amd64.c
  1844  			bi.gStructOffset = 0x28
  1845  		}
  1846  	case _IMAGE_FILE_MACHINE_ARM64:
  1847  		// Use runtime.tls_g as pointer to offset from R18 to G struct:
  1848  		// https://golang.org/src/runtime/sys_windows_arm64.s
  1849  		bi.gStructOffset = readtls_g()
  1850  		bi.gStructOffsetIsPtr = true
  1851  	}
  1852  }
  1853  
  1854  func openExecutablePathPE(path string) (*pe.File, io.Closer, error) {
  1855  	f, err := os.OpenFile(path, 0, os.ModePerm)
  1856  	if err != nil {
  1857  		return nil, nil, err
  1858  	}
  1859  	peFile, err := pe.NewFile(f)
  1860  	if err != nil {
  1861  		f.Close()
  1862  		return nil, nil, err
  1863  	}
  1864  	return peFile, f, nil
  1865  }
  1866  
  1867  func (bi *BinaryInfo) parseDebugFramePE(image *Image, exe *pe.File, debugInfoBytes []byte, wg *sync.WaitGroup) {
  1868  	defer wg.Done()
  1869  
  1870  	debugFrameBytes, err := godwarf.GetDebugSectionPE(exe, "frame")
  1871  	bi.parseDebugFrameGeneral(image, debugFrameBytes, ".debug_frame", err, nil, 0, "", frame.DwarfEndian(debugInfoBytes))
  1872  }
  1873  
  1874  // MACH-O ////////////////////////////////////////////////////////////
  1875  
  1876  // loadBinaryInfoMacho specifically loads information from a Mach-O binary.
  1877  func loadBinaryInfoMacho(bi *BinaryInfo, image *Image, path string, entryPoint uint64, wg *sync.WaitGroup) error {
  1878  	exe, err := macho.Open(path)
  1879  
  1880  	if err != nil {
  1881  		return err
  1882  	}
  1883  
  1884  	if entryPoint != 0 {
  1885  		machoOff := uint64(0x100000000)
  1886  		for _, ld := range exe.Loads {
  1887  			if seg, _ := ld.(*macho.Segment); seg != nil {
  1888  				if seg.Name == "__TEXT" {
  1889  					machoOff = seg.Addr
  1890  					break
  1891  				}
  1892  			}
  1893  		}
  1894  		logflags.DebuggerLogger().Debugf("entryPoint %#x machoOff %#x", entryPoint, machoOff)
  1895  		image.StaticBase = entryPoint - machoOff
  1896  	}
  1897  
  1898  	image.closer = exe
  1899  	if !supportedDarwinArch[exe.Cpu] {
  1900  		return &ErrUnsupportedArch{os: "darwin", cpuArch: exe.Cpu}
  1901  	}
  1902  	var dwerr error
  1903  	image.dwarf, dwerr = exe.DWARF()
  1904  	if dwerr != nil {
  1905  		if len(bi.Images) <= 1 {
  1906  			fmt.Fprintln(os.Stderr, "Warning: no debug info found, some functionality will be missing such as stack traces and variable evaluation.")
  1907  		}
  1908  		err := loadBinaryInfoGoRuntimeMacho(bi, image, path, exe)
  1909  		if err != nil {
  1910  			return fmt.Errorf("could not read debug info (%v) and could not read go symbol table (%v)", dwerr, err)
  1911  		}
  1912  		return nil
  1913  	}
  1914  	debugInfoBytes, err := godwarf.GetDebugSectionMacho(exe, "info")
  1915  	if err != nil {
  1916  		return err
  1917  	}
  1918  
  1919  	image.dwarfReader = image.dwarf.Reader()
  1920  
  1921  	debugLineBytes, err := godwarf.GetDebugSectionMacho(exe, "line")
  1922  	if err != nil {
  1923  		return err
  1924  	}
  1925  	debugLocBytes, _ := godwarf.GetDebugSectionMacho(exe, "loc")
  1926  	image.loclist2 = loclist.NewDwarf2Reader(debugLocBytes, bi.Arch.PtrSize())
  1927  	debugLoclistBytes, _ := godwarf.GetDebugSectionMacho(exe, "loclists")
  1928  	image.loclist5 = loclist.NewDwarf5Reader(debugLoclistBytes)
  1929  	debugAddrBytes, _ := godwarf.GetDebugSectionMacho(exe, "addr")
  1930  	image.debugAddr = godwarf.ParseAddr(debugAddrBytes)
  1931  	debugLineStrBytes, _ := godwarf.GetDebugSectionMacho(exe, "line_str")
  1932  	image.debugLineStr = debugLineStrBytes
  1933  
  1934  	wg.Add(2)
  1935  	go bi.parseDebugFrameMacho(image, exe, debugInfoBytes, wg)
  1936  	go bi.loadDebugInfoMaps(image, debugInfoBytes, debugLineBytes, wg, bi.setGStructOffsetMacho)
  1937  	return nil
  1938  }
  1939  
  1940  func (bi *BinaryInfo) setGStructOffsetMacho() {
  1941  	// In go1.11 it's 0x30, before 0x8a0, see:
  1942  	// https://github.com/golang/go/issues/23617
  1943  	// and go commit b3a854c733257c5249c3435ffcee194f8439676a
  1944  	producer := bi.Producer()
  1945  	if producer != "" && goversion.ProducerAfterOrEqual(producer, 1, 11) {
  1946  		bi.gStructOffset = 0x30
  1947  		return
  1948  	}
  1949  	bi.gStructOffset = 0x8a0
  1950  }
  1951  
  1952  func (bi *BinaryInfo) parseDebugFrameMacho(image *Image, exe *macho.File, debugInfoBytes []byte, wg *sync.WaitGroup) {
  1953  	defer wg.Done()
  1954  
  1955  	debugFrameBytes, debugFrameErr := godwarf.GetDebugSectionMacho(exe, "frame")
  1956  	ehFrameSection := exe.Section("__eh_frame")
  1957  	var ehFrameBytes []byte
  1958  	var ehFrameAddr uint64
  1959  	if ehFrameSection != nil {
  1960  		ehFrameAddr = ehFrameSection.Addr
  1961  		ehFrameBytes, _ = ehFrameSection.Data()
  1962  	}
  1963  
  1964  	bi.parseDebugFrameGeneral(image, debugFrameBytes, "__debug_frame", debugFrameErr, ehFrameBytes, ehFrameAddr, "__eh_frame", frame.DwarfEndian(debugInfoBytes))
  1965  }
  1966  
  1967  // macOSDebugFrameBugWorkaround applies a workaround for [golang/go#25841]
  1968  //
  1969  // It finds the Go function with the lowest entry point and the first
  1970  // debug_frame FDE, calculates the difference between the start of the
  1971  // function and the start of the FDE and sums it to all debug_frame FDEs.
  1972  // A number of additional checks are performed to make sure we don't ruin
  1973  // executables unaffected by this bug.
  1974  //
  1975  // [golang/go#25841]: https://github.com/golang/go/issues/25841
  1976  func (bi *BinaryInfo) macOSDebugFrameBugWorkaround() {
  1977  	if bi.GOOS != "darwin" {
  1978  		return
  1979  	}
  1980  	if len(bi.Images) > 1 {
  1981  		// Only do this for the first executable, but it might work for plugins as
  1982  		// well if we had a way to distinguish where entries in bi.frameEntries
  1983  		// come from
  1984  		return
  1985  	}
  1986  	exe, ok := bi.Images[0].closer.(*macho.File)
  1987  	if !ok {
  1988  		return
  1989  	}
  1990  	if bi.Arch.Name == "arm64" {
  1991  		if exe.Flags&macho.FlagPIE == 0 {
  1992  			bi.logger.Infof("debug_frame workaround not needed: not a PIE (%#x)", exe.Flags)
  1993  			return
  1994  		}
  1995  	} else {
  1996  		prod := goversion.ParseProducer(bi.Producer())
  1997  		if !prod.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 19, Rev: 3}) && !prod.IsDevel() {
  1998  			bi.logger.Infof("debug_frame workaround not needed (version %q on %s)", bi.Producer(), bi.Arch.Name)
  1999  			return
  2000  		}
  2001  		found := false
  2002  		for i := range bi.frameEntries {
  2003  			if bi.frameEntries[i].CIE.CIE_id == ^uint32(0) && bi.frameEntries[i].Begin() < 0x4000000 {
  2004  				found = true
  2005  				break
  2006  			}
  2007  		}
  2008  		if !found {
  2009  			bi.logger.Infof("debug_frame workaround not needed (all FDEs above 0x4000000)")
  2010  			return
  2011  		}
  2012  	}
  2013  
  2014  	// Find first Go function (first = lowest entry point)
  2015  	var fn *Function
  2016  	for i := range bi.Functions {
  2017  		if bi.Functions[i].cu.isgo && bi.Functions[i].Entry > 0 {
  2018  			fn = &bi.Functions[i]
  2019  			break
  2020  		}
  2021  	}
  2022  	if fn == nil {
  2023  		bi.logger.Warn("debug_frame workaround not applied: could not find a Go function")
  2024  		return
  2025  	}
  2026  
  2027  	if fde, _ := bi.frameEntries.FDEForPC(fn.Entry); fde != nil {
  2028  		// Function is covered, no need to apply workaround
  2029  		bi.logger.Warnf("debug_frame workaround not applied: function %s (at %#x) covered by %#x-%#x", fn.Name, fn.Entry, fde.Begin(), fde.End())
  2030  		return
  2031  	}
  2032  
  2033  	// Find lowest FDE in debug_frame
  2034  	var fde *frame.FrameDescriptionEntry
  2035  	for i := range bi.frameEntries {
  2036  		if bi.frameEntries[i].CIE.CIE_id == ^uint32(0) {
  2037  			fde = bi.frameEntries[i]
  2038  			break
  2039  		}
  2040  	}
  2041  
  2042  	if fde == nil {
  2043  		bi.logger.Warnf("debug_frame workaround not applied because there are no debug_frame entries (%d)", len(bi.frameEntries))
  2044  		return
  2045  	}
  2046  
  2047  	fnsize := fn.End - fn.Entry
  2048  
  2049  	if fde.End()-fde.Begin() != fnsize || fde.Begin() > fn.Entry {
  2050  		bi.logger.Warnf("debug_frame workaround not applied: function %s (at %#x-%#x) has a different size than the first FDE (%#x-%#x) (or the FDE starts after the function)", fn.Name, fn.Entry, fn.End, fde.Begin(), fde.End())
  2051  		return
  2052  	}
  2053  
  2054  	delta := fn.Entry - fde.Begin()
  2055  
  2056  	bi.logger.Infof("applying debug_frame workaround +%#x: function %s (at %#x-%#x) and FDE %#x-%#x", delta, fn.Name, fn.Entry, fn.End, fde.Begin(), fde.End())
  2057  
  2058  	for i := range bi.frameEntries {
  2059  		if bi.frameEntries[i].CIE.CIE_id == ^uint32(0) {
  2060  			bi.frameEntries[i].Translate(delta)
  2061  		}
  2062  	}
  2063  }
  2064  
  2065  // GO RUNTIME INFO ////////////////////////////////////////////////////////////
  2066  
  2067  // loadBinaryInfoGoRuntimeElf loads information from the Go runtime sections
  2068  // of an ELF binary, it is only called when debug info has been stripped.
  2069  func loadBinaryInfoGoRuntimeElf(bi *BinaryInfo, image *Image, path string, elfFile *elf.File) (err error) {
  2070  	// This is a best-effort procedure, it can go wrong in unexpected ways, so
  2071  	// recover all panics.
  2072  	defer func() {
  2073  		ierr := recover()
  2074  		if ierr != nil {
  2075  			err = fmt.Errorf("error loading binary info from Go runtime: %v", ierr)
  2076  		}
  2077  	}()
  2078  
  2079  	cu := &compileUnit{}
  2080  	cu.image = image
  2081  	symTable, symTabAddr, err := readPcLnTableElf(elfFile, path)
  2082  	if err != nil {
  2083  		return err
  2084  	}
  2085  	image.symTable = symTable
  2086  	noPtrSectionData, err := elfFile.Section(".noptrdata").Data()
  2087  	if err != nil {
  2088  		return err
  2089  	}
  2090  	md, err := parseModuleData(noPtrSectionData, symTabAddr)
  2091  	if err != nil {
  2092  		return err
  2093  	}
  2094  	roDataAddr := elfFile.Section(".rodata").Addr
  2095  	goFuncVal, err := findGoFuncVal(md, roDataAddr, bi.Arch.ptrSize)
  2096  	if err != nil {
  2097  		return err
  2098  	}
  2099  	prog := gosym.ProgContaining(elfFile, goFuncVal)
  2100  	var progAddr uint64
  2101  	var progReaderAt io.ReaderAt
  2102  	if prog != nil {
  2103  		progAddr = prog.Vaddr
  2104  		progReaderAt = prog.ReaderAt
  2105  	}
  2106  	return loadBinaryInfoGoRuntimeCommon(bi, image, cu, goFuncVal, progAddr, progReaderAt)
  2107  }
  2108  
  2109  // loadBinaryInfoGoRuntimeMacho loads information from the Go runtime sections
  2110  // of an Macho-o binary, it is only called when debug info has been stripped.
  2111  func loadBinaryInfoGoRuntimeMacho(bi *BinaryInfo, image *Image, path string, exe *macho.File) (err error) {
  2112  	// This is a best-effort procedure, it can go wrong in unexpected ways, so
  2113  	// recover all panics.
  2114  	defer func() {
  2115  		ierr := recover()
  2116  		if ierr != nil {
  2117  			err = fmt.Errorf("error loading binary info from Go runtime: %v", ierr)
  2118  		}
  2119  	}()
  2120  
  2121  	cu := &compileUnit{}
  2122  	cu.image = image
  2123  	symTable, symTabAddr, err := readPcLnTableMacho(exe, path)
  2124  	if err != nil {
  2125  		return err
  2126  	}
  2127  	image.symTable = symTable
  2128  	noPtrSectionData, err := exe.Section("__noptrdata").Data()
  2129  	if err != nil {
  2130  		return err
  2131  	}
  2132  	md, err := parseModuleData(noPtrSectionData, symTabAddr)
  2133  	if err != nil {
  2134  		return err
  2135  	}
  2136  	roDataAddr := exe.Section("__rodata").Addr
  2137  	goFuncVal, err := findGoFuncVal(md, roDataAddr, bi.Arch.ptrSize)
  2138  	if err != nil {
  2139  		return err
  2140  	}
  2141  	seg := gosym.SegmentContaining(exe, goFuncVal)
  2142  	var segAddr uint64
  2143  	var segReaderAt io.ReaderAt
  2144  	if seg != nil {
  2145  		segAddr = seg.Addr
  2146  		segReaderAt = seg.ReaderAt
  2147  	}
  2148  	return loadBinaryInfoGoRuntimeCommon(bi, image, cu, goFuncVal, segAddr, segReaderAt)
  2149  }
  2150  
  2151  func loadBinaryInfoGoRuntimeCommon(bi *BinaryInfo, image *Image, cu *compileUnit, goFuncVal uint64, goFuncSegAddr uint64, goFuncReader io.ReaderAt) error {
  2152  	inlFuncs := make(map[string]*Function)
  2153  	for _, f := range image.symTable.Funcs {
  2154  		fnEntry := f.Entry + image.StaticBase
  2155  		if goFuncReader != nil {
  2156  			inlCalls, err := image.symTable.GetInlineTree(&f, goFuncVal, goFuncSegAddr, goFuncReader)
  2157  			if err != nil {
  2158  				return err
  2159  			}
  2160  			for _, inlfn := range inlCalls {
  2161  				newInlinedCall := InlinedCall{cu: cu, LowPC: fnEntry + uint64(inlfn.ParentPC)}
  2162  				if fn, ok := inlFuncs[inlfn.Name]; ok {
  2163  					fn.InlinedCalls = append(fn.InlinedCalls, newInlinedCall)
  2164  					continue
  2165  				}
  2166  				inlFuncs[inlfn.Name] = &Function{
  2167  					Name:  inlfn.Name,
  2168  					Entry: 0, End: 0,
  2169  					cu: cu,
  2170  					InlinedCalls: []InlinedCall{
  2171  						newInlinedCall,
  2172  					},
  2173  				}
  2174  			}
  2175  		}
  2176  		fn := Function{Name: f.Name, Entry: fnEntry, End: f.End + image.StaticBase, cu: cu}
  2177  		bi.Functions = append(bi.Functions, fn)
  2178  	}
  2179  	for i := range inlFuncs {
  2180  		bi.Functions = append(bi.Functions, *inlFuncs[i])
  2181  	}
  2182  	sort.Sort(functionsDebugInfoByEntry(bi.Functions))
  2183  	for f := range image.symTable.Files {
  2184  		bi.Sources = append(bi.Sources, f)
  2185  	}
  2186  	sort.Strings(bi.Sources)
  2187  	bi.Sources = uniq(bi.Sources)
  2188  	return nil
  2189  }
  2190  
  2191  // Do not call this function directly it isn't able to deal correctly with package paths
  2192  func (bi *BinaryInfo) findType(name string) (godwarf.Type, error) {
  2193  	name = strings.ReplaceAll(name, "interface{", "interface {")
  2194  	name = strings.ReplaceAll(name, "struct{", "struct {")
  2195  	ref, found := bi.types[name]
  2196  	if !found {
  2197  		return nil, reader.ErrTypeNotFound
  2198  	}
  2199  	image := bi.Images[ref.imageIndex]
  2200  	return godwarf.ReadType(image.dwarf, ref.imageIndex, ref.offset, image.typeCache)
  2201  }
  2202  
  2203  func (bi *BinaryInfo) findTypeExpr(expr ast.Expr) (godwarf.Type, error) {
  2204  	if lit, islit := expr.(*ast.BasicLit); islit && lit.Kind == token.STRING {
  2205  		// Allow users to specify type names verbatim as quoted
  2206  		// string. Useful as a catch-all workaround for cases where we don't
  2207  		// parse/serialize types correctly or can not resolve package paths.
  2208  		typn, _ := strconv.Unquote(lit.Value)
  2209  
  2210  		// Check if the type in question is an array type, in which case we try to
  2211  		// fake it.
  2212  		if len(typn) > 0 && typn[0] == '[' {
  2213  			closedBrace := strings.Index(typn, "]")
  2214  			if closedBrace > 1 {
  2215  				n, err := strconv.Atoi(typn[1:closedBrace])
  2216  				if err == nil {
  2217  					return bi.findArrayType(n, typn[closedBrace+1:])
  2218  				}
  2219  			}
  2220  		}
  2221  		return bi.findType(typn)
  2222  	}
  2223  	bi.expandPackagesInType(expr)
  2224  	if snode, ok := expr.(*ast.StarExpr); ok {
  2225  		// Pointer types only appear in the dwarf information when
  2226  		// a pointer to the type is used in the target program, here
  2227  		// we create a pointer type on the fly so that the user can
  2228  		// specify a pointer to any variable used in the target program
  2229  		ptyp, err := bi.findTypeExpr(snode.X)
  2230  		if err != nil {
  2231  			return nil, err
  2232  		}
  2233  		return pointerTo(ptyp, bi.Arch), nil
  2234  	}
  2235  	if anode, ok := expr.(*ast.ArrayType); ok {
  2236  		// Array types (for example [N]byte) are only present in DWARF if they are
  2237  		// used by the program, but it's convenient to make all of them available
  2238  		// to the user for two reasons:
  2239  		// 1. to allow reading arbitrary memory byte-by-byte (by casting an
  2240  		//    address to an array of bytes).
  2241  		// 2. to read the contents of a channel's buffer (we create fake array
  2242  		//    types for them)
  2243  
  2244  		alen, litlen := anode.Len.(*ast.BasicLit)
  2245  		if litlen && alen.Kind == token.INT {
  2246  			n, _ := strconv.Atoi(alen.Value)
  2247  			return bi.findArrayType(n, exprToString(anode.Elt))
  2248  		}
  2249  	}
  2250  	return bi.findType(exprToString(expr))
  2251  }
  2252  
  2253  func (bi *BinaryInfo) findArrayType(n int, etyp string) (godwarf.Type, error) {
  2254  	switch etyp {
  2255  	case "byte", "uint8":
  2256  		etyp = "uint8"
  2257  		fallthrough
  2258  	default:
  2259  		btyp, err := bi.findType(etyp)
  2260  		if err != nil {
  2261  			return nil, err
  2262  		}
  2263  		return fakeArrayType(uint64(n), btyp), nil
  2264  	}
  2265  }
  2266  
  2267  func complexType(typename string) bool {
  2268  	for _, ch := range typename {
  2269  		switch ch {
  2270  		case '*', '[', '<', '{', '(', ' ':
  2271  			return true
  2272  		}
  2273  	}
  2274  	return false
  2275  }
  2276  
  2277  func (bi *BinaryInfo) registerTypeToPackageMap(entry *dwarf.Entry) {
  2278  	if entry.Tag != dwarf.TagTypedef && entry.Tag != dwarf.TagBaseType && entry.Tag != dwarf.TagClassType && entry.Tag != dwarf.TagStructType {
  2279  		return
  2280  	}
  2281  
  2282  	typename, ok := entry.Val(dwarf.AttrName).(string)
  2283  	if !ok || complexType(typename) {
  2284  		return
  2285  	}
  2286  
  2287  	dot := strings.LastIndex(typename, ".")
  2288  	if dot < 0 {
  2289  		return
  2290  	}
  2291  	path := typename[:dot]
  2292  	slash := strings.LastIndex(path, "/")
  2293  	if slash < 0 || slash+1 >= len(path) {
  2294  		return
  2295  	}
  2296  	name := path[slash+1:]
  2297  	bi.PackageMap[name] = []string{path}
  2298  }
  2299  
  2300  func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugInfoBytes, debugLineBytes []byte, wg *sync.WaitGroup, cont func()) {
  2301  	if wg != nil {
  2302  		defer wg.Done()
  2303  	}
  2304  
  2305  	if bi.types == nil {
  2306  		bi.types = make(map[string]dwarfRef)
  2307  	}
  2308  	if bi.consts == nil {
  2309  		bi.consts = make(map[dwarfRef]*constantType)
  2310  	}
  2311  	if bi.PackageMap == nil {
  2312  		bi.PackageMap = make(map[string][]string)
  2313  	}
  2314  	if bi.inlinedCallLines == nil {
  2315  		bi.inlinedCallLines = make(map[fileLine][]uint64)
  2316  	}
  2317  	if bi.dwrapUnwrapCache == nil {
  2318  		bi.dwrapUnwrapCache = make(map[uint64]*Function)
  2319  	}
  2320  
  2321  	image.runtimeTypeToDIE = make(map[uint64]runtimeTypeDIE)
  2322  
  2323  	ctxt := newLoadDebugInfoMapsContext(bi, image, pdwarf.ReadUnitVersions(debugInfoBytes))
  2324  
  2325  	reader := image.DwarfReader()
  2326  
  2327  	for {
  2328  		entry, err := reader.Next()
  2329  		if err != nil {
  2330  			image.setLoadError(bi.logger, "error reading debug_info: %v", err)
  2331  			break
  2332  		}
  2333  		if entry == nil {
  2334  			break
  2335  		}
  2336  		switch entry.Tag {
  2337  		case dwarf.TagCompileUnit:
  2338  			cu := &compileUnit{}
  2339  			cu.image = image
  2340  			cu.entry = entry
  2341  			cu.offset = entry.Offset
  2342  			cu.Version = ctxt.offsetToVersion[cu.offset]
  2343  			if lang, _ := entry.Val(dwarf.AttrLanguage).(int64); lang == dwarfGoLanguage {
  2344  				cu.isgo = true
  2345  			}
  2346  			cu.name, _ = entry.Val(dwarf.AttrName).(string)
  2347  			compdir, _ := entry.Val(dwarf.AttrCompDir).(string)
  2348  			if compdir != "" {
  2349  				cu.name = filepath.Join(compdir, cu.name)
  2350  			}
  2351  			cu.ranges, _ = image.dwarf.Ranges(entry)
  2352  			for i := range cu.ranges {
  2353  				cu.ranges[i][0] += image.StaticBase
  2354  				cu.ranges[i][1] += image.StaticBase
  2355  			}
  2356  			if len(cu.ranges) >= 1 {
  2357  				cu.lowPC = cu.ranges[0][0]
  2358  			}
  2359  			lineInfoOffset, hasLineInfo := entry.Val(dwarf.AttrStmtList).(int64)
  2360  			if hasLineInfo && lineInfoOffset >= 0 && lineInfoOffset < int64(len(debugLineBytes)) {
  2361  				var logfn func(string, ...interface{})
  2362  				if logflags.DebugLineErrors() {
  2363  					logfn = logflags.DebugLineLogger().Debugf
  2364  				}
  2365  				cu.lineInfo = line.Parse(compdir, bytes.NewBuffer(debugLineBytes[lineInfoOffset:]), image.debugLineStr, logfn, image.StaticBase, bi.GOOS == "windows", bi.Arch.PtrSize())
  2366  			}
  2367  			cu.producer, _ = entry.Val(dwarf.AttrProducer).(string)
  2368  			if cu.isgo && cu.producer != "" {
  2369  				semicolon := strings.Index(cu.producer, ";")
  2370  				if semicolon < 0 {
  2371  					cu.optimized = goversion.ProducerAfterOrEqual(cu.producer, 1, 10)
  2372  				} else {
  2373  					cu.optimized = !strings.Contains(cu.producer[semicolon:], "-N") || !strings.Contains(cu.producer[semicolon:], "-l")
  2374  					const regabi = " regabi"
  2375  					if i := strings.Index(cu.producer[semicolon:], regabi); i > 0 {
  2376  						i += semicolon
  2377  						if i+len(regabi) >= len(cu.producer) || cu.producer[i+len(regabi)] == ' ' {
  2378  							bi.regabi = true
  2379  						}
  2380  					}
  2381  					cu.producer = cu.producer[:semicolon]
  2382  				}
  2383  			}
  2384  			gopkg, _ := entry.Val(godwarf.AttrGoPackageName).(string)
  2385  			if cu.isgo && gopkg != "" {
  2386  				bi.PackageMap[gopkg] = append(bi.PackageMap[gopkg], escapePackagePath(strings.ReplaceAll(cu.name, "\\", "/")))
  2387  			}
  2388  			image.compileUnits = append(image.compileUnits, cu)
  2389  			if entry.Children {
  2390  				bi.loadDebugInfoMapsCompileUnit(ctxt, image, reader, cu)
  2391  			}
  2392  
  2393  		case dwarf.TagPartialUnit:
  2394  			reader.SkipChildren()
  2395  
  2396  		default:
  2397  			// ignore unknown tags
  2398  			reader.SkipChildren()
  2399  		}
  2400  	}
  2401  
  2402  	sort.Sort(compileUnitsByOffset(image.compileUnits))
  2403  	sort.Sort(functionsDebugInfoByEntry(bi.Functions))
  2404  	sort.Sort(packageVarsByAddr(bi.packageVars))
  2405  
  2406  	bi.lookupFunc = nil
  2407  	bi.lookupGenericFunc = nil
  2408  
  2409  	for _, cu := range image.compileUnits {
  2410  		if cu.lineInfo != nil {
  2411  			for _, fileEntry := range cu.lineInfo.FileNames {
  2412  				bi.Sources = append(bi.Sources, fileEntry.Path)
  2413  			}
  2414  		}
  2415  	}
  2416  	sort.Strings(bi.Sources)
  2417  	bi.Sources = uniq(bi.Sources)
  2418  
  2419  	if cont != nil {
  2420  		cont()
  2421  	}
  2422  }
  2423  
  2424  // LookupGenericFunc returns a map that allows searching for instantiations of generic function by specifying a function name without type parameters.
  2425  // For example the key "pkg.(*Receiver).Amethod" will find all instantiations of Amethod:
  2426  //   - pkg.(*Receiver[.shape.int]).Amethod
  2427  //   - pkg.(*Receiver[.shape.*uint8]).Amethod
  2428  //   - etc.
  2429  func (bi *BinaryInfo) LookupGenericFunc() map[string][]*Function {
  2430  	if bi.lookupGenericFunc == nil {
  2431  		bi.lookupGenericFunc = make(map[string][]*Function)
  2432  		for i := range bi.Functions {
  2433  			dn := bi.Functions[i].NameWithoutTypeParams()
  2434  			if dn != bi.Functions[i].Name {
  2435  				bi.lookupGenericFunc[dn] = append(bi.lookupGenericFunc[dn], &bi.Functions[i])
  2436  			}
  2437  		}
  2438  	}
  2439  	return bi.lookupGenericFunc
  2440  }
  2441  
  2442  func (bi *BinaryInfo) LookupFunc() map[string][]*Function {
  2443  	if bi.lookupFunc == nil {
  2444  		bi.lookupFunc = make(map[string][]*Function)
  2445  		for i := range bi.Functions {
  2446  			name := bi.Functions[i].Name
  2447  			bi.lookupFunc[name] = append(bi.lookupFunc[name], &bi.Functions[i])
  2448  		}
  2449  	}
  2450  	return bi.lookupFunc
  2451  }
  2452  
  2453  func (bi *BinaryInfo) lookupOneFunc(name string) *Function {
  2454  	fns := bi.LookupFunc()[name]
  2455  	if fns == nil {
  2456  		return nil
  2457  	}
  2458  	return fns[0]
  2459  }
  2460  
  2461  // loadDebugInfoMapsCompileUnit loads entry from a single compile unit.
  2462  func (bi *BinaryInfo) loadDebugInfoMapsCompileUnit(ctxt *loadDebugInfoMapsContext, image *Image, reader *reader.Reader, cu *compileUnit) {
  2463  	hasAttrGoPkgName := goversion.ProducerAfterOrEqual(cu.producer, 1, 13)
  2464  
  2465  	depth := 0
  2466  
  2467  	for {
  2468  		entry, err := reader.Next()
  2469  		if err != nil {
  2470  			image.setLoadError(bi.logger, "error reading debug_info: %v", err)
  2471  			return
  2472  		}
  2473  		if entry == nil {
  2474  			break
  2475  		}
  2476  		switch entry.Tag {
  2477  		case 0:
  2478  			if depth == 0 {
  2479  				return
  2480  			} else {
  2481  				depth--
  2482  			}
  2483  		case dwarf.TagImportedUnit:
  2484  			bi.loadDebugInfoMapsImportedUnit(entry, ctxt, image, cu)
  2485  			reader.SkipChildren()
  2486  
  2487  		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:
  2488  			if name, ok := entry.Val(dwarf.AttrName).(string); ok {
  2489  				if !cu.isgo {
  2490  					name = "C." + name
  2491  				}
  2492  				if _, exists := bi.types[name]; !exists {
  2493  					bi.types[name] = dwarfRef{image.index, entry.Offset}
  2494  				}
  2495  			}
  2496  			if cu != nil && cu.isgo && !hasAttrGoPkgName {
  2497  				bi.registerTypeToPackageMap(entry)
  2498  			}
  2499  			image.registerRuntimeTypeToDIE(entry, ctxt.ardr)
  2500  			reader.SkipChildren()
  2501  
  2502  		case dwarf.TagVariable:
  2503  			if n, ok := entry.Val(dwarf.AttrName).(string); ok {
  2504  				var addr uint64
  2505  				if loc, ok := entry.Val(dwarf.AttrLocation).([]byte); ok {
  2506  					if len(loc) == bi.Arch.PtrSize()+1 && op.Opcode(loc[0]) == op.DW_OP_addr {
  2507  						addr, _ = pdwarf.ReadUintRaw(bytes.NewReader(loc[1:]), binary.LittleEndian, bi.Arch.PtrSize())
  2508  					}
  2509  				}
  2510  				if !cu.isgo {
  2511  					n = "C." + n
  2512  				}
  2513  				if _, known := ctxt.knownPackageVars[n]; !known {
  2514  					bi.packageVars = append(bi.packageVars, packageVar{n, cu, entry.Offset, addr + image.StaticBase})
  2515  				}
  2516  			}
  2517  			reader.SkipChildren()
  2518  
  2519  		case dwarf.TagConstant:
  2520  			name, okName := entry.Val(dwarf.AttrName).(string)
  2521  			typ, okType := entry.Val(dwarf.AttrType).(dwarf.Offset)
  2522  			val, okVal := entry.Val(dwarf.AttrConstValue).(int64)
  2523  			if okName && okType && okVal {
  2524  				if !cu.isgo {
  2525  					name = "C." + name
  2526  				}
  2527  				ct := bi.consts[dwarfRef{image.index, typ}]
  2528  				if ct == nil {
  2529  					ct = &constantType{}
  2530  					bi.consts[dwarfRef{image.index, typ}] = ct
  2531  				}
  2532  				ct.values = append(ct.values, constantValue{name: name, fullName: name, value: val})
  2533  			}
  2534  			reader.SkipChildren()
  2535  
  2536  		case dwarf.TagSubprogram:
  2537  			inlined := false
  2538  			if inval, ok := entry.Val(dwarf.AttrInline).(int64); ok {
  2539  				inlined = inval >= 1
  2540  			}
  2541  
  2542  			if inlined {
  2543  				bi.addAbstractSubprogram(entry, ctxt, reader, image, cu)
  2544  			} else {
  2545  				originOffset, hasAbstractOrigin := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
  2546  				if hasAbstractOrigin {
  2547  					bi.addConcreteInlinedSubprogram(entry, originOffset, ctxt, reader, cu)
  2548  				} else {
  2549  					bi.addConcreteSubprogram(entry, ctxt, reader, cu)
  2550  				}
  2551  			}
  2552  
  2553  		default:
  2554  			if entry.Children {
  2555  				depth++
  2556  			}
  2557  		}
  2558  	}
  2559  }
  2560  
  2561  // loadDebugInfoMapsImportedUnit loads entries into cu from the partial unit
  2562  // referenced in a DW_TAG_imported_unit entry.
  2563  func (bi *BinaryInfo) loadDebugInfoMapsImportedUnit(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, image *Image, cu *compileUnit) {
  2564  	off, ok := entry.Val(dwarf.AttrImport).(dwarf.Offset)
  2565  	if !ok {
  2566  		return
  2567  	}
  2568  	reader := image.DwarfReader()
  2569  	reader.Seek(off)
  2570  	imentry, err := reader.Next()
  2571  	if err != nil {
  2572  		return
  2573  	}
  2574  	if imentry.Tag != dwarf.TagPartialUnit {
  2575  		return
  2576  	}
  2577  	bi.loadDebugInfoMapsCompileUnit(ctxt, image, reader, cu)
  2578  }
  2579  
  2580  // addAbstractSubprogram adds the abstract entry for an inlined function.
  2581  func (bi *BinaryInfo) addAbstractSubprogram(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, reader *reader.Reader, image *Image, cu *compileUnit) {
  2582  	name, ok := subprogramEntryName(entry, cu)
  2583  	if !ok {
  2584  		bi.logger.Warnf("reading debug_info: abstract subprogram without name at %#x", entry.Offset)
  2585  		// In some cases clang produces abstract subprograms that do not have a
  2586  		// name, but we should process them anyway.
  2587  	}
  2588  
  2589  	if entry.Children {
  2590  		bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
  2591  	}
  2592  
  2593  	originIdx := ctxt.lookupAbstractOrigin(bi, entry.Offset)
  2594  	fn := &bi.Functions[originIdx]
  2595  	fn.Name = name
  2596  	fn.offset = entry.Offset
  2597  	fn.cu = cu
  2598  }
  2599  
  2600  // addConcreteInlinedSubprogram adds the concrete entry of a subprogram that was also inlined.
  2601  func (bi *BinaryInfo) addConcreteInlinedSubprogram(entry *dwarf.Entry, originOffset dwarf.Offset, ctxt *loadDebugInfoMapsContext, reader *reader.Reader, cu *compileUnit) {
  2602  	lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
  2603  	if !ok {
  2604  		bi.logger.Warnf("reading debug_info: concrete inlined subprogram without address range at %#x", entry.Offset)
  2605  		if entry.Children {
  2606  			reader.SkipChildren()
  2607  		}
  2608  		return
  2609  	}
  2610  
  2611  	originIdx := ctxt.lookupAbstractOrigin(bi, originOffset)
  2612  	fn := &bi.Functions[originIdx]
  2613  	fn.offset = entry.Offset
  2614  	fn.Entry = lowpc
  2615  	fn.End = highpc
  2616  	fn.cu = cu
  2617  
  2618  	if entry.Children {
  2619  		bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
  2620  	}
  2621  }
  2622  
  2623  // addConcreteSubprogram adds a concrete subprogram (a normal subprogram
  2624  // that doesn't have abstract or inlined entries)
  2625  func (bi *BinaryInfo) addConcreteSubprogram(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, reader *reader.Reader, cu *compileUnit) {
  2626  	lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
  2627  	if !ok {
  2628  		bi.logger.Warnf("reading debug_info: concrete subprogram without address range at %#x", entry.Offset)
  2629  		// When clang inlines a function, in some cases, it produces a concrete
  2630  		// subprogram without address range and then inlined calls that reference
  2631  		// it, instead of producing an abstract subprogram.
  2632  		// It is unclear if this behavior is standard.
  2633  	}
  2634  
  2635  	name, ok := subprogramEntryName(entry, cu)
  2636  	if !ok {
  2637  		bi.logger.Warnf("reading debug_info: concrete subprogram without name at %#x", entry.Offset)
  2638  	}
  2639  
  2640  	trampoline, _ := entry.Val(dwarf.AttrTrampoline).(bool)
  2641  
  2642  	originIdx := ctxt.lookupAbstractOrigin(bi, entry.Offset)
  2643  	fn := &bi.Functions[originIdx]
  2644  
  2645  	fn.Name = name
  2646  	fn.Entry = lowpc
  2647  	fn.End = highpc
  2648  	fn.offset = entry.Offset
  2649  	fn.cu = cu
  2650  	fn.trampoline = trampoline
  2651  
  2652  	if entry.Children {
  2653  		bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
  2654  	}
  2655  }
  2656  
  2657  func subprogramEntryName(entry *dwarf.Entry, cu *compileUnit) (string, bool) {
  2658  	name, ok := entry.Val(dwarf.AttrName).(string)
  2659  	if !ok {
  2660  		return "", false
  2661  	}
  2662  	if !cu.isgo {
  2663  		name = "C." + name
  2664  	}
  2665  	return name, true
  2666  }
  2667  
  2668  func subprogramEntryRange(entry *dwarf.Entry, image *Image) (lowpc, highpc uint64, ok bool) {
  2669  	ok = false
  2670  	if ranges, _ := image.dwarf.Ranges(entry); len(ranges) >= 1 {
  2671  		ok = true
  2672  		lowpc = ranges[0][0] + image.StaticBase
  2673  		highpc = ranges[0][1] + image.StaticBase
  2674  	}
  2675  	return lowpc, highpc, ok
  2676  }
  2677  
  2678  func (bi *BinaryInfo) loadDebugInfoMapsInlinedCalls(ctxt *loadDebugInfoMapsContext, reader *reader.Reader, cu *compileUnit) {
  2679  	for {
  2680  		entry, err := reader.Next()
  2681  		if err != nil {
  2682  			cu.image.setLoadError(bi.logger, "error reading debug_info: %v", err)
  2683  			return
  2684  		}
  2685  		switch entry.Tag {
  2686  		case 0:
  2687  			return
  2688  		case dwarf.TagInlinedSubroutine:
  2689  			originOffset, ok := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
  2690  			if !ok {
  2691  				bi.logger.Warnf("reading debug_info: inlined call without origin offset at %#x", entry.Offset)
  2692  				reader.SkipChildren()
  2693  				continue
  2694  			}
  2695  
  2696  			lowpc, highpc, ok := subprogramEntryRange(entry, cu.image)
  2697  			if !ok {
  2698  				bi.logger.Warnf("reading debug_info: inlined call without address range at %#x", entry.Offset)
  2699  				reader.SkipChildren()
  2700  				continue
  2701  			}
  2702  
  2703  			callfileidx, ok1 := entry.Val(dwarf.AttrCallFile).(int64)
  2704  			callline, ok2 := entry.Val(dwarf.AttrCallLine).(int64)
  2705  			if !ok1 || !ok2 {
  2706  				bi.logger.Warnf("reading debug_info: inlined call without CallFile/CallLine at %#x", entry.Offset)
  2707  				reader.SkipChildren()
  2708  				continue
  2709  			}
  2710  			callfile, cferr := cu.filePath(int(callfileidx), entry)
  2711  			if cferr != nil {
  2712  				bi.logger.Warnf("%v", cferr)
  2713  				reader.SkipChildren()
  2714  				continue
  2715  			}
  2716  
  2717  			originIdx := ctxt.lookupAbstractOrigin(bi, originOffset)
  2718  			fn := &bi.Functions[originIdx]
  2719  
  2720  			fn.InlinedCalls = append(fn.InlinedCalls, InlinedCall{
  2721  				cu:     cu,
  2722  				LowPC:  lowpc,
  2723  				HighPC: highpc,
  2724  			})
  2725  
  2726  			if fn.cu == nil {
  2727  				fn.cu = cu
  2728  			}
  2729  
  2730  			fl := fileLine{callfile, int(callline)}
  2731  			bi.inlinedCallLines[fl] = append(bi.inlinedCallLines[fl], lowpc)
  2732  
  2733  			if entry.Children {
  2734  				bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu)
  2735  			}
  2736  		}
  2737  		reader.SkipChildren()
  2738  	}
  2739  }
  2740  
  2741  func uniq(s []string) []string {
  2742  	if len(s) == 0 {
  2743  		return s
  2744  	}
  2745  	src, dst := 1, 1
  2746  	for src < len(s) {
  2747  		if s[src] != s[dst-1] {
  2748  			s[dst] = s[src]
  2749  			dst++
  2750  		}
  2751  		src++
  2752  	}
  2753  	return s[:dst]
  2754  }
  2755  
  2756  func (bi *BinaryInfo) expandPackagesInType(expr ast.Expr) {
  2757  	switch e := expr.(type) {
  2758  	case *ast.ArrayType:
  2759  		bi.expandPackagesInType(e.Elt)
  2760  	case *ast.ChanType:
  2761  		bi.expandPackagesInType(e.Value)
  2762  	case *ast.FuncType:
  2763  		for i := range e.Params.List {
  2764  			bi.expandPackagesInType(e.Params.List[i].Type)
  2765  		}
  2766  		if e.Results != nil {
  2767  			for i := range e.Results.List {
  2768  				bi.expandPackagesInType(e.Results.List[i].Type)
  2769  			}
  2770  		}
  2771  	case *ast.MapType:
  2772  		bi.expandPackagesInType(e.Key)
  2773  		bi.expandPackagesInType(e.Value)
  2774  	case *ast.ParenExpr:
  2775  		bi.expandPackagesInType(e.X)
  2776  	case *ast.SelectorExpr:
  2777  		switch x := e.X.(type) {
  2778  		case *ast.Ident:
  2779  			if len(bi.PackageMap[x.Name]) > 0 {
  2780  				// There's no particular reason to expect the first entry to be the
  2781  				// correct one if the package name is ambiguous, but trying all possible
  2782  				// expansions of all types mentioned in the expression is complicated
  2783  				// and, besides type assertions, users can always specify the type they
  2784  				// want exactly, using a string.
  2785  				x.Name = bi.PackageMap[x.Name][0]
  2786  			}
  2787  		default:
  2788  			bi.expandPackagesInType(e.X)
  2789  		}
  2790  	case *ast.StarExpr:
  2791  		bi.expandPackagesInType(e.X)
  2792  	default:
  2793  		// nothing to do
  2794  	}
  2795  }
  2796  
  2797  // escapePackagePath returns pkg with '.' replaced with '%2e' (in all
  2798  // elements of the path except the first one) like Go does in variable and
  2799  // type names.
  2800  func escapePackagePath(pkg string) string {
  2801  	slash := strings.Index(pkg, "/")
  2802  	if slash < 0 {
  2803  		slash = 0
  2804  	}
  2805  	return pkg[:slash] + strings.ReplaceAll(pkg[slash:], ".", "%2e")
  2806  }
  2807  
  2808  // Looks up symbol (either functions or global variables) at address addr.
  2809  // Used by disassembly formatter.
  2810  func (bi *BinaryInfo) symLookup(addr uint64) (string, uint64) {
  2811  	fn := bi.PCToFunc(addr)
  2812  	if fn != nil {
  2813  		if fn.Entry == addr {
  2814  			// only report the function name if it's the exact address because it's
  2815  			// easier to read the absolute address than function_name+offset.
  2816  			return fn.Name, fn.Entry
  2817  		}
  2818  		return "", 0
  2819  	}
  2820  	if sym, ok := bi.SymNames[addr]; ok {
  2821  		return sym.Name, addr
  2822  	}
  2823  	i := sort.Search(len(bi.packageVars), func(i int) bool {
  2824  		return bi.packageVars[i].addr >= addr
  2825  	})
  2826  	if i >= len(bi.packageVars) {
  2827  		return "", 0
  2828  	}
  2829  	if bi.packageVars[i].addr > addr {
  2830  		// report previous variable + offset if i-th variable starts after addr
  2831  		i--
  2832  	}
  2833  	if i >= 0 && bi.packageVars[i].addr != 0 {
  2834  		return bi.packageVars[i].name, bi.packageVars[i].addr
  2835  	}
  2836  	return "", 0
  2837  }
  2838  
  2839  type PackageBuildInfo struct {
  2840  	ImportPath    string
  2841  	DirectoryPath string
  2842  	Files         map[string]struct{}
  2843  }
  2844  
  2845  // ListPackagesBuildInfo returns the list of packages used by the program along with
  2846  // the directory where each package was compiled and optionally the list of
  2847  // files constituting the package.
  2848  func (bi *BinaryInfo) ListPackagesBuildInfo(includeFiles bool) []*PackageBuildInfo {
  2849  	m := make(map[string]*PackageBuildInfo)
  2850  	for _, cu := range bi.Images[0].compileUnits {
  2851  		if cu.image != bi.Images[0] || !cu.isgo || cu.lineInfo == nil {
  2852  			//TODO(aarzilli): what's the correct thing to do for plugins?
  2853  			continue
  2854  		}
  2855  
  2856  		ip := strings.ReplaceAll(cu.name, "\\", "/")
  2857  		if _, ok := m[ip]; !ok {
  2858  			path := cu.lineInfo.FirstFile()
  2859  			if ext := filepath.Ext(path); ext != ".go" && ext != ".s" {
  2860  				continue
  2861  			}
  2862  			dp := filepath.Dir(path)
  2863  			m[ip] = &PackageBuildInfo{
  2864  				ImportPath:    ip,
  2865  				DirectoryPath: dp,
  2866  				Files:         make(map[string]struct{}),
  2867  			}
  2868  		}
  2869  
  2870  		if includeFiles {
  2871  			pbi := m[ip]
  2872  
  2873  			for _, file := range cu.lineInfo.FileNames {
  2874  				pbi.Files[file.Path] = struct{}{}
  2875  			}
  2876  		}
  2877  	}
  2878  
  2879  	r := make([]*PackageBuildInfo, 0, len(m))
  2880  	for _, pbi := range m {
  2881  		r = append(r, pbi)
  2882  	}
  2883  
  2884  	sort.Slice(r, func(i, j int) bool { return r[i].ImportPath < r[j].ImportPath })
  2885  	return r
  2886  }
  2887  
  2888  // cuFilePath takes a compilation unit "cu" and a file index reference
  2889  // "fileidx" and returns the corresponding file name entry from the
  2890  // DWARF line table associated with the unit; "entry" is the offset of
  2891  // the attribute where the file reference originated, for logging
  2892  // purposes. Return value is the file string and an error value; error
  2893  // will be non-nil if the file could not be recovered, perhaps due to
  2894  // malformed DWARF.
  2895  func (cu *compileUnit) filePath(fileidx int, entry *dwarf.Entry) (string, error) {
  2896  	if cu.lineInfo == nil {
  2897  		return "", fmt.Errorf("reading debug_info: file reference within a compilation unit without debug_line section at %#x", entry.Offset)
  2898  	}
  2899  	// File numbering is slightly different before and after DWARF 5;
  2900  	// account for this here. See section 6.2.4 of the DWARF 5 spec.
  2901  	if cu.Version < 5 {
  2902  		fileidx--
  2903  	}
  2904  	if fileidx < 0 || fileidx >= len(cu.lineInfo.FileNames) {
  2905  		return "", fmt.Errorf("reading debug_info: file index (%d) out of range in compile unit file table at %#x", fileidx, entry.Offset)
  2906  	}
  2907  	return cu.lineInfo.FileNames[fileidx].Path, nil
  2908  }