diff --git a/clang/utils/ClangDataFormat.py b/clang/utils/ClangDataFormat.py --- a/clang/utils/ClangDataFormat.py +++ b/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 "" - 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 "" + 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 "" - return desc + def summary(self): + desc = self.getAsString() + if desc == '"NULL TYPE"': + return "" + 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 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 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