Home | History | Annotate | Download | only in utils
      1 """lldb data formatters for clang classes.
      2 
      3 Usage
      4 --
      5 import this file in your ~/.lldbinit by adding this line:
      6 
      7 command script import /path/to/ClangDataFormat.py
      8 
      9 After that, instead of getting this:
     10 
     11 (lldb) p Tok.Loc
     12 (clang::SourceLocation) $0 = {
     13   (unsigned int) ID = 123582
     14 }
     15 
     16 you'll get:
     17 
     18 (lldb) p Tok.Loc
     19 (clang::SourceLocation) $4 = "/usr/include/i386/_types.h:37:1" (offset: 123582, file, local)
     20 """
     21 
     22 import lldb
     23 
     24 def __lldb_init_module(debugger, internal_dict):
     25 	debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation")
     26 	debugger.HandleCommand("type summary add -F ClangDataFormat.QualType_summary clang::QualType")
     27 	debugger.HandleCommand("type summary add -F ClangDataFormat.StringRef_summary llvm::StringRef")
     28 
     29 def SourceLocation_summary(srcloc, internal_dict):
     30 	return SourceLocation(srcloc).summary()
     31 
     32 def QualType_summary(qualty, internal_dict):
     33 	return QualType(qualty).summary()
     34 
     35 def StringRef_summary(strref, internal_dict):
     36 	return StringRef(strref).summary()
     37 
     38 class SourceLocation(object):
     39 	def __init__(self, srcloc):
     40 		self.srcloc = srcloc
     41 		self.ID = srcloc.GetChildAtIndex(0).GetValueAsUnsigned()
     42 		self.frame = srcloc.GetFrame()
     43 	
     44 	def offset(self):
     45 		return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned()
     46 
     47 	def isInvalid(self):
     48 		return self.ID == 0
     49 
     50 	def isMacro(self):
     51 		return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned()
     52 
     53 	def isLocal(self, srcmgr_path):
     54 		return self.frame.EvaluateExpression("(%s).isLocalSourceLocation(%s)" % (srcmgr_path, getExpressionPath(self.srcloc))).GetValueAsUnsigned()
     55 
     56 	def getPrint(self, srcmgr_path):
     57 		print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path)
     58 		return print_str.GetSummary()
     59 
     60 	def summary(self):
     61 		if self.isInvalid():
     62 			return "<invalid loc>"
     63 		srcmgr_path = findObjectExpressionPath("clang::SourceManager", self.frame)
     64 		if srcmgr_path:
     65 			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")
     66 		return "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file")
     67 
     68 class QualType(object):
     69 	def __init__(self, qualty):
     70 		self.qualty = qualty
     71 
     72 	def getAsString(self):
     73 		std_str = getValueFromExpression(self.qualty, ".getAsString()")
     74 		return std_str.GetSummary()
     75 
     76 	def summary(self):
     77 		desc = self.getAsString()
     78 		if desc == '"NULL TYPE"':
     79 			return "<NULL TYPE>"
     80 		return desc
     81 
     82 class StringRef(object):
     83 	def __init__(self, strref):
     84 		self.strref = strref
     85 		self.Data_value = strref.GetChildAtIndex(0)
     86 		self.Length = strref.GetChildAtIndex(1).GetValueAsUnsigned()
     87 
     88 	def summary(self):
     89 		if self.Length == 0:
     90 			return '""'
     91 		data = self.Data_value.GetPointeeData(0, self.Length)
     92 		error = lldb.SBError()
     93 		string = data.ReadRawData(error, 0, data.GetByteSize())
     94 		if error.Fail():
     95 			return None
     96 		return '"%s"' % string
     97 
     98 
     99 # Key is a (function address, type name) tuple, value is the expression path for
    100 # an object with such a type name from inside that function.
    101 FramePathMapCache = {}
    102 
    103 def findObjectExpressionPath(typename, frame):
    104 	func_addr = frame.GetFunction().GetStartAddress().GetFileAddress()
    105 	key = (func_addr, typename)
    106 	try:
    107 		return FramePathMapCache[key]
    108 	except KeyError:
    109 		#print "CACHE MISS"
    110 		path = None
    111 		obj = findObject(typename, frame)
    112 		if obj:
    113 			path = getExpressionPath(obj)
    114 		FramePathMapCache[key] = path
    115 		return path
    116 
    117 def findObject(typename, frame):
    118 	def getTypename(value):
    119 		# FIXME: lldb should provide something like getBaseType
    120 		ty = value.GetType()
    121 		if ty.IsPointerType() or ty.IsReferenceType():
    122 			return ty.GetPointeeType().GetName()
    123 		return ty.GetName()
    124 
    125 	def searchForType(value, searched):
    126 		tyname = getTypename(value)
    127 		#print "SEARCH:", getExpressionPath(value), value.GetType().GetName()
    128 		if tyname == typename:
    129 			return value
    130 		ty = value.GetType()
    131 		if not (ty.IsPointerType() or
    132 		        ty.IsReferenceType() or
    133 				# FIXME: lldb should provide something like getCanonicalType
    134 		        tyname.startswith("llvm::IntrusiveRefCntPtr<") or
    135 		        tyname.startswith("llvm::OwningPtr<")):
    136 			return None
    137 		# FIXME: Hashing for SBTypes does not seem to work correctly, uses the typename instead,
    138 		# and not the canonical one unfortunately.
    139 		if tyname in searched:
    140 			return None
    141 		searched.add(tyname)
    142 		for i in range(value.GetNumChildren()):
    143 			child = value.GetChildAtIndex(i, 0, False)
    144 			found = searchForType(child, searched)
    145 			if found:
    146 				return found
    147 
    148 	searched = set()
    149 	value_list = frame.GetVariables(True, True, True, True)
    150 	for val in value_list:
    151 		found = searchForType(val, searched)
    152 		if found:
    153 			return found if not found.TypeIsPointerType() else found.Dereference()
    154 
    155 def getValueFromExpression(val, expr):
    156 	return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr)
    157 
    158 def getExpressionPath(val):
    159 	stream = lldb.SBStream()
    160 	val.GetExpressionPath(stream)
    161 	return stream.GetData()
    162