mksyscall.awk 7.7 KB

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