| author | |
| committer | |
| log | 4ff7553d6b918e4eef643d10bd8f41492355f39c |
| tree | bfc47888a58259ea17fd1f0306c64875f563bbbe |
| parent | 0bd84e03b98a75806c47cb7f514a15de7e4d2b6e |
5 files changed, 370 insertions(+), 391 deletions(-)
tools/stage1_gdb_pretty_printers.py created+37| ... | @@ -0,0 +1,37 @@ | ||
| 1 | # pretty printing for stage1. | ||
| 2 | # put "source /path/to/stage1_gdb_pretty_printers.py" in ~/.gdbinit to load it automatically. | ||
| 3 | import gdb.printing | ||
| 4 | |||
| 5 | class ZigListPrinter: | ||
| 6 | def __init__(self, val): | ||
| 7 | self.val = val | ||
| 8 | |||
| 9 | def to_string(self): | ||
| 10 | return '%s of length %d, capacity %d' % (self.val.type.name, int(self.val['length']), int(self.val['capacity'])) | ||
| 11 | |||
| 12 | def children(self): | ||
| 13 | def it(ziglist): | ||
| 14 | for i in range(int(ziglist.val['length'])): | ||
| 15 | item = ziglist.val['items'] + i | ||
| 16 | yield ('[%d]' % i, item.dereference()) | ||
| 17 | return it(self) | ||
| 18 | |||
| 19 | def display_hint(self): | ||
| 20 | return 'array' | ||
| 21 | |||
| 22 | # handle both Buf and ZigList<char> because Buf* doesn't work otherwise (gdb bug?) | ||
| 23 | class BufPrinter: | ||
| 24 | def __init__(self, val): | ||
| 25 | self.val = val['list'] if val.type.name == 'Buf' else val | ||
| 26 | |||
| 27 | def to_string(self): | ||
| 28 | return self.val['items'].string(length=int(self.val['length'])) | ||
| 29 | |||
| 30 | def display_hint(self): | ||
| 31 | return 'string' | ||
| 32 | |||
| 33 | pp = gdb.printing.RegexpCollectionPrettyPrinter('Zig stage1 compiler') | ||
| 34 | pp.add_printer('Buf', '^Buf$', BufPrinter) | ||
| 35 | pp.add_printer('ZigList<char>', '^ZigList<char>$', BufPrinter) | ||
| 36 | pp.add_printer('ZigList', '^ZigList<.*>$', ZigListPrinter) | ||
| 37 | gdb.printing.register_pretty_printer(gdb.current_objfile(), pp) | ||
tools/stage2_gdb_pretty_printers.py created+189| ... | @@ -0,0 +1,189 @@ | ||
| 1 | # pretty printing for stage 2. | ||
| 2 | # put "source /path/to/stage2_gdb_pretty_printers.py" in ~/.gdbinit to load it automatically. | ||
| 3 | import re | ||
| 4 | import gdb.printing | ||
| 5 | |||
| 6 | class TypePrinter: | ||
| 7 | no_payload_count = 4096 | ||
| 8 | |||
| 9 | # Keep in sync with src/type.zig | ||
| 10 | # Types which have no payload do not need to be entered here. | ||
| 11 | payload_type_names = { | ||
| 12 | 'array_u8': 'type.Len', | ||
| 13 | 'array_u8_sentinel_0': 'Len', | ||
| 14 | |||
| 15 | 'single_const_pointer': 'ElemType', | ||
| 16 | 'single_mut_pointer': 'ElemType', | ||
| 17 | 'many_const_pointer': 'ElemType', | ||
| 18 | 'many_mut_pointer': 'ElemType', | ||
| 19 | 'c_const_pointer': 'ElemType', | ||
| 20 | 'c_mut_pointer': 'ElemType', | ||
| 21 | 'const_slice': 'ElemType', | ||
| 22 | 'mut_slice': 'ElemType', | ||
| 23 | 'optional': 'ElemType', | ||
| 24 | 'optional_single_mut_pointer': 'ElemType', | ||
| 25 | 'optional_single_const_pointer': 'ElemType', | ||
| 26 | 'anyframe_T': 'ElemType', | ||
| 27 | |||
| 28 | 'int_signed': 'Bits', | ||
| 29 | 'int_unsigned': 'Bits', | ||
| 30 | |||
| 31 | 'error_set': 'ErrorSet', | ||
| 32 | 'error_set_inferred': 'ErrorSetInferred', | ||
| 33 | 'error_set_merged': 'ErrorSetMerged', | ||
| 34 | |||
| 35 | 'array': 'Array', | ||
| 36 | 'vector': 'Array', | ||
| 37 | |||
| 38 | 'array_sentinel': 'ArraySentinel', | ||
| 39 | 'pointer': 'Pointer', | ||
| 40 | 'function': 'Function', | ||
| 41 | 'error_union': 'ErrorUnion', | ||
| 42 | 'error_set_single': 'Name', | ||
| 43 | 'opaque': 'Opaque', | ||
| 44 | 'struct': 'Struct', | ||
| 45 | 'union': 'Union', | ||
| 46 | 'union_tagged': 'Union', | ||
| 47 | 'enum_full, .enum_nonexhaustive': 'EnumFull', | ||
| 48 | 'enum_simple': 'EnumSimple', | ||
| 49 | 'enum_numbered': 'EnumNumbered', | ||
| 50 | 'empty_struct': 'ContainerScope', | ||
| 51 | 'tuple': 'Tuple', | ||
| 52 | 'anon_struct': 'AnonStruct', | ||
| 53 | } | ||
| 54 | |||
| 55 | def __init__(self, val): | ||
| 56 | self.val = val | ||
| 57 | |||
| 58 | def tag(self): | ||
| 59 | tag_if_small_enough = self.val['tag_if_small_enough'] | ||
| 60 | tag_type = tag_if_small_enough.type | ||
| 61 | |||
| 62 | if tag_if_small_enough < TypePrinter.no_payload_count: | ||
| 63 | return tag_if_small_enough | ||
| 64 | else: | ||
| 65 | return self.val['ptr_otherwise'].dereference()['tag'] | ||
| 66 | |||
| 67 | def payload_type(self): | ||
| 68 | tag = self.tag() | ||
| 69 | if tag is None: | ||
| 70 | return None | ||
| 71 | |||
| 72 | type_name = TypePrinter.payload_type_names.get(str(tag)) | ||
| 73 | if type_name is None: | ||
| 74 | return None | ||
| 75 | return gdb.lookup_type('struct type.%s' % type_name) | ||
| 76 | |||
| 77 | def to_string(self): | ||
| 78 | tag = self.tag() | ||
| 79 | if tag is None: | ||
| 80 | return '(invalid type)' | ||
| 81 | if self.val['tag_if_small_enough'] < TypePrinter.no_payload_count: | ||
| 82 | return '.%s' % str(tag) | ||
| 83 | return None | ||
| 84 | |||
| 85 | def children(self): | ||
| 86 | if self.val['tag_if_small_enough'] < TypePrinter.no_payload_count: | ||
| 87 | return | ||
| 88 | |||
| 89 | yield ('tag', '.%s' % str(self.tag())) | ||
| 90 | |||
| 91 | payload_type = self.payload_type() | ||
| 92 | if payload_type is not None: | ||
| 93 | yield ('payload', self.val['ptr_otherwise'].cast(payload_type.pointer()).dereference()['data']) | ||
| 94 | |||
| 95 | class ValuePrinter: | ||
| 96 | no_payload_count = 4096 | ||
| 97 | |||
| 98 | # Keep in sync with src/value.zig | ||
| 99 | # Values which have no payload do not need to be entered here. | ||
| 100 | payload_type_names = { | ||
| 101 | 'big_int_positive': 'BigInt', | ||
| 102 | 'big_int_negative': 'BigInt', | ||
| 103 | |||
| 104 | 'extern_fn': 'ExternFn', | ||
| 105 | |||
| 106 | 'decl_ref': 'Decl', | ||
| 107 | |||
| 108 | 'repeated': 'SubValue', | ||
| 109 | 'eu_payload': 'SubValue', | ||
| 110 | 'opt_payload': 'SubValue', | ||
| 111 | 'empty_array_sentinel': 'SubValue', | ||
| 112 | |||
| 113 | 'eu_payload_ptr': 'PayloadPtr', | ||
| 114 | 'opt_payload_ptr': 'PayloadPtr', | ||
| 115 | |||
| 116 | 'bytes': 'Bytes', | ||
| 117 | 'enum_literal': 'Bytes', | ||
| 118 | |||
| 119 | 'slice': 'Slice', | ||
| 120 | |||
| 121 | 'enum_field_index': 'U32', | ||
| 122 | |||
| 123 | 'ty': 'Ty', | ||
| 124 | 'int_type': 'IntType', | ||
| 125 | 'int_u64': 'U64', | ||
| 126 | 'int_i64': 'I64', | ||
| 127 | 'function': 'Function', | ||
| 128 | 'variable': 'Variable', | ||
| 129 | 'decl_ref_mut': 'DeclRefMut', | ||
| 130 | 'elem_ptr': 'ElemPtr', | ||
| 131 | 'field_ptr': 'FieldPtr', | ||
| 132 | 'float_16': 'Float_16', | ||
| 133 | 'float_32': 'Float_32', | ||
| 134 | 'float_64': 'Float_64', | ||
| 135 | 'float_80': 'Float_80', | ||
| 136 | 'float_128': 'Float_128', | ||
| 137 | 'error': 'Error', | ||
| 138 | 'inferred_alloc': 'InferredAlloc', | ||
| 139 | 'inferred_alloc_comptime': 'InferredAllocComptime', | ||
| 140 | 'aggregate': 'Aggregate', | ||
| 141 | 'union': 'Union', | ||
| 142 | 'bound_fn': 'BoundFn', | ||
| 143 | } | ||
| 144 | |||
| 145 | def __init__(self, val): | ||
| 146 | self.val = val | ||
| 147 | |||
| 148 | def tag(self): | ||
| 149 | tag_if_small_enough = self.val['tag_if_small_enough'] | ||
| 150 | tag_type = tag_if_small_enough.type | ||
| 151 | |||
| 152 | if tag_if_small_enough < ValuePrinter.no_payload_count: | ||
| 153 | return tag_if_small_enough | ||
| 154 | else: | ||
| 155 | return self.val['ptr_otherwise'].dereference()['tag'] | ||
| 156 | |||
| 157 | def payload_type(self): | ||
| 158 | tag = self.tag() | ||
| 159 | if tag is None: | ||
| 160 | return None | ||
| 161 | |||
| 162 | type_name = ValuePrinter.payload_type_names.get(str(tag)) | ||
| 163 | if type_name is None: | ||
| 164 | return None | ||
| 165 | return gdb.lookup_type('struct value.%s' % type_name) | ||
| 166 | |||
| 167 | def to_string(self): | ||
| 168 | tag = self.tag() | ||
| 169 | if tag is None: | ||
| 170 | return '(invalid value)' | ||
| 171 | if self.val['tag_if_small_enough'] < ValuePrinter.no_payload_count: | ||
| 172 | return '.%s' % str(tag) | ||
| 173 | return None | ||
| 174 | |||
| 175 | def children(self): | ||
| 176 | if self.val['tag_if_small_enough'] < ValuePrinter.no_payload_count: | ||
| 177 | return | ||
| 178 | |||
| 179 | yield ('tag', '.%s' % str(self.tag())) | ||
| 180 | |||
| 181 | payload_type = self.payload_type() | ||
| 182 | if payload_type is not None: | ||
| 183 | yield ('payload', self.val['ptr_otherwise'].cast(payload_type.pointer()).dereference()['data']) | ||
| 184 | |||
| 185 | pp = gdb.printing.RegexpCollectionPrettyPrinter('Zig stage2 compiler') | ||
| 186 | pp.add_printer('Type', r'^type\.Type$', TypePrinter) | ||
| 187 | pp.add_printer('Value', r'^value\.Value$', ValuePrinter) | ||
| 188 | gdb.printing.register_pretty_printer(gdb.current_objfile(), pp) | ||
| 189 | |||
tools/std_gdb_pretty_printers.py created+142| ... | @@ -0,0 +1,142 @@ | ||
| 1 | # pretty printing for the standard library. | ||
| 2 | # put "source /path/to/stage2_gdb_pretty_printers.py" in ~/.gdbinit to load it automatically. | ||
| 3 | import re | ||
| 4 | import gdb.printing | ||
| 5 | |||
| 6 | # Handles both ArrayList and ArrayListUnmanaged. | ||
| 7 | class 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 | |||
| 24 | class MultiArrayListPrinter: | ||
| 25 | def __init__(self, val): | ||
| 26 | self.val = val | ||
| 27 | |||
| 28 | def child_type(self): | ||
| 29 | (helper_fn, _) = gdb.lookup_symbol('%s.gdbHelper' % 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. | ||
| 61 | class 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.gdbHelper' % 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. | ||
| 105 | class 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 | |||
| 137 | pp = gdb.printing.RegexpCollectionPrettyPrinter('Zig standard library') | ||
| 138 | pp.add_printer('ArrayList', r'^std\.array_list\.ArrayListAligned(Unmanaged)?\(.*\)$', ArrayListPrinter) | ||
| 139 | pp.add_printer('MultiArrayList', r'^std\.multi_array_list\.MultiArrayList\(.*\)$', MultiArrayListPrinter) | ||
| 140 | pp.add_printer('HashMap', r'^std\.hash_map\.HashMap(Unmanaged)?\(.*\)$', HashMapPrinter) | ||
| 141 | pp.add_printer('ArrayHashMap', r'^std\.array_hash_map\.ArrayHashMap(Unmanaged)?\(.*\)$', ArrayHashMapPrinter) | ||
| 142 | gdb.printing.register_pretty_printer(gdb.current_objfile(), pp) | ||
tools/zig-gdb.py deleted-389| ... | @@ -1,389 +0,0 @@ | ||
| 1 | # pretty printing for stage1, stage2 and the standard library | ||
| 2 | # put "source /path/to/zig-gdb.py" in ~/.gdbinit to load it automatically | ||
| 3 | |||
| 4 | import re | ||
| 5 | import gdb.printing | ||
| 6 | import gdb.types | ||
| 7 | |||
| 8 | class ZigListPrinter: | ||
| 9 | def __init__(self, val): | ||
| 10 | self.val = val | ||
| 11 | |||
| 12 | def to_string(self): | ||
| 13 | return '%s of length %d, capacity %d' % (self.val.type.name, int(self.val['length']), int(self.val['capacity'])) | ||
| 14 | |||
| 15 | def children(self): | ||
| 16 | def it(ziglist): | ||
| 17 | for i in range(int(ziglist.val['length'])): | ||
| 18 | item = ziglist.val['items'] + i | ||
| 19 | yield ('[%d]' % i, item.dereference()) | ||
| 20 | return it(self) | ||
| 21 | |||
| 22 | def display_hint(self): | ||
| 23 | return 'array' | ||
| 24 | |||
| 25 | # handle both Buf and ZigList<char> because Buf* doesn't work otherwise (gdb bug?) | ||
| 26 | class BufPrinter: | ||
| 27 | def __init__(self, val): | ||
| 28 | self.val = val['list'] if val.type.name == 'Buf' else val | ||
| 29 | |||
| 30 | def to_string(self): | ||
| 31 | return self.val['items'].string(length=int(self.val['length'])) | ||
| 32 | |||
| 33 | def display_hint(self): | ||
| 34 | return 'string' | ||
| 35 | |||
| 36 | class SlicePrinter: | ||
| 37 | def __init__(self, val): | ||
| 38 | self.val = val | ||
| 39 | |||
| 40 | def children(self): | ||
| 41 | for i in range(self.val['len']): | ||
| 42 | yield ('[%d]' % i, (self.val['ptr'] + i).dereference()) | ||
| 43 | |||
| 44 | def display_hint(self): | ||
| 45 | return 'array' | ||
| 46 | |||
| 47 | class SliceStringPrinter: | ||
| 48 | def __init__(self, val): | ||
| 49 | self.val = val | ||
| 50 | |||
| 51 | def to_string(self): | ||
| 52 | return self.val['ptr'].string(length=self.val['len']) | ||
| 53 | |||
| 54 | def display_hint(self): | ||
| 55 | return 'string' | ||
| 56 | |||
| 57 | # Handles both ArrayList and ArrayListUnmanaged. | ||
| 58 | class ArrayListPrinter: | ||
| 59 | def __init__(self, val): | ||
| 60 | self.val = val | ||
| 61 | |||
| 62 | def to_string(self): | ||
| 63 | type = self.val.type.name[len('std.array_list.'):] | ||
| 64 | type = re.sub(r'^ArrayListAligned(Unmanaged)?\((.*),null\)$', r'ArrayList\1(\2)', type) | ||
| 65 | return '%s of length %s, capacity %s' % (type, self.val['items']['len'], self.val['capacity']) | ||
| 66 | |||
| 67 | def children(self): | ||
| 68 | for i in range(self.val['items']['len']): | ||
| 69 | item = self.val['items']['ptr'] + i | ||
| 70 | yield ('[%d]' % i, item.dereference()) | ||
| 71 | |||
| 72 | def display_hint(self): | ||
| 73 | return 'array' | ||
| 74 | |||
| 75 | class MultiArrayListPrinter: | ||
| 76 | def __init__(self, val): | ||
| 77 | self.val = val | ||
| 78 | |||
| 79 | def child_type(self): | ||
| 80 | (helper_fn, _) = gdb.lookup_symbol('%s.gdbHelper' % self.val.type.name) | ||
| 81 | return helper_fn.type.fields()[1].type.target() | ||
| 82 | |||
| 83 | def to_string(self): | ||
| 84 | type = self.val.type.name[len('std.multi_array_list.'):] | ||
| 85 | return '%s of length %s, capacity %s' % (type, self.val['len'], self.val['capacity']) | ||
| 86 | |||
| 87 | def slice(self): | ||
| 88 | fields = self.child_type().fields() | ||
| 89 | base = self.val['bytes'] | ||
| 90 | cap = self.val['capacity'] | ||
| 91 | len = self.val['len'] | ||
| 92 | |||
| 93 | if len == 0: | ||
| 94 | return | ||
| 95 | |||
| 96 | fields = sorted(fields, key=lambda field: field.type.alignof, reverse=True) | ||
| 97 | |||
| 98 | for field in fields: | ||
| 99 | ptr = base.cast(field.type.pointer()).dereference().cast(field.type.array(len - 1)) | ||
| 100 | base += field.type.sizeof * cap | ||
| 101 | yield (field.name, ptr) | ||
| 102 | |||
| 103 | def children(self): | ||
| 104 | for i, (name, ptr) in enumerate(self.slice()): | ||
| 105 | yield ('[%d]' % i, name) | ||
| 106 | yield ('[%d]' % i, ptr) | ||
| 107 | |||
| 108 | def display_hint(self): | ||
| 109 | return 'map' | ||
| 110 | |||
| 111 | # Handles both HashMap and HashMapUnmanaged. | ||
| 112 | class HashMapPrinter: | ||
| 113 | def __init__(self, val): | ||
| 114 | self.type = val.type | ||
| 115 | is_managed = re.search(r'^std\.hash_map\.HashMap\(', self.type.name) | ||
| 116 | self.val = val['unmanaged'] if is_managed else val | ||
| 117 | |||
| 118 | def header_ptr_type(self): | ||
| 119 | (helper_fn, _) = gdb.lookup_symbol('%s.gdbHelper' % self.val.type.name) | ||
| 120 | return helper_fn.type.fields()[1].type | ||
| 121 | |||
| 122 | def header(self): | ||
| 123 | if self.val['metadata'] == 0: | ||
| 124 | return None | ||
| 125 | return (self.val['metadata'].cast(self.header_ptr_type()) - 1).dereference() | ||
| 126 | |||
| 127 | def to_string(self): | ||
| 128 | type = self.type.name[len('std.hash_map.'):] | ||
| 129 | type = re.sub(r'^HashMap(Unmanaged)?\((.*),std.hash_map.AutoContext\(.*$', r'AutoHashMap\1(\2)', type) | ||
| 130 | hdr = self.header() | ||
| 131 | if hdr is not None: | ||
| 132 | cap = hdr['capacity'] | ||
| 133 | else: | ||
| 134 | cap = 0 | ||
| 135 | return '%s of length %s, capacity %s' % (type, self.val['size'], cap) | ||
| 136 | |||
| 137 | def children(self): | ||
| 138 | hdr = self.header() | ||
| 139 | if hdr is None: | ||
| 140 | return | ||
| 141 | is_map = self.display_hint() == 'map' | ||
| 142 | for i in range(hdr['capacity']): | ||
| 143 | metadata = self.val['metadata'] + i | ||
| 144 | if metadata.dereference()['used'] == 1: | ||
| 145 | yield ('[%d]' % i, (hdr['keys'] + i).dereference()) | ||
| 146 | if is_map: | ||
| 147 | yield ('[%d]' % i, (hdr['values'] + i).dereference()) | ||
| 148 | |||
| 149 | def display_hint(self): | ||
| 150 | for field in self.header_ptr_type().target().fields(): | ||
| 151 | if field.name == 'values': | ||
| 152 | return 'map' | ||
| 153 | return 'array' | ||
| 154 | |||
| 155 | # Handles both ArrayHashMap and ArrayHashMapUnmanaged. | ||
| 156 | class ArrayHashMapPrinter: | ||
| 157 | def __init__(self, val): | ||
| 158 | self.type = val.type | ||
| 159 | is_managed = re.search(r'^std\.array_hash_map\.ArrayHashMap\(', self.type.name) | ||
| 160 | self.val = val['unmanaged'] if is_managed else val | ||
| 161 | |||
| 162 | def to_string(self): | ||
| 163 | type = self.type.name[len('std.array_hash_map.'):] | ||
| 164 | type = re.sub(r'^ArrayHashMap(Unmanaged)?\((.*),std.array_hash_map.AutoContext\(.*$', r'AutoArrayHashMap\1(\2)', type) | ||
| 165 | return '%s of length %s' % (type, self.val['entries']['len']) | ||
| 166 | |||
| 167 | def children(self): | ||
| 168 | entries = MultiArrayListPrinter(self.val['entries']) | ||
| 169 | len = self.val['entries']['len'] | ||
| 170 | fields = {} | ||
| 171 | for name, ptr in entries.slice(): | ||
| 172 | fields[str(name)] = ptr | ||
| 173 | |||
| 174 | for i in range(len): | ||
| 175 | if 'key' in fields: | ||
| 176 | yield ('[%d]' % i, fields['key'][i]) | ||
| 177 | else: | ||
| 178 | yield ('[%d]' % i, '{}') | ||
| 179 | if 'value' in fields: | ||
| 180 | yield ('[%d]' % i, fields['value'][i]) | ||
| 181 | |||
| 182 | def display_hint(self): | ||
| 183 | for name, ptr in MultiArrayListPrinter(self.val['entries']).slice(): | ||
| 184 | if name == 'value': | ||
| 185 | return 'map' | ||
| 186 | return 'array' | ||
| 187 | |||
| 188 | class TypePrinter: | ||
| 189 | no_payload_count = 4096 | ||
| 190 | |||
| 191 | # Keep in sync with src/type.zig | ||
| 192 | # Types which have no payload do not need to be entered here. | ||
| 193 | payload_type_names = { | ||
| 194 | 'array_u8': 'type.Len', | ||
| 195 | 'array_u8_sentinel_0': 'Len', | ||
| 196 | |||
| 197 | 'single_const_pointer': 'ElemType', | ||
| 198 | 'single_mut_pointer': 'ElemType', | ||
| 199 | 'many_const_pointer': 'ElemType', | ||
| 200 | 'many_mut_pointer': 'ElemType', | ||
| 201 | 'c_const_pointer': 'ElemType', | ||
| 202 | 'c_mut_pointer': 'ElemType', | ||
| 203 | 'const_slice': 'ElemType', | ||
| 204 | 'mut_slice': 'ElemType', | ||
| 205 | 'optional': 'ElemType', | ||
| 206 | 'optional_single_mut_pointer': 'ElemType', | ||
| 207 | 'optional_single_const_pointer': 'ElemType', | ||
| 208 | 'anyframe_T': 'ElemType', | ||
| 209 | |||
| 210 | 'int_signed': 'Bits', | ||
| 211 | 'int_unsigned': 'Bits', | ||
| 212 | |||
| 213 | 'error_set': 'ErrorSet', | ||
| 214 | 'error_set_inferred': 'ErrorSetInferred', | ||
| 215 | 'error_set_merged': 'ErrorSetMerged', | ||
| 216 | |||
| 217 | 'array': 'Array', | ||
| 218 | 'vector': 'Array', | ||
| 219 | |||
| 220 | 'array_sentinel': 'ArraySentinel', | ||
| 221 | 'pointer': 'Pointer', | ||
| 222 | 'function': 'Function', | ||
| 223 | 'error_union': 'ErrorUnion', | ||
| 224 | 'error_set_single': 'Name', | ||
| 225 | 'opaque': 'Opaque', | ||
| 226 | 'struct': 'Struct', | ||
| 227 | 'union': 'Union', | ||
| 228 | 'union_tagged': 'Union', | ||
| 229 | 'enum_full, .enum_nonexhaustive': 'EnumFull', | ||
| 230 | 'enum_simple': 'EnumSimple', | ||
| 231 | 'enum_numbered': 'EnumNumbered', | ||
| 232 | 'empty_struct': 'ContainerScope', | ||
| 233 | 'tuple': 'Tuple', | ||
| 234 | 'anon_struct': 'AnonStruct', | ||
| 235 | } | ||
| 236 | |||
| 237 | def __init__(self, val): | ||
| 238 | self.val = val | ||
| 239 | |||
| 240 | def tag(self): | ||
| 241 | tag_if_small_enough = self.val['tag_if_small_enough'] | ||
| 242 | tag_type = tag_if_small_enough.type | ||
| 243 | |||
| 244 | if tag_if_small_enough < TypePrinter.no_payload_count: | ||
| 245 | return tag_if_small_enough | ||
| 246 | else: | ||
| 247 | return self.val['ptr_otherwise'].dereference()['tag'] | ||
| 248 | |||
| 249 | def payload_type(self): | ||
| 250 | tag = self.tag() | ||
| 251 | if tag is None: | ||
| 252 | return None | ||
| 253 | |||
| 254 | type_name = TypePrinter.payload_type_names.get(str(tag)) | ||
| 255 | if type_name is None: | ||
| 256 | return None | ||
| 257 | return gdb.lookup_type('struct type.%s' % type_name) | ||
| 258 | |||
| 259 | def to_string(self): | ||
| 260 | tag = self.tag() | ||
| 261 | if tag is None: | ||
| 262 | return '(invalid type)' | ||
| 263 | if self.val['tag_if_small_enough'] < TypePrinter.no_payload_count: | ||
| 264 | return '.%s' % str(tag) | ||
| 265 | return None | ||
| 266 | |||
| 267 | def children(self): | ||
| 268 | if self.val['tag_if_small_enough'] < TypePrinter.no_payload_count: | ||
| 269 | return | ||
| 270 | |||
| 271 | yield ('tag', '.%s' % str(self.tag())) | ||
| 272 | |||
| 273 | payload_type = self.payload_type() | ||
| 274 | if payload_type is not None: | ||
| 275 | yield ('payload', self.val['ptr_otherwise'].cast(payload_type.pointer()).dereference()['data']) | ||
| 276 | |||
| 277 | class ValuePrinter: | ||
| 278 | no_payload_count = 4096 | ||
| 279 | |||
| 280 | # Keep in sync with src/value.zig | ||
| 281 | # Values which have no payload do not need to be entered here. | ||
| 282 | payload_type_names = { | ||
| 283 | 'big_int_positive': 'BigInt', | ||
| 284 | 'big_int_negative': 'BigInt', | ||
| 285 | |||
| 286 | 'extern_fn': 'ExternFn', | ||
| 287 | |||
| 288 | 'decl_ref': 'Decl', | ||
| 289 | |||
| 290 | 'repeated': 'SubValue', | ||
| 291 | 'eu_payload': 'SubValue', | ||
| 292 | 'opt_payload': 'SubValue', | ||
| 293 | 'empty_array_sentinel': 'SubValue', | ||
| 294 | |||
| 295 | 'eu_payload_ptr': 'PayloadPtr', | ||
| 296 | 'opt_payload_ptr': 'PayloadPtr', | ||
| 297 | |||
| 298 | 'bytes': 'Bytes', | ||
| 299 | 'enum_literal': 'Bytes', | ||
| 300 | |||
| 301 | 'slice': 'Slice', | ||
| 302 | |||
| 303 | 'enum_field_index': 'U32', | ||
| 304 | |||
| 305 | 'ty': 'Ty', | ||
| 306 | 'int_type': 'IntType', | ||
| 307 | 'int_u64': 'U64', | ||
| 308 | 'int_i64': 'I64', | ||
| 309 | 'function': 'Function', | ||
| 310 | 'variable': 'Variable', | ||
| 311 | 'decl_ref_mut': 'DeclRefMut', | ||
| 312 | 'elem_ptr': 'ElemPtr', | ||
| 313 | 'field_ptr': 'FieldPtr', | ||
| 314 | 'float_16': 'Float_16', | ||
| 315 | 'float_32': 'Float_32', | ||
| 316 | 'float_64': 'Float_64', | ||
| 317 | 'float_80': 'Float_80', | ||
| 318 | 'float_128': 'Float_128', | ||
| 319 | 'error': 'Error', | ||
| 320 | 'inferred_alloc': 'InferredAlloc', | ||
| 321 | 'inferred_alloc_comptime': 'InferredAllocComptime', | ||
| 322 | 'aggregate': 'Aggregate', | ||
| 323 | 'union': 'Union', | ||
| 324 | 'bound_fn': 'BoundFn', | ||
| 325 | } | ||
| 326 | |||
| 327 | def __init__(self, val): | ||
| 328 | self.val = val | ||
| 329 | |||
| 330 | def tag(self): | ||
| 331 | tag_if_small_enough = self.val['tag_if_small_enough'] | ||
| 332 | tag_type = tag_if_small_enough.type | ||
| 333 | |||
| 334 | if tag_if_small_enough < ValuePrinter.no_payload_count: | ||
| 335 | return tag_if_small_enough | ||
| 336 | else: | ||
| 337 | return self.val['ptr_otherwise'].dereference()['tag'] | ||
| 338 | |||
| 339 | def payload_type(self): | ||
| 340 | tag = self.tag() | ||
| 341 | if tag is None: | ||
| 342 | return None | ||
| 343 | |||
| 344 | type_name = ValuePrinter.payload_type_names.get(str(tag)) | ||
| 345 | if type_name is None: | ||
| 346 | return None | ||
| 347 | return gdb.lookup_type('struct value.%s' % type_name) | ||
| 348 | |||
| 349 | def to_string(self): | ||
| 350 | tag = self.tag() | ||
| 351 | if tag is None: | ||
| 352 | return '(invalid value)' | ||
| 353 | if self.val['tag_if_small_enough'] < ValuePrinter.no_payload_count: | ||
| 354 | return '.%s' % str(tag) | ||
| 355 | return None | ||
| 356 | |||
| 357 | def children(self): | ||
| 358 | if self.val['tag_if_small_enough'] < ValuePrinter.no_payload_count: | ||
| 359 | return | ||
| 360 | |||
| 361 | yield ('tag', '.%s' % str(self.tag())) | ||
| 362 | |||
| 363 | payload_type = self.payload_type() | ||
| 364 | if payload_type is not None: | ||
| 365 | yield ('payload', self.val['ptr_otherwise'].cast(payload_type.pointer()).dereference()['data']) | ||
| 366 | |||
| 367 | pp1 = gdb.printing.RegexpCollectionPrettyPrinter('Zig stage1 compiler') | ||
| 368 | pp1.add_printer('Buf', '^Buf$', BufPrinter) | ||
| 369 | pp1.add_printer('ZigList<char>', '^ZigList<char>$', BufPrinter) | ||
| 370 | pp1.add_printer('ZigList', '^ZigList<.*>$', ZigListPrinter) | ||
| 371 | gdb.printing.register_pretty_printer(gdb.current_objfile(), pp1) | ||
| 372 | |||
| 373 | pplang = gdb.printing.RegexpCollectionPrettyPrinter('Zig language') | ||
| 374 | pplang.add_printer('Slice', '^\[\]u8', SliceStringPrinter) | ||
| 375 | pplang.add_printer('Slice', '^\[\]', SlicePrinter) | ||
| 376 | gdb.printing.register_pretty_printer(gdb.current_objfile(), pplang) | ||
| 377 | |||
| 378 | ppstd = gdb.printing.RegexpCollectionPrettyPrinter('Zig standard library') | ||
| 379 | ppstd.add_printer('ArrayList', r'^std\.array_list\.ArrayListAligned(Unmanaged)?\(.*\)$', ArrayListPrinter) | ||
| 380 | ppstd.add_printer('MultiArrayList', r'^std\.multi_array_list\.MultiArrayList\(.*\)$', MultiArrayListPrinter) | ||
| 381 | ppstd.add_printer('HashMap', r'^std\.hash_map\.HashMap(Unmanaged)?\(.*\)$', HashMapPrinter) | ||
| 382 | ppstd.add_printer('ArrayHashMap', r'^std\.array_hash_map\.ArrayHashMap(Unmanaged)?\(.*\)$', ArrayHashMapPrinter) | ||
| 383 | gdb.printing.register_pretty_printer(gdb.current_objfile(), ppstd) | ||
| 384 | |||
| 385 | pp2 = gdb.printing.RegexpCollectionPrettyPrinter('Zig stage2 compiler') | ||
| 386 | pp2.add_printer('Type', r'^type\.Type$', TypePrinter) | ||
| 387 | pp2.add_printer('Value', r'^value\.Value$', ValuePrinter) | ||
| 388 | gdb.printing.register_pretty_printer(gdb.current_objfile(), pp2) | ||
| 389 | |||
tools/zig_gdb_pretty_printers.py+2-2| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | # gdb pretty printers for Zig language constructs | 1 | # pretty printing for the language. |
| 2 | 2 | # put "source /path/to/zig_gdb_pretty_printers.py" in ~/.gdbinit to load it automatically. | |
| 3 | import gdb.printing | 3 | import gdb.printing |
| 4 | 4 | ||
| 5 | class ZigPrettyPrinter(gdb.printing.PrettyPrinter): | 5 | class ZigPrettyPrinter(gdb.printing.PrettyPrinter): |