162 lines
4.9 KiB
Python
162 lines
4.9 KiB
Python
"""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()
|