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