1"""
2LLDB Formatters for LLVM data types.
3
4Load into LLDB with 'command script import /path/to/lldbDataFormatters.py'
5"""
6
7import lldb
8
9def __lldb_init_module(debugger, internal_dict):
10    debugger.HandleCommand('type category define -e llvm -l c++')
11    debugger.HandleCommand('type synthetic add -w llvm '
12                           '-l lldbDataFormatters.SmallVectorSynthProvider '
13                           '-x "^llvm::SmallVectorImpl<.+>$"')
14    debugger.HandleCommand('type synthetic add -w llvm '
15                           '-l lldbDataFormatters.SmallVectorSynthProvider '
16                           '-x "^llvm::SmallVector<.+,.+>$"')
17    debugger.HandleCommand('type synthetic add -w llvm '
18                           '-l lldbDataFormatters.ArrayRefSynthProvider '
19                           '-x "^llvm::ArrayRef<.+>$"')
20    debugger.HandleCommand('type synthetic add -w llvm '
21                           '-l lldbDataFormatters.OptionalSynthProvider '
22                           '-x "^llvm::Optional<.+>$"')
23    debugger.HandleCommand('type summary add -w llvm '
24                           '-F lldbDataFormatters.OptionalSummaryProvider '
25                           '-x "^llvm::Optional<.+>$"')
26    debugger.HandleCommand('type summary add -w llvm '
27                           '-F lldbDataFormatters.SmallStringSummaryProvider '
28                           '-x "^llvm::SmallString<.+>$"')
29    debugger.HandleCommand('type summary add -w llvm '
30                           '-F lldbDataFormatters.StringRefSummaryProvider '
31                           '-x "^llvm::StringRef$"')
32    debugger.HandleCommand('type summary add -w llvm '
33                           '-F lldbDataFormatters.ConstStringSummaryProvider '
34                           '-x "^lldb_private::ConstString$"')
35
36# Pretty printer for llvm::SmallVector/llvm::SmallVectorImpl
37class SmallVectorSynthProvider:
38    def __init__(self, valobj, internal_dict):
39        self.valobj = valobj;
40        self.update() # initialize this provider
41
42    def num_children(self):
43        return self.size.GetValueAsUnsigned(0)
44
45    def get_child_index(self, name):
46        try:
47            return int(name.lstrip('[').rstrip(']'))
48        except:
49            return -1;
50
51    def get_child_at_index(self, index):
52        # Do bounds checking.
53        if index < 0:
54            return None
55        if index >= self.num_children():
56            return None;
57
58        offset = index * self.type_size
59        return self.begin.CreateChildAtOffset('['+str(index)+']',
60                                              offset, self.data_type)
61
62    def update(self):
63        self.begin = self.valobj.GetChildMemberWithName('BeginX')
64        self.size = self.valobj.GetChildMemberWithName('Size')
65        the_type = self.valobj.GetType()
66        # If this is a reference type we have to dereference it to get to the
67        # template parameter.
68        if the_type.IsReferenceType():
69            the_type = the_type.GetDereferencedType()
70
71        self.data_type = the_type.GetTemplateArgumentType(0)
72        self.type_size = self.data_type.GetByteSize()
73        assert self.type_size != 0
74
75class ArrayRefSynthProvider:
76    """ Provider for llvm::ArrayRef """
77    def __init__(self, valobj, internal_dict):
78        self.valobj = valobj;
79        self.update() # initialize this provider
80
81    def num_children(self):
82        return self.length
83
84    def get_child_index(self, name):
85        try:
86            return int(name.lstrip('[').rstrip(']'))
87        except:
88            return -1;
89
90    def get_child_at_index(self, index):
91        if index < 0 or index >= self.num_children():
92            return None;
93        offset = index * self.type_size
94        return self.data.CreateChildAtOffset('[' + str(index) + ']',
95                                             offset, self.data_type)
96
97    def update(self):
98        self.data = self.valobj.GetChildMemberWithName('Data')
99        length_obj = self.valobj.GetChildMemberWithName('Length')
100        self.length = length_obj.GetValueAsUnsigned(0)
101        self.data_type = self.data.GetType().GetPointeeType()
102        self.type_size = self.data_type.GetByteSize()
103        assert self.type_size != 0
104
105def GetOptionalValue(valobj):
106    storage = valobj.GetChildMemberWithName('Storage')
107    if not storage:
108        storage = valobj
109
110    failure = 2
111    hasVal = storage.GetChildMemberWithName('hasVal').GetValueAsUnsigned(failure)
112    if hasVal == failure:
113        return '<could not read llvm::Optional>'
114
115    if hasVal == 0:
116        return None
117
118    underlying_type = storage.GetType().GetTemplateArgumentType(0)
119    storage = storage.GetChildMemberWithName('value')
120    return storage.Cast(underlying_type)
121
122def OptionalSummaryProvider(valobj, internal_dict):
123    val = GetOptionalValue(valobj)
124    return val.summary if val else 'None'
125
126class OptionalSynthProvider:
127    """Provides deref support to llvm::Optional<T>"""
128    def __init__(self, valobj, internal_dict):
129        self.valobj = valobj
130
131    def num_children(self):
132        return self.valobj.num_children
133
134    def get_child_index(self, name):
135        if name == '$$dereference$$':
136            return self.valobj.num_children
137        return self.valobj.GetIndexOfChildWithName(name)
138
139    def get_child_at_index(self, index):
140        if index < self.valobj.num_children:
141            return self.valobj.GetChildAtIndex(index)
142        return GetOptionalValue(self.valobj) or lldb.SBValue()
143
144def SmallStringSummaryProvider(valobj, internal_dict):
145    num_elements = valobj.GetNumChildren()
146    res = "\""
147    for i in range(0, num_elements):
148        c = valobj.GetChildAtIndex(i).GetValue()
149        if c:
150            res += c.strip("'")
151    res += "\""
152    return res
153
154def StringRefSummaryProvider(valobj, internal_dict):
155    if valobj.GetNumChildren() == 2:
156        # StringRef's are also used to point at binary blobs in memory,
157        # so filter out suspiciously long strings.
158        max_length = 256
159        length = valobj.GetChildAtIndex(1).GetValueAsUnsigned(max_length)
160        if length == 0:
161            return "NULL"
162        if length < max_length:
163            return valobj.GetChildAtIndex(0).GetSummary()
164    return ""
165
166def ConstStringSummaryProvider(valobj, internal_dict):
167    if valobj.GetNumChildren() == 1:
168        return valobj.GetChildAtIndex(0).GetSummary()
169    return ""
170