libcruft-util/cruft/util/debug/gdb/printers.py

131 lines
3.5 KiB
Python
Raw Normal View History

import re
import gdb
import struct
class CoordPrinter(object):
val: gdb.Value
def __init__(self, val: gdb.Value):
self.val = val
def to_string(self) -> str:
return self.val['data']
@staticmethod
def display_hint() -> str:
return 'array'
def children(self):
data = self.val['data']
indices = data.type.range()
for i in range(indices[0], indices[1] + 1):
yield (str(i), data[i])
class ViewPrinter(object):
def __init__(self, val: gdb.Value):
self.val = val
def to_string(self) -> str:
end = int(self.val["m_end"])
begin = int(self.val["m_begin"])
size = end - begin
return f"{self.val.type.tag} of length {size}"
@staticmethod
def display_hint() -> str:
return 'array'
def children(self):
cursor = self.val["m_begin"]
last = self.val["m_end"]
index = 0
while cursor != last:
val = cursor.dereference()
res = ("[%d]" % index, val)
yield res
cursor = cursor + 1
index = index + 1
class EndianValuePrinter(object):
val: gdb.Type
def __init__(self, val: gdb.Value):
self.val = val
# The type should be something like:
# "cruft::endian::value<cruft::endian::BIG,u64>"
order_name = str(val.type.template_argument(0))
# Fuck knows how to use the GDB API. It's easier to just search for a
# differentiator that's unlikely to be present in anything else.
if '::BIG' in order_name:
self.order = '>'
elif '::LITTLE' in order_name:
self.order = '<'
else:
raise RuntimeError("Unknown endianness")
# Find a format specifier for the size of the underlying value
self.size = {
1: 'B',
2: 'H',
4: 'I',
8: 'Q',
}[self.val.type.sizeof]
def to_string(self):
# Construct format specifiers for converting to bytes, then from
# bytes, so that we can perform the byte reversal.
to_bytes = f"{self.order}{self.size}"
from_bytes = f"={self.size}"
raw = int(self.val["raw"])
native = struct.unpack(from_bytes, struct.pack(to_bytes, raw))[0]
# Print the value and some annotations so that the user isn't misled
# about what value they're looking at.
return f"{native} (0x{native:x}, from 0x{raw:x})"
def build_cruft_dict():
pretty_printers_dict[re.compile('^cruft::point.*$')] = lambda val: CoordPrinter(val)
pretty_printers_dict[re.compile('^cruft::vector.*$')] = lambda val: CoordPrinter(val)
pretty_printers_dict[re.compile('^cruft::extent.*$')] = lambda val: CoordPrinter(val)
pretty_printers_dict[re.compile('^cruft::colour.*$')] = lambda val: CoordPrinter(val)
pretty_printers_dict[re.compile('^cruft::view')] = lambda val: ViewPrinter(val)
pretty_printers_dict[re.compile('^cruft::endian::value')] = lambda val: EndianValuePrinter(val)
def lookup(val):
t = val.type
if t.code == gdb.TYPE_CODE_REF:
t = t.target()
t = t.unqualified().strip_typedefs()
typename = t.tag
if typename == None:
return None
for function in pretty_printers_dict:
if function.search(typename):
return pretty_printers_dict[function](val)
return None
def register_cruft_printers():
gdb.pretty_printers.append(lookup)
pretty_printers_dict = {}
build_cruft_dict()