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