github.com/lsg2020/go-forceexport@v1.0.5/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 216 // (*Func).Name() assumes that the *Func was created by some exported 217 // method that would have returned a nil *Func pointer IF the 218 // desired function's datap resolves to nil. 219 // (a.k.a. if findmoduledatap(pc) returns nil) 220 // Since the last element of the moduleData.ftab has a datap of nil 221 // (from experimentation), .Name() Seg Faults on the last element. 222 // 223 // If we instead ask the external function FuncForPc to fetch 224 // our *Func object, it will check the datap first and give us 225 // a proper nil *Func, that .Name() understands. 226 // The down side of doing this is that internally, the 227 // findmoduledatap(pc) function is called twice for every element 228 // we loop over. 229 f = runtime.FuncForPC(f.Entry()) 230 231 funcName = f.Name() 232 return funcName, err 233 }