def build_proc_of_protocol(g, syscalls): procs = [] for syscall in syscalls: if drop_prefix(syscall.name) in g.manually_defined_syscalls: continue fmt = """private class {proc} extends CommandDispatcher.Proc {{ public void call(Command command) throws IOException, SigkillException {{ PayloadSize payloadSize = mIn.readPayloadSize(); {decls}; {params} SyscallResult.{rettype} result = mSlave.do{name}({args}); writeResult(Command.{cmd}, result); }} }}""" proc = make_proc(syscall) decls = make_params_declarations(syscall) params = make_params_reading(syscall) rettype = rettype_class_of_syscall(syscall) name = make_class_prefix(syscall) args = make_params_passing(syscall) cmd = syscall.ret_name procs.append(fmt.format(**locals())) return ("\n\n" + make_indent(4)).join(procs)
def print_fslave_head(p, syscall): args = ["struct slave_thread *slave_thread", "int *retval", "int *errnum"] for a in syscall.output_args: args.append(make_formal_arguments_of_execute_call(syscall, a)) name = drop_prefix(syscall.name) print_caution(p) p("""\ #include <sys/types.h> #include <sys/event.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/uio.h> #include <sys/wait.h> #include <errno.h> #include <fcntl.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <fsyscall/private.h> #include <fsyscall/private/command.h> #include <fsyscall/private/encode.h> #include <fsyscall/private/fslave.h> #include <fsyscall/private/io.h> #include <fsyscall/private/io_or_die.h> static void execute_call({args}) {{ """.format(args=", ".join(args)))
def write_fslave(dirpath, syscalls): for syscall in [sc for sc in syscalls if sc.name in FSLAVE_SYSCALLS]: name = drop_prefix(syscall.name) path = join(dirpath, "fslave_{name}.c".format(**locals())) with open(path, "w") as fp: p, print_newline = partial_print(fp) print_fslave_head(p, syscall) print_fslave_call(p, print_newline, syscall) print_newline() if 0 < len(syscall.output_args): print_fslave_return(p, print_newline, syscall) print_newline() print_fslave_main(p, print_newline, syscall)
def write_dispatch(dirpath, syscalls): with open(join(dirpath, "dispatch.inc"), "w") as fp: p, _ = partial_print(fp) for syscall in syscalls: if syscall.name not in SYSCALLS: continue cmd = make_cmd_name(syscall.name) name = drop_prefix(syscall.name) p("""\ \t\t\tcase {cmd}_CALL: \t\t\t\tprocess_{name}(slave_thread); \t\t\t\tbreak; """.format(**locals())) write_c_footer(p)
def build_syscall_results(g, syscalls): stmts = [] for syscall in syscalls: if syscall.name in g.manually_defined_syscalls: continue if len(syscall.output_args) == 0: continue name = drop_prefix(syscall.name).capitalize() size = datasize_of_datatype(syscall.rettype) base = "Generic{size}".format(**locals()) members = build_members_of_result(syscall) stmts.append("""public static class {name} extends {base} {{ {members}; }}""".format(**locals())) return "\n\n ".join(stmts)
def print_wrapper(p, print_newline, syscall): name = syscall.name syscall_name = drop_prefix(name) fmt_args = make_args_format(syscall) args = make_log_args(syscall) p(""" int sys_{name}(struct thread *td, struct {name}_args *uap) {{ \tstruct timeval time_start; \tint error; \tfmaster_log(td, LOG_DEBUG, \"{syscall_name}: started{fmt_args}\"{args}); \tmicrotime(&time_start); \terror = {name}_main(td, uap); \tfmaster_log_syscall_end(td, \"{syscall_name}\", &time_start, error); \treturn (error); }} """.format(**locals()))
def print_fslave_main(p, print_newline, syscall): name = drop_prefix(syscall.name) p("""\ void process_{name}(struct slave_thread *slave_thread) {{ """.format(**locals())) local_vars = [] for datatype, name in (("int", "retval"), ("int", "errnum")): local_vars.append(Variable(datatype, name)) out_arguments = syscall.output_args if len(out_arguments) == 0: cmd_name = make_cmd_name(syscall.name) print_locals(p, local_vars) print_newline() return_func = get_fslave_return_func(syscall) p("""\ \texecute_call(slave_thread, &retval, &errnum); \t{return_func}(slave_thread, {cmd_name}_RETURN, retval, errnum); }} """.format(**locals())) return for a in out_arguments: data = data_of_argument(syscall, a) datatype = a.datatype if data.is_array else drop_pointer(a.datatype) local_vars.append(Variable(datatype, a.name)) print_locals(p, local_vars) print_newline() call_args = ", ".join(["&{name}".format(**vars(a)) for a in out_arguments]) ret_args = make_execute_return_actual_arguments(syscall, out_arguments) p("""\ \texecute_call(slave_thread, &retval, &errnum, {call_args}); \texecute_return(slave_thread, retval, errnum, {ret_args}); }} """.format(**locals()))
def write_dummy(dirpath, name): with open(join(dirpath, "{name}.c".format(**locals())), "w") as fp: syscall = drop_prefix(name) print("""\ /* * Dummy implementation generated automatically. DO NOT EDIT THIS! */ #include <sys/param.h> #include <sys/proc.h> #include <sys/syslog.h> #include <sys/systm.h> #include <fsyscall/private/fmaster.h> #include <sys/fmaster/fmaster_proto.h> int sys_{name}(struct thread *td, struct {name}_args *uap) {{ \tfmaster_log(td, LOG_DEBUG, \"{syscall}: this is a dummy, unimplemented.\"); \treturn (ENOSYS); }}""".format(**locals()), file=fp)
def write_proto(dirpath, syscalls): try: mkdir(dirpath) except OSError: pass with open(join(dirpath, "proto.h"), "w") as fp: p, print_newline = partial_print(fp) print_caution(p) p("""\ #if !defined(FSYSCALL_PRIVATE_FSLAVE_PROTO_H_INCLUDED) #define FSYSCALL_PRIVATE_FSLAVE_PROTO_H_INCLUDED """) print_newline() for syscall in syscalls: if syscall.name not in FSLAVE_SYSCALLS: continue p("""\ void process_{name}(struct slave_thread *); """.format(name=drop_prefix(syscall.name))) print_newline() p("""\ #endif """)
def print_master_call(p, print_newline, syscall): a = find_file_descriptor_argument(syscall) if a is None: return name = drop_prefix(syscall.name) p("""\ \terror = fmaster_get_vnode_info(td, uap->{a}, &place, &lfd); \tif (error != 0) \t\treturn (error); \tswitch (place) {{ \tcase FFP_MASTER: {{ \t\tstruct {name}_args a; \t\tmemcpy(&a, uap, sizeof(a)); \t\ta.{a} = lfd; \t\terror = sys_{name}(td, &a); \t\tif (error != 0) \t\t\treturn (error); """.format(**locals())) if syscall.post_common: p("""\ \t\terror = fmaster_{name}_post_common(td, uap); \t\tif (error != 0) \t\t\treturn (error); """.format(**locals())) p("""\ \t\treturn (0); \t\t}} \tcase FFP_SLAVE: \t\tbreak; \tcase FFP_PENDING_SOCKET: \t\tfmaster_log(td, LOG_INFO, "{name}: called for a pending socket: fd=%d, lfd=%d", uap->{a}, lfd); \t\treturn (ENOTCONN); \tdefault: \t\treturn (EBADF); \t}} """.format(**locals())) print_newline()
def make_class_prefix(syscall): return drop_prefix(syscall.name).title()
def build_proc_of_writing_result(syscalls): stmts = [] for syscall in syscalls: rettype = rettype_class_of_syscall(syscall) if rettype in ["Generic32", "Generic64"]: continue name = drop_prefix(syscall.name) if name == "readlink": d = { "annotation": name, "name": name.capitalize() } stmts.append("""private void writeResult(Command command, SyscallResult.{name} result) throws IOException {{ String fmt = \"result ({annotation}): retval=%d, errno=%s\"; mLogger.info(fmt, result.retval, result.errno); writeError(command, result); }}""".format(**d)) continue if name in ["fstat", "lstat", "stat"]: d = { "annotation": name, "name": name.capitalize(), "out": syscall.output_args[0].name } stmts.append("""private void writeResult(Command command, SyscallResult.{name} result) throws IOException {{ String logHead = \"result ({annotation})\"; if (result.retval == -1) {{ String fmt = \"%s: retval=%d, errno=%s\"; Errno errno = result.errno; mLogger.info(fmt, logHead, result.retval, errno); writeError(command, result); return; }} mLogger.info(\"%s: retval=%d\", logHead, result.retval); Payload payload = new Payload(); payload.add(result.retval); payload.add(result.{out}); writePayload(command, payload); }}""".format(**d)) continue if name in ["pread", "read"]: d = { "annotation": name, "rettype": rettype } stmts.append("""private void writeResult(Command command, SyscallResult.{rettype} result) throws IOException {{ String logHead = \"result ({annotation})\"; if (result.retval == -1) {{ String fmt = \"%s: retval=%d, errno=%s\"; Errno errno = result.errno; mLogger.info(fmt, logHead, result.retval, errno); writeError(command, result); return; }} mLogger.info(\"%s: retval=%d\", logHead, result.retval); Payload payload = new Payload(); payload.add(result.retval); payload.add(result.buf); writePayload(command, payload); }}""".format(**d)) continue return "\n\n ".join(stmts)
def rettype_class_of_syscall(syscall): if len(syscall.output_args) == 0: fmt = "Generic{size}" return fmt.format(size=datasize_of_datatype(syscall.rettype)) return drop_prefix(syscall.name).capitalize()
def get_const_name(self): return drop_prefix(self.name).upper()
def print_fslave_call(p, print_newline, syscall): local_vars = [] for datatype, name in ( ("sigset_t", "oset"), ("payload_size_t", "payload_size"), ("payload_size_t", "actual_payload_size"), ("int", "rfd")): local_vars.append(Variable(datatype, name)) input_arguments = syscall.input_args for a in input_arguments: if a.datatype == "void *": local_vars.append(Variable(a.datatype, a.name)) continue if a.datatype == "struct iovec *": for datatype, name in ( (a.datatype, a.name), ("payload_size_t *", "{name}_iov_len_len"), ("int", "i"), ("payload_size_t", "{name}_payload_size")): local_vars.append(Variable(datatype, name.format(**vars(a)))) continue for datatype, name in ( ("payload_size_t", "{name}_len"), ("{datatype}", "{name}")): d = vars(a) v = Variable(datatype.format(**d), name.format(**d)) local_vars.append(v) print_locals(p, local_vars) print_newline() p("""\ \trfd = slave_thread->fsth_rfd; \tpayload_size = read_payload_size(rfd); """) print_newline() for a in syscall.input_args: name = a.name if a.datatype == "void *": size = SYSCALLS[syscall.name][name].size p("""\ \t{name} = alloca({size}); \tread_or_die(rfd, {name}, {size}); """.format(**locals())) continue if a.datatype == "struct iovec *": name = a.name size = data_of_argument(syscall, a).size p("""\ \t{name} = (struct iovec *)alloca(sizeof(*{name}) * {size}); \t{name}_iov_len_len = (payload_size_t *)alloca(sizeof(int) * {size}); \tfor (i = 0; i < {size}; i++) {{ \t\t{name}[i].iov_len = read_uint64(rfd, &{name}_iov_len_len[i]); \t\t{name}[i].iov_base = alloca({name}[i].iov_len); \t\tread_or_die(rfd, {name}[i].iov_base, {name}[i].iov_len); \t}} """.format(**locals())) continue f = { "char *": "read_string", "long": "read_int64", "int": "read_int32", "u_int": "read_uint32", "off_t": "read_int64", "size_t": "read_uint64" }[a.datatype] assignment = "{name} = {f}(rfd, &{name}_len)".format(**locals()) opt = opt_of_syscall(FSLAVE_SYSCALLS, syscall, a) if opt is not None: p("""\ \tif ({opt}) \t\t{assignment}; \telse \t\t{name} = {name}_len = 0; """.format(**locals())) else: p("""\ \t{assignment}; """.format(**locals())) if 0 < len(syscall.args): print_newline() for a in [a for a in input_arguments if a.datatype == "struct iovec *"]: name = a.name size = data_of_argument(syscall, a).size p("""\ \t{name}_payload_size = 0; \tfor (i = 0; i < {size}; i++) \t\t{name}_payload_size += {name}_iov_len_len[i] + {name}[i].iov_len; """.format(**locals())) continue payload_size = make_fslave_payload_size_expr(syscall) p("""\ \tactual_payload_size = {payload_size}; \tdie_if_payload_size_mismatched(payload_size, actual_payload_size); """.format(**locals())) print_newline() malloced = False out_arguments = syscall.output_args for a in out_arguments: data = data_of_argument(syscall, a) if not data.is_array: continue name = a.name datatype = a.datatype size = data.size p("""\ \t*{name} = ({datatype})malloc({size}); """.format(**locals())) malloced = True if malloced: print_newline() args = [] for a in syscall.args: data = data_of_argument(syscall, a) ast = (1 if data.out and data.is_array else 0) * "*" args.append("{ast}{name}".format(ast=ast, name=a.name)) p("""\ \tsuspend_signal(slave_thread, &oset); \t*retval = {name}({args}); \t*errnum = errno; \tresume_signal(slave_thread, &oset); """.format(name=drop_prefix(syscall.name), args=", ".join(args))) for a in syscall.args: if (a.datatype != "char *") or data_of_argument(syscall, a).out: continue p("""\ \tfree({name}); """.format(**vars(a))) p("""\ }} """.format(**locals()))