github.com/linux4life798/go-forceexport@v0.0.0-20180425053403-37ebe5b408f3/forceexport.go (about)

     1  package forceexport
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"runtime"
     7  	"unsafe"
     8  )
     9  
    10  // GetFunc gets the function defined by the given fully-qualified name. The
    11  // outFuncPtr parameter should be a pointer to a function with the appropriate
    12  // type (e.g. the address of a local variable), and is set to a new function
    13  // value that calls the specified function. If the specified function does not
    14  // exist, outFuncPtr is not set and an error is returned.
    15  func GetFunc(outFuncPtr interface{}, name string) error {
    16  	codePtr, err := FindFuncWithName(name)
    17  	if err != nil {
    18  		return err
    19  	}
    20  	CreateFuncForCodePtr(outFuncPtr, codePtr)
    21  	return nil
    22  }
    23  
    24  // Convenience struct for modifying the underlying code pointer of a function
    25  // value. The actual struct has other values, but always starts with a code
    26  // pointer.
    27  type Func struct {
    28  	codePtr uintptr
    29  }
    30  
    31  // CreateFuncForCodePtr is given a code pointer and creates a function value
    32  // that uses that pointer. The outFun argument should be a pointer to a function
    33  // of the proper type (e.g. the address of a local variable), and will be set to
    34  // the result function value.
    35  func CreateFuncForCodePtr(outFuncPtr interface{}, codePtr uintptr) {
    36  	outFuncVal := reflect.ValueOf(outFuncPtr).Elem()
    37  	// Use reflect.MakeFunc to create a well-formed function value that's
    38  	// guaranteed to be of the right type and guaranteed to be on the heap
    39  	// (so that we can modify it). We give a nil delegate function because
    40  	// it will never actually be called.
    41  	newFuncVal := reflect.MakeFunc(outFuncVal.Type(), nil)
    42  	// Use reflection on the reflect.Value (yep!) to grab the underling
    43  	// function value pointer. Trying to call newFuncVal.Pointer() wouldn't
    44  	// work because it gives the code pointer rather than the function value
    45  	// pointer. The function value is a struct that starts with its code
    46  	// pointer, so we can swap out the code pointer with our desired value.
    47  	funcValuePtr := reflect.ValueOf(newFuncVal).FieldByName("ptr").Pointer()
    48  	funcPtr := (*Func)(unsafe.Pointer(funcValuePtr))
    49  	funcPtr.codePtr = codePtr
    50  	outFuncVal.Set(newFuncVal)
    51  }
    52  
    53  // FindFuncWithName searches through the moduledata table created by the linker
    54  // and returns the function's code pointer. If the function was not found, it
    55  // returns an error. Since the data structures here are not exported, we copy
    56  // them below (and they need to stay in sync or else things will fail
    57  // catastrophically).
    58  func FindFuncWithName(name string) (uintptr, error) {
    59  	for moduleData := &Firstmoduledata; moduleData != nil; moduleData = moduleData.next {
    60  		for _, ftab := range moduleData.ftab {
    61  			f := (*runtime.Func)(unsafe.Pointer(&moduleData.pclntable[ftab.funcoff]))
    62  
    63  			// (*Func).Name() assumes that the *Func was created by some exported
    64  			// method that would have returned a nil *Func pointer IF the
    65  			// desired function's datap resolves to nil.
    66  			// (a.k.a. if findmoduledatap(pc) returns nil)
    67  			// Since the last element of the moduleData.ftab has a datap of nil
    68  			// (from experimentation), .Name() Seg Faults on the last element.
    69  			//
    70  			// If we instead ask the external function FuncForPc to fetch
    71  			// our *Func object, it will check the datap first and give us
    72  			// a proper nil *Func, that .Name() understands.
    73  			// The down side of doing this is that internally, the
    74  			// findmoduledatap(pc) function is called twice for every element
    75  			// we loop over.
    76  			f = runtime.FuncForPC(f.Entry())
    77  			if f.Name() == name {
    78  				return f.Entry(), nil
    79  			}
    80  		}
    81  	}
    82  	return 0, fmt.Errorf("Invalid function name: %s", name)
    83  }
    84  
    85  // Everything below is taken from the runtime package, and must stay in sync
    86  // with it.
    87  
    88  //go:linkname Firstmoduledata runtime.firstmoduledata
    89  var Firstmoduledata Moduledata
    90  
    91  type Moduledata struct {
    92  	pclntable    []byte
    93  	ftab         []Functab
    94  	filetab      []uint32
    95  	findfunctab  uintptr
    96  	minpc, maxpc uintptr
    97  
    98  	text, etext           uintptr
    99  	noptrdata, enoptrdata uintptr
   100  	data, edata           uintptr
   101  	bss, ebss             uintptr
   102  	noptrbss, enoptrbss   uintptr
   103  	end, gcdata, gcbss    uintptr
   104  	types, etypes         uintptr
   105  
   106  	textsectmap []Textsect
   107  	typelinks   []int32 // offsets from types
   108  	// Original type was []*itab
   109  	itablinks []*struct{}
   110  
   111  	ptab []PtabEntry
   112  
   113  	pluginpath string
   114  	// Original type was []modulehash
   115  	pkghashes []interface{}
   116  
   117  	modulename string
   118  	// Original type was []modulehash
   119  	modulehashes []interface{}
   120  
   121  	hasmain uint8 // 1 if module contains the main function, 0 otherwise
   122  
   123  	gcdatamask, gcbssmask Bitvector
   124  
   125  	// Original type was map[typeOff]*_type
   126  	typemap map[typeOff]*struct{}
   127  
   128  	bad bool // module failed to load and should be ignored
   129  
   130  	next *Moduledata
   131  }
   132  
   133  type Textsect struct {
   134  	vaddr    uintptr // prelinked section vaddr
   135  	length   uintptr // section length
   136  	baseaddr uintptr // relocated section address
   137  }
   138  
   139  type nameOff int32
   140  type typeOff int32
   141  type textOff int32
   142  
   143  type PtabEntry struct {
   144  	name nameOff
   145  	typ  typeOff
   146  }
   147  
   148  type Functab struct {
   149  	entry   uintptr
   150  	funcoff uintptr
   151  }
   152  
   153  type Bitvector struct {
   154  	n        int32 // # of bits
   155  	bytedata *uint8
   156  }