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 `