Package lldb :: Package formatters :: Package cpp :: Module gnu_libstdcpp
[hide private]
[frames] | no frames]

Source Code for Module lldb.formatters.cpp.gnu_libstdcpp

  1  import re 
  2  import lldb.formatters.Logger 
  3   
  4  # C++ STL formatters for LLDB 
  5  # These formatters are based upon the version of the GNU libstdc++ 
  6  # as it ships with Mac OS X 10.6.8 thru 10.8.0 
  7  # 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 
  9   
 10   
11 -class StdListSynthProvider:
12
13 - 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())
19
20 - def next_node(self, node):
21 logger = lldb.formatters.Logger.Logger() 22 return node.GetChildMemberWithName('_M_next')
23
24 - 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
32
33 - 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
39 40 # 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
60
61 - 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
71
72 - 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
96
97 - 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
103
104 - 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
123
124 - 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
134
135 - 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
150
151 - def has_children(self):
152 return True
153 154
155 -class StdVectorSynthProvider:
156
157 - class StdVectorImplementation(object):
158
159 - def __init__(self, valobj):
160 self.valobj = valobj 161 self.count = None
162
163 - def num_children(self):
164 if self.count is None: 165 self.count = self.num_children_impl() 166 return self.count
167
168 - 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 179 180 # 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 189 190 # 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
202
203 - 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
216
217 - 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
238
239 - class StdVBoolImplementation(object):
240
241 - def __init__(self, valobj, bool_type):
242 self.valobj = valobj 243 self.bool_type = bool_type 244 self.valid = False
245
246 - 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
254
255 - 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)
272
273 - 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
285
286 - 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())
296
297 - def num_children(self):
298 return self.impl.num_children()
299
300 - def get_child_index(self, name):
301 try: 302 return int(name.lstrip('[').rstrip(']')) 303 except: 304 return -1
305
306 - 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
314 315
316 -class StdMapSynthProvider:
317
318 - 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())
324 325 # 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
343
344 - 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') 357 358 map_type = self.valobj.GetType() 359 if map_type.IsReferenceType(): 360 logger >> "Dereferencing type" 361 map_type = map_type.GetDereferencedType() 362 363 # 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) 373 374 # 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
380
381 - 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
386
387 - 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
399
400 - 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
406
407 - 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
428 429 # utility functions
430 - def node_ptr_value(self, node):
431 logger = lldb.formatters.Logger.Logger() 432 return node.GetValueAsUnsigned(0)
433
434 - def right(self, node):
435 logger = lldb.formatters.Logger.Logger() 436 return node.GetChildMemberWithName("_M_right")
437
438 - 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
479 480 _list_uses_loop_detector = True 481