[RISCV] Rename Mips instruction records to start with MIPS_. NFC (#125170)
[llvm-project.git] / llvm / utils / lldbDataFormatters.py
blob09143d2d81cbb790ba75415a135b868faf61c3d0
1 """
2 LLDB Formatters for LLVM data types.
4 Load into LLDB with 'command script import /path/to/lldbDataFormatters.py'
5 """
6 from __future__ import annotations
8 import collections
9 import lldb
10 import json
13 def __lldb_init_module(debugger, internal_dict):
14 debugger.HandleCommand("type category define -e llvm -l c++")
15 debugger.HandleCommand(
16 "type synthetic add -w llvm "
17 f"-l {__name__}.SmallVectorSynthProvider "
18 '-x "^llvm::SmallVectorImpl<.+>$"'
20 debugger.HandleCommand(
21 "type summary add -w llvm "
22 '-e -s "size=${svar%#}" '
23 '-x "^llvm::SmallVectorImpl<.+>$"'
25 debugger.HandleCommand(
26 "type synthetic add -w llvm "
27 f"-l {__name__}.SmallVectorSynthProvider "
28 '-x "^llvm::SmallVector<.+,.+>$"'
30 debugger.HandleCommand(
31 "type summary add -w llvm "
32 '-e -s "size=${svar%#}" '
33 '-x "^llvm::SmallVector<.+,.+>$"'
35 debugger.HandleCommand(
36 "type synthetic add -w llvm "
37 f"-l {__name__}.ArrayRefSynthProvider "
38 '-x "^llvm::ArrayRef<.+>$"'
40 debugger.HandleCommand(
41 "type summary add -w llvm "
42 '-e -s "size=${svar%#}" '
43 '-x "^llvm::ArrayRef<.+>$"'
45 debugger.HandleCommand(
46 "type synthetic add -w llvm "
47 f"-l {__name__}.OptionalSynthProvider "
48 '-x "^llvm::Optional<.+>$"'
50 debugger.HandleCommand(
51 "type summary add -w llvm "
52 f"-e -F {__name__}.OptionalSummaryProvider "
53 '-x "^llvm::Optional<.+>$"'
55 debugger.HandleCommand(
56 "type summary add -w llvm "
57 f"-F {__name__}.SmallStringSummaryProvider "
58 '-x "^llvm::SmallString<.+>$"'
60 debugger.HandleCommand(
61 "type summary add -w llvm "
62 f"-F {__name__}.StringRefSummaryProvider "
63 "llvm::StringRef"
65 debugger.HandleCommand(
66 "type summary add -w llvm "
67 f"-F {__name__}.ConstStringSummaryProvider "
68 "lldb_private::ConstString"
71 # The synthetic providers for PointerIntPair and PointerUnion are disabled
72 # because of a few issues. One example is template arguments that are
73 # non-pointer types that instead specialize PointerLikeTypeTraits.
74 # debugger.HandleCommand(
75 # "type synthetic add -w llvm "
76 # f"-l {__name__}.PointerIntPairSynthProvider "
77 # '-x "^llvm::PointerIntPair<.+>$"'
78 # )
79 # debugger.HandleCommand(
80 # "type synthetic add -w llvm "
81 # f"-l {__name__}.PointerUnionSynthProvider "
82 # '-x "^llvm::PointerUnion<.+>$"'
83 # )
85 debugger.HandleCommand(
86 "type summary add -w llvm "
87 f"-e -F {__name__}.DenseMapSummary "
88 '-x "^llvm::DenseMap<.+>$"'
90 debugger.HandleCommand(
91 "type synthetic add -w llvm "
92 f"-l {__name__}.DenseMapSynthetic "
93 '-x "^llvm::DenseMap<.+>$"'
96 debugger.HandleCommand(
97 "type synthetic add -w llvm "
98 f"-l {__name__}.ExpectedSynthetic "
99 '-x "^llvm::Expected<.+>$"'
103 # Pretty printer for llvm::SmallVector/llvm::SmallVectorImpl
104 class SmallVectorSynthProvider:
105 def __init__(self, valobj, internal_dict):
106 self.valobj = valobj
107 self.update() # initialize this provider
109 def num_children(self):
110 return self.size.GetValueAsUnsigned(0)
112 def get_child_index(self, name):
113 try:
114 return int(name.lstrip("[").rstrip("]"))
115 except:
116 return -1
118 def get_child_at_index(self, index):
119 # Do bounds checking.
120 if index < 0:
121 return None
122 if index >= self.num_children():
123 return None
125 offset = index * self.type_size
126 return self.begin.CreateChildAtOffset(
127 "[" + str(index) + "]", offset, self.data_type
130 def update(self):
131 self.begin = self.valobj.GetChildMemberWithName("BeginX")
132 self.size = self.valobj.GetChildMemberWithName("Size")
133 the_type = self.valobj.GetType()
134 # If this is a reference type we have to dereference it to get to the
135 # template parameter.
136 if the_type.IsReferenceType():
137 the_type = the_type.GetDereferencedType()
139 if the_type.IsPointerType():
140 the_type = the_type.GetPointeeType()
142 self.data_type = the_type.GetTemplateArgumentType(0)
143 self.type_size = self.data_type.GetByteSize()
144 assert self.type_size != 0
147 class ArrayRefSynthProvider:
148 """Provider for llvm::ArrayRef"""
150 def __init__(self, valobj, internal_dict):
151 self.valobj = valobj
152 self.update() # initialize this provider
154 def num_children(self):
155 return self.length
157 def get_child_index(self, name):
158 try:
159 return int(name.lstrip("[").rstrip("]"))
160 except:
161 return -1
163 def get_child_at_index(self, index):
164 if index < 0 or index >= self.num_children():
165 return None
166 offset = index * self.type_size
167 return self.data.CreateChildAtOffset(
168 "[" + str(index) + "]", offset, self.data_type
171 def update(self):
172 self.data = self.valobj.GetChildMemberWithName("Data")
173 length_obj = self.valobj.GetChildMemberWithName("Length")
174 self.length = length_obj.GetValueAsUnsigned(0)
175 self.data_type = self.data.GetType().GetPointeeType()
176 self.type_size = self.data_type.GetByteSize()
177 assert self.type_size != 0
180 def GetOptionalValue(valobj):
181 storage = valobj.GetChildMemberWithName("Storage")
182 if not storage:
183 storage = valobj
185 failure = 2
186 hasVal = storage.GetChildMemberWithName("hasVal").GetValueAsUnsigned(failure)
187 if hasVal == failure:
188 return "<could not read llvm::Optional>"
190 if hasVal == 0:
191 return None
193 underlying_type = storage.GetType().GetTemplateArgumentType(0)
194 storage = storage.GetChildMemberWithName("value")
195 return storage.Cast(underlying_type)
198 def OptionalSummaryProvider(valobj, internal_dict):
199 val = GetOptionalValue(valobj)
200 if val is None:
201 return "None"
202 if val.summary:
203 return val.summary
204 return ""
207 class OptionalSynthProvider:
208 """Provides deref support to llvm::Optional<T>"""
210 def __init__(self, valobj, internal_dict):
211 self.valobj = valobj
213 def num_children(self):
214 return self.valobj.num_children
216 def get_child_index(self, name):
217 if name == "$$dereference$$":
218 return self.valobj.num_children
219 return self.valobj.GetIndexOfChildWithName(name)
221 def get_child_at_index(self, index):
222 if index < self.valobj.num_children:
223 return self.valobj.GetChildAtIndex(index)
224 return GetOptionalValue(self.valobj) or lldb.SBValue()
227 def SmallStringSummaryProvider(valobj, internal_dict):
228 # The underlying SmallVector base class is the first child.
229 vector = valobj.GetChildAtIndex(0)
230 num_elements = vector.GetNumChildren()
231 res = '"'
232 for i in range(num_elements):
233 c = vector.GetChildAtIndex(i)
234 if c:
235 res += chr(c.GetValueAsUnsigned())
236 res += '"'
237 return res
240 def StringRefSummaryProvider(valobj, internal_dict):
241 if valobj.GetNumChildren() == 2:
242 # StringRef's are also used to point at binary blobs in memory,
243 # so filter out suspiciously long strings.
244 max_length = 1024
245 actual_length = valobj.GetChildAtIndex(1).GetValueAsUnsigned()
246 truncate = actual_length > max_length
247 length = min(max_length, actual_length)
248 if length == 0:
249 return '""'
251 data = valobj.GetChildAtIndex(0).GetPointeeData(item_count=length)
252 error = lldb.SBError()
253 string = data.ReadRawData(error, 0, data.GetByteSize()).decode()
254 if error.Fail():
255 return "<error: %s>" % error.description
257 # json.dumps conveniently escapes the string for us.
258 string = json.dumps(string)
259 if truncate:
260 string += "..."
261 return string
262 return None
265 def ConstStringSummaryProvider(valobj, internal_dict):
266 if valobj.GetNumChildren() == 1:
267 return valobj.GetChildAtIndex(0).GetSummary()
268 return ""
271 def get_expression_path(val):
272 stream = lldb.SBStream()
273 if not val.GetExpressionPath(stream):
274 return None
275 return stream.GetData()
278 class PointerIntPairSynthProvider:
279 def __init__(self, valobj, internal_dict):
280 self.valobj = valobj
281 self.update()
283 def num_children(self):
284 return 2
286 def get_child_index(self, name):
287 if name == "Pointer":
288 return 0
289 if name == "Int":
290 return 1
291 return None
293 def get_child_at_index(self, index):
294 expr_path = get_expression_path(self.valobj)
295 if index == 0:
296 return self.valobj.CreateValueFromExpression(
297 "Pointer", f"({self.pointer_ty.name}){expr_path}.getPointer()"
299 if index == 1:
300 return self.valobj.CreateValueFromExpression(
301 "Int", f"({self.int_ty.name}){expr_path}.getInt()"
303 return None
305 def update(self):
306 self.pointer_ty = self.valobj.GetType().GetTemplateArgumentType(0)
307 self.int_ty = self.valobj.GetType().GetTemplateArgumentType(2)
310 def parse_template_parameters(typename):
312 LLDB doesn't support template parameter packs, so let's parse them manually.
314 result = []
315 start = typename.find("<")
316 end = typename.rfind(">")
317 if start < 1 or end < 2 or end - start < 2:
318 return result
320 nesting_level = 0
321 current_parameter_start = start + 1
323 for i in range(start + 1, end + 1):
324 c = typename[i]
325 if c == "<":
326 nesting_level += 1
327 elif c == ">":
328 nesting_level -= 1
329 elif c == "," and nesting_level == 0:
330 result.append(typename[current_parameter_start:i].strip())
331 current_parameter_start = i + 1
333 result.append(typename[current_parameter_start:i].strip())
335 return result
338 class PointerUnionSynthProvider:
339 def __init__(self, valobj, internal_dict):
340 self.valobj = valobj
341 self.update()
343 def num_children(self):
344 return 1
346 def get_child_index(self, name):
347 if name == "Ptr":
348 return 0
349 return None
351 def get_child_at_index(self, index):
352 if index != 0:
353 return None
354 ptr_type_name = self.template_args[self.active_type_tag]
355 return self.valobj.CreateValueFromExpression(
356 "Ptr", f"({ptr_type_name}){self.val_expr_path}.getPointer()"
359 def update(self):
360 self.pointer_int_pair = self.valobj.GetChildMemberWithName("Val")
361 self.val_expr_path = get_expression_path(
362 self.valobj.GetChildMemberWithName("Val")
364 self.active_type_tag = self.valobj.CreateValueFromExpression(
365 "", f"(int){self.val_expr_path}.getInt()"
366 ).GetValueAsSigned()
367 self.template_args = parse_template_parameters(self.valobj.GetType().name)
370 def DenseMapSummary(valobj: lldb.SBValue, _) -> str:
371 raw_value = valobj.GetNonSyntheticValue()
372 num_entries = raw_value.GetChildMemberWithName("NumEntries").unsigned
373 num_tombstones = raw_value.GetChildMemberWithName("NumTombstones").unsigned
375 summary = f"size={num_entries}"
376 if num_tombstones == 1:
377 # The heuristic to identify valid entries does not handle the case of a
378 # single tombstone. The summary calls attention to this.
379 summary = f"tombstones=1, {summary}"
380 return summary
383 class DenseMapSynthetic:
384 valobj: lldb.SBValue
386 # The indexes into `Buckets` that contain valid map entries.
387 child_buckets: list[int]
389 def __init__(self, valobj: lldb.SBValue, _) -> None:
390 self.valobj = valobj
392 def num_children(self) -> int:
393 return len(self.child_buckets)
395 def get_child_at_index(self, child_index: int) -> lldb.SBValue:
396 bucket_index = self.child_buckets[child_index]
397 entry = self.valobj.GetValueForExpressionPath(f".Buckets[{bucket_index}]")
399 # By default, DenseMap instances use DenseMapPair to hold key-value
400 # entries. When the entry is a DenseMapPair, unwrap it to expose the
401 # children as simple std::pair values.
403 # This entry type is customizable (a template parameter). For other
404 # types, expose the entry type as is.
405 if entry.type.name.startswith("llvm::detail::DenseMapPair<"):
406 entry = entry.GetChildAtIndex(0)
408 return entry.Clone(f"[{child_index}]")
410 def update(self):
411 self.child_buckets = []
413 num_entries = self.valobj.GetChildMemberWithName("NumEntries").unsigned
414 if num_entries == 0:
415 return
417 buckets = self.valobj.GetChildMemberWithName("Buckets")
418 num_buckets = self.valobj.GetChildMemberWithName("NumBuckets").unsigned
420 # Bucket entries contain one of the following:
421 # 1. Valid key-value
422 # 2. Empty key
423 # 3. Tombstone key (a deleted entry)
425 # NumBuckets is always greater than NumEntries. The empty key, and
426 # potentially the tombstone key, will occur multiple times. A key that
427 # is repeated is either the empty key or the tombstone key.
429 # For each key, collect a list of buckets it appears in.
430 key_buckets: dict[str, list[int]] = collections.defaultdict(list)
431 for index in range(num_buckets):
432 key = buckets.GetValueForExpressionPath(f"[{index}].first")
433 key_buckets[str(key.data)].append(index)
435 # Heuristic: This is not a multi-map, any repeated (non-unique) keys are
436 # either the the empty key or the tombstone key. Populate child_buckets
437 # with the indexes of entries containing unique keys.
438 for indexes in key_buckets.values():
439 if len(indexes) == 1:
440 self.child_buckets.append(indexes[0])
443 class ExpectedSynthetic:
444 # The llvm::Expected<T> value.
445 expected: lldb.SBValue
446 # The stored success value or error value.
447 stored_value: lldb.SBValue
449 def __init__(self, valobj: lldb.SBValue, _) -> None:
450 self.expected = valobj
452 def update(self) -> None:
453 has_error = self.expected.GetChildMemberWithName("HasError").unsigned
454 if not has_error:
455 name = "value"
456 member = "TStorage"
457 else:
458 name = "error"
459 member = "ErrorStorage"
460 # Anonymous union.
461 union = self.expected.child[0]
462 storage = union.GetChildMemberWithName(member)
463 stored_type = storage.type.template_args[0]
464 self.stored_value = storage.Cast(stored_type).Clone(name)
466 def num_children(self) -> int:
467 return 1
469 def get_child_index(self, name: str) -> int:
470 if name == self.stored_value.name:
471 return 0
472 # Allow dereferencing for values, not errors.
473 if name == "$$dereference$$" and self.stored_value.name == "value":
474 return 0
475 return -1
477 def get_child_at_index(self, idx: int) -> lldb.SBValue:
478 if idx == 0:
479 return self.stored_value
480 return lldb.SBValue()