You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mksyscall_aix_ppc.go 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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. if sysname == "select" {
  196. // select is a keyword of Go. Its name is
  197. // changed to c_select.
  198. cExtern += "#define c_select select\n"
  199. }
  200. // Imports of system calls from libc
  201. cExtern += fmt.Sprintf("%s %s", cRettype, sysname)
  202. cIn := strings.Join(cIn, ", ")
  203. cExtern += fmt.Sprintf("(%s);\n", cIn)
  204. }
  205. // So file name.
  206. if *aix {
  207. if modname == "" {
  208. modname = "libc.a/shr_64.o"
  209. } else {
  210. fmt.Fprintf(os.Stderr, "%s: only syscall using libc are available\n", funct)
  211. os.Exit(1)
  212. }
  213. }
  214. strconvfunc := "C.CString"
  215. // Go function header.
  216. if outps != "" {
  217. outps = fmt.Sprintf(" (%s)", outps)
  218. }
  219. if text != "" {
  220. text += "\n"
  221. }
  222. text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outps)
  223. // Prepare arguments to Syscall.
  224. var args []string
  225. n := 0
  226. argN := 0
  227. for _, param := range in {
  228. p := parseParam(param)
  229. if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil {
  230. args = append(args, "C.uintptr_t(uintptr(unsafe.Pointer("+p.Name+")))")
  231. } else if p.Type == "string" && errvar != "" {
  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 p.Type == "string" {
  236. fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n")
  237. text += fmt.Sprintf("\t_p%d := uintptr(unsafe.Pointer(%s(%s)))\n", n, strconvfunc, p.Name)
  238. args = append(args, fmt.Sprintf("C.uintptr_t(_p%d)", n))
  239. n++
  240. } else if m := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); m != nil {
  241. // Convert slice into pointer, length.
  242. // Have to be careful not to take address of &a[0] if len == 0:
  243. // pass nil in that case.
  244. text += fmt.Sprintf("\tvar _p%d *%s\n", n, m[1])
  245. text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name)
  246. args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(unsafe.Pointer(_p%d)))", n))
  247. n++
  248. text += fmt.Sprintf("\tvar _p%d int\n", n)
  249. text += fmt.Sprintf("\t_p%d = len(%s)\n", n, p.Name)
  250. args = append(args, fmt.Sprintf("C.size_t(_p%d)", n))
  251. n++
  252. } else if p.Type == "int64" && endianness != "" {
  253. if endianness == "big-endian" {
  254. args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name))
  255. } else {
  256. args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name))
  257. }
  258. n++
  259. } else if p.Type == "bool" {
  260. text += fmt.Sprintf("\tvar _p%d uint32\n", n)
  261. 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)
  262. args = append(args, fmt.Sprintf("_p%d", n))
  263. } else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil {
  264. args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(%s))", p.Name))
  265. } else if p.Type == "unsafe.Pointer" {
  266. args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(%s))", p.Name))
  267. } else if p.Type == "int" {
  268. if (argN == 2) && ((funct == "readlen") || (funct == "writelen")) {
  269. args = append(args, fmt.Sprintf("C.size_t(%s)", p.Name))
  270. } else if argN == 0 && funct == "fcntl" {
  271. args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name))
  272. } else if (argN == 2) && ((funct == "fcntl") || (funct == "FcntlInt")) {
  273. args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name))
  274. } else {
  275. args = append(args, fmt.Sprintf("C.int(%s)", p.Name))
  276. }
  277. } else if p.Type == "int32" {
  278. args = append(args, fmt.Sprintf("C.int(%s)", p.Name))
  279. } else if p.Type == "int64" {
  280. args = append(args, fmt.Sprintf("C.longlong(%s)", p.Name))
  281. } else if p.Type == "uint32" {
  282. args = append(args, fmt.Sprintf("C.uint(%s)", p.Name))
  283. } else if p.Type == "uint64" {
  284. args = append(args, fmt.Sprintf("C.ulonglong(%s)", p.Name))
  285. } else if p.Type == "uintptr" {
  286. args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name))
  287. } else {
  288. args = append(args, fmt.Sprintf("C.int(%s)", p.Name))
  289. }
  290. argN++
  291. }
  292. // Actual call.
  293. arglist := strings.Join(args, ", ")
  294. call := ""
  295. if sysname == "exit" {
  296. if errvar != "" {
  297. call += "er :="
  298. } else {
  299. call += ""
  300. }
  301. } else if errvar != "" {
  302. call += "r0,er :="
  303. } else if retvar != "" {
  304. call += "r0,_ :="
  305. } else {
  306. call += ""
  307. }
  308. if sysname == "select" {
  309. // select is a keyword of Go. Its name is
  310. // changed to c_select.
  311. call += fmt.Sprintf("C.c_%s(%s)", sysname, arglist)
  312. } else {
  313. call += fmt.Sprintf("C.%s(%s)", sysname, arglist)
  314. }
  315. // Assign return values.
  316. body := ""
  317. for i := 0; i < len(out); i++ {
  318. p := parseParam(out[i])
  319. reg := ""
  320. if p.Name == "err" {
  321. reg = "e1"
  322. } else {
  323. reg = "r0"
  324. }
  325. if reg != "e1" {
  326. body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg)
  327. }
  328. }
  329. // verify return
  330. if sysname != "exit" && errvar != "" {
  331. if regexp.MustCompile(`^uintptr`).FindStringSubmatch(cRettype) != nil {
  332. body += "\tif (uintptr(r0) ==^uintptr(0) && er != nil) {\n"
  333. body += fmt.Sprintf("\t\t%s = er\n", errvar)
  334. body += "\t}\n"
  335. } else {
  336. body += "\tif (r0 ==-1 && er != nil) {\n"
  337. body += fmt.Sprintf("\t\t%s = er\n", errvar)
  338. body += "\t}\n"
  339. }
  340. } else if errvar != "" {
  341. body += "\tif (er != nil) {\n"
  342. body += fmt.Sprintf("\t\t%s = er\n", errvar)
  343. body += "\t}\n"
  344. }
  345. text += fmt.Sprintf("\t%s\n", call)
  346. text += body
  347. text += "\treturn\n"
  348. text += "}\n"
  349. }
  350. if err := s.Err(); err != nil {
  351. fmt.Fprintf(os.Stderr, err.Error())
  352. os.Exit(1)
  353. }
  354. file.Close()
  355. }
  356. imp := ""
  357. if pack != "unix" {
  358. imp = "import \"golang.org/x/sys/unix\"\n"
  359. }
  360. fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, cExtern, imp, text)
  361. }
  362. const srcTemplate = `// %s
  363. // Code generated by the command above; see README.md. DO NOT EDIT.
  364. // +build %s
  365. package %s
  366. %s
  367. */
  368. import "C"
  369. import (
  370. "unsafe"
  371. )
  372. %s
  373. %s
  374. `