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