From bf484dde0b982540b06fe84f10ff3a390acb8957 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 7 Mar 2026 21:52:44 +0100 Subject: [PATCH 1/3] Refactor address handling in filter_exception_decoder --- monitor/filter_exception_decoder.py | 46 +++++++++++------------------ 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/monitor/filter_exception_decoder.py b/monitor/filter_exception_decoder.py index a34c9a5c5..9788ad34b 100644 --- a/monitor/filter_exception_decoder.py +++ b/monitor/filter_exception_decoder.py @@ -800,17 +800,18 @@ def _finalize_batch_entry(self, addr, lines, elf_path): output += "\n (inlined by) " + p self._addr_cache[(addr, elf_path)] = output - def _prefetch_addresses(self, addr_specs): - """Pre-populate _addr_cache in batch for a list of (addr, is_return_addr).""" + def _prefetch_addresses(self, addrs): + """Pre-populate _addr_cache in batch for a list of address strings. + Addresses are passed as-is to addr2line (no decrement). + """ lookups = [] seen = set() - for addr, is_ret in addr_specs: + for addr in addrs: if self.is_address_ignored(addr): continue - lookup = "0x%08x" % (int(addr, 16) - 1) if is_ret else addr - if lookup not in seen: - seen.add(lookup) - lookups.append(lookup) + if addr not in seen: + seen.add(addr) + lookups.append(addr) if not lookups: return @@ -899,13 +900,11 @@ def filter_addresses(self, addresses_str): size -= 1 return addresses[:size] - def _resolve_address(self, addr, is_return_addr=False): + def _resolve_address(self, addr): """Resolve a single address through firmware ELF, then ROM ELF. Applies PcAddressMatcher filtering before calling addr2line. - For return addresses (*is_return_addr=True*) the lookup address is - decremented by 1 so addr2line reports the call site rather than the - instruction after the call. + Addresses are passed as-is (no decrement). Returns: ``(decoded_string, is_rom)`` or ``(None, False)`` if unresolved. @@ -914,9 +913,6 @@ def _resolve_address(self, addr, is_return_addr=False): return None, False lookup = addr - if is_return_addr: - lookup = "0x%08x" % (int(addr, 16) - 1) - int_addr = int(lookup, 16) output = None @@ -969,9 +965,7 @@ def build_backtrace(self, line, address_match): if not addresses: return "" - self._prefetch_addresses( - [(addr, j > 0) for j, addr in enumerate(addresses)] - ) + self._prefetch_addresses(addresses) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" @@ -979,9 +973,7 @@ def build_backtrace(self, line, address_match): trace = "" i = 0 for j, addr in enumerate(addresses): - output, is_rom = self._resolve_address( - addr, is_return_addr=(j > 0) - ) + output, is_rom = self._resolve_address(addr) if output is not None: fmt = "%s #%-2d %s %s\n" if is_rom else "%s #%-2d %s in %s\n" trace += fmt % (prefix, i, addr, output) @@ -1002,14 +994,14 @@ def build_stack_trace(self, line, addresses_str): if not addresses: return "" - self._prefetch_addresses([(addr, True) for addr in addresses]) + self._prefetch_addresses(addresses) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" trace = "" for addr in addresses: - output, _ = self._resolve_address(addr, is_return_addr=True) + output, _ = self._resolve_address(addr) if output is not None: trace += "%s %s: %s\n" % (prefix, addr, output) @@ -1027,14 +1019,14 @@ def build_register_trace(self, line, reg_matches): Formatted annotation string, or empty string if nothing decoded. """ # Pre-fetch code-address registers - addr_specs = [] + reg_addrs = [] for reg_name, addr in reg_matches: if reg_name in ("EXCCAUSE", "MCAUSE"): continue if reg_name in self.NON_CODE_REGISTERS: continue - addr_specs.append((addr, reg_name == "RA")) - self._prefetch_addresses(addr_specs) + reg_addrs.append(addr) + self._prefetch_addresses(reg_addrs) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" @@ -1062,9 +1054,7 @@ def build_register_trace(self, line, reg_matches): if reg_name in self.NON_CODE_REGISTERS: continue - output, _ = self._resolve_address( - addr, is_return_addr=(reg_name == "RA") - ) + output, _ = self._resolve_address(addr) if output is not None: trace += "%s %s: %s: %s\n" % (prefix, reg_name, addr, output) From 3659429bdfa7c1000702c7df4d39b09467ba3a26 Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Sat, 7 Mar 2026 22:25:20 +0100 Subject: [PATCH 2/3] re add --- monitor/filter_exception_decoder.py | 58 +++++++++++++++++++---------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/monitor/filter_exception_decoder.py b/monitor/filter_exception_decoder.py index 9788ad34b..898170197 100644 --- a/monitor/filter_exception_decoder.py +++ b/monitor/filter_exception_decoder.py @@ -800,18 +800,17 @@ def _finalize_batch_entry(self, addr, lines, elf_path): output += "\n (inlined by) " + p self._addr_cache[(addr, elf_path)] = output - def _prefetch_addresses(self, addrs): - """Pre-populate _addr_cache in batch for a list of address strings. - Addresses are passed as-is to addr2line (no decrement). - """ + def _prefetch_addresses(self, addr_specs): + """Pre-populate _addr_cache in batch for a list of (addr, is_return_addr).""" lookups = [] seen = set() - for addr in addrs: + for addr, is_ret in addr_specs: if self.is_address_ignored(addr): continue - if addr not in seen: - seen.add(addr) - lookups.append(addr) + lookup = self._normalize_return_addr(addr, is_ret) + if lookup not in seen: + seen.add(lookup) + lookups.append(lookup) if not lookups: return @@ -888,6 +887,19 @@ def decode_address(self, addr, elf_path): # Address helpers # ------------------------------------------------------------------------- + @staticmethod + def _normalize_return_addr(addr, is_return_addr): + """Return the addr2line lookup address. + + For return addresses (backtrace frames after the first, RA register, + stack-memory hits) the address points to the instruction *after* the + call. Decrementing by 1 lets addr2line report the actual call site. + Non-return addresses (faulting PC) are returned unchanged. + """ + if is_return_addr and int(addr, 16) != 0: + return "0x%08x" % (int(addr, 16) - 1) + return addr + def is_address_ignored(self, address): """Return True for empty or null addresses that should be skipped.""" return address in ("", "0x00000000") @@ -900,11 +912,13 @@ def filter_addresses(self, addresses_str): size -= 1 return addresses[:size] - def _resolve_address(self, addr): + def _resolve_address(self, addr, is_return_addr=False): """Resolve a single address through firmware ELF, then ROM ELF. Applies PcAddressMatcher filtering before calling addr2line. - Addresses are passed as-is (no decrement). + For return addresses (*is_return_addr=True*) the lookup address is + decremented by 1 so addr2line reports the call site rather than the + instruction after the call. Returns: ``(decoded_string, is_rom)`` or ``(None, False)`` if unresolved. @@ -912,7 +926,7 @@ def _resolve_address(self, addr): if self.is_address_ignored(addr): return None, False - lookup = addr + lookup = self._normalize_return_addr(addr, is_return_addr) int_addr = int(lookup, 16) output = None @@ -965,7 +979,9 @@ def build_backtrace(self, line, address_match): if not addresses: return "" - self._prefetch_addresses(addresses) + self._prefetch_addresses( + [(addr, j > 0) for j, addr in enumerate(addresses)] + ) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" @@ -973,7 +989,9 @@ def build_backtrace(self, line, address_match): trace = "" i = 0 for j, addr in enumerate(addresses): - output, is_rom = self._resolve_address(addr) + output, is_rom = self._resolve_address( + addr, is_return_addr=(j > 0) + ) if output is not None: fmt = "%s #%-2d %s %s\n" if is_rom else "%s #%-2d %s in %s\n" trace += fmt % (prefix, i, addr, output) @@ -994,14 +1012,14 @@ def build_stack_trace(self, line, addresses_str): if not addresses: return "" - self._prefetch_addresses(addresses) + self._prefetch_addresses([(addr, True) for addr in addresses]) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" trace = "" for addr in addresses: - output, _ = self._resolve_address(addr) + output, _ = self._resolve_address(addr, is_return_addr=True) if output is not None: trace += "%s %s: %s\n" % (prefix, addr, output) @@ -1019,14 +1037,14 @@ def build_register_trace(self, line, reg_matches): Formatted annotation string, or empty string if nothing decoded. """ # Pre-fetch code-address registers - reg_addrs = [] + addr_specs = [] for reg_name, addr in reg_matches: if reg_name in ("EXCCAUSE", "MCAUSE"): continue if reg_name in self.NON_CODE_REGISTERS: continue - reg_addrs.append(addr) - self._prefetch_addresses(reg_addrs) + addr_specs.append((addr, reg_name == "RA")) + self._prefetch_addresses(addr_specs) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" @@ -1054,7 +1072,9 @@ def build_register_trace(self, line, reg_matches): if reg_name in self.NON_CODE_REGISTERS: continue - output, _ = self._resolve_address(addr) + output, _ = self._resolve_address( + addr, is_return_addr=(reg_name == "RA") + ) if output is not None: trace += "%s %s: %s: %s\n" % (prefix, reg_name, addr, output) From 84965286098f8a4b4137a7066504c51c144b580b Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Sat, 7 Mar 2026 23:01:51 +0100 Subject: [PATCH 3/3] all addresses are passed verbatim to addr2line with no decrement --- monitor/filter_exception_decoder.py | 55 +++++++++-------------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/monitor/filter_exception_decoder.py b/monitor/filter_exception_decoder.py index 898170197..43a8f7fd3 100644 --- a/monitor/filter_exception_decoder.py +++ b/monitor/filter_exception_decoder.py @@ -800,17 +800,16 @@ def _finalize_batch_entry(self, addr, lines, elf_path): output += "\n (inlined by) " + p self._addr_cache[(addr, elf_path)] = output - def _prefetch_addresses(self, addr_specs): - """Pre-populate _addr_cache in batch for a list of (addr, is_return_addr).""" + def _prefetch_addresses(self, addrs): + """Pre-populate _addr_cache in batch for a list of address strings.""" lookups = [] seen = set() - for addr, is_ret in addr_specs: + for addr in addrs: if self.is_address_ignored(addr): continue - lookup = self._normalize_return_addr(addr, is_ret) - if lookup not in seen: - seen.add(lookup) - lookups.append(lookup) + if addr not in seen: + seen.add(addr) + lookups.append(addr) if not lookups: return @@ -887,19 +886,6 @@ def decode_address(self, addr, elf_path): # Address helpers # ------------------------------------------------------------------------- - @staticmethod - def _normalize_return_addr(addr, is_return_addr): - """Return the addr2line lookup address. - - For return addresses (backtrace frames after the first, RA register, - stack-memory hits) the address points to the instruction *after* the - call. Decrementing by 1 lets addr2line report the actual call site. - Non-return addresses (faulting PC) are returned unchanged. - """ - if is_return_addr and int(addr, 16) != 0: - return "0x%08x" % (int(addr, 16) - 1) - return addr - def is_address_ignored(self, address): """Return True for empty or null addresses that should be skipped.""" return address in ("", "0x00000000") @@ -912,13 +898,10 @@ def filter_addresses(self, addresses_str): size -= 1 return addresses[:size] - def _resolve_address(self, addr, is_return_addr=False): + def _resolve_address(self, addr): """Resolve a single address through firmware ELF, then ROM ELF. Applies PcAddressMatcher filtering before calling addr2line. - For return addresses (*is_return_addr=True*) the lookup address is - decremented by 1 so addr2line reports the call site rather than the - instruction after the call. Returns: ``(decoded_string, is_rom)`` or ``(None, False)`` if unresolved. @@ -926,7 +909,7 @@ def _resolve_address(self, addr, is_return_addr=False): if self.is_address_ignored(addr): return None, False - lookup = self._normalize_return_addr(addr, is_return_addr) + lookup = addr int_addr = int(lookup, 16) output = None @@ -979,9 +962,7 @@ def build_backtrace(self, line, address_match): if not addresses: return "" - self._prefetch_addresses( - [(addr, j > 0) for j, addr in enumerate(addresses)] - ) + self._prefetch_addresses(addresses) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" @@ -989,9 +970,7 @@ def build_backtrace(self, line, address_match): trace = "" i = 0 for j, addr in enumerate(addresses): - output, is_rom = self._resolve_address( - addr, is_return_addr=(j > 0) - ) + output, is_rom = self._resolve_address(addr) if output is not None: fmt = "%s #%-2d %s %s\n" if is_rom else "%s #%-2d %s in %s\n" trace += fmt % (prefix, i, addr, output) @@ -1012,14 +991,14 @@ def build_stack_trace(self, line, addresses_str): if not addresses: return "" - self._prefetch_addresses([(addr, True) for addr in addresses]) + self._prefetch_addresses(addresses) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" trace = "" for addr in addresses: - output, _ = self._resolve_address(addr, is_return_addr=True) + output, _ = self._resolve_address(addr) if output is not None: trace += "%s %s: %s\n" % (prefix, addr, output) @@ -1037,14 +1016,14 @@ def build_register_trace(self, line, reg_matches): Formatted annotation string, or empty string if nothing decoded. """ # Pre-fetch code-address registers - addr_specs = [] + reg_addrs = [] for reg_name, addr in reg_matches: if reg_name in ("EXCCAUSE", "MCAUSE"): continue if reg_name in self.NON_CODE_REGISTERS: continue - addr_specs.append((addr, reg_name == "RA")) - self._prefetch_addresses(addr_specs) + reg_addrs.append(addr) + self._prefetch_addresses(reg_addrs) prefix_match = self.PREFIX_RE.match(line) prefix = prefix_match.group(0) if prefix_match is not None else "" @@ -1072,9 +1051,7 @@ def build_register_trace(self, line, reg_matches): if reg_name in self.NON_CODE_REGISTERS: continue - output, _ = self._resolve_address( - addr, is_return_addr=(reg_name == "RA") - ) + output, _ = self._resolve_address(addr) if output is not None: trace += "%s %s: %s: %s\n" % (prefix, reg_name, addr, output)