Skip to content

Commit

Permalink
Remove cGo and use syscall (lose static types) (#7)
Browse files Browse the repository at this point in the history
fixes #6
  • Loading branch information
KnicKnic authored Nov 7, 2019
1 parent b295cee commit 8e4b87b
Show file tree
Hide file tree
Showing 19 changed files with 594 additions and 486 deletions.
1 change: 0 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ steps:
inputs:
targetType: 'inline'
script: 'choco install -y golang --no-progress;
choco install -y mingw --no-progress;
refreshenv ;
copy native-powershell\host.h .\pkg\powershell\ ;
copy native-powershell\x64\Release\psh_host.dll . ;
Expand Down
3 changes: 3 additions & 0 deletions bin/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ extern "C" {
}NativePowerShell_LogString_Holder, * PNativePowerShell_LogString_Holder;

void NativePowerShell_InitLibrary( NativePowerShell_AllocPointer, NativePowerShell_FreePointer);

unsigned char* NativePowerShell_DefaultAlloc(unsigned long long size);
void NativePowerShell_DefaultFree(void* address);

//typedef struct NativePowerShell_RunspaceHandle_ {} *NativePowerShell_RunspaceHandle;
// typedef struct NativePowerShell_PowerShellHandle_ {} *NativePowerShell_PowerShellHandle;
Expand Down
Binary file modified bin/psh_host.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ go 1.12

require (
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6
k8s.io/klog v1.0.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekf
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 h1:ZJUmhYTp8GbGC0ViZRc2U+MIYQ8xx9MscsdXnclfIhw=
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
180 changes: 33 additions & 147 deletions pkg/powershell/chelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,171 +6,57 @@ import (
"golang.org/x/sys/windows"
)

/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -static ${SRCDIR}/../../bin/psh_host.dll
#include <stddef.h>
#include <string.h>
#include "powershell.h"
*/
import "C"

func makeString(str *C.wchar_t) string {
ptr := unsafe.Pointer(str)
count := C.wcslen(str) + 1
arr := make([]uint16, count)
ptrwchar := unsafe.Pointer(&arr[0])

C.memcpy(ptrwchar, ptr, count*2)

s := windows.UTF16ToString(arr)
return s
}

func makeCString(str string) *C.wchar_t {
cs, _ := windows.UTF16PtrFromString(str)
ptrwchar := unsafe.Pointer(cs)
return C.MallocCopy((*C.wchar_t)(ptrwchar))
}

//export logWchart
// logWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Write(s)
}
}

//export logWarningWchart
// logWarningWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logWarningWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Warning(s)
}
func makeUint64FromPtr(v uintptr) uint64 {
return *((*uint64)(unsafe.Pointer(&v)))
}

//export logInformationWchart
// logInformationWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logInformationWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Information(s)
}
func makeUintptrFromUint64(v uint64) uintptr {
return *((*uintptr)(unsafe.Pointer(&v)))
}

//export logVerboseWchart
// logVerboseWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logVerboseWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Verbose(s)
}
func allocWrapper(size uint64) uintptr {
return nativePowerShell_DefaultAlloc(size)
}

//export logDebugWchart
// logDebugWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logDebugWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Debug(s)
}
func freeWrapper(v uintptr) {
nativePowerShell_DefaultFree(v)
}

//export logErrorWchart
// logErrorWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logErrorWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Error(s)
}
}
func mallocCopy(input uintptr, size uintptr) uintptr {

u64Size := makeUint64FromPtr(size)
data := allocWrapper(u64Size)
_ = memcpy(data, uintptr(unsafe.Pointer(input)), u64Size)

//export loglnWchart
// loglnWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func loglnWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Writeln(s)
}
return data
}

//export logWarninglnWchart
// logWarninglnWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logWarninglnWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Warningln(s)
func wsclen(str uintptr) uint64 {
var charCode uint16 = 1
var i uint64 = 0
for ; charCode != 0; i++ {
charCode = *(*uint16)(unsafe.Pointer(str + (makeUintptrFromUint64(i) * unsafe.Sizeof(charCode))))
}
return i
}

//export logInformationlnWchart
// logInformationlnWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logInformationlnWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Informationln(s)
}
}
func makeString(str uintptr) string {
count := wsclen(str) + 1
arr := make([]uint16, count)
ptrwchar := unsafe.Pointer(&arr[0])

//export logVerboselnWchart
// logVerboselnWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logVerboselnWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Verboseln(s)
}
}
memcpy(uintptr(ptrwchar), str, count*2)

//export logDebuglnWchart
// logDebuglnWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logDebuglnWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Debugln(s)
}
s := windows.UTF16ToString(arr)
return s
}

//export logErrorlnWchart
// logErrorlnWchart the C function pointer that dispatches to the Golang function for SimpleLogging
func logErrorlnWchart(context uint64, str *C.wchar_t) {
if context != 0 {
s := makeString(str)
contextInterface := getRunspaceContext(context)
contextInterface.log.Errorln(s)
}
func uintptrMakeString(ptr uintptr) string {
return makeString(ptr)
}

//export commandWchart
// commandWchart the C function pointer that dispatches to the Golang function for Send-HostCommand
func commandWchart(context uint64, cMessage *C.wchar_t, input *C.NativePowerShell_PowerShellObject, inputCount uint64, ret *C.NativePowerShell_JsonReturnValues) {
func makeCStringUintptr(str string) uintptr {
cs, _ := windows.UTF16PtrFromString(str)
ptrwchar := unsafe.Pointer(cs)
size := 2 * (wsclen(uintptr(ptrwchar)) + 1)

var resultsWriter callbackResultsWriter
if context != 0 {
contextInterface := getRunspaceContext(context)
inputArr := make([]Object, inputCount)
for i := uint32(0); uint64(i) < inputCount; i++ {
inputArr[i] = makePowerShellObjectIndexed(input, i)
}
message := makeString(cMessage)
contextInterface.callback.Callback(contextInterface.recreateRunspace(), message, inputArr, &resultsWriter)
}
resultsWriter.filloutResults(ret)
return mallocCopy(uintptr(ptrwchar), makeUintptrFromUint64(size))
}
4 changes: 2 additions & 2 deletions pkg/powershell/higherops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ func TestCpowershellJsonMarshal(t *testing.T) {
}

func TestClogWchart_lookupFail(t *testing.T) {
cStr := makeCString("test String")
cStr := makeCStringUintptr("test String")
caughtFailedToLoad := false
defer func() {
if r := recover(); r != nil {
Expand All @@ -517,7 +517,7 @@ func TestClogWchart_lookupFail(t *testing.T) {
caughtFailedToLoad = true
}
}()
logWchart(1, cStr)
loggerCallbackDebugln(1, cStr)
if !caughtFailedToLoad {
t.Fail()
}
Expand Down
58 changes: 33 additions & 25 deletions pkg/powershell/hostcommand.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
package powershell

/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -static ${SRCDIR}/../../bin/psh_host.dll
#include <stddef.h>
#include "powershell.h"
*/
import "C"
import "unsafe"

// CallbackResultsWriter allows you to write values to powershell when inside Send-HostCommand
type CallbackResultsWriter interface {
Expand All @@ -35,34 +25,52 @@ func (callback CallbackFuncPtr) Callback(runspace Runspace, message string, inpu

// callbackResultsWriter is the internal implementation of CallbackResultsWriter
type callbackResultsWriter struct {
objects []C.NativePowerShell_GenericPowerShellObject
objects []nativePowerShell_GenericPowerShellObject
}

func setGenericPowershellString(object *nativePowerShell_GenericPowerShellObject, value uintptr, autoRelease byte) {
object.typeEnum = nativePowerShell_PowerShellObjectTypeString
object.object = makeUint64FromPtr(value)
object.releaseObject = autoRelease
}

func setGenericPowerShellHandle(object *nativePowerShell_GenericPowerShellObject, value nativePowerShell_PowerShellObject, autoRelease byte) {
object.typeEnum = nativePowerShell_PowerShellObjectHandle
object.object = value
object.releaseObject = autoRelease
}

// WriteString accumulates a string object to return from Send-HostCommand
func (writer *callbackResultsWriter) WriteString(str string) {
cStr := makeCString(str)
var obj C.NativePowerShell_GenericPowerShellObject
C.SetGenericPowershellString(&obj, cStr, 1)
cStr := makeCStringUintptr(str)
var obj nativePowerShell_GenericPowerShellObject
setGenericPowershellString(&obj, cStr, 1)
writer.objects = append(writer.objects, obj)
}

// Write accumulates a string object to return from Send-HostCommand
func (writer *callbackResultsWriter) Write(handle Object, needsClose bool) {
var obj C.NativePowerShell_GenericPowerShellObject
var autoClose C.char
if needsClose {
autoClose = 1
}
C.SetGenericPowerShellHandle(&obj, handle.toCHandle(), autoClose)
var obj nativePowerShell_GenericPowerShellObject
var autoClose = boolToByte(needsClose)

setGenericPowerShellHandle(&obj, handle.toCHandle(), autoClose)
writer.objects = append(writer.objects, obj)
}

func mallocCopyGenericPowerShellObject(input *nativePowerShell_GenericPowerShellObject, inputCount uint64) *nativePowerShell_GenericPowerShellObject {

size := uintptr(inputCount) * unsafe.Sizeof(*input)

return (*nativePowerShell_GenericPowerShellObject)(unsafe.Pointer(mallocCopy(uintptr(unsafe.Pointer(input)), size)))
}

// filloutResults takes accumulated objects from Write calls and prepares them to cross the C boundary
func (writer *callbackResultsWriter) filloutResults(results *C.NativePowerShell_JsonReturnValues) {
func (writer *callbackResultsWriter) filloutResults(res uintptr) {
results := (*nativePowerShell_JsonReturnValues)(unsafe.Pointer(res))
results.objects = nil
results.count = 0
if writer.objects != nil {
results.count = C.ulong(len(writer.objects))
results.objects = C.MallocCopyGenericPowerShellObject(&writer.objects[0], C.ulonglong(len(writer.objects)))
if writer.objects != nil && len(writer.objects) > 0 {
results.count = uint32(len(writer.objects))
results.objects = mallocCopyGenericPowerShellObject(&writer.objects[0], uint64(len(writer.objects)))
}
}
Loading

0 comments on commit 8e4b87b

Please sign in to comment.