github.com/alangpierce/go-forceexport@v0.0.0-20160317203124-8f1d6941cd75/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 if f.Name() == name { 63 return f.Entry(), nil 64 } 65 } 66 } 67 return 0, fmt.Errorf("Invalid function name: %s", name) 68 } 69 70 // Everything below is taken from the runtime package, and must stay in sync 71 // with it. 72 73 //go:linkname Firstmoduledata runtime.firstmoduledata 74 var Firstmoduledata Moduledata 75 76 type Moduledata struct { 77 pclntable []byte 78 ftab []Functab 79 filetab []uint32 80 findfunctab uintptr 81 minpc, maxpc uintptr 82 83 text, etext uintptr 84 noptrdata, enoptrdata uintptr 85 data, edata uintptr 86 bss, ebss uintptr 87 noptrbss, enoptrbss uintptr 88 end, gcdata, gcbss uintptr 89 90 // Original type was []*_type 91 typelinks []interface{} 92 93 modulename string 94 // Original type was []modulehash 95 modulehashes []interface{} 96 97 gcdatamask, gcbssmask Bitvector 98 99 next *Moduledata 100 } 101 102 type Functab struct { 103 entry uintptr 104 funcoff uintptr 105 } 106 107 type Bitvector struct { 108 n int32 // # of bits 109 bytedata *uint8 110 }