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 }