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

# Source Code for Module lldb.formatters.cpp.gnu_libstdcpp

      1  import re
      2  import lldb.formatters.Logger
      3
      4  # C++ STL formatters for LLDB
      5  # These formatters are based upon the version of the GNU libstdc++
      6  # as it ships with Mac OS X 10.6.8 thru 10.8.0
      7  # You are encouraged to look at the STL implementation for your platform
      8  # before relying on these formatters to do the right thing for your setup
      9
     10 -class StdListSynthProvider:
     11
     12 -        def __init__(self, valobj, dict):
     13                  logger = lldb.formatters.Logger.Logger()
     14                  self.valobj = valobj
     15                  self.count = None
     16                  logger >> "Providing synthetic children for a map named " + str(valobj.GetName())
     17
     18 -        def next_node(self,node):
     19                  logger = lldb.formatters.Logger.Logger()
     20                  return node.GetChildMemberWithName('_M_next')
     21
     22 -        def is_valid(self,node):
     23                  logger = lldb.formatters.Logger.Logger()
     24                  return self.value(self.next_node(node)) != self.node_address
     25
     26 -        def value(self,node):
     27                  logger = lldb.formatters.Logger.Logger()
     28                  return node.GetValueAsUnsigned()
     29
     30          # Floyd's cyle-finding algorithm
     31          # try to detect if this list has a loop
     32 -        def has_loop(self):
     33                  global _list_uses_loop_detector
     34                  logger = lldb.formatters.Logger.Logger()
     35                  if _list_uses_loop_detector == False:
     36                          logger >> "Asked not to use loop detection"
     37                          return False
     38                  slow = self.next
     39                  fast1 = self.next
     40                  fast2 = self.next
     41                  while self.is_valid(slow):
     42                          slow_value = self.value(slow)
     43                          fast1 = self.next_node(fast2)
     44                          fast2 = self.next_node(fast1)
     45                          if self.value(fast1) == slow_value or self.value(fast2) == slow_value:
     46                                  return True
     47                          slow = self.next_node(slow)
     48                  return False
     49
     50 -        def num_children(self):
     51                  global _list_capping_size
     52                  logger = lldb.formatters.Logger.Logger()
     53                  if self.count == None:
     54                          self.count = self.num_children_impl()
     55                          if self.count > _list_capping_size:
     56                                  self.count = _list_capping_size
     57                  return self.count
     58
     59 -        def num_children_impl(self):
     60                  logger = lldb.formatters.Logger.Logger()
     61                  global _list_capping_size
     62                  try:
     63                          next_val = self.next.GetValueAsUnsigned(0)
     64                          prev_val = self.prev.GetValueAsUnsigned(0)
     65                          # After a std::list has been initialized, both next and prev will be non-NULL
     66                          if next_val == 0 or prev_val == 0:
     67                                  return 0
     68                          if next_val == self.node_address:
     69                                  return 0
     70                          if next_val == prev_val:
     71                                  return 1
     72                          if self.has_loop():
     73                                  return 0
     74                          size = 2
     75                          current = self.next
     76                          while current.GetChildMemberWithName('_M_next').GetValueAsUnsigned(0) != self.node_address:
     77                                  size = size + 1
     78                                  current = current.GetChildMemberWithName('_M_next')
     79                                  if size > _list_capping_size:
     80                                          return _list_capping_size
     81                          return (size - 1)
     82                  except:
     83                          return 0;
     84
     85 -        def get_child_index(self,name):
     86                  logger = lldb.formatters.Logger.Logger()
     87                  try:
     88                          return int(name.lstrip('[').rstrip(']'))
     89                  except:
     90                          return -1
     91
     92 -        def get_child_at_index(self,index):
     93                  logger = lldb.formatters.Logger.Logger()
     94                  logger >> "Fetching child " + str(index)
     95                  if index < 0:
     96                          return None;
     97                  if index >= self.num_children():
     98                          return None;
     99                  try:
    100                          offset = index
    101                          current = self.next
    102                          while offset > 0:
    103                                  current = current.GetChildMemberWithName('_M_next')
    104                                  offset = offset - 1
    105                          return current.CreateChildAtOffset('['+str(index)+']',2*current.GetType().GetByteSize(),self.data_type)
    106                  except:
    107                          return None
    108
    109 -        def extract_type(self):
    110                  logger = lldb.formatters.Logger.Logger()
    111                  list_type = self.valobj.GetType().GetUnqualifiedType()
    112                  if list_type.IsReferenceType():
    113                          list_type = list_type.GetDereferencedType()
    114                  if list_type.GetNumberOfTemplateArguments() > 0:
    115                          data_type = list_type.GetTemplateArgumentType(0)
    116                  else:
    117                          data_type = None
    118                  return data_type
    119
    120 -        def update(self):
    121                  logger = lldb.formatters.Logger.Logger()
    122                  # preemptively setting this to None - we might end up changing our mind later
    123                  self.count = None
    124                  try:
    125                          impl = self.valobj.GetChildMemberWithName('_M_impl')
    126                          node = impl.GetChildMemberWithName('_M_node')
    127                          self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
    128                          self.next = node.GetChildMemberWithName('_M_next')
    129                          self.prev = node.GetChildMemberWithName('_M_prev')
    130                          self.data_type = self.extract_type()
    131                          self.data_size = self.data_type.GetByteSize()
    132                  except:
    133                          pass
    134
    135 -        def has_children(self):
    136                  return True
    137
    138 -class StdVectorSynthProvider:
    139
    140 -        def __init__(self, valobj, dict):
    141                  logger = lldb.formatters.Logger.Logger()
    142                  self.count = None
    143                  self.valobj = valobj
    144                  logger >> "Providing synthetic children for a map named " + str(valobj.GetName())
    145
    146 -        def num_children(self):
    147                  logger = lldb.formatters.Logger.Logger()
    148                  if self.count == None:
    149                          self.count = self.num_children_impl()
    150                  return self.count
    151
    152 -        def is_valid_pointer(ptr,process):
    153                  logger = lldb.formatters.Logger.Logger()
    154                  error = lldb.SBError()
    155                  process.ReadMemory(ptr,1,error)
    156                  return False if error.Fail() else True
    157
    158 -        def num_children_impl(self):
    159                  logger = lldb.formatters.Logger.Logger()
    160                  try:
    161                          start_val = self.start.GetValueAsUnsigned(0)
    162                          finish_val = self.finish.GetValueAsUnsigned(0)
    163                          end_val  = self.end.GetValueAsUnsigned(0)
    164                          # Before a vector has been constructed, it will contain bad values
    165                          # so we really need to be careful about the length we return since
    166                          # unitialized data can cause us to return a huge number. We need
    167                          # to also check for any of the start, finish or end of storage values
    168                          # being zero (NULL). If any are, then this vector has not been
    169                          # initialized yet and we should return zero
    170
    171                          # Make sure nothing is NULL
    172                          if start_val == 0 or finish_val == 0 or end_val == 0:
    173                                  return 0
    174                          # Make sure start is less than finish
    175                          if start_val >= finish_val:
    176                                  return 0
    177                          # Make sure finish is less than or equal to end of storage
    178                          if finish_val > end_val:
    179                                  return 0
    180
    181                          # if we have a struct (or other data type that the compiler pads to native word size)
    182                          # this check might fail, unless the sizeof() we get is itself incremented to take the
    183                          # padding bytes into account - on current clang it looks like this is the case
    184                          num_children = (finish_val-start_val)
    185                          if (num_children % self.data_size) != 0:
    186                                  return 0
    187                          else:
    188                                  num_children = num_children/self.data_size
    189                          return num_children
    190                  except:
    191                          return 0;
    192
    193 -        def get_child_index(self,name):
    194                  logger = lldb.formatters.Logger.Logger()
    195                  try:
    196                          return int(name.lstrip('[').rstrip(']'))
    197                  except:
    198                          return -1
    199
    200 -        def get_child_at_index(self,index):
    201                  logger = lldb.formatters.Logger.Logger()
    202                  logger >> "Retrieving child " + str(index)
    203                  if index < 0:
    204                          return None;
    205                  if index >= self.num_children():
    206                          return None;
    207                  try:
    208                          offset = index * self.data_size
    209                          return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type)
    210                  except:
    211                          return None
    212
    213 -        def update(self):
    214                  logger = lldb.formatters.Logger.Logger()
    215                  # preemptively setting this to None - we might end up changing our mind later
    216                  self.count = None
    217                  try:
    218                          impl = self.valobj.GetChildMemberWithName('_M_impl')
    219                          self.start = impl.GetChildMemberWithName('_M_start')
    220                          self.finish = impl.GetChildMemberWithName('_M_finish')
    221                          self.end = impl.GetChildMemberWithName('_M_end_of_storage')
    222                          self.data_type = self.start.GetType().GetPointeeType()
    223                          self.data_size = self.data_type.GetByteSize()
    224                          # if any of these objects is invalid, it means there is no point in trying to fetch anything
    225                          if self.start.IsValid() and self.finish.IsValid() and self.end.IsValid() and self.data_type.IsValid():
    226                                  self.count = None
    227                          else:
    228                                  self.count = 0
    229                  except:
    230                          pass
    231
    232
    233 -        def has_children(self):
    234                  return True
    235
    236
    237 -class StdMapSynthProvider:
    238
    239 -        def __init__(self, valobj, dict):
    240                  logger = lldb.formatters.Logger.Logger()
    241                  self.valobj = valobj;
    242                  self.count = None
    243                  logger >> "Providing synthetic children for a map named " + str(valobj.GetName())
    244
    245          # we need this function as a temporary workaround for rdar://problem/10801549
    246          # which prevents us from extracting the std::pair<K,V> SBType out of the template
    247          # arguments for _Rep_Type _M_t in the map itself - because we have to make up the
    248          # typename and then find it, we may hit the situation were std::string has multiple
    249          # names but only one is actually referenced in the debug information. hence, we need
    250          # to replace the longer versions of std::string with the shorter one in order to be able
    251          # to find the type name
    252 -        def fixup_class_name(self, class_name):
    253                  logger = lldb.formatters.Logger.Logger()
    254                  if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
    255                          return 'std::basic_string<char>',True
    256                  if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
    257                          return 'std::basic_string<char>',True
    258                  if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
    259                          return 'std::basic_string<char>',True
    260                  if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
    261                          return 'std::basic_string<char>',True
    262                  return class_name,False
    263
    264 -        def update(self):
    265                  logger = lldb.formatters.Logger.Logger()
    266                  # preemptively setting this to None - we might end up changing our mind later
    267                  self.count = None
    268                  try:
    269                          # 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
    270                          # if this gets set to True, then we will merrily return None for any child from that moment on
    271                          self.garbage = False
    272                          self.Mt = self.valobj.GetChildMemberWithName('_M_t')
    273                          self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl')
    274                          self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header')
    275
    276                          map_type = self.valobj.GetType()
    277                          if map_type.IsReferenceType():
    278                                  logger >> "Dereferencing type"
    279                                  map_type = map_type.GetDereferencedType()
    280
    281                          map_arg_0 = str(map_type.GetTemplateArgumentType(0).GetName())
    282                          map_arg_1 = str(map_type.GetTemplateArgumentType(1).GetName())
    283
    284                          logger >> "map has args " + str(map_arg_0) + " and " + str(map_arg_1)
    285
    286                          map_arg_0,fixed_0 = self.fixup_class_name(map_arg_0)
    287                          map_arg_1,fixed_1 = self.fixup_class_name(map_arg_1)
    288
    289                          logger >> "arg_0 has become: " + str(map_arg_0) + " (fixed: " + str(fixed_0) + ")"
    290                          logger >> "arg_1 has become: " + str(map_arg_1) + " (fixed: " + str(fixed_1) + ")"
    291
    292                          # HACK: this is related to the above issue with the typename for std::string
    293                          # being shortened by clang - the changes to typename display and searching to honor
    294                          # namespaces make it so that we go looking for std::pair<const std::basic_string<char>, ...>
    295                          # but when we find a type for this, we then compare it against the fully-qualified
    296                          # std::pair<const std::basic_string<char, std::char_traits... and of course fail
    297                          # the way to bypass this problem is to avoid using the std:: prefix in this specific case
    298                          if fixed_0 or fixed_1:
    299                                  map_arg_type = "pair<const " + map_arg_0 + ", " + map_arg_1
    300                          else:
    301                                  map_arg_type = "std::pair<const " + map_arg_0 + ", " + map_arg_1
    302
    303                          if map_arg_1[-1] == '>':
    304                                  map_arg_type = map_arg_type + " >"
    305                          else:
    306                                  map_arg_type = map_arg_type + ">"
    307
    308                          logger >> "final contents datatype is: " + str(map_arg_type)
    309
    310                          self.data_type = self.valobj.GetTarget().FindFirstType(map_arg_type)
    311
    312                          logger >> "and the SBType is: " + str(self.data_type)
    313
    314                          # from libstdc++ implementation of _M_root for rbtree
    315                          self.Mroot = self.Mheader.GetChildMemberWithName('_M_parent')
    316                          self.data_size = self.data_type.GetByteSize()
    317                          self.skip_size = self.Mheader.GetType().GetByteSize()
    318                  except:
    319                          pass
    320
    321 -        def num_children(self):
    322                  global _map_capping_size
    323                  logger = lldb.formatters.Logger.Logger()
    324                  if self.count == None:
    325                          self.count = self.num_children_impl()
    326                          if self.count > _map_capping_size:
    327                                  self.count = _map_capping_size
    328                  return self.count
    329
    330 -        def num_children_impl(self):
    331                  logger = lldb.formatters.Logger.Logger()
    332                  try:
    333                          root_ptr_val = self.node_ptr_value(self.Mroot)
    334                          if root_ptr_val == 0:
    335                                  return 0;
    336                          count = self.Mimpl.GetChildMemberWithName('_M_node_count').GetValueAsUnsigned(0)
    337                          logger >> "I have " + str(count) + " children available"
    338                          return count
    339                  except:
    340                          return 0;
    341
    342 -        def get_child_index(self,name):
    343                  logger = lldb.formatters.Logger.Logger()
    344                  try:
    345                          return int(name.lstrip('[').rstrip(']'))
    346                  except:
    347                          return -1
    348
    349 -        def get_child_at_index(self,index):
    350                  logger = lldb.formatters.Logger.Logger()
    351                  logger >> "Being asked to fetch child[" + str(index) + "]"
    352                  if index < 0:
    353                          return None
    354                  if index >= self.num_children():
    355                          return None;
    356                  if self.garbage:
    357                          logger >> "Returning None since we are a garbage tree"
    358                          return None
    359                  try:
    360                          offset = index
    361                          current = self.left(self.Mheader);
    362                          while offset > 0:
    363                                  current = self.increment_node(current)
    364                                  offset = offset - 1;
    365                          # skip all the base stuff and get at the data
    366                          return current.CreateChildAtOffset('['+str(index)+']',self.skip_size,self.data_type)
    367                  except:
    368                          return None
    369
    370          # utility functions
    371 -        def node_ptr_value(self,node):
    372                  logger = lldb.formatters.Logger.Logger()
    373                  return node.GetValueAsUnsigned(0)
    374
    375 -        def right(self,node):
    376                  logger = lldb.formatters.Logger.Logger()
    377                  return node.GetChildMemberWithName("_M_right");
    378
    379 -        def left(self,node):
    380                  logger = lldb.formatters.Logger.Logger()
    381                  return node.GetChildMemberWithName("_M_left");
    382
    383 -        def parent(self,node):
    384                  logger = lldb.formatters.Logger.Logger()
    385                  return node.GetChildMemberWithName("_M_parent");
    386
    387          # from libstdc++ implementation of iterator for rbtree
    388 -        def increment_node(self,node):
    389                  logger = lldb.formatters.Logger.Logger()
    390                  max_steps = self.num_children()
    391                  if self.node_ptr_value(self.right(node)) != 0:
    392                          x = self.right(node);
    393                          max_steps -= 1
    394                          while self.node_ptr_value(self.left(x)) != 0:
    395                                  x = self.left(x);
    396                                  max_steps -= 1
    397                                  logger >> str(max_steps) + " more to go before giving up"
    398                                  if max_steps <= 0:
    399                                          self.garbage = True
    400                                          return None
    401                          return x;
    402                  else:
    403                          x = node;
    404                          y = self.parent(x)
    405                          max_steps -= 1
    406                          while(self.node_ptr_value(x) == self.node_ptr_value(self.right(y))):
    407                                  x = y;
    408                                  y = self.parent(y);
    409                                  max_steps -= 1
    410                                  logger >> str(max_steps) + " more to go before giving up"
    411                                  if max_steps <= 0:
    412                                          self.garbage = True
    413                                          return None
    414                          if self.node_ptr_value(self.right(x)) != self.node_ptr_value(y):
    415                                  x = y;
    416                          return x;
    417
    418 -        def has_children(self):
    419                  return True
    420
    421  _map_capping_size = 255
    422  _list_capping_size = 255
    423  _list_uses_loop_detector = True
    424