[Lldb-commits] [lldb] r153676 - in /lldb/trunk: examples/summaries/cocoa/Logger.py examples/summaries/cocoa/NSData.py examples/synthetic/gnu_libstdcpp.py examples/synthetic/libcxx.py scripts/Python/finish-swig-Python-LLDB.sh source/Interpreter/ScriptInterpreterPython.cpp

Enrico Granata egranata at apple.com
Thu Mar 29 12:29:45 PDT 2012


Author: enrico
Date: Thu Mar 29 14:29:45 2012
New Revision: 153676

URL: http://llvm.org/viewvc/llvm-project?rev=153676&view=rev
Log:
Part 1 of a series of fixes meant to improve reliability and increase ease of bug fixing for data formatter issues.
We are introducing a new Logger class on the Python side. This has the same purpose, but is unrelated, to the C++ logging facility
The Pythonic logging can be enabled by using the following scripting commands:
(lldb) script Logger._lldb_formatters_debug_level = {0,1,2,...}
0 = no logging
1 = do log
2 = flush after logging each line - slower but safer
3 or more = each time a Logger is constructed, log the function that has created it
more log levels may be added, each one being more log-active than the previous
by default, the log output will come out on your screen, to direct it to a file:
(lldb) script Logger._lldb_formatters_debug_filename = 'filename'
that will make the output go to the file - set to None to disable the file output and get screen logging back
Logging has been enabled for the C++ STL formatters and for Cocoa class NSData - more logging will follow


synthetic children providers for classes list and map (both libstdcpp and libcxx) now have internal capping for safety reasons
this will fix crashers where a malformed list or map would not ever meet our termination conditions

to set the cap to a different value:

(lldb) script {gnu_libstdcpp|libcxx}.{map|list}_capping_size = new_cap (by default, it is 255)

you can optionally disable the loop detection algorithm for lists

(lldb) script {gnu_libstdcpp|libcxx}.list_uses_loop_detector = False

Added:
    lldb/trunk/examples/summaries/cocoa/Logger.py
Modified:
    lldb/trunk/examples/summaries/cocoa/NSData.py
    lldb/trunk/examples/synthetic/gnu_libstdcpp.py
    lldb/trunk/examples/synthetic/libcxx.py
    lldb/trunk/scripts/Python/finish-swig-Python-LLDB.sh
    lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp

Added: lldb/trunk/examples/summaries/cocoa/Logger.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/summaries/cocoa/Logger.py?rev=153676&view=auto
==============================================================================
--- lldb/trunk/examples/summaries/cocoa/Logger.py (added)
+++ lldb/trunk/examples/summaries/cocoa/Logger.py Thu Mar 29 14:29:45 2012
@@ -0,0 +1,122 @@
+from __future__ import print_function
+import sys
+import os.path
+import inspect
+
+class NopLogger:
+	def __init__(self):
+		pass
+
+	def write(self,data):
+		pass
+
+	def flush(self):
+		pass
+
+	def close(self):
+		pass
+
+
+class StdoutLogger:
+	def __init__(self):
+		pass
+
+	def write(self,data):
+		print(data)
+
+	def flush(self):
+		pass
+
+	def close(self):
+		pass
+
+class FileLogger:
+	def __init__(self, name):
+		self.file = None
+		try:
+			name = os.path.abspath(name)
+			self.file = open(name,'a')
+		except:
+			try:
+				self.file = open('formatters.log','a')
+			except:
+				pass
+
+	def write(self,data):
+		if self.file != None:
+			print(data,file=self.file)
+		else:
+			print(data)
+
+	def flush(self):
+		if self.file != None:
+			self.file.flush()
+
+	def close(self):
+		if self.file != None:
+			self.file.close()
+			self.file = None
+
+# to enable logging:
+# define Logger._lldb_formatters_debug_level to any number greater than 0
+# if you define it to any value greater than 1, the log will be automatically flushed after each write (slower but should make sure most of the stuff makes it to the log even if we crash)
+# if you define it to any value greater than 2, the calling function's details will automatically be logged (even slower, but provides additional details)
+# if you need the log to go to a file instead of on screen, define Logger._lldb_formatters_debug_filename to a valid filename
+class Logger:
+	def __init__(self,autoflush=False,logcaller=False):
+		global _lldb_formatters_debug_level
+		global _lldb_formatters_debug_filename
+		self.autoflush = autoflush
+		want_log = False
+		try:
+			want_log = (_lldb_formatters_debug_level > 0)
+		except:
+			pass
+		if not (want_log):
+			self.impl = NopLogger()
+			return
+		want_file = False
+		try:
+			want_file = (_lldb_formatters_debug_filename != None and _lldb_formatters_debug_filename != '' and _lldb_formatters_debug_filename != 0)
+		except:
+			pass
+		if want_file:
+			self.impl = FileLogger(_lldb_formatters_debug_filename)
+		else:
+			self.impl = StdoutLogger()
+		try:
+			self.autoflush = (_lldb_formatters_debug_level > 1)
+		except:
+			self.autoflush = autoflush
+		want_caller_info = False
+		try:
+			want_caller_info = (_lldb_formatters_debug_level > 2)
+		except:
+			pass
+		if want_caller_info:
+			self._log_caller()
+
+	def _log_caller(self):
+		caller = inspect.stack()[2]
+		try:
+			if caller != None and len(caller) > 3:
+				self.write('Logging from function ' + str(caller))
+			else:
+				self.write('Caller info not available - Required caller logging not possible')
+		finally:
+			del caller # needed per Python docs to avoid keeping objects alive longer than we care
+
+	def write(self,data):
+		self.impl.write(data)
+		if self.autoflush:
+			self.flush()
+
+	def __rshift__(self,data):
+		self.write(data)
+
+	def flush(self):
+		self.impl.flush()
+
+	def close(self):
+		self.impl.close()
+

Modified: lldb/trunk/examples/summaries/cocoa/NSData.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/summaries/cocoa/NSData.py?rev=153676&r1=153675&r2=153676&view=diff
==============================================================================
--- lldb/trunk/examples/summaries/cocoa/NSData.py (original)
+++ lldb/trunk/examples/summaries/cocoa/NSData.py Thu Mar 29 14:29:45 2012
@@ -10,6 +10,7 @@
 import ctypes
 import objc_runtime
 import metrics
+import Logger
 
 statistics = metrics.Metrics()
 statistics.add_metric('invalid_isa')
@@ -25,6 +26,8 @@
 		pass
 
 	def __init__(self, valobj, params):
+		logger = Logger.Logger()
+		logger >> "NSConcreteData_SummaryProvider __init__"
 		self.valobj = valobj;
 		self.sys_params = params
 		if not(self.sys_params.types_cache.NSUInteger):
@@ -46,9 +49,13 @@
 		return 2 * self.sys_params.pointer_size
 
 	def length(self):
+		logger = Logger.Logger()
+		logger >> "NSConcreteData_SummaryProvider length"
 		size = self.valobj.CreateChildAtOffset("count",
 							self.offset(),
 							self.sys_params.types_cache.NSUInteger)
+		logger >> str(size)
+		logger >> str(size.GetValueAsUnsigned(0))
 		return size.GetValueAsUnsigned(0)
 
 
@@ -57,6 +64,8 @@
 		pass
 
 	def __init__(self, valobj, params):
+		logger = Logger.Logger()
+		logger >> "NSDataUnknown_SummaryProvider __init__"
 		self.valobj = valobj;
 		self.sys_params = params
 		self.update();
@@ -65,21 +74,31 @@
 		self.adjust_for_architecture();
 
 	def length(self):
+		logger = Logger.Logger()
+		logger >> "NSDataUnknown_SummaryProvider length"
 		stream = lldb.SBStream()
 		self.valobj.GetExpressionPath(stream)
+		logger >> stream.GetData()
 		num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " length]");
+		logger >> "still in after expression: " + str(num_children_vo)
 		if num_children_vo.IsValid():
+			logger >> "wow - expr output is valid: " + str(num_children_vo.GetValueAsUnsigned())
 			return num_children_vo.GetValueAsUnsigned(0)
+		logger >> "invalid expr output - too bad"
 		return '<variable is not NSData>'
 
 
 def GetSummary_Impl(valobj):
 	global statistics
+	logger = Logger.Logger()
+	logger >> "NSData GetSummary_Impl"
 	class_data,wrapper = objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
 	if wrapper:
+		logger >> "got a wrapper summary - using it"
 		return wrapper
 	
 	name_string = class_data.class_name()
+	logger >> "class name: " + name_string
 	if name_string == 'NSConcreteData' or \
 	   name_string == 'NSConcreteMutableData' or \
 	   name_string == '__NSCFData':
@@ -91,12 +110,16 @@
 	return wrapper;
 
 def NSData_SummaryProvider (valobj,dict):
+	logger = Logger.Logger()
+	logger >> "NSData_SummaryProvider"
 	provider = GetSummary_Impl(valobj);
+	logger >> "found a summary provider, it is: " + str(provider)
 	if provider != None:
 		try:
 			summary = provider.length();
 		except:
 			summary = None
+		logger >> "got a summary: it is " + str(summary)
 		if summary == None:
 			summary = '<variable is not NSData>'
 		elif isinstance(summary,basestring):
@@ -110,7 +133,10 @@
 	return 'Summary Unavailable'
 
 def NSData_SummaryProvider2 (valobj,dict):
+	logger = Logger.Logger()
+	logger >> "NSData_SummaryProvider2"
 	provider = GetSummary_Impl(valobj);
+	logger >> "found a summary provider, it is: " + str(provider)
 	if provider != None:
 		if isinstance(provider,objc_runtime.SpecialSituation_Description):
 			return provider.message()
@@ -118,6 +144,7 @@
 			summary = provider.length();
 		except:
 			summary = None
+		logger >> "got a summary: it is " + str(summary)
 		if summary == None:
 			summary = '<variable is not CFData>'
 		elif isinstance(summary,basestring):

Modified: lldb/trunk/examples/synthetic/gnu_libstdcpp.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/synthetic/gnu_libstdcpp.py?rev=153676&r1=153675&r2=153676&view=diff
==============================================================================
--- lldb/trunk/examples/synthetic/gnu_libstdcpp.py (original)
+++ lldb/trunk/examples/synthetic/gnu_libstdcpp.py Thu Mar 29 14:29:45 2012
@@ -1,4 +1,5 @@
 import re
+import Logger
 
 # C++ STL formatters for LLDB
 # These formatters are based upon the version of the GNU libstdc++
@@ -9,20 +10,29 @@
 class StdListSynthProvider:
 
 	def __init__(self, valobj, dict):
+		logger = Logger.Logger()
 		self.valobj = valobj
 
 	def next_node(self,node):
+		logger = Logger.Logger()
 		return node.GetChildMemberWithName('_M_next')
 
 	def is_valid(self,node):
+		logger = Logger.Logger()
 		return self.value(self.next_node(node)) != self.node_address
 
 	def value(self,node):
+		logger = Logger.Logger()
 		return node.GetValueAsUnsigned()
 
 	# Floyd's cyle-finding algorithm
 	# try to detect if this list has a loop
 	def has_loop(self):
+		global _list_uses_loop_detector
+		logger = Logger.Logger()
+		if _list_uses_loop_detector == False:
+			logger >> "Asked not to use loop detection"
+			return False
 		slow = self.next
 		fast1 = self.next
 		fast2 = self.next
@@ -36,11 +46,17 @@
 		return False
 
 	def num_children(self):
+		global _list_capping_size
+		logger = Logger.Logger()
 		if self.count == None:
 			self.count = self.num_children_impl()
+			if self.count > _list_capping_size:
+				self.count = _list_capping_size
 		return self.count
 
 	def num_children_impl(self):
+		logger = Logger.Logger()
+		global _list_capping_size
 		try:
 			next_val = self.next.GetValueAsUnsigned(0)
 			prev_val = self.prev.GetValueAsUnsigned(0)
@@ -58,17 +74,21 @@
 			while current.GetChildMemberWithName('_M_next').GetValueAsUnsigned(0) != self.node_address:
 				size = size + 1
 				current = current.GetChildMemberWithName('_M_next')
+				if size > _list_capping_size:
+					return _list_capping_size
 			return (size - 1)
 		except:
 			return 0;
 
 	def get_child_index(self,name):
+		logger = Logger.Logger()
 		try:
 			return int(name.lstrip('[').rstrip(']'))
 		except:
 			return -1
 
 	def get_child_at_index(self,index):
+		logger = Logger.Logger()
 		if index < 0:
 			return None;
 		if index >= self.num_children():
@@ -84,6 +104,7 @@
 			return None
 
 	def extract_type(self):
+		logger = Logger.Logger()
 		list_type = self.valobj.GetType().GetUnqualifiedType()
 		if list_type.IsReferenceType():
 			list_type = list_type.GetDereferencedType()
@@ -94,6 +115,7 @@
 		return data_type
 
 	def update(self):
+		logger = Logger.Logger()
 		try:
 			impl = self.valobj.GetChildMemberWithName('_M_impl')
 			node = impl.GetChildMemberWithName('_M_node')
@@ -109,19 +131,23 @@
 class StdVectorSynthProvider:
 
 	def __init__(self, valobj, dict):
+		logger = Logger.Logger()
 		self.valobj = valobj;
 
 	def num_children(self):
+		logger = Logger.Logger()
 		if self.count == None:
 			self.count = self.num_children_impl()
 		return self.count
 
 	def is_valid_pointer(ptr,process):
+		logger = Logger.Logger()
 		error = lldb.SBError()
 		process.ReadMemory(ptr,1,error)
 		return False if error.Fail() else True
 
 	def num_children_impl(self):
+		logger = Logger.Logger()
 		try:
 			start_val = self.start.GetValueAsUnsigned(0)
 			finish_val = self.finish.GetValueAsUnsigned(0)
@@ -156,12 +182,14 @@
 			return 0;
 
 	def get_child_index(self,name):
+		logger = Logger.Logger()
 		try:
 			return int(name.lstrip('[').rstrip(']'))
 		except:
 			return -1
 
 	def get_child_at_index(self,index):
+		logger = Logger.Logger()
 		if index < 0:
 			return None;
 		if index >= self.num_children():
@@ -173,6 +201,7 @@
 			return None
 
 	def update(self):
+		logger = Logger.Logger()
 		try:
 			impl = self.valobj.GetChildMemberWithName('_M_impl')
 			self.start = impl.GetChildMemberWithName('_M_start')
@@ -192,7 +221,9 @@
 class StdMapSynthProvider:
 
 	def __init__(self, valobj, dict):
+		logger = Logger.Logger()
 		self.valobj = valobj;
+		logger >> "Providing synthetic children for a map named " + str(valobj.GetName())
 		
 	# we need this function as a temporary workaround for rdar://problem/10801549
 	# which prevents us from extracting the std::pair<K,V> SBType out of the template
@@ -202,6 +233,7 @@
 	# to replace the longer versions of std::string with the shorter one in order to be able
 	# to find the type name
 	def fixup_class_name(self, class_name):
+		logger = Logger.Logger()
 		if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
 			return 'std::basic_string<char>',True
 		if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
@@ -213,7 +245,12 @@
 		return class_name,False
 
 	def update(self):
+		logger = Logger.Logger()
 		try:
+			self.count = None
+			# 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
+			# if this gets set to True, then we will merrily return None for any child from that moment on
+			self.garbage = False
 			self.Mt = self.valobj.GetChildMemberWithName('_M_t')
 			self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl')
 			self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header')
@@ -254,25 +291,43 @@
 			pass
 
 	def num_children(self):
+		global _map_capping_size
+		logger = Logger.Logger()
+		if self.count == None:
+			self.count = self.num_children_impl()
+			if self.count > _map_capping_size:
+				self.count = _map_capping_size
+		return self.count
+
+	def num_children_impl(self):
+		logger = Logger.Logger()
 		try:
 			root_ptr_val = self.node_ptr_value(self.Mroot)
 			if root_ptr_val == 0:
 				return 0;
-			return self.Mimpl.GetChildMemberWithName('_M_node_count').GetValueAsUnsigned(0)
+			count = self.Mimpl.GetChildMemberWithName('_M_node_count').GetValueAsUnsigned(0)
+			logger >> "I have " + str(count) + " children available"
+			return count
 		except:
 			return 0;
 
 	def get_child_index(self,name):
+		logger = Logger.Logger()
 		try:
 			return int(name.lstrip('[').rstrip(']'))
 		except:
 			return -1
 
 	def get_child_at_index(self,index):
+		logger = Logger.Logger()
+		logger >> "Being asked to fetch child[" + str(index) + "]"
 		if index < 0:
 			return None
 		if index >= self.num_children():
 			return None;
+		if self.garbage:
+			logger >> "Returning None since we are a garbage tree"
+			return None
 		try:
 			offset = index
 			current = self.left(self.Mheader);
@@ -286,31 +341,53 @@
 
 	# utility functions
 	def node_ptr_value(self,node):
+		logger = Logger.Logger()
 		return node.GetValueAsUnsigned(0)
 
 	def right(self,node):
+		logger = Logger.Logger()
 		return node.GetChildMemberWithName("_M_right");
 
 	def left(self,node):
+		logger = Logger.Logger()
 		return node.GetChildMemberWithName("_M_left");
 
 	def parent(self,node):
+		logger = Logger.Logger()
 		return node.GetChildMemberWithName("_M_parent");
 
 	# from libstdc++ implementation of iterator for rbtree
 	def increment_node(self,node):
+		logger = Logger.Logger()
+		max_steps = self.num_children()
 		if self.node_ptr_value(self.right(node)) != 0:
 			x = self.right(node);
+			max_steps -= 1
 			while self.node_ptr_value(self.left(x)) != 0:
 				x = self.left(x);
+				max_steps -= 1
+				logger >> str(max_steps) + " more to go before giving up"
+				if max_steps <= 0:
+					self.garbage = True
+					return None
 			return x;
 		else:
 			x = node;
 			y = self.parent(x)
+			max_steps -= 1
 			while(self.node_ptr_value(x) == self.node_ptr_value(self.right(y))):
 				x = y;
 				y = self.parent(y);
+				max_steps -= 1
+				logger >> str(max_steps) + " more to go before giving up"
+				if max_steps <= 0:
+					self.garbage = True
+					return None
 			if self.node_ptr_value(self.right(x)) != self.node_ptr_value(y):
 				x = y;
 			return x;
 
+
+_map_capping_size = 255
+_list_capping_size = 255
+_list_uses_loop_detector = True

Modified: lldb/trunk/examples/synthetic/libcxx.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/examples/synthetic/libcxx.py?rev=153676&r1=153675&r2=153676&view=diff
==============================================================================
--- lldb/trunk/examples/synthetic/libcxx.py (original)
+++ lldb/trunk/examples/synthetic/libcxx.py Thu Mar 29 14:29:45 2012
@@ -1,4 +1,5 @@
 import lldb
+import Logger
 
 # libcxx STL formatters for LLDB
 # These formatters are based upon the implementation of libc++ that
@@ -27,6 +28,7 @@
 # no external significance - we access them by index since this saves a name lookup that would add
 # no information for readers of the code, but when possible try to use meaningful variable names
 def stdstring_SummaryProvider(valobj,dict):
+	logger = Logger.Logger()
 	r = valobj.GetChildAtIndex(0)
 	B = r.GetChildAtIndex(0)
 	first = B.GetChildAtIndex(0)
@@ -55,9 +57,11 @@
 class stdvector_SynthProvider:
 
 	def __init__(self, valobj, dict):
+		logger = Logger.Logger()
 		self.valobj = valobj;
 
 	def num_children(self):
+		logger = Logger.Logger()
 		try:
 			start_val = self.start.GetValueAsUnsigned(0)
 			finish_val = self.finish.GetValueAsUnsigned(0)
@@ -85,12 +89,14 @@
 			return 0;
 
 	def get_child_index(self,name):
+		logger = Logger.Logger()
 		try:
 			return int(name.lstrip('[').rstrip(']'))
 		except:
 			return -1
 
 	def get_child_at_index(self,index):
+		logger = Logger.Logger()
 		if index < 0:
 			return None;
 		if index >= self.num_children():
@@ -102,6 +108,7 @@
 			return None
 
 	def update(self):
+		logger = Logger.Logger()
 		try:
 			self.start = self.valobj.GetChildMemberWithName('__begin_')
 			self.finish = self.valobj.GetChildMemberWithName('__end_')
@@ -121,21 +128,27 @@
 class stdlist_entry:
 
 	def __init__(self,entry):
+		logger = Logger.Logger()
 		self.entry = entry
 
 	def _next_impl(self):
+		logger = Logger.Logger()
 		return stdlist_entry(self.entry.GetChildMemberWithName('__next_'))
 
 	def _prev_impl(self):
+		logger = Logger.Logger()
 		return stdlist_entry(self.entry.GetChildMemberWithName('__prev_'))
 
 	def _value_impl(self):
+		logger = Logger.Logger()
 		return self.entry.GetValueAsUnsigned(0)
 
 	def _isnull_impl(self):
+		logger = Logger.Logger()
 		return self._value_impl() == 0
 
 	def _sbvalue_impl(self):
+		logger = Logger.Logger()
 		return self.entry
 
 	next = property(_next_impl,None)
@@ -146,17 +159,21 @@
 class stdlist_iterator:
 
 	def increment_node(self,node):
+		logger = Logger.Logger()
 		if node.is_null:
 			return None
 		return node.next
 
 	def __init__(self,node):
+		logger = Logger.Logger()
 		self.node = stdlist_entry(node) # we convert the SBValue to an internal node object on entry
 
 	def value(self):
+		logger = Logger.Logger()
 		return self.node.sbvalue # and return the SBValue back on exit
 
 	def next(self):
+		logger = Logger.Logger()
 		node = self.increment_node(self.node)
 		if node != None and node.sbvalue.IsValid() and not(node.is_null):
 			self.node = node
@@ -165,6 +182,7 @@
 			return None
 
 	def advance(self,N):
+		logger = Logger.Logger()
 		if N < 0:
 			return None
 		if N == 0:
@@ -179,17 +197,25 @@
 
 class stdlist_SynthProvider:
 	def __init__(self, valobj, dict):
+		logger = Logger.Logger()
 		self.valobj = valobj
 
 	def next_node(self,node):
+		logger = Logger.Logger()
 		return node.GetChildMemberWithName('__next_')
 
 	def value(self,node):
+		logger = Logger.Logger()
 		return node.GetValueAsUnsigned()
 
 	# Floyd's cyle-finding algorithm
 	# try to detect if this list has a loop
 	def has_loop(self):
+		global _list_uses_loop_detector
+		logger = Logger.Logger()
+		if _list_uses_loop_detector == False:
+			logger >> "Asked not to use loop detection"
+			return False
 		slow = stdlist_entry(self.head)
 		fast1 = stdlist_entry(self.head)
 		fast2 = stdlist_entry(self.head)
@@ -203,11 +229,17 @@
 		return False
 
 	def num_children(self):
+		global _list_capping_size
+		logger = Logger.Logger()
 		if self.count == None:
 			self.count = self.num_children_impl()
+			if self.count > _list_capping_size:
+				self.count = _list_capping_size
 		return self.count
 
 	def num_children_impl(self):
+		global _list_capping_size
+		logger = Logger.Logger()
 		try:
 			next_val = self.head.GetValueAsUnsigned(0)
 			prev_val = self.tail.GetValueAsUnsigned(0)
@@ -225,17 +257,21 @@
 			while current.next.value != self.node_address:
 				size = size + 1
 				current = current.next
+				if size > _list_capping_size:
+					return _list_capping_size
 			return (size - 1)
 		except:
 			return 0;
 
 	def get_child_index(self,name):
+		logger = Logger.Logger()
 		try:
 			return int(name.lstrip('[').rstrip(']'))
 		except:
 			return -1
 
 	def get_child_at_index(self,index):
+		logger = Logger.Logger()
 		if index < 0:
 			return None;
 		if index >= self.num_children():
@@ -252,6 +288,7 @@
 			return None
 
 	def extract_type(self):
+		logger = Logger.Logger()
 		list_type = self.valobj.GetType().GetUnqualifiedType()
 		if list_type.IsReferenceType():
 			list_type = list_type.GetDereferencedType()
@@ -262,6 +299,7 @@
 		return data_type
 
 	def update(self):
+		logger = Logger.Logger()
 		try:
 			impl = self.valobj.GetChildMemberWithName('__end_')
 			self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
@@ -281,24 +319,31 @@
 # a tree node - this class makes the syntax in the actual iterator nicer to read and maintain
 class stdmap_iterator_node:
 	def _left_impl(self):
+		logger = Logger.Logger()
 		return stdmap_iterator_node(self.node.GetChildMemberWithName("__left_"))
 
 	def _right_impl(self):
+		logger = Logger.Logger()
 		return stdmap_iterator_node(self.node.GetChildMemberWithName("__right_"))
 
 	def _parent_impl(self):
+		logger = Logger.Logger()
 		return stdmap_iterator_node(self.node.GetChildMemberWithName("__parent_"))
 
 	def _value_impl(self):
+		logger = Logger.Logger()
 		return self.node.GetValueAsUnsigned(0)
 
 	def _sbvalue_impl(self):
+		logger = Logger.Logger()
 		return self.node
 
 	def _null_impl(self):
+		logger = Logger.Logger()
 		return self.value == 0
 
 	def __init__(self,node):
+		logger = Logger.Logger()
 		self.node = node
 
 	left = property(_left_impl,None)
@@ -312,13 +357,20 @@
 class stdmap_iterator:
 
 	def tree_min(self,x):
+		logger = Logger.Logger()
+		steps = 0
 		if x.is_null:
 			return None
 		while (not x.left.is_null):
 			x = x.left
+			steps += 1
+			if steps > self.max_count:
+				logger >> "Returning None - we overflowed"
+				return None
 		return x
 
 	def tree_max(self,x):
+		logger = Logger.Logger()
 		if x.is_null:
 			return None
 		while (not x.right.is_null):
@@ -326,26 +378,37 @@
 		return x
 
 	def tree_is_left_child(self,x):
+		logger = Logger.Logger()
 		if x.is_null:
 			return None
 		return True if x.value == x.parent.left.value else False
 
 	def increment_node(self,node):
+		logger = Logger.Logger()
 		if node.is_null:
 			return None
 		if not node.right.is_null:
 			return self.tree_min(node.right)
+		steps = 0
 		while (not self.tree_is_left_child(node)):
+			steps += 1
+			if steps > self.max_count:
+				logger >> "Returning None - we overflowed"
+				return None
 			node = node.parent
 		return node.parent
 
-	def __init__(self,node):
+	def __init__(self,node,max_count=0):
+		logger = Logger.Logger()
 		self.node = stdmap_iterator_node(node) # we convert the SBValue to an internal node object on entry
+		self.max_count = max_count
 
 	def value(self):
+		logger = Logger.Logger()
 		return self.node.sbvalue # and return the SBValue back on exit
 
 	def next(self):
+		logger = Logger.Logger()
 		node = self.increment_node(self.node)
 		if node != None and node.sbvalue.IsValid() and not(node.is_null):
 			self.node = node
@@ -354,6 +417,7 @@
 			return None
 
 	def advance(self,N):
+		logger = Logger.Logger()
 		if N < 0:
 			return None
 		if N == 0:
@@ -361,18 +425,24 @@
 		if N == 1:
 			return self.next()
 		while N > 0:
-			self.next()
+			if self.next() == None:
+				return None
 			N = N - 1
 		return self.value()
 
 class stdmap_SynthProvider:
 
 	def __init__(self, valobj, dict):
+		logger = Logger.Logger()
 		self.valobj = valobj;
 		self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
 
 	def update(self):
+		logger = Logger.Logger()
 		try:
+			# 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
+			# if this gets set to True, then we will merrily return None for any child from that moment on
+			self.garbage = False
 			self.tree = self.valobj.GetChildMemberWithName('__tree_')
 			self.root_node = self.tree.GetChildMemberWithName('__begin_node_')
 			# this data is either lazily-calculated, or cannot be inferred at this moment
@@ -385,17 +455,23 @@
 			pass
 
 	def num_children(self):
+		global _map_capping_size
+		logger = Logger.Logger()
 		if self.count == None:
 			self.count = self.num_children_impl()
+			if self.count > _map_capping_size:
+				self.count = _map_capping_size
 		return self.count
 
 	def num_children_impl(self):
+		logger = Logger.Logger()
 		try:
 			return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName('__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned()
 		except:
 			return 0;
 
 	def get_data_type(self):
+		logger = Logger.Logger()
 		if self.data_type == None or self.data_size == None:
 			if self.num_children() == 0:
 				return False
@@ -413,6 +489,7 @@
 			return True
 
 	def get_value_offset(self,node):
+		logger = Logger.Logger()
 		if self.skip_size == None:
 			node_type = node.GetType()
 			fields_count = node_type.GetNumberOfFields()
@@ -424,24 +501,31 @@
 		return (self.skip_size != None)
 
 	def get_child_index(self,name):
+		logger = Logger.Logger()
 		try:
 			return int(name.lstrip('[').rstrip(']'))
 		except:
 			return -1
 
 	def get_child_at_index(self,index):
+		logger = Logger.Logger()
 		if index < 0:
 			return None
 		if index >= self.num_children():
 			return None;
+		if self.garbage:
+			return None
 		try:
-			iterator = stdmap_iterator(self.root_node)
+			iterator = stdmap_iterator(self.root_node,max_count=self.num_children())
 			# the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type
 			# out of which we can grab the information we need - every other node has a less informative
 			# type which omits all value information and only contains housekeeping information for the RB tree
 			# hence, we need to know if we are at a node != 0, so that we can still get at the data
 			need_to_skip = (index > 0)
 			current = iterator.advance(index)
+			if current == None:
+				self.garbage = True
+				return None
 			if self.get_data_type():
 				if not(need_to_skip):
 					current = current.Dereference()
@@ -481,3 +565,7 @@
 	debugger.HandleCommand('type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx')
 	debugger.HandleCommand('type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx')
 	debugger.HandleCommand("type category enable libcxx")
+
+_map_capping_size = 255
+_list_capping_size = 255
+_list_uses_loop_detector = True

Modified: lldb/trunk/scripts/Python/finish-swig-Python-LLDB.sh
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/finish-swig-Python-LLDB.sh?rev=153676&r1=153675&r2=153676&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/finish-swig-Python-LLDB.sh (original)
+++ lldb/trunk/scripts/Python/finish-swig-Python-LLDB.sh Thu Mar 29 14:29:45 2012
@@ -508,6 +508,20 @@
     fi
 fi
 
+if [ -f "${SRC_ROOT}/examples/summaries/cocoa/Logger.py" ]
+then
+    if [ $Debug == 1 ]
+    then
+        echo "Copying Logger.py to ${framework_python_dir}"
+    fi
+    cp "${SRC_ROOT}/examples/summaries/cocoa/Logger.py" "${framework_python_dir}"
+else
+    if [ $Debug == 1 ]
+    then
+        echo "Unable to find ${SRC_ROOT}/examples/summaries/cocoa/Logger.py"
+    fi
+fi
+
 if [ -f "${SRC_ROOT}/examples/summaries/cocoa/objc_lldb.py" ]
 then
     if [ $Debug == 1 ]

Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=153676&r1=153675&r2=153676&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Thu Mar 29 14:29:45 2012
@@ -296,8 +296,7 @@
     
     int old_count = Debugger::TestDebuggerRefCount();
     
-
-    run_string.Printf ("run_one_line (%s, 'import copy, os, re, sys, uuid, lldb, gnu_libstdcpp, libcxx, objc')", m_dictionary_name.c_str());
+    run_string.Printf ("run_one_line (%s, 'import copy, os, re, sys, uuid, lldb, gnu_libstdcpp, libcxx, objc, Logger')", m_dictionary_name.c_str());
     PyRun_SimpleString (run_string.GetData());
 
     // WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set





More information about the lldb-commits mailing list