Commit 1e963053d0

Jacob Young <jacobly0@users.noreply.github.com>
2022-10-17 05:33:13
tools: add lldb stage2 pretty printers
* Fix untagged struct names in debug info for llvm. * Factor out common stage2 pretty printer data. * Add lldb version of stage2 pretty printers.
1 parent c010767
src/codegen/llvm.zig
@@ -2153,7 +2153,7 @@ pub const Object = struct {
                     ));
                 }
 
-                const union_name = if (layout.tag_size == 0) "AnonUnion" else name.ptr;
+                const union_name = if (layout.tag_size == 0) name.ptr else "AnonUnion";
 
                 const union_di_ty = dib.createUnionType(
                     compile_unit_scope,
src/type.zig
@@ -6062,7 +6062,7 @@ pub const Type = extern union {
         pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
 
         pub fn Type(comptime t: Tag) type {
-            // Keep in sync with tools/zig-gdb.py
+            // Keep in sync with tools/stage2_pretty_printers_common.py
             return switch (t) {
                 .u1,
                 .u8,
src/value.zig
@@ -22,7 +22,7 @@ pub const Value = extern union {
     tag_if_small_enough: Tag,
     ptr_otherwise: *Payload,
 
-    // Keep in sync with tools/zig-gdb.py
+    // Keep in sync with tools/stage2_pretty_printers_common.py
     pub const Tag = enum(usize) {
         // The first section of this enum are tags that require no payload.
         u1_type,
tools/stage2_gdb_pretty_printers.py
@@ -2,56 +2,9 @@
 # put "source /path/to/stage2_gdb_pretty_printers.py" in ~/.gdbinit to load it automatically.
 import re
 import gdb.printing
+import stage2_pretty_printers_common as common
 
 class TypePrinter:
-    no_payload_count = 4096
-
-    # Keep in sync with src/type.zig
-    # Types which have no payload do not need to be entered here.
-    payload_type_names = {
-        'array_u8': 'Type.Payload.Len',
-        'array_u8_sentinel_0': 'Type.Payload.Len',
-
-        'single_const_pointer': 'Type.Payload.ElemType',
-        'single_mut_pointer': 'Type.Payload.ElemType',
-        'many_const_pointer': 'Type.Payload.ElemType',
-        'many_mut_pointer': 'Type.Payload.ElemType',
-        'c_const_pointer': 'Type.Payload.ElemType',
-        'c_mut_pointer': 'Type.Payload.ElemType',
-        'const_slice': 'Type.Payload.ElemType',
-        'mut_slice': 'Type.Payload.ElemType',
-        'optional': 'Type.Payload.ElemType',
-        'optional_single_mut_pointer': 'Type.Payload.ElemType',
-        'optional_single_const_pointer': 'Type.Payload.ElemType',
-        'anyframe_T': 'Type.Payload.ElemType',
-
-        'int_signed': 'Type.Payload.Bits',
-        'int_unsigned': 'Type.Payload.Bits',
-
-        'error_set': 'Type.Payload.ErrorSet',
-        'error_set_inferred': 'Type.Payload.ErrorSetInferred',
-        'error_set_merged': 'Type.Payload.ErrorSetMerged',
-
-        'array': 'Type.Payload.Array',
-        'vector': 'Type.Payload.Array',
-
-        'array_sentinel': 'Type.Payload.ArraySentinel',
-        'pointer': 'Type.Payload.Pointer',
-        'function': 'Type.Payload.Function',
-        'error_union': 'Type.Payload.ErrorUnion',
-        'error_set_single': 'Type.Payload.Name',
-        'opaque': 'Type.Payload.Opaque',
-        'struct': 'Type.Payload.Struct',
-        'union': 'Type.Payload.Union',
-        'union_tagged': 'Type.Payload.Union',
-        'enum_full, .enum_nonexhaustive': 'Type.Payload.EnumFull',
-        'enum_simple': 'Type.Payload.EnumSimple',
-        'enum_numbered': 'Type.Payload.EnumNumbered',
-        'empty_struct': 'Type.Payload.ContainerScope',
-        'tuple': 'Type.Payload.Tuple',
-        'anon_struct': 'Type.Payload.AnonStruct',
-    }
-
     def __init__(self, val):
         self.val = val
 
@@ -59,7 +12,7 @@ class TypePrinter:
         tag_if_small_enough = self.val['tag_if_small_enough']
         tag_type = tag_if_small_enough.type
 
-        if tag_if_small_enough < TypePrinter.no_payload_count:
+        if tag_if_small_enough < common.Type.no_payload_count:
             return tag_if_small_enough
         else:
             return self.val['ptr_otherwise'].dereference()['tag']
@@ -69,7 +22,7 @@ class TypePrinter:
         if tag is None:
             return None
 
-        type_name = TypePrinter.payload_type_names.get(str(tag))
+        type_name = common.Type.payload_type_names.get(str(tag))
         if type_name is None:
             return None
         return gdb.lookup_type('struct type.%s' % type_name)
@@ -78,12 +31,12 @@ class TypePrinter:
         tag = self.tag()
         if tag is None:
             return '(invalid type)'
-        if self.val['tag_if_small_enough'] < TypePrinter.no_payload_count:
+        if self.val['tag_if_small_enough'] < common.Type.no_payload_count:
             return '.%s' % str(tag)
         return None
 
     def children(self):
-        if self.val['tag_if_small_enough'] < TypePrinter.no_payload_count:
+        if self.val['tag_if_small_enough'] < common.Type.no_payload_count:
             return
 
         yield ('tag', '.%s' % str(self.tag()))
@@ -93,55 +46,6 @@ class TypePrinter:
             yield ('payload', self.val['ptr_otherwise'].cast(payload_type.pointer()).dereference()['data'])
 
 class ValuePrinter:
-    no_payload_count = 4096
-
-    # Keep in sync with src/value.zig
-    # Values which have no payload do not need to be entered here.
-    payload_type_names = {
-        'big_int_positive': 'Value.Payload.BigInt',
-        'big_int_negative': 'Value.Payload.BigInt',
-
-        'extern_fn': 'Value.Payload.ExternFn',
-
-        'decl_ref': 'Value.Payload.Decl',
-
-        'repeated': 'Value.Payload.SubValue',
-        'eu_payload': 'Value.Payload.SubValue',
-        'opt_payload': 'Value.Payload.SubValue',
-        'empty_array_sentinel': 'Value.Payload.SubValue',
-
-        'eu_payload_ptr': 'Value.Payload.PayloadPtr',
-        'opt_payload_ptr': 'Value.Payload.PayloadPtr',
-
-        'bytes': 'Value.Payload.Bytes',
-        'enum_literal': 'Value.Payload.Bytes',
-
-        'slice': 'Value.Payload.Slice',
-
-        'enum_field_index': 'Value.Payload.U32',
-
-        'ty': 'Value.Payload.Ty',
-        'int_type': 'Value.Payload.IntType',
-        'int_u64': 'Value.Payload.U64',
-        'int_i64': 'Value.Payload.I64',
-        'function': 'Value.Payload.Function',
-        'variable': 'Value.Payload.Variable',
-        'decl_ref_mut': 'Value.Payload.DeclRefMut',
-        'elem_ptr': 'Value.Payload.ElemPtr',
-        'field_ptr': 'Value.Payload.FieldPtr',
-        'float_16': 'Value.Payload.Float_16',
-        'float_32': 'Value.Payload.Float_32',
-        'float_64': 'Value.Payload.Float_64',
-        'float_80': 'Value.Payload.Float_80',
-        'float_128': 'Value.Payload.Float_128',
-        'error': 'Value.Payload.Error',
-        'inferred_alloc': 'Value.Payload.InferredAlloc',
-        'inferred_alloc_comptime': 'Value.Payload.InferredAllocComptime',
-        'aggregate': 'Value.Payload.Aggregate',
-        'union': 'Value.Payload.Union',
-        'bound_fn': 'Value.Payload.BoundFn',
-    }
-
     def __init__(self, val):
         self.val = val
 
@@ -149,7 +53,7 @@ class ValuePrinter:
         tag_if_small_enough = self.val['tag_if_small_enough']
         tag_type = tag_if_small_enough.type
 
-        if tag_if_small_enough < ValuePrinter.no_payload_count:
+        if tag_if_small_enough < common.Value.no_payload_count:
             return tag_if_small_enough
         else:
             return self.val['ptr_otherwise'].dereference()['tag']
@@ -159,7 +63,7 @@ class ValuePrinter:
         if tag is None:
             return None
 
-        type_name = ValuePrinter.payload_type_names.get(str(tag))
+        type_name = Comman.Value.payload_type_names.get(str(tag))
         if type_name is None:
             return None
         return gdb.lookup_type('struct value.%s' % type_name)
@@ -168,12 +72,12 @@ class ValuePrinter:
         tag = self.tag()
         if tag is None:
             return '(invalid value)'
-        if self.val['tag_if_small_enough'] < ValuePrinter.no_payload_count:
+        if self.val['tag_if_small_enough'] < common.Value.no_payload_count:
             return '.%s' % str(tag)
         return None
 
     def children(self):
-        if self.val['tag_if_small_enough'] < ValuePrinter.no_payload_count:
+        if self.val['tag_if_small_enough'] < common.Value.no_payload_count:
             return
 
         yield ('tag', '.%s' % str(self.tag()))
tools/stage2_lldb_pretty_printers.py
@@ -0,0 +1,59 @@
+# pretty printing for stage 2.
+# put "command script /path/to/stage2_lldb_pretty_printers.py" and "type category enable stage2" in ~/.lldbinit to load it automatically.
+import lldb
+import stage2_pretty_printers_common as common
+
+category = 'stage2'
+module = category + '_lldb_pretty_printers'
+
+class type_Type_SynthProvider:
+    def __init__(self, type, _=None):
+        self.type = type
+
+    def update(self):
+        self.tag = self.type.GetChildMemberWithName('tag_if_small_enough').Clone('tag')
+        self.payload = None
+        if self.tag.GetValueAsUnsigned() >= common.Type.no_payload_count:
+            ptr_otherwise = self.type.GetChildMemberWithName('ptr_otherwise')
+            self.tag = ptr_otherwise.Dereference().GetChildMemberWithName('tag')
+            payload_type = self.type.target.FindFirstType('type.' + common.Type.payload_type_names[self.tag.GetValue()])
+            self.payload = ptr_otherwise.Cast(payload_type.GetPointerType()).Dereference().GetChildMemberWithName('data').Clone('payload')
+
+    def num_children(self):
+        return 1 + (self.payload is not None)
+
+    def get_child_index(self, name):
+        return ['tag', 'payload'].index(name)
+
+    def get_child_at_index(self, index):
+        return [self.tag, self.payload][index]
+
+class value_Value_SynthProvider:
+    def __init__(self, value, _=None):
+        self.value = value
+
+    def update(self):
+        self.tag = self.value.GetChildMemberWithName('tag_if_small_enough').Clone('tag')
+        self.payload = None
+        if self.tag.GetValueAsUnsigned() >= common.Value.no_payload_count:
+            ptr_otherwise = self.value.GetChildMemberWithName('ptr_otherwise')
+            self.tag = ptr_otherwise.Dereference().GetChildMemberWithName('tag')
+            payload_type = self.value.target.FindFirstType('value.' + common.Value.payload_type_names[self.tag.GetValue()])
+            self.payload = ptr_otherwise.Cast(payload_type.GetPointerType()).Dereference().GetChildMemberWithName('data').Clone('payload')
+
+    def num_children(self):
+        return 1 + (self.payload is not None)
+
+    def get_child_index(self, name):
+        return ['tag', 'payload'].index(name)
+
+    def get_child_at_index(self, index):
+        return [self.tag, self.payload][index]
+
+def add(debugger, type, summary=False, synth=False):
+    if summary: debugger.HandleCommand('type summary add --python-function ' + module + '.' + type.replace('.', '_') + '_SummaryProvider "' + type + '" --category ' + category)
+    if synth: debugger.HandleCommand('type synthetic add --python-class ' + module + '.' + type.replace('.', '_') + '_SynthProvider "' + type + '" --category ' + category)
+
+def __lldb_init_module(debugger, _=None):
+    add(debugger, 'type.Type', synth=True)
+    add(debugger, 'value.Value', synth=True)
tools/stage2_pretty_printers_common.py
@@ -0,0 +1,98 @@
+class Type:
+    no_payload_count = 4096
+
+    # Keep in sync with src/type.zig
+    # Types which have no payload do not need to be entered here.
+    payload_type_names = {
+        'array_u8': 'Type.Payload.Len',
+        'array_u8_sentinel_0': 'Type.Payload.Len',
+
+        'single_const_pointer': 'Type.Payload.ElemType',
+        'single_mut_pointer': 'Type.Payload.ElemType',
+        'many_const_pointer': 'Type.Payload.ElemType',
+        'many_mut_pointer': 'Type.Payload.ElemType',
+        'c_const_pointer': 'Type.Payload.ElemType',
+        'c_mut_pointer': 'Type.Payload.ElemType',
+        'const_slice': 'Type.Payload.ElemType',
+        'mut_slice': 'Type.Payload.ElemType',
+        'optional': 'Type.Payload.ElemType',
+        'optional_single_mut_pointer': 'Type.Payload.ElemType',
+        'optional_single_const_pointer': 'Type.Payload.ElemType',
+        'anyframe_T': 'Type.Payload.ElemType',
+
+        'int_signed': 'Type.Payload.Bits',
+        'int_unsigned': 'Type.Payload.Bits',
+
+        'error_set': 'Type.Payload.ErrorSet',
+        'error_set_inferred': 'Type.Payload.ErrorSetInferred',
+        'error_set_merged': 'Type.Payload.ErrorSetMerged',
+
+        'array': 'Type.Payload.Array',
+        'vector': 'Type.Payload.Array',
+
+        'array_sentinel': 'Type.Payload.ArraySentinel',
+        'pointer': 'Type.Payload.Pointer',
+        'function': 'Type.Payload.Function',
+        'error_union': 'Type.Payload.ErrorUnion',
+        'error_set_single': 'Type.Payload.Name',
+        'opaque': 'Type.Payload.Opaque',
+        'struct': 'Type.Payload.Struct',
+        'union': 'Type.Payload.Union',
+        'union_tagged': 'Type.Payload.Union',
+        'enum_full, .enum_nonexhaustive': 'Type.Payload.EnumFull',
+        'enum_simple': 'Type.Payload.EnumSimple',
+        'enum_numbered': 'Type.Payload.EnumNumbered',
+        'empty_struct': 'Type.Payload.ContainerScope',
+        'tuple': 'Type.Payload.Tuple',
+        'anon_struct': 'Type.Payload.AnonStruct',
+    }
+
+class Value:
+    no_payload_count = 4096
+
+    # Keep in sync with src/value.zig
+    # Values which have no payload do not need to be entered here.
+    payload_type_names = {
+        'big_int_positive': 'Value.Payload.BigInt',
+        'big_int_negative': 'Value.Payload.BigInt',
+
+        'extern_fn': 'Value.Payload.ExternFn',
+
+        'decl_ref': 'Value.Payload.Decl',
+
+        'repeated': 'Value.Payload.SubValue',
+        'eu_payload': 'Value.Payload.SubValue',
+        'opt_payload': 'Value.Payload.SubValue',
+        'empty_array_sentinel': 'Value.Payload.SubValue',
+
+        'eu_payload_ptr': 'Value.Payload.PayloadPtr',
+        'opt_payload_ptr': 'Value.Payload.PayloadPtr',
+
+        'bytes': 'Value.Payload.Bytes',
+        'enum_literal': 'Value.Payload.Bytes',
+
+        'slice': 'Value.Payload.Slice',
+
+        'enum_field_index': 'Value.Payload.U32',
+
+        'ty': 'Value.Payload.Ty',
+        'int_type': 'Value.Payload.IntType',
+        'int_u64': 'Value.Payload.U64',
+        'int_i64': 'Value.Payload.I64',
+        'function': 'Value.Payload.Function',
+        'variable': 'Value.Payload.Variable',
+        'decl_ref_mut': 'Value.Payload.DeclRefMut',
+        'elem_ptr': 'Value.Payload.ElemPtr',
+        'field_ptr': 'Value.Payload.FieldPtr',
+        'float_16': 'Value.Payload.Float_16',
+        'float_32': 'Value.Payload.Float_32',
+        'float_64': 'Value.Payload.Float_64',
+        'float_80': 'Value.Payload.Float_80',
+        'float_128': 'Value.Payload.Float_128',
+        'error': 'Value.Payload.Error',
+        'inferred_alloc': 'Value.Payload.InferredAlloc',
+        'inferred_alloc_comptime': 'Value.Payload.InferredAllocComptime',
+        'aggregate': 'Value.Payload.Aggregate',
+        'union': 'Value.Payload.Union',
+        'bound_fn': 'Value.Payload.BoundFn',
+    }