1061da546Spatrickimport lldb 2061da546Spatrickimport lldb.formatters.Logger 3061da546Spatrick 4061da546Spatrick# libcxx STL formatters for LLDB 5061da546Spatrick# These formatters are based upon the implementation of libc++ that 6061da546Spatrick# ships with current releases of OS X - They will not work for other implementations 7061da546Spatrick# of the standard C++ library - and they are bound to use the 8061da546Spatrick# libc++-specific namespace 9061da546Spatrick 10061da546Spatrick# the std::string summary is just an example for your convenience 11061da546Spatrick# the actual summary that LLDB uses is C++ code inside the debugger's own core 12061da546Spatrick 13061da546Spatrick# this could probably be made more efficient but since it only reads a handful of bytes at a time 14061da546Spatrick# we probably don't need to worry too much about this for the time being 15061da546Spatrick 16061da546Spatrick 17061da546Spatrickdef make_string(F, L): 18061da546Spatrick strval = '' 19061da546Spatrick G = F.GetData().uint8 20061da546Spatrick for X in range(L): 21061da546Spatrick V = G[X] 22061da546Spatrick if V == 0: 23061da546Spatrick break 24061da546Spatrick strval = strval + chr(V % 256) 25061da546Spatrick return '"' + strval + '"' 26061da546Spatrick 27061da546Spatrick# if we ever care about big-endian, these two functions might need to change 28061da546Spatrick 29061da546Spatrick 30061da546Spatrickdef is_short_string(value): 31061da546Spatrick return True if (value & 1) == 0 else False 32061da546Spatrick 33061da546Spatrick 34061da546Spatrickdef extract_short_size(value): 35061da546Spatrick return ((value >> 1) % 256) 36061da546Spatrick 37061da546Spatrick# some of the members of libc++ std::string are anonymous or have internal names that convey 38061da546Spatrick# no external significance - we access them by index since this saves a name lookup that would add 39061da546Spatrick# no information for readers of the code, but when possible try to use 40061da546Spatrick# meaningful variable names 41061da546Spatrick 42061da546Spatrick 43061da546Spatrickdef stdstring_SummaryProvider(valobj, dict): 44061da546Spatrick logger = lldb.formatters.Logger.Logger() 45061da546Spatrick r = valobj.GetChildAtIndex(0) 46061da546Spatrick B = r.GetChildAtIndex(0) 47061da546Spatrick first = B.GetChildAtIndex(0) 48061da546Spatrick D = first.GetChildAtIndex(0) 49061da546Spatrick l = D.GetChildAtIndex(0) 50061da546Spatrick s = D.GetChildAtIndex(1) 51061da546Spatrick D20 = s.GetChildAtIndex(0) 52061da546Spatrick size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0) 53061da546Spatrick if is_short_string(size_mode): 54061da546Spatrick size = extract_short_size(size_mode) 55061da546Spatrick return make_string(s.GetChildAtIndex(1), size) 56061da546Spatrick else: 57061da546Spatrick data_ptr = l.GetChildAtIndex(2) 58061da546Spatrick size_vo = l.GetChildAtIndex(1) 59061da546Spatrick # the NULL terminator must be accounted for 60061da546Spatrick size = size_vo.GetValueAsUnsigned(0) + 1 61061da546Spatrick if size <= 1 or size is None: # should never be the case 62061da546Spatrick return '""' 63061da546Spatrick try: 64061da546Spatrick data = data_ptr.GetPointeeData(0, size) 65061da546Spatrick except: 66061da546Spatrick return '""' 67061da546Spatrick error = lldb.SBError() 68061da546Spatrick strval = data.GetString(error, 0) 69061da546Spatrick if error.Fail(): 70061da546Spatrick return '<error:' + error.GetCString() + '>' 71061da546Spatrick else: 72061da546Spatrick return '"' + strval + '"' 73061da546Spatrick 74061da546Spatrick 75061da546Spatrickclass stdvector_SynthProvider: 76061da546Spatrick 77061da546Spatrick def __init__(self, valobj, dict): 78061da546Spatrick logger = lldb.formatters.Logger.Logger() 79061da546Spatrick self.valobj = valobj 80061da546Spatrick 81061da546Spatrick def num_children(self): 82061da546Spatrick logger = lldb.formatters.Logger.Logger() 83061da546Spatrick try: 84061da546Spatrick start_val = self.start.GetValueAsUnsigned(0) 85061da546Spatrick finish_val = self.finish.GetValueAsUnsigned(0) 86061da546Spatrick # Before a vector has been constructed, it will contain bad values 87061da546Spatrick # so we really need to be careful about the length we return since 88061da546Spatrick # uninitialized data can cause us to return a huge number. We need 89061da546Spatrick # to also check for any of the start, finish or end of storage values 90061da546Spatrick # being zero (NULL). If any are, then this vector has not been 91061da546Spatrick # initialized yet and we should return zero 92061da546Spatrick 93061da546Spatrick # Make sure nothing is NULL 94061da546Spatrick if start_val == 0 or finish_val == 0: 95061da546Spatrick return 0 96061da546Spatrick # Make sure start is less than finish 97061da546Spatrick if start_val >= finish_val: 98061da546Spatrick return 0 99061da546Spatrick 100061da546Spatrick num_children = (finish_val - start_val) 101061da546Spatrick if (num_children % self.data_size) != 0: 102061da546Spatrick return 0 103061da546Spatrick else: 104061da546Spatrick num_children = num_children / self.data_size 105061da546Spatrick return num_children 106061da546Spatrick except: 107061da546Spatrick return 0 108061da546Spatrick 109061da546Spatrick def get_child_index(self, name): 110061da546Spatrick logger = lldb.formatters.Logger.Logger() 111061da546Spatrick try: 112061da546Spatrick return int(name.lstrip('[').rstrip(']')) 113061da546Spatrick except: 114061da546Spatrick return -1 115061da546Spatrick 116061da546Spatrick def get_child_at_index(self, index): 117061da546Spatrick logger = lldb.formatters.Logger.Logger() 118061da546Spatrick logger >> "Retrieving child " + str(index) 119061da546Spatrick if index < 0: 120061da546Spatrick return None 121061da546Spatrick if index >= self.num_children(): 122061da546Spatrick return None 123061da546Spatrick try: 124061da546Spatrick offset = index * self.data_size 125061da546Spatrick return self.start.CreateChildAtOffset( 126061da546Spatrick '[' + str(index) + ']', offset, self.data_type) 127061da546Spatrick except: 128061da546Spatrick return None 129061da546Spatrick 130061da546Spatrick def update(self): 131061da546Spatrick logger = lldb.formatters.Logger.Logger() 132061da546Spatrick try: 133061da546Spatrick self.start = self.valobj.GetChildMemberWithName('__begin_') 134061da546Spatrick self.finish = self.valobj.GetChildMemberWithName('__end_') 135061da546Spatrick # the purpose of this field is unclear, but it is the only field whose type is clearly T* for a vector<T> 136061da546Spatrick # if this ends up not being correct, we can use the APIs to get at 137061da546Spatrick # template arguments 138061da546Spatrick data_type_finder = self.valobj.GetChildMemberWithName( 139061da546Spatrick '__end_cap_').GetChildMemberWithName('__first_') 140061da546Spatrick self.data_type = data_type_finder.GetType().GetPointeeType() 141061da546Spatrick self.data_size = self.data_type.GetByteSize() 142061da546Spatrick except: 143061da546Spatrick pass 144061da546Spatrick 145061da546Spatrick def has_children(self): 146061da546Spatrick return True 147061da546Spatrick 148061da546Spatrick# Just an example: the actual summary is produced by a summary string: 149061da546Spatrick# size=${svar%#} 150061da546Spatrick 151061da546Spatrick 152061da546Spatrickdef stdvector_SummaryProvider(valobj, dict): 153061da546Spatrick prov = stdvector_SynthProvider(valobj, None) 154061da546Spatrick return 'size=' + str(prov.num_children()) 155061da546Spatrick 156061da546Spatrick 157061da546Spatrickclass stdlist_entry: 158061da546Spatrick 159061da546Spatrick def __init__(self, entry): 160061da546Spatrick logger = lldb.formatters.Logger.Logger() 161061da546Spatrick self.entry = entry 162061da546Spatrick 163061da546Spatrick def _next_impl(self): 164061da546Spatrick logger = lldb.formatters.Logger.Logger() 165061da546Spatrick return stdlist_entry(self.entry.GetChildMemberWithName('__next_')) 166061da546Spatrick 167061da546Spatrick def _prev_impl(self): 168061da546Spatrick logger = lldb.formatters.Logger.Logger() 169061da546Spatrick return stdlist_entry(self.entry.GetChildMemberWithName('__prev_')) 170061da546Spatrick 171061da546Spatrick def _value_impl(self): 172061da546Spatrick logger = lldb.formatters.Logger.Logger() 173061da546Spatrick return self.entry.GetValueAsUnsigned(0) 174061da546Spatrick 175061da546Spatrick def _isnull_impl(self): 176061da546Spatrick logger = lldb.formatters.Logger.Logger() 177061da546Spatrick return self._value_impl() == 0 178061da546Spatrick 179061da546Spatrick def _sbvalue_impl(self): 180061da546Spatrick logger = lldb.formatters.Logger.Logger() 181061da546Spatrick return self.entry 182061da546Spatrick 183061da546Spatrick next = property(_next_impl, None) 184061da546Spatrick value = property(_value_impl, None) 185061da546Spatrick is_null = property(_isnull_impl, None) 186061da546Spatrick sbvalue = property(_sbvalue_impl, None) 187061da546Spatrick 188061da546Spatrick 189061da546Spatrickclass stdlist_iterator: 190061da546Spatrick 191061da546Spatrick def increment_node(self, node): 192061da546Spatrick logger = lldb.formatters.Logger.Logger() 193061da546Spatrick if node.is_null: 194061da546Spatrick return None 195061da546Spatrick return node.next 196061da546Spatrick 197061da546Spatrick def __init__(self, node): 198061da546Spatrick logger = lldb.formatters.Logger.Logger() 199061da546Spatrick # we convert the SBValue to an internal node object on entry 200061da546Spatrick self.node = stdlist_entry(node) 201061da546Spatrick 202061da546Spatrick def value(self): 203061da546Spatrick logger = lldb.formatters.Logger.Logger() 204061da546Spatrick return self.node.sbvalue # and return the SBValue back on exit 205061da546Spatrick 206061da546Spatrick def next(self): 207061da546Spatrick logger = lldb.formatters.Logger.Logger() 208061da546Spatrick node = self.increment_node(self.node) 209061da546Spatrick if node is not None and node.sbvalue.IsValid() and not(node.is_null): 210061da546Spatrick self.node = node 211061da546Spatrick return self.value() 212061da546Spatrick else: 213061da546Spatrick return None 214061da546Spatrick 215061da546Spatrick def advance(self, N): 216061da546Spatrick logger = lldb.formatters.Logger.Logger() 217061da546Spatrick if N < 0: 218061da546Spatrick return None 219061da546Spatrick if N == 0: 220061da546Spatrick return self.value() 221061da546Spatrick if N == 1: 222061da546Spatrick return self.next() 223061da546Spatrick while N > 0: 224061da546Spatrick self.next() 225061da546Spatrick N = N - 1 226061da546Spatrick return self.value() 227061da546Spatrick 228061da546Spatrick 229061da546Spatrickclass stdlist_SynthProvider: 230061da546Spatrick 231061da546Spatrick def __init__(self, valobj, dict): 232061da546Spatrick logger = lldb.formatters.Logger.Logger() 233061da546Spatrick self.valobj = valobj 234061da546Spatrick self.count = None 235061da546Spatrick 236061da546Spatrick def next_node(self, node): 237061da546Spatrick logger = lldb.formatters.Logger.Logger() 238061da546Spatrick return node.GetChildMemberWithName('__next_') 239061da546Spatrick 240061da546Spatrick def value(self, node): 241061da546Spatrick logger = lldb.formatters.Logger.Logger() 242061da546Spatrick return node.GetValueAsUnsigned() 243061da546Spatrick 244061da546Spatrick # Floyd's cycle-finding algorithm 245061da546Spatrick # try to detect if this list has a loop 246061da546Spatrick def has_loop(self): 247061da546Spatrick global _list_uses_loop_detector 248061da546Spatrick logger = lldb.formatters.Logger.Logger() 249061da546Spatrick if not _list_uses_loop_detector: 250061da546Spatrick logger >> "Asked not to use loop detection" 251061da546Spatrick return False 252061da546Spatrick slow = stdlist_entry(self.head) 253061da546Spatrick fast1 = stdlist_entry(self.head) 254061da546Spatrick fast2 = stdlist_entry(self.head) 255061da546Spatrick while slow.next.value != self.node_address: 256061da546Spatrick slow_value = slow.value 257061da546Spatrick fast1 = fast2.next 258061da546Spatrick fast2 = fast1.next 259061da546Spatrick if fast1.value == slow_value or fast2.value == slow_value: 260061da546Spatrick return True 261061da546Spatrick slow = slow.next 262061da546Spatrick return False 263061da546Spatrick 264061da546Spatrick def num_children(self): 265061da546Spatrick global _list_capping_size 266061da546Spatrick logger = lldb.formatters.Logger.Logger() 267061da546Spatrick if self.count is None: 268061da546Spatrick self.count = self.num_children_impl() 269061da546Spatrick if self.count > _list_capping_size: 270061da546Spatrick self.count = _list_capping_size 271061da546Spatrick return self.count 272061da546Spatrick 273061da546Spatrick def num_children_impl(self): 274061da546Spatrick global _list_capping_size 275061da546Spatrick logger = lldb.formatters.Logger.Logger() 276061da546Spatrick try: 277061da546Spatrick next_val = self.head.GetValueAsUnsigned(0) 278061da546Spatrick prev_val = self.tail.GetValueAsUnsigned(0) 279061da546Spatrick # After a std::list has been initialized, both next and prev will 280061da546Spatrick # be non-NULL 281061da546Spatrick if next_val == 0 or prev_val == 0: 282061da546Spatrick return 0 283061da546Spatrick if next_val == self.node_address: 284061da546Spatrick return 0 285061da546Spatrick if next_val == prev_val: 286061da546Spatrick return 1 287061da546Spatrick if self.has_loop(): 288061da546Spatrick return 0 289061da546Spatrick size = 2 290061da546Spatrick current = stdlist_entry(self.head) 291061da546Spatrick while current.next.value != self.node_address: 292061da546Spatrick size = size + 1 293061da546Spatrick current = current.next 294061da546Spatrick if size > _list_capping_size: 295061da546Spatrick return _list_capping_size 296061da546Spatrick return (size - 1) 297061da546Spatrick except: 298061da546Spatrick return 0 299061da546Spatrick 300061da546Spatrick def get_child_index(self, name): 301061da546Spatrick logger = lldb.formatters.Logger.Logger() 302061da546Spatrick try: 303061da546Spatrick return int(name.lstrip('[').rstrip(']')) 304061da546Spatrick except: 305061da546Spatrick return -1 306061da546Spatrick 307061da546Spatrick def get_child_at_index(self, index): 308061da546Spatrick logger = lldb.formatters.Logger.Logger() 309061da546Spatrick logger >> "Fetching child " + str(index) 310061da546Spatrick if index < 0: 311061da546Spatrick return None 312061da546Spatrick if index >= self.num_children(): 313061da546Spatrick return None 314061da546Spatrick try: 315061da546Spatrick current = stdlist_iterator(self.head) 316061da546Spatrick current = current.advance(index) 317061da546Spatrick # we do not return __value_ because then all our children would be named __value_ 318061da546Spatrick # we need to make a copy of __value__ with the right name - 319061da546Spatrick # unfortunate 320061da546Spatrick obj = current.GetChildMemberWithName('__value_') 321061da546Spatrick obj_data = obj.GetData() 322061da546Spatrick return self.valobj.CreateValueFromData( 323061da546Spatrick '[' + str(index) + ']', obj_data, self.data_type) 324061da546Spatrick except: 325061da546Spatrick return None 326061da546Spatrick 327061da546Spatrick def extract_type(self): 328061da546Spatrick logger = lldb.formatters.Logger.Logger() 329061da546Spatrick list_type = self.valobj.GetType().GetUnqualifiedType() 330061da546Spatrick if list_type.IsReferenceType(): 331061da546Spatrick list_type = list_type.GetDereferencedType() 332061da546Spatrick if list_type.GetNumberOfTemplateArguments() > 0: 333061da546Spatrick data_type = list_type.GetTemplateArgumentType(0) 334061da546Spatrick else: 335061da546Spatrick data_type = None 336061da546Spatrick return data_type 337061da546Spatrick 338061da546Spatrick def update(self): 339061da546Spatrick logger = lldb.formatters.Logger.Logger() 340061da546Spatrick self.count = None 341061da546Spatrick try: 342061da546Spatrick impl = self.valobj.GetChildMemberWithName('__end_') 343061da546Spatrick self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) 344061da546Spatrick self.head = impl.GetChildMemberWithName('__next_') 345061da546Spatrick self.tail = impl.GetChildMemberWithName('__prev_') 346061da546Spatrick self.data_type = self.extract_type() 347061da546Spatrick self.data_size = self.data_type.GetByteSize() 348061da546Spatrick except: 349061da546Spatrick pass 350061da546Spatrick 351061da546Spatrick def has_children(self): 352061da546Spatrick return True 353061da546Spatrick 354061da546Spatrick 355061da546Spatrick# Just an example: the actual summary is produced by a summary string: 356061da546Spatrick# size=${svar%#} 357061da546Spatrickdef stdlist_SummaryProvider(valobj, dict): 358061da546Spatrick prov = stdlist_SynthProvider(valobj, None) 359061da546Spatrick return 'size=' + str(prov.num_children()) 360061da546Spatrick 361061da546Spatrick# a tree node - this class makes the syntax in the actual iterator nicer 362061da546Spatrick# to read and maintain 363061da546Spatrick 364061da546Spatrick 365061da546Spatrickclass stdmap_iterator_node: 366061da546Spatrick 367061da546Spatrick def _left_impl(self): 368061da546Spatrick logger = lldb.formatters.Logger.Logger() 369061da546Spatrick return stdmap_iterator_node( 370061da546Spatrick self.node.GetChildMemberWithName("__left_")) 371061da546Spatrick 372061da546Spatrick def _right_impl(self): 373061da546Spatrick logger = lldb.formatters.Logger.Logger() 374061da546Spatrick return stdmap_iterator_node( 375061da546Spatrick self.node.GetChildMemberWithName("__right_")) 376061da546Spatrick 377061da546Spatrick def _parent_impl(self): 378061da546Spatrick logger = lldb.formatters.Logger.Logger() 379061da546Spatrick return stdmap_iterator_node( 380061da546Spatrick self.node.GetChildMemberWithName("__parent_")) 381061da546Spatrick 382061da546Spatrick def _value_impl(self): 383061da546Spatrick logger = lldb.formatters.Logger.Logger() 384061da546Spatrick return self.node.GetValueAsUnsigned(0) 385061da546Spatrick 386061da546Spatrick def _sbvalue_impl(self): 387061da546Spatrick logger = lldb.formatters.Logger.Logger() 388061da546Spatrick return self.node 389061da546Spatrick 390061da546Spatrick def _null_impl(self): 391061da546Spatrick logger = lldb.formatters.Logger.Logger() 392061da546Spatrick return self.value == 0 393061da546Spatrick 394061da546Spatrick def __init__(self, node): 395061da546Spatrick logger = lldb.formatters.Logger.Logger() 396061da546Spatrick self.node = node 397061da546Spatrick 398061da546Spatrick left = property(_left_impl, None) 399061da546Spatrick right = property(_right_impl, None) 400061da546Spatrick parent = property(_parent_impl, None) 401061da546Spatrick value = property(_value_impl, None) 402061da546Spatrick is_null = property(_null_impl, None) 403061da546Spatrick sbvalue = property(_sbvalue_impl, None) 404061da546Spatrick 405061da546Spatrick# a Python implementation of the tree iterator used by libc++ 406061da546Spatrick 407061da546Spatrick 408061da546Spatrickclass stdmap_iterator: 409061da546Spatrick 410061da546Spatrick def tree_min(self, x): 411061da546Spatrick logger = lldb.formatters.Logger.Logger() 412061da546Spatrick steps = 0 413061da546Spatrick if x.is_null: 414061da546Spatrick return None 415061da546Spatrick while (not x.left.is_null): 416061da546Spatrick x = x.left 417061da546Spatrick steps += 1 418061da546Spatrick if steps > self.max_count: 419061da546Spatrick logger >> "Returning None - we overflowed" 420061da546Spatrick return None 421061da546Spatrick return x 422061da546Spatrick 423061da546Spatrick def tree_max(self, x): 424061da546Spatrick logger = lldb.formatters.Logger.Logger() 425061da546Spatrick if x.is_null: 426061da546Spatrick return None 427061da546Spatrick while (not x.right.is_null): 428061da546Spatrick x = x.right 429061da546Spatrick return x 430061da546Spatrick 431061da546Spatrick def tree_is_left_child(self, x): 432061da546Spatrick logger = lldb.formatters.Logger.Logger() 433061da546Spatrick if x.is_null: 434061da546Spatrick return None 435061da546Spatrick return True if x.value == x.parent.left.value else False 436061da546Spatrick 437061da546Spatrick def increment_node(self, node): 438061da546Spatrick logger = lldb.formatters.Logger.Logger() 439061da546Spatrick if node.is_null: 440061da546Spatrick return None 441061da546Spatrick if not node.right.is_null: 442061da546Spatrick return self.tree_min(node.right) 443061da546Spatrick steps = 0 444061da546Spatrick while (not self.tree_is_left_child(node)): 445061da546Spatrick steps += 1 446061da546Spatrick if steps > self.max_count: 447061da546Spatrick logger >> "Returning None - we overflowed" 448061da546Spatrick return None 449061da546Spatrick node = node.parent 450061da546Spatrick return node.parent 451061da546Spatrick 452061da546Spatrick def __init__(self, node, max_count=0): 453061da546Spatrick logger = lldb.formatters.Logger.Logger() 454061da546Spatrick # we convert the SBValue to an internal node object on entry 455061da546Spatrick self.node = stdmap_iterator_node(node) 456061da546Spatrick self.max_count = max_count 457061da546Spatrick 458061da546Spatrick def value(self): 459061da546Spatrick logger = lldb.formatters.Logger.Logger() 460061da546Spatrick return self.node.sbvalue # and return the SBValue back on exit 461061da546Spatrick 462061da546Spatrick def next(self): 463061da546Spatrick logger = lldb.formatters.Logger.Logger() 464061da546Spatrick node = self.increment_node(self.node) 465061da546Spatrick if node is not None and node.sbvalue.IsValid() and not(node.is_null): 466061da546Spatrick self.node = node 467061da546Spatrick return self.value() 468061da546Spatrick else: 469061da546Spatrick return None 470061da546Spatrick 471061da546Spatrick def advance(self, N): 472061da546Spatrick logger = lldb.formatters.Logger.Logger() 473061da546Spatrick if N < 0: 474061da546Spatrick return None 475061da546Spatrick if N == 0: 476061da546Spatrick return self.value() 477061da546Spatrick if N == 1: 478061da546Spatrick return self.next() 479061da546Spatrick while N > 0: 480061da546Spatrick if self.next() is None: 481061da546Spatrick return None 482061da546Spatrick N = N - 1 483061da546Spatrick return self.value() 484061da546Spatrick 485061da546Spatrick 486061da546Spatrickclass stdmap_SynthProvider: 487061da546Spatrick 488061da546Spatrick def __init__(self, valobj, dict): 489061da546Spatrick logger = lldb.formatters.Logger.Logger() 490061da546Spatrick self.valobj = valobj 491061da546Spatrick self.pointer_size = self.valobj.GetProcess().GetAddressByteSize() 492061da546Spatrick self.count = None 493061da546Spatrick 494061da546Spatrick def update(self): 495061da546Spatrick logger = lldb.formatters.Logger.Logger() 496061da546Spatrick self.count = None 497061da546Spatrick try: 498061da546Spatrick # 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 499061da546Spatrick # if this gets set to True, then we will merrily return None for 500061da546Spatrick # any child from that moment on 501061da546Spatrick self.garbage = False 502061da546Spatrick self.tree = self.valobj.GetChildMemberWithName('__tree_') 503061da546Spatrick self.root_node = self.tree.GetChildMemberWithName('__begin_node_') 504061da546Spatrick # this data is either lazily-calculated, or cannot be inferred at this moment 505061da546Spatrick # we still need to mark it as None, meaning "please set me ASAP" 506061da546Spatrick self.data_type = None 507061da546Spatrick self.data_size = None 508061da546Spatrick self.skip_size = None 509061da546Spatrick except: 510061da546Spatrick pass 511061da546Spatrick 512061da546Spatrick def num_children(self): 513061da546Spatrick global _map_capping_size 514061da546Spatrick logger = lldb.formatters.Logger.Logger() 515061da546Spatrick if self.count is None: 516061da546Spatrick self.count = self.num_children_impl() 517061da546Spatrick if self.count > _map_capping_size: 518061da546Spatrick self.count = _map_capping_size 519061da546Spatrick return self.count 520061da546Spatrick 521061da546Spatrick def num_children_impl(self): 522061da546Spatrick logger = lldb.formatters.Logger.Logger() 523061da546Spatrick try: 524061da546Spatrick return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName( 525061da546Spatrick '__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned() 526061da546Spatrick except: 527061da546Spatrick return 0 528061da546Spatrick 529061da546Spatrick def has_children(self): 530061da546Spatrick return True 531061da546Spatrick 532061da546Spatrick def get_data_type(self): 533061da546Spatrick logger = lldb.formatters.Logger.Logger() 534061da546Spatrick if self.data_type is None or self.data_size is None: 535061da546Spatrick if self.num_children() == 0: 536061da546Spatrick return False 537061da546Spatrick deref = self.root_node.Dereference() 538061da546Spatrick if not(deref.IsValid()): 539061da546Spatrick return False 540061da546Spatrick value = deref.GetChildMemberWithName('__value_') 541061da546Spatrick if not(value.IsValid()): 542061da546Spatrick return False 543061da546Spatrick self.data_type = value.GetType() 544061da546Spatrick self.data_size = self.data_type.GetByteSize() 545061da546Spatrick self.skip_size = None 546061da546Spatrick return True 547061da546Spatrick else: 548061da546Spatrick return True 549061da546Spatrick 550061da546Spatrick def get_value_offset(self, node): 551061da546Spatrick logger = lldb.formatters.Logger.Logger() 552061da546Spatrick if self.skip_size is None: 553061da546Spatrick node_type = node.GetType() 554061da546Spatrick fields_count = node_type.GetNumberOfFields() 555061da546Spatrick for i in range(fields_count): 556061da546Spatrick field = node_type.GetFieldAtIndex(i) 557061da546Spatrick if field.GetName() == '__value_': 558061da546Spatrick self.skip_size = field.GetOffsetInBytes() 559061da546Spatrick break 560061da546Spatrick return (self.skip_size is not None) 561061da546Spatrick 562061da546Spatrick def get_child_index(self, name): 563061da546Spatrick logger = lldb.formatters.Logger.Logger() 564061da546Spatrick try: 565061da546Spatrick return int(name.lstrip('[').rstrip(']')) 566061da546Spatrick except: 567061da546Spatrick return -1 568061da546Spatrick 569061da546Spatrick def get_child_at_index(self, index): 570061da546Spatrick logger = lldb.formatters.Logger.Logger() 571061da546Spatrick logger >> "Retrieving child " + str(index) 572061da546Spatrick if index < 0: 573061da546Spatrick return None 574061da546Spatrick if index >= self.num_children(): 575061da546Spatrick return None 576061da546Spatrick if self.garbage: 577061da546Spatrick logger >> "Returning None since this tree is garbage" 578061da546Spatrick return None 579061da546Spatrick try: 580061da546Spatrick iterator = stdmap_iterator( 581061da546Spatrick self.root_node, max_count=self.num_children()) 582061da546Spatrick # the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type 583061da546Spatrick # out of which we can grab the information we need - every other node has a less informative 584061da546Spatrick # type which omits all value information and only contains housekeeping information for the RB tree 585061da546Spatrick # hence, we need to know if we are at a node != 0, so that we can 586061da546Spatrick # still get at the data 587061da546Spatrick need_to_skip = (index > 0) 588061da546Spatrick current = iterator.advance(index) 589061da546Spatrick if current is None: 590061da546Spatrick logger >> "Tree is garbage - returning None" 591061da546Spatrick self.garbage = True 592061da546Spatrick return None 593061da546Spatrick if self.get_data_type(): 594061da546Spatrick if not(need_to_skip): 595061da546Spatrick current = current.Dereference() 596061da546Spatrick obj = current.GetChildMemberWithName('__value_') 597061da546Spatrick obj_data = obj.GetData() 598061da546Spatrick # make sure we have a valid offset for the next items 599061da546Spatrick self.get_value_offset(current) 600061da546Spatrick # we do not return __value_ because then we would end up with a child named 601061da546Spatrick # __value_ instead of [0] 602061da546Spatrick return self.valobj.CreateValueFromData( 603061da546Spatrick '[' + str(index) + ']', obj_data, self.data_type) 604061da546Spatrick else: 605061da546Spatrick # FIXME we need to have accessed item 0 before accessing 606061da546Spatrick # any other item! 607061da546Spatrick if self.skip_size is None: 608061da546Spatrick logger >> "You asked for item > 0 before asking for item == 0, I will fetch 0 now then retry" 609061da546Spatrick if self.get_child_at_index(0): 610061da546Spatrick return self.get_child_at_index(index) 611061da546Spatrick else: 612061da546Spatrick logger >> "item == 0 could not be found. sorry, nothing can be done here." 613061da546Spatrick return None 614061da546Spatrick return current.CreateChildAtOffset( 615061da546Spatrick '[' + str(index) + ']', self.skip_size, self.data_type) 616061da546Spatrick else: 617061da546Spatrick logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)" 618061da546Spatrick return None 619061da546Spatrick except Exception as err: 620061da546Spatrick logger >> "Hit an exception: " + str(err) 621061da546Spatrick return None 622061da546Spatrick 623061da546Spatrick# Just an example: the actual summary is produced by a summary string: 624061da546Spatrick# size=${svar%#} 625061da546Spatrick 626061da546Spatrick 627061da546Spatrickdef stdmap_SummaryProvider(valobj, dict): 628061da546Spatrick prov = stdmap_SynthProvider(valobj, None) 629061da546Spatrick return 'size=' + str(prov.num_children()) 630061da546Spatrick 631061da546Spatrick 632061da546Spatrickclass stddeque_SynthProvider: 633061da546Spatrick 634061da546Spatrick def __init__(self, valobj, d): 635061da546Spatrick logger = lldb.formatters.Logger.Logger() 636061da546Spatrick logger.write("init") 637061da546Spatrick self.valobj = valobj 638061da546Spatrick self.pointer_size = self.valobj.GetProcess().GetAddressByteSize() 639061da546Spatrick self.count = None 640061da546Spatrick try: 641061da546Spatrick self.find_block_size() 642061da546Spatrick except: 643061da546Spatrick self.block_size = -1 644061da546Spatrick self.element_size = -1 645061da546Spatrick logger.write( 646061da546Spatrick "block_size=%d, element_size=%d" % 647061da546Spatrick (self.block_size, self.element_size)) 648061da546Spatrick 649061da546Spatrick def find_block_size(self): 650061da546Spatrick # in order to use the deque we must have the block size, or else 651061da546Spatrick # it's impossible to know what memory addresses are valid 652061da546Spatrick self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) 653061da546Spatrick self.element_size = self.element_type.GetByteSize() 654061da546Spatrick # The code says this, but there must be a better way: 655061da546Spatrick # template <class _Tp, class _Allocator> 656061da546Spatrick # class __deque_base { 657061da546Spatrick # static const difference_type __block_size = sizeof(value_type) < 256 ? 4096 / sizeof(value_type) : 16; 658061da546Spatrick # } 659061da546Spatrick if self.element_size < 256: 660*f6aab3d8Srobert self.block_size = 4096 // self.element_size 661061da546Spatrick else: 662061da546Spatrick self.block_size = 16 663061da546Spatrick 664061da546Spatrick def num_children(self): 665061da546Spatrick logger = lldb.formatters.Logger.Logger() 666061da546Spatrick if self.count is None: 667061da546Spatrick return 0 668*f6aab3d8Srobert return self.count 669061da546Spatrick 670061da546Spatrick def has_children(self): 671061da546Spatrick return True 672061da546Spatrick 673061da546Spatrick def get_child_index(self, name): 674061da546Spatrick logger = lldb.formatters.Logger.Logger() 675061da546Spatrick try: 676061da546Spatrick return int(name.lstrip('[').rstrip(']')) 677061da546Spatrick except: 678061da546Spatrick return -1 679061da546Spatrick 680061da546Spatrick def get_child_at_index(self, index): 681061da546Spatrick logger = lldb.formatters.Logger.Logger() 682061da546Spatrick logger.write("Fetching child " + str(index)) 683061da546Spatrick if index < 0 or self.count is None: 684061da546Spatrick return None 685061da546Spatrick if index >= self.num_children(): 686061da546Spatrick return None 687061da546Spatrick try: 688061da546Spatrick i, j = divmod(self.start + index, self.block_size) 689*f6aab3d8Srobert 690061da546Spatrick return self.first.CreateValueFromExpression( 691061da546Spatrick '[' + str(index) + ']', '*(*(%s + %d) + %d)' % 692*f6aab3d8Srobert (self.map_begin.get_expr_path(), i, j)) 693061da546Spatrick except: 694061da546Spatrick return None 695061da546Spatrick 696061da546Spatrick def _get_value_of_compressed_pair(self, pair): 697061da546Spatrick value = pair.GetChildMemberWithName("__value_") 698061da546Spatrick if not value.IsValid(): 699061da546Spatrick # pre-r300140 member name 700061da546Spatrick value = pair.GetChildMemberWithName("__first_") 701061da546Spatrick return value.GetValueAsUnsigned(0) 702061da546Spatrick 703061da546Spatrick def update(self): 704061da546Spatrick logger = lldb.formatters.Logger.Logger() 705061da546Spatrick try: 706061da546Spatrick # A deque is effectively a two-dim array, with fixed width. 707061da546Spatrick # 'map' contains pointers to the rows of this array. The 708061da546Spatrick # full memory area allocated by the deque is delimited 709061da546Spatrick # by 'first' and 'end_cap'. However, only a subset of this 710061da546Spatrick # memory contains valid data since a deque may have some slack 711061da546Spatrick # at the front and back in order to have O(1) insertion at 712061da546Spatrick # both ends. The rows in active use are delimited by 713061da546Spatrick # 'begin' and 'end'. 714061da546Spatrick # 715061da546Spatrick # To find the elements that are actually constructed, the 'start' 716061da546Spatrick # variable tells which element in this NxM array is the 0th 717061da546Spatrick # one, and the 'size' element gives the number of elements 718061da546Spatrick # in the deque. 719061da546Spatrick count = self._get_value_of_compressed_pair( 720061da546Spatrick self.valobj.GetChildMemberWithName('__size_')) 721061da546Spatrick # give up now if we cant access memory reliably 722061da546Spatrick if self.block_size < 0: 723061da546Spatrick logger.write("block_size < 0") 724061da546Spatrick return 725061da546Spatrick map_ = self.valobj.GetChildMemberWithName('__map_') 726061da546Spatrick start = self.valobj.GetChildMemberWithName( 727061da546Spatrick '__start_').GetValueAsUnsigned(0) 728061da546Spatrick first = map_.GetChildMemberWithName('__first_') 729061da546Spatrick map_first = first.GetValueAsUnsigned(0) 730*f6aab3d8Srobert self.map_begin = map_.GetChildMemberWithName( 731*f6aab3d8Srobert '__begin_') 732*f6aab3d8Srobert map_begin = self.map_begin.GetValueAsUnsigned(0) 733061da546Spatrick map_end = map_.GetChildMemberWithName( 734061da546Spatrick '__end_').GetValueAsUnsigned(0) 735061da546Spatrick map_endcap = self._get_value_of_compressed_pair( 736061da546Spatrick map_.GetChildMemberWithName( '__end_cap_')) 737*f6aab3d8Srobert 738061da546Spatrick # check consistency 739061da546Spatrick if not map_first <= map_begin <= map_end <= map_endcap: 740061da546Spatrick logger.write("map pointers are not monotonic") 741061da546Spatrick return 742061da546Spatrick total_rows, junk = divmod( 743061da546Spatrick map_endcap - map_first, self.pointer_size) 744061da546Spatrick if junk: 745061da546Spatrick logger.write("endcap-first doesnt align correctly") 746061da546Spatrick return 747061da546Spatrick active_rows, junk = divmod(map_end - map_begin, self.pointer_size) 748061da546Spatrick if junk: 749061da546Spatrick logger.write("end-begin doesnt align correctly") 750061da546Spatrick return 751061da546Spatrick start_row, junk = divmod(map_begin - map_first, self.pointer_size) 752061da546Spatrick if junk: 753061da546Spatrick logger.write("begin-first doesnt align correctly") 754061da546Spatrick return 755*f6aab3d8Srobert 756061da546Spatrick logger.write( 757061da546Spatrick "update success: count=%r, start=%r, first=%r" % 758061da546Spatrick (count, start, first)) 759061da546Spatrick # if consistent, save all we really need: 760061da546Spatrick self.count = count 761061da546Spatrick self.start = start 762061da546Spatrick self.first = first 763061da546Spatrick except: 764061da546Spatrick self.count = None 765061da546Spatrick self.start = None 766061da546Spatrick self.map_first = None 767061da546Spatrick self.map_begin = None 768*f6aab3d8Srobert return False 769061da546Spatrick 770061da546Spatrick 771061da546Spatrickclass stdsharedptr_SynthProvider: 772061da546Spatrick 773061da546Spatrick def __init__(self, valobj, d): 774061da546Spatrick logger = lldb.formatters.Logger.Logger() 775061da546Spatrick logger.write("init") 776061da546Spatrick self.valobj = valobj 777061da546Spatrick #self.element_ptr_type = self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType() 778061da546Spatrick self.ptr = None 779061da546Spatrick self.cntrl = None 780061da546Spatrick process = valobj.GetProcess() 781061da546Spatrick self.endianness = process.GetByteOrder() 782061da546Spatrick self.pointer_size = process.GetAddressByteSize() 783061da546Spatrick self.count_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) 784061da546Spatrick 785061da546Spatrick def num_children(self): 786061da546Spatrick return 1 787061da546Spatrick 788061da546Spatrick def has_children(self): 789061da546Spatrick return True 790061da546Spatrick 791061da546Spatrick def get_child_index(self, name): 792061da546Spatrick if name == "__ptr_": 793061da546Spatrick return 0 794061da546Spatrick if name == "count": 795061da546Spatrick return 1 796061da546Spatrick if name == "weak_count": 797061da546Spatrick return 2 798061da546Spatrick return -1 799061da546Spatrick 800061da546Spatrick def get_child_at_index(self, index): 801061da546Spatrick if index == 0: 802061da546Spatrick return self.ptr 803061da546Spatrick if index == 1: 804061da546Spatrick if self.cntrl is None: 805061da546Spatrick count = 0 806061da546Spatrick else: 807061da546Spatrick count = 1 + \ 808061da546Spatrick self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned() 809061da546Spatrick return self.valobj.CreateValueFromData( 810061da546Spatrick "count", lldb.SBData.CreateDataFromUInt64Array( 811061da546Spatrick self.endianness, self.pointer_size, [count]), self.count_type) 812061da546Spatrick if index == 2: 813061da546Spatrick if self.cntrl is None: 814061da546Spatrick count = 0 815061da546Spatrick else: 816061da546Spatrick count = 1 + \ 817061da546Spatrick self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned() 818061da546Spatrick return self.valobj.CreateValueFromData( 819061da546Spatrick "weak_count", lldb.SBData.CreateDataFromUInt64Array( 820061da546Spatrick self.endianness, self.pointer_size, [count]), self.count_type) 821061da546Spatrick return None 822061da546Spatrick 823061da546Spatrick def update(self): 824061da546Spatrick logger = lldb.formatters.Logger.Logger() 825061da546Spatrick self.ptr = self.valobj.GetChildMemberWithName( 826061da546Spatrick '__ptr_') # .Cast(self.element_ptr_type) 827061da546Spatrick cntrl = self.valobj.GetChildMemberWithName('__cntrl_') 828061da546Spatrick if cntrl.GetValueAsUnsigned(0): 829061da546Spatrick self.cntrl = cntrl.Dereference() 830061da546Spatrick else: 831061da546Spatrick self.cntrl = None 832061da546Spatrick 833061da546Spatrick# we can use two different categories for old and new formatters - type names are different enough that we should make no confusion 834061da546Spatrick# talking with libc++ developer: "std::__1::class_name is set in stone 835061da546Spatrick# until we decide to change the ABI. That shouldn't happen within a 5 year 836061da546Spatrick# time frame" 837061da546Spatrick 838061da546Spatrick 839061da546Spatrickdef __lldb_init_module(debugger, dict): 840061da546Spatrick debugger.HandleCommand( 841061da546Spatrick 'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx') 842061da546Spatrick debugger.HandleCommand( 843061da546Spatrick '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') 844061da546Spatrick debugger.HandleCommand( 845061da546Spatrick 'type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx') 846061da546Spatrick debugger.HandleCommand( 847061da546Spatrick 'type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx') 848061da546Spatrick debugger.HandleCommand( 849061da546Spatrick 'type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx') 850061da546Spatrick debugger.HandleCommand( 851061da546Spatrick 'type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx') 852061da546Spatrick debugger.HandleCommand( 853061da546Spatrick 'type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx') 854061da546Spatrick debugger.HandleCommand( 855061da546Spatrick 'type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx') 856061da546Spatrick debugger.HandleCommand("type category enable libcxx") 857061da546Spatrick debugger.HandleCommand( 858061da546Spatrick 'type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx') 859061da546Spatrick debugger.HandleCommand( 860061da546Spatrick 'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx') 861061da546Spatrick # turns out the structs look the same, so weak_ptr can be handled the same! 862061da546Spatrick debugger.HandleCommand( 863061da546Spatrick 'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx') 864061da546Spatrick 865061da546Spatrick_map_capping_size = 255 866061da546Spatrick_list_capping_size = 255 867061da546Spatrick_list_uses_loop_detector = True 868