From 18ad76a7a2baa9c78e01e85886f693e572fcb2a9 Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Sat, 1 Mar 2025 14:54:22 -0700 Subject: stack.c.gen: Fix analysis --- build-aux/stack.c.gen | 229 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 187 insertions(+), 42 deletions(-) diff --git a/build-aux/stack.c.gen b/build-aux/stack.c.gen index 2965c00..edc7bae 100755 --- a/build-aux/stack.c.gen +++ b/build-aux/stack.c.gen @@ -351,6 +351,7 @@ re_call_other = re.compile(r"(?P[^(]+)\(.*") class Plugin(typing.Protocol): + def is_intrhandler(self, name: str) -> bool: ... def extra_nodes(self) -> typing.Collection[Node]: ... def indirect_callees( self, loc: str, line: str @@ -404,6 +405,14 @@ class PluginApplication: class AppPlugin: + def is_intrhandler(self, name: str) -> bool: + return name in [ + "rp2040_hwtimer_intrhandler", + "_cr_gdb_intrhandler", + "hostclock_handle_sig_alarm", + "hostnet_handle_sig_io", + ] + def extra_nodes(self) -> typing.Collection[Node]: return [] @@ -466,6 +475,9 @@ class LibObjPlugin: objcalls[method_name].add(impl_name + "_" + method_name) self.objcalls = objcalls + def is_intrhandler(self, name: str) -> bool: + return False + def extra_nodes(self) -> typing.Collection[Node]: return [] @@ -476,7 +488,7 @@ class LibObjPlugin: return None if m := re_call_objcall.fullmatch(line): if m.group("meth") in self.objcalls: - return sorted(self.objcalls[m.group("meth")]), True + return sorted(self.objcalls[m.group("meth")]), False return [ f"__indirect_call:{m.group('obj')}.vtable->{m.group('meth')}" ], False @@ -487,6 +499,14 @@ class LibObjPlugin: class LibHWPlugin: + pico_platform: str + + def __init__(self, arg_pico_platform: str) -> None: + self.pico_platform = arg_pico_platform + + def is_intrhandler(self, name: str) -> bool: + return False + def extra_nodes(self) -> typing.Collection[Node]: return [] @@ -494,11 +514,15 @@ class LibHWPlugin: if "/3rd-party/" in loc: return None if "trigger->cb(trigger->cb_arg)" in line: - return [ + ret = [ "alarmclock_sleep_intrhandler", - "w5500_tcp_alarm_handler", - "w5500_udp_alarm_handler", - ], True + ] + if self.pico_platform == "rp2040": + ret += [ + "w5500_tcp_alarm_handler", + "w5500_udp_alarm_handler", + ] + return ret, False return None def skip_call(self, chain: list[str], call: str) -> bool: @@ -506,6 +530,9 @@ class LibHWPlugin: class LibCRIPCPlugin: + def is_intrhandler(self, name: str) -> bool: + return False + def extra_nodes(self) -> typing.Collection[Node]: return [] @@ -603,6 +630,9 @@ class Lib9PPlugin: return self._CONFIG_9P_NUM_SOCKS * self.CONFIG_9P_SRV_MAX_REQS return 1 + def is_intrhandler(self, name: str) -> bool: + return False + def extra_nodes(self) -> typing.Collection[Node]: return [] @@ -631,10 +661,23 @@ class Lib9PPlugin: for c in chain[-self.CONFIG_9P_SRV_MAX_DEPTH :] ): return True + re_msg_meth = re.compile( + r"^lib9p_(?P[TR])msg_(?Pvalidate|unmarshal|marshal)$" + ) + wrapper = next((c for c in chain if re_msg_meth.match(c)), None) + if wrapper: + m = re_msg_meth.match(wrapper) + assert m + deny = ":" + m.group("meth") + "_" + ("R" if m.group("grp") == "T" else "T") + if deny in call: + return True return False class LibMiscPlugin: + def is_intrhandler(self, name: str) -> bool: + return False + def extra_nodes(self) -> typing.Collection[Node]: return [] @@ -654,9 +697,57 @@ class LibMiscPlugin: class PicoSDKPlugin: app_gpio_handlers: typing.Collection[str] + app_init_array: typing.Collection[str] + app_preinit_array: typing.Collection[str] - def __init__(self, app_gpio_handlers: typing.Collection[str]) -> None: + def __init__( + self, + *, + app_gpio_handlers: typing.Collection[str], + app_init_array: typing.Collection[str], + ) -> None: self.app_gpio_handlers = app_gpio_handlers + self.app_init_array = app_init_array + + # git grep '^PICO_RUNTIME_INIT_FUNC\S*(' + self.app_preinit_array = [ + # "runtime_init_mutex", # pico_mutex + # "runtime_init_default_alarm_pool", # pico_time + # "runtime_init_boot_locks_reset", # hardware_boot_lock + "runtime_init_per_core_irq_priorities", # hardware_irq + # "spinlock_set_extexclall", # hardware_sync_spin_lock + "__aeabi_bits_init", # pico_bit_ops + # "runtime_init_bootrom_locking_enable", # pico_bootrom, rp2350-only + # "runtime_init_pre_core_tls_setup", # pico_clib_interface, picolibc-only + # "__aeabi_double_init", # pico_double + # "__aeabi_float_init", # pico_float + "__aeabi_mem_init", # pico_mem_ops + "first_per_core_initializer", # pico_runtime + # pico_runtime_init + # "runtime_init_bootrom_reset", # rp2350-only + # "runtime_init_per_core_bootrom_reset", # rp2350-only + # "runtime_init_per_core_h3_irq_registers", # rp2350-only + "runtime_init_early_resets", + "runtime_init_usb_power_down", + # "runtime_init_per_core_enable_coprocessors", # PICO_RUNTIME_SKIP_INIT_PER_CORE_ENABLE_COPROCESSORS + "runtime_init_clocks", + "runtime_init_post_clock_resets", + "runtime_init_rp2040_gpio_ie_disable", + "runtime_init_spin_locks_reset", + "runtime_init_install_ram_vector_table", + ] + + def is_intrhandler(self, name: str) -> bool: + return name in [ + "gpio_default_irq_handler", + "isr_invalid", + "isr_nmi", + "isr_hardfault", + "isr_svcall", + "isr_pendsv", + "isr_systick", + *[f"isr_irq{n}" for n in range(32)], + ] def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: if "/3rd-party/pico-sdk/" not in loc or "/3rd-party/pico-sdk/lib/" in loc: @@ -678,7 +769,7 @@ class PicoSDKPlugin: if "/flash.c:" in loc and "boot2_copyout" in line: return ["_stage2_boot"], False if "/gpio.c:" in loc and call == "callback": - return sorted(self.app_gpio_handlers), True + return sorted(self.app_gpio_handlers), False if "/printf.c:" in loc: if call == "out": return [ @@ -703,6 +794,11 @@ class PicoSDKPlugin: return ["stdio_uart_out_flush"], False case "in_chars": return ["stdio_uart_in_chars"], False + if "/newlib_interface.c:" in loc: + if line == "*p)();": + return sorted(self.app_init_array), False + if "/pico_runtime/runtime.c:" in loc: + return sorted(self.app_preinit_array), False return None def skip_call(self, chain: list[str], call: str) -> bool: @@ -723,18 +819,35 @@ class PicoSDKPlugin: return False def extra_nodes(self) -> typing.Collection[Node]: + ret = [] + # src/rp2_common/hardware_divider/include/hardware/divider_helper.S save_div_state_and_lr = 5 * 4 # src/rp2_common/pico_divider/divider_hardware.S save_div_state_and_lr_64 = 5 * 4 - return [ + + # src/src/rp2_common/pico_crt0/crt0.S + for n in range(32): + ret += [synthetic_node(f"isr_irq{n}", 0, {"__unhandled_user_irq"})] + ret += [ + synthetic_node("isr_invalid", 0, {"__unhandled_user_irq"}), + synthetic_node("isr_nmi", 0, {"__unhandled_user_irq"}), + synthetic_node("isr_hardfault", 0, {"__unhandled_user_irq"}), + synthetic_node("isr_svcall", 0, {"__unhandled_user_irq"}), + synthetic_node("isr_pendsv", 0, {"__unhandled_user_irq"}), + synthetic_node("isr_systick", 0, {"__unhandled_user_irq"}), + synthetic_node(f"__unhandled_user_irq", 0), + synthetic_node("_reset_handler", 0, {"runtime_init", "main", "exit"}), + ] + + ret += [ # src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S - synthetic_node("__aeabi_lmul", 4), + synthetic_node("__wrap___aeabi_lmul", 4), # src/rp2_common/pico_divider/divider_hardware.S # s32 aliases synthetic_node("div_s32s32", 0, {"divmod_s32s32"}), - synthetic_node("__aeabi_idiv", 0, {"divmod_s32s32"}), - synthetic_node("__aeabi_idivmod", 0, {"divmod_s32s32"}), + synthetic_node("__wrap___aeabi_idiv", 0, {"divmod_s32s32"}), + synthetic_node("__wrap___aeabi_idivmod", 0, {"divmod_s32s32"}), # s32 impl synthetic_node("divmod_s32s32", 0, {"divmod_s32s32_savestate"}), synthetic_node( @@ -745,8 +858,8 @@ class PicoSDKPlugin: synthetic_node("divmod_s32s32_unsafe", 2 * 4, {"__aeabi_idiv0"}), # u32 aliases synthetic_node("div_u32u32", 0, {"divmod_u32u32"}), - synthetic_node("__aeabi_uidiv", 0, {"divmod_u32u32"}), - synthetic_node("__aeabi_uidivmod", 0, {"divmod_u32u32"}), + synthetic_node("__wrap___aeabi_uidiv", 0, {"divmod_u32u32"}), + synthetic_node("__wrap___aeabi_uidivmod", 0, {"divmod_u32u32"}), # u32 impl synthetic_node("divmod_u32u32", 0, {"divmod_u32u32_savestate"}), synthetic_node( @@ -757,8 +870,8 @@ class PicoSDKPlugin: synthetic_node("divmod_u32u32_unsafe", 2 * 4, {"__aeabi_idiv0"}), # s64 aliases synthetic_node("div_s64s64", 0, {"divmod_s64s64"}), - synthetic_node("__aeabi_ldiv", 0, {"divmod_s64s64"}), - synthetic_node("__aeabi_ldivmod", 0, {"divmod_s64s64"}), + synthetic_node("__wrap___aeabi_ldiv", 0, {"divmod_s64s64"}), + synthetic_node("__wrap___aeabi_ldivmod", 0, {"divmod_s64s64"}), # s64 impl synthetic_node("divmod_s64s64", 0, {"divmod_s64s64_savestate"}), synthetic_node( @@ -771,8 +884,7 @@ class PicoSDKPlugin: ), # u64 aliases synthetic_node("div_u64u64", 0, {"divmod_u64u64"}), - synthetic_node("__aeabi_uldiv", 0, {"divmod_u64u64"}), - synthetic_node("__aeabi_uldivmod", 0, {"divmod_u64u64"}), + synthetic_node("__wrap___aeabi_uldivmod", 0, {"divmod_u64u64"}), # u64 impl synthetic_node("divmod_u64u64", 0, {"divmod_u64u64_savestate"}), synthetic_node( @@ -786,6 +898,42 @@ class PicoSDKPlugin: # *_rem synthetic_node("divod_s64s64_rem", 2 * 4, {"divmod_s64s64"}), synthetic_node("divod_u64u64_rem", 2 * 4, {"divmod_u64u64"}), + # src/rp2_common/pico_mem_ops/mem_ops_aeabi.S + synthetic_node("__aeabi_mem_init", 0, {"rom_funcs_lookup"}), + synthetic_node( + "__wrap___aeabi_memset", 0, {"rom_func_lookup(ROM_FUNC_MEMSET)"} + ), + synthetic_node("__wrap___aeabi_memset4", 0, {"__wrap___aeabi_memset8"}), + synthetic_node( + "__wrap___aeabi_memset8", 0, {"rom_func_lookup(ROM_FUNC_MEMSET4)"} + ), + synthetic_node("__wrap___aeabi_memcpy4", 0, {"__wrap___aeabi_memcpy8"}), + synthetic_node( + "__wrap___aeabi_memcpy7", 0, {"rom_func_lookup(ROM_FUNC_MEMCPY4)"} + ), + synthetic_node("__wrap_memset", 0, {"rom_func_lookup(ROM_FUNC_MEMSET)"}), + synthetic_node("__wrap___aeabi_memcpy", 0, {"__wrap_memcpy"}), + synthetic_node("__wrap_memcpy", 0, {"rom_func_lookup(ROM_FUNC_MEMCPY)"}), + # src/rp2_common/pico_bit_ops/bit_ops_aeabi.S + synthetic_node("__aeabi_bits_init", 0, {"rom_funcs_lookup"}), + synthetic_node("__wrap___clz", 0, {"__wrap___clzsi2"}), + synthetic_node("__wrap___clzl", 0, {"__wrap___clzsi2"}), + synthetic_node("__wrap___clzsi2", 0, {"rom_func_lookup(ROM_FUNC_CLZ32"}), + synthetic_node("__wrap___ctzsi2", 0, {"rom_func_lookup(ROM_FUNC_CTZ32"}), + synthetic_node( + "__wrap___popcountsi2", 0, {"rom_func_lookup(ROM_FUNC_POPCOUNT32"} + ), + synthetic_node("__wrap___clzll", 0, {"__wrap___clzdi2"}), + synthetic_node("__wrap___clzdi2", 4, {"rom_func_lookup(ROM_FUNC_CLZ32"}), + synthetic_node("__wrap___ctzdi2", 4, {"rom_func_lookup(ROM_FUNC_CTZ32"}), + synthetic_node( + "__wrap___popcountdi2", 3 * 4, {"rom_func_lookup(ROM_FUNC_POPCOUNT32"} + ), + synthetic_node("__rev", 0, {"reverse32"}), + synthetic_node("__revl", 0, {"reverse32"}), + synthetic_node("reverse32", 0, {"rom_func_lookup(ROM_FUNC_REVERSE32"}), + synthetic_node("__revll", 0, {"reverse64"}), + synthetic_node("reverse64", 3 * 4, {"rom_func_lookup(ROM_FUNC_REVERSE32"}), # src/rp2040/boot_stage2/boot2_${name,,}.S for name=W25Q080, # controlled by `#define PICO_BOOT_STAGE2_{name} 1` in # src/boards/include/boards/pico.h @@ -796,6 +944,7 @@ class PicoSDKPlugin: # synthetic_node("rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE)", 0), # TODO # synthetic_node("rom_hword_as_ptr(BOOTROM_TABLE_LOOKUP_OFFSET)", 0), # TODO ] + return ret class TinyUSBDevicePlugin: @@ -862,6 +1011,9 @@ class TinyUSBDevicePlugin: in_table = True self.tud_drivers = tud_drivers + def is_intrhandler(self, name: str) -> bool: + return False + def extra_nodes(self) -> typing.Collection[Node]: return [] @@ -890,6 +1042,9 @@ class TinyUSBDevicePlugin: class NewlibPlugin: + def is_intrhandler(self, name: str) -> bool: + return False + def extra_nodes(self) -> typing.Collection[Node]: # This is accurate to # /usr/arm-none-eabi/lib/thumb/v6-m/nofp/libg.a as of @@ -922,6 +1077,7 @@ class NewlibPlugin: synthetic_node("__errno", 0), synthetic_node("_getpid_r", 8, {"_getpid"}), synthetic_node("random", 8), + synthetic_node("register_fini", 8, {"atexit"}), ] def indirect_callees(self, loc: str, line: str) -> tuple[list[str], bool] | None: @@ -932,6 +1088,9 @@ class NewlibPlugin: class LibGCCPlugin: + def is_intrhandler(self, name: str) -> bool: + return False + def extra_nodes(self) -> typing.Collection[Node]: # This is accurate to # /usr/lib/gcc/arm-none-eabi/14.2.0/thumb/v6-m/nofp/libgcc.a @@ -958,7 +1117,6 @@ def main( ) -> None: plugins: list[Plugin] = [] - hooks_is_intrhandler: list[typing.Callable[[str], bool]] = [] # sbc-harness #################################################### @@ -973,24 +1131,14 @@ def main( if "9p" in name: return lib9p_plugin.thread_count(name) return 1 - if name == "main": + if name == ("_reset_handler" if arg_pico_platform == "rp2040" else "main"): return 1 return 0 - def sbc_is_intrhandler(name: str) -> bool: - return name in [ - "rp2040_hwtimer_intrhandler", - "_cr_gdb_intrhandler", - "hostclock_handle_sig_alarm", - "hostnet_handle_sig_io", - ] - - hooks_is_intrhandler += [sbc_is_intrhandler] - plugins += [ AppPlugin(), LibObjPlugin(arg_c_fnames), - LibHWPlugin(), + LibHWPlugin(arg_pico_platform), LibCRIPCPlugin(), lib9p_plugin, LibMiscPlugin(), @@ -999,16 +1147,11 @@ def main( # pico-sdk ####################################################### if arg_pico_platform == "rp2040": - - def pico_is_intrhandler(name: str) -> bool: - return name in [ - "gpio_default_irq_handler", - ] - - hooks_is_intrhandler += [pico_is_intrhandler] - plugins += [ - PicoSDKPlugin(sbc_gpio_handlers), + PicoSDKPlugin( + app_gpio_handlers=sbc_gpio_handlers, + app_init_array=["register_fini"], + ), TinyUSBDevicePlugin(arg_c_fnames), NewlibPlugin(), LibGCCPlugin(), @@ -1021,8 +1164,8 @@ def main( def intrhandler_filter(name: str) -> int: name = name.rsplit(":", 1)[-1] - for hook in hooks_is_intrhandler: - if hook(name): + for plugin in plugins: + if plugin.is_intrhandler(name): return 1 return 0 @@ -1061,6 +1204,8 @@ def main( # Print. print("= " + grp_name + " " + sep1[len(grp_name) + 3 :]) for name, num in sorted(grp.rows.items()): + if num == 0: + continue print(f"{name.ljust(namelen)} {str(num).rjust(numlen)}") print(sep2) print(f"{'Total'.ljust(namelen)} {str(grp.nsum).rjust(numlen)}") @@ -1084,7 +1229,7 @@ def main( baselen = max(len(str(r[1])) for r in rows) sizelen = max(len(str(r[2])) for r in rows) for row in sorted(rows): - if row[0] == "main": + if row[0] in ("main", "_reset_handler"): continue print("const size_t CONFIG_COROUTINE_STACK_SIZE_", end="") print(f"{row[0].ljust(namelen)} =", end="") -- cgit v1.2.3-2-g168b