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 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                          # uninitialized 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 cycle-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