Package lldb :: Package formatters :: Package cpp :: Module gnu_libstdcpp
[hide private]
[frames] | no frames]

Source Code for Module lldb.formatters.cpp.gnu_libstdcpp

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