Commit 724804a4e0
Changed files (1)
tools/generate_linux_syscalls.zig
@@ -48,100 +48,132 @@ fn isReservedNameOld(name: []const u8) bool {
std.mem.startsWith(u8, name, "unused");
}
-pub fn main() !void {
- var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
- defer arena.deinit();
- const allocator = arena.allocator();
-
- const args = try std.process.argsAlloc(allocator);
- if (args.len < 3 or mem.eql(u8, args[1], "--help"))
- usageAndExit(std.io.getStdErr(), args[0], 1);
- const zig_exe = args[1];
- const linux_path = args[2];
-
- var buf_out = std.io.bufferedWriter(std.io.getStdOut().writer());
- const writer = buf_out.writer();
-
- // As of 5.17.1, the largest table is 23467 bytes.
- // 32k should be enough for now.
- const buf = try allocator.alloc(u8, 1 << 15);
- const linux_dir = try std.fs.openDirAbsolute(linux_path, .{});
-
- try writer.writeAll(
- \\// This file is automatically generated.
- \\// See tools/generate_linux_syscalls.zig for more info.
- \\
- \\
- );
-
- // These architectures have their syscall definitions generated from a TSV
- // file, processed via scripts/syscallhdr.sh.
- {
- try writer.writeAll("pub const X86 = enum(usize) {\n");
-
- const table = try linux_dir.readFile("arch/x86/entry/syscalls/syscall_32.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- // abi is always i386
- _ = fields.next() orelse return error.Incomplete;
- const name = fields.next() orelse return error.Incomplete;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
- }
-
- try writer.writeAll("};\n\n");
- }
- {
- try writer.writeAll("pub const X64 = enum(usize) {\n");
-
- const table = try linux_dir.readFile("arch/x86/entry/syscalls/syscall_64.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- const abi = fields.next() orelse return error.Incomplete;
- // The x32 abi syscalls are always at the end.
- if (mem.eql(u8, abi, "x32")) break;
- const name = fields.next() orelse return error.Incomplete;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
- }
-
- try writer.writeAll("};\n\n");
- }
- {
- try writer.writeAll(
- \\pub const Arm = enum(usize) {
- \\ const arm_base = 0x0f0000;
- \\
- \\
- );
-
- const table = try linux_dir.readFile("arch/arm/tools/syscall.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- const abi = fields.next() orelse return error.Incomplete;
- if (mem.eql(u8, abi, "oabi")) continue;
- const name = fields.next() orelse return error.Incomplete;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
+const default_args: []const []const u8 = &.{
+ "-E",
+ // -dM is cleaner, but -dD preserves iteration order.
+ "-dD",
+ // No need for line-markers.
+ "-P",
+ "-nostdinc",
+ // Using -I=[dir] includes the zig linux headers, which we don't want.
+ "-Itools/include",
+ "-Itools/include/uapi",
+ // Output the syscall in a format we can easily recognize.
+ "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
+};
+
+const ProcessPreprocessedFileFn = *const fn (bytes: []const u8, writer: anytype) anyerror!void;
+const ProcessTableBasedArchFileFn = *const fn (
+ bytes: []const u8,
+ filters: Filters,
+ writer: anytype,
+ optional_writer: anytype,
+) anyerror!void;
+
+const FlowControl = enum {
+ @"break",
+ @"continue",
+ none,
+};
+
+const AbiCheckParams = struct { abi: []const u8, flow: FlowControl };
+
+const Filters = struct {
+ abiCheckParams: ?AbiCheckParams,
+ fixedName: ?*const fn (name: []const u8) []const u8,
+ isReservedNameOld: ?*const fn (name: []const u8) bool,
+};
+
+fn abiCheck(abi: []const u8, params: *const AbiCheckParams) FlowControl {
+ if (mem.eql(u8, abi, params.abi)) return params.flow;
+ return .none;
+}
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
- }
+fn fixedName(name: []const u8) []const u8 {
+ return if (stdlib_renames.get(name)) |fixed| fixed else name;
+}
- // TODO: maybe extract these from arch/arm/include/uapi/asm/unistd.h
- try writer.writeAll(
+const ArchInfo = union(enum) {
+ table: struct {
+ name: []const u8,
+ enum_name: []const u8,
+ file_path: []const u8,
+ header: ?[]const u8,
+ extra_values: ?[]const u8,
+ process_file: ProcessTableBasedArchFileFn,
+ filters: Filters,
+ additional_enum: ?[]const u8,
+ },
+ preprocessor: struct {
+ name: []const u8,
+ enum_name: []const u8,
+ file_path: []const u8,
+ child_options: struct {
+ comptime additional_args: ?[]const []const u8 = null,
+ target: []const u8,
+
+ pub inline fn getArgs(self: *const @This(), zig_exe: []const u8, file_path: []const u8) []const []const u8 {
+ const additional_args: []const []const u8 = self.additional_args orelse &.{};
+ return .{ zig_exe, "cc" } ++ additional_args ++ .{ "-target", self.target } ++ default_args ++ .{file_path};
+ }
+ },
+ header: ?[]const u8,
+ extra_values: ?[]const u8,
+ process_file: ProcessPreprocessedFileFn,
+ additional_enum: ?[]const u8,
+ },
+};
+
+const arch_infos = [_]ArchInfo{
+ .{
+ // These architectures have their syscall definitions generated from a TSV
+ // file, processed via scripts/syscallhdr.sh.
+ .table = .{
+ .name = "x86",
+ .enum_name = "X86",
+ .file_path = "arch/x86/entry/syscalls/syscall_32.tbl",
+ .process_file = &processTableBasedArch,
+ .filters = .{
+ .abiCheckParams = null,
+ .fixedName = &fixedName,
+ .isReservedNameOld = null,
+ },
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "x64",
+ .enum_name = "X64",
+ .file_path = "arch/x86/entry/syscalls/syscall_64.tbl",
+ .process_file = &processTableBasedArch,
+ .filters = .{
+ // The x32 abi syscalls are always at the end.
+ .abiCheckParams = .{ .abi = "x32", .flow = .@"break" },
+ .fixedName = &fixedName,
+ .isReservedNameOld = null,
+ },
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "arm",
+ .enum_name = "Arm",
+ .file_path = "arch/arm/tools/syscall.tbl",
+ .process_file = &processTableBasedArch,
+ .filters = .{
+ .abiCheckParams = .{ .abi = "oabi", .flow = .@"continue" },
+ .fixedName = &fixedName,
+ .isReservedNameOld = null,
+ },
+ .header = " const arm_base = 0x0f0000;\n\n",
+ // TODO: maybe extract these from arch/arm/include/uapi/asm/unistd.h
+ .extra_values =
\\
\\ breakpoint = arm_base + 1,
\\ cacheflush = arm_base + 2,
@@ -149,609 +181,514 @@ pub fn main() !void {
\\ usr32 = arm_base + 4,
\\ set_tls = arm_base + 5,
\\ get_tls = arm_base + 6,
- \\};
- \\
\\
- );
- }
- {
- try writer.writeAll("pub const Sparc = enum(usize) {\n");
- const table = try linux_dir.readFile("arch/sparc/kernel/syscalls/syscall.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- const abi = fields.next() orelse return error.Incomplete;
- if (mem.eql(u8, abi, "64")) continue;
- const name = fields.next() orelse return error.Incomplete;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
- }
-
- try writer.writeAll("};\n\n");
- }
- {
- try writer.writeAll("pub const Sparc64 = enum(usize) {\n");
- const table = try linux_dir.readFile("arch/sparc/kernel/syscalls/syscall.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- const abi = fields.next() orelse return error.Incomplete;
- if (mem.eql(u8, abi, "32")) continue;
- const name = fields.next() orelse return error.Incomplete;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
- }
-
- try writer.writeAll("};\n\n");
+ ,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "sparc",
+ .enum_name = "Sparc",
+ .file_path = "arch/sparc/kernel/syscalls/syscall.tbl",
+ .process_file = &processTableBasedArch,
+ .filters = .{
+ .abiCheckParams = .{ .abi = "64", .flow = .@"continue" },
+ .fixedName = &fixedName,
+ .isReservedNameOld = null,
+ },
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "sparc64",
+ .enum_name = "Sparc64",
+ .file_path = "arch/sparc/kernel/syscalls/syscall.tbl",
+ .process_file = &processTableBasedArch,
+ .filters = .{
+ .abiCheckParams = .{ .abi = "32", .flow = .@"continue" },
+ .fixedName = &fixedName,
+ .isReservedNameOld = null,
+ },
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "m68k",
+ .enum_name = "M68k",
+ .file_path = "arch/m68k/kernel/syscalls/syscall.tbl",
+ .process_file = &processTableBasedArch,
+ .filters = .{
+ // abi is always common
+ .abiCheckParams = null,
+ .fixedName = &fixedName,
+ .isReservedNameOld = null,
+ },
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "mips_o32",
+ .enum_name = "MipsO32",
+ .file_path = "arch/mips/kernel/syscalls/syscall_o32.tbl",
+ .process_file = &processMipsBasedArch,
+ .filters = .{
+ // abi is always o32
+ .abiCheckParams = null,
+ .fixedName = &fixedName,
+ .isReservedNameOld = &isReservedNameOld,
+ },
+ .header = " const linux_base = 4000;\n\n",
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "mips_n64",
+ .enum_name = "MipsN64",
+ .file_path = "arch/mips/kernel/syscalls/syscall_n64.tbl",
+ .process_file = &processMipsBasedArch,
+ .filters = .{
+ // abi is always n64
+ .abiCheckParams = null,
+ .fixedName = &fixedName,
+ .isReservedNameOld = &isReservedNameOld,
+ },
+ .header = " const linux_base = 5000;\n\n",
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "mips_n32",
+ .enum_name = "MipsN32",
+ .file_path = "arch/mips/kernel/syscalls/syscall_n32.tbl",
+ .process_file = &processMipsBasedArch,
+ .filters = .{
+ // abi is always n32
+ .abiCheckParams = null,
+ .fixedName = &fixedName,
+ .isReservedNameOld = &isReservedNameOld,
+ },
+ .header = " const linux_base = 6000;\n\n",
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "powerpc",
+ .enum_name = "PowerPC",
+ .file_path = "arch/powerpc/kernel/syscalls/syscall.tbl",
+ .process_file = &processPowerPcBasedArch,
+ .filters = .{
+ .abiCheckParams = null,
+ .fixedName = null,
+ .isReservedNameOld = null,
+ },
+ .header = null,
+ .extra_values = null,
+ .additional_enum = "PowerPC64",
+ },
+ },
+ .{
+ .table = .{
+ .name = "s390x",
+ .enum_name = "S390x",
+ .file_path = "arch/s390/kernel/syscalls/syscall.tbl",
+ .process_file = &processTableBasedArch,
+ .filters = .{
+ // 32-bit s390 support in linux is deprecated
+ .abiCheckParams = .{ .abi = "32", .flow = .@"continue" },
+ .fixedName = &fixedName,
+ .isReservedNameOld = null,
+ },
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .table = .{
+ .name = "xtensa",
+ .enum_name = "Xtensa",
+ .file_path = "arch/xtensa/kernel/syscalls/syscall.tbl",
+ .process_file = &processTableBasedArch,
+ .filters = .{
+ // abi is always common
+ .abiCheckParams = null,
+ .fixedName = fixedName,
+ .isReservedNameOld = &isReservedNameOld,
+ },
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .preprocessor = .{
+ .name = "arm64",
+ .enum_name = "Arm64",
+ .file_path = "arch/arm64/include/uapi/asm/unistd.h",
+ .child_options = .{
+ .additional_args = null,
+ .target = "aarch64-freestanding-none",
+ },
+ .process_file = &processPreprocessedFile,
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .preprocessor = .{
+ .name = "riscv32",
+ .enum_name = "RiscV32",
+ .file_path = "arch/riscv/include/uapi/asm/unistd.h",
+ .child_options = .{
+ .additional_args = null,
+ .target = "riscv32-freestanding-none",
+ },
+ .process_file = &processPreprocessedFile,
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .preprocessor = .{
+ .name = "riscv64",
+ .enum_name = "RiscV64",
+ .file_path = "arch/riscv/include/uapi/asm/unistd.h",
+ .child_options = .{
+ .additional_args = null,
+ .target = "riscv64-freestanding-none",
+ },
+ .process_file = &processPreprocessedFile,
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .preprocessor = .{
+ .name = "loongarch",
+ .enum_name = "LoongArch64",
+ .file_path = "arch/loongarch/include/uapi/asm/unistd.h",
+ .child_options = .{
+ .additional_args = null,
+ .target = "loongarch64-freestanding-none",
+ },
+ .process_file = &processPreprocessedFile,
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .preprocessor = .{
+ .name = "arc",
+ .enum_name = "Arc",
+ .file_path = "arch/arc/include/uapi/asm/unistd.h",
+ .child_options = .{
+ .additional_args = null,
+ .target = "arc-freestanding-none",
+ },
+ .process_file = &processPreprocessedFile,
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .preprocessor = .{
+ .name = "csky",
+ .enum_name = "CSky",
+ .file_path = "arch/csky/include/uapi/asm/unistd.h",
+ .child_options = .{
+ .additional_args = null,
+ .target = "csky-freestanding-none",
+ },
+ .process_file = &processPreprocessedFile,
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+ .{
+ .preprocessor = .{
+ .name = "hexagon",
+ .enum_name = "Hexagon",
+ .file_path = "arch/hexagon/include/uapi/asm/unistd.h",
+ .child_options = .{
+ .additional_args = null,
+ .target = "hexagon-freestanding-none",
+ },
+ .process_file = &processPreprocessedFile,
+ .header = null,
+ .extra_values = null,
+ .additional_enum = null,
+ },
+ },
+};
+
+fn processPreprocessedFile(
+ bytes: []const u8,
+ writer: anytype,
+) !void {
+ var lines = mem.tokenizeScalar(u8, bytes, '\n');
+ while (lines.next()) |line| {
+ var fields = mem.tokenizeAny(u8, line, " ");
+ const prefix = fields.next() orelse return error.Incomplete;
+
+ if (!mem.eql(u8, prefix, "zigsyscall")) continue;
+
+ const sys_name = fields.next() orelse return error.Incomplete;
+ const value = fields.rest();
+ const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
+ const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
+
+ try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
}
- {
- try writer.writeAll("pub const M68k = enum(usize) {\n");
-
- const table = try linux_dir.readFile("arch/m68k/kernel/syscalls/syscall.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- // abi is always common
- _ = fields.next() orelse return error.Incomplete;
- const name = fields.next() orelse return error.Incomplete;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
+}
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
+fn processTableBasedArch(
+ bytes: []const u8,
+ filters: Filters,
+ writer: anytype,
+ optional_writer: anytype,
+) !void {
+ _ = optional_writer;
+
+ var lines = mem.tokenizeScalar(u8, bytes, '\n');
+ while (lines.next()) |line| {
+ if (line[0] == '#') continue;
+
+ var fields = mem.tokenizeAny(u8, line, " \t");
+ const number = fields.next() orelse return error.Incomplete;
+
+ const abi = fields.next() orelse return error.Incomplete;
+ if (filters.abiCheckParams) |*params| {
+ switch (abiCheck(abi, params)) {
+ .none => {},
+ .@"break" => break,
+ .@"continue" => continue,
+ }
}
-
- try writer.writeAll("};\n\n");
- }
- {
- try writer.writeAll(
- \\pub const MipsO32 = enum(usize) {
- \\ const linux_base = 4000;
- \\
- \\
- );
-
- const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_o32.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- // abi is always o32
- _ = fields.next() orelse return error.Incomplete;
- const name = fields.next() orelse return error.Incomplete;
- if (isReservedNameOld(name)) continue;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- try writer.print(" {p} = linux_base + {s},\n", .{ zig.fmtId(fixed_name), number });
+ const name = fields.next() orelse return error.Incomplete;
+ if (filters.isReservedNameOld) |isReservedNameOldFn| {
+ if (isReservedNameOldFn(name)) continue;
}
+ const fixed_name = if (filters.fixedName) |fixedNameFn| fixedNameFn(name) else name;
- try writer.writeAll("};\n\n");
+ try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
}
- {
- try writer.writeAll(
- \\pub const MipsN64 = enum(usize) {
- \\ const linux_base = 5000;
- \\
- \\
- );
-
- const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_n64.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- // abi is always n64
- _ = fields.next() orelse return error.Incomplete;
- const name = fields.next() orelse return error.Incomplete;
- if (isReservedNameOld(name)) continue;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- try writer.print(" {p} = linux_base + {s},\n", .{ zig.fmtId(fixed_name), number });
- }
-
- try writer.writeAll("};\n\n");
- }
- {
- try writer.writeAll(
- \\pub const MipsN32 = enum(usize) {
- \\ const linux_base = 6000;
- \\
- \\
- );
-
- const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_n32.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- // abi is always n32
- _ = fields.next() orelse return error.Incomplete;
- const name = fields.next() orelse return error.Incomplete;
- if (isReservedNameOld(name)) continue;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- try writer.print(" {p} = linux_base + {s},\n", .{ zig.fmtId(fixed_name), number });
- }
+}
- try writer.writeAll("};\n\n");
- }
- {
- try writer.writeAll("pub const PowerPC = enum(usize) {\n");
-
- const table = try linux_dir.readFile("arch/powerpc/kernel/syscalls/syscall.tbl", buf);
- var list_64 = std.ArrayList(u8).init(allocator);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- const abi = fields.next() orelse return error.Incomplete;
- const name = fields.next() orelse return error.Incomplete;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- if (mem.eql(u8, abi, "spu")) {
- continue;
- } else if (mem.eql(u8, abi, "32")) {
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
- } else if (mem.eql(u8, abi, "64")) {
- try list_64.writer().print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
- } else { // common/nospu
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
- try list_64.writer().print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
+fn processMipsBasedArch(
+ bytes: []const u8,
+ filters: Filters,
+ writer: anytype,
+ optional_writer: anytype,
+) !void {
+ _ = optional_writer;
+
+ var lines = mem.tokenizeScalar(u8, bytes, '\n');
+ while (lines.next()) |line| {
+ if (line[0] == '#') continue;
+
+ var fields = mem.tokenizeAny(u8, line, " \t");
+ const number = fields.next() orelse return error.Incomplete;
+
+ const abi = fields.next() orelse return error.Incomplete;
+ if (filters.abiCheckParams) |*params| {
+ switch (abiCheck(abi, params)) {
+ .none => {},
+ .@"break" => break,
+ .@"continue" => continue,
}
}
-
- try writer.writeAll(
- \\};
- \\
- \\pub const PowerPC64 = enum(usize) {
- \\
- );
- try writer.writeAll(list_64.items);
- try writer.writeAll("};\n\n");
- }
- {
- try writer.writeAll("pub const S390x = enum(usize) {\n");
-
- const table = try linux_dir.readFile("arch/s390/kernel/syscalls/syscall.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- const abi = fields.next() orelse return error.Incomplete;
- if (mem.eql(u8, abi, "32")) continue; // 32-bit s390 support in linux is deprecated
- const name = fields.next() orelse return error.Incomplete;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
+ const name = fields.next() orelse return error.Incomplete;
+ if (filters.isReservedNameOld) |isReservedNameOldFn| {
+ if (isReservedNameOldFn(name)) continue;
}
+ const fixed_name = if (filters.fixedName) |fixedNameFn| fixedNameFn(name) else name;
- try writer.writeAll("};\n\n");
+ try writer.print(" {p} = linux_base + {s},\n", .{ zig.fmtId(fixed_name), number });
}
- {
- try writer.writeAll("pub const Xtensa = enum(usize) {\n");
-
- const table = try linux_dir.readFile("arch/xtensa/kernel/syscalls/syscall.tbl", buf);
- var lines = mem.tokenizeScalar(u8, table, '\n');
- while (lines.next()) |line| {
- if (line[0] == '#') continue;
-
- var fields = mem.tokenizeAny(u8, line, " \t");
- const number = fields.next() orelse return error.Incomplete;
- // abi is always common
- _ = fields.next() orelse return error.Incomplete;
- const name = fields.next() orelse return error.Incomplete;
- if (isReservedNameOld(name)) continue;
- const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
+}
+fn processPowerPcBasedArch(
+ bytes: []const u8,
+ filters: Filters,
+ writer: anytype,
+ optional_writer: anytype,
+) !void {
+ _ = filters;
+ var lines = mem.tokenizeScalar(u8, bytes, '\n');
+
+ while (lines.next()) |line| {
+ if (line[0] == '#') continue;
+
+ var fields = mem.tokenizeAny(u8, line, " \t");
+ const number = fields.next() orelse return error.Incomplete;
+ const abi = fields.next() orelse return error.Incomplete;
+ const name = fields.next() orelse return error.Incomplete;
+ const fixed_name = if (stdlib_renames.get(name)) |fixed| fixed else name;
+
+ if (mem.eql(u8, abi, "spu")) {
+ continue;
+ } else if (mem.eql(u8, abi, "32")) {
+ try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
+ } else if (mem.eql(u8, abi, "64")) {
+ try optional_writer.?.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
+ } else { // common/nospu
try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
+ try optional_writer.?.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
}
-
- try writer.writeAll("};\n\n");
}
+}
- // Newer architectures (starting with aarch64 c. 2012) now use the same C
- // header file for their syscall numbers. Arch-specific headers are used to
- // define pre-proc. vars that add additional (usually obsolete) syscalls.
- {
- try writer.writeAll("pub const Arm64 = enum(usize) {\n");
-
- const child_args = [_][]const u8{
- zig_exe,
- "cc",
- "-target",
- "aarch64-linux-gnu",
- "-E",
- // -dM is cleaner, but -dD preserves iteration order.
- "-dD",
- // No need for line-markers.
- "-P",
- "-nostdinc",
- // Using -I=[dir] includes the zig linux headers, which we don't want.
- "-Itools/include",
- "-Itools/include/uapi",
- // Output the syscall in a format we can easily recognize.
- "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
- "arch/arm64/include/uapi/asm/unistd.h",
- };
-
- const child_result = try std.process.Child.run(.{
- .allocator = allocator,
- .argv = &child_args,
- .cwd = linux_path,
- .cwd_dir = linux_dir,
- });
- if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr});
-
- const defines = switch (child_result.term) {
- .Exited => |code| if (code == 0) child_result.stdout else {
- std.debug.print("zig cc exited with code {d}\n", .{code});
- std.process.exit(1);
- },
- else => {
- std.debug.print("zig cc crashed\n", .{});
- std.process.exit(1);
- },
- };
+fn generateSyscallsFromTable(
+ allocator: std.mem.Allocator,
+ buf: []u8,
+ linux_dir: std.fs.Dir,
+ writer: anytype,
+ _arch_info: *const ArchInfo,
+) !void {
+ std.debug.assert(_arch_info.* == .table);
- var lines = mem.tokenizeScalar(u8, defines, '\n');
- while (lines.next()) |line| {
- var fields = mem.tokenizeAny(u8, line, " ");
- const prefix = fields.next() orelse return error.Incomplete;
+ const arch_info = _arch_info.table;
- if (!mem.eql(u8, prefix, "zigsyscall")) continue;
+ const table = try linux_dir.readFile(arch_info.file_path, buf);
- const sys_name = fields.next() orelse return error.Incomplete;
- const value = fields.rest();
- const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
- const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
+ var optional_array_list: ?std.ArrayList(u8) = if (arch_info.additional_enum) |_| std.ArrayList(u8).init(allocator) else null;
+ const optional_writer = if (optional_array_list) |_| optional_array_list.?.writer() else null;
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
- }
+ try writer.print("pub const {s} = enum(usize) {{\n", .{arch_info.enum_name});
- try writer.writeAll("};\n\n");
+ if (arch_info.header) |header| {
+ try writer.writeAll(header);
}
- {
- try writer.writeAll("pub const RiscV32 = enum(usize) {\n");
-
- const child_args = [_][]const u8{
- zig_exe,
- "cc",
- "-target",
- "riscv32-linux-gnuilp32",
- "-E",
- "-dD",
- "-P",
- "-nostdinc",
- "-Itools/include",
- "-Itools/include/uapi",
- "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
- "arch/riscv/include/uapi/asm/unistd.h",
- };
-
- const child_result = try std.process.Child.run(.{
- .allocator = allocator,
- .argv = &child_args,
- .cwd = linux_path,
- .cwd_dir = linux_dir,
- });
- if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr});
-
- const defines = switch (child_result.term) {
- .Exited => |code| if (code == 0) child_result.stdout else {
- std.debug.print("zig cc exited with code {d}\n", .{code});
- std.process.exit(1);
- },
- else => {
- std.debug.print("zig cc crashed\n", .{});
- std.process.exit(1);
- },
- };
- var lines = mem.tokenizeScalar(u8, defines, '\n');
- while (lines.next()) |line| {
- var fields = mem.tokenizeAny(u8, line, " ");
- const prefix = fields.next() orelse return error.Incomplete;
+ try arch_info.process_file(table, arch_info.filters, writer, optional_writer);
- if (!mem.eql(u8, prefix, "zigsyscall")) continue;
-
- const sys_name = fields.next() orelse return error.Incomplete;
- const value = fields.rest();
- const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
- const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
- }
-
- try writer.writeAll("};\n\n");
+ if (arch_info.extra_values) |extra_values| {
+ try writer.writeAll(extra_values);
}
- {
- try writer.writeAll("pub const RiscV64 = enum(usize) {\n");
-
- const child_args = [_][]const u8{
- zig_exe,
- "cc",
- "-target",
- "riscv64-linux-gnu",
- "-E",
- "-dD",
- "-P",
- "-nostdinc",
- "-Itools/include",
- "-Itools/include/uapi",
- "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
- "arch/riscv/include/uapi/asm/unistd.h",
- };
-
- const child_result = try std.process.Child.run(.{
- .allocator = allocator,
- .argv = &child_args,
- .cwd = linux_path,
- .cwd_dir = linux_dir,
- });
- if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr});
-
- const defines = switch (child_result.term) {
- .Exited => |code| if (code == 0) child_result.stdout else {
- std.debug.print("zig cc exited with code {d}\n", .{code});
- std.process.exit(1);
- },
- else => {
- std.debug.print("zig cc crashed\n", .{});
- std.process.exit(1);
- },
- };
-
- var lines = mem.tokenizeScalar(u8, defines, '\n');
- while (lines.next()) |line| {
- var fields = mem.tokenizeAny(u8, line, " ");
- const prefix = fields.next() orelse return error.Incomplete;
-
- if (!mem.eql(u8, prefix, "zigsyscall")) continue;
- const sys_name = fields.next() orelse return error.Incomplete;
- const value = fields.rest();
- const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
- const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
- }
+ try writer.writeAll("};\n\n");
+ if (arch_info.additional_enum) |additional_enum| {
+ try writer.print("pub const {s} = enum(usize) {{\n", .{additional_enum});
+ try writer.writeAll(optional_array_list.?.items);
try writer.writeAll("};\n\n");
}
- {
- try writer.writeAll("pub const LoongArch64 = enum(usize) {\n");
-
- const child_args = [_][]const u8{
- zig_exe,
- "cc",
- "-target",
- "loongarch64-linux-gnu",
- "-E",
- "-dD",
- "-P",
- "-nostdinc",
- "-Itools/include",
- "-Itools/include/uapi",
- "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
- "arch/loongarch/include/uapi/asm/unistd.h",
- };
-
- const child_result = try std.process.Child.run(.{
- .allocator = allocator,
- .argv = &child_args,
- .cwd = linux_path,
- .cwd_dir = linux_dir,
- });
- if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr});
-
- const defines = switch (child_result.term) {
- .Exited => |code| if (code == 0) child_result.stdout else {
- std.debug.print("zig cc exited with code {d}\n", .{code});
- std.process.exit(1);
- },
- else => {
- std.debug.print("zig cc crashed\n", .{});
- std.process.exit(1);
- },
- };
-
- var lines = mem.tokenizeScalar(u8, defines, '\n');
- while (lines.next()) |line| {
- var fields = mem.tokenizeAny(u8, line, " ");
- const prefix = fields.next() orelse return error.Incomplete;
-
- if (!mem.eql(u8, prefix, "zigsyscall")) continue;
-
- const sys_name = fields.next() orelse return error.Incomplete;
- const value = fields.rest();
- const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
- const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
- }
+}
- try writer.writeAll("};\n\n");
+fn generateSyscallsFromPreprocessor(
+ allocator: std.mem.Allocator,
+ linux_dir: std.fs.Dir,
+ linux_path: []const u8,
+ zig_exe: []const u8,
+ writer: anytype,
+ _arch_info: *const ArchInfo,
+) !void {
+ std.debug.assert(_arch_info.* == .preprocessor);
+
+ const arch_info = _arch_info.preprocessor;
+
+ const child_result = try std.process.Child.run(.{
+ .allocator = allocator,
+ .argv = arch_info.child_options.getArgs(zig_exe, arch_info.file_path),
+ .cwd = linux_path,
+ .cwd_dir = linux_dir,
+ });
+ if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr});
+
+ const defines = switch (child_result.term) {
+ .Exited => |code| if (code == 0) child_result.stdout else {
+ std.debug.print("zig cc exited with code {d}\n", .{code});
+ std.process.exit(1);
+ },
+ else => {
+ std.debug.print("zig cc crashed\n", .{});
+ std.process.exit(1);
+ },
+ };
+
+ try writer.print("pub const {s} = enum(usize) {{\n", .{arch_info.enum_name});
+ if (arch_info.header) |header| {
+ try writer.writeAll(header);
}
- {
- try writer.writeAll("pub const Arc = enum(usize) {\n");
-
- const child_args = [_][]const u8{
- zig_exe,
- "cc",
- "-target",
- "arc-freestanding-none",
- "-E",
- "-dD",
- "-P",
- "-nostdinc",
- "-Itools/include",
- "-Itools/include/uapi",
- "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
- "arch/arc/include/uapi/asm/unistd.h",
- };
-
- const child_result = try std.process.Child.run(.{
- .allocator = allocator,
- .argv = &child_args,
- .cwd = linux_path,
- .cwd_dir = linux_dir,
- });
- if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr});
-
- const defines = switch (child_result.term) {
- .Exited => |code| if (code == 0) child_result.stdout else {
- std.debug.print("zig cc exited with code {d}\n", .{code});
- std.process.exit(1);
- },
- else => {
- std.debug.print("zig cc crashed\n", .{});
- std.process.exit(1);
- },
- };
-
- var lines = mem.tokenizeScalar(u8, defines, '\n');
- while (lines.next()) |line| {
- var fields = mem.tokenizeAny(u8, line, " ");
- const prefix = fields.next() orelse return error.Incomplete;
- if (!mem.eql(u8, prefix, "zigsyscall")) continue;
-
- const sys_name = fields.next() orelse return error.Incomplete;
- const value = fields.rest();
- const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
- const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
-
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
- }
+ try arch_info.process_file(defines, writer);
- try writer.writeAll("};\n\n");
+ if (arch_info.extra_values) |extra_values| {
+ try writer.writeAll(extra_values);
}
- {
- try writer.writeAll("pub const CSky = enum(usize) {\n");
-
- const child_args = [_][]const u8{
- zig_exe,
- "cc",
- "-target",
- "csky-freestanding-none",
- "-E",
- "-dD",
- "-P",
- "-nostdinc",
- "-Itools/include",
- "-Itools/include/uapi",
- "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
- "arch/csky/include/uapi/asm/unistd.h",
- };
-
- const child_result = try std.process.Child.run(.{
- .allocator = allocator,
- .argv = &child_args,
- .cwd = linux_path,
- .cwd_dir = linux_dir,
- });
- if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr});
-
- const defines = switch (child_result.term) {
- .Exited => |code| if (code == 0) child_result.stdout else {
- std.debug.print("zig cc exited with code {d}\n", .{code});
- std.process.exit(1);
- },
- else => {
- std.debug.print("zig cc crashed\n", .{});
- std.process.exit(1);
- },
- };
- var lines = mem.tokenizeScalar(u8, defines, '\n');
- while (lines.next()) |line| {
- var fields = mem.tokenizeAny(u8, line, " ");
- const prefix = fields.next() orelse return error.Incomplete;
-
- if (!mem.eql(u8, prefix, "zigsyscall")) continue;
-
- const sys_name = fields.next() orelse return error.Incomplete;
- const value = fields.rest();
- const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
- const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
+ try writer.writeAll("};\n\n");
+}
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
- }
+pub fn main() !void {
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ defer arena.deinit();
+ const allocator = arena.allocator();
- try writer.writeAll("};\n\n");
- }
- {
- try writer.writeAll("pub const Hexagon = enum(usize) {\n");
-
- const child_args = [_][]const u8{
- zig_exe,
- "cc",
- "-target",
- "hexagon-freestanding-none",
- "-E",
- "-dD",
- "-P",
- "-nostdinc",
- "-Itools/include",
- "-Itools/include/uapi",
- "-D __SYSCALL(nr, nm)=zigsyscall nm nr",
- "arch/hexagon/include/uapi/asm/unistd.h",
- };
-
- const child_result = try std.process.Child.run(.{
- .allocator = allocator,
- .argv = &child_args,
- .cwd = linux_path,
- .cwd_dir = linux_dir,
- });
- if (child_result.stderr.len > 0) std.debug.print("{s}\n", .{child_result.stderr});
-
- const defines = switch (child_result.term) {
- .Exited => |code| if (code == 0) child_result.stdout else {
- std.debug.print("zig cc exited with code {d}\n", .{code});
- std.process.exit(1);
- },
- else => {
- std.debug.print("zig cc crashed\n", .{});
- std.process.exit(1);
- },
- };
+ const args = try std.process.argsAlloc(allocator);
+ if (args.len < 3 or mem.eql(u8, args[1], "--help"))
+ usageAndExit(std.io.getStdErr(), args[0], 1);
+ const zig_exe = args[1];
+ const linux_path = args[2];
- var lines = mem.tokenizeScalar(u8, defines, '\n');
- while (lines.next()) |line| {
- var fields = mem.tokenizeAny(u8, line, " ");
- const prefix = fields.next() orelse return error.Incomplete;
+ var buf_out = std.io.bufferedWriter(std.io.getStdOut().writer());
+ const writer = buf_out.writer();
- if (!mem.eql(u8, prefix, "zigsyscall")) continue;
+ var linux_dir = try std.fs.cwd().openDir(linux_path, .{});
+ defer linux_dir.close();
- const sys_name = fields.next() orelse return error.Incomplete;
- const value = fields.rest();
- const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
- const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
+ try writer.writeAll(
+ \\// This file is automatically generated.
+ \\// See tools/generate_linux_syscalls.zig for more info.
+ \\
+ \\
+ );
- try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
+ // As of 5.17.1, the largest table is 23467 bytes.
+ // 32k should be enough for now.
+ const buf = try allocator.alloc(u8, 1 << 15);
+ defer allocator.free(buf);
+
+ inline for (arch_infos) |arch_info| {
+ switch (arch_info) {
+ .table => try generateSyscallsFromTable(
+ allocator,
+ buf,
+ linux_dir,
+ writer,
+ &arch_info,
+ ),
+ .preprocessor => try generateSyscallsFromPreprocessor(
+ allocator,
+ linux_dir,
+ linux_path,
+ zig_exe,
+ writer,
+ &arch_info,
+ ),
}
-
- try writer.writeAll("};\n\n");
}
try buf_out.flush();