[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / llvm / utils / lldbDataFormatters.py
blobbdcd1c931ba825d1d98a66e86d597a9d3640434b
1 """
2 LLDB Formatters for LLVM data types.
4 Load into LLDB with 'command script import /path/to/lldbDataFormatters.py'
5 """
7 import lldb
8 import json
10 def __lldb_init_module(debugger, internal_dict):
11 debugger.HandleCommand('type category define -e llvm -l c++')
12 debugger.HandleCommand('type synthetic add -w llvm '
13 '-l lldbDataFormatters.SmallVectorSynthProvider '
14 '-x "^llvm::SmallVectorImpl<.+>$"')
15 debugger.HandleCommand('type summary add -w llvm '
16 '-e -s "size=${svar%#}" '
17 '-x "^llvm::SmallVectorImpl<.+>$"')
18 debugger.HandleCommand('type synthetic add -w llvm '
19 '-l lldbDataFormatters.SmallVectorSynthProvider '
20 '-x "^llvm::SmallVector<.+,.+>$"')
21 debugger.HandleCommand('type summary add -w llvm '
22 '-e -s "size=${svar%#}" '
23 '-x "^llvm::SmallVector<.+,.+>$"')
24 debugger.HandleCommand('type synthetic add -w llvm '
25 '-l lldbDataFormatters.ArrayRefSynthProvider '
26 '-x "^llvm::ArrayRef<.+>$"')
27 debugger.HandleCommand('type summary add -w llvm '
28 '-e -s "size=${svar%#}" '
29 '-x "^llvm::ArrayRef<.+>$"')
30 debugger.HandleCommand('type synthetic add -w llvm '
31 '-l lldbDataFormatters.OptionalSynthProvider '
32 '-x "^llvm::Optional<.+>$"')
33 debugger.HandleCommand('type summary add -w llvm '
34 '-e -F lldbDataFormatters.OptionalSummaryProvider '
35 '-x "^llvm::Optional<.+>$"')
36 debugger.HandleCommand('type summary add -w llvm '
37 '-F lldbDataFormatters.SmallStringSummaryProvider '
38 '-x "^llvm::SmallString<.+>$"')
39 debugger.HandleCommand('type summary add -w llvm '
40 '-F lldbDataFormatters.StringRefSummaryProvider '
41 '-x "^llvm::StringRef$"')
42 debugger.HandleCommand('type summary add -w llvm '
43 '-F lldbDataFormatters.ConstStringSummaryProvider '
44 '-x "^lldb_private::ConstString$"')
45 debugger.HandleCommand('type synthetic add -w llvm '
46 '-l lldbDataFormatters.PointerIntPairSynthProvider '
47 '-x "^llvm::PointerIntPair<.+>$"')
48 debugger.HandleCommand('type synthetic add -w llvm '
49 '-l lldbDataFormatters.PointerUnionSynthProvider '
50 '-x "^llvm::PointerUnion<.+>$"')
53 # Pretty printer for llvm::SmallVector/llvm::SmallVectorImpl
54 class SmallVectorSynthProvider:
55 def __init__(self, valobj, internal_dict):
56 self.valobj = valobj;
57 self.update() # initialize this provider
59 def num_children(self):
60 return self.size.GetValueAsUnsigned(0)
62 def get_child_index(self, name):
63 try:
64 return int(name.lstrip('[').rstrip(']'))
65 except:
66 return -1;
68 def get_child_at_index(self, index):
69 # Do bounds checking.
70 if index < 0:
71 return None
72 if index >= self.num_children():
73 return None;
75 offset = index * self.type_size
76 return self.begin.CreateChildAtOffset('['+str(index)+']',
77 offset, self.data_type)
79 def update(self):
80 self.begin = self.valobj.GetChildMemberWithName('BeginX')
81 self.size = self.valobj.GetChildMemberWithName('Size')
82 the_type = self.valobj.GetType()
83 # If this is a reference type we have to dereference it to get to the
84 # template parameter.
85 if the_type.IsReferenceType():
86 the_type = the_type.GetDereferencedType()
88 self.data_type = the_type.GetTemplateArgumentType(0)
89 self.type_size = self.data_type.GetByteSize()
90 assert self.type_size != 0
92 class ArrayRefSynthProvider:
93 """ Provider for llvm::ArrayRef """
94 def __init__(self, valobj, internal_dict):
95 self.valobj = valobj;
96 self.update() # initialize this provider
98 def num_children(self):
99 return self.length
101 def get_child_index(self, name):
102 try:
103 return int(name.lstrip('[').rstrip(']'))
104 except:
105 return -1;
107 def get_child_at_index(self, index):
108 if index < 0 or index >= self.num_children():
109 return None;
110 offset = index * self.type_size
111 return self.data.CreateChildAtOffset('[' + str(index) + ']',
112 offset, self.data_type)
114 def update(self):
115 self.data = self.valobj.GetChildMemberWithName('Data')
116 length_obj = self.valobj.GetChildMemberWithName('Length')
117 self.length = length_obj.GetValueAsUnsigned(0)
118 self.data_type = self.data.GetType().GetPointeeType()
119 self.type_size = self.data_type.GetByteSize()
120 assert self.type_size != 0
122 def GetOptionalValue(valobj):
123 storage = valobj.GetChildMemberWithName('Storage')
124 if not storage:
125 storage = valobj
127 failure = 2
128 hasVal = storage.GetChildMemberWithName('hasVal').GetValueAsUnsigned(failure)
129 if hasVal == failure:
130 return '<could not read llvm::Optional>'
132 if hasVal == 0:
133 return None
135 underlying_type = storage.GetType().GetTemplateArgumentType(0)
136 storage = storage.GetChildMemberWithName('value')
137 return storage.Cast(underlying_type)
139 def OptionalSummaryProvider(valobj, internal_dict):
140 val = GetOptionalValue(valobj)
141 if val is None:
142 return 'None'
143 if val.summary:
144 return val.summary
145 return ''
147 class OptionalSynthProvider:
148 """Provides deref support to llvm::Optional<T>"""
149 def __init__(self, valobj, internal_dict):
150 self.valobj = valobj
152 def num_children(self):
153 return self.valobj.num_children
155 def get_child_index(self, name):
156 if name == '$$dereference$$':
157 return self.valobj.num_children
158 return self.valobj.GetIndexOfChildWithName(name)
160 def get_child_at_index(self, index):
161 if index < self.valobj.num_children:
162 return self.valobj.GetChildAtIndex(index)
163 return GetOptionalValue(self.valobj) or lldb.SBValue()
165 def SmallStringSummaryProvider(valobj, internal_dict):
166 num_elements = valobj.GetNumChildren()
167 res = "\""
168 for i in range(0, num_elements):
169 c = valobj.GetChildAtIndex(i).GetValue()
170 if c:
171 res += c.strip("'")
172 res += "\""
173 return res
176 def StringRefSummaryProvider(valobj, internal_dict):
177 if valobj.GetNumChildren() == 2:
178 # StringRef's are also used to point at binary blobs in memory,
179 # so filter out suspiciously long strings.
180 max_length = 1024
181 actual_length = valobj.GetChildAtIndex(1).GetValueAsUnsigned()
182 truncate = actual_length > max_length
183 length = min(max_length, actual_length)
184 if length == 0:
185 return '""'
187 data = valobj.GetChildAtIndex(0).GetPointeeData(item_count=length)
188 error = lldb.SBError()
189 string = data.ReadRawData(error, 0, data.GetByteSize()).decode()
190 if error.Fail():
191 return "<error: %s>" % error.description
193 # json.dumps conveniently escapes the string for us.
194 string = json.dumps(string)
195 if truncate:
196 string += "..."
197 return string
198 return None
201 def ConstStringSummaryProvider(valobj, internal_dict):
202 if valobj.GetNumChildren() == 1:
203 return valobj.GetChildAtIndex(0).GetSummary()
204 return ""
207 def get_expression_path(val):
208 stream = lldb.SBStream()
209 if not val.GetExpressionPath(stream):
210 return None
211 return stream.GetData()
214 class PointerIntPairSynthProvider:
215 def __init__(self, valobj, internal_dict):
216 self.valobj = valobj
217 self.update()
219 def num_children(self):
220 return 2
222 def get_child_index(self, name):
223 if name == 'Pointer':
224 return 0
225 if name == 'Int':
226 return 1
227 return None
229 def get_child_at_index(self, index):
230 expr_path = get_expression_path(self.valobj)
231 if index == 0:
232 return self.valobj.CreateValueFromExpression('Pointer', f'({self.pointer_ty.name}){expr_path}.getPointer()')
233 if index == 1:
234 return self.valobj.CreateValueFromExpression('Int', f'({self.int_ty.name}){expr_path}.getInt()')
235 return None
237 def update(self):
238 self.pointer_ty = self.valobj.GetType().GetTemplateArgumentType(0)
239 self.int_ty = self.valobj.GetType().GetTemplateArgumentType(2)
242 def parse_template_parameters(typename):
244 LLDB doesn't support template parameter packs, so let's parse them manually.
246 result = []
247 start = typename.find('<')
248 end = typename.rfind('>')
249 if start < 1 or end < 2 or end - start < 2:
250 return result
252 nesting_level = 0
253 current_parameter_start = start + 1
255 for i in range(start + 1, end + 1):
256 c = typename[i]
257 if c == '<':
258 nesting_level += 1
259 elif c == '>':
260 nesting_level -= 1
261 elif c == ',' and nesting_level == 0:
262 result.append(typename[current_parameter_start:i].strip())
263 current_parameter_start = i + 1
265 result.append(typename[current_parameter_start:i].strip())
267 return result
270 class PointerUnionSynthProvider:
271 def __init__(self, valobj, internal_dict):
272 self.valobj = valobj
273 self.update()
275 def num_children(self):
276 return 1
278 def get_child_index(self, name):
279 if name == 'Ptr':
280 return 0
281 return None
283 def get_child_at_index(self, index):
284 if index != 0:
285 return None
286 ptr_type_name = self.template_args[self.active_type_tag]
287 return self.valobj.CreateValueFromExpression('Ptr', f'({ptr_type_name}){self.val_expr_path}.getPointer()')
289 def update(self):
290 self.pointer_int_pair = self.valobj.GetChildMemberWithName('Val')
291 self.val_expr_path = get_expression_path(self.valobj.GetChildMemberWithName('Val'))
292 self.active_type_tag = self.valobj.CreateValueFromExpression('', f'(int){self.val_expr_path}.getInt()').GetValueAsSigned()
293 self.template_args = parse_template_parameters(self.valobj.GetType().name)