lldb.formatters.cpp.libcxx

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