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 debugger.HandleCommand("type summary add -F ClangDataFormat.StringRef_summary llvm::StringRef") 28 29def SourceLocation_summary(srcloc, internal_dict): 30 return SourceLocation(srcloc).summary() 31 32def QualType_summary(qualty, internal_dict): 33 return QualType(qualty).summary() 34 35def StringRef_summary(strref, internal_dict): 36 return StringRef(strref).summary() 37 38class 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 68class 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 82class 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. 101FramePathMapCache = {} 102 103def 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 117def 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 155def getValueFromExpression(val, expr): 156 return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr) 157 158def getExpressionPath(val): 159 stream = lldb.SBStream() 160 val.GetExpressionPath(stream) 161 return stream.GetData() 162