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

Source Code for Module lldb.formatters.cpp.libcxx

  1  import lldb 
  2  import lldb.formatters.Logger 
  3   
  4  # libcxx STL formatters for LLDB 
  5  # These formatters are based upon the implementation of libc++ that 
  6  # ships with current releases of OS X - They will not work for other implementations 
  7  # of the standard C++ library - and they are bound to use the libc++-specific namespace 
  8   
  9  # the std::string summary is just an example for your convenience 
 10  # the actual summary that LLDB uses is C++ code inside the debugger's own core 
 11   
 12  # this could probably be made more efficient but since it only reads a handful of bytes at a time 
 13  # we probably don't need to worry too much about this for the time being 
14 -def make_string(F,L):
15 strval = '' 16 G = F.GetData().uint8 17 for X in range(L): 18 V = G[X] 19 if V == 0: 20 break 21 strval = strval + chr(V % 256) 22 return '"' + strval + '"'
23 24 # if we ever care about big-endian, these two functions might need to change
25 -def is_short_string(value):
26 return True if (value & 1) == 0 else False
27 -def extract_short_size(value):
28 return ((value >> 1) % 256)
29 30 # some of the members of libc++ std::string are anonymous or have internal names that convey 31 # no external significance - we access them by index since this saves a name lookup that would add 32 # no information for readers of the code, but when possible try to use meaningful variable names
33 -def stdstring_SummaryProvider(valobj,dict):
34 logger = lldb.formatters.Logger.Logger() 35 r = valobj.GetChildAtIndex(0) 36 B = r.GetChildAtIndex(0) 37 first = B.GetChildAtIndex(0) 38 D = first.GetChildAtIndex(0) 39 l = D.GetChildAtIndex(0) 40 s = D.GetChildAtIndex(1) 41 D20 = s.GetChildAtIndex(0) 42 size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0) 43 if is_short_string(size_mode): 44 size = extract_short_size(size_mode) 45 return make_string(s.GetChildAtIndex(1),size) 46 else: 47 data_ptr = l.GetChildAtIndex(2) 48 size_vo = l.GetChildAtIndex(1) 49 size = size_vo.GetValueAsUnsigned(0)+1 # the NULL terminator must be accounted for 50 if size <= 1 or size == None: # should never be the case 51 return '""' 52 try: 53 data = data_ptr.GetPointeeData(0,size) 54 except: 55 return '""' 56 error = lldb.SBError() 57 strval = data.GetString(error,0) 58 if error.Fail(): 59 return '<error:' + error.GetCString() + '>' 60 else: 61 return '"' + strval + '"'
62
63 -class stdvector_SynthProvider:
64
65 - def __init__(self, valobj, dict):
66 logger = lldb.formatters.Logger.Logger() 67 self.valobj = valobj;
68
69 - def num_children(self):
70 logger = lldb.formatters.Logger.Logger() 71 try: 72 start_val = self.start.GetValueAsUnsigned(0) 73 finish_val = self.finish.GetValueAsUnsigned(0) 74 # Before a vector has been constructed, it will contain bad values 75 # so we really need to be careful about the length we return since 76 # unitialized data can cause us to return a huge number. We need 77 # to also check for any of the start, finish or end of storage values 78 # being zero (NULL). If any are, then this vector has not been 79 # initialized yet and we should return zero 80 81 # Make sure nothing is NULL 82 if start_val == 0 or finish_val == 0: 83 return 0 84 # Make sure start is less than finish 85 if start_val >= finish_val: 86 return 0 87 88 num_children = (finish_val-start_val) 89 if (num_children % self.data_size) != 0: 90 return 0 91 else: 92 num_children = num_children/self.data_size 93 return num_children 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 >> "Retrieving child " + str(index) 107 if index < 0: 108 return None; 109 if index >= self.num_children(): 110 return None; 111 try: 112 offset = index * self.data_size 113 return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type) 114 except: 115 return None
116
117 - def update(self):
118 logger = lldb.formatters.Logger.Logger() 119 try: 120 self.start = self.valobj.GetChildMemberWithName('__begin_') 121 self.finish = self.valobj.GetChildMemberWithName('__end_') 122 # the purpose of this field is unclear, but it is the only field whose type is clearly T* for a vector<T> 123 # if this ends up not being correct, we can use the APIs to get at template arguments 124 data_type_finder = self.valobj.GetChildMemberWithName('__end_cap_').GetChildMemberWithName('__first_') 125 self.data_type = data_type_finder.GetType().GetPointeeType() 126 self.data_size = self.data_type.GetByteSize() 127 except: 128 pass
129
130 - def has_children(self):
131 return True
132 133 # Just an example: the actual summary is produced by a summary string: size=${svar%#}
134 -def stdvector_SummaryProvider(valobj,dict):
135 prov = stdvector_SynthProvider(valobj,None) 136 return 'size=' + str(prov.num_children())
137
138 -class stdlist_entry:
139
140 - def __init__(self,entry):
141 logger = lldb.formatters.Logger.Logger() 142 self.entry = entry
143
144 - def _next_impl(self):
145 logger = lldb.formatters.Logger.Logger() 146 return stdlist_entry(self.entry.GetChildMemberWithName('__next_'))
147
148 - def _prev_impl(self):
149 logger = lldb.formatters.Logger.Logger() 150 return stdlist_entry(self.entry.GetChildMemberWithName('__prev_'))
151
152 - def _value_impl(self):
153 logger = lldb.formatters.Logger.Logger() 154 return self.entry.GetValueAsUnsigned(0)
155
156 - def _isnull_impl(self):
157 logger = lldb.formatters.Logger.Logger() 158 return self._value_impl() == 0
159
160 - def _sbvalue_impl(self):
161 logger = lldb.formatters.Logger.Logger() 162 return self.entry
163 164 next = property(_next_impl,None) 165 value = property(_value_impl,None) 166 is_null = property(_isnull_impl,None) 167 sbvalue = property(_sbvalue_impl,None)
168
169 -class stdlist_iterator:
170
171 - def increment_node(self,node):
172 logger = lldb.formatters.Logger.Logger() 173 if node.is_null: 174 return None 175 return node.next
176
177 - def __init__(self,node):
178 logger = lldb.formatters.Logger.Logger() 179 self.node = stdlist_entry(node) # we convert the SBValue to an internal node object on entry
180
181 - def value(self):
182 logger = lldb.formatters.Logger.Logger() 183 return self.node.sbvalue # and return the SBValue back on exit
184
185 - def next(self):
186 logger = lldb.formatters.Logger.Logger() 187 node = self.increment_node(self.node) 188 if node != None and node.sbvalue.IsValid() and not(node.is_null): 189 self.node = node 190 return self.value() 191 else: 192 return None
193
194 - def advance(self,N):
195 logger = lldb.formatters.Logger.Logger() 196 if N < 0: 197 return None 198 if N == 0: 199 return self.value() 200 if N == 1: 201 return self.next() 202 while N > 0: 203 self.next() 204 N = N - 1 205 return self.value()
206 207
208 -class stdlist_SynthProvider:
209 - def __init__(self, valobj, dict):
210 logger = lldb.formatters.Logger.Logger() 211 self.valobj = valobj 212 self.count = None
213
214 - def next_node(self,node):
215 logger = lldb.formatters.Logger.Logger() 216 return node.GetChildMemberWithName('__next_')
217
218 - def value(self,node):
219 logger = lldb.formatters.Logger.Logger() 220 return node.GetValueAsUnsigned()
221 222 # Floyd's cyle-finding algorithm 223 # try to detect if this list has a loop
224 - def has_loop(self):
225 global _list_uses_loop_detector 226 logger = lldb.formatters.Logger.Logger() 227 if _list_uses_loop_detector == False: 228 logger >> "Asked not to use loop detection" 229 return False 230 slow = stdlist_entry(self.head) 231 fast1 = stdlist_entry(self.head) 232 fast2 = stdlist_entry(self.head) 233 while slow.next.value != self.node_address: 234 slow_value = slow.value 235 fast1 = fast2.next 236 fast2 = fast1.next 237 if fast1.value == slow_value or fast2.value == slow_value: 238 return True 239 slow = slow.next 240 return False
241
242 - def num_children(self):
243 global _list_capping_size 244 logger = lldb.formatters.Logger.Logger() 245 if self.count == None: 246 self.count = self.num_children_impl() 247 if self.count > _list_capping_size: 248 self.count = _list_capping_size 249 return self.count
250
251 - def num_children_impl(self):
252 global _list_capping_size 253 logger = lldb.formatters.Logger.Logger() 254 try: 255 next_val = self.head.GetValueAsUnsigned(0) 256 prev_val = self.tail.GetValueAsUnsigned(0) 257 # After a std::list has been initialized, both next and prev will be non-NULL 258 if next_val == 0 or prev_val == 0: 259 return 0 260 if next_val == self.node_address: 261 return 0 262 if next_val == prev_val: 263 return 1 264 if self.has_loop(): 265 return 0 266 size = 2 267 current = stdlist_entry(self.head) 268 while current.next.value != self.node_address: 269 size = size + 1 270 current = current.next 271 if size > _list_capping_size: 272 return _list_capping_size 273 return (size - 1) 274 except: 275 return 0;
276
277 - def get_child_index(self,name):
278 logger = lldb.formatters.Logger.Logger() 279 try: 280 return int(name.lstrip('[').rstrip(']')) 281 except: 282 return -1
283
284 - def get_child_at_index(self,index):
285 logger = lldb.formatters.Logger.Logger() 286 logger >> "Fetching child " + str(index) 287 if index < 0: 288 return None; 289 if index >= self.num_children(): 290 return None; 291 try: 292 current = stdlist_iterator(self.head) 293 current = current.advance(index) 294 # we do not return __value_ because then all our children would be named __value_ 295 # we need to make a copy of __value__ with the right name - unfortunate 296 obj = current.GetChildMemberWithName('__value_') 297 obj_data = obj.GetData() 298 return self.valobj.CreateValueFromData('[' + str(index) + ']',obj_data,self.data_type) 299 except: 300 return None
301
302 - def extract_type(self):
303 logger = lldb.formatters.Logger.Logger() 304 list_type = self.valobj.GetType().GetUnqualifiedType() 305 if list_type.IsReferenceType(): 306 list_type = list_type.GetDereferencedType() 307 if list_type.GetNumberOfTemplateArguments() > 0: 308 data_type = list_type.GetTemplateArgumentType(0) 309 else: 310 data_type = None 311 return data_type
312
313 - def update(self):
314 logger = lldb.formatters.Logger.Logger() 315 self.count = None 316 try: 317 impl = self.valobj.GetChildMemberWithName('__end_') 318 self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) 319 self.head = impl.GetChildMemberWithName('__next_') 320 self.tail = impl.GetChildMemberWithName('__prev_') 321 self.data_type = self.extract_type() 322 self.data_size = self.data_type.GetByteSize() 323 except: 324 pass
325
326 - def has_children(self):
327 return True
328 329 330 # Just an example: the actual summary is produced by a summary string: size=${svar%#}
331 -def stdlist_SummaryProvider(valobj,dict):
332 prov = stdlist_SynthProvider(valobj,None) 333 return 'size=' + str(prov.num_children())
334 335 # a tree node - this class makes the syntax in the actual iterator nicer to read and maintain
336 -class stdmap_iterator_node:
337 - def _left_impl(self):
338 logger = lldb.formatters.Logger.Logger() 339 return stdmap_iterator_node(self.node.GetChildMemberWithName("__left_"))
340
341 - def _right_impl(self):
342 logger = lldb.formatters.Logger.Logger() 343 return stdmap_iterator_node(self.node.GetChildMemberWithName("__right_"))
344
345 - def _parent_impl(self):
346 logger = lldb.formatters.Logger.Logger() 347 return stdmap_iterator_node(self.node.GetChildMemberWithName("__parent_"))
348
349 - def _value_impl(self):
350 logger = lldb.formatters.Logger.Logger() 351 return self.node.GetValueAsUnsigned(0)
352
353 - def _sbvalue_impl(self):
354 logger = lldb.formatters.Logger.Logger() 355 return self.node
356
357 - def _null_impl(self):
358 logger = lldb.formatters.Logger.Logger() 359 return self.value == 0
360
361 - def __init__(self,node):
362 logger = lldb.formatters.Logger.Logger() 363 self.node = node
364 365 left = property(_left_impl,None) 366 right = property(_right_impl,None) 367 parent = property(_parent_impl,None) 368 value = property(_value_impl,None) 369 is_null = property(_null_impl,None) 370 sbvalue = property(_sbvalue_impl,None)
371 372 # a Python implementation of the tree iterator used by libc++
373 -class stdmap_iterator:
374
375 - def tree_min(self,x):
376 logger = lldb.formatters.Logger.Logger() 377 steps = 0 378 if x.is_null: 379 return None 380 while (not x.left.is_null): 381 x = x.left 382 steps += 1 383 if steps > self.max_count: 384 logger >> "Returning None - we overflowed" 385 return None 386 return x
387
388 - def tree_max(self,x):
389 logger = lldb.formatters.Logger.Logger() 390 if x.is_null: 391 return None 392 while (not x.right.is_null): 393 x = x.right 394 return x
395
396 - def tree_is_left_child(self,x):
397 logger = lldb.formatters.Logger.Logger() 398 if x.is_null: 399 return None 400 return True if x.value == x.parent.left.value else False
401
402 - def increment_node(self,node):
403 logger = lldb.formatters.Logger.Logger() 404 if node.is_null: 405 return None 406 if not node.right.is_null: 407 return self.tree_min(node.right) 408 steps = 0 409 while (not self.tree_is_left_child(node)): 410 steps += 1 411 if steps > self.max_count: 412 logger >> "Returning None - we overflowed" 413 return None 414 node = node.parent 415 return node.parent
416
417 - def __init__(self,node,max_count=0):
418 logger = lldb.formatters.Logger.Logger() 419 self.node = stdmap_iterator_node(node) # we convert the SBValue to an internal node object on entry 420 self.max_count = max_count
421
422 - def value(self):
423 logger = lldb.formatters.Logger.Logger() 424 return self.node.sbvalue # and return the SBValue back on exit
425
426 - def next(self):
427 logger = lldb.formatters.Logger.Logger() 428 node = self.increment_node(self.node) 429 if node != None and node.sbvalue.IsValid() and not(node.is_null): 430 self.node = node 431 return self.value() 432 else: 433 return None
434
435 - def advance(self,N):
436 logger = lldb.formatters.Logger.Logger() 437 if N < 0: 438 return None 439 if N == 0: 440 return self.value() 441 if N == 1: 442 return self.next() 443 while N > 0: 444 if self.next() == None: 445 return None 446 N = N - 1 447 return self.value()
448
449 -class stdmap_SynthProvider:
450
451 - def __init__(self, valobj, dict):
452 logger = lldb.formatters.Logger.Logger() 453 self.valobj = valobj; 454 self.pointer_size = self.valobj.GetProcess().GetAddressByteSize() 455 self.count = None
456
457 - def update(self):
458 logger = lldb.formatters.Logger.Logger() 459 self.count = None 460 try: 461 # 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 462 # if this gets set to True, then we will merrily return None for any child from that moment on 463 self.garbage = False 464 self.tree = self.valobj.GetChildMemberWithName('__tree_') 465 self.root_node = self.tree.GetChildMemberWithName('__begin_node_') 466 # this data is either lazily-calculated, or cannot be inferred at this moment 467 # we still need to mark it as None, meaning "please set me ASAP" 468 self.data_type = None 469 self.data_size = None 470 self.skip_size = None 471 except: 472 pass
473
474 - def num_children(self):
475 global _map_capping_size 476 logger = lldb.formatters.Logger.Logger() 477 if self.count == None: 478 self.count = self.num_children_impl() 479 if self.count > _map_capping_size: 480 self.count = _map_capping_size 481 return self.count
482
483 - def num_children_impl(self):
484 logger = lldb.formatters.Logger.Logger() 485 try: 486 return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName('__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned() 487 except: 488 return 0;
489
490 - def has_children(self):
491 return True
492
493 - def get_data_type(self):
494 logger = lldb.formatters.Logger.Logger() 495 if self.data_type == None or self.data_size == None: 496 if self.num_children() == 0: 497 return False 498 deref = self.root_node.Dereference() 499 if not(deref.IsValid()): 500 return False 501 value = deref.GetChildMemberWithName('__value_') 502 if not(value.IsValid()): 503 return False 504 self.data_type = value.GetType() 505 self.data_size = self.data_type.GetByteSize() 506 self.skip_size = None 507 return True 508 else: 509 return True
510
511 - def get_value_offset(self,node):
512 logger = lldb.formatters.Logger.Logger() 513 if self.skip_size == None: 514 node_type = node.GetType() 515 fields_count = node_type.GetNumberOfFields() 516 for i in range(fields_count): 517 field = node_type.GetFieldAtIndex(i) 518 if field.GetName() == '__value_': 519 self.skip_size = field.GetOffsetInBytes() 520 break 521 return (self.skip_size != None)
522
523 - def get_child_index(self,name):
524 logger = lldb.formatters.Logger.Logger() 525 try: 526 return int(name.lstrip('[').rstrip(']')) 527 except: 528 return -1
529
530 - def get_child_at_index(self,index):
531 logger = lldb.formatters.Logger.Logger() 532 logger >> "Retrieving child " + str(index) 533 if index < 0: 534 return None 535 if index >= self.num_children(): 536 return None; 537 if self.garbage: 538 logger >> "Returning None since this tree is garbage" 539 return None 540 try: 541 iterator = stdmap_iterator(self.root_node,max_count=self.num_children()) 542 # the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type 543 # out of which we can grab the information we need - every other node has a less informative 544 # type which omits all value information and only contains housekeeping information for the RB tree 545 # hence, we need to know if we are at a node != 0, so that we can still get at the data 546 need_to_skip = (index > 0) 547 current = iterator.advance(index) 548 if current == None: 549 logger >> "Tree is garbage - returning None" 550 self.garbage = True 551 return None 552 if self.get_data_type(): 553 if not(need_to_skip): 554 current = current.Dereference() 555 obj = current.GetChildMemberWithName('__value_') 556 obj_data = obj.GetData() 557 self.get_value_offset(current) # make sure we have a valid offset for the next items 558 # we do not return __value_ because then we would end up with a child named 559 # __value_ instead of [0] 560 return self.valobj.CreateValueFromData('[' + str(index) + ']',obj_data,self.data_type) 561 else: 562 # FIXME we need to have accessed item 0 before accessing any other item! 563 if self.skip_size == None: 564 logger >> "You asked for item > 0 before asking for item == 0, I will fetch 0 now then retry" 565 if self.get_child_at_index(0): 566 return self.get_child_at_index(index) 567 else: 568 logger >> "item == 0 could not be found. sorry, nothing can be done here." 569 return None 570 return current.CreateChildAtOffset('[' + str(index) + ']',self.skip_size,self.data_type) 571 else: 572 logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)" 573 return None 574 except Exception as err: 575 logger >> "Hit an exception: " + str(err) 576 return None
577 578 # Just an example: the actual summary is produced by a summary string: size=${svar%#}
579 -def stdmap_SummaryProvider(valobj,dict):
580 prov = stdmap_SynthProvider(valobj,None) 581 return 'size=' + str(prov.num_children())
582
583 -class stddeque_SynthProvider:
584 - def __init__(self, valobj, d):
585 logger = lldb.formatters.Logger.Logger() 586 logger.write("init") 587 self.valobj = valobj 588 self.pointer_size = self.valobj.GetProcess().GetAddressByteSize() 589 self.count = None 590 try: 591 self.find_block_size() 592 except: 593 self.block_size = -1 594 self.element_size = -1 595 logger.write("block_size=%d, element_size=%d" % (self.block_size, self.element_size))
596
597 - def find_block_size(self):
598 # in order to use the deque we must have the block size, or else 599 # it's impossible to know what memory addresses are valid 600 self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) 601 self.element_size = self.element_type.GetByteSize() 602 # The code says this, but there must be a better way: 603 # template <class _Tp, class _Allocator> 604 # class __deque_base { 605 # static const difference_type __block_size = sizeof(value_type) < 256 ? 4096 / sizeof(value_type) : 16; 606 # } 607 if self.element_size < 256: 608 self.block_size = 4096 / self.element_size 609 else: 610 self.block_size = 16
611
612 - def num_children(self):
613 global _deque_capping_size 614 logger = lldb.formatters.Logger.Logger() 615 if self.count is None: 616 return 0 617 return min(self.count, _deque_capping_size)
618
619 - def has_children(self):
620 return True
621
622 - def get_child_index(self,name):
623 logger = lldb.formatters.Logger.Logger() 624 try: 625 return int(name.lstrip('[').rstrip(']')) 626 except: 627 return -1
628
629 - def get_child_at_index(self,index):
630 logger = lldb.formatters.Logger.Logger() 631 logger.write("Fetching child " + str(index)) 632 if index < 0 or self.count is None: 633 return None; 634 if index >= self.num_children(): 635 return None; 636 try: 637 i, j = divmod(self.start+index, self.block_size) 638 return self.first.CreateValueFromExpression('[' + str(index) + ']', 639 '*(*(%s + %d) + %d)' % (self.first.get_expr_path(), i, j)) 640 except: 641 return None
642
643 - def update(self):
644 logger = lldb.formatters.Logger.Logger() 645 try: 646 # A deque is effectively a two-dim array, with fixed width. 647 # 'map' contains pointers to the rows of this array. The 648 # full memory area allocated by the deque is delimited 649 # by 'first' and 'end_cap'. However, only a subset of this 650 # memory contains valid data since a deque may have some slack 651 # at the front and back in order to have O(1) insertion at 652 # both ends. The rows in active use are delimited by 653 # 'begin' and 'end'. 654 # 655 # To find the elements that are actually constructed, the 'start' 656 # variable tells which element in this NxM array is the 0th 657 # one, and the 'size' element gives the number of elements 658 # in the deque. 659 count = self.valobj.GetChildMemberWithName('__size_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) 660 # give up now if we cant access memory reliably 661 if self.block_size < 0: 662 logger.write("block_size < 0") 663 return 664 map_ = self.valobj.GetChildMemberWithName('__map_') 665 start = self.valobj.GetChildMemberWithName('__start_').GetValueAsUnsigned(0) 666 first = map_.GetChildMemberWithName('__first_') 667 map_first = first.GetValueAsUnsigned(0) 668 map_begin = map_.GetChildMemberWithName('__begin_').GetValueAsUnsigned(0) 669 map_end = map_.GetChildMemberWithName('__end_').GetValueAsUnsigned(0) 670 map_endcap= map_.GetChildMemberWithName('__end_cap_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) 671 # check consistency 672 if not map_first <= map_begin <= map_end <= map_endcap: 673 logger.write("map pointers are not monotonic") 674 return 675 total_rows, junk = divmod(map_endcap - map_first, self.pointer_size) 676 if junk: 677 logger.write("endcap-first doesnt align correctly") 678 return 679 active_rows, junk = divmod(map_end - map_begin, self.pointer_size) 680 if junk: 681 logger.write("end-begin doesnt align correctly") 682 return 683 start_row, junk = divmod(map_begin - map_first, self.pointer_size) 684 if junk: 685 logger.write("begin-first doesnt align correctly") 686 return 687 if not start_row*self.block_size <= start < (start_row+1)*self.block_size: 688 logger.write("0th element must be in the 'begin' row") 689 return 690 end_row = start_row + active_rows 691 if not count: 692 if active_rows: 693 logger.write("empty deque but begin!=end") 694 return 695 elif not (end_row-1)*self.block_size <= start+count < end_row*self.block_size: 696 logger.write("nth element must be before the 'end' row") 697 return 698 logger.write("update success: count=%r, start=%r, first=%r" % (count,start,first)) 699 # if consistent, save all we really need: 700 self.count = count 701 self.start = start 702 self.first = first 703 except: 704 self.count = None 705 self.start = None 706 self.map_first = None 707 self.map_begin = None
708
709 -class stdsharedptr_SynthProvider:
710 - def __init__(self, valobj, d):
711 logger = lldb.formatters.Logger.Logger() 712 logger.write("init") 713 self.valobj = valobj 714 #self.element_ptr_type = self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType() 715 self.ptr = None 716 self.cntrl = None 717 process = valobj.GetProcess() 718 self.endianness = process.GetByteOrder() 719 self.pointer_size = process.GetAddressByteSize() 720 self.count_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
721
722 - def num_children(self):
723 return 1
724
725 - def has_children(self):
726 return True
727
728 - def get_child_index(self,name):
729 if name=="__ptr_": 730 return 0 731 if name=="count": 732 return 1 733 if name=="weak_count": 734 return 2 735 return -1
736
737 - def get_child_at_index(self,index):
738 if index == 0: 739 return self.ptr 740 if index == 1: 741 if self.cntrl == None: 742 count = 0 743 else: 744 count = 1 + self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned() 745 return self.valobj.CreateValueFromData("count", 746 lldb.SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [count]), 747 self.count_type) 748 if index == 2: 749 if self.cntrl == None: 750 count = 0 751 else: 752 count = 1 + self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned() 753 return self.valobj.CreateValueFromData("weak_count", 754 lldb.SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [count]), 755 self.count_type) 756 return None
757
758 - def update(self):
759 logger = lldb.formatters.Logger.Logger() 760 self.ptr = self.valobj.GetChildMemberWithName('__ptr_')#.Cast(self.element_ptr_type) 761 cntrl = self.valobj.GetChildMemberWithName('__cntrl_') 762 if cntrl.GetValueAsUnsigned(0): 763 self.cntrl = cntrl.Dereference() 764 else: 765 self.cntrl = None
766 767 # we can use two different categories for old and new formatters - type names are different enough that we should make no confusion 768 # talking with libc++ developer: "std::__1::class_name is set in stone until we decide to change the ABI. That shouldn't happen within a 5 year time frame"
769 -def __lldb_init_module(debugger,dict):
770 debugger.HandleCommand('type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx') 771 debugger.HandleCommand('type summary add -F libcxx.stdstring_SummaryProvider "std::__1::basic_string<char, class std::__1::char_traits<char>, class std::__1::allocator<char> >" -w libcxx') 772 debugger.HandleCommand('type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx') 773 debugger.HandleCommand('type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx') 774 debugger.HandleCommand('type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx') 775 debugger.HandleCommand('type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx') 776 debugger.HandleCommand('type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx') 777 debugger.HandleCommand('type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx') 778 debugger.HandleCommand("type category enable libcxx") 779 debugger.HandleCommand('type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx') 780 debugger.HandleCommand('type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx') 781 # turns out the structs look the same, so weak_ptr can be handled the same! 782 debugger.HandleCommand('type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx')
783 784 _map_capping_size = 255 785 _list_capping_size = 255 786 _list_uses_loop_detector = True 787 _deque_capping_size = 255 788