master
1# pretty printing for the standard library.
2# put "source /path/to/stage2_gdb_pretty_printers.py" in ~/.gdbinit to load it automatically.
3import re
4import gdb.printing
5
6# Handles both ArrayList and ArrayListUnmanaged.
7class ArrayListPrinter:
8 def __init__(self, val):
9 self.val = val
10
11 def to_string(self):
12 type = self.val.type.name[len('std.array_list.'):]
13 type = re.sub(r'^ArrayListAligned(Unmanaged)?\((.*),null\)$', r'ArrayList\1(\2)', type)
14 return '%s of length %s, capacity %s' % (type, self.val['items']['len'], self.val['capacity'])
15
16 def children(self):
17 for i in range(self.val['items']['len']):
18 item = self.val['items']['ptr'] + i
19 yield ('[%d]' % i, item.dereference())
20
21 def display_hint(self):
22 return 'array'
23
24class MultiArrayListPrinter:
25 def __init__(self, val):
26 self.val = val
27
28 def child_type(self):
29 (helper_fn, _) = gdb.lookup_symbol('%s.dbHelper' % self.val.type.name)
30 return helper_fn.type.fields()[1].type.target()
31
32 def to_string(self):
33 type = self.val.type.name[len('std.multi_array_list.'):]
34 return '%s of length %s, capacity %s' % (type, self.val['len'], self.val['capacity'])
35
36 def slice(self):
37 fields = self.child_type().fields()
38 base = self.val['bytes']
39 cap = self.val['capacity']
40 len = self.val['len']
41
42 if len == 0:
43 return
44
45 fields = sorted(fields, key=lambda field: field.type.alignof, reverse=True)
46
47 for field in fields:
48 ptr = base.cast(field.type.pointer()).dereference().cast(field.type.array(len - 1))
49 base += field.type.sizeof * cap
50 yield (field.name, ptr)
51
52 def children(self):
53 for i, (name, ptr) in enumerate(self.slice()):
54 yield ('[%d]' % i, name)
55 yield ('[%d]' % i, ptr)
56
57 def display_hint(self):
58 return 'map'
59
60# Handles both HashMap and HashMapUnmanaged.
61class HashMapPrinter:
62 def __init__(self, val):
63 self.type = val.type
64 is_managed = re.search(r'^std\.hash_map\.HashMap\(', self.type.name)
65 self.val = val['unmanaged'] if is_managed else val
66
67 def header_ptr_type(self):
68 (helper_fn, _) = gdb.lookup_symbol('%s.dbHelper' % self.val.type.name)
69 return helper_fn.type.fields()[1].type
70
71 def header(self):
72 if self.val['metadata'] == 0:
73 return None
74 return (self.val['metadata'].cast(self.header_ptr_type()) - 1).dereference()
75
76 def to_string(self):
77 type = self.type.name[len('std.hash_map.'):]
78 type = re.sub(r'^HashMap(Unmanaged)?\((.*),std.hash_map.AutoContext\(.*$', r'AutoHashMap\1(\2)', type)
79 hdr = self.header()
80 if hdr is not None:
81 cap = hdr['capacity']
82 else:
83 cap = 0
84 return '%s of length %s, capacity %s' % (type, self.val['size'], cap)
85
86 def children(self):
87 hdr = self.header()
88 if hdr is None:
89 return
90 is_map = self.display_hint() == 'map'
91 for i in range(hdr['capacity']):
92 metadata = self.val['metadata'] + i
93 if metadata.dereference()['used'] == 1:
94 yield ('[%d]' % i, (hdr['keys'] + i).dereference())
95 if is_map:
96 yield ('[%d]' % i, (hdr['values'] + i).dereference())
97
98 def display_hint(self):
99 for field in self.header_ptr_type().target().fields():
100 if field.name == 'values':
101 return 'map'
102 return 'array'
103
104# Handles both ArrayHashMap and ArrayHashMapUnmanaged.
105class ArrayHashMapPrinter:
106 def __init__(self, val):
107 self.type = val.type
108 is_managed = re.search(r'^std\.array_hash_map\.ArrayHashMap\(', self.type.name)
109 self.val = val['unmanaged'] if is_managed else val
110
111 def to_string(self):
112 type = self.type.name[len('std.array_hash_map.'):]
113 type = re.sub(r'^ArrayHashMap(Unmanaged)?\((.*),std.array_hash_map.AutoContext\(.*$', r'AutoArrayHashMap\1(\2)', type)
114 return '%s of length %s' % (type, self.val['entries']['len'])
115
116 def children(self):
117 entries = MultiArrayListPrinter(self.val['entries'])
118 len = self.val['entries']['len']
119 fields = {}
120 for name, ptr in entries.slice():
121 fields[str(name)] = ptr
122
123 for i in range(len):
124 if 'key' in fields:
125 yield ('[%d]' % i, fields['key'][i])
126 else:
127 yield ('[%d]' % i, '{}')
128 if 'value' in fields:
129 yield ('[%d]' % i, fields['value'][i])
130
131 def display_hint(self):
132 for name, ptr in MultiArrayListPrinter(self.val['entries']).slice():
133 if name == 'value':
134 return 'map'
135 return 'array'
136
137pp = gdb.printing.RegexpCollectionPrettyPrinter('Zig standard library')
138pp.add_printer('ArrayList', r'^std\.array_list\.ArrayListAligned(Unmanaged)?\(.*\)$', ArrayListPrinter)
139pp.add_printer('MultiArrayList', r'^std\.multi_array_list\.MultiArrayList\(.*\)$', MultiArrayListPrinter)
140pp.add_printer('HashMap', r'^std\.hash_map\.HashMap(Unmanaged)?\(.*\)$', HashMapPrinter)
141pp.add_printer('ArrayHashMap', r'^std\.array_hash_map\.ArrayHashMap(Unmanaged)?\(.*\)$', ArrayHashMapPrinter)
142gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)