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