|  | import lldb | 
|  |  | 
|  | _map_capping_size = 255 | 
|  |  | 
|  |  | 
|  | class libcxx_hash_table_SynthProvider: | 
|  | def __init__(self, valobj, dict): | 
|  | self.valobj = valobj | 
|  | self.num_elements = None | 
|  | self.next_element = None | 
|  | self.bucket_count = None | 
|  |  | 
|  | def update(self): | 
|  | logger = lldb.formatters.Logger.Logger() | 
|  | self.num_elements = None | 
|  | self.next_element = None | 
|  | self.bucket_count = None | 
|  | try: | 
|  | # unordered_map is made up of a hash_map, which has 4 pieces in it: | 
|  | #   bucket list : | 
|  | #      array of buckets | 
|  | #   p1 (pair): | 
|  | #      first - pointer to first loaded element | 
|  | #   p2 (pair): | 
|  | #      first - number of elements | 
|  | #      second - hash function | 
|  | #   p3 (pair): | 
|  | #      first - max_load_factor | 
|  | #      second - equality operator function | 
|  | # | 
|  | # For display, we actually don't need to go inside the buckets, since 'p1' has a way to iterate over all | 
|  | # the elements directly. | 
|  | # | 
|  | # We will calculate other values about the map because they will be useful for the summary. | 
|  | # | 
|  | table = self.valobj.GetChildMemberWithName("__table_") | 
|  |  | 
|  | bl_ptr = table.GetChildMemberWithName( | 
|  | "__bucket_list_" | 
|  | ).GetChildMemberWithName("__ptr_") | 
|  | self.bucket_array_ptr = bl_ptr.GetChildMemberWithName( | 
|  | "__first_" | 
|  | ).GetValueAsUnsigned(0) | 
|  | self.bucket_count = ( | 
|  | bl_ptr.GetChildMemberWithName("__second_") | 
|  | .GetChildMemberWithName("__data_") | 
|  | .GetChildMemberWithName("__first_") | 
|  | .GetValueAsUnsigned(0) | 
|  | ) | 
|  | logger >> "Bucket count = %r" % self.bucket_count | 
|  |  | 
|  | self.begin_ptr = ( | 
|  | table.GetChildMemberWithName("__p1_") | 
|  | .GetChildMemberWithName("__first_") | 
|  | .GetChildMemberWithName("__next_") | 
|  | ) | 
|  |  | 
|  | self.num_elements = ( | 
|  | table.GetChildMemberWithName("__p2_") | 
|  | .GetChildMemberWithName("__first_") | 
|  | .GetValueAsUnsigned(0) | 
|  | ) | 
|  | self.max_load_factor = ( | 
|  | table.GetChildMemberWithName("__p3_") | 
|  | .GetChildMemberWithName("__first_") | 
|  | .GetValueAsUnsigned(0) | 
|  | ) | 
|  | logger >> "Num elements = %r" % self.num_elements | 
|  |  | 
|  | # save the pointers as we get them | 
|  | #   -- don't access this first element if num_element==0! | 
|  | self.elements_cache = [] | 
|  | if self.num_elements: | 
|  | self.next_element = self.begin_ptr | 
|  | else: | 
|  | self.next_element = None | 
|  | except Exception as e: | 
|  | logger >> "Caught exception: %r" % e | 
|  | pass | 
|  |  | 
|  | def num_children(self): | 
|  | global _map_capping_size | 
|  | num_elements = self.num_elements | 
|  | if num_elements is not None: | 
|  | if num_elements > _map_capping_size: | 
|  | num_elements = _map_capping_size | 
|  | return num_elements | 
|  |  | 
|  | def has_children(self): | 
|  | return True | 
|  |  | 
|  | def get_child_index(self, name): | 
|  | logger = lldb.formatters.Logger.Logger() | 
|  | try: | 
|  | return int(name.lstrip("[").rstrip("]")) | 
|  | except: | 
|  | return -1 | 
|  |  | 
|  | def get_child_at_index(self, index): | 
|  | logger = lldb.formatters.Logger.Logger() | 
|  | logger >> "Retrieving child " + str(index) | 
|  | if index < 0: | 
|  | return None | 
|  | if index >= self.num_children(): | 
|  | return None | 
|  |  | 
|  | # extend | 
|  | logger >> " : cache size starts with %d elements" % len(self.elements_cache) | 
|  | while index >= len(self.elements_cache): | 
|  | # if we hit the end before we get the index, give up: | 
|  | if not self.next_element: | 
|  | logger >> " : hit end of list" | 
|  | return None | 
|  |  | 
|  | node = self.next_element.Dereference() | 
|  |  | 
|  | value = node.GetChildMemberWithName("__value_") | 
|  | hash_value = node.GetChildMemberWithName("__hash_").GetValueAsUnsigned() | 
|  | self.elements_cache.append((value, hash_value)) | 
|  |  | 
|  | self.next_element = node.GetChildMemberWithName("__next_") | 
|  | if not self.next_element.GetValueAsUnsigned(0): | 
|  | self.next_element = None | 
|  |  | 
|  | # hit the index! so we have the value | 
|  | logger >> " : cache size ends with %d elements" % len(self.elements_cache) | 
|  | value, hash_value = self.elements_cache[index] | 
|  | return self.valobj.CreateValueFromData( | 
|  | "[%d] <hash %d>" % (index, hash_value), value.GetData(), value.GetType() | 
|  | ) | 
|  |  | 
|  |  | 
|  | def __lldb_init_module(debugger, dict): | 
|  | debugger.HandleCommand( | 
|  | 'type synthetic add -l unordered_multi.libcxx_hash_table_SynthProvider -x "^(std::__1::)unordered_(multi)?(map|set)<.+> >$" -w libcxx' | 
|  | ) |