|  | """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() |