github.com/dearplain/goloader@v0.0.0-20190107071432-2b1e47d74273/type.go (about)

     1  package goloader
     2  
     3  import (
     4  	"reflect"
     5  	"runtime"
     6  	"strings"
     7  	"unsafe"
     8  )
     9  
    10  type tflag uint8
    11  
    12  type _type struct {
    13  	size       uintptr
    14  	ptrdata    uintptr // size of memory prefix holding all pointers
    15  	hash       uint32
    16  	tflag      tflag
    17  	align      uint8
    18  	fieldalign uint8
    19  	kind       uint8
    20  	alg        *typeAlg
    21  	// gcdata stores the GC type data for the garbage collector.
    22  	// If the KindGCProg bit is set in kind, gcdata is a GC program.
    23  	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
    24  	gcdata    *byte
    25  	str       nameOff
    26  	ptrToThis typeOff
    27  }
    28  
    29  type typeAlg struct {
    30  	// function for hashing objects of this type
    31  	// (ptr to object, seed) -> hash
    32  	hash func(unsafe.Pointer, uintptr) uintptr
    33  	// function for comparing objects of this type
    34  	// (ptr to object A, ptr to object B) -> ==?
    35  	equal func(unsafe.Pointer, unsafe.Pointer) bool
    36  }
    37  
    38  type imethod struct {
    39  	name nameOff
    40  	ityp typeOff
    41  }
    42  
    43  type interfacetype struct {
    44  	typ     _type
    45  	pkgpath name
    46  	mhdr    []imethod
    47  }
    48  
    49  type uncommonType struct {
    50  	pkgPath nameOff // import path; empty for built-in types like int, string
    51  	mcount  uint16  // number of methods
    52  	_       uint16  // unused
    53  	moff    uint32  // offset from this uncommontype to [mcount]method
    54  	_       uint32  // unused
    55  }
    56  
    57  type name struct {
    58  	bytes *byte
    59  }
    60  
    61  //go:linkname (*_type).uncommon runtime.(*_type).uncommon
    62  func (t *_type) uncommon() *uncommonType
    63  
    64  //go:linkname (*_type).nameOff runtime.(*_type).nameOff
    65  func (t *_type) nameOff(off nameOff) name
    66  
    67  //go:linkname (*_type).typeOff runtime.(*_type).typeOff
    68  func (t *_type) typeOff(off typeOff) *_type
    69  
    70  //go:linkname name.name runtime.name.name
    71  func (n name) name() (s string)
    72  
    73  func (t *_type) PkgPath() string {
    74  	ut := t.uncommon()
    75  	if ut == nil {
    76  		return ""
    77  	}
    78  	return t.nameOff(ut.pkgPath).name()
    79  }
    80  
    81  func (t *_type) Name() string {
    82  	return t.nameOff(t.str).name()
    83  }
    84  
    85  func (t *_type) Type() reflect.Type {
    86  	var obj interface{} = reflect.TypeOf(0)
    87  	(*interfaceHeader)(unsafe.Pointer(&obj)).word = unsafe.Pointer(t)
    88  	typ := obj.(reflect.Type)
    89  	return typ
    90  }
    91  
    92  func ToType(typ reflect.Type) *_type {
    93  	var obj interface{} = typ
    94  	typePtr := uintptr((*interfaceHeader)(unsafe.Pointer(&obj)).word)
    95  	return (*_type)(unsafe.Pointer(typePtr))
    96  }
    97  
    98  func GetFunctionName(i interface{}) string {
    99  	return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
   100  }
   101  
   102  func RegTypes(symPtr map[string]uintptr, interfaces ...interface{}) {
   103  	for _, ins := range interfaces {
   104  		v := reflect.ValueOf(ins)
   105  		regTypeInfo(symPtr, v)
   106  		if v.Kind() == reflect.Ptr {
   107  			v = v.Elem()
   108  			regTypeInfo(symPtr, v)
   109  		}
   110  	}
   111  }
   112  
   113  func regTypeInfo(symPtr map[string]uintptr, v reflect.Value) {
   114  	ins := v.Interface()
   115  	header := (*interfaceHeader)(unsafe.Pointer(&ins))
   116  
   117  	var ptr uintptr
   118  	var typePrefix string
   119  	var symName string
   120  	pptr := (uintptr)(header.word)
   121  	if v.Kind() == reflect.Func && pptr != 0 {
   122  		ptr = *(*uintptr)(header.word)
   123  		symName = GetFunctionName(ins)
   124  	} else {
   125  		ptr = uintptr(header.typ)
   126  		typePrefix = "type."
   127  		symName = v.Type().String()
   128  	}
   129  
   130  	if symName[0] == '*' {
   131  		typePrefix += "*"
   132  		symName = symName[1:]
   133  	}
   134  
   135  	pkgPath := (*_type)(unsafe.Pointer(header.typ)).PkgPath()
   136  
   137  	var symFullName string
   138  	lastSlash := strings.LastIndexByte(pkgPath, '/')
   139  	if lastSlash > -1 {
   140  		symFullName = typePrefix + pkgPath[:lastSlash] + "/" + symName
   141  	} else {
   142  		symFullName = typePrefix + symName
   143  	}
   144  	symPtr[symFullName] = ptr
   145  	// fmt.Println(symFullName, v.Kind())
   146  }
   147  
   148  //go:linkname getitab runtime.getitab
   149  func getitab(inter int, typ int, canfail bool) int
   150  
   151  func addIFaceSubFuncType(funcTypeMap map[string]*int, typemap map[typeOff]uintptr,
   152  	inter *interfacetype, dataBase int) {
   153  	pkgPath := inter.typ.PkgPath()
   154  	lastSlash := strings.LastIndexByte(pkgPath, '/')
   155  	var head = pkgPath
   156  	if lastSlash > -1 {
   157  		head = pkgPath[lastSlash+1:]
   158  	}
   159  	ni := len(inter.mhdr)
   160  	for k := 0; k < ni; k++ {
   161  		i := &inter.mhdr[k]
   162  		itype := inter.typ.typeOff(i.ityp)
   163  		name := itype.Name()
   164  		if name[0] == '*' {
   165  			name = name[1:]
   166  		}
   167  		name = strings.Replace(name, head+".", pkgPath+".", -1)
   168  		name = "type." + name
   169  		if symAddrPtr, ok := funcTypeMap[name]; ok {
   170  			itypePtr := int(uintptr(unsafe.Pointer(itype)))
   171  			*symAddrPtr = itypePtr
   172  			// fmt.Println(*symAddrPtr)
   173  			typemap[typeOff(itypePtr-dataBase)] = uintptr(itypePtr)
   174  			// fmt.Println(name, itypePtr-dataBase, itypePtr)
   175  		}
   176  	}
   177  }