// Copyright 2023 The Libc Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build linux && (amd64 || loong64) //go:generate go run generator.go // Package libc is the runtime for programs generated by ccgo/v4 or later. // // # Version compatibility // // The API of this package, in particular the bits that directly support the // ccgo compiler, may change in a way that is not backward compatible. If you // have generated some Go code from C you should stick to the version of this // package that you used at that time and was tested with your payload. The // correct way to upgrade to a newer version of this package is to first // recompile (C to Go) your code with a newwer version if ccgo that depends on // the new libc version. // // If you use C to Go translated code provided by others, stick to the version // of libc that translated code shows in its go.mod file and do not upgrade the // dependency just because a newer libc is tagged.Vgq // // This is if course unfortunate. However, it's somewhat similar to C code // linked with a specific version of, say GNU libc. When such code asking for // glibc5 is run on a system with glibc6, or vice versa, it will fail. // // As a particular example, if your project imports modernc.org/sqlite you // should use the same libc version as seen in the go.mod file of the sqlite // package. // // tl;dr: It is not always possible to fix ccgo bugs and/or improve performance // of the ccgo transpiled code without occasionally making incompatible changes // to this package. // // # Thread Local Storage // // A TLS instance represents a main thread or a thread created by // Xpthread_create. A TLS instance is not safe for concurrent use by multiple // goroutines. // // If a program starts the C main function, a TLS instance is created // automatically and the goroutine entering main() is locked to the OS thread. // The translated C code then may create other pthreads by calling // Xpthread_create. // // If the translated C code is part of a library package, new TLS instances // must be created manually in user/client code. The first TLS instance created // will be the "main" libc thread, but it will be not locked to OS thread // automatically. Any subsequently manually created TLS instances will call // Xpthread_create, but without spawning a new goroutine. // // A manual call to Xpthread_create will create a new TLS instance automatically // and spawn a new goroutine executing the thread function. // Package libc provides run time support for programs generated by the // [ccgo] C to Go transpiler, version 4 or later. // // # Concurrency // // Many C libc functions are not thread safe. Such functions are not safe // for concurrent use by multiple goroutines in the Go translation as well. // // # Thread Local Storage // // C threads are modeled as Go goroutines. Every such C thread, ie. a Go // goroutine, must use its own Thread Local Storage instance implemented by the // [TLS] type. // // # Signals // // Signal handling in translated C code is not coordinated with the Go runtime. // This is probably the same as when running C code via CGo. // // # Environmental variables // // This package synchronizes its environ with the current Go environ lazily and // only once. // // # libc API documentation copyright // // From [Linux man-pages Copyleft] // // Permission is granted to make and distribute verbatim copies of this // manual provided the copyright notice and this permission notice are // preserved on all copies. // // Permission is granted to copy and distribute modified versions of this // manual under the conditions for verbatim copying, provided that the // entire resulting derived work is distributed under the terms of a // permission notice identical to this one. // // Since the Linux kernel and libraries are constantly changing, this // manual page may be incorrect or out-of-date. The author(s) assume no // responsibility for errors or omissions, or for damages resulting from // the use of the information contained herein. The author(s) may not have // taken the same level of care in the production of this manual, which is // licensed free of charge, as they might when working professionally. // // Formatted or processed versions of this manual, if unaccompanied by the // source, must acknowledge the copyright and authors of this work. // // [Linux man-pages Copyleft]: https://spdx.org/licenses/Linux-man-pages-copyleft.html // [ccgo]: http://modernc.org/ccgo/v4 package libc // import "modernc.org/libc" import ( "fmt" "io" "math" "math/rand" "os" "os/exec" gosignal "os/signal" "path/filepath" "runtime" "sort" "strings" "sync" "sync/atomic" "syscall" "unsafe" "golang.org/x/sys/unix" "modernc.org/memory" ) const ( heapAlign = 16 heapGuard = 16 ) var ( _ error = (*MemAuditError)(nil) allocator memory.Allocator allocatorMu sync.Mutex atExitMu sync.Mutex atExit []func() tid atomic.Int32 // TLS Go ID Covered = map[uintptr]struct{}{} CoveredC = map[string]struct{}{} coverPCs [1]uintptr //TODO not concurrent safe ) func init() { nm, err := os.Executable() if err != nil { return } Xprogram_invocation_name = mustCString(nm) Xprogram_invocation_short_name = mustCString(filepath.Base(nm)) } // RawMem64 represents the biggest uint64 array the runtime can handle. type RawMem64 [unsafe.Sizeof(RawMem{}) / unsafe.Sizeof(uint64(0))]uint64 type MemAuditError struct { Caller string Message string } func (e *MemAuditError) Error() string { return fmt.Sprintf("%s: %s", e.Caller, e.Message) } // Start executes C's main. func Start(main func(*TLS, int32, uintptr) int32) { runtime.LockOSThread() if isMemBrk { defer func() { trc("==== PANIC") for _, v := range MemAudit() { trc("", v.Error()) } }() } tls := NewTLS() Xexit(tls, main(tls, int32(len(os.Args)), mustAllocStrings(os.Args))) } func mustAllocStrings(a []string) (r uintptr) { nPtrs := len(a) + 1 pPtrs := mustCalloc(Tsize_t(uintptr(nPtrs) * unsafe.Sizeof(uintptr(0)))) ptrs := unsafe.Slice((*uintptr)(unsafe.Pointer(pPtrs)), nPtrs) nBytes := 0 for _, v := range a { nBytes += len(v) + 1 } pBytes := mustCalloc(Tsize_t(nBytes)) b := unsafe.Slice((*byte)(unsafe.Pointer(pBytes)), nBytes) for i, v := range a { copy(b, v) b = b[len(v)+1:] ptrs[i] = pBytes pBytes += uintptr(len(v)) + 1 } return pPtrs } func mustCString(s string) (r uintptr) { n := len(s) r = mustMalloc(Tsize_t(n + 1)) copy(unsafe.Slice((*byte)(unsafe.Pointer(r)), n), s) *(*byte)(unsafe.Pointer(r + uintptr(n))) = 0 return r } // CString returns a pointer to a zero-terminated version of s. The caller is // responsible for freeing the allocated memory using Xfree. func CString(s string) (uintptr, error) { n := len(s) p := Xmalloc(nil, Tsize_t(n)+1) if p == 0 { return 0, fmt.Errorf("CString: cannot allocate %d bytes", n+1) } copy(unsafe.Slice((*byte)(unsafe.Pointer(p)), n), s) *(*byte)(unsafe.Pointer(p + uintptr(n))) = 0 return p, nil } // GoBytes returns a byte slice from a C char* having length len bytes. func GoBytes(s uintptr, len int) []byte { return unsafe.Slice((*byte)(unsafe.Pointer(s)), len) } // GoString returns the value of a C string at s. func GoString(s uintptr) string { if s == 0 { return "" } var buf []byte for { b := *(*byte)(unsafe.Pointer(s)) if b == 0 { return string(buf) } buf = append(buf, b) s++ } } func mustMalloc(sz Tsize_t) (r uintptr) { if r = Xmalloc(nil, sz); r != 0 || sz == 0 { return r } panic(todo("OOM")) } func mustCalloc(sz Tsize_t) (r uintptr) { if r := Xcalloc(nil, 1, sz); r != 0 || sz == 0 { return r } panic(todo("OOM")) } type tlsStackSlot struct { p uintptr sz Tsize_t } // TLS emulates thread local storage. TLS is not safe for concurrent use by // multiple goroutines. type TLS struct { allocaStack []int allocas []uintptr jumpBuffers []uintptr pthread uintptr // *t__pthread pthreadCleanupItems []pthreadCleanupItem pthreadKeyValues map[Tpthread_key_t]uintptr sp int stack []tlsStackSlot ID int32 ownsPthread bool } var __ccgo_environOnce sync.Once // NewTLS returns a newly created TLS that must be eventually closed to prevent // resource leaks. func NewTLS() (r *TLS) { id := tid.Add(1) if id == 0 { id = tid.Add(1) } __ccgo_environOnce.Do(func() { Xenviron = mustAllocStrings(os.Environ()) }) pthread := mustMalloc(Tsize_t(unsafe.Sizeof(t__pthread{}))) *(*t__pthread)(unsafe.Pointer(pthread)) = t__pthread{ Flocale: uintptr(unsafe.Pointer(&X__libc.Fglobal_locale)), Fself: pthread, Ftid: id, } return &TLS{ ID: id, ownsPthread: true, pthread: pthread, } } // int *__errno_location(void) func X__errno_location(tls *TLS) (r uintptr) { return tls.pthread + unsafe.Offsetof(t__pthread{}.Ferrno_val) } // int *__errno_location(void) func X___errno_location(tls *TLS) (r uintptr) { return X__errno_location(tls) } func (tls *TLS) setErrno(n int32) { if tls == nil { return } *(*int32)(unsafe.Pointer(X__errno_location(tls))) = n } func (tls *TLS) String() string { return fmt.Sprintf("TLS#%v pthread=%x", tls.ID, tls.pthread) } // Alloc allocates n bytes in tls's local storage. Calls to Alloc() must be // strictly paired with calls to TLS.Free on function exit. That also means any // memory from Alloc must not be used after a function returns. // // The order matters. This is ok: // // p := tls.Alloc(11) // q := tls.Alloc(22) // tls.Free(22) // // q is no more usable here. // tls.Free(11) // // p is no more usable here. // // This is not correct: // // tls.Alloc(11) // tls.Alloc(22) // tls.Free(11) // tls.Free(22) func (tls *TLS) Alloc(n0 int) (r uintptr) { // shrink stats speedtest1 // ----------------------------------------------------------------------------------------------- // 0 total 2,544, nallocs 107,553,070, nmallocs 25, nreallocs 107,553,045 10.984s // 1 total 2,544, nallocs 107,553,070, nmallocs 25, nreallocs 38,905,980 9.597s // 2 total 2,616, nallocs 107,553,070, nmallocs 25, nreallocs 18,201,284 9.206s // 3 total 2,624, nallocs 107,553,070, nmallocs 25, nreallocs 16,716,302 9.155s // 4 total 2,624, nallocs 107,553,070, nmallocs 25, nreallocs 16,156,102 9.398s // 8 total 3,408, nallocs 107,553,070, nmallocs 25, nreallocs 14,364,274 9.198s // 16 total 3,976, nallocs 107,553,070, nmallocs 25, nreallocs 6,219,602 8.910s // --------------------------------------------------------------------------------------------- // 32 total 5,120, nallocs 107,553,070, nmallocs 25, nreallocs 1,089,037 8.836s // --------------------------------------------------------------------------------------------- // 64 total 6,520, nallocs 107,553,070, nmallocs 25, nreallocs 1,788 8.420s // 128 total 8,848, nallocs 107,553,070, nmallocs 25, nreallocs 1,098 8.833s // 256 total 8,848, nallocs 107,553,070, nmallocs 25, nreallocs 1,049 9.508s // 512 total 33,336, nallocs 107,553,070, nmallocs 25, nreallocs 88 8.667s // none total 33,336, nallocs 107,553,070, nmallocs 25, nreallocs 88 8.408s const shrinkSegment = 32 n := Tsize_t(n0) if tls.sp < len(tls.stack) { p := tls.stack[tls.sp].p sz := tls.stack[tls.sp].sz if sz >= n /* && sz <= shrinkSegment*n */ { // Segment shrinking is nice to have but Tcl does some dirty hacks in coroutine // handling that require stability of stack addresses, out of the C execution // model. Disabled. tls.sp++ return p } Xfree(tls, p) r = mustMalloc(n) tls.stack[tls.sp] = tlsStackSlot{p: r, sz: Xmalloc_usable_size(tls, r)} tls.sp++ return r } r = mustMalloc(n) tls.stack = append(tls.stack, tlsStackSlot{p: r, sz: Xmalloc_usable_size(tls, r)}) tls.sp++ return r } // Free manages memory of the preceding TLS.Alloc() func (tls *TLS) Free(n int) { //TODO shrink stacks if possible. Tcl is currently against. tls.sp-- } func (tls *TLS) alloca(n Tsize_t) (r uintptr) { r = mustMalloc(n) tls.allocas = append(tls.allocas, r) return r } // AllocaEntry must be called early on function entry when the function calls // or may call alloca(3). func (tls *TLS) AllocaEntry() { tls.allocaStack = append(tls.allocaStack, len(tls.allocas)) } // AllocaExit must be defer-called on function exit when the function calls or // may call alloca(3). func (tls *TLS) AllocaExit() { n := len(tls.allocaStack) x := tls.allocaStack[n-1] tls.allocaStack = tls.allocaStack[:n-1] for _, v := range tls.allocas[x:] { Xfree(tls, v) } tls.allocas = tls.allocas[:x] } func (tls *TLS) Close() { defer func() { *tls = TLS{} }() for _, v := range tls.allocas { Xfree(tls, v) } for _, v := range tls.stack /* shrink diabled[:tls.sp] */ { Xfree(tls, v.p) } if tls.ownsPthread { Xfree(tls, tls.pthread) } } func (tls *TLS) PushJumpBuffer(jb uintptr) { tls.jumpBuffers = append(tls.jumpBuffers, jb) } type LongjmpRetval int32 func (tls *TLS) PopJumpBuffer(jb uintptr) { n := len(tls.jumpBuffers) if n == 0 || tls.jumpBuffers[n-1] != jb { panic(todo("unsupported setjmp/longjmp usage")) } tls.jumpBuffers = tls.jumpBuffers[:n-1] } func (tls *TLS) Longjmp(jb uintptr, val int32) { tls.PopJumpBuffer(jb) if val == 0 { val = 1 } panic(LongjmpRetval(val)) } // ============================================================================ func Xexit(tls *TLS, code int32) { //TODO atexit finalizers X__stdio_exit(tls) for _, v := range atExit { v() } os.Exit(int(code)) } func _exit(tls *TLS, code int32) { Xexit(tls, code) } var abort Tsigaction func Xabort(tls *TLS) { X__libc_sigaction(tls, SIGABRT, uintptr(unsafe.Pointer(&abort)), 0) unix.Kill(unix.Getpid(), syscall.Signal(SIGABRT)) panic(todo("unrechable")) } type lock struct { sync.Mutex waiters int } var ( locksMu sync.Mutex locks = map[uintptr]*lock{} ) /* T1 T2 lock(&foo) // foo: 0 -> 1 lock(&foo) // foo: 1 -> 2 unlock(&foo) // foo: 2 -> 1, non zero means waiter(s) active unlock(&foo) // foo: 1 -> 0 */ func ___lock(tls *TLS, p uintptr) { if atomic.AddInt32((*int32)(unsafe.Pointer(p)), 1) == 1 { return } // foo was already acquired by some other C thread. locksMu.Lock() l := locks[p] if l == nil { l = &lock{} locks[p] = l l.Lock() } l.waiters++ locksMu.Unlock() l.Lock() // Wait for T1 to release foo. (X below) } func ___unlock(tls *TLS, p uintptr) { if atomic.AddInt32((*int32)(unsafe.Pointer(p)), -1) == 0 { return } // Some other C thread is waiting for foo. locksMu.Lock() l := locks[p] if l == nil { // We are T1 and we got the locksMu locked before T2. l = &lock{waiters: 1} l.Lock() } l.Unlock() // Release foo, T2 may now lock it. (X above) l.waiters-- if l.waiters == 0 { // we are T2 delete(locks, p) } locksMu.Unlock() } type lockedFile struct { ch chan struct{} waiters int } var ( lockedFilesMu sync.Mutex lockedFiles = map[uintptr]*lockedFile{} ) func X__lockfile(tls *TLS, file uintptr) int32 { return ___lockfile(tls, file) } // int __lockfile(FILE *f) func ___lockfile(tls *TLS, file uintptr) int32 { panic(todo("")) // lockedFilesMu.Lock() // defer lockedFilesMu.Unlock() // l := lockedFiles[file] // if l == nil { // l = &lockedFile{ch: make(chan struct{}, 1)} // lockedFiles[file] = l // } // l.waiters++ // l.ch <- struct{}{} } func X__unlockfile(tls *TLS, file uintptr) { ___unlockfile(tls, file) } // void __unlockfile(FILE *f) func ___unlockfile(tls *TLS, file uintptr) { panic(todo("")) lockedFilesMu.Lock() defer lockedFilesMu.Unlock() l := lockedFiles[file] l.waiters-- if l.waiters == 0 { delete(lockedFiles, file) } <-l.ch } // void __synccall(void (*func)(void *), void *ctx) func ___synccall(tls *TLS, fn, ctx uintptr) { (*(*func(*TLS, uintptr))(unsafe.Pointer(&struct{ uintptr }{fn})))(tls, ctx) } func ___randname(tls *TLS, template uintptr) (r1 uintptr) { bp := tls.Alloc(16) defer tls.Free(16) var i int32 var r uint64 var _ /* ts at bp+0 */ Ttimespec X__clock_gettime(tls, CLOCK_REALTIME, bp) goto _2 _2: r = uint64((*(*Ttimespec)(unsafe.Pointer(bp))).Ftv_sec+(*(*Ttimespec)(unsafe.Pointer(bp))).Ftv_nsec) + uint64(tls.ID)*uint64(65537) i = 0 for { if !(i < int32(6)) { break } *(*int8)(unsafe.Pointer(template + uintptr(i))) = int8(uint64('A') + r&uint64(15) + r&uint64(16)*uint64(2)) goto _3 _3: i++ r >>= uint64(5) } return template } func ___get_tp(tls *TLS) uintptr { return tls.pthread } func Xfork(t *TLS) int32 { if __ccgo_strace { trc("t=%v, (%v:)", t, origin(2)) } t.setErrno(ENOSYS) return -1 } const SIG_DFL = 0 const SIG_IGN = 1 var sigHandlers = map[int32]uintptr{} func Xsignal(tls *TLS, signum int32, handler uintptr) (r uintptr) { r, sigHandlers[signum] = sigHandlers[signum], handler sigHandlers[signum] = handler switch handler { case SIG_DFL: gosignal.Reset(syscall.Signal(signum)) case SIG_IGN: gosignal.Ignore(syscall.Signal(signum)) default: panic(todo("")) } return r } func Xatexit(tls *TLS, func_ uintptr) (r int32) { return -1 } var __sync_synchronize_dummy int32 // __sync_synchronize(); func X__sync_synchronize(t *TLS) { if __ccgo_strace { trc("t=%v, (%v:)", t, origin(2)) } // Attempt to implement a full memory barrier without assembler. atomic.StoreInt32(&__sync_synchronize_dummy, atomic.LoadInt32(&__sync_synchronize_dummy)+1) } func Xdlopen(t *TLS, filename uintptr, flags int32) uintptr { if __ccgo_strace { trc("t=%v filename=%v flags=%v, (%v:)", t, filename, flags, origin(2)) } return 0 } func Xdlsym(t *TLS, handle, symbol uintptr) uintptr { if __ccgo_strace { trc("t=%v symbol=%v, (%v:)", t, symbol, origin(2)) } return 0 } var dlErrorMsg = []byte("not supported\x00") func Xdlerror(t *TLS) uintptr { if __ccgo_strace { trc("t=%v, (%v:)", t, origin(2)) } return uintptr(unsafe.Pointer(&dlErrorMsg[0])) } func Xdlclose(t *TLS, handle uintptr) int32 { if __ccgo_strace { trc("t=%v handle=%v, (%v:)", t, handle, origin(2)) } panic(todo("")) } func Xsystem(t *TLS, command uintptr) int32 { if __ccgo_strace { trc("t=%v command=%v, (%v:)", t, command, origin(2)) } s := GoString(command) if command == 0 { panic(todo("")) } cmd := exec.Command("sh", "-c", s) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { ps := err.(*exec.ExitError) return int32(ps.ExitCode()) } return 0 } func Xsched_yield(tls *TLS) int32 { runtime.Gosched() return 0 } // AtExit will attempt to run f at process exit. The execution cannot be // guaranteed, neither its ordering with respect to any other handlers // registered by AtExit. func AtExit(f func()) { atExitMu.Lock() atExit = append(atExit, f) atExitMu.Unlock() } func Bool64(b bool) int64 { if b { return 1 } return 0 } func Environ() uintptr { __ccgo_environOnce.Do(func() { Xenviron = mustAllocStrings(os.Environ()) }) return Xenviron } func EnvironP() uintptr { __ccgo_environOnce.Do(func() { Xenviron = mustAllocStrings(os.Environ()) }) return uintptr(unsafe.Pointer(&Xenviron)) } // NewVaList is like VaList but automatically allocates the correct amount of // memory for all of the items in args. // // The va_list return value is used to pass the constructed var args to var // args accepting functions. The caller of NewVaList is responsible for freeing // the va_list. func NewVaList(args ...interface{}) (va_list uintptr) { return VaList(NewVaListN(len(args)), args...) } // NewVaListN returns a newly allocated va_list for n items. The caller of // NewVaListN is responsible for freeing the va_list. func NewVaListN(n int) (va_list uintptr) { return Xmalloc(nil, Tsize_t(8*n)) } func SetEnviron(t *TLS, env []string) { __ccgo_environOnce.Do(func() { Xenviron = mustAllocStrings(env) }) } func Dmesg(s string, args ...interface{}) { // nop } func Xalloca(tls *TLS, size Tsize_t) uintptr { return tls.alloca(size) } // struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg); func X__cmsg_nxthdr(t *TLS, msgh, cmsg uintptr) uintptr { panic(todo("")) } func Cover() { runtime.Callers(2, coverPCs[:]) Covered[coverPCs[0]] = struct{}{} } func CoverReport(w io.Writer) error { var a []string pcs := make([]uintptr, 1) for pc := range Covered { pcs[0] = pc frame, _ := runtime.CallersFrames(pcs).Next() a = append(a, fmt.Sprintf("%s:%07d:%s", filepath.Base(frame.File), frame.Line, frame.Func.Name())) } sort.Strings(a) _, err := fmt.Fprintf(w, "%s\n", strings.Join(a, "\n")) return err } func CoverC(s string) { CoveredC[s] = struct{}{} } func CoverCReport(w io.Writer) error { var a []string for k := range CoveredC { a = append(a, k) } sort.Strings(a) _, err := fmt.Fprintf(w, "%s\n", strings.Join(a, "\n")) return err } func X__ccgo_dmesg(t *TLS, fmt uintptr, va uintptr) { panic(todo("")) } func X__ccgo_getMutexType(tls *TLS, m uintptr) int32 { /* pthread_mutex_lock.c:3:5: */ panic(todo("")) } func X__ccgo_in6addr_anyp(t *TLS) uintptr { panic(todo("")) } func X__ccgo_pthreadAttrGetDetachState(tls *TLS, a uintptr) int32 { /* pthread_attr_get.c:3:5: */ panic(todo("")) } func X__ccgo_pthreadMutexattrGettype(tls *TLS, a uintptr) int32 { /* pthread_attr_get.c:93:5: */ panic(todo("")) } // void sqlite3_log(int iErrCode, const char *zFormat, ...); func X__ccgo_sqlite3_log(t *TLS, iErrCode int32, zFormat uintptr, args uintptr) { // nop } // unsigned __sync_add_and_fetch_uint32(*unsigned, unsigned) func X__sync_add_and_fetch_uint32(t *TLS, p uintptr, v uint32) uint32 { return atomic.AddUint32((*uint32)(unsafe.Pointer(p)), v) } // unsigned __sync_sub_and_fetch_uint32(*unsigned, unsigned) func X__sync_sub_and_fetch_uint32(t *TLS, p uintptr, v uint32) uint32 { return atomic.AddUint32((*uint32)(unsafe.Pointer(p)), -v) } var ( randomData = map[uintptr]*rand.Rand{} randomDataMu sync.Mutex ) // The initstate_r() function is like initstate(3) except that it initializes // the state in the object pointed to by buf, rather than initializing the // global state variable. Before calling this function, the buf.state field // must be initialized to NULL. The initstate_r() function records a pointer // to the statebuf argument inside the structure pointed to by buf. Thus, // stateā€ buf should not be deallocated so long as buf is still in use. (So, // statebuf should typically be allocated as a static variable, or allocated on // the heap using malloc(3) or similar.) // // char *initstate_r(unsigned int seed, char *statebuf, size_t statelen, struct random_data *buf); func Xinitstate_r(t *TLS, seed uint32, statebuf uintptr, statelen Tsize_t, buf uintptr) int32 { if buf == 0 { panic(todo("")) } randomDataMu.Lock() defer randomDataMu.Unlock() randomData[buf] = rand.New(rand.NewSource(int64(seed))) return 0 } // int random_r(struct random_data *buf, int32_t *result); func Xrandom_r(t *TLS, buf, result uintptr) int32 { randomDataMu.Lock() defer randomDataMu.Unlock() mr := randomData[buf] if RAND_MAX != math.MaxInt32 { panic(todo("")) } *(*int32)(unsafe.Pointer(result)) = mr.Int31() return 0 } // void longjmp(jmp_buf env, int val); func Xlongjmp(t *TLS, env uintptr, val int32) { panic(todo("")) } // void _longjmp(jmp_buf env, int val); func X_longjmp(t *TLS, env uintptr, val int32) { panic(todo("")) } // int _obstack_begin (struct obstack *h, _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment, void *(*chunkfun) (size_t), void (*freefun) (void *)) func X_obstack_begin(t *TLS, obstack uintptr, size, alignment int32, chunkfun, freefun uintptr) int32 { panic(todo("")) } // extern void _obstack_newchunk(struct obstack *, int); func X_obstack_newchunk(t *TLS, obstack uintptr, length int32) int32 { panic(todo("")) } // void obstack_free (struct obstack *h, void *obj) func Xobstack_free(t *TLS, obstack, obj uintptr) { panic(todo("")) } // int obstack_vprintf (struct obstack *obstack, const char *template, va_list ap) func Xobstack_vprintf(t *TLS, obstack, template, va uintptr) int32 { panic(todo("")) } // int _setjmp(jmp_buf env); func X_setjmp(t *TLS, env uintptr) int32 { return 0 //TODO } // int setjmp(jmp_buf env); func Xsetjmp(t *TLS, env uintptr) int32 { panic(todo("")) } // int backtrace(void **buffer, int size); func Xbacktrace(t *TLS, buf uintptr, size int32) int32 { panic(todo("")) } // void backtrace_symbols_fd(void *const *buffer, int size, int fd); func Xbacktrace_symbols_fd(t *TLS, buffer uintptr, size, fd int32) { panic(todo("")) } // int fts_close(FTS *ftsp); func Xfts_close(t *TLS, ftsp uintptr) int32 { panic(todo("")) } // FTS *fts_open(char * const *path_argv, int options, int (*compar)(const FTSENT **, const FTSENT **)); func Xfts_open(t *TLS, path_argv uintptr, options int32, compar uintptr) uintptr { panic(todo("")) } // FTSENT *fts_read(FTS *ftsp); func Xfts64_read(t *TLS, ftsp uintptr) uintptr { panic(todo("")) } // int fts_close(FTS *ftsp); func Xfts64_close(t *TLS, ftsp uintptr) int32 { panic(todo("")) } // FTS *fts_open(char * const *path_argv, int options, int (*compar)(const FTSENT **, const FTSENT **)); func Xfts64_open(t *TLS, path_argv uintptr, options int32, compar uintptr) uintptr { panic(todo("")) } // FTSENT *fts_read(FTS *ftsp); func Xfts_read(t *TLS, ftsp uintptr) uintptr { panic(todo("")) } // FILE *popen(const char *command, const char *type); func Xpopen(t *TLS, command, type1 uintptr) uintptr { panic(todo("")) } // int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); func Xsysctlbyname(t *TLS, name, oldp, oldlenp, newp uintptr, newlen Tsize_t) int32 { oldlen := *(*Tsize_t)(unsafe.Pointer(oldlenp)) switch GoString(name) { case "hw.ncpu": if oldlen != 4 { panic(todo("")) } *(*int32)(unsafe.Pointer(oldp)) = int32(runtime.GOMAXPROCS(-1)) return 0 default: panic(todo("")) t.setErrno(ENOENT) return -1 } } // void uuid_copy(uuid_t dst, uuid_t src); func Xuuid_copy(t *TLS, dst, src uintptr) { panic(todo("")) } // int uuid_parse( char *in, uuid_t uu); func Xuuid_parse(t *TLS, in uintptr, uu uintptr) int32 { panic(todo("")) } // void uuid_generate_random(uuid_t out); func Xuuid_generate_random(t *TLS, out uintptr) { panic(todo("")) } // void uuid_unparse(uuid_t uu, char *out); func Xuuid_unparse(t *TLS, uu, out uintptr) { panic(todo("")) } var Xzero_struct_address Taddress