github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/syscall/mksyscall.awk (about) 1 # Copyright 2011 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 # This AWK script reads a Go file with comments describing syscall 6 # functions and the C routines they map to. It generates the Go code 7 # which calls the C routines. 8 9 # The syscall functins are marked by lines beginning with "//sys" and 10 # read like func declarations if //sys is replaced by func, but: 11 # * The parameter lists must give a name for each argument. 12 # This includes return parameters. 13 # * The parameter lists must give a type for each argument: 14 # the (x, y, z int) shorthand is not allowed. 15 # * If the return parameter is an error, it must be named err. 16 17 # A line beginning with //sysnb is like //sys, except that the 18 # goroutine will not be suspended during the execution of the library 19 # call. This must only be used for library calls which can never 20 # block, as otherwise the library call could cause all goroutines to 21 # hang. 22 23 # After the //sys or //sysnb line comes a second line which describes 24 # the C function. The name must be the name of the function in the C 25 # library, and may be the same as the Go function. The limitations on 26 # the argument list are the same as for the //sys line, but there must 27 # be at most one result parameter, and it must be given as just a 28 # type, without a name. 29 30 BEGIN { 31 print "// This file was automatically generated by mksyscall.awk" 32 print "" 33 print "package syscall" 34 print "" 35 print "import \"unsafe\"" 36 print "" 37 status = 0 38 } 39 40 /^\/\/sys/ { 41 if ($1 == "//sysnb") { 42 blocking = 0 43 } else { 44 blocking = 1 45 } 46 47 line = $0 48 49 if (match(line, "//sys(nb)?[ ]*[a-zA-Z0-9_]+\\([^()]*\\) *(\\(([^()]+)\\))?") == 0) { 50 print "unmatched line:", $0 | "cat 1>&2" 51 status = 1 52 next 53 } 54 55 # Sets a[1] = //sysnb, a[2] == function name. 56 split(line, a, "[ (]+") 57 gofnname = a[2] 58 59 off = match(line, "\\([^()]*\\)") 60 end = index(substr(line, off, length(line) - off + 1), ")") 61 gofnparams = substr(line, off + 1, end - 2) 62 63 line = substr(line, off + end, length(line) - (off + end) + 1) 64 off = match(line, "\\([^()]*\\)") 65 if (off == 0) { 66 gofnresults = "" 67 } else { 68 end = index(substr(line, off, length(line) - off + 1), ")") 69 gofnresults = substr(line, off + 1, end - 2) 70 } 71 72 getline 73 line = $0 74 75 if (match(line, "//[a-zA-Z0-9_]+\\([^()]*\\)") == 0) { 76 print "unmatched C line", $0, "after", gofnname | "cat 1>&2" 77 status = 1 78 next 79 } 80 81 split(line, a, "[ (]+") 82 cfnname = substr(a[1], 3, length(a[1]) - 2) 83 84 off = match(line, "\\([^()]*\\)") 85 end = index(substr(line, off, length(line) - off + 1), ")") 86 cfnparams = substr(line, off + 1, end - 2) 87 88 line = substr(line, off + end + 1, length(line) - (off + end) + 1) 89 while (substr(line, 1, 1) == " ") { 90 line = substr(line, 2, length(line) - 1) 91 } 92 end = index(line, " ") 93 if (end != 0) { 94 line = substr(line, 1, end) 95 } 96 cfnresult = line 97 98 printf("// Automatically generated wrapper for %s/%s\n", gofnname, cfnname) 99 if (!(cfnname in cfns)) { 100 cfns[cfnname] = 1 101 printf("//extern %s\n", cfnname) 102 printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult) 103 } 104 printf("func %s(%s) %s%s%s%s{\n", 105 gofnname, gofnparams, gofnresults == "" ? "" : "(", gofnresults, 106 gofnresults == "" ? "" : ")", gofnresults == "" ? "" : " ") 107 108 loc = gofnname "/" cfnname ":" 109 110 haserr = 0 111 if (gofnresults != "") { 112 fields = split(gofnresults, goresults, ", *") 113 for (goresult = 1; goresults[goresult] != ""; goresult++) { 114 if (split(goresults[goresult], goparam) == 2) { 115 if (goparam[1] == "err") { 116 haserr = 1 117 break 118 } 119 } 120 } 121 } 122 123 split(gofnparams, goargs, ", *") 124 split(cfnparams, cargs, ", *") 125 args = "" 126 carg = 1 127 for (goarg = 1; goargs[goarg] != ""; goarg++) { 128 if (cargs[carg] == "") { 129 print loc, "not enough C parameters" 130 } 131 132 if (args != "") { 133 args = args ", " 134 } 135 136 if (split(goargs[goarg], a) != 2) { 137 print loc, "bad parameter:", goargs[goarg] | "cat 1>&2" 138 status = 1 139 next 140 } 141 142 goname = a[1] 143 gotype = a[2] 144 145 if (split(cargs[carg], a) != 2) { 146 print loc, "bad C parameter:", cargs[carg] | "cat 1>&2" 147 status = 1 148 next 149 } 150 151 ctype = a[2] 152 153 if (gotype ~ /^\*/) { 154 if (gotype != ctype) { 155 print loc, "Go/C pointer type mismatch:", gotype, ctype | "cat 1>&2" 156 status = 1 157 next 158 } 159 args = args goname 160 } else if (gotype == "string") { 161 if (ctype != "*byte") { 162 print loc, "Go string not matched to C *byte:", gotype, ctype | "cat 1>&2" 163 status = 1 164 next 165 } 166 printf("\tvar _p%d *byte\n", goarg) 167 if (haserr) { 168 printf("\t_p%d, err = BytePtrFromString(%s)\n", goarg, goname) 169 printf("\tif err != nil {\n\t\treturn\n\t}\n") 170 } else { 171 print loc, "uses string arguments but has no error return" | "cat 1>&2" 172 printf("\t_p%d, _ = BytePtrFromString(%s)\n", goarg, goname) 173 } 174 args = sprintf("%s_p%d", args, goarg) 175 } else if (gotype ~ /^\[\](.*)/) { 176 if (ctype !~ /^\*/ || cargs[carg + 1] == "") { 177 print loc, "bad C type for slice:", gotype, ctype | "cat 1>&2" 178 status = 1 179 next 180 } 181 182 # Convert a slice into a pair of pointer, length. 183 # Don't try to take the address of the zeroth element of a 184 # nil slice. 185 printf("\tvar _p%d %s\n", goarg, ctype) 186 printf("\tif len(%s) > 0 {\n", goname) 187 printf("\t\t_p%d = (%s)(unsafe.Pointer(&%s[0]))\n", goarg, ctype, goname) 188 printf("\t} else {\n") 189 printf("\t\t_p%d = (%s)(unsafe.Pointer(&_zero))\n", goarg, ctype) 190 printf("\t}\n") 191 192 ++carg 193 if (split(cargs[carg], cparam) != 2) { 194 print loc, "bad C parameter:", cargs[carg] | "cat 1>&2" 195 status = 1 196 next 197 } 198 199 args = sprintf("%s_p%d, %s(len(%s))", args, goarg, cparam[2], goname) 200 } else if (gotype == "uintptr" && ctype ~ /^\*/) { 201 args = sprintf("%s(%s)(unsafe.Pointer(%s))", args, ctype, goname) 202 } else if (gotype == "unsafe.Pointer" && ctype ~ /^\*/) { 203 args = sprintf("%s(%s)(%s)", args, ctype, goname) 204 } else { 205 args = sprintf("%s%s(%s)", args, ctype, goname) 206 } 207 208 carg++ 209 } 210 211 if (cargs[carg] != "") { 212 print loc, "too many C parameters" | "cat 1>&2" 213 status = 1 214 next 215 } 216 217 if (blocking) { 218 print "\tEntersyscall()" 219 } 220 221 printf("\t") 222 if (gofnresults != "") { 223 printf("_r := ") 224 } 225 printf("c_%s(%s)\n", cfnname, args) 226 227 seterr = 0 228 if (gofnresults != "") { 229 fields = split(gofnresults, goresults, ", *") 230 if (fields > 2) { 231 print loc, "too many Go results" | "cat 1>&2" 232 status = 1 233 next 234 } 235 usedr = 0 236 for (goresult = 1; goresults[goresult] != ""; goresult++) { 237 if (split(goresults[goresult], goparam) != 2) { 238 print loc, "bad result:", goresults[goresult] | "cat 1>&2" 239 status = 1 240 next 241 } 242 243 goname = goparam[1] 244 gotype = goparam[2] 245 246 if (goname == "err") { 247 print "\tvar errno Errno" 248 print "\tsetErrno := false" 249 if (cfnresult ~ /^\*/) { 250 print "\tif _r == nil {" 251 } else { 252 print "\tif _r < 0 {" 253 } 254 print "\t\terrno = GetErrno()" 255 print "\t\tsetErrno = true" 256 print "\t}" 257 seterr = 1 258 } else if (gotype == "uintptr" && cfnresult ~ /^\*/) { 259 printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname, gotype) 260 } else { 261 if (usedr) { 262 print loc, "two parameters but no errno parameter" | "cat 1>&2" 263 status = 1 264 next 265 } 266 printf("\t%s = (%s)(_r)\n", goname, gotype) 267 usedr = 1 268 } 269 } 270 } 271 272 if (blocking) { 273 print "\tExitsyscall()" 274 } 275 276 if (seterr) { 277 print "\tif setErrno {" 278 print "\t\terr = errno" 279 print "\t}" 280 } 281 282 if (gofnresults != "") { 283 print "\treturn" 284 } 285 286 print "}" 287 288 print "" 289 290 next 291 } 292 293 { next } 294 295 END { 296 if (status != 0) { 297 print "*** mksyscall.awk failed" | "cat 1>&2" 298 exit status 299 } 300 }