1331722Seadler"""lldb data formatters for clang classes.
2239281Sgonzo
3239281SgonzoUsage
4239281Sgonzo--
5239281Sgonzoimport this file in your ~/.lldbinit by adding this line:
6239281Sgonzo
7239281Sgonzocommand script import /path/to/ClangDataFormat.py
8239281Sgonzo
9239281SgonzoAfter that, instead of getting this:
10239281Sgonzo
11239281Sgonzo(lldb) p Tok.Loc
12239281Sgonzo(clang::SourceLocation) $0 = {
13239281Sgonzo  (unsigned int) ID = 123582
14239281Sgonzo}
15239281Sgonzo
16239281Sgonzoyou'll get:
17239281Sgonzo
18239281Sgonzo(lldb) p Tok.Loc
19239281Sgonzo(clang::SourceLocation) $4 = "/usr/include/i386/_types.h:37:1" (offset: 123582, file, local)
20239281Sgonzo"""
21239281Sgonzo
22239281Sgonzoimport lldb
23239281Sgonzo
24239281Sgonzodef __lldb_init_module(debugger, internal_dict):
25239281Sgonzo	debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation")
26239281Sgonzo	debugger.HandleCommand("type summary add -F ClangDataFormat.QualType_summary clang::QualType")
27239281Sgonzo	debugger.HandleCommand("type summary add -F ClangDataFormat.StringRef_summary llvm::StringRef")
28239281Sgonzo
29239281Sgonzodef SourceLocation_summary(srcloc, internal_dict):
30239281Sgonzo	return SourceLocation(srcloc).summary()
31239281Sgonzo
32239281Sgonzodef QualType_summary(qualty, internal_dict):
33239281Sgonzo	return QualType(qualty).summary()
34239281Sgonzo
35239281Sgonzodef StringRef_summary(strref, internal_dict):
36239281Sgonzo	return StringRef(strref).summary()
37239281Sgonzo
38239281Sgonzoclass SourceLocation(object):
39239281Sgonzo	def __init__(self, srcloc):
40239281Sgonzo		self.srcloc = srcloc
41239281Sgonzo		self.ID = srcloc.GetChildAtIndex(0).GetValueAsUnsigned()
42239281Sgonzo		self.frame = srcloc.GetFrame()
43239281Sgonzo
44239281Sgonzo	def offset(self):
45239281Sgonzo		return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned()
46239281Sgonzo
47239281Sgonzo	def isInvalid(self):
48239281Sgonzo		return self.ID == 0
49239281Sgonzo
50239281Sgonzo	def isMacro(self):
51239281Sgonzo		return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned()
52239281Sgonzo
53239281Sgonzo	def isLocal(self, srcmgr_path):
54239281Sgonzo		return self.frame.EvaluateExpression("(%s).isLocalSourceLocation(%s)" % (srcmgr_path, getExpressionPath(self.srcloc))).GetValueAsUnsigned()
55239281Sgonzo
56239281Sgonzo	def getPrint(self, srcmgr_path):
57239281Sgonzo		print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path)
58239281Sgonzo		return print_str.GetSummary()
59239281Sgonzo
60239281Sgonzo	def summary(self):
61239281Sgonzo		if self.isInvalid():
62239281Sgonzo			return "<invalid loc>"
63239281Sgonzo		srcmgr_path = findObjectExpressionPath("clang::SourceManager", self.frame)
64239281Sgonzo		if srcmgr_path:
65283276Sgonzo			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")
66239281Sgonzo		return "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file")
67239281Sgonzo
68239281Sgonzoclass QualType(object):
69239281Sgonzo	def __init__(self, qualty):
70239281Sgonzo		self.qualty = qualty
71239281Sgonzo
72239281Sgonzo	def getAsString(self):
73239281Sgonzo		std_str = getValueFromExpression(self.qualty, ".getAsString()")
74239281Sgonzo		return std_str.GetSummary()
75239281Sgonzo
76239281Sgonzo	def summary(self):
77239281Sgonzo		desc = self.getAsString()
78239281Sgonzo		if desc == '"NULL TYPE"':
79239281Sgonzo			return "<NULL TYPE>"
80239281Sgonzo		return desc
81239281Sgonzo
82239281Sgonzoclass StringRef(object):
83239281Sgonzo	def __init__(self, strref):
84239281Sgonzo		self.strref = strref
85239281Sgonzo		self.Data_value = strref.GetChildAtIndex(0)
86239281Sgonzo		self.Length = strref.GetChildAtIndex(1).GetValueAsUnsigned()
87239281Sgonzo
88239281Sgonzo	def summary(self):
89239281Sgonzo		if self.Length == 0:
90261410Sian			return '""'
91261410Sian		data = self.Data_value.GetPointeeData(0, self.Length)
92261410Sian		error = lldb.SBError()
93283276Sgonzo		string = data.ReadRawData(error, 0, data.GetByteSize())
94239281Sgonzo		if error.Fail():
95239281Sgonzo			return None
96283276Sgonzo		return '"%s"' % string
97283276Sgonzo
98283276Sgonzo
99283276Sgonzo# Key is a (function address, type name) tuple, value is the expression path for
100239281Sgonzo# an object with such a type name from inside that function.
101239281SgonzoFramePathMapCache = {}
102239281Sgonzo
103239281Sgonzodef findObjectExpressionPath(typename, frame):
104239281Sgonzo	func_addr = frame.GetFunction().GetStartAddress().GetFileAddress()
105239281Sgonzo	key = (func_addr, typename)
106239281Sgonzo	try:
107239281Sgonzo		return FramePathMapCache[key]
108239281Sgonzo	except KeyError:
109239281Sgonzo		#print "CACHE MISS"
110239281Sgonzo		path = None
111239281Sgonzo		obj = findObject(typename, frame)
112299069Spfg		if obj:
113239281Sgonzo			path = getExpressionPath(obj)
114239281Sgonzo		FramePathMapCache[key] = path
115239281Sgonzo		return path
116239281Sgonzo
117239281Sgonzodef findObject(typename, frame):
118239281Sgonzo	def getTypename(value):
119239281Sgonzo		# FIXME: lldb should provide something like getBaseType
120239281Sgonzo		ty = value.GetType()
121239281Sgonzo		if ty.IsPointerType() or ty.IsReferenceType():
122239281Sgonzo			return ty.GetPointeeType().GetName()
123239281Sgonzo		return ty.GetName()
124239281Sgonzo
125239281Sgonzo	def searchForType(value, searched):
126239281Sgonzo		tyname = getTypename(value)
127239281Sgonzo		#print "SEARCH:", getExpressionPath(value), value.GetType().GetName()
128239281Sgonzo		if tyname == typename:
129239281Sgonzo			return value
130239281Sgonzo		ty = value.GetType()
131239281Sgonzo		if not (ty.IsPointerType() or
132310856Sloos		        ty.IsReferenceType() or
133310856Sloos				# FIXME: lldb should provide something like getCanonicalType
134310856Sloos		        tyname.startswith("llvm::IntrusiveRefCntPtr<") or
135310856Sloos		        tyname.startswith("llvm::OwningPtr<")):
136239281Sgonzo			return None
137239281Sgonzo		# FIXME: Hashing for SBTypes does not seem to work correctly, uses the typename instead,
138239281Sgonzo		# and not the canonical one unfortunately.
139239281Sgonzo		if tyname in searched:
140239281Sgonzo			return None
141239281Sgonzo		searched.add(tyname)
142239281Sgonzo		for i in range(value.GetNumChildren()):
143239281Sgonzo			child = value.GetChildAtIndex(i, 0, False)
144239281Sgonzo			found = searchForType(child, searched)
145239281Sgonzo			if found:
146239281Sgonzo				return found
147239281Sgonzo
148239281Sgonzo	searched = set()
149239281Sgonzo	value_list = frame.GetVariables(True, True, True, True)
150239281Sgonzo	for val in value_list:
151239281Sgonzo		found = searchForType(val, searched)
152239281Sgonzo		if found:
153239281Sgonzo			return found if not found.TypeIsPointerType() else found.Dereference()
154239281Sgonzo
155239281Sgonzodef getValueFromExpression(val, expr):
156239281Sgonzo	return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr)
157239281Sgonzo
158239281Sgonzodef getExpressionPath(val):
159239281Sgonzo	stream = lldb.SBStream()
160239281Sgonzo	val.GetExpressionPath(stream)
161239281Sgonzo	return stream.GetData()
162283276Sgonzo