Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import gdb
- from collections import namedtuple
- # displays given string, no children
- class LiteralStringPrinter:
- def __init__(self, literal):
- self.literal = literal
- def to_string(self):
- return self.literal
- # ===================================================================================
- # this hack provides feature similar to the ",view(*)" and "Synthetic" of natvis
- # it allows to pin specific pretty-printer class to a gdb.Value
- # fixed-size circular buffer
- # every added element has ID: you can find it by ID and check if it was removed
- class GdbHelperCircularBuffer:
- def __init__(self, max_count):
- self.max_count = max_count
- self.stat_count = 0 # number of values
- self.array = [None] * self.max_count
- self.beg = 0
- self.end = 0
- def remove(self):
- assert self.end - self.beg > 0
- elem = self.array[self.beg % len(self.array)]
- self.beg += 1
- self.stat_count -= 1
- return elem
- def add(self, elem):
- assert self.end - self.beg < self.max_count
- id = self.end
- self.array[id % len(self.array)] = elem
- self.end += 1
- self.stat_count += 1
- return id
- # if budget is exceeded, then removes oldest values automatically
- # budget is: don't overwrite itself
- def add_limited(self, elem):
- while self.stat_count + 1 >= self.max_count:
- self.remove()
- id = self.add(elem)
- return id
- def get(self, id):
- if not (id >= self.beg and id < self.end):
- return None # already removed
- index = id % len(self.array)
- value = self.array[index]
- return value
- # every gdb.Value with pinned printer is stored in this huge global buffer
- g_gdb_helper_table = GdbHelperCircularBuffer(10 ** 6)
- GdbHelperEntry = namedtuple('GdbHelperEntry', ['value', 'gen_printer'])
- def embed_printer_for_value(value, gen_printer):
- id = g_gdb_helper_table.add_limited(GdbHelperEntry(value, gen_printer))
- helper_type = gdb.lookup_type('GdbHelper')
- assert helper_type and helper_type.sizeof == 8, "Make sure GdbHelper struct exists and is not stripped out."
- helper_value = gdb.Value(id.to_bytes(8, byteorder = 'little'), helper_type)
- return helper_value
- def GdbHelperPrinter(value):
- id = int.from_bytes(value.bytes, byteorder = 'little')
- elem = g_gdb_helper_table.get(id)
- if elem is None:
- return LiteralStringPrinter('{{value is obsolete}}')
- return elem.gen_printer(elem.value)
- # register the pretty-printer for GdbHelper
- def register_gdb_helper():
- coll = gdb.printing.RegexpCollectionPrettyPrinter('GdbHelper')
- coll.add_printer('GdbHelper', '^GdbHelper$', GdbHelperPrinter)
- gdb.printing.register_pretty_printer(gdb.current_objfile(), coll, replace = True)
- register_gdb_helper()
- #=========================================================================
- # this is alternative printer for DataBlock
- # it shows the internal subobject
- class SyntheticPrinter:
- def __init__(self, value):
- self.value = value
- def to_string(self):
- return '{...}'
- def children(self):
- size = int(self.value['size'])
- pointer = self.value['hb']['data']
- return ((str(i), pointer[i]) for i in range(size))
- # this printer is actually registered for DataBlock type
- class DataBlockPrinter:
- def __init__(self, value):
- self.value = value
- def to_string(self):
- size = int(self.value['size'])
- address = int(self.value['hb']['data'])
- return 'Size %d @ 0x%x' % (size, address)
- def children(self):
- size = int(self.value['size'])
- return [
- ('size', size),
- ('data', embed_printer_for_value(self.value, SyntheticPrinter)),
- ]
- coll = gdb.printing.RegexpCollectionPrettyPrinter('test')
- coll.add_printer('DataBlock', '^DataBlock$', DataBlockPrinter)
- gdb.printing.register_pretty_printer(gdb.current_objfile(), coll, replace = True)
Advertisement
Add Comment
Please, Sign In to add comment