2 LLDB Formatters for LLVM data types.
4 Load into LLDB with 'command script import /path/to/lldbDataFormatters.py'
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
):
57 self
.update() # initialize this provider
59 def num_children(self
):
60 return self
.size
.GetValueAsUnsigned(0)
62 def get_child_index(self
, name
):
64 return int(name
.lstrip('[').rstrip(']'))
68 def get_child_at_index(self
, index
):
72 if index
>= self
.num_children():
75 offset
= index
* self
.type_size
76 return self
.begin
.CreateChildAtOffset('['+str(index
)+']',
77 offset
, self
.data_type
)
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
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
):
96 self
.update() # initialize this provider
98 def num_children(self
):
101 def get_child_index(self
, name
):
103 return int(name
.lstrip('[').rstrip(']'))
107 def get_child_at_index(self
, index
):
108 if index
< 0 or index
>= self
.num_children():
110 offset
= index
* self
.type_size
111 return self
.data
.CreateChildAtOffset('[' + str(index
) + ']',
112 offset
, self
.data_type
)
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')
128 hasVal
= storage
.GetChildMemberWithName('hasVal').GetValueAsUnsigned(failure
)
129 if hasVal
== failure
:
130 return '<could not read llvm::Optional>'
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
)
147 class OptionalSynthProvider
:
148 """Provides deref support to llvm::Optional<T>"""
149 def __init__(self
, valobj
, internal_dict
):
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()
168 for i
in range(0, num_elements
):
169 c
= valobj
.GetChildAtIndex(i
).GetValue()
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.
181 actual_length
= valobj
.GetChildAtIndex(1).GetValueAsUnsigned()
182 truncate
= actual_length
> max_length
183 length
= min(max_length
, actual_length
)
187 data
= valobj
.GetChildAtIndex(0).GetPointeeData(item_count
=length
)
188 error
= lldb
.SBError()
189 string
= data
.ReadRawData(error
, 0, data
.GetByteSize()).decode()
191 return "<error: %s>" % error
.description
193 # json.dumps conveniently escapes the string for us.
194 string
= json
.dumps(string
)
201 def ConstStringSummaryProvider(valobj
, internal_dict
):
202 if valobj
.GetNumChildren() == 1:
203 return valobj
.GetChildAtIndex(0).GetSummary()
207 def get_expression_path(val
):
208 stream
= lldb
.SBStream()
209 if not val
.GetExpressionPath(stream
):
211 return stream
.GetData()
214 class PointerIntPairSynthProvider
:
215 def __init__(self
, valobj
, internal_dict
):
219 def num_children(self
):
222 def get_child_index(self
, name
):
223 if name
== 'Pointer':
229 def get_child_at_index(self
, index
):
230 expr_path
= get_expression_path(self
.valobj
)
232 return self
.valobj
.CreateValueFromExpression('Pointer', f
'({self.pointer_ty.name}){expr_path}.getPointer()')
234 return self
.valobj
.CreateValueFromExpression('Int', f
'({self.int_ty.name}){expr_path}.getInt()')
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.
247 start
= typename
.find('<')
248 end
= typename
.rfind('>')
249 if start
< 1 or end
< 2 or end
- start
< 2:
253 current_parameter_start
= start
+ 1
255 for i
in range(start
+ 1, end
+ 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())
270 class PointerUnionSynthProvider
:
271 def __init__(self
, valobj
, internal_dict
):
275 def num_children(self
):
278 def get_child_index(self
, name
):
283 def get_child_at_index(self
, index
):
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()')
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
)