def print_encoding(p, syscall): for a in syscall.input_args: if a.datatype == "void *": continue if data_of_argument(syscall, a).fd: fmt = "{name} = lfd" else: fmt = "{name} = uap->{name}" p("\t" + fmt.format(**vars(a)) + ";\n") if a.datatype == "struct iovec *": concrete_datatype = concrete_datatype_of_abstract_datatype("size_t") size = data_of_argument(syscall, a).size name = a.name p("""\ \t{name}_iov_len_buf = (char (*)[FSYSCALL_BUFSIZE_UINT64])malloc( \t\tsizeof(char [FSYSCALL_BUFSIZE_UINT64]) * {size}, \t\tM_TEMP, \t\tM_WAITOK); \t{name}_iov_len_len = (int *)malloc( \t\tsizeof(u_int) * iovcnt, \t\tM_TEMP, \t\tM_WAITOK); \tfor (i = 0; i < iovcnt; i++) {{ \t\t{name}_iov_len_len[i] = fsyscall_encode_{concrete_datatype}( \t\t\t{name}[i].iov_len, \t\t\t{name}_iov_len_buf[i], \t\t\tarray_sizeof({name}_iov_len_buf[i])); \t\tif ({name}_iov_len_len[i] < 0) \t\t\treturn (EMSGSIZE); \t}} """.format(**locals())) continue if a.datatype == "char *": p("""\ \t{name}_len = strlen({name}); """.format(name=a.name)) name = "{name}_len".format(**vars(a)) else: name = a.name concrete_datatype = concrete_datatype_of_abstract_datatype(a.datatype) opt = opt_of_syscall(FMASTER_SYSCALLS, syscall, a) if opt is not None: expr_head = "{opt} ? ".format(**locals()) expr_tail = " : 0" else: expr_head = expr_tail = "" p("""\ \t{name}_len = {expr_head}fsyscall_encode_{concrete_datatype}( \t\t{name}, \t\t{name}_buf, \t\tarray_sizeof({name}_buf)){expr_tail}; \tif ({name}_len < 0) \t\treturn (EMSGSIZE); """.format(**locals()))
def make_execute_return_actual_arguments(syscall, args): exprs = [] for a in args: st = data_of_argument(syscall, a).struct fmt = "&{name}" if st is not None else "{name}" exprs.append(fmt.format(**vars(a))) return ", ".join(exprs)
def print_tail(p, print_newline, syscall): if len([a for a in syscall.args if data_of_argument(syscall, a).out]) == 0: print_generic_tail(p, print_newline, syscall) return print_call_tail(p, print_newline) print_execute_return(p, print_newline, syscall) print_newline() print_syscall(p, print_newline, syscall)
def write_syscall(dirpath, syscall): local_vars = [] for datatype, name in ( ("payload_size_t", "payload_size"), ("int", "error")): local_vars.append(Variable(datatype, name)) if 0 < len(syscall.input_args): for datatyoe, name in (("int", "wfd"), ): local_vars.append(Variable(datatype, name)) for a in syscall.args: if (a.datatype == "void *") or data_of_argument(syscall, a).out: continue if a.datatype == "char *": local_vars.extend(make_string_locals(a.name)) continue if a.datatype == "struct iovec *": local_vars.append(Variable(a.datatype, a.name)) local_vars.append(Variable("u_int", "i")) name = "{name}_payload_size".format(**vars(a)) local_vars.append(Variable("payload_size_t", name)) size = bufsize_of_datatype("size_t") datatype = "char (*)[{size}]".format(**locals()) name = "{name}_iov_len_buf".format(name=a.name) local_vars.append(Variable(datatype, name)) name = "{name}_iov_len_len".format(name=a.name) local_vars.append(Variable("int *", name)) continue for datatype, fmt, size in ( (a.datatype, "{name}", None), ("char", "{name}_buf", bufsize_of_datatype(a.datatype)), ("int", "{name}_len", None)): v = Variable(datatype, fmt.format(name=a.name), size) local_vars.append(v) name = syscall.name with open(join(dirpath, name) + ".c", "w") as fp: p, print_newline = partial_print(fp) print_head(syscall, p, name) print_locals(p, local_vars) print_newline() print_encoding(p, syscall) if 0 < len(syscall.args): print_newline() print_write(p, print_newline, syscall) print_newline() print_tail(p, print_newline, syscall)
def make_fslave_payload_size_expr(syscall): if len(syscall.input_args) == 0: return "0" terms = [] for a in syscall.args: if data_of_argument(syscall, a).out: continue if a.datatype == "void *": terms.append(SYSCALLS[syscall.name][a.name].size) continue if a.datatype == "struct iovec *": terms.append("{name}_payload_size".format(**vars(a))) continue terms.append("{name}_len".format(**vars(a))) return " + ".join(terms)
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 make_params_passing(syscall): args = [a.name for a in syscall.args if not data_of_argument(syscall, a).out] return ", ".join(args)
def print_execute_return(p, print_newline, syscall): name = syscall.name p("""\ static int execute_return(struct thread *td, struct {name}_args *uap) {{ """.format(**locals())) local_vars = [] for datatype, name in ( ("command_t", "cmd"), ("int", "errnum"), ("int", "errnum_len"), ("int", "error"), ("int", "retval_len"), ("int", "rfd"), ("payload_size_t", "expected_payload_size"), ("payload_size_t", "payload_size"), (syscall.rettype, "retval")): local_vars.append(Variable(datatype, name)) out_arguments = syscall.output_args for a in out_arguments: if a.datatype in ("char *", "void *"): continue data = data_of_argument(syscall, a) st = data.struct if st is not None: local_vars.append(Variable(drop_pointer(a.datatype), a.name)) for _, name in st.expand_all_members(a.name): n = "{name}_len".format(**locals()) local_vars.append(Variable("int", n)) continue assert data_of_argument(syscall, a).is_atom name = a.name local_vars.append(Variable("int", "{name}_len".format(**locals()))) local_vars.append(Variable(drop_pointer(a.datatype), a.name)) print_locals(p, local_vars) print_newline() cmd_name = make_cmd_name(syscall.name) t = concrete_datatype_of_abstract_datatype(syscall.rettype) p("""\ \terror = fmaster_read_command(td, &cmd); \tif (error != 0) \t\treturn (error); \tif (cmd != {cmd_name}_RETURN) {{ \t\tfmaster_log(td, LOG_ERR, \"command mismatched: expected=%d, actual=%d\", {cmd_name}_RETURN, cmd); \t\treturn (EPROTO); \t}} \terror = fmaster_read_payload_size(td, &payload_size); \tif (error != 0) \t\treturn (error); \terror = fmaster_read_{t}(td, &retval, &retval_len); \tif (error != 0) \t\treturn (error); \tif (retval == -1) {{ \t\terror = fmaster_read_int32(td, &errnum, &errnum_len); \t\tif (error != 0) \t\t\treturn (error); \t\tif (retval_len + errnum_len != payload_size) {{ \t\tfmaster_log(td, LOG_ERR, \"payload size mismatched: expected=%d, actual=%d\", payload_size, retval_len + errnum_len); \t\t\treturn (EPROTO); \t\t}} \t\treturn (errnum); \t}} """.format(**locals())) print_newline() p("""\ \trfd = fmaster_rfd_of_thread(td); """) for a in out_arguments: if a.datatype in ("char *", "void *"): p("""\ \terror = fmaster_read_to_userspace(td, rfd, uap->{name}, {size}); \tif (error != 0) \t\treturn (error); """.format(name=a.name, size=data_of_argument(syscall, a).retsize)) continue data = data_of_argument(syscall, a) st = data.struct if st is not None: for datatype, var, name in st.zip_members(a.name): t = concrete_datatype_of_abstract_datatype(datatype) p("""\ \terror = fmaster_read_{t}(td, &{name}, &{var}_len); \tif (error != 0) \t\treturn (error); """.format(**locals())) continue assert data.is_atom t = concrete_datatype_of_abstract_datatype(drop_pointer(a.datatype)) name = a.name p("""\ \terror = fmaster_read_{t}(td, &{name}, &{name}_len); \tif (error != 0) \t\treturn (error); """.format(**locals())) print_newline() expected_payload_size = make_payload_size_expr(syscall, out_arguments, "retsize") p("""\ \texpected_payload_size = retval_len + {expected_payload_size}; \tif (expected_payload_size != payload_size) {{ \t\tfmaster_log(td, LOG_ERR, \"payload size mismatched: expected=%d, actual=%d\", expected_payload_size, payload_size); \t\treturn (EPROTO); \t}} """.format(**locals())) print_newline() for a in syscall.output_args: data = data_of_argument(syscall, a) if data.is_array: continue p("""\ \tif (uap->{name} != NULL) {{ \t\terror = copyout(&{name}, uap->{name}, sizeof({name})); \t\tif (error != 0) \t\t\treturn (error); \t}} """.format(**vars(a))) p("""\ \ttd->td_retval[0] = retval; \treturn (0); }} """.format(**locals()))
def find_file_descriptor_argument(syscall): for a in syscall.args: if data_of_argument(syscall, a).fd: return a.name return None
def print_write(p, print_newline, syscall): cmd_name = make_cmd_name(syscall.name) p("""\ \terror = fmaster_write_command(td, {cmd_name}_CALL); \tif (error != 0) \t\treturn (error); """.format(**locals())) input_arguments = syscall.input_args 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())) payload_size_expr = make_payload_size_expr(syscall, input_arguments) p("""\ \tpayload_size = {payload_size_expr}; \terror = fmaster_write_payload_size(td, payload_size); \tif (error != 0) \t\treturn (error); """.format(**locals())) if len(input_arguments) == 0: return p("""\ \twfd = fmaster_wfd_of_thread(td); """.format(**locals())) for a in syscall.input_args: if a.datatype == "char *": buf = "{name}_len_buf".format(**vars(a)) size = "{name}_len_len".format(**vars(a)) print_fmaster_write(p, buf, size) print_fmaster_write(p, a.name, "{name}_len".format(**vars(a))) continue if a.datatype == "void *": name = a.name size = SYSCALLS[syscall.name][name].size p("""\ \terror = fmaster_write_from_userspace(td, wfd, uap->{name}, {size}); \tif (error != 0) \t\treturn (error); """.format(**locals())) continue if a.datatype == "struct iovec *": p("""\ \tfor (i = 0; i < iovcnt; i++) {{ """.format(**locals())) buf = "{name}_iov_len_buf[i]".format(**vars(a)) size = "{name}_iov_len_len[i]".format(**vars(a)) print_fmaster_write(p, buf, size, 2) buf = "{name}[i].iov_base".format(**vars(a)) size = "{name}[i].iov_len".format(**vars(a)) print_fmaster_write(p, buf, size, 2) p("""\ \t}} """.format(**locals())) continue opt = opt_of_syscall(FMASTER_SYSCALLS, syscall, a) if opt is not None: p("""\ \tif (!({opt})) \t\treturn (0); """.format(**locals())) buf = "{name}_buf".format(**vars(a)) size = "{name}_len".format(**vars(a)) print_fmaster_write(p, buf, size) cleanup_args = [ a for a in syscall.sending_order_args if a.datatype == "struct iovec *"] if len(cleanup_args) == 0: return print_newline() for a in cleanup_args: p("""\ \tfree({name}_iov_len_len, M_TEMP); \tfree({name}_iov_len_buf, M_TEMP); """.format(**vars(a)))
def get_input_args(self): return [a for a in self.sending_order_args if not data_of_argument(self, a).out]
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()))
def print_fslave_return(p, print_newline, syscall): output_args = syscall.output_args args = ", ".join([make_formal_arguments_of_execute_return(syscall, a) for a in output_args]) p("""\ static void execute_return(struct slave_thread *slave_thread, int retval, int errnum, {args}) {{ """.format(**locals())) local_vars = [Variable(datatype, name, size) for datatype, name, size in ( ("payload_size_t", "payload_size", None), ("char", "retval_buf", bufsize_of_datatype(syscall.rettype)), ("int", "retval_len", None), ("int", "wfd", None))] out_arguments = syscall.output_args for a in out_arguments: datatype = a.datatype if a.datatype in ("char *", "void *"): # in case of an array continue st = data_of_argument(syscall, a).struct append = local_vars.append if st is not None: for datatype, name in st.expand_all_members(a.name): fmt = "{name}_len" append(Variable("int", fmt.format(**locals()))) fmt = "{name}_buf" size = bufsize_of_datatype(datatype) append(Variable("char", fmt.format(**locals()), size)) continue name = a.name size = bufsize_of_datatype(drop_pointer(datatype)) append(Variable("int", "{name}_len".format(**locals()))) append(Variable("char", "{name}_buf".format(**locals()), size)) print_locals(p, local_vars) print_newline() cmd_name = make_cmd_name(syscall.name) return_func = get_fslave_return_func(syscall) p("""\ \tif (retval == -1) {{ \t\t{return_func}(slave_thread, {cmd_name}_RETURN, retval, errnum); \t\treturn; \t}} """.format(**locals())) print_newline() p("""\ \tretval_len = encode_{datatype}(retval, retval_buf, array_sizeof(retval_buf)); """.format(datatype=concrete_datatype_of_abstract_datatype(syscall.rettype))) for a in out_arguments: if a.datatype in ("char *", "void *"): continue st = data_of_argument(syscall, a).struct if st is not None: for datatype, var, name in st.zip_members(a.name, "->"): struct_name = a.name t = concrete_datatype_of_abstract_datatype(datatype) p("""\ \t{var}_len = encode_{t}({name}, {var}_buf, array_sizeof({var}_buf)); """.format(**locals())) continue name = a.name t = drop_pointer(a.datatype) datatype = concrete_datatype_of_abstract_datatype(t) p("""\ \t{name}_len = encode_{datatype}({name}, {name}_buf, sizeof({name}_buf)); """.format(**locals())) payload_size = make_payload_size_expr(syscall, out_arguments, "retsize") p("""\ \tpayload_size = retval_len + {payload_size}; \twfd = slave_thread->fsth_wfd; \twrite_command(wfd, {cmd_name}_RETURN); \twrite_payload_size(wfd, payload_size); \twrite_or_die(wfd, retval_buf, retval_len); """.format(**locals())) for a in out_arguments: if a.datatype in ("char *", "void *"): name = a.name size = data_of_argument(syscall, a).retsize p("""\ \twrite_or_die(wfd, {name}, {size}); """.format(**locals())) continue st = data_of_argument(syscall, a).struct if st is not None: for _, name in st.expand_all_members(a.name): p("""\ \twrite_or_die(wfd, {name}_buf, {name}_len); """.format(**locals())) continue name = a.name p("""\ \twrite_or_die(wfd, {name}_buf, {name}_len); """.format(**locals())) newlined = False for a in out_arguments: data = data_of_argument(syscall, a) if not data.is_array: continue if not newlined: print_newline() newlined = True p("""\ \tfree({name}); """.format(**vars(a))) p("""\ }} """.format(**locals()))
def make_formal_arguments_of_execute_return(syscall, a): data = data_of_argument(syscall, a) dt = a.datatype datatype = drop_pointer(dt) if data.is_atom else dt name = a.name return "{datatype} {name}".format(**locals())
def make_formal_arguments_of_execute_call(syscall, a): datatype = a.datatype asterisk = (1 if data_of_argument(syscall, a).is_array else 0) * "*" name = a.name return "{datatype}{asterisk}{name}".format(**locals())