github.com/pkujhd/goloader@v0.0.0-20240411034752-1a28096bd7bd/type.go (about)

     1  package goloader
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  	"unsafe"
     8  
     9  	"github.com/pkujhd/goloader/obj"
    10  )
    11  
    12  type tflag uint8
    13  
    14  const (
    15  	tflagUncommon      tflag = 1 << 0
    16  	tflagExtraStar     tflag = 1 << 1
    17  	tflagNamed         tflag = 1 << 2
    18  	tflagRegularMemory tflag = 1 << 3 // equal and hash can treat values of this type as a single region of t.size bytes
    19  )
    20  
    21  // See reflect/value.go emptyInterface
    22  type emptyInterface struct {
    23  	typ  *_type
    24  	word unsafe.Pointer
    25  }
    26  
    27  // See reflect/value.go sliceHeader
    28  type sliceHeader struct {
    29  	Data uintptr
    30  	Len  int
    31  	Cap  int
    32  }
    33  
    34  // See reflect/value.go stringHeader
    35  type stringHeader struct {
    36  	Data uintptr
    37  	Len  int
    38  }
    39  
    40  // Method on non-interface type
    41  type method struct {
    42  	name nameOff // name of method
    43  	mtyp typeOff // method type (without receiver)
    44  	ifn  textOff // fn used in interface call (one-word receiver)
    45  	tfn  textOff // fn used for normal method call
    46  }
    47  
    48  type imethod struct {
    49  	name nameOff
    50  	ityp typeOff
    51  }
    52  
    53  type interfacetype struct {
    54  	typ     _type
    55  	pkgpath name
    56  	mhdr    []imethod
    57  }
    58  
    59  type name struct {
    60  	bytes *byte
    61  }
    62  
    63  type funcType struct {
    64  	_type
    65  	inCount  uint16
    66  	outCount uint16 // top bit is set if last input parameter is ...
    67  }
    68  
    69  type uncommonType struct {
    70  	pkgPath nameOff // import path; empty for built-in types like int, string
    71  	mcount  uint16  // number of methods
    72  	xcount  uint16  // number of exported methods
    73  	moff    uint32  // offset from this uncommontype to [mcount]method
    74  	_       uint32  // unused
    75  }
    76  
    77  //go:linkname _Kind reflect.(*rtype).Kind
    78  func _Kind(t *_type) reflect.Kind
    79  
    80  //go:linkname _NumField reflect.(*rtype).NumField
    81  func _NumField(t *_type) int
    82  
    83  //go:linkname _Field reflect.(*rtype).Field
    84  func _Field(t *_type, i int) reflect.StructField
    85  
    86  //go:linkname _NumIn reflect.(*rtype).NumIn
    87  func _NumIn(t *_type) int
    88  
    89  //go:linkname _In reflect.(*rtype).In
    90  func _In(t *_type, i int) reflect.Type
    91  
    92  //go:linkname _NumOut reflect.(*rtype).NumOut
    93  func _NumOut(t *_type) int
    94  
    95  //go:linkname _Out reflect.(*rtype).Out
    96  func _Out(t *_type, i int) reflect.Type
    97  
    98  //go:linkname _Key reflect.(*rtype).Key
    99  func _Key(t *_type) reflect.Type
   100  
   101  //go:linkname _Elem reflect.(*rtype).Elem
   102  func _Elem(t *_type) reflect.Type
   103  
   104  //go:linkname _NumMethod reflect.(*rtype).NumMethod
   105  func _NumMethod(t *_type) int
   106  
   107  //go:linkname _Method reflect.(*rtype).Method
   108  func _Method(t *_type, i int) reflect.Method
   109  
   110  //go:linkname _ChanDir reflect.(*rtype).ChanDir
   111  func _ChanDir(t *_type) reflect.ChanDir
   112  
   113  //go:linkname _Len reflect.(*rtype).Len
   114  func _Len(t *_type) int
   115  
   116  //go:linkname _IsVariadic reflect.(*rtype).IsVariadic
   117  func _IsVariadic(t *_type) bool
   118  
   119  //go:linkname _Name reflect.(*rtype).Name
   120  func _Name(t *_type) string
   121  
   122  //go:linkname _String reflect.(*rtype).String
   123  func _String(t *_type) string
   124  
   125  //go:linkname _PkgPath reflect.(*rtype).PkgPath
   126  func _PkgPath(t *_type) string
   127  
   128  //go:linkname typelinksinit runtime.typelinksinit
   129  func typelinksinit()
   130  
   131  func (t *_type) Kind() reflect.Kind              { return _Kind(t) }
   132  func (t *_type) NumField() int                   { return _NumField(t) }
   133  func (t *_type) Field(i int) reflect.StructField { return _Field(t, i) }
   134  func (t *_type) NumIn() int                      { return _NumIn(t) }
   135  func (t *_type) In(i int) reflect.Type           { return _In(t, i) }
   136  func (t *_type) NumOut() int                     { return _NumOut(t) }
   137  func (t *_type) Out(i int) reflect.Type          { return _Out(t, i) }
   138  func (t *_type) Key() reflect.Type               { return _Key(t) }
   139  func (t *_type) Elem() reflect.Type              { return _Elem(t) }
   140  func (t *_type) NumMethod() int                  { return _NumMethod(t) }
   141  func (t *_type) Method(i int) reflect.Method     { return _Method(t, i) }
   142  func (t *_type) ChanDir() reflect.ChanDir        { return _ChanDir(t) }
   143  func (t *_type) Len() int                        { return _Len(t) }
   144  func (t *_type) IsVariadic() bool                { return _IsVariadic(t) }
   145  func (t *_type) Name() string                    { return _Name(t) }
   146  func (t *_type) String() string                  { return _String(t) }
   147  func (t *_type) PkgPath() string                 { return _PkgPath(t) }
   148  
   149  func rtypeOf(i reflect.Type) *_type {
   150  	eface := (*emptyInterface)(unsafe.Pointer(&i))
   151  	return (*_type)(eface.word)
   152  }
   153  
   154  func resolveTypeName(typ *_type) string {
   155  	pkgPath := obj.PathToPrefix(typ.PkgPath())
   156  	name := typ.Name()
   157  	if pkgPath != EmptyString && name != EmptyString {
   158  		return pkgPath + "." + name
   159  	}
   160  	if name != EmptyString && typ.Kind() != reflect.UnsafePointer {
   161  		return name
   162  	}
   163  	//golang <= 1.16 map.bucket has a self-contained struct field
   164  	if strings.HasPrefix(typ.String(), "map.bucket[") {
   165  		return typ.String()
   166  	}
   167  	switch typ.Kind() {
   168  	case reflect.Ptr:
   169  		name := "*" + resolveTypeName(rtypeOf(typ.Elem()))
   170  		return name
   171  	case reflect.Struct:
   172  		if typ.NumField() == 0 {
   173  			return typ.String()
   174  		}
   175  		fields := make([]string, typ.NumField())
   176  		for i := 0; i < typ.NumField(); i++ {
   177  			fieldName := EmptyString
   178  			if !typ.Field(i).Anonymous {
   179  				if typ.Field(i).PkgPath != EmptyString {
   180  					fieldName = obj.PathToPrefix(typ.Field(i).PkgPath) + "."
   181  				}
   182  				fieldName = fieldName + typ.Field(i).Name + " "
   183  			}
   184  			fields[i] = fieldName + resolveTypeName(rtypeOf(typ.Field(i).Type))
   185  			if typ.Field(i).Tag != EmptyString {
   186  				fields[i] = fields[i] + fmt.Sprintf(" %q", string(typ.Field(i).Tag))
   187  			}
   188  		}
   189  		return fmt.Sprintf("struct { %s }", strings.Join(fields, "; "))
   190  	case reflect.Map:
   191  		return fmt.Sprintf("map[%s]%s", resolveTypeName(rtypeOf(typ.Key())), resolveTypeName(rtypeOf(typ.Elem())))
   192  	case reflect.Chan:
   193  		return fmt.Sprintf("%s %s", typ.ChanDir().String(), resolveTypeName(rtypeOf(typ.Elem())))
   194  	case reflect.Slice:
   195  		return fmt.Sprintf("[]%s", resolveTypeName(rtypeOf(typ.Elem())))
   196  	case reflect.Array:
   197  		return fmt.Sprintf("[%d]%s", typ.Len(), resolveTypeName(rtypeOf(typ.Elem())))
   198  	case reflect.Func:
   199  		ins := make([]string, typ.NumIn())
   200  		outs := make([]string, typ.NumOut())
   201  		for i := 0; i < typ.NumIn(); i++ {
   202  			if i == typ.NumIn()-1 && typ.IsVariadic() {
   203  				ins[i] = "..." + resolveTypeName(rtypeOf(typ.In(i).Elem()))
   204  			} else {
   205  				ins[i] = resolveTypeName(rtypeOf(typ.In(i)))
   206  			}
   207  		}
   208  		for i := 0; i < typ.NumOut(); i++ {
   209  			outs[i] = resolveTypeName(rtypeOf(typ.Out(i)))
   210  		}
   211  		name := "func(" + strings.Join(ins, ", ") + ")"
   212  		if len(outs) > 0 {
   213  			name += " "
   214  		}
   215  		outName := strings.Join(outs, ", ")
   216  		if len(outs) > 1 {
   217  			outName = "(" + outName + ")"
   218  		}
   219  		return name + outName
   220  	case reflect.Interface:
   221  		if typ.NumMethod() == 0 {
   222  			return typ.String()
   223  		}
   224  		methods := make([]string, typ.NumMethod())
   225  		for i := 0; i < typ.NumMethod(); i++ {
   226  			method := typ.Method(i)
   227  			methods[i] = method.Name + strings.TrimPrefix(resolveTypeName(rtypeOf(method.Type)), "func")
   228  		}
   229  		return fmt.Sprintf("interface { %s }", strings.Join(methods, "; "))
   230  	case reflect.Bool,
   231  		reflect.Int, reflect.Uint,
   232  		reflect.Int64, reflect.Uint64,
   233  		reflect.Int32, reflect.Uint32,
   234  		reflect.Int16, reflect.Uint16,
   235  		reflect.Int8, reflect.Uint8,
   236  		reflect.Float64, reflect.Float32,
   237  		reflect.Complex64, reflect.Complex128,
   238  		reflect.String, reflect.UnsafePointer,
   239  		reflect.Uintptr:
   240  		return typ.String()
   241  	default:
   242  		panic("unexpected builtin type: " + typ.String())
   243  	}
   244  }
   245  
   246  func RegTypes(symPtr map[string]uintptr, interfaces ...interface{}) {
   247  	for _, inter := range interfaces {
   248  		header := (*emptyInterface)(unsafe.Pointer(&inter))
   249  		registerType(header.typ, symPtr)
   250  	}
   251  }