blob: becf168f42b521eb50acbd4e5d42fd3ec88fba06 [file] [log] [blame]
Enrico Granata217f91f2011-08-17 19:07:52 +00001import re
Enrico Granata85ce21c2012-04-25 16:32:39 +00002import lldb.formatters.Logger
Enrico Granata217f91f2011-08-17 19:07:52 +00003
4# C++ STL formatters for LLDB
Enrico Granata5a61fc0d2011-08-22 16:10:25 +00005# These formatters are based upon the version of the GNU libstdc++
Enrico Granata114bb192012-08-27 17:42:50 +00006# as it ships with Mac OS X 10.6.8 thru 10.8.0
Enrico Granata5a61fc0d2011-08-22 16:10:25 +00007# You are encouraged to look at the STL implementation for your platform
8# before relying on these formatters to do the right thing for your setup
Enrico Granata217f91f2011-08-17 19:07:52 +00009
Kate Stoneb9c1b512016-09-06 20:57:50 +000010
Enrico Granata217f91f2011-08-17 19:07:52 +000011class StdListSynthProvider:
12
Kate Stoneb9c1b512016-09-06 20:57:50 +000013 def __init__(self, valobj, dict):
14 logger = lldb.formatters.Logger.Logger()
15 self.valobj = valobj
16 self.count = None
17 logger >> "Providing synthetic children for a list named " + \
18 str(valobj.GetName())
Enrico Granata217f91f2011-08-17 19:07:52 +000019
Kate Stoneb9c1b512016-09-06 20:57:50 +000020 def next_node(self, node):
21 logger = lldb.formatters.Logger.Logger()
22 return node.GetChildMemberWithName('_M_next')
Enrico Granata9d60f602012-03-09 03:09:58 +000023
Kate Stoneb9c1b512016-09-06 20:57:50 +000024 def is_valid(self, node):
25 logger = lldb.formatters.Logger.Logger()
26 valid = self.value(self.next_node(node)) != self.node_address
27 if valid:
28 logger >> "%s is valid" % str(self.valobj.GetName())
29 else:
30 logger >> "synthetic value is not valid"
31 return valid
Enrico Granata9d60f602012-03-09 03:09:58 +000032
Kate Stoneb9c1b512016-09-06 20:57:50 +000033 def value(self, node):
34 logger = lldb.formatters.Logger.Logger()
35 value = node.GetValueAsUnsigned()
36 logger >> "synthetic value for {}: {}".format(
37 str(self.valobj.GetName()), value)
38 return value
Enrico Granata9d60f602012-03-09 03:09:58 +000039
Kate Stoneb9c1b512016-09-06 20:57:50 +000040 # Floyd's cycle-finding algorithm
41 # try to detect if this list has a loop
42 def has_loop(self):
43 global _list_uses_loop_detector
44 logger = lldb.formatters.Logger.Logger()
45 if not _list_uses_loop_detector:
46 logger >> "Asked not to use loop detection"
47 return False
48 slow = self.next
49 fast1 = self.next
50 fast2 = self.next
51 while self.is_valid(slow):
52 slow_value = self.value(slow)
53 fast1 = self.next_node(fast2)
54 fast2 = self.next_node(fast1)
55 if self.value(fast1) == slow_value or self.value(
56 fast2) == slow_value:
57 return True
58 slow = self.next_node(slow)
59 return False
Enrico Granata9d60f602012-03-09 03:09:58 +000060
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 def num_children(self):
62 logger = lldb.formatters.Logger.Logger()
63 if self.count is None:
64 # libstdc++ 6.0.21 added dedicated count field.
65 count_child = self.node.GetChildMemberWithName('_M_data')
66 if count_child and count_child.IsValid():
67 self.count = count_child.GetValueAsUnsigned(0)
68 if self.count is None:
69 self.count = self.num_children_impl()
70 return self.count
Enrico Granata9d60f602012-03-09 03:09:58 +000071
Kate Stoneb9c1b512016-09-06 20:57:50 +000072 def num_children_impl(self):
73 logger = lldb.formatters.Logger.Logger()
74 try:
75 next_val = self.next.GetValueAsUnsigned(0)
76 prev_val = self.prev.GetValueAsUnsigned(0)
77 # After a std::list has been initialized, both next and prev will
78 # be non-NULL
79 if next_val == 0 or prev_val == 0:
80 return 0
81 if next_val == self.node_address:
82 return 0
83 if next_val == prev_val:
84 return 1
85 if self.has_loop():
86 return 0
87 size = 2
88 current = self.next
89 while current.GetChildMemberWithName(
90 '_M_next').GetValueAsUnsigned(0) != self.node_address:
91 size = size + 1
92 current = current.GetChildMemberWithName('_M_next')
93 return (size - 1)
94 except:
95 return 0
Enrico Granata217f91f2011-08-17 19:07:52 +000096
Kate Stoneb9c1b512016-09-06 20:57:50 +000097 def get_child_index(self, name):
98 logger = lldb.formatters.Logger.Logger()
99 try:
100 return int(name.lstrip('[').rstrip(']'))
101 except:
102 return -1
Enrico Granata217f91f2011-08-17 19:07:52 +0000103
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104 def get_child_at_index(self, index):
105 logger = lldb.formatters.Logger.Logger()
106 logger >> "Fetching child " + str(index)
107 if index < 0:
108 return None
109 if index >= self.num_children():
110 return None
111 try:
112 offset = index
113 current = self.next
114 while offset > 0:
115 current = current.GetChildMemberWithName('_M_next')
116 offset = offset - 1
117 return current.CreateChildAtOffset(
118 '[' + str(index) + ']',
119 2 * current.GetType().GetByteSize(),
120 self.data_type)
121 except:
122 return None
Enrico Granata217f91f2011-08-17 19:07:52 +0000123
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124 def extract_type(self):
125 logger = lldb.formatters.Logger.Logger()
126 list_type = self.valobj.GetType().GetUnqualifiedType()
127 if list_type.IsReferenceType():
128 list_type = list_type.GetDereferencedType()
129 if list_type.GetNumberOfTemplateArguments() > 0:
130 data_type = list_type.GetTemplateArgumentType(0)
131 else:
132 data_type = None
133 return data_type
Enrico Granata217f91f2011-08-17 19:07:52 +0000134
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 def update(self):
136 logger = lldb.formatters.Logger.Logger()
137 # preemptively setting this to None - we might end up changing our mind
138 # later
139 self.count = None
140 try:
141 impl = self.valobj.GetChildMemberWithName('_M_impl')
142 self.node = impl.GetChildMemberWithName('_M_node')
143 self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
144 self.next = self.node.GetChildMemberWithName('_M_next')
145 self.prev = self.node.GetChildMemberWithName('_M_prev')
146 self.data_type = self.extract_type()
147 self.data_size = self.data_type.GetByteSize()
148 except:
149 pass
Enrico Granata217f91f2011-08-17 19:07:52 +0000150
Kate Stoneb9c1b512016-09-06 20:57:50 +0000151 def has_children(self):
152 return True
153
Enrico Granata91fe0172012-10-23 21:54:53 +0000154
Enrico Granata217f91f2011-08-17 19:07:52 +0000155class StdVectorSynthProvider:
156
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157 class StdVectorImplementation(object):
Siva Chandra8d88d082015-03-17 21:23:17 +0000158
Kate Stoneb9c1b512016-09-06 20:57:50 +0000159 def __init__(self, valobj):
160 self.valobj = valobj
161 self.count = None
Siva Chandra8d88d082015-03-17 21:23:17 +0000162
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163 def num_children(self):
164 if self.count is None:
165 self.count = self.num_children_impl()
166 return self.count
Siva Chandra8d88d082015-03-17 21:23:17 +0000167
Kate Stoneb9c1b512016-09-06 20:57:50 +0000168 def num_children_impl(self):
169 try:
170 start_val = self.start.GetValueAsUnsigned(0)
171 finish_val = self.finish.GetValueAsUnsigned(0)
172 end_val = self.end.GetValueAsUnsigned(0)
173 # Before a vector has been constructed, it will contain bad values
174 # so we really need to be careful about the length we return since
175 # uninitialized data can cause us to return a huge number. We need
176 # to also check for any of the start, finish or end of storage values
177 # being zero (NULL). If any are, then this vector has not been
178 # initialized yet and we should return zero
Siva Chandra8d88d082015-03-17 21:23:17 +0000179
Kate Stoneb9c1b512016-09-06 20:57:50 +0000180 # Make sure nothing is NULL
181 if start_val == 0 or finish_val == 0 or end_val == 0:
182 return 0
183 # Make sure start is less than finish
184 if start_val >= finish_val:
185 return 0
186 # Make sure finish is less than or equal to end of storage
187 if finish_val > end_val:
188 return 0
Siva Chandra8d88d082015-03-17 21:23:17 +0000189
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 # if we have a struct (or other data type that the compiler pads to native word size)
191 # this check might fail, unless the sizeof() we get is itself incremented to take the
192 # padding bytes into account - on current clang it looks like
193 # this is the case
194 num_children = (finish_val - start_val)
195 if (num_children % self.data_size) != 0:
196 return 0
197 else:
198 num_children = num_children / self.data_size
199 return num_children
200 except:
201 return 0
Siva Chandra8d88d082015-03-17 21:23:17 +0000202
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 def get_child_at_index(self, index):
204 logger = lldb.formatters.Logger.Logger()
205 logger >> "Retrieving child " + str(index)
206 if index < 0:
207 return None
208 if index >= self.num_children():
209 return None
210 try:
211 offset = index * self.data_size
212 return self.start.CreateChildAtOffset(
213 '[' + str(index) + ']', offset, self.data_type)
214 except:
215 return None
Siva Chandra8d88d082015-03-17 21:23:17 +0000216
Kate Stoneb9c1b512016-09-06 20:57:50 +0000217 def update(self):
218 # preemptively setting this to None - we might end up changing our
219 # mind later
220 self.count = None
221 try:
222 impl = self.valobj.GetChildMemberWithName('_M_impl')
223 self.start = impl.GetChildMemberWithName('_M_start')
224 self.finish = impl.GetChildMemberWithName('_M_finish')
225 self.end = impl.GetChildMemberWithName('_M_end_of_storage')
226 self.data_type = self.start.GetType().GetPointeeType()
227 self.data_size = self.data_type.GetByteSize()
228 # if any of these objects is invalid, it means there is no
229 # point in trying to fetch anything
230 if self.start.IsValid() and self.finish.IsValid(
231 ) and self.end.IsValid() and self.data_type.IsValid():
232 self.count = None
233 else:
234 self.count = 0
235 except:
236 pass
237 return True
Siva Chandra8d88d082015-03-17 21:23:17 +0000238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 class StdVBoolImplementation(object):
Siva Chandra8d88d082015-03-17 21:23:17 +0000240
Kate Stoneb9c1b512016-09-06 20:57:50 +0000241 def __init__(self, valobj, bool_type):
242 self.valobj = valobj
243 self.bool_type = bool_type
244 self.valid = False
Siva Chandra8d88d082015-03-17 21:23:17 +0000245
Kate Stoneb9c1b512016-09-06 20:57:50 +0000246 def num_children(self):
247 if self.valid:
248 start = self.start_p.GetValueAsUnsigned(0)
249 finish = self.finish_p.GetValueAsUnsigned(0)
250 offset = self.offset.GetValueAsUnsigned(0)
251 if finish >= start:
252 return (finish - start) * 8 + offset
253 return 0
Siva Chandra8d88d082015-03-17 21:23:17 +0000254
Kate Stoneb9c1b512016-09-06 20:57:50 +0000255 def get_child_at_index(self, index):
256 if index >= self.num_children():
257 return None
258 element_type = self.start_p.GetType().GetPointeeType()
259 element_bits = 8 * element_type.GetByteSize()
260 element_offset = (index / element_bits) * \
261 element_type.GetByteSize()
262 bit_offset = index % element_bits
263 element = self.start_p.CreateChildAtOffset(
264 '[' + str(index) + ']', element_offset, element_type)
265 bit = element.GetValueAsUnsigned(0) & (1 << bit_offset)
266 if bit != 0:
267 value_expr = "(bool)true"
268 else:
269 value_expr = "(bool)false"
270 return self.valobj.CreateValueFromExpression(
271 "[%d]" % index, value_expr)
Enrico Granata217f91f2011-08-17 19:07:52 +0000272
Kate Stoneb9c1b512016-09-06 20:57:50 +0000273 def update(self):
274 try:
275 m_impl = self.valobj.GetChildMemberWithName('_M_impl')
276 self.m_start = m_impl.GetChildMemberWithName('_M_start')
277 self.m_finish = m_impl.GetChildMemberWithName('_M_finish')
278 self.start_p = self.m_start.GetChildMemberWithName('_M_p')
279 self.finish_p = self.m_finish.GetChildMemberWithName('_M_p')
280 self.offset = self.m_finish.GetChildMemberWithName('_M_offset')
281 self.valid = True
282 except:
283 self.valid = False
284 return True
Enrico Granata217f91f2011-08-17 19:07:52 +0000285
Kate Stoneb9c1b512016-09-06 20:57:50 +0000286 def __init__(self, valobj, dict):
287 logger = lldb.formatters.Logger.Logger()
288 first_template_arg_type = valobj.GetType().GetTemplateArgumentType(0)
289 if str(first_template_arg_type.GetName()) == "bool":
290 self.impl = self.StdVBoolImplementation(
291 valobj, first_template_arg_type)
292 else:
293 self.impl = self.StdVectorImplementation(valobj)
294 logger >> "Providing synthetic children for a vector named " + \
295 str(valobj.GetName())
Enrico Granata217f91f2011-08-17 19:07:52 +0000296
Kate Stoneb9c1b512016-09-06 20:57:50 +0000297 def num_children(self):
298 return self.impl.num_children()
Enrico Granata217f91f2011-08-17 19:07:52 +0000299
Kate Stoneb9c1b512016-09-06 20:57:50 +0000300 def get_child_index(self, name):
301 try:
302 return int(name.lstrip('[').rstrip(']'))
303 except:
304 return -1
Enrico Granata91fe0172012-10-23 21:54:53 +0000305
Kate Stoneb9c1b512016-09-06 20:57:50 +0000306 def get_child_at_index(self, index):
307 return self.impl.get_child_at_index(index)
308
309 def update(self):
310 return self.impl.update()
311
312 def has_children(self):
313 return True
Enrico Granata217f91f2011-08-17 19:07:52 +0000314
315
316class StdMapSynthProvider:
317
Kate Stoneb9c1b512016-09-06 20:57:50 +0000318 def __init__(self, valobj, dict):
319 logger = lldb.formatters.Logger.Logger()
320 self.valobj = valobj
321 self.count = None
322 logger >> "Providing synthetic children for a map named " + \
323 str(valobj.GetName())
Enrico Granata217f91f2011-08-17 19:07:52 +0000324
Kate Stoneb9c1b512016-09-06 20:57:50 +0000325 # we need this function as a temporary workaround for rdar://problem/10801549
326 # which prevents us from extracting the std::pair<K,V> SBType out of the template
327 # arguments for _Rep_Type _M_t in the map itself - because we have to make up the
328 # typename and then find it, we may hit the situation were std::string has multiple
329 # names but only one is actually referenced in the debug information. hence, we need
330 # to replace the longer versions of std::string with the shorter one in order to be able
331 # to find the type name
332 def fixup_class_name(self, class_name):
333 logger = lldb.formatters.Logger.Logger()
334 if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
335 return 'std::basic_string<char>', True
336 if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
337 return 'std::basic_string<char>', True
338 if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
339 return 'std::basic_string<char>', True
340 if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
341 return 'std::basic_string<char>', True
342 return class_name, False
Siva Chandra05fd66d2015-03-18 22:01:45 +0000343
Kate Stoneb9c1b512016-09-06 20:57:50 +0000344 def update(self):
345 logger = lldb.formatters.Logger.Logger()
346 # preemptively setting this to None - we might end up changing our mind
347 # later
348 self.count = None
349 try:
350 # we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree
351 # if this gets set to True, then we will merrily return None for
352 # any child from that moment on
353 self.garbage = False
354 self.Mt = self.valobj.GetChildMemberWithName('_M_t')
355 self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl')
356 self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header')
Enrico Granata217f91f2011-08-17 19:07:52 +0000357
Kate Stoneb9c1b512016-09-06 20:57:50 +0000358 map_type = self.valobj.GetType()
359 if map_type.IsReferenceType():
360 logger >> "Dereferencing type"
361 map_type = map_type.GetDereferencedType()
Enrico Granatad50f18b2012-03-29 19:29:45 +0000362
Kate Stoneb9c1b512016-09-06 20:57:50 +0000363 # Get the type of std::pair<key, value>. It is the first template
364 # argument type of the 4th template argument to std::map.
365 allocator_type = map_type.GetTemplateArgumentType(3)
366 self.data_type = allocator_type.GetTemplateArgumentType(0)
367 if not self.data_type:
368 # GCC does not emit DW_TAG_template_type_parameter for
369 # std::allocator<...>. For such a case, get the type of
370 # std::pair from a member of std::map.
371 rep_type = self.valobj.GetChildMemberWithName('_M_t').GetType()
372 self.data_type = rep_type.GetTypedefedType().GetTemplateArgumentType(1)
Enrico Granata217f91f2011-08-17 19:07:52 +0000373
Kate Stoneb9c1b512016-09-06 20:57:50 +0000374 # from libstdc++ implementation of _M_root for rbtree
375 self.Mroot = self.Mheader.GetChildMemberWithName('_M_parent')
376 self.data_size = self.data_type.GetByteSize()
377 self.skip_size = self.Mheader.GetType().GetByteSize()
378 except:
379 pass
Enrico Granata217f91f2011-08-17 19:07:52 +0000380
Kate Stoneb9c1b512016-09-06 20:57:50 +0000381 def num_children(self):
382 logger = lldb.formatters.Logger.Logger()
383 if self.count is None:
384 self.count = self.num_children_impl()
385 return self.count
Enrico Granata217f91f2011-08-17 19:07:52 +0000386
Kate Stoneb9c1b512016-09-06 20:57:50 +0000387 def num_children_impl(self):
388 logger = lldb.formatters.Logger.Logger()
389 try:
390 root_ptr_val = self.node_ptr_value(self.Mroot)
391 if root_ptr_val == 0:
392 return 0
393 count = self.Mimpl.GetChildMemberWithName(
394 '_M_node_count').GetValueAsUnsigned(0)
395 logger >> "I have " + str(count) + " children available"
396 return count
397 except:
398 return 0
Enrico Granata217f91f2011-08-17 19:07:52 +0000399
Kate Stoneb9c1b512016-09-06 20:57:50 +0000400 def get_child_index(self, name):
401 logger = lldb.formatters.Logger.Logger()
402 try:
403 return int(name.lstrip('[').rstrip(']'))
404 except:
405 return -1
Enrico Granata217f91f2011-08-17 19:07:52 +0000406
Kate Stoneb9c1b512016-09-06 20:57:50 +0000407 def get_child_at_index(self, index):
408 logger = lldb.formatters.Logger.Logger()
409 logger >> "Being asked to fetch child[" + str(index) + "]"
410 if index < 0:
411 return None
412 if index >= self.num_children():
413 return None
414 if self.garbage:
415 logger >> "Returning None since we are a garbage tree"
416 return None
417 try:
418 offset = index
419 current = self.left(self.Mheader)
420 while offset > 0:
421 current = self.increment_node(current)
422 offset = offset - 1
423 # skip all the base stuff and get at the data
424 return current.CreateChildAtOffset(
425 '[' + str(index) + ']', self.skip_size, self.data_type)
426 except:
427 return None
Enrico Granata217f91f2011-08-17 19:07:52 +0000428
Kate Stoneb9c1b512016-09-06 20:57:50 +0000429 # utility functions
430 def node_ptr_value(self, node):
431 logger = lldb.formatters.Logger.Logger()
432 return node.GetValueAsUnsigned(0)
Enrico Granata217f91f2011-08-17 19:07:52 +0000433
Kate Stoneb9c1b512016-09-06 20:57:50 +0000434 def right(self, node):
435 logger = lldb.formatters.Logger.Logger()
436 return node.GetChildMemberWithName("_M_right")
Enrico Granata217f91f2011-08-17 19:07:52 +0000437
Kate Stoneb9c1b512016-09-06 20:57:50 +0000438 def left(self, node):
439 logger = lldb.formatters.Logger.Logger()
440 return node.GetChildMemberWithName("_M_left")
441
442 def parent(self, node):
443 logger = lldb.formatters.Logger.Logger()
444 return node.GetChildMemberWithName("_M_parent")
445
446 # from libstdc++ implementation of iterator for rbtree
447 def increment_node(self, node):
448 logger = lldb.formatters.Logger.Logger()
449 max_steps = self.num_children()
450 if self.node_ptr_value(self.right(node)) != 0:
451 x = self.right(node)
452 max_steps -= 1
453 while self.node_ptr_value(self.left(x)) != 0:
454 x = self.left(x)
455 max_steps -= 1
456 logger >> str(max_steps) + " more to go before giving up"
457 if max_steps <= 0:
458 self.garbage = True
459 return None
460 return x
461 else:
462 x = node
463 y = self.parent(x)
464 max_steps -= 1
465 while(self.node_ptr_value(x) == self.node_ptr_value(self.right(y))):
466 x = y
467 y = self.parent(y)
468 max_steps -= 1
469 logger >> str(max_steps) + " more to go before giving up"
470 if max_steps <= 0:
471 self.garbage = True
472 return None
473 if self.node_ptr_value(self.right(x)) != self.node_ptr_value(y):
474 x = y
475 return x
476
477 def has_children(self):
478 return True
Enrico Granatad50f18b2012-03-29 19:29:45 +0000479
Enrico Granatad50f18b2012-03-29 19:29:45 +0000480_list_uses_loop_detector = True