stgatilov

embed_printer_for_value full working demo

Aug 2nd, 2026
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.04 KB | None | 0 0
  1. import gdb
  2. from collections import namedtuple
  3.  
  4. # displays given string, no children
  5. class LiteralStringPrinter:
  6.     def __init__(self, literal):
  7.         self.literal = literal
  8.     def to_string(self):
  9.         return self.literal
  10.  
  11. # ===================================================================================
  12. # this hack provides feature similar to the ",view(*)" and "Synthetic" of natvis
  13. # it allows to pin specific pretty-printer class to a gdb.Value
  14.  
  15. # fixed-size circular buffer
  16. # every added element has ID: you can find it by ID and check if it was removed
  17. class GdbHelperCircularBuffer:
  18.     def __init__(self, max_count):
  19.         self.max_count = max_count
  20.         self.stat_count = 0     # number of values
  21.         self.array = [None] * self.max_count
  22.         self.beg = 0
  23.         self.end = 0
  24.  
  25.     def remove(self):
  26.         assert self.end - self.beg > 0
  27.         elem = self.array[self.beg % len(self.array)]
  28.         self.beg += 1
  29.         self.stat_count -= 1
  30.         return elem
  31.  
  32.     def add(self, elem):
  33.         assert self.end - self.beg < self.max_count
  34.         id = self.end
  35.         self.array[id % len(self.array)] = elem
  36.         self.end += 1
  37.         self.stat_count += 1
  38.         return id
  39.    
  40.     # if budget is exceeded, then removes oldest values automatically
  41.     # budget is: don't overwrite itself
  42.     def add_limited(self, elem):
  43.         while self.stat_count + 1 >= self.max_count:
  44.             self.remove()
  45.        
  46.         id = self.add(elem)
  47.         return id
  48.  
  49.     def get(self, id):
  50.         if not (id >= self.beg and id < self.end):
  51.             return None     # already removed
  52.         index = id % len(self.array)
  53.         value = self.array[index]
  54.         return value
  55.  
  56. # every gdb.Value with pinned printer is stored in this huge global buffer
  57. g_gdb_helper_table = GdbHelperCircularBuffer(10 ** 6)
  58. GdbHelperEntry = namedtuple('GdbHelperEntry', ['value', 'gen_printer'])
  59.  
  60. def embed_printer_for_value(value, gen_printer):
  61.     id = g_gdb_helper_table.add_limited(GdbHelperEntry(value, gen_printer))
  62.     helper_type = gdb.lookup_type('GdbHelper')
  63.     assert helper_type and helper_type.sizeof == 8, "Make sure GdbHelper struct exists and is not stripped out."
  64.     helper_value = gdb.Value(id.to_bytes(8, byteorder = 'little'), helper_type)
  65.     return helper_value
  66.  
  67. def GdbHelperPrinter(value):
  68.     id = int.from_bytes(value.bytes, byteorder = 'little')
  69.     elem = g_gdb_helper_table.get(id)
  70.     if elem is None:
  71.         return LiteralStringPrinter('{{value is obsolete}}')
  72.     return elem.gen_printer(elem.value)
  73.  
  74. # register the pretty-printer for GdbHelper
  75. def register_gdb_helper():
  76.     coll = gdb.printing.RegexpCollectionPrettyPrinter('GdbHelper')
  77.     coll.add_printer('GdbHelper', '^GdbHelper$', GdbHelperPrinter)
  78.     gdb.printing.register_pretty_printer(gdb.current_objfile(), coll, replace = True)
  79. register_gdb_helper()
  80.  
  81. #=========================================================================
  82.  
  83. # this is alternative printer for DataBlock
  84. # it shows the internal subobject
  85. class SyntheticPrinter:
  86.     def __init__(self, value):
  87.         self.value = value
  88.     def to_string(self):
  89.         return '{...}'
  90.     def children(self):
  91.         size = int(self.value['size'])
  92.         pointer = self.value['hb']['data']
  93.         return ((str(i), pointer[i]) for i in range(size))
  94.  
  95.  
  96. # this printer is actually registered for DataBlock type
  97. class DataBlockPrinter:
  98.     def __init__(self, value):
  99.         self.value = value
  100.  
  101.     def to_string(self):
  102.         size = int(self.value['size'])
  103.         address = int(self.value['hb']['data'])
  104.         return 'Size %d @ 0x%x' % (size, address)
  105.    
  106.     def children(self):
  107.         size = int(self.value['size'])
  108.         return [
  109.             ('size', size),
  110.             ('data', embed_printer_for_value(self.value, SyntheticPrinter)),
  111.         ]
  112.  
  113.  
  114. coll = gdb.printing.RegexpCollectionPrettyPrinter('test')
  115. coll.add_printer('DataBlock', '^DataBlock$', DataBlockPrinter)
  116. gdb.printing.register_pretty_printer(gdb.current_objfile(), coll, replace = True)
  117.  
Tags: gdb
Advertisement
Add Comment
Please, Sign In to add comment