mksysnum.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright 2018 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. package main
  6. import (
  7. "bufio"
  8. "fmt"
  9. "os"
  10. "os/exec"
  11. "regexp"
  12. "strconv"
  13. "strings"
  14. )
  15. var (
  16. goos, goarch string
  17. )
  18. // cmdLine returns this programs's commandline arguments
  19. func cmdLine() string {
  20. return "go run linux/mksysnum.go " + strings.Join(os.Args[1:], " ")
  21. }
  22. // buildTags returns build tags
  23. func buildTags() string {
  24. return fmt.Sprintf("%s,%s", goarch, goos)
  25. }
  26. func format(name string, num int, offset int) string {
  27. if num > 999 {
  28. // ignore deprecated syscalls that are no longer implemented
  29. // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/unistd.h?id=refs/heads/master#n716
  30. return ""
  31. }
  32. name = strings.ToUpper(name)
  33. num = num + offset
  34. return fmt.Sprintf(" SYS_%s = %d;\n", name, num)
  35. }
  36. func checkErr(err error) {
  37. if err != nil {
  38. fmt.Fprintf(os.Stderr, "%v\n", err)
  39. os.Exit(1)
  40. }
  41. }
  42. // source string and substring slice for regexp
  43. type re struct {
  44. str string // source string
  45. sub []string // matched sub-string
  46. }
  47. // Match performs regular expression match
  48. func (r *re) Match(exp string) bool {
  49. r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str)
  50. if r.sub != nil {
  51. return true
  52. }
  53. return false
  54. }
  55. func main() {
  56. // Get the OS and architecture (using GOARCH_TARGET if it exists)
  57. goos = os.Getenv("GOOS")
  58. goarch = os.Getenv("GOARCH_TARGET")
  59. if goarch == "" {
  60. goarch = os.Getenv("GOARCH")
  61. }
  62. // Check if GOOS and GOARCH environment variables are defined
  63. if goarch == "" || goos == "" {
  64. fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n")
  65. os.Exit(1)
  66. }
  67. // Check that we are using the new build system if we should
  68. if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
  69. fmt.Fprintf(os.Stderr, "In the new build system, mksysnum should not be called directly.\n")
  70. fmt.Fprintf(os.Stderr, "See README.md\n")
  71. os.Exit(1)
  72. }
  73. cc := os.Getenv("CC")
  74. if cc == "" {
  75. fmt.Fprintf(os.Stderr, "CC is not defined in environment\n")
  76. os.Exit(1)
  77. }
  78. args := os.Args[1:]
  79. args = append([]string{"-E", "-dD"}, args...)
  80. cmd, err := exec.Command(cc, args...).Output() // execute command and capture output
  81. if err != nil {
  82. fmt.Fprintf(os.Stderr, "can't run %s", cc)
  83. os.Exit(1)
  84. }
  85. text := ""
  86. s := bufio.NewScanner(strings.NewReader(string(cmd)))
  87. var offset, prev int
  88. for s.Scan() {
  89. t := re{str: s.Text()}
  90. if t.Match(`^#define __NR_Linux\s+([0-9]+)`) {
  91. // mips/mips64: extract offset
  92. offset, _ = strconv.Atoi(t.sub[1]) // Make offset=0 if empty or non-numeric
  93. } else if t.Match(`^#define __NR(\w*)_SYSCALL_BASE\s+([0-9]+)`) {
  94. // arm: extract offset
  95. offset, _ = strconv.Atoi(t.sub[1]) // Make offset=0 if empty or non-numeric
  96. } else if t.Match(`^#define __NR_syscalls\s+`) {
  97. // ignore redefinitions of __NR_syscalls
  98. } else if t.Match(`^#define __NR_(\w*)Linux_syscalls\s+`) {
  99. // mips/mips64: ignore definitions about the number of syscalls
  100. } else if t.Match(`^#define __NR_(\w+)\s+([0-9]+)`) {
  101. prev, err = strconv.Atoi(t.sub[2])
  102. checkErr(err)
  103. text += format(t.sub[1], prev, offset)
  104. } else if t.Match(`^#define __NR3264_(\w+)\s+([0-9]+)`) {
  105. prev, err = strconv.Atoi(t.sub[2])
  106. checkErr(err)
  107. text += format(t.sub[1], prev, offset)
  108. } else if t.Match(`^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)`) {
  109. r2, err := strconv.Atoi(t.sub[2])
  110. checkErr(err)
  111. text += format(t.sub[1], prev+r2, offset)
  112. } else if t.Match(`^#define __NR_(\w+)\s+\(__NR_(?:SYSCALL_BASE|Linux) \+ ([0-9]+)`) {
  113. r2, err := strconv.Atoi(t.sub[2])
  114. checkErr(err)
  115. text += format(t.sub[1], r2, offset)
  116. }
  117. }
  118. err = s.Err()
  119. checkErr(err)
  120. fmt.Printf(template, cmdLine(), buildTags(), text)
  121. }
  122. const template = `// %s
  123. // Code generated by the command above; see README.md. DO NOT EDIT.
  124. // +build %s
  125. package unix
  126. const(
  127. %s)`