Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 1 | import lldb |
| 2 | |
| 3 | _map_capping_size = 255 |
| 4 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 5 | |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 6 | class libcxx_hash_table_SynthProvider: |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 7 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 13 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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_') |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 38 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 46 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 47 | self.begin_ptr = table.GetChildMemberWithName('__p1_').GetChildMemberWithName( |
| 48 | '__first_').GetChildMemberWithName('__next_') |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 49 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 55 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 66 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 74 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 75 | def has_children(self): |
| 76 | return True |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 77 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 84 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 92 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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 |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 101 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 102 | node = self.next_element.Dereference() |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 103 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 104 | value = node.GetChildMemberWithName('__value_') |
| 105 | hash_value = node.GetChildMemberWithName( |
| 106 | '__hash_').GetValueAsUnsigned() |
| 107 | self.elements_cache.append((value, hash_value)) |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 108 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 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()) |
Enrico Granata | d589b34 | 2013-09-04 17:48:52 +0000 | [diff] [blame] | 120 | |
| 121 | |
Kate Stone | b9c1b51 | 2016-09-06 20:57:50 +0000 | [diff] [blame] | 122 | def __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') |