authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-06-22 18:33:22+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-07-29 09:50:41+02:00
log7e74276661fd76ce7d23b97e151aa9a6e367aea5
tree322f77e5e62d078398bf58baf54a696e1fbedada
parentf494a47ca5ac89fcc159d5db6c70763946193630
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

generate_linux_syscalls: Rework generation strategy for newer kernel ports.

If we're going to abuse the preprocessor, we may as well go all the way and have it generate a convenient format for us. This achieves two things: 1. We no longer need hacks for the arch-specific syscalls. 2. We now generate the correct syscall names for 32-bit platforms. The latter is because we now resolve __SC_3264, etc.

1 files changed, 69 insertions(+), 75 deletions(-)

tools/generate_linux_syscalls.zig+69-75
...@@ -10,7 +10,12 @@ const zig = std.zig;...@@ -10,7 +10,12 @@ const zig = std.zig;
10const fs = std.fs;10const fs = std.fs;
1111
12const stdlib_renames = std.StaticStringMap([]const u8).initComptime(.{12const stdlib_renames = std.StaticStringMap([]const u8).initComptime(.{
13 // Remove underscore prefix.
14 .{ "_llseek", "llseek" },
15 .{ "_newselect", "newselect" },
16 .{ "_sysctl", "sysctl" },
13 // Most 64-bit archs.17 // Most 64-bit archs.
18 .{ "newfstat", "fstat64" },
14 .{ "newfstatat", "fstatat64" },19 .{ "newfstatat", "fstatat64" },
15 // POWER.20 // POWER.
16 .{ "sync_file_range2", "sync_file_range" },21 .{ "sync_file_range2", "sync_file_range" },
...@@ -19,6 +24,24 @@ const stdlib_renames = std.StaticStringMap([]const u8).initComptime(.{...@@ -19,6 +24,24 @@ const stdlib_renames = std.StaticStringMap([]const u8).initComptime(.{
19 .{ "arm_fadvise64_64", "fadvise64_64" },24 .{ "arm_fadvise64_64", "fadvise64_64" },
20});25});
2126
27// Only for newer architectures where we use the C preprocessor.
28const stdlib_renames_new = std.StaticStringMap([]const u8).initComptime(.{
29 .{ "newuname", "uname" },
30 .{ "umount", "umount2" },
31});
32
33// We use this to deal with the fact that multiple syscalls can be mapped to sys_ni_syscall.
34// Thankfully it's only 2 well-known syscalls in newer kernel ports at the moment.
35fn getOverridenNameNew(value: []const u8) ?[]const u8 {
36 if (mem.eql(u8, value, "18")) {
37 return "sys_lookup_dcookie";
38 } else if (mem.eql(u8, value, "42")) {
39 return "sys_nfsservctl";
40 } else {
41 return null;
42 }
43}
44
22pub fn main() !void {45pub fn main() !void {
23 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);46 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
24 defer arena.deinit();47 defer arena.deinit();
...@@ -60,8 +83,9 @@ pub fn main() !void {...@@ -60,8 +83,9 @@ pub fn main() !void {
60 // abi is always i38683 // abi is always i386
61 _ = fields.next() orelse return error.Incomplete;84 _ = fields.next() orelse return error.Incomplete;
62 const name = fields.next() orelse return error.Incomplete;85 const name = fields.next() orelse return error.Incomplete;
86 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
6387
64 try writer.print(" {p} = {s},\n", .{ zig.fmtId(name), number });88 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
65 }89 }
6690
67 try writer.writeAll("};\n\n");91 try writer.writeAll("};\n\n");
...@@ -80,8 +104,8 @@ pub fn main() !void {...@@ -80,8 +104,8 @@ pub fn main() !void {
80 // The x32 abi syscalls are always at the end.104 // The x32 abi syscalls are always at the end.
81 if (mem.eql(u8, abi, "x32")) break;105 if (mem.eql(u8, abi, "x32")) break;
82 const name = fields.next() orelse return error.Incomplete;106 const name = fields.next() orelse return error.Incomplete;
83
84 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;107 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
108
85 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });109 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
86 }110 }
87111
...@@ -105,8 +129,8 @@ pub fn main() !void {...@@ -105,8 +129,8 @@ pub fn main() !void {
105 const abi = fields.next() orelse return error.Incomplete;129 const abi = fields.next() orelse return error.Incomplete;
106 if (mem.eql(u8, abi, "oabi")) continue;130 if (mem.eql(u8, abi, "oabi")) continue;
107 const name = fields.next() orelse return error.Incomplete;131 const name = fields.next() orelse return error.Incomplete;
108
109 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;132 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
133
110 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });134 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
111 }135 }
112136
...@@ -136,8 +160,9 @@ pub fn main() !void {...@@ -136,8 +160,9 @@ pub fn main() !void {
136 const abi = fields.next() orelse return error.Incomplete;160 const abi = fields.next() orelse return error.Incomplete;
137 if (mem.eql(u8, abi, "32")) continue;161 if (mem.eql(u8, abi, "32")) continue;
138 const name = fields.next() orelse return error.Incomplete;162 const name = fields.next() orelse return error.Incomplete;
163 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
139164
140 try writer.print(" {p} = {s},\n", .{ zig.fmtId(name), number });165 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
141 }166 }
142167
143 try writer.writeAll("};\n\n");168 try writer.writeAll("};\n\n");
...@@ -161,8 +186,9 @@ pub fn main() !void {...@@ -161,8 +186,9 @@ pub fn main() !void {
161 _ = fields.next() orelse return error.Incomplete;186 _ = fields.next() orelse return error.Incomplete;
162 const name = fields.next() orelse return error.Incomplete;187 const name = fields.next() orelse return error.Incomplete;
163 if (mem.startsWith(u8, name, "unused")) continue;188 if (mem.startsWith(u8, name, "unused")) continue;
189 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
164190
165 try writer.print(" {p} = Linux + {s},\n", .{ zig.fmtId(name), number });191 try writer.print(" {p} = Linux + {s},\n", .{ zig.fmtId(fixed_name), number });
166 }192 }
167193
168 try writer.writeAll("};\n\n");194 try writer.writeAll("};\n\n");
...@@ -232,11 +258,6 @@ pub fn main() !void {...@@ -232,11 +258,6 @@ pub fn main() !void {
232 // Newer architectures (starting with aarch64 c. 2012) now use the same C258 // Newer architectures (starting with aarch64 c. 2012) now use the same C
233 // header file for their syscall numbers. Arch-specific headers are used to259 // header file for their syscall numbers. Arch-specific headers are used to
234 // define pre-proc. vars that add additional (usually obsolete) syscalls.260 // define pre-proc. vars that add additional (usually obsolete) syscalls.
235 //
236 // TODO:
237 // - It would be better to use libclang/translate-c directly to extract the definitions.
238 // - The `-dD` option only does minimal pre-processing and doesn't resolve addition,
239 // so arch specific syscalls are dealt with manually.
240 {261 {
241 try writer.writeAll("pub const Arm64 = enum(usize) {\n");262 try writer.writeAll("pub const Arm64 = enum(usize) {\n");
242263
...@@ -254,6 +275,8 @@ pub fn main() !void {...@@ -254,6 +275,8 @@ pub fn main() !void {
254 // Using -I=[dir] includes the zig linux headers, which we don't want.275 // Using -I=[dir] includes the zig linux headers, which we don't want.
255 "-Iinclude",276 "-Iinclude",
256 "-Iinclude/uapi",277 "-Iinclude/uapi",
278 // Output the syscall in a format we can easily recognize.
279 "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
257 "arch/arm64/include/uapi/asm/unistd.h",280 "arch/arm64/include/uapi/asm/unistd.h",
258 };281 };
259282
...@@ -277,32 +300,24 @@ pub fn main() !void {...@@ -277,32 +300,24 @@ pub fn main() !void {
277 };300 };
278301
279 var lines = mem.tokenizeScalar(u8, defines, '\n');302 var lines = mem.tokenizeScalar(u8, defines, '\n');
280 loop: while (lines.next()) |line| {303 while (lines.next()) |line| {
281 var fields = mem.tokenizeAny(u8, line, " \t");304 var fields = mem.tokenizeAny(u8, line, " ");
282 const cmd = fields.next() orelse return error.Incomplete;305 const prefix = fields.next() orelse return error.Incomplete;
283 if (!mem.eql(u8, cmd, "#define")) continue;
284 const define = fields.next() orelse return error.Incomplete;
285 const number = fields.next() orelse continue;
286306
287 if (!std.ascii.isDigit(number[0])) continue;307 if (!mem.eql(u8, prefix, "zigsyscall")) continue;
288 if (!mem.startsWith(u8, define, "__NR")) continue;
289 const name = mem.trimLeft(u8, mem.trimLeft(u8, define, "__NR3264_"), "__NR_");
290 if (mem.eql(u8, name, "arch_specific_syscall")) continue;
291 if (mem.eql(u8, name, "syscalls")) break :loop;
292308
293 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;309 const sys_name = fields.next() orelse return error.Incomplete;
294 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });310 const value = fields.rest();
311 const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
312 const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
313
314 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
295 }315 }
296316
297 try writer.writeAll("};\n\n");317 try writer.writeAll("};\n\n");
298 }318 }
299 {319 {
300 try writer.writeAll(320 try writer.writeAll("pub const RiscV32 = enum(usize) {\n");
301 \\pub const RiscV32 = enum(usize) {
302 \\ pub const arch_specific_syscall = 244;
303 \\
304 \\
305 );
306321
307 const child_args = [_][]const u8{322 const child_args = [_][]const u8{
308 zig_exe,323 zig_exe,
...@@ -316,6 +331,7 @@ pub fn main() !void {...@@ -316,6 +331,7 @@ pub fn main() !void {
316 "-Iinclude",331 "-Iinclude",
317 "-Iinclude/uapi",332 "-Iinclude/uapi",
318 "-Iarch/riscv/include/uapi",333 "-Iarch/riscv/include/uapi",
334 "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
319 "arch/riscv/include/uapi/asm/unistd.h",335 "arch/riscv/include/uapi/asm/unistd.h",
320 };336 };
321337
...@@ -339,38 +355,24 @@ pub fn main() !void {...@@ -339,38 +355,24 @@ pub fn main() !void {
339 };355 };
340356
341 var lines = mem.tokenizeScalar(u8, defines, '\n');357 var lines = mem.tokenizeScalar(u8, defines, '\n');
342 loop: while (lines.next()) |line| {358 while (lines.next()) |line| {
343 var fields = mem.tokenizeAny(u8, line, " \t");359 var fields = mem.tokenizeAny(u8, line, " ");
344 const cmd = fields.next() orelse return error.Incomplete;360 const prefix = fields.next() orelse return error.Incomplete;
345 if (!mem.eql(u8, cmd, "#define")) continue;
346 const define = fields.next() orelse return error.Incomplete;
347 const number = fields.next() orelse continue;
348361
349 if (!std.ascii.isDigit(number[0])) continue;362 if (!mem.eql(u8, prefix, "zigsyscall")) continue;
350 if (!mem.startsWith(u8, define, "__NR")) continue;
351 const name = mem.trimLeft(u8, mem.trimLeft(u8, define, "__NR3264_"), "__NR_");
352 if (mem.eql(u8, name, "arch_specific_syscall")) continue;
353 if (mem.eql(u8, name, "syscalls")) break :loop;
354363
355 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;364 const sys_name = fields.next() orelse return error.Incomplete;
356 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });365 const value = fields.rest();
366 const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
367 const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
368
369 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
357 }370 }
358371
359 try writer.writeAll(372 try writer.writeAll("};\n\n");
360 \\
361 \\ riscv_flush_icache = arch_specific_syscall + 15,
362 \\ riscv_hwprobe = arch_specific_syscall + 14,
363 \\};
364 \\
365 );
366 }373 }
367 {374 {
368 try writer.writeAll(375 try writer.writeAll("pub const RiscV64 = enum(usize) {\n");
369 \\pub const RiscV64 = enum(usize) {
370 \\ pub const arch_specific_syscall = 244;
371 \\
372 \\
373 );
374376
375 const child_args = [_][]const u8{377 const child_args = [_][]const u8{
376 zig_exe,378 zig_exe,
...@@ -384,6 +386,7 @@ pub fn main() !void {...@@ -384,6 +386,7 @@ pub fn main() !void {
384 "-Iinclude",386 "-Iinclude",
385 "-Iinclude/uapi",387 "-Iinclude/uapi",
386 "-Iarch/riscv/include/uapi",388 "-Iarch/riscv/include/uapi",
389 "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
387 "arch/riscv/include/uapi/asm/unistd.h",390 "arch/riscv/include/uapi/asm/unistd.h",
388 };391 };
389392
...@@ -407,30 +410,21 @@ pub fn main() !void {...@@ -407,30 +410,21 @@ pub fn main() !void {
407 };410 };
408411
409 var lines = mem.tokenizeScalar(u8, defines, '\n');412 var lines = mem.tokenizeScalar(u8, defines, '\n');
410 loop: while (lines.next()) |line| {413 while (lines.next()) |line| {
411 var fields = mem.tokenizeAny(u8, line, " \t");414 var fields = mem.tokenizeAny(u8, line, " ");
412 const cmd = fields.next() orelse return error.Incomplete;415 const prefix = fields.next() orelse return error.Incomplete;
413 if (!mem.eql(u8, cmd, "#define")) continue;
414 const define = fields.next() orelse return error.Incomplete;
415 const number = fields.next() orelse continue;
416416
417 if (!std.ascii.isDigit(number[0])) continue;417 if (!mem.eql(u8, prefix, "zigsyscall")) continue;
418 if (!mem.startsWith(u8, define, "__NR")) continue;
419 const name = mem.trimLeft(u8, mem.trimLeft(u8, define, "__NR3264_"), "__NR_");
420 if (mem.eql(u8, name, "arch_specific_syscall")) continue;
421 if (mem.eql(u8, name, "syscalls")) break :loop;
422418
423 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;419 const sys_name = fields.next() orelse return error.Incomplete;
424 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });420 const value = fields.rest();
421 const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
422 const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
423
424 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
425 }425 }
426426
427 try writer.writeAll(427 try writer.writeAll("};\n\n");
428 \\
429 \\ riscv_flush_icache = arch_specific_syscall + 15,
430 \\ riscv_hwprobe = arch_specific_syscall + 14,
431 \\};
432 \\
433 );
434 }428 }
435 {429 {
436 try writer.writeAll(430 try writer.writeAll(