github.com/go-darwin/sys@v0.0.0-20220510002607-68fd01f054ca/ccall.go (about)

     1  // Copyright 2021 The Go Darwin Authors
     2  // SPDX-License-Identifier: BSD-3-Clause
     3  
     4  //go:build darwin && amd64
     5  // +build darwin,amd64
     6  
     7  package sys
     8  
     9  import (
    10  	"bytes"
    11  	"unsafe"
    12  
    13  	"github.com/go-darwin/sys/unsafeheader"
    14  )
    15  
    16  //go:linkname ccall syscall.syscall
    17  //go:noescape
    18  func ccall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
    19  
    20  // Ccall calls a function in libc on behalf of the syscall package.
    21  //
    22  // syscall takes a pointer to a struct like:
    23  //
    24  //	struct {
    25  //	 fn    uintptr
    26  //	 a1    uintptr
    27  //	 a2    uintptr
    28  //	 a3    uintptr
    29  //	 r1    uintptr
    30  //	 r2    uintptr
    31  //	 err   uintptr
    32  //	}
    33  //
    34  // Ccall must be called on the g0 stack with the
    35  // C calling convention (use libcCall).
    36  //
    37  // Ccall expects a 32-bit result and tests for 32-bit -1
    38  // to decide there was an error.
    39  //
    40  //go:nosplit
    41  func Ccall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
    42  	return ccall(fn, a1, a2, a3)
    43  }
    44  
    45  //go:linkname ccall6 syscall.syscall6
    46  //go:noescape
    47  func ccall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
    48  
    49  // Ccall6 calls a function in libc on behalf of the syscall package.
    50  //
    51  // Ccall6 takes a pointer to a struct like:
    52  //
    53  //	struct {
    54  //	 fn    uintptr
    55  //	 a1    uintptr
    56  //	 a2    uintptr
    57  //	 a3    uintptr
    58  //	 a4    uintptr
    59  //	 a5    uintptr
    60  //	 a6    uintptr
    61  //	 r1    uintptr
    62  //	 r2    uintptr
    63  //	 err   uintptr
    64  //	}
    65  //
    66  // Ccall6 must be called on the g0 stack with the
    67  // C calling convention (use libcCall).
    68  //
    69  // Ccall6 expects a 32-bit result and tests for 32-bit -1
    70  // to decide there was an error.
    71  //
    72  //go:nosplit
    73  func Ccall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
    74  	return ccall6(fn, a1, a2, a3, a4, a5, a6)
    75  }
    76  
    77  //go:linkname ccall6X syscall.syscall6X
    78  //go:noescape
    79  func ccall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
    80  
    81  // Ccall6X calls a function in libc on behalf of the syscall package.
    82  //
    83  // Ccall6X takes a pointer to a struct like:
    84  //
    85  //	struct {
    86  //	 fn    uintptr
    87  //	 a1    uintptr
    88  //	 a2    uintptr
    89  //	 a3    uintptr
    90  //	 a4    uintptr
    91  //	 a5    uintptr
    92  //	 a6    uintptr
    93  //	 r1    uintptr
    94  //	 r2    uintptr
    95  //	 err   uintptr
    96  //	}
    97  //
    98  // Ccall6X must be called on the g0 stack with the
    99  // C calling convention (use libcCall).
   100  //
   101  // Ccall6X is like syscall6 but expects a 64-bit result
   102  // and tests for 64-bit -1 to decide there was an error.
   103  //
   104  //go:nosplit
   105  func Ccall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
   106  	return ccall6X(fn, a1, a2, a3, a4, a5, a6)
   107  }
   108  
   109  // Ccall9 calls a function in libc on behalf of the syscall package.
   110  //
   111  // Ccall9 takes a pointer to a struct like:
   112  //
   113  //	struct {
   114  //	 fn    uintptr
   115  //	 a1    uintptr
   116  //	 a2    uintptr
   117  //	 a3    uintptr
   118  //	 a4    uintptr
   119  //	 a5    uintptr
   120  //	 a6    uintptr
   121  //	 a7    uintptr
   122  //	 a8    uintptr
   123  //	 a9    uintptr
   124  //	 r1    uintptr
   125  //	 r2    uintptr
   126  //	 err   uintptr
   127  //	}
   128  //
   129  // Ccall9 must be called on the g0 stack with the
   130  // C calling convention (use libcCall).
   131  //
   132  // Ccall9 expects a 32-bit result and tests for 32-bit -1
   133  // to decide there was an error.
   134  //
   135  //go:linkname Ccall9 syscall.Syscall9
   136  //go:nosplit
   137  func Ccall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
   138  
   139  //go:linkname ccallPtr syscall.syscallPtr
   140  //go:noescape
   141  func ccallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
   142  
   143  // CcallPtr is like syscallX except that the libc function reports an
   144  // error by returning NULL and setting errno.
   145  //
   146  //go:nosplit
   147  func CcallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
   148  	return ccallPtr(fn, a1, a2, a3)
   149  }
   150  
   151  //go:linkname rawCcall syscall.rawSyscall
   152  //go:noescape
   153  func rawCcall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
   154  
   155  // RawCcall calls a function in libc on behalf of the syscall package.
   156  //
   157  //go:nosplit
   158  func RawCcall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
   159  	return rawCcall(fn, a1, a2, a3)
   160  }
   161  
   162  //go:linkname rawSyscall6 syscall.rawSyscall6
   163  //go:noescape
   164  func rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
   165  
   166  // RawCcall6 calls a function in libc on behalf of the syscall package.
   167  //
   168  //go:nosplit
   169  func RawCcall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
   170  	return rawSyscall6(fn, a1, a2, a3, a4, a5, a6)
   171  }
   172  
   173  // RawCcall9 calls a function in libc on behalf of the syscall package.
   174  //
   175  //go:noescape
   176  //go:nosplit
   177  func RawCcall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
   178  
   179  // ByteSliceFromString returns a NUL-terminated slice of bytes
   180  // containing the text of s.
   181  func ByteSliceFromString(s string) []byte {
   182  	a := make([]byte, len(s)+1)
   183  	copy(a, s)
   184  
   185  	return a
   186  }
   187  
   188  // BytePtrFromString returns a pointer to a NUL-terminated array of
   189  // bytes containing the text of s.
   190  func BytePtrFromString(s string) *byte {
   191  	a := ByteSliceFromString(s)
   192  
   193  	return &a[0]
   194  }
   195  
   196  // ByteSliceToString returns a string form of the text represented by the slice s, with a terminating NUL and any
   197  // bytes after the NUL removed.
   198  func ByteSliceToString(s []byte) string {
   199  	if i := bytes.IndexByte(s, 0); i != -1 {
   200  		s = s[:i]
   201  	}
   202  
   203  	return string(s)
   204  }
   205  
   206  // BytePtrToString takes a pointer to a sequence of text and returns the corresponding string.
   207  // If the pointer is nil, it returns the empty string. It assumes that the text sequence is terminated
   208  // at a zero byte; if the zero byte is not present, the program may crash.
   209  func BytePtrToString(p *byte) string {
   210  	if p == nil || *p == 0 {
   211  		return ""
   212  	}
   213  
   214  	// Find NUL terminator.
   215  	n := 0
   216  	for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ {
   217  		ptr = unsafe.Pointer(uintptr(ptr) + 1)
   218  	}
   219  
   220  	var b []byte
   221  	h := (*unsafeheader.Slice)(unsafe.Pointer(&b))
   222  	h.Data = unsafe.Pointer(p)
   223  	h.Len = n
   224  	h.Cap = n
   225  
   226  	return string(b)
   227  }