AJ ONeal
5 years ago
220 changed files with 62949 additions and 11013 deletions
@ -0,0 +1,29 @@ |
|||
// Copyright 2018 The Go Authors. All rights reserved. |
|||
// Use of this source code is governed by a BSD-style |
|||
// license that can be found in the LICENSE file. |
|||
|
|||
// +build !gccgo |
|||
|
|||
#include "textflag.h" |
|||
|
|||
// |
|||
// System call support for ARM64, FreeBSD |
|||
// |
|||
|
|||
// Just jump to package syscall's implementation for all these functions. |
|||
// The runtime may know about them. |
|||
|
|||
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
|||
JMP syscall·Syscall(SB) |
|||
|
|||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
|||
JMP syscall·Syscall6(SB) |
|||
|
|||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
|||
JMP syscall·Syscall9(SB) |
|||
|
|||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
|||
JMP syscall·RawSyscall(SB) |
|||
|
|||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
|||
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,54 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved. |
|||
// Use of this source code is governed by a BSD-style |
|||
// license that can be found in the LICENSE file. |
|||
|
|||
// +build riscv64,!gccgo |
|||
|
|||
#include "textflag.h" |
|||
|
|||
// |
|||
// System calls for linux/riscv64. |
|||
// |
|||
// Where available, just jump to package syscall's implementation of |
|||
// these functions. |
|||
|
|||
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
|||
JMP syscall·Syscall(SB) |
|||
|
|||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
|||
JMP syscall·Syscall6(SB) |
|||
|
|||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 |
|||
CALL runtime·entersyscall(SB) |
|||
MOV a1+8(FP), A0 |
|||
MOV a2+16(FP), A1 |
|||
MOV a3+24(FP), A2 |
|||
MOV $0, A3 |
|||
MOV $0, A4 |
|||
MOV $0, A5 |
|||
MOV $0, A6 |
|||
MOV trap+0(FP), A7 // syscall entry |
|||
ECALL |
|||
MOV A0, r1+32(FP) // r1 |
|||
MOV A1, r2+40(FP) // r2 |
|||
CALL runtime·exitsyscall(SB) |
|||
RET |
|||
|
|||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
|||
JMP syscall·RawSyscall(SB) |
|||
|
|||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
|||
JMP syscall·RawSyscall6(SB) |
|||
|
|||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 |
|||
MOV a1+8(FP), A0 |
|||
MOV a2+16(FP), A1 |
|||
MOV a3+24(FP), A2 |
|||
MOV ZERO, A3 |
|||
MOV ZERO, A4 |
|||
MOV ZERO, A5 |
|||
MOV trap+0(FP), A7 // syscall entry |
|||
ECALL |
|||
MOV A0, r1+32(FP) |
|||
MOV A1, r2+40(FP) |
|||
RET |
@ -0,0 +1,29 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved. |
|||
// Use of this source code is governed by a BSD-style |
|||
// license that can be found in the LICENSE file. |
|||
|
|||
// +build !gccgo |
|||
|
|||
#include "textflag.h" |
|||
|
|||
// |
|||
// System call support for ARM64, NetBSD |
|||
// |
|||
|
|||
// Just jump to package syscall's implementation for all these functions. |
|||
// The runtime may know about them. |
|||
|
|||
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
|||
B syscall·Syscall(SB) |
|||
|
|||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
|||
B syscall·Syscall6(SB) |
|||
|
|||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
|||
B syscall·Syscall9(SB) |
|||
|
|||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
|||
B syscall·RawSyscall(SB) |
|||
|
|||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
|||
B syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved. |
|||
// Use of this source code is governed by a BSD-style |
|||
// license that can be found in the LICENSE file. |
|||
|
|||
// +build !gccgo |
|||
|
|||
#include "textflag.h" |
|||
|
|||
// |
|||
// System call support for arm64, OpenBSD |
|||
// |
|||
|
|||
// Just jump to package syscall's implementation for all these functions. |
|||
// The runtime may know about them. |
|||
|
|||
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
|||
JMP syscall·Syscall(SB) |
|||
|
|||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
|||
JMP syscall·Syscall6(SB) |
|||
|
|||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
|||
JMP syscall·Syscall9(SB) |
|||
|
|||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
|||
JMP syscall·RawSyscall(SB) |
|||
|
|||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
|||
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,18 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
package unix |
|||
|
|||
import "unsafe" |
|||
|
|||
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
|
|||
func FcntlInt(fd uintptr, cmd, arg int) (int, error) { |
|||
return fcntl(int(fd), cmd, arg) |
|||
} |
|||
|
|||
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
|
|||
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { |
|||
_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk)))) |
|||
return err |
|||
} |
@ -0,0 +1,61 @@ |
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build ignore
|
|||
|
|||
// mkasm_darwin.go generates assembly trampolines to call libSystem routines from Go.
|
|||
//This program must be run after mksyscall.go.
|
|||
package main |
|||
|
|||
import ( |
|||
"bytes" |
|||
"fmt" |
|||
"io/ioutil" |
|||
"log" |
|||
"os" |
|||
"strings" |
|||
) |
|||
|
|||
func main() { |
|||
in1, err := ioutil.ReadFile("syscall_darwin.go") |
|||
if err != nil { |
|||
log.Fatalf("can't open syscall_darwin.go: %s", err) |
|||
} |
|||
arch := os.Args[1] |
|||
in2, err := ioutil.ReadFile(fmt.Sprintf("syscall_darwin_%s.go", arch)) |
|||
if err != nil { |
|||
log.Fatalf("can't open syscall_darwin_%s.go: %s", arch, err) |
|||
} |
|||
in3, err := ioutil.ReadFile(fmt.Sprintf("zsyscall_darwin_%s.go", arch)) |
|||
if err != nil { |
|||
log.Fatalf("can't open zsyscall_darwin_%s.go: %s", arch, err) |
|||
} |
|||
in := string(in1) + string(in2) + string(in3) |
|||
|
|||
trampolines := map[string]bool{} |
|||
|
|||
var out bytes.Buffer |
|||
|
|||
fmt.Fprintf(&out, "// go run mkasm_darwin.go %s\n", strings.Join(os.Args[1:], " ")) |
|||
fmt.Fprintf(&out, "// Code generated by the command above; DO NOT EDIT.\n") |
|||
fmt.Fprintf(&out, "\n") |
|||
fmt.Fprintf(&out, "// +build go1.12\n") |
|||
fmt.Fprintf(&out, "\n") |
|||
fmt.Fprintf(&out, "#include \"textflag.h\"\n") |
|||
for _, line := range strings.Split(in, "\n") { |
|||
if !strings.HasPrefix(line, "func ") || !strings.HasSuffix(line, "_trampoline()") { |
|||
continue |
|||
} |
|||
fn := line[5 : len(line)-13] |
|||
if !trampolines[fn] { |
|||
trampolines[fn] = true |
|||
fmt.Fprintf(&out, "TEXT ·%s_trampoline(SB),NOSPLIT,$0-0\n", fn) |
|||
fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn) |
|||
} |
|||
} |
|||
err = ioutil.WriteFile(fmt.Sprintf("zsyscall_darwin_%s.s", arch), out.Bytes(), 0644) |
|||
if err != nil { |
|||
log.Fatalf("can't write zsyscall_darwin_%s.s: %s", arch, err) |
|||
} |
|||
} |
@ -0,0 +1,407 @@ |
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build ignore
|
|||
|
|||
/* |
|||
This program reads a file containing function prototypes |
|||
(like syscall_darwin.go) and generates system call bodies. |
|||
The prototypes are marked by lines beginning with "//sys" |
|||
and read like func declarations if //sys is replaced by func, but:
|
|||
* The parameter lists must give a name for each argument. |
|||
This includes return parameters. |
|||
* The parameter lists must give a type for each argument: |
|||
the (x, y, z int) shorthand is not allowed. |
|||
* If the return parameter is an error number, it must be named errno. |
|||
|
|||
A line beginning with //sysnb is like //sys, except that the
|
|||
goroutine will not be suspended during the execution of the system |
|||
call. This must only be used for system calls which can never |
|||
block, as otherwise the system call could cause all goroutines to |
|||
hang. |
|||
*/ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"flag" |
|||
"fmt" |
|||
"os" |
|||
"regexp" |
|||
"strings" |
|||
) |
|||
|
|||
var ( |
|||
b32 = flag.Bool("b32", false, "32bit big-endian") |
|||
l32 = flag.Bool("l32", false, "32bit little-endian") |
|||
plan9 = flag.Bool("plan9", false, "plan9") |
|||
openbsd = flag.Bool("openbsd", false, "openbsd") |
|||
netbsd = flag.Bool("netbsd", false, "netbsd") |
|||
dragonfly = flag.Bool("dragonfly", false, "dragonfly") |
|||
arm = flag.Bool("arm", false, "arm") // 64-bit value should use (even, odd)-pair
|
|||
tags = flag.String("tags", "", "build tags") |
|||
filename = flag.String("output", "", "output file name (standard output if omitted)") |
|||
) |
|||
|
|||
// cmdLine returns this programs's commandline arguments
|
|||
func cmdLine() string { |
|||
return "go run mksyscall.go " + strings.Join(os.Args[1:], " ") |
|||
} |
|||
|
|||
// buildTags returns build tags
|
|||
func buildTags() string { |
|||
return *tags |
|||
} |
|||
|
|||
// Param is function parameter
|
|||
type Param struct { |
|||
Name string |
|||
Type string |
|||
} |
|||
|
|||
// usage prints the program usage
|
|||
func usage() { |
|||
fmt.Fprintf(os.Stderr, "usage: go run mksyscall.go [-b32 | -l32] [-tags x,y] [file ...]\n") |
|||
os.Exit(1) |
|||
} |
|||
|
|||
// parseParamList parses parameter list and returns a slice of parameters
|
|||
func parseParamList(list string) []string { |
|||
list = strings.TrimSpace(list) |
|||
if list == "" { |
|||
return []string{} |
|||
} |
|||
return regexp.MustCompile(`\s*,\s*`).Split(list, -1) |
|||
} |
|||
|
|||
// parseParam splits a parameter into name and type
|
|||
func parseParam(p string) Param { |
|||
ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) |
|||
if ps == nil { |
|||
fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) |
|||
os.Exit(1) |
|||
} |
|||
return Param{ps[1], ps[2]} |
|||
} |
|||
|
|||
func main() { |
|||
// Get the OS and architecture (using GOARCH_TARGET if it exists)
|
|||
goos := os.Getenv("GOOS") |
|||
if goos == "" { |
|||
fmt.Fprintln(os.Stderr, "GOOS not defined in environment") |
|||
os.Exit(1) |
|||
} |
|||
goarch := os.Getenv("GOARCH_TARGET") |
|||
if goarch == "" { |
|||
goarch = os.Getenv("GOARCH") |
|||
} |
|||
|
|||
// Check that we are using the Docker-based build system if we should
|
|||
if goos == "linux" { |
|||
if os.Getenv("GOLANG_SYS_BUILD") != "docker" { |
|||
fmt.Fprintf(os.Stderr, "In the Docker-based build system, mksyscall should not be called directly.\n") |
|||
fmt.Fprintf(os.Stderr, "See README.md\n") |
|||
os.Exit(1) |
|||
} |
|||
} |
|||
|
|||
flag.Usage = usage |
|||
flag.Parse() |
|||
if len(flag.Args()) <= 0 { |
|||
fmt.Fprintf(os.Stderr, "no files to parse provided\n") |
|||
usage() |
|||
} |
|||
|
|||
endianness := "" |
|||
if *b32 { |
|||
endianness = "big-endian" |
|||
} else if *l32 { |
|||
endianness = "little-endian" |
|||
} |
|||
|
|||
libc := false |
|||
if goos == "darwin" && strings.Contains(buildTags(), ",go1.12") { |
|||
libc = true |
|||
} |
|||
trampolines := map[string]bool{} |
|||
|
|||
text := "" |
|||
for _, path := range flag.Args() { |
|||
file, err := os.Open(path) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
s := bufio.NewScanner(file) |
|||
for s.Scan() { |
|||
t := s.Text() |
|||
t = strings.TrimSpace(t) |
|||
t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) |
|||
nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) |
|||
if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { |
|||
continue |
|||
} |
|||
|
|||
// Line must be of the form
|
|||
// func Open(path string, mode int, perm int) (fd int, errno error)
|
|||
// Split into name, in params, out params.
|
|||
f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$`).FindStringSubmatch(t) |
|||
if f == nil { |
|||
fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) |
|||
os.Exit(1) |
|||
} |
|||
funct, inps, outps, sysname := f[2], f[3], f[4], f[5] |
|||
|
|||
// ClockGettime doesn't have a syscall number on Darwin, only generate libc wrappers.
|
|||
if goos == "darwin" && !libc && funct == "ClockGettime" { |
|||
continue |
|||
} |
|||
|
|||
// Split argument lists on comma.
|
|||
in := parseParamList(inps) |
|||
out := parseParamList(outps) |
|||
|
|||
// Try in vain to keep people from editing this file.
|
|||
// The theory is that they jump into the middle of the file
|
|||
// without reading the header.
|
|||
text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
|||
|
|||
// Go function header.
|
|||
outDecl := "" |
|||
if len(out) > 0 { |
|||
outDecl = fmt.Sprintf(" (%s)", strings.Join(out, ", ")) |
|||
} |
|||
text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outDecl) |
|||
|
|||
// Check if err return available
|
|||
errvar := "" |
|||
for _, param := range out { |
|||
p := parseParam(param) |
|||
if p.Type == "error" { |
|||
errvar = p.Name |
|||
break |
|||
} |
|||
} |
|||
|
|||
// Prepare arguments to Syscall.
|
|||
var args []string |
|||
n := 0 |
|||
for _, param := range in { |
|||
p := parseParam(param) |
|||
if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { |
|||
args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))") |
|||
} else if p.Type == "string" && errvar != "" { |
|||
text += fmt.Sprintf("\tvar _p%d *byte\n", n) |
|||
text += fmt.Sprintf("\t_p%d, %s = BytePtrFromString(%s)\n", n, errvar, p.Name) |
|||
text += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) |
|||
args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) |
|||
n++ |
|||
} else if p.Type == "string" { |
|||
fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") |
|||
text += fmt.Sprintf("\tvar _p%d *byte\n", n) |
|||
text += fmt.Sprintf("\t_p%d, _ = BytePtrFromString(%s)\n", n, p.Name) |
|||
args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) |
|||
n++ |
|||
} else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil { |
|||
// Convert slice into pointer, length.
|
|||
// Have to be careful not to take address of &a[0] if len == 0:
|
|||
// pass dummy pointer in that case.
|
|||
// Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
|
|||
text += fmt.Sprintf("\tvar _p%d unsafe.Pointer\n", n) |
|||
text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = unsafe.Pointer(&%s[0])\n\t}", p.Name, n, p.Name) |
|||
text += fmt.Sprintf(" else {\n\t\t_p%d = unsafe.Pointer(&_zero)\n\t}\n", n) |
|||
args = append(args, fmt.Sprintf("uintptr(_p%d)", n), fmt.Sprintf("uintptr(len(%s))", p.Name)) |
|||
n++ |
|||
} else if p.Type == "int64" && (*openbsd || *netbsd) { |
|||
args = append(args, "0") |
|||
if endianness == "big-endian" { |
|||
args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} else if endianness == "little-endian" { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) |
|||
} else { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} |
|||
} else if p.Type == "int64" && *dragonfly { |
|||
if regexp.MustCompile(`^(?i)extp(read|write)`).FindStringSubmatch(funct) == nil { |
|||
args = append(args, "0") |
|||
} |
|||
if endianness == "big-endian" { |
|||
args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} else if endianness == "little-endian" { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) |
|||
} else { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} |
|||
} else if (p.Type == "int64" || p.Type == "uint64") && endianness != "" { |
|||
if len(args)%2 == 1 && *arm { |
|||
// arm abi specifies 64-bit argument uses
|
|||
// (even, odd) pair
|
|||
args = append(args, "0") |
|||
} |
|||
if endianness == "big-endian" { |
|||
args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} else { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) |
|||
} |
|||
} else { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} |
|||
} |
|||
|
|||
// Determine which form to use; pad args with zeros.
|
|||
asm := "Syscall" |
|||
if nonblock != nil { |
|||
if errvar == "" && goos == "linux" { |
|||
asm = "RawSyscallNoError" |
|||
} else { |
|||
asm = "RawSyscall" |
|||
} |
|||
} else { |
|||
if errvar == "" && goos == "linux" { |
|||
asm = "SyscallNoError" |
|||
} |
|||
} |
|||
if len(args) <= 3 { |
|||
for len(args) < 3 { |
|||
args = append(args, "0") |
|||
} |
|||
} else if len(args) <= 6 { |
|||
asm += "6" |
|||
for len(args) < 6 { |
|||
args = append(args, "0") |
|||
} |
|||
} else if len(args) <= 9 { |
|||
asm += "9" |
|||
for len(args) < 9 { |
|||
args = append(args, "0") |
|||
} |
|||
} else { |
|||
fmt.Fprintf(os.Stderr, "%s:%s too many arguments to system call\n", path, funct) |
|||
} |
|||
|
|||
// System call number.
|
|||
if sysname == "" { |
|||
sysname = "SYS_" + funct |
|||
sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`) |
|||
sysname = strings.ToUpper(sysname) |
|||
} |
|||
|
|||
var libcFn string |
|||
if libc { |
|||
asm = "syscall_" + strings.ToLower(asm[:1]) + asm[1:] // internal syscall call
|
|||
sysname = strings.TrimPrefix(sysname, "SYS_") // remove SYS_
|
|||
sysname = strings.ToLower(sysname) // lowercase
|
|||
if sysname == "getdirentries64" { |
|||
// Special case - libSystem name and
|
|||
// raw syscall name don't match.
|
|||
sysname = "__getdirentries64" |
|||
} |
|||
libcFn = sysname |
|||
sysname = "funcPC(libc_" + sysname + "_trampoline)" |
|||
} |
|||
|
|||
// Actual call.
|
|||
arglist := strings.Join(args, ", ") |
|||
call := fmt.Sprintf("%s(%s, %s)", asm, sysname, arglist) |
|||
|
|||
// Assign return values.
|
|||
body := "" |
|||
ret := []string{"_", "_", "_"} |
|||
doErrno := false |
|||
for i := 0; i < len(out); i++ { |
|||
p := parseParam(out[i]) |
|||
reg := "" |
|||
if p.Name == "err" && !*plan9 { |
|||
reg = "e1" |
|||
ret[2] = reg |
|||
doErrno = true |
|||
} else if p.Name == "err" && *plan9 { |
|||
ret[0] = "r0" |
|||
ret[2] = "e1" |
|||
break |
|||
} else { |
|||
reg = fmt.Sprintf("r%d", i) |
|||
ret[i] = reg |
|||
} |
|||
if p.Type == "bool" { |
|||
reg = fmt.Sprintf("%s != 0", reg) |
|||
} |
|||
if p.Type == "int64" && endianness != "" { |
|||
// 64-bit number in r1:r0 or r0:r1.
|
|||
if i+2 > len(out) { |
|||
fmt.Fprintf(os.Stderr, "%s:%s not enough registers for int64 return\n", path, funct) |
|||
} |
|||
if endianness == "big-endian" { |
|||
reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i, i+1) |
|||
} else { |
|||
reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i+1, i) |
|||
} |
|||
ret[i] = fmt.Sprintf("r%d", i) |
|||
ret[i+1] = fmt.Sprintf("r%d", i+1) |
|||
} |
|||
if reg != "e1" || *plan9 { |
|||
body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) |
|||
} |
|||
} |
|||
if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" { |
|||
text += fmt.Sprintf("\t%s\n", call) |
|||
} else { |
|||
if errvar == "" && goos == "linux" { |
|||
// raw syscall without error on Linux, see golang.org/issue/22924
|
|||
text += fmt.Sprintf("\t%s, %s := %s\n", ret[0], ret[1], call) |
|||
} else { |
|||
text += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call) |
|||
} |
|||
} |
|||
text += body |
|||
|
|||
if *plan9 && ret[2] == "e1" { |
|||
text += "\tif int32(r0) == -1 {\n" |
|||
text += "\t\terr = e1\n" |
|||
text += "\t}\n" |
|||
} else if doErrno { |
|||
text += "\tif e1 != 0 {\n" |
|||
text += "\t\terr = errnoErr(e1)\n" |
|||
text += "\t}\n" |
|||
} |
|||
text += "\treturn\n" |
|||
text += "}\n\n" |
|||
|
|||
if libc && !trampolines[libcFn] { |
|||
// some system calls share a trampoline, like read and readlen.
|
|||
trampolines[libcFn] = true |
|||
// Declare assembly trampoline.
|
|||
text += fmt.Sprintf("func libc_%s_trampoline()\n", libcFn) |
|||
// Assembly trampoline calls the libc_* function, which this magic
|
|||
// redirects to use the function from libSystem.
|
|||
text += fmt.Sprintf("//go:linkname libc_%s libc_%s\n", libcFn, libcFn) |
|||
text += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"/usr/lib/libSystem.B.dylib\"\n", libcFn, libcFn) |
|||
text += "\n" |
|||
} |
|||
} |
|||
if err := s.Err(); err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
file.Close() |
|||
} |
|||
fmt.Printf(srcTemplate, cmdLine(), buildTags(), text) |
|||
} |
|||
|
|||
const srcTemplate = `// %s
|
|||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|||
|
|||
// +build %s
|
|||
|
|||
package unix |
|||
|
|||
import ( |
|||
"syscall" |
|||
"unsafe" |
|||
) |
|||
|
|||
var _ syscall.Errno |
|||
|
|||
%s |
|||
` |
@ -1,341 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2009 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
|
|||
# This program reads a file containing function prototypes |
|||
# (like syscall_darwin.go) and generates system call bodies. |
|||
# The prototypes are marked by lines beginning with "//sys" |
|||
# and read like func declarations if //sys is replaced by func, but: |
|||
# * The parameter lists must give a name for each argument. |
|||
# This includes return parameters. |
|||
# * The parameter lists must give a type for each argument: |
|||
# the (x, y, z int) shorthand is not allowed. |
|||
# * If the return parameter is an error number, it must be named errno. |
|||
|
|||
# A line beginning with //sysnb is like //sys, except that the |
|||
# goroutine will not be suspended during the execution of the system |
|||
# call. This must only be used for system calls which can never |
|||
# block, as otherwise the system call could cause all goroutines to |
|||
# hang. |
|||
|
|||
use strict; |
|||
|
|||
my $cmdline = "mksyscall.pl " . join(' ', @ARGV); |
|||
my $errors = 0; |
|||
my $_32bit = ""; |
|||
my $plan9 = 0; |
|||
my $openbsd = 0; |
|||
my $netbsd = 0; |
|||
my $dragonfly = 0; |
|||
my $arm = 0; # 64-bit value should use (even, odd)-pair |
|||
my $tags = ""; # build tags |
|||
|
|||
if($ARGV[0] eq "-b32") { |
|||
$_32bit = "big-endian"; |
|||
shift; |
|||
} elsif($ARGV[0] eq "-l32") { |
|||
$_32bit = "little-endian"; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-plan9") { |
|||
$plan9 = 1; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-openbsd") { |
|||
$openbsd = 1; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-netbsd") { |
|||
$netbsd = 1; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-dragonfly") { |
|||
$dragonfly = 1; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-arm") { |
|||
$arm = 1; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-tags") { |
|||
shift; |
|||
$tags = $ARGV[0]; |
|||
shift; |
|||
} |
|||
|
|||
if($ARGV[0] =~ /^-/) { |
|||
print STDERR "usage: mksyscall.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
# Check that we are using the new build system if we should |
|||
if($ENV{'GOOS'} eq "linux" && $ENV{'GOARCH'} ne "sparc64") { |
|||
if($ENV{'GOLANG_SYS_BUILD'} ne "docker") { |
|||
print STDERR "In the new build system, mksyscall should not be called directly.\n"; |
|||
print STDERR "See README.md\n"; |
|||
exit 1; |
|||
} |
|||
} |
|||
|
|||
|
|||
sub parseparamlist($) { |
|||
my ($list) = @_; |
|||
$list =~ s/^\s*//; |
|||
$list =~ s/\s*$//; |
|||
if($list eq "") { |
|||
return (); |
|||
} |
|||
return split(/\s*,\s*/, $list); |
|||
} |
|||
|
|||
sub parseparam($) { |
|||
my ($p) = @_; |
|||
if($p !~ /^(\S*) (\S*)$/) { |
|||
print STDERR "$ARGV:$.: malformed parameter: $p\n"; |
|||
$errors = 1; |
|||
return ("xx", "int"); |
|||
} |
|||
return ($1, $2); |
|||
} |
|||
|
|||
my $text = ""; |
|||
while(<>) { |
|||
chomp; |
|||
s/\s+/ /g; |
|||
s/^\s+//; |
|||
s/\s+$//; |
|||
my $nonblock = /^\/\/sysnb /; |
|||
next if !/^\/\/sys / && !$nonblock; |
|||
|
|||
# Line must be of the form |
|||
# func Open(path string, mode int, perm int) (fd int, errno error) |
|||
# Split into name, in params, out params. |
|||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) { |
|||
print STDERR "$ARGV:$.: malformed //sys declaration\n"; |
|||
$errors = 1; |
|||
next; |
|||
} |
|||
my ($func, $in, $out, $sysname) = ($2, $3, $4, $5); |
|||
|
|||
# Split argument lists on comma. |
|||
my @in = parseparamlist($in); |
|||
my @out = parseparamlist($out); |
|||
|
|||
# Try in vain to keep people from editing this file. |
|||
# The theory is that they jump into the middle of the file |
|||
# without reading the header. |
|||
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; |
|||
|
|||
# Go function header. |
|||
my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : ""; |
|||
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl; |
|||
|
|||
# Check if err return available |
|||
my $errvar = ""; |
|||
foreach my $p (@out) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type eq "error") { |
|||
$errvar = $name; |
|||
last; |
|||
} |
|||
} |
|||
|
|||
# Prepare arguments to Syscall. |
|||
my @args = (); |
|||
my $n = 0; |
|||
foreach my $p (@in) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type =~ /^\*/) { |
|||
push @args, "uintptr(unsafe.Pointer($name))"; |
|||
} elsif($type eq "string" && $errvar ne "") { |
|||
$text .= "\tvar _p$n *byte\n"; |
|||
$text .= "\t_p$n, $errvar = BytePtrFromString($name)\n"; |
|||
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; |
|||
push @args, "uintptr(unsafe.Pointer(_p$n))"; |
|||
$n++; |
|||
} elsif($type eq "string") { |
|||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; |
|||
$text .= "\tvar _p$n *byte\n"; |
|||
$text .= "\t_p$n, _ = BytePtrFromString($name)\n"; |
|||
push @args, "uintptr(unsafe.Pointer(_p$n))"; |
|||
$n++; |
|||
} elsif($type =~ /^\[\](.*)/) { |
|||
# Convert slice into pointer, length. |
|||
# Have to be careful not to take address of &a[0] if len == 0: |
|||
# pass dummy pointer in that case. |
|||
# Used to pass nil, but some OSes or simulators reject write(fd, nil, 0). |
|||
$text .= "\tvar _p$n unsafe.Pointer\n"; |
|||
$text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}"; |
|||
$text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}"; |
|||
$text .= "\n"; |
|||
push @args, "uintptr(_p$n)", "uintptr(len($name))"; |
|||
$n++; |
|||
} elsif($type eq "int64" && ($openbsd || $netbsd)) { |
|||
push @args, "0"; |
|||
if($_32bit eq "big-endian") { |
|||
push @args, "uintptr($name>>32)", "uintptr($name)"; |
|||
} elsif($_32bit eq "little-endian") { |
|||
push @args, "uintptr($name)", "uintptr($name>>32)"; |
|||
} else { |
|||
push @args, "uintptr($name)"; |
|||
} |
|||
} elsif($type eq "int64" && $dragonfly) { |
|||
if ($func !~ /^extp(read|write)/i) { |
|||
push @args, "0"; |
|||
} |
|||
if($_32bit eq "big-endian") { |
|||
push @args, "uintptr($name>>32)", "uintptr($name)"; |
|||
} elsif($_32bit eq "little-endian") { |
|||
push @args, "uintptr($name)", "uintptr($name>>32)"; |
|||
} else { |
|||
push @args, "uintptr($name)"; |
|||
} |
|||
} elsif($type eq "int64" && $_32bit ne "") { |
|||
if(@args % 2 && $arm) { |
|||
# arm abi specifies 64-bit argument uses |
|||
# (even, odd) pair |
|||
push @args, "0" |
|||
} |
|||
if($_32bit eq "big-endian") { |
|||
push @args, "uintptr($name>>32)", "uintptr($name)"; |
|||
} else { |
|||
push @args, "uintptr($name)", "uintptr($name>>32)"; |
|||
} |
|||
} else { |
|||
push @args, "uintptr($name)"; |
|||
} |
|||
} |
|||
|
|||
# Determine which form to use; pad args with zeros. |
|||
my $asm = "Syscall"; |
|||
if ($nonblock) { |
|||
if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { |
|||
$asm = "RawSyscallNoError"; |
|||
} else { |
|||
$asm = "RawSyscall"; |
|||
} |
|||
} else { |
|||
if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { |
|||
$asm = "SyscallNoError"; |
|||
} |
|||
} |
|||
if(@args <= 3) { |
|||
while(@args < 3) { |
|||
push @args, "0"; |
|||
} |
|||
} elsif(@args <= 6) { |
|||
$asm .= "6"; |
|||
while(@args < 6) { |
|||
push @args, "0"; |
|||
} |
|||
} elsif(@args <= 9) { |
|||
$asm .= "9"; |
|||
while(@args < 9) { |
|||
push @args, "0"; |
|||
} |
|||
} else { |
|||
print STDERR "$ARGV:$.: too many arguments to system call\n"; |
|||
} |
|||
|
|||
# System call number. |
|||
if($sysname eq "") { |
|||
$sysname = "SYS_$func"; |
|||
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar |
|||
$sysname =~ y/a-z/A-Z/; |
|||
} |
|||
|
|||
# Actual call. |
|||
my $args = join(', ', @args); |
|||
my $call = "$asm($sysname, $args)"; |
|||
|
|||
# Assign return values. |
|||
my $body = ""; |
|||
my @ret = ("_", "_", "_"); |
|||
my $do_errno = 0; |
|||
for(my $i=0; $i<@out; $i++) { |
|||
my $p = $out[$i]; |
|||
my ($name, $type) = parseparam($p); |
|||
my $reg = ""; |
|||
if($name eq "err" && !$plan9) { |
|||
$reg = "e1"; |
|||
$ret[2] = $reg; |
|||
$do_errno = 1; |
|||
} elsif($name eq "err" && $plan9) { |
|||
$ret[0] = "r0"; |
|||
$ret[2] = "e1"; |
|||
next; |
|||
} else { |
|||
$reg = sprintf("r%d", $i); |
|||
$ret[$i] = $reg; |
|||
} |
|||
if($type eq "bool") { |
|||
$reg = "$reg != 0"; |
|||
} |
|||
if($type eq "int64" && $_32bit ne "") { |
|||
# 64-bit number in r1:r0 or r0:r1. |
|||
if($i+2 > @out) { |
|||
print STDERR "$ARGV:$.: not enough registers for int64 return\n"; |
|||
} |
|||
if($_32bit eq "big-endian") { |
|||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); |
|||
} else { |
|||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); |
|||
} |
|||
$ret[$i] = sprintf("r%d", $i); |
|||
$ret[$i+1] = sprintf("r%d", $i+1); |
|||
} |
|||
if($reg ne "e1" || $plan9) { |
|||
$body .= "\t$name = $type($reg)\n"; |
|||
} |
|||
} |
|||
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { |
|||
$text .= "\t$call\n"; |
|||
} else { |
|||
if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { |
|||
# raw syscall without error on Linux, see golang.org/issue/22924 |
|||
$text .= "\t$ret[0], $ret[1] := $call\n"; |
|||
} else { |
|||
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; |
|||
} |
|||
} |
|||
$text .= $body; |
|||
|
|||
if ($plan9 && $ret[2] eq "e1") { |
|||
$text .= "\tif int32(r0) == -1 {\n"; |
|||
$text .= "\t\terr = e1\n"; |
|||
$text .= "\t}\n"; |
|||
} elsif ($do_errno) { |
|||
$text .= "\tif e1 != 0 {\n"; |
|||
$text .= "\t\terr = errnoErr(e1)\n"; |
|||
$text .= "\t}\n"; |
|||
} |
|||
$text .= "\treturn\n"; |
|||
$text .= "}\n\n"; |
|||
} |
|||
|
|||
chomp $text; |
|||
chomp $text; |
|||
|
|||
if($errors) { |
|||
exit 1; |
|||
} |
|||
|
|||
print <<EOF; |
|||
// $cmdline |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $tags |
|||
|
|||
package unix |
|||
|
|||
import ( |
|||
"syscall" |
|||
"unsafe" |
|||
) |
|||
|
|||
var _ syscall.Errno |
|||
|
|||
$text |
|||
EOF |
|||
exit 0; |
@ -0,0 +1,415 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build ignore
|
|||
|
|||
/* |
|||
This program reads a file containing function prototypes |
|||
(like syscall_aix.go) and generates system call bodies. |
|||
The prototypes are marked by lines beginning with "//sys" |
|||
and read like func declarations if //sys is replaced by func, but:
|
|||
* The parameter lists must give a name for each argument. |
|||
This includes return parameters. |
|||
* The parameter lists must give a type for each argument: |
|||
the (x, y, z int) shorthand is not allowed. |
|||
* If the return parameter is an error number, it must be named err. |
|||
* If go func name needs to be different than its libc name, |
|||
* or the function is not in libc, name could be specified |
|||
* at the end, after "=" sign, like |
|||
//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
|
|||
*/ |
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"flag" |
|||
"fmt" |
|||
"os" |
|||
"regexp" |
|||
"strings" |
|||
) |
|||
|
|||
var ( |
|||
b32 = flag.Bool("b32", false, "32bit big-endian") |
|||
l32 = flag.Bool("l32", false, "32bit little-endian") |
|||
aix = flag.Bool("aix", false, "aix") |
|||
tags = flag.String("tags", "", "build tags") |
|||
) |
|||
|
|||
// cmdLine returns this programs's commandline arguments
|
|||
func cmdLine() string { |
|||
return "go run mksyscall_aix_ppc.go " + strings.Join(os.Args[1:], " ") |
|||
} |
|||
|
|||
// buildTags returns build tags
|
|||
func buildTags() string { |
|||
return *tags |
|||
} |
|||
|
|||
// Param is function parameter
|
|||
type Param struct { |
|||
Name string |
|||
Type string |
|||
} |
|||
|
|||
// usage prints the program usage
|
|||
func usage() { |
|||
fmt.Fprintf(os.Stderr, "usage: go run mksyscall_aix_ppc.go [-b32 | -l32] [-tags x,y] [file ...]\n") |
|||
os.Exit(1) |
|||
} |
|||
|
|||
// parseParamList parses parameter list and returns a slice of parameters
|
|||
func parseParamList(list string) []string { |
|||
list = strings.TrimSpace(list) |
|||
if list == "" { |
|||
return []string{} |
|||
} |
|||
return regexp.MustCompile(`\s*,\s*`).Split(list, -1) |
|||
} |
|||
|
|||
// parseParam splits a parameter into name and type
|
|||
func parseParam(p string) Param { |
|||
ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) |
|||
if ps == nil { |
|||
fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) |
|||
os.Exit(1) |
|||
} |
|||
return Param{ps[1], ps[2]} |
|||
} |
|||
|
|||
func main() { |
|||
flag.Usage = usage |
|||
flag.Parse() |
|||
if len(flag.Args()) <= 0 { |
|||
fmt.Fprintf(os.Stderr, "no files to parse provided\n") |
|||
usage() |
|||
} |
|||
|
|||
endianness := "" |
|||
if *b32 { |
|||
endianness = "big-endian" |
|||
} else if *l32 { |
|||
endianness = "little-endian" |
|||
} |
|||
|
|||
pack := "" |
|||
text := "" |
|||
cExtern := "/*\n#include <stdint.h>\n#include <stddef.h>\n" |
|||
for _, path := range flag.Args() { |
|||
file, err := os.Open(path) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
s := bufio.NewScanner(file) |
|||
for s.Scan() { |
|||
t := s.Text() |
|||
t = strings.TrimSpace(t) |
|||
t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) |
|||
if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" { |
|||
pack = p[1] |
|||
} |
|||
nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) |
|||
if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { |
|||
continue |
|||
} |
|||
|
|||
// Line must be of the form
|
|||
// func Open(path string, mode int, perm int) (fd int, err error)
|
|||
// Split into name, in params, out params.
|
|||
f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t) |
|||
if f == nil { |
|||
fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) |
|||
os.Exit(1) |
|||
} |
|||
funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6] |
|||
|
|||
// Split argument lists on comma.
|
|||
in := parseParamList(inps) |
|||
out := parseParamList(outps) |
|||
|
|||
inps = strings.Join(in, ", ") |
|||
outps = strings.Join(out, ", ") |
|||
|
|||
// Try in vain to keep people from editing this file.
|
|||
// The theory is that they jump into the middle of the file
|
|||
// without reading the header.
|
|||
text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
|||
|
|||
// Check if value return, err return available
|
|||
errvar := "" |
|||
retvar := "" |
|||
rettype := "" |
|||
for _, param := range out { |
|||
p := parseParam(param) |
|||
if p.Type == "error" { |
|||
errvar = p.Name |
|||
} else { |
|||
retvar = p.Name |
|||
rettype = p.Type |
|||
} |
|||
} |
|||
|
|||
// System call name.
|
|||
if sysname == "" { |
|||
sysname = funct |
|||
} |
|||
sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`) |
|||
sysname = strings.ToLower(sysname) // All libc functions are lowercase.
|
|||
|
|||
cRettype := "" |
|||
if rettype == "unsafe.Pointer" { |
|||
cRettype = "uintptr_t" |
|||
} else if rettype == "uintptr" { |
|||
cRettype = "uintptr_t" |
|||
} else if regexp.MustCompile(`^_`).FindStringSubmatch(rettype) != nil { |
|||
cRettype = "uintptr_t" |
|||
} else if rettype == "int" { |
|||
cRettype = "int" |
|||
} else if rettype == "int32" { |
|||
cRettype = "int" |
|||
} else if rettype == "int64" { |
|||
cRettype = "long long" |
|||
} else if rettype == "uint32" { |
|||
cRettype = "unsigned int" |
|||
} else if rettype == "uint64" { |
|||
cRettype = "unsigned long long" |
|||
} else { |
|||
cRettype = "int" |
|||
} |
|||
if sysname == "exit" { |
|||
cRettype = "void" |
|||
} |
|||
|
|||
// Change p.Types to c
|
|||
var cIn []string |
|||
for _, param := range in { |
|||
p := parseParam(param) |
|||
if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if p.Type == "string" { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil { |
|||
cIn = append(cIn, "uintptr_t", "size_t") |
|||
} else if p.Type == "unsafe.Pointer" { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if p.Type == "uintptr" { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if p.Type == "int" { |
|||
cIn = append(cIn, "int") |
|||
} else if p.Type == "int32" { |
|||
cIn = append(cIn, "int") |
|||
} else if p.Type == "int64" { |
|||
cIn = append(cIn, "long long") |
|||
} else if p.Type == "uint32" { |
|||
cIn = append(cIn, "unsigned int") |
|||
} else if p.Type == "uint64" { |
|||
cIn = append(cIn, "unsigned long long") |
|||
} else { |
|||
cIn = append(cIn, "int") |
|||
} |
|||
} |
|||
|
|||
if funct != "fcntl" && funct != "FcntlInt" && funct != "readlen" && funct != "writelen" { |
|||
if sysname == "select" { |
|||
// select is a keyword of Go. Its name is
|
|||
// changed to c_select.
|
|||
cExtern += "#define c_select select\n" |
|||
} |
|||
// Imports of system calls from libc
|
|||
cExtern += fmt.Sprintf("%s %s", cRettype, sysname) |
|||
cIn := strings.Join(cIn, ", ") |
|||
cExtern += fmt.Sprintf("(%s);\n", cIn) |
|||
} |
|||
|
|||
// So file name.
|
|||
if *aix { |
|||
if modname == "" { |
|||
modname = "libc.a/shr_64.o" |
|||
} else { |
|||
fmt.Fprintf(os.Stderr, "%s: only syscall using libc are available\n", funct) |
|||
os.Exit(1) |
|||
} |
|||
} |
|||
|
|||
strconvfunc := "C.CString" |
|||
|
|||
// Go function header.
|
|||
if outps != "" { |
|||
outps = fmt.Sprintf(" (%s)", outps) |
|||
} |
|||
if text != "" { |
|||
text += "\n" |
|||
} |
|||
|
|||
text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outps) |
|||
|
|||
// Prepare arguments to Syscall.
|
|||
var args []string |
|||
n := 0 |
|||
argN := 0 |
|||
for _, param := range in { |
|||
p := parseParam(param) |
|||
if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { |
|||
args = append(args, "C.uintptr_t(uintptr(unsafe.Pointer("+p.Name+")))") |
|||
} else if p.Type == "string" && errvar != "" { |
|||
text += fmt.Sprintf("\t_p%d := uintptr(unsafe.Pointer(%s(%s)))\n", n, strconvfunc, p.Name) |
|||
args = append(args, fmt.Sprintf("C.uintptr_t(_p%d)", n)) |
|||
n++ |
|||
} else if p.Type == "string" { |
|||
fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") |
|||
text += fmt.Sprintf("\t_p%d := uintptr(unsafe.Pointer(%s(%s)))\n", n, strconvfunc, p.Name) |
|||
args = append(args, fmt.Sprintf("C.uintptr_t(_p%d)", n)) |
|||
n++ |
|||
} else if m := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); m != nil { |
|||
// Convert slice into pointer, length.
|
|||
// Have to be careful not to take address of &a[0] if len == 0:
|
|||
// pass nil in that case.
|
|||
text += fmt.Sprintf("\tvar _p%d *%s\n", n, m[1]) |
|||
text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name) |
|||
args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(unsafe.Pointer(_p%d)))", n)) |
|||
n++ |
|||
text += fmt.Sprintf("\tvar _p%d int\n", n) |
|||
text += fmt.Sprintf("\t_p%d = len(%s)\n", n, p.Name) |
|||
args = append(args, fmt.Sprintf("C.size_t(_p%d)", n)) |
|||
n++ |
|||
} else if p.Type == "int64" && endianness != "" { |
|||
if endianness == "big-endian" { |
|||
args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} else { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) |
|||
} |
|||
n++ |
|||
} else if p.Type == "bool" { |
|||
text += fmt.Sprintf("\tvar _p%d uint32\n", n) |
|||
text += fmt.Sprintf("\tif %s {\n\t\t_p%d = 1\n\t} else {\n\t\t_p%d = 0\n\t}\n", p.Name, n, n) |
|||
args = append(args, fmt.Sprintf("_p%d", n)) |
|||
} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil { |
|||
args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(%s))", p.Name)) |
|||
} else if p.Type == "unsafe.Pointer" { |
|||
args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(%s))", p.Name)) |
|||
} else if p.Type == "int" { |
|||
if (argN == 2) && ((funct == "readlen") || (funct == "writelen")) { |
|||
args = append(args, fmt.Sprintf("C.size_t(%s)", p.Name)) |
|||
} else if argN == 0 && funct == "fcntl" { |
|||
args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
|||
} else if (argN == 2) && ((funct == "fcntl") || (funct == "FcntlInt")) { |
|||
args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
|||
} else { |
|||
args = append(args, fmt.Sprintf("C.int(%s)", p.Name)) |
|||
} |
|||
} else if p.Type == "int32" { |
|||
args = append(args, fmt.Sprintf("C.int(%s)", p.Name)) |
|||
} else if p.Type == "int64" { |
|||
args = append(args, fmt.Sprintf("C.longlong(%s)", p.Name)) |
|||
} else if p.Type == "uint32" { |
|||
args = append(args, fmt.Sprintf("C.uint(%s)", p.Name)) |
|||
} else if p.Type == "uint64" { |
|||
args = append(args, fmt.Sprintf("C.ulonglong(%s)", p.Name)) |
|||
} else if p.Type == "uintptr" { |
|||
args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
|||
} else { |
|||
args = append(args, fmt.Sprintf("C.int(%s)", p.Name)) |
|||
} |
|||
argN++ |
|||
} |
|||
|
|||
// Actual call.
|
|||
arglist := strings.Join(args, ", ") |
|||
call := "" |
|||
if sysname == "exit" { |
|||
if errvar != "" { |
|||
call += "er :=" |
|||
} else { |
|||
call += "" |
|||
} |
|||
} else if errvar != "" { |
|||
call += "r0,er :=" |
|||
} else if retvar != "" { |
|||
call += "r0,_ :=" |
|||
} else { |
|||
call += "" |
|||
} |
|||
if sysname == "select" { |
|||
// select is a keyword of Go. Its name is
|
|||
// changed to c_select.
|
|||
call += fmt.Sprintf("C.c_%s(%s)", sysname, arglist) |
|||
} else { |
|||
call += fmt.Sprintf("C.%s(%s)", sysname, arglist) |
|||
} |
|||
|
|||
// Assign return values.
|
|||
body := "" |
|||
for i := 0; i < len(out); i++ { |
|||
p := parseParam(out[i]) |
|||
reg := "" |
|||
if p.Name == "err" { |
|||
reg = "e1" |
|||
} else { |
|||
reg = "r0" |
|||
} |
|||
if reg != "e1" { |
|||
body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) |
|||
} |
|||
} |
|||
|
|||
// verify return
|
|||
if sysname != "exit" && errvar != "" { |
|||
if regexp.MustCompile(`^uintptr`).FindStringSubmatch(cRettype) != nil { |
|||
body += "\tif (uintptr(r0) ==^uintptr(0) && er != nil) {\n" |
|||
body += fmt.Sprintf("\t\t%s = er\n", errvar) |
|||
body += "\t}\n" |
|||
} else { |
|||
body += "\tif (r0 ==-1 && er != nil) {\n" |
|||
body += fmt.Sprintf("\t\t%s = er\n", errvar) |
|||
body += "\t}\n" |
|||
} |
|||
} else if errvar != "" { |
|||
body += "\tif (er != nil) {\n" |
|||
body += fmt.Sprintf("\t\t%s = er\n", errvar) |
|||
body += "\t}\n" |
|||
} |
|||
|
|||
text += fmt.Sprintf("\t%s\n", call) |
|||
text += body |
|||
|
|||
text += "\treturn\n" |
|||
text += "}\n" |
|||
} |
|||
if err := s.Err(); err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
file.Close() |
|||
} |
|||
imp := "" |
|||
if pack != "unix" { |
|||
imp = "import \"golang.org/x/sys/unix\"\n" |
|||
|
|||
} |
|||
fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, cExtern, imp, text) |
|||
} |
|||
|
|||
const srcTemplate = `// %s
|
|||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|||
|
|||
// +build %s
|
|||
|
|||
package %s |
|||
|
|||
|
|||
%s |
|||
*/ |
|||
import "C" |
|||
import ( |
|||
"unsafe" |
|||
) |
|||
|
|||
|
|||
%s |
|||
|
|||
%s |
|||
` |
@ -1,384 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2018 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
|
|||
# This program reads a file containing function prototypes |
|||
# (like syscall_aix.go) and generates system call bodies. |
|||
# The prototypes are marked by lines beginning with "//sys" |
|||
# and read like func declarations if //sys is replaced by func, but: |
|||
# * The parameter lists must give a name for each argument. |
|||
# This includes return parameters. |
|||
# * The parameter lists must give a type for each argument: |
|||
# the (x, y, z int) shorthand is not allowed. |
|||
# * If the return parameter is an error number, it must be named err. |
|||
# * If go func name needs to be different than its libc name, |
|||
# * or the function is not in libc, name could be specified |
|||
# * at the end, after "=" sign, like |
|||
# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt |
|||
|
|||
use strict; |
|||
|
|||
my $cmdline = "mksyscall_aix_ppc.pl " . join(' ', @ARGV); |
|||
my $errors = 0; |
|||
my $_32bit = ""; |
|||
my $tags = ""; # build tags |
|||
my $aix = 0; |
|||
my $solaris = 0; |
|||
|
|||
binmode STDOUT; |
|||
|
|||
if($ARGV[0] eq "-b32") { |
|||
$_32bit = "big-endian"; |
|||
shift; |
|||
} elsif($ARGV[0] eq "-l32") { |
|||
$_32bit = "little-endian"; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-aix") { |
|||
$aix = 1; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-tags") { |
|||
shift; |
|||
$tags = $ARGV[0]; |
|||
shift; |
|||
} |
|||
|
|||
if($ARGV[0] =~ /^-/) { |
|||
print STDERR "usage: mksyscall_aix.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
sub parseparamlist($) { |
|||
my ($list) = @_; |
|||
$list =~ s/^\s*//; |
|||
$list =~ s/\s*$//; |
|||
if($list eq "") { |
|||
return (); |
|||
} |
|||
return split(/\s*,\s*/, $list); |
|||
} |
|||
|
|||
sub parseparam($) { |
|||
my ($p) = @_; |
|||
if($p !~ /^(\S*) (\S*)$/) { |
|||
print STDERR "$ARGV:$.: malformed parameter: $p\n"; |
|||
$errors = 1; |
|||
return ("xx", "int"); |
|||
} |
|||
return ($1, $2); |
|||
} |
|||
|
|||
my $package = ""; |
|||
my $text = ""; |
|||
my $c_extern = "/*\n#include <stdint.h>\n#include <stddef.h>\n"; |
|||
my @vars = (); |
|||
while(<>) { |
|||
chomp; |
|||
s/\s+/ /g; |
|||
s/^\s+//; |
|||
s/\s+$//; |
|||
$package = $1 if !$package && /^package (\S+)$/; |
|||
my $nonblock = /^\/\/sysnb /; |
|||
next if !/^\/\/sys / && !$nonblock; |
|||
|
|||
# Line must be of the form |
|||
# func Open(path string, mode int, perm int) (fd int, err error) |
|||
# Split into name, in params, out params. |
|||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) { |
|||
print STDERR "$ARGV:$.: malformed //sys declaration\n"; |
|||
$errors = 1; |
|||
next; |
|||
} |
|||
my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6); |
|||
|
|||
# Split argument lists on comma. |
|||
my @in = parseparamlist($in); |
|||
my @out = parseparamlist($out); |
|||
|
|||
$in = join(', ', @in); |
|||
$out = join(', ', @out); |
|||
|
|||
# Try in vain to keep people from editing this file. |
|||
# The theory is that they jump into the middle of the file |
|||
# without reading the header. |
|||
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; |
|||
|
|||
# Check if value return, err return available |
|||
my $errvar = ""; |
|||
my $retvar = ""; |
|||
my $rettype = ""; |
|||
foreach my $p (@out) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type eq "error") { |
|||
$errvar = $name; |
|||
} else { |
|||
$retvar = $name; |
|||
$rettype = $type; |
|||
} |
|||
} |
|||
|
|||
# System call name. |
|||
#if($func ne "fcntl") { |
|||
|
|||
if($sysname eq "") { |
|||
$sysname = "$func"; |
|||
} |
|||
|
|||
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; |
|||
$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase. |
|||
|
|||
my $C_rettype = ""; |
|||
if($rettype eq "unsafe.Pointer") { |
|||
$C_rettype = "uintptr_t"; |
|||
} elsif($rettype eq "uintptr") { |
|||
$C_rettype = "uintptr_t"; |
|||
} elsif($rettype =~ /^_/) { |
|||
$C_rettype = "uintptr_t"; |
|||
} elsif($rettype eq "int") { |
|||
$C_rettype = "int"; |
|||
} elsif($rettype eq "int32") { |
|||
$C_rettype = "int"; |
|||
} elsif($rettype eq "int64") { |
|||
$C_rettype = "long long"; |
|||
} elsif($rettype eq "uint32") { |
|||
$C_rettype = "unsigned int"; |
|||
} elsif($rettype eq "uint64") { |
|||
$C_rettype = "unsigned long long"; |
|||
} else { |
|||
$C_rettype = "int"; |
|||
} |
|||
if($sysname eq "exit") { |
|||
$C_rettype = "void"; |
|||
} |
|||
|
|||
# Change types to c |
|||
my @c_in = (); |
|||
foreach my $p (@in) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type =~ /^\*/) { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type eq "string") { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type =~ /^\[\](.*)/) { |
|||
push @c_in, "uintptr_t", "size_t"; |
|||
} elsif($type eq "unsafe.Pointer") { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type eq "uintptr") { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type =~ /^_/) { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type eq "int") { |
|||
push @c_in, "int"; |
|||
} elsif($type eq "int32") { |
|||
push @c_in, "int"; |
|||
} elsif($type eq "int64") { |
|||
push @c_in, "long long"; |
|||
} elsif($type eq "uint32") { |
|||
push @c_in, "unsigned int"; |
|||
} elsif($type eq "uint64") { |
|||
push @c_in, "unsigned long long"; |
|||
} else { |
|||
push @c_in, "int"; |
|||
} |
|||
} |
|||
|
|||
if ($func ne "fcntl" && $func ne "FcntlInt" && $func ne "readlen" && $func ne "writelen") { |
|||
# Imports of system calls from libc |
|||
$c_extern .= "$C_rettype $sysname"; |
|||
my $c_in = join(', ', @c_in); |
|||
$c_extern .= "($c_in);\n"; |
|||
} |
|||
|
|||
# So file name. |
|||
if($aix) { |
|||
if($modname eq "") { |
|||
$modname = "libc.a/shr_64.o"; |
|||
} else { |
|||
print STDERR "$func: only syscall using libc are available\n"; |
|||
$errors = 1; |
|||
next; |
|||
} |
|||
} |
|||
|
|||
my $strconvfunc = "C.CString"; |
|||
my $strconvtype = "*byte"; |
|||
|
|||
# Go function header. |
|||
if($out ne "") { |
|||
$out = " ($out)"; |
|||
} |
|||
if($text ne "") { |
|||
$text .= "\n" |
|||
} |
|||
|
|||
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out ; |
|||
|
|||
# Prepare arguments to call. |
|||
my @args = (); |
|||
my $n = 0; |
|||
my $arg_n = 0; |
|||
foreach my $p (@in) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type =~ /^\*/) { |
|||
push @args, "C.uintptr_t(uintptr(unsafe.Pointer($name)))"; |
|||
} elsif($type eq "string" && $errvar ne "") { |
|||
$text .= "\t_p$n := uintptr(unsafe.Pointer($strconvfunc($name)))\n"; |
|||
push @args, "C.uintptr_t(_p$n)"; |
|||
$n++; |
|||
} elsif($type eq "string") { |
|||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; |
|||
$text .= "\t_p$n := uintptr(unsafe.Pointer($strconvfunc($name)))\n"; |
|||
push @args, "C.uintptr_t(_p$n)"; |
|||
$n++; |
|||
} elsif($type =~ /^\[\](.*)/) { |
|||
# Convert slice into pointer, length. |
|||
# Have to be careful not to take address of &a[0] if len == 0: |
|||
# pass nil in that case. |
|||
$text .= "\tvar _p$n *$1\n"; |
|||
$text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; |
|||
push @args, "C.uintptr_t(uintptr(unsafe.Pointer(_p$n)))"; |
|||
$n++; |
|||
$text .= "\tvar _p$n int\n"; |
|||
$text .= "\t_p$n = len($name)\n"; |
|||
push @args, "C.size_t(_p$n)"; |
|||
$n++; |
|||
} elsif($type eq "int64" && $_32bit ne "") { |
|||
if($_32bit eq "big-endian") { |
|||
push @args, "uintptr($name >> 32)", "uintptr($name)"; |
|||
} else { |
|||
push @args, "uintptr($name)", "uintptr($name >> 32)"; |
|||
} |
|||
$n++; |
|||
} elsif($type eq "bool") { |
|||
$text .= "\tvar _p$n uint32\n"; |
|||
$text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; |
|||
push @args, "_p$n"; |
|||
$n++; |
|||
} elsif($type =~ /^_/) { |
|||
push @args, "C.uintptr_t(uintptr($name))"; |
|||
} elsif($type eq "unsafe.Pointer") { |
|||
push @args, "C.uintptr_t(uintptr($name))"; |
|||
} elsif($type eq "int") { |
|||
if (($arg_n == 2) && (($func eq "readlen") || ($func eq "writelen"))) { |
|||
push @args, "C.size_t($name)"; |
|||
} elsif ($arg_n == 0 && $func eq "fcntl") { |
|||
push @args, "C.uintptr_t($name)"; |
|||
} elsif (($arg_n == 2) && (($func eq "fcntl") || ($func eq "FcntlInt"))) { |
|||
push @args, "C.uintptr_t($name)"; |
|||
} else { |
|||
push @args, "C.int($name)"; |
|||
} |
|||
} elsif($type eq "int32") { |
|||
push @args, "C.int($name)"; |
|||
} elsif($type eq "int64") { |
|||
push @args, "C.longlong($name)"; |
|||
} elsif($type eq "uint32") { |
|||
push @args, "C.uint($name)"; |
|||
} elsif($type eq "uint64") { |
|||
push @args, "C.ulonglong($name)"; |
|||
} elsif($type eq "uintptr") { |
|||
push @args, "C.uintptr_t($name)"; |
|||
} else { |
|||
push @args, "C.int($name)"; |
|||
} |
|||
$arg_n++; |
|||
} |
|||
my $nargs = @args; |
|||
|
|||
|
|||
# Determine which form to use; pad args with zeros. |
|||
if ($nonblock) { |
|||
} |
|||
|
|||
my $args = join(', ', @args); |
|||
my $call = ""; |
|||
if ($sysname eq "exit") { |
|||
if ($errvar ne "") { |
|||
$call .= "er :="; |
|||
} else { |
|||
$call .= ""; |
|||
} |
|||
} elsif ($errvar ne "") { |
|||
$call .= "r0,er :="; |
|||
} elsif ($retvar ne "") { |
|||
$call .= "r0,_ :="; |
|||
} else { |
|||
$call .= "" |
|||
} |
|||
$call .= "C.$sysname($args)"; |
|||
|
|||
# Assign return values. |
|||
my $body = ""; |
|||
my $failexpr = ""; |
|||
|
|||
for(my $i=0; $i<@out; $i++) { |
|||
my $p = $out[$i]; |
|||
my ($name, $type) = parseparam($p); |
|||
my $reg = ""; |
|||
if($name eq "err") { |
|||
$reg = "e1"; |
|||
} else { |
|||
$reg = "r0"; |
|||
} |
|||
if($reg ne "e1" ) { |
|||
$body .= "\t$name = $type($reg)\n"; |
|||
} |
|||
} |
|||
|
|||
# verify return |
|||
if ($sysname ne "exit" && $errvar ne "") { |
|||
if ($C_rettype =~ /^uintptr/) { |
|||
$body .= "\tif \(uintptr\(r0\) ==\^uintptr\(0\) && er != nil\) {\n"; |
|||
$body .= "\t\t$errvar = er\n"; |
|||
$body .= "\t}\n"; |
|||
} else { |
|||
$body .= "\tif \(r0 ==-1 && er != nil\) {\n"; |
|||
$body .= "\t\t$errvar = er\n"; |
|||
$body .= "\t}\n"; |
|||
} |
|||
} elsif ($errvar ne "") { |
|||
$body .= "\tif \(er != nil\) {\n"; |
|||
$body .= "\t\t$errvar = er\n"; |
|||
$body .= "\t}\n"; |
|||
} |
|||
|
|||
$text .= "\t$call\n"; |
|||
$text .= $body; |
|||
|
|||
$text .= "\treturn\n"; |
|||
$text .= "}\n"; |
|||
} |
|||
|
|||
if($errors) { |
|||
exit 1; |
|||
} |
|||
|
|||
print <<EOF; |
|||
// $cmdline |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $tags |
|||
|
|||
package $package |
|||
|
|||
|
|||
$c_extern |
|||
*/ |
|||
import "C" |
|||
import ( |
|||
"unsafe" |
|||
) |
|||
|
|||
|
|||
EOF |
|||
|
|||
print "import \"golang.org/x/sys/unix\"\n" if $package ne "unix"; |
|||
|
|||
chomp($_=<<EOF); |
|||
|
|||
$text |
|||
EOF |
|||
print $_; |
|||
exit 0; |
@ -0,0 +1,614 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build ignore
|
|||
|
|||
/* |
|||
This program reads a file containing function prototypes |
|||
(like syscall_aix.go) and generates system call bodies. |
|||
The prototypes are marked by lines beginning with "//sys" |
|||
and read like func declarations if //sys is replaced by func, but:
|
|||
* The parameter lists must give a name for each argument. |
|||
This includes return parameters. |
|||
* The parameter lists must give a type for each argument: |
|||
the (x, y, z int) shorthand is not allowed. |
|||
* If the return parameter is an error number, it must be named err. |
|||
* If go func name needs to be different than its libc name, |
|||
* or the function is not in libc, name could be specified |
|||
* at the end, after "=" sign, like |
|||
//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
|
|||
|
|||
|
|||
This program will generate three files and handle both gc and gccgo implementation: |
|||
- zsyscall_aix_ppc64.go: the common part of each implementation (error handler, pointer creation) |
|||
- zsyscall_aix_ppc64_gc.go: gc part with //go_cgo_import_dynamic and a call to syscall6
|
|||
- zsyscall_aix_ppc64_gccgo.go: gccgo part with C function and conversion to C type. |
|||
|
|||
The generated code looks like this |
|||
|
|||
zsyscall_aix_ppc64.go |
|||
func asyscall(...) (n int, err error) { |
|||
// Pointer Creation
|
|||
r1, e1 := callasyscall(...) |
|||
// Type Conversion
|
|||
// Error Handler
|
|||
return |
|||
} |
|||
|
|||
zsyscall_aix_ppc64_gc.go |
|||
//go:cgo_import_dynamic libc_asyscall asyscall "libc.a/shr_64.o"
|
|||
//go:linkname libc_asyscall libc_asyscall
|
|||
var asyscall syscallFunc |
|||
|
|||
func callasyscall(...) (r1 uintptr, e1 Errno) { |
|||
r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_asyscall)), "nb_args", ... ) |
|||
return |
|||
} |
|||
|
|||
zsyscall_aix_ppc64_ggcgo.go |
|||
|
|||
// int asyscall(...)
|
|||
|
|||
import "C" |
|||
|
|||
func callasyscall(...) (r1 uintptr, e1 Errno) { |
|||
r1 = uintptr(C.asyscall(...)) |
|||
e1 = syscall.GetErrno() |
|||
return |
|||
} |
|||
*/ |
|||
|
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"flag" |
|||
"fmt" |
|||
"io/ioutil" |
|||
"os" |
|||
"regexp" |
|||
"strings" |
|||
) |
|||
|
|||
var ( |
|||
b32 = flag.Bool("b32", false, "32bit big-endian") |
|||
l32 = flag.Bool("l32", false, "32bit little-endian") |
|||
aix = flag.Bool("aix", false, "aix") |
|||
tags = flag.String("tags", "", "build tags") |
|||
) |
|||
|
|||
// cmdLine returns this programs's commandline arguments
|
|||
func cmdLine() string { |
|||
return "go run mksyscall_aix_ppc64.go " + strings.Join(os.Args[1:], " ") |
|||
} |
|||
|
|||
// buildTags returns build tags
|
|||
func buildTags() string { |
|||
return *tags |
|||
} |
|||
|
|||
// Param is function parameter
|
|||
type Param struct { |
|||
Name string |
|||
Type string |
|||
} |
|||
|
|||
// usage prints the program usage
|
|||
func usage() { |
|||
fmt.Fprintf(os.Stderr, "usage: go run mksyscall_aix_ppc64.go [-b32 | -l32] [-tags x,y] [file ...]\n") |
|||
os.Exit(1) |
|||
} |
|||
|
|||
// parseParamList parses parameter list and returns a slice of parameters
|
|||
func parseParamList(list string) []string { |
|||
list = strings.TrimSpace(list) |
|||
if list == "" { |
|||
return []string{} |
|||
} |
|||
return regexp.MustCompile(`\s*,\s*`).Split(list, -1) |
|||
} |
|||
|
|||
// parseParam splits a parameter into name and type
|
|||
func parseParam(p string) Param { |
|||
ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) |
|||
if ps == nil { |
|||
fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) |
|||
os.Exit(1) |
|||
} |
|||
return Param{ps[1], ps[2]} |
|||
} |
|||
|
|||
func main() { |
|||
flag.Usage = usage |
|||
flag.Parse() |
|||
if len(flag.Args()) <= 0 { |
|||
fmt.Fprintf(os.Stderr, "no files to parse provided\n") |
|||
usage() |
|||
} |
|||
|
|||
endianness := "" |
|||
if *b32 { |
|||
endianness = "big-endian" |
|||
} else if *l32 { |
|||
endianness = "little-endian" |
|||
} |
|||
|
|||
pack := "" |
|||
// GCCGO
|
|||
textgccgo := "" |
|||
cExtern := "/*\n#include <stdint.h>\n" |
|||
// GC
|
|||
textgc := "" |
|||
dynimports := "" |
|||
linknames := "" |
|||
var vars []string |
|||
// COMMON
|
|||
textcommon := "" |
|||
for _, path := range flag.Args() { |
|||
file, err := os.Open(path) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
s := bufio.NewScanner(file) |
|||
for s.Scan() { |
|||
t := s.Text() |
|||
t = strings.TrimSpace(t) |
|||
t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) |
|||
if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" { |
|||
pack = p[1] |
|||
} |
|||
nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) |
|||
if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { |
|||
continue |
|||
} |
|||
|
|||
// Line must be of the form
|
|||
// func Open(path string, mode int, perm int) (fd int, err error)
|
|||
// Split into name, in params, out params.
|
|||
f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t) |
|||
if f == nil { |
|||
fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) |
|||
os.Exit(1) |
|||
} |
|||
funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6] |
|||
|
|||
// Split argument lists on comma.
|
|||
in := parseParamList(inps) |
|||
out := parseParamList(outps) |
|||
|
|||
inps = strings.Join(in, ", ") |
|||
outps = strings.Join(out, ", ") |
|||
|
|||
if sysname == "" { |
|||
sysname = funct |
|||
} |
|||
|
|||
onlyCommon := false |
|||
if funct == "readlen" || funct == "writelen" || funct == "FcntlInt" || funct == "FcntlFlock" { |
|||
// This function call another syscall which is already implemented.
|
|||
// Therefore, the gc and gccgo part must not be generated.
|
|||
onlyCommon = true |
|||
} |
|||
|
|||
// Try in vain to keep people from editing this file.
|
|||
// The theory is that they jump into the middle of the file
|
|||
// without reading the header.
|
|||
|
|||
textcommon += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
|||
if !onlyCommon { |
|||
textgccgo += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
|||
textgc += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
|||
} |
|||
|
|||
// Check if value return, err return available
|
|||
errvar := "" |
|||
rettype := "" |
|||
for _, param := range out { |
|||
p := parseParam(param) |
|||
if p.Type == "error" { |
|||
errvar = p.Name |
|||
} else { |
|||
rettype = p.Type |
|||
} |
|||
} |
|||
|
|||
sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`) |
|||
sysname = strings.ToLower(sysname) // All libc functions are lowercase.
|
|||
|
|||
// GCCGO Prototype return type
|
|||
cRettype := "" |
|||
if rettype == "unsafe.Pointer" { |
|||
cRettype = "uintptr_t" |
|||
} else if rettype == "uintptr" { |
|||
cRettype = "uintptr_t" |
|||
} else if regexp.MustCompile(`^_`).FindStringSubmatch(rettype) != nil { |
|||
cRettype = "uintptr_t" |
|||
} else if rettype == "int" { |
|||
cRettype = "int" |
|||
} else if rettype == "int32" { |
|||
cRettype = "int" |
|||
} else if rettype == "int64" { |
|||
cRettype = "long long" |
|||
} else if rettype == "uint32" { |
|||
cRettype = "unsigned int" |
|||
} else if rettype == "uint64" { |
|||
cRettype = "unsigned long long" |
|||
} else { |
|||
cRettype = "int" |
|||
} |
|||
if sysname == "exit" { |
|||
cRettype = "void" |
|||
} |
|||
|
|||
// GCCGO Prototype arguments type
|
|||
var cIn []string |
|||
for i, param := range in { |
|||
p := parseParam(param) |
|||
if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if p.Type == "string" { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil { |
|||
cIn = append(cIn, "uintptr_t", "size_t") |
|||
} else if p.Type == "unsafe.Pointer" { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if p.Type == "uintptr" { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil { |
|||
cIn = append(cIn, "uintptr_t") |
|||
} else if p.Type == "int" { |
|||
if (i == 0 || i == 2) && funct == "fcntl" { |
|||
// These fcntl arguments needs to be uintptr to be able to call FcntlInt and FcntlFlock
|
|||
cIn = append(cIn, "uintptr_t") |
|||
} else { |
|||
cIn = append(cIn, "int") |
|||
} |
|||
|
|||
} else if p.Type == "int32" { |
|||
cIn = append(cIn, "int") |
|||
} else if p.Type == "int64" { |
|||
cIn = append(cIn, "long long") |
|||
} else if p.Type == "uint32" { |
|||
cIn = append(cIn, "unsigned int") |
|||
} else if p.Type == "uint64" { |
|||
cIn = append(cIn, "unsigned long long") |
|||
} else { |
|||
cIn = append(cIn, "int") |
|||
} |
|||
} |
|||
|
|||
if !onlyCommon { |
|||
// GCCGO Prototype Generation
|
|||
// Imports of system calls from libc
|
|||
if sysname == "select" { |
|||
// select is a keyword of Go. Its name is
|
|||
// changed to c_select.
|
|||
cExtern += "#define c_select select\n" |
|||
} |
|||
cExtern += fmt.Sprintf("%s %s", cRettype, sysname) |
|||
cIn := strings.Join(cIn, ", ") |
|||
cExtern += fmt.Sprintf("(%s);\n", cIn) |
|||
} |
|||
// GC Library name
|
|||
if modname == "" { |
|||
modname = "libc.a/shr_64.o" |
|||
} else { |
|||
fmt.Fprintf(os.Stderr, "%s: only syscall using libc are available\n", funct) |
|||
os.Exit(1) |
|||
} |
|||
sysvarname := fmt.Sprintf("libc_%s", sysname) |
|||
|
|||
if !onlyCommon { |
|||
// GC Runtime import of function to allow cross-platform builds.
|
|||
dynimports += fmt.Sprintf("//go:cgo_import_dynamic %s %s \"%s\"\n", sysvarname, sysname, modname) |
|||
// GC Link symbol to proc address variable.
|
|||
linknames += fmt.Sprintf("//go:linkname %s %s\n", sysvarname, sysvarname) |
|||
// GC Library proc address variable.
|
|||
vars = append(vars, sysvarname) |
|||
} |
|||
|
|||
strconvfunc := "BytePtrFromString" |
|||
strconvtype := "*byte" |
|||
|
|||
// Go function header.
|
|||
if outps != "" { |
|||
outps = fmt.Sprintf(" (%s)", outps) |
|||
} |
|||
if textcommon != "" { |
|||
textcommon += "\n" |
|||
} |
|||
|
|||
textcommon += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outps) |
|||
|
|||
// Prepare arguments tocall.
|
|||
var argscommon []string // Arguments in the common part
|
|||
var argscall []string // Arguments for call prototype
|
|||
var argsgc []string // Arguments for gc call (with syscall6)
|
|||
var argsgccgo []string // Arguments for gccgo call (with C.name_of_syscall)
|
|||
n := 0 |
|||
argN := 0 |
|||
for _, param := range in { |
|||
p := parseParam(param) |
|||
if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { |
|||
argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.Name)) |
|||
argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) |
|||
argsgc = append(argsgc, p.Name) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
|||
} else if p.Type == "string" && errvar != "" { |
|||
textcommon += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) |
|||
textcommon += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) |
|||
textcommon += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) |
|||
|
|||
argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) |
|||
argscall = append(argscall, fmt.Sprintf("_p%d uintptr ", n)) |
|||
argsgc = append(argsgc, fmt.Sprintf("_p%d", n)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n)) |
|||
n++ |
|||
} else if p.Type == "string" { |
|||
fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") |
|||
textcommon += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) |
|||
textcommon += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) |
|||
textcommon += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) |
|||
|
|||
argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) |
|||
argscall = append(argscall, fmt.Sprintf("_p%d uintptr", n)) |
|||
argsgc = append(argsgc, fmt.Sprintf("_p%d", n)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n)) |
|||
n++ |
|||
} else if m := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); m != nil { |
|||
// Convert slice into pointer, length.
|
|||
// Have to be careful not to take address of &a[0] if len == 0:
|
|||
// pass nil in that case.
|
|||
textcommon += fmt.Sprintf("\tvar _p%d *%s\n", n, m[1]) |
|||
textcommon += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name) |
|||
argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n), fmt.Sprintf("len(%s)", p.Name)) |
|||
argscall = append(argscall, fmt.Sprintf("_p%d uintptr", n), fmt.Sprintf("_lenp%d int", n)) |
|||
argsgc = append(argsgc, fmt.Sprintf("_p%d", n), fmt.Sprintf("uintptr(_lenp%d)", n)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n), fmt.Sprintf("C.size_t(_lenp%d)", n)) |
|||
n++ |
|||
} else if p.Type == "int64" && endianness != "" { |
|||
fmt.Fprintf(os.Stderr, path+":"+funct+" uses int64 with 32 bits mode. Case not yet implemented\n") |
|||
} else if p.Type == "bool" { |
|||
fmt.Fprintf(os.Stderr, path+":"+funct+" uses bool. Case not yet implemented\n") |
|||
} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil || p.Type == "unsafe.Pointer" { |
|||
argscommon = append(argscommon, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) |
|||
argsgc = append(argsgc, p.Name) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
|||
} else if p.Type == "int" { |
|||
if (argN == 0 || argN == 2) && ((funct == "fcntl") || (funct == "FcntlInt") || (funct == "FcntlFlock")) { |
|||
// These fcntl arguments need to be uintptr to be able to call FcntlInt and FcntlFlock
|
|||
argscommon = append(argscommon, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) |
|||
argsgc = append(argsgc, p.Name) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
|||
|
|||
} else { |
|||
argscommon = append(argscommon, p.Name) |
|||
argscall = append(argscall, fmt.Sprintf("%s int", p.Name)) |
|||
argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) |
|||
} |
|||
} else if p.Type == "int32" { |
|||
argscommon = append(argscommon, p.Name) |
|||
argscall = append(argscall, fmt.Sprintf("%s int32", p.Name)) |
|||
argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) |
|||
} else if p.Type == "int64" { |
|||
argscommon = append(argscommon, p.Name) |
|||
argscall = append(argscall, fmt.Sprintf("%s int64", p.Name)) |
|||
argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.longlong(%s)", p.Name)) |
|||
} else if p.Type == "uint32" { |
|||
argscommon = append(argscommon, p.Name) |
|||
argscall = append(argscall, fmt.Sprintf("%s uint32", p.Name)) |
|||
argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.uint(%s)", p.Name)) |
|||
} else if p.Type == "uint64" { |
|||
argscommon = append(argscommon, p.Name) |
|||
argscall = append(argscall, fmt.Sprintf("%s uint64", p.Name)) |
|||
argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.ulonglong(%s)", p.Name)) |
|||
} else if p.Type == "uintptr" { |
|||
argscommon = append(argscommon, p.Name) |
|||
argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) |
|||
argsgc = append(argsgc, p.Name) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
|||
} else { |
|||
argscommon = append(argscommon, fmt.Sprintf("int(%s)", p.Name)) |
|||
argscall = append(argscall, fmt.Sprintf("%s int", p.Name)) |
|||
argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) |
|||
} |
|||
argN++ |
|||
} |
|||
nargs := len(argsgc) |
|||
|
|||
// COMMON function generation
|
|||
argscommonlist := strings.Join(argscommon, ", ") |
|||
callcommon := fmt.Sprintf("call%s(%s)", sysname, argscommonlist) |
|||
ret := []string{"_", "_"} |
|||
body := "" |
|||
doErrno := false |
|||
for i := 0; i < len(out); i++ { |
|||
p := parseParam(out[i]) |
|||
reg := "" |
|||
if p.Name == "err" { |
|||
reg = "e1" |
|||
ret[1] = reg |
|||
doErrno = true |
|||
} else { |
|||
reg = "r0" |
|||
ret[0] = reg |
|||
} |
|||
if p.Type == "bool" { |
|||
reg = fmt.Sprintf("%s != 0", reg) |
|||
} |
|||
if reg != "e1" { |
|||
body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) |
|||
} |
|||
} |
|||
if ret[0] == "_" && ret[1] == "_" { |
|||
textcommon += fmt.Sprintf("\t%s\n", callcommon) |
|||
} else { |
|||
textcommon += fmt.Sprintf("\t%s, %s := %s\n", ret[0], ret[1], callcommon) |
|||
} |
|||
textcommon += body |
|||
|
|||
if doErrno { |
|||
textcommon += "\tif e1 != 0 {\n" |
|||
textcommon += "\t\terr = errnoErr(e1)\n" |
|||
textcommon += "\t}\n" |
|||
} |
|||
textcommon += "\treturn\n" |
|||
textcommon += "}\n" |
|||
|
|||
if onlyCommon { |
|||
continue |
|||
} |
|||
|
|||
// CALL Prototype
|
|||
callProto := fmt.Sprintf("func call%s(%s) (r1 uintptr, e1 Errno) {\n", sysname, strings.Join(argscall, ", ")) |
|||
|
|||
// GC function generation
|
|||
asm := "syscall6" |
|||
if nonblock != nil { |
|||
asm = "rawSyscall6" |
|||
} |
|||
|
|||
if len(argsgc) <= 6 { |
|||
for len(argsgc) < 6 { |
|||
argsgc = append(argsgc, "0") |
|||
} |
|||
} else { |
|||
fmt.Fprintf(os.Stderr, "%s: too many arguments to system call", funct) |
|||
os.Exit(1) |
|||
} |
|||
argsgclist := strings.Join(argsgc, ", ") |
|||
callgc := fmt.Sprintf("%s(uintptr(unsafe.Pointer(&%s)), %d, %s)", asm, sysvarname, nargs, argsgclist) |
|||
|
|||
textgc += callProto |
|||
textgc += fmt.Sprintf("\tr1, _, e1 = %s\n", callgc) |
|||
textgc += "\treturn\n}\n" |
|||
|
|||
// GCCGO function generation
|
|||
argsgccgolist := strings.Join(argsgccgo, ", ") |
|||
var callgccgo string |
|||
if sysname == "select" { |
|||
// select is a keyword of Go. Its name is
|
|||
// changed to c_select.
|
|||
callgccgo = fmt.Sprintf("C.c_%s(%s)", sysname, argsgccgolist) |
|||
} else { |
|||
callgccgo = fmt.Sprintf("C.%s(%s)", sysname, argsgccgolist) |
|||
} |
|||
textgccgo += callProto |
|||
textgccgo += fmt.Sprintf("\tr1 = uintptr(%s)\n", callgccgo) |
|||
textgccgo += "\te1 = syscall.GetErrno()\n" |
|||
textgccgo += "\treturn\n}\n" |
|||
} |
|||
if err := s.Err(); err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
file.Close() |
|||
} |
|||
imp := "" |
|||
if pack != "unix" { |
|||
imp = "import \"golang.org/x/sys/unix\"\n" |
|||
|
|||
} |
|||
|
|||
// Print zsyscall_aix_ppc64.go
|
|||
err := ioutil.WriteFile("zsyscall_aix_ppc64.go", |
|||
[]byte(fmt.Sprintf(srcTemplate1, cmdLine(), buildTags(), pack, imp, textcommon)), |
|||
0644) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
// Print zsyscall_aix_ppc64_gc.go
|
|||
vardecls := "\t" + strings.Join(vars, ",\n\t") |
|||
vardecls += " syscallFunc" |
|||
err = ioutil.WriteFile("zsyscall_aix_ppc64_gc.go", |
|||
[]byte(fmt.Sprintf(srcTemplate2, cmdLine(), buildTags(), pack, imp, dynimports, linknames, vardecls, textgc)), |
|||
0644) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
// Print zsyscall_aix_ppc64_gccgo.go
|
|||
err = ioutil.WriteFile("zsyscall_aix_ppc64_gccgo.go", |
|||
[]byte(fmt.Sprintf(srcTemplate3, cmdLine(), buildTags(), pack, cExtern, imp, textgccgo)), |
|||
0644) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
} |
|||
|
|||
const srcTemplate1 = `// %s
|
|||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|||
|
|||
// +build %s
|
|||
|
|||
package %s |
|||
|
|||
import ( |
|||
"unsafe" |
|||
) |
|||
|
|||
|
|||
%s |
|||
|
|||
%s |
|||
` |
|||
const srcTemplate2 = `// %s
|
|||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|||
|
|||
// +build %s
|
|||
// +build !gccgo
|
|||
|
|||
package %s |
|||
|
|||
import ( |
|||
"unsafe" |
|||
) |
|||
%s |
|||
%s |
|||
%s |
|||
type syscallFunc uintptr |
|||
|
|||
var ( |
|||
%s |
|||
) |
|||
|
|||
// Implemented in runtime/syscall_aix.go.
|
|||
func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
|||
func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
|||
|
|||
%s |
|||
` |
|||
const srcTemplate3 = `// %s
|
|||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|||
|
|||
// +build %s
|
|||
// +build gccgo
|
|||
|
|||
package %s |
|||
|
|||
%s |
|||
*/ |
|||
import "C" |
|||
import ( |
|||
"syscall" |
|||
) |
|||
|
|||
|
|||
%s |
|||
|
|||
%s |
|||
` |
@ -1,579 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2018 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
|
|||
# This program reads a file containing function prototypes |
|||
# (like syscall_aix.go) and generates system call bodies. |
|||
# The prototypes are marked by lines beginning with "//sys" |
|||
# and read like func declarations if //sys is replaced by func, but: |
|||
# * The parameter lists must give a name for each argument. |
|||
# This includes return parameters. |
|||
# * The parameter lists must give a type for each argument: |
|||
# the (x, y, z int) shorthand is not allowed. |
|||
# * If the return parameter is an error number, it must be named err. |
|||
# * If go func name needs to be different than its libc name, |
|||
# * or the function is not in libc, name could be specified |
|||
# * at the end, after "=" sign, like |
|||
# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt |
|||
|
|||
# This program will generate three files and handle both gc and gccgo implementation: |
|||
# - zsyscall_aix_ppc64.go: the common part of each implementation (error handler, pointer creation) |
|||
# - zsyscall_aix_ppc64_gc.go: gc part with //go_cgo_import_dynamic and a call to syscall6 |
|||
# - zsyscall_aix_ppc64_gccgo.go: gccgo part with C function and conversion to C type. |
|||
|
|||
# The generated code looks like this |
|||
# |
|||
# zsyscall_aix_ppc64.go |
|||
# func asyscall(...) (n int, err error) { |
|||
# // Pointer Creation |
|||
# r1, e1 := callasyscall(...) |
|||
# // Type Conversion |
|||
# // Error Handler |
|||
# return |
|||
# } |
|||
# |
|||
# zsyscall_aix_ppc64_gc.go |
|||
# //go:cgo_import_dynamic libc_asyscall asyscall "libc.a/shr_64.o" |
|||
# //go:linkname libc_asyscall libc_asyscall |
|||
# var asyscall syscallFunc |
|||
# |
|||
# func callasyscall(...) (r1 uintptr, e1 Errno) { |
|||
# r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_asyscall)), "nb_args", ... ) |
|||
# return |
|||
# } |
|||
# |
|||
# zsyscall_aix_ppc64_ggcgo.go |
|||
# /* |
|||
# int asyscall(...) |
|||
# |
|||
# */ |
|||
# import "C" |
|||
# |
|||
# func callasyscall(...) (r1 uintptr, e1 Errno) { |
|||
# r1 = uintptr(C.asyscall(...)) |
|||
# e1 = syscall.GetErrno() |
|||
# return |
|||
# } |
|||
|
|||
|
|||
|
|||
use strict; |
|||
|
|||
my $cmdline = "mksyscall_aix_ppc64.pl " . join(' ', @ARGV); |
|||
my $errors = 0; |
|||
my $_32bit = ""; |
|||
my $tags = ""; # build tags |
|||
my $aix = 0; |
|||
my $solaris = 0; |
|||
|
|||
binmode STDOUT; |
|||
|
|||
if($ARGV[0] eq "-b32") { |
|||
$_32bit = "big-endian"; |
|||
shift; |
|||
} elsif($ARGV[0] eq "-l32") { |
|||
$_32bit = "little-endian"; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-aix") { |
|||
$aix = 1; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-tags") { |
|||
shift; |
|||
$tags = $ARGV[0]; |
|||
shift; |
|||
} |
|||
|
|||
if($ARGV[0] =~ /^-/) { |
|||
print STDERR "usage: mksyscall_aix.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
sub parseparamlist($) { |
|||
my ($list) = @_; |
|||
$list =~ s/^\s*//; |
|||
$list =~ s/\s*$//; |
|||
if($list eq "") { |
|||
return (); |
|||
} |
|||
return split(/\s*,\s*/, $list); |
|||
} |
|||
|
|||
sub parseparam($) { |
|||
my ($p) = @_; |
|||
if($p !~ /^(\S*) (\S*)$/) { |
|||
print STDERR "$ARGV:$.: malformed parameter: $p\n"; |
|||
$errors = 1; |
|||
return ("xx", "int"); |
|||
} |
|||
return ($1, $2); |
|||
} |
|||
|
|||
my $package = ""; |
|||
# GCCGO |
|||
my $textgccgo = ""; |
|||
my $c_extern = "/*\n#include <stdint.h>\n"; |
|||
# GC |
|||
my $textgc = ""; |
|||
my $dynimports = ""; |
|||
my $linknames = ""; |
|||
my @vars = (); |
|||
# COMMUN |
|||
my $textcommon = ""; |
|||
|
|||
while(<>) { |
|||
chomp; |
|||
s/\s+/ /g; |
|||
s/^\s+//; |
|||
s/\s+$//; |
|||
$package = $1 if !$package && /^package (\S+)$/; |
|||
my $nonblock = /^\/\/sysnb /; |
|||
next if !/^\/\/sys / && !$nonblock; |
|||
|
|||
# Line must be of the form |
|||
# func Open(path string, mode int, perm int) (fd int, err error) |
|||
# Split into name, in params, out params. |
|||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) { |
|||
print STDERR "$ARGV:$.: malformed //sys declaration\n"; |
|||
$errors = 1; |
|||
next; |
|||
} |
|||
my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6); |
|||
|
|||
# Split argument lists on comma. |
|||
my @in = parseparamlist($in); |
|||
my @out = parseparamlist($out); |
|||
|
|||
$in = join(', ', @in); |
|||
$out = join(', ', @out); |
|||
|
|||
if($sysname eq "") { |
|||
$sysname = "$func"; |
|||
} |
|||
|
|||
my $onlyCommon = 0; |
|||
if ($func eq "readlen" || $func eq "writelen" || $func eq "FcntlInt" || $func eq "FcntlFlock") { |
|||
# This function call another syscall which is already implemented. |
|||
# Therefore, the gc and gccgo part must not be generated. |
|||
$onlyCommon = 1 |
|||
} |
|||
|
|||
# Try in vain to keep people from editing this file. |
|||
# The theory is that they jump into the middle of the file |
|||
# without reading the header. |
|||
|
|||
$textcommon .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; |
|||
if (!$onlyCommon) { |
|||
$textgccgo .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; |
|||
$textgc .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; |
|||
} |
|||
|
|||
|
|||
# Check if value return, err return available |
|||
my $errvar = ""; |
|||
my $retvar = ""; |
|||
my $rettype = ""; |
|||
foreach my $p (@out) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type eq "error") { |
|||
$errvar = $name; |
|||
} else { |
|||
$retvar = $name; |
|||
$rettype = $type; |
|||
} |
|||
} |
|||
|
|||
|
|||
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; |
|||
$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase. |
|||
|
|||
# GCCGO Prototype return type |
|||
my $C_rettype = ""; |
|||
if($rettype eq "unsafe.Pointer") { |
|||
$C_rettype = "uintptr_t"; |
|||
} elsif($rettype eq "uintptr") { |
|||
$C_rettype = "uintptr_t"; |
|||
} elsif($rettype =~ /^_/) { |
|||
$C_rettype = "uintptr_t"; |
|||
} elsif($rettype eq "int") { |
|||
$C_rettype = "int"; |
|||
} elsif($rettype eq "int32") { |
|||
$C_rettype = "int"; |
|||
} elsif($rettype eq "int64") { |
|||
$C_rettype = "long long"; |
|||
} elsif($rettype eq "uint32") { |
|||
$C_rettype = "unsigned int"; |
|||
} elsif($rettype eq "uint64") { |
|||
$C_rettype = "unsigned long long"; |
|||
} else { |
|||
$C_rettype = "int"; |
|||
} |
|||
if($sysname eq "exit") { |
|||
$C_rettype = "void"; |
|||
} |
|||
|
|||
# GCCGO Prototype arguments type |
|||
my @c_in = (); |
|||
foreach my $i (0 .. $#in) { |
|||
my ($name, $type) = parseparam($in[$i]); |
|||
if($type =~ /^\*/) { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type eq "string") { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type =~ /^\[\](.*)/) { |
|||
push @c_in, "uintptr_t", "size_t"; |
|||
} elsif($type eq "unsafe.Pointer") { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type eq "uintptr") { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type =~ /^_/) { |
|||
push @c_in, "uintptr_t"; |
|||
} elsif($type eq "int") { |
|||
if (($i == 0 || $i == 2) && $func eq "fcntl"){ |
|||
# These fcntl arguments needs to be uintptr to be able to call FcntlInt and FcntlFlock |
|||
push @c_in, "uintptr_t"; |
|||
} else { |
|||
push @c_in, "int"; |
|||
} |
|||
} elsif($type eq "int32") { |
|||
push @c_in, "int"; |
|||
} elsif($type eq "int64") { |
|||
push @c_in, "long long"; |
|||
} elsif($type eq "uint32") { |
|||
push @c_in, "unsigned int"; |
|||
} elsif($type eq "uint64") { |
|||
push @c_in, "unsigned long long"; |
|||
} else { |
|||
push @c_in, "int"; |
|||
} |
|||
} |
|||
|
|||
if (!$onlyCommon){ |
|||
# GCCGO Prototype Generation |
|||
# Imports of system calls from libc |
|||
$c_extern .= "$C_rettype $sysname"; |
|||
my $c_in = join(', ', @c_in); |
|||
$c_extern .= "($c_in);\n"; |
|||
} |
|||
|
|||
# GC Library name |
|||
if($modname eq "") { |
|||
$modname = "libc.a/shr_64.o"; |
|||
} else { |
|||
print STDERR "$func: only syscall using libc are available\n"; |
|||
$errors = 1; |
|||
next; |
|||
} |
|||
my $sysvarname = "libc_${sysname}"; |
|||
|
|||
if (!$onlyCommon){ |
|||
# GC Runtime import of function to allow cross-platform builds. |
|||
$dynimports .= "//go:cgo_import_dynamic ${sysvarname} ${sysname} \"$modname\"\n"; |
|||
# GC Link symbol to proc address variable. |
|||
$linknames .= "//go:linkname ${sysvarname} ${sysvarname}\n"; |
|||
# GC Library proc address variable. |
|||
push @vars, $sysvarname; |
|||
} |
|||
|
|||
my $strconvfunc ="BytePtrFromString"; |
|||
my $strconvtype = "*byte"; |
|||
|
|||
# Go function header. |
|||
if($out ne "") { |
|||
$out = " ($out)"; |
|||
} |
|||
if($textcommon ne "") { |
|||
$textcommon .= "\n" |
|||
} |
|||
|
|||
$textcommon .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out ; |
|||
|
|||
# Prepare arguments to call. |
|||
my @argscommun = (); # Arguments in the commun part |
|||
my @argscall = (); # Arguments for call prototype |
|||
my @argsgc = (); # Arguments for gc call (with syscall6) |
|||
my @argsgccgo = (); # Arguments for gccgo call (with C.name_of_syscall) |
|||
my $n = 0; |
|||
my $arg_n = 0; |
|||
foreach my $p (@in) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type =~ /^\*/) { |
|||
push @argscommun, "uintptr(unsafe.Pointer($name))"; |
|||
push @argscall, "$name uintptr"; |
|||
push @argsgc, "$name"; |
|||
push @argsgccgo, "C.uintptr_t($name)"; |
|||
} elsif($type eq "string" && $errvar ne "") { |
|||
$textcommon .= "\tvar _p$n $strconvtype\n"; |
|||
$textcommon .= "\t_p$n, $errvar = $strconvfunc($name)\n"; |
|||
$textcommon .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; |
|||
|
|||
push @argscommun, "uintptr(unsafe.Pointer(_p$n))"; |
|||
push @argscall, "_p$n uintptr "; |
|||
push @argsgc, "_p$n"; |
|||
push @argsgccgo, "C.uintptr_t(_p$n)"; |
|||
$n++; |
|||
} elsif($type eq "string") { |
|||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; |
|||
$textcommon .= "\tvar _p$n $strconvtype\n"; |
|||
$textcommon .= "\t_p$n, $errvar = $strconvfunc($name)\n"; |
|||
$textcommon .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; |
|||
|
|||
push @argscommun, "uintptr(unsafe.Pointer(_p$n))"; |
|||
push @argscall, "_p$n uintptr"; |
|||
push @argsgc, "_p$n"; |
|||
push @argsgccgo, "C.uintptr_t(_p$n)"; |
|||
$n++; |
|||
} elsif($type =~ /^\[\](.*)/) { |
|||
# Convert slice into pointer, length. |
|||
# Have to be careful not to take address of &a[0] if len == 0: |
|||
# pass nil in that case. |
|||
$textcommon .= "\tvar _p$n *$1\n"; |
|||
$textcommon .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; |
|||
push @argscommun, "uintptr(unsafe.Pointer(_p$n))", "len($name)"; |
|||
push @argscall, "_p$n uintptr", "_lenp$n int"; |
|||
push @argsgc, "_p$n", "uintptr(_lenp$n)"; |
|||
push @argsgccgo, "C.uintptr_t(_p$n)", "C.size_t(_lenp$n)"; |
|||
$n++; |
|||
} elsif($type eq "int64" && $_32bit ne "") { |
|||
print STDERR "$ARGV:$.: $func uses int64 with 32 bits mode. Case not yet implemented\n"; |
|||
# if($_32bit eq "big-endian") { |
|||
# push @args, "uintptr($name >> 32)", "uintptr($name)"; |
|||
# } else { |
|||
# push @args, "uintptr($name)", "uintptr($name >> 32)"; |
|||
# } |
|||
# $n++; |
|||
} elsif($type eq "bool") { |
|||
print STDERR "$ARGV:$.: $func uses bool. Case not yet implemented\n"; |
|||
# $text .= "\tvar _p$n uint32\n"; |
|||
# $text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; |
|||
# push @args, "_p$n"; |
|||
# $n++; |
|||
} elsif($type =~ /^_/ ||$type eq "unsafe.Pointer") { |
|||
push @argscommun, "uintptr($name)"; |
|||
push @argscall, "$name uintptr"; |
|||
push @argsgc, "$name"; |
|||
push @argsgccgo, "C.uintptr_t($name)"; |
|||
} elsif($type eq "int") { |
|||
if (($arg_n == 0 || $arg_n == 2) && ($func eq "fcntl" || $func eq "FcntlInt" || $func eq "FcntlFlock")) { |
|||
# These fcntl arguments need to be uintptr to be able to call FcntlInt and FcntlFlock |
|||
push @argscommun, "uintptr($name)"; |
|||
push @argscall, "$name uintptr"; |
|||
push @argsgc, "$name"; |
|||
push @argsgccgo, "C.uintptr_t($name)"; |
|||
} else { |
|||
push @argscommun, "$name"; |
|||
push @argscall, "$name int"; |
|||
push @argsgc, "uintptr($name)"; |
|||
push @argsgccgo, "C.int($name)"; |
|||
} |
|||
} elsif($type eq "int32") { |
|||
push @argscommun, "$name"; |
|||
push @argscall, "$name int32"; |
|||
push @argsgc, "uintptr($name)"; |
|||
push @argsgccgo, "C.int($name)"; |
|||
} elsif($type eq "int64") { |
|||
push @argscommun, "$name"; |
|||
push @argscall, "$name int64"; |
|||
push @argsgc, "uintptr($name)"; |
|||
push @argsgccgo, "C.longlong($name)"; |
|||
} elsif($type eq "uint32") { |
|||
push @argscommun, "$name"; |
|||
push @argscall, "$name uint32"; |
|||
push @argsgc, "uintptr($name)"; |
|||
push @argsgccgo, "C.uint($name)"; |
|||
} elsif($type eq "uint64") { |
|||
push @argscommun, "$name"; |
|||
push @argscall, "$name uint64"; |
|||
push @argsgc, "uintptr($name)"; |
|||
push @argsgccgo, "C.ulonglong($name)"; |
|||
} elsif($type eq "uintptr") { |
|||
push @argscommun, "$name"; |
|||
push @argscall, "$name uintptr"; |
|||
push @argsgc, "$name"; |
|||
push @argsgccgo, "C.uintptr_t($name)"; |
|||
} else { |
|||
push @argscommun, "int($name)"; |
|||
push @argscall, "$name int"; |
|||
push @argsgc, "uintptr($name)"; |
|||
push @argsgccgo, "C.int($name)"; |
|||
} |
|||
$arg_n++; |
|||
} |
|||
my $nargs = @argsgc; |
|||
|
|||
# COMMUN function generation |
|||
my $argscommun = join(', ', @argscommun); |
|||
my $callcommun = "call$sysname($argscommun)"; |
|||
my @ret = ("_", "_"); |
|||
my $body = ""; |
|||
my $do_errno = 0; |
|||
for(my $i=0; $i<@out; $i++) { |
|||
my $p = $out[$i]; |
|||
my ($name, $type) = parseparam($p); |
|||
my $reg = ""; |
|||
if($name eq "err") { |
|||
$reg = "e1"; |
|||
$ret[1] = $reg; |
|||
$do_errno = 1; |
|||
} else { |
|||
$reg = "r0"; |
|||
$ret[0] = $reg; |
|||
} |
|||
if($type eq "bool") { |
|||
$reg = "$reg != 0"; |
|||
} |
|||
if($reg ne "e1") { |
|||
$body .= "\t$name = $type($reg)\n"; |
|||
} |
|||
} |
|||
if ($ret[0] eq "_" && $ret[1] eq "_") { |
|||
$textcommon .= "\t$callcommun\n"; |
|||
} else { |
|||
$textcommon .= "\t$ret[0], $ret[1] := $callcommun\n"; |
|||
} |
|||
$textcommon .= $body; |
|||
|
|||
if ($do_errno) { |
|||
$textcommon .= "\tif e1 != 0 {\n"; |
|||
$textcommon .= "\t\terr = errnoErr(e1)\n"; |
|||
$textcommon .= "\t}\n"; |
|||
} |
|||
$textcommon .= "\treturn\n"; |
|||
$textcommon .= "}\n"; |
|||
|
|||
if ($onlyCommon){ |
|||
next |
|||
} |
|||
# CALL Prototype |
|||
my $callProto = sprintf "func call%s(%s) (r1 uintptr, e1 Errno) {\n", $sysname, join(', ', @argscall); |
|||
|
|||
# GC function generation |
|||
my $asm = "syscall6"; |
|||
if ($nonblock) { |
|||
$asm = "rawSyscall6"; |
|||
} |
|||
|
|||
if(@argsgc <= 6) { |
|||
while(@argsgc < 6) { |
|||
push @argsgc, "0"; |
|||
} |
|||
} else { |
|||
print STDERR "$ARGV:$.: too many arguments to system call\n"; |
|||
} |
|||
my $argsgc = join(', ', @argsgc); |
|||
my $callgc = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $argsgc)"; |
|||
|
|||
$textgc .= $callProto; |
|||
$textgc .= "\tr1, _, e1 = $callgc\n"; |
|||
$textgc .= "\treturn\n}\n"; |
|||
|
|||
# GCCGO function generation |
|||
my $argsgccgo = join(', ', @argsgccgo); |
|||
my $callgccgo = "C.$sysname($argsgccgo)"; |
|||
$textgccgo .= $callProto; |
|||
$textgccgo .= "\tr1 = uintptr($callgccgo)\n"; |
|||
$textgccgo .= "\te1 = syscall.GetErrno()\n"; |
|||
$textgccgo .= "\treturn\n}\n"; |
|||
} |
|||
|
|||
if($errors) { |
|||
exit 1; |
|||
} |
|||
|
|||
# Print zsyscall_aix_ppc64.go |
|||
open(my $fcommun, '>', 'zsyscall_aix_ppc64.go'); |
|||
my $tofcommun = <<EOF; |
|||
// $cmdline |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $tags |
|||
|
|||
package $package |
|||
|
|||
import ( |
|||
"unsafe" |
|||
) |
|||
|
|||
EOF |
|||
|
|||
$tofcommun .= "import \"golang.org/x/sys/unix\"\n" if $package ne "unix"; |
|||
|
|||
$tofcommun .=<<EOF; |
|||
|
|||
$textcommon |
|||
EOF |
|||
print $fcommun $tofcommun; |
|||
|
|||
|
|||
# Print zsyscall_aix_ppc64_gc.go |
|||
open(my $fgc, '>', 'zsyscall_aix_ppc64_gc.go'); |
|||
my $tofgc = <<EOF; |
|||
// $cmdline |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $tags |
|||
// +build !gccgo |
|||
|
|||
package $package |
|||
|
|||
import ( |
|||
"unsafe" |
|||
) |
|||
|
|||
|
|||
EOF |
|||
|
|||
$tofgc .= "import \"golang.org/x/sys/unix\"\n" if $package ne "unix"; |
|||
|
|||
my $vardecls = "\t" . join(",\n\t", @vars); |
|||
$vardecls .= " syscallFunc"; |
|||
|
|||
$tofgc .=<<EOF; |
|||
$dynimports |
|||
$linknames |
|||
type syscallFunc uintptr |
|||
|
|||
var ( |
|||
$vardecls |
|||
) |
|||
|
|||
// Implemented in runtime/syscall_aix.go. |
|||
func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
|||
func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
|||
|
|||
$textgc |
|||
EOF |
|||
print $fgc $tofgc; |
|||
|
|||
# Print zsyscall_aix_ppc64_gc.go |
|||
open(my $fgccgo, '>', 'zsyscall_aix_ppc64_gccgo.go'); |
|||
my $tofgccgo = <<EOF; |
|||
// $cmdline |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $tags |
|||
// +build gccgo |
|||
|
|||
package $package |
|||
|
|||
|
|||
$c_extern |
|||
*/ |
|||
import "C" |
|||
import ( |
|||
"syscall" |
|||
) |
|||
|
|||
|
|||
EOF |
|||
|
|||
$tofgccgo .= "import \"golang.org/x/sys/unix\"\n" if $package ne "unix"; |
|||
|
|||
$tofgccgo .=<<EOF; |
|||
|
|||
$textgccgo |
|||
EOF |
|||
print $fgccgo $tofgccgo; |
|||
exit 0; |
@ -0,0 +1,335 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build ignore
|
|||
|
|||
/* |
|||
This program reads a file containing function prototypes |
|||
(like syscall_solaris.go) and generates system call bodies. |
|||
The prototypes are marked by lines beginning with "//sys" |
|||
and read like func declarations if //sys is replaced by func, but:
|
|||
* The parameter lists must give a name for each argument. |
|||
This includes return parameters. |
|||
* The parameter lists must give a type for each argument: |
|||
the (x, y, z int) shorthand is not allowed. |
|||
* If the return parameter is an error number, it must be named err. |
|||
* If go func name needs to be different than its libc name, |
|||
* or the function is not in libc, name could be specified |
|||
* at the end, after "=" sign, like |
|||
//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
|
|||
*/ |
|||
|
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"flag" |
|||
"fmt" |
|||
"os" |
|||
"regexp" |
|||
"strings" |
|||
) |
|||
|
|||
var ( |
|||
b32 = flag.Bool("b32", false, "32bit big-endian") |
|||
l32 = flag.Bool("l32", false, "32bit little-endian") |
|||
tags = flag.String("tags", "", "build tags") |
|||
) |
|||
|
|||
// cmdLine returns this programs's commandline arguments
|
|||
func cmdLine() string { |
|||
return "go run mksyscall_solaris.go " + strings.Join(os.Args[1:], " ") |
|||
} |
|||
|
|||
// buildTags returns build tags
|
|||
func buildTags() string { |
|||
return *tags |
|||
} |
|||
|
|||
// Param is function parameter
|
|||
type Param struct { |
|||
Name string |
|||
Type string |
|||
} |
|||
|
|||
// usage prints the program usage
|
|||
func usage() { |
|||
fmt.Fprintf(os.Stderr, "usage: go run mksyscall_solaris.go [-b32 | -l32] [-tags x,y] [file ...]\n") |
|||
os.Exit(1) |
|||
} |
|||
|
|||
// parseParamList parses parameter list and returns a slice of parameters
|
|||
func parseParamList(list string) []string { |
|||
list = strings.TrimSpace(list) |
|||
if list == "" { |
|||
return []string{} |
|||
} |
|||
return regexp.MustCompile(`\s*,\s*`).Split(list, -1) |
|||
} |
|||
|
|||
// parseParam splits a parameter into name and type
|
|||
func parseParam(p string) Param { |
|||
ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) |
|||
if ps == nil { |
|||
fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) |
|||
os.Exit(1) |
|||
} |
|||
return Param{ps[1], ps[2]} |
|||
} |
|||
|
|||
func main() { |
|||
flag.Usage = usage |
|||
flag.Parse() |
|||
if len(flag.Args()) <= 0 { |
|||
fmt.Fprintf(os.Stderr, "no files to parse provided\n") |
|||
usage() |
|||
} |
|||
|
|||
endianness := "" |
|||
if *b32 { |
|||
endianness = "big-endian" |
|||
} else if *l32 { |
|||
endianness = "little-endian" |
|||
} |
|||
|
|||
pack := "" |
|||
text := "" |
|||
dynimports := "" |
|||
linknames := "" |
|||
var vars []string |
|||
for _, path := range flag.Args() { |
|||
file, err := os.Open(path) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
s := bufio.NewScanner(file) |
|||
for s.Scan() { |
|||
t := s.Text() |
|||
t = strings.TrimSpace(t) |
|||
t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) |
|||
if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" { |
|||
pack = p[1] |
|||
} |
|||
nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) |
|||
if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { |
|||
continue |
|||
} |
|||
|
|||
// Line must be of the form
|
|||
// func Open(path string, mode int, perm int) (fd int, err error)
|
|||
// Split into name, in params, out params.
|
|||
f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t) |
|||
if f == nil { |
|||
fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) |
|||
os.Exit(1) |
|||
} |
|||
funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6] |
|||
|
|||
// Split argument lists on comma.
|
|||
in := parseParamList(inps) |
|||
out := parseParamList(outps) |
|||
|
|||
inps = strings.Join(in, ", ") |
|||
outps = strings.Join(out, ", ") |
|||
|
|||
// Try in vain to keep people from editing this file.
|
|||
// The theory is that they jump into the middle of the file
|
|||
// without reading the header.
|
|||
text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
|||
|
|||
// So file name.
|
|||
if modname == "" { |
|||
modname = "libc" |
|||
} |
|||
|
|||
// System call name.
|
|||
if sysname == "" { |
|||
sysname = funct |
|||
} |
|||
|
|||
// System call pointer variable name.
|
|||
sysvarname := fmt.Sprintf("proc%s", sysname) |
|||
|
|||
strconvfunc := "BytePtrFromString" |
|||
strconvtype := "*byte" |
|||
|
|||
sysname = strings.ToLower(sysname) // All libc functions are lowercase.
|
|||
|
|||
// Runtime import of function to allow cross-platform builds.
|
|||
dynimports += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"%s.so\"\n", sysname, sysname, modname) |
|||
// Link symbol to proc address variable.
|
|||
linknames += fmt.Sprintf("//go:linkname %s libc_%s\n", sysvarname, sysname) |
|||
// Library proc address variable.
|
|||
vars = append(vars, sysvarname) |
|||
|
|||
// Go function header.
|
|||
outlist := strings.Join(out, ", ") |
|||
if outlist != "" { |
|||
outlist = fmt.Sprintf(" (%s)", outlist) |
|||
} |
|||
if text != "" { |
|||
text += "\n" |
|||
} |
|||
text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outlist) |
|||
|
|||
// Check if err return available
|
|||
errvar := "" |
|||
for _, param := range out { |
|||
p := parseParam(param) |
|||
if p.Type == "error" { |
|||
errvar = p.Name |
|||
continue |
|||
} |
|||
} |
|||
|
|||
// Prepare arguments to Syscall.
|
|||
var args []string |
|||
n := 0 |
|||
for _, param := range in { |
|||
p := parseParam(param) |
|||
if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { |
|||
args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))") |
|||
} else if p.Type == "string" && errvar != "" { |
|||
text += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) |
|||
text += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) |
|||
text += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) |
|||
args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) |
|||
n++ |
|||
} else if p.Type == "string" { |
|||
fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") |
|||
text += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) |
|||
text += fmt.Sprintf("\t_p%d, _ = %s(%s)\n", n, strconvfunc, p.Name) |
|||
args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) |
|||
n++ |
|||
} else if s := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); s != nil { |
|||
// Convert slice into pointer, length.
|
|||
// Have to be careful not to take address of &a[0] if len == 0:
|
|||
// pass nil in that case.
|
|||
text += fmt.Sprintf("\tvar _p%d *%s\n", n, s[1]) |
|||
text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name) |
|||
args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n), fmt.Sprintf("uintptr(len(%s))", p.Name)) |
|||
n++ |
|||
} else if p.Type == "int64" && endianness != "" { |
|||
if endianness == "big-endian" { |
|||
args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} else { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) |
|||
} |
|||
} else if p.Type == "bool" { |
|||
text += fmt.Sprintf("\tvar _p%d uint32\n", n) |
|||
text += fmt.Sprintf("\tif %s {\n\t\t_p%d = 1\n\t} else {\n\t\t_p%d = 0\n\t}\n", p.Name, n, n) |
|||
args = append(args, fmt.Sprintf("uintptr(_p%d)", n)) |
|||
n++ |
|||
} else { |
|||
args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) |
|||
} |
|||
} |
|||
nargs := len(args) |
|||
|
|||
// Determine which form to use; pad args with zeros.
|
|||
asm := "sysvicall6" |
|||
if nonblock != nil { |
|||
asm = "rawSysvicall6" |
|||
} |
|||
if len(args) <= 6 { |
|||
for len(args) < 6 { |
|||
args = append(args, "0") |
|||
} |
|||
} else { |
|||
fmt.Fprintf(os.Stderr, "%s: too many arguments to system call\n", path) |
|||
os.Exit(1) |
|||
} |
|||
|
|||
// Actual call.
|
|||
arglist := strings.Join(args, ", ") |
|||
call := fmt.Sprintf("%s(uintptr(unsafe.Pointer(&%s)), %d, %s)", asm, sysvarname, nargs, arglist) |
|||
|
|||
// Assign return values.
|
|||
body := "" |
|||
ret := []string{"_", "_", "_"} |
|||
doErrno := false |
|||
for i := 0; i < len(out); i++ { |
|||
p := parseParam(out[i]) |
|||
reg := "" |
|||
if p.Name == "err" { |
|||
reg = "e1" |
|||
ret[2] = reg |
|||
doErrno = true |
|||
} else { |
|||
reg = fmt.Sprintf("r%d", i) |
|||
ret[i] = reg |
|||
} |
|||
if p.Type == "bool" { |
|||
reg = fmt.Sprintf("%d != 0", reg) |
|||
} |
|||
if p.Type == "int64" && endianness != "" { |
|||
// 64-bit number in r1:r0 or r0:r1.
|
|||
if i+2 > len(out) { |
|||
fmt.Fprintf(os.Stderr, "%s: not enough registers for int64 return\n", path) |
|||
os.Exit(1) |
|||
} |
|||
if endianness == "big-endian" { |
|||
reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i, i+1) |
|||
} else { |
|||
reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i+1, i) |
|||
} |
|||
ret[i] = fmt.Sprintf("r%d", i) |
|||
ret[i+1] = fmt.Sprintf("r%d", i+1) |
|||
} |
|||
if reg != "e1" { |
|||
body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) |
|||
} |
|||
} |
|||
if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" { |
|||
text += fmt.Sprintf("\t%s\n", call) |
|||
} else { |
|||
text += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call) |
|||
} |
|||
text += body |
|||
|
|||
if doErrno { |
|||
text += "\tif e1 != 0 {\n" |
|||
text += "\t\terr = e1\n" |
|||
text += "\t}\n" |
|||
} |
|||
text += "\treturn\n" |
|||
text += "}\n" |
|||
} |
|||
if err := s.Err(); err != nil { |
|||
fmt.Fprintf(os.Stderr, err.Error()) |
|||
os.Exit(1) |
|||
} |
|||
file.Close() |
|||
} |
|||
imp := "" |
|||
if pack != "unix" { |
|||
imp = "import \"golang.org/x/sys/unix\"\n" |
|||
|
|||
} |
|||
vardecls := "\t" + strings.Join(vars, ",\n\t") |
|||
vardecls += " syscallFunc" |
|||
fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, imp, dynimports, linknames, vardecls, text) |
|||
} |
|||
|
|||
const srcTemplate = `// %s
|
|||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|||
|
|||
// +build %s
|
|||
|
|||
package %s |
|||
|
|||
import ( |
|||
"syscall" |
|||
"unsafe" |
|||
) |
|||
%s |
|||
%s |
|||
%s |
|||
var ( |
|||
%s |
|||
) |
|||
|
|||
%s |
|||
` |
@ -1,294 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2009 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
|
|||
# This program reads a file containing function prototypes |
|||
# (like syscall_solaris.go) and generates system call bodies. |
|||
# The prototypes are marked by lines beginning with "//sys" |
|||
# and read like func declarations if //sys is replaced by func, but: |
|||
# * The parameter lists must give a name for each argument. |
|||
# This includes return parameters. |
|||
# * The parameter lists must give a type for each argument: |
|||
# the (x, y, z int) shorthand is not allowed. |
|||
# * If the return parameter is an error number, it must be named err. |
|||
# * If go func name needs to be different than its libc name, |
|||
# * or the function is not in libc, name could be specified |
|||
# * at the end, after "=" sign, like |
|||
# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt |
|||
|
|||
use strict; |
|||
|
|||
my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV); |
|||
my $errors = 0; |
|||
my $_32bit = ""; |
|||
my $tags = ""; # build tags |
|||
|
|||
binmode STDOUT; |
|||
|
|||
if($ARGV[0] eq "-b32") { |
|||
$_32bit = "big-endian"; |
|||
shift; |
|||
} elsif($ARGV[0] eq "-l32") { |
|||
$_32bit = "little-endian"; |
|||
shift; |
|||
} |
|||
if($ARGV[0] eq "-tags") { |
|||
shift; |
|||
$tags = $ARGV[0]; |
|||
shift; |
|||
} |
|||
|
|||
if($ARGV[0] =~ /^-/) { |
|||
print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
sub parseparamlist($) { |
|||
my ($list) = @_; |
|||
$list =~ s/^\s*//; |
|||
$list =~ s/\s*$//; |
|||
if($list eq "") { |
|||
return (); |
|||
} |
|||
return split(/\s*,\s*/, $list); |
|||
} |
|||
|
|||
sub parseparam($) { |
|||
my ($p) = @_; |
|||
if($p !~ /^(\S*) (\S*)$/) { |
|||
print STDERR "$ARGV:$.: malformed parameter: $p\n"; |
|||
$errors = 1; |
|||
return ("xx", "int"); |
|||
} |
|||
return ($1, $2); |
|||
} |
|||
|
|||
my $package = ""; |
|||
my $text = ""; |
|||
my $dynimports = ""; |
|||
my $linknames = ""; |
|||
my @vars = (); |
|||
while(<>) { |
|||
chomp; |
|||
s/\s+/ /g; |
|||
s/^\s+//; |
|||
s/\s+$//; |
|||
$package = $1 if !$package && /^package (\S+)$/; |
|||
my $nonblock = /^\/\/sysnb /; |
|||
next if !/^\/\/sys / && !$nonblock; |
|||
|
|||
# Line must be of the form |
|||
# func Open(path string, mode int, perm int) (fd int, err error) |
|||
# Split into name, in params, out params. |
|||
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) { |
|||
print STDERR "$ARGV:$.: malformed //sys declaration\n"; |
|||
$errors = 1; |
|||
next; |
|||
} |
|||
my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6); |
|||
|
|||
# Split argument lists on comma. |
|||
my @in = parseparamlist($in); |
|||
my @out = parseparamlist($out); |
|||
|
|||
# Try in vain to keep people from editing this file. |
|||
# The theory is that they jump into the middle of the file |
|||
# without reading the header. |
|||
$text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"; |
|||
|
|||
# So file name. |
|||
if($modname eq "") { |
|||
$modname = "libc"; |
|||
} |
|||
|
|||
# System call name. |
|||
if($sysname eq "") { |
|||
$sysname = "$func"; |
|||
} |
|||
|
|||
# System call pointer variable name. |
|||
my $sysvarname = "proc$sysname"; |
|||
|
|||
my $strconvfunc = "BytePtrFromString"; |
|||
my $strconvtype = "*byte"; |
|||
|
|||
$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase. |
|||
|
|||
# Runtime import of function to allow cross-platform builds. |
|||
$dynimports .= "//go:cgo_import_dynamic libc_${sysname} ${sysname} \"$modname.so\"\n"; |
|||
# Link symbol to proc address variable. |
|||
$linknames .= "//go:linkname ${sysvarname} libc_${sysname}\n"; |
|||
# Library proc address variable. |
|||
push @vars, $sysvarname; |
|||
|
|||
# Go function header. |
|||
$out = join(', ', @out); |
|||
if($out ne "") { |
|||
$out = " ($out)"; |
|||
} |
|||
if($text ne "") { |
|||
$text .= "\n" |
|||
} |
|||
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out; |
|||
|
|||
# Check if err return available |
|||
my $errvar = ""; |
|||
foreach my $p (@out) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type eq "error") { |
|||
$errvar = $name; |
|||
last; |
|||
} |
|||
} |
|||
|
|||
# Prepare arguments to Syscall. |
|||
my @args = (); |
|||
my $n = 0; |
|||
foreach my $p (@in) { |
|||
my ($name, $type) = parseparam($p); |
|||
if($type =~ /^\*/) { |
|||
push @args, "uintptr(unsafe.Pointer($name))"; |
|||
} elsif($type eq "string" && $errvar ne "") { |
|||
$text .= "\tvar _p$n $strconvtype\n"; |
|||
$text .= "\t_p$n, $errvar = $strconvfunc($name)\n"; |
|||
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; |
|||
push @args, "uintptr(unsafe.Pointer(_p$n))"; |
|||
$n++; |
|||
} elsif($type eq "string") { |
|||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; |
|||
$text .= "\tvar _p$n $strconvtype\n"; |
|||
$text .= "\t_p$n, _ = $strconvfunc($name)\n"; |
|||
push @args, "uintptr(unsafe.Pointer(_p$n))"; |
|||
$n++; |
|||
} elsif($type =~ /^\[\](.*)/) { |
|||
# Convert slice into pointer, length. |
|||
# Have to be careful not to take address of &a[0] if len == 0: |
|||
# pass nil in that case. |
|||
$text .= "\tvar _p$n *$1\n"; |
|||
$text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; |
|||
push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; |
|||
$n++; |
|||
} elsif($type eq "int64" && $_32bit ne "") { |
|||
if($_32bit eq "big-endian") { |
|||
push @args, "uintptr($name >> 32)", "uintptr($name)"; |
|||
} else { |
|||
push @args, "uintptr($name)", "uintptr($name >> 32)"; |
|||
} |
|||
} elsif($type eq "bool") { |
|||
$text .= "\tvar _p$n uint32\n"; |
|||
$text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; |
|||
push @args, "uintptr(_p$n)"; |
|||
$n++; |
|||
} else { |
|||
push @args, "uintptr($name)"; |
|||
} |
|||
} |
|||
my $nargs = @args; |
|||
|
|||
# Determine which form to use; pad args with zeros. |
|||
my $asm = "sysvicall6"; |
|||
if ($nonblock) { |
|||
$asm = "rawSysvicall6"; |
|||
} |
|||
if(@args <= 6) { |
|||
while(@args < 6) { |
|||
push @args, "0"; |
|||
} |
|||
} else { |
|||
print STDERR "$ARGV:$.: too many arguments to system call\n"; |
|||
} |
|||
|
|||
# Actual call. |
|||
my $args = join(', ', @args); |
|||
my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)"; |
|||
|
|||
# Assign return values. |
|||
my $body = ""; |
|||
my $failexpr = ""; |
|||
my @ret = ("_", "_", "_"); |
|||
my @pout= (); |
|||
my $do_errno = 0; |
|||
for(my $i=0; $i<@out; $i++) { |
|||
my $p = $out[$i]; |
|||
my ($name, $type) = parseparam($p); |
|||
my $reg = ""; |
|||
if($name eq "err") { |
|||
$reg = "e1"; |
|||
$ret[2] = $reg; |
|||
$do_errno = 1; |
|||
} else { |
|||
$reg = sprintf("r%d", $i); |
|||
$ret[$i] = $reg; |
|||
} |
|||
if($type eq "bool") { |
|||
$reg = "$reg != 0"; |
|||
} |
|||
if($type eq "int64" && $_32bit ne "") { |
|||
# 64-bit number in r1:r0 or r0:r1. |
|||
if($i+2 > @out) { |
|||
print STDERR "$ARGV:$.: not enough registers for int64 return\n"; |
|||
} |
|||
if($_32bit eq "big-endian") { |
|||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); |
|||
} else { |
|||
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); |
|||
} |
|||
$ret[$i] = sprintf("r%d", $i); |
|||
$ret[$i+1] = sprintf("r%d", $i+1); |
|||
} |
|||
if($reg ne "e1") { |
|||
$body .= "\t$name = $type($reg)\n"; |
|||
} |
|||
} |
|||
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { |
|||
$text .= "\t$call\n"; |
|||
} else { |
|||
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; |
|||
} |
|||
$text .= $body; |
|||
|
|||
if ($do_errno) { |
|||
$text .= "\tif e1 != 0 {\n"; |
|||
$text .= "\t\terr = e1\n"; |
|||
$text .= "\t}\n"; |
|||
} |
|||
$text .= "\treturn\n"; |
|||
$text .= "}\n"; |
|||
} |
|||
|
|||
if($errors) { |
|||
exit 1; |
|||
} |
|||
|
|||
print <<EOF; |
|||
// $cmdline |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $tags |
|||
|
|||
package $package |
|||
|
|||
import ( |
|||
"syscall" |
|||
"unsafe" |
|||
) |
|||
EOF |
|||
|
|||
print "import \"golang.org/x/sys/unix\"\n" if $package ne "unix"; |
|||
|
|||
my $vardecls = "\t" . join(",\n\t", @vars); |
|||
$vardecls .= " syscallFunc"; |
|||
|
|||
chomp($_=<<EOF); |
|||
|
|||
$dynimports |
|||
$linknames |
|||
var ( |
|||
$vardecls |
|||
) |
|||
|
|||
$text |
|||
EOF |
|||
print $_; |
|||
exit 0; |
@ -0,0 +1,355 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build ignore
|
|||
|
|||
// Parse the header files for OpenBSD and generate a Go usable sysctl MIB.
|
|||
//
|
|||
// Build a MIB with each entry being an array containing the level, type and
|
|||
// a hash that will contain additional entries if the current entry is a node.
|
|||
// We then walk this MIB and create a flattened sysctl name to OID hash.
|
|||
|
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"fmt" |
|||
"os" |
|||
"path/filepath" |
|||
"regexp" |
|||
"sort" |
|||
"strings" |
|||
) |
|||
|
|||
var ( |
|||
goos, goarch string |
|||
) |
|||
|
|||
// cmdLine returns this programs's commandline arguments.
|
|||
func cmdLine() string { |
|||
return "go run mksysctl_openbsd.go " + strings.Join(os.Args[1:], " ") |
|||
} |
|||
|
|||
// buildTags returns build tags.
|
|||
func buildTags() string { |
|||
return fmt.Sprintf("%s,%s", goarch, goos) |
|||
} |
|||
|
|||
// reMatch performs regular expression match and stores the substring slice to value pointed by m.
|
|||
func reMatch(re *regexp.Regexp, str string, m *[]string) bool { |
|||
*m = re.FindStringSubmatch(str) |
|||
if *m != nil { |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
type nodeElement struct { |
|||
n int |
|||
t string |
|||
pE *map[string]nodeElement |
|||
} |
|||
|
|||
var ( |
|||
debugEnabled bool |
|||
mib map[string]nodeElement |
|||
node *map[string]nodeElement |
|||
nodeMap map[string]string |
|||
sysCtl []string |
|||
) |
|||
|
|||
var ( |
|||
ctlNames1RE = regexp.MustCompile(`^#define\s+(CTL_NAMES)\s+{`) |
|||
ctlNames2RE = regexp.MustCompile(`^#define\s+(CTL_(.*)_NAMES)\s+{`) |
|||
ctlNames3RE = regexp.MustCompile(`^#define\s+((.*)CTL_NAMES)\s+{`) |
|||
netInetRE = regexp.MustCompile(`^netinet/`) |
|||
netInet6RE = regexp.MustCompile(`^netinet6/`) |
|||
netRE = regexp.MustCompile(`^net/`) |
|||
bracesRE = regexp.MustCompile(`{.*}`) |
|||
ctlTypeRE = regexp.MustCompile(`{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}`) |
|||
fsNetKernRE = regexp.MustCompile(`^(fs|net|kern)_`) |
|||
) |
|||
|
|||
func debug(s string) { |
|||
if debugEnabled { |
|||
fmt.Fprintln(os.Stderr, s) |
|||
} |
|||
} |
|||
|
|||
// Walk the MIB and build a sysctl name to OID mapping.
|
|||
func buildSysctl(pNode *map[string]nodeElement, name string, oid []int) { |
|||
lNode := pNode // local copy of pointer to node
|
|||
var keys []string |
|||
for k := range *lNode { |
|||
keys = append(keys, k) |
|||
} |
|||
sort.Strings(keys) |
|||
|
|||
for _, key := range keys { |
|||
nodename := name |
|||
if name != "" { |
|||
nodename += "." |
|||
} |
|||
nodename += key |
|||
|
|||
nodeoid := append(oid, (*pNode)[key].n) |
|||
|
|||
if (*pNode)[key].t == `CTLTYPE_NODE` { |
|||
if _, ok := nodeMap[nodename]; ok { |
|||
lNode = &mib |
|||
ctlName := nodeMap[nodename] |
|||
for _, part := range strings.Split(ctlName, ".") { |
|||
lNode = ((*lNode)[part]).pE |
|||
} |
|||
} else { |
|||
lNode = (*pNode)[key].pE |
|||
} |
|||
buildSysctl(lNode, nodename, nodeoid) |
|||
} else if (*pNode)[key].t != "" { |
|||
oidStr := []string{} |
|||
for j := range nodeoid { |
|||
oidStr = append(oidStr, fmt.Sprintf("%d", nodeoid[j])) |
|||
} |
|||
text := "\t{ \"" + nodename + "\", []_C_int{ " + strings.Join(oidStr, ", ") + " } }, \n" |
|||
sysCtl = append(sysCtl, text) |
|||
} |
|||
} |
|||
} |
|||
|
|||
func main() { |
|||
// Get the OS (using GOOS_TARGET if it exist)
|
|||
goos = os.Getenv("GOOS_TARGET") |
|||
if goos == "" { |
|||
goos = os.Getenv("GOOS") |
|||
} |
|||
// Get the architecture (using GOARCH_TARGET if it exists)
|
|||
goarch = os.Getenv("GOARCH_TARGET") |
|||
if goarch == "" { |
|||
goarch = os.Getenv("GOARCH") |
|||
} |
|||
// Check if GOOS and GOARCH environment variables are defined
|
|||
if goarch == "" || goos == "" { |
|||
fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n") |
|||
os.Exit(1) |
|||
} |
|||
|
|||
mib = make(map[string]nodeElement) |
|||
headers := [...]string{ |
|||
`sys/sysctl.h`, |
|||
`sys/socket.h`, |
|||
`sys/tty.h`, |
|||
`sys/malloc.h`, |
|||
`sys/mount.h`, |
|||
`sys/namei.h`, |
|||
`sys/sem.h`, |
|||
`sys/shm.h`, |
|||
`sys/vmmeter.h`, |
|||
`uvm/uvmexp.h`, |
|||
`uvm/uvm_param.h`, |
|||
`uvm/uvm_swap_encrypt.h`, |
|||
`ddb/db_var.h`, |
|||
`net/if.h`, |
|||
`net/if_pfsync.h`, |
|||
`net/pipex.h`, |
|||
`netinet/in.h`, |
|||
`netinet/icmp_var.h`, |
|||
`netinet/igmp_var.h`, |
|||
`netinet/ip_ah.h`, |
|||
`netinet/ip_carp.h`, |
|||
`netinet/ip_divert.h`, |
|||
`netinet/ip_esp.h`, |
|||
`netinet/ip_ether.h`, |
|||
`netinet/ip_gre.h`, |
|||
`netinet/ip_ipcomp.h`, |
|||
`netinet/ip_ipip.h`, |
|||
`netinet/pim_var.h`, |
|||
`netinet/tcp_var.h`, |
|||
`netinet/udp_var.h`, |
|||
`netinet6/in6.h`, |
|||
`netinet6/ip6_divert.h`, |
|||
`netinet6/pim6_var.h`, |
|||
`netinet/icmp6.h`, |
|||
`netmpls/mpls.h`, |
|||
} |
|||
|
|||
ctls := [...]string{ |
|||
`kern`, |
|||
`vm`, |
|||
`fs`, |
|||
`net`, |
|||
//debug /* Special handling required */
|
|||
`hw`, |
|||
//machdep /* Arch specific */
|
|||
`user`, |
|||
`ddb`, |
|||
//vfs /* Special handling required */
|
|||
`fs.posix`, |
|||
`kern.forkstat`, |
|||
`kern.intrcnt`, |
|||
`kern.malloc`, |
|||
`kern.nchstats`, |
|||
`kern.seminfo`, |
|||
`kern.shminfo`, |
|||
`kern.timecounter`, |
|||
`kern.tty`, |
|||
`kern.watchdog`, |
|||
`net.bpf`, |
|||
`net.ifq`, |
|||
`net.inet`, |
|||
`net.inet.ah`, |
|||
`net.inet.carp`, |
|||
`net.inet.divert`, |
|||
`net.inet.esp`, |
|||
`net.inet.etherip`, |
|||
`net.inet.gre`, |
|||
`net.inet.icmp`, |
|||
`net.inet.igmp`, |
|||
`net.inet.ip`, |
|||
`net.inet.ip.ifq`, |
|||
`net.inet.ipcomp`, |
|||
`net.inet.ipip`, |
|||
`net.inet.mobileip`, |
|||
`net.inet.pfsync`, |
|||
`net.inet.pim`, |
|||
`net.inet.tcp`, |
|||
`net.inet.udp`, |
|||
`net.inet6`, |
|||
`net.inet6.divert`, |
|||
`net.inet6.ip6`, |
|||
`net.inet6.icmp6`, |
|||
`net.inet6.pim6`, |
|||
`net.inet6.tcp6`, |
|||
`net.inet6.udp6`, |
|||
`net.mpls`, |
|||
`net.mpls.ifq`, |
|||
`net.key`, |
|||
`net.pflow`, |
|||
`net.pfsync`, |
|||
`net.pipex`, |
|||
`net.rt`, |
|||
`vm.swapencrypt`, |
|||
//vfsgenctl /* Special handling required */
|
|||
} |
|||
|
|||
// Node name "fixups"
|
|||
ctlMap := map[string]string{ |
|||
"ipproto": "net.inet", |
|||
"net.inet.ipproto": "net.inet", |
|||
"net.inet6.ipv6proto": "net.inet6", |
|||
"net.inet6.ipv6": "net.inet6.ip6", |
|||
"net.inet.icmpv6": "net.inet6.icmp6", |
|||
"net.inet6.divert6": "net.inet6.divert", |
|||
"net.inet6.tcp6": "net.inet.tcp", |
|||
"net.inet6.udp6": "net.inet.udp", |
|||
"mpls": "net.mpls", |
|||
"swpenc": "vm.swapencrypt", |
|||
} |
|||
|
|||
// Node mappings
|
|||
nodeMap = map[string]string{ |
|||
"net.inet.ip.ifq": "net.ifq", |
|||
"net.inet.pfsync": "net.pfsync", |
|||
"net.mpls.ifq": "net.ifq", |
|||
} |
|||
|
|||
mCtls := make(map[string]bool) |
|||
for _, ctl := range ctls { |
|||
mCtls[ctl] = true |
|||
} |
|||
|
|||
for _, header := range headers { |
|||
debug("Processing " + header) |
|||
file, err := os.Open(filepath.Join("/usr/include", header)) |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, "%v\n", err) |
|||
os.Exit(1) |
|||
} |
|||
s := bufio.NewScanner(file) |
|||
for s.Scan() { |
|||
var sub []string |
|||
if reMatch(ctlNames1RE, s.Text(), &sub) || |
|||
reMatch(ctlNames2RE, s.Text(), &sub) || |
|||
reMatch(ctlNames3RE, s.Text(), &sub) { |
|||
if sub[1] == `CTL_NAMES` { |
|||
// Top level.
|
|||
node = &mib |
|||
} else { |
|||
// Node.
|
|||
nodename := strings.ToLower(sub[2]) |
|||
ctlName := "" |
|||
if reMatch(netInetRE, header, &sub) { |
|||
ctlName = "net.inet." + nodename |
|||
} else if reMatch(netInet6RE, header, &sub) { |
|||
ctlName = "net.inet6." + nodename |
|||
} else if reMatch(netRE, header, &sub) { |
|||
ctlName = "net." + nodename |
|||
} else { |
|||
ctlName = nodename |
|||
ctlName = fsNetKernRE.ReplaceAllString(ctlName, `$1.`) |
|||
} |
|||
|
|||
if val, ok := ctlMap[ctlName]; ok { |
|||
ctlName = val |
|||
} |
|||
if _, ok := mCtls[ctlName]; !ok { |
|||
debug("Ignoring " + ctlName + "...") |
|||
continue |
|||
} |
|||
|
|||
// Walk down from the top of the MIB.
|
|||
node = &mib |
|||
for _, part := range strings.Split(ctlName, ".") { |
|||
if _, ok := (*node)[part]; !ok { |
|||
debug("Missing node " + part) |
|||
(*node)[part] = nodeElement{n: 0, t: "", pE: &map[string]nodeElement{}} |
|||
} |
|||
node = (*node)[part].pE |
|||
} |
|||
} |
|||
|
|||
// Populate current node with entries.
|
|||
i := -1 |
|||
for !strings.HasPrefix(s.Text(), "}") { |
|||
s.Scan() |
|||
if reMatch(bracesRE, s.Text(), &sub) { |
|||
i++ |
|||
} |
|||
if !reMatch(ctlTypeRE, s.Text(), &sub) { |
|||
continue |
|||
} |
|||
(*node)[sub[1]] = nodeElement{n: i, t: sub[2], pE: &map[string]nodeElement{}} |
|||
} |
|||
} |
|||
} |
|||
err = s.Err() |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, "%v\n", err) |
|||
os.Exit(1) |
|||
} |
|||
file.Close() |
|||
} |
|||
buildSysctl(&mib, "", []int{}) |
|||
|
|||
sort.Strings(sysCtl) |
|||
text := strings.Join(sysCtl, "") |
|||
|
|||
fmt.Printf(srcTemplate, cmdLine(), buildTags(), text) |
|||
} |
|||
|
|||
const srcTemplate = `// %s
|
|||
// Code generated by the command above; DO NOT EDIT.
|
|||
|
|||
// +build %s
|
|||
|
|||
package unix |
|||
|
|||
type mibentry struct { |
|||
ctlname string |
|||
ctloid []_C_int |
|||
} |
|||
|
|||
var sysctlMib = []mibentry { |
|||
%s |
|||
} |
|||
` |
@ -1,265 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
|
|||
# Copyright 2011 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
|
|||
# |
|||
# Parse the header files for OpenBSD and generate a Go usable sysctl MIB. |
|||
# |
|||
# Build a MIB with each entry being an array containing the level, type and |
|||
# a hash that will contain additional entries if the current entry is a node. |
|||
# We then walk this MIB and create a flattened sysctl name to OID hash. |
|||
# |
|||
|
|||
use strict; |
|||
|
|||
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
|||
print STDERR "GOARCH or GOOS not defined in environment\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
my $debug = 0; |
|||
my %ctls = (); |
|||
|
|||
my @headers = qw ( |
|||
sys/sysctl.h |
|||
sys/socket.h |
|||
sys/tty.h |
|||
sys/malloc.h |
|||
sys/mount.h |
|||
sys/namei.h |
|||
sys/sem.h |
|||
sys/shm.h |
|||
sys/vmmeter.h |
|||
uvm/uvmexp.h |
|||
uvm/uvm_param.h |
|||
uvm/uvm_swap_encrypt.h |
|||
ddb/db_var.h |
|||
net/if.h |
|||
net/if_pfsync.h |
|||
net/pipex.h |
|||
netinet/in.h |
|||
netinet/icmp_var.h |
|||
netinet/igmp_var.h |
|||
netinet/ip_ah.h |
|||
netinet/ip_carp.h |
|||
netinet/ip_divert.h |
|||
netinet/ip_esp.h |
|||
netinet/ip_ether.h |
|||
netinet/ip_gre.h |
|||
netinet/ip_ipcomp.h |
|||
netinet/ip_ipip.h |
|||
netinet/pim_var.h |
|||
netinet/tcp_var.h |
|||
netinet/udp_var.h |
|||
netinet6/in6.h |
|||
netinet6/ip6_divert.h |
|||
netinet6/pim6_var.h |
|||
netinet/icmp6.h |
|||
netmpls/mpls.h |
|||
); |
|||
|
|||
my @ctls = qw ( |
|||
kern |
|||
vm |
|||
fs |
|||
net |
|||
#debug # Special handling required |
|||
hw |
|||
#machdep # Arch specific |
|||
user |
|||
ddb |
|||
#vfs # Special handling required |
|||
fs.posix |
|||
kern.forkstat |
|||
kern.intrcnt |
|||
kern.malloc |
|||
kern.nchstats |
|||
kern.seminfo |
|||
kern.shminfo |
|||
kern.timecounter |
|||
kern.tty |
|||
kern.watchdog |
|||
net.bpf |
|||
net.ifq |
|||
net.inet |
|||
net.inet.ah |
|||
net.inet.carp |
|||
net.inet.divert |
|||
net.inet.esp |
|||
net.inet.etherip |
|||
net.inet.gre |
|||
net.inet.icmp |
|||
net.inet.igmp |
|||
net.inet.ip |
|||
net.inet.ip.ifq |
|||
net.inet.ipcomp |
|||
net.inet.ipip |
|||
net.inet.mobileip |
|||
net.inet.pfsync |
|||
net.inet.pim |
|||
net.inet.tcp |
|||
net.inet.udp |
|||
net.inet6 |
|||
net.inet6.divert |
|||
net.inet6.ip6 |
|||
net.inet6.icmp6 |
|||
net.inet6.pim6 |
|||
net.inet6.tcp6 |
|||
net.inet6.udp6 |
|||
net.mpls |
|||
net.mpls.ifq |
|||
net.key |
|||
net.pflow |
|||
net.pfsync |
|||
net.pipex |
|||
net.rt |
|||
vm.swapencrypt |
|||
#vfsgenctl # Special handling required |
|||
); |
|||
|
|||
# Node name "fixups" |
|||
my %ctl_map = ( |
|||
"ipproto" => "net.inet", |
|||
"net.inet.ipproto" => "net.inet", |
|||
"net.inet6.ipv6proto" => "net.inet6", |
|||
"net.inet6.ipv6" => "net.inet6.ip6", |
|||
"net.inet.icmpv6" => "net.inet6.icmp6", |
|||
"net.inet6.divert6" => "net.inet6.divert", |
|||
"net.inet6.tcp6" => "net.inet.tcp", |
|||
"net.inet6.udp6" => "net.inet.udp", |
|||
"mpls" => "net.mpls", |
|||
"swpenc" => "vm.swapencrypt" |
|||
); |
|||
|
|||
# Node mappings |
|||
my %node_map = ( |
|||
"net.inet.ip.ifq" => "net.ifq", |
|||
"net.inet.pfsync" => "net.pfsync", |
|||
"net.mpls.ifq" => "net.ifq" |
|||
); |
|||
|
|||
my $ctlname; |
|||
my %mib = (); |
|||
my %sysctl = (); |
|||
my $node; |
|||
|
|||
sub debug() { |
|||
print STDERR "$_[0]\n" if $debug; |
|||
} |
|||
|
|||
# Walk the MIB and build a sysctl name to OID mapping. |
|||
sub build_sysctl() { |
|||
my ($node, $name, $oid) = @_; |
|||
my %node = %{$node}; |
|||
my @oid = @{$oid}; |
|||
|
|||
foreach my $key (sort keys %node) { |
|||
my @node = @{$node{$key}}; |
|||
my $nodename = $name.($name ne '' ? '.' : '').$key; |
|||
my @nodeoid = (@oid, $node[0]); |
|||
if ($node[1] eq 'CTLTYPE_NODE') { |
|||
if (exists $node_map{$nodename}) { |
|||
$node = \%mib; |
|||
$ctlname = $node_map{$nodename}; |
|||
foreach my $part (split /\./, $ctlname) { |
|||
$node = \%{@{$$node{$part}}[2]}; |
|||
} |
|||
} else { |
|||
$node = $node[2]; |
|||
} |
|||
&build_sysctl($node, $nodename, \@nodeoid); |
|||
} elsif ($node[1] ne '') { |
|||
$sysctl{$nodename} = \@nodeoid; |
|||
} |
|||
} |
|||
} |
|||
|
|||
foreach my $ctl (@ctls) { |
|||
$ctls{$ctl} = $ctl; |
|||
} |
|||
|
|||
# Build MIB |
|||
foreach my $header (@headers) { |
|||
&debug("Processing $header..."); |
|||
open HEADER, "/usr/include/$header" || |
|||
print STDERR "Failed to open $header\n"; |
|||
while (<HEADER>) { |
|||
if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ || |
|||
$_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ || |
|||
$_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) { |
|||
if ($1 eq 'CTL_NAMES') { |
|||
# Top level. |
|||
$node = \%mib; |
|||
} else { |
|||
# Node. |
|||
my $nodename = lc($2); |
|||
if ($header =~ /^netinet\//) { |
|||
$ctlname = "net.inet.$nodename"; |
|||
} elsif ($header =~ /^netinet6\//) { |
|||
$ctlname = "net.inet6.$nodename"; |
|||
} elsif ($header =~ /^net\//) { |
|||
$ctlname = "net.$nodename"; |
|||
} else { |
|||
$ctlname = "$nodename"; |
|||
$ctlname =~ s/^(fs|net|kern)_/$1\./; |
|||
} |
|||
if (exists $ctl_map{$ctlname}) { |
|||
$ctlname = $ctl_map{$ctlname}; |
|||
} |
|||
if (not exists $ctls{$ctlname}) { |
|||
&debug("Ignoring $ctlname..."); |
|||
next; |
|||
} |
|||
|
|||
# Walk down from the top of the MIB. |
|||
$node = \%mib; |
|||
foreach my $part (split /\./, $ctlname) { |
|||
if (not exists $$node{$part}) { |
|||
&debug("Missing node $part"); |
|||
$$node{$part} = [ 0, '', {} ]; |
|||
} |
|||
$node = \%{@{$$node{$part}}[2]}; |
|||
} |
|||
} |
|||
|
|||
# Populate current node with entries. |
|||
my $i = -1; |
|||
while (defined($_) && $_ !~ /^}/) { |
|||
$_ = <HEADER>; |
|||
$i++ if $_ =~ /{.*}/; |
|||
next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/; |
|||
$$node{$1} = [ $i, $2, {} ]; |
|||
} |
|||
} |
|||
} |
|||
close HEADER; |
|||
} |
|||
|
|||
&build_sysctl(\%mib, "", []); |
|||
|
|||
print <<EOF; |
|||
// mksysctl_openbsd.pl |
|||
// Code generated by the command above; DO NOT EDIT. |
|||
|
|||
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
|||
|
|||
package unix; |
|||
|
|||
type mibentry struct { |
|||
ctlname string |
|||
ctloid []_C_int |
|||
} |
|||
|
|||
var sysctlMib = []mibentry { |
|||
EOF |
|||
|
|||
foreach my $name (sort keys %sysctl) { |
|||
my @oid = @{$sysctl{$name}}; |
|||
print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n"; |
|||
} |
|||
|
|||
print <<EOF; |
|||
} |
|||
EOF |
@ -0,0 +1,190 @@ |
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build ignore
|
|||
|
|||
// Generate system call table for DragonFly, NetBSD,
|
|||
// FreeBSD, OpenBSD or Darwin from master list
|
|||
// (for example, /usr/src/sys/kern/syscalls.master or
|
|||
// sys/syscall.h).
|
|||
package main |
|||
|
|||
import ( |
|||
"bufio" |
|||
"fmt" |
|||
"io" |
|||
"io/ioutil" |
|||
"net/http" |
|||
"os" |
|||
"regexp" |
|||
"strings" |
|||
) |
|||
|
|||
var ( |
|||
goos, goarch string |
|||
) |
|||
|
|||
// cmdLine returns this programs's commandline arguments
|
|||
func cmdLine() string { |
|||
return "go run mksysnum.go " + strings.Join(os.Args[1:], " ") |
|||
} |
|||
|
|||
// buildTags returns build tags
|
|||
func buildTags() string { |
|||
return fmt.Sprintf("%s,%s", goarch, goos) |
|||
} |
|||
|
|||
func checkErr(err error) { |
|||
if err != nil { |
|||
fmt.Fprintf(os.Stderr, "%v\n", err) |
|||
os.Exit(1) |
|||
} |
|||
} |
|||
|
|||
// source string and substring slice for regexp
|
|||
type re struct { |
|||
str string // source string
|
|||
sub []string // matched sub-string
|
|||
} |
|||
|
|||
// Match performs regular expression match
|
|||
func (r *re) Match(exp string) bool { |
|||
r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str) |
|||
if r.sub != nil { |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
// fetchFile fetches a text file from URL
|
|||
func fetchFile(URL string) io.Reader { |
|||
resp, err := http.Get(URL) |
|||
checkErr(err) |
|||
defer resp.Body.Close() |
|||
body, err := ioutil.ReadAll(resp.Body) |
|||
checkErr(err) |
|||
return strings.NewReader(string(body)) |
|||
} |
|||
|
|||
// readFile reads a text file from path
|
|||
func readFile(path string) io.Reader { |
|||
file, err := os.Open(os.Args[1]) |
|||
checkErr(err) |
|||
return file |
|||
} |
|||
|
|||
func format(name, num, proto string) string { |
|||
name = strings.ToUpper(name) |
|||
// There are multiple entries for enosys and nosys, so comment them out.
|
|||
nm := re{str: name} |
|||
if nm.Match(`^SYS_E?NOSYS$`) { |
|||
name = fmt.Sprintf("// %s", name) |
|||
} |
|||
if name == `SYS_SYS_EXIT` { |
|||
name = `SYS_EXIT` |
|||
} |
|||
return fmt.Sprintf(" %s = %s; // %s\n", name, num, proto) |
|||
} |
|||
|
|||
func main() { |
|||
// Get the OS (using GOOS_TARGET if it exist)
|
|||
goos = os.Getenv("GOOS_TARGET") |
|||
if goos == "" { |
|||
goos = os.Getenv("GOOS") |
|||
} |
|||
// Get the architecture (using GOARCH_TARGET if it exists)
|
|||
goarch = os.Getenv("GOARCH_TARGET") |
|||
if goarch == "" { |
|||
goarch = os.Getenv("GOARCH") |
|||
} |
|||
// Check if GOOS and GOARCH environment variables are defined
|
|||
if goarch == "" || goos == "" { |
|||
fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n") |
|||
os.Exit(1) |
|||
} |
|||
|
|||
file := strings.TrimSpace(os.Args[1]) |
|||
var syscalls io.Reader |
|||
if strings.HasPrefix(file, "https://") || strings.HasPrefix(file, "http://") { |
|||
// Download syscalls.master file
|
|||
syscalls = fetchFile(file) |
|||
} else { |
|||
syscalls = readFile(file) |
|||
} |
|||
|
|||
var text, line string |
|||
s := bufio.NewScanner(syscalls) |
|||
for s.Scan() { |
|||
t := re{str: line} |
|||
if t.Match(`^(.*)\\$`) { |
|||
// Handle continuation
|
|||
line = t.sub[1] |
|||
line += strings.TrimLeft(s.Text(), " \t") |
|||
} else { |
|||
// New line
|
|||
line = s.Text() |
|||
} |
|||
t = re{str: line} |
|||
if t.Match(`\\$`) { |
|||
continue |
|||
} |
|||
t = re{str: line} |
|||
|
|||
switch goos { |
|||
case "dragonfly": |
|||
if t.Match(`^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$`) { |
|||
num, proto := t.sub[1], t.sub[2] |
|||
name := fmt.Sprintf("SYS_%s", t.sub[3]) |
|||
text += format(name, num, proto) |
|||
} |
|||
case "freebsd": |
|||
if t.Match(`^([0-9]+)\s+\S+\s+(?:(?:NO)?STD|COMPAT10)\s+({ \S+\s+(\w+).*)$`) { |
|||
num, proto := t.sub[1], t.sub[2] |
|||
name := fmt.Sprintf("SYS_%s", t.sub[3]) |
|||
text += format(name, num, proto) |
|||
} |
|||
case "openbsd": |
|||
if t.Match(`^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$`) { |
|||
num, proto, name := t.sub[1], t.sub[3], t.sub[4] |
|||
text += format(name, num, proto) |
|||
} |
|||
case "netbsd": |
|||
if t.Match(`^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$`) { |
|||
num, proto, compat := t.sub[1], t.sub[6], t.sub[8] |
|||
name := t.sub[7] + "_" + t.sub[9] |
|||
if t.sub[11] != "" { |
|||
name = t.sub[7] + "_" + t.sub[11] |
|||
} |
|||
name = strings.ToUpper(name) |
|||
if compat == "" || compat == "13" || compat == "30" || compat == "50" { |
|||
text += fmt.Sprintf(" %s = %s; // %s\n", name, num, proto) |
|||
} |
|||
} |
|||
case "darwin": |
|||
if t.Match(`^#define\s+SYS_(\w+)\s+([0-9]+)`) { |
|||
name, num := t.sub[1], t.sub[2] |
|||
name = strings.ToUpper(name) |
|||
text += fmt.Sprintf(" SYS_%s = %s;\n", name, num) |
|||
} |
|||
default: |
|||
fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos) |
|||
os.Exit(1) |
|||
|
|||
} |
|||
} |
|||
err := s.Err() |
|||
checkErr(err) |
|||
|
|||
fmt.Printf(template, cmdLine(), buildTags(), text) |
|||
} |
|||
|
|||
const template = `// %s
|
|||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
|||
|
|||
// +build %s
|
|||
|
|||
package unix |
|||
|
|||
const( |
|||
%s)` |
@ -1,39 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2009 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
# |
|||
# Generate system call table for Darwin from sys/syscall.h |
|||
|
|||
use strict; |
|||
|
|||
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
|||
print STDERR "GOARCH or GOOS not defined in environment\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
my $command = "mksysnum_darwin.pl " . join(' ', @ARGV); |
|||
|
|||
print <<EOF; |
|||
// $command |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
|||
|
|||
package unix |
|||
|
|||
const ( |
|||
EOF |
|||
|
|||
while(<>){ |
|||
if(/^#define\s+SYS_(\w+)\s+([0-9]+)/){ |
|||
my $name = $1; |
|||
my $num = $2; |
|||
$name =~ y/a-z/A-Z/; |
|||
print " SYS_$name = $num;" |
|||
} |
|||
} |
|||
|
|||
print <<EOF; |
|||
) |
|||
EOF |
@ -1,50 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2009 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
# |
|||
# Generate system call table for DragonFly from master list |
|||
# (for example, /usr/src/sys/kern/syscalls.master). |
|||
|
|||
use strict; |
|||
|
|||
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
|||
print STDERR "GOARCH or GOOS not defined in environment\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
my $command = "mksysnum_dragonfly.pl " . join(' ', @ARGV); |
|||
|
|||
print <<EOF; |
|||
// $command |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
|||
|
|||
package unix |
|||
|
|||
const ( |
|||
EOF |
|||
|
|||
while(<>){ |
|||
if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){ |
|||
my $num = $1; |
|||
my $proto = $2; |
|||
my $name = "SYS_$3"; |
|||
$name =~ y/a-z/A-Z/; |
|||
|
|||
# There are multiple entries for enosys and nosys, so comment them out. |
|||
if($name =~ /^SYS_E?NOSYS$/){ |
|||
$name = "// $name"; |
|||
} |
|||
if($name eq 'SYS_SYS_EXIT'){ |
|||
$name = 'SYS_EXIT'; |
|||
} |
|||
|
|||
print " $name = $num; // $proto\n"; |
|||
} |
|||
} |
|||
|
|||
print <<EOF; |
|||
) |
|||
EOF |
@ -1,50 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2009 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
# |
|||
# Generate system call table for FreeBSD from master list |
|||
# (for example, /usr/src/sys/kern/syscalls.master). |
|||
|
|||
use strict; |
|||
|
|||
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
|||
print STDERR "GOARCH or GOOS not defined in environment\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
my $command = "mksysnum_freebsd.pl " . join(' ', @ARGV); |
|||
|
|||
print <<EOF; |
|||
// $command |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
|||
|
|||
package unix |
|||
|
|||
const ( |
|||
EOF |
|||
|
|||
while(<>){ |
|||
if(/^([0-9]+)\s+\S+\s+(?:NO)?STD\s+({ \S+\s+(\w+).*)$/){ |
|||
my $num = $1; |
|||
my $proto = $2; |
|||
my $name = "SYS_$3"; |
|||
$name =~ y/a-z/A-Z/; |
|||
|
|||
# There are multiple entries for enosys and nosys, so comment them out. |
|||
if($name =~ /^SYS_E?NOSYS$/){ |
|||
$name = "// $name"; |
|||
} |
|||
if($name eq 'SYS_SYS_EXIT'){ |
|||
$name = 'SYS_EXIT'; |
|||
} |
|||
|
|||
print " $name = $num; // $proto\n"; |
|||
} |
|||
} |
|||
|
|||
print <<EOF; |
|||
) |
|||
EOF |
@ -1,58 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2009 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
# |
|||
# Generate system call table for OpenBSD from master list |
|||
# (for example, /usr/src/sys/kern/syscalls.master). |
|||
|
|||
use strict; |
|||
|
|||
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
|||
print STDERR "GOARCH or GOOS not defined in environment\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
my $command = "mksysnum_netbsd.pl " . join(' ', @ARGV); |
|||
|
|||
print <<EOF; |
|||
// $command |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
|||
|
|||
package unix |
|||
|
|||
const ( |
|||
EOF |
|||
|
|||
my $line = ''; |
|||
while(<>){ |
|||
if($line =~ /^(.*)\\$/) { |
|||
# Handle continuation |
|||
$line = $1; |
|||
$_ =~ s/^\s+//; |
|||
$line .= $_; |
|||
} else { |
|||
# New line |
|||
$line = $_; |
|||
} |
|||
next if $line =~ /\\$/; |
|||
if($line =~ /^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$/) { |
|||
my $num = $1; |
|||
my $proto = $6; |
|||
my $compat = $8; |
|||
my $name = "$7_$9"; |
|||
|
|||
$name = "$7_$11" if $11 ne ''; |
|||
$name =~ y/a-z/A-Z/; |
|||
|
|||
if($compat eq '' || $compat eq '13' || $compat eq '30' || $compat eq '50') { |
|||
print " $name = $num; // $proto\n"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
print <<EOF; |
|||
) |
|||
EOF |
@ -1,50 +0,0 @@ |
|||
#!/usr/bin/env perl |
|||
# Copyright 2009 The Go Authors. All rights reserved. |
|||
# Use of this source code is governed by a BSD-style |
|||
# license that can be found in the LICENSE file. |
|||
# |
|||
# Generate system call table for OpenBSD from master list |
|||
# (for example, /usr/src/sys/kern/syscalls.master). |
|||
|
|||
use strict; |
|||
|
|||
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
|||
print STDERR "GOARCH or GOOS not defined in environment\n"; |
|||
exit 1; |
|||
} |
|||
|
|||
my $command = "mksysnum_openbsd.pl " . join(' ', @ARGV); |
|||
|
|||
print <<EOF; |
|||
// $command |
|||
// Code generated by the command above; see README.md. DO NOT EDIT. |
|||
|
|||
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
|||
|
|||
package unix |
|||
|
|||
const ( |
|||
EOF |
|||
|
|||
while(<>){ |
|||
if(/^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$/){ |
|||
my $num = $1; |
|||
my $proto = $3; |
|||
my $name = $4; |
|||
$name =~ y/a-z/A-Z/; |
|||
|
|||
# There are multiple entries for enosys and nosys, so comment them out. |
|||
if($name =~ /^SYS_E?NOSYS$/){ |
|||
$name = "// $name"; |
|||
} |
|||
if($name eq 'SYS_SYS_EXIT'){ |
|||
$name = 'SYS_EXIT'; |
|||
} |
|||
|
|||
print " $name = $num; // $proto\n"; |
|||
} |
|||
} |
|||
|
|||
print <<EOF; |
|||
) |
|||
EOF |
@ -0,0 +1,12 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build aix dragonfly freebsd linux netbsd openbsd
|
|||
|
|||
package unix |
|||
|
|||
// ReadDirent reads directory entries from fd and writes them into buf.
|
|||
func ReadDirent(fd int, buf []byte) (n int, err error) { |
|||
return Getdents(fd, buf) |
|||
} |
@ -0,0 +1,19 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build darwin
|
|||
|
|||
package unix |
|||
|
|||
import "unsafe" |
|||
|
|||
// ReadDirent reads directory entries from fd and writes them into buf.
|
|||
func ReadDirent(fd int, buf []byte) (n int, err error) { |
|||
// Final argument is (basep *uintptr) and the syscall doesn't take nil.
|
|||
// 64 bits should be enough. (32 bits isn't even on 386). Since the
|
|||
// actual system call is getdirentries64, 64 is a good guess.
|
|||
// TODO(rsc): Can we use a single global basep for all calls?
|
|||
var base = (*uintptr)(unsafe.Pointer(new(uint64))) |
|||
return Getdirentries(fd, buf, base) |
|||
} |
@ -0,0 +1,31 @@ |
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build darwin,go1.12
|
|||
|
|||
package unix |
|||
|
|||
import "unsafe" |
|||
|
|||
// Implemented in the runtime package (runtime/sys_darwin.go)
|
|||
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) |
|||
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
|||
func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
|||
func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // 32-bit only
|
|||
func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) |
|||
func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
|||
|
|||
//go:linkname syscall_syscall syscall.syscall
|
|||
//go:linkname syscall_syscall6 syscall.syscall6
|
|||
//go:linkname syscall_syscall6X syscall.syscall6X
|
|||
//go:linkname syscall_syscall9 syscall.syscall9
|
|||
//go:linkname syscall_rawSyscall syscall.rawSyscall
|
|||
//go:linkname syscall_rawSyscall6 syscall.rawSyscall6
|
|||
|
|||
// Find the entry point for f. See comments in runtime/proc.go for the
|
|||
// function of the same name.
|
|||
//go:nosplit
|
|||
func funcPC(f func()) uintptr { |
|||
return **(**uintptr)(unsafe.Pointer(&f)) |
|||
} |
@ -0,0 +1,52 @@ |
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build arm64,freebsd
|
|||
|
|||
package unix |
|||
|
|||
import ( |
|||
"syscall" |
|||
"unsafe" |
|||
) |
|||
|
|||
func setTimespec(sec, nsec int64) Timespec { |
|||
return Timespec{Sec: sec, Nsec: nsec} |
|||
} |
|||
|
|||
func setTimeval(sec, usec int64) Timeval { |
|||
return Timeval{Sec: sec, Usec: usec} |
|||
} |
|||
|
|||
func SetKevent(k *Kevent_t, fd, mode, flags int) { |
|||
k.Ident = uint64(fd) |
|||
k.Filter = int16(mode) |
|||
k.Flags = uint16(flags) |
|||
} |
|||
|
|||
func (iov *Iovec) SetLen(length int) { |
|||
iov.Len = uint64(length) |
|||
} |
|||
|
|||
func (msghdr *Msghdr) SetControllen(length int) { |
|||
msghdr.Controllen = uint32(length) |
|||
} |
|||
|
|||
func (cmsg *Cmsghdr) SetLen(length int) { |
|||
cmsg.Len = uint32(length) |
|||
} |
|||
|
|||
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { |
|||
var writtenOut uint64 = 0 |
|||
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0) |
|||
|
|||
written = int(writtenOut) |
|||
|
|||
if e1 != 0 { |
|||
err = e1 |
|||
} |
|||
return |
|||
} |
|||
|
|||
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) |
@ -0,0 +1,33 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build arm64,netbsd
|
|||
|
|||
package unix |
|||
|
|||
func setTimespec(sec, nsec int64) Timespec { |
|||
return Timespec{Sec: sec, Nsec: nsec} |
|||
} |
|||
|
|||
func setTimeval(sec, usec int64) Timeval { |
|||
return Timeval{Sec: sec, Usec: int32(usec)} |
|||
} |
|||
|
|||
func SetKevent(k *Kevent_t, fd, mode, flags int) { |
|||
k.Ident = uint64(fd) |
|||
k.Filter = uint32(mode) |
|||
k.Flags = uint32(flags) |
|||
} |
|||
|
|||
func (iov *Iovec) SetLen(length int) { |
|||
iov.Len = uint64(length) |
|||
} |
|||
|
|||
func (msghdr *Msghdr) SetControllen(length int) { |
|||
msghdr.Controllen = uint32(length) |
|||
} |
|||
|
|||
func (cmsg *Cmsghdr) SetLen(length int) { |
|||
cmsg.Len = uint32(length) |
|||
} |
@ -0,0 +1,37 @@ |
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build arm64,openbsd
|
|||
|
|||
package unix |
|||
|
|||
func setTimespec(sec, nsec int64) Timespec { |
|||
return Timespec{Sec: sec, Nsec: nsec} |
|||
} |
|||
|
|||
func setTimeval(sec, usec int64) Timeval { |
|||
return Timeval{Sec: sec, Usec: usec} |
|||
} |
|||
|
|||
func SetKevent(k *Kevent_t, fd, mode, flags int) { |
|||
k.Ident = uint64(fd) |
|||
k.Filter = int16(mode) |
|||
k.Flags = uint16(flags) |
|||
} |
|||
|
|||
func (iov *Iovec) SetLen(length int) { |
|||
iov.Len = uint64(length) |
|||
} |
|||
|
|||
func (msghdr *Msghdr) SetControllen(length int) { |
|||
msghdr.Controllen = uint32(length) |
|||
} |
|||
|
|||
func (cmsg *Cmsghdr) SetLen(length int) { |
|||
cmsg.Len = uint32(length) |
|||
} |
|||
|
|||
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
|
|||
// of openbsd/amd64 the syscall is called sysctl instead of __sysctl.
|
|||
const SYS___SYSCTL = SYS_SYSCTL |
@ -0,0 +1,24 @@ |
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// +build linux
|
|||
// +build ppc64le ppc64
|
|||
// +build !gccgo
|
|||
|
|||
package unix |
|||
|
|||
import "syscall" |
|||
|
|||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
|||
return syscall.Syscall(trap, a1, a2, a3) |
|||
} |
|||
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
|||
return syscall.Syscall6(trap, a1, a2, a3, a4, a5, a6) |
|||
} |
|||
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
|||
return syscall.RawSyscall(trap, a1, a2, a3) |
|||
} |
|||
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
|||
return syscall.RawSyscall6(trap, a1, a2, a3, a4, a5, a6) |
|||
} |
@ -0,0 +1,42 @@ |
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
package unix |
|||
|
|||
import ( |
|||
"syscall" |
|||
"unsafe" |
|||
) |
|||
|
|||
// Unveil implements the unveil syscall.
|
|||
// For more information see unveil(2).
|
|||
// Note that the special case of blocking further
|
|||
// unveil calls is handled by UnveilBlock.
|
|||
func Unveil(path string, flags string) error { |
|||
pathPtr, err := syscall.BytePtrFromString(path) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
flagsPtr, err := syscall.BytePtrFromString(flags) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
_, _, e := syscall.Syscall(SYS_UNVEIL, uintptr(unsafe.Pointer(pathPtr)), uintptr(unsafe.Pointer(flagsPtr)), 0) |
|||
if e != 0 { |
|||
return e |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// UnveilBlock blocks future unveil calls.
|
|||
// For more information see unveil(2).
|
|||
func UnveilBlock() error { |
|||
// Both pointers must be nil.
|
|||
var pathUnsafe, flagsUnsafe unsafe.Pointer |
|||
_, _, e := syscall.Syscall(SYS_UNVEIL, uintptr(pathUnsafe), uintptr(flagsUnsafe), 0) |
|||
if e != 0 { |
|||
return e |
|||
} |
|||
return nil |
|||
} |
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue