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

     1  package proc
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"errors"
     6  	"fmt"
     7  	"go/constant"
     8  	"reflect"
     9  
    10  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/godwarf"
    11  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/reader"
    12  )
    13  
    14  // The kind field in runtime._type is a reflect.Kind value plus
    15  // some extra flags defined here.
    16  // See equivalent declaration in $GOROOT/src/reflect/type.go
    17  const (
    18  	kindDirectIface = 1 << 5 // +rtype kindDirectIface|internal/abi.KindDirectIface
    19  	kindGCProg      = 1 << 6 // +rtype kindGCProg|internal/abi.KindGCProg
    20  	kindNoPointers  = 1 << 7
    21  	kindMask        = (1 << 5) - 1 // +rtype kindMask|internal/abi.KindMask
    22  )
    23  
    24  type runtimeTypeDIE struct {
    25  	offset dwarf.Offset
    26  	kind   int64
    27  }
    28  
    29  func pointerTo(typ godwarf.Type, arch *Arch) godwarf.Type {
    30  	return &godwarf.PtrType{
    31  		CommonType: godwarf.CommonType{
    32  			ByteSize:    int64(arch.PtrSize()),
    33  			Name:        "*" + typ.Common().Name,
    34  			ReflectKind: reflect.Ptr,
    35  			Offset:      0,
    36  		},
    37  		Type: typ,
    38  	}
    39  }
    40  
    41  type functionsDebugInfoByEntry []Function
    42  
    43  func (v functionsDebugInfoByEntry) Len() int           { return len(v) }
    44  func (v functionsDebugInfoByEntry) Less(i, j int) bool { return v[i].Entry < v[j].Entry }
    45  func (v functionsDebugInfoByEntry) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
    46  
    47  type compileUnitsByOffset []*compileUnit
    48  
    49  func (v compileUnitsByOffset) Len() int               { return len(v) }
    50  func (v compileUnitsByOffset) Less(i int, j int) bool { return v[i].offset < v[j].offset }
    51  func (v compileUnitsByOffset) Swap(i int, j int)      { v[i], v[j] = v[j], v[i] }
    52  
    53  type packageVarsByAddr []packageVar
    54  
    55  func (v packageVarsByAddr) Len() int               { return len(v) }
    56  func (v packageVarsByAddr) Less(i int, j int) bool { return v[i].addr < v[j].addr }
    57  func (v packageVarsByAddr) Swap(i int, j int)      { v[i], v[j] = v[j], v[i] }
    58  
    59  type loadDebugInfoMapsContext struct {
    60  	ardr                *reader.Reader
    61  	abstractOriginTable map[dwarf.Offset]int
    62  	knownPackageVars    map[string]struct{}
    63  	offsetToVersion     map[dwarf.Offset]uint8
    64  }
    65  
    66  func newLoadDebugInfoMapsContext(bi *BinaryInfo, image *Image, offsetToVersion map[dwarf.Offset]uint8) *loadDebugInfoMapsContext {
    67  	ctxt := &loadDebugInfoMapsContext{}
    68  
    69  	ctxt.ardr = image.DwarfReader()
    70  	ctxt.abstractOriginTable = make(map[dwarf.Offset]int)
    71  	ctxt.offsetToVersion = offsetToVersion
    72  
    73  	ctxt.knownPackageVars = map[string]struct{}{}
    74  	for _, v := range bi.packageVars {
    75  		ctxt.knownPackageVars[v.name] = struct{}{}
    76  	}
    77  
    78  	return ctxt
    79  }
    80  
    81  func (ctxt *loadDebugInfoMapsContext) lookupAbstractOrigin(bi *BinaryInfo, off dwarf.Offset) int {
    82  	r, ok := ctxt.abstractOriginTable[off]
    83  	if !ok {
    84  		bi.Functions = append(bi.Functions, Function{})
    85  		r = len(bi.Functions) - 1
    86  		bi.Functions[r].offset = off
    87  		ctxt.abstractOriginTable[off] = r
    88  	}
    89  	return r
    90  }
    91  
    92  // runtimeTypeToDIE returns the DIE corresponding to the runtime._type.
    93  // This is done in three different ways depending on the version of go.
    94  //   - Before go1.7 the type name is retrieved directly from the runtime._type
    95  //     and looked up in debug_info
    96  //   - After go1.7 the runtime._type struct is read recursively to reconstruct
    97  //     the name of the type, and then the type's name is used to look up
    98  //     debug_info
    99  //   - After go1.11 the runtimeTypeToDIE map is used to look up the address of
   100  //     the type and map it directly to a DIE.
   101  func runtimeTypeToDIE(_type *Variable, dataAddr uint64) (typ godwarf.Type, kind int64, err error) {
   102  	bi := _type.bi
   103  
   104  	_type = _type.maybeDereference()
   105  
   106  	// go 1.11 implementation: use extended attribute in debug_info
   107  
   108  	mds, err := loadModuleData(bi, _type.mem)
   109  	if err != nil {
   110  		return nil, 0, fmt.Errorf("error loading module data: %v", err)
   111  	}
   112  
   113  	md := findModuleDataForType(bi, mds, _type.Addr, _type.mem)
   114  	if md != nil {
   115  		so := bi.moduleDataToImage(md)
   116  		if so != nil {
   117  			if rtdie, ok := so.runtimeTypeToDIE[_type.Addr-md.types]; ok {
   118  				typ, err := godwarf.ReadType(so.dwarf, so.index, rtdie.offset, so.typeCache)
   119  				if err != nil {
   120  					return nil, 0, fmt.Errorf("invalid interface type: %v", err)
   121  				}
   122  				if rtdie.kind == -1 {
   123  					if kindField := _type.loadFieldNamed("kind"); kindField != nil && kindField.Value != nil {
   124  						rtdie.kind, _ = constant.Int64Val(kindField.Value)
   125  					} else if kindField := _type.loadFieldNamed("Kind_"); kindField != nil && kindField.Value != nil {
   126  						rtdie.kind, _ = constant.Int64Val(kindField.Value)
   127  					}
   128  				}
   129  				return typ, rtdie.kind, nil
   130  			}
   131  		}
   132  	}
   133  
   134  	return nil, 0, fmt.Errorf("could not resolve interface type")
   135  }
   136  
   137  // resolveParametricType returns the real type of t if t is a parametric
   138  // type, by reading the correct dictionary entry.
   139  func resolveParametricType(bi *BinaryInfo, mem MemoryReadWriter, t godwarf.Type, dictAddr uint64) (godwarf.Type, error) {
   140  	ptyp, _ := t.(*godwarf.ParametricType)
   141  	if ptyp == nil {
   142  		return t, nil
   143  	}
   144  	if dictAddr == 0 {
   145  		return ptyp.TypedefType.Type, errors.New("parametric type without a dictionary")
   146  	}
   147  	rtypeAddr, err := readUintRaw(mem, dictAddr+uint64(ptyp.DictIndex*int64(bi.Arch.PtrSize())), int64(bi.Arch.PtrSize()))
   148  	if err != nil {
   149  		return ptyp.TypedefType.Type, err
   150  	}
   151  	runtimeType, err := bi.findType(bi.runtimeTypeTypename())
   152  	if err != nil {
   153  		return ptyp.TypedefType.Type, err
   154  	}
   155  	_type := newVariable("", rtypeAddr, runtimeType, bi, mem)
   156  
   157  	typ, _, err := runtimeTypeToDIE(_type, 0)
   158  	if err != nil {
   159  		return ptyp.TypedefType.Type, err
   160  	}
   161  
   162  	return typ, nil
   163  }
   164  
   165  func dwarfToRuntimeType(bi *BinaryInfo, mem MemoryReadWriter, typ godwarf.Type) (typeAddr uint64, typeKind uint64, found bool, err error) {
   166  	so := bi.typeToImage(typ)
   167  	rdr := so.DwarfReader()
   168  	rdr.Seek(typ.Common().Offset)
   169  	e, err := rdr.Next()
   170  	if err != nil {
   171  		return 0, 0, false, err
   172  	}
   173  	off, ok := e.Val(godwarf.AttrGoRuntimeType).(uint64)
   174  	if !ok {
   175  		return 0, 0, false, nil
   176  	}
   177  
   178  	mds, err := loadModuleData(bi, mem)
   179  	if err != nil {
   180  		return 0, 0, false, err
   181  	}
   182  
   183  	md := bi.imageToModuleData(so, mds)
   184  	if md == nil {
   185  		if so.index > 0 {
   186  			return 0, 0, false, fmt.Errorf("could not find module data for type %s (shared object: %q)", typ, so.Path)
   187  		} else {
   188  			return 0, 0, false, fmt.Errorf("could not find module data for type %s", typ)
   189  		}
   190  	}
   191  
   192  	typeAddr = md.types + off
   193  
   194  	rtyp, err := bi.findType(bi.runtimeTypeTypename())
   195  	if err != nil {
   196  		return 0, 0, false, err
   197  	}
   198  	_type := newVariable("", typeAddr, rtyp, bi, mem)
   199  	kindv := _type.loadFieldNamed("kind")
   200  	if kindv == nil || kindv.Unreadable != nil || kindv.Kind != reflect.Uint {
   201  		kindv = _type.loadFieldNamed("Kind_")
   202  	}
   203  	if kindv == nil || kindv.Unreadable != nil || kindv.Kind != reflect.Uint {
   204  		return 0, 0, false, fmt.Errorf("unreadable interface type: %v", kindv.Unreadable)
   205  	}
   206  	typeKind, _ = constant.Uint64Val(kindv.Value)
   207  	return typeAddr, typeKind, true, nil
   208  }