@@ -13,6 +13,7 @@ import (
13
13
"os"
14
14
"os/exec"
15
15
"regexp"
16
+ "sort"
16
17
"strconv"
17
18
"strings"
18
19
)
@@ -36,15 +37,15 @@ func plusBuildTags() string {
36
37
return fmt .Sprintf ("%s,%s" , goarch , goos )
37
38
}
38
39
39
- func format (name string , num int , offset int ) string {
40
+ func format (name string , num int , offset int ) ( int , string ) {
40
41
if num > 999 {
41
42
// ignore deprecated syscalls that are no longer implemented
42
43
// 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 , ""
44
45
}
45
46
name = strings .ToUpper (name )
46
47
num = num + offset
47
- return fmt .Sprintf (" SYS_%s = %d;\n " , name , num )
48
+ return num , fmt .Sprintf (" SYS_%s = %d;\n " , name , num )
48
49
}
49
50
50
51
func checkErr (err error ) {
@@ -69,6 +70,36 @@ func (r *re) Match(exp string) bool {
69
70
return false
70
71
}
71
72
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
+
72
103
func main () {
73
104
// Get the OS and architecture (using GOARCH_TARGET if it exists)
74
105
goos = os .Getenv ("GOOS" )
@@ -100,11 +131,23 @@ func main() {
100
131
fmt .Fprintf (os .Stderr , "can't run %s" , cc )
101
132
os .Exit (1 )
102
133
}
103
- text := ""
104
134
s := bufio .NewScanner (strings .NewReader (string (cmd )))
105
- var offset , prev int
135
+ var offset , prev , asOffset int
136
+ var nums syscallNums
106
137
for s .Scan () {
107
138
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
+
108
151
if t .Match (`^#define __NR_Linux\s+([0-9]+)` ) {
109
152
// mips/mips64: extract offset
110
153
offset , _ = strconv .Atoi (t .sub [1 ]) // Make offset=0 if empty or non-numeric
@@ -118,24 +161,32 @@ func main() {
118
161
} else if t .Match (`^#define __NR_(\w+)\s+([0-9]+)` ) {
119
162
prev , err = strconv .Atoi (t .sub [2 ])
120
163
checkErr (err )
121
- text += format (t .sub [1 ], prev , offset )
164
+ nums . addSyscallNum ( format (t .sub [1 ], prev , offset ) )
122
165
} else if t .Match (`^#define __NR3264_(\w+)\s+([0-9]+)` ) {
123
166
prev , err = strconv .Atoi (t .sub [2 ])
124
167
checkErr (err )
125
- text += format (t .sub [1 ], prev , offset )
168
+ nums . addSyscallNum ( format (t .sub [1 ], prev , offset ) )
126
169
} else if t .Match (`^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)` ) {
127
170
r2 , err := strconv .Atoi (t .sub [2 ])
128
171
checkErr (err )
129
- text += format (t .sub [1 ], prev + r2 , offset )
172
+ nums . addSyscallNum ( format (t .sub [1 ], prev + r2 , offset ) )
130
173
} else if t .Match (`^#define __NR_(\w+)\s+\(__NR_(?:SYSCALL_BASE|Linux) \+ ([0-9]+)` ) {
131
174
r2 , err := strconv .Atoi (t .sub [2 ])
132
175
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 ))
134
181
}
135
182
}
136
183
err = s .Err ()
137
184
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 ())
139
190
}
140
191
141
192
const template = `// %s
0 commit comments