blob: 8266c75840496d709ca86e8186bd5da41a03a375 [file] [log] [blame]
#!/usr/bin/env python3
import assembly_templates
from io import StringIO
import os
import string
import sys
import syscalls
def arch_syscall_number(arch, syscall):
s = getattr(syscall[1], arch)
if s == None:
s = -1
return s
def write_syscall_enum(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(" %s = %d,\n" % (name, enum_number))
f.write(" SYSCALL_COUNT,\n")
f.write("};\n")
f.write("\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_syscallname_arch(f):
f.write("template <typename Arch> static std::string syscallname_arch(int syscall);\n")
f.write("\n");
for specializer, arch in [("X86Arch", "x86"), ("X64Arch", "x64"), ("ARM64Arch", "generic")]:
f.write("template <> std::string syscallname_arch<%s>(int syscall) {\n" % specializer)
f.write(" switch (syscall) {\n");
def write_case(name):
f.write(" case %(specializer)s::%(syscall)s: return \"%(syscall)s\";\n"
% { 'specializer': specializer, 'syscall': name })
for name, _ in syscalls.for_arch(arch):
write_case(name)
f.write(" default: {")
f.write(" char buf[100];")
f.write(" sprintf(buf, \"<unknown-syscall-%d>\", syscall);")
f.write(" return buf;\n")
f.write(" }\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);\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")
has_syscall = string.Template("""inline bool
has_${syscall}_syscall(SupportedArch arch) {
switch (arch) {
case x86:
return X86Arch::${syscall} >= 0;
case x86_64:
return X64Arch::${syscall} >= 0;
case aarch64:
return ARM64Arch::${syscall} >= 0;
default:
DEBUG_ASSERT(0 && "unsupported architecture");
return false;
}
}
""")
is_syscall = string.Template("""inline bool
is_${syscall}_syscall(int syscallno, SupportedArch arch) {
switch (arch) {
case x86:
return syscallno >= 0 && syscallno == X86Arch::${syscall};
case x86_64:
return syscallno >= 0 && syscallno == X64Arch::${syscall};
case aarch64:
return syscallno >= 0 && syscallno == ARM64Arch::${syscall};
default:
DEBUG_ASSERT(0 && "unsupported architecture");
return false;
}
}
""")
syscall_number = string.Template("""inline int
syscall_number_for_${syscall}(SupportedArch arch) {
switch (arch) {
case x86:
DEBUG_ASSERT(X86Arch::${syscall} >= 0);
return X86Arch::${syscall};
case x86_64:
DEBUG_ASSERT(X64Arch::${syscall} >= 0);
return X64Arch::${syscall};
case aarch64:
DEBUG_ASSERT(ARM64Arch::${syscall} >= 0);
return ARM64Arch::${syscall};
default:
DEBUG_ASSERT(0 && "unsupported architecture");
return -1;
}
}
""")
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_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))
generators_for = {
'AssemblyTemplates': lambda f: assembly_templates.generate(f),
'CheckSyscallNumbers': write_check_syscall_numbers,
'SyscallEnumsX86': lambda f: write_syscall_enum(f, 'x86'),
'SyscallEnumsX64': lambda f: write_syscall_enum(f, 'x64'),
'SyscallEnumsGeneric': lambda f: write_syscall_enum(f, 'generic'),
'SyscallEnumsForTestsX86': lambda f: write_syscall_enum_for_tests(f, 'x86'),
'SyscallEnumsForTestsX64': lambda f: write_syscall_enum_for_tests(f, 'x64'),
'SyscallEnumsForTestsGeneric': lambda f: write_syscall_enum_for_tests(f, 'generic'),
'SyscallnameArch': write_syscallname_arch,
'SyscallRecordCase': write_syscall_record_cases,
'SyscallHelperFunctions': write_syscall_helper_functions,
}
def main(argv):
filename = argv[0]
base, extension = os.path.splitext(os.path.basename(filename))
if os.access(filename, os.F_OK):
with open(filename, 'r') as f:
before = f.read()
else:
before = ""
stream = StringIO()
generators_for[base](stream)
after = stream.getvalue()
stream.close()
if before != after:
with open(filename, 'w') as f:
f.write(after)
if __name__ == '__main__':
main(sys.argv[1:])