2015-11-26 13:10:58 +00:00
|
|
|
package proc
|
|
|
|
|
|
|
|
import (
|
2016-09-08 16:11:20 +00:00
|
|
|
"bytes"
|
2017-05-29 13:20:01 +00:00
|
|
|
"debug/dwarf"
|
2016-09-08 16:11:20 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"go/constant"
|
2016-01-24 09:25:54 +00:00
|
|
|
"reflect"
|
2015-11-26 13:10:58 +00:00
|
|
|
"strings"
|
2016-09-08 16:11:20 +00:00
|
|
|
|
2019-01-04 18:39:25 +00:00
|
|
|
"github.com/go-delve/delve/pkg/dwarf/godwarf"
|
|
|
|
"github.com/go-delve/delve/pkg/dwarf/reader"
|
2015-11-26 13:10:58 +00:00
|
|
|
)
|
|
|
|
|
2016-09-08 16:11:20 +00:00
|
|
|
// The kind field in runtime._type is a reflect.Kind value plus
|
|
|
|
// some extra flags defined here.
|
|
|
|
// See equivalent declaration in $GOROOT/src/reflect/type.go
|
|
|
|
const (
|
|
|
|
kindDirectIface = 1 << 5
|
|
|
|
kindGCProg = 1 << 6 // Type.gc points to GC program
|
|
|
|
kindNoPointers = 1 << 7
|
|
|
|
kindMask = (1 << 5) - 1
|
|
|
|
)
|
|
|
|
|
|
|
|
// Value of tflag field in runtime._type.
|
|
|
|
// See $GOROOT/reflect/type.go for a description of these flags.
|
|
|
|
const (
|
|
|
|
tflagUncommon = 1 << 0
|
|
|
|
tflagExtraStar = 1 << 1
|
|
|
|
tflagNamed = 1 << 2
|
|
|
|
)
|
|
|
|
|
2017-05-03 07:56:59 +00:00
|
|
|
// These constants contain the names of the fields of runtime.interfacetype
|
|
|
|
// and runtime.imethod.
|
|
|
|
// runtime.interfacetype.mhdr is a slice of runtime.imethod describing the
|
|
|
|
// methods of the interface.
|
|
|
|
const (
|
|
|
|
imethodFieldName = "name"
|
|
|
|
imethodFieldItyp = "ityp"
|
|
|
|
interfacetypeFieldMhdr = "mhdr"
|
|
|
|
)
|
|
|
|
|
2019-11-12 19:44:08 +00:00
|
|
|
type runtimeTypeDIE struct {
|
|
|
|
offset dwarf.Offset
|
|
|
|
kind int64
|
|
|
|
}
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
func pointerTo(typ godwarf.Type, arch Arch) godwarf.Type {
|
2018-08-31 18:08:18 +00:00
|
|
|
return &godwarf.PtrType{
|
|
|
|
CommonType: godwarf.CommonType{
|
|
|
|
ByteSize: int64(arch.PtrSize()),
|
|
|
|
Name: "*" + typ.Common().Name,
|
|
|
|
ReflectKind: reflect.Ptr,
|
|
|
|
Offset: 0,
|
|
|
|
},
|
|
|
|
Type: typ,
|
|
|
|
}
|
2015-11-26 13:10:58 +00:00
|
|
|
}
|
|
|
|
|
2017-09-01 13:30:45 +00:00
|
|
|
type functionsDebugInfoByEntry []Function
|
2017-02-07 21:08:11 +00:00
|
|
|
|
2017-09-01 13:30:45 +00:00
|
|
|
func (v functionsDebugInfoByEntry) Len() int { return len(v) }
|
|
|
|
func (v functionsDebugInfoByEntry) Less(i, j int) bool { return v[i].Entry < v[j].Entry }
|
|
|
|
func (v functionsDebugInfoByEntry) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
|
|
|
|
|
2019-06-24 15:02:14 +00:00
|
|
|
type compileUnitsByOffset []*compileUnit
|
2017-09-01 13:30:45 +00:00
|
|
|
|
2019-06-24 15:02:14 +00:00
|
|
|
func (v compileUnitsByOffset) Len() int { return len(v) }
|
|
|
|
func (v compileUnitsByOffset) Less(i int, j int) bool { return v[i].offset < v[j].offset }
|
|
|
|
func (v compileUnitsByOffset) Swap(i int, j int) { v[i], v[j] = v[j], v[i] }
|
2017-02-07 21:08:11 +00:00
|
|
|
|
2017-10-26 11:37:19 +00:00
|
|
|
type packageVarsByAddr []packageVar
|
|
|
|
|
|
|
|
func (v packageVarsByAddr) Len() int { return len(v) }
|
|
|
|
func (v packageVarsByAddr) Less(i int, j int) bool { return v[i].addr < v[j].addr }
|
|
|
|
func (v packageVarsByAddr) Swap(i int, j int) { v[i], v[j] = v[j], v[i] }
|
|
|
|
|
2019-05-31 16:08:20 +00:00
|
|
|
type loadDebugInfoMapsContext struct {
|
2019-11-01 19:41:06 +00:00
|
|
|
ardr *reader.Reader
|
|
|
|
abstractOriginTable map[dwarf.Offset]int
|
|
|
|
knownPackageVars map[string]struct{}
|
2019-05-31 16:08:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func newLoadDebugInfoMapsContext(bi *BinaryInfo, image *Image) *loadDebugInfoMapsContext {
|
|
|
|
ctxt := &loadDebugInfoMapsContext{}
|
|
|
|
|
|
|
|
ctxt.ardr = image.DwarfReader()
|
2019-11-01 19:41:06 +00:00
|
|
|
ctxt.abstractOriginTable = make(map[dwarf.Offset]int)
|
2019-05-31 16:08:20 +00:00
|
|
|
|
|
|
|
ctxt.knownPackageVars = map[string]struct{}{}
|
|
|
|
for _, v := range bi.packageVars {
|
|
|
|
ctxt.knownPackageVars[v.name] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctxt
|
|
|
|
}
|
|
|
|
|
2018-04-18 18:09:33 +00:00
|
|
|
// runtimeTypeToDIE returns the DIE corresponding to the runtime._type.
|
|
|
|
// This is done in three different ways depending on the version of go.
|
|
|
|
// * Before go1.7 the type name is retrieved directly from the runtime._type
|
|
|
|
// and looked up in debug_info
|
|
|
|
// * After go1.7 the runtime._type struct is read recursively to reconstruct
|
|
|
|
// the name of the type, and then the type's name is used to look up
|
|
|
|
// debug_info
|
|
|
|
// * After go1.11 the runtimeTypeToDIE map is used to look up the address of
|
|
|
|
// the type and map it drectly to a DIE.
|
|
|
|
func runtimeTypeToDIE(_type *Variable, dataAddr uintptr) (typ godwarf.Type, kind int64, err error) {
|
|
|
|
bi := _type.bi
|
|
|
|
|
|
|
|
_type = _type.maybeDereference()
|
|
|
|
|
|
|
|
// go 1.11 implementation: use extended attribute in debug_info
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
mds, err := loadModuleData(bi, _type.mem)
|
2018-04-18 18:09:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("error loading module data: %v", err)
|
|
|
|
}
|
2019-05-08 21:06:38 +00:00
|
|
|
|
|
|
|
md := findModuleDataForType(bi, mds, _type.Addr, _type.mem)
|
2018-04-18 18:09:33 +00:00
|
|
|
if md != nil {
|
2019-05-08 21:06:38 +00:00
|
|
|
so := bi.moduleDataToImage(md)
|
|
|
|
if rtdie, ok := so.runtimeTypeToDIE[uint64(_type.Addr-md.types)]; ok {
|
|
|
|
typ, err := godwarf.ReadType(so.dwarf, so.index, rtdie.offset, so.typeCache)
|
2018-04-18 18:09:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("invalid interface type: %v", err)
|
|
|
|
}
|
|
|
|
if rtdie.kind == -1 {
|
|
|
|
if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil {
|
|
|
|
rtdie.kind, _ = constant.Int64Val(kindField.Value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return typ, rtdie.kind, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// go1.7 to go1.10 implementation: convert runtime._type structs to type names
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
typename, kind, err := nameOfRuntimeType(mds, _type)
|
2018-04-18 18:09:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("invalid interface type: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
typ, err = bi.findType(typename)
|
|
|
|
if err != nil {
|
|
|
|
return nil, 0, fmt.Errorf("interface type %q not found for %#x: %v", typename, dataAddr, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return typ, kind, nil
|
|
|
|
}
|
|
|
|
|
2016-09-08 16:11:20 +00:00
|
|
|
type nameOfRuntimeTypeEntry struct {
|
|
|
|
typename string
|
|
|
|
kind int64
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the type name of the type described in _type.
|
|
|
|
// _type is a non-loaded Variable pointing to runtime._type struct in the target.
|
|
|
|
// The returned string is in the format that's used in DWARF data
|
2019-05-08 21:06:38 +00:00
|
|
|
func nameOfRuntimeType(mds []moduleData, _type *Variable) (typename string, kind int64, err error) {
|
2017-04-13 23:19:57 +00:00
|
|
|
if e, ok := _type.bi.nameOfRuntimeType[_type.Addr]; ok {
|
2016-09-08 16:11:20 +00:00
|
|
|
return e.typename, e.kind, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var tflag int64
|
|
|
|
|
2017-02-07 21:08:11 +00:00
|
|
|
if tflagField := _type.loadFieldNamed("tflag"); tflagField != nil && tflagField.Value != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
tflag, _ = constant.Int64Val(tflagField.Value)
|
|
|
|
}
|
2017-02-07 21:08:11 +00:00
|
|
|
if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
kind, _ = constant.Int64Val(kindField.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Named types are defined by a 'type' expression, everything else
|
|
|
|
// (for example pointers to named types) are not considered named.
|
|
|
|
if tflag&tflagNamed != 0 {
|
2019-05-08 21:06:38 +00:00
|
|
|
typename, err = nameOfNamedRuntimeType(mds, _type, kind, tflag)
|
|
|
|
if err == nil {
|
|
|
|
_type.bi.nameOfRuntimeType[_type.Addr] = nameOfRuntimeTypeEntry{typename: typename, kind: kind}
|
|
|
|
}
|
2016-09-08 16:11:20 +00:00
|
|
|
return typename, kind, err
|
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
typename, err = nameOfUnnamedRuntimeType(mds, _type, kind, tflag)
|
|
|
|
if err == nil {
|
|
|
|
_type.bi.nameOfRuntimeType[_type.Addr] = nameOfRuntimeTypeEntry{typename: typename, kind: kind}
|
|
|
|
}
|
2018-08-31 18:08:18 +00:00
|
|
|
return typename, kind, err
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// The layout of a runtime._type struct is as follows:
|
|
|
|
//
|
|
|
|
// <runtime._type><kind specific struct fields><runtime.uncommontype>
|
|
|
|
//
|
|
|
|
// with the 'uncommon type struct' being optional
|
|
|
|
//
|
|
|
|
// For named types first we extract the type name from the 'str'
|
|
|
|
// field in the runtime._type struct.
|
|
|
|
// Then we prepend the package path from the runtime.uncommontype
|
|
|
|
// struct, when it exists.
|
|
|
|
//
|
|
|
|
// To find out the memory address of the runtime.uncommontype struct
|
|
|
|
// we first cast the Variable pointing to the runtime._type struct
|
|
|
|
// to a struct specific to the type's kind (for example, if the type
|
|
|
|
// being described is a slice type the variable will be specialized
|
|
|
|
// to a runtime.slicetype).
|
2019-05-08 21:06:38 +00:00
|
|
|
func nameOfNamedRuntimeType(mds []moduleData, _type *Variable, kind, tflag int64) (typename string, err error) {
|
2016-09-08 16:11:20 +00:00
|
|
|
var strOff int64
|
2017-02-07 21:08:11 +00:00
|
|
|
if strField := _type.loadFieldNamed("str"); strField != nil && strField.Value != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
strOff, _ = constant.Int64Val(strField.Value)
|
|
|
|
} else {
|
|
|
|
return "", errors.New("could not find str field")
|
|
|
|
}
|
|
|
|
|
|
|
|
// The following code is adapted from reflect.(*rtype).Name.
|
|
|
|
// For a description of how memory is organized for type names read
|
|
|
|
// the comment to 'type name struct' in $GOROOT/src/reflect/type.go
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
typename, _, _, err = resolveNameOff(_type.bi, mds, _type.Addr, uintptr(strOff), _type.mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if tflag&tflagExtraStar != 0 {
|
|
|
|
typename = typename[1:]
|
|
|
|
}
|
|
|
|
|
|
|
|
if i := strings.Index(typename, "."); i >= 0 {
|
|
|
|
typename = typename[i+1:]
|
|
|
|
} else {
|
|
|
|
return typename, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// The following code is adapted from reflect.(*rtype).PkgPath in
|
|
|
|
// $GOROOT/src/reflect/type.go
|
|
|
|
|
|
|
|
_type, err = specificRuntimeType(_type, kind)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if ut := uncommon(_type, tflag); ut != nil {
|
2017-02-07 21:08:11 +00:00
|
|
|
if pkgPathField := ut.loadFieldNamed("pkgpath"); pkgPathField != nil && pkgPathField.Value != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
pkgPathOff, _ := constant.Int64Val(pkgPathField.Value)
|
2019-05-08 21:06:38 +00:00
|
|
|
pkgPath, _, _, err := resolveNameOff(_type.bi, mds, _type.Addr, uintptr(pkgPathOff), _type.mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2018-03-03 11:28:39 +00:00
|
|
|
if slash := strings.LastIndex(pkgPath, "/"); slash >= 0 {
|
|
|
|
fixedName := strings.Replace(pkgPath[slash+1:], ".", "%2e", -1)
|
|
|
|
if fixedName != pkgPath[slash+1:] {
|
|
|
|
pkgPath = pkgPath[:slash+1] + fixedName
|
|
|
|
}
|
|
|
|
}
|
2016-09-08 16:11:20 +00:00
|
|
|
typename = pkgPath + "." + typename
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return typename, nil
|
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
func nameOfUnnamedRuntimeType(mds []moduleData, _type *Variable, kind, tflag int64) (string, error) {
|
2016-09-08 16:11:20 +00:00
|
|
|
_type, err := specificRuntimeType(_type, kind)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
// The types referred to here are defined in $GOROOT/src/runtime/type.go
|
|
|
|
switch reflect.Kind(kind & kindMask) {
|
|
|
|
case reflect.Array:
|
|
|
|
var len int64
|
2017-02-07 21:08:11 +00:00
|
|
|
if lenField := _type.loadFieldNamed("len"); lenField != nil && lenField.Value != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
len, _ = constant.Int64Val(lenField.Value)
|
|
|
|
}
|
2019-05-08 21:06:38 +00:00
|
|
|
elemname, err := fieldToType(mds, _type, "elem")
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("[%d]%s", len, elemname), nil
|
|
|
|
case reflect.Chan:
|
2019-05-08 21:06:38 +00:00
|
|
|
elemname, err := fieldToType(mds, _type, "elem")
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return "chan " + elemname, nil
|
|
|
|
case reflect.Func:
|
2019-05-08 21:06:38 +00:00
|
|
|
return nameOfFuncRuntimeType(mds, _type, tflag, true)
|
2016-09-08 16:11:20 +00:00
|
|
|
case reflect.Interface:
|
2019-05-08 21:06:38 +00:00
|
|
|
return nameOfInterfaceRuntimeType(mds, _type, kind, tflag)
|
2016-09-08 16:11:20 +00:00
|
|
|
case reflect.Map:
|
2019-05-08 21:06:38 +00:00
|
|
|
keyname, err := fieldToType(mds, _type, "key")
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2019-05-08 21:06:38 +00:00
|
|
|
elemname, err := fieldToType(mds, _type, "elem")
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return "map[" + keyname + "]" + elemname, nil
|
|
|
|
case reflect.Ptr:
|
2019-05-08 21:06:38 +00:00
|
|
|
elemname, err := fieldToType(mds, _type, "elem")
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return "*" + elemname, nil
|
|
|
|
case reflect.Slice:
|
2019-05-08 21:06:38 +00:00
|
|
|
elemname, err := fieldToType(mds, _type, "elem")
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return "[]" + elemname, nil
|
|
|
|
case reflect.Struct:
|
2019-05-08 21:06:38 +00:00
|
|
|
return nameOfStructRuntimeType(mds, _type, kind, tflag)
|
2016-09-08 16:11:20 +00:00
|
|
|
default:
|
2019-05-08 21:06:38 +00:00
|
|
|
return nameOfNamedRuntimeType(mds, _type, kind, tflag)
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the expression describing an anonymous function type.
|
|
|
|
// A runtime.functype is followed by a runtime.uncommontype
|
|
|
|
// (optional) and then by an array of pointers to runtime._type,
|
|
|
|
// one for each input and output argument.
|
2019-05-08 21:06:38 +00:00
|
|
|
func nameOfFuncRuntimeType(mds []moduleData, _type *Variable, tflag int64, anonymous bool) (string, error) {
|
2017-04-13 23:19:57 +00:00
|
|
|
rtyp, err := _type.bi.findType("runtime._type")
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2017-04-21 06:55:53 +00:00
|
|
|
prtyp := pointerTo(rtyp, _type.bi.Arch)
|
2016-09-08 16:11:20 +00:00
|
|
|
|
|
|
|
uadd := _type.RealType.Common().ByteSize
|
|
|
|
if ut := uncommon(_type, tflag); ut != nil {
|
|
|
|
uadd += ut.RealType.Common().ByteSize
|
|
|
|
}
|
|
|
|
|
|
|
|
var inCount, outCount int64
|
2017-02-07 21:08:11 +00:00
|
|
|
if inCountField := _type.loadFieldNamed("inCount"); inCountField != nil && inCountField.Value != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
inCount, _ = constant.Int64Val(inCountField.Value)
|
|
|
|
}
|
2017-02-07 21:08:11 +00:00
|
|
|
if outCountField := _type.loadFieldNamed("outCount"); outCountField != nil && outCountField.Value != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
outCount, _ = constant.Int64Val(outCountField.Value)
|
|
|
|
// only the lowest 15 bits of outCount are used, rest are flags
|
|
|
|
outCount = outCount & (1<<15 - 1)
|
|
|
|
}
|
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
cursortyp := _type.newVariable("", _type.Addr+uintptr(uadd), prtyp, _type.mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
var buf bytes.Buffer
|
|
|
|
if anonymous {
|
|
|
|
buf.WriteString("func(")
|
|
|
|
} else {
|
|
|
|
buf.WriteString("(")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := int64(0); i < inCount; i++ {
|
|
|
|
argtype := cursortyp.maybeDereference()
|
2017-04-21 06:55:53 +00:00
|
|
|
cursortyp.Addr += uintptr(_type.bi.Arch.PtrSize())
|
2019-05-08 21:06:38 +00:00
|
|
|
argtypename, _, err := nameOfRuntimeType(mds, argtype)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
buf.WriteString(argtypename)
|
|
|
|
if i != inCount-1 {
|
|
|
|
buf.WriteString(", ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buf.WriteString(")")
|
|
|
|
|
|
|
|
switch outCount {
|
|
|
|
case 0:
|
|
|
|
// nothing to do
|
|
|
|
case 1:
|
|
|
|
buf.WriteString(" ")
|
|
|
|
argtype := cursortyp.maybeDereference()
|
2019-05-08 21:06:38 +00:00
|
|
|
argtypename, _, err := nameOfRuntimeType(mds, argtype)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
buf.WriteString(argtypename)
|
|
|
|
default:
|
|
|
|
buf.WriteString(" (")
|
|
|
|
for i := int64(0); i < outCount; i++ {
|
|
|
|
argtype := cursortyp.maybeDereference()
|
2017-04-21 06:55:53 +00:00
|
|
|
cursortyp.Addr += uintptr(_type.bi.Arch.PtrSize())
|
2019-05-08 21:06:38 +00:00
|
|
|
argtypename, _, err := nameOfRuntimeType(mds, argtype)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
buf.WriteString(argtypename)
|
|
|
|
if i != inCount-1 {
|
|
|
|
buf.WriteString(", ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buf.WriteString(")")
|
|
|
|
}
|
|
|
|
return buf.String(), nil
|
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
func nameOfInterfaceRuntimeType(mds []moduleData, _type *Variable, kind, tflag int64) (string, error) {
|
2016-09-08 16:11:20 +00:00
|
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString("interface {")
|
|
|
|
|
2017-05-03 07:56:59 +00:00
|
|
|
methods, _ := _type.structMember(interfacetypeFieldMhdr)
|
2018-10-29 11:22:03 +00:00
|
|
|
methods.loadArrayValues(0, LoadConfig{false, 1, 0, 4096, -1, 0})
|
2016-09-08 16:11:20 +00:00
|
|
|
if methods.Unreadable != nil {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(methods.Children) == 0 {
|
|
|
|
buf.WriteString("}")
|
|
|
|
return buf.String(), nil
|
|
|
|
}
|
2018-08-31 18:08:18 +00:00
|
|
|
buf.WriteString(" ")
|
2016-09-08 16:11:20 +00:00
|
|
|
|
|
|
|
for i, im := range methods.Children {
|
|
|
|
var methodname, methodtype string
|
|
|
|
for i := range im.Children {
|
|
|
|
switch im.Children[i].Name {
|
2017-05-03 07:56:59 +00:00
|
|
|
case imethodFieldName:
|
2016-09-08 16:11:20 +00:00
|
|
|
nameoff, _ := constant.Int64Val(im.Children[i].Value)
|
|
|
|
var err error
|
2019-05-08 21:06:38 +00:00
|
|
|
methodname, _, _, err = resolveNameOff(_type.bi, mds, _type.Addr, uintptr(nameoff), _type.mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2017-05-03 07:56:59 +00:00
|
|
|
case imethodFieldItyp:
|
2016-09-08 16:11:20 +00:00
|
|
|
typeoff, _ := constant.Int64Val(im.Children[i].Value)
|
2019-05-08 21:06:38 +00:00
|
|
|
typ, err := resolveTypeOff(_type.bi, mds, _type.Addr, uintptr(typeoff), _type.mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
typ, err = specificRuntimeType(typ, int64(reflect.Func))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
var tflag int64
|
2017-02-07 21:08:11 +00:00
|
|
|
if tflagField := typ.loadFieldNamed("tflag"); tflagField != nil && tflagField.Value != nil {
|
2016-09-08 16:11:20 +00:00
|
|
|
tflag, _ = constant.Int64Val(tflagField.Value)
|
|
|
|
}
|
2019-05-08 21:06:38 +00:00
|
|
|
methodtype, err = nameOfFuncRuntimeType(mds, typ, tflag, false)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf.WriteString(methodname)
|
|
|
|
buf.WriteString(methodtype)
|
|
|
|
|
|
|
|
if i != len(methods.Children)-1 {
|
|
|
|
buf.WriteString("; ")
|
|
|
|
} else {
|
|
|
|
buf.WriteString(" }")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return buf.String(), nil
|
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
func nameOfStructRuntimeType(mds []moduleData, _type *Variable, kind, tflag int64) (string, error) {
|
2016-09-08 16:11:20 +00:00
|
|
|
var buf bytes.Buffer
|
|
|
|
buf.WriteString("struct {")
|
|
|
|
|
|
|
|
fields, _ := _type.structMember("fields")
|
2018-10-29 11:22:03 +00:00
|
|
|
fields.loadArrayValues(0, LoadConfig{false, 2, 0, 4096, -1, 0})
|
2016-09-08 16:11:20 +00:00
|
|
|
if fields.Unreadable != nil {
|
|
|
|
return "", fields.Unreadable
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(fields.Children) == 0 {
|
|
|
|
buf.WriteString("}")
|
|
|
|
return buf.String(), nil
|
|
|
|
}
|
2018-08-31 18:08:18 +00:00
|
|
|
buf.WriteString(" ")
|
2016-09-08 16:11:20 +00:00
|
|
|
|
|
|
|
for i, field := range fields.Children {
|
|
|
|
var fieldname, fieldtypename string
|
|
|
|
var typeField *Variable
|
2017-05-03 07:56:59 +00:00
|
|
|
isembed := false
|
2016-09-08 16:11:20 +00:00
|
|
|
for i := range field.Children {
|
|
|
|
switch field.Children[i].Name {
|
|
|
|
case "name":
|
2017-05-03 07:56:59 +00:00
|
|
|
var nameoff int64
|
|
|
|
switch field.Children[i].Kind {
|
|
|
|
case reflect.Struct:
|
|
|
|
nameoff = int64(field.Children[i].fieldVariable("bytes").Children[0].Addr)
|
|
|
|
default:
|
|
|
|
nameoff, _ = constant.Int64Val(field.Children[i].Value)
|
|
|
|
}
|
|
|
|
|
2016-09-08 16:11:20 +00:00
|
|
|
var err error
|
2017-04-13 23:19:57 +00:00
|
|
|
fieldname, _, _, err = loadName(_type.bi, uintptr(nameoff), _type.mem)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
case "typ":
|
|
|
|
typeField = field.Children[i].maybeDereference()
|
|
|
|
var err error
|
2019-05-08 21:06:38 +00:00
|
|
|
fieldtypename, _, err = nameOfRuntimeType(mds, typeField)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2017-05-03 07:56:59 +00:00
|
|
|
|
|
|
|
case "offsetAnon":
|
|
|
|
// The offsetAnon field of runtime.structfield combines the offset of
|
|
|
|
// the struct field from the base address of the struct with a flag
|
2018-03-20 10:05:35 +00:00
|
|
|
// determining whether the field is anonymous (i.e. an embedded struct).
|
2017-05-03 07:56:59 +00:00
|
|
|
//
|
|
|
|
// offsetAnon = (offset<<1) | (anonFlag)
|
|
|
|
//
|
|
|
|
// Here we are only interested in the anonymous flag.
|
|
|
|
offsetAnon, _ := constant.Int64Val(field.Children[i].Value)
|
|
|
|
isembed = offsetAnon%2 != 0
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fieldname will be the empty string for anonymous fields
|
2017-05-03 07:56:59 +00:00
|
|
|
if fieldname != "" && !isembed {
|
2016-09-08 16:11:20 +00:00
|
|
|
buf.WriteString(fieldname)
|
|
|
|
buf.WriteString(" ")
|
|
|
|
}
|
|
|
|
buf.WriteString(fieldtypename)
|
|
|
|
if i != len(fields.Children)-1 {
|
|
|
|
buf.WriteString("; ")
|
|
|
|
} else {
|
|
|
|
buf.WriteString(" }")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf.String(), nil
|
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
func fieldToType(mds []moduleData, _type *Variable, fieldName string) (string, error) {
|
2016-09-08 16:11:20 +00:00
|
|
|
typeField, err := _type.structMember(fieldName)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
typeField = typeField.maybeDereference()
|
2019-05-08 21:06:38 +00:00
|
|
|
typename, _, err := nameOfRuntimeType(mds, typeField)
|
2016-09-08 16:11:20 +00:00
|
|
|
return typename, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func specificRuntimeType(_type *Variable, kind int64) (*Variable, error) {
|
2017-05-03 07:56:59 +00:00
|
|
|
typ, err := typeForKind(kind, _type.bi)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-05-03 07:56:59 +00:00
|
|
|
if typ == nil {
|
|
|
|
return _type, nil
|
|
|
|
}
|
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
return _type.newVariable(_type.Name, _type.Addr, typ, _type.mem), nil
|
2017-05-03 07:56:59 +00:00
|
|
|
}
|
2016-09-08 16:11:20 +00:00
|
|
|
|
2017-05-03 07:56:59 +00:00
|
|
|
// See reflect.(*rtype).uncommon in $GOROOT/src/reflect/type.go
|
|
|
|
func uncommon(_type *Variable, tflag int64) *Variable {
|
|
|
|
if tflag&tflagUncommon == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
typ, err := _type.bi.findType("runtime.uncommontype")
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
return _type.newVariable(_type.Name, _type.Addr+uintptr(_type.RealType.Size()), typ, _type.mem)
|
2017-05-03 07:56:59 +00:00
|
|
|
}
|
|
|
|
|
2020-02-20 18:52:48 +00:00
|
|
|
var kindToRuntimeTypeName = map[reflect.Kind]string{
|
|
|
|
reflect.Array: "runtime.arraytype",
|
|
|
|
reflect.Chan: "runtime.chantype",
|
|
|
|
reflect.Func: "runtime.functype",
|
|
|
|
reflect.Interface: "runtime.interfacetype",
|
|
|
|
reflect.Map: "runtime.maptype",
|
|
|
|
reflect.Ptr: "runtime.ptrtype",
|
|
|
|
reflect.Slice: "runtime.slicetype",
|
|
|
|
reflect.Struct: "runtime.structtype",
|
|
|
|
}
|
|
|
|
|
2017-05-03 07:56:59 +00:00
|
|
|
// typeForKind returns a *dwarf.StructType describing the specialization of
|
|
|
|
// runtime._type for the specified type kind. For example if kind is
|
|
|
|
// reflect.ArrayType it will return runtime.arraytype
|
|
|
|
func typeForKind(kind int64, bi *BinaryInfo) (*godwarf.StructType, error) {
|
2020-02-20 18:52:48 +00:00
|
|
|
typename, ok := kindToRuntimeTypeName[reflect.Kind(kind&kindMask)]
|
|
|
|
if !ok {
|
2017-05-03 07:56:59 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
2020-02-20 18:52:48 +00:00
|
|
|
typ, err := bi.findType(typename)
|
2016-09-08 16:11:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-02-20 18:52:48 +00:00
|
|
|
typ = resolveTypedef(typ)
|
|
|
|
return typ.(*godwarf.StructType), nil
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
2018-07-27 17:19:01 +00:00
|
|
|
|
|
|
|
func dwarfToRuntimeType(bi *BinaryInfo, mem MemoryReadWriter, typ godwarf.Type) (typeAddr uint64, typeKind uint64, found bool, err error) {
|
2019-05-08 21:06:38 +00:00
|
|
|
so := bi.typeToImage(typ)
|
|
|
|
rdr := so.DwarfReader()
|
2018-07-27 17:19:01 +00:00
|
|
|
rdr.Seek(typ.Common().Offset)
|
|
|
|
e, err := rdr.Next()
|
|
|
|
if err != nil {
|
|
|
|
return 0, 0, false, err
|
|
|
|
}
|
|
|
|
off, ok := e.Val(godwarf.AttrGoRuntimeType).(uint64)
|
|
|
|
if !ok {
|
|
|
|
return 0, 0, false, nil
|
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
mds, err := loadModuleData(bi, mem)
|
|
|
|
if err != nil {
|
2018-07-27 17:19:01 +00:00
|
|
|
return 0, 0, false, err
|
|
|
|
}
|
|
|
|
|
2019-05-08 21:06:38 +00:00
|
|
|
md := bi.imageToModuleData(so, mds)
|
|
|
|
if md == nil {
|
|
|
|
if so.index > 0 {
|
|
|
|
return 0, 0, false, fmt.Errorf("could not find module data for type %s (shared object: %q)", typ, so.Path)
|
|
|
|
} else {
|
|
|
|
return 0, 0, false, fmt.Errorf("could not find module data for type %s", typ)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
typeAddr = uint64(md.types) + off
|
2018-07-27 17:19:01 +00:00
|
|
|
|
|
|
|
rtyp, err := bi.findType("runtime._type")
|
|
|
|
if err != nil {
|
|
|
|
return 0, 0, false, err
|
|
|
|
}
|
|
|
|
_type := newVariable("", uintptr(typeAddr), rtyp, bi, mem)
|
|
|
|
kindv := _type.loadFieldNamed("kind")
|
|
|
|
if kindv.Unreadable != nil || kindv.Kind != reflect.Uint {
|
|
|
|
return 0, 0, false, fmt.Errorf("unreadable interface type: %v", kindv.Unreadable)
|
|
|
|
}
|
|
|
|
typeKind, _ = constant.Uint64Val(kindv.Value)
|
|
|
|
return typeAddr, typeKind, true, nil
|
|
|
|
}
|