mksyscall_aix_ppc.go 12 KB

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