.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / sys@v0.0.0-20210124154548-22da62e12c0c / plan9 / mksyscall.go
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // +build ignore
6
7 /*
8 This program reads a file containing function prototypes
9 (like syscall_plan9.go) and generates system call bodies.
10 The prototypes are marked by lines beginning with "//sys"
11 and read like func declarations if //sys is replaced by func, but:
12         * The parameter lists must give a name for each argument.
13           This includes return parameters.
14         * The parameter lists must give a type for each argument:
15           the (x, y, z int) shorthand is not allowed.
16         * If the return parameter is an error number, it must be named errno.
17
18 A line beginning with //sysnb is like //sys, except that the
19 goroutine will not be suspended during the execution of the system
20 call.  This must only be used for system calls which can never
21 block, as otherwise the system call could cause all goroutines to
22 hang.
23 */
24 package main
25
26 import (
27         "bufio"
28         "flag"
29         "fmt"
30         "os"
31         "regexp"
32         "strings"
33 )
34
35 var (
36         b32       = flag.Bool("b32", false, "32bit big-endian")
37         l32       = flag.Bool("l32", false, "32bit little-endian")
38         plan9     = flag.Bool("plan9", false, "plan9")
39         openbsd   = flag.Bool("openbsd", false, "openbsd")
40         netbsd    = flag.Bool("netbsd", false, "netbsd")
41         dragonfly = flag.Bool("dragonfly", false, "dragonfly")
42         arm       = flag.Bool("arm", false, "arm") // 64-bit value should use (even, odd)-pair
43         tags      = flag.String("tags", "", "build tags")
44         filename  = flag.String("output", "", "output file name (standard output if omitted)")
45 )
46
47 // cmdLine returns this programs's commandline arguments
48 func cmdLine() string {
49         return "go run mksyscall.go " + strings.Join(os.Args[1:], " ")
50 }
51
52 // buildTags returns build tags
53 func buildTags() string {
54         return *tags
55 }
56
57 // Param is function parameter
58 type Param struct {
59         Name string
60         Type string
61 }
62
63 // usage prints the program usage
64 func usage() {
65         fmt.Fprintf(os.Stderr, "usage: go run mksyscall.go [-b32 | -l32] [-tags x,y] [file ...]\n")
66         os.Exit(1)
67 }
68
69 // parseParamList parses parameter list and returns a slice of parameters
70 func parseParamList(list string) []string {
71         list = strings.TrimSpace(list)
72         if list == "" {
73                 return []string{}
74         }
75         return regexp.MustCompile(`\s*,\s*`).Split(list, -1)
76 }
77
78 // parseParam splits a parameter into name and type
79 func parseParam(p string) Param {
80         ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p)
81         if ps == nil {
82                 fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p)
83                 os.Exit(1)
84         }
85         return Param{ps[1], ps[2]}
86 }
87
88 func main() {
89         // Get the OS and architecture (using GOARCH_TARGET if it exists)
90         goos := os.Getenv("GOOS")
91         goarch := os.Getenv("GOARCH_TARGET")
92         if goarch == "" {
93                 goarch = os.Getenv("GOARCH")
94         }
95
96         // Check that we are using the Docker-based build system if we should
97         if goos == "linux" {
98                 if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
99                         fmt.Fprintf(os.Stderr, "In the Docker-based build system, mksyscall should not be called directly.\n")
100                         fmt.Fprintf(os.Stderr, "See README.md\n")
101                         os.Exit(1)
102                 }
103         }
104
105         flag.Usage = usage
106         flag.Parse()
107         if len(flag.Args()) <= 0 {
108                 fmt.Fprintf(os.Stderr, "no files to parse provided\n")
109                 usage()
110         }
111
112         endianness := ""
113         if *b32 {
114                 endianness = "big-endian"
115         } else if *l32 {
116                 endianness = "little-endian"
117         }
118
119         libc := false
120         if goos == "darwin" && strings.Contains(buildTags(), ",go1.12") {
121                 libc = true
122         }
123         trampolines := map[string]bool{}
124
125         text := ""
126         for _, path := range flag.Args() {
127                 file, err := os.Open(path)
128                 if err != nil {
129                         fmt.Fprintf(os.Stderr, err.Error())
130                         os.Exit(1)
131                 }
132                 s := bufio.NewScanner(file)
133                 for s.Scan() {
134                         t := s.Text()
135                         t = strings.TrimSpace(t)
136                         t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `)
137                         nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t)
138                         if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil {
139                                 continue
140                         }
141
142                         // Line must be of the form
143                         //      func Open(path string, mode int, perm int) (fd int, errno error)
144                         // Split into name, in params, out params.
145                         f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$`).FindStringSubmatch(t)
146                         if f == nil {
147                                 fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t)
148                                 os.Exit(1)
149                         }
150                         funct, inps, outps, sysname := f[2], f[3], f[4], f[5]
151
152                         // Split argument lists on comma.
153                         in := parseParamList(inps)
154                         out := parseParamList(outps)
155
156                         // Try in vain to keep people from editing this file.
157                         // The theory is that they jump into the middle of the file
158                         // without reading the header.
159                         text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"
160
161                         // Go function header.
162                         outDecl := ""
163                         if len(out) > 0 {
164                                 outDecl = fmt.Sprintf(" (%s)", strings.Join(out, ", "))
165                         }
166                         text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outDecl)
167
168                         // Check if err return available
169                         errvar := ""
170                         for _, param := range out {
171                                 p := parseParam(param)
172                                 if p.Type == "error" {
173                                         errvar = p.Name
174                                         break
175                                 }
176                         }
177
178                         // Prepare arguments to Syscall.
179                         var args []string
180                         n := 0
181                         for _, param := range in {
182                                 p := parseParam(param)
183                                 if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil {
184                                         args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))")
185                                 } else if p.Type == "string" && errvar != "" {
186                                         text += fmt.Sprintf("\tvar _p%d *byte\n", n)
187                                         text += fmt.Sprintf("\t_p%d, %s = BytePtrFromString(%s)\n", n, errvar, p.Name)
188                                         text += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar)
189                                         args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n))
190                                         n++
191                                 } else if p.Type == "string" {
192                                         fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n")
193                                         text += fmt.Sprintf("\tvar _p%d *byte\n", n)
194                                         text += fmt.Sprintf("\t_p%d, _ = BytePtrFromString(%s)\n", n, p.Name)
195                                         args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n))
196                                         n++
197                                 } else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil {
198                                         // Convert slice into pointer, length.
199                                         // Have to be careful not to take address of &a[0] if len == 0:
200                                         // pass dummy pointer in that case.
201                                         // Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
202                                         text += fmt.Sprintf("\tvar _p%d unsafe.Pointer\n", n)
203                                         text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = unsafe.Pointer(&%s[0])\n\t}", p.Name, n, p.Name)
204                                         text += fmt.Sprintf(" else {\n\t\t_p%d = unsafe.Pointer(&_zero)\n\t}\n", n)
205                                         args = append(args, fmt.Sprintf("uintptr(_p%d)", n), fmt.Sprintf("uintptr(len(%s))", p.Name))
206                                         n++
207                                 } else if p.Type == "int64" && (*openbsd || *netbsd) {
208                                         args = append(args, "0")
209                                         if endianness == "big-endian" {
210                                                 args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
211                                         } else if endianness == "little-endian" {
212                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
213                                         } else {
214                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
215                                         }
216                                 } else if p.Type == "int64" && *dragonfly {
217                                         if regexp.MustCompile(`^(?i)extp(read|write)`).FindStringSubmatch(funct) == nil {
218                                                 args = append(args, "0")
219                                         }
220                                         if endianness == "big-endian" {
221                                                 args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
222                                         } else if endianness == "little-endian" {
223                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
224                                         } else {
225                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
226                                         }
227                                 } else if p.Type == "int64" && endianness != "" {
228                                         if len(args)%2 == 1 && *arm {
229                                                 // arm abi specifies 64-bit argument uses
230                                                 // (even, odd) pair
231                                                 args = append(args, "0")
232                                         }
233                                         if endianness == "big-endian" {
234                                                 args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
235                                         } else {
236                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
237                                         }
238                                 } else {
239                                         args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
240                                 }
241                         }
242
243                         // Determine which form to use; pad args with zeros.
244                         asm := "Syscall"
245                         if nonblock != nil {
246                                 if errvar == "" && goos == "linux" {
247                                         asm = "RawSyscallNoError"
248                                 } else {
249                                         asm = "RawSyscall"
250                                 }
251                         } else {
252                                 if errvar == "" && goos == "linux" {
253                                         asm = "SyscallNoError"
254                                 }
255                         }
256                         if len(args) <= 3 {
257                                 for len(args) < 3 {
258                                         args = append(args, "0")
259                                 }
260                         } else if len(args) <= 6 {
261                                 asm += "6"
262                                 for len(args) < 6 {
263                                         args = append(args, "0")
264                                 }
265                         } else if len(args) <= 9 {
266                                 asm += "9"
267                                 for len(args) < 9 {
268                                         args = append(args, "0")
269                                 }
270                         } else {
271                                 fmt.Fprintf(os.Stderr, "%s:%s too many arguments to system call\n", path, funct)
272                         }
273
274                         // System call number.
275                         if sysname == "" {
276                                 sysname = "SYS_" + funct
277                                 sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`)
278                                 sysname = strings.ToUpper(sysname)
279                         }
280
281                         var libcFn string
282                         if libc {
283                                 asm = "syscall_" + strings.ToLower(asm[:1]) + asm[1:] // internal syscall call
284                                 sysname = strings.TrimPrefix(sysname, "SYS_")         // remove SYS_
285                                 sysname = strings.ToLower(sysname)                    // lowercase
286                                 if sysname == "getdirentries64" {
287                                         // Special case - libSystem name and
288                                         // raw syscall name don't match.
289                                         sysname = "__getdirentries64"
290                                 }
291                                 libcFn = sysname
292                                 sysname = "funcPC(libc_" + sysname + "_trampoline)"
293                         }
294
295                         // Actual call.
296                         arglist := strings.Join(args, ", ")
297                         call := fmt.Sprintf("%s(%s, %s)", asm, sysname, arglist)
298
299                         // Assign return values.
300                         body := ""
301                         ret := []string{"_", "_", "_"}
302                         doErrno := false
303                         for i := 0; i < len(out); i++ {
304                                 p := parseParam(out[i])
305                                 reg := ""
306                                 if p.Name == "err" && !*plan9 {
307                                         reg = "e1"
308                                         ret[2] = reg
309                                         doErrno = true
310                                 } else if p.Name == "err" && *plan9 {
311                                         ret[0] = "r0"
312                                         ret[2] = "e1"
313                                         break
314                                 } else {
315                                         reg = fmt.Sprintf("r%d", i)
316                                         ret[i] = reg
317                                 }
318                                 if p.Type == "bool" {
319                                         reg = fmt.Sprintf("%s != 0", reg)
320                                 }
321                                 if p.Type == "int64" && endianness != "" {
322                                         // 64-bit number in r1:r0 or r0:r1.
323                                         if i+2 > len(out) {
324                                                 fmt.Fprintf(os.Stderr, "%s:%s not enough registers for int64 return\n", path, funct)
325                                         }
326                                         if endianness == "big-endian" {
327                                                 reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i, i+1)
328                                         } else {
329                                                 reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i+1, i)
330                                         }
331                                         ret[i] = fmt.Sprintf("r%d", i)
332                                         ret[i+1] = fmt.Sprintf("r%d", i+1)
333                                 }
334                                 if reg != "e1" || *plan9 {
335                                         body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg)
336                                 }
337                         }
338                         if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" {
339                                 text += fmt.Sprintf("\t%s\n", call)
340                         } else {
341                                 if errvar == "" && goos == "linux" {
342                                         // raw syscall without error on Linux, see golang.org/issue/22924
343                                         text += fmt.Sprintf("\t%s, %s := %s\n", ret[0], ret[1], call)
344                                 } else {
345                                         text += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call)
346                                 }
347                         }
348                         text += body
349
350                         if *plan9 && ret[2] == "e1" {
351                                 text += "\tif int32(r0) == -1 {\n"
352                                 text += "\t\terr = e1\n"
353                                 text += "\t}\n"
354                         } else if doErrno {
355                                 text += "\tif e1 != 0 {\n"
356                                 text += "\t\terr = errnoErr(e1)\n"
357                                 text += "\t}\n"
358                         }
359                         text += "\treturn\n"
360                         text += "}\n\n"
361
362                         if libc && !trampolines[libcFn] {
363                                 // some system calls share a trampoline, like read and readlen.
364                                 trampolines[libcFn] = true
365                                 // Declare assembly trampoline.
366                                 text += fmt.Sprintf("func libc_%s_trampoline()\n", libcFn)
367                                 // Assembly trampoline calls the libc_* function, which this magic
368                                 // redirects to use the function from libSystem.
369                                 text += fmt.Sprintf("//go:linkname libc_%s libc_%s\n", libcFn, libcFn)
370                                 text += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"/usr/lib/libSystem.B.dylib\"\n", libcFn, libcFn)
371                                 text += "\n"
372                         }
373                 }
374                 if err := s.Err(); err != nil {
375                         fmt.Fprintf(os.Stderr, err.Error())
376                         os.Exit(1)
377                 }
378                 file.Close()
379         }
380         fmt.Printf(srcTemplate, cmdLine(), buildTags(), text)
381 }
382
383 const srcTemplate = `// %s
384 // Code generated by the command above; see README.md. DO NOT EDIT.
385
386 // +build %s
387
388 package plan9
389
390 import "unsafe"
391
392 %s
393 `