github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/hooker/native_api.go (about) 1 //go:build !windows && (amd64 || arm64) && cgo 2 // +build !windows 3 // +build amd64 arm64 4 // +build cgo 5 6 package hooker 7 8 import ( 9 "fmt" 10 "reflect" 11 "unsafe" 12 13 "github.com/Rookout/GoSDK/pkg/augs" 14 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 15 "github.com/Rookout/GoSDK/pkg/services/instrumentation/module" 16 "github.com/Rookout/GoSDK/pkg/services/safe_hook_validator" 17 ) 18 19 20 21 /* #cgo CFLAGS: -I${SRCDIR} 22 // Dynamic alpine X86 23 #cgo rookout_dynamic,linux,alpine314,amd64 rookout_dynamic,linux,alpine,amd64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_alpine314_x86_64.a -lpthread -lrt -ldl -lz -lm -lstdc++ 24 // Static alpine X86 25 #cgo !rookout_dynamic,linux,alpine314,amd64 !rookout_dynamic,linux,alpine,amd64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_alpine314_x86_64.a -static -lpthread -lrt -ldl -lz -lm -lstdc++ 26 // Dynamic debian X86 27 #cgo rookout_dynamic,linux,amd64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_ubuntu18_x86_64.a -lpthread -lrt -ldl -lz -lm -lstdc++ 28 // Static debian X86 29 #cgo !rookout_dynamic,linux,amd64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_ubuntu18_x86_64.a -static -lpthread -lrt -ldl -lz -lm -lstdc++ 30 // Dynamic macos X86 31 #cgo darwin,amd64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_macos_x86_64.a -lpthread -lz -lffi -ledit -lm -lc++ 32 // Dynamic alpine arm64 33 #cgo rookout_dynamic,linux,alpine314,arm64 rookout_dynamic,linux,alpine,arm64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_alpine314_arm64.a -lpthread -lrt -ldl -lz -lm -lstdc++ 34 // Static alpine arm64 35 #cgo !rookout_dynamic,linux,alpine314,arm64 !rookout_dynamic,linux,alpine,arm64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_alpine314_arm64.a -static -lpthread -lrt -ldl -lz -lm -lstdc++ 36 // Dynamic debian arm64 37 #cgo rookout_dynamic,linux,arm64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_ubuntu_arm64.a -lpthread -lrt -ldl -lz -lm -lstdc++ 38 // Static debian arm64 39 #cgo !rookout_dynamic,linux,arm64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_ubuntu_arm64.a -static -lpthread -lrt -ldl -lz -lstdc++ -lm 40 // Dynamic macos arm64 41 #cgo darwin,arm64 LDFLAGS: -v ${SRCDIR}/libhook_lib_pack_macos_arm64.a -lpthread -lz -lffi -ledit -lm -lc++ 42 #include <stdlib.h> 43 #include <hook_api.h> 44 */ 45 import "C" 46 47 type nativeAPIImpl struct{} 48 49 func NewNativeAPI() *nativeAPIImpl { 50 return &nativeAPIImpl{} 51 } 52 53 54 55 func cArrayToUint64Slice(arrayPointer unsafe.Pointer, count int) []uint64 { 56 return (*[1 << 28]uint64)(arrayPointer)[:count:count] 57 } 58 59 60 61 62 func bufferToAddressMapping(addressMappingsBufferPointer unsafe.Pointer, origFuncAddress uintptr) (addressMappings []module.AddressMapping, 63 offsetMappings []module.AddressMapping) { 64 addressMappingsCount := *(*uint64)(addressMappingsBufferPointer) 65 66 addressMappingsBufferPointer = unsafe.Pointer(uintptr(addressMappingsBufferPointer) + unsafe.Sizeof(uint64(0))) 67 addressMappingsSlice := cArrayToUint64Slice(addressMappingsBufferPointer, int(addressMappingsCount)*2) 68 69 newFuncAddress := uintptr(addressMappingsSlice[0]) 70 71 for i := 0; i < len(addressMappingsSlice); i += 2 { 72 newAddress := uintptr(addressMappingsSlice[i]) 73 origAddress := uintptr(addressMappingsSlice[i+1]) 74 newOffset := newAddress - newFuncAddress 75 origOffset := origAddress - origFuncAddress 76 77 78 79 if _, ok := module.CallbacksMarkers[origAddress]; ok { 80 origOffset = origAddress 81 } 82 83 addressMappings = append(addressMappings, module.AddressMapping{newAddress, origAddress}) 84 offsetMappings = append(offsetMappings, module.AddressMapping{newOffset, origOffset}) 85 } 86 return addressMappings, offsetMappings 87 } 88 89 func getUnsafePointer(value uint64) unsafe.Pointer { 90 //goland:noinspection GoVetUnsafePointer 91 return unsafe.Pointer(uintptr(value)) 92 } 93 94 func (a *nativeAPIImpl) RegisterFunctionBreakpointsState(functionEntry, functionEnd uint64, breakpoints []*augs.BreakpointInstance, bpCallback uintptr, prologue []byte, hasStackFrame bool) (int, error) { 95 96 var breakpointAddrs []uint64 97 var bpAddr unsafe.Pointer 98 var failedCounters []*uint64 99 var failedCountersAddr unsafe.Pointer 100 bpCallbackPtr := unsafe.Pointer(bpCallback) 101 var prologueAddr unsafe.Pointer 102 prologueLen := 0 103 104 if len(breakpoints) > 0 { 105 breakpointAddrs = make([]uint64, len(breakpoints)) 106 for i, bp := range breakpoints { 107 breakpointAddrs[i] = bp.Addr 108 } 109 bpAddr = unsafe.Pointer(&breakpointAddrs[0]) 110 111 failedCounters = make([]*uint64, len(breakpoints)) 112 failedCountersAddr = unsafe.Pointer(&failedCounters[0]) 113 114 if len(prologue) > 0 { 115 prologueAddr = unsafe.Pointer(&prologue[0]) 116 prologueLen = len(prologue) 117 } 118 } 119 cHasStackFrame := 0 120 if hasStackFrame { 121 cHasStackFrame = 1 122 } 123 stateID := int(C.RookoutRegisterFunctionBreakpointsState( 124 getUnsafePointer(functionEntry), 125 getUnsafePointer(functionEnd), 126 C.int(len(breakpoints)), 127 bpAddr, 128 failedCountersAddr, 129 bpCallbackPtr, 130 prologueAddr, 131 C.int(prologueLen), 132 C.int(cHasStackFrame))) 133 134 if stateID < 0 { 135 return stateID, fmt.Errorf("couldn't set new function breakpoint state (%v) (%s)", breakpoints, C.GoString(C.RookoutGetHookerLastError())) 136 } 137 138 for i := range failedCounters { 139 breakpoints[i].FailedCounter = failedCounters[i] 140 } 141 142 return stateID, nil 143 } 144 145 func (a *nativeAPIImpl) GetInstructionMapping(functionEntry uint64, functionEnd uint64, stateId int) (addressMappings []module.AddressMapping, offsetMappings []module.AddressMapping, err error) { 146 rawAddressMapping := C.RookoutGetInstructionMapping(getUnsafePointer(functionEntry), getUnsafePointer(functionEnd), C.int(stateId)) 147 if rawAddressMapping == nil { 148 return nil, nil, fmt.Errorf("Couldn't get instruction mapping (%s)\n", C.GoString(C.RookoutGetHookerLastError())) 149 } 150 151 addressMappings, offsetMappings = bufferToAddressMapping(rawAddressMapping, uintptr(functionEntry)) 152 return addressMappings, offsetMappings, nil 153 } 154 155 156 func (a *nativeAPIImpl) GetStateEntryAddr(functionEntry uint64, functionEnd uint64, stateId int) (uintptr, error) { 157 addressMappings, _, err := a.GetInstructionMapping(functionEntry, functionEnd, stateId) 158 if err != nil { 159 return 0, err 160 } 161 return addressMappings[0].NewAddress, nil 162 } 163 164 func (a *nativeAPIImpl) ApplyBreakpointsState(functionEntry uint64, functionEnd uint64, stateId int) error { 165 ret := int(C.RookoutApplyBreakpointsState(getUnsafePointer(functionEntry), getUnsafePointer(functionEnd), C.int(stateId))) 166 if ret != 0 { 167 return fmt.Errorf("Couldn't apply breakpoint state (%s)\n", C.GoString(C.RookoutGetHookerLastError())) 168 } 169 170 return nil 171 } 172 173 func (a *nativeAPIImpl) GetHookAddress(functionEntry uint64, functionEnd uint64, stateId int) (uintptr, rookoutErrors.RookoutError) { 174 funcEntry := getUnsafePointer(functionEntry) 175 funcEnd := getUnsafePointer(functionEnd) 176 hookAddr := uint64(C.RookoutGetHookAddress(funcEntry, funcEnd, C.int(stateId))) 177 if hookAddr == 0 { 178 return 0, rookoutErrors.NewFailedToGetHookAddress(C.GoString(C.RookoutGetHookerLastError())) 179 } 180 return uintptr(hookAddr), nil 181 } 182 183 func (a *nativeAPIImpl) GetFunctionType(functionEntry uint64, functionEnd uint64) (safe_hook_validator.FunctionType, error) { 184 var err error 185 funcEntry := getUnsafePointer(functionEntry) 186 funcEnd := getUnsafePointer(functionEnd) 187 funcType := int(C.RookoutGetFunctionType(funcEntry, funcEnd)) 188 if funcType < 0 { 189 err = fmt.Errorf("Failed to get the function type (%s)\n", C.GoString(C.RookoutGetHookerLastError())) 190 } 191 return safe_hook_validator.FunctionType(funcType), err 192 } 193 194 func (a *nativeAPIImpl) TriggerWatchDog(timeoutMS uint64) error { 195 var err error = nil 196 res := int(C.RookoutTriggerWatchDog(C.ulonglong(timeoutMS))) 197 if res < 0 { 198 err = fmt.Errorf("Failed to trigger the watchdog (%s)\n", C.GoString(C.RookoutGetHookerLastError())) 199 } 200 return err 201 } 202 203 func (a *nativeAPIImpl) DefuseWatchDog() { 204 C.RookoutDefuseWatchDog() 205 } 206 207 func Init(someFunc func()) rookoutErrors.RookoutError { 208 if C.RookoutInit(unsafe.Pointer(reflect.ValueOf(someFunc).Pointer())) != 0 { 209 return rookoutErrors.NewFailedToInitNative(C.GoString(C.RookoutGetHookerLastError())) 210 } 211 212 return nil 213 } 214 215 func Destroy() error { 216 if C.RookoutDestroy() != 0 { 217 return fmt.Errorf("Native `Destroy` failed with error message: %s\n", C.GoString(C.RookoutGetHookerLastError())) 218 } 219 220 return nil 221 }