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