def write_check_syscall_numbers(f): for name, obj in syscalls.all(): # XXX hard-coded to x86 currently if not obj.x86: continue f.write("""static_assert(X86Arch::%s == SYS_%s, "Incorrect syscall number for %s");\n""" % (name, name, name))
def write_is_always_emulated_syscall(f): semantics_to_retval = { syscalls.ReplaySemantics.EMU: 'true', syscalls.ReplaySemantics.EXEC: 'false', syscalls.ReplaySemantics.MAY_EXEC: 'false' } f.write( "template <typename Arch> static bool is_always_emulated_syscall_arch(int syscall);\n" ) f.write("\n") for specializer, arch in [("X86Arch", "x86"), ("X64Arch", "x64")]: f.write( "template<> bool is_always_emulated_syscall_arch<%s>(int syscallno) {\n" % specializer) f.write(" switch (syscallno) {\n") for name, obj in syscalls.all(): f.write(" case %s::%s: return %s;\n" % (specializer, name, semantics_to_retval[obj.semantics])) f.write(" default:\n") f.write(" FATAL() << \"Unknown syscall \" << syscallno;\n") f.write(" return true;\n") f.write(" }\n") f.write("}\n") f.write("\n")
def write_syscall_helper_functions(f): def write_helpers(syscall): subs = { 'syscall': syscall } f.write(has_syscall.safe_substitute(subs)) f.write(is_syscall.safe_substitute(subs)) f.write(syscall_number.safe_substitute(subs)) for name, obj in syscalls.all(): write_helpers(name)
def write_syscall_record_cases(f): def write_recorder_for_arg(syscall, arg): arg_descriptor = getattr(syscall, 'arg' + str(arg), None) if isinstance(arg_descriptor, str): f.write(" syscall_state.reg_parameter<%s>(%d);\n" % (arg_descriptor, arg)) for name, obj in syscalls.all(): # Irregular syscalls will be handled by hand-written code elsewhere. if isinstance(obj, syscalls.RegularSyscall): f.write(" case Arch::%s:\n" % name) for arg in range(1,6): write_recorder_for_arg(obj, arg) f.write(" return PREVENT_SWITCH;\n")
def write_syscall_enum_for_tests(f, arch): f.write("enum Syscalls {\n") undefined_syscall = -1 for name, obj in sorted(syscalls.all(), key=lambda x: arch_syscall_number(arch, x)): syscall_number = getattr(obj, arch) if syscall_number is not None: enum_number = syscall_number else: enum_number = undefined_syscall undefined_syscall -= 1 f.write(" RR_%s = %d,\n" % (name, enum_number)) f.write("};\n") f.write("\n")
def write_syscall_consts_for_tests(f, arch): f.write("// This file has been autogenerated. DO NOT MODIFY!\n") undefined_syscall = -1 for name, obj in sorted(syscalls.all(), key=lambda x: arch_syscall_number(arch, x)): syscall_number = getattr(obj, arch) if syscall_number is not None: enum_number = syscall_number else: enum_number = undefined_syscall undefined_syscall -= 1 f.write("pub const RR_%s = %d,\n" % (name.upper(), enum_number)) f.write("\n")
def write_syscall_consts(f, arch, mode): f.write("// This file has been autogenerated. DO NOT MODIFY!\n") undefined_syscall = -1 valid_syscalls = 0 invalid_syscalls = 0 for name, obj in sorted(syscalls.all(), key=lambda x: arch_syscall_number(arch, x)): syscall_number = getattr(obj, arch) if syscall_number is not None: enum_number = syscall_number valid_syscalls += 1 else: enum_number = undefined_syscall undefined_syscall -= 1 invalid_syscalls += 1 if mode == SyscallGen.CONST_ASSERTS: if arch == 'x86': f.write("const_assert_eq!(X86Arch::%s, %d);\n" % (name.upper(), enum_number)) elif arch == 'x64': f.write("const_assert_eq!(X64Arch::%s, %d);\n" % (name.upper(), enum_number)) elif mode == SyscallGen.DEFAULT: f.write("pub const %s: i32 = %d;\n" % (name.upper(), enum_number)) elif mode == SyscallGen.TRAIT: f.write("const %s: i32;\n" % (name.upper())) elif mode == SyscallGen.TRAIT_IMPL: f.write("const %s: i32 = %d;\n" % (name.upper(), enum_number)) if mode == SyscallGen.CONST_ASSERTS: if arch == 'x86': f.write("const_assert_eq!(X86Arch::VALID_SYSCALL_COUNT, %d);\n" % (valid_syscalls)) f.write("const_assert_eq!(X86Arch::INVALID_SYSCALL_COUNT, %d);\n" % (invalid_syscalls)) elif arch == 'x64': f.write("const_assert_eq!(X64Arch::VALID_SYSCALL_COUNT, %d);\n" % (valid_syscalls)) f.write("const_assert_eq!(X64Arch::INVALID_SYSCALL_COUNT, %d);\n" % (invalid_syscalls)) elif mode == SyscallGen.DEFAULT: f.write("pub const VALID_SYSCALL_COUNT: i32 = %d;\n" % (valid_syscalls)) f.write("pub const INVALID_SYSCALL_COUNT: i32 = %d;\n" % (invalid_syscalls)) elif mode == SyscallGen.TRAIT: f.write("const VALID_SYSCALL_COUNT: i32;\n") f.write("const INVALID_SYSCALL_COUNT: i32;\n") elif mode == SyscallGen.TRAIT_IMPL: f.write("const VALID_SYSCALL_COUNT: i32 = %d;\n" % (valid_syscalls)) f.write("const INVALID_SYSCALL_COUNT: i32 = %d;\n" % (invalid_syscalls))
def write_syscall_enum(f, arch): f.write("enum Syscalls {\n") undefined_syscall = -1 for name, obj in sorted(syscalls.all(), key=lambda x: getattr(x[1], arch)): syscall_number = getattr(obj, arch) if syscall_number is not None: enum_number = syscall_number else: enum_number = undefined_syscall undefined_syscall -= 1 f.write(" %s = %d,\n" % (name, enum_number)) f.write(" SYSCALL_COUNT,\n") f.write("};\n") f.write("\n")
def write_check_syscall_numbers(f): f.write("""use crate::arch::{Architecture, X86Arch, X64Arch};\n""") f.write("""use crate::kernel_abi::common::preload_interface;\n""") for name, obj in syscalls.all(): # @TODO hard-coded to x64 currently # @TODO Note this is different from rr where it is hardcoded to x86 if not obj.x64: continue if name.startswith("rdcall_"): f.write( """const_assert_eq!(X64Arch::%s, preload_interface::SYS_%s as i32);\n""" % (name.upper(), name)) else: f.write( """const_assert_eq!(X64Arch::%s, libc::SYS_%s as i32);\n""" % (name.upper(), name))
def write_syscall_helper_functions(f): def write_helpers(syscall): no_snake_case = '' if syscall.startswith('_') or syscall.endswith('_'): no_snake_case = '\n#[allow(non_snake_case)]' subs = { 'syscall': syscall, 'syscall_upper': syscall.upper(), 'no_snake_case': no_snake_case } f.write(has_syscall.safe_substitute(subs)) f.write(is_syscall.safe_substitute(subs)) f.write(syscall_number.safe_substitute(subs)) f.write("// This file has been autogenerated. DO NOT MODIFY!\n") f.write("use SupportedArch::*;\n") for name, obj in syscalls.all(): write_helpers(name)
def write_is_always_emulated_syscall(f): semantics_to_retval = { syscalls.ReplaySemantics.EMU: 'true', syscalls.ReplaySemantics.EXEC: 'false', syscalls.ReplaySemantics.MAY_EXEC: 'false' } f.write("template <typename Arch> static bool is_always_emulated_syscall_arch(int syscall);\n"); f.write("\n"); for specializer, arch in [("X86Arch", "x86"), ("X64Arch", "x64")]: f.write("template<> bool is_always_emulated_syscall_arch<%s>(int syscallno) {\n" % specializer) f.write(" switch (syscallno) {\n") for name, obj in syscalls.all(): f.write(" case %s::%s: return %s;\n" % (specializer, name, semantics_to_retval[obj.semantics])) f.write(" default:\n") f.write(" FATAL() << \"Unknown syscall \" << syscallno;\n") f.write(" return true;\n") f.write(" }\n") f.write("}\n") f.write("\n")
def write_syscall_record_cases(f): def write_recorder_for_arg(syscall, arg): arg_descriptor = getattr(syscall, 'arg' + str(arg), None) if isinstance(arg_descriptor, str): f.write( " syscall_state.reg_parameter::<%s>(%d, None, None);\n" % (arg_descriptor, arg)) f.write("// This file has been autogenerated. DO NOT MODIFY!\n") f.write("{\n") f.write(" use crate::kernel_abi::common;\n") f.write(" use crate::kernel_abi::x64;\n") for name, obj in syscalls.all(): # Irregular syscalls will be handled by hand-written code elsewhere. if isinstance(obj, syscalls.RegularSyscall): f.write(" if sys == Arch::%s {\n" % name.upper()) for arg in range(1, 6): write_recorder_for_arg(obj, arg) f.write(" return Switchable::PreventSwitch;\n") f.write(" }\n") f.write("}\n")
def write_syscall_record_cases(f): def write_recorder_for_arg(syscall, arg): arg_descriptor = getattr(syscall, arg, None) if arg_descriptor is None: return if isinstance(arg_descriptor, str): f.write(" t->record_remote(remote_ptr<%s>(t->regs().%s()));\n" % (arg_descriptor, arg)) elif isinstance(arg_descriptor, syscalls.DynamicSize): f.write(" t->record_remote(remote_ptr<void>(t->regs().%s()), %s);\n" % (arg, arg_descriptor.size_expr)) elif isinstance(arg_descriptor, syscalls.NullTerminatedString): f.write(" t->record_remote_str(remote_ptr<void>(t->regs().%s()));\n" % arg) else: # Not reached assert None for name, obj in syscalls.all(): # Irregular syscalls will be handled by hand-written code elsewhere. if isinstance(obj, syscalls.RegularSyscall): f.write(" case Arch::%s:\n" % name) for arg in syscalls.RegularSyscall.ARGUMENT_SLOTS: write_recorder_for_arg(obj, arg) f.write(" break;\n")