mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[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.
This commit is contained in:
@@ -1,8 +1,12 @@
|
|||||||
import gdb
|
import gdb
|
||||||
import gdb.printing
|
import gdb.printing
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.path.append('./scripts')
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"])
|
Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"])
|
||||||
|
LogEntry = namedtuple("LogHeader", ["id", "bytes", "severity", "area", "message"])
|
||||||
|
|
||||||
class PrintStackCommand(gdb.Command):
|
class PrintStackCommand(gdb.Command):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -283,6 +287,57 @@ class PrintProfilesCommand(gdb.Command):
|
|||||||
print(f"{name:>{max_len}}: {avg:15.3f}")
|
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:
|
class CapTablePrinter:
|
||||||
def __init__(self, val):
|
def __init__(self, val):
|
||||||
node_map = val["m_caps"]
|
node_map = val["m_caps"]
|
||||||
@@ -415,6 +470,7 @@ PrintBacktraceCommand()
|
|||||||
TableWalkCommand()
|
TableWalkCommand()
|
||||||
GetThreadsCommand()
|
GetThreadsCommand()
|
||||||
PrintProfilesCommand()
|
PrintProfilesCommand()
|
||||||
|
DumpLogCommand()
|
||||||
|
|
||||||
gdb.execute("display/i $rip")
|
gdb.execute("display/i $rip")
|
||||||
if not gdb.selected_inferior().was_attached:
|
if not gdb.selected_inferior().was_attached:
|
||||||
|
|||||||
Reference in New Issue
Block a user