From 19791d1d7f0a29c1fae75cf91b2f68ffd157bcae Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 9 Oct 2022 16:46:12 -0700 Subject: [PATCH] [debug] Add gdb pretty-printers: vectors, handle sets, cap table Adding pretty printers to aid in debugging: * For the cap_table type so that `p g_cap_table` displays a neat table * For node_sets of handles to easily see what handles a process owns * For util::vector to include its contents in the output --- assets/debugging/jsix.elf-gdb.py | 132 +++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/assets/debugging/jsix.elf-gdb.py b/assets/debugging/jsix.elf-gdb.py index e2f8b91..944dd72 100644 --- a/assets/debugging/jsix.elf-gdb.py +++ b/assets/debugging/jsix.elf-gdb.py @@ -1,4 +1,8 @@ import gdb +import gdb.printing + +from collections import namedtuple +Capability = namedtuple("Capability", ["id", "parent", "refcount", "caps", "type", "koid"]) class PrintStackCommand(gdb.Command): def __init__(self): @@ -278,6 +282,134 @@ class PrintProfilesCommand(gdb.Command): for name, avg in results.items(): print(f"{name:>{max_len}}: {avg:15.3f}") + +class CapTablePrinter: + def __init__(self, val): + node_map = val["m_caps"] + self.nodes = node_map["m_nodes"] + self.count = int(node_map["m_count"]) + self.capacity = int(node_map["m_capacity"]) + + class _iterator: + def __init__(self, nodes, capacity): + self.nodes = [] + + for i in range(capacity): + node = nodes[i] + + node_id = int(node["id"]) + if node_id == 0: + continue + + self.nodes.append(Capability( + id = node_id, + parent = int(node["parent"]), + refcount = int(node["holders"]), + caps = int(node["caps"]), + type = str(node["type"])[14:], + koid = node['object']['m_koid'])) + + self.nodes.sort(key=lambda n: n.id, reverse=True) + + def __iter__(self): + return self + + def __next__(self): + if not self.nodes: + raise StopIteration + + node = self.nodes.pop() + + desc = f'p:{node.parent:016x} refs:{node.refcount:2} caps:{node.caps:04x} {node.type:14} {node.koid}' + return (f"{node.id:016x}", desc) + + def to_string(self): + return f"Cap table with {self.count}/{self.capacity} nodes.\n" + + def children(self): + return self._iterator(self.nodes, self.capacity) + + +class VectorPrinter: + def __init__(self, vector): + self.name = vector.type.tag + self.count = vector["m_size"] + self.array = vector["m_elements"] + + class _iterator: + def __init__(self, array, count, deref): + self.array = array + self.count = count + self.deref = deref + self.index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.index >= self.count: + raise StopIteration + + item = self.array[self.index] + if self.deref: + item = item.dereference() + + result = (f"{self.index:3}", item) + self.index += 1 + return result + + def to_string(self): + return f"{self.name} [{self.count}]" + + def children(self): + deref = self.count > 0 and self.array[0].type.code == gdb.TYPE_CODE_PTR + return self._iterator(self.array, int(self.count), deref) + + +class HandleSetPrinter: + def __init__(self, nodeset): + self.node_map = nodeset['m_map'] + self.count = self.node_map['m_count'] + self.capacity = self.node_map['m_capacity'] + + class _iterator: + def __init__(self, nodes, capacity): + self.items = [] + self.index = 0 + for i in range(capacity): + item = nodes[i] + if int(item) != 0: + self.items.append(int(item)) + self.items.sort() + + def __iter__(self): + return self + + def __next__(self): + if self.index >= len(self.items): + raise StopIteration + result = (f"{self.index}", f"{self.items[self.index]:016x}") + self.index += 1 + return result + + def to_string(self): + return f"node_set[{self.count} / {self.capacity}]:" + + def children(self): + return self._iterator(self.node_map['m_nodes'], self.capacity) + + +def build_pretty_printers(): + pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix") + pp.add_printer("cap table", '^cap_table$', CapTablePrinter) + pp.add_printer("handle set", '^util::node_set$', HandleSetPrinter) + pp.add_printer("vector", '^util::vector<.*>$', VectorPrinter) + return pp + +gdb.printing.register_pretty_printer( + gdb.current_objfile(), + build_pretty_printers()) + PrintStackCommand() PrintBacktraceCommand() TableWalkCommand()