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