Scott Baker | c6e54cb | 2019-11-04 09:31:25 -0800 | [diff] [blame] | 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 | // +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 | |
| 23 | This program will generate three files and handle both gc and gccgo implementation: |
| 24 | - zsyscall_aix_ppc64.go: the common part of each implementation (error handler, pointer creation) |
| 25 | - zsyscall_aix_ppc64_gc.go: gc part with //go_cgo_import_dynamic and a call to syscall6 |
| 26 | - zsyscall_aix_ppc64_gccgo.go: gccgo part with C function and conversion to C type. |
| 27 | |
| 28 | The generated code looks like this |
| 29 | |
| 30 | zsyscall_aix_ppc64.go |
| 31 | func asyscall(...) (n int, err error) { |
| 32 | // Pointer Creation |
| 33 | r1, e1 := callasyscall(...) |
| 34 | // Type Conversion |
| 35 | // Error Handler |
| 36 | return |
| 37 | } |
| 38 | |
| 39 | zsyscall_aix_ppc64_gc.go |
| 40 | //go:cgo_import_dynamic libc_asyscall asyscall "libc.a/shr_64.o" |
| 41 | //go:linkname libc_asyscall libc_asyscall |
| 42 | var asyscall syscallFunc |
| 43 | |
| 44 | func callasyscall(...) (r1 uintptr, e1 Errno) { |
| 45 | r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_asyscall)), "nb_args", ... ) |
| 46 | return |
| 47 | } |
| 48 | |
| 49 | zsyscall_aix_ppc64_ggcgo.go |
| 50 | |
| 51 | // int asyscall(...) |
| 52 | |
| 53 | import "C" |
| 54 | |
| 55 | func callasyscall(...) (r1 uintptr, e1 Errno) { |
| 56 | r1 = uintptr(C.asyscall(...)) |
| 57 | e1 = syscall.GetErrno() |
| 58 | return |
| 59 | } |
| 60 | */ |
| 61 | |
| 62 | package main |
| 63 | |
| 64 | import ( |
| 65 | "bufio" |
| 66 | "flag" |
| 67 | "fmt" |
| 68 | "io/ioutil" |
| 69 | "os" |
| 70 | "regexp" |
| 71 | "strings" |
| 72 | ) |
| 73 | |
| 74 | var ( |
| 75 | b32 = flag.Bool("b32", false, "32bit big-endian") |
| 76 | l32 = flag.Bool("l32", false, "32bit little-endian") |
| 77 | aix = flag.Bool("aix", false, "aix") |
| 78 | tags = flag.String("tags", "", "build tags") |
| 79 | ) |
| 80 | |
| 81 | // cmdLine returns this programs's commandline arguments |
| 82 | func cmdLine() string { |
| 83 | return "go run mksyscall_aix_ppc64.go " + strings.Join(os.Args[1:], " ") |
| 84 | } |
| 85 | |
| 86 | // buildTags returns build tags |
| 87 | func buildTags() string { |
| 88 | return *tags |
| 89 | } |
| 90 | |
| 91 | // Param is function parameter |
| 92 | type Param struct { |
| 93 | Name string |
| 94 | Type string |
| 95 | } |
| 96 | |
| 97 | // usage prints the program usage |
| 98 | func usage() { |
| 99 | fmt.Fprintf(os.Stderr, "usage: go run mksyscall_aix_ppc64.go [-b32 | -l32] [-tags x,y] [file ...]\n") |
| 100 | os.Exit(1) |
| 101 | } |
| 102 | |
| 103 | // parseParamList parses parameter list and returns a slice of parameters |
| 104 | func parseParamList(list string) []string { |
| 105 | list = strings.TrimSpace(list) |
| 106 | if list == "" { |
| 107 | return []string{} |
| 108 | } |
| 109 | return regexp.MustCompile(`\s*,\s*`).Split(list, -1) |
| 110 | } |
| 111 | |
| 112 | // parseParam splits a parameter into name and type |
| 113 | func parseParam(p string) Param { |
| 114 | ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) |
| 115 | if ps == nil { |
| 116 | fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) |
| 117 | os.Exit(1) |
| 118 | } |
| 119 | return Param{ps[1], ps[2]} |
| 120 | } |
| 121 | |
| 122 | func main() { |
| 123 | flag.Usage = usage |
| 124 | flag.Parse() |
| 125 | if len(flag.Args()) <= 0 { |
| 126 | fmt.Fprintf(os.Stderr, "no files to parse provided\n") |
| 127 | usage() |
| 128 | } |
| 129 | |
| 130 | endianness := "" |
| 131 | if *b32 { |
| 132 | endianness = "big-endian" |
| 133 | } else if *l32 { |
| 134 | endianness = "little-endian" |
| 135 | } |
| 136 | |
| 137 | pack := "" |
| 138 | // GCCGO |
| 139 | textgccgo := "" |
| 140 | cExtern := "/*\n#include <stdint.h>\n" |
| 141 | // GC |
| 142 | textgc := "" |
| 143 | dynimports := "" |
| 144 | linknames := "" |
| 145 | var vars []string |
| 146 | // COMMON |
| 147 | textcommon := "" |
| 148 | for _, path := range flag.Args() { |
| 149 | file, err := os.Open(path) |
| 150 | if err != nil { |
| 151 | fmt.Fprintf(os.Stderr, err.Error()) |
| 152 | os.Exit(1) |
| 153 | } |
| 154 | s := bufio.NewScanner(file) |
| 155 | for s.Scan() { |
| 156 | t := s.Text() |
| 157 | t = strings.TrimSpace(t) |
| 158 | t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) |
| 159 | if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" { |
| 160 | pack = p[1] |
| 161 | } |
| 162 | nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) |
| 163 | if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { |
| 164 | continue |
| 165 | } |
| 166 | |
| 167 | // Line must be of the form |
| 168 | // func Open(path string, mode int, perm int) (fd int, err error) |
| 169 | // Split into name, in params, out params. |
| 170 | f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t) |
| 171 | if f == nil { |
| 172 | fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) |
| 173 | os.Exit(1) |
| 174 | } |
| 175 | funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6] |
| 176 | |
| 177 | // Split argument lists on comma. |
| 178 | in := parseParamList(inps) |
| 179 | out := parseParamList(outps) |
| 180 | |
| 181 | inps = strings.Join(in, ", ") |
| 182 | outps = strings.Join(out, ", ") |
| 183 | |
| 184 | if sysname == "" { |
| 185 | sysname = funct |
| 186 | } |
| 187 | |
| 188 | onlyCommon := false |
| 189 | if funct == "readlen" || funct == "writelen" || funct == "FcntlInt" || funct == "FcntlFlock" { |
| 190 | // This function call another syscall which is already implemented. |
| 191 | // Therefore, the gc and gccgo part must not be generated. |
| 192 | onlyCommon = true |
| 193 | } |
| 194 | |
| 195 | // Try in vain to keep people from editing this file. |
| 196 | // The theory is that they jump into the middle of the file |
| 197 | // without reading the header. |
| 198 | |
| 199 | textcommon += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
| 200 | if !onlyCommon { |
| 201 | textgccgo += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
| 202 | textgc += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" |
| 203 | } |
| 204 | |
| 205 | // Check if value return, err return available |
| 206 | errvar := "" |
| 207 | rettype := "" |
| 208 | for _, param := range out { |
| 209 | p := parseParam(param) |
| 210 | if p.Type == "error" { |
| 211 | errvar = p.Name |
| 212 | } else { |
| 213 | rettype = p.Type |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`) |
| 218 | sysname = strings.ToLower(sysname) // All libc functions are lowercase. |
| 219 | |
| 220 | // GCCGO Prototype return type |
| 221 | cRettype := "" |
| 222 | if rettype == "unsafe.Pointer" { |
| 223 | cRettype = "uintptr_t" |
| 224 | } else if rettype == "uintptr" { |
| 225 | cRettype = "uintptr_t" |
| 226 | } else if regexp.MustCompile(`^_`).FindStringSubmatch(rettype) != nil { |
| 227 | cRettype = "uintptr_t" |
| 228 | } else if rettype == "int" { |
| 229 | cRettype = "int" |
| 230 | } else if rettype == "int32" { |
| 231 | cRettype = "int" |
| 232 | } else if rettype == "int64" { |
| 233 | cRettype = "long long" |
| 234 | } else if rettype == "uint32" { |
| 235 | cRettype = "unsigned int" |
| 236 | } else if rettype == "uint64" { |
| 237 | cRettype = "unsigned long long" |
| 238 | } else { |
| 239 | cRettype = "int" |
| 240 | } |
| 241 | if sysname == "exit" { |
| 242 | cRettype = "void" |
| 243 | } |
| 244 | |
| 245 | // GCCGO Prototype arguments type |
| 246 | var cIn []string |
| 247 | for i, param := range in { |
| 248 | p := parseParam(param) |
| 249 | if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { |
| 250 | cIn = append(cIn, "uintptr_t") |
| 251 | } else if p.Type == "string" { |
| 252 | cIn = append(cIn, "uintptr_t") |
| 253 | } else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil { |
| 254 | cIn = append(cIn, "uintptr_t", "size_t") |
| 255 | } else if p.Type == "unsafe.Pointer" { |
| 256 | cIn = append(cIn, "uintptr_t") |
| 257 | } else if p.Type == "uintptr" { |
| 258 | cIn = append(cIn, "uintptr_t") |
| 259 | } else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil { |
| 260 | cIn = append(cIn, "uintptr_t") |
| 261 | } else if p.Type == "int" { |
| 262 | if (i == 0 || i == 2) && funct == "fcntl" { |
| 263 | // These fcntl arguments needs to be uintptr to be able to call FcntlInt and FcntlFlock |
| 264 | cIn = append(cIn, "uintptr_t") |
| 265 | } else { |
| 266 | cIn = append(cIn, "int") |
| 267 | } |
| 268 | |
| 269 | } else if p.Type == "int32" { |
| 270 | cIn = append(cIn, "int") |
| 271 | } else if p.Type == "int64" { |
| 272 | cIn = append(cIn, "long long") |
| 273 | } else if p.Type == "uint32" { |
| 274 | cIn = append(cIn, "unsigned int") |
| 275 | } else if p.Type == "uint64" { |
| 276 | cIn = append(cIn, "unsigned long long") |
| 277 | } else { |
| 278 | cIn = append(cIn, "int") |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | if !onlyCommon { |
| 283 | // GCCGO Prototype Generation |
| 284 | // Imports of system calls from libc |
| 285 | if sysname == "select" { |
| 286 | // select is a keyword of Go. Its name is |
| 287 | // changed to c_select. |
| 288 | cExtern += "#define c_select select\n" |
| 289 | } |
| 290 | cExtern += fmt.Sprintf("%s %s", cRettype, sysname) |
| 291 | cIn := strings.Join(cIn, ", ") |
| 292 | cExtern += fmt.Sprintf("(%s);\n", cIn) |
| 293 | } |
| 294 | // GC Library name |
| 295 | if modname == "" { |
| 296 | modname = "libc.a/shr_64.o" |
| 297 | } else { |
| 298 | fmt.Fprintf(os.Stderr, "%s: only syscall using libc are available\n", funct) |
| 299 | os.Exit(1) |
| 300 | } |
| 301 | sysvarname := fmt.Sprintf("libc_%s", sysname) |
| 302 | |
| 303 | if !onlyCommon { |
| 304 | // GC Runtime import of function to allow cross-platform builds. |
| 305 | dynimports += fmt.Sprintf("//go:cgo_import_dynamic %s %s \"%s\"\n", sysvarname, sysname, modname) |
| 306 | // GC Link symbol to proc address variable. |
| 307 | linknames += fmt.Sprintf("//go:linkname %s %s\n", sysvarname, sysvarname) |
| 308 | // GC Library proc address variable. |
| 309 | vars = append(vars, sysvarname) |
| 310 | } |
| 311 | |
| 312 | strconvfunc := "BytePtrFromString" |
| 313 | strconvtype := "*byte" |
| 314 | |
| 315 | // Go function header. |
| 316 | if outps != "" { |
| 317 | outps = fmt.Sprintf(" (%s)", outps) |
| 318 | } |
| 319 | if textcommon != "" { |
| 320 | textcommon += "\n" |
| 321 | } |
| 322 | |
| 323 | textcommon += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outps) |
| 324 | |
| 325 | // Prepare arguments tocall. |
| 326 | var argscommon []string // Arguments in the common part |
| 327 | var argscall []string // Arguments for call prototype |
| 328 | var argsgc []string // Arguments for gc call (with syscall6) |
| 329 | var argsgccgo []string // Arguments for gccgo call (with C.name_of_syscall) |
| 330 | n := 0 |
| 331 | argN := 0 |
| 332 | for _, param := range in { |
| 333 | p := parseParam(param) |
| 334 | if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { |
| 335 | argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.Name)) |
| 336 | argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) |
| 337 | argsgc = append(argsgc, p.Name) |
| 338 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
| 339 | } else if p.Type == "string" && errvar != "" { |
| 340 | textcommon += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) |
| 341 | textcommon += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) |
| 342 | textcommon += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) |
| 343 | |
| 344 | argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) |
| 345 | argscall = append(argscall, fmt.Sprintf("_p%d uintptr ", n)) |
| 346 | argsgc = append(argsgc, fmt.Sprintf("_p%d", n)) |
| 347 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n)) |
| 348 | n++ |
| 349 | } else if p.Type == "string" { |
| 350 | fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") |
| 351 | textcommon += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) |
| 352 | textcommon += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) |
| 353 | textcommon += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) |
| 354 | |
| 355 | argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) |
| 356 | argscall = append(argscall, fmt.Sprintf("_p%d uintptr", n)) |
| 357 | argsgc = append(argsgc, fmt.Sprintf("_p%d", n)) |
| 358 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n)) |
| 359 | n++ |
| 360 | } else if m := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); m != nil { |
| 361 | // Convert slice into pointer, length. |
| 362 | // Have to be careful not to take address of &a[0] if len == 0: |
| 363 | // pass nil in that case. |
| 364 | textcommon += fmt.Sprintf("\tvar _p%d *%s\n", n, m[1]) |
| 365 | textcommon += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name) |
| 366 | argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n), fmt.Sprintf("len(%s)", p.Name)) |
| 367 | argscall = append(argscall, fmt.Sprintf("_p%d uintptr", n), fmt.Sprintf("_lenp%d int", n)) |
| 368 | argsgc = append(argsgc, fmt.Sprintf("_p%d", n), fmt.Sprintf("uintptr(_lenp%d)", n)) |
| 369 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n), fmt.Sprintf("C.size_t(_lenp%d)", n)) |
| 370 | n++ |
| 371 | } else if p.Type == "int64" && endianness != "" { |
| 372 | fmt.Fprintf(os.Stderr, path+":"+funct+" uses int64 with 32 bits mode. Case not yet implemented\n") |
| 373 | } else if p.Type == "bool" { |
| 374 | fmt.Fprintf(os.Stderr, path+":"+funct+" uses bool. Case not yet implemented\n") |
| 375 | } else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil || p.Type == "unsafe.Pointer" { |
| 376 | argscommon = append(argscommon, fmt.Sprintf("uintptr(%s)", p.Name)) |
| 377 | argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) |
| 378 | argsgc = append(argsgc, p.Name) |
| 379 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
| 380 | } else if p.Type == "int" { |
| 381 | if (argN == 0 || argN == 2) && ((funct == "fcntl") || (funct == "FcntlInt") || (funct == "FcntlFlock")) { |
| 382 | // These fcntl arguments need to be uintptr to be able to call FcntlInt and FcntlFlock |
| 383 | argscommon = append(argscommon, fmt.Sprintf("uintptr(%s)", p.Name)) |
| 384 | argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) |
| 385 | argsgc = append(argsgc, p.Name) |
| 386 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
| 387 | |
| 388 | } else { |
| 389 | argscommon = append(argscommon, p.Name) |
| 390 | argscall = append(argscall, fmt.Sprintf("%s int", p.Name)) |
| 391 | argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
| 392 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) |
| 393 | } |
| 394 | } else if p.Type == "int32" { |
| 395 | argscommon = append(argscommon, p.Name) |
| 396 | argscall = append(argscall, fmt.Sprintf("%s int32", p.Name)) |
| 397 | argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
| 398 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) |
| 399 | } else if p.Type == "int64" { |
| 400 | argscommon = append(argscommon, p.Name) |
| 401 | argscall = append(argscall, fmt.Sprintf("%s int64", p.Name)) |
| 402 | argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
| 403 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.longlong(%s)", p.Name)) |
| 404 | } else if p.Type == "uint32" { |
| 405 | argscommon = append(argscommon, p.Name) |
| 406 | argscall = append(argscall, fmt.Sprintf("%s uint32", p.Name)) |
| 407 | argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
| 408 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.uint(%s)", p.Name)) |
| 409 | } else if p.Type == "uint64" { |
| 410 | argscommon = append(argscommon, p.Name) |
| 411 | argscall = append(argscall, fmt.Sprintf("%s uint64", p.Name)) |
| 412 | argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
| 413 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.ulonglong(%s)", p.Name)) |
| 414 | } else if p.Type == "uintptr" { |
| 415 | argscommon = append(argscommon, p.Name) |
| 416 | argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) |
| 417 | argsgc = append(argsgc, p.Name) |
| 418 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) |
| 419 | } else { |
| 420 | argscommon = append(argscommon, fmt.Sprintf("int(%s)", p.Name)) |
| 421 | argscall = append(argscall, fmt.Sprintf("%s int", p.Name)) |
| 422 | argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) |
| 423 | argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) |
| 424 | } |
| 425 | argN++ |
| 426 | } |
| 427 | nargs := len(argsgc) |
| 428 | |
| 429 | // COMMON function generation |
| 430 | argscommonlist := strings.Join(argscommon, ", ") |
| 431 | callcommon := fmt.Sprintf("call%s(%s)", sysname, argscommonlist) |
| 432 | ret := []string{"_", "_"} |
| 433 | body := "" |
| 434 | doErrno := false |
| 435 | for i := 0; i < len(out); i++ { |
| 436 | p := parseParam(out[i]) |
| 437 | reg := "" |
| 438 | if p.Name == "err" { |
| 439 | reg = "e1" |
| 440 | ret[1] = reg |
| 441 | doErrno = true |
| 442 | } else { |
| 443 | reg = "r0" |
| 444 | ret[0] = reg |
| 445 | } |
| 446 | if p.Type == "bool" { |
| 447 | reg = fmt.Sprintf("%s != 0", reg) |
| 448 | } |
| 449 | if reg != "e1" { |
| 450 | body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) |
| 451 | } |
| 452 | } |
| 453 | if ret[0] == "_" && ret[1] == "_" { |
| 454 | textcommon += fmt.Sprintf("\t%s\n", callcommon) |
| 455 | } else { |
| 456 | textcommon += fmt.Sprintf("\t%s, %s := %s\n", ret[0], ret[1], callcommon) |
| 457 | } |
| 458 | textcommon += body |
| 459 | |
| 460 | if doErrno { |
| 461 | textcommon += "\tif e1 != 0 {\n" |
| 462 | textcommon += "\t\terr = errnoErr(e1)\n" |
| 463 | textcommon += "\t}\n" |
| 464 | } |
| 465 | textcommon += "\treturn\n" |
| 466 | textcommon += "}\n" |
| 467 | |
| 468 | if onlyCommon { |
| 469 | continue |
| 470 | } |
| 471 | |
| 472 | // CALL Prototype |
| 473 | callProto := fmt.Sprintf("func call%s(%s) (r1 uintptr, e1 Errno) {\n", sysname, strings.Join(argscall, ", ")) |
| 474 | |
| 475 | // GC function generation |
| 476 | asm := "syscall6" |
| 477 | if nonblock != nil { |
| 478 | asm = "rawSyscall6" |
| 479 | } |
| 480 | |
| 481 | if len(argsgc) <= 6 { |
| 482 | for len(argsgc) < 6 { |
| 483 | argsgc = append(argsgc, "0") |
| 484 | } |
| 485 | } else { |
| 486 | fmt.Fprintf(os.Stderr, "%s: too many arguments to system call", funct) |
| 487 | os.Exit(1) |
| 488 | } |
| 489 | argsgclist := strings.Join(argsgc, ", ") |
| 490 | callgc := fmt.Sprintf("%s(uintptr(unsafe.Pointer(&%s)), %d, %s)", asm, sysvarname, nargs, argsgclist) |
| 491 | |
| 492 | textgc += callProto |
| 493 | textgc += fmt.Sprintf("\tr1, _, e1 = %s\n", callgc) |
| 494 | textgc += "\treturn\n}\n" |
| 495 | |
| 496 | // GCCGO function generation |
| 497 | argsgccgolist := strings.Join(argsgccgo, ", ") |
| 498 | var callgccgo string |
| 499 | if sysname == "select" { |
| 500 | // select is a keyword of Go. Its name is |
| 501 | // changed to c_select. |
| 502 | callgccgo = fmt.Sprintf("C.c_%s(%s)", sysname, argsgccgolist) |
| 503 | } else { |
| 504 | callgccgo = fmt.Sprintf("C.%s(%s)", sysname, argsgccgolist) |
| 505 | } |
| 506 | textgccgo += callProto |
| 507 | textgccgo += fmt.Sprintf("\tr1 = uintptr(%s)\n", callgccgo) |
| 508 | textgccgo += "\te1 = syscall.GetErrno()\n" |
| 509 | textgccgo += "\treturn\n}\n" |
| 510 | } |
| 511 | if err := s.Err(); err != nil { |
| 512 | fmt.Fprintf(os.Stderr, err.Error()) |
| 513 | os.Exit(1) |
| 514 | } |
| 515 | file.Close() |
| 516 | } |
| 517 | imp := "" |
| 518 | if pack != "unix" { |
| 519 | imp = "import \"golang.org/x/sys/unix\"\n" |
| 520 | |
| 521 | } |
| 522 | |
| 523 | // Print zsyscall_aix_ppc64.go |
| 524 | err := ioutil.WriteFile("zsyscall_aix_ppc64.go", |
| 525 | []byte(fmt.Sprintf(srcTemplate1, cmdLine(), buildTags(), pack, imp, textcommon)), |
| 526 | 0644) |
| 527 | if err != nil { |
| 528 | fmt.Fprintf(os.Stderr, err.Error()) |
| 529 | os.Exit(1) |
| 530 | } |
| 531 | |
| 532 | // Print zsyscall_aix_ppc64_gc.go |
| 533 | vardecls := "\t" + strings.Join(vars, ",\n\t") |
| 534 | vardecls += " syscallFunc" |
| 535 | err = ioutil.WriteFile("zsyscall_aix_ppc64_gc.go", |
| 536 | []byte(fmt.Sprintf(srcTemplate2, cmdLine(), buildTags(), pack, imp, dynimports, linknames, vardecls, textgc)), |
| 537 | 0644) |
| 538 | if err != nil { |
| 539 | fmt.Fprintf(os.Stderr, err.Error()) |
| 540 | os.Exit(1) |
| 541 | } |
| 542 | |
| 543 | // Print zsyscall_aix_ppc64_gccgo.go |
| 544 | err = ioutil.WriteFile("zsyscall_aix_ppc64_gccgo.go", |
| 545 | []byte(fmt.Sprintf(srcTemplate3, cmdLine(), buildTags(), pack, cExtern, imp, textgccgo)), |
| 546 | 0644) |
| 547 | if err != nil { |
| 548 | fmt.Fprintf(os.Stderr, err.Error()) |
| 549 | os.Exit(1) |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | const srcTemplate1 = `// %s |
| 554 | // Code generated by the command above; see README.md. DO NOT EDIT. |
| 555 | |
| 556 | // +build %s |
| 557 | |
| 558 | package %s |
| 559 | |
| 560 | import ( |
| 561 | "unsafe" |
| 562 | ) |
| 563 | |
| 564 | |
| 565 | %s |
| 566 | |
| 567 | %s |
| 568 | ` |
| 569 | const srcTemplate2 = `// %s |
| 570 | // Code generated by the command above; see README.md. DO NOT EDIT. |
| 571 | |
| 572 | // +build %s |
| 573 | // +build !gccgo |
| 574 | |
| 575 | package %s |
| 576 | |
| 577 | import ( |
| 578 | "unsafe" |
| 579 | ) |
| 580 | %s |
| 581 | %s |
| 582 | %s |
| 583 | type syscallFunc uintptr |
| 584 | |
| 585 | var ( |
| 586 | %s |
| 587 | ) |
| 588 | |
| 589 | // Implemented in runtime/syscall_aix.go. |
| 590 | func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
| 591 | func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) |
| 592 | |
| 593 | %s |
| 594 | ` |
| 595 | const srcTemplate3 = `// %s |
| 596 | // Code generated by the command above; see README.md. DO NOT EDIT. |
| 597 | |
| 598 | // +build %s |
| 599 | // +build gccgo |
| 600 | |
| 601 | package %s |
| 602 | |
| 603 | %s |
| 604 | */ |
| 605 | import "C" |
| 606 | import ( |
| 607 | "syscall" |
| 608 | ) |
| 609 | |
| 610 | |
| 611 | %s |
| 612 | |
| 613 | %s |
| 614 | ` |