Skip to content

Commit 44a3c6b

Browse files
Add auto-generation script for syscall mappings
1 parent d66d561 commit 44a3c6b

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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("\nGenerating 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("\nDone!")
131+
132+
133+
if __name__ == "__main__":
134+
main()

0 commit comments

Comments
 (0)