github.com/undoio/delve@v1.9.0/pkg/proc/types.go (about)

     1  package proc
     2  
     3  import (
     4  	"bytes"
     5  	"debug/dwarf"
     6  	"errors"
     7  	"fmt"
     8  	"go/constant"
     9  	"reflect"
    10  	"strings"
    11  
    12  	"github.com/undoio/delve/pkg/dwarf/godwarf"
    13  	"github.com/undoio/delve/pkg/dwarf/reader"
    14  	"github.com/undoio/delve/pkg/goversion"
    15  )
    16  
    17  // The kind field in runtime._type is a reflect.Kind value plus
    18  // some extra flags defined here.
    19  // See equivalent declaration in $GOROOT/src/reflect/type.go
    20  const (
    21  	kindDirectIface = 1 << 5 // +rtype kindDirectIface
    22  	kindGCProg      = 1 << 6 // +rtype kindGCProg
    23  	kindNoPointers  = 1 << 7
    24  	kindMask        = (1 << 5) - 1 // +rtype kindMask
    25  )
    26  
    27  // Value of tflag field in runtime._type.
    28  // See $GOROOT/reflect/type.go for a description of these flags.
    29  const (
    30  	tflagUncommon  = 1 << 0
    31  	tflagExtraStar = 1 << 1
    32  	tflagNamed     = 1 << 2
    33  )
    34  
    35  // These constants contain the names of the fields of runtime.interfacetype
    36  // and runtime.imethod.
    37  // runtime.interfacetype.mhdr is a slice of runtime.imethod describing the
    38  // methods of the interface.
    39  const (
    40  	imethodFieldName       = "name"
    41  	imethodFieldItyp       = "ityp"
    42  	interfacetypeFieldMhdr = "mhdr"
    43  )
    44  
    45  type runtimeTypeDIE struct {
    46  	offset dwarf.Offset
    47  	kind   int64
    48  }
    49  
    50  func pointerTo(typ godwarf.Type, arch *Arch) godwarf.Type {
    51  	return &godwarf.PtrType{
    52  		CommonType: godwarf.CommonType{
    53  			ByteSize:    int64(arch.PtrSize()),
    54  			Name:        "*" + typ.Common().Name,
    55  			ReflectKind: reflect.Ptr,
    56  			Offset:      0,
    57  		},
    58  		Type: typ,
    59  	}
    60  }
    61  
    62  type functionsDebugInfoByEntry []Function
    63  
    64  func (v functionsDebugInfoByEntry) Len() int           { return len(v) }
    65  func (v functionsDebugInfoByEntry) Less(i, j int) bool { return v[i].Entry < v[j].Entry }
    66  func (v functionsDebugInfoByEntry) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
    67  
    68  type compileUnitsByOffset []*compileUnit
    69  
    70  func (v compileUnitsByOffset) Len() int               { return len(v) }
    71  func (v compileUnitsByOffset) Less(i int, j int) bool { return v[i].offset < v[j].offset }
    72  func (v compileUnitsByOffset) Swap(i int, j int)      { v[i], v[j] = v[j], v[i] }
    73  
    74  type packageVarsByAddr []packageVar
    75  
    76  func (v packageVarsByAddr) Len() int               { return len(v) }
    77  func (v packageVarsByAddr) Less(i int, j int) bool { return v[i].addr < v[j].addr }
    78  func (v packageVarsByAddr) Swap(i int, j int)      { v[i], v[j] = v[j], v[i] }
    79  
    80  type loadDebugInfoMapsContext struct {
    81  	ardr                *reader.Reader
    82  	abstractOriginTable map[dwarf.Offset]int
    83  	knownPackageVars    map[string]struct{}
    84  	offsetToVersion     map[dwarf.Offset]uint8
    85  }
    86  
    87  func newLoadDebugInfoMapsContext(bi *BinaryInfo, image *Image, offsetToVersion map[dwarf.Offset]uint8) *loadDebugInfoMapsContext {
    88  	ctxt := &loadDebugInfoMapsContext{}
    89  
    90  	ctxt.ardr = image.DwarfReader()
    91  	ctxt.abstractOriginTable = make(map[dwarf.Offset]int)
    92  	ctxt.offsetToVersion = offsetToVersion
    93  
    94  	ctxt.knownPackageVars = map[string]struct{}{}
    95  	for _, v := range bi.packageVars {
    96  		ctxt.knownPackageVars[v.name] = struct{}{}
    97  	}
    98  
    99  	return ctxt
   100  }
   101  
   102  func (ctxt *loadDebugInfoMapsContext) lookupAbstractOrigin(bi *BinaryInfo, off dwarf.Offset) int {
   103  	r, ok := ctxt.abstractOriginTable[off]
   104  	if !ok {
   105  		bi.Functions = append(bi.Functions, Function{})
   106  		r = len(bi.Functions) - 1
   107  		bi.Functions[r].offset = off
   108  		ctxt.abstractOriginTable[off] = r
   109  	}
   110  	return r
   111  }
   112  
   113  // runtimeTypeToDIE returns the DIE corresponding to the runtime._type.
   114  // This is done in three different ways depending on the version of go.
   115  //   - Before go1.7 the type name is retrieved directly from the runtime._type
   116  //     and looked up in debug_info
   117  //   - After go1.7 the runtime._type struct is read recursively to reconstruct
   118  //     the name of the type, and then the type's name is used to look up
   119  //     debug_info
   120  //   - After go1.11 the runtimeTypeToDIE map is used to look up the address of
   121  //     the type and map it drectly to a DIE.
   122  func runtimeTypeToDIE(_type *Variable, dataAddr uint64) (typ godwarf.Type, kind int64, err error) {
   123  	bi := _type.bi
   124  
   125  	_type = _type.maybeDereference()
   126  
   127  	// go 1.11 implementation: use extended attribute in debug_info
   128  
   129  	mds, err := loadModuleData(bi, _type.mem)
   130  	if err != nil {
   131  		return nil, 0, fmt.Errorf("error loading module data: %v", err)
   132  	}
   133  
   134  	md := findModuleDataForType(bi, mds, _type.Addr, _type.mem)
   135  	if md != nil {
   136  		so := bi.moduleDataToImage(md)
   137  		if so != nil {
   138  			if rtdie, ok := so.runtimeTypeToDIE[uint64(_type.Addr-md.types)]; ok {
   139  				typ, err := godwarf.ReadType(so.dwarf, so.index, rtdie.offset, so.typeCache)
   140  				if err != nil {
   141  					return nil, 0, fmt.Errorf("invalid interface type: %v", err)
   142  				}
   143  				if rtdie.kind == -1 {
   144  					if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil {
   145  						rtdie.kind, _ = constant.Int64Val(kindField.Value)
   146  					}
   147  				}
   148  				return typ, rtdie.kind, nil
   149  			}
   150  		}
   151  	}
   152  
   153  	// go1.7 to go1.10 implementation: convert runtime._type structs to type names
   154  
   155  	if goversion.ProducerAfterOrEqual(_type.bi.Producer(), 1, 17) {
   156  		// Go 1.17 changed the encoding of names in runtime._type breaking the
   157  		// code below, but the codepath above, using runtimeTypeToDIE should be
   158  		// enough.
   159  		// The change happened in commit 287025925f66f90ad9b30aea2e533928026a8376
   160  		// reviewed in https://go-review.googlesource.com/c/go/+/318249
   161  		return nil, 0, fmt.Errorf("could not resolve interface type")
   162  	}
   163  
   164  	typename, kind, err := nameOfRuntimeType(mds, _type)
   165  	if err != nil {
   166  		return nil, 0, fmt.Errorf("invalid interface type: %v", err)
   167  	}
   168  
   169  	typ, err = bi.findType(typename)
   170  	if err != nil {
   171  		return nil, 0, fmt.Errorf("interface type %q not found for %#x: %v", typename, dataAddr, err)
   172  	}
   173  
   174  	return typ, kind, nil
   175  }
   176  
   177  // resolveParametricType returns the real type of t if t is a parametric
   178  // type, by reading the correct dictionary entry.
   179  func resolveParametricType(tgt *Target, bi *BinaryInfo, mem MemoryReadWriter, t godwarf.Type, dictAddr uint64) (godwarf.Type, error) {
   180  	ptyp, _ := t.(*godwarf.ParametricType)
   181  	if ptyp == nil {
   182  		return t, nil
   183  	}
   184  	if dictAddr == 0 {
   185  		return ptyp.TypedefType.Type, errors.New("parametric type without a dictionary")
   186  	}
   187  	rtypeAddr, err := readUintRaw(mem, dictAddr+uint64(ptyp.DictIndex*int64(bi.Arch.PtrSize())), int64(bi.Arch.PtrSize()))
   188  	if err != nil {
   189  		return ptyp.TypedefType.Type, err
   190  	}
   191  	runtimeType, err := bi.findType("runtime._type")
   192  	if err != nil {
   193  		return ptyp.TypedefType.Type, err
   194  	}
   195  	_type := newVariable("", rtypeAddr, runtimeType, bi, mem)
   196  
   197  	typ, _, err := runtimeTypeToDIE(_type, 0)
   198  	if err != nil {
   199  		return ptyp.TypedefType.Type, err
   200  	}
   201  
   202  	return typ, nil
   203  }
   204  
   205  type nameOfRuntimeTypeEntry struct {
   206  	typename string
   207  	kind     int64
   208  }
   209  
   210  // Returns the type name of the type described in _type.
   211  // _type is a non-loaded Variable pointing to runtime._type struct in the target.
   212  // The returned string is in the format that's used in DWARF data
   213  func nameOfRuntimeType(mds []moduleData, _type *Variable) (typename string, kind int64, err error) {
   214  	if e, ok := _type.bi.nameOfRuntimeType[_type.Addr]; ok {
   215  		return e.typename, e.kind, nil
   216  	}
   217  
   218  	var tflag int64
   219  
   220  	if tflagField := _type.loadFieldNamed("tflag"); tflagField != nil && tflagField.Value != nil {
   221  		tflag, _ = constant.Int64Val(tflagField.Value)
   222  	}
   223  	if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil {
   224  		kind, _ = constant.Int64Val(kindField.Value)
   225  	}
   226  
   227  	// Named types are defined by a 'type' expression, everything else
   228  	// (for example pointers to named types) are not considered named.
   229  	if tflag&tflagNamed != 0 {
   230  		typename, err = nameOfNamedRuntimeType(mds, _type, kind, tflag)
   231  		if err == nil {
   232  			_type.bi.nameOfRuntimeType[_type.Addr] = nameOfRuntimeTypeEntry{typename: typename, kind: kind}
   233  		}
   234  		return typename, kind, err
   235  	}
   236  
   237  	typename, err = nameOfUnnamedRuntimeType(mds, _type, kind, tflag)
   238  	if err == nil {
   239  		_type.bi.nameOfRuntimeType[_type.Addr] = nameOfRuntimeTypeEntry{typename: typename, kind: kind}
   240  	}
   241  	return typename, kind, err
   242  }
   243  
   244  // The layout of a runtime._type struct is as follows:
   245  //
   246  // <runtime._type><kind specific struct fields><runtime.uncommontype>
   247  //
   248  // with the 'uncommon type struct' being optional
   249  //
   250  // For named types first we extract the type name from the 'str'
   251  // field in the runtime._type struct.
   252  // Then we prepend the package path from the runtime.uncommontype
   253  // struct, when it exists.
   254  //
   255  // To find out the memory address of the runtime.uncommontype struct
   256  // we first cast the Variable pointing to the runtime._type struct
   257  // to a struct specific to the type's kind (for example, if the type
   258  // being described is a slice type the variable will be specialized
   259  // to a runtime.slicetype).
   260  func nameOfNamedRuntimeType(mds []moduleData, _type *Variable, kind, tflag int64) (typename string, err error) {
   261  	var strOff int64
   262  	if strField := _type.loadFieldNamed("str"); strField != nil && strField.Value != nil {
   263  		strOff, _ = constant.Int64Val(strField.Value)
   264  	} else {
   265  		return "", errors.New("could not find str field")
   266  	}
   267  
   268  	// The following code is adapted from reflect.(*rtype).Name.
   269  	// For a description of how memory is organized for type names read
   270  	// the comment to 'type name struct' in $GOROOT/src/reflect/type.go
   271  
   272  	typename, _, _, err = resolveNameOff(_type.bi, mds, _type.Addr, uint64(strOff), _type.mem)
   273  	if err != nil {
   274  		return "", err
   275  	}
   276  
   277  	if tflag&tflagExtraStar != 0 {
   278  		typename = typename[1:]
   279  	}
   280  
   281  	if i := strings.Index(typename, "."); i >= 0 {
   282  		typename = typename[i+1:]
   283  	} else {
   284  		return typename, nil
   285  	}
   286  
   287  	// The following code is adapted from reflect.(*rtype).PkgPath in
   288  	// $GOROOT/src/reflect/type.go
   289  
   290  	_type, err = specificRuntimeType(_type, kind)
   291  	if err != nil {
   292  		return "", err
   293  	}
   294  
   295  	if ut := uncommon(_type, tflag); ut != nil {
   296  		if pkgPathField := ut.loadFieldNamed("pkgpath"); pkgPathField != nil && pkgPathField.Value != nil {
   297  			pkgPathOff, _ := constant.Int64Val(pkgPathField.Value)
   298  			pkgPath, _, _, err := resolveNameOff(_type.bi, mds, _type.Addr, uint64(pkgPathOff), _type.mem)
   299  			if err != nil {
   300  				return "", err
   301  			}
   302  			if slash := strings.LastIndex(pkgPath, "/"); slash >= 0 {
   303  				fixedName := strings.Replace(pkgPath[slash+1:], ".", "%2e", -1)
   304  				if fixedName != pkgPath[slash+1:] {
   305  					pkgPath = pkgPath[:slash+1] + fixedName
   306  				}
   307  			}
   308  			typename = pkgPath + "." + typename
   309  		}
   310  	}
   311  
   312  	return typename, nil
   313  }
   314  
   315  func nameOfUnnamedRuntimeType(mds []moduleData, _type *Variable, kind, tflag int64) (string, error) {
   316  	_type, err := specificRuntimeType(_type, kind)
   317  	if err != nil {
   318  		return "", err
   319  	}
   320  
   321  	// The types referred to here are defined in $GOROOT/src/runtime/type.go
   322  	switch reflect.Kind(kind & kindMask) {
   323  	case reflect.Array:
   324  		var len int64
   325  		if lenField := _type.loadFieldNamed("len"); lenField != nil && lenField.Value != nil {
   326  			len, _ = constant.Int64Val(lenField.Value)
   327  		}
   328  		elemname, err := fieldToType(mds, _type, "elem")
   329  		if err != nil {
   330  			return "", err
   331  		}
   332  		return fmt.Sprintf("[%d]%s", len, elemname), nil
   333  	case reflect.Chan:
   334  		elemname, err := fieldToType(mds, _type, "elem")
   335  		if err != nil {
   336  			return "", err
   337  		}
   338  		return "chan " + elemname, nil
   339  	case reflect.Func:
   340  		return nameOfFuncRuntimeType(mds, _type, tflag, true)
   341  	case reflect.Interface:
   342  		return nameOfInterfaceRuntimeType(mds, _type, kind, tflag)
   343  	case reflect.Map:
   344  		keyname, err := fieldToType(mds, _type, "key")
   345  		if err != nil {
   346  			return "", err
   347  		}
   348  		elemname, err := fieldToType(mds, _type, "elem")
   349  		if err != nil {
   350  			return "", err
   351  		}
   352  		return "map[" + keyname + "]" + elemname, nil
   353  	case reflect.Ptr:
   354  		elemname, err := fieldToType(mds, _type, "elem")
   355  		if err != nil {
   356  			return "", err
   357  		}
   358  		return "*" + elemname, nil
   359  	case reflect.Slice:
   360  		elemname, err := fieldToType(mds, _type, "elem")
   361  		if err != nil {
   362  			return "", err
   363  		}
   364  		return "[]" + elemname, nil
   365  	case reflect.Struct:
   366  		return nameOfStructRuntimeType(mds, _type, kind, tflag)
   367  	default:
   368  		return nameOfNamedRuntimeType(mds, _type, kind, tflag)
   369  	}
   370  }
   371  
   372  // Returns the expression describing an anonymous function type.
   373  // A runtime.functype is followed by a runtime.uncommontype
   374  // (optional) and then by an array of pointers to runtime._type,
   375  // one for each input and output argument.
   376  func nameOfFuncRuntimeType(mds []moduleData, _type *Variable, tflag int64, anonymous bool) (string, error) {
   377  	rtyp, err := _type.bi.findType("runtime._type")
   378  	if err != nil {
   379  		return "", err
   380  	}
   381  	prtyp := pointerTo(rtyp, _type.bi.Arch)
   382  
   383  	uadd := _type.RealType.Common().ByteSize
   384  	if ut := uncommon(_type, tflag); ut != nil {
   385  		uadd += ut.RealType.Common().ByteSize
   386  	}
   387  
   388  	var inCount, outCount int64
   389  	if inCountField := _type.loadFieldNamed("inCount"); inCountField != nil && inCountField.Value != nil {
   390  		inCount, _ = constant.Int64Val(inCountField.Value)
   391  	}
   392  	if outCountField := _type.loadFieldNamed("outCount"); outCountField != nil && outCountField.Value != nil {
   393  		outCount, _ = constant.Int64Val(outCountField.Value)
   394  		// only the lowest 15 bits of outCount are used, rest are flags
   395  		outCount = outCount & (1<<15 - 1)
   396  	}
   397  
   398  	cursortyp := _type.newVariable("", _type.Addr+uint64(uadd), prtyp, _type.mem)
   399  	var buf bytes.Buffer
   400  	if anonymous {
   401  		buf.WriteString("func(")
   402  	} else {
   403  		buf.WriteString("(")
   404  	}
   405  
   406  	for i := int64(0); i < inCount; i++ {
   407  		argtype := cursortyp.maybeDereference()
   408  		cursortyp.Addr += uint64(_type.bi.Arch.PtrSize())
   409  		argtypename, _, err := nameOfRuntimeType(mds, argtype)
   410  		if err != nil {
   411  			return "", err
   412  		}
   413  		buf.WriteString(argtypename)
   414  		if i != inCount-1 {
   415  			buf.WriteString(", ")
   416  		}
   417  	}
   418  	buf.WriteString(")")
   419  
   420  	switch outCount {
   421  	case 0:
   422  		// nothing to do
   423  	case 1:
   424  		buf.WriteString(" ")
   425  		argtype := cursortyp.maybeDereference()
   426  		argtypename, _, err := nameOfRuntimeType(mds, argtype)
   427  		if err != nil {
   428  			return "", err
   429  		}
   430  		buf.WriteString(argtypename)
   431  	default:
   432  		buf.WriteString(" (")
   433  		for i := int64(0); i < outCount; i++ {
   434  			argtype := cursortyp.maybeDereference()
   435  			cursortyp.Addr += uint64(_type.bi.Arch.PtrSize())
   436  			argtypename, _, err := nameOfRuntimeType(mds, argtype)
   437  			if err != nil {
   438  				return "", err
   439  			}
   440  			buf.WriteString(argtypename)
   441  			if i != inCount-1 {
   442  				buf.WriteString(", ")
   443  			}
   444  		}
   445  		buf.WriteString(")")
   446  	}
   447  	return buf.String(), nil
   448  }
   449  
   450  func nameOfInterfaceRuntimeType(mds []moduleData, _type *Variable, kind, tflag int64) (string, error) {
   451  	var buf bytes.Buffer
   452  	buf.WriteString("interface {")
   453  
   454  	methods, _ := _type.structMember(interfacetypeFieldMhdr)
   455  	methods.loadArrayValues(0, LoadConfig{false, 1, 0, 4096, -1, 0})
   456  	if methods.Unreadable != nil {
   457  		return "", nil
   458  	}
   459  
   460  	if len(methods.Children) == 0 {
   461  		buf.WriteString("}")
   462  		return buf.String(), nil
   463  	}
   464  	buf.WriteString(" ")
   465  
   466  	for i, im := range methods.Children {
   467  		var methodname, methodtype string
   468  		for i := range im.Children {
   469  			switch im.Children[i].Name {
   470  			case imethodFieldName:
   471  				nameoff, _ := constant.Int64Val(im.Children[i].Value)
   472  				var err error
   473  				methodname, _, _, err = resolveNameOff(_type.bi, mds, _type.Addr, uint64(nameoff), _type.mem)
   474  				if err != nil {
   475  					return "", err
   476  				}
   477  
   478  			case imethodFieldItyp:
   479  				typeoff, _ := constant.Int64Val(im.Children[i].Value)
   480  				typ, err := resolveTypeOff(_type.bi, mds, _type.Addr, uint64(typeoff), _type.mem)
   481  				if err != nil {
   482  					return "", err
   483  				}
   484  				typ, err = specificRuntimeType(typ, int64(reflect.Func))
   485  				if err != nil {
   486  					return "", err
   487  				}
   488  				var tflag int64
   489  				if tflagField := typ.loadFieldNamed("tflag"); tflagField != nil && tflagField.Value != nil {
   490  					tflag, _ = constant.Int64Val(tflagField.Value)
   491  				}
   492  				methodtype, err = nameOfFuncRuntimeType(mds, typ, tflag, false)
   493  				if err != nil {
   494  					return "", err
   495  				}
   496  			}
   497  		}
   498  
   499  		buf.WriteString(methodname)
   500  		buf.WriteString(methodtype)
   501  
   502  		if i != len(methods.Children)-1 {
   503  			buf.WriteString("; ")
   504  		} else {
   505  			buf.WriteString(" }")
   506  		}
   507  	}
   508  	return buf.String(), nil
   509  }
   510  
   511  func nameOfStructRuntimeType(mds []moduleData, _type *Variable, kind, tflag int64) (string, error) {
   512  	var buf bytes.Buffer
   513  	buf.WriteString("struct {")
   514  
   515  	fields, _ := _type.structMember("fields")
   516  	fields.loadArrayValues(0, LoadConfig{false, 2, 0, 4096, -1, 0})
   517  	if fields.Unreadable != nil {
   518  		return "", fields.Unreadable
   519  	}
   520  
   521  	if len(fields.Children) == 0 {
   522  		buf.WriteString("}")
   523  		return buf.String(), nil
   524  	}
   525  	buf.WriteString(" ")
   526  
   527  	for i, field := range fields.Children {
   528  		var fieldname, fieldtypename string
   529  		var typeField *Variable
   530  		isembed := false
   531  		for i := range field.Children {
   532  			switch field.Children[i].Name {
   533  			case "name":
   534  				var nameoff int64
   535  				switch field.Children[i].Kind {
   536  				case reflect.Struct:
   537  					nameoff = int64(field.Children[i].fieldVariable("bytes").Children[0].Addr)
   538  				default:
   539  					nameoff, _ = constant.Int64Val(field.Children[i].Value)
   540  				}
   541  
   542  				var err error
   543  				fieldname, _, _, err = loadName(_type.bi, uint64(nameoff), _type.mem)
   544  				if err != nil {
   545  					return "", err
   546  				}
   547  
   548  			case "typ":
   549  				typeField = field.Children[i].maybeDereference()
   550  				var err error
   551  				fieldtypename, _, err = nameOfRuntimeType(mds, typeField)
   552  				if err != nil {
   553  					return "", err
   554  				}
   555  
   556  			case "offsetAnon":
   557  				// The offsetAnon field of runtime.structfield combines the offset of
   558  				// the struct field from the base address of the struct with a flag
   559  				// determining whether the field is anonymous (i.e. an embedded struct).
   560  				//
   561  				//  offsetAnon = (offset<<1) | (anonFlag)
   562  				//
   563  				// Here we are only interested in the anonymous flag.
   564  				offsetAnon, _ := constant.Int64Val(field.Children[i].Value)
   565  				isembed = offsetAnon%2 != 0
   566  			}
   567  		}
   568  
   569  		// fieldname will be the empty string for anonymous fields
   570  		if fieldname != "" && !isembed {
   571  			buf.WriteString(fieldname)
   572  			buf.WriteString(" ")
   573  		}
   574  		buf.WriteString(fieldtypename)
   575  		if i != len(fields.Children)-1 {
   576  			buf.WriteString("; ")
   577  		} else {
   578  			buf.WriteString(" }")
   579  		}
   580  	}
   581  
   582  	return buf.String(), nil
   583  }
   584  
   585  func fieldToType(mds []moduleData, _type *Variable, fieldName string) (string, error) {
   586  	typeField, err := _type.structMember(fieldName)
   587  	if err != nil {
   588  		return "", err
   589  	}
   590  	typeField = typeField.maybeDereference()
   591  	typename, _, err := nameOfRuntimeType(mds, typeField)
   592  	return typename, err
   593  }
   594  
   595  func specificRuntimeType(_type *Variable, kind int64) (*Variable, error) {
   596  	typ, err := typeForKind(kind, _type.bi)
   597  	if err != nil {
   598  		return nil, err
   599  	}
   600  	if typ == nil {
   601  		return _type, nil
   602  	}
   603  
   604  	return _type.newVariable(_type.Name, _type.Addr, typ, _type.mem), nil
   605  }
   606  
   607  // See reflect.(*rtype).uncommon in $GOROOT/src/reflect/type.go
   608  func uncommon(_type *Variable, tflag int64) *Variable {
   609  	if tflag&tflagUncommon == 0 {
   610  		return nil
   611  	}
   612  
   613  	typ, err := _type.bi.findType("runtime.uncommontype")
   614  	if err != nil {
   615  		return nil
   616  	}
   617  
   618  	return _type.newVariable(_type.Name, _type.Addr+uint64(_type.RealType.Size()), typ, _type.mem)
   619  }
   620  
   621  var kindToRuntimeTypeName = map[reflect.Kind]string{
   622  	reflect.Array:     "runtime.arraytype",
   623  	reflect.Chan:      "runtime.chantype",
   624  	reflect.Func:      "runtime.functype",
   625  	reflect.Interface: "runtime.interfacetype",
   626  	reflect.Map:       "runtime.maptype",
   627  	reflect.Ptr:       "runtime.ptrtype",
   628  	reflect.Slice:     "runtime.slicetype",
   629  	reflect.Struct:    "runtime.structtype",
   630  }
   631  
   632  // typeForKind returns a *dwarf.StructType describing the specialization of
   633  // runtime._type for the specified type kind. For example if kind is
   634  // reflect.ArrayType it will return runtime.arraytype
   635  func typeForKind(kind int64, bi *BinaryInfo) (*godwarf.StructType, error) {
   636  	typename, ok := kindToRuntimeTypeName[reflect.Kind(kind&kindMask)]
   637  	if !ok {
   638  		return nil, nil
   639  	}
   640  	typ, err := bi.findType(typename)
   641  	if err != nil {
   642  		return nil, err
   643  	}
   644  	typ = resolveTypedef(typ)
   645  	return typ.(*godwarf.StructType), nil
   646  }
   647  
   648  func dwarfToRuntimeType(bi *BinaryInfo, mem MemoryReadWriter, typ godwarf.Type) (typeAddr uint64, typeKind uint64, found bool, err error) {
   649  	so := bi.typeToImage(typ)
   650  	rdr := so.DwarfReader()
   651  	rdr.Seek(typ.Common().Offset)
   652  	e, err := rdr.Next()
   653  	if err != nil {
   654  		return 0, 0, false, err
   655  	}
   656  	off, ok := e.Val(godwarf.AttrGoRuntimeType).(uint64)
   657  	if !ok {
   658  		return 0, 0, false, nil
   659  	}
   660  
   661  	mds, err := loadModuleData(bi, mem)
   662  	if err != nil {
   663  		return 0, 0, false, err
   664  	}
   665  
   666  	md := bi.imageToModuleData(so, mds)
   667  	if md == nil {
   668  		if so.index > 0 {
   669  			return 0, 0, false, fmt.Errorf("could not find module data for type %s (shared object: %q)", typ, so.Path)
   670  		} else {
   671  			return 0, 0, false, fmt.Errorf("could not find module data for type %s", typ)
   672  		}
   673  	}
   674  
   675  	typeAddr = uint64(md.types) + off
   676  
   677  	rtyp, err := bi.findType("runtime._type")
   678  	if err != nil {
   679  		return 0, 0, false, err
   680  	}
   681  	_type := newVariable("", typeAddr, rtyp, bi, mem)
   682  	kindv := _type.loadFieldNamed("kind")
   683  	if kindv.Unreadable != nil || kindv.Kind != reflect.Uint {
   684  		return 0, 0, false, fmt.Errorf("unreadable interface type: %v", kindv.Unreadable)
   685  	}
   686  	typeKind, _ = constant.Uint64Val(kindv.Value)
   687  	return typeAddr, typeKind, true, nil
   688  }