""" LLDB Formatters for LLVM data types for use in the swift project. Load into LLDB with 'command script import /path/to/lldbSwiftDataFormatters.py' """ import sys from enum import Enum def __lldb_init_module(debugger, internal_dict): category = 'swift-compiler-internals' debugger.HandleCommand(f'type category define -e {category} -l c++') tName = 'lldbSwiftDataFormatters.SmallBitVectorSummaryProvider' debugger.HandleCommand('type summary add -w llvm ' f'-F {tName} -x "^llvm::SmallBitVector$"') debugger.HandleCommand(f'type summary add --expand --skip-references -w {category} ' '-F lldbSwiftDataFormatters.DemangleNodeSummaryProvider ' '-x "^swift::Demangle::Node$"') debugger.HandleCommand(f'type synthetic add --skip-references -w {category} ' '-l lldbSwiftDataFormatters.DemangleNodeSynthProvider ' '-x "^swift::Demangle::Node$"') debugger.HandleCommand(f'type summary add -w {category} ' '-s "${var.Pointer%S}" ' 'swift::Identifier') def SmallBitVectorSummaryProvider(valobj, internal_dict): underlyingValue = valobj.GetChildMemberWithName('X').GetValueAsUnsigned() numBaseBits = 32 is64Bit = sys.maxsize > 2**32 if is64Bit: numBaseBits = 64 smallNumRawBits = numBaseBits - 1 smallNumSizeBits = None if numBaseBits == 32: smallNumSizeBits = 5 elif numBaseBits == 64: smallNumSizeBits = 6 else: smallNumSizeBits = smallNumRawBits smallNumDataBits = smallNumRawBits - smallNumSizeBits # If our underlying value is not small, print we can not dump large values. isSmallMask = 1 if (underlyingValue & isSmallMask) == 0: return '' smallRawBits = underlyingValue >> 1 smallSize = smallRawBits >> smallNumDataBits bits = smallRawBits & ((1 << (smallSize + 1)) - 1) res = "[" for i in reversed(range(0, smallSize)): if bool(bits & (1 << i)): res += '1' else: res += '0' res += "]" return res class DemangleNodePayloadKind(Enum): NONE = 0 ONE_CHILD = 1 TWO_CHILDREN = 2 TEXT = 3 INDEX = 4 MANY_CHILDREN = 5 class DemangleNodeSynthProvider: """ Provider for swift::Demangle::Node """ def __init__(self, valobj, internal_dict): self.valobj = valobj self.update() # initialize this provider def num_children(self): if self.payload_kind in [DemangleNodePayloadKind.TEXT, DemangleNodePayloadKind.INDEX, DemangleNodePayloadKind.ONE_CHILD]: return 2 if self.payload_kind is DemangleNodePayloadKind.TWO_CHILDREN: return 3 if self.payload_kind is DemangleNodePayloadKind.MANY_CHILDREN: return self.payload.GetChildMemberWithName('Children'). \ GetChildMemberWithName('Number').GetValueAsUnsigned() + 1 return 1 def get_child_index(self, name): if name == 'NodeKind': return 0 if self.payload_kind is DemangleNodePayloadKind.TEXT and name == 'Text': return 1 if self.payload_kind is DemangleNodePayloadKind.INDEX and name == 'Index': return 1 if self.payload_kind is DemangleNodePayloadKind.NONE: return None try: return int(name.lstrip('[').rstrip(']')) + 1 except ValueError: return None def get_child_at_index(self, index): if index == 0: return self.valobj.GetChildMemberWithName('NodeKind') index -= 1 if self.payload_kind is DemangleNodePayloadKind.TEXT and index == 0: return self.payload.GetChildMemberWithName('Text') if self.payload_kind is DemangleNodePayloadKind.INDEX and index == 0: return self.payload.GetChildMemberWithName('Index') if self.payload_kind is DemangleNodePayloadKind.ONE_CHILD \ and index == 0: return self.payload \ .GetChildMemberWithName('InlineChildren') \ .GetChildAtIndex(0) if self.payload_kind is DemangleNodePayloadKind.TWO_CHILDREN \ and 0 <= index <= 1: return self.payload \ .GetChildMemberWithName('InlineChildren') \ .GetChildAtIndex(index) if self.payload_kind is DemangleNodePayloadKind.MANY_CHILDREN \ and index >= 0: node_vector = self.payload.GetChildMemberWithName('Children') length = node_vector.GetChildMemberWithName('Number') if index >= length.GetValueAsUnsigned(): return None nodes_ptr = node_vector.GetChildMemberWithName('Nodes') offset = self.node_ptr_size * index return nodes_ptr.CreateChildAtOffset('[' + str(index) + ']', offset, self.node_ptr_type) return None def update(self): self.payload_kind = DemangleNodePayloadKind( self.valobj.GetChildMemberWithName('NodePayloadKind').GetValueAsUnsigned() ) valobj_type = self.valobj.GetType() if valobj_type.IsPointerType(): self.node_ptr_type = valobj_type else: self.node_ptr_type = valobj_type.GetPointerType() self.node_ptr_size = self.node_ptr_type.GetByteSize() self.payload = self.valobj.GetChildAtIndex(0) def DemangleNodeSummaryProvider(valobj, internal_dict): valobj = valobj.GetNonSyntheticValue() result = valobj.GetChildMemberWithName('NodeKind').GetValue() result += ', ' payload_kind = DemangleNodePayloadKind( valobj.GetChildMemberWithName('NodePayloadKind').GetValueAsUnsigned() ) if payload_kind is DemangleNodePayloadKind.NONE: result += '0 children' if payload_kind is DemangleNodePayloadKind.TEXT: result += 'Text=' result += valobj \ .GetChildAtIndex(0) \ .GetChildMemberWithName('Text') \ .GetSummary() if payload_kind is DemangleNodePayloadKind.INDEX: result += 'Index=' index = valobj \ .GetChildAtIndex(0) \ .GetChildMemberWithName('Index') \ .GetValueAsUnsigned() result += str(index) if payload_kind is DemangleNodePayloadKind.ONE_CHILD: result += '1 child' if payload_kind in [DemangleNodePayloadKind.TWO_CHILDREN, DemangleNodePayloadKind.MANY_CHILDREN]: num_children = \ DemangleNodeSynthProvider(valobj, internal_dict).num_children() - 1 result += str(num_children) result += ' children' return result