github.com/AlaxLee/go-forceexport@v1.0.3/go114/forceexport.go (about)

     1  // for go1.14 and go1.15
     2  
     3  package forceexport
     4  
     5  import (
     6  	"fmt"
     7  	"reflect"
     8  	"runtime"
     9  	"unsafe"
    10  )
    11  
    12  // GetFunc gets the function defined by the given fully-qualified name. The
    13  // outFuncPtr parameter should be a pointer to a function with the appropriate
    14  // type (e.g. the address of a local variable), and is set to a new function
    15  // value that calls the specified function. If the specified function does not
    16  // exist, outFuncPtr is not set and an error is returned.
    17  func GetFunc(outFuncPtr interface{}, name string) error {
    18  	codePtr, err := FindFuncWithName(name)
    19  	if err != nil {
    20  		return err
    21  	}
    22  	CreateFuncForCodePtr(outFuncPtr, codePtr)
    23  	return nil
    24  }
    25  
    26  // Convenience struct for modifying the underlying code pointer of a function
    27  // value. The actual struct has other values, but always starts with a code
    28  // pointer.
    29  type Func struct {
    30  	codePtr uintptr
    31  }
    32  
    33  // CreateFuncForCodePtr is given a code pointer and creates a function value
    34  // that uses that pointer. The outFun argument should be a pointer to a function
    35  // of the proper type (e.g. the address of a local variable), and will be set to
    36  // the result function value.
    37  func CreateFuncForCodePtr(outFuncPtr interface{}, codePtr uintptr) {
    38  	outFuncVal := reflect.ValueOf(outFuncPtr).Elem()
    39  	// Use reflect.MakeFunc to create a well-formed function value that's
    40  	// guaranteed to be of the right type and guaranteed to be on the heap
    41  	// (so that we can modify it). We give a nil delegate function because
    42  	// it will never actually be called.
    43  	newFuncVal := reflect.MakeFunc(outFuncVal.Type(), nil)
    44  	// Use reflection on the reflect.Value (yep!) to grab the underling
    45  	// function value pointer. Trying to call newFuncVal.Pointer() wouldn't
    46  	// work because it gives the code pointer rather than the function value
    47  	// pointer. The function value is a struct that starts with its code
    48  	// pointer, so we can swap out the code pointer with our desired value.
    49  	funcValuePtr := reflect.ValueOf(newFuncVal).FieldByName("ptr").Pointer()
    50  	funcPtr := (*Func)(unsafe.Pointer(funcValuePtr))
    51  	funcPtr.codePtr = codePtr
    52  	outFuncVal.Set(newFuncVal)
    53  }
    54  
    55  // FindFuncWithName searches through the moduledata table created by the linker
    56  // and returns the function's code pointer. If the function was not found, it
    57  // returns an error. Since the data structures here are not exported, we copy
    58  // them below (and they need to stay in sync or else things will fail
    59  // catastrophically).
    60  func FindFuncWithName(name string) (uintptr, error) {
    61  	for moduleData := &Firstmoduledata; moduleData != nil; moduleData = moduleData.next {
    62  		for _, ftab := range moduleData.ftab {
    63  			f := (*runtime.Func)(unsafe.Pointer(&moduleData.pclntable[ftab.funcoff]))
    64  			funcName, err := getFuncName(f)
    65  			if err == nil && funcName == name {
    66  				return f.Entry(), nil
    67  			}
    68  		}
    69  	}
    70  	return 0, fmt.Errorf("Invalid function name: %s", name)
    71  }
    72  
    73  func GetAllFuncName() (names []string) {
    74  	for moduleData := &Firstmoduledata; moduleData != nil; moduleData = moduleData.next {
    75  		for _, ftab := range moduleData.ftab {
    76  			f := (*runtime.Func)(unsafe.Pointer(&moduleData.pclntable[ftab.funcoff]))
    77  			funcName, err := getFuncName(f)
    78  			if err == nil {
    79  				names = append(names, funcName)
    80  			}
    81  		}
    82  	}
    83  	return
    84  }
    85  
    86  // Everything below is taken from the runtime package, and must stay in sync
    87  // with it.
    88  
    89  //go:linkname Firstmoduledata runtime.firstmoduledata
    90  var Firstmoduledata Moduledata
    91  
    92  type Moduledata struct {
    93  	pclntable    []byte //include func (which type is runtime.Func) by funcoff and funcName (which type is string) by nameoff
    94  	ftab         []functab
    95  	filetab      []uint32
    96  	findfunctab  uintptr
    97  	minpc, maxpc uintptr
    98  
    99  	text, etext           uintptr
   100  	noptrdata, enoptrdata uintptr
   101  	data, edata           uintptr
   102  	bss, ebss             uintptr
   103  	noptrbss, enoptrbss   uintptr
   104  	end, gcdata, gcbss    uintptr
   105  	types, etypes         uintptr
   106  
   107  	textsectmap []textsect
   108  	typelinks   []int32 // offsets from types
   109  	itablinks   []*itab
   110  
   111  	ptab []ptabEntry
   112  
   113  	pluginpath string
   114  	pkghashes  []modulehash
   115  
   116  	modulename   string
   117  	modulehashes []modulehash
   118  
   119  	hasmain uint8 // 1 if module contains the main function, 0 otherwise
   120  
   121  	gcdatamask, gcbssmask bitvector
   122  
   123  	typemap map[typeOff]*_type // offset to *_rtype in previous module
   124  
   125  	bad bool // module failed to load and should be ignored
   126  
   127  	next *Moduledata
   128  }
   129  
   130  type functab struct {
   131  	entry   uintptr
   132  	funcoff uintptr
   133  }
   134  
   135  type textsect struct {
   136  	vaddr    uintptr // prelinked section vaddr
   137  	length   uintptr // section length
   138  	baseaddr uintptr // relocated section address
   139  }
   140  
   141  type itab struct {
   142  	inter *interfacetype
   143  	_type *_type
   144  	hash  uint32 // copy of _type.hash. Used for type switches.
   145  	_     [4]byte
   146  	fun   [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
   147  }
   148  
   149  type interfacetype struct {
   150  	typ     _type
   151  	pkgpath name
   152  	mhdr    []imethod
   153  }
   154  
   155  type _type struct {
   156  	size       uintptr
   157  	ptrdata    uintptr // size of memory prefix holding all pointers
   158  	hash       uint32
   159  	tflag      tflag
   160  	align      uint8
   161  	fieldAlign uint8
   162  	kind       uint8
   163  	// function for comparing objects of this type
   164  	// (ptr to object A, ptr to object B) -> ==?
   165  	equal func(unsafe.Pointer, unsafe.Pointer) bool
   166  	// gcdata stores the GC type data for the garbage collector.
   167  	// If the KindGCProg bit is set in kind, gcdata is a GC program.
   168  	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
   169  	gcdata    *byte
   170  	str       nameOff
   171  	ptrToThis typeOff
   172  }
   173  
   174  type name struct {
   175  	bytes *byte
   176  }
   177  
   178  type imethod struct {
   179  	name nameOff
   180  	ityp typeOff
   181  }
   182  
   183  type tflag uint8
   184  type nameOff int32
   185  type typeOff int32
   186  
   187  type ptabEntry struct {
   188  	name nameOff
   189  	typ  typeOff
   190  }
   191  
   192  type modulehash struct {
   193  	modulename   string
   194  	linktimehash string
   195  	runtimehash  *string
   196  }
   197  
   198  type bitvector struct {
   199  	n        int32 // # of bits
   200  	bytedata *uint8
   201  }
   202  
   203  func getFuncName(f *runtime.Func) (funcName string, err error) {
   204  	// f.Name() may panic because runtime.findmoduledatap may return nil
   205  	defer func() {
   206  		if r := recover(); r != nil {
   207  			switch e := r.(type) {
   208  			case error:
   209  				err = e
   210  			default:
   211  				panic("unexpect")
   212  			}
   213  		}
   214  	}()
   215  	funcName = f.Name()
   216  	return funcName, err
   217  }