1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
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'
)
|