#!/usr/bin/env python3 # Simple kernel symbol dumper # Usage: ksyms.py --input --output import sys import subprocess import argparse excluded_symbols = ['text_start_addr', 'text_end_addr', 'rodata_start_addr', 'rodata_end_addr', 'data_start_addr', 'data_end_addr'] def parse_nm_line(line: str) -> tuple[int, str]: parts = line.split() if len(parts) < 3: return None addr_str, type, name = parts[0], parts[1], parts[2] # Only get symbols in text if type.lower() != 't': return None if name in excluded_symbols: return None addr = int(addr_str, 16) return addr, name def run_nm(binary: str) -> list[str]: result = subprocess.run(["nm", "-n", binary], capture_output=True, text=True) if result.returncode != 0: raise RuntimeError(f"nm failed: {result.stderr}") return result.stdout.splitlines() parser = argparse.ArgumentParser(description="Generate kernel symbols from a binary") parser.add_argument("--input", help="Input kernel binary") parser.add_argument("--output", help="Output C file") parser.add_argument("--empty", action="store_true", help="Generate empty ksyms") args = parser.parse_args() if args.empty: with open(args.output, 'w') as f: f.write("// Auto-generated by build/ksyms.py - do not edit\n\n") f.write("pub const KSym = struct {\n addr: u64,\n name: []const u8,\n};\n\n") f.write("pub const ksyms: []const KSym = &.{};\n") sys.exit(0) lines = run_nm(args.input) symbols = [] for line in lines: parsed = parse_nm_line(line) if parsed: symbols.append(parsed) # Sort by address symbols.sort(key=lambda x: x[0]) with open(args.output, 'w') as f: f.write("// Auto-generated by build/ksyms.py - do not edit\n\n") f.write("pub const KSym = struct {\n addr: u64,\n name: []const u8,\n};\n\n") f.write("pub const ksyms: []const KSym = &.{\n") for addr, name in symbols: escaped = name.replace('\\', '\\\\').replace('"', '\\"') f.write(f" .{{ .addr = 0x{addr:016x}, .name = \"{escaped}\" }},\n") f.write("};\n")