master
  1# pretty printing for stage 2.
  2# put "source /path/to/stage2_gdb_pretty_printers.py" in ~/.gdbinit to load it automatically.
  3import re
  4import gdb.printing
  5
  6class 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.Payload.Len',
 13        'array_u8_sentinel_0': 'Type.Payload.Len',
 14
 15        'single_const_pointer': 'Type.Payload.ElemType',
 16        'single_mut_pointer': 'Type.Payload.ElemType',
 17        'many_const_pointer': 'Type.Payload.ElemType',
 18        'many_mut_pointer': 'Type.Payload.ElemType',
 19        'c_const_pointer': 'Type.Payload.ElemType',
 20        'c_mut_pointer': 'Type.Payload.ElemType',
 21        'slice_const': 'Type.Payload.ElemType',
 22        'mut_slice': 'Type.Payload.ElemType',
 23        'optional': 'Type.Payload.ElemType',
 24        'optional_single_mut_pointer': 'Type.Payload.ElemType',
 25        'optional_single_const_pointer': 'Type.Payload.ElemType',
 26        'anyframe_T': 'Type.Payload.ElemType',
 27
 28        'int_signed': 'Type.Payload.Bits',
 29        'int_unsigned': 'Type.Payload.Bits',
 30
 31        'error_set': 'Type.Payload.ErrorSet',
 32        'error_set_inferred': 'Type.Payload.ErrorSetInferred',
 33        'error_set_merged': 'Type.Payload.ErrorSetMerged',
 34
 35        'array': 'Type.Payload.Array',
 36        'vector': 'Type.Payload.Array',
 37
 38        'array_sentinel': 'Type.Payload.ArraySentinel',
 39        'pointer': 'Type.Payload.Pointer',
 40        'function': 'Type.Payload.Function',
 41        'error_union': 'Type.Payload.ErrorUnion',
 42        'error_set_single': 'Type.Payload.Name',
 43        'opaque': 'Type.Payload.Opaque',
 44        'struct': 'Type.Payload.Struct',
 45        'union': 'Type.Payload.Union',
 46        'union_tagged': 'Type.Payload.Union',
 47        'enum_full, .enum_nonexhaustive': 'Type.Payload.EnumFull',
 48        'enum_simple': 'Type.Payload.EnumSimple',
 49        'enum_numbered': 'Type.Payload.EnumNumbered',
 50        'empty_struct': 'Type.Payload.ContainerScope',
 51        'tuple': 'Type.Payload.Tuple',
 52        'anon_struct': 'Type.Payload.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
 95class 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': 'Value.Payload.BigInt',
102        'big_int_negative': 'Value.Payload.BigInt',
103
104        'extern_fn': 'Value.Payload.ExternFn',
105
106        'decl_ref': 'Value.Payload.Decl',
107
108        'repeated': 'Value.Payload.SubValue',
109        'eu_payload': 'Value.Payload.SubValue',
110        'opt_payload': 'Value.Payload.SubValue',
111        'empty_array_sentinel': 'Value.Payload.SubValue',
112
113        'eu_payload_ptr': 'Value.Payload.PayloadPtr',
114        'opt_payload_ptr': 'Value.Payload.PayloadPtr',
115
116        'bytes': 'Value.Payload.Bytes',
117        'enum_literal': 'Value.Payload.Bytes',
118
119        'slice': 'Value.Payload.Slice',
120
121        'enum_field_index': 'Value.Payload.U32',
122
123        'ty': 'Value.Payload.Ty',
124        'int_type': 'Value.Payload.IntType',
125        'int_u64': 'Value.Payload.U64',
126        'int_i64': 'Value.Payload.I64',
127        'function': 'Value.Payload.Function',
128        'variable': 'Value.Payload.Variable',
129        'decl_ref_mut': 'Value.Payload.DeclRefMut',
130        'elem_ptr': 'Value.Payload.ElemPtr',
131        'field_ptr': 'Value.Payload.FieldPtr',
132        'float_16': 'Value.Payload.Float_16',
133        'float_32': 'Value.Payload.Float_32',
134        'float_64': 'Value.Payload.Float_64',
135        'float_80': 'Value.Payload.Float_80',
136        'float_128': 'Value.Payload.Float_128',
137        'error': 'Value.Payload.Error',
138        'inferred_alloc': 'Value.Payload.InferredAlloc',
139        'inferred_alloc_comptime': 'Value.Payload.InferredAllocComptime',
140        'aggregate': 'Value.Payload.Aggregate',
141        'union': 'Value.Payload.Union',
142        'bound_fn': 'Value.Payload.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
185pp = gdb.printing.RegexpCollectionPrettyPrinter('Zig stage2 compiler')
186pp.add_printer('Type', r'^type\.Type$', TypePrinter)
187pp.add_printer('Value', r'^value\.Value$', ValuePrinter)
188gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
189