@@ -13,6 +13,7 @@ import (
1313 "os"
1414 "os/exec"
1515 "regexp"
16+ "sort"
1617 "strconv"
1718 "strings"
1819)
@@ -36,15 +37,15 @@ func plusBuildTags() string {
3637 return fmt .Sprintf ("%s,%s" , goarch , goos )
3738}
3839
39- func format (name string , num int , offset int ) string {
40+ func format (name string , num int , offset int ) ( int , string ) {
4041 if num > 999 {
4142 // ignore deprecated syscalls that are no longer implemented
4243 // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/unistd.h?id=refs/heads/master#n716
43- return ""
44+ return 0 , ""
4445 }
4546 name = strings .ToUpper (name )
4647 num = num + offset
47- return fmt .Sprintf (" SYS_%s = %d;\n " , name , num )
48+ return num , fmt .Sprintf (" SYS_%s = %d;\n " , name , num )
4849}
4950
5051func checkErr (err error ) {
@@ -69,6 +70,36 @@ func (r *re) Match(exp string) bool {
6970 return false
7071}
7172
73+ // syscallNum holds the syscall number and the string
74+ // we will write to the generated file.
75+ type syscallNum struct {
76+ num int
77+ declaration string
78+ }
79+
80+ // syscallNums is a slice of syscallNum sorted by the syscall number in ascending order.
81+ type syscallNums []syscallNum
82+
83+ // addSyscallNum adds the syscall declaration to syscallNums.
84+ func (nums * syscallNums ) addSyscallNum (num int , declaration string ) {
85+ if declaration == "" {
86+ return
87+ }
88+ if len (* nums ) == 0 || (* nums )[len (* nums )- 1 ].num <= num {
89+ // This is the most common case as the syscall declarations output by the preprocessor
90+ // are almost always sorted.
91+ * nums = append (* nums , syscallNum {num , declaration })
92+ return
93+ }
94+ i := sort .Search (len (* nums ), func (i int ) bool { return (* nums )[i ].num >= num })
95+
96+ // Maintain the ordering in the preprocessor output when we have multiple definitions with
97+ // the same value. i cannot be > len(nums) - 1 as nums[len(nums)-1].num > num.
98+ for ; (* nums )[i ].num == num ; i ++ {
99+ }
100+ * nums = append ((* nums )[:i ], append ([]syscallNum {{num , declaration }}, (* nums )[i :]... )... )
101+ }
102+
72103func main () {
73104 // Get the OS and architecture (using GOARCH_TARGET if it exists)
74105 goos = os .Getenv ("GOOS" )
@@ -100,11 +131,23 @@ func main() {
100131 fmt .Fprintf (os .Stderr , "can't run %s" , cc )
101132 os .Exit (1 )
102133 }
103- text := ""
104134 s := bufio .NewScanner (strings .NewReader (string (cmd )))
105- var offset , prev int
135+ var offset , prev , asOffset int
136+ var nums syscallNums
106137 for s .Scan () {
107138 t := re {str : s .Text ()}
139+
140+ // The generated zsysnum_linux_*.go files for some platforms (arm64, loong64, riscv64)
141+ // treat SYS_ARCH_SPECIFIC_SYSCALL as if it's a syscall which it isn't. It's an offset.
142+ // However, as this constant is already part of the public API we leave it in place.
143+ // Lines of type SYS_ARCH_SPECIFIC_SYSCALL = 244 are thus processed twice, once to extract
144+ // the offset and once to add the constant.
145+
146+ if t .Match (`^#define __NR_arch_specific_syscall\s+([0-9]+)` ) {
147+ // riscv: extract arch specific offset
148+ asOffset , _ = strconv .Atoi (t .sub [1 ]) // Make asOffset=0 if empty or non-numeric
149+ }
150+
108151 if t .Match (`^#define __NR_Linux\s+([0-9]+)` ) {
109152 // mips/mips64: extract offset
110153 offset , _ = strconv .Atoi (t .sub [1 ]) // Make offset=0 if empty or non-numeric
@@ -118,24 +161,32 @@ func main() {
118161 } else if t .Match (`^#define __NR_(\w+)\s+([0-9]+)` ) {
119162 prev , err = strconv .Atoi (t .sub [2 ])
120163 checkErr (err )
121- text += format (t .sub [1 ], prev , offset )
164+ nums . addSyscallNum ( format (t .sub [1 ], prev , offset ) )
122165 } else if t .Match (`^#define __NR3264_(\w+)\s+([0-9]+)` ) {
123166 prev , err = strconv .Atoi (t .sub [2 ])
124167 checkErr (err )
125- text += format (t .sub [1 ], prev , offset )
168+ nums . addSyscallNum ( format (t .sub [1 ], prev , offset ) )
126169 } else if t .Match (`^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)` ) {
127170 r2 , err := strconv .Atoi (t .sub [2 ])
128171 checkErr (err )
129- text += format (t .sub [1 ], prev + r2 , offset )
172+ nums . addSyscallNum ( format (t .sub [1 ], prev + r2 , offset ) )
130173 } else if t .Match (`^#define __NR_(\w+)\s+\(__NR_(?:SYSCALL_BASE|Linux) \+ ([0-9]+)` ) {
131174 r2 , err := strconv .Atoi (t .sub [2 ])
132175 checkErr (err )
133- text += format (t .sub [1 ], r2 , offset )
176+ nums .addSyscallNum (format (t .sub [1 ], r2 , offset ))
177+ } else if asOffset != 0 && t .Match (`^#define __NR_(\w+)\s+\(__NR_arch_specific_syscall \+ ([0-9]+)` ) {
178+ r2 , err := strconv .Atoi (t .sub [2 ])
179+ checkErr (err )
180+ nums .addSyscallNum (format (t .sub [1 ], r2 , asOffset ))
134181 }
135182 }
136183 err = s .Err ()
137184 checkErr (err )
138- fmt .Printf (template , cmdLine (), goBuildTags (), plusBuildTags (), text )
185+ var text strings.Builder
186+ for _ , num := range nums {
187+ text .WriteString (num .declaration )
188+ }
189+ fmt .Printf (template , cmdLine (), goBuildTags (), plusBuildTags (), text .String ())
139190}
140191
141192const template = `// %s
0 commit comments