| """lldb data formatters for clang classes. | 
 |  | 
 | Usage | 
 | -- | 
 | import this file in your ~/.lldbinit by adding this line: | 
 |  | 
 | command script import /path/to/ClangDataFormat.py | 
 |  | 
 | After that, instead of getting this: | 
 |  | 
 | (lldb) p Tok.Loc | 
 | (clang::SourceLocation) $0 = { | 
 |   (unsigned int) ID = 123582 | 
 | } | 
 |  | 
 | you'll get: | 
 |  | 
 | (lldb) p Tok.Loc | 
 | (clang::SourceLocation) $4 = "/usr/include/i386/_types.h:37:1" (offset: 123582, file, local) | 
 | """ | 
 |  | 
 | import lldb | 
 |  | 
 | def __lldb_init_module(debugger, internal_dict): | 
 | 	debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation") | 
 | 	debugger.HandleCommand("type summary add -F ClangDataFormat.QualType_summary clang::QualType") | 
 | 	debugger.HandleCommand("type summary add -F ClangDataFormat.StringRef_summary llvm::StringRef") | 
 |  | 
 | def SourceLocation_summary(srcloc, internal_dict): | 
 | 	return SourceLocation(srcloc).summary() | 
 |  | 
 | def QualType_summary(qualty, internal_dict): | 
 | 	return QualType(qualty).summary() | 
 |  | 
 | def StringRef_summary(strref, internal_dict): | 
 | 	return StringRef(strref).summary() | 
 |  | 
 | class SourceLocation(object): | 
 | 	def __init__(self, srcloc): | 
 | 		self.srcloc = srcloc | 
 | 		self.ID = srcloc.GetChildAtIndex(0).GetValueAsUnsigned() | 
 | 		self.frame = srcloc.GetFrame() | 
 | 	 | 
 | 	def offset(self): | 
 | 		return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned() | 
 |  | 
 | 	def isInvalid(self): | 
 | 		return self.ID == 0 | 
 |  | 
 | 	def isMacro(self): | 
 | 		return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned() | 
 |  | 
 | 	def isLocal(self, srcmgr_path): | 
 | 		return self.frame.EvaluateExpression("(%s).isLocalSourceLocation(%s)" % (srcmgr_path, getExpressionPath(self.srcloc))).GetValueAsUnsigned() | 
 |  | 
 | 	def getPrint(self, srcmgr_path): | 
 | 		print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path) | 
 | 		return print_str.GetSummary() | 
 |  | 
 | 	def summary(self): | 
 | 		if self.isInvalid(): | 
 | 			return "<invalid loc>" | 
 | 		srcmgr_path = findObjectExpressionPath("clang::SourceManager", self.frame) | 
 | 		if srcmgr_path: | 
 | 			return "%s (offset: %d, %s, %s)" % (self.getPrint(srcmgr_path), self.offset(), "macro" if self.isMacro() else "file", "local" if self.isLocal(srcmgr_path) else "loaded") | 
 | 		return "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file") | 
 |  | 
 | class QualType(object): | 
 | 	def __init__(self, qualty): | 
 | 		self.qualty = qualty | 
 |  | 
 | 	def getAsString(self): | 
 | 		std_str = getValueFromExpression(self.qualty, ".getAsString()") | 
 | 		return std_str.GetSummary() | 
 |  | 
 | 	def summary(self): | 
 | 		desc = self.getAsString() | 
 | 		if desc == '"NULL TYPE"': | 
 | 			return "<NULL TYPE>" | 
 | 		return desc | 
 |  | 
 | class StringRef(object): | 
 | 	def __init__(self, strref): | 
 | 		self.strref = strref | 
 | 		self.Data_value = strref.GetChildAtIndex(0) | 
 | 		self.Length = strref.GetChildAtIndex(1).GetValueAsUnsigned() | 
 |  | 
 | 	def summary(self): | 
 | 		if self.Length == 0: | 
 | 			return '""' | 
 | 		data = self.Data_value.GetPointeeData(0, self.Length) | 
 | 		error = lldb.SBError() | 
 | 		string = data.ReadRawData(error, 0, data.GetByteSize()) | 
 | 		if error.Fail(): | 
 | 			return None | 
 | 		return '"%s"' % string | 
 |  | 
 |  | 
 | # Key is a (function address, type name) tuple, value is the expression path for | 
 | # an object with such a type name from inside that function. | 
 | FramePathMapCache = {} | 
 |  | 
 | def findObjectExpressionPath(typename, frame): | 
 | 	func_addr = frame.GetFunction().GetStartAddress().GetFileAddress() | 
 | 	key = (func_addr, typename) | 
 | 	try: | 
 | 		return FramePathMapCache[key] | 
 | 	except KeyError: | 
 | 		#print "CACHE MISS" | 
 | 		path = None | 
 | 		obj = findObject(typename, frame) | 
 | 		if obj: | 
 | 			path = getExpressionPath(obj) | 
 | 		FramePathMapCache[key] = path | 
 | 		return path | 
 |  | 
 | def findObject(typename, frame): | 
 | 	def getTypename(value): | 
 | 		# FIXME: lldb should provide something like getBaseType | 
 | 		ty = value.GetType() | 
 | 		if ty.IsPointerType() or ty.IsReferenceType(): | 
 | 			return ty.GetPointeeType().GetName() | 
 | 		return ty.GetName() | 
 |  | 
 | 	def searchForType(value, searched): | 
 | 		tyname = getTypename(value) | 
 | 		#print "SEARCH:", getExpressionPath(value), value.GetType().GetName() | 
 | 		if tyname == typename: | 
 | 			return value | 
 | 		ty = value.GetType() | 
 | 		if not (ty.IsPointerType() or | 
 | 		        ty.IsReferenceType() or | 
 | 				# FIXME: lldb should provide something like getCanonicalType | 
 | 		        tyname.startswith("llvm::IntrusiveRefCntPtr<") or | 
 | 		        tyname.startswith("llvm::OwningPtr<")): | 
 | 			return None | 
 | 		# FIXME: Hashing for SBTypes does not seem to work correctly, uses the typename instead, | 
 | 		# and not the canonical one unfortunately. | 
 | 		if tyname in searched: | 
 | 			return None | 
 | 		searched.add(tyname) | 
 | 		for i in range(value.GetNumChildren()): | 
 | 			child = value.GetChildAtIndex(i, 0, False) | 
 | 			found = searchForType(child, searched) | 
 | 			if found: | 
 | 				return found | 
 |  | 
 | 	searched = set() | 
 | 	value_list = frame.GetVariables(True, True, True, True) | 
 | 	for val in value_list: | 
 | 		found = searchForType(val, searched) | 
 | 		if found: | 
 | 			return found if not found.TypeIsPointerType() else found.Dereference() | 
 |  | 
 | def getValueFromExpression(val, expr): | 
 | 	return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr) | 
 |  | 
 | def getExpressionPath(val): | 
 | 	stream = lldb.SBStream() | 
 | 	val.GetExpressionPath(stream) | 
 | 	return stream.GetData() |