.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / sys@v0.0.0-20210124154548-22da62e12c0c / unix / 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_darwin.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         goos := os.Getenv("GOOS_TARGET")
90         if goos == "" {
91                 goos = os.Getenv("GOOS")
92         }
93         if goos == "" {
94                 fmt.Fprintln(os.Stderr, "GOOS not defined in environment")
95                 os.Exit(1)
96         }
97
98         // Check that we are using the Docker-based build system if we should
99         if goos == "linux" {
100                 if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
101                         fmt.Fprintf(os.Stderr, "In the Docker-based build system, mksyscall should not be called directly.\n")
102                         fmt.Fprintf(os.Stderr, "See README.md\n")
103                         os.Exit(1)
104                 }
105         }
106
107         flag.Usage = usage
108         flag.Parse()
109         if len(flag.Args()) <= 0 {
110                 fmt.Fprintf(os.Stderr, "no files to parse provided\n")
111                 usage()
112         }
113
114         endianness := ""
115         if *b32 {
116                 endianness = "big-endian"
117         } else if *l32 {
118                 endianness = "little-endian"
119         }
120
121         libc := false
122         if goos == "darwin" {
123                 libc = true
124         }
125         trampolines := map[string]bool{}
126
127         text := ""
128         for _, path := range flag.Args() {
129                 file, err := os.Open(path)
130                 if err != nil {
131                         fmt.Fprintf(os.Stderr, err.Error())
132                         os.Exit(1)
133                 }
134                 s := bufio.NewScanner(file)
135                 for s.Scan() {
136                         t := s.Text()
137                         t = strings.TrimSpace(t)
138                         t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `)
139                         nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t)
140                         if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil {
141                                 continue
142                         }
143
144                         // Line must be of the form
145                         //      func Open(path string, mode int, perm int) (fd int, errno error)
146                         // Split into name, in params, out params.
147                         f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$`).FindStringSubmatch(t)
148                         if f == nil {
149                                 fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t)
150                                 os.Exit(1)
151                         }
152                         funct, inps, outps, sysname := f[2], f[3], f[4], f[5]
153
154                         // Split argument lists on comma.
155                         in := parseParamList(inps)
156                         out := parseParamList(outps)
157
158                         // Try in vain to keep people from editing this file.
159                         // The theory is that they jump into the middle of the file
160                         // without reading the header.
161                         text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"
162
163                         // Go function header.
164                         outDecl := ""
165                         if len(out) > 0 {
166                                 outDecl = fmt.Sprintf(" (%s)", strings.Join(out, ", "))
167                         }
168                         text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outDecl)
169
170                         // Check if err return available
171                         errvar := ""
172                         for _, param := range out {
173                                 p := parseParam(param)
174                                 if p.Type == "error" {
175                                         errvar = p.Name
176                                         break
177                                 }
178                         }
179
180                         // Prepare arguments to Syscall.
181                         var args []string
182                         n := 0
183                         for _, param := range in {
184                                 p := parseParam(param)
185                                 if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil {
186                                         args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))")
187                                 } else if p.Type == "string" && errvar != "" {
188                                         text += fmt.Sprintf("\tvar _p%d *byte\n", n)
189                                         text += fmt.Sprintf("\t_p%d, %s = BytePtrFromString(%s)\n", n, errvar, p.Name)
190                                         text += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar)
191                                         args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n))
192                                         n++
193                                 } else if p.Type == "string" {
194                                         fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n")
195                                         text += fmt.Sprintf("\tvar _p%d *byte\n", n)
196                                         text += fmt.Sprintf("\t_p%d, _ = BytePtrFromString(%s)\n", n, p.Name)
197                                         args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n))
198                                         n++
199                                 } else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil {
200                                         // Convert slice into pointer, length.
201                                         // Have to be careful not to take address of &a[0] if len == 0:
202                                         // pass dummy pointer in that case.
203                                         // Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
204                                         text += fmt.Sprintf("\tvar _p%d unsafe.Pointer\n", n)
205                                         text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = unsafe.Pointer(&%s[0])\n\t}", p.Name, n, p.Name)
206                                         text += fmt.Sprintf(" else {\n\t\t_p%d = unsafe.Pointer(&_zero)\n\t}\n", n)
207                                         args = append(args, fmt.Sprintf("uintptr(_p%d)", n), fmt.Sprintf("uintptr(len(%s))", p.Name))
208                                         n++
209                                 } else if p.Type == "int64" && (*openbsd || *netbsd) {
210                                         args = append(args, "0")
211                                         if endianness == "big-endian" {
212                                                 args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
213                                         } else if endianness == "little-endian" {
214                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
215                                         } else {
216                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
217                                         }
218                                 } else if p.Type == "int64" && *dragonfly {
219                                         if regexp.MustCompile(`^(?i)extp(read|write)`).FindStringSubmatch(funct) == nil {
220                                                 args = append(args, "0")
221                                         }
222                                         if endianness == "big-endian" {
223                                                 args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
224                                         } else if endianness == "little-endian" {
225                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
226                                         } else {
227                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
228                                         }
229                                 } else if (p.Type == "int64" || p.Type == "uint64") && endianness != "" {
230                                         if len(args)%2 == 1 && *arm {
231                                                 // arm abi specifies 64-bit argument uses
232                                                 // (even, odd) pair
233                                                 args = append(args, "0")
234                                         }
235                                         if endianness == "big-endian" {
236                                                 args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
237                                         } else {
238                                                 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
239                                         }
240                                 } else {
241                                         args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
242                                 }
243                         }
244
245                         // Determine which form to use; pad args with zeros.
246                         asm := "Syscall"
247                         if nonblock != nil {
248                                 if errvar == "" && goos == "linux" {
249                                         asm = "RawSyscallNoError"
250                                 } else {
251                                         asm = "RawSyscall"
252                                 }
253                         } else {
254                                 if errvar == "" && goos == "linux" {
255                                         asm = "SyscallNoError"
256                                 }
257                         }
258                         if len(args) <= 3 {
259                                 for len(args) < 3 {
260                                         args = append(args, "0")
261                                 }
262                         } else if len(args) <= 6 {
263                                 asm += "6"
264                                 for len(args) < 6 {
265                                         args = append(args, "0")
266                                 }
267                         } else if len(args) <= 9 {
268                                 asm += "9"
269                                 for len(args) < 9 {
270                                         args = append(args, "0")
271                                 }
272                         } else {
273                                 fmt.Fprintf(os.Stderr, "%s:%s too many arguments to system call\n", path, funct)
274                         }
275
276                         // System call number.
277                         if sysname == "" {
278                                 sysname = "SYS_" + funct
279                                 sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`)
280                                 sysname = strings.ToUpper(sysname)
281                         }
282
283                         var libcFn string
284                         if libc {
285                                 asm = "syscall_" + strings.ToLower(asm[:1]) + asm[1:] // internal syscall call
286                                 sysname = strings.TrimPrefix(sysname, "SYS_")         // remove SYS_
287                                 sysname = strings.ToLower(sysname)                    // lowercase
288                                 libcFn = sysname
289                                 sysname = "funcPC(libc_" + sysname + "_trampoline)"
290                         }
291
292                         // Actual call.
293                         arglist := strings.Join(args, ", ")
294                         call := fmt.Sprintf("%s(%s, %s)", asm, sysname, arglist)
295
296                         // Assign return values.
297                         body := ""
298                         ret := []string{"_", "_", "_"}
299                         doErrno := false
300                         for i := 0; i < len(out); i++ {
301                                 p := parseParam(out[i])
302                                 reg := ""
303                                 if p.Name == "err" && !*plan9 {
304                                         reg = "e1"
305                                         ret[2] = reg
306                                         doErrno = true
307                                 } else if p.Name == "err" && *plan9 {
308                                         ret[0] = "r0"
309                                         ret[2] = "e1"
310                                         break
311                                 } else {
312                                         reg = fmt.Sprintf("r%d", i)
313                                         ret[i] = reg
314                                 }
315                                 if p.Type == "bool" {
316                                         reg = fmt.Sprintf("%s != 0", reg)
317                                 }
318                                 if p.Type == "int64" && endianness != "" {
319                                         // 64-bit number in r1:r0 or r0:r1.
320                                         if i+2 > len(out) {
321                                                 fmt.Fprintf(os.Stderr, "%s:%s not enough registers for int64 return\n", path, funct)
322                                         }
323                                         if endianness == "big-endian" {
324                                                 reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i, i+1)
325                                         } else {
326                                                 reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i+1, i)
327                                         }
328                                         ret[i] = fmt.Sprintf("r%d", i)
329                                         ret[i+1] = fmt.Sprintf("r%d", i+1)
330                                 }
331                                 if reg != "e1" || *plan9 {
332                                         body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg)
333                                 }
334                         }
335                         if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" {
336                                 text += fmt.Sprintf("\t%s\n", call)
337                         } else {
338                                 if errvar == "" && goos == "linux" {
339                                         // raw syscall without error on Linux, see golang.org/issue/22924
340                                         text += fmt.Sprintf("\t%s, %s := %s\n", ret[0], ret[1], call)
341                                 } else {
342                                         text += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call)
343                                 }
344                         }
345                         text += body
346
347                         if *plan9 && ret[2] == "e1" {
348                                 text += "\tif int32(r0) == -1 {\n"
349                                 text += "\t\terr = e1\n"
350                                 text += "\t}\n"
351                         } else if doErrno {
352                                 text += "\tif e1 != 0 {\n"
353                                 text += "\t\terr = errnoErr(e1)\n"
354                                 text += "\t}\n"
355                         }
356                         text += "\treturn\n"
357                         text += "}\n\n"
358
359                         if libc && !trampolines[libcFn] {
360                                 // some system calls share a trampoline, like read and readlen.
361                                 trampolines[libcFn] = true
362                                 // Declare assembly trampoline.
363                                 text += fmt.Sprintf("func libc_%s_trampoline()\n", libcFn)
364                                 // Assembly trampoline calls the libc_* function, which this magic
365                                 // redirects to use the function from libSystem.
366                                 text += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"/usr/lib/libSystem.B.dylib\"\n", libcFn, libcFn)
367                                 text += "\n"
368                         }
369                 }
370                 if err := s.Err(); err != nil {
371                         fmt.Fprintf(os.Stderr, err.Error())
372                         os.Exit(1)
373                 }
374                 file.Close()
375         }
376         fmt.Printf(srcTemplate, cmdLine(), buildTags(), text)
377 }
378
379 const srcTemplate = `// %s
380 // Code generated by the command above; see README.md. DO NOT EDIT.
381
382 // +build %s
383
384 package unix
385
386 import (
387         "syscall"
388         "unsafe"
389 )
390
391 var _ syscall.Errno
392
393 %s
394 `