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;
1010const fs = std.fs;
1111
1212const stdlib_renames = std.StaticStringMap([]const u8).initComptime(.{
13 // Remove underscore prefix.
14 .{ "_llseek", "llseek" },
15 .{ "_newselect", "newselect" },
16 .{ "_sysctl", "sysctl" },
1317 // Most 64-bit archs.
18 .{ "newfstat", "fstat64" },
1419 .{ "newfstatat", "fstatat64" },
1520 // POWER.
1621 .{ "sync_file_range2", "sync_file_range" },
......@@ -19,6 +24,24 @@ const stdlib_renames = std.StaticStringMap([]const u8).initComptime(.{
1924 .{ "arm_fadvise64_64", "fadvise64_64" },
2025});
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
2245pub fn main() !void {
2346 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
2447 defer arena.deinit();
......@@ -60,8 +83,9 @@ pub fn main() !void {
6083 // abi is always i386
6184 _ = fields.next() orelse return error.Incomplete;
6285 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 });
6589 }
6690
6791 try writer.writeAll("};\n\n");
......@@ -80,8 +104,8 @@ pub fn main() !void {
80104 // The x32 abi syscalls are always at the end.
81105 if (mem.eql(u8, abi, "x32")) break;
82106 const name = fields.next() orelse return error.Incomplete;
83
84107 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
108
85109 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
86110 }
87111
......@@ -105,8 +129,8 @@ pub fn main() !void {
105129 const abi = fields.next() orelse return error.Incomplete;
106130 if (mem.eql(u8, abi, "oabi")) continue;
107131 const name = fields.next() orelse return error.Incomplete;
108
109132 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
133
110134 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
111135 }
112136
......@@ -136,8 +160,9 @@ pub fn main() !void {
136160 const abi = fields.next() orelse return error.Incomplete;
137161 if (mem.eql(u8, abi, "32")) continue;
138162 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 });
141166 }
142167
143168 try writer.writeAll("};\n\n");
......@@ -161,8 +186,9 @@ pub fn main() !void {
161186 _ = fields.next() orelse return error.Incomplete;
162187 const name = fields.next() orelse return error.Incomplete;
163188 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 });
166192 }
167193
168194 try writer.writeAll("};\n\n");
......@@ -232,11 +258,6 @@ pub fn main() !void {
232258 // Newer architectures (starting with aarch64 c. 2012) now use the same C
233259 // header file for their syscall numbers. Arch-specific headers are used to
234260 // 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.
240261 {
241262 try writer.writeAll("pub const Arm64 = enum(usize) {\n");
242263
......@@ -254,6 +275,8 @@ pub fn main() !void {
254275 // Using -I=[dir] includes the zig linux headers, which we don't want.
255276 "-Iinclude",
256277 "-Iinclude/uapi",
278 // Output the syscall in a format we can easily recognize.
279 "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
257280 "arch/arm64/include/uapi/asm/unistd.h",
258281 };
259282
......@@ -277,32 +300,24 @@ pub fn main() !void {
277300 };
278301
279302 var lines = mem.tokenizeScalar(u8, defines, '\n');
280 loop: while (lines.next()) |line| {
281 var fields = mem.tokenizeAny(u8, line, " \t");
282 const cmd = 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;
303 while (lines.next()) |line| {
304 var fields = mem.tokenizeAny(u8, line, " ");
305 const prefix = fields.next() orelse return error.Incomplete;
286306
287 if (!std.ascii.isDigit(number[0])) 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;
307 if (!mem.eql(u8, prefix, "zigsyscall")) continue;
292308
293 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
294 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
309 const sys_name = fields.next() orelse return error.Incomplete;
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 });
295315 }
296316
297317 try writer.writeAll("};\n\n");
298318 }
299319 {
300 try writer.writeAll(
301 \\pub const RiscV32 = enum(usize) {
302 \\ pub const arch_specific_syscall = 244;
303 \\
304 \\
305 );
320 try writer.writeAll("pub const RiscV32 = enum(usize) {\n");
306321
307322 const child_args = [_][]const u8{
308323 zig_exe,
......@@ -316,6 +331,7 @@ pub fn main() !void {
316331 "-Iinclude",
317332 "-Iinclude/uapi",
318333 "-Iarch/riscv/include/uapi",
334 "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
319335 "arch/riscv/include/uapi/asm/unistd.h",
320336 };
321337
......@@ -339,38 +355,24 @@ pub fn main() !void {
339355 };
340356
341357 var lines = mem.tokenizeScalar(u8, defines, '\n');
342 loop: while (lines.next()) |line| {
343 var fields = mem.tokenizeAny(u8, line, " \t");
344 const cmd = 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;
358 while (lines.next()) |line| {
359 var fields = mem.tokenizeAny(u8, line, " ");
360 const prefix = fields.next() orelse return error.Incomplete;
348361
349 if (!std.ascii.isDigit(number[0])) 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;
362 if (!mem.eql(u8, prefix, "zigsyscall")) continue;
354363
355 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
356 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
364 const sys_name = fields.next() orelse return error.Incomplete;
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 });
357370 }
358371
359 try writer.writeAll(
360 \\
361 \\ riscv_flush_icache = arch_specific_syscall + 15,
362 \\ riscv_hwprobe = arch_specific_syscall + 14,
363 \\};
364 \\
365 );
372 try writer.writeAll("};\n\n");
366373 }
367374 {
368 try writer.writeAll(
369 \\pub const RiscV64 = enum(usize) {
370 \\ pub const arch_specific_syscall = 244;
371 \\
372 \\
373 );
375 try writer.writeAll("pub const RiscV64 = enum(usize) {\n");
374376
375377 const child_args = [_][]const u8{
376378 zig_exe,
......@@ -384,6 +386,7 @@ pub fn main() !void {
384386 "-Iinclude",
385387 "-Iinclude/uapi",
386388 "-Iarch/riscv/include/uapi",
389 "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
387390 "arch/riscv/include/uapi/asm/unistd.h",
388391 };
389392
......@@ -407,30 +410,21 @@ pub fn main() !void {
407410 };
408411
409412 var lines = mem.tokenizeScalar(u8, defines, '\n');
410 loop: while (lines.next()) |line| {
411 var fields = mem.tokenizeAny(u8, line, " \t");
412 const cmd = 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;
413 while (lines.next()) |line| {
414 var fields = mem.tokenizeAny(u8, line, " ");
415 const prefix = fields.next() orelse return error.Incomplete;
416416
417 if (!std.ascii.isDigit(number[0])) 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;
417 if (!mem.eql(u8, prefix, "zigsyscall")) continue;
422418
423 const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
424 try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
419 const sys_name = fields.next() orelse return error.Incomplete;
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 });
425425 }
426426
427 try writer.writeAll(
428 \\
429 \\ riscv_flush_icache = arch_specific_syscall + 15,
430 \\ riscv_hwprobe = arch_specific_syscall + 14,
431 \\};
432 \\
433 );
427 try writer.writeAll("};\n\n");
434428 }
435429 {
436430 try writer.writeAll(