github.com/ks888/tgo@v0.0.0-20190130135156-80bf89407292/tracee/binary.go (about)

     1  package tracee
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"sort"
    10  	"strings"
    11  	"unicode"
    12  
    13  	"github.com/ks888/tgo/log"
    14  )
    15  
    16  const (
    17  	// AttrVariableParameter is the extended DWARF attribute. If true, the parameter is output. Else, it's input.
    18  	attrVariableParameter = 0x4b
    19  	attrGoRuntimeType     = 0x2904 // DW_AT_go_runtime_type
    20  	dwarfOpCallFrameCFA   = 0x9c   // DW_OP_call_frame_cfa
    21  	dwarfOpFbreg          = 0x91   // DW_OP_fbreg
    22  )
    23  
    24  // BinaryFile represents the program the tracee process is executing.
    25  type BinaryFile interface {
    26  	// FindFunction returns the function info to which the given pc specifies.
    27  	FindFunction(pc uint64) (*Function, error)
    28  	// Close closes the binary file.
    29  	Close() error
    30  	// findDwarfTypeByAddr finds the dwarf.Type to which the given address specifies.
    31  	// The given address must be the address of the type (not value) and need to be adjusted
    32  	// using the moduledata.
    33  	findDwarfTypeByAddr(typeAddr uint64) (dwarf.Type, error)
    34  	// moduleDataType returns the dwarf.Type of runtime.moduledata struct type.
    35  	moduleDataType() dwarf.Type
    36  	// runtimeGType returns the dwarf.Type of runtime.g struct type.
    37  	runtimeGType() dwarf.Type
    38  }
    39  
    40  // debuggableBinaryFile represents the binary file with DWARF sections.
    41  type debuggableBinaryFile struct {
    42  	dwarf                dwarfData
    43  	closer               io.Closer
    44  	types                map[uint64]dwarf.Offset
    45  	cachedRuntimeGType   dwarf.Type
    46  	cachedModuleDataType dwarf.Type
    47  }
    48  
    49  type dwarfData struct {
    50  	*dwarf.Data
    51  	locationList []byte
    52  }
    53  
    54  // Function represents a function info in the debug info section.
    55  type Function struct {
    56  	Name string
    57  	// StartAddr is the start address of the function, inclusive.
    58  	StartAddr uint64
    59  	// EndAddr is the end address of the function, exclusive. 0 if unknown.
    60  	EndAddr uint64
    61  	// Parameters may be empty due to the lack of information.
    62  	Parameters []Parameter
    63  }
    64  
    65  // Parameter represents a parameter given to or the returned from the function.
    66  type Parameter struct {
    67  	Name string
    68  	Typ  dwarf.Type
    69  	// Offset is the offset from the beginning of the parameter list.
    70  	Offset int
    71  	// Exist is false when the parameter is removed due to the optimization.
    72  	Exist    bool
    73  	IsOutput bool
    74  }
    75  
    76  // OpenBinaryFile opens the specified program file.
    77  func OpenBinaryFile(pathToProgram string, goVersion GoVersion) (BinaryFile, error) {
    78  	return openBinaryFile(pathToProgram, goVersion)
    79  }
    80  
    81  func newDebuggableBinaryFile(data dwarfData, goVersion GoVersion, closer io.Closer) (debuggableBinaryFile, error) {
    82  	binary := debuggableBinaryFile{dwarf: data, closer: closer}
    83  
    84  	var err error
    85  	binary.types, err = binary.buildTypes(goVersion)
    86  	if err != nil {
    87  		return debuggableBinaryFile{}, err
    88  	}
    89  
    90  	binary.cachedModuleDataType, err = binary.findModuleDataType()
    91  	if err != nil {
    92  		return debuggableBinaryFile{}, err
    93  	}
    94  
    95  	binary.cachedRuntimeGType, err = binary.findRuntimeGType()
    96  	if err != nil {
    97  		return debuggableBinaryFile{}, err
    98  	}
    99  
   100  	return binary, nil
   101  }
   102  
   103  func (b debuggableBinaryFile) buildTypes(goVersion GoVersion) (map[uint64]dwarf.Offset, error) {
   104  	if !goVersion.LaterThan(GoVersion{MajorVersion: 1, MinorVersion: 11, PatchVersion: 0}) {
   105  		// attrGoRuntimeType is not supported
   106  		return nil, nil
   107  	}
   108  	types := make(map[uint64]dwarf.Offset)
   109  	reader := b.dwarf.Reader()
   110  	for {
   111  		entry, err := reader.Next()
   112  		if err != nil || entry == nil {
   113  			return types, err
   114  		}
   115  
   116  		switch entry.Tag {
   117  		case dwarf.TagArrayType, dwarf.TagPointerType, dwarf.TagStructType, dwarf.TagSubroutineType, dwarf.TagBaseType, dwarf.TagTypedef:
   118  			// based on the 'abbrevs' variable in src/cmd/internal/dwarf/dwarf.go. It indicates which tag types *may* have the DW_AT_go_runtime_type attribute.
   119  			val, err := addressClassAttr(entry, attrGoRuntimeType)
   120  			if err != nil || val == 0 {
   121  				break
   122  			}
   123  			types[val] = entry.Offset
   124  		}
   125  	}
   126  }
   127  
   128  const moduleDataTypeName = "runtime.moduledata"
   129  
   130  func (b debuggableBinaryFile) findModuleDataType() (dwarf.Type, error) {
   131  	return b.findType(dwarf.TagStructType, moduleDataTypeName)
   132  }
   133  
   134  const gTypeName = "runtime.g"
   135  
   136  func (b debuggableBinaryFile) findRuntimeGType() (dwarf.Type, error) {
   137  	return b.findType(dwarf.TagStructType, gTypeName)
   138  }
   139  
   140  func (b debuggableBinaryFile) findType(targetTag dwarf.Tag, targetName string) (dwarf.Type, error) {
   141  	entry, err := b.findDWARFEntryByName(func(entry *dwarf.Entry) bool {
   142  		if entry.Tag != targetTag {
   143  			return false
   144  		}
   145  		name, err := stringClassAttr(entry, dwarf.AttrName)
   146  		return name == targetName && err == nil
   147  	})
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	return b.dwarf.Type(entry.Offset)
   153  }
   154  
   155  func (b debuggableBinaryFile) findDWARFEntryByName(match func(*dwarf.Entry) bool) (*dwarf.Entry, error) {
   156  	reader := b.dwarf.Reader()
   157  	for {
   158  		entry, err := reader.Next()
   159  		if err != nil {
   160  			return nil, err
   161  		} else if entry == nil {
   162  			return nil, errors.New("failed to find a matched entry")
   163  		}
   164  
   165  		if match(entry) {
   166  			return entry, nil
   167  		}
   168  	}
   169  }
   170  
   171  // FindFunction looks up the function info described in the debug info section.
   172  func (b debuggableBinaryFile) FindFunction(pc uint64) (*Function, error) {
   173  	reader := subprogramReader{raw: b.dwarf.Reader(), dwarfData: b.dwarf}
   174  	return reader.Seek(pc)
   175  }
   176  
   177  // Close releases the resources associated with the binary.
   178  func (b debuggableBinaryFile) Close() error {
   179  	return b.closer.Close()
   180  }
   181  
   182  func (b debuggableBinaryFile) findDwarfTypeByAddr(typeAddr uint64) (dwarf.Type, error) {
   183  	implTypOffset := b.types[typeAddr]
   184  	return b.dwarf.Type(implTypOffset)
   185  }
   186  
   187  func (b debuggableBinaryFile) moduleDataType() dwarf.Type {
   188  	return b.cachedModuleDataType
   189  }
   190  
   191  func (b debuggableBinaryFile) runtimeGType() dwarf.Type {
   192  	return b.cachedRuntimeGType
   193  }
   194  
   195  // IsExported returns true if the function is exported.
   196  // See https://golang.org/ref/spec#Exported_identifiers for the spec.
   197  func (f Function) IsExported() bool {
   198  	elems := strings.Split(f.Name, ".")
   199  	for _, ch := range elems[len(elems)-1] {
   200  		return unicode.IsUpper(ch)
   201  	}
   202  	return false
   203  }
   204  
   205  type subprogramReader struct {
   206  	raw       *dwarf.Reader
   207  	dwarfData dwarfData
   208  }
   209  
   210  func (r subprogramReader) Next(setParameters bool) (*Function, error) {
   211  	for {
   212  		entry, err := r.raw.Next()
   213  		if err != nil || entry == nil {
   214  			return nil, err
   215  		}
   216  
   217  		if entry.Tag != dwarf.TagSubprogram || r.isInline(entry) {
   218  			continue
   219  		}
   220  
   221  		function, err := r.buildFunction(entry)
   222  		if err != nil {
   223  			return nil, err
   224  		}
   225  
   226  		if setParameters {
   227  			function.Parameters, err = r.parameters()
   228  		}
   229  		return function, err
   230  
   231  	}
   232  }
   233  
   234  func (r subprogramReader) Seek(pc uint64) (*Function, error) {
   235  	_, err := r.raw.SeekPC(pc)
   236  	if err != nil {
   237  		return nil, err
   238  	}
   239  
   240  	for {
   241  		subprogram, err := r.raw.Next()
   242  		if err != nil {
   243  			return nil, err
   244  		}
   245  		if subprogram == nil {
   246  			return nil, errors.New("subprogram not found")
   247  		}
   248  
   249  		if subprogram.Tag != dwarf.TagSubprogram || !r.includesPC(subprogram, pc) {
   250  			r.raw.SkipChildren()
   251  			continue
   252  		}
   253  
   254  		function, err := r.buildFunction(subprogram)
   255  		if err != nil {
   256  			return nil, err
   257  		}
   258  
   259  		function.Parameters, err = r.parameters()
   260  		return function, err
   261  	}
   262  }
   263  
   264  func (r subprogramReader) includesPC(subprogram *dwarf.Entry, pc uint64) bool {
   265  	lowPC, err := addressClassAttr(subprogram, dwarf.AttrLowpc)
   266  	if err != nil {
   267  		// inlined subprogram doesn't have the lowPC and highPC attributes.
   268  		return false
   269  	}
   270  
   271  	highPC, err := addressClassAttr(subprogram, dwarf.AttrHighpc)
   272  	if err != nil {
   273  		return false
   274  	}
   275  
   276  	if pc < lowPC || highPC <= pc {
   277  		return false
   278  	}
   279  	return true
   280  }
   281  
   282  func (r subprogramReader) isInline(subprogram *dwarf.Entry) bool {
   283  	return subprogram.AttrField(dwarf.AttrInline) != nil
   284  }
   285  
   286  func (r subprogramReader) buildFunction(subprogram *dwarf.Entry) (*Function, error) {
   287  	var name string
   288  	err := walkUpOrigins(subprogram, r.dwarfData.Data, func(entry *dwarf.Entry) bool {
   289  		var err error
   290  		name, err = stringClassAttr(entry, dwarf.AttrName)
   291  		return err == nil
   292  	})
   293  	if err != nil {
   294  		return nil, errors.New("name attr not found")
   295  	}
   296  
   297  	lowPC, err := addressClassAttr(subprogram, dwarf.AttrLowpc)
   298  	if err != nil {
   299  		return nil, fmt.Errorf("%s: %v", name, err)
   300  	}
   301  
   302  	highPC, err := addressClassAttr(subprogram, dwarf.AttrHighpc)
   303  	if err != nil {
   304  		return nil, fmt.Errorf("%s: %v", name, err)
   305  	}
   306  
   307  	frameBase, err := locationClassAttr(subprogram, dwarf.AttrFrameBase)
   308  	if err != nil {
   309  		return nil, fmt.Errorf("%s: %v", name, err)
   310  	} else if len(frameBase) != 1 || frameBase[0] != dwarfOpCallFrameCFA {
   311  		log.Printf("The frame base attribute of %s has the unexpected value. The parameter values may be wrong.", name)
   312  	}
   313  
   314  	return &Function{Name: name, StartAddr: lowPC, EndAddr: highPC}, nil
   315  }
   316  
   317  func (r subprogramReader) parameters() ([]Parameter, error) {
   318  	var params []Parameter
   319  	for {
   320  		param, err := r.nextParameter()
   321  		if err != nil || param == nil {
   322  			// the parameters are sorted by the name.
   323  			sort.Slice(params, func(i, j int) bool { return params[i].Offset < params[j].Offset })
   324  			return params, err
   325  		}
   326  
   327  		params = append(params, *param)
   328  		r.raw.SkipChildren()
   329  	}
   330  }
   331  
   332  func (r subprogramReader) nextParameter() (*Parameter, error) {
   333  	for {
   334  		param, err := r.raw.Next()
   335  		if err != nil || param.Tag == 0 {
   336  			return nil, err
   337  		}
   338  
   339  		if param.Tag != dwarf.TagFormalParameter {
   340  			r.raw.SkipChildren()
   341  			continue
   342  		}
   343  
   344  		return r.buildParameter(param)
   345  	}
   346  }
   347  
   348  func (r subprogramReader) buildParameter(param *dwarf.Entry) (*Parameter, error) {
   349  	var name string
   350  	var typeOffset dwarf.Offset
   351  	var isOutput bool
   352  	err := walkUpOrigins(param, r.dwarfData.Data, func(entry *dwarf.Entry) bool {
   353  		var err error
   354  		name, err = stringClassAttr(entry, dwarf.AttrName)
   355  		if err != nil {
   356  			return false
   357  		}
   358  
   359  		typeOffset, err = referenceClassAttr(entry, dwarf.AttrType)
   360  		if err != nil {
   361  			return false
   362  		}
   363  
   364  		isOutput, err = flagClassAttr(entry, attrVariableParameter)
   365  		return err == nil
   366  	})
   367  	if err != nil {
   368  		return nil, err
   369  	}
   370  
   371  	typ, err := r.dwarfData.Type(typeOffset)
   372  	if err != nil {
   373  		return nil, err
   374  	}
   375  
   376  	offset, exist, err := r.findLocation(param)
   377  	return &Parameter{Name: name, Typ: typ, Offset: offset, IsOutput: isOutput, Exist: exist}, err
   378  }
   379  
   380  func (r subprogramReader) findLocation(param *dwarf.Entry) (offset int, exist bool, err error) {
   381  	offset, exist, err = r.findLocationByLocationDesc(param)
   382  	if err != nil && r.dwarfData.locationList != nil {
   383  		offset, exist, err = r.findLocationByLocationList(param)
   384  	}
   385  	return
   386  }
   387  
   388  func (r subprogramReader) findLocationByLocationDesc(param *dwarf.Entry) (offset int, exist bool, err error) {
   389  	loc, err := locationClassAttr(param, dwarf.AttrLocation)
   390  	if err != nil {
   391  		return 0, false, fmt.Errorf("loc attr not found: %v", err)
   392  	}
   393  
   394  	if len(loc) == 0 {
   395  		// the location description may be empty due to the optimization (see the DWARF spec 2.6.1.1.4)
   396  		return 0, false, nil
   397  	}
   398  
   399  	offset, err = parseLocationDesc(loc)
   400  	if err != nil {
   401  		log.Debugf("failed to parse location description at %#x: %v", param.Offset, err)
   402  	}
   403  	return offset, err == nil, nil
   404  }
   405  
   406  // parseLocationDesc returns the offset from the beginning of the parameter list.
   407  // It assumes the value is present in the memory and not separated.
   408  // Also, it's supposed the function's frame base always specifies to the CFA.
   409  func parseLocationDesc(loc []byte) (int, error) {
   410  	if len(loc) == 0 {
   411  		return 0, errors.New("location description is empty")
   412  	}
   413  
   414  	// TODO: support the value in the register and the separated value.
   415  	switch loc[0] {
   416  	case dwarfOpCallFrameCFA:
   417  		return 0, nil
   418  	case dwarfOpFbreg:
   419  		return decodeSignedLEB128(loc[1:]), nil
   420  	default:
   421  		return 0, fmt.Errorf("unknown operation: %#x", loc[0])
   422  	}
   423  }
   424  
   425  func (r subprogramReader) findLocationByLocationList(param *dwarf.Entry) (int, bool, error) {
   426  	loc, err := locationListClassAttr(param, dwarf.AttrLocation)
   427  	if err != nil {
   428  		return 0, false, fmt.Errorf("loc list attr not found: %v", err)
   429  	}
   430  
   431  	locList := buildLocationList(r.dwarfData.locationList, int(loc))
   432  	if len(locList.locListEntries) == 0 {
   433  		return 0, false, errors.New("no location list entry")
   434  	}
   435  
   436  	// TODO: it's more precise to choose the right location list entry using PC and address offsets.
   437  	//       Usually the first entry specifies to the right location in our use case, though.
   438  	offset, err := parseLocationDesc(locList.locListEntries[0].locationDesc)
   439  	if err != nil {
   440  		log.Debugf("failed to parse location list at %#x: %v", param.Offset, err)
   441  	}
   442  	return offset, err == nil, nil
   443  }
   444  
   445  type locationList struct {
   446  	baseAddress    uint64
   447  	locListEntries []locationListEntry
   448  }
   449  
   450  type locationListEntry struct {
   451  	beginOffset, endOffset int
   452  	locationDesc           []byte
   453  }
   454  
   455  func buildLocationList(locSectionData []byte, offset int) (locList locationList) {
   456  	for {
   457  		beginOffset := binary.LittleEndian.Uint64(locSectionData[offset : offset+8])
   458  		offset += 8
   459  		endOffset := binary.LittleEndian.Uint64(locSectionData[offset : offset+8])
   460  		offset += 8
   461  		if beginOffset == 0x0 && endOffset == 0x0 {
   462  			// end of list entry
   463  			break
   464  		} else if beginOffset == ^uint64(0) {
   465  			// base address selection entry
   466  			locList.baseAddress = endOffset
   467  			continue
   468  		}
   469  
   470  		// location list entry
   471  		locListEntry := locationListEntry{beginOffset: int(beginOffset), endOffset: int(endOffset)}
   472  		locationDescLen := int(binary.LittleEndian.Uint16(locSectionData[offset : offset+2]))
   473  		offset += 2
   474  
   475  		locListEntry.locationDesc = locSectionData[offset : offset+locationDescLen]
   476  		offset += locationDescLen
   477  
   478  		locList.locListEntries = append(locList.locListEntries, locListEntry)
   479  	}
   480  	return
   481  }
   482  
   483  func addressClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (uint64, error) {
   484  	field := entry.AttrField(attrName)
   485  	if field == nil {
   486  		return 0, errors.New("attr not found")
   487  	}
   488  
   489  	if field.Class != dwarf.ClassAddress {
   490  		return 0, fmt.Errorf("invalid class: %v", field.Class)
   491  	}
   492  
   493  	// https://golang.org/pkg/debug/dwarf/#Field
   494  	val := field.Val.(uint64)
   495  	return val, nil
   496  }
   497  
   498  func stringClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (string, error) {
   499  	field := entry.AttrField(attrName)
   500  	if field == nil {
   501  		return "", errors.New("attr not found")
   502  	}
   503  
   504  	if field.Class != dwarf.ClassString {
   505  		return "", fmt.Errorf("invalid class: %v", field.Class)
   506  	}
   507  
   508  	// https://golang.org/pkg/debug/dwarf/#Field
   509  	val := field.Val.(string)
   510  	return val, nil
   511  }
   512  
   513  func referenceClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (dwarf.Offset, error) {
   514  	field := entry.AttrField(attrName)
   515  	if field == nil {
   516  		return 0, errors.New("attr not found")
   517  	}
   518  
   519  	if field.Class != dwarf.ClassReference {
   520  		return 0, fmt.Errorf("invalid class: %v", field.Class)
   521  	}
   522  
   523  	// https://golang.org/pkg/debug/dwarf/#Field
   524  	val := field.Val.(dwarf.Offset)
   525  	return val, nil
   526  }
   527  
   528  func locationClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) ([]byte, error) {
   529  	field := entry.AttrField(attrName)
   530  	if field == nil {
   531  		return nil, errors.New("attr not found")
   532  	}
   533  
   534  	if field.Class != dwarf.ClassExprLoc {
   535  		return nil, fmt.Errorf("invalid class: %v", field.Class)
   536  	}
   537  
   538  	// https://golang.org/pkg/debug/dwarf/#Field
   539  	val := field.Val.([]byte)
   540  	return val, nil
   541  }
   542  
   543  func locationListClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (int64, error) {
   544  	field := entry.AttrField(attrName)
   545  	if field == nil {
   546  		return 0, errors.New("attr not found")
   547  	}
   548  
   549  	if field.Class != dwarf.ClassLocListPtr {
   550  		return 0, fmt.Errorf("invalid class: %v", field.Class)
   551  	}
   552  
   553  	// https://golang.org/pkg/debug/dwarf/#Field
   554  	val := field.Val.(int64)
   555  	return val, nil
   556  }
   557  
   558  func flagClassAttr(entry *dwarf.Entry, attrName dwarf.Attr) (bool, error) {
   559  	field := entry.AttrField(attrName)
   560  	if field == nil {
   561  		return false, errors.New("attr not found")
   562  	}
   563  
   564  	if field.Class != dwarf.ClassFlag {
   565  		return false, fmt.Errorf("invalid class: %v", field.Class)
   566  	}
   567  
   568  	// https://golang.org/pkg/debug/dwarf/#Field
   569  	val := field.Val.(bool)
   570  	return val, nil
   571  }
   572  
   573  // walkUpOrigins follows the entry's origins until the walkFn returns true.
   574  //
   575  // It can find the DIE of the inlined instance from the DIE of the out-of-line instance (see the DWARF spec for the terminology).
   576  func walkUpOrigins(entry *dwarf.Entry, dwarfData *dwarf.Data, walkFn func(*dwarf.Entry) bool) error {
   577  	if ok := walkFn(entry); ok {
   578  		return nil
   579  	}
   580  
   581  	origin := findAbstractOrigin(entry, dwarfData)
   582  	if origin == nil {
   583  		return errors.New("failed to find abstract origin")
   584  	}
   585  
   586  	return walkUpOrigins(origin, dwarfData, walkFn)
   587  }
   588  
   589  func findAbstractOrigin(entry *dwarf.Entry, dwarfData *dwarf.Data) *dwarf.Entry {
   590  	ref, err := referenceClassAttr(entry, dwarf.AttrAbstractOrigin)
   591  	if err != nil {
   592  		return nil
   593  	}
   594  
   595  	reader := dwarfData.Reader()
   596  	reader.Seek(ref)
   597  	originEntry, err := reader.Next()
   598  	if err != nil {
   599  		return nil
   600  	}
   601  	return originEntry
   602  }
   603  
   604  func decodeSignedLEB128(input []byte) (val int) {
   605  	var i int
   606  	for {
   607  		val |= int(input[i]) & 0x7F << (7 * uint(i))
   608  
   609  		if input[i]>>7&0x1 == 0x0 {
   610  			break
   611  		}
   612  		i++
   613  	}
   614  
   615  	if input[i]>>6&0x1 == 0x1 {
   616  		// negative value
   617  		return (^0)<<((uint(i)+1)*7) + val
   618  	}
   619  	return val
   620  }
   621  
   622  type symbol struct {
   623  	Name  string
   624  	Value uint64
   625  }
   626  
   627  // nonDebuggableBinaryFile represents the binary file WITHOUT DWARF sections.
   628  type nonDebuggableBinaryFile struct {
   629  	closer io.Closer
   630  }
   631  
   632  func newNonDebuggableBinaryFile(closer io.Closer) (nonDebuggableBinaryFile, error) {
   633  	return nonDebuggableBinaryFile{closer: closer}, nil
   634  }
   635  
   636  // FindFunction always returns error because it's difficult to get function info using non-DWARF binary.
   637  func (b nonDebuggableBinaryFile) FindFunction(pc uint64) (*Function, error) {
   638  	return nil, errors.New("no DWARF info")
   639  }
   640  
   641  func (b nonDebuggableBinaryFile) Close() error {
   642  	return b.closer.Close()
   643  }
   644  
   645  func (b nonDebuggableBinaryFile) findDwarfTypeByAddr(typeAddr uint64) (dwarf.Type, error) {
   646  	return nil, errors.New("no DWARF info")
   647  }
   648  
   649  // Assume this dwarf.Type represents a subset of the module data type in the case DWARF is not available.
   650  var moduleDataType = &dwarf.StructType{
   651  	StructName: "runtime.moduledata",
   652  	CommonType: dwarf.CommonType{ByteSize: 456},
   653  	Field: []*dwarf.StructField{
   654  		&dwarf.StructField{
   655  			Name: "pclntable",
   656  			Type: &dwarf.StructType{
   657  				CommonType: dwarf.CommonType{ByteSize: 24},
   658  				StructName: "[]uint8",
   659  				Field: []*dwarf.StructField{
   660  					&dwarf.StructField{
   661  						Name: "array",
   662  						Type: &dwarf.PtrType{
   663  							CommonType: dwarf.CommonType{ByteSize: 8},
   664  							Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 1}}},
   665  						},
   666  						ByteOffset: 0,
   667  					},
   668  					&dwarf.StructField{
   669  						Name:       "len",
   670  						Type:       &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   671  						ByteOffset: 8,
   672  					},
   673  				},
   674  			},
   675  			ByteOffset: 0,
   676  		},
   677  		&dwarf.StructField{
   678  			Name: "ftab",
   679  			Type: &dwarf.StructType{
   680  				CommonType: dwarf.CommonType{ByteSize: 24},
   681  				StructName: "[]runtime.functab",
   682  				Field: []*dwarf.StructField{
   683  					&dwarf.StructField{
   684  						Name: "array",
   685  						Type: &dwarf.PtrType{
   686  							CommonType: dwarf.CommonType{ByteSize: 8},
   687  							Type: &dwarf.StructType{
   688  								CommonType: dwarf.CommonType{ByteSize: 16},
   689  								StructName: "runtime.functab",
   690  								Field: []*dwarf.StructField{
   691  									&dwarf.StructField{
   692  										Name:       "entry",
   693  										Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   694  										ByteOffset: 0,
   695  									},
   696  									&dwarf.StructField{
   697  										Name:       "funcoff",
   698  										Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   699  										ByteOffset: 8,
   700  									},
   701  								},
   702  							},
   703  						},
   704  						ByteOffset: 0,
   705  					},
   706  					&dwarf.StructField{
   707  						Name:       "len",
   708  						Type:       &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   709  						ByteOffset: 8,
   710  					},
   711  				},
   712  			},
   713  			ByteOffset: 24,
   714  		},
   715  		&dwarf.StructField{
   716  			Name:       "findfunctab",
   717  			Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   718  			ByteOffset: 72,
   719  		},
   720  		&dwarf.StructField{
   721  			Name:       "minpc",
   722  			Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   723  			ByteOffset: 80,
   724  		},
   725  		&dwarf.StructField{
   726  			Name:       "maxpc",
   727  			Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   728  			ByteOffset: 88,
   729  		},
   730  		&dwarf.StructField{
   731  			Name:       "types",
   732  			Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   733  			ByteOffset: 200,
   734  		},
   735  		&dwarf.StructField{
   736  			Name:       "etypes",
   737  			Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   738  			ByteOffset: 208,
   739  		},
   740  		&dwarf.StructField{
   741  			Name:       "next",
   742  			Type:       &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}},
   743  			ByteOffset: 448,
   744  		},
   745  	},
   746  }
   747  
   748  func (b nonDebuggableBinaryFile) moduleDataType() dwarf.Type {
   749  	return moduleDataType
   750  }
   751  
   752  // Assume this dwarf.Type represents a subset of the runtime.g type in the case DWARF is not available.
   753  var runtimeGType = &dwarf.StructType{
   754  	StructName: "runtime.moduledata",
   755  	CommonType: dwarf.CommonType{ByteSize: 456},
   756  	Field: []*dwarf.StructField{
   757  		&dwarf.StructField{
   758  			Name: "stack",
   759  			Type: &dwarf.StructType{
   760  				CommonType: dwarf.CommonType{ByteSize: 16},
   761  				StructName: "runtime.stack",
   762  				Field: []*dwarf.StructField{
   763  					&dwarf.StructField{
   764  						Name:       "lo",
   765  						Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   766  						ByteOffset: 0,
   767  					},
   768  					&dwarf.StructField{
   769  						Name:       "hi",
   770  						Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   771  						ByteOffset: 8,
   772  					},
   773  				},
   774  			},
   775  			ByteOffset: 0,
   776  		},
   777  		&dwarf.StructField{
   778  			Name:       "_panic",
   779  			Type:       &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}},
   780  			ByteOffset: 32,
   781  		},
   782  		&dwarf.StructField{
   783  			Name: "_defer",
   784  			Type: &dwarf.PtrType{
   785  				CommonType: dwarf.CommonType{ByteSize: 8},
   786  				Type: &dwarf.StructType{
   787  					CommonType: dwarf.CommonType{ByteSize: 48},
   788  					StructName: "runtime._defer",
   789  					Field: []*dwarf.StructField{
   790  						&dwarf.StructField{
   791  							Name:       "sp",
   792  							Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   793  							ByteOffset: 8,
   794  						},
   795  						&dwarf.StructField{
   796  							Name:       "pc",
   797  							Type:       &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   798  							ByteOffset: 16,
   799  						},
   800  						&dwarf.StructField{
   801  							Name:       "fn",
   802  							Type:       &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}},
   803  							ByteOffset: 24,
   804  						},
   805  						&dwarf.StructField{
   806  							Name:       "_panic",
   807  							Type:       &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}},
   808  							ByteOffset: 32,
   809  						},
   810  						&dwarf.StructField{
   811  							Name:       "link",
   812  							Type:       &dwarf.PtrType{CommonType: dwarf.CommonType{ByteSize: 8}},
   813  							ByteOffset: 40,
   814  						},
   815  					},
   816  				},
   817  			},
   818  			ByteOffset: 40,
   819  		},
   820  		&dwarf.StructField{
   821  			Name:       "goid",
   822  			Type:       &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   823  			ByteOffset: 152,
   824  		},
   825  		&dwarf.StructField{
   826  			Name: "ancestors",
   827  			Type: &dwarf.PtrType{
   828  				CommonType: dwarf.CommonType{ByteSize: 8},
   829  				Type: &dwarf.StructType{
   830  					CommonType: dwarf.CommonType{ByteSize: 24},
   831  					StructName: "[]runtime.ancestorInfo",
   832  					Field: []*dwarf.StructField{
   833  						&dwarf.StructField{
   834  							Name: "array",
   835  							Type: &dwarf.PtrType{
   836  								CommonType: dwarf.CommonType{ByteSize: 8},
   837  								Type: &dwarf.StructType{
   838  									CommonType: dwarf.CommonType{ByteSize: 40},
   839  									StructName: "runtime.ancestorInfo",
   840  									Field: []*dwarf.StructField{
   841  										&dwarf.StructField{
   842  											Name:       "goid",
   843  											Type:       &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   844  											ByteOffset: 24,
   845  										},
   846  									},
   847  								},
   848  							},
   849  							ByteOffset: 0,
   850  						},
   851  						&dwarf.StructField{
   852  							Name:       "len",
   853  							Type:       &dwarf.IntType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 8}}},
   854  							ByteOffset: 8,
   855  						},
   856  					},
   857  				},
   858  			},
   859  			ByteOffset: 288,
   860  		},
   861  	},
   862  }
   863  
   864  func (b nonDebuggableBinaryFile) runtimeGType() dwarf.Type {
   865  	return runtimeGType
   866  }