Browse Source

feat: gdb pretty printer

greatbridf 2 years ago
parent
commit
69cc04e836
1 changed files with 104 additions and 10 deletions
  1. 104 10
      pretty-print.py

+ 104 - 10
pretty-print.py

@@ -1,4 +1,5 @@
 import gdb.printing
+import re
 
 def create_iter(item, end, idx):
     return vectorPrinter._iterator(item, end, idx)
@@ -35,12 +36,78 @@ class vectorPrinter:
     def children(self):
         return self._iterator(self.val['m_arr'], self.val['m_arr'] + self.val['m_size'], 0)
 
+def _leftmost(node):
+    ret = node
+    while ret['left'] != 0:
+        ret = ret['left'].dereference()
+    return ret
+
+def _next(node):
+    if node['right']:
+        return _leftmost(node['right'].dereference())
+    else:
+        if node['parent'] == 0:
+            return None
+        parent = node['parent'].dereference()
+        if parent['left'] == node.address:
+            return parent
+        ret = node
+        while True:
+            ret = ret['parent'].dereference()
+            if ret['parent'] == 0:
+                return None
+            if ret['parent'].dereference()['left'] == ret.address:
+                break
+        return ret['parent'].dereference()
+
+class mapPrinter:
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        return "types::map"
+
+    def display_hint(self):
+        return 'array'
+
+    def children(self):
+        yield '[root]', self.val['root']
+        if self.val['root'] == 0:
+            return
+
+        nd = _leftmost(self.val['root'].dereference())
+        i = 0
+        while True:
+            yield "[%d]" % i, nd['v']
+            nd = _next(nd)
+            i += 1
+            if nd == None:
+                break
+
 class stringPrinter:
     def __init__(self, val):
         self.val = val
     
     def to_string(self):
         return self.val['m_arr']
+    
+    def children(self):
+        yield 'str', self.val['m_arr']
+
+        if self.val['m_arr'] == 0:
+            return
+
+        yield 'length', self.val['m_size'] - 1
+
+        ptr = self.val['m_arr']
+        i = 0
+
+        while ptr.dereference() != 0:
+            yield '[%d]' % i, ptr.dereference()
+            ptr += 1
+            i += 1
+
+        yield '[%d]' % i, 0
 
 class listPrinter:
     def __init__(self, val):
@@ -53,21 +120,48 @@ class listPrinter:
         return 'array'
 
     def children(self):
-        node = self.val['head']['next']
+        head = self.val['head']
         end = self.val['tail']
+
+        yield '[head]', head
+        yield '[tail]', end
+        
+        if head == 0 or end == 0:
+            return
+
+        node = head['next']
         idx = 0
         while node != end:
             yield '[%d]' % idx, node['value']
             idx += 1
             node = node['next']
 
-def build_pretty_printer():
-    pp = gdb.printing.RegexpCollectionPrettyPrinter("gbos")
-    pp.add_printer("vector", "^types::vector<.*?>$", vectorPrinter)
-    pp.add_printer("string", "^types::string<.*?>$", stringPrinter)
-    pp.add_printer("list", "^types::list<.*?>$", listPrinter)
-    return pp
+def build_pretty_printer(val):
+    type = val.type
+
+    if type.code == gdb.TYPE_CODE_REF:
+        type = type.target()
+    if type.code == gdb.TYPE_CODE_PTR:
+        type = type.target()
+    
+    type = type.unqualified().strip_typedefs()
+    typename = type.tag
+
+    if typename == None:
+        return None
+    
+    if re.compile(r"^types::list<.*?>$").match(typename):
+        return listPrinter(val)
+
+    if re.compile(r"^types::vector<.*?>$").match(typename):
+        return vectorPrinter(val)
+
+    if re.compile(r"^types::string<.*?>$").match(typename):
+        return stringPrinter(val)
+
+    if re.compile(r"^types::map<.*?>$").match(typename):
+        return mapPrinter(val)
+    
+    return None
 
-gdb.printing.register_pretty_printer(
-        gdb.current_objfile(),
-        build_pretty_printer())
+gdb.pretty_printers.append(build_pretty_printer)