From 6fa9b33ac00f6ce2798e14cc695bcb5bf3bf4712 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Tue, 14 Feb 2023 20:10:30 -0800 Subject: [PATCH] [debugging] Add `j6log` gdb command Now that the log ring buffer is at a fixed known address, and entries persist even after being read, it's easy to add a command to see what's in the buffer from GDB. Useful if there's some log messages that hadn't yet been printed at the time of a panic. --- assets/debugging/jsix.elf-gdb.py | 56 ++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/assets/debugging/jsix.elf-gdb.py b/assets/debugging/jsix.elf-gdb.py index 73e5238..382226b 100644 --- a/assets/debugging/jsix.elf-gdb.py +++ b/assets/debugging/jsix.elf-gdb.py @@ -1,8 +1,12 @@ import gdb import gdb.printing +import sys +sys.path.append('./scripts') + from collections import namedtuple Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"]) +LogEntry = namedtuple("LogHeader", ["id", "bytes", "severity", "area", "message"]) class PrintStackCommand(gdb.Command): def __init__(self): @@ -283,6 +287,57 @@ class PrintProfilesCommand(gdb.Command): print(f"{name:>{max_len}}: {avg:15.3f}") +class DumpLogCommand(gdb.Command): + level_names = ["", "fatal", "error", "warn", "info", "verbose", "spam"] + + def __init__(self): + super().__init__("j6log", gdb.COMMAND_DATA) + + from memory import Layout + layout = Layout("definitions/memory_layout.yaml") + for region in layout.regions: + if region.name == "logs": + self.base_addr = region.start + break + + self.areas = [] + area_re = re.compile(r"LOG\(\s*(\w+).*") + with open("src/libraries/j6/j6/tables/log_areas.inc", 'r') as areas_inc: + for line in areas_inc: + m = area_re.match(line) + if m: + self.areas.append(m.group(1)) + + def get_entry(self, addr): + addr = int(addr) + size = int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->bytes")) + mlen = size - 8 + + return LogEntry( + int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->id")), + size, + int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->severity")), + int(gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->area")), + gdb.parse_and_eval(f"((j6_log_entry*){addr:#x})->message").string(length=mlen)) + + def invoke(self, arg, from_tty): + start = gdb.parse_and_eval("g_logger.m_start & (g_logger.m_buffer.count - 1)") + end = gdb.parse_and_eval("g_logger.m_end & (g_logger.m_buffer.count - 1)") + if end < start: + end += gdb.parse_and_eval("g_logger.m_buffer.count") + + print(f"Logs are {start} -> {end}") + + addr = self.base_addr + start + end += self.base_addr + while addr < end: + entry = self.get_entry(addr) + addr += entry.bytes + area = self.areas[entry.area] + level = self.level_names[entry.severity] + print(f"{area:>7}:{level:7} {entry.message}") + + class CapTablePrinter: def __init__(self, val): node_map = val["m_caps"] @@ -415,6 +470,7 @@ PrintBacktraceCommand() TableWalkCommand() GetThreadsCommand() PrintProfilesCommand() +DumpLogCommand() gdb.execute("display/i $rip") if not gdb.selected_inferior().was_attached: