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