github.com/etecs-ru/go-sys-wineventlog@v0.0.0-20210227233244-4c3abb794018/unix/mksyscall_aix_ppc.go (about)

     1  // Copyright 2019 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  //go:build ignore
     6  // +build ignore
     7  
     8  /*
     9  This program reads a file containing function prototypes
    10  (like syscall_aix.go) and generates system call bodies.
    11  The prototypes are marked by lines beginning with "//sys"
    12  and read like func declarations if //sys is replaced by func, but:
    13  	* The parameter lists must give a name for each argument.
    14  	  This includes return parameters.
    15  	* The parameter lists must give a type for each argument:
    16  	  the (x, y, z int) shorthand is not allowed.
    17  	* If the return parameter is an error number, it must be named err.
    18  	* If go func name needs to be different than its libc name,
    19  	* or the function is not in libc, name could be specified
    20  	* at the end, after "=" sign, like
    21  	  //sys	getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
    22  */
    23  package main
    24  
    25  import (
    26  	"bufio"
    27  	"flag"
    28  	"fmt"
    29  	"os"
    30  	"regexp"
    31  	"strings"
    32  )
    33  
    34  var (
    35  	b32  = flag.Bool("b32", false, "32bit big-endian")
    36  	l32  = flag.Bool("l32", false, "32bit little-endian")
    37  	aix  = flag.Bool("aix", false, "aix")
    38  	tags = flag.String("tags", "", "build tags")
    39  )
    40  
    41  // cmdLine returns this programs's commandline arguments
    42  func cmdLine() string {
    43  	return "go run mksyscall_aix_ppc.go " + strings.Join(os.Args[1:], " ")
    44  }
    45  
    46  // buildTags returns build tags
    47  func buildTags() string {
    48  	return *tags
    49  }
    50  
    51  // Param is function parameter
    52  type Param struct {
    53  	Name string
    54  	Type string
    55  }
    56  
    57  // usage prints the program usage
    58  func usage() {
    59  	fmt.Fprintf(os.Stderr, "usage: go run mksyscall_aix_ppc.go [-b32 | -l32] [-tags x,y] [file ...]\n")
    60  	os.Exit(1)
    61  }
    62  
    63  // parseParamList parses parameter list and returns a slice of parameters
    64  func parseParamList(list string) []string {
    65  	list = strings.TrimSpace(list)
    66  	if list == "" {
    67  		return []string{}
    68  	}
    69  	return regexp.MustCompile(`\s*,\s*`).Split(list, -1)
    70  }
    71  
    72  // parseParam splits a parameter into name and type
    73  func parseParam(p string) Param {
    74  	ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p)
    75  	if ps == nil {
    76  		fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p)
    77  		os.Exit(1)
    78  	}
    79  	return Param{ps[1], ps[2]}
    80  }
    81  
    82  func main() {
    83  	flag.Usage = usage
    84  	flag.Parse()
    85  	if len(flag.Args()) <= 0 {
    86  		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
    87  		usage()
    88  	}
    89  
    90  	endianness := ""
    91  	if *b32 {
    92  		endianness = "big-endian"
    93  	} else if *l32 {
    94  		endianness = "little-endian"
    95  	}
    96  
    97  	pack := ""
    98  	text := ""
    99  	cExtern := "/*\n#include <stdint.h>\n#include <stddef.h>\n"
   100  	for _, path := range flag.Args() {
   101  		file, err := os.Open(path)
   102  		if err != nil {
   103  			fmt.Fprintf(os.Stderr, err.Error())
   104  			os.Exit(1)
   105  		}
   106  		s := bufio.NewScanner(file)
   107  		for s.Scan() {
   108  			t := s.Text()
   109  			if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" {
   110  				pack = p[1]
   111  			}
   112  			nonblock := regexp.MustCompile(`^\/\/sysnb\t`).FindStringSubmatch(t)
   113  			if regexp.MustCompile(`^\/\/sys\t`).FindStringSubmatch(t) == nil && nonblock == nil {
   114  				continue
   115  			}
   116  
   117  			// Line must be of the form
   118  			//	func Open(path string, mode int, perm int) (fd int, err error)
   119  			// Split into name, in params, out params.
   120  			f := regexp.MustCompile(`^\/\/sys(nb)?\t(\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t)
   121  			if f == nil {
   122  				fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t)
   123  				os.Exit(1)
   124  			}
   125  			funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6]
   126  
   127  			// Split argument lists on comma.
   128  			in := parseParamList(inps)
   129  			out := parseParamList(outps)
   130  
   131  			inps = strings.Join(in, ", ")
   132  			outps = strings.Join(out, ", ")
   133  
   134  			// Try in vain to keep people from editing this file.
   135  			// The theory is that they jump into the middle of the file
   136  			// without reading the header.
   137  			text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"
   138  
   139  			// Check if value return, err return available
   140  			errvar := ""
   141  			retvar := ""
   142  			rettype := ""
   143  			for _, param := range out {
   144  				p := parseParam(param)
   145  				if p.Type == "error" {
   146  					errvar = p.Name
   147  				} else {
   148  					retvar = p.Name
   149  					rettype = p.Type
   150  				}
   151  			}
   152  
   153  			// System call name.
   154  			if sysname == "" {
   155  				sysname = funct
   156  			}
   157  			sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`)
   158  			sysname = strings.ToLower(sysname) // All libc functions are lowercase.
   159  
   160  			cRettype := ""
   161  			if rettype == "unsafe.Pointer" {
   162  				cRettype = "uintptr_t"
   163  			} else if rettype == "uintptr" {
   164  				cRettype = "uintptr_t"
   165  			} else if regexp.MustCompile(`^_`).FindStringSubmatch(rettype) != nil {
   166  				cRettype = "uintptr_t"
   167  			} else if rettype == "int" {
   168  				cRettype = "int"
   169  			} else if rettype == "int32" {
   170  				cRettype = "int"
   171  			} else if rettype == "int64" {
   172  				cRettype = "long long"
   173  			} else if rettype == "uint32" {
   174  				cRettype = "unsigned int"
   175  			} else if rettype == "uint64" {
   176  				cRettype = "unsigned long long"
   177  			} else {
   178  				cRettype = "int"
   179  			}
   180  			if sysname == "exit" {
   181  				cRettype = "void"
   182  			}
   183  
   184  			// Change p.Types to c
   185  			var cIn []string
   186  			for _, param := range in {
   187  				p := parseParam(param)
   188  				if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil {
   189  					cIn = append(cIn, "uintptr_t")
   190  				} else if p.Type == "string" {
   191  					cIn = append(cIn, "uintptr_t")
   192  				} else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil {
   193  					cIn = append(cIn, "uintptr_t", "size_t")
   194  				} else if p.Type == "unsafe.Pointer" {
   195  					cIn = append(cIn, "uintptr_t")
   196  				} else if p.Type == "uintptr" {
   197  					cIn = append(cIn, "uintptr_t")
   198  				} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil {
   199  					cIn = append(cIn, "uintptr_t")
   200  				} else if p.Type == "int" {
   201  					cIn = append(cIn, "int")
   202  				} else if p.Type == "int32" {
   203  					cIn = append(cIn, "int")
   204  				} else if p.Type == "int64" {
   205  					cIn = append(cIn, "long long")
   206  				} else if p.Type == "uint32" {
   207  					cIn = append(cIn, "unsigned int")
   208  				} else if p.Type == "uint64" {
   209  					cIn = append(cIn, "unsigned long long")
   210  				} else {
   211  					cIn = append(cIn, "int")
   212  				}
   213  			}
   214  
   215  			if funct != "fcntl" && funct != "FcntlInt" && funct != "readlen" && funct != "writelen" {
   216  				if sysname == "select" {
   217  					// select is a keyword of Go. Its name is
   218  					// changed to c_select.
   219  					cExtern += "#define c_select select\n"
   220  				}
   221  				// Imports of system calls from libc
   222  				cExtern += fmt.Sprintf("%s %s", cRettype, sysname)
   223  				cIn := strings.Join(cIn, ", ")
   224  				cExtern += fmt.Sprintf("(%s);\n", cIn)
   225  			}
   226  
   227  			// So file name.
   228  			if *aix {
   229  				if modname == "" {
   230  					modname = "libc.a/shr_64.o"
   231  				} else {
   232  					fmt.Fprintf(os.Stderr, "%s: only syscall using libc are available\n", funct)
   233  					os.Exit(1)
   234  				}
   235  			}
   236  
   237  			strconvfunc := "C.CString"
   238  
   239  			// Go function header.
   240  			if outps != "" {
   241  				outps = fmt.Sprintf(" (%s)", outps)
   242  			}
   243  			if text != "" {
   244  				text += "\n"
   245  			}
   246  
   247  			text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outps)
   248  
   249  			// Prepare arguments to Syscall.
   250  			var args []string
   251  			n := 0
   252  			argN := 0
   253  			for _, param := range in {
   254  				p := parseParam(param)
   255  				if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil {
   256  					args = append(args, "C.uintptr_t(uintptr(unsafe.Pointer("+p.Name+")))")
   257  				} else if p.Type == "string" && errvar != "" {
   258  					text += fmt.Sprintf("\t_p%d := uintptr(unsafe.Pointer(%s(%s)))\n", n, strconvfunc, p.Name)
   259  					args = append(args, fmt.Sprintf("C.uintptr_t(_p%d)", n))
   260  					n++
   261  				} else if p.Type == "string" {
   262  					fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n")
   263  					text += fmt.Sprintf("\t_p%d := uintptr(unsafe.Pointer(%s(%s)))\n", n, strconvfunc, p.Name)
   264  					args = append(args, fmt.Sprintf("C.uintptr_t(_p%d)", n))
   265  					n++
   266  				} else if m := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); m != nil {
   267  					// Convert slice into pointer, length.
   268  					// Have to be careful not to take address of &a[0] if len == 0:
   269  					// pass nil in that case.
   270  					text += fmt.Sprintf("\tvar _p%d *%s\n", n, m[1])
   271  					text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name)
   272  					args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(unsafe.Pointer(_p%d)))", n))
   273  					n++
   274  					text += fmt.Sprintf("\tvar _p%d int\n", n)
   275  					text += fmt.Sprintf("\t_p%d = len(%s)\n", n, p.Name)
   276  					args = append(args, fmt.Sprintf("C.size_t(_p%d)", n))
   277  					n++
   278  				} else if p.Type == "int64" && endianness != "" {
   279  					if endianness == "big-endian" {
   280  						args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
   281  					} else {
   282  						args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
   283  					}
   284  					n++
   285  				} else if p.Type == "bool" {
   286  					text += fmt.Sprintf("\tvar _p%d uint32\n", n)
   287  					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)
   288  					args = append(args, fmt.Sprintf("_p%d", n))
   289  				} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil {
   290  					args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(%s))", p.Name))
   291  				} else if p.Type == "unsafe.Pointer" {
   292  					args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(%s))", p.Name))
   293  				} else if p.Type == "int" {
   294  					if (argN == 2) && ((funct == "readlen") || (funct == "writelen")) {
   295  						args = append(args, fmt.Sprintf("C.size_t(%s)", p.Name))
   296  					} else if argN == 0 && funct == "fcntl" {
   297  						args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name))
   298  					} else if (argN == 2) && ((funct == "fcntl") || (funct == "FcntlInt")) {
   299  						args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name))
   300  					} else {
   301  						args = append(args, fmt.Sprintf("C.int(%s)", p.Name))
   302  					}
   303  				} else if p.Type == "int32" {
   304  					args = append(args, fmt.Sprintf("C.int(%s)", p.Name))
   305  				} else if p.Type == "int64" {
   306  					args = append(args, fmt.Sprintf("C.longlong(%s)", p.Name))
   307  				} else if p.Type == "uint32" {
   308  					args = append(args, fmt.Sprintf("C.uint(%s)", p.Name))
   309  				} else if p.Type == "uint64" {
   310  					args = append(args, fmt.Sprintf("C.ulonglong(%s)", p.Name))
   311  				} else if p.Type == "uintptr" {
   312  					args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name))
   313  				} else {
   314  					args = append(args, fmt.Sprintf("C.int(%s)", p.Name))
   315  				}
   316  				argN++
   317  			}
   318  
   319  			// Actual call.
   320  			arglist := strings.Join(args, ", ")
   321  			call := ""
   322  			if sysname == "exit" {
   323  				if errvar != "" {
   324  					call += "er :="
   325  				} else {
   326  					call += ""
   327  				}
   328  			} else if errvar != "" {
   329  				call += "r0,er :="
   330  			} else if retvar != "" {
   331  				call += "r0,_ :="
   332  			} else {
   333  				call += ""
   334  			}
   335  			if sysname == "select" {
   336  				// select is a keyword of Go. Its name is
   337  				// changed to c_select.
   338  				call += fmt.Sprintf("C.c_%s(%s)", sysname, arglist)
   339  			} else {
   340  				call += fmt.Sprintf("C.%s(%s)", sysname, arglist)
   341  			}
   342  
   343  			// Assign return values.
   344  			body := ""
   345  			for i := 0; i < len(out); i++ {
   346  				p := parseParam(out[i])
   347  				reg := ""
   348  				if p.Name == "err" {
   349  					reg = "e1"
   350  				} else {
   351  					reg = "r0"
   352  				}
   353  				if reg != "e1" {
   354  					body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg)
   355  				}
   356  			}
   357  
   358  			// verify return
   359  			if sysname != "exit" && errvar != "" {
   360  				if regexp.MustCompile(`^uintptr`).FindStringSubmatch(cRettype) != nil {
   361  					body += "\tif (uintptr(r0) ==^uintptr(0) && er != nil) {\n"
   362  					body += fmt.Sprintf("\t\t%s = er\n", errvar)
   363  					body += "\t}\n"
   364  				} else {
   365  					body += "\tif (r0 ==-1 && er != nil) {\n"
   366  					body += fmt.Sprintf("\t\t%s = er\n", errvar)
   367  					body += "\t}\n"
   368  				}
   369  			} else if errvar != "" {
   370  				body += "\tif (er != nil) {\n"
   371  				body += fmt.Sprintf("\t\t%s = er\n", errvar)
   372  				body += "\t}\n"
   373  			}
   374  
   375  			text += fmt.Sprintf("\t%s\n", call)
   376  			text += body
   377  
   378  			text += "\treturn\n"
   379  			text += "}\n"
   380  		}
   381  		if err := s.Err(); err != nil {
   382  			fmt.Fprintf(os.Stderr, err.Error())
   383  			os.Exit(1)
   384  		}
   385  		file.Close()
   386  	}
   387  	imp := ""
   388  	if pack != "unix" {
   389  		imp = "import \"golang.org/x/sys/unix\"\n"
   390  
   391  	}
   392  	fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, cExtern, imp, text)
   393  }
   394  
   395  const srcTemplate = `// %s
   396  // Code generated by the command above; see README.md. DO NOT EDIT.
   397  
   398  // +build %s
   399  
   400  package %s
   401  
   402  
   403  %s
   404  */
   405  import "C"
   406  import (
   407  	"unsafe"
   408  )
   409  
   410  
   411  %s
   412  
   413  %s
   414  `