|
| 1 | +# Copyright 2025 © Institute of Software, CAS. All rights reserved. |
| 2 | +# SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +import subprocess |
| 5 | +import os |
| 6 | +import re |
| 7 | +from lib.kernel_source import prepare_source |
| 8 | +from lib import MAP_RUST_ARCH, SUPPORT_ARCHS |
| 9 | +from pathlib import Path |
| 10 | + |
| 11 | +SECCOMPILER_SYSCALL_DIR = "src/syscall_table" |
| 12 | + |
| 13 | + |
| 14 | +def generate_seccompiler(args): |
| 15 | + installed_header_path = prepare_source(args) |
| 16 | + |
| 17 | + # If arch is not provided, install headers for all supported archs |
| 18 | + if args.arch is None: |
| 19 | + for arch in SUPPORT_ARCHS: |
| 20 | + generate_rust_code(installed_header_path, arch, args.output_path) |
| 21 | + else: |
| 22 | + generate_rust_code(installed_header_path, args.arch, args.output_path) |
| 23 | + |
| 24 | + |
| 25 | +def generate_rust_code(installed_header_path: str, arch: str, output_path: str): |
| 26 | + # Generate syscall table |
| 27 | + arch_headers = os.path.join(installed_header_path, f"{arch}_headers") |
| 28 | + syscall_header = Path(os.path.join(arch_headers, f"include/asm/unistd_64.h")) |
| 29 | + if not syscall_header.is_file(): |
| 30 | + raise FileNotFoundError(f"syscall headers missing at {syscall_header}") |
| 31 | + syscalls = generate_syscall_table(syscall_header) |
| 32 | + |
| 33 | + arch = MAP_RUST_ARCH[arch] |
| 34 | + output_file_path = f"{output_path}/{arch}.rs" |
| 35 | + |
| 36 | + """Generate Rust code and format with rustfmt""" |
| 37 | + print(f"Generating to: {output_file_path}") |
| 38 | + code = f"""use std::collections::HashMap; |
| 39 | +pub(crate) fn make_syscall_table() -> HashMap<&'static str, i64> {{ |
| 40 | + vec![ |
| 41 | + {syscalls} |
| 42 | + ].into_iter().collect() |
| 43 | +}} |
| 44 | +""" |
| 45 | + try: |
| 46 | + with open(output_file_path, "w") as f: |
| 47 | + f.write(code) |
| 48 | + |
| 49 | + # Format with rustfmt |
| 50 | + subprocess.run(["rustfmt", output_file_path], check=True) |
| 51 | + print(f"Generation succeeded: {output_file_path}") |
| 52 | + except subprocess.CalledProcessError: |
| 53 | + raise RuntimeError("rustfmt formatting failed") |
| 54 | + except IOError as e: |
| 55 | + raise RuntimeError(f"File write error: {str(e)}") |
| 56 | + |
| 57 | + |
| 58 | +def generate_syscall_table(syscall_header_path: str): |
| 59 | + """Generate syscall table from specified header file""" |
| 60 | + try: |
| 61 | + with open(syscall_header_path, "r") as f: |
| 62 | + syscalls = [] |
| 63 | + pattern = re.compile(r"^#define __NR_(\w+)\s+(\d+)") |
| 64 | + |
| 65 | + for line in f: |
| 66 | + line = line.strip() |
| 67 | + if line.startswith("#define __NR_"): |
| 68 | + match = pattern.match(line) |
| 69 | + if match: |
| 70 | + name = match.group(1) |
| 71 | + num = int(match.group(2)) |
| 72 | + syscalls.append((name, num)) |
| 73 | + |
| 74 | + # Sort alphabetically by syscall name |
| 75 | + syscalls.sort(key=lambda x: x[0]) |
| 76 | + syscall_list = [f'("{name}", {num}),' for name, num in syscalls] |
| 77 | + return " ".join(syscall_list) |
| 78 | + |
| 79 | + except Exception as e: |
| 80 | + raise RuntimeError(f"File processing failed: {str(e)}") |
0 commit comments