clayborg created this revision.
clayborg added reviewers: labath, teemperor, aprantl.
Herald added subscribers: usaxena95, arphaman.
clayborg requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
This allows us to see the contents of the SmallVector just like std::vector and
also adds a summary string that shows the size of the array.
For llvm::Optional, the value will show as llvm::None when it has no value, or
it will show the value of the type T.
For llvm::Error or, it will show the std::error_code as a structure or the
value if it has a value.
For llvm::Expected, it will show the dynamic classname of the contained error,
or the value.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D116113
Files:
clang/utils/ClangDataFormat.py
Index: clang/utils/ClangDataFormat.py
===================================================================
--- clang/utils/ClangDataFormat.py
+++ clang/utils/ClangDataFormat.py
@@ -22,140 +22,408 @@
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")
+ 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")
+ debugger.HandleCommand("type summary add -F ClangDataFormat.Optional_summary -x 'llvm::Optional<.*>'")
+ debugger.HandleCommand("type summary add -F ClangDataFormat.SmallVector_summary -x 'llvm::SmallVector<.*>'")
+ debugger.HandleCommand("type summary add -F ClangDataFormat.Expected_summary -x 'llvm::Expected<.*>'")
+ debugger.HandleCommand("type summary add -F ClangDataFormat.ErrorOr_summary -x 'llvm::ErrorOr<.*>'")
+ debugger.HandleCommand("type synthetic add -l ClangDataFormat.Optional -x 'llvm::Optional<.*>'")
+ debugger.HandleCommand("type synthetic add -l ClangDataFormat.SmallVector -x 'llvm::SmallVector<.*>'")
+ debugger.HandleCommand("type synthetic add -l ClangDataFormat.Expected -x 'llvm::Expected<.*>'")
+ debugger.HandleCommand("type synthetic add -l ClangDataFormat.ErrorOr -x 'llvm::ErrorOr<.*>'")
-def SourceLocation_summary(srcloc, internal_dict):
- return SourceLocation(srcloc).summary()
+def SourceLocation_summary(valobj, internal_dict):
+ return SourceLocation(valobj).summary()
-def QualType_summary(qualty, internal_dict):
- return QualType(qualty).summary()
+def QualType_summary(valobj, internal_dict):
+ return QualType(valobj).summary()
-def StringRef_summary(strref, internal_dict):
- return StringRef(strref).summary()
+def StringRef_summary(valobj, internal_dict):
+ return StringRef(valobj).summary()
+
+def Optional_summary(valobj, internal_dict):
+ return Optional(valobj, internal_dict).summary()
+
+def SmallVector_summary(valobj, internal_dict):
+ return SmallVector(valobj, internal_dict).summary()
+
+def Expected_summary(valobj, internal_dict):
+ return Expected(valobj, internal_dict).summary()
+
+def ErrorOr_summary(valobj, internal_dict):
+ return ErrorOr(valobj, internal_dict).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")
+ 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 __init__(self, qualty):
+ self.qualty = qualty
- def getAsString(self):
- std_str = getValueFromExpression(self.qualty, ".getAsString()")
- return std_str.GetSummary()
+ 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
+ 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
+ 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
+ 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 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)
+ return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr)
def getExpressionPath(val):
- stream = lldb.SBStream()
- val.GetExpressionPath(stream)
- return stream.GetData()
+ stream = lldb.SBStream()
+ val.GetExpressionPath(stream)
+ return stream.GetData()
+
+class Optional(object):
+ def __init__(self, valobj, internal_dict):
+ # We use this class for both the synthetic children and for the summary.
+ # For the summary, we will be given the synthetic lldb.SBValue so we
+ # must make sure to get the non-synthetic lldb.SBValue.
+ self.valobj = valobj.GetNonSyntheticValue()
+ self.update()
+
+ def summary(self):
+ self.update()
+ if not self.hasVal:
+ return "llvm::None"
+ summary = self.value.GetSummary()
+ if summary:
+ return summary
+ return ""
+
+ def update(self):
+ storage = self.valobj.GetChildMemberWithName('Storage')
+ self.hasVal = storage.GetChildMemberWithName('hasVal').GetValueAsUnsigned(0)
+ self.value = storage.GetChildMemberWithName('value')
+ # Return false to make sure we always update this object every time we
+ # stop. If we return True, then the value will never update again.
+ return False
+
+ def num_children(self):
+ # If we have a value we get the number of children from our contained
+ # value, else we have no children.
+ if self.hasVal:
+ return self.value.GetNumChildren()
+ return 0
+
+ def get_child_index(self, name):
+ if self.hasVal:
+ result = self.value.GetIndexOfChildWithName(name)
+ return None if result == 4294967295 else result
+ return None
+
+ def get_child_at_index(self, index):
+ if self.hasVal:
+ return self.value.GetChildAtIndex(index)
+ return None
+
+ def has_children(self):
+ return self.value.MightHaveChildren()
+
+ def get_value(self):
+ # this call can return an SBValue to be presented as the value of the
+ # synthetic value under consideration.[3]
+ if self.hasVal:
+ return self.value
+ return None
+
+class SmallVector(object):
+ def __init__(self, valobj, internal_dict):
+ # We use this class for both the synthetic children and for the summary.
+ # For the summary, we will be given the synthetic lldb.SBValue so we
+ # must make sure to get the non-synthetic lldb.SBValue.
+ self.valobj = valobj.GetNonSyntheticValue()
+ type = self.valobj.GetType().GetUnqualifiedType()
+ if type.IsReferenceType():
+ type = type.GetDereferencedType()
+ if type.GetNumberOfTemplateArguments() > 0:
+ self.type = type.GetTemplateArgumentType(0)
+ else:
+ self.type = lldb.SBType()
+ self.element_size = self.type.GetByteSize()
+ self.ptr = lldb.SBValue()
+ self.size = 0
+ self.update()
+
+ def summary(self):
+ self.update()
+ return 'size=%u' % (self.size)
+
+ def update(self):
+ self.ptr = self.valobj.GetChildMemberWithName('BeginX')
+ self.size = self.valobj.GetChildMemberWithName('Size').GetValueAsUnsigned()
+ # Return false to make sure we always update this object every time we
+ # stop. If we return True, then the value will never update again.
+ return False
+
+ def num_children(self):
+ return self.size
+
+ def get_child_index(self, name):
+ try:
+ return int(name.lstrip('[').rstrip(']'))
+ except:
+ return -1
+
+ def get_child_at_index(self, index):
+ return self.ptr.CreateChildAtOffset( '[' + str(index) + ']', self.element_size * index, self.type)
+
+ def has_children(self):
+ return True
+
+class Expected(object):
+ def __init__(self, valobj, internal_dict):
+ # We use this class for both the synthetic children and for the summary.
+ # For the summary, we will be given the synthetic lldb.SBValue so we
+ # must make sure to get the non-synthetic lldb.SBValue.
+ self.valobj = valobj.GetNonSyntheticValue()
+ value_type = self.valobj.GetType().GetUnqualifiedType()
+ if value_type.IsReferenceType():
+ value_type = value_type.GetDereferencedType()
+ if value_type.GetNumberOfTemplateArguments() > 0:
+ self.value_type = value_type.GetTemplateArgumentType(0)
+ else:
+ self.value_type = lldb.SBType()
+ self.error_type = valobj.GetTarget().FindFirstType('llvm::ErrorInfoBase').GetPointerType()
+ self.hasError = lldb.SBValue()
+ self.value = lldb.SBValue()
+ self.update()
+
+ def summary(self):
+ # If we have an error the value for "self.value" will return the
+ # llvm::ErrorInfoBase pointer as the value so we append the error
+ # typename which will be dynamically figured out at runtime. So the
+ # value and the summary will look like:
+ #
+ # 0x0000600001705880 (llvm::StringError *)
+ #
+ # If we have no error, then we still will display the typename in parens
+ # after the value if the type T has a value or alone if it doesn't.
+ self.update()
+ return "(%s)" % (self.value.GetType().GetDisplayTypeName())
+
+ def update(self):
+ # Here we figure out if we have an error here and then we cast the value
+ # in the "ErrorStorage.buffer" to the error type, or we cast the
+ # "TStorage.buffer" to the value type and set "self.value" to the
+ # correct value.
+ self.hasError = self.valobj.GetChildMemberWithName('HasError').GetValueAsUnsigned() != 0
+ if self.hasError:
+ self.value = self.valobj.GetChildMemberWithName('ErrorStorage').GetChildMemberWithName('buffer').CreateChildAtOffset('Error', 0, self.error_type)
+ else:
+ self.value = self.valobj.GetChildMemberWithName('TStorage').GetChildMemberWithName('buffer').CreateChildAtOffset('Value', 0, self.value_type)
+ # Return false to make sure we always update this object every time we
+ # stop. If we return True, then the value will never update again.
+ return False
+
+ def num_children(self):
+ # We compute the right value to use as the lldb.SBValue to use in
+ # self.value in the update() method so we can just use that object to
+ # get our asnwers
+ return self.value.GetNumChildren()
+
+ def get_child_index(self, name):
+ # We compute the right value to use as the lldb.SBValue to use in
+ # self.value in the update() method so we can just use that object to
+ # get our asnwers
+ result = self.value.GetIndexOfChildWithName(name)
+ return None if result == 4294967295 else result
+
+ def get_child_at_index(self, index):
+ # We compute the right value to use as the lldb.SBValue to use in
+ # self.value in the update() method so we can just use that object to
+ # get our asnwers
+ return self.value.GetChildAtIndex(index)
+
+ def has_children(self):
+ # We always return true to ensure we can expand this variable as the
+ # Expected<T> might start out uninitialized and then change to be
+ # initialized. If the T value can be expanded, the user can try. If the
+ # object contains an error, then we can always expand this item to show
+ # its children.
+ return self.value.MightHaveChildren()
+
+ def get_value(self):
+ # We compute the right value to use as the lldb.SBValue to display in
+ # self.value in the update() method so we can just return that here.
+ return self.value
+
+
+class ErrorOr(object):
+ def __init__(self, valobj, internal_dict):
+ # We use this class for both the synthetic children and for the summary.
+ # For the summary, we will be given the synthetic lldb.SBValue so we
+ # must make sure to get the non-synthetic lldb.SBValue.
+ self.valobj = valobj.GetNonSyntheticValue()
+ value_type = self.valobj.GetType().GetUnqualifiedType()
+ if value_type.IsReferenceType():
+ value_type = value_type.GetDereferencedType()
+ if value_type.GetNumberOfTemplateArguments() > 0:
+ self.value_type = value_type.GetTemplateArgumentType(0)
+ else:
+ self.value_type = lldb.SBType()
+ target = valobj.GetTarget()
+ self.error_type = target.FindFirstType('std::__1::error_code')
+ if not self.error_type.IsValid():
+ self.error_type = target.FindFirstType('std::error_code').GetPointerType()
+ self.hasError = lldb.SBValue()
+ self.value = lldb.SBValue()
+ self.update()
+
+ def summary(self):
+ # Display the typename for the std::error_code or for the value in
+ # parens so we can tell the difference between an ErroOr object in an
+ # error state of when it contains a value.
+ self.update()
+ return "(%s)" % (self.value.GetType().GetDisplayTypeName())
+
+ def update(self):
+ # Here we figure out if we have an error here and then we cast the value
+ # in the "ErrorStorage.buffer" to the error type, or we cast the
+ # "TStorage.buffer" to the value type and set "self.value" to the
+ # correct value.
+ self.hasError = self.valobj.GetChildMemberWithName('HasError').GetValueAsUnsigned() != 0
+ if self.hasError:
+ self.value = self.valobj.GetChildMemberWithName('ErrorStorage').GetChildMemberWithName('buffer').CreateChildAtOffset('Error', 0, self.error_type)
+ else:
+ self.value = self.valobj.GetChildMemberWithName('TStorage').GetChildMemberWithName('buffer').CreateChildAtOffset('Value', 0, self.value_type)
+ # Return false to make sure we always update this object every time we
+ # stop. If we return True, then the value will never update again.
+ return False
+
+ def num_children(self):
+ # We compute the right value to use as the lldb.SBValue to use in
+ # self.value in the update() method so we can just use that object to
+ # get our asnwers
+ return self.value.GetNumChildren()
+
+ def get_child_index(self, name):
+ # We compute the right value to use as the lldb.SBValue to use in
+ # self.value in the update() method so we can just use that object to
+ # get our asnwers
+ result = self.value.GetIndexOfChildWithName(name)
+ return None if result == 4294967295 else result
+
+ def get_child_at_index(self, index):
+ # We compute the right value to use as the lldb.SBValue to use in
+ # self.value in the update() method so we can just use that object to
+ # get our asnwers
+ return self.value.GetChildAtIndex(index)
+
+ def has_children(self):
+ # We always return true to ensure we can expand this variable as the
+ # Expected<T> might start out uninitialized and then change to be
+ # initialized. If the T value can be expanded, the user can try. If the
+ # object contains an error, then we can always expand this item to show
+ # its children.
+ return self.value.MightHaveChildren()
+
+ def get_value(self):
+ # We compute the right value to use as the lldb.SBValue to display in
+ # self.value in the update() method so we can just return that here.
+ return self.value
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits