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  }