authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-03-16 15:38:30+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-03-16 15:50:03+01:00
logfeb8981a95988434506bad9864498e2ff1ff9243
treea22230a1a1c91ac5c6101bd89e9ab2e30a01a327
parente18c29af5bf873ed3165ab9abb57b2246f37c406

gdb: add slice, multi array list, and array hash map printers


3 files changed, 155 insertions(+), 15 deletions(-)

lib/std/hash_map.zig+14
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");
2const assert = debug.assert;3const assert = debug.assert;
3const autoHash = std.hash.autoHash;4const autoHash = std.hash.autoHash;
4const debug = std.debug;5const debug = std.debug;
...@@ -1576,6 +1577,19 @@ pub fn HashMapUnmanaged(...@@ -1576,6 +1577,19 @@ pub fn HashMapUnmanaged(
1576 self.metadata = null;1577 self.metadata = null;
1577 self.available = 0;1578 self.available = 0;
1578 }1579 }
1580
1581 /// This function is used in tools/zig-gdb.py to fetch the header type to facilitate
1582 /// fancy debug printing for this type.
1583 fn gdbHelper(self: *Self, hdr: *Header) void {
1584 _ = self;
1585 _ = hdr;
1586 }
1587
1588 comptime {
1589 if (builtin.mode == .Debug) {
1590 _ = gdbHelper;
1591 }
1592 }
1579 };1593 };
1580}1594}
15811595
lib/std/multi_array_list.zig+14
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
3const meta = std.meta;4const meta = std.meta;
4const mem = std.mem;5const mem = std.mem;
...@@ -433,6 +434,19 @@ pub fn MultiArrayList(comptime S: type) type {...@@ -433,6 +434,19 @@ pub fn MultiArrayList(comptime S: type) type {
433 fn FieldType(field: Field) type {434 fn FieldType(field: Field) type {
434 return meta.fieldInfo(S, field).field_type;435 return meta.fieldInfo(S, field).field_type;
435 }436 }
437
438 /// This function is used in tools/zig-gdb.py to fetch the child type to facilitate
439 /// fancy debug printing for this type.
440 fn gdbHelper(self: *Self, child: *S) void {
441 _ = self;
442 _ = child;
443 }
444
445 comptime {
446 if (builtin.mode == .Debug) {
447 _ = gdbHelper;
448 }
449 }
436 };450 };
437}451}
438452
tools/zig-gdb.py+127-15
...@@ -32,6 +32,27 @@ class BufPrinter:...@@ -32,6 +32,27 @@ class BufPrinter:
32 def display_hint(self):32 def display_hint(self):
33 return 'string'33 return 'string'
3434
35class SlicePrinter:
36 def __init__(self, val):
37 self.val = val
38
39 def children(self):
40 for i in range(self.val['len']):
41 yield ('[%d]' % i, (self.val['ptr'] + i).dereference())
42
43 def display_hint(self):
44 return 'array'
45
46class SliceStringPrinter:
47 def __init__(self, val):
48 self.val = val
49
50 def to_string(self):
51 return self.val['ptr'].string(length=self.val['len'])
52
53 def display_hint(self):
54 return 'string'
55
35# Handles both ArrayList and ArrayListUnmanaged.56# Handles both ArrayList and ArrayListUnmanaged.
36class ArrayListPrinter:57class ArrayListPrinter:
37 def __init__(self, val):58 def __init__(self, val):
...@@ -39,52 +60,143 @@ class ArrayListPrinter:...@@ -39,52 +60,143 @@ class ArrayListPrinter:
3960
40 def to_string(self):61 def to_string(self):
41 type = self.val.type.name[len('std.array_list.'):]62 type = self.val.type.name[len('std.array_list.'):]
42 type = re.sub(r'ArrayListAligned(Unmanaged)?\((.*),null\)$', r'ArrayList\1(\2)', type)63 type = re.sub(r'^ArrayListAligned(Unmanaged)?\((.*),null\)$', r'ArrayList\1(\2)', type)
43 return '%s of length %s, capacity %s' % (type, self.val['items']['len'], self.val['capacity'])64 return '%s of length %s, capacity %s' % (type, self.val['items']['len'], self.val['capacity'])
4465
45 def children(self):66 def children(self):
46 for i in range(int(self.val['items']['len'])):67 for i in range(self.val['items']['len']):
47 item = self.val['items']['ptr'] + i68 item = self.val['items']['ptr'] + i
48 yield ('[%d]' % i, item.dereference())69 yield ('[%d]' % i, item.dereference())
4970
50 def display_hint(self):71 def display_hint(self):
51 return 'array'72 return 'array'
5273
53# Handles both HashMap and HashMapUnmanaged74class MultiArrayListPrinter:
75 def __init__(self, val):
76 self.val = val
77
78 def child_type(self):
79 (helper_fn, _) = gdb.lookup_symbol('%s.gdbHelper' % self.val.type.name)
80 return helper_fn.type.fields()[1].type.target()
81
82 def to_string(self):
83 type = self.val.type.name[len('std.multi_array_list.'):]
84 return '%s of length %s, capacity %s' % (type, self.val['len'], self.val['capacity'])
85
86 def slice(self):
87 fields = self.child_type().fields()
88 base = self.val['bytes']
89 cap = self.val['capacity']
90 len = self.val['len']
91
92 if len == 0:
93 return
94
95 fields = sorted(fields, key=lambda field: field.type.alignof, reverse=True)
96
97 for field in fields:
98 ptr = base.cast(field.type.pointer()).dereference().cast(field.type.array(len - 1))
99 base += field.type.sizeof * cap
100 yield (field.name, ptr)
101
102 def children(self):
103 for i, (name, ptr) in enumerate(self.slice()):
104 yield ('[%d]' % i, name)
105 yield ('[%d]' % i, ptr)
106
107 def display_hint(self):
108 return 'map'
109
110# Handles both HashMap and HashMapUnmanaged.
54class HashMapPrinter:111class HashMapPrinter:
55 def __init__(self, val):112 def __init__(self, val):
56 self.type = val.type113 self.type = val.type
57 is_managed = re.search(r'^std\.hash_map\.HashMap\(', self.type.name)114 is_managed = re.search(r'^std\.hash_map\.HashMap\(', self.type.name)
58 self.val = val['unmanaged'] if is_managed else val115 self.val = val['unmanaged'] if is_managed else val
59116
117 def header_ptr_type(self):
118 (helper_fn, _) = gdb.lookup_symbol('%s.gdbHelper' % self.val.type.name)
119 return helper_fn.type.fields()[1].type
120
60 def header(self):121 def header(self):
61 (header_fn, _) = gdb.lookup_symbol('%s.header' % self.val.type.name)122 if self.val['metadata'] == 0:
62 header_ptr_type = header_fn.type.target()123 return None
63 return (self.val['metadata'].cast(header_ptr_type) - 1).dereference()124 return (self.val['metadata'].cast(self.header_ptr_type()) - 1).dereference()
64125
65 def to_string(self):126 def to_string(self):
66 type = self.type.name[len('std.hash_map.'):]127 type = self.type.name[len('std.hash_map.'):]
67 type = re.sub(r'^HashMap(Unmanaged)?\((.*),std.hash_map.AutoContext\(.*$', r'AutoHashMap\1(\2)', type)128 type = re.sub(r'^HashMap(Unmanaged)?\((.*),std.hash_map.AutoContext\(.*$', r'AutoHashMap\1(\2)', type)
68 return '%s of length %s, capacity %s' % (type, self.val['size'], self.header()['capacity'])129 hdr = self.header()
130 if hdr is not None:
131 cap = hdr['capacity']
132 else:
133 cap = 0
134 return '%s of length %s, capacity %s' % (type, self.val['size'], cap)
69135
70 def children(self):136 def children(self):
71 hdr = self.header()137 hdr = self.header()
72 for i in range(int(hdr['capacity'])):138 if hdr is None:
139 return
140 is_map = self.display_hint() == 'map'
141 for i in range(hdr['capacity']):
73 metadata = self.val['metadata'] + i142 metadata = self.val['metadata'] + i
74 if metadata.dereference()['used'] == 1:143 if metadata.dereference()['used'] == 1:
75 yield ('[%d]' % i, (hdr['keys'] + i).dereference())144 yield ('[%d]' % i, (hdr['keys'] + i).dereference())
76 yield ('[%d]' % i, (hdr['values'] + i).dereference())145 if is_map:
146 yield ('[%d]' % i, (hdr['values'] + i).dereference())
77147
78 def display_hint(self):148 def display_hint(self):
79 return 'map'149 for field in self.header_ptr_type().target().fields():
150 if field.name == 'values':
151 return 'map'
152 return 'array'
153
154# Handles both ArrayHashMap and ArrayHashMapUnmanaged.
155class ArrayHashMapPrinter:
156 def __init__(self, val):
157 self.type = val.type
158 is_managed = re.search(r'^std\.array_hash_map\.ArrayHashMap\(', self.type.name)
159 self.val = val['unmanaged'] if is_managed else val
160
161 def to_string(self):
162 type = self.type.name[len('std.array_hash_map.'):]
163 type = re.sub(r'^ArrayHashMap(Unmanaged)?\((.*),std.array_hash_map.AutoContext\(.*$', r'AutoArrayHashMap\1(\2)', type)
164 return '%s of length %s' % (type, self.val['entries']['len'])
165
166 def children(self):
167 entries = MultiArrayListPrinter(self.val['entries'])
168 len = self.val['entries']['len']
169 fields = {}
170 for name, ptr in entries.slice():
171 fields[str(name)] = ptr
172
173 for i in range(len):
174 if 'key' in fields:
175 yield ('[%d]' % i, fields['key'][i])
176 else:
177 yield ('[%d]' % i, '{}')
178 if 'value' in fields:
179 yield ('[%d]' % i, fields['value'][i])
180
181 def display_hint(self):
182 for name, ptr in MultiArrayListPrinter(self.val['entries']).slice():
183 if name == 'value':
184 return 'map'
185 return 'array'
186
187pp1 = gdb.printing.RegexpCollectionPrettyPrinter('Zig stage1 compiler')
188pp1.add_printer('Buf', '^Buf$', BufPrinter)
189pp1.add_printer('ZigList<char>', '^ZigList<char>$', BufPrinter)
190pp1.add_printer('ZigList', '^ZigList<.*>$', ZigListPrinter)
191gdb.printing.register_pretty_printer(gdb.current_objfile(), pp1)
80192
81pp = gdb.printing.RegexpCollectionPrettyPrinter('Zig stage1 compiler')193pplang = gdb.printing.RegexpCollectionPrettyPrinter('Zig language')
82pp.add_printer('Buf', '^Buf$', BufPrinter)194pplang.add_printer('Slice', '^\[\]u8', SliceStringPrinter)
83pp.add_printer('ZigList<char>', '^ZigList<char>$', BufPrinter)195pplang.add_printer('Slice', '^\[\]', SlicePrinter)
84pp.add_printer('ZigList', '^ZigList<.*>$', ZigListPrinter)
85gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
86196
87ppstd = gdb.printing.RegexpCollectionPrettyPrinter('Zig standard library')197ppstd = gdb.printing.RegexpCollectionPrettyPrinter('Zig standard library')
88ppstd.add_printer('ArrayList', r'^std\.array_list\.ArrayListAligned(Unmanaged)?\(.*\)$', ArrayListPrinter)198ppstd.add_printer('ArrayList', r'^std\.array_list\.ArrayListAligned(Unmanaged)?\(.*\)$', ArrayListPrinter)
199ppstd.add_printer('MultiArrayList', r'^std\.multi_array_list\.MultiArrayList\(.*\)$', MultiArrayListPrinter)
89ppstd.add_printer('HashMap', r'^std\.hash_map\.HashMap(Unmanaged)?\(.*\)$', HashMapPrinter)200ppstd.add_printer('HashMap', r'^std\.hash_map\.HashMap(Unmanaged)?\(.*\)$', HashMapPrinter)
201ppstd.add_printer('ArrayHashMap', r'^std\.array_hash_map\.ArrayHashMap(Unmanaged)?\(.*\)$', ArrayHashMapPrinter)
90gdb.printing.register_pretty_printer(gdb.current_objfile(), ppstd)202gdb.printing.register_pretty_printer(gdb.current_objfile(), ppstd)