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