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