diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-02-12 20:54:28 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-02-12 20:54:28 -0700 |
commit | d148555bd86e323a51734b7881f92d09e2f08425 (patch) | |
tree | 0fa494fa06ca00e72926a6bde8158adb0ddc5a06 | |
parent | 6cd125e1ffd44fdf62c44d22c519561a8c9d7268 (diff) | |
parent | bd0f2f3e0fe721c7fbce63aeacffaec8344e166c (diff) |
Merge branch 'lukeshu/misc'
-rw-r--r-- | GNUmakefile | 1 | ||||
-rwxr-xr-x | build-aux/stack.c.gen | 81 | ||||
-rw-r--r-- | lib9p/9p.c | 32 | ||||
-rwxr-xr-x | lib9p/idl.gen | 44 | ||||
-rw-r--r-- | lib9p/internal.h | 6 | ||||
-rw-r--r-- | lib9p/map.h | 4 | ||||
-rw-r--r-- | lib9p/srv.c | 10 |
7 files changed, 119 insertions, 59 deletions
diff --git a/GNUmakefile b/GNUmakefile index db7f7fd..4b68f3f 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -103,6 +103,7 @@ lint/python3: lint/%: build-aux/venv ./build-aux/venv/bin/mypy --strict --scripts-are-modules $(sources_$*) ./build-aux/venv/bin/black --check $(sources_$*) ./build-aux/venv/bin/isort --check $(sources_$*) + ! grep -nh 'SPECIAL$$' -- lib9p/idl.gen lint/c: lint/%: build-aux/lint-h build-aux/get-dscname ./build-aux/lint-h $(filter %.h,$(sources_$*)) lint/make lint/cmake lint/gitignore lint/ini lint/9p lint/markdown: lint/%: diff --git a/build-aux/stack.c.gen b/build-aux/stack.c.gen index e327298..af5d740 100755 --- a/build-aux/stack.c.gen +++ b/build-aux/stack.c.gen @@ -135,7 +135,7 @@ def analyze( *, ci_fnames: list[str], extra_nodes: list[Node] = [], - app_func_filters: dict[str, typing.Callable[[str], bool]], + app_func_filters: dict[str, typing.Callable[[str], int]], app_location_xform: typing.Callable[[str], str], app_indirect_callees: typing.Callable[[VCGElem], list[str]], app_skip_call: typing.Callable[[list[str], str], bool], @@ -289,12 +289,12 @@ def analyze( nsum = 0 rows: dict[str, int] = {} for funcname in graph: - if grp_filter(funcname): + if cnt := grp_filter(funcname): n = nstatic(funcname) rows[app_location_xform(funcname)] = n if n > nmax: nmax = n - nsum += n + nsum += cnt * n # Figure sizes. namelen = max([len(k) for k in rows.keys()] + [len(grp_name) + 4]) @@ -314,7 +314,7 @@ def analyze( for funcname in sorted(missing): print(f"warning: missing: {funcname}") for funcname in sorted(dynamic): - print(f"warning: dynamic: {funcname}") + print(f"warning: dynamic-stack-usage: {funcname}") print("*/") @@ -431,9 +431,14 @@ def main( hooks_indirect_callees += [sbc_indirect_callees] - def sbc_is_thread(name: str) -> bool: + def sbc_is_thread(name: str) -> int: if name.endswith("_cr") and name != "lib9p_srv_read_cr": - return True + if "9p" in name: + if "read" in name: + return 8 + elif "write" in name: + return 16 + return 1 if name == "main": return True return False @@ -721,51 +726,67 @@ def main( # newlib ######################################################### if arg_pico_platform == "rp2040": + # This is accurate to + # /usr/arm-none-eabi/lib/thumb/v6-m/nofp/libg.a as of + # Parabola's arm-none-eabi-newlib 4.5.0.20241231-1. all_nodes += [ # malloc - synthetic_node("free", 0), # TODO - synthetic_node("malloc", 0), # TODO - synthetic_node("realloc", 0), # TODO - synthetic_node("aligned_alloc", 0), # TODO - synthetic_node("reallocarray", 0), # TODO + synthetic_node("free", 8, {"_free_r"}), + synthetic_node("malloc", 8, {"_malloc_r"}), + synthetic_node("realloc", 8, {"_realloc_r"}), + synthetic_node("aligned_alloc", 8, {"_memalign_r"}), + synthetic_node("reallocarray", 24, {"realloc", "__errno"}), + synthetic_node("_free_r", 0), # TODO + synthetic_node("_malloc_r", 0), # TODO + synthetic_node("_realloc_r", 0), # TODO + synthetic_node("_memalign_r", 0), # TODO # execution - synthetic_node("abort", 0), # TODO - synthetic_node("longjmp", 0), # TODO - synthetic_node("setjmp", 0), # TODO + synthetic_node("raise", 16, {"_getpid_r"}), + synthetic_node("abort", 8, {"raise", "_exit"}), + synthetic_node("longjmp", 0), + synthetic_node("setjmp", 0), # <strings.h> - synthetic_node("memcmp", 0), # TODO - synthetic_node("memcpy", 0), # TODO - synthetic_node("memset", 0), # TODO - synthetic_node("strcmp", 0), # TODO - synthetic_node("strlen", 0), # TODO - synthetic_node("strncpy", 0), # TODO - synthetic_node("strnlen", 0), # TODO + synthetic_node("memcmp", 12), + synthetic_node("memcpy", 28), + synthetic_node("memset", 20), + synthetic_node("strcmp", 16), + synthetic_node("strlen", 8), + synthetic_node("strncpy", 16), + synthetic_node("strnlen", 8), # other - synthetic_node("random", 0), # TODO + synthetic_node("__errno", 0), + synthetic_node("_getpid_r", 8, {"_getpid"}), + synthetic_node("random", 8), ] # libgcc ######################################################### if arg_pico_platform == "rp2040": + # This is accurate to + # /usr/lib/gcc/arm-none-eabi/14.2.0/thumb/v6-m/nofp/libgcc.a + # as of Parabola's arm-none-eabi-gcc 14.2.0-1. all_nodes += [ - synthetic_node("__aeabi_idiv0", 0), # TODO - synthetic_node("__aeabi_ldiv0", 0), # TODO + synthetic_node("__aeabi_idiv0", 0), + synthetic_node("__aeabi_ldiv0", 0), + synthetic_node("__aeabi_llsr", 0), ] # Tie it all together ############################################ - def thread_filter(name: str) -> bool: + def thread_filter(name: str) -> int: return sbc_is_thread(name) - def intrhandler_filter(name: str) -> bool: + def intrhandler_filter(name: str) -> int: name = name.rsplit(":", 1)[-1] for hook in hooks_is_intrhandler: if hook(name): - return True - return False + return 1 + return 0 - def misc_filter(name: str) -> bool: - return name.endswith(":__lm_printf") or name == "__assert_msg_fail" + def misc_filter(name: str) -> int: + if name.endswith(":__lm_printf") or name == "__assert_msg_fail": + return 1 + return 0 def location_xform(loc: str) -> str: if not loc.startswith("/"): @@ -124,10 +124,12 @@ ssize_t _lib9p_validate(uint8_t xxx_low_typ_bit, struct lib9p_ctx *ctx, uint8_t *net_bytes) { /* Inspect the first 5 bytes ourselves. */ struct _validate_ctx subctx = { + /* input */ .ctx = ctx, .net_size = uint32le_decode(net_bytes), .net_bytes = net_bytes, + /* output */ .net_offset = 0, .host_extra = 0, }; @@ -171,17 +173,19 @@ static void _lib9p_unmarshal(const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0x80], struct lib9p_ctx *ctx, uint8_t *net_bytes, enum lib9p_msg_type *ret_typ, void *ret_body) { + enum lib9p_msg_type typ = net_bytes[4]; + *ret_typ = typ; + struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; + struct _unmarshal_ctx subctx = { + /* input */ .ctx = ctx, .net_bytes = net_bytes, + /* output */ .net_offset = 0, + .extra = ret_body + tentry.basesize, }; - - enum lib9p_msg_type typ = net_bytes[4]; - *ret_typ = typ; - struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; - subctx.extra = ret_body + tentry.basesize; tentry.unmarshal(&subctx, ret_body); } @@ -202,7 +206,10 @@ bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x8 struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *body, uint8_t *ret_bytes) { struct _marshal_ctx subctx = { + /* input */ .ctx = ctx, + + /* ouptut */ .net_bytes = ret_bytes, .net_offset = 0, }; @@ -228,10 +235,12 @@ bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *bo bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, uint32_t *ret_net_size, ssize_t *ret_host_size) { struct _validate_ctx subctx = { + /* input */ .ctx = ctx, .net_size = net_size, .net_bytes = net_bytes, + /* output */ .net_offset = 0, .host_extra = 0, }; @@ -248,11 +257,13 @@ bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_ uint32_t lib9p_stat_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, struct lib9p_stat *ret_obj, void *ret_extra) { struct _unmarshal_ctx subctx = { - .ctx = ctx, - .net_bytes = net_bytes, - .net_offset = 0, + /* input */ + .ctx = ctx, + .net_bytes = net_bytes, - .extra = ret_extra, + /* output */ + .net_offset = 0, + .extra = ret_extra, }; _lib9p_stat_unmarshal(&subctx, ret_obj); return subctx.net_offset; @@ -263,7 +274,10 @@ uint32_t lib9p_stat_marshal(struct lib9p_ctx *ctx, uint32_t max_net_size, struct struct lib9p_ctx _ctx = *ctx; _ctx.max_msg_size = max_net_size; struct _marshal_ctx subctx = { + /* input */ .ctx = &_ctx, + + /* output */ .net_bytes = ret_bytes, .net_offset = 0, }; diff --git a/lib9p/idl.gen b/lib9p/idl.gen index 8782771..adb15ce 100755 --- a/lib9p/idl.gen +++ b/lib9p/idl.gen @@ -53,13 +53,13 @@ def c_ver_enum(ver: str) -> str: return f"{idprefix.upper()}VER_{ver.replace('.', '_')}" -def c_ver_ifdef(versions: set[str]) -> str: +def c_ver_ifdef(versions: typing.Collection[str]) -> str: return " || ".join( f"CONFIG_9P_ENABLE_{v.replace('.', '_')}" for v in sorted(versions) ) -def c_ver_cond(versions: set[str]) -> str: +def c_ver_cond(versions: typing.Collection[str]) -> str: if len(versions) == 1: v = next(v for v in versions) return f"is_ver(ctx, {v.replace('.', '_')})" @@ -84,7 +84,7 @@ def c_typename(typ: idl.Type, parent: idl.StructMember | None = None) -> str: raise ValueError(f"not a type: {typ.__class__.__name__}") -def c_expr(expr: idl.Expr) -> str: +def c_expr(expr: idl.Expr, lookup_sym: typing.Callable[[str], str]) -> str: ret: list[str] = [] for tok in expr.tokens: match tok: @@ -92,14 +92,14 @@ def c_expr(expr: idl.Expr) -> str: ret.append(tok.op) case idl.ExprLit(): ret.append(str(tok.val)) - case idl.ExprSym(name="end"): - ret.append("ctx->net_offset") case idl.ExprSym(name="s32_max"): ret.append("INT32_MAX") case idl.ExprSym(name="s64_max"): ret.append("INT64_MAX") case idl.ExprSym(): - ret.append(f"_{tok.name[1:]}_offset") + ret.append(lookup_sym(tok.name)) + case _: + assert False return " ".join(ret) @@ -411,7 +411,7 @@ def gen_c(versions: set[str], typs: list[idl.Type]) -> str: ret += f""" /* strings ********************************************************************/ -const char *_lib9p_table_ver_name[{c_ver_enum('NUM')}] = {{ +const char *_{idprefix}table_ver_name[{c_ver_enum('NUM')}] = {{ """ for ver in ["unknown", *sorted(versions)]: if ver in versions: @@ -573,17 +573,26 @@ LM_ALWAYS_INLINE static bool validate_8(struct _validate_ctx *ctx) { return _val # Pass 4 - validate ,max= and ,val= constraints for member in typ.members: + + def lookup_sym(sym: str) -> str: + match sym: + case "end": + return "ctx->net_offset" + case _: + assert sym.startswith("&") + return f"_{sym[1:]}_offset" + if member.max: assert member.static_size nbits = member.static_size * 8 ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - ret += f"\t || ({{ uint{nbits}_t max = {c_expr(member.max)}; (((uint{nbits}_t){member.name}) > max) &&\n" + ret += f"\t || ({{ uint{nbits}_t max = {c_expr(member.max, lookup_sym)}; (((uint{nbits}_t){member.name}) > max) &&\n" ret += f'\t lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "{member.name} value is too large (%"PRIu{nbits}" > %"PRIu{nbits}")", {member.name}, max); }})\n' if member.val: assert member.static_size nbits = member.static_size * 8 ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) - ret += f"\t || ({{ uint{nbits}_t exp = {c_expr(member.val)}; (((uint{nbits}_t){member.name}) != exp) &&\n" + ret += f"\t || ({{ uint{nbits}_t exp = {c_expr(member.val, lookup_sym)}; (((uint{nbits}_t){member.name}) != exp) &&\n" ret += f'\t lib9p_errorf(ctx->ctx, LINUX_EBADMSG, "{member.name} value is wrong (actual:%"PRIu{nbits}" != correct:%"PRIu{nbits}")", (uint{nbits}_t){member.name}, exp); }})\n' ret += ifdef_pop(1) @@ -775,10 +784,19 @@ LM_ALWAYS_INLINE static bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) if member.val: assert member.static_size ret += ifdef_push(2, c_ver_ifdef(member.in_versions)) + + def lookup_sym(sym: str) -> str: + match sym: + case "end": + return "ctx->net_offset" + case _: + assert sym.startswith("&") + return f"_{sym[1:]}_offset" + if member.static_size == 1: - ret += f"\t || ({{ ctx->net_bytes[_{member.name}_offset] = {c_expr(member.val)}; false; }})\n" + ret += f"\t || ({{ ctx->net_bytes[_{member.name}_offset] = {c_expr(member.val, lookup_sym)}; false; }})\n" else: - ret += f"\t || ({{ uint{member.static_size*8}le_encode(&ctx->net_bytes[_{member.name}_offset], {c_expr(member.val)}); false; }})\n" + ret += f"\t || ({{ uint{member.static_size*8}le_encode(&ctx->net_bytes[_{member.name}_offset], {c_expr(member.val, lookup_sym)}); false; }})\n" ret += ifdef_pop(1) ret += "\t ;\n" @@ -815,10 +833,10 @@ LM_ALWAYS_INLINE static bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) LM_FLATTEN bool _{idprefix}stat_validate(struct _validate_ctx *ctx) {{ \treturn validate_stat(ctx); }} -LM_FLATTEN void _{idprefix}stat_unmarshal(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) {{ +LM_FLATTEN void _{idprefix}stat_unmarshal(struct _unmarshal_ctx *ctx, struct {idprefix}stat *out) {{ \tunmarshal_stat(ctx, out); }} -LM_FLATTEN bool _{idprefix}stat_marshal(struct _marshal_ctx *ctx, struct lib9p_stat *val) {{ +LM_FLATTEN bool _{idprefix}stat_marshal(struct _marshal_ctx *ctx, struct {idprefix}stat *val) {{ \treturn marshal_stat(ctx, val); }} """ diff --git a/lib9p/internal.h b/lib9p/internal.h index d939d46..a648532 100644 --- a/lib9p/internal.h +++ b/lib9p/internal.h @@ -39,10 +39,12 @@ static_assert(CONFIG_9P_MAX_HOSTMSG_SIZE <= SSIZE_MAX); /* specialized contexts *******************************************************/ struct _validate_ctx { + /* input */ struct lib9p_ctx *ctx; uint32_t net_size; uint8_t *net_bytes; + /* output */ uint32_t net_offset; /* Increment `host_extra` to pre-allocate space that is * "extra" beyond sizeof(). */ @@ -51,9 +53,11 @@ struct _validate_ctx { typedef bool (*_validate_fn_t)(struct _validate_ctx *ctx); struct _unmarshal_ctx { + /* input */ struct lib9p_ctx *ctx; uint8_t *net_bytes; + /* output */ uint32_t net_offset; /* `extra` points to the beginning of unallocated space. */ void *extra; @@ -61,8 +65,10 @@ struct _unmarshal_ctx { typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out); struct _marshal_ctx { + /* input */ struct lib9p_ctx *ctx; + /* output */ uint8_t *net_bytes; uint32_t net_offset; }; diff --git a/lib9p/map.h b/lib9p/map.h index b59c83d..ab9564f 100644 --- a/lib9p/map.h +++ b/lib9p/map.h @@ -1,6 +1,6 @@ -/* lib9p/map.h - A really dumb map/dict data structur +/* lib9p/map.h - A really dumb map/dict data structure * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ diff --git a/lib9p/srv.c b/lib9p/srv.c index 0e58068..9837994 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -205,12 +205,12 @@ static void respond_error(struct _lib9p_srv_req *req) { /* read coroutine *************************************************************/ -static bool read_at_least(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) { +static bool read_exactly(lo_interface net_stream_conn fd, uint8_t *buf, size_t goal, size_t *done) { assert(buf); assert(goal); assert(done); while (*done < goal) { - ssize_t r = LO_CALL(fd, read, &buf[*done], CONFIG_9P_MAX_MSG_SIZE - *done); + ssize_t r = LO_CALL(fd, read, &buf[*done], goal - *done); if (r < 0) { nonrespond_errorf("read: %s", net_strerror(-r)); return true; @@ -263,14 +263,14 @@ static void handle_message(struct _lib9p_srv_req *ctx); nextmsg: /* Read the message. */ size_t done = 0; - if (read_at_least(conn.fd, buf, 4, &done)) + if (read_exactly(conn.fd, buf, 4, &done)) goto close; size_t goal = uint32le_decode(buf); if (goal < 7) { nonrespond_errorf("T-message is impossibly small"); goto close; } - if (read_at_least(conn.fd, buf, 7, &done)) + if (read_exactly(conn.fd, buf, 7, &done)) goto close; struct _lib9p_srv_req req = { .parent_sess = &sess, @@ -292,7 +292,7 @@ static void handle_message(struct _lib9p_srv_req *ctx); respond_error(&req); goto nextmsg; } - if (read_at_least(conn.fd, buf, goal, &done)) + if (read_exactly(conn.fd, buf, goal, &done)) goto close; /* Handle the message... */ |