1+ #!/usr/bin/env python3
2+ # Auto-generates syscall mapping constants for lind-wasm.
3+ #
4+ # Reads syscall definitions from glibc's lind_syscall_num.h and generates:
5+ # - src/sysdefs/src/constants/syscall_const.rs (full set)
6+ # - src/wasmtime/crates/lind-utils/src/lind_syscall_numbers.rs (minimal set)
7+ #
8+ # Source of truth: src/glibc/lind_syscall/lind_syscall_num.h
9+
10+ from __future__ import annotations
11+
12+ import re
13+ import sys
14+ from pathlib import Path
15+
16+
17+ def parse_c_header (header_path : str ) -> dict [str , int ]:
18+ """Parse syscall constants from glibc's lind_syscall_num.h header file."""
19+ syscalls = {}
20+
21+ try :
22+ with open (header_path ) as f :
23+ content = f .read ()
24+ except FileNotFoundError :
25+ print (f"Error: Could not find { header_path } " , file = sys .stderr )
26+ sys .exit (1 )
27+
28+ # Match #define SYSCALL_NAME number
29+ pattern = r'#define\s+(\w+)\s+(\d+)'
30+
31+ for match in re .finditer (pattern , content ):
32+ name , number = match .groups ()
33+ syscalls [name ] = int (number )
34+
35+ if not syscalls :
36+ print (f"Error: Could not parse any syscalls from { header_path } " , file = sys .stderr )
37+ sys .exit (1 )
38+
39+ return syscalls
40+
41+
42+ def generate_rust_constants (syscalls : dict [str , int ]) -> str :
43+ """Generate Rust constants for sysdefs/constants/syscall_const.rs."""
44+ lines = [
45+ "//! Syscall number constants for the Lind platform." ,
46+ "//!" ,
47+ "//! Source of truth: Linux x86_64 syscall table" ,
48+ "//! https://github.com/torvalds/linux/blob/v6.16-rc1/arch/x86/entry/syscalls/syscall_64.tbl" ,
49+ "//! (Historical overview: https://filippo.io/linux-syscall-table/)" ,
50+ "//!" ,
51+ "//! Keep these in sync with glibc's lind_syscall_num.h and RawPOSIX dispatcher." ,
52+ "" ,
53+ ]
54+
55+ # Sort by syscall number for readability
56+ sorted_syscalls = sorted (syscalls .items (), key = lambda x : x [1 ])
57+
58+ for name , number in sorted_syscalls :
59+ lines .append (f"pub const { name } : i32 = { number } ;" )
60+
61+ lines .append ("" )
62+ return "\n " .join (lines )
63+
64+
65+ def get_minimal_syscalls () -> dict [str , int ]:
66+ """Return the minimal set of syscalls needed by Wasmtime runtime."""
67+ return {
68+ 'MMAP_SYSCALL' : 9 ,
69+ 'CLONE_SYSCALL' : 56 ,
70+ 'FORK_SYSCALL' : 57 ,
71+ 'EXEC_SYSCALL' : 59 ,
72+ 'EXIT_SYSCALL' : 60 ,
73+ 'EXIT_GROUP_SYSCALL' : 231 ,
74+ }
75+
76+
77+ def generate_wasmtime_minimal (minimal : dict [str , int ]) -> str :
78+ """Generate minimal Rust constants for wasmtime lind_syscall_numbers.rs."""
79+ lines = [
80+ "// Minimal set of syscall numbers used by Wasmtime side for Lind" ,
81+ "// Keeps the runtime minimal and the rawposix dispatcher handles the rest" ,
82+ "// Source of truth: Linux x86_64 syscall table" ,
83+ "// https://github.com/torvalds/linux/blob/v6.16-rc1/arch/x86/entry/syscalls/syscall_64.tbl" ,
84+ "// (Historical overview: https://filippo.io/linux-syscall-table/)" ,
85+ "// Keep these in sync with glibc's lind_syscall_num.h and RawPOSIX dispatcher" ,
86+ ]
87+
88+ # Sort by syscall number
89+ sorted_syscalls = sorted (minimal .items (), key = lambda x : x [1 ])
90+
91+ for name , number in sorted_syscalls :
92+ lines .append (f"pub const { name } : i32 = { number } ;" )
93+
94+ lines .append ("" )
95+ return "\n " .join (lines )
96+
97+
98+ def write_file (path : str , content : str ) -> None :
99+ """Write content to file, creating directories if needed."""
100+ Path (path ).parent .mkdir (parents = True , exist_ok = True )
101+ with open (path , 'w' ) as f :
102+ f .write (content )
103+ print (f"Generated: { path } " )
104+
105+
106+ def main () -> None :
107+ """Generate all syscall mapping files."""
108+ # Find workspace root (should be run from lind-wasm directory)
109+ workspace_root = Path (__file__ ).parent .parent
110+
111+ c_header = workspace_root / "src/glibc/lind_syscall/lind_syscall_num.h"
112+ rust_sysdefs_out = workspace_root / "src/sysdefs/src/constants/syscall_const.rs"
113+ rust_wasmtime_out = workspace_root / "src/wasmtime/crates/lind-utils/src/lind_syscall_numbers.rs"
114+
115+ print ("Parsing syscall definitions..." )
116+ syscalls = parse_c_header (str (c_header ))
117+ print (f"Found { len (syscalls )} syscall definitions" )
118+
119+ # Generate full Rust constants for sysdefs
120+ print ("\n Generating sysdefs constants..." )
121+ rust_content = generate_rust_constants (syscalls )
122+ write_file (str (rust_sysdefs_out ), rust_content )
123+
124+ # Generate minimal constants for wasmtime
125+ print ("Generating wasmtime minimal constants..." )
126+ minimal = get_minimal_syscalls ()
127+ wasmtime_content = generate_wasmtime_minimal (minimal )
128+ write_file (str (rust_wasmtime_out ), wasmtime_content )
129+
130+ print ("\n Done!" )
131+
132+
133+ if __name__ == "__main__" :
134+ main ()
0 commit comments