github.com/lsg2020/gort@v0.0.0-20220515072951-7a7794baa036/gort_types.go (about)

     1  package gort
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"fmt"
     6  	"reflect"
     7  	"unsafe"
     8  
     9  	"github.com/go-delve/delve/pkg/dwarf/godwarf"
    10  	"github.com/go-delve/delve/pkg/proc"
    11  )
    12  
    13  func (d *DwarfRT) ForeachType(f func(name string)) error {
    14  	if err := d.check(); err != nil {
    15  		return err
    16  	}
    17  
    18  	types, err := d.bi.Types()
    19  	if err != nil {
    20  		return err
    21  	}
    22  	for _, name := range types {
    23  		f(name)
    24  	}
    25  	return nil
    26  }
    27  
    28  func (d *DwarfRT) FindType(name string) (reflect.Type, error) {
    29  	if err := d.check(); err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	dwarfType, err := findType(d.bi, name)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	typeAddr, err := d.dwarfToRuntimeType(dwarfType, name)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	typ := reflect.TypeOf(*(*interface{})(unsafe.Pointer(&typeAddr)))
    44  	return typ, nil
    45  }
    46  
    47  func (d *DwarfRT) findImageType(img *proc.Image, name string) uint64 {
    48  	if d.imageCacheTypes == nil {
    49  		d.imageCacheTypes = make(map[*proc.Image]map[string]uint64)
    50  	}
    51  	cache, ok := d.imageCacheTypes[img]
    52  	if !ok {
    53  		cache = make(map[string]uint64)
    54  		d.imageCacheTypes[img] = cache
    55  
    56  		reader := img.DwarfReader()
    57  		md := imageToModuleData(d.bi, img, d.mds)
    58  		if md == nil {
    59  			return 0
    60  		}
    61  
    62  		rRuntimeTypes := reflect.ValueOf(img).Elem().FieldByName("runtimeTypeToDIE")
    63  		iter := rRuntimeTypes.MapRange()
    64  		for iter.Next() {
    65  			k := iter.Key()
    66  			v := iter.Value()
    67  
    68  			offset := v.FieldByName("offset").Uint()
    69  			reader.Seek(dwarf.Offset(offset))
    70  			entry, err := reader.Next()
    71  			if err != nil || entry == nil {
    72  				continue
    73  			}
    74  			entryName, ok := entry.Val(dwarf.AttrName).(string)
    75  			if !ok {
    76  				continue
    77  			}
    78  			if k.Uint() == 0 {
    79  				continue
    80  			}
    81  
    82  			typeAddr := md.types + k.Uint()
    83  			if typeAddr < md.types || typeAddr >= md.etypes {
    84  				cache[entryName] = k.Uint()
    85  			} else {
    86  				cache[entryName] = typeAddr
    87  			}
    88  		}
    89  	}
    90  
    91  	return cache[name]
    92  }
    93  
    94  func (d *DwarfRT) dwarfToRuntimeType(typ godwarf.Type, name string) (typeAddr uint64, err error) {
    95  	bi := d.bi
    96  	mds := d.mds
    97  
    98  	if typ.Common().Index >= len(bi.Images) {
    99  		return 0, fmt.Errorf("could not find image for type %s", name)
   100  	}
   101  	img := bi.Images[typ.Common().Index]
   102  	rdr := img.DwarfReader()
   103  	rdr.Seek(typ.Common().Offset)
   104  	e, err := rdr.Next()
   105  	if err != nil {
   106  		return 0, fmt.Errorf("could not find dwarf entry for type:%s err:%s", name, err)
   107  	}
   108  	entryName, ok := e.Val(dwarf.AttrName).(string)
   109  	if !ok || entryName != name {
   110  		return 0, fmt.Errorf("could not find name for type:%s entry:%s", name, entryName)
   111  	}
   112  	off, ok := e.Val(godwarf.AttrGoRuntimeType).(uint64)
   113  	if !ok || off == 0 {
   114  		for i, img := range bi.Images {
   115  			if i == 0 {
   116  				continue
   117  			}
   118  			addr := d.findImageType(img, name)
   119  			if addr != 0 {
   120  				return addr, nil
   121  			}
   122  		}
   123  		return 0, fmt.Errorf("could not find runtime type for type:%s", name)
   124  	}
   125  
   126  	md := imageToModuleData(bi, img, mds)
   127  	if md == nil {
   128  		return 0, fmt.Errorf("could not find module data for type %s", name)
   129  	}
   130  
   131  	typeAddr = md.types + off
   132  	if typeAddr < md.types || typeAddr >= md.etypes {
   133  		return off, nil
   134  	}
   135  	return typeAddr, nil
   136  }