[RISCV] Add addu.w and slliu.w test that uses getelementptr with zero extended indices.
[lldb.git] / lldb / examples / synthetic / gnu_libstdcpp.py
1 from __future__ import division
2 import re
3 import lldb.formatters.Logger
4
5 # C++ STL formatters for LLDB
6 # These formatters are based upon the version of the GNU libstdc++
7 # as it ships with Mac OS X 10.6.8 thru 10.8.0
8 # You are encouraged to look at the STL implementation for your platform
9 # before relying on these formatters to do the right thing for your setup
10
11
12 class StdListSynthProvider:
13
14     def __init__(self, valobj, dict):
15         logger = lldb.formatters.Logger.Logger()
16         self.valobj = valobj
17         self.count = None
18         logger >> "Providing synthetic children for a list named " + \
19             str(valobj.GetName())
20
21     def next_node(self, node):
22         logger = lldb.formatters.Logger.Logger()
23         return node.GetChildMemberWithName('_M_next')
24
25     def is_valid(self, node):
26         logger = lldb.formatters.Logger.Logger()
27         valid = self.value(self.next_node(node)) != self.node_address
28         if valid:
29             logger >> "%s is valid" % str(self.valobj.GetName())
30         else:
31             logger >> "synthetic value is not valid"
32         return valid
33
34     def value(self, node):
35         logger = lldb.formatters.Logger.Logger()
36         value = node.GetValueAsUnsigned()
37         logger >> "synthetic value for {}: {}".format(
38             str(self.valobj.GetName()), value)
39         return value
40
41     # Floyd's cycle-finding algorithm
42     # try to detect if this list has a loop
43     def has_loop(self):
44         global _list_uses_loop_detector
45         logger = lldb.formatters.Logger.Logger()
46         if not _list_uses_loop_detector:
47             logger >> "Asked not to use loop detection"
48             return False
49         slow = self.next
50         fast1 = self.next
51         fast2 = self.next
52         while self.is_valid(slow):
53             slow_value = self.value(slow)
54             fast1 = self.next_node(fast2)
55             fast2 = self.next_node(fast1)
56             if self.value(fast1) == slow_value or self.value(
57                     fast2) == slow_value:
58                 return True
59             slow = self.next_node(slow)
60         return False
61
62     def num_children(self):
63         logger = lldb.formatters.Logger.Logger()
64         if self.count is None:
65             # libstdc++ 6.0.21 added dedicated count field.
66             count_child = self.node.GetChildMemberWithName('_M_data')
67             if count_child and count_child.IsValid():
68                 self.count = count_child.GetValueAsUnsigned(0)
69             if self.count is None:
70                 self.count = self.num_children_impl()
71         return self.count
72
73     def num_children_impl(self):
74         logger = lldb.formatters.Logger.Logger()
75         try:
76             next_val = self.next.GetValueAsUnsigned(0)
77             prev_val = self.prev.GetValueAsUnsigned(0)
78             # After a std::list has been initialized, both next and prev will
79             # be non-NULL
80             if next_val == 0 or prev_val == 0:
81                 return 0
82             if next_val == self.node_address:
83                 return 0
84             if next_val == prev_val:
85                 return 1
86             if self.has_loop():
87                 return 0
88             size = 2
89             current = self.next
90             while current.GetChildMemberWithName(
91                     '_M_next').GetValueAsUnsigned(0) != self.node_address:
92                 size = size + 1
93                 current = current.GetChildMemberWithName('_M_next')
94             return (size - 1)
95         except:
96             return 0
97
98     def get_child_index(self, name):
99         logger = lldb.formatters.Logger.Logger()
100         try:
101             return int(name.lstrip('[').rstrip(']'))
102         except:
103             return -1
104
105     def get_child_at_index(self, index):
106         logger = lldb.formatters.Logger.Logger()
107         logger >> "Fetching child " + str(index)
108         if index < 0:
109             return None
110         if index >= self.num_children():
111             return None
112         try:
113             offset = index
114             current = self.next
115             while offset > 0:
116                 current = current.GetChildMemberWithName('_M_next')
117                 offset = offset - 1
118             return current.CreateChildAtOffset(
119                 '[' + str(index) + ']',
120                 2 * current.GetType().GetByteSize(),
121                 self.data_type)
122         except:
123             return None
124
125     def extract_type(self):
126         logger = lldb.formatters.Logger.Logger()
127         list_type = self.valobj.GetType().GetUnqualifiedType()
128         if list_type.IsReferenceType():
129             list_type = list_type.GetDereferencedType()
130         if list_type.GetNumberOfTemplateArguments() > 0:
131             data_type = list_type.GetTemplateArgumentType(0)
132         else:
133             data_type = None
134         return data_type
135
136     def update(self):
137         logger = lldb.formatters.Logger.Logger()
138         # preemptively setting this to None - we might end up changing our mind
139         # later
140         self.count = None
141         try:
142             impl = self.valobj.GetChildMemberWithName('_M_impl')
143             self.node = impl.GetChildMemberWithName('_M_node')
144             self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
145             self.next = self.node.GetChildMemberWithName('_M_next')
146             self.prev = self.node.GetChildMemberWithName('_M_prev')
147             self.data_type = self.extract_type()
148             self.data_size = self.data_type.GetByteSize()
149         except:
150             pass
151
152     def has_children(self):
153         return True
154
155
156 class StdVectorSynthProvider:
157
158     class StdVectorImplementation(object):
159
160         def __init__(self, valobj):
161             self.valobj = valobj
162             self.count = None
163
164         def num_children(self):
165             if self.count is None:
166                 self.count = self.num_children_impl()
167             return self.count
168
169         def num_children_impl(self):
170             try:
171                 start_val = self.start.GetValueAsUnsigned(0)
172                 finish_val = self.finish.GetValueAsUnsigned(0)
173                 end_val = self.end.GetValueAsUnsigned(0)
174                 # Before a vector has been constructed, it will contain bad values
175                 # so we really need to be careful about the length we return since
176                 # uninitialized data can cause us to return a huge number. We need
177                 # to also check for any of the start, finish or end of storage values
178                 # being zero (NULL). If any are, then this vector has not been
179                 # initialized yet and we should return zero
180
181                 # Make sure nothing is NULL
182                 if start_val == 0 or finish_val == 0 or end_val == 0:
183                     return 0
184                 # Make sure start is less than finish
185                 if start_val >= finish_val:
186                     return 0
187                 # Make sure finish is less than or equal to end of storage
188                 if finish_val > end_val:
189                     return 0
190
191                 # if we have a struct (or other data type that the compiler pads to native word size)
192                 # this check might fail, unless the sizeof() we get is itself incremented to take the
193                 # padding bytes into account - on current clang it looks like
194                 # this is the case
195                 num_children = (finish_val - start_val)
196                 if (num_children % self.data_size) != 0:
197                     return 0
198                 else:
199                     num_children = num_children // self.data_size
200                 return num_children
201             except:
202                 return 0
203
204         def get_child_at_index(self, index):
205             logger = lldb.formatters.Logger.Logger()
206             logger >> "Retrieving child " + str(index)
207             if index < 0:
208                 return None
209             if index >= self.num_children():
210                 return None
211             try:
212                 offset = index * self.data_size
213                 return self.start.CreateChildAtOffset(
214                     '[' + str(index) + ']', offset, self.data_type)
215             except:
216                 return None
217
218         def update(self):
219             # preemptively setting this to None - we might end up changing our
220             # mind later
221             self.count = None
222             try:
223                 impl = self.valobj.GetChildMemberWithName('_M_impl')
224                 self.start = impl.GetChildMemberWithName('_M_start')
225                 self.finish = impl.GetChildMemberWithName('_M_finish')
226                 self.end = impl.GetChildMemberWithName('_M_end_of_storage')
227                 self.data_type = self.start.GetType().GetPointeeType()
228                 self.data_size = self.data_type.GetByteSize()
229                 # if any of these objects is invalid, it means there is no
230                 # point in trying to fetch anything
231                 if self.start.IsValid() and self.finish.IsValid(
232                 ) and self.end.IsValid() and self.data_type.IsValid():
233                     self.count = None
234                 else:
235                     self.count = 0
236             except:
237                 pass
238             return True
239
240     class StdVBoolImplementation(object):
241
242         def __init__(self, valobj, bool_type):
243             self.valobj = valobj
244             self.bool_type = bool_type
245             self.valid = False
246
247         def num_children(self):
248             if self.valid:
249                 start = self.start_p.GetValueAsUnsigned(0)
250                 finish = self.finish_p.GetValueAsUnsigned(0)
251                 offset = self.offset.GetValueAsUnsigned(0)
252                 if finish >= start:
253                     return (finish - start) * 8 + offset
254             return 0
255
256         def get_child_at_index(self, index):
257             if index >= self.num_children():
258                 return None
259             element_type = self.start_p.GetType().GetPointeeType()
260             element_bits = 8 * element_type.GetByteSize()
261             element_offset = (index // element_bits) * \
262                 element_type.GetByteSize()
263             bit_offset = index % element_bits
264             element = self.start_p.CreateChildAtOffset(
265                 '[' + str(index) + ']', element_offset, element_type)
266             bit = element.GetValueAsUnsigned(0) & (1 << bit_offset)
267             if bit != 0:
268                 value_expr = "(bool)true"
269             else:
270                 value_expr = "(bool)false"
271             return self.valobj.CreateValueFromExpression(
272                 "[%d]" % index, value_expr)
273
274         def update(self):
275             try:
276                 m_impl = self.valobj.GetChildMemberWithName('_M_impl')
277                 self.m_start = m_impl.GetChildMemberWithName('_M_start')
278                 self.m_finish = m_impl.GetChildMemberWithName('_M_finish')
279                 self.start_p = self.m_start.GetChildMemberWithName('_M_p')
280                 self.finish_p = self.m_finish.GetChildMemberWithName('_M_p')
281                 self.offset = self.m_finish.GetChildMemberWithName('_M_offset')
282                 self.valid = True
283             except:
284                 self.valid = False
285             return True
286
287     def __init__(self, valobj, dict):
288         logger = lldb.formatters.Logger.Logger()
289         first_template_arg_type = valobj.GetType().GetTemplateArgumentType(0)
290         if str(first_template_arg_type.GetName()) == "bool":
291             self.impl = self.StdVBoolImplementation(
292                 valobj, first_template_arg_type)
293         else:
294             self.impl = self.StdVectorImplementation(valobj)
295         logger >> "Providing synthetic children for a vector named " + \
296             str(valobj.GetName())
297
298     def num_children(self):
299         return self.impl.num_children()
300
301     def get_child_index(self, name):
302         try:
303             return int(name.lstrip('[').rstrip(']'))
304         except:
305             return -1
306
307     def get_child_at_index(self, index):
308         return self.impl.get_child_at_index(index)
309
310     def update(self):
311         return self.impl.update()
312
313     def has_children(self):
314         return True
315
316
317 class StdMapSynthProvider:
318
319     def __init__(self, valobj, dict):
320         logger = lldb.formatters.Logger.Logger()
321         self.valobj = valobj
322         self.count = None
323         logger >> "Providing synthetic children for a map named " + \
324             str(valobj.GetName())
325
326     # we need this function as a temporary workaround for rdar://problem/10801549
327     # which prevents us from extracting the std::pair<K,V> SBType out of the template
328     # arguments for _Rep_Type _M_t in the map itself - because we have to make up the
329     # typename and then find it, we may hit the situation were std::string has multiple
330     # names but only one is actually referenced in the debug information. hence, we need
331     # to replace the longer versions of std::string with the shorter one in order to be able
332     # to find the type name
333     def fixup_class_name(self, class_name):
334         logger = lldb.formatters.Logger.Logger()
335         if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
336             return 'std::basic_string<char>', True
337         if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
338             return 'std::basic_string<char>', True
339         if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
340             return 'std::basic_string<char>', True
341         if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
342             return 'std::basic_string<char>', True
343         return class_name, False
344
345     def update(self):
346         logger = lldb.formatters.Logger.Logger()
347         # preemptively setting this to None - we might end up changing our mind
348         # later
349         self.count = None
350         try:
351             # we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree
352             # if this gets set to True, then we will merrily return None for
353             # any child from that moment on
354             self.garbage = False
355             self.Mt = self.valobj.GetChildMemberWithName('_M_t')
356             self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl')
357             self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header')
358
359             map_type = self.valobj.GetType()
360             if map_type.IsReferenceType():
361                 logger >> "Dereferencing type"
362                 map_type = map_type.GetDereferencedType()
363
364             # Get the type of std::pair<key, value>. It is the first template
365             # argument type of the 4th template argument to std::map.
366             allocator_type = map_type.GetTemplateArgumentType(3)
367             self.data_type = allocator_type.GetTemplateArgumentType(0)
368             if not self.data_type:
369                 # GCC does not emit DW_TAG_template_type_parameter for
370                 # std::allocator<...>. For such a case, get the type of
371                 # std::pair from a member of std::map.
372                 rep_type = self.valobj.GetChildMemberWithName('_M_t').GetType()
373                 self.data_type = rep_type.GetTypedefedType().GetTemplateArgumentType(1)
374
375             # from libstdc++ implementation of _M_root for rbtree
376             self.Mroot = self.Mheader.GetChildMemberWithName('_M_parent')
377             self.data_size = self.data_type.GetByteSize()
378             self.skip_size = self.Mheader.GetType().GetByteSize()
379         except:
380             pass
381
382     def num_children(self):
383         logger = lldb.formatters.Logger.Logger()
384         if self.count is None:
385             self.count = self.num_children_impl()
386         return self.count
387
388     def num_children_impl(self):
389         logger = lldb.formatters.Logger.Logger()
390         try:
391             root_ptr_val = self.node_ptr_value(self.Mroot)
392             if root_ptr_val == 0:
393                 return 0
394             count = self.Mimpl.GetChildMemberWithName(
395                 '_M_node_count').GetValueAsUnsigned(0)
396             logger >> "I have " + str(count) + " children available"
397             return count
398         except:
399             return 0
400
401     def get_child_index(self, name):
402         logger = lldb.formatters.Logger.Logger()
403         try:
404             return int(name.lstrip('[').rstrip(']'))
405         except:
406             return -1
407
408     def get_child_at_index(self, index):
409         logger = lldb.formatters.Logger.Logger()
410         logger >> "Being asked to fetch child[" + str(index) + "]"
411         if index < 0:
412             return None
413         if index >= self.num_children():
414             return None
415         if self.garbage:
416             logger >> "Returning None since we are a garbage tree"
417             return None
418         try:
419             offset = index
420             current = self.left(self.Mheader)
421             while offset > 0:
422                 current = self.increment_node(current)
423                 offset = offset - 1
424             # skip all the base stuff and get at the data
425             return current.CreateChildAtOffset(
426                 '[' + str(index) + ']', self.skip_size, self.data_type)
427         except:
428             return None
429
430     # utility functions
431     def node_ptr_value(self, node):
432         logger = lldb.formatters.Logger.Logger()
433         return node.GetValueAsUnsigned(0)
434
435     def right(self, node):
436         logger = lldb.formatters.Logger.Logger()
437         return node.GetChildMemberWithName("_M_right")
438
439     def left(self, node):
440         logger = lldb.formatters.Logger.Logger()
441         return node.GetChildMemberWithName("_M_left")
442
443     def parent(self, node):
444         logger = lldb.formatters.Logger.Logger()
445         return node.GetChildMemberWithName("_M_parent")
446
447     # from libstdc++ implementation of iterator for rbtree
448     def increment_node(self, node):
449         logger = lldb.formatters.Logger.Logger()
450         max_steps = self.num_children()
451         if self.node_ptr_value(self.right(node)) != 0:
452             x = self.right(node)
453             max_steps -= 1
454             while self.node_ptr_value(self.left(x)) != 0:
455                 x = self.left(x)
456                 max_steps -= 1
457                 logger >> str(max_steps) + " more to go before giving up"
458                 if max_steps <= 0:
459                     self.garbage = True
460                     return None
461             return x
462         else:
463             x = node
464             y = self.parent(x)
465             max_steps -= 1
466             while(self.node_ptr_value(x) == self.node_ptr_value(self.right(y))):
467                 x = y
468                 y = self.parent(y)
469                 max_steps -= 1
470                 logger >> str(max_steps) + " more to go before giving up"
471                 if max_steps <= 0:
472                     self.garbage = True
473                     return None
474             if self.node_ptr_value(self.right(x)) != self.node_ptr_value(y):
475                 x = y
476             return x
477
478     def has_children(self):
479         return True
480
481 _list_uses_loop_detector = True