1*061da546Spatrickimport lldb 2*061da546Spatrick 3*061da546Spatrick_map_capping_size = 255 4*061da546Spatrick 5*061da546Spatrick 6*061da546Spatrickclass libcxx_hash_table_SynthProvider: 7*061da546Spatrick 8*061da546Spatrick def __init__(self, valobj, dict): 9*061da546Spatrick self.valobj = valobj 10*061da546Spatrick self.num_elements = None 11*061da546Spatrick self.next_element = None 12*061da546Spatrick self.bucket_count = None 13*061da546Spatrick 14*061da546Spatrick def update(self): 15*061da546Spatrick logger = lldb.formatters.Logger.Logger() 16*061da546Spatrick self.num_elements = None 17*061da546Spatrick self.next_element = None 18*061da546Spatrick self.bucket_count = None 19*061da546Spatrick try: 20*061da546Spatrick # unordered_map is made up of a hash_map, which has 4 pieces in it: 21*061da546Spatrick # bucket list : 22*061da546Spatrick # array of buckets 23*061da546Spatrick # p1 (pair): 24*061da546Spatrick # first - pointer to first loaded element 25*061da546Spatrick # p2 (pair): 26*061da546Spatrick # first - number of elements 27*061da546Spatrick # second - hash function 28*061da546Spatrick # p3 (pair): 29*061da546Spatrick # first - max_load_factor 30*061da546Spatrick # second - equality operator function 31*061da546Spatrick # 32*061da546Spatrick # For display, we actually don't need to go inside the buckets, since 'p1' has a way to iterate over all 33*061da546Spatrick # the elements directly. 34*061da546Spatrick # 35*061da546Spatrick # We will calculate other values about the map because they will be useful for the summary. 36*061da546Spatrick # 37*061da546Spatrick table = self.valobj.GetChildMemberWithName('__table_') 38*061da546Spatrick 39*061da546Spatrick bl_ptr = table.GetChildMemberWithName( 40*061da546Spatrick '__bucket_list_').GetChildMemberWithName('__ptr_') 41*061da546Spatrick self.bucket_array_ptr = bl_ptr.GetChildMemberWithName( 42*061da546Spatrick '__first_').GetValueAsUnsigned(0) 43*061da546Spatrick self.bucket_count = bl_ptr.GetChildMemberWithName('__second_').GetChildMemberWithName( 44*061da546Spatrick '__data_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) 45*061da546Spatrick logger >> "Bucket count = %r" % self.bucket_count 46*061da546Spatrick 47*061da546Spatrick self.begin_ptr = table.GetChildMemberWithName('__p1_').GetChildMemberWithName( 48*061da546Spatrick '__first_').GetChildMemberWithName('__next_') 49*061da546Spatrick 50*061da546Spatrick self.num_elements = table.GetChildMemberWithName( 51*061da546Spatrick '__p2_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) 52*061da546Spatrick self.max_load_factor = table.GetChildMemberWithName( 53*061da546Spatrick '__p3_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) 54*061da546Spatrick logger >> "Num elements = %r" % self.num_elements 55*061da546Spatrick 56*061da546Spatrick # save the pointers as we get them 57*061da546Spatrick # -- don't access this first element if num_element==0! 58*061da546Spatrick self.elements_cache = [] 59*061da546Spatrick if self.num_elements: 60*061da546Spatrick self.next_element = self.begin_ptr 61*061da546Spatrick else: 62*061da546Spatrick self.next_element = None 63*061da546Spatrick except Exception as e: 64*061da546Spatrick logger >> "Caught exception: %r" % e 65*061da546Spatrick pass 66*061da546Spatrick 67*061da546Spatrick def num_children(self): 68*061da546Spatrick global _map_capping_size 69*061da546Spatrick num_elements = self.num_elements 70*061da546Spatrick if num_elements is not None: 71*061da546Spatrick if num_elements > _map_capping_size: 72*061da546Spatrick num_elements = _map_capping_size 73*061da546Spatrick return num_elements 74*061da546Spatrick 75*061da546Spatrick def has_children(self): 76*061da546Spatrick return True 77*061da546Spatrick 78*061da546Spatrick def get_child_index(self, name): 79*061da546Spatrick logger = lldb.formatters.Logger.Logger() 80*061da546Spatrick try: 81*061da546Spatrick return int(name.lstrip('[').rstrip(']')) 82*061da546Spatrick except: 83*061da546Spatrick return -1 84*061da546Spatrick 85*061da546Spatrick def get_child_at_index(self, index): 86*061da546Spatrick logger = lldb.formatters.Logger.Logger() 87*061da546Spatrick logger >> "Retrieving child " + str(index) 88*061da546Spatrick if index < 0: 89*061da546Spatrick return None 90*061da546Spatrick if index >= self.num_children(): 91*061da546Spatrick return None 92*061da546Spatrick 93*061da546Spatrick # extend 94*061da546Spatrick logger >> " : cache size starts with %d elements" % len( 95*061da546Spatrick self.elements_cache) 96*061da546Spatrick while index >= len(self.elements_cache): 97*061da546Spatrick # if we hit the end before we get the index, give up: 98*061da546Spatrick if not self.next_element: 99*061da546Spatrick logger >> " : hit end of list" 100*061da546Spatrick return None 101*061da546Spatrick 102*061da546Spatrick node = self.next_element.Dereference() 103*061da546Spatrick 104*061da546Spatrick value = node.GetChildMemberWithName('__value_') 105*061da546Spatrick hash_value = node.GetChildMemberWithName( 106*061da546Spatrick '__hash_').GetValueAsUnsigned() 107*061da546Spatrick self.elements_cache.append((value, hash_value)) 108*061da546Spatrick 109*061da546Spatrick self.next_element = node.GetChildMemberWithName('__next_') 110*061da546Spatrick if not self.next_element.GetValueAsUnsigned(0): 111*061da546Spatrick self.next_element = None 112*061da546Spatrick 113*061da546Spatrick # hit the index! so we have the value 114*061da546Spatrick logger >> " : cache size ends with %d elements" % len( 115*061da546Spatrick self.elements_cache) 116*061da546Spatrick value, hash_value = self.elements_cache[index] 117*061da546Spatrick return self.valobj.CreateValueFromData( 118*061da546Spatrick '[%d] <hash %d>' % 119*061da546Spatrick (index, hash_value), value.GetData(), value.GetType()) 120*061da546Spatrick 121*061da546Spatrick 122*061da546Spatrickdef __lldb_init_module(debugger, dict): 123*061da546Spatrick debugger.HandleCommand( 124*061da546Spatrick 'type synthetic add -l unordered_multi.libcxx_hash_table_SynthProvider -x "^(std::__1::)unordered_(multi)?(map|set)<.+> >$" -w libcxx') 125