diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3c84585e1ae3b..1ae927d63f9d4 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -771,6 +771,12 @@ def Artificial : InheritableAttr { let SimpleHandler = 1; } +def TransparentStepping: InheritableAttr { + let Spellings = [Clang<"transparent_stepping">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [TransparentSteppingDocs]; +} + def XRayInstrument : InheritableAttr { let Spellings = [Clang<"xray_always_instrument">, Clang<"xray_never_instrument">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index f19af47749d74..d1f3bd0af3087 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -6924,6 +6924,66 @@ As such, this function attribute is currently only supported on X86 targets. }]; } +def TransparentSteppingDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``transparent_stepping`` attribute is intended as a hint for debuggers that this +function itself is not interesting, but it calls a function that might be. So, when +stepping in arrives at a function with this attribute, debuggers should transparently +step-in through it into the functions called by the annotated function (but not by +subsequent calls made by those functions), stopping at the first one its normal rules +for whether to stop says to stop at - or stepping out again if none qualify. Also, when +stepping out arrives at a function with this attribute, the debugger should continue +stepping out to its caller. + +For example: + +.. code-block:: c + + int bar(void) { + return 42; + } + + __attribute__((transparent_stepping)) + int foo(void) { + return bar(); + } + + int caller(void) { + return foo(); + } + +Stepping into ``foo`` should step directly into ``bar`` instead, and stepping out of ``bar`` +should stop in ``caller``. + +Functions with the ``transparent_stepping`` attribute can be chained together: + +.. code-block:: c + + int baz(void) { + return 42; + } + + __attribute__((transparent_stepping)) + int bar(void) { + return baz(); + } + + __attribute__((transparent_stepping)) + int foo(void) { + return bar(); + } + + int caller(void) { + return foo(); + } + +In this example, stepping into ``foo`` should step directly into ``baz``, and stepping out of +``baz`` should stop in ``caller``. + }]; +} + + def ReadOnlyPlacementDocs : Documentation { let Category = DocCatType; let Content = [{This attribute is attached to a structure, class or union declaration. diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 81877ea252a7b..9d3af50111fc2 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -252,8 +252,10 @@ def warn_module_config_macro_undef : Warning< def note_module_def_undef_here : Note< "macro was %select{defined|#undef'd}0 here">; def remark_module_build : Remark<"building module '%0' as '%1'">, + ShowInSystemHeader, InGroup; def remark_module_build_done : Remark<"finished building module '%0'">, + ShowInSystemHeader, InGroup; def remark_module_lock : Remark<"locking '%0' to build module '%1'">, InGroup; diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index f515ea0d9f6dd..ecf2c82b32be3 100644 --- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -75,6 +75,7 @@ def note_module_file_conflict : Note< def remark_module_import : Remark< "importing module '%0'%select{| into '%3'}2 from '%1'">, + ShowInSystemHeader, InGroup; def err_imported_module_not_found : Error< diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h index f6546fb4776a6..a31648b80195a 100644 --- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h @@ -14,24 +14,27 @@ #ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H #define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H +#include "llvm/ADT/FunctionExtras.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ParentMapContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/SourceManager.h" #include "clang/ExtractAPI/API.h" -#include "llvm/ADT/FunctionExtras.h" +#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" +#include namespace clang { namespace extractapi { +namespace impl { -/// The RecursiveASTVisitor to traverse symbol declarations and collect API -/// information. -class ExtractAPIVisitor : public RecursiveASTVisitor { -public: - ExtractAPIVisitor(ASTContext &Context, - llvm::unique_function LocationChecker, - APISet &API) - : Context(Context), API(API), - LocationChecker(std::move(LocationChecker)) {} +template +class ExtractAPIVisitorBase : public RecursiveASTVisitor { +protected: + ExtractAPIVisitorBase(ASTContext &Context, APISet &API) + : Context(Context), API(API) {} +public: const APISet &getAPI() const { return API; } bool VisitVarDecl(const VarDecl *Decl); @@ -50,7 +53,11 @@ class ExtractAPIVisitor : public RecursiveASTVisitor { bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl); -private: + bool shouldDeclBeIncluded(const Decl *Decl) const; + + const RawComment *fetchRawCommentForDecl(const Decl *Decl) const; + +protected: /// Collect API information for the enum constants and associate with the /// parent enum. void recordEnumConstants(EnumRecord *EnumRecord, @@ -77,9 +84,582 @@ class ExtractAPIVisitor : public RecursiveASTVisitor { void recordObjCProtocols(ObjCContainerRecord *Container, ObjCInterfaceDecl::protocol_range Protocols); + ASTContext &Context; APISet &API; - llvm::unique_function LocationChecker; + + StringRef getTypedefName(const TagDecl *Decl) { + if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl()) + return TypedefDecl->getName(); + + return {}; + } + + bool isInSystemHeader(const Decl *D) { + return Context.getSourceManager().isInSystemHeader(D->getLocation()); + } + +private: + Derived &getDerivedExtractAPIVisitor() { + return *static_cast(this); + } +}; + +template +bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { + // skip function parameters. + if (isa(Decl)) + return true; + + // Skip non-global variables in records (struct/union/class). + if (Decl->getDeclContext()->isRecord()) + return true; + + // Skip local variables inside function or method. + if (!Decl->isDefinedOutsideFunctionOrMethod()) + return true; + + // If this is a template but not specialization or instantiation, skip. + if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && + Decl->getTemplateSpecializationKind() == TSK_Undeclared) + return true; + + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + return true; + + // Collect symbol information. + StringRef Name = Decl->getName(); + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + LinkageInfo Linkage = Decl->getLinkageAndVisibility(); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the variable. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForVar(Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + // Add the global variable record to the API set. + API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, + Declaration, SubHeading, isInSystemHeader(Decl)); + return true; +} + +template +bool ExtractAPIVisitorBase::VisitFunctionDecl( + const FunctionDecl *Decl) { + if (const auto *Method = dyn_cast(Decl)) { + // Skip member function in class templates. + if (Method->getParent()->getDescribedClassTemplate() != nullptr) + return true; + + // Skip methods in records. + for (auto P : Context.getParents(*Method)) { + if (P.template get()) + return true; + } + + // Skip ConstructorDecl and DestructorDecl. + if (isa(Method) || isa(Method)) + return true; + } + + // Skip templated functions. + switch (Decl->getTemplatedKind()) { + case FunctionDecl::TK_NonTemplate: + case FunctionDecl::TK_DependentNonTemplate: + break; + case FunctionDecl::TK_MemberSpecialization: + case FunctionDecl::TK_FunctionTemplateSpecialization: + if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { + if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) + return true; + } + break; + case FunctionDecl::TK_FunctionTemplate: + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: + return true; + } + + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + return true; + + // Collect symbol information. + StringRef Name = Decl->getName(); + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + LinkageInfo Linkage = Decl->getLinkageAndVisibility(); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments, sub-heading, and signature of the function. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + FunctionSignature Signature = + DeclarationFragmentsBuilder::getFunctionSignature(Decl); + + // Add the function record to the API set. + API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, + Declaration, SubHeading, Signature, + isInSystemHeader(Decl)); + return true; +} + +template +bool ExtractAPIVisitorBase::VisitEnumDecl(const EnumDecl *Decl) { + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + return true; + + SmallString<128> QualifiedNameBuffer; + // Collect symbol information. + StringRef Name = Decl->getName(); + if (Name.empty()) + Name = getTypedefName(Decl); + if (Name.empty()) { + llvm::raw_svector_ostream OS(QualifiedNameBuffer); + Decl->printQualifiedName(OS); + Name = QualifiedNameBuffer.str(); + } + + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the enum. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + EnumRecord *EnumRecord = + API.addEnum(API.copyString(Name), USR, Loc, AvailabilitySet(Decl), + Comment, Declaration, SubHeading, isInSystemHeader(Decl)); + + // Now collect information about the enumerators in this enum. + getDerivedExtractAPIVisitor().recordEnumConstants(EnumRecord, + Decl->enumerators()); + + return true; +} + +template +bool ExtractAPIVisitorBase::VisitRecordDecl(const RecordDecl *Decl) { + // Skip C++ structs/classes/unions + // TODO: support C++ records + if (isa(Decl)) + return true; + + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + return true; + + // Collect symbol information. + StringRef Name = Decl->getName(); + if (Name.empty()) + Name = getTypedefName(Decl); + if (Name.empty()) + return true; + + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the struct. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + StructRecord *StructRecord = + API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, + SubHeading, isInSystemHeader(Decl)); + + // Now collect information about the fields in this struct. + getDerivedExtractAPIVisitor().recordStructFields(StructRecord, + Decl->fields()); + + return true; +} + +template +bool ExtractAPIVisitorBase::VisitObjCInterfaceDecl( + const ObjCInterfaceDecl *Decl) { + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + return true; + + // Collect symbol information. + StringRef Name = Decl->getName(); + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + LinkageInfo Linkage = Decl->getLinkageAndVisibility(); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the interface. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + // Collect super class information. + SymbolReference SuperClass; + if (const auto *SuperClassDecl = Decl->getSuperClass()) { + SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); + SuperClass.USR = API.recordUSR(SuperClassDecl); + } + + ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( + Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration, + SubHeading, SuperClass, isInSystemHeader(Decl)); + + // Record all methods (selectors). This doesn't include automatically + // synthesized property methods. + getDerivedExtractAPIVisitor().recordObjCMethods(ObjCInterfaceRecord, + Decl->methods()); + getDerivedExtractAPIVisitor().recordObjCProperties(ObjCInterfaceRecord, + Decl->properties()); + getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCInterfaceRecord, + Decl->ivars()); + getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCInterfaceRecord, + Decl->protocols()); + + return true; +} + +template +bool ExtractAPIVisitorBase::VisitObjCProtocolDecl( + const ObjCProtocolDecl *Decl) { + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + return true; + + // Collect symbol information. + StringRef Name = Decl->getName(); + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the protocol. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + ObjCProtocolRecord *ObjCProtocolRecord = + API.addObjCProtocol(Name, USR, Loc, AvailabilitySet(Decl), Comment, + Declaration, SubHeading, isInSystemHeader(Decl)); + + getDerivedExtractAPIVisitor().recordObjCMethods(ObjCProtocolRecord, + Decl->methods()); + getDerivedExtractAPIVisitor().recordObjCProperties(ObjCProtocolRecord, + Decl->properties()); + getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCProtocolRecord, + Decl->protocols()); + + return true; +} + +template +bool ExtractAPIVisitorBase::VisitTypedefNameDecl( + const TypedefNameDecl *Decl) { + // Skip ObjC Type Parameter for now. + if (isa(Decl)) + return true; + + if (!Decl->isDefinedOutsideFunctionOrMethod()) + return true; + + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + return true; + + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + StringRef Name = Decl->getName(); + StringRef USR = API.recordUSR(Decl); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + QualType Type = Decl->getUnderlyingType(); + SymbolReference SymRef = + TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, + API); + + API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment, + DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), + DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, + isInSystemHeader(Decl)); + + return true; +} + +template +bool ExtractAPIVisitorBase::VisitObjCCategoryDecl( + const ObjCCategoryDecl *Decl) { + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) + return true; + + StringRef Name = Decl->getName(); + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + // Build declaration fragments and sub-heading for the category. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); + SymbolReference Interface(InterfaceDecl->getName(), + API.recordUSR(InterfaceDecl)); + + ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory( + Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading, + Interface, isInSystemHeader(Decl)); + + getDerivedExtractAPIVisitor().recordObjCMethods(ObjCCategoryRecord, + Decl->methods()); + getDerivedExtractAPIVisitor().recordObjCProperties(ObjCCategoryRecord, + Decl->properties()); + getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCCategoryRecord, + Decl->ivars()); + getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCCategoryRecord, + Decl->protocols()); + + return true; +} + +/// Collect API information for the enum constants and associate with the +/// parent enum. +template +void ExtractAPIVisitorBase::recordEnumConstants( + EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) { + for (const auto *Constant : Constants) { + // Collect symbol information. + StringRef Name = Constant->getName(); + StringRef USR = API.recordUSR(Constant); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Constant->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Constant)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the enum constant. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Constant); + + API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant), + Comment, Declaration, SubHeading, + isInSystemHeader(Constant)); + } +} + +/// Collect API information for the struct fields and associate with the +/// parent struct. +template +void ExtractAPIVisitorBase::recordStructFields( + StructRecord *StructRecord, const RecordDecl::field_range Fields) { + for (const auto *Field : Fields) { + // Collect symbol information. + StringRef Name = Field->getName(); + StringRef USR = API.recordUSR(Field); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Field->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Field)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the struct field. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForField(Field); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Field); + + API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field), + Comment, Declaration, SubHeading, + isInSystemHeader(Field)); + } +} + +/// Collect API information for the Objective-C methods and associate with the +/// parent container. +template +void ExtractAPIVisitorBase::recordObjCMethods( + ObjCContainerRecord *Container, + const ObjCContainerDecl::method_range Methods) { + for (const auto *Method : Methods) { + // Don't record selectors for properties. + if (Method->isPropertyAccessor()) + continue; + + StringRef Name = API.copyString(Method->getSelector().getAsString()); + StringRef USR = API.recordUSR(Method); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Method->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Method)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments, sub-heading, and signature for the method. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Method); + FunctionSignature Signature = + DeclarationFragmentsBuilder::getFunctionSignature(Method); + + API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method), + Comment, Declaration, SubHeading, Signature, + Method->isInstanceMethod(), isInSystemHeader(Method)); + } +} + +template +void ExtractAPIVisitorBase::recordObjCProperties( + ObjCContainerRecord *Container, + const ObjCContainerDecl::prop_range Properties) { + for (const auto *Property : Properties) { + StringRef Name = Property->getName(); + StringRef USR = API.recordUSR(Property); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Property->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Property)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the property. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Property); + + StringRef GetterName = + API.copyString(Property->getGetterName().getAsString()); + StringRef SetterName = + API.copyString(Property->getSetterName().getAsString()); + + // Get the attributes for property. + unsigned Attributes = ObjCPropertyRecord::NoAttr; + if (Property->getPropertyAttributes() & + ObjCPropertyAttribute::kind_readonly) + Attributes |= ObjCPropertyRecord::ReadOnly; + + API.addObjCProperty( + Container, Name, USR, Loc, AvailabilitySet(Property), Comment, + Declaration, SubHeading, + static_cast(Attributes), GetterName, + SetterName, Property->isOptional(), + !(Property->getPropertyAttributes() & + ObjCPropertyAttribute::kind_class), + isInSystemHeader(Property)); + } +} + +template +void ExtractAPIVisitorBase::recordObjCInstanceVariables( + ObjCContainerRecord *Container, + const llvm::iterator_range< + DeclContext::specific_decl_iterator> + Ivars) { + for (const auto *Ivar : Ivars) { + StringRef Name = Ivar->getName(); + StringRef USR = API.recordUSR(Ivar); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); + DocComment Comment; + if (auto *RawComment = + getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Ivar)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading for the instance variable. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForField(Ivar); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Ivar); + + ObjCInstanceVariableRecord::AccessControl Access = + Ivar->getCanonicalAccessControl(); + + API.addObjCInstanceVariable(Container, Name, USR, Loc, + AvailabilitySet(Ivar), Comment, Declaration, + SubHeading, Access, isInSystemHeader(Ivar)); + } +} + +template +void ExtractAPIVisitorBase::recordObjCProtocols( + ObjCContainerRecord *Container, + ObjCInterfaceDecl::protocol_range Protocols) { + for (const auto *Protocol : Protocols) + Container->Protocols.emplace_back(Protocol->getName(), + API.recordUSR(Protocol)); +} + +} // namespace impl + +/// The RecursiveASTVisitor to traverse symbol declarations and collect API +/// information. +template +class ExtractAPIVisitor + : public impl::ExtractAPIVisitorBase, ExtractAPIVisitor<>, Derived>> { + using Base = impl::ExtractAPIVisitorBase, ExtractAPIVisitor<>, Derived>>; + +public: + ExtractAPIVisitor(ASTContext &Context, APISet &API) : Base(Context, API) {} + + bool shouldDeclBeIncluded(const Decl *D) const { return true; } + const RawComment *fetchRawCommentForDecl(const Decl *D) const { + return this->Context.getRawCommentForDeclNoCache(D); + } }; } // namespace extractapi diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h b/clang/include/clang/ExtractAPI/TypedefUnderlyingTypeResolver.h similarity index 100% rename from clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h rename to clang/include/clang/ExtractAPI/TypedefUnderlyingTypeResolver.h diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index c1e1da22978bf..f5efd290e63b7 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -819,11 +819,10 @@ class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo case CC_PreserveAll: case CC_X86_64SysV: case CC_Swift: + case CC_SwiftAsync: case CC_X86RegCall: case CC_OpenCLKernel: return CCCR_OK; - case CC_SwiftAsync: - return CCCR_Error; default: return CCCR_Warning; } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 63235d792b1df..59315e553c5c5 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -67,6 +67,12 @@ static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) { return D->hasAttr() ? D->getMaxAlignment() : 0; } +static bool getIsTransparentStepping(const Decl *D) { + if (!D) + return false; + return D->hasAttr(); +} + CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()), DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs), @@ -1882,6 +1888,8 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit; if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; + if (getIsTransparentStepping(Method)) + SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping; // In this debug mode, emit type info for a class when its constructor type // info is emitted. @@ -3832,6 +3840,8 @@ llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD, if (Stub) { Flags |= getCallSiteRelatedAttrs(); SPFlags |= llvm::DISubprogram::SPFlagDefinition; + if (getIsTransparentStepping(FD)) + SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping; return DBuilder.createFunction( DContext, Name, LinkageName, Unit, Line, getOrCreateFunctionType(GD.getDecl(), FnType, Unit), 0, Flags, SPFlags, @@ -3981,6 +3991,8 @@ llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration( if (It == TypeCache.end()) return nullptr; auto *InterfaceType = cast(It->second); + if (getIsTransparentStepping(D)) + SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping; llvm::DISubprogram *FD = DBuilder.createFunction( InterfaceType, getObjCMethodName(OMD), StringRef(), InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags); @@ -4147,6 +4159,8 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit; if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; + if (getIsTransparentStepping(D)) + SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping; llvm::DINode::DIFlags FlagsForDef = Flags | getCallSiteRelatedAttrs(); llvm::DISubprogram::DISPFlags SPFlagsForDef = @@ -4233,6 +4247,9 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); llvm::DISubroutineType *STy = getOrCreateFunctionType(D, FnType, Unit); + if (getIsTransparentStepping(D)) + SPFlags |= llvm::DISubprogram::SPFlagIsTransparentStepping; + llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, STy, ScopeLine, Flags, SPFlags, TParamsArray.get(), nullptr, nullptr, Annotations); diff --git a/clang/lib/ExtractAPI/CMakeLists.txt b/clang/lib/ExtractAPI/CMakeLists.txt index d73cfdec98feb..e7de57d2984cc 100644 --- a/clang/lib/ExtractAPI/CMakeLists.txt +++ b/clang/lib/ExtractAPI/CMakeLists.txt @@ -7,7 +7,6 @@ add_clang_library(clangExtractAPI APIIgnoresList.cpp AvailabilityInfo.cpp ExtractAPIConsumer.cpp - ExtractAPIVisitor.cpp DeclarationFragments.cpp Serialization/SerializerBase.cpp Serialization/SymbolGraphSerializer.cpp diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index b8de1270b5f02..312ff5fd33e4f 100644 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/DeclarationFragments.h" -#include "TypedefUnderlyingTypeResolver.h" +#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringSwitch.h" diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index ccc8765138390..5a490080f38c6 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -12,8 +12,10 @@ /// //===----------------------------------------------------------------------===// +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" @@ -33,6 +35,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -218,11 +221,34 @@ struct LocationFileChecker { llvm::DenseSet ExternalFileEntries; }; +struct BatchExtractAPIVisitor : ExtractAPIVisitor { + bool shouldDeclBeIncluded(const Decl *D) const { + bool ShouldBeIncluded = true; + // Check that we have the definition for redeclarable types. + if (auto *TD = llvm::dyn_cast(D)) + ShouldBeIncluded = TD->isThisDeclarationADefinition(); + else if (auto *Interface = llvm::dyn_cast(D)) + ShouldBeIncluded = Interface->isThisDeclarationADefinition(); + else if (auto *Protocol = llvm::dyn_cast(D)) + ShouldBeIncluded = Protocol->isThisDeclarationADefinition(); + + ShouldBeIncluded = ShouldBeIncluded && LCF(D->getLocation()); + return ShouldBeIncluded; + } + + BatchExtractAPIVisitor(LocationFileChecker &LCF, ASTContext &Context, + APISet &API) + : ExtractAPIVisitor(Context, API), LCF(LCF) {} + +private: + LocationFileChecker &LCF; +}; + class ExtractAPIConsumer : public ASTConsumer { public: ExtractAPIConsumer(ASTContext &Context, std::unique_ptr LCF, APISet &API) - : Visitor(Context, *LCF, API), LCF(std::move(LCF)) {} + : Visitor(*LCF, Context, API), LCF(std::move(LCF)) {} void HandleTranslationUnit(ASTContext &Context) override { // Use ExtractAPIVisitor to traverse symbol declarations in the context. @@ -230,7 +256,7 @@ class ExtractAPIConsumer : public ASTConsumer { } private: - ExtractAPIVisitor Visitor; + BatchExtractAPIVisitor Visitor; std::unique_ptr LCF; }; diff --git a/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp b/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp deleted file mode 100644 index 24260cf89383d..0000000000000 --- a/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp +++ /dev/null @@ -1,560 +0,0 @@ -//===- ExtractAPI/ExtractAPIVisitor.cpp -------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file implements the ExtractAPIVisitor an ASTVisitor to collect API -/// information. -/// -//===----------------------------------------------------------------------===// - -#include "clang/ExtractAPI/ExtractAPIVisitor.h" - -#include "TypedefUnderlyingTypeResolver.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/ParentMapContext.h" -#include "clang/AST/RawCommentList.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/ExtractAPI/API.h" -#include "clang/ExtractAPI/AvailabilityInfo.h" -#include "clang/ExtractAPI/DeclarationFragments.h" -#include "clang/Frontend/ASTConsumers.h" -#include "clang/Frontend/FrontendOptions.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace extractapi; - -namespace { - -StringRef getTypedefName(const TagDecl *Decl) { - if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl()) - return TypedefDecl->getName(); - - return {}; -} - -template -bool isInSystemHeader(const ASTContext &Context, const DeclTy *D) { - return Context.getSourceManager().isInSystemHeader(D->getLocation()); -} - -} // namespace - -bool ExtractAPIVisitor::VisitVarDecl(const VarDecl *Decl) { - // skip function parameters. - if (isa(Decl)) - return true; - - // Skip non-global variables in records (struct/union/class). - if (Decl->getDeclContext()->isRecord()) - return true; - - // Skip local variables inside function or method. - if (!Decl->isDefinedOutsideFunctionOrMethod()) - return true; - - // If this is a template but not specialization or instantiation, skip. - if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && - Decl->getTemplateSpecializationKind() == TSK_Undeclared) - return true; - - if (!LocationChecker(Decl->getLocation())) - return true; - - // Collect symbol information. - StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - LinkageInfo Linkage = Decl->getLinkageAndVisibility(); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the variable. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForVar(Decl); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Decl); - - // Add the global variable record to the API set. - API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, - Declaration, SubHeading, isInSystemHeader(Context, Decl)); - return true; -} - -bool ExtractAPIVisitor::VisitFunctionDecl(const FunctionDecl *Decl) { - if (const auto *Method = dyn_cast(Decl)) { - // Skip member function in class templates. - if (Method->getParent()->getDescribedClassTemplate() != nullptr) - return true; - - // Skip methods in records. - for (auto P : Context.getParents(*Method)) { - if (P.get()) - return true; - } - - // Skip ConstructorDecl and DestructorDecl. - if (isa(Method) || isa(Method)) - return true; - } - - // Skip templated functions. - switch (Decl->getTemplatedKind()) { - case FunctionDecl::TK_NonTemplate: - case FunctionDecl::TK_DependentNonTemplate: - break; - case FunctionDecl::TK_MemberSpecialization: - case FunctionDecl::TK_FunctionTemplateSpecialization: - if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { - if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) - return true; - } - break; - case FunctionDecl::TK_FunctionTemplate: - case FunctionDecl::TK_DependentFunctionTemplateSpecialization: - return true; - } - - if (!LocationChecker(Decl->getLocation())) - return true; - - // Collect symbol information. - StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - LinkageInfo Linkage = Decl->getLinkageAndVisibility(); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments, sub-heading, and signature of the function. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Decl); - FunctionSignature Signature = - DeclarationFragmentsBuilder::getFunctionSignature(Decl); - - // Add the function record to the API set. - API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, - Declaration, SubHeading, Signature, - isInSystemHeader(Context, Decl)); - return true; -} - -bool ExtractAPIVisitor::VisitEnumDecl(const EnumDecl *Decl) { - if (!Decl->isComplete()) - return true; - - // Skip forward declaration. - if (!Decl->isThisDeclarationADefinition()) - return true; - - if (!LocationChecker(Decl->getLocation())) - return true; - - SmallString<128> QualifiedNameBuffer; - // Collect symbol information. - StringRef Name = Decl->getName(); - if (Name.empty()) - Name = getTypedefName(Decl); - if (Name.empty()) { - llvm::raw_svector_ostream OS(QualifiedNameBuffer); - Decl->printQualifiedName(OS); - Name = QualifiedNameBuffer.str(); - } - - StringRef USR = API.recordUSR(Decl); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the enum. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Decl); - - EnumRecord *EnumRecord = API.addEnum( - API.copyString(Name), USR, Loc, AvailabilitySet(Decl), Comment, - Declaration, SubHeading, isInSystemHeader(Context, Decl)); - - // Now collect information about the enumerators in this enum. - recordEnumConstants(EnumRecord, Decl->enumerators()); - - return true; -} - -bool ExtractAPIVisitor::VisitRecordDecl(const RecordDecl *Decl) { - if (!Decl->isCompleteDefinition()) - return true; - - // Skip C++ structs/classes/unions - // TODO: support C++ records - if (isa(Decl)) - return true; - - if (!LocationChecker(Decl->getLocation())) - return true; - - // Collect symbol information. - StringRef Name = Decl->getName(); - if (Name.empty()) - Name = getTypedefName(Decl); - if (Name.empty()) - return true; - - StringRef USR = API.recordUSR(Decl); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the struct. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Decl); - - StructRecord *StructRecord = - API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, - SubHeading, isInSystemHeader(Context, Decl)); - - // Now collect information about the fields in this struct. - recordStructFields(StructRecord, Decl->fields()); - - return true; -} - -bool ExtractAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) { - // Skip forward declaration for classes (@class) - if (!Decl->isThisDeclarationADefinition()) - return true; - - if (!LocationChecker(Decl->getLocation())) - return true; - - // Collect symbol information. - StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - LinkageInfo Linkage = Decl->getLinkageAndVisibility(); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the interface. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Decl); - - // Collect super class information. - SymbolReference SuperClass; - if (const auto *SuperClassDecl = Decl->getSuperClass()) { - SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); - SuperClass.USR = API.recordUSR(SuperClassDecl); - } - - ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( - Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration, - SubHeading, SuperClass, isInSystemHeader(Context, Decl)); - - // Record all methods (selectors). This doesn't include automatically - // synthesized property methods. - recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); - recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); - recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); - recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols()); - - return true; -} - -bool ExtractAPIVisitor::VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) { - // Skip forward declaration for protocols (@protocol). - if (!Decl->isThisDeclarationADefinition()) - return true; - - if (!LocationChecker(Decl->getLocation())) - return true; - - // Collect symbol information. - StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the protocol. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Decl); - - ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( - Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading, - isInSystemHeader(Context, Decl)); - - recordObjCMethods(ObjCProtocolRecord, Decl->methods()); - recordObjCProperties(ObjCProtocolRecord, Decl->properties()); - recordObjCProtocols(ObjCProtocolRecord, Decl->protocols()); - - return true; -} - -bool ExtractAPIVisitor::VisitTypedefNameDecl(const TypedefNameDecl *Decl) { - // Skip ObjC Type Parameter for now. - if (isa(Decl)) - return true; - - if (!Decl->isDefinedOutsideFunctionOrMethod()) - return true; - - if (!LocationChecker(Decl->getLocation())) - return true; - - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - QualType Type = Decl->getUnderlyingType(); - SymbolReference SymRef = - TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, - API); - - API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment, - DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), - DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, - isInSystemHeader(Context, Decl)); - - return true; -} - -bool ExtractAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) { - // Collect symbol information. - StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - // Build declaration fragments and sub-heading for the category. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Decl); - - const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); - SymbolReference Interface(InterfaceDecl->getName(), - API.recordUSR(InterfaceDecl)); - - ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory( - Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading, - Interface, isInSystemHeader(Context, Decl)); - - recordObjCMethods(ObjCCategoryRecord, Decl->methods()); - recordObjCProperties(ObjCCategoryRecord, Decl->properties()); - recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars()); - recordObjCProtocols(ObjCCategoryRecord, Decl->protocols()); - - return true; -} - -/// Collect API information for the enum constants and associate with the -/// parent enum. -void ExtractAPIVisitor::recordEnumConstants( - EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) { - for (const auto *Constant : Constants) { - // Collect symbol information. - StringRef Name = Constant->getName(); - StringRef USR = API.recordUSR(Constant); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Constant->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the enum constant. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Constant); - - API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant), - Comment, Declaration, SubHeading, - isInSystemHeader(Context, Constant)); - } -} - -/// Collect API information for the struct fields and associate with the -/// parent struct. -void ExtractAPIVisitor::recordStructFields( - StructRecord *StructRecord, const RecordDecl::field_range Fields) { - for (const auto *Field : Fields) { - // Collect symbol information. - StringRef Name = Field->getName(); - StringRef USR = API.recordUSR(Field); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Field->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the struct field. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForField(Field); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Field); - - API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field), - Comment, Declaration, SubHeading, - isInSystemHeader(Context, Field)); - } -} - -/// Collect API information for the Objective-C methods and associate with the -/// parent container. -void ExtractAPIVisitor::recordObjCMethods( - ObjCContainerRecord *Container, - const ObjCContainerDecl::method_range Methods) { - for (const auto *Method : Methods) { - // Don't record selectors for properties. - if (Method->isPropertyAccessor()) - continue; - - StringRef Name = API.copyString(Method->getSelector().getAsString()); - StringRef USR = API.recordUSR(Method); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Method->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments, sub-heading, and signature for the method. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Method); - FunctionSignature Signature = - DeclarationFragmentsBuilder::getFunctionSignature(Method); - - API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method), - Comment, Declaration, SubHeading, Signature, - Method->isInstanceMethod(), - isInSystemHeader(Context, Method)); - } -} - -void ExtractAPIVisitor::recordObjCProperties( - ObjCContainerRecord *Container, - const ObjCContainerDecl::prop_range Properties) { - for (const auto *Property : Properties) { - StringRef Name = Property->getName(); - StringRef USR = API.recordUSR(Property); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Property->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the property. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Property); - - StringRef GetterName = - API.copyString(Property->getGetterName().getAsString()); - StringRef SetterName = - API.copyString(Property->getSetterName().getAsString()); - - // Get the attributes for property. - unsigned Attributes = ObjCPropertyRecord::NoAttr; - if (Property->getPropertyAttributes() & - ObjCPropertyAttribute::kind_readonly) - Attributes |= ObjCPropertyRecord::ReadOnly; - - API.addObjCProperty( - Container, Name, USR, Loc, AvailabilitySet(Property), Comment, - Declaration, SubHeading, - static_cast(Attributes), GetterName, - SetterName, Property->isOptional(), - !(Property->getPropertyAttributes() & - ObjCPropertyAttribute::kind_class), - isInSystemHeader(Context, Property)); - } -} - -void ExtractAPIVisitor::recordObjCInstanceVariables( - ObjCContainerRecord *Container, - const llvm::iterator_range< - DeclContext::specific_decl_iterator> - Ivars) { - for (const auto *Ivar : Ivars) { - StringRef Name = Ivar->getName(); - StringRef USR = API.recordUSR(Ivar); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); - DocComment Comment; - if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the instance variable. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForField(Ivar); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Ivar); - - ObjCInstanceVariableRecord::AccessControl Access = - Ivar->getCanonicalAccessControl(); - - API.addObjCInstanceVariable( - Container, Name, USR, Loc, AvailabilitySet(Ivar), Comment, Declaration, - SubHeading, Access, isInSystemHeader(Context, Ivar)); - } -} - -void ExtractAPIVisitor::recordObjCProtocols( - ObjCContainerRecord *Container, - ObjCInterfaceDecl::protocol_range Protocols) { - for (const auto *Protocol : Protocols) - Container->Protocols.emplace_back(Protocol->getName(), - API.recordUSR(Protocol)); -} diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index a9c69e058f63c..26f65325ec20b 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -544,10 +544,6 @@ Array generateParentContexts(const RecordTy &Record, const APISet &API, serializeParentContext(PC, Lang)); }); - // The last component would be the record itself so let's remove it. - if (!ParentContexts.empty()) - ParentContexts.pop_back(); - return ParentContexts; } diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp index 3da2424ea7263..3a5f62c9b2e6c 100644 --- a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp +++ b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp @@ -11,7 +11,7 @@ /// //===----------------------------------------------------------------------===// -#include "TypedefUnderlyingTypeResolver.h" +#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" using namespace clang; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 39218c9c287ae..b0b1e86fbe4b0 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6687,6 +6687,12 @@ static void handleSwiftAsyncName(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) SwiftAsyncNameAttr(S.Context, AL, Name)); } +static void handleTransparentStepping(Sema &S, Decl *D, + const ParsedAttr &AL) { + D->addAttr(::new (S.Context) + TransparentSteppingAttr(S.Context, AL)); +} + static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) { // Make sure that there is an identifier as the annotation's single argument. if (!AL.checkExactlyNumArgs(S, 1)) @@ -8948,6 +8954,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_NoDebug: handleNoDebugAttr(S, D, AL); break; + case ParsedAttr::AT_TransparentStepping: + handleTransparentStepping(S, D, AL); + break; case ParsedAttr::AT_CmseNSEntry: handleCmseNSEntryAttr(S, D, AL); break; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index fe63145171747..8fd551211fe67 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -78,27 +78,18 @@ class PrebuiltModuleListener : public ASTReaderListener { public: PrebuiltModuleListener(CompilerInstance &CI, PrebuiltModuleFilesT &PrebuiltModuleFiles, - llvm::StringSet<> &InputFiles, bool VisitInputFiles, llvm::SmallVector &NewModuleFiles) : CI(CI), PrebuiltModuleFiles(PrebuiltModuleFiles), - InputFiles(InputFiles), VisitInputFiles(VisitInputFiles), + NewModuleFiles(NewModuleFiles) {} bool needsImportVisitation() const override { return true; } - bool needsInputFileVisitation() override { return VisitInputFiles; } - bool needsSystemInputFileVisitation() override { return VisitInputFiles; } void visitImport(StringRef ModuleName, StringRef Filename) override { if (PrebuiltModuleFiles.insert({ModuleName.str(), Filename.str()}).second) NewModuleFiles.push_back(Filename.str()); } - bool visitInputFile(StringRef Filename, bool isSystem, bool isOverridden, - bool isExplicitModule) override { - InputFiles.insert(Filename); - return true; - } - bool readModuleCacheKey(StringRef ModuleName, StringRef Filename, StringRef CacheKey) override { CI.getFrontendOpts().ModuleCacheKeys.emplace_back(std::string(Filename), @@ -110,8 +101,6 @@ class PrebuiltModuleListener : public ASTReaderListener { private: CompilerInstance &CI; PrebuiltModuleFilesT &PrebuiltModuleFiles; - llvm::StringSet<> &InputFiles; - bool VisitInputFiles; llvm::SmallVector &NewModuleFiles; }; @@ -119,13 +108,10 @@ class PrebuiltModuleListener : public ASTReaderListener { /// transitively imports and contributing input files. static void visitPrebuiltModule(StringRef PrebuiltModuleFilename, CompilerInstance &CI, - PrebuiltModuleFilesT &ModuleFiles, - llvm::StringSet<> &InputFiles, - bool VisitInputFiles) { + PrebuiltModuleFilesT &ModuleFiles) { // List of module files to be processed. llvm::SmallVector Worklist{PrebuiltModuleFilename.str()}; - PrebuiltModuleListener Listener(CI, ModuleFiles, InputFiles, VisitInputFiles, - Worklist); + PrebuiltModuleListener Listener(CI, ModuleFiles, Worklist); while (!Worklist.empty()) ASTReader::readASTFileControlBlock( @@ -338,16 +324,13 @@ class DependencyScanningAction : public tooling::ToolAction { ScanInstance.createSourceManager(*FileMgr); - llvm::StringSet<> PrebuiltModulesInputFiles; // Store the list of prebuilt module files into header search options. This // will prevent the implicit build to create duplicate modules and will // force reuse of the existing prebuilt module files instead. if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) visitPrebuiltModule( ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance, - ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles, - PrebuiltModulesInputFiles, - /*VisitInputFiles=*/getDepScanFS() != nullptr); + ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles); // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { diff --git a/clang/test/ClangScanDeps/modules-pch.c b/clang/test/ClangScanDeps/modules-pch.c index 1d46c89d57909..e2778dc7c4f6a 100644 --- a/clang/test/ClangScanDeps/modules-pch.c +++ b/clang/test/ClangScanDeps/modules-pch.c @@ -7,8 +7,8 @@ // Scan dependencies of the PCH: // -// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_pch.json > %t/cdb.json -// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full \ +// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_pch.json > %t/cdb_pch.json +// RUN: clang-scan-deps -compilation-database %t/cdb_pch.json -format experimental-full \ // RUN: -module-files-dir %t/build > %t/result_pch.json // RUN: cat %t/result_pch.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t -check-prefix=CHECK-PCH // @@ -94,8 +94,8 @@ // Scan dependencies of the TU: // -// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_tu.json > %t/cdb.json -// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full \ +// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_tu.json > %t/cdb_tu.json +// RUN: clang-scan-deps -compilation-database %t/cdb_tu.json -format experimental-full \ // RUN: -module-files-dir %t/build > %t/result_tu.json // RUN: cat %t/result_tu.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t -check-prefix=CHECK-TU // @@ -142,8 +142,8 @@ // Scan dependencies of the TU that has common modules with the PCH: // -// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_tu_with_common.json > %t/cdb.json -// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full \ +// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_tu_with_common.json > %t/cdb_tu_with_common.json +// RUN: clang-scan-deps -compilation-database %t/cdb_tu_with_common.json -format experimental-full \ // RUN: -module-files-dir %t/build > %t/result_tu_with_common.json // RUN: cat %t/result_tu_with_common.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t -check-prefix=CHECK-TU-WITH-COMMON // diff --git a/clang/test/CodeGen/attr-transparent-stepping-method.cpp b/clang/test/CodeGen/attr-transparent-stepping-method.cpp new file mode 100644 index 0000000000000..5eb91b90bd65b --- /dev/null +++ b/clang/test/CodeGen/attr-transparent-stepping-method.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s + +void bar(void) {} + +struct A { +[[clang::transparent_stepping()]] +void foo(void) { + bar(); +} +}; + +int main() { + A().foo(); +} + +// CHECK: DISubprogram(name: "foo"{{.*}} DISPFlagIsTransparentStepping diff --git a/clang/test/CodeGen/attr-transparent-stepping.c b/clang/test/CodeGen/attr-transparent-stepping.c new file mode 100644 index 0000000000000..6ae42dce78123 --- /dev/null +++ b/clang/test/CodeGen/attr-transparent-stepping.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -debug-info-kind=limited -emit-llvm -o - %s | FileCheck %s + +void bar(void) {} + +__attribute__((transparent_stepping)) +void foo(void) { + bar(); +} + +// CHECK: DISubprogram(name: "foo"{{.*}} DISPFlagIsTransparentStepping diff --git a/clang/test/Index/extract-api-cursor.m b/clang/test/Index/extract-api-cursor.m index 078f2f52e215c..1b27b6f61437b 100644 --- a/clang/test/Index/extract-api-cursor.m +++ b/clang/test/Index/extract-api-cursor.m @@ -1,3 +1,5 @@ +// Test is line- and column-sensitive. Run lines are below + /// Foo docs struct Foo { /// Bar docs @@ -25,91 +27,94 @@ @interface Derived: Base - (void)derivedMethodWithValue:(id)value; @end -/// This won't show up in docs because we can't serialize it -@interface Derived () -/// Derived method in category docs, won't show up either. -- (void)derivedMethodInCategory; +@implementation Derived +- (void)derivedMethodWithValue:(id)value { + int a = 5; +} @end -// RUN: c-index-test -single-symbol-sgfs local %s | FileCheck %s - -// Checking for Foo -// CHECK: "parentContexts":[] -// CHECK-SAME: "relatedSymbols":[] -// CHECK-SAME: "relationships":[] -// CHECK-SAME: "text":"Foo docs" -// CHECK-SAME: "kind":{"displayName":"Structure","identifier":"objective-c.struct"} -// CHECK-SAME: "title":"Foo" - -// Checking for bar -// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S@Foo"}] -// CHECK-SAME: "relatedSymbols":[] -// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:@S@Foo@FI@bar","target":"c:@S@Foo" -// CHECK-SAME: "text":"Bar docs" -// CHECK-SAME: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"} -// CHECK-SAME: "title":"bar" - -// Checking for Base -// CHECK-NEXT: "parentContexts":[] -// CHECK-SAME: "relatedSymbols":[] -// CHECK-SAME: "relationships":[] -// CHECK-SAME: "text":"Base docs" -// CHECK-SAME: "kind":{"displayName":"Class","identifier":"objective-c.class"} -// CHECK-SAME: "title":"Base" - -// Checking for baseProperty -// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}] -// CHECK-SAME: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" -// CHECK-SAME: "isSystem":false -// CHECK-SAME: "usr":"c:@S@Foo"}] -// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(py)baseProperty","target":"c:objc(cs)Base" -// CHECK-SAME: "text":"Base property docs" -// CHECK-SAME: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"} -// CHECK-SAME: "title":"baseProperty" - -// Checking for baseMethodWithArg -// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}] -// CHECK-SAME: "relatedSymbols":[] -// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(im)baseMethodWithArg:","target":"c:objc(cs)Base" -// CHECK-SAME: "text":"Base method docs" -// CHECK-SAME: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"} -// CHECK-SAME: "title":"baseMethodWithArg:" - -// Checking for Protocol -// CHECK-NEXT: "parentContexts":[] -// CHECK-SAME: "relatedSymbols":[] -// CHECK-SAME: "relationships":[] -// CHECK-SAME: "text":"Protocol docs" -// CHECK-SAME: "kind":{"displayName":"Protocol","identifier":"objective-c.protocol"} -// CHECK-SAME: "title":"Protocol" - -// Checking for protocolProperty -// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}] -// CHECK-SAME: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" -// CHECK-SAME: "isSystem":false -// CHECK-SAME: "usr":"c:@S@Foo"}] -// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(pl)Protocol(py)protocolProperty","target":"c:objc(pl)Protocol" -// CHECK-SAME: "text":"Protocol property docs" -// CHECK-SAME: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"} -// CHECK-SAME: "title":"protocolProperty" - -// Checking for Derived -// CHECK-NEXT: "parentContexts":[] -// CHECK-SAME: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" -// CHECK-SAME: "isSystem":false -// CHECK-SAME: "usr":"c:objc(cs)Base"}] -// CHECK-SAME: "relationships":[{"kind":"inheritsFrom","source":"c:objc(cs)Derived","target":"c:objc(cs)Base" -// CHECK-SAME: "text":"Derived docs" -// CHECK-SAME: "kind":{"displayName":"Class","identifier":"objective-c.class"} -// CHECK-SAME: "title":"Derived" - -// Checking for derivedMethodWithValue -// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}] -// CHECK-SAME: "relatedSymbols":[] -// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)derivedMethodWithValue:","target":"c:objc(cs)Derived" -// CHECK-SAME: "text":"Derived method docs" -// CHECK-SAME: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"} -// CHECK-SAME: "title":"derivedMethodWithValue:" - -// CHECK-NOT: This won't show up in docs because we can't serialize it -// CHECK-NOT: Derived method in category docs, won't show up either. +// RUN: c-index-test -single-symbol-sgf-at=%s:4:9 local %s | FileCheck -check-prefix=CHECK-FOO %s +// CHECK-FOO: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S@Foo"}] +// CHECK-FOO: "relatedSymbols":[] +// CHECK-FOO: "relationships":[] +// CHECK-FOO: "text":"Foo docs" +// CHECK-FOO: "kind":{"displayName":"Structure","identifier":"objective-c.struct"} +// CHECK-FOO: "title":"Foo" + +// RUN: c-index-test -single-symbol-sgf-at=%s:6:9 local %s | FileCheck -check-prefix=CHECK-BAR %s +// CHECK-BAR: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S@Foo"},{"kind":"objective-c.property","name":"bar","usr":"c:@S@Foo@FI@bar"}] +// CHECK-BAR: "relatedSymbols":[] +// CHECK-BAR: "relationships":[{"kind":"memberOf","source":"c:@S@Foo@FI@bar","target":"c:@S@Foo" +// CHECK-BAR: "text":"Bar docs" +// CHECK-BAR: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"} +// CHECK-BAR: "title":"bar" + +// RUN: c-index-test -single-symbol-sgf-at=%s:10:11 local %s | FileCheck -check-prefix=CHECK-BASE %s +// CHECK-BASE: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}] +// CHECK-BASE: "relatedSymbols":[] +// CHECK-BASE: "relationships":[] +// CHECK-BASE: "text":"Base docs" +// CHECK-BASE: "kind":{"displayName":"Class","identifier":"objective-c.class"} +// CHECK-BASE: "title":"Base" + +// RUN: c-index-test -single-symbol-sgf-at=%s:12:25 local %s | FileCheck -check-prefix=CHECK-BASE-PROP %s +// CHECK-BASE-PROP: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"},{"kind":"objective-c.property","name":"baseProperty","usr":"c:objc(cs)Base(py)baseProperty"}] +// CHECK-BASE-PROP: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" +// CHECK-BASE-PROP: "isSystem":false +// CHECK-BASE-PROP: "usr":"c:@S@Foo"}] +// CHECK-BASE-PROP: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(py)baseProperty","target":"c:objc(cs)Base" +// CHECK-BASE-PROP: "text":"Base property docs" +// CHECK-BASE-PROP: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"} +// CHECK-BASE-PROP: "title":"baseProperty" + +// RUN: c-index-test -single-symbol-sgf-at=%s:15:9 local %s | FileCheck -check-prefix=CHECK-BASE-METHOD %s +// CHECK-BASE-METHOD: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"},{"kind":"objective-c.method","name":"baseMethodWithArg:","usr":"c:objc(cs)Base(im)baseMethodWithArg:"}] +// CHECK-BASE-METHOD: "relatedSymbols":[] +// CHECK-BASE-METHOD: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(im)baseMethodWithArg:","target":"c:objc(cs)Base" +// CHECK-BASE-METHOD: "text":"Base method docs" +// CHECK-BASE-METHOD: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"} +// CHECK-BASE-METHOD: "title":"baseMethodWithArg:" + +// RUN: c-index-test -single-symbol-sgf-at=%s:19:11 local %s | FileCheck -check-prefix=CHECK-PROTOCOL %s +// CHECK-PROTOCOL: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}] +// CHECK-PROTOCOL: "relatedSymbols":[] +// CHECK-PROTOCOL: "relationships":[] +// CHECK-PROTOCOL: "text":"Protocol docs" +// CHECK-PROTOCOL: "kind":{"displayName":"Protocol","identifier":"objective-c.protocol"} +// CHECK-PROTOCOL: "title":"Protocol" + +// RUN: c-index-test -single-symbol-sgf-at=%s:21:27 local %s | FileCheck -check-prefix=CHECK-PROTOCOL-PROP %s +// CHECK-PROTOCOL-PROP: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"},{"kind":"objective-c.property","name":"protocolProperty","usr":"c:objc(pl)Protocol(py)protocolProperty"}] +// CHECK-PROTOCOL-PROP: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" +// CHECK-PROTOCOL-PROP: "isSystem":false +// CHECK-PROTOCOL-PROP: "usr":"c:@S@Foo"}] +// CHECK-PROTOCOL-PROP: "relationships":[{"kind":"memberOf","source":"c:objc(pl)Protocol(py)protocolProperty","target":"c:objc(pl)Protocol" +// CHECK-PROTOCOL-PROP: "text":"Protocol property docs" +// CHECK-PROTOCOL-PROP: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"} +// CHECK-PROTOCOL-PROP: "title":"protocolProperty" + +// RUN: c-index-test -single-symbol-sgf-at=%s:25:15 local %s | FileCheck -check-prefix=CHECK-DERIVED %s +// CHECK-DERIVED: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}] +// CHECK-DERIVED: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" +// CHECK-DERIVED: "isSystem":false +// CHECK-DERIVED: "usr":"c:objc(cs)Base"}] +// CHECK-DERIVED: "relationships":[{"kind":"inheritsFrom","source":"c:objc(cs)Derived","target":"c:objc(cs)Base" +// CHECK-DERIVED: "text":"Derived docs" +// CHECK-DERIVED: "kind":{"displayName":"Class","identifier":"objective-c.class"} +// CHECK-DERIVED: "title":"Derived" + +// RUN: c-index-test -single-symbol-sgf-at=%s:27:11 local %s | FileCheck -check-prefix=CHECK-DERIVED-METHOD %s +// CHECK-DERIVED-METHOD: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"},{"kind":"objective-c.method","name":"derivedMethodWithValue:","usr":"c:objc(cs)Derived(im)derivedMethodWithValue:"}] +// CHECK-DERIVED-METHOD: "relatedSymbols":[] +// CHECK-DERIVED-METHOD: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)derivedMethodWithValue:","target":"c:objc(cs)Derived" +// CHECK-DERIVED-METHOD: "text":"Derived method docs" +// CHECK-DERIVED-METHOD: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"} +// CHECK-DERIVED-METHOD: "title":"derivedMethodWithValue:" + +// RUN: c-index-test -single-symbol-sgf-at=%s:31:11 local %s | FileCheck -check-prefix=CHECK-DERIVED-METHOD-IMPL %s +// CHECK-DERIVED-METHOD-IMPL: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"},{"kind":"objective-c.method","name":"derivedMethodWithValue:","usr":"c:objc(cs)Derived(im)derivedMethodWithValue:"}] +// CHECK-DERIVED-METHOD-IMPL: "relatedSymbols":[] +// CHECK-DERIVED-METHOD-IMPL: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)derivedMethodWithValue:","target":"c:objc(cs)Derived" +// CHECK-DERIVED-METHOD-IMPL: "text":"Derived method docs" +// CHECK-DERIVED-METHOD-IMPL: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"} +// CHECK-DERIVED-METHOD-IMPL: "title":"derivedMethodWithValue:" diff --git a/clang/test/Index/extract-api-usr.m b/clang/test/Index/extract-api-usr.m index 12bfb0a676e66..0b468ee916708 100644 --- a/clang/test/Index/extract-api-usr.m +++ b/clang/test/Index/extract-api-usr.m @@ -28,7 +28,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for Foo // RUN: c-index-test "-single-symbol-sgf-for=c:@S@Foo" %s | FileCheck -check-prefix=CHECK-FOO %s -// CHECK-FOO: "parentContexts":[] +// CHECK-FOO: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S@Foo"}] // CHECK-FOO-SAME: "relatedSymbols":[] // CHECK-FOO-SAME: "relationships":[] // CHECK-FOO-SAME: "text":"Foo docs" @@ -38,7 +38,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for bar // RUN: c-index-test "-single-symbol-sgf-for=c:@S@Foo@FI@bar" %s | FileCheck -check-prefix=CHECK-BAR %s -// CHECK-BAR: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S@Foo"}] +// CHECK-BAR: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S@Foo"},{"kind":"objective-c.property","name":"bar","usr":"c:@S@Foo@FI@bar"}] // CHECK-BAR-SAME: "relatedSymbols":[] // CHECK-BAR-SAME: "relationships":[{"kind":"memberOf","source":"c:@S@Foo@FI@bar","target":"c:@S@Foo" // CHECK-BAR-SAME: "text":"Bar docs" @@ -47,7 +47,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for Base // RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Base" %s | FileCheck -check-prefix=CHECK-BASE %s -// CHECK-BASE: "parentContexts":[] +// CHECK-BASE: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}] // CHECK-BASE-SAME: "relatedSymbols":[] // CHECK-BASE-SAME: "relationships":[] // CHECK-BASE-SAME: "text":"Base docs" @@ -56,7 +56,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for baseProperty // RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Base(py)baseProperty" %s | FileCheck -check-prefix=CHECK-BASEPROP %s -// CHECK-BASEPROP: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}] +// CHECK-BASEPROP: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"},{"kind":"objective-c.property","name":"baseProperty","usr":"c:objc(cs)Base(py)baseProperty"}] // CHECK-BASEPROP-SAME:"relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" // CHECK-BASEPROP-SAME: "isSystem":false // CHECK-BASEPROP-SAME: "usr":"c:@S@Foo"}] @@ -67,7 +67,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for baseMethodWithArg // RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Base(im)baseMethodWithArg:" %s | FileCheck -check-prefix=CHECK-BASEMETHOD %s -// CHECK-BASEMETHOD: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}] +// CHECK-BASEMETHOD: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"},{"kind":"objective-c.method","name":"baseMethodWithArg:","usr":"c:objc(cs)Base(im)baseMethodWithArg:"}] // CHECK-BASEMETHOD-SAME:"relatedSymbols":[] // CHECK-BASEMETHOD-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(im)baseMethodWithArg:","target":"c:objc(cs)Base" // CHECK-BASEMETHOD-SAME: "text":"Base method docs" @@ -76,7 +76,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for Protocol // RUN: c-index-test "-single-symbol-sgf-for=c:objc(pl)Protocol" %s | FileCheck -check-prefix=CHECK-PROT %s -// CHECK-PROT: "parentContexts":[] +// CHECK-PROT: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}] // CHECK-PROT-SAME: "relatedSymbols":[] // CHECK-PROT-SAME: "relationships":[] // CHECK-PROT-SAME: "text":"Protocol docs" @@ -85,7 +85,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for protocolProperty // RUN: c-index-test "-single-symbol-sgf-for=c:objc(pl)Protocol(py)protocolProperty" %s | FileCheck -check-prefix=CHECK-PROTPROP %s -// CHECK-PROTPROP: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}] +// CHECK-PROTPROP: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"},{"kind":"objective-c.property","name":"protocolProperty","usr":"c:objc(pl)Protocol(py)protocolProperty"}] // CHECK-PROTPROP-SAME:"relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" // CHECK-PROTPROP-SAME: "isSystem":false // CHECK-PROTPROP-SAME: "usr":"c:@S@Foo"}] @@ -96,7 +96,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for Derived // RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Derived" %s | FileCheck -check-prefix=CHECK-DERIVED %s -// CHECK-DERIVED: "parentContexts":[] +// CHECK-DERIVED: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}] // CHECK-DERIVED-SAME:"relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c" // CHECK-DERIVED-SAME: "isSystem":false // CHECK-DERIVED-SAME: "usr":"c:objc(cs)Base"}] @@ -107,7 +107,7 @@ - (void)derivedMethodWithValue:(id)value; // Checking for derivedMethodWithValue // RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Derived(im)derivedMethodWithValue:" %s | FileCheck -check-prefix=CHECK-DERIVEDMETHOD %s -// CHECK-DERIVEDMETHOD: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}] +// CHECK-DERIVEDMETHOD: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"},{"kind":"objective-c.method","name":"derivedMethodWithValue:","usr":"c:objc(cs)Derived(im)derivedMethodWithValue:"}] // CHECK-DERIVEDMETHOD-SAME:"relatedSymbols":[] // CHECK-DERIVEDMETHOD-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)derivedMethodWithValue:","target":"c:objc(cs)Derived" // CHECK-DERIVEDMETHOD-SAME: "text":"Derived method docs" diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index f7c5ce9468841..d55874611cabe 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -185,6 +185,7 @@ // CHECK-NEXT: Target (SubjectMatchRule_function) // CHECK-NEXT: TargetClones (SubjectMatchRule_function) // CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member) +// CHECK-NEXT: TransparentStepping (SubjectMatchRule_function) // CHECK-NEXT: TrivialABI (SubjectMatchRule_record) // CHECK-NEXT: Uninitialized (SubjectMatchRule_variable_is_local) // CHECK-NEXT: UseHandle (SubjectMatchRule_variable_is_parameter) diff --git a/clang/test/Modules/system-Rmodule-build.m b/clang/test/Modules/system-Rmodule-build.m new file mode 100644 index 0000000000000..f631487befd20 --- /dev/null +++ b/clang/test/Modules/system-Rmodule-build.m @@ -0,0 +1,16 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t/sys +// RUN: echo '#include ' > %t/sys/A.h +// RUN: echo '' > %t/sys/B.h +// RUN: echo 'module A { header "A.h" }' > %t/sys/module.modulemap +// RUN: echo 'module B { header "B.h" }' >> %t/sys/module.modulemap + +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fsyntax-only %s \ +// RUN: -isystem %t/sys -Rmodule-build 2>&1 | FileCheck %s + +@import A; + +// CHECK: building module 'A' as +// CHECK: building module 'B' as +// CHECK: finished building module 'B' +// CHECK: finished building module 'A' diff --git a/clang/test/Sema/attr-transparent-stepping.c b/clang/test/Sema/attr-transparent-stepping.c new file mode 100644 index 0000000000000..8bcaa823f9542 --- /dev/null +++ b/clang/test/Sema/attr-transparent-stepping.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only + +__attribute__((transparent_stepping)) +void correct(void) {} + +__attribute__((transparent_stepping(1))) // expected-error {{'transparent_stepping' attribute takes no arguments}} +void wrong_arg(void) {} diff --git a/clang/test/SemaCXX/attr-transparent-stepping-method.cpp b/clang/test/SemaCXX/attr-transparent-stepping-method.cpp new file mode 100644 index 0000000000000..7f2be98a7c584 --- /dev/null +++ b/clang/test/SemaCXX/attr-transparent-stepping-method.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only + + +struct S { +[[clang::transparent_stepping]] +void correct(void) {} + +[[clang::transparent_stepping(1)]] // expected-error {{'transparent_stepping' attribute takes no arguments}} +void one_arg(void) {} +}; + diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index 052c39a15d33e..cd0034d938aa8 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -3,6 +3,7 @@ #include "clang-c/BuildSystem.h" #include "clang-c/CXCompilationDatabase.h" #include "clang-c/CXErrorCode.h" +#include "clang-c/CXSourceLocation.h" #include "clang-c/CXString.h" #include "clang-c/Documentation.h" #include "clang-c/Index.h" @@ -4887,6 +4888,22 @@ static int perform_test_single_symbol_sgf(const char *input, int argc, return result; } +static void inspect_single_symbol_sgf_cursor(CXCursor Cursor) { + CXSourceLocation CursorLoc; + CXString SGFData; + const char *SGF; + unsigned line, column; + CursorLoc = clang_getCursorLocation(Cursor); + clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0); + + SGFData = clang_getSymbolGraphForCursor(Cursor); + SGF = clang_getCString(SGFData); + if (SGF) + printf("%d:%d: %s\n", line, column, SGF); + + clang_disposeString(SGFData); +} + /******************************************************************************/ /* Command line processing. */ /******************************************************************************/ @@ -4946,6 +4963,7 @@ static void print_usage(void) { " c-index-test -print-usr-file \n"); fprintf(stderr, " c-index-test -single-symbol-sgfs {*}\n" + " c-index-test -single-symbol-sgf-at= {*}\n" " c-index-test -single-symbol-sgf-for= {}*\n"); fprintf(stderr, " c-index-test -write-pch \n" @@ -5082,6 +5100,9 @@ int cindextest_main(int argc, const char **argv) { else if (argc > 3 && strcmp(argv[1], "-single-symbol-sgfs") == 0) return perform_test_load_source(argc - 3, argv + 3, argv[2], PrintSingleSymbolSGFs, NULL); + else if (argc > 2 && strstr(argv[1], "-single-symbol-sgf-at=") == argv[1]) + return inspect_cursor_at( + argc, argv, "-single-symbol-sgf-at=", inspect_single_symbol_sgf_cursor); else if (argc > 2 && strstr(argv[1], "-single-symbol-sgf-for=") == argv[1]) return perform_test_single_symbol_sgf(argv[1], argc - 2, argv + 2); diff --git a/clang/tools/libclang/CXExtractAPI.cpp b/clang/tools/libclang/CXExtractAPI.cpp index 787334ab1bbb2..9128e891538a8 100644 --- a/clang/tools/libclang/CXExtractAPI.cpp +++ b/clang/tools/libclang/CXExtractAPI.cpp @@ -18,6 +18,7 @@ #include "clang-c/Index.h" #include "clang-c/Platform.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" #include "clang/Basic/TargetInfo.h" #include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/ExtractAPIVisitor.h" @@ -34,13 +35,73 @@ using namespace clang; using namespace clang::extractapi; +namespace { +struct LibClangExtractAPIVisitor + : ExtractAPIVisitor { + using Base = ExtractAPIVisitor; + + LibClangExtractAPIVisitor(ASTContext &Context, APISet &API) + : ExtractAPIVisitor(Context, API) {} + + const RawComment *fetchRawCommentForDecl(const Decl *D) const { + return Context.getRawCommentForAnyRedecl(D); + } + + // We need to visit implementations as well to ensure that when a user clicks + // on a method defined only within the implementation that we can still + // provide a symbol graph for it. + bool VisitObjCImplementationDecl(const ObjCImplementationDecl *Decl) { + if (!shouldDeclBeIncluded(Decl)) + return true; + + const ObjCInterfaceDecl *Interface = Decl->getClassInterface(); + StringRef Name = Interface->getName(); + StringRef USR = API.recordUSR(Decl); + PresumedLoc Loc = + Context.getSourceManager().getPresumedLoc(Decl->getLocation()); + LinkageInfo Linkage = Decl->getLinkageAndVisibility(); + DocComment Comment; + if (auto *RawComment = fetchRawCommentForDecl(Interface)) + Comment = RawComment->getFormattedLines(Context.getSourceManager(), + Context.getDiagnostics()); + + // Build declaration fragments and sub-heading by generating them for the + // interface. + DeclarationFragments Declaration = + DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Interface); + DeclarationFragments SubHeading = + DeclarationFragmentsBuilder::getSubHeading(Decl); + + // Collect super class information. + SymbolReference SuperClass; + if (const auto *SuperClassDecl = Decl->getSuperClass()) { + SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); + SuperClass.USR = API.recordUSR(SuperClassDecl); + } + + ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( + Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration, + SubHeading, SuperClass, isInSystemHeader(Decl)); + + // Record all methods (selectors). This doesn't include automatically + // synthesized property methods. + recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); + recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); + recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); + + return true; + } +}; +} // namespace + DEFINE_SIMPLE_CONVERSION_FUNCTIONS(APISet, CXAPISet) -static void WalkupFromMostDerivedType(ExtractAPIVisitor &Visitor, Decl *D); +static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor, + Decl *D); template static bool WalkupParentContext(DeclContext *Parent, - ExtractAPIVisitor &Visitor) { + LibClangExtractAPIVisitor &Visitor) { if (auto *D = dyn_cast(Parent)) { WalkupFromMostDerivedType(Visitor, D); return true; @@ -48,7 +109,8 @@ static bool WalkupParentContext(DeclContext *Parent, return false; } -static void WalkupFromMostDerivedType(ExtractAPIVisitor &Visitor, Decl *D) { +static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor, + Decl *D) { switch (D->getKind()) { #define ABSTRACT_DECL(DECL) #define DECL(CLASS, BASE) \ @@ -84,8 +146,7 @@ enum CXErrorCode clang_createAPISet(CXTranslationUnit tu, CXAPISet *out_api) { auto Lang = Unit->getInputKind().getLanguage(); APISet *API = new APISet(Ctx.getTargetInfo().getTriple(), Lang, Unit->getMainFileName().str()); - ExtractAPIVisitor Visitor( - Ctx, [](SourceLocation Loc) { return true; }, *API); + LibClangExtractAPIVisitor Visitor(Ctx, *API); for (auto It = Unit->top_level_begin(); It != Unit->top_level_end(); ++It) { Visitor.TraverseDecl(*It); @@ -107,45 +168,50 @@ CXString clang_getSymbolGraphForUSR(const char *usr, CXAPISet api) { } CXString clang_getSymbolGraphForCursor(CXCursor cursor) { + cursor = clang_getCursorReferenced(cursor); CXCursorKind Kind = clang_getCursorKind(cursor); - if (clang_isDeclaration(Kind)) { - const Decl *D = cxcursor::getCursorDecl(cursor); + if (!clang_isDeclaration(Kind)) + return cxstring::createNull(); - if (!D) - return cxstring::createNull(); + const Decl *D = cxcursor::getCursorDecl(cursor); - CXTranslationUnit TU = cxcursor::getCursorTU(cursor); - if (!TU) - return cxstring::createNull(); + if (!D) + return cxstring::createNull(); - ASTUnit *Unit = cxtu::getASTUnit(TU); + CXTranslationUnit TU = cxcursor::getCursorTU(cursor); + if (!TU) + return cxstring::createNull(); - auto &Ctx = Unit->getASTContext(); - auto Lang = Unit->getInputKind().getLanguage(); - APISet API(Ctx.getTargetInfo().getTriple(), Lang, - Unit->getMainFileName().str()); - ExtractAPIVisitor Visitor( - Ctx, [](SourceLocation Loc) { return true; }, API); + ASTUnit *Unit = cxtu::getASTUnit(TU); - SmallString<128> USR; - if (index::generateUSRForDecl(D, USR)) - return cxstring::createNull(); + auto &Ctx = Unit->getASTContext(); - WalkupFromMostDerivedType(Visitor, const_cast(D)); - auto *Record = API.findRecordForUSR(USR); + auto Lang = Unit->getInputKind().getLanguage(); + APISet API(Ctx.getTargetInfo().getTriple(), Lang, + Unit->getMainFileName().str()); + LibClangExtractAPIVisitor Visitor(Ctx, API); - if (!Record) - return cxstring::createNull(); + const Decl *CanonicalDecl = D->getCanonicalDecl(); + CanonicalDecl = CanonicalDecl ? CanonicalDecl : D; - for (const auto &Fragment : Record->Declaration.getFragments()) { - if (Fragment.Declaration) - WalkupFromMostDerivedType(Visitor, - const_cast(Fragment.Declaration)); - } + SmallString<128> USR; + if (index::generateUSRForDecl(CanonicalDecl, USR)) + return cxstring::createNull(); - if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API)) - return GenerateCXStringFromSymbolGraphData(std::move(*SGF)); + WalkupFromMostDerivedType(Visitor, const_cast(CanonicalDecl)); + auto *Record = API.findRecordForUSR(USR); + + if (!Record) + return cxstring::createNull(); + + for (const auto &Fragment : Record->Declaration.getFragments()) { + if (Fragment.Declaration) + WalkupFromMostDerivedType(Visitor, + const_cast(Fragment.Declaration)); } + if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API)) + return GenerateCXStringFromSymbolGraphData(std::move(*SGF)); + return cxstring::createNull(); } diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cpp index 1ee47bcd1237e..e4f9e2915ced2 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cpp @@ -18,6 +18,7 @@ #include "tsan_interceptors.h" #include "tsan_interface.h" #include "tsan_interface_ann.h" +#include "tsan_spinlock_defs_mac.h" #include "sanitizer_common/sanitizer_addrhashmap.h" #include diff --git a/compiler-rt/lib/tsan/rtl/tsan_spinlock_defs_mac.h b/compiler-rt/lib/tsan/rtl/tsan_spinlock_defs_mac.h new file mode 100644 index 0000000000000..1a99a81c03023 --- /dev/null +++ b/compiler-rt/lib/tsan/rtl/tsan_spinlock_defs_mac.h @@ -0,0 +1,45 @@ +//===-- tsan_spinlock_defs_mac.h -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer (TSan), a race detector. +// +// Mac-specific forward-declared function defintions that may be +// deprecated in later versions of the OS. +// These are needed for interceptors. +// +//===----------------------------------------------------------------------===// + +#if SANITIZER_APPLE + +#ifndef TSAN_SPINLOCK_DEFS_MAC_H +#define TSAN_SPINLOCK_DEFS_MAC_H + +#include + +extern "C" { + +/* +Provides forward declarations related to OSSpinLocks on Darwin. These functions are +deprecated on macOS version 10.12 and later, +and are no longer included in the system headers. + +However, the symbols are still available on the system, so we provide these forward +declarations to prevent compilation errors in tsan_interceptors_mac.cpp, which +references these functions when defining TSAN interceptor functions. +*/ + +typedef int32_t OSSpinLock; + +void OSSpinLockLock(volatile OSSpinLock *__lock); +void OSSpinLockUnlock(volatile OSSpinLock *__lock); +bool OSSpinLockTry(volatile OSSpinLock *__lock); + +} + +#endif //TSAN_SPINLOCK_DEFS_MAC_H +#endif // SANITIZER_APPLE diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index f4114494d951c..86a75977ab5e1 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -17,6 +17,10 @@ endif() # Must go below project(..) include(GNUInstallDirs) +# BEGIN SWIFT MOD +option(LLDB_ENABLE_SWIFT_SUPPORT "Enable swift support" ON) +# END SWIFT MOD + if(LLDB_BUILT_STANDALONE) include(LLDBStandalone) @@ -33,25 +37,29 @@ include(LLDBConfig) include(AddLLDB) # BEGIN - Swift Mods -if(EXISTS "${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}") - list(APPEND CMAKE_MODULE_PATH - "${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}/cmake" - "${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}/cmake/modules") -elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../swift) - list(APPEND CMAKE_MODULE_PATH - "${CMAKE_CURRENT_SOURCE_DIR}/../swift/cmake" - "${CMAKE_CURRENT_SOURCE_DIR}/../swift/cmake/modules") +if (LLDB_ENABLE_SWIFT_SUPPORT) + if(EXISTS "${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}") + list(APPEND CMAKE_MODULE_PATH + "${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}/cmake" + "${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}/cmake/modules") + elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../swift) + list(APPEND CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/../swift/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/../swift/cmake/modules") + endif() endif() # When we have the early SwiftSyntax build, we can include its parser. -if(SWIFT_PATH_TO_EARLYSWIFTSYNTAX_BUILD_DIR) - set(SWIFT_PATH_TO_EARLYSWIFTSYNTAX_TARGETS - ${SWIFT_PATH_TO_EARLYSWIFTSYNTAX_BUILD_DIR}/cmake/SwiftSyntaxTargets.cmake) - if(NOT EXISTS "${SWIFT_PATH_TO_EARLYSWIFTSYNTAX_TARGETS}") - message(STATUS "Skipping Swift Swift parser integration due to missing early SwiftSyntax") - else() - set(SWIFT_SWIFT_PARSER TRUE) - include(${SWIFT_PATH_TO_EARLYSWIFTSYNTAX_TARGETS}) +if (LLDB_ENABLE_SWIFT_SUPPORT) + if(SWIFT_PATH_TO_EARLYSWIFTSYNTAX_BUILD_DIR) + set(SWIFT_PATH_TO_EARLYSWIFTSYNTAX_TARGETS + ${SWIFT_PATH_TO_EARLYSWIFTSYNTAX_BUILD_DIR}/cmake/SwiftSyntaxTargets.cmake) + if(NOT EXISTS "${SWIFT_PATH_TO_EARLYSWIFTSYNTAX_TARGETS}") + message(STATUS "Skipping Swift Swift parser integration due to missing early SwiftSyntax") + else() + set(SWIFT_SWIFT_PARSER TRUE) + include(${SWIFT_PATH_TO_EARLYSWIFTSYNTAX_TARGETS}) + endif() endif() endif() # END - Swift Mods diff --git a/lldb/bindings/interface/SBDebugger.i b/lldb/bindings/interface/SBDebugger.i index 07f807b739499..28094081e555e 100644 --- a/lldb/bindings/interface/SBDebugger.i +++ b/lldb/bindings/interface/SBDebugger.i @@ -131,6 +131,8 @@ public: uint64_t &OUTPUT, bool &OUTPUT); + static lldb::SBStructuredData GetProgressDataFromEvent(const lldb::SBEvent &event); + static lldb::SBStructuredData GetDiagnosticFromEvent(const lldb::SBEvent &event); SBBroadcaster GetBroadcaster(); diff --git a/lldb/bindings/python/static-binding/LLDBWrapPython.cpp b/lldb/bindings/python/static-binding/LLDBWrapPython.cpp index b67527430e79c..fc418ca3518ee 100644 --- a/lldb/bindings/python/static-binding/LLDBWrapPython.cpp +++ b/lldb/bindings/python/static-binding/LLDBWrapPython.cpp @@ -21677,6 +21677,36 @@ SWIGINTERN PyObject *_wrap_SBDebugger_GetProgressFromEvent(PyObject *self, PyObj } +SWIGINTERN PyObject *_wrap_SBDebugger_GetProgressDataFromEvent(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + lldb::SBEvent *arg1 = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + lldb::SBStructuredData result; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1, SWIGTYPE_p_lldb__SBEvent, 0 | 0); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "SBDebugger_GetProgressDataFromEvent" "', argument " "1"" of type '" "lldb::SBEvent const &""'"); + } + if (!argp1) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "SBDebugger_GetProgressDataFromEvent" "', argument " "1"" of type '" "lldb::SBEvent const &""'"); + } + arg1 = reinterpret_cast< lldb::SBEvent * >(argp1); + { + SWIG_PYTHON_THREAD_BEGIN_ALLOW; + result = lldb::SBDebugger::GetProgressDataFromEvent((lldb::SBEvent const &)*arg1); + SWIG_PYTHON_THREAD_END_ALLOW; + } + resultobj = SWIG_NewPointerObj((new lldb::SBStructuredData(result)), SWIGTYPE_p_lldb__SBStructuredData, SWIG_POINTER_OWN | 0 ); + return resultobj; +fail: + return NULL; +} + + SWIGINTERN PyObject *_wrap_SBDebugger_GetDiagnosticFromEvent(PyObject *self, PyObject *args) { PyObject *resultobj = 0; lldb::SBEvent *arg1 = 0 ; @@ -84702,6 +84732,7 @@ static PyMethodDef SwigMethods[] = { { "SBData_swigregister", SBData_swigregister, METH_O, NULL}, { "SBData_swiginit", SBData_swiginit, METH_VARARGS, NULL}, { "SBDebugger_GetProgressFromEvent", _wrap_SBDebugger_GetProgressFromEvent, METH_O, "SBDebugger_GetProgressFromEvent(SBEvent event) -> char const *"}, + { "SBDebugger_GetProgressDataFromEvent", _wrap_SBDebugger_GetProgressDataFromEvent, METH_O, "SBDebugger_GetProgressDataFromEvent(SBEvent event) -> SBStructuredData"}, { "SBDebugger_GetDiagnosticFromEvent", _wrap_SBDebugger_GetDiagnosticFromEvent, METH_O, "SBDebugger_GetDiagnosticFromEvent(SBEvent event) -> SBStructuredData"}, { "SBDebugger_GetBroadcaster", _wrap_SBDebugger_GetBroadcaster, METH_O, "SBDebugger_GetBroadcaster(SBDebugger self) -> SBBroadcaster"}, { "SBDebugger_Initialize", _wrap_SBDebugger_Initialize, METH_NOARGS, "SBDebugger_Initialize()"}, diff --git a/lldb/bindings/python/static-binding/lldb.py b/lldb/bindings/python/static-binding/lldb.py index 2c489165fc293..077c8b4cf31df 100644 --- a/lldb/bindings/python/static-binding/lldb.py +++ b/lldb/bindings/python/static-binding/lldb.py @@ -4191,6 +4191,11 @@ def GetProgressFromEvent(event): r"""GetProgressFromEvent(SBEvent event) -> char const *""" return _lldb.SBDebugger_GetProgressFromEvent(event) + @staticmethod + def GetProgressDataFromEvent(event): + r"""GetProgressDataFromEvent(SBEvent event) -> SBStructuredData""" + return _lldb.SBDebugger_GetProgressDataFromEvent(event) + @staticmethod def GetDiagnosticFromEvent(event): r"""GetDiagnosticFromEvent(SBEvent event) -> SBStructuredData""" diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 97ee382203c4d..048a6db104553 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -86,10 +86,18 @@ option(LLDB_ENFORCE_STRICT_TEST_REQUIREMENTS "Fail to configure if certain requirements are not met for testing." OFF) # BEGIN SWIFT MOD -option(LLDB_ENABLE_SWIFT_SUPPORT "Enable swift support" ON) option(LLDB_ENABLE_WERROR "Fail and stop if a warning is triggered." ${LLVM_ENABLE_WERROR}) if(LLDB_ENABLE_SWIFT_SUPPORT) add_definitions( -DLLDB_ENABLE_SWIFT ) +else() + # LLVM_DISTRIBUTION_COMPONENTS may have swift-specific things in them (e.g. + # repl_swift). This may be set in a cache where LLDB_ENABLE_SWIFT_SUPPORT does + # not yet have a value. We have to touch up LLVM_DISTRIBUTION_COMPONENTS after + # the fact. + if(LLVM_DISTRIBUTION_COMPONENTS) + list(REMOVE_ITEM LLVM_DISTRIBUTION_COMPONENTS repl_swift) + set(LLVM_DISTRIBUTION_COMPONENTS ${LLVM_DISTRIBUTION_COMPONENTS} CACHE STRING "" FORCE) + endif() endif() # END SWIFT CODE @@ -210,17 +218,19 @@ else () endif () include_directories("${CMAKE_CURRENT_BINARY_DIR}/../clang/include") -if(NOT LLDB_BUILT_STANDALONE) - if (LLVM_EXTERNAL_SWIFT_SOURCE_DIR) - include_directories(${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}/include) - include_directories(${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}/stdlib/public/SwiftShims) +if(LLDB_ENABLE_SWIFT_SUPPORT) + if(NOT LLDB_BUILT_STANDALONE) + if (LLVM_EXTERNAL_SWIFT_SOURCE_DIR) + include_directories(${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}/include) + include_directories(${LLVM_EXTERNAL_SWIFT_SOURCE_DIR}/stdlib/public/SwiftShims) + else () + include_directories(${CMAKE_SOURCE_DIR}/tools/swift/include) + include_directories(${CMAKE_SOURCE_DIR}/tools/swift/stdlib/public/SwiftShims) + endif () + include_directories("${CMAKE_CURRENT_BINARY_DIR}/../swift/include") else () - include_directories(${CMAKE_SOURCE_DIR}/tools/swift/include) - include_directories(${CMAKE_SOURCE_DIR}/tools/swift/stdlib/public/SwiftShims) - endif () - include_directories("${CMAKE_CURRENT_BINARY_DIR}/../swift/include") -else () - include_directories("${SWIFT_INCLUDE_DIRS}") + include_directories("${SWIFT_INCLUDE_DIRS}") + endif() endif() # GCC silently accepts any -Wno- option, but warns about those options diff --git a/lldb/cmake/modules/LLDBStandalone.cmake b/lldb/cmake/modules/LLDBStandalone.cmake index f6e2bd11cf252..d64791f194172 100644 --- a/lldb/cmake/modules/LLDBStandalone.cmake +++ b/lldb/cmake/modules/LLDBStandalone.cmake @@ -14,7 +14,9 @@ option(LLVM_INSTALL_TOOLCHAIN_ONLY "Only include toolchain files in the 'install find_package(LLVM REQUIRED CONFIG HINTS ${LLVM_DIR} NO_CMAKE_FIND_ROOT_PATH) find_package(Clang REQUIRED CONFIG HINTS ${Clang_DIR} ${LLVM_DIR}/../clang NO_CMAKE_FIND_ROOT_PATH) -find_package(Swift REQUIRED CONFIG HINTS "${Swift_DIR}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) +if(LLDB_ENABLE_SWIFT_SUPPORT) + find_package(Swift REQUIRED CONFIG HINTS "${Swift_DIR}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) +endif() # We set LLVM_CMAKE_DIR so that GetSVN.cmake is found correctly when building SVNVersion.inc set(LLVM_CMAKE_DIR ${LLVM_CMAKE_DIR} CACHE PATH "Path to LLVM CMake modules") @@ -88,7 +90,9 @@ endif() # CMake modules to be in that directory as well. file(TO_CMAKE_PATH ${LLVM_DIR} LLVM_DIR) list(APPEND CMAKE_MODULE_PATH "${LLVM_DIR}") -list(APPEND CMAKE_MODULE_PATH "${SWIFT_CMAKE_DIR}") +if(LLDB_ENABLE_SWIFT_SUPPORT) + list(APPEND CMAKE_MODULE_PATH "${SWIFT_CMAKE_DIR}") +endif() include(AddLLVM) include(TableGen) @@ -124,9 +128,12 @@ include_directories( "${CMAKE_BINARY_DIR}/include" "${LLVM_INCLUDE_DIRS}" "${CLANG_INCLUDE_DIRS}" - "${SWIFT_INCLUDE_DIRS}" - "${SWIFT_MAIN_SRC_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/source") +if(LLDB_ENABLE_SWIFT_SUPPORT) + include_directories( + "${SWIFT_INCLUDE_DIRS}" + "${SWIFT_MAIN_SRC_DIR}/include") +endif() if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h index a246057626869..35970b011023a 100644 --- a/lldb/include/lldb/API/SBDebugger.h +++ b/lldb/include/lldb/API/SBDebugger.h @@ -83,6 +83,9 @@ class LLDB_API SBDebugger { uint64_t &completed, uint64_t &total, bool &is_debugger_specific); + static lldb::SBStructuredData + GetProgressDataFromEvent(const lldb::SBEvent &event); + static lldb::SBStructuredData GetDiagnosticFromEvent(const lldb::SBEvent &event); diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 05bd2445e2fbf..42b9f27014f3d 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -514,8 +514,9 @@ class Debugger : public std::enable_shared_from_this, /// debugger identifier that this progress should be delivered to. If this /// optional parameter does not have a value, the progress will be /// delivered to all debuggers. - static void ReportProgress(uint64_t progress_id, const std::string &message, - uint64_t completed, uint64_t total, + static void ReportProgress(uint64_t progress_id, std::string title, + std::string details, uint64_t completed, + uint64_t total, llvm::Optional debugger_id); static void ReportDiagnosticImpl(DiagnosticEventData::Type type, diff --git a/lldb/include/lldb/Core/DebuggerEvents.h b/lldb/include/lldb/Core/DebuggerEvents.h index e1203dcf38c8c..5240d1b0c1dfb 100644 --- a/lldb/include/lldb/Core/DebuggerEvents.h +++ b/lldb/include/lldb/Core/DebuggerEvents.h @@ -20,10 +20,11 @@ class Stream; class ProgressEventData : public EventData { public: - ProgressEventData(uint64_t progress_id, const std::string &message, + ProgressEventData(uint64_t progress_id, std::string title, std::string update, uint64_t completed, uint64_t total, bool debugger_specific) - : m_message(message), m_id(progress_id), m_completed(completed), - m_total(total), m_debugger_specific(debugger_specific) {} + : m_title(std::move(title)), m_details(std::move(update)), + m_id(progress_id), m_completed(completed), m_total(total), + m_debugger_specific(debugger_specific) {} static ConstString GetFlavorString(); @@ -32,16 +33,38 @@ class ProgressEventData : public EventData { void Dump(Stream *s) const override; static const ProgressEventData *GetEventDataFromEvent(const Event *event_ptr); + + static StructuredData::DictionarySP + GetAsStructuredData(const Event *event_ptr); + uint64_t GetID() const { return m_id; } bool IsFinite() const { return m_total != UINT64_MAX; } uint64_t GetCompleted() const { return m_completed; } uint64_t GetTotal() const { return m_total; } - const std::string &GetMessage() const { return m_message; } + std::string GetMessage() const { + std::string message = m_title; + if (!m_details.empty()) { + message.append(": "); + message.append(m_details); + } + return message; + } + const std::string &GetTitle() const { return m_title; } + const std::string &GetDetails() const { return m_details; } bool IsDebuggerSpecific() const { return m_debugger_specific; } private: - std::string m_message; + /// The title of this progress event. The value is expected to remain stable + /// for a given progress ID. + std::string m_title; + + /// Details associated with this progress event update. The value is expected + /// to change between progress events. + std::string m_details; + + /// Unique ID used to associate progress events. const uint64_t m_id; + uint64_t m_completed; const uint64_t m_total; const bool m_debugger_specific; diff --git a/lldb/include/lldb/Core/Progress.h b/lldb/include/lldb/Core/Progress.h index f625d014f2684..3cce73564c489 100644 --- a/lldb/include/lldb/Core/Progress.h +++ b/lldb/include/lldb/Core/Progress.h @@ -86,10 +86,12 @@ class Progress { /// anything nor send any progress updates. /// /// @param [in] amount The amount to increment m_completed by. - void Increment(uint64_t amount = 1); + /// + /// @param [in] an optional message associated with this update. + void Increment(uint64_t amount = 1, std::string update = {}); private: - void ReportProgress(); + void ReportProgress(std::string update = {}); static std::atomic g_id; /// The title of the progress activity. std::string m_title; diff --git a/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h b/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h index c40ccd1cdb439..d92d7fff2a00f 100644 --- a/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h +++ b/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h @@ -105,6 +105,8 @@ class DumpValueObjectOptions { DumpValueObjectOptions &SetHideRootType(bool hide_root_type = false); + DumpValueObjectOptions &SetHideRootName(bool hide_root_name); + DumpValueObjectOptions &SetHideName(bool hide_name = false); DumpValueObjectOptions &SetHideValue(bool hide_value = false); @@ -146,6 +148,7 @@ class DumpValueObjectOptions { bool m_show_location : 1; bool m_use_objc : 1; bool m_hide_root_type : 1; + bool m_hide_root_name : 1; bool m_hide_name : 1; bool m_hide_value : 1; bool m_run_validator : 1; diff --git a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h index 90e54021a71f7..a4946a20591a5 100644 --- a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h +++ b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h @@ -98,7 +98,7 @@ class ValueObjectPrinter { ValueObject *GetValueObjectForChildrenGeneration(); - void PrintChildrenPreamble(); + void PrintChildrenPreamble(bool value_printed, bool summary_printed); void PrintChildrenPostamble(bool print_dotdotdot); @@ -120,6 +120,8 @@ class ValueObjectPrinter { bool HasReachedMaximumDepth(); private: + bool ShouldShowName() const; + ValueObject *m_orig_valobj; ValueObject *m_valobj; Stream *m_stream; diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index 091a384af0f8e..9e03f51e75de2 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -636,6 +636,9 @@ class CommandInterpreter : public Broadcaster, bool IOHandlerInterrupt(IOHandler &io_handler) override; + Status PreprocessCommand(std::string &command); + Status PreprocessToken(std::string &token); + protected: friend class Debugger; @@ -670,8 +673,6 @@ class CommandInterpreter : public Broadcaster, void RestoreExecutionContext(); - Status PreprocessCommand(std::string &command); - void SourceInitFile(FileSpec file, CommandReturnObject &result); // Completely resolves aliases and abbreviations, returning a pointer to the diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h index fe2416aed783d..de9400e7af97c 100644 --- a/lldb/include/lldb/Symbol/Function.h +++ b/lldb/include/lldb/Symbol/Function.h @@ -442,7 +442,7 @@ class Function : public UserID, public SymbolContextScope { Function(CompileUnit *comp_unit, lldb::user_id_t func_uid, lldb::user_id_t func_type_uid, const Mangled &mangled, Type *func_type, const AddressRange &range, - bool can_throw = false); + bool can_throw = false, bool generic_trampoline = false); /// Destructor. ~Function() override; @@ -554,6 +554,10 @@ class Function : public UserID, public SymbolContextScope { /// A type object pointer. Type *GetType(); + bool IsGenericTrampoline() const { + return m_is_generic_trampoline; + } + /// Get const accessor for the type that describes the function return value /// type, and parameter types. /// @@ -659,6 +663,8 @@ class Function : public UserID, public SymbolContextScope { /// information. Mangled m_mangled; + bool m_is_generic_trampoline; + /// All lexical blocks contained in this function. Block m_block; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 8936402da644f..5e1c6874eec6f 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -289,6 +289,12 @@ class TargetProperties : public Properties { bool GetDebugUtilityExpression() const; + /// Trampoline support includes stepping through trampolines directly to their + /// targets, stepping out of trampolines directly to their callers, and + /// automatically filtering out trampolines as possible breakpoint locations + /// when set by name. + bool GetEnableTrampolineSupport() const; + private: // Callbacks for m_launch_info. void Arg0ValueChangedCallback(); diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index 94bc413d93ff8..73daf1ebcd541 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -904,6 +904,27 @@ class Thread : public std::enable_shared_from_this, bool abort_other_plans, bool stop_other_threads, Status &status); + /// Gets the plan used to step through a function with a generic trampoline. A + /// generic trampoline is one without a function target, which the thread plan + /// will attempt to step through until it finds a place where it makes sense + /// to stop at. + /// \param[in] abort_other_plans + /// \b true if we discard the currently queued plans and replace them with + /// this one. + /// Otherwise this plan will go on the end of the plan stack. + /// + /// \param[in] stop_other_threads + /// \b true if we will stop other threads while we single step this one. + /// + /// \param[out] status + /// A status with an error if queuing failed. + /// + /// \return + /// A shared pointer to the newly queued thread plan, or nullptr if the + /// plan could not be queued. + virtual lldb::ThreadPlanSP QueueThreadPlanForStepThroughGenericTrampoline( + bool abort_other_plans, lldb::RunMode stop_other_threads, Status &status); + /// Gets the plan used to continue from the current PC. /// This is a simple plan, mostly useful as a backstop when you are continuing /// for some particular purpose. diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index 57fee942441b4..cd5d4a4ecc1f8 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -302,6 +302,7 @@ class ThreadPlan : public std::enable_shared_from_this, eKindStepInRange, eKindRunToAddress, eKindStepThrough, + eKindStepThroughGenericTrampoline, eKindStepUntil }; diff --git a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h index 8585ac62f09b3..d2bddcb573a2e 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepOverRange.h +++ b/lldb/include/lldb/Target/ThreadPlanStepOverRange.h @@ -30,7 +30,6 @@ class ThreadPlanStepOverRange : public ThreadPlanStepRange, bool ShouldStop(Event *event_ptr) override; protected: - bool DoPlanExplainsStop(Event *event_ptr) override; bool DoWillResume(lldb::StateType resume_state, bool current_plan) override; void SetFlagsToDefault() override { diff --git a/lldb/include/lldb/Target/ThreadPlanStepRange.h b/lldb/include/lldb/Target/ThreadPlanStepRange.h index 2fe8852771000..606135022dfc2 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepRange.h +++ b/lldb/include/lldb/Target/ThreadPlanStepRange.h @@ -41,6 +41,7 @@ class ThreadPlanStepRange : public ThreadPlan { void AddRange(const AddressRange &new_range); protected: + bool DoPlanExplainsStop(Event *event_ptr) override; bool InRange(); lldb::FrameComparison CompareCurrentFrameToStartFrame(); bool InSymbol(); diff --git a/lldb/include/lldb/Target/ThreadPlanStepThroughGenericTrampoline.h b/lldb/include/lldb/Target/ThreadPlanStepThroughGenericTrampoline.h new file mode 100644 index 0000000000000..03ebb83918858 --- /dev/null +++ b/lldb/include/lldb/Target/ThreadPlanStepThroughGenericTrampoline.h @@ -0,0 +1,52 @@ +//===-- ThreadPlanStepInRange.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TARGET_THREADPLANSTEPTHROUGHGENERICTRAMPOLINE_H +#define LLDB_TARGET_THREADPLANSTEPTHROUGHGENERICTRAMPOLINE_H + +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlanShouldStopHere.h" +#include "lldb/Target/ThreadPlanStepRange.h" + +namespace lldb_private { + +class ThreadPlanStepThroughGenericTrampoline : public ThreadPlanStepRange, + public ThreadPlanShouldStopHere { +public: + ThreadPlanStepThroughGenericTrampoline(Thread &thread, + lldb::RunMode stop_others); + + ~ThreadPlanStepThroughGenericTrampoline() override; + + void GetDescription(Stream *s, lldb::DescriptionLevel level) override; + + bool ShouldStop(Event *event_ptr) override; + bool ValidatePlan(Stream *error) override; + +protected: + void SetFlagsToDefault() override { + GetFlags().Set( + ThreadPlanStepThroughGenericTrampoline::s_default_flag_values); + } + +private: + // Need an appropriate marker for the current stack so we can tell step out + // from step in. + + static uint32_t + s_default_flag_values; // These are the default flag values + // for the ThreadPlanStepThroughGenericTrampoline. + ThreadPlanStepThroughGenericTrampoline( + const ThreadPlanStepThroughGenericTrampoline &) = delete; + const ThreadPlanStepThroughGenericTrampoline & + operator=(const ThreadPlanStepThroughGenericTrampoline &) = delete; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_THREADPLANSTEPTHROUGHGENERICTRAMPOLINE_H diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 92bd52083296e..bf9cc1073959c 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -553,7 +553,6 @@ def setUpClass(cls): if traceAlways: print("Change dir to:", full_dir, file=sys.stderr) os.chdir(full_dir) - lldb.SBReproducer.SetWorkingDirectory(full_dir) # Set platform context. cls.platformContext = lldbplatformutil.createPlatformContext() diff --git a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules index afcfc7417bd52..ac6c26285299b 100644 --- a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules +++ b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules @@ -183,7 +183,7 @@ ARCHFLAG ?= -arch #---------------------------------------------------------------------- ifeq "$(OS)" "Darwin" DS := $(DSYMUTIL) - DSFLAGS = + DSFLAGS := $(DSFLAGS_EXTRAS) DSYM = $(EXE).dSYM AR := $(CROSS_COMPILE)libtool ARFLAGS := -static -o diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index cc186862f24ad..a7080e081432d 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -156,6 +156,7 @@ const char *SBDebugger::GetProgressFromEvent(const lldb::SBEvent &event, uint64_t &total, bool &is_debugger_specific) { LLDB_INSTRUMENT_VA(event); + const ProgressEventData *progress_data = ProgressEventData::GetEventDataFromEvent(event.get()); if (progress_data == nullptr) @@ -164,7 +165,23 @@ const char *SBDebugger::GetProgressFromEvent(const lldb::SBEvent &event, completed = progress_data->GetCompleted(); total = progress_data->GetTotal(); is_debugger_specific = progress_data->IsDebuggerSpecific(); - return progress_data->GetMessage().c_str(); + ConstString message(progress_data->GetMessage()); + return message.AsCString(); +} + +lldb::SBStructuredData +SBDebugger::GetProgressDataFromEvent(const lldb::SBEvent &event) { + LLDB_INSTRUMENT_VA(event); + + StructuredData::DictionarySP dictionary_sp = + ProgressEventData::GetAsStructuredData(event.get()); + + if (!dictionary_sp) + return {}; + + SBStructuredData data; + data.m_impl_up->SetObjectSP(std::move(dictionary_sp)); + return data; } lldb::SBStructuredData diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp index e9d8ee874a2d4..9955e7a0cf0ee 100644 --- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp +++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp @@ -63,16 +63,22 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command, OptionsWithRaw args{command}; StringRef expr = args.GetRawPart(); + if (expr.empty()) { + result.AppendErrorWithFormatv("'{0}' takes a variable or expression", + m_cmd_name); + return false; + } + if (args.HasArgs()) { if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, m_exe_ctx)) return false; - } else if (command.empty()) { - result.AppendErrorWithFormatv("'{0}' takes a variable or expression", - m_cmd_name); - return false; } + // If the user has not specified, default to disabling persistent results. + if (m_expr_options.suppress_persistent_result == eLazyBoolCalculate) + m_expr_options.suppress_persistent_result = eLazyBoolYes; + auto verbosity = GetDebugger().GetDWIMPrintVerbosity(); Target *target_ptr = m_exe_ctx.GetTargetPtr(); @@ -84,7 +90,7 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command, DumpValueObjectOptions dump_options = m_varobj_options.GetAsDumpOptions( m_expr_options.m_verbosity, m_format_options.GetFormat()); - dump_options.SetHideName(eval_options.GetSuppressPersistentResult()); + dump_options.SetHideRootName(eval_options.GetSuppressPersistentResult()); StackFrame *frame = m_exe_ctx.GetFramePtr(); diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index b49ca3ce8a419..19a7a7319c79e 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -150,7 +150,7 @@ Status CommandObjectExpression::CommandOptions::SetOptionValue( bool persist_result = OptionArgParser::ToBoolean(option_arg, true, &success); if (success) - suppress_persistent_result = !persist_result; + suppress_persistent_result = !persist_result ? eLazyBoolYes : eLazyBoolNo; else error.SetErrorStringWithFormat( "could not convert \"%s\" to a boolean value.", @@ -197,7 +197,7 @@ void CommandObjectExpression::CommandOptions::OptionParsingStarting( auto_apply_fixits = eLazyBoolCalculate; top_level = false; allow_jit = true; - suppress_persistent_result = false; + suppress_persistent_result = eLazyBoolCalculate; // BEGIN SWIFT bind_generic_types = eBindAuto; // END SWIFT @@ -215,8 +215,9 @@ CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions( options.SetCoerceToId(display_opts.use_objc); // Explicitly disabling persistent results takes precedence over the // m_verbosity/use_objc logic. - if (suppress_persistent_result) - options.SetSuppressPersistentResult(true); + if (suppress_persistent_result != eLazyBoolCalculate) + options.SetSuppressPersistentResult(suppress_persistent_result == + eLazyBoolYes); else if (m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact) options.SetSuppressPersistentResult(display_opts.use_objc); options.SetUnwindOnError(unwind_on_error); @@ -482,7 +483,7 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( m_command_options.m_verbosity, format)); - options.SetHideName(eval_options.GetSuppressPersistentResult()); + options.SetHideRootName(eval_options.GetSuppressPersistentResult()); options.SetVariableFormatDisplayLanguage( result_valobj_sp->GetPreferredDisplayLanguage()); diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index a685f4a8108dd..e30b94db1012b 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -53,7 +53,7 @@ class CommandObjectExpression : public CommandObjectRaw, lldb::LanguageType language; LanguageRuntimeDescriptionDisplayVerbosity m_verbosity; LazyBool auto_apply_fixits; - bool suppress_persistent_result; + LazyBool suppress_persistent_result; // BEGIN SWIFT lldb::BindGenericTypes bind_generic_types; // END SWIFT diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 6def870d9c75f..e8be96171515d 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1347,7 +1347,7 @@ void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback, } static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id, - const std::string &message, + std::string title, std::string details, uint64_t completed, uint64_t total, bool is_debugger_specific) { // Only deliver progress events if we have any progress listeners. @@ -1355,13 +1355,15 @@ static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id, if (!debugger.GetBroadcaster().EventTypeHasListeners(event_type)) return; EventSP event_sp(new Event( - event_type, new ProgressEventData(progress_id, message, completed, total, - is_debugger_specific))); + event_type, + new ProgressEventData(progress_id, std::move(title), std::move(details), + completed, total, is_debugger_specific))); debugger.GetBroadcaster().BroadcastEvent(event_sp); } -void Debugger::ReportProgress(uint64_t progress_id, const std::string &message, - uint64_t completed, uint64_t total, +void Debugger::ReportProgress(uint64_t progress_id, std::string title, + std::string details, uint64_t completed, + uint64_t total, llvm::Optional debugger_id) { // Check if this progress is for a specific debugger. if (debugger_id) { @@ -1369,8 +1371,9 @@ void Debugger::ReportProgress(uint64_t progress_id, const std::string &message, // still exists. DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id); if (debugger_sp) - PrivateReportProgress(*debugger_sp, progress_id, message, completed, - total, /*is_debugger_specific*/ true); + PrivateReportProgress(*debugger_sp, progress_id, std::move(title), + std::move(details), completed, total, + /*is_debugger_specific*/ true); return; } // The progress event is not debugger specific, iterate over all debuggers @@ -1379,8 +1382,8 @@ void Debugger::ReportProgress(uint64_t progress_id, const std::string &message, std::lock_guard guard(*g_debugger_list_mutex_ptr); DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) - PrivateReportProgress(*(*pos), progress_id, message, completed, total, - /*is_debugger_specific*/ false); + PrivateReportProgress(*(*pos), progress_id, title, details, completed, + total, /*is_debugger_specific*/ false); } } diff --git a/lldb/source/Core/DebuggerEvents.cpp b/lldb/source/Core/DebuggerEvents.cpp index 0cc9ee9ad96f5..3af2e31b83851 100644 --- a/lldb/source/Core/DebuggerEvents.cpp +++ b/lldb/source/Core/DebuggerEvents.cpp @@ -33,7 +33,9 @@ ConstString ProgressEventData::GetFlavor() const { } void ProgressEventData::Dump(Stream *s) const { - s->Printf(" id = %" PRIu64 ", message = \"%s\"", m_id, m_message.c_str()); + s->Printf(" id = %" PRIu64 ", title = \"%s\"", m_id, m_title.c_str()); + if (!m_details.empty()) + s->Printf(", details = \"%s\"", m_details.c_str()); if (m_completed == 0 || m_completed == m_total) s->Printf(", type = %s", m_completed == 0 ? "start" : "end"); else @@ -49,6 +51,27 @@ ProgressEventData::GetEventDataFromEvent(const Event *event_ptr) { return GetEventDataFromEventImpl(event_ptr); } +StructuredData::DictionarySP +ProgressEventData::GetAsStructuredData(const Event *event_ptr) { + const ProgressEventData *progress_data = + ProgressEventData::GetEventDataFromEvent(event_ptr); + + if (!progress_data) + return {}; + + auto dictionary_sp = std::make_shared(); + dictionary_sp->AddStringItem("title", progress_data->GetTitle()); + dictionary_sp->AddStringItem("details", progress_data->GetDetails()); + dictionary_sp->AddStringItem("message", progress_data->GetMessage()); + dictionary_sp->AddIntegerItem("progress_id", progress_data->GetID()); + dictionary_sp->AddIntegerItem("completed", progress_data->GetCompleted()); + dictionary_sp->AddIntegerItem("total", progress_data->GetTotal()); + dictionary_sp->AddBooleanItem("debugger_specific", + progress_data->IsDebuggerSpecific()); + + return dictionary_sp; +} + llvm::StringRef DiagnosticEventData::GetPrefix() const { switch (m_type) { case Type::Warning: diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 2582d7bcd66fa..e885a1798265e 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -799,7 +799,12 @@ void Module::LookupInfo::Prune(SymbolContextList &sc_list, if (!sc_list.GetContextAtIndex(i, sc)) break; + bool is_trampoline = + Target::GetGlobalProperties().GetEnableTrampolineSupport() && + sc.function && sc.function->IsGenericTrampoline(); + bool keep_it = + !is_trampoline && NameMatchesLookupInfo(sc.GetFunctionName(), sc.GetLanguage()); if (keep_it) ++i; diff --git a/lldb/source/Core/Progress.cpp b/lldb/source/Core/Progress.cpp index c54e7774adf3a..08be73f1470f3 100644 --- a/lldb/source/Core/Progress.cpp +++ b/lldb/source/Core/Progress.cpp @@ -36,7 +36,7 @@ Progress::~Progress() { } } -void Progress::Increment(uint64_t amount) { +void Progress::Increment(uint64_t amount, std::string update) { if (amount > 0) { std::lock_guard guard(m_mutex); // Watch out for unsigned overflow and make sure we don't increment too @@ -45,16 +45,16 @@ void Progress::Increment(uint64_t amount) { m_completed = m_total; else m_completed += amount; - ReportProgress(); + ReportProgress(update); } } -void Progress::ReportProgress() { +void Progress::ReportProgress(std::string update) { if (!m_complete) { // Make sure we only send one notification that indicates the progress is // complete. m_complete = m_completed == m_total; - Debugger::ReportProgress(m_id, m_title, m_completed, m_total, - m_debugger_id); + Debugger::ReportProgress(m_id, m_title, std::move(update), m_completed, + m_total, m_debugger_id); } } diff --git a/lldb/source/DataFormatters/DumpValueObjectOptions.cpp b/lldb/source/DataFormatters/DumpValueObjectOptions.cpp index 38de4428bb235..3fbff86a14172 100644 --- a/lldb/source/DataFormatters/DumpValueObjectOptions.cpp +++ b/lldb/source/DataFormatters/DumpValueObjectOptions.cpp @@ -19,10 +19,10 @@ DumpValueObjectOptions::DumpValueObjectOptions() m_decl_printing_helper(), m_pointer_as_array(), m_use_synthetic(true), m_scope_already_checked(false), m_flat_output(false), m_ignore_cap(false), m_show_types(false), m_show_location(false), m_use_objc(false), - m_hide_root_type(false), m_hide_name(false), m_hide_value(false), - m_run_validator(false), m_use_type_display_name(true), - m_allow_oneliner_mode(true), m_hide_pointer_value(false), - m_reveal_empty_aggregates(true) {} + m_hide_root_type(false), m_hide_root_name(false), m_hide_name(false), + m_hide_value(false), m_run_validator(false), + m_use_type_display_name(true), m_allow_oneliner_mode(true), + m_hide_pointer_value(false), m_reveal_empty_aggregates(true) {} DumpValueObjectOptions::DumpValueObjectOptions(ValueObject &valobj) : DumpValueObjectOptions() { @@ -143,6 +143,12 @@ DumpValueObjectOptions::SetHideRootType(bool hide_root_type) { return *this; } +DumpValueObjectOptions & +DumpValueObjectOptions::SetHideRootName(bool hide_root_name) { + m_hide_root_name = hide_root_name; + return *this; +} + DumpValueObjectOptions &DumpValueObjectOptions::SetHideName(bool hide_name) { m_hide_name = hide_name; return *this; diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp index 5f0336ebd890e..39213c6878935 100644 --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -275,7 +275,7 @@ void ValueObjectPrinter::PrintDecl() { StreamString varName; - if (!m_options.m_hide_name) { + if (ShouldShowName()) { if (m_options.m_flat_output) m_valobj->GetExpressionPath(varName); else @@ -314,7 +314,7 @@ void ValueObjectPrinter::PrintDecl() { m_stream->Printf("(%s) ", typeName.GetData()); if (!varName.Empty()) m_stream->Printf("%s =", varName.GetData()); - else if (!m_options.m_hide_name) + else if (ShouldShowName()) m_stream->Printf(" ="); } } @@ -437,7 +437,7 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, if (m_options.m_hide_pointer_value && IsPointerValue(m_valobj->GetCompilerType())) { } else { - if (!m_options.m_hide_name) + if (ShouldShowName()) m_stream->PutChar(' '); m_stream->PutCString(m_value); value_printed = true; @@ -445,7 +445,9 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, } if (m_summary.size()) { - m_stream->Printf(" %s", m_summary.c_str()); + if (ShouldShowName() || value_printed) + m_stream->PutChar(' '); + m_stream->PutCString(m_summary); summary_printed = true; } } @@ -459,7 +461,7 @@ bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed, // let's avoid the overly verbose no description error for a nil thing if (m_options.m_use_objc && !IsNil() && !IsUninitialized() && (!m_options.m_pointer_as_array)) { - if (!m_options.m_hide_value || !m_options.m_hide_name) + if (!m_options.m_hide_value || ShouldShowName()) m_stream->Printf(" "); const char *object_desc = nullptr; if (value_printed || summary_printed) @@ -582,13 +584,20 @@ ValueObject *ValueObjectPrinter::GetValueObjectForChildrenGeneration() { return m_valobj; } -void ValueObjectPrinter::PrintChildrenPreamble() { +void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed, + bool summary_printed) { if (m_options.m_flat_output) { if (ShouldPrintValueObject()) m_stream->EOL(); } else { - if (ShouldPrintValueObject()) - m_stream->PutCString(IsRef() ? ": {\n" : " {\n"); + if (ShouldPrintValueObject()) { + if (IsRef()) { + m_stream->PutCString(": "); + } else if (value_printed || summary_printed || ShouldShowName()) { + m_stream->PutChar(' '); + } + m_stream->PutCString("{\n"); + } m_stream->IndentMore(); } } @@ -710,7 +719,7 @@ void ValueObjectPrinter::PrintChildren( for (size_t idx = 0; idx < num_children; ++idx) { if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) { if (!any_children_printed) { - PrintChildrenPreamble(); + PrintChildrenPreamble(value_printed, summary_printed); any_children_printed = true; } PrintChild(child_sp, curr_ptr_depth); @@ -841,3 +850,9 @@ void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, bool ValueObjectPrinter::HasReachedMaximumDepth() { return m_curr_depth >= m_options.m_max_depth; } + +bool ValueObjectPrinter::ShouldShowName() const { + if (m_curr_depth == 0) + return !m_options.m_hide_root_name && !m_options.m_hide_name; + return !m_options.m_hide_name; +} diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 8c5b359417510..3382fc6b31d3f 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -1761,112 +1761,124 @@ Status CommandInterpreter::PreprocessCommand(std::string &command) { std::string expr_str(command, expr_content_start, end_backtick - expr_content_start); + error = PreprocessToken(expr_str); + // We always stop at the first error: + if (error.Fail()) + break; - ExecutionContext exe_ctx(GetExecutionContext()); + command.erase(start_backtick, end_backtick - start_backtick + 1); + command.insert(start_backtick, std::string(expr_str)); + pos = start_backtick + expr_str.size(); + } + return error; +} - // Get a dummy target to allow for calculator mode while processing - // backticks. This also helps break the infinite loop caused when target is - // null. - Target *exe_target = exe_ctx.GetTargetPtr(); - Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget(); - - ValueObjectSP expr_result_valobj_sp; - - EvaluateExpressionOptions options; - options.SetCoerceToId(false); - options.SetUnwindOnError(true); - options.SetIgnoreBreakpoints(true); - options.SetKeepInMemory(false); - options.SetTryAllThreads(true); - options.SetTimeout(llvm::None); - - ExpressionResults expr_result = - target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(), - expr_result_valobj_sp, options); - - if (expr_result == eExpressionCompleted) { - Scalar scalar; - if (expr_result_valobj_sp) - expr_result_valobj_sp = - expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable( - expr_result_valobj_sp->GetDynamicValueType(), true); - if (expr_result_valobj_sp->ResolveValue(scalar)) { - command.erase(start_backtick, end_backtick - start_backtick + 1); - StreamString value_strm; - const bool show_type = false; - scalar.GetValue(&value_strm, show_type); - size_t value_string_size = value_strm.GetSize(); - if (value_string_size) { - command.insert(start_backtick, std::string(value_strm.GetString())); - pos = start_backtick + value_string_size; - continue; - } else { - error.SetErrorStringWithFormat("expression value didn't result " - "in a scalar value for the " - "expression '%s'", - expr_str.c_str()); - break; - } - } else { - error.SetErrorStringWithFormat("expression value didn't result " - "in a scalar value for the " - "expression '%s'", - expr_str.c_str()); - break; - } +Status +CommandInterpreter::PreprocessToken(std::string &expr_str) { + Status error; + ExecutionContext exe_ctx(GetExecutionContext()); - continue; - } + // Get a dummy target to allow for calculator mode while processing + // backticks. This also helps break the infinite loop caused when target is + // null. + Target *exe_target = exe_ctx.GetTargetPtr(); + Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget(); - if (expr_result_valobj_sp) - error = expr_result_valobj_sp->GetError(); + ValueObjectSP expr_result_valobj_sp; - if (error.Success()) { - switch (expr_result) { - case eExpressionSetupError: - error.SetErrorStringWithFormat( - "expression setup error for the expression '%s'", expr_str.c_str()); - break; - case eExpressionParseError: - error.SetErrorStringWithFormat( - "expression parse error for the expression '%s'", expr_str.c_str()); - break; - case eExpressionResultUnavailable: - error.SetErrorStringWithFormat( - "expression error fetching result for the expression '%s'", - expr_str.c_str()); - break; - case eExpressionCompleted: - break; - case eExpressionDiscarded: - error.SetErrorStringWithFormat( - "expression discarded for the expression '%s'", expr_str.c_str()); - break; - case eExpressionInterrupted: - error.SetErrorStringWithFormat( - "expression interrupted for the expression '%s'", expr_str.c_str()); - break; - case eExpressionHitBreakpoint: - error.SetErrorStringWithFormat( - "expression hit breakpoint for the expression '%s'", - expr_str.c_str()); - break; - case eExpressionTimedOut: - error.SetErrorStringWithFormat( - "expression timed out for the expression '%s'", expr_str.c_str()); - break; - case eExpressionStoppedForDebug: - error.SetErrorStringWithFormat("expression stop at entry point " - "for debugging for the " + EvaluateExpressionOptions options; + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetKeepInMemory(false); + options.SetTryAllThreads(true); + options.SetTimeout(std::nullopt); + + ExpressionResults expr_result = + target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(), + expr_result_valobj_sp, options); + + if (expr_result == eExpressionCompleted) { + Scalar scalar; + if (expr_result_valobj_sp) + expr_result_valobj_sp = + expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable( + expr_result_valobj_sp->GetDynamicValueType(), true); + if (expr_result_valobj_sp->ResolveValue(scalar)) { + + StreamString value_strm; + const bool show_type = false; + scalar.GetValue(&value_strm, show_type); + size_t value_string_size = value_strm.GetSize(); + if (value_string_size) { + expr_str = value_strm.GetData(); + } else { + error.SetErrorStringWithFormat("expression value didn't result " + "in a scalar value for the " "expression '%s'", expr_str.c_str()); - break; - case eExpressionThreadVanished: - error.SetErrorStringWithFormat( - "expression thread vanished for the expression '%s'", - expr_str.c_str()); - break; } + } else { + error.SetErrorStringWithFormat("expression value didn't result " + "in a scalar value for the " + "expression '%s'", + expr_str.c_str()); + } + return error; + } + + // If we have an error from the expression evaluation it will be in the + // ValueObject error, which won't be success and we will just report it. + // But if for some reason we didn't get a value object at all, then we will + // make up some helpful errors from the expression result. + if (expr_result_valobj_sp) + error = expr_result_valobj_sp->GetError(); + + if (error.Success()) { + switch (expr_result) { + case eExpressionSetupError: + error.SetErrorStringWithFormat( + "expression setup error for the expression '%s'", expr_str.c_str()); + break; + case eExpressionParseError: + error.SetErrorStringWithFormat( + "expression parse error for the expression '%s'", expr_str.c_str()); + break; + case eExpressionResultUnavailable: + error.SetErrorStringWithFormat( + "expression error fetching result for the expression '%s'", + expr_str.c_str()); + break; + case eExpressionCompleted: + break; + case eExpressionDiscarded: + error.SetErrorStringWithFormat( + "expression discarded for the expression '%s'", expr_str.c_str()); + break; + case eExpressionInterrupted: + error.SetErrorStringWithFormat( + "expression interrupted for the expression '%s'", expr_str.c_str()); + break; + case eExpressionHitBreakpoint: + error.SetErrorStringWithFormat( + "expression hit breakpoint for the expression '%s'", + expr_str.c_str()); + break; + case eExpressionTimedOut: + error.SetErrorStringWithFormat( + "expression timed out for the expression '%s'", expr_str.c_str()); + break; + case eExpressionStoppedForDebug: + error.SetErrorStringWithFormat("expression stop at entry point " + "for debugging for the " + "expression '%s'", + expr_str.c_str()); + break; + case eExpressionThreadVanished: + error.SetErrorStringWithFormat( + "expression thread vanished for the expression '%s'", + expr_str.c_str()); + break; } } return error; diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index 4500378c62298..c13ce4ece4297 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -727,10 +727,14 @@ bool CommandObjectParsed::Execute(const char *args_string, } if (!handled) { for (auto entry : llvm::enumerate(cmd_args.entries())) { - if (!entry.value().ref().empty() && entry.value().GetQuoteChar() == '`') { - cmd_args.ReplaceArgumentAtIndex( - entry.index(), - m_interpreter.ProcessEmbeddedScriptCommands(entry.value().c_str())); + const Args::ArgEntry &value = entry.value(); + if (!value.ref().empty() && value.GetQuoteChar() == '`') { + // We have to put the backtick back in place for PreprocessCommand. + std::string opt_string = value.c_str(); + Status error; + error = m_interpreter.PreprocessToken(opt_string); + if (error.Success()) + cmd_args.ReplaceArgumentAtIndex(entry.index(), opt_string); } } diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 22198bfb1f4af..e09861e217dca 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -1069,6 +1069,7 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { if (m_kernel.IsLoaded() && m_kernel.GetModule()) { static ConstString kext_summary_symbol("gLoadedKextSummaries"); + static ConstString arm64_T1Sz_value("gT1Sz"); const Symbol *symbol = m_kernel.GetModule()->FindFirstSymbolWithNameAndType( kext_summary_symbol, eSymbolTypeData); @@ -1077,6 +1078,36 @@ void DynamicLoaderDarwinKernel::LoadKernelModuleIfNeeded() { // Update all image infos ReadAllKextSummaries(); } + // If the kernel global with the T1Sz setting is available, + // update the target.process.virtual-addressable-bits to be correct. + symbol = m_kernel.GetModule()->FindFirstSymbolWithNameAndType( + arm64_T1Sz_value, eSymbolTypeData); + if (symbol) { + const uint32_t orig_bits_value = m_process->GetVirtualAddressableBits(); + // Mark all bits as addressable so we don't strip any from our + // memory read below, with an incorrect default value. + // b55 is the sign extension bit with PAC, b56:63 are TBI, + // don't mark those as addressable. + m_process->SetVirtualAddressableBits(55); + Status error; + // gT1Sz is 8 bytes. We may run on a stripped kernel binary + // where we can't get the size accurately. Hardcode it. + const size_t sym_bytesize = 8; // size of gT1Sz value + uint64_t sym_value = + m_process->GetTarget().ReadUnsignedIntegerFromMemory( + symbol->GetAddress(), sym_bytesize, 0, error); + if (error.Success()) { + // 64 - T1Sz is the highest bit used for auth. + // The value we pass in to SetVirtualAddressableBits is + // the number of bits used for addressing, so if + // T1Sz is 25, then 64-25 == 39, bits 0..38 are used for + // addressing, bits 39..63 are used for PAC/TBI or whatever. + uint32_t virt_addr_bits = 64 - sym_value; + m_process->SetVirtualAddressableBits(virt_addr_bits); + } else { + m_process->SetVirtualAddressableBits(orig_bits_value); + } + } } else { m_kernel.Clear(); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index ec4e9f12fc974..d5317a4408c53 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticFrontend.h" +#include "clang/Basic/DiagnosticSerialization.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" @@ -15,7 +18,9 @@ #include "clang/Parse/Parser.h" #include "clang/Sema/Lookup.h" #include "clang/Serialization/ASTReader.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/Threading.h" @@ -25,6 +30,7 @@ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ModuleList.h" +#include "lldb/Core/Progress.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/CompileUnit.h" @@ -61,6 +67,9 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer { void EndSourceFile() override; private: + bool HandleModuleRemark(const clang::Diagnostic &info); + void SetCurrentModuleProgress(std::string module_name); + typedef std::pair IDAndDiagnostic; std::vector m_diagnostics; @@ -72,6 +81,9 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer { /// Output string filled by m_os. Will be reused for different diagnostics. std::string m_output; Log *m_log; + /// A Progress with explicitly managed lifetime. + std::unique_ptr m_current_progress_up; + std::vector m_module_build_stack; }; /// The private implementation of our ClangModulesDeclVendor. Contains all the @@ -140,6 +152,9 @@ StoringDiagnosticConsumer::StoringDiagnosticConsumer() { void StoringDiagnosticConsumer::HandleDiagnostic( clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info) { + if (HandleModuleRemark(info)) + return; + // Print the diagnostic to m_output. m_output.clear(); m_diag_printer->HandleDiagnostic(DiagLevel, info); @@ -170,9 +185,54 @@ void StoringDiagnosticConsumer::BeginSourceFile( } void StoringDiagnosticConsumer::EndSourceFile() { + m_current_progress_up = nullptr; m_diag_printer->EndSourceFile(); } +bool StoringDiagnosticConsumer::HandleModuleRemark( + const clang::Diagnostic &info) { + Log *log = GetLog(LLDBLog::Expressions); + switch (info.getID()) { + case clang::diag::remark_module_build: { + const auto &module_name = info.getArgStdStr(0); + SetCurrentModuleProgress(module_name); + m_module_build_stack.push_back(module_name); + + const auto &module_path = info.getArgStdStr(1); + LLDB_LOG(log, "Building Clang module {0} as {1}", module_name, module_path); + return true; + } + case clang::diag::remark_module_build_done: { + // The current module is done. + m_module_build_stack.pop_back(); + if (m_module_build_stack.empty()) { + m_current_progress_up = nullptr; + } else { + // When the just completed module began building, a module that depends on + // it ("module A") was effectively paused. Update the progress to re-show + // "module A" as continuing to be built. + const auto &resumed_module_name = m_module_build_stack.back(); + SetCurrentModuleProgress(resumed_module_name); + } + + const auto &module_name = info.getArgStdStr(0); + LLDB_LOG(log, "Finished building Clang module {0}", module_name); + return true; + } + default: + return false; + } +} + +void StoringDiagnosticConsumer::SetCurrentModuleProgress( + std::string module_name) { + if (!m_current_progress_up) + m_current_progress_up = + std::make_unique("Building Clang modules"); + + m_current_progress_up->Increment(1, std::move(module_name)); +} + ClangModulesDeclVendor::ClangModulesDeclVendor() : ClangDeclVendor(eClangModuleDeclVendor) {} @@ -609,7 +669,8 @@ ClangModulesDeclVendor::Create(Target &target) { "-target", arch.GetTriple().str(), "-fmodules-validate-system-headers", - "-Werror=non-modular-include-in-framework-module"}; + "-Werror=non-modular-include-in-framework-module", + "-Rmodule-build"}; target.GetPlatform()->AddClangModuleCompilationOptions( &target, compiler_invocation_arguments); @@ -647,16 +708,18 @@ ClangModulesDeclVendor::Create(Target &target) { } } - llvm::IntrusiveRefCntPtr diagnostics_engine = - clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions, - new StoringDiagnosticConsumer); - std::vector compiler_invocation_argument_cstrs; compiler_invocation_argument_cstrs.reserve( compiler_invocation_arguments.size()); for (const std::string &arg : compiler_invocation_arguments) compiler_invocation_argument_cstrs.push_back(arg.c_str()); + auto diag_options_up = + clang::CreateAndPopulateDiagOpts(compiler_invocation_argument_cstrs); + llvm::IntrusiveRefCntPtr diagnostics_engine = + clang::CompilerInstance::createDiagnostics(diag_options_up.release(), + new StoringDiagnosticConsumer); + Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}", llvm::make_range(compiler_invocation_arguments.begin(), diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp index e0c0040e61796..5bf9644ea84b8 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp @@ -35,6 +35,7 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/OptionParsing.h" #include "lldb/Utility/Timer.h" @@ -924,7 +925,7 @@ void SwiftLanguageRuntimeImpl::ModulesDidLoad(const ModuleList &module_list) { std::string SwiftLanguageRuntimeImpl::GetObjectDescriptionExpr_Result(ValueObject &object) { - Log *log(GetLog(LLDBLog::DataFormatters)); + Log *log(GetLog(LLDBLog::DataFormatters | LLDBLog::Expressions)); std::string expr_string = llvm::formatv("Swift._DebuggerSupport.stringForPrintObject({0})", object.GetName().GetCString()).str(); @@ -936,7 +937,7 @@ SwiftLanguageRuntimeImpl::GetObjectDescriptionExpr_Result(ValueObject &object) { std::string SwiftLanguageRuntimeImpl::GetObjectDescriptionExpr_Ref(ValueObject &object) { - Log *log(GetLog(LLDBLog::DataFormatters)); + Log *log(GetLog(LLDBLog::DataFormatters | LLDBLog::Expressions)); StreamString expr_string; std::string expr_str @@ -960,7 +961,7 @@ std::string SwiftLanguageRuntimeImpl::GetObjectDescriptionExpr_Copy(ValueObject &object, lldb::addr_t ©_location) { - Log *log(GetLog(LLDBLog::DataFormatters)); + Log *log(GetLog(LLDBLog::DataFormatters | LLDBLog::Expressions)); ValueObjectSP static_sp(object.GetStaticValue()); @@ -1028,7 +1029,7 @@ SwiftLanguageRuntimeImpl::RunObjectDescriptionExpr(ValueObject &object, std::string &expr_string, Stream &result) { - Log *log(GetLog(LLDBLog::DataFormatters)); + Log *log(GetLog(LLDBLog::DataFormatters | LLDBLog::Expressions)); ValueObjectSP result_sp; EvaluateExpressionOptions eval_options; eval_options.SetLanguage(lldb::eLanguageTypeSwift); diff --git a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp index 78e0a4b2f499f..9af9c0120dd7d 100644 --- a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp +++ b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp @@ -57,7 +57,8 @@ ObjectContainer *ObjectContainerUniversalMachO::CreateInstance( bool ObjectContainerUniversalMachO::MagicBytesMatch(const DataExtractor &data) { lldb::offset_t offset = 0; uint32_t magic = data.GetU32(&offset); - return magic == FAT_MAGIC || magic == FAT_CIGAM; + return magic == FAT_MAGIC || magic == FAT_CIGAM || magic == FAT_MAGIC_64 || + magic == FAT_CIGAM_64; } ObjectContainerUniversalMachO::ObjectContainerUniversalMachO( @@ -82,38 +83,51 @@ bool ObjectContainerUniversalMachO::ParseHeader() { bool ObjectContainerUniversalMachO::ParseHeader( lldb_private::DataExtractor &data, llvm::MachO::fat_header &header, - std::vector &fat_archs) { - bool success = false; + std::vector &fat_archs) { // Store the file offset for this universal file as we could have a universal // .o file in a BSD archive, or be contained in another kind of object. - // Universal mach-o files always have their headers in big endian. lldb::offset_t offset = 0; data.SetByteOrder(eByteOrderBig); header.magic = data.GetU32(&offset); fat_archs.clear(); - if (header.magic == FAT_MAGIC) { - - data.SetAddressByteSize(4); + // Universal mach-o files always have their headers in big endian. + if (header.magic == FAT_MAGIC || header.magic == FAT_MAGIC_64) { + const bool is_fat64 = header.magic == FAT_MAGIC_64; + data.SetAddressByteSize(is_fat64 ? 8 : 4); header.nfat_arch = data.GetU32(&offset); // Now we should have enough data for all of the fat headers, so lets index // them so we know how many architectures that this universal binary // contains. - uint32_t arch_idx = 0; - for (arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx) { + for (uint32_t arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx) { if (data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch))) { - fat_arch arch; - if (data.GetU32(&offset, &arch, sizeof(fat_arch) / sizeof(uint32_t))) - fat_archs.push_back(arch); + if (is_fat64) { + fat_arch_64 arch; + arch.cputype = data.GetU32(&offset); + arch.cpusubtype = data.GetU32(&offset); + arch.offset = data.GetU64(&offset); + arch.size = data.GetU64(&offset); + arch.align = data.GetU32(&offset); + arch.reserved = data.GetU32(&offset); + fat_archs.emplace_back(arch); + } else { + fat_arch arch; + arch.cputype = data.GetU32(&offset); + arch.cpusubtype = data.GetU32(&offset); + arch.offset = data.GetU32(&offset); + arch.size = data.GetU32(&offset); + arch.align = data.GetU32(&offset); + fat_archs.emplace_back(arch); + } } } - success = true; - } else { - memset(&header, 0, sizeof(header)); + return true; } - return success; + + memset(&header, 0, sizeof(header)); + return true; } size_t ObjectContainerUniversalMachO::GetNumArchitectures() const { @@ -123,8 +137,8 @@ size_t ObjectContainerUniversalMachO::GetNumArchitectures() const { bool ObjectContainerUniversalMachO::GetArchitectureAtIndex( uint32_t idx, ArchSpec &arch) const { if (idx < m_header.nfat_arch) { - arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].cputype, - m_fat_archs[idx].cpusubtype); + arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].GetCPUType(), + m_fat_archs[idx].GetCPUSubType()); return true; } return false; @@ -166,8 +180,8 @@ ObjectContainerUniversalMachO::GetObjectFile(const FileSpec *file) { DataBufferSP data_sp; lldb::offset_t data_offset = 0; return ObjectFile::FindPlugin( - module_sp, file, m_offset + m_fat_archs[arch_idx].offset, - m_fat_archs[arch_idx].size, data_sp, data_offset); + module_sp, file, m_offset + m_fat_archs[arch_idx].GetOffset(), + m_fat_archs[arch_idx].GetSize(), data_sp, data_offset); } } return ObjectFileSP(); @@ -184,11 +198,12 @@ size_t ObjectContainerUniversalMachO::GetModuleSpecifications( if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) { llvm::MachO::fat_header header; - std::vector fat_archs; + std::vector fat_archs; if (ParseHeader(data, header, fat_archs)) { - for (const llvm::MachO::fat_arch &fat_arch : fat_archs) { - const lldb::offset_t slice_file_offset = fat_arch.offset + file_offset; - if (fat_arch.offset < file_size && file_size > slice_file_offset) { + for (const FatArch &fat_arch : fat_archs) { + const lldb::offset_t slice_file_offset = + fat_arch.GetOffset() + file_offset; + if (fat_arch.GetOffset() < file_size && file_size > slice_file_offset) { ObjectFile::GetModuleSpecifications( file, slice_file_offset, file_size - slice_file_offset, specs); } diff --git a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h index 4fbea936ac85c..20f1f051e07a0 100644 --- a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h +++ b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h @@ -63,11 +63,46 @@ class ObjectContainerUniversalMachO : public lldb_private::ObjectContainer { protected: llvm::MachO::fat_header m_header; - std::vector m_fat_archs; + + struct FatArch { + FatArch(llvm::MachO::fat_arch arch) : m_arch(arch), m_is_fat64(false) {} + FatArch(llvm::MachO::fat_arch_64 arch) : m_arch(arch), m_is_fat64(true) {} + + uint32_t GetCPUType() const { + return m_is_fat64 ? m_arch.fat_arch_64.cputype : m_arch.fat_arch.cputype; + } + + uint32_t GetCPUSubType() const { + return m_is_fat64 ? m_arch.fat_arch_64.cpusubtype + : m_arch.fat_arch.cpusubtype; + } + + uint64_t GetOffset() const { + return m_is_fat64 ? m_arch.fat_arch_64.offset : m_arch.fat_arch.offset; + } + + uint64_t GetSize() const { + return m_is_fat64 ? m_arch.fat_arch_64.size : m_arch.fat_arch.size; + } + + uint32_t GetAlign() const { + return m_is_fat64 ? m_arch.fat_arch_64.align : m_arch.fat_arch.align; + } + + private: + const union Arch { + Arch(llvm::MachO::fat_arch arch) : fat_arch(arch) {} + Arch(llvm::MachO::fat_arch_64 arch) : fat_arch_64(arch) {} + llvm::MachO::fat_arch fat_arch; + llvm::MachO::fat_arch_64 fat_arch_64; + } m_arch; + const bool m_is_fat64; + }; + std::vector m_fat_archs; static bool ParseHeader(lldb_private::DataExtractor &data, llvm::MachO::fat_header &header, - std::vector &fat_archs); + std::vector &fat_archs); }; #endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_UNIVERSAL_MACH_O_OBJECTCONTAINERUNIVERSALMACHO_H diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 5c9c69b77443b..81d846ba2a25f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2395,12 +2395,16 @@ DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, assert(func_type == nullptr || func_type != DIE_IS_BEING_PARSED); + bool is_generic_trampoline = die.IsGenericTrampoline(); + const user_id_t func_user_id = die.GetID(); func_sp = std::make_shared(&comp_unit, func_user_id, // UserID is the DIE offset func_user_id, func_name, func_type, - func_range); // first address range + func_range, // first address range + false, // canThrow + is_generic_trampoline); if (func_sp.get() != nullptr) { if (frame_base.IsValid()) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp index e2b1375863c5a..bf93346aad510 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp @@ -274,9 +274,11 @@ Function *DWARFASTParserSwift::ParseFunctionFromDWARF( decl_column)); const user_id_t func_user_id = die.GetID(); + bool is_generic_trampoline = die.IsGenericTrampoline(); func_sp.reset(new Function(&comp_unit, func_user_id, func_user_id, - func_name, nullptr, func_range, - can_throw)); // first address range + func_name, nullptr, + func_range, // first address range + can_throw, is_generic_trampoline)); if (func_sp.get() != NULL) { if (frame_base.IsValid()) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index e8492079af88a..2b8032eae8032 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -203,6 +203,13 @@ const char *DWARFDIE::GetMangledName() const { return nullptr; } +bool DWARFDIE::IsGenericTrampoline() const { + if (IsValid()) + return m_die->GetIsGenericTrampoline(m_cu); + else + return false; +} + const char *DWARFDIE::GetPubname() const { if (IsValid()) return m_die->GetPubname(m_cu); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 7ce9550a081e9..db353071546f4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -28,6 +28,8 @@ class DWARFDIE : public DWARFBaseDIE { // Accessing information about a DIE const char *GetMangledName() const; + bool IsGenericTrampoline() const; + const char *GetPubname() const; const char *GetQualifiedName(std::string &storage) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 5a584e15c397d..769ca30e458ea 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -679,6 +679,12 @@ DWARFDebugInfoEntry::GetMangledName(const DWARFUnit *cu, return name; } +bool +DWARFDebugInfoEntry::GetIsGenericTrampoline(const DWARFUnit *cu) const { + DWARFFormValue form_value; + return GetAttributeValue(cu, DW_AT_trampoline, form_value, nullptr, true) != 0; +} + // GetPubname // // Get value the name for a DIE as it should appear for a .debug_pubnames or diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 63d6aa79240b3..3fc9a90d7a129 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -97,6 +97,8 @@ class DWARFDebugInfoEntry { const char *GetMangledName(const DWARFUnit *cu, bool substitute_name_allowed = true) const; + bool GetIsGenericTrampoline(const DWARFUnit *cu) const; + const char *GetPubname(const DWARFUnit *cu) const; const char *GetQualifiedName(DWARFUnit *cu, std::string &storage) const; diff --git a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp index 2cec760726388..4862848250398 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp @@ -8340,6 +8340,8 @@ bool SwiftASTContext::GetCompileUnitImportsImpl( return true; auto cu_imports = compile_unit->GetImportedModules(); + if (cu_imports.size() == 0) + return true; Progress progress( llvm::formatv("Getting Swift compile unit imports for '{0}'", diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp index b60e6634fc430..5223f0d122f0b 100644 --- a/lldb/source/Symbol/Function.cpp +++ b/lldb/source/Symbol/Function.cpp @@ -233,10 +233,11 @@ Function *IndirectCallEdge::GetCallee(ModuleList &images, // Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid, lldb::user_id_t type_uid, const Mangled &mangled, Type *type, - const AddressRange &range, bool canThrow) + const AddressRange &range, bool canThrow, bool is_generic_trampoline) : UserID(func_uid), m_comp_unit(comp_unit), m_type_uid(type_uid), - m_type(type), m_mangled(mangled), m_block(func_uid), m_range(range), - m_frame_base(), m_flags(), m_prologue_byte_size(0) { + m_type(type), m_mangled(mangled), + m_is_generic_trampoline(is_generic_trampoline), m_block(func_uid), + m_range(range), m_frame_base(), m_flags(), m_prologue_byte_size(0) { m_block.SetParentScope(this); if (canThrow) m_flags.Set(flagsFunctionCanThrow); diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index 8129cf7c421d7..b921118b2e4f3 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -65,6 +65,7 @@ add_lldb_library(lldbTarget ThreadPlanStepOverRange.cpp ThreadPlanStepRange.cpp ThreadPlanStepThrough.cpp + ThreadPlanStepThroughGenericTrampoline.cpp ThreadPlanStepUntil.cpp ThreadPlanTracer.cpp ThreadPlanStack.cpp diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 1c0af2b29d52d..87dccb2f6d409 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -256,7 +256,7 @@ class StopInfoBreakpoint : public StopInfo { if (!m_should_perform_action) return; m_should_perform_action = false; - bool internal_breakpoint = true; + bool all_stopping_locs_internal = true; ThreadSP thread_sp(m_thread_wp.lock()); @@ -421,8 +421,6 @@ class StopInfoBreakpoint : public StopInfo { continue; } - internal_breakpoint = bp_loc_sp->GetBreakpoint().IsInternal(); - // First run the precondition, but since the precondition is per // breakpoint, only run it once per breakpoint. std::pair::iterator, bool> result = @@ -509,7 +507,7 @@ class StopInfoBreakpoint : public StopInfo { loc_desc.GetData()); // We want this stop reported, so you will know we auto-continued // but only for external breakpoints: - if (!internal_breakpoint) + if (!bp_loc_sp->GetBreakpoint().IsInternal()) thread_sp->SetShouldReportStop(eVoteYes); auto_continue_says_stop = false; } @@ -539,6 +537,9 @@ class StopInfoBreakpoint : public StopInfo { actually_said_continue = true; } + if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal()) + all_stopping_locs_internal = false; + // If we are going to stop for this breakpoint, then remove the // breakpoint. if (callback_says_stop && bp_loc_sp && @@ -576,7 +577,7 @@ class StopInfoBreakpoint : public StopInfo { __FUNCTION__, m_value); } - if ((!m_should_stop || internal_breakpoint) && + if ((!m_should_stop || all_stopping_locs_internal) && thread_sp->CompletedPlanOverridesBreakpoint()) { // Override should_stop decision when we have completed step plan diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index edc00a9c8e190..f884a9414fd0f 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -5305,6 +5305,12 @@ bool TargetProperties::GetDebugUtilityExpression() const { nullptr, idx, g_target_properties[idx].default_uint_value != 0); } +bool TargetProperties::GetEnableTrampolineSupport() const { + const uint32_t idx = ePropertyEnableTrampolineSupport; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_target_properties[idx].default_uint_value != 0); +} + void TargetProperties::SetDebugUtilityExpression(bool debug) { const uint32_t idx = ePropertyDebugUtilityExpression; m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, debug); diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 2bdc218fd8181..de93957633f7b 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -218,6 +218,9 @@ let Definition = "target" in { def DebugUtilityExpression: Property<"debug-utility-expression", "Boolean">, DefaultFalse, Desc<"Enable debugging of LLDB-internal utility expressions.">; + def EnableTrampolineSupport: Property<"enable-trampoline-support", "Boolean">, + Global, DefaultTrue, + Desc<"Enable trampoline support in LLDB. Trampoline support includes stepping through trampolines directly to their targets, stepping out of trampolines directly to their callers, and automatically filtering out trampolines as possible breakpoint locations when set by name.">; } let Definition = "process_experimental" in { diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 428da24f0fcbb..6de3453f41567 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -41,6 +41,7 @@ #include "lldb/Target/ThreadPlanStepOverBreakpoint.h" #include "lldb/Target/ThreadPlanStepOverRange.h" #include "lldb/Target/ThreadPlanStepThrough.h" +#include "lldb/Target/ThreadPlanStepThroughGenericTrampoline.h" #include "lldb/Target/ThreadPlanStepUntil.h" #include "lldb/Target/ThreadSpec.h" #include "lldb/Target/UnwindLLDB.h" @@ -1419,6 +1420,17 @@ ThreadPlanSP Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id, return thread_plan_sp; } +ThreadPlanSP Thread::QueueThreadPlanForStepThroughGenericTrampoline( + bool abort_other_plans, lldb::RunMode stop_other_threads, Status &status) { + ThreadPlanSP thread_plan_sp( + new ThreadPlanStepThroughGenericTrampoline(*this, stop_other_threads)); + + if (!thread_plan_sp || !thread_plan_sp->ValidatePlan(nullptr)) + return ThreadPlanSP(); + status = QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; +} + ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(bool abort_other_plans, Address &target_addr, bool stop_other_threads, diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index a470e969037bd..d59178689f9c1 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Target/ThreadPlanShouldStopHere.h" +#include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Process.h" @@ -96,10 +97,16 @@ bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( // independently. If this ever // becomes expensive (this one isn't) we can try to have this set a state // that the StepFromHere can use. - if (frame) { - SymbolContext sc; - sc = frame->GetSymbolContext(eSymbolContextLineEntry); - if (sc.line_entry.line == 0) + SymbolContext sc; + sc = frame->GetSymbolContext(eSymbolContextLineEntry); + + if (sc.line_entry.line == 0) + should_stop_here = false; + + // If we're in a trampoline, don't stop by default. + if (Target::GetGlobalProperties().GetEnableTrampolineSupport()) { + sc = frame->GetSymbolContext(lldb::eSymbolContextFunction); + if (sc.function && sc.function->IsGenericTrampoline()) should_stop_here = false; } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 3e1cd4910949f..d679d9587dc53 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -221,6 +221,17 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // We may have set the plan up above in the FrameIsOlder section: + if (!m_sub_plan_sp) + m_sub_plan_sp = thread.QueueThreadPlanForStepThroughGenericTrampoline( + false, m_stop_others, m_status); + if (log) { + if (m_sub_plan_sp) + LLDB_LOGF(log, "Found a generic step through plan: %s", + m_sub_plan_sp->GetName()); + else + LLDB_LOGF(log, "No generic step through plan found."); + } + if (!m_sub_plan_sp) m_sub_plan_sp = thread.QueueThreadPlanForStepThrough( m_stack_id, false, stop_others, m_status); diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index b1cb070e0a3d0..0db2fe855854d 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -334,37 +334,6 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { return false; } -bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) { - // For crashes, breakpoint hits, signals, etc, let the base plan (or some - // plan above us) handle the stop. That way the user can see the stop, step - // around, and then when they are done, continue and have their step - // complete. The exception is if we've hit our "run to next branch" - // breakpoint. Note, unlike the step in range plan, we don't mark ourselves - // complete if we hit an unexplained breakpoint/crash. - - Log *log = GetLog(LLDBLog::Step); - StopInfoSP stop_info_sp = GetPrivateStopInfo(); - bool return_value; - - if (stop_info_sp) { - StopReason reason = stop_info_sp->GetStopReason(); - - if (reason == eStopReasonTrace) { - return_value = true; - } else if (reason == eStopReasonBreakpoint) { - return_value = NextRangeBreakpointExplainsStop(stop_info_sp); - } else { - if (log) - log->PutCString("ThreadPlanStepInRange got asked if it explains the " - "stop for some reason other than step."); - return_value = false; - } - } else - return_value = true; - - return return_value; -} - bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state, bool current_plan) { if (resume_state != eStateSuspended && m_first_resume) { diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index e2323bb31577c..409590db90b1a 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -494,3 +494,35 @@ bool ThreadPlanStepRange::IsPlanStale() { } return false; } + + +bool ThreadPlanStepRange::DoPlanExplainsStop(Event *event_ptr) { + // For crashes, breakpoint hits, signals, etc, let the base plan (or some + // plan above us) handle the stop. That way the user can see the stop, step + // around, and then when they are done, continue and have their step + // complete. The exception is if we've hit our "run to next branch" + // breakpoint. Note, unlike the step in range plan, we don't mark ourselves + // complete if we hit an unexplained breakpoint/crash. + + Log *log = GetLog(LLDBLog::Step); + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + bool return_value; + + if (stop_info_sp) { + StopReason reason = stop_info_sp->GetStopReason(); + + if (reason == eStopReasonTrace) { + return_value = true; + } else if (reason == eStopReasonBreakpoint) { + return_value = NextRangeBreakpointExplainsStop(stop_info_sp); + } else { + if (log) + log->PutCString("ThreadPlanStepRange got asked if it explains the " + "stop for some reason other than step."); + return_value = false; + } + } else + return_value = true; + + return return_value; +} diff --git a/lldb/source/Target/ThreadPlanStepThrough.cpp b/lldb/source/Target/ThreadPlanStepThrough.cpp index e195abf7e6526..0856aa506e569 100644 --- a/lldb/source/Target/ThreadPlanStepThrough.cpp +++ b/lldb/source/Target/ThreadPlanStepThrough.cpp @@ -33,6 +33,10 @@ ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread, m_start_address(0), m_backstop_bkpt_id(LLDB_INVALID_BREAK_ID), m_backstop_addr(LLDB_INVALID_ADDRESS), m_return_stack_id(m_stack_id), m_stop_others(stop_others) { + // If trampoline support is disabled, there's nothing for us to do. + if (!Target::GetGlobalProperties().GetEnableTrampolineSupport()) + return; + LookForPlanToStepThroughFromCurrentPC(); // If we don't get a valid step through plan, don't bother to set up a diff --git a/lldb/source/Target/ThreadPlanStepThroughGenericTrampoline.cpp b/lldb/source/Target/ThreadPlanStepThroughGenericTrampoline.cpp new file mode 100644 index 0000000000000..769eee476967d --- /dev/null +++ b/lldb/source/Target/ThreadPlanStepThroughGenericTrampoline.cpp @@ -0,0 +1,137 @@ +//===-- ThreadPlanStepThroughGenericTrampoline.cpp +//-----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/ThreadPlanStepThroughGenericTrampoline.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb; +using namespace lldb_private; + +uint32_t ThreadPlanStepThroughGenericTrampoline::s_default_flag_values = + ThreadPlanShouldStopHere::eStepInAvoidNoDebug; + +ThreadPlanStepThroughGenericTrampoline::ThreadPlanStepThroughGenericTrampoline( + Thread &thread, lldb::RunMode stop_others) + : ThreadPlanStepRange(ThreadPlan::eKindStepThroughGenericTrampoline, + "Step through generic trampoline", thread, {}, {}, + stop_others), + ThreadPlanShouldStopHere(this) { + + SetFlagsToDefault(); + auto frame = GetThread().GetFrameWithStackID(m_stack_id); + if (!frame) + return; + SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction); + + if (!sc.function) + return; + AddRange(sc.function->GetAddressRange()); +} + +ThreadPlanStepThroughGenericTrampoline:: + ~ThreadPlanStepThroughGenericTrampoline() = default; + +void ThreadPlanStepThroughGenericTrampoline::GetDescription( + Stream *s, lldb::DescriptionLevel level) { + + auto PrintFailureIfAny = [&]() { + if (m_status.Success()) + return; + s->Printf(" failed (%s)", m_status.AsCString()); + }; + + if (level == lldb::eDescriptionLevelBrief) { + s->Printf("step through generic trampoline"); + PrintFailureIfAny(); + return; + } + + auto frame = GetThread().GetFrameWithStackID(m_stack_id); + if (!frame) { + s->Printf(""); + return; + } + + SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction); + if (!sc.function) { + s->Printf(""); + return; + } + + s->Printf("Stepping through generic trampoline %s", + sc.function->GetName().AsCString()); + + lldb::StackFrameSP curr_frame = GetThread().GetStackFrameAtIndex(0); + if (!curr_frame) + return; + + SymbolContext curr_frame_sc = + curr_frame->GetSymbolContext(eSymbolContextFunction); + if (!curr_frame_sc.function) + return; + s->Printf(", current function: %s", + curr_frame_sc.function->GetName().GetCString()); + + PrintFailureIfAny(); + + s->PutChar('.'); +} + +bool ThreadPlanStepThroughGenericTrampoline::ShouldStop(Event *event_ptr) { + Log *log = GetLog(LLDBLog::Step); + + if (log) { + StreamString s; + DumpAddress(s.AsRawOstream(), GetThread().GetRegisterContext()->GetPC(), + GetTarget().GetArchitecture().GetAddressByteSize()); + LLDB_LOGF(log, "ThreadPlanStepThroughGenericTrampoline reached %s.", + s.GetData()); + } + + if (IsPlanComplete()) + return true; + + m_no_more_plans = false; + + Thread &thread = GetThread(); + lldb::StackFrameSP curr_frame = thread.GetStackFrameAtIndex(0); + if (!curr_frame) + return false; + + SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction); + + if (sc.function && sc.function->IsGenericTrampoline() && + SetNextBranchBreakpoint()) { + // While whatever frame we're in is a generic trampoline, + // continue stepping to the next branch, until we + // end up in a function which isn't a trampoline. + return false; + } + + m_no_more_plans = true; + SetPlanComplete(); + return true; +} + +bool ThreadPlanStepThroughGenericTrampoline::ValidatePlan(Stream *error) { + // If trampoline support is disabled, there's nothing for us to do. + if (!Target::GetGlobalProperties().GetEnableTrampolineSupport()) + return false; + + auto frame = GetThread().GetFrameWithStackID(m_stack_id); + if (!frame) + return false; + + SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction); + return sc.function && sc.function->IsGenericTrampoline(); +} diff --git a/lldb/test/API/commands/command/backticks/TestBackticksInAlias.py b/lldb/test/API/commands/command/backticks/TestBackticksInAlias.py index 495e52db53aa3..74c33c66cdd08 100644 --- a/lldb/test/API/commands/command/backticks/TestBackticksInAlias.py +++ b/lldb/test/API/commands/command/backticks/TestBackticksInAlias.py @@ -29,4 +29,54 @@ def test_backticks_in_alias(self): interp.HandleCommand("_test-argv-parray-cmd", result) self.assertFalse(result.Succeeded(), "CommandAlias::Desugar currently fails if a alias substitutes %N arguments in another alias") + def test_backticks_in_parsed_cmd_argument(self): + """ break list is a parsed command, use a variable for the breakpoint number + and make sure that and the direct use of the ID get the same result. """ + self.build() + target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) + # Make a second breakpoint so that if the backtick part -> nothing we'll print too much: + # It doesn't need to resolve to anything. + dummy_bkpt = target.BreakpointCreateByName("dont_really_care_if_this_exists") + + bkpt_id = bkpt.GetID() + self.runCmd(f"expr int $number = {bkpt_id}") + direct_result = lldb.SBCommandReturnObject() + backtick_result = lldb.SBCommandReturnObject() + interp = self.dbg.GetCommandInterpreter() + interp.HandleCommand(f"break list {bkpt_id}", direct_result) + self.assertTrue(direct_result.Succeeded(), "Break list with id works") + interp.HandleCommand("break list `$number`", backtick_result) + self.assertTrue(direct_result.Succeeded(), "Break list with backtick works") + self.assertEqual(direct_result.GetOutput(), backtick_result.GetOutput(), "Output is the same") + + def test_backticks_in_parsed_cmd_option(self): + # The script interpreter is a raw command, so try that one: + self.build() + target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) + + self.runCmd(f"expr int $number = 2") + direct_result = lldb.SBCommandReturnObject() + backtick_result = lldb.SBCommandReturnObject() + interp = self.dbg.GetCommandInterpreter() + interp.HandleCommand(f"memory read --count 2 argv", direct_result) + self.assertTrue(direct_result.Succeeded(), "memory read with direct count works") + interp.HandleCommand("memory read --count `$number` argv", backtick_result) + self.assertTrue(direct_result.Succeeded(), "memory read with backtick works") + self.assertEqual(direct_result.GetOutput(), backtick_result.GetOutput(), "Output is the same") + + def test_backticks_in_raw_cmd(self): + # The script interpreter is a raw command, so try that one: + self.build() + target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) + argc_valobj = thread.frames[0].FindVariable("argc") + self.assertTrue(argc_valobj.GetError().Success(), "Made argc valobj") + argc_value = argc_valobj.GetValueAsUnsigned(0) + self.assertNotEqual(argc_value, 0, "Got a value for argc") + result = lldb.SBCommandReturnObject() + interp = self.dbg.GetCommandInterpreter() + interp.HandleCommand(f"script {argc_value} - `argc`", result) + self.assertTrue(result.Succeeded(), "Command succeeded") + fixed_output = result.GetOutput().rstrip() + self.assertEqual("0", fixed_output, "Substitution worked") + diff --git a/lldb/test/API/commands/dwim-print/TestDWIMPrint.py b/lldb/test/API/commands/dwim-print/TestDWIMPrint.py index 705e2ef79ddeb..26736d5127386 100644 --- a/lldb/test/API/commands/dwim-print/TestDWIMPrint.py +++ b/lldb/test/API/commands/dwim-print/TestDWIMPrint.py @@ -16,18 +16,16 @@ def _run_cmd(self, cmd: str) -> str: self.ci.HandleCommand(cmd, result) return result.GetOutput().rstrip() - VAR_IDENT_RAW = r"(?:\$\d+|\w+) = " - VAR_IDENT = re.compile(VAR_IDENT_RAW) + VAR_IDENT = re.compile(r"(?:\$\d+|\w+) = ") - def _mask_persistent_var(self, string: str) -> str: + def _strip_result_var(self, string: str) -> str: """ - Replace persistent result variables (ex '$0', '$1', etc) with a regex - that matches any persistent result (r'\$\d+'). The returned string can - be matched against other `expression` results. + Strip (persistent) result variables (ex '$0 = ', or 'someVar = ', etc). + + This allows for using the output of `expression`/`frame variable`, to + compare it to `dwim-print` output, which disables result variables. """ - before, after = self.VAR_IDENT.split(string, maxsplit=1) - # Support either a frame variable (\w+) or a persistent result (\$\d+). - return re.escape(before) + self.VAR_IDENT_RAW + re.escape(after) + return self.VAR_IDENT.subn("", string, 1)[0] def _expect_cmd( self, @@ -46,19 +44,16 @@ def _expect_cmd( if actual_cmd == "frame variable": resolved_cmd = resolved_cmd.replace(" -- ", " ", 1) - expected_output = self._run_cmd(resolved_cmd) + resolved_cmd_output = self._run_cmd(resolved_cmd) + dwim_cmd_output = self._strip_result_var(resolved_cmd_output) # Verify dwim-print chose the expected command. self.runCmd("settings set dwim-print-verbosity full") - substrs = [f"note: ran `{resolved_cmd}`"] - patterns = [] - - if self.VAR_IDENT.search(expected_output): - patterns.append(self._mask_persistent_var(expected_output)) - else: - substrs.append(expected_output) - self.expect(dwim_cmd, substrs=substrs, patterns=patterns) + self.expect(dwim_cmd, substrs=[ + f"note: ran `{resolved_cmd}`", + dwim_cmd_output, + ]) def test_variables(self): """Test dwim-print with variables.""" @@ -112,3 +107,27 @@ def test_expression_language(self): lldbutil.run_to_name_breakpoint(self, "main") self._expect_cmd(f"dwim-print -l c++ -- argc", "frame variable") self._expect_cmd(f"dwim-print -l c++ -- argc + 1", "expression") + + def test_empty_expression(self): + self.build() + lldbutil.run_to_name_breakpoint(self, "main") + error_msg = "error: 'dwim-print' takes a variable or expression" + self.expect(f"dwim-print", error=True, startstr=error_msg) + self.expect(f"dwim-print -- ", error=True, startstr=error_msg) + + def test_nested_values(self): + """Test dwim-print with nested values (structs, etc).""" + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c")) + self.runCmd("settings set auto-one-line-summaries false") + self._expect_cmd(f"dwim-print s", "frame variable") + self._expect_cmd(f"dwim-print (struct Structure)s", "expression") + + def test_summary_strings(self): + """Test dwim-print with nested values (structs, etc).""" + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c")) + self.runCmd("settings set auto-one-line-summaries false") + self.runCmd("type summary add -e -s 'stub summary' Structure") + self._expect_cmd(f"dwim-print s", "frame variable") + self._expect_cmd(f"dwim-print (struct Structure)s", "expression") diff --git a/lldb/test/API/commands/dwim-print/main.c b/lldb/test/API/commands/dwim-print/main.c index 5c2fa9bb6a78e..e2eccf3a88b4b 100644 --- a/lldb/test/API/commands/dwim-print/main.c +++ b/lldb/test/API/commands/dwim-print/main.c @@ -1,3 +1,10 @@ +struct Structure { + int number; +}; + int main(int argc, char **argv) { + struct Structure s; + s.number = 30; + // break here return 0; } diff --git a/lldb/test/API/commands/dwim-print/swift/TestDWIMPrintSwift.py b/lldb/test/API/commands/dwim-print/swift/TestDWIMPrintSwift.py index 07222e64b8a3c..a2245c4c59ddc 100644 --- a/lldb/test/API/commands/dwim-print/swift/TestDWIMPrintSwift.py +++ b/lldb/test/API/commands/dwim-print/swift/TestDWIMPrintSwift.py @@ -7,8 +7,8 @@ from lldbsuite.test.decorators import * import lldbsuite.test.lldbutil as lldbutil - class TestCase(TestBase): + @swiftTest def test_swift_po_address(self): self.build() _, _, thread, _ = lldbutil.run_to_source_breakpoint( @@ -20,6 +20,7 @@ def test_swift_po_address(self): self.expect(f"dwim-print -O -- 0x{hex_addr}", patterns=[f"Object@0x0*{hex_addr}"]) self.expect(f"dwim-print -O -- {addr}", patterns=[f"Object@0x0*{hex_addr}"]) + @swiftTest def test_swift_po_non_address_hex(self): """No special handling of non-memory integer values.""" self.build() diff --git a/lldb/test/API/commands/expression/persistent_result/TestPersistentResult.py b/lldb/test/API/commands/expression/persistent_result/TestPersistentResult.py index 10eb100bac37b..911b8f605939b 100644 --- a/lldb/test/API/commands/expression/persistent_result/TestPersistentResult.py +++ b/lldb/test/API/commands/expression/persistent_result/TestPersistentResult.py @@ -31,7 +31,7 @@ def test_expression_persists_result(self): self.expect("expression i", substrs=["(int) $0 = 30"]) self.expect("expression $0", substrs=["(int) $0 = 30"]) - def test_p_persists_result(self): - """Test `p` does persist a result variable.""" - self.expect("p i", substrs=["(int) $0 = 30"]) - self.expect("p $0", substrs=["(int) $0 = 30"]) + def test_p_does_not_persist_results(self): + """Test `p` does not persist a result variable.""" + self.expect("p i", startstr="(int) 30") + self.expect("p $0", error=True) diff --git a/lldb/test/API/commands/frame/var/direct-ivar/swift/TestFrameVarDirectIvarSwift.py b/lldb/test/API/commands/frame/var/direct-ivar/swift/TestFrameVarDirectIvarSwift.py index c45094fe70465..e2288f6e044d3 100644 --- a/lldb/test/API/commands/frame/var/direct-ivar/swift/TestFrameVarDirectIvarSwift.py +++ b/lldb/test/API/commands/frame/var/direct-ivar/swift/TestFrameVarDirectIvarSwift.py @@ -5,12 +5,14 @@ class TestCase(TestBase): + @swiftTest @skipUnlessDarwin def test_objc_self(self): self.build() lldbutil.run_to_source_breakpoint(self, "check self", lldb.SBFileSpec("main.swift")) self.expect("frame variable _prop", startstr="(Int) _prop = 30") + @swiftTest @skipUnlessDarwin def test_objc_self_capture_idiom(self): self.build() diff --git a/lldb/test/API/functionalities/alias/TestPAlias.py b/lldb/test/API/functionalities/alias/TestPAlias.py index b694e903b9f00..e1f00b91e0149 100644 --- a/lldb/test/API/functionalities/alias/TestPAlias.py +++ b/lldb/test/API/functionalities/alias/TestPAlias.py @@ -7,5 +7,5 @@ class TestCase(TestBase): def test(self): self.build() lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.c")) - self.expect("p -g", substrs=["$0 = -"]) + self.expect("p -g", startstr="(int) -41") self.expect("p -i0 -g", error=True) diff --git a/lldb/test/API/functionalities/breakpoint/swift_exception/TestExpressionErrorBreakpoint.py b/lldb/test/API/functionalities/breakpoint/swift_exception/TestExpressionErrorBreakpoint.py index 1da102f13211b..dbfade98dca1c 100644 --- a/lldb/test/API/functionalities/breakpoint/swift_exception/TestExpressionErrorBreakpoint.py +++ b/lldb/test/API/functionalities/breakpoint/swift_exception/TestExpressionErrorBreakpoint.py @@ -28,26 +28,29 @@ class TestSwiftErrorBreakpoint(TestBase): @swiftTest def test_swift_error_no_typename(self): """Tests that swift error throws are correctly caught by the Swift Error breakpoint""" + self.build() self.do_tests(None, True) @swiftTest def test_swift_error_matching_base_typename(self): """Tests that swift error throws are correctly caught by the Swift Error breakpoint""" + self.build() self.do_tests("EnumError", True) @swiftTest def test_swift_error_matching_full_typename(self): """Tests that swift error throws are correctly caught by the Swift Error breakpoint""" + self.build() self.do_tests("a.EnumError", True) @swiftTest def test_swift_error_bogus_typename(self): """Tests that swift error throws are correctly caught by the Swift Error breakpoint""" + self.build() self.do_tests("NoSuchErrorHere", False) def setUp(self): TestBase.setUp(self) - self.build() def do_tests(self, typename, should_stop): self.do_test(typename, should_stop, self.create_breakpoint_with_api) diff --git a/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/Makefile b/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/Makefile new file mode 100644 index 0000000000000..2c00681fa2280 --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/Makefile @@ -0,0 +1,8 @@ +CXX_SOURCES := main.cpp + +ifneq (,$(findstring icc,$(CC))) + CXXFLAGS_EXTRAS := -debug inline-debug-info +endif + + +include Makefile.rules diff --git a/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/TestThreadPlanUserBreakpoint.py b/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/TestThreadPlanUserBreakpoint.py new file mode 100644 index 0000000000000..aaecdff0069f6 --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/TestThreadPlanUserBreakpoint.py @@ -0,0 +1,121 @@ +""" +Test that breakpoints (reason = breakpoint) have more priority than +plan completion (reason = step in/out/over) when reporting stop reason after step, +in particular 'step out' and 'step over', and in addition 'step in'. +Check for correct StopReason when stepping to the line with breakpoint, +which should be eStopReasonBreakpoint in general, +and eStopReasonPlanComplete when breakpoint's condition fails or it is disabled. +""" + + +import unittest2 +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class ThreadPlanUserBreakpointsTestCase(TestBase): + + def setUp(self): + TestBase.setUp(self) + + # Build and run to starting breakpoint + self.build() + src = lldb.SBFileSpec('main.cpp') + (self.target, self.process, self.thread, _) = \ + lldbutil.run_to_source_breakpoint(self, '// Start from here', src) + + # Setup two more breakpoints + self.breakpoints = [self.target.BreakpointCreateBySourceRegex('breakpoint_%i' % i, src) + for i in range(2)] + self.assertTrue( + all(bp and bp.GetNumLocations() == 1 for bp in self.breakpoints), + VALID_BREAKPOINT) + + def check_correct_stop_reason(self, breakpoint_idx, condition): + self.assertState(self.process.GetState(), lldb.eStateStopped) + if condition: + # All breakpoints active, stop reason is breakpoint + thread1 = lldbutil.get_one_thread_stopped_at_breakpoint(self.process, self.breakpoints[breakpoint_idx]) + self.assertEquals(self.thread, thread1, "Didn't stop at breakpoint %i." % breakpoint_idx) + else: + # Breakpoints are inactive, stop reason is plan complete + self.assertEquals(self.thread.GetStopReason(), lldb.eStopReasonPlanComplete, + 'Expected stop reason to be step into/over/out for inactive breakpoint %i line.' % breakpoint_idx) + + def change_breakpoints(self, action): + for bp in self.breakpoints: + action(bp) + + def check_thread_plan_user_breakpoint(self, condition, set_up_breakpoint_func): + # Make breakpoints active/inactive in different ways + self.change_breakpoints(lambda bp: set_up_breakpoint_func(condition, bp)) + + self.thread.StepInto() + # We should be stopped at the breakpoint_0 line with the correct stop reason + self.check_correct_stop_reason(0, condition) + + # This step-over creates a step-out from `func_1` plan + self.thread.StepOver() + # We should be stopped at the breakpoint_1 line with the correct stop reason + self.check_correct_stop_reason(1, condition) + + # Check explicit step-out + # Make sure we install the breakpoint at the right address: + # step-out might stop on different lines, if the compiler + # did or did not emit more instructions after the return + return_addr = self.thread.GetFrameAtIndex(1).GetPC() + step_out_breakpoint = self.target.BreakpointCreateByAddress(return_addr) + self.assertTrue(step_out_breakpoint, VALID_BREAKPOINT) + set_up_breakpoint_func(condition, step_out_breakpoint) + self.breakpoints.append(step_out_breakpoint) + self.thread.StepOut() + # We should be stopped somewhere in the main frame with the correct stop reason + self.check_correct_stop_reason(2, condition) + + # Run the process until termination + self.process.Continue() + self.assertState(self.process.GetState(), lldb.eStateExited) + + def set_up_breakpoints_condition(self, condition, bp): + # Set breakpoint condition to true/false + conditionStr = 'true' if condition else 'false' + bp.SetCondition(conditionStr) + + def set_up_breakpoints_enable(self, condition, bp): + # Enable/disable breakpoint + bp.SetEnabled(condition) + + def set_up_breakpoints_callback(self, condition, bp): + # Set breakpoint callback to return True/False + bp.SetScriptCallbackBody('return %s' % condition) + + def test_thread_plan_user_breakpoint_conditional_active(self): + # Test with breakpoints having true condition + self.check_thread_plan_user_breakpoint(condition=True, + set_up_breakpoint_func=self.set_up_breakpoints_condition) + + def test_thread_plan_user_breakpoint_conditional_inactive(self): + # Test with breakpoints having false condition + self.check_thread_plan_user_breakpoint(condition=False, + set_up_breakpoint_func=self.set_up_breakpoints_condition) + + def test_thread_plan_user_breakpoint_unconditional_active(self): + # Test with breakpoints enabled unconditionally + self.check_thread_plan_user_breakpoint(condition=True, + set_up_breakpoint_func=self.set_up_breakpoints_enable) + + def test_thread_plan_user_breakpoint_unconditional_inactive(self): + # Test with breakpoints disabled unconditionally + self.check_thread_plan_user_breakpoint(condition=False, + set_up_breakpoint_func=self.set_up_breakpoints_enable) + + def test_thread_plan_user_breakpoint_callback_active(self): + # Test with breakpoints with callback that returns 'True' + self.check_thread_plan_user_breakpoint(condition=True, + set_up_breakpoint_func=self.set_up_breakpoints_callback) + + def test_thread_plan_user_breakpoint_callback_inactive(self): + # Test with breakpoints with callback that returns 'False' + self.check_thread_plan_user_breakpoint(condition=False, + set_up_breakpoint_func=self.set_up_breakpoints_callback) diff --git a/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/main.cpp b/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/main.cpp new file mode 100644 index 0000000000000..2d7e06eb6da49 --- /dev/null +++ b/lldb/test/API/functionalities/breakpoint/thread_plan_user_breakpoint/main.cpp @@ -0,0 +1,11 @@ +int func_1() { return 1; } + +int func_2() { + func_1(); // breakpoint_0 + return 1 + func_1(); // breakpoint_1 +} + +int main(int argc, char const *argv[]) { + func_2(); // Start from here + return 0; +} diff --git a/lldb/test/API/functionalities/data-formatter/swift-unsafe/main.swift b/lldb/test/API/functionalities/data-formatter/swift-unsafe/main.swift index 0c147b7532608..86db72fb60d54 100644 --- a/lldb/test/API/functionalities/data-formatter/swift-unsafe/main.swift +++ b/lldb/test/API/functionalities/data-formatter/swift-unsafe/main.swift @@ -103,6 +103,7 @@ func main() { colors.withUnsafeBufferPointer { let buf = $0 + print("break") //% self.expect("frame variable -d run-target buf", //% patterns=[ //% '\(UnsafeBufferPointer<(.*)\.ColorCode>\) buf = 2 values \(0[xX][0-9a-fA-F]+\) {', @@ -139,6 +140,7 @@ func main() { numbers.withUnsafeBufferPointer { let buf = $0 + print("break") //% self.expect("frame variable -d run-target buf", //% patterns=[ //% '\(UnsafeBufferPointer<(.*)\.Number>\) buf = 2 values \(0[xX][0-9a-fA-F]+\) {', @@ -153,6 +155,7 @@ func main() { bytes.withUnsafeBufferPointer { let buf = $0 let rawbuf = UnsafeRawBufferPointer(buf) + print("break") //% self.expect("frame variable -d run-target rawbuf", //% patterns=[ //% '\(UnsafeRawBufferPointer\) rawbuf = 256 values \(0[xX][0-9a-fA-F]+\) {', @@ -160,6 +163,7 @@ func main() { //% ]) typealias ByteBuffer = UnsafeRawBufferPointer; let alias = rawbuf as ByteBuffer + print("break") //% self.expect("frame variable -d run-target alias", //% patterns=[ //% '\(ByteBuffer\) alias = 256 values \(0[xX][0-9a-fA-F]+\) {', @@ -167,6 +171,7 @@ func main() { //% ]) typealias ByteBufferAlias = ByteBuffer let secondAlias = alias as ByteBufferAlias + print("break") //% self.expect("frame variable -d run-target secondAlias", //% patterns=[ //% '\(ByteBufferAlias\) secondAlias = 256 values \(0[xX][0-9a-fA-F]+\) {', diff --git a/lldb/test/API/functionalities/progress_reporting/TestProgressReporting.py b/lldb/test/API/functionalities/progress_reporting/TestProgressReporting.py index 164ccbf72bf8e..8d1821e4e92d3 100644 --- a/lldb/test/API/functionalities/progress_reporting/TestProgressReporting.py +++ b/lldb/test/API/functionalities/progress_reporting/TestProgressReporting.py @@ -28,3 +28,14 @@ def test_dwarf_symbol_loading_progress_report(self): message = ret_args[0] self.assertGreater(len(message), 0) + def test_dwarf_symbol_loading_progress_report_structured_data(self): + """Test that we are able to fetch dwarf symbol loading progress events + using the structured data API""" + self.build() + + lldbutil.run_to_source_breakpoint(self, 'break here', lldb.SBFileSpec('main.c')) + + event = lldbutil.fetch_next_event(self, self.listener, self.broadcaster) + progress_data = lldb.SBDebugger.GetProgressDataFromEvent(event) + message = progress_data.GetValueForKey("message").GetStringValue(100) + self.assertGreater(len(message), 0) diff --git a/lldb/test/API/functionalities/progress_reporting/clang_modules/Makefile b/lldb/test/API/functionalities/progress_reporting/clang_modules/Makefile new file mode 100644 index 0000000000000..4ad4c54783a46 --- /dev/null +++ b/lldb/test/API/functionalities/progress_reporting/clang_modules/Makefile @@ -0,0 +1,4 @@ +OBJC_SOURCES := main.m +CFLAGS_EXTRAS = -fmodules -I$(BUILDDIR) + +include Makefile.rules diff --git a/lldb/test/API/functionalities/progress_reporting/clang_modules/MyModule.h b/lldb/test/API/functionalities/progress_reporting/clang_modules/MyModule.h new file mode 100644 index 0000000000000..ab96a103ec4ec --- /dev/null +++ b/lldb/test/API/functionalities/progress_reporting/clang_modules/MyModule.h @@ -0,0 +1 @@ +extern int doesNotActuallyExist; diff --git a/lldb/test/API/functionalities/progress_reporting/clang_modules/TestClangModuleBuildProgress.py b/lldb/test/API/functionalities/progress_reporting/clang_modules/TestClangModuleBuildProgress.py new file mode 100644 index 0000000000000..228f676aedf6a --- /dev/null +++ b/lldb/test/API/functionalities/progress_reporting/clang_modules/TestClangModuleBuildProgress.py @@ -0,0 +1,46 @@ +""" +Test clang module build progress events. +""" +import os +import shutil + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + + +class TestCase(TestBase): + @skipUnlessDarwin + def test_clang_module_build_progress_report(self): + """Test receipt of progress events for clang module builds""" + self.build() + + # Ensure an empty module cache. + mod_cache = self.getBuildArtifact("new-modules") + if os.path.isdir(mod_cache): + shutil.rmtree(mod_cache) + self.runCmd(f"settings set symbols.clang-modules-cache-path '{mod_cache}'") + + # TODO: The need for this seems like a bug. + self.runCmd( + f"settings set target.clang-module-search-paths '{self.getSourceDir()}'" + ) + + lldbutil.run_to_name_breakpoint(self, "main") + + # Just before triggering module builds, start listening for progress + # events. Listening any earlier would result in a queue filled with + # other unrelated progress events. + broadcaster = self.dbg.GetBroadcaster() + listener = lldbutil.start_listening_from( + broadcaster, lldb.SBDebugger.eBroadcastBitProgress + ) + + # Trigger module builds. + self.expect("expression @import MyModule") + + event = lldbutil.fetch_next_event(self, listener, broadcaster) + payload = lldb.SBDebugger.GetProgressFromEvent(event) + message = payload[0] + self.assertEqual(message, "Building Clang modules") diff --git a/lldb/test/API/functionalities/progress_reporting/clang_modules/main.m b/lldb/test/API/functionalities/progress_reporting/clang_modules/main.m new file mode 100644 index 0000000000000..237c8ce181774 --- /dev/null +++ b/lldb/test/API/functionalities/progress_reporting/clang_modules/main.m @@ -0,0 +1 @@ +int main() {} diff --git a/lldb/test/API/functionalities/progress_reporting/clang_modules/module.modulemap b/lldb/test/API/functionalities/progress_reporting/clang_modules/module.modulemap new file mode 100644 index 0000000000000..88caf2cb678ff --- /dev/null +++ b/lldb/test/API/functionalities/progress_reporting/clang_modules/module.modulemap @@ -0,0 +1,4 @@ +module MyModule { + header "MyModule.h" + export * +} diff --git a/lldb/test/API/lang/c/trampoline_stepping/Makefile b/lldb/test/API/lang/c/trampoline_stepping/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/lang/c/trampoline_stepping/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/lang/c/trampoline_stepping/TestTrampolineStepping.py b/lldb/test/API/lang/c/trampoline_stepping/TestTrampolineStepping.py new file mode 100644 index 0000000000000..4531a727c4900 --- /dev/null +++ b/lldb/test/API/lang/c/trampoline_stepping/TestTrampolineStepping.py @@ -0,0 +1,104 @@ +"""Test that stepping in/out of trampolines works as expected. +""" + + + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestTrampoline(TestBase): + def setup(self, bkpt_str): + self.build() + + _, _, thread, _ = lldbutil.run_to_source_breakpoint( + self, bkpt_str, lldb.SBFileSpec('main.c')) + return thread + + def test_direct_call(self): + thread = self.setup('Break here for direct') + + # Sanity check that we start out in the correct function. + name = thread.frames[0].GetFunctionName() + self.assertIn('direct_trampoline_call', name) + + # Check that stepping in will take us directly to the trampoline target. + thread.StepInto() + name = thread.frames[0].GetFunctionName() + self.assertIn('foo', name) + + # Check that stepping out takes us back to the trampoline caller. + thread.StepOut() + name = thread.frames[0].GetFunctionName() + self.assertIn('direct_trampoline_call', name) + + # Check that stepping over the end of the trampoline target + # takes us back to the trampoline caller. + thread.StepInto() + thread.StepOver() + name = thread.frames[0].GetFunctionName() + self.assertIn('direct_trampoline_call', name) + + + def test_chained_call(self): + thread = self.setup('Break here for chained') + + # Sanity check that we start out in the correct function. + name = thread.frames[0].GetFunctionName() + self.assertIn('chained_trampoline_call', name) + + # Check that stepping in will take us directly to the trampoline target. + thread.StepInto() + name = thread.frames[0].GetFunctionName() + self.assertIn('foo', name) + + # Check that stepping out takes us back to the trampoline caller. + thread.StepOut() + name = thread.frames[0].GetFunctionName() + self.assertIn('chained_trampoline_call', name) + + # Check that stepping over the end of the trampoline target + # takes us back to the trampoline caller. + thread.StepInto() + thread.StepOver() + name = thread.frames[0].GetFunctionName() + self.assertIn('chained_trampoline_call', name) + + def test_trampoline_after_nodebug(self): + thread = self.setup('Break here for nodebug then trampoline') + + # Sanity check that we start out in the correct function. + name = thread.frames[0].GetFunctionName() + self.assertIn('trampoline_after_nodebug', name) + + # Check that stepping in will take us directly to the trampoline target. + thread.StepInto() + name = thread.frames[0].GetFunctionName() + self.assertIn('foo', name) + + # Check that stepping out takes us back to the trampoline caller. + thread.StepOut() + name = thread.frames[0].GetFunctionName() + self.assertIn('trampoline_after_nodebug', name) + + # Check that stepping over the end of the trampoline target + # takes us back to the trampoline caller. + thread.StepInto() + thread.StepOver() + name = thread.frames[0].GetFunctionName() + self.assertIn('trampoline_after_nodebug', name) + + def test_unused_target(self): + thread = self.setup('Break here for unused') + + # Sanity check that we start out in the correct function. + name = thread.frames[0].GetFunctionName() + self.assertIn('unused_target', name) + + # Check that stepping into a trampoline that doesn't call its target + # jumps back to its caller. + thread.StepInto() + name = thread.frames[0].GetFunctionName() + self.assertIn('unused_target', name) + diff --git a/lldb/test/API/lang/c/trampoline_stepping/main.c b/lldb/test/API/lang/c/trampoline_stepping/main.c new file mode 100644 index 0000000000000..cb98be00ca1f6 --- /dev/null +++ b/lldb/test/API/lang/c/trampoline_stepping/main.c @@ -0,0 +1,52 @@ +void foo(void) {} + +__attribute__((transparent_stepping)) +void bar(void) { + foo(); +} + +__attribute__((transparent_stepping)) +void baz(void) { + bar(); +} + +__attribute__((nodebug)) +void nodebug(void) {} + +__attribute__((transparent_stepping)) +void nodebug_then_trampoline(void) { + nodebug(); + baz(); +} + +__attribute__((transparent_stepping)) +void doesnt_call_trampoline(void) {} + +void direct_trampoline_call(void) { + bar(); // Break here for direct + bar(); +} + +void chained_trampoline_call(void) { + baz(); // Break here for chained + baz(); +} + +void trampoline_after_nodebug(void) { + nodebug_then_trampoline(); // Break here for nodebug then trampoline + nodebug_then_trampoline(); +} + +void unused_target(void) { + doesnt_call_trampoline(); // Break here for unused +} + + +int main(void) { + direct_trampoline_call(); + chained_trampoline_call(); + trampoline_after_nodebug(); + unused_target(); + return 0; +} + diff --git a/lldb/test/API/lang/swift/clangimporter/Werror/TestSwiftStripWerror.py b/lldb/test/API/lang/swift/clangimporter/Werror/TestSwiftStripWerror.py index 4a65a9ab30fbb..2a2889ab26a00 100644 --- a/lldb/test/API/lang/swift/clangimporter/Werror/TestSwiftStripWerror.py +++ b/lldb/test/API/lang/swift/clangimporter/Werror/TestSwiftStripWerror.py @@ -28,7 +28,7 @@ def test(self): log = self.getBuildArtifact("types.log") self.expect("log enable lldb types -f "+log) - self.expect("p foo", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["42"]) + self.expect("expression foo", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["42"]) sanity = 0 import io logfile = io.open(log, "r", encoding='utf-8') diff --git a/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py b/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py index 5d17cceda66c9..7cb6b09eac2d2 100644 --- a/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py +++ b/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py @@ -49,7 +49,7 @@ def testSwiftDebugMacros(self): log = self.getBuildArtifact("types.log") self.expect("log enable lldb types -f "+log) - self.expect("p foo", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["42"]) + self.expect("expression foo", DATA_TYPES_DISPLAYED_CORRECTLY, substrs=["42"]) debug = 0 space = 0 ndebug = 0 diff --git a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py index c7c5411a4d3d7..f7c68353949e6 100644 --- a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py +++ b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py @@ -53,11 +53,11 @@ def test(self): process = target.LaunchSimple(None, None, os.getcwd()) # This is failing because the Target-SwiftASTContext uses the # amalgamated target header search options from all dylibs. - self.expect("p baz", "wrong baz", substrs=["i_am_from_Foo"]) + self.expect("expression baz", "wrong baz", substrs=["i_am_from_Foo"]) self.expect("fr var baz", "wrong baz", substrs=["i_am_from_Foo"]) process.Continue() - self.expect("p baz", "correct baz", substrs=["i_am_from_Foo"]) + self.expect("expression baz", "correct baz", substrs=["i_am_from_Foo"]) self.expect("fr var baz", "correct baz", substrs=["i_am_from_Foo"]) diff --git a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py index 3d7f8f048fd97..e68a5aa7bc6fd 100644 --- a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py +++ b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py @@ -52,9 +52,9 @@ def test(self): # This initially fails with the shared scratch context and is # then retried with the per-dylib scratch context. - # self.expect("p bar", "expected result", substrs=["$R0", "42"]) - # self.expect("p $R0", "expected result", substrs=["$R1", "42"]) - # self.expect("p $R1", "expected result", substrs=["$R2", "42"]) + # self.expect("expression bar", "expected result", substrs=["$R0", "42"]) + # self.expect("expression $R0", "expected result", substrs=["$R1", "42"]) + # self.expect("expression $R1", "expected result", substrs=["$R2", "42"]) # This works by accident because the search paths are in the right order. foo_breakpoint = target.BreakpointCreateBySourceRegex( @@ -64,7 +64,7 @@ def test(self): # FIXME: The following expression evaluator tests are disabled # because it's nondeterministic which one will work. - # self.expect("p foo", "expected result", substrs=["$R3", "23"]) - # self.expect("p $R3", "expected result", substrs=["23"]) - # self.expect("p $R4", "expected result", substrs=["23"]) + # self.expect("expression foo", "expected result", substrs=["$R3", "23"]) + # self.expect("expression $R3", "expected result", substrs=["23"]) + # self.expect("expression $R4", "expected result", substrs=["23"]) diff --git a/lldb/test/API/lang/swift/clangimporter/remap_sdk_path/TestSwiftRemapSDKPath.py b/lldb/test/API/lang/swift/clangimporter/remap_sdk_path/TestSwiftRemapSDKPath.py index 45ada8bed8fe8..9255e7bede1f9 100644 --- a/lldb/test/API/lang/swift/clangimporter/remap_sdk_path/TestSwiftRemapSDKPath.py +++ b/lldb/test/API/lang/swift/clangimporter/remap_sdk_path/TestSwiftRemapSDKPath.py @@ -22,7 +22,7 @@ def test(self): self.runCmd('log enable lldb types -f "%s"' % log) target, process, thread, bkpt = lldbutil.run_to_name_breakpoint( self, 'main') - self.expect("p 1", substrs=["1"]) + self.expect("expression 1", substrs=["1"]) # Scan through the types log. import io diff --git a/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py b/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py index 8fe575e0bfb71..ed74b734850b0 100644 --- a/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py +++ b/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py @@ -52,7 +52,7 @@ def test(self): # This test tests that the search paths from all swiftmodules # that are part of the main binary are honored. self.expect("fr var foo", "expected result", substrs=["23"]) - self.expect("p foo", "expected result", substrs=["$R0", "i", "23"]) + self.expect("expression foo", "expected result", substrs=["$R0", "i", "23"]) process.Continue() self.expect("fr var bar", "expected result", substrs=["42"]) - self.expect("p bar", "expected result", substrs=["j", "42"]) + self.expect("expression bar", "expected result", substrs=["j", "42"]) diff --git a/lldb/test/API/lang/swift/class_empty/main.swift b/lldb/test/API/lang/swift/class_empty/main.swift index a58229dbe7778..bfff59c2ebc02 100644 --- a/lldb/test/API/lang/swift/class_empty/main.swift +++ b/lldb/test/API/lang/swift/class_empty/main.swift @@ -17,7 +17,7 @@ class Empty : CustomStringConvertible { func main() { var e = Empty() - print(e) //% self.expect("p 1", substrs=['1']) + print(e) //% self.expect("expression 1", substrs=['1']) } main() diff --git a/lldb/test/API/lang/swift/closure_shortcuts/main.swift b/lldb/test/API/lang/swift/closure_shortcuts/main.swift index a2d3bb4968e5a..1b696796d3633 100644 --- a/lldb/test/API/lang/swift/closure_shortcuts/main.swift +++ b/lldb/test/API/lang/swift/closure_shortcuts/main.swift @@ -15,8 +15,8 @@ func main() -> Int { let names = ["foo", "patatino"] var reversedNames = names.sorted(by: { - $0 > $1 } //%self.expect('p $0', substrs=['patatino']) - //%self.expect('p $1', substrs=['foo']) + $0 > $1 } //%self.expect('expr $0', substrs=['patatino']) + //%self.expect('expr $1', substrs=['foo']) //%self.expect('frame var $0', substrs=['patatino']) //%self.expect('frame var $1', substrs=['foo']) ) diff --git a/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py b/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py index 5f436172ca96a..4c3db53f01234 100644 --- a/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py +++ b/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py @@ -34,7 +34,7 @@ def test_swift_deployment_target(self): lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec('main.swift')) - self.expect("p f", substrs=['i = 23']) + self.expect("expression f", substrs=['i = 23']) @skipUnlessDarwin @skipIfDarwinEmbedded # This test uses macOS triples explicitly. @@ -47,7 +47,7 @@ def test_swift_deployment_target_dlopen(self): bkpt = target.BreakpointCreateBySourceRegex( 'break here', lldb.SBFileSpec('NewerTarget.swift')) lldbutil.continue_to_breakpoint(process, bkpt) - self.expect("p self", substrs=['i = 23']) + self.expect("expression self", substrs=['i = 23']) @skipUnlessDarwin @skipIfDarwinEmbedded # This test uses macOS triples explicitly. @@ -61,7 +61,7 @@ def test_swift_deployment_target_from_macho(self): lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec('main.swift')) - self.expect("p f", substrs=['i = 23']) + self.expect("expression f", substrs=['i = 23']) found_no_ast = False found_triple = False diff --git a/lldb/test/API/lang/swift/expression/allocator/TestSwiftExprAllocator.py b/lldb/test/API/lang/swift/expression/allocator/TestSwiftExprAllocator.py index 746b4110670be..14ceb7fe5cf05 100644 --- a/lldb/test/API/lang/swift/expression/allocator/TestSwiftExprAllocator.py +++ b/lldb/test/API/lang/swift/expression/allocator/TestSwiftExprAllocator.py @@ -19,4 +19,4 @@ def test_allocator_self(self): target, process, thread, bkpt = lldbutil.run_to_source_breakpoint( self, 'break here', lldb.SBFileSpec('main.swift')) - self.expect("p x", substrs=['23']) + self.expect("expression x", substrs=['23']) diff --git a/lldb/test/API/lang/swift/generic_class/main.swift b/lldb/test/API/lang/swift/generic_class/main.swift index a50d00f1123a1..972a676818104 100644 --- a/lldb/test/API/lang/swift/generic_class/main.swift +++ b/lldb/test/API/lang/swift/generic_class/main.swift @@ -11,7 +11,7 @@ protocol P { } extension F : P { @inline(never) func method() { - print("break here \(b)") + print("break here \(b) \(self)") } } diff --git a/lldb/test/API/lang/swift/macCatalyst/TestSwiftMacCatalyst.py b/lldb/test/API/lang/swift/macCatalyst/TestSwiftMacCatalyst.py index fe29fdaaba1b9..51267cc3a5436 100644 --- a/lldb/test/API/lang/swift/macCatalyst/TestSwiftMacCatalyst.py +++ b/lldb/test/API/lang/swift/macCatalyst/TestSwiftMacCatalyst.py @@ -36,7 +36,7 @@ def test_macCatalyst(self): self.expect("fr v s", "Hello macCatalyst") expr_log = self.getBuildArtifact("expr.log") self.expect('log enable lldb expr -f "%s"' % expr_log) - self.expect("p s", "Hello macCatalyst") + self.expect("expression s", "Hello macCatalyst") import io expr_logfile = io.open(expr_log, "r", encoding='utf-8') diff --git a/lldb/test/API/lang/swift/missing_sdk/TestMissingSDK.py b/lldb/test/API/lang/swift/missing_sdk/TestMissingSDK.py index 67ed05992e7c3..cbd9f12b972ba 100644 --- a/lldb/test/API/lang/swift/missing_sdk/TestMissingSDK.py +++ b/lldb/test/API/lang/swift/missing_sdk/TestMissingSDK.py @@ -26,6 +26,6 @@ def testMissingSDK(self): os.unlink(self.getBuildArtifact("fakesdk")) lldbutil.run_to_source_breakpoint(self, 'break here', lldb.SBFileSpec('main.swift')) - self.expect("p message", VARIABLES_DISPLAYED_CORRECTLY, + self.expect("expression message", VARIABLES_DISPLAYED_CORRECTLY, substrs = ["Hello"]) diff --git a/lldb/test/API/lang/swift/po/sys_types/main.swift b/lldb/test/API/lang/swift/po/sys_types/main.swift index eb51c43bc5cad..84ca55dda4ff1 100644 --- a/lldb/test/API/lang/swift/po/sys_types/main.swift +++ b/lldb/test/API/lang/swift/po/sys_types/main.swift @@ -29,10 +29,8 @@ func main() { #endif //% self.expect("po nsarr", substrs = ['1','2','3','4']) var nsobject = NSObject() //% self.expect("po clr", substrs = ['1 0 0 1']) # may change depending on OS/platform - // Disabled: rdar://106152599 - // self.expect("po nsobject", substrs = ['"]) + return //%self.expect('expression self.radians', substrs=["CGFloat) $R0", "= 1.745"]) + //%self.expect('expression self', substrs=["Measurement"]) } } diff --git a/lldb/test/API/lang/swift/protocol_extension_two/main.swift b/lldb/test/API/lang/swift/protocol_extension_two/main.swift index 2618f01f17257..bc4a86bfa0aa4 100644 --- a/lldb/test/API/lang/swift/protocol_extension_two/main.swift +++ b/lldb/test/API/lang/swift/protocol_extension_two/main.swift @@ -10,8 +10,8 @@ extension Patatino where T == Winky { } func f() { - return //%self.expect('p self.baciotto', substrs=["(Int) $R0 = 0"]) - //%self.expect('p self', substrs=["a.Patatino"]) + return //%self.expect('expression self.baciotto', substrs=["(Int) $R0 = 0"]) + //%self.expect('expression self', substrs=["a.Patatino"]) } } diff --git a/lldb/test/API/lang/swift/runtime_library_path/TestSwiftRuntimeLibraryPath.py b/lldb/test/API/lang/swift/runtime_library_path/TestSwiftRuntimeLibraryPath.py index 28217304aa657..19b34b0941256 100644 --- a/lldb/test/API/lang/swift/runtime_library_path/TestSwiftRuntimeLibraryPath.py +++ b/lldb/test/API/lang/swift/runtime_library_path/TestSwiftRuntimeLibraryPath.py @@ -25,7 +25,7 @@ def test(self): target, process, thread, bkpt = lldbutil.run_to_name_breakpoint( self, 'main') - self.expect("p 1") + self.expect("expression 1") import io logfile = io.open(log, "r", encoding='utf-8') in_expr_log = 0 diff --git a/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py b/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py index 9507c7a4dc302..0e4bc818f4681 100644 --- a/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py +++ b/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py @@ -200,9 +200,10 @@ def do_test(self): thread.StepOver() self.hit_correct_line(thread, "At point initializer.") thread.StepOver() - self.hit_correct_line (thread, "At the beginning of the switch.") + stopped_at_switch = self.hit_correct_line (thread, "At the beginning of the switch.", False) + if stopped_at_switch: + thread.StepOver() - thread.StepOver() stopped_at_case = self.hit_correct_line( thread, "case (let x, let y) where", False) if stopped_at_case: @@ -312,6 +313,10 @@ def do_test(self): if stop_on_partial_apply: thread.StepOver() + stop_at_brace = self.hit_correct_line(thread, "Opening brace", False) + if stop_at_brace: + thread.StepOver() + self.hit_correct_line(thread, "doSomethingWithFunction(cd_maker, 10)") thread.StepInto() diff --git a/lldb/test/API/lang/swift/stepping/main.swift b/lldb/test/API/lang/swift/stepping/main.swift index cd9352805c4cd..535e707aa1bee 100644 --- a/lldb/test/API/lang/swift/stepping/main.swift +++ b/lldb/test/API/lang/swift/stepping/main.swift @@ -205,7 +205,7 @@ func main () -> Void indirect.protocol_func(20) var cd_maker = - { + { // Opening brace (arg : Int) -> ConformsDirectly in // Step into cd_maker stops at closure decl instead. return ConformsDirectly(arg) // Step into should stop here in closure. } diff --git a/lldb/test/API/lang/swift/swift-healthcheck/TestSwiftHealthCheck.py b/lldb/test/API/lang/swift/swift-healthcheck/TestSwiftHealthCheck.py index 36adc00421843..8adada198859f 100644 --- a/lldb/test/API/lang/swift/swift-healthcheck/TestSwiftHealthCheck.py +++ b/lldb/test/API/lang/swift/swift-healthcheck/TestSwiftHealthCheck.py @@ -19,7 +19,7 @@ def test_run_healthcheck(self): target, process, thread, bkpt = lldbutil.run_to_name_breakpoint( self, 'main') - self.expect("p 1") + self.expect("expression 1") result = lldb.SBCommandReturnObject() ret_val = self.dbg.GetCommandInterpreter().HandleCommand("swift-healthcheck", result) log = result.GetOutput()[:-1].split(" ")[-1] diff --git a/lldb/test/API/lang/swift/tripleDetection/TestSwiftTripleDetection.py b/lldb/test/API/lang/swift/tripleDetection/TestSwiftTripleDetection.py index 0c2e930d3567e..d73dbee78bf77 100644 --- a/lldb/test/API/lang/swift/tripleDetection/TestSwiftTripleDetection.py +++ b/lldb/test/API/lang/swift/tripleDetection/TestSwiftTripleDetection.py @@ -26,7 +26,7 @@ def test(self): arch+"-apple-macos-unknown") bkpt = target.BreakpointCreateByName("main") process = target.LaunchSimple(None, None, self.get_process_working_directory()) - self.expect("p 1") + self.expect("expression 1") import io types_logfile = io.open(types_log, "r", encoding='utf-8') diff --git a/lldb/test/API/lang/swift/variables/consume_operator/TestSwiftConsumeOperator.py b/lldb/test/API/lang/swift/variables/consume_operator/TestSwiftConsumeOperator.py index f0261c14e8be4..02fc4d7542fca 100644 --- a/lldb/test/API/lang/swift/variables/consume_operator/TestSwiftConsumeOperator.py +++ b/lldb/test/API/lang/swift/variables/consume_operator/TestSwiftConsumeOperator.py @@ -71,95 +71,87 @@ def get_var(self, name): return frame.FindVariable(name) def do_check_copyable_value_test(self): - # We haven't defined varK yet. - varK = self.get_var('k') - - self.assertIsNone(varK.value, "varK initialized too early?!") + # We haven't defined k yet. + self.assertIsNone(self.get_var('k').value, "k initialized too early?!") # Go to break point 2. k should be valid. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to breakpoint 3. k should no longer be valid. self.process.Continue() - self.assertIsNone(varK.value, "K is live but was consumed?!") + self.assertIsNone(self.get_var('k').value, "K is live but was consumed?!") # Run so we hit the next breakpoint to jump to the next test's # breakpoint. self.process.Continue() def do_check_copyable_var_test(self): - # We haven't defined varK yet. - varK = self.get_var('k') - self.assertIsNone(varK.value, "varK initialized too early?!") + # We haven't defined k yet. + self.assertIsNone(self.get_var('k').value, "k initialized too early?!") # Go to break point 2. k should be valid. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to breakpoint 3. We invalidated k self.process.Continue() - self.assertIsNone(varK.value, "K is live but was consumed?!") + self.assertIsNone(self.get_var('k').value, "K is live but was consumed?!") # Go to the last breakpoint and make sure that k is reinitialized # properly. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized") # Run so we hit the next breakpoint to go to the next test. self.process.Continue() def do_check_addressonly_value_test(self): - # We haven't defined varK yet. - varK = self.get_var('k') - + # We haven't defined k yet. # Go to break point 2. k should be valid and m should not be. Since M is # a dbg.declare it is hard to test robustly that it is not initialized # so we don't do so. We have an additional llvm.dbg.addr test where we # move the other variable and show the correct behavior with # llvm.dbg.declare. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "var not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "var not initialized?!") # Go to breakpoint 3. self.process.Continue() - self.assertEqual(varK.unsigned, 0, - "dbg thinks varK is live despite move?!") + self.assertEqual(self.get_var('k').unsigned, 0, + "dbg thinks k is live despite move?!") # Run so we hit the next breakpoint as part of the next test. self.process.Continue() def do_check_addressonly_var_test(self): - varK = self.get_var('k') - # Go to break point 2. k should be valid. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to breakpoint 3. K was invalidated. self.process.Continue() - self.assertIsNone(varK.value, "K is live but was consumed?!") + self.assertIsNone(self.get_var('k').value, "K is live but was consumed?!") # Go to the last breakpoint and make sure that k is reinitialized # properly. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized") # Run so we hit the next breakpoint as part of the next test. self.process.Continue() def do_check_copyable_value_arg_test(self): # k is defined by the argument so it is valid. - varK = self.get_var('k') - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to break point 2. k should be valid. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to breakpoint 3. k should no longer be valid. self.process.Continue() - #self.assertIsNone(varK.value, "K is live but was consumed?!") + #self.assertIsNone(self.get_var('k').value, "K is live but was consumed?!") # Run so we hit the next breakpoint to jump to the next test's # breakpoint. @@ -167,29 +159,27 @@ def do_check_copyable_value_arg_test(self): def do_check_copyable_var_arg_test(self): # k is already defined and is an argument. - varK = self.get_var('k') - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to break point 2. k should be valid. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to breakpoint 3. We invalidated k self.process.Continue() - self.assertIsNone(varK.value, "K is live but was consumed?!") + self.assertIsNone(self.get_var('k').value, "K is live but was consumed?!") # Go to the last breakpoint and make sure that k is reinitialized # properly. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized") # Run so we hit the next breakpoint to go to the next test. self.process.Continue() def do_check_addressonly_value_arg_test(self): # k is defined since it is an argument. - varK = self.get_var('k') - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to break point 2. k should be valid and m should not be. Since M is # a dbg.declare it is hard to test robustly that it is not initialized @@ -197,27 +187,26 @@ def do_check_addressonly_value_arg_test(self): # move the other variable and show the correct behavior with # llvm.dbg.declare. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "var not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "var not initialized?!") # Go to breakpoint 3. self.process.Continue() - self.assertEqual(varK.unsigned, 0, - "dbg thinks varK is live despite move?!") + self.assertEqual(self.get_var('k').unsigned, 0, + "dbg thinks k is live despite move?!") # Run so we hit the next breakpoint as part of the next test. self.process.Continue() def do_check_addressonly_var_arg_test(self): - varK = self.get_var('k') - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to break point 2. k should be valid. self.process.Continue() - self.assertGreater(varK.unsigned, 0, "varK not initialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized?!") # Go to breakpoint 3. K was invalidated. self.process.Continue() - self.assertIsNone(varK.value, "K is live but was consumed?!") + self.assertIsNone(self.get_var('k').value, "K is live but was consumed?!") # Go to the last breakpoint and make sure that k is reinitialized # properly. @@ -225,170 +214,158 @@ def do_check_addressonly_var_arg_test(self): # There is some sort of bug here. We should have the value here. For now # leave the next line commented out and validate we are not seeing the # value so we can detect change in behavior. - self.assertGreater(varK.unsigned, 0, "varK not initialized") + self.assertGreater(self.get_var('k').unsigned, 0, "k not initialized") # Run so we hit the next breakpoint as part of the next test. self.process.Continue() def do_check_copyable_value_ccf_true(self): - varK = self.get_var('k') - - # Check at our start point that we do not have any state for varK and + # Check at our start point that we do not have any state for k and # then continue to our next breakpoint. - self.assertIsNone(varK.value, "varK should not have a value?!") + self.assertIsNone(self.get_var('k').value, "k should not have a value?!") self.process.Continue() # At this breakpoint, k should be defined since we are going to do # something with it. - self.assertIsNotNone(varK.value, "varK should have a value?!") + self.assertIsNotNone(self.get_var('k').value, "k should have a value?!") self.process.Continue() # At this breakpoint, we are now in the conditional control flow part of # the loop. Make sure that we can see k still. - self.assertIsNotNone(varK.value, "varK should have a value?!") + self.assertIsNotNone(self.get_var('k').value, "k should have a value?!") self.process.Continue() # Ok, we just performed the move. k should not be no longer initialized. - self.assertIsNone(varK.value, "varK should not have a value?!") + self.assertIsNone(self.get_var('k').value, "k should not have a value?!") self.process.Continue() # Finally we left the conditional control flow part of the function. k # should still be None. - self.assertIsNone(varK.value, "varK should not have a value!") + self.assertIsNone(self.get_var('k').value, "k should not have a value!") # Run again so we go and run to the next test. self.process.Continue() def do_check_copyable_value_ccf_false(self): - varK = self.get_var('k') - - # Check at our start point that we do not have any state for varK and + # Check at our start point that we do not have any state for k and # then continue to our next breakpoint. - self.assertIsNone(varK.value, "varK should not have a value?!") + self.assertIsNone(self.get_var('k').value, "k should not have a value?!") self.process.Continue() # At this breakpoint, k should be defined since we are going to do # something with it. - self.assertIsNotNone(varK.value, "varK should have a value?!") + self.assertIsNotNone(self.get_var('k').value, "k should have a value?!") self.process.Continue() # At this breakpoint, we are now past the end of the conditional # statement. We know due to the move checking that k can not have any # uses that are reachable from the move. So it is safe to always not # provide the value here. - self.assertIsNone(varK.value, "varK should have a value?!") + self.assertIsNone(self.get_var('k').value, "k should have a value?!") # Run again so we go and run to the next test. self.process.Continue() def do_check_copyable_var_ccf_true_reinit_out_block(self): - varK = self.get_var('k') - # At first we should not have a value for k. - self.assertEqual(varK.unsigned, 0, "varK should be nullptr!") + self.assertEqual(self.get_var('k').unsigned, 0, "k should be nullptr!") self.process.Continue() # Now we are in the conditional true block. K should be defined since we # are on the move itself. - self.assertGreater(varK.unsigned, 0, "varK should not be nullptr!") + self.assertGreater(self.get_var('k').unsigned, 0, "k should not be nullptr!") self.process.Continue() # Now we have executed the move and we are about to run code using # m. Make sure that K is not available! - self.assertEqual(varK.unsigned, 0, - "varK was already consumed! Should be nullptr") + self.assertEqual(self.get_var('k').unsigned, 0, + "k was already consumed! Should be nullptr") self.process.Continue() # We are now out of the conditional lexical block on the line of code # that redefines k. k should still be not available. - self.assertEqual(varK.unsigned, 0, - "varK was already consumed! Should be nullptr") + self.assertEqual(self.get_var('k').unsigned, 0, + "k was already consumed! Should be nullptr") self.process.Continue() # Ok, we have now reinit k and are about to call a method on it. We # should be valid now. - self.assertGreater(varK.unsigned, 0, - "varK should have be reinitialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, + "k should have be reinitialized?!") # Run again so we go and run to the next test. self.process.Continue() def do_check_copyable_var_ccf_true_reinit_in_block(self): - varK = self.get_var('k') - # At first we should not have a value for k. - self.assertEqual(varK.unsigned, 0, "varK should be nullptr!") + self.assertEqual(self.get_var('k').unsigned, 0, "k should be nullptr!") self.process.Continue() # Now we are in the conditional true block. K should be defined since we # are on the move itself. - self.assertGreater(varK.unsigned, 0, "varK should not be nullptr!") + self.assertGreater(self.get_var('k').unsigned, 0, "k should not be nullptr!") self.process.Continue() # Now we have executed the move and we are about to reinit k but have # not yet. Make sure we are not available! - self.assertEqual(varK.unsigned, 0, - "varK was already consumed! Should be nullptr") + self.assertEqual(self.get_var('k').unsigned, 0, + "k was already consumed! Should be nullptr") self.process.Continue() # We are now still inside the conditional part of the code, but have - # reinitialized varK. - self.assertGreater(varK.unsigned, 0, - "varK was reinit! Should be valid value!") + # reinitialized k. + self.assertGreater(self.get_var('k').unsigned, 0, + "k was reinit! Should be valid value!") self.process.Continue() # We now have left the conditional part of the function. k should still # be available. - self.assertGreater(varK.unsigned, 0, - "varK should have be reinitialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, + "k should have be reinitialized?!") # Run again so we go and run to the next test. self.process.Continue() def do_check_copyable_var_ccf_false_reinit_out_block(self): - varK = self.get_var('k') - # At first we should not have a value for k. - self.assertEqual(varK.unsigned, 0, "varK should be nullptr!") + self.assertEqual(self.get_var('k').unsigned, 0, "k should be nullptr!") self.process.Continue() - # Now we are right above the beginning of the false check. varK should + # Now we are right above the beginning of the false check. k should # still be valid. - self.assertGreater(varK.unsigned, 0, "varK should not be nullptr!") + self.assertGreater(self.get_var('k').unsigned, 0, "k should not be nullptr!") self.process.Continue() # Now we are after the conditional part of the code on the reinit # line. Since this is reachable from the move and we haven't reinit yet, # k should not be available. - self.assertEqual(varK.unsigned, 0, - "varK was already consumed! Should be nullptr") + self.assertEqual(self.get_var('k').unsigned, 0, + "k was already consumed! Should be nullptr") self.process.Continue() # Ok, we have now reinit k and are about to call a method on it. We # should be valid now. - self.assertGreater(varK.unsigned, 0, - "varK should have be reinitialized?!") + self.assertGreater(self.get_var('k').unsigned, 0, + "k should have be reinitialized?!") # Run again so we go and run to the next test. self.process.Continue() def do_check_copyable_var_ccf_false_reinit_in_block(self): - varK = self.get_var('k') - # At first we should not have a value for k. - self.assertEqual(varK.unsigned, 0, "varK should be nullptr!") + self.assertEqual(self.get_var('k').unsigned, 0, "k should be nullptr!") self.process.Continue() - # Now we are on the doSomething above the false check. So varK should be + # Now we are on the doSomething above the false check. So k should be # valid. - self.assertGreater(varK.unsigned, 0, "varK should not be nullptr!") + self.assertGreater(self.get_var('k').unsigned, 0, "k should not be nullptr!") self.process.Continue() # Now we are after the conditional scope. Since k was reinitialized in - # the conditional scope, along all paths we are valid so varK should + # the conditional scope, along all paths we are valid so k should # still be available. - self.assertGreater(varK.unsigned, 0, - "varK should not be nullptr?!") + self.assertGreater(self.get_var('k').unsigned, 0, + "k should not be nullptr?!") # Run again so we go and run to the next test. self.process.Continue() diff --git a/lldb/test/API/lang/swift/variables/inout/TestInOutVariables.py b/lldb/test/API/lang/swift/variables/inout/TestInOutVariables.py index e22d4b7147b29..aadd864ee7e2b 100644 --- a/lldb/test/API/lang/swift/variables/inout/TestInOutVariables.py +++ b/lldb/test/API/lang/swift/variables/inout/TestInOutVariables.py @@ -72,19 +72,19 @@ def check_class_internal( ivar = x_actual.GetChildAtIndex(0).GetChildAtIndex(0) ovar = x_actual.GetChildAtIndex(1) - self.assertTrue( - ivar.GetName() == "ivar", "Name: %s is not ivar %s" % + self.assertEquals( + ivar.GetName(), "ivar", "Name: %s is not ivar %s" % (ivar.GetName(), message_end)) - self.assertTrue( - ovar.GetName() == "ovar", + self.assertEquals( + ovar.GetName(), "ovar", "ovar is not ovar %s" % (message_end)) - self.assertTrue( - ivar.GetValue() == ivar_value, + self.assertEquals( + ivar.GetValue(), ivar_value, "ivar wrong %s" % (message_end)) - self.assertTrue( - ovar.GetValue() == ovar_value, + self.assertEquals( + ovar.GetValue(), ovar_value, "ovar wrong %s" % (message_end)) diff --git a/lldb/test/API/lang/swift/variables/inout/main.swift b/lldb/test/API/lang/swift/variables/inout/main.swift index 2daecca7b9a1b..9fbd151491ef1 100644 --- a/lldb/test/API/lang/swift/variables/inout/main.swift +++ b/lldb/test/API/lang/swift/variables/inout/main.swift @@ -39,13 +39,13 @@ struct Struct { } func foo (_ x: inout Class) { - print(x.ivar) - x.ivar += 1 // Set breakpoint here for Class access + print(x.ivar) // Set breakpoint here for Class access + x.ivar += 1 } func foo(_ x: inout Struct) { - print(x.ivar) - x.ivar += 1 // Set breakpoint here for Struct access + print(x.ivar) // Set breakpoint here for Struct access + x.ivar += 1 } func fn_ptrs (_ str: Struct) { diff --git a/lldb/test/API/lang/swift/variables/swift/TestSwiftTypes.py b/lldb/test/API/lang/swift/variables/swift/TestSwiftTypes.py index 25ee19418e845..cbe9ca64446a5 100644 --- a/lldb/test/API/lang/swift/variables/swift/TestSwiftTypes.py +++ b/lldb/test/API/lang/swift/variables/swift/TestSwiftTypes.py @@ -177,9 +177,9 @@ def do_test(self): self.expect("frame variable --raw hello", substrs=['String']) - self.expect("p/x int64_minus_two", substrs=['0xfffffffffffffffe']) - self.expect("p/u ~1", substrs=['18446744073709551614']) - self.expect("p/d ~1", substrs=['-2']) + self.expect("expression/x int64_minus_two", substrs=['0xfffffffffffffffe']) + self.expect("expression/u ~1", substrs=['18446744073709551614']) + self.expect("expression/d ~1", substrs=['-2']) self.expect('frame variable uint8_max', substrs=['-1'], matching=False) self.expect( diff --git a/lldb/test/API/lang/swift/xcode_sdk/TestSwiftXcodeSDK.py b/lldb/test/API/lang/swift/xcode_sdk/TestSwiftXcodeSDK.py index b22c22aca2ec1..ee234235edbfa 100644 --- a/lldb/test/API/lang/swift/xcode_sdk/TestSwiftXcodeSDK.py +++ b/lldb/test/API/lang/swift/xcode_sdk/TestSwiftXcodeSDK.py @@ -35,7 +35,7 @@ def test_decode(self): lldbutil.run_to_name_breakpoint(self, 'main') - self.expect("p 1") + self.expect("expression 1") self.check_log(log, "MacOSX") @swiftTest diff --git a/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py b/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py index 87953cbad475f..f554d5b39eaf7 100644 --- a/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py +++ b/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py @@ -153,10 +153,10 @@ def test_non_address_bit_memory_caching(self): # This should fill the cache by doing a read of buf_with_non_address # with the non-address bits removed (which is == buf). - self.runCmd("p buf_with_non_address") + self.runCmd("expression buf_with_non_address") # This will read from the cache since the two pointers point to the # same place. - self.runCmd("p buf") + self.runCmd("expression buf") # Open log ignoring utf-8 decode errors with open(log_file, 'r', errors='ignore') as f: diff --git a/lldb/test/API/macosx/universal64/Makefile b/lldb/test/API/macosx/universal64/Makefile new file mode 100644 index 0000000000000..f763f3ae2f6c9 --- /dev/null +++ b/lldb/test/API/macosx/universal64/Makefile @@ -0,0 +1,24 @@ +EXE := fat.out + +ifdef FAT64_DSYM + DSFLAGS_EXTRAS=-fat64 +endif + +include Makefile.rules + +all: fat.out + +fat.out: fat.arm64.out fat.x86_64.out + lipo -fat64 -create -o $@ $^ + +fat.x86_64.out: fat.x86_64.o + $(CC) -isysroot $(SDKROOT) -target x86_64-apple-macosx10.9 -o $@ $< + +fat.arm64.out: fat.arm64.o + $(CC) -isysroot $(SDKROOT) -target arm64-apple-macosx10.9 -o $@ $< + +fat.x86_64.o: main.c + $(CC) -isysroot $(SDKROOT) -g -O0 -target x86_64-apple-macosx11 -c -o $@ $< + +fat.arm64.o: main.c + $(CC) -isysroot $(SDKROOT) -g -O0 -target arm64-apple-macosx11 -c -o $@ $< diff --git a/lldb/test/API/macosx/universal64/TestUniversal64.py b/lldb/test/API/macosx/universal64/TestUniversal64.py new file mode 100644 index 0000000000000..0c4226fac5380 --- /dev/null +++ b/lldb/test/API/macosx/universal64/TestUniversal64.py @@ -0,0 +1,39 @@ +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class Universal64TestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def do_test(self): + # Get the executable. + exe = self.getBuildArtifact("fat.out") + + # Create a target. + self.target = self.dbg.CreateTarget(exe) + + # Create a breakpoint on main. + main_bp = self.target.BreakpointCreateByName("main") + self.assertTrue(main_bp, VALID_BREAKPOINT) + + # Make sure the binary and the dSYM are in the image list. + self.expect("image list ", patterns=['fat.out', 'fat.out.dSYM']) + + # The dynamic loader doesn't support fat64 executables so we can't + # actually launch them here. + + @skipUnlessDarwin + @skipIfDarwinEmbedded + def test_universal64_executable(self): + """Test fat64 universal executable""" + self.build(debug_info="dsym") + self.do_test() + + @skipUnlessDarwin + @skipIfDarwinEmbedded + @skipIf(compiler="clang", compiler_version=['<', '7.0']) + def test_universal64_dsym(self): + """Test fat64 universal dSYM""" + self.build(debug_info="dsym", dictionary={'FAT64_DSYM': '1'}) + self.do_test() diff --git a/lldb/test/API/macosx/universal64/main.c b/lldb/test/API/macosx/universal64/main.c new file mode 100644 index 0000000000000..5124e0afbfc19 --- /dev/null +++ b/lldb/test/API/macosx/universal64/main.c @@ -0,0 +1,5 @@ +#include + +int foo() { return 0; } + +int main(int argc, char **argv) { return foo(); } diff --git a/lldb/test/Shell/Commands/command-source.test b/lldb/test/Shell/Commands/command-source.test index fa389f2a12889..579e3989f6fd0 100644 --- a/lldb/test/Shell/Commands/command-source.test +++ b/lldb/test/Shell/Commands/command-source.test @@ -6,7 +6,7 @@ # RUN: %lldb -x -b -o 'settings set interpreter.stop-command-source-on-error false' -o "command source %s" 2>&1 | FileCheck %s --check-prefix CONTINUE bogus -p 10+1 +expression 10+1 # CONTINUE: $0 = 11 # STOP-NOT: $0 = 11 diff --git a/lldb/test/Shell/Commands/command-stop-hook-no-target.test b/lldb/test/Shell/Commands/command-stop-hook-no-target.test index ee9ded164d745..cc5e71dff00cd 100644 --- a/lldb/test/Shell/Commands/command-stop-hook-no-target.test +++ b/lldb/test/Shell/Commands/command-stop-hook-no-target.test @@ -1,4 +1,4 @@ # RUN: %clang_host -g %S/Inputs/main.c -o %t -# RUN: %lldb -b -o 'target stop-hook add --name test --shlib test -o "p 95000 + 126"' -o 'file %t' -o 'b main' -o 'r' 2>&1 | FileCheck %s +# RUN: %lldb -b -o 'target stop-hook add --name test --shlib test -o "expression 95000 + 126"' -o 'file %t' -o 'b main' -o 'r' 2>&1 | FileCheck %s # CHECK: Stop hook #1 added # CHECK-NOT: 95126 diff --git a/lldb/test/Shell/Expr/nodefaultlib.cpp b/lldb/test/Shell/Expr/nodefaultlib.cpp index fb53da7fcb08b..f97d8aad9a8db 100644 --- a/lldb/test/Shell/Expr/nodefaultlib.cpp +++ b/lldb/test/Shell/Expr/nodefaultlib.cpp @@ -7,10 +7,10 @@ // XFAIL: system-netbsd || system-freebsd || system-darwin // RUN: %build %s --nodefaultlib -o %t -// RUN: %lldb %t -o "b main" -o run -o "p call_me(5, 6)" -o exit \ +// RUN: %lldb %t -o "b main" -o run -o "expression call_me(5, 6)" -o exit \ // RUN: | FileCheck %s -// CHECK: p call_me(5, 6) +// CHECK: expression call_me(5, 6) // CHECK: (int) $0 = 30 int call_me(int x, long y) { return x * y; } diff --git a/lldb/test/Shell/Register/x86-64-fp-read.test b/lldb/test/Shell/Register/x86-64-fp-read.test index 39fdaf170f3f2..e23e333c204a5 100644 --- a/lldb/test/Shell/Register/x86-64-fp-read.test +++ b/lldb/test/Shell/Register/x86-64-fp-read.test @@ -9,9 +9,9 @@ process launch # CHECK: Process {{.*}} stopped # fdiv (%rbx) gets encoded into 2 bytes, int3 into 1 byte -print (void*)($pc-3) +expression (void*)($pc-3) # CHECK: (void *) $0 = [[FDIV:0x[0-9a-f]*]] -print &zero +expression &zero # CHECK: (uint32_t *) $1 = [[ZERO:0x[0-9a-f]*]] register read --all @@ -32,9 +32,9 @@ register read --all # CHECK-DAG: st{{(mm)?}}7 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} # legacy approach, superseded by fip/fdp registers -print (void*)($fiseg*0x100000000 + $fioff) +expression (void*)($fiseg*0x100000000 + $fioff) # CHECK: (void *) $2 = [[FDIV]] -print (uint32_t*)($foseg * 0x100000000 + $fooff) +expression (uint32_t*)($foseg * 0x100000000 + $fooff) # CHECK: (uint32_t *) $3 = [[ZERO]] process continue diff --git a/lldb/test/Shell/Register/x86-db-read.test b/lldb/test/Shell/Register/x86-db-read.test index f8380440c6270..85cdcd1cb8104 100644 --- a/lldb/test/Shell/Register/x86-db-read.test +++ b/lldb/test/Shell/Register/x86-db-read.test @@ -15,13 +15,13 @@ watchpoint set variable -w write g_32w watchpoint set variable -w read_write g_32rw # CHECK: Watchpoint created: Watchpoint 4: addr = 0x{{[0-9a-f]*}} size = 4 state = enabled type = rw -print &g_8w +expression &g_8w # CHECK: (uint8_t *) $0 = [[VAR8W:0x[0-9a-f]*]] -print &g_16rw +expression &g_16rw # CHECK: (uint16_t *) $1 = [[VAR16RW:0x[0-9a-f]*]] -print &g_32w +expression &g_32w # CHECK: (uint32_t *) $2 = [[VAR32W:0x[0-9a-f]*]] -print &g_32rw +expression &g_32rw # CHECK: (uint32_t *) $3 = [[VAR64RW:0x[0-9a-f]*]] register read --all diff --git a/lldb/test/Shell/Register/x86-fp-read.test b/lldb/test/Shell/Register/x86-fp-read.test index 566157b938367..f668b8cb78658 100644 --- a/lldb/test/Shell/Register/x86-fp-read.test +++ b/lldb/test/Shell/Register/x86-fp-read.test @@ -9,9 +9,9 @@ process launch # CHECK: Process {{.*}} stopped # fdiv (%rbx) gets encoded into 2 bytes, int3 into 1 byte -print (void*)($pc-3) +expression (void*)($pc-3) # CHECK: (void *) $0 = [[FDIV:0x[0-9a-f]*]] -print &zero +expression &zero # CHECK: (uint32_t *) $1 = [[ZERO:0x[0-9a-f]*]] register read --all diff --git a/lldb/test/Shell/Settings/Inputs/DontStopCommandSource.in b/lldb/test/Shell/Settings/Inputs/DontStopCommandSource.in index e33a1e329cad9..f3ef2a9e7016b 100644 --- a/lldb/test/Shell/Settings/Inputs/DontStopCommandSource.in +++ b/lldb/test/Shell/Settings/Inputs/DontStopCommandSource.in @@ -1,3 +1,3 @@ settings set interpreter.stop-command-source-on-error false bogus -print 123400000 + 56789 +expression 123400000 + 56789 diff --git a/lldb/test/Shell/Settings/Inputs/StopCommandSource.in b/lldb/test/Shell/Settings/Inputs/StopCommandSource.in index 19974c0c444b1..1159554e3425f 100644 --- a/lldb/test/Shell/Settings/Inputs/StopCommandSource.in +++ b/lldb/test/Shell/Settings/Inputs/StopCommandSource.in @@ -1,3 +1,3 @@ settings set interpreter.stop-command-source-on-error true bogus -print 123400000 + 56789 +expression 123400000 + 56789 diff --git a/lldb/test/Shell/Settings/TestStopCommandSourceOnError.test b/lldb/test/Shell/Settings/TestStopCommandSourceOnError.test index d734a0940a2d7..f99c9c204c19c 100644 --- a/lldb/test/Shell/Settings/TestStopCommandSourceOnError.test +++ b/lldb/test/Shell/Settings/TestStopCommandSourceOnError.test @@ -12,10 +12,10 @@ # RUN: %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -s %S/Inputs/StopCommandSource.in | FileCheck %s --check-prefix CONTINUE # FIXME: Should continue -# RUN: not %lldb -b -s %S/Inputs/DontStopCommandSource.in -o 'bogus' -o 'print 111100000 + 11111' | FileCheck %s --check-prefix STOP +# RUN: not %lldb -b -s %S/Inputs/DontStopCommandSource.in -o 'bogus' -o 'expression 111100000 + 11111' | FileCheck %s --check-prefix STOP # FIXME: Should continue -# RUN: not %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -o 'bogus' -o 'print 123400000 + 56789' | FileCheck %s --check-prefix STOP +# RUN: not %lldb -b -o 'settings set interpreter.stop-command-source-on-error false' -o 'bogus' -o 'expression 123400000 + 56789' | FileCheck %s --check-prefix STOP # FIXME: Should continue # RUN: not %lldb -b -s %S/Inputs/DontStopCommandSource.in | FileCheck %s --check-prefix STOP diff --git a/lldb/test/Shell/Swift/DeserializationFailure.test b/lldb/test/Shell/Swift/DeserializationFailure.test index c54e200342f65..a2a15c6e68e58 100644 --- a/lldb/test/Shell/Swift/DeserializationFailure.test +++ b/lldb/test/Shell/Swift/DeserializationFailure.test @@ -15,7 +15,7 @@ b main run # Create a SwiftASTContext, to induce error output. -p 1 +expression 1 # The {{ }} avoids accidentally matching the input script! # CHECK: a.out:{{ }}{{.*}}The serialized module is corrupted. diff --git a/lldb/test/Shell/Swift/DynamicTyperesolutionConflict.test b/lldb/test/Shell/Swift/DynamicTyperesolutionConflict.test index b2e5f8b3e53ee..d229f99273f5b 100644 --- a/lldb/test/Shell/Swift/DynamicTyperesolutionConflict.test +++ b/lldb/test/Shell/Swift/DynamicTyperesolutionConflict.test @@ -21,8 +21,8 @@ b Dylib.swift:9 run target v foofoo -p input -p input +expression input +expression input # The {{ }} avoids accidentally matching the input script! # CHECK: {{Swift}} error in fallback scratch context diff --git a/lldb/test/Shell/Swift/MissingVFSOverlay.test b/lldb/test/Shell/Swift/MissingVFSOverlay.test index 5a4decc34f2f5..e79d439487f95 100644 --- a/lldb/test/Shell/Swift/MissingVFSOverlay.test +++ b/lldb/test/Shell/Swift/MissingVFSOverlay.test @@ -12,7 +12,7 @@ b main run # Create a SwiftASTContext, to induce error output. -p 1 +expression 1 # The {{ }} avoids accidentally matching the input script! # CHECK: a.out:{{ }} diff --git a/lldb/test/Shell/Swift/RemoteASTImport.test b/lldb/test/Shell/Swift/RemoteASTImport.test index 06522707862a4..7c6d5094bb3aa 100644 --- a/lldb/test/Shell/Swift/RemoteASTImport.test +++ b/lldb/test/Shell/Swift/RemoteASTImport.test @@ -45,7 +45,7 @@ b Library.swift:10 run -p input +expression input # The {{ }} avoids accidentally matching the input script! # CHECK-NOT: undeclared identifier {{'SYNTAX_ERROR'}} diff --git a/lldb/test/Shell/SymbolFile/DWARF/debug-types-expressions.test b/lldb/test/Shell/SymbolFile/DWARF/debug-types-expressions.test index 0442cd8faa3b2..653af7b17c449 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/debug-types-expressions.test +++ b/lldb/test/Shell/SymbolFile/DWARF/debug-types-expressions.test @@ -40,18 +40,18 @@ frame variable *a # CHECK-NEXT: j = 42 # CHECK-NEXT: } -print a->f() -# CHECK-LABEL: print a->f() +expression a->f() +# CHECK-LABEL: expression a->f() # CHECK: (int) $0 = 47 -print ns::A() -# CHECK-LABEL: print ns::A() +expression ns::A() +# CHECK-LABEL: expression ns::A() # CHECK: (ns::A) $1 = (i = 147) -print ns::A().i + a->i -# CHECK-LABEL: print ns::A().i + a->i +expression ns::A().i + a->i +# CHECK-LABEL: expression ns::A().i + a->i # CHECK: (int) $2 = 194 -print ns::A().getA() +expression ns::A().getA() # CHECK-LABEL: ns::A().getA() # CHECK: (A) $3 = (i = 146) diff --git a/lldb/test/Shell/SymbolFile/DWARF/split-dwarf-expression-eval-bug.cpp b/lldb/test/Shell/SymbolFile/DWARF/split-dwarf-expression-eval-bug.cpp index ef1aa257665df..4a8004ddd287f 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/split-dwarf-expression-eval-bug.cpp +++ b/lldb/test/Shell/SymbolFile/DWARF/split-dwarf-expression-eval-bug.cpp @@ -11,10 +11,10 @@ // RUN: %clang_host -c -gsplit-dwarf -g %s -o %t2.o -DTWO // RUN: %clang_host -c -gsplit-dwarf -g %s -o %t3.o -DTHREE // RUN: %clang_host %t1.o %t2.o %t3.o -o %t -// RUN: %lldb %t -o "br set -n foo" -o run -o "p bool_in_first_cu" -o exit \ +// RUN: %lldb %t -o "br set -n foo" -o run -o "expression bool_in_first_cu" -o exit \ // RUN: | FileCheck %s -// CHECK: (lldb) p bool_in_first_cu +// CHECK: (lldb) expression bool_in_first_cu // CHECK: (bool) $0 = true diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/DW_TAG_GNU_call_site-DW_AT_low_pc.s b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_TAG_GNU_call_site-DW_AT_low_pc.s index 8cc1cc1ed2f95..c6e5ccda5f2ef 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/DW_TAG_GNU_call_site-DW_AT_low_pc.s +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_TAG_GNU_call_site-DW_AT_low_pc.s @@ -11,7 +11,7 @@ # REQUIRES: target-x86_64, system-linux, lld # RUN: %clang_host -o %t %s -# RUN: %lldb %t -o r -o 'p p' -o exit | FileCheck %s +# RUN: %lldb %t -o r -o 'expression p' -o exit | FileCheck %s # CHECK: (int) $0 = 1 diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/DW_TAG_variable-DW_AT_const_value.s b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_TAG_variable-DW_AT_const_value.s index 7ab9a8c61bafd..1d9bec342de5b 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/DW_TAG_variable-DW_AT_const_value.s +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/DW_TAG_variable-DW_AT_const_value.s @@ -1,7 +1,7 @@ # This tests that lldb is able to print DW_TAG_variable using DW_AT_const_value. # RUN: llvm-mc -triple x86_64-unknown-linux-gnu %s -filetype=obj > %t.o -# RUN: %lldb %t.o -o "p/x magic64" -o exit | FileCheck %s +# RUN: %lldb %t.o -o "expression/x magic64" -o exit | FileCheck %s # CHECK: (const long) $0 = 0xed9a924c00011151 diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-basic.test b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-basic.test index 947b43ba6b2ff..dc8005f73930e 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-basic.test +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-basic.test @@ -51,12 +51,12 @@ type lookup EC # CHECK-NEXT: e3 # CHECK-NEXT: } -print (E) 1 -# CHECK-LABEL: print (E) 1 +expression (E) 1 +# CHECK-LABEL: expression (E) 1 # CHECK: (E) $0 = e2 -print (EC) 1 -# CHECK-LABEL: print (EC) 1 +expression (EC) 1 +# CHECK-LABEL: expression (EC) 1 # CHECK: (EC) $1 = e2 target variable a e ec diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test index 8bdc2219cc1c9..e94b10a68d4e9 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-missing-signature.test @@ -14,10 +14,10 @@ LOOKUPE: no type was found matching 'E' RUN: %lldb %t -b -o "type lookup EC" | FileCheck --check-prefix=LOOKUPEC %s LOOKUPEC: no type was found matching 'EC' -RUN: not %lldb %t -b -o "print (E) 1" 2>&1 | FileCheck --check-prefix=PRINTE %s +RUN: not %lldb %t -b -o "expression (E) 1" 2>&1 | FileCheck --check-prefix=PRINTE %s PRINTE: use of undeclared identifier 'E' -RUN: not %lldb %t -b -o "print (EC) 1" 2>&1 | FileCheck --check-prefix=PRINTEC %s +RUN: not %lldb %t -b -o "expression (EC) 1" 2>&1 | FileCheck --check-prefix=PRINTEC %s PRINTEC: use of undeclared identifier 'EC' RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-signature-loop.s b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-signature-loop.s index d0d0fd5705a45..64b835353ed4e 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-signature-loop.s +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-types-signature-loop.s @@ -4,7 +4,7 @@ # RUN: ld.lld %t.o -o %t # RUN: %lldb %t -o "target variable e" -b | FileCheck %s -# CHECK: e = +# CHECK: Error: 'Unable to determine byte size.' .type e,@object # @e .section .rodata,"a",@progbits diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/dwarf5-line-strp.s b/lldb/test/Shell/SymbolFile/DWARF/x86/dwarf5-line-strp.s index 5c08f4a40528b..67f52454604f6 100755 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/dwarf5-line-strp.s +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/dwarf5-line-strp.s @@ -3,7 +3,7 @@ # UNSUPPORTED: system-darwin, system-windows # RUN: llvm-mc -filetype=obj -o %t -triple x86_64-pc-linux %s -# RUN: %lldb %t -o "p main" \ +# RUN: %lldb %t -o "expression main" \ # RUN: -o exit | FileCheck %s # CHECK: (void (*)()) $0 = 0x0000000000000000 diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/limit-debug-info.s b/lldb/test/Shell/SymbolFile/DWARF/x86/limit-debug-info.s index 6a2140a147921..4bd0fc8a9b55e 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/x86/limit-debug-info.s +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/limit-debug-info.s @@ -3,10 +3,10 @@ # RUN: llvm-mc --triple=x86_64-pc-windows --filetype=obj --defsym EXE=0 %s >%t.exe.o # RUN: lld-link /OUT:%t.dll %t.dll.o /SUBSYSTEM:console /dll /noentry /debug # RUN: lld-link /OUT:%t.exe %t.exe.o /SUBSYSTEM:console /debug /force -# RUN: %lldb %t.exe -o "target modules add %t.dll" -o "p var" \ +# RUN: %lldb %t.exe -o "target modules add %t.dll" -o "expression var" \ # RUN: -o exit 2>&1 | FileCheck %s -# CHECK: (lldb) p var +# CHECK: (lldb) expression var # CHECK: (A) $0 = (member = 47) .section .debug_abbrev,"dr" diff --git a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/inline_sites_live.lldbinit b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/inline_sites_live.lldbinit index 584d835977bf0..2291c7c452717 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/inline_sites_live.lldbinit +++ b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/inline_sites_live.lldbinit @@ -1,7 +1,7 @@ br set -p BP_bar -f inline_sites_live.cpp br set -p BP_foo -f inline_sites_live.cpp run -p param +expression param continue -p param -p local +expression param +expression local diff --git a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables.lldbinit b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables.lldbinit index 1071edd25c92b..4c8073e7bd884 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables.lldbinit +++ b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables.lldbinit @@ -1,30 +1,30 @@ break set -f local-variables.cpp -l 17 run a b c d e f g -p argc +expression argc step -p SomeLocal +expression SomeLocal step -p Param1 -p Param2 +expression Param1 +expression Param2 step -p Param1 -p Param2 -p Local1 +expression Param1 +expression Param2 +expression Local1 step -p Param1 -p Param2 -p Local1 -p Local2 +expression Param1 +expression Param2 +expression Local1 +expression Local2 step -p Param1 -p Param2 -p Local1 -p Local2 +expression Param1 +expression Param2 +expression Local1 +expression Local2 step -p Param1 -p Param2 -p Local1 -p Local2 +expression Param1 +expression Param2 +expression Local1 +expression Local2 continue target modules dump ast diff --git a/lldb/test/Shell/SymbolFile/NativePDB/inline_sites_live.cpp b/lldb/test/Shell/SymbolFile/NativePDB/inline_sites_live.cpp index bd3f80afd849c..767149ea18c46 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/inline_sites_live.cpp +++ b/lldb/test/Shell/SymbolFile/NativePDB/inline_sites_live.cpp @@ -24,11 +24,11 @@ int main(int argc, char** argv) { // CHECK: * thread #1, stop reason = breakpoint 1 // CHECK-NEXT: frame #0: {{.*}}`main [inlined] bar(param=2) -// CHECK: (lldb) p param +// CHECK: (lldb) expression param // CHECK-NEXT: (int) $0 = 2 // CHECK: * thread #1, stop reason = breakpoint 2 // CHECK-NEXT: frame #0: {{.*}}`main [inlined] foo(param=1) -// CHECK: (lldb) p param +// CHECK: (lldb) expression param // CHECK-NEXT: (int) $1 = 1 -// CHECK-NEXT: (lldb) p local +// CHECK-NEXT: (lldb) expression local // CHECK-NEXT: (int) $2 = 2 diff --git a/lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp b/lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp index 4779a28c8b380..a1f147b4bda6d 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp +++ b/lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp @@ -37,7 +37,7 @@ int main(int argc, char **argv) { // CHECK-NEXT: 20 // CHECK: Process {{.*}} launched: '{{.*}}local-variables.cpp.tmp.exe' -// CHECK-NEXT: (lldb) p argc +// CHECK-NEXT: (lldb) expression argc // CHECK-NEXT: (int) $0 = 8 // CHECK-NEXT: (lldb) step // CHECK-NEXT: Process {{.*}} stopped @@ -50,7 +50,7 @@ int main(int argc, char **argv) { // CHECK-NEXT: 19 } // CHECK-NEXT: 20 -// CHECK: (lldb) p SomeLocal +// CHECK: (lldb) expression SomeLocal // CHECK-NEXT: (int) $1 = 16 // CHECK-NEXT: (lldb) step // CHECK-NEXT: Process {{.*}} stopped @@ -64,9 +64,9 @@ int main(int argc, char **argv) { // CHECK-NEXT: 11 ++Local1; // CHECK-NEXT: 12 ++Local2; -// CHECK: (lldb) p Param1 +// CHECK: (lldb) expression Param1 // CHECK-NEXT: (int) $2 = 16 -// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (lldb) expression Param2 // CHECK-NEXT: (char) $3 = 'a' // CHECK-NEXT: (lldb) step // CHECK-NEXT: Process {{.*}} stopped @@ -80,11 +80,11 @@ int main(int argc, char **argv) { // CHECK-NEXT: 12 ++Local2; // CHECK-NEXT: 13 return Local1; -// CHECK: (lldb) p Param1 +// CHECK: (lldb) expression Param1 // CHECK-NEXT: (int) $4 = 16 -// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (lldb) expression Param2 // CHECK-NEXT: (char) $5 = 'a' -// CHECK-NEXT: (lldb) p Local1 +// CHECK-NEXT: (lldb) expression Local1 // CHECK-NEXT: (unsigned int) $6 = 17 // CHECK-NEXT: (lldb) step // CHECK-NEXT: Process {{.*}} stopped @@ -98,13 +98,13 @@ int main(int argc, char **argv) { // CHECK-NEXT: 13 return Local1; // CHECK-NEXT: 14 } -// CHECK: (lldb) p Param1 +// CHECK: (lldb) expression Param1 // CHECK-NEXT: (int) $7 = 16 -// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (lldb) expression Param2 // CHECK-NEXT: (char) $8 = 'a' -// CHECK-NEXT: (lldb) p Local1 +// CHECK-NEXT: (lldb) expression Local1 // CHECK-NEXT: (unsigned int) $9 = 17 -// CHECK-NEXT: (lldb) p Local2 +// CHECK-NEXT: (lldb) expression Local2 // CHECK-NEXT: (char) $10 = 'b' // CHECK-NEXT: (lldb) step // CHECK-NEXT: Process {{.*}} stopped @@ -118,13 +118,13 @@ int main(int argc, char **argv) { // CHECK-NEXT: 14 } // CHECK-NEXT: 15 -// CHECK: (lldb) p Param1 +// CHECK: (lldb) expression Param1 // CHECK-NEXT: (int) $11 = 16 -// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (lldb) expression Param2 // CHECK-NEXT: (char) $12 = 'a' -// CHECK-NEXT: (lldb) p Local1 +// CHECK-NEXT: (lldb) expression Local1 // CHECK-NEXT: (unsigned int) $13 = 18 -// CHECK-NEXT: (lldb) p Local2 +// CHECK-NEXT: (lldb) expression Local2 // CHECK-NEXT: (char) $14 = 'b' // CHECK-NEXT: (lldb) step // CHECK-NEXT: Process {{.*}} stopped @@ -138,13 +138,13 @@ int main(int argc, char **argv) { // CHECK-NEXT: 15 // CHECK-NEXT: 16 int main(int argc, char **argv) { -// CHECK: (lldb) p Param1 +// CHECK: (lldb) expression Param1 // CHECK-NEXT: (int) $15 = 16 -// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (lldb) expression Param2 // CHECK-NEXT: (char) $16 = 'a' -// CHECK-NEXT: (lldb) p Local1 +// CHECK-NEXT: (lldb) expression Local1 // CHECK-NEXT: (unsigned int) $17 = 18 -// CHECK-NEXT: (lldb) p Local2 +// CHECK-NEXT: (lldb) expression Local2 // CHECK-NEXT: (char) $18 = 'c' // CHECK-NEXT: (lldb) continue // CHECK-NEXT: Process {{.*}} resuming diff --git a/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest0.script b/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest0.script index d31a2abb68a2f..dcdaa9e1731d2 100644 --- a/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest0.script +++ b/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest0.script @@ -1,7 +1,7 @@ breakpoint set --file ExpressionsTest.cpp --line 19 run -print result -print N0::N1::sum(N0::N1::buf1, sizeof(N0::N1::buf1)) -print N1::sum(N1::buf1, sizeof(N1::buf1)) -print sum(buf1, sizeof(buf1)) -print sum(buf1, 1000000000) +expression result +expression N0::N1::sum(N0::N1::buf1, sizeof(N0::N1::buf1)) +expression N1::sum(N1::buf1, sizeof(N1::buf1)) +expression sum(buf1, sizeof(buf1)) +expression sum(buf1, 1000000000) diff --git a/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest1.script b/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest1.script index dac887faa5bba..d5d6292d3fdb7 100644 --- a/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest1.script +++ b/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest1.script @@ -1 +1 @@ -print sum(buf0, 1) +expression sum(buf0, 1) diff --git a/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest2.script b/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest2.script index b19240baf99da..ce6af93463711 100644 --- a/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest2.script +++ b/lldb/test/Shell/SymbolFile/PDB/Inputs/ExpressionsTest2.script @@ -1,2 +1,2 @@ -print sum(buf0, result - 28) -print sum(buf1 + 3, 3) +expression sum(buf0, result - 28) +expression sum(buf1 + 3, 3) diff --git a/lldb/test/Shell/SymbolFile/PDB/Inputs/VBases.script b/lldb/test/Shell/SymbolFile/PDB/Inputs/VBases.script index 8675890b76e1d..9206ccadafdb9 100644 --- a/lldb/test/Shell/SymbolFile/PDB/Inputs/VBases.script +++ b/lldb/test/Shell/SymbolFile/PDB/Inputs/VBases.script @@ -2,6 +2,6 @@ breakpoint set --file VBases.cpp --line 15 run -print c +expression c -frame variable c \ No newline at end of file +frame variable c diff --git a/lldb/test/Shell/SymbolFile/PDB/expressions.test b/lldb/test/Shell/SymbolFile/PDB/expressions.test index 819e2e180945c..89d7c94e7aa06 100644 --- a/lldb/test/Shell/SymbolFile/PDB/expressions.test +++ b/lldb/test/Shell/SymbolFile/PDB/expressions.test @@ -2,34 +2,34 @@ REQUIRES: system-windows, msvc RUN: %build --compiler=msvc --nodefaultlib --output=%t.exe %S/Inputs/ExpressionsTest.cpp RUN: not %lldb -b -s %S/Inputs/ExpressionsTest0.script -s %S/Inputs/ExpressionsTest1.script -s %S/Inputs/ExpressionsTest2.script -- %t.exe 2>&1 | FileCheck %s -// Check the variable value through `print` -CHECK: (lldb) print result +// Check the variable value through `expression` +CHECK: (lldb) expression result CHECK: (char) $0 = '\x1c' // Call the function just like in the code -CHECK: (lldb) print N0::N1::sum(N0::N1::buf1, sizeof(N0::N1::buf1)) +CHECK: (lldb) expression N0::N1::sum(N0::N1::buf1, sizeof(N0::N1::buf1)) CHECK: (char) $1 = '\x1c' // Try the relaxed namespaces search -CHECK: (lldb) print N1::sum(N1::buf1, sizeof(N1::buf1)) +CHECK: (lldb) expression N1::sum(N1::buf1, sizeof(N1::buf1)) CHECK: (char) $2 = '\x1c' // Try the relaxed variables and functions search -CHECK: (lldb) print sum(buf1, sizeof(buf1)) +CHECK: (lldb) expression sum(buf1, sizeof(buf1)) CHECK: (char) $3 = '\x1c' // Make a crash during expression calculation -CHECK: (lldb) print sum(buf1, 1000000000) +CHECK: (lldb) expression sum(buf1, 1000000000) CHECK: The process has been returned to the state before expression evaluation. // Make one more crash -CHECK: (lldb) print sum(buf0, 1) +CHECK: (lldb) expression sum(buf0, 1) CHECK: The process has been returned to the state before expression evaluation. // Check if the process state was restored succesfully -CHECK: (lldb) print sum(buf0, result - 28) +CHECK: (lldb) expression sum(buf0, result - 28) CHECK: (char) $4 = '\0' // Call the function with arbitrary parameters -CHECK: (lldb) print sum(buf1 + 3, 3) +CHECK: (lldb) expression sum(buf1 + 3, 3) CHECK: (char) $5 = '\f' diff --git a/llvm/docs/CommandGuide/dsymutil.rst b/llvm/docs/CommandGuide/dsymutil.rst index 7ee6566cad421..d3ae16d03679e 100644 --- a/llvm/docs/CommandGuide/dsymutil.rst +++ b/llvm/docs/CommandGuide/dsymutil.rst @@ -37,6 +37,10 @@ OPTIONS Dump the *executable*'s debug-map (the list of the object files containing the debug information) in YAML format and exit. No DWARF link will take place. +.. option:: --fat64 + + Use a 64-bit header when emitting universal binaries. + .. option:: --flat, -f Produce a flat dSYM file. A ``.dwarf`` extension will be appended to the diff --git a/llvm/include/llvm/IR/DebugInfoFlags.def b/llvm/include/llvm/IR/DebugInfoFlags.def index df375b6c68e81..6e9be38e7272e 100644 --- a/llvm/include/llvm/IR/DebugInfoFlags.def +++ b/llvm/include/llvm/IR/DebugInfoFlags.def @@ -91,11 +91,12 @@ HANDLE_DISP_FLAG((1u << 8), MainSubprogram) // for defaulted functions HANDLE_DISP_FLAG((1u << 9), Deleted) HANDLE_DISP_FLAG((1u << 11), ObjCDirect) +HANDLE_DISP_FLAG((1u << 12), IsTransparentStepping) #ifdef DISP_FLAG_LARGEST_NEEDED // Intended to be used with ADT/BitmaskEnum.h. // NOTE: Always must be equal to largest flag, check this when adding new flags. -HANDLE_DISP_FLAG((1 << 11), Largest) +HANDLE_DISP_FLAG((1 << 12), Largest) #undef DISP_FLAG_LARGEST_NEEDED #endif diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index b8f10fa31c7b0..e4392bc286697 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2025,6 +2025,9 @@ class DISubprogram : public DILocalScope { bool isElemental() const { return getSPFlags() & SPFlagElemental; } bool isRecursive() const { return getSPFlags() & SPFlagRecursive; } bool isObjCDirect() const { return getSPFlags() & SPFlagObjCDirect; } + bool getIsTransparentStepping() const { + return getSPFlags() & SPFlagIsTransparentStepping; + } /// Check if this is deleted member function. /// diff --git a/llvm/include/llvm/Support/HashingOutputBackend.h b/llvm/include/llvm/Support/HashingOutputBackend.h new file mode 100644 index 0000000000000..2c760515e99be --- /dev/null +++ b/llvm/include/llvm/Support/HashingOutputBackend.h @@ -0,0 +1,114 @@ +//===- HashingOutputBackends.h - Hashing output backends --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_HASHINGOUTPUTBACKEND_H +#define LLVM_SUPPORT_HASHINGOUTPUTBACKEND_H + +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/HashBuilder.h" +#include "llvm/Support/VirtualOutputBackend.h" +#include "llvm/Support/VirtualOutputConfig.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace vfs { + +/// raw_pwrite_stream that writes to a hasher. +template +class HashingStream : public llvm::raw_pwrite_stream { +private: + SmallVector Buffer; + raw_svector_ostream OS; + + using HashBuilderT = HashBuilder; + HashBuilderT Builder; + + void write_impl(const char *Ptr, size_t Size) override { + OS.write(Ptr, Size); + } + + void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override { + OS.pwrite(Ptr, Size, Offset); + } + + uint64_t current_pos() const override { return OS.str().size(); } + +public: + HashingStream() : OS(Buffer) { SetUnbuffered(); } + + auto final() { + Builder.update(OS.str()); + return Builder.final(); + } +}; + +template class HashingOutputFile; + +/// An output backend that only generates the hash for outputs. +template class HashingOutputBackend : public OutputBackend { +private: + friend class HashingOutputFile; + void addOutputFile(StringRef Path, StringRef Hash) { + OutputHashes[Path] = std::string(Hash); + } + +protected: + IntrusiveRefCntPtr cloneImpl() const override { + return const_cast *>(this); + } + + Expected> + createFileImpl(StringRef Path, Optional Config) override { + return std::make_unique>(Path, *this); + } + +public: + /// Iterator for all the output file names. + auto outputFiles() const { return OutputHashes.keys(); } + + /// Get hash value for the output files in hex representation. + /// Return None if the requested path is not generated. + Optional getHashValueForFile(StringRef Path) { + auto F = OutputHashes.find(Path); + if (F == OutputHashes.end()) + return None; + return toHex(F->second); + } + +private: + StringMap OutputHashes; +}; + +/// HashingOutputFile. +template +class HashingOutputFile final : public OutputFileImpl { +public: + Error keep() override { + auto Result = OS.final(); + Backend.addOutputFile(OutputPath, toStringRef(Result)); + return Error::success(); + } + Error discard() override { return Error::success(); } + raw_pwrite_stream &getOS() override { return OS; } + + HashingOutputFile(StringRef OutputPath, + HashingOutputBackend &Backend) + : OutputPath(OutputPath.str()), Backend(Backend) {} + +private: + const std::string OutputPath; + HashingStream OS; + HashingOutputBackend &Backend; +}; + +} // namespace vfs +} // namespace llvm + +#endif // LLVM_SUPPORT_HASHINGOUTPUTBACKEND_H diff --git a/llvm/include/llvm/Support/ScopedDurationTimer.h b/llvm/include/llvm/Support/ScopedDurationTimer.h index ad704d20b7b66..4f8e90d6ae19b 100644 --- a/llvm/include/llvm/Support/ScopedDurationTimer.h +++ b/llvm/include/llvm/Support/ScopedDurationTimer.h @@ -11,6 +11,7 @@ #include #include +#include namespace llvm { diff --git a/llvm/include/llvm/Support/VirtualOutputConfig.def b/llvm/include/llvm/Support/VirtualOutputConfig.def index bf9159ec22eb8..9b88448887e88 100644 --- a/llvm/include/llvm/Support/VirtualOutputConfig.def +++ b/llvm/include/llvm/Support/VirtualOutputConfig.def @@ -19,5 +19,7 @@ HANDLE_OUTPUT_CONFIG_FLAG(CRLF, false) // OF_CRLF. HANDLE_OUTPUT_CONFIG_FLAG(DiscardOnSignal, true) // E.g., RemoveFileOnSignal. HANDLE_OUTPUT_CONFIG_FLAG(AtomicWrite, true) // E.g., use temporaries. HANDLE_OUTPUT_CONFIG_FLAG(ImplyCreateDirectories, true) +// Skip atomic write if existing file content is the same +HANDLE_OUTPUT_CONFIG_FLAG(OnlyIfDifferent, false) #undef HANDLE_OUTPUT_CONFIG_FLAG diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index 3c9736d382951..4ee848e1713f8 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1362,6 +1362,9 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, if (!SP->getTargetFuncName().empty()) addString(SPDie, dwarf::DW_AT_trampoline, SP->getTargetFuncName()); + if (SP->getIsTransparentStepping()) + addFlag(SPDie, dwarf::DW_AT_trampoline); + if (DD->getDwarfVersion() >= 5 && SP->isDeleted()) addFlag(SPDie, dwarf::DW_AT_deleted); } diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp index 4908b09553825..022f25772811c 100644 --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -2837,8 +2837,9 @@ Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit, bool DWARFLinker::verify(const DWARFFile &File) { assert(File.Dwarf); + raw_ostream &os = Options.Verbose ? errs() : nulls(); DIDumpOptions DumpOpts; - if (!File.Dwarf->verify(llvm::outs(), DumpOpts.noImplicitRecursion())) { + if (!File.Dwarf->verify(os, DumpOpts.noImplicitRecursion())) { reportWarning("input verification failed", File); return false; } diff --git a/llvm/lib/Support/VirtualOutputBackends.cpp b/llvm/lib/Support/VirtualOutputBackends.cpp index 6b90c4db9d5bb..e57282a2973df 100644 --- a/llvm/lib/Support/VirtualOutputBackends.cpp +++ b/llvm/lib/Support/VirtualOutputBackends.cpp @@ -337,6 +337,89 @@ Error OnDiskOutputFile::initializeStream() { return Error::success(); } +namespace { +class OpenFileRAII { + static const int InvalidFd = -1; + +public: + int Fd = InvalidFd; + + ~OpenFileRAII() { + if (Fd != InvalidFd) + llvm::sys::Process::SafelyCloseFileDescriptor(Fd); + } +}; + +enum class FileDifference : uint8_t { + /// The source and destination paths refer to the exact same file. + IdenticalFile, + /// The source and destination paths refer to separate files with identical + /// contents. + SameContents, + /// The source and destination paths refer to separate files with different + /// contents. + DifferentContents +}; +} // end anonymous namespace + +static Expected +areFilesDifferent(const llvm::Twine &Source, const llvm::Twine &Destination) { + if (sys::fs::equivalent(Source, Destination)) + return FileDifference::IdenticalFile; + + OpenFileRAII SourceFile; + sys::fs::file_status SourceStatus; + // If we can't open the source file, fail. + if (std::error_code EC = sys::fs::openFileForRead(Source, SourceFile.Fd)) + return convertToOutputError(Source, EC); + + // If we can't stat the source file, fail. + if (std::error_code EC = sys::fs::status(SourceFile.Fd, SourceStatus)) + return convertToOutputError(Source, EC); + + OpenFileRAII DestFile; + sys::fs::file_status DestStatus; + // If we can't open the destination file, report different. + if (std::error_code Error = + sys::fs::openFileForRead(Destination, DestFile.Fd)) + return FileDifference::DifferentContents; + + // If we can't open the destination file, report different. + if (std::error_code Error = sys::fs::status(DestFile.Fd, DestStatus)) + return FileDifference::DifferentContents; + + // If the files are different sizes, they must be different. + uint64_t Size = SourceStatus.getSize(); + if (Size != DestStatus.getSize()) + return FileDifference::DifferentContents; + + // If both files are zero size, they must be the same. + if (Size == 0) + return FileDifference::SameContents; + + // The two files match in size, so we have to compare the bytes to determine + // if they're the same. + std::error_code SourceRegionErr; + sys::fs::mapped_file_region SourceRegion( + sys::fs::convertFDToNativeFile(SourceFile.Fd), + sys::fs::mapped_file_region::readonly, Size, 0, SourceRegionErr); + if (SourceRegionErr) + return convertToOutputError(Source, SourceRegionErr); + + std::error_code DestRegionErr; + sys::fs::mapped_file_region DestRegion( + sys::fs::convertFDToNativeFile(DestFile.Fd), + sys::fs::mapped_file_region::readonly, Size, 0, DestRegionErr); + + if (DestRegionErr) + return FileDifference::DifferentContents; + + if (memcmp(SourceRegion.const_data(), DestRegion.const_data(), Size) != 0) + return FileDifference::DifferentContents; + + return FileDifference::SameContents; +} + Error OnDiskOutputFile::keep() { // Destroy the streams to flush them. BufferOS.reset(); @@ -351,6 +434,25 @@ Error OnDiskOutputFile::keep() { if (!TempPath) return Error::success(); + if (Config.getOnlyIfDifferent()) { + auto Result = areFilesDifferent(*TempPath, OutputPath); + if (!Result) + return Result.takeError(); + switch (*Result) { + case FileDifference::IdenticalFile: + // Do nothing for a self-move. + return Error::success(); + + case FileDifference::SameContents: + // Files are identical; remove the source file. + (void) sys::fs::remove(*TempPath); + return Error::success(); + + case FileDifference::DifferentContents: + break; // Rename the file. + } + } + // Move temporary to the final output path and remove it if that fails. std::error_code RenameEC = sys::fs::rename(*TempPath, OutputPath); if (!RenameEC) diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp index b6fa3d5d4e543..11987d265efd0 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -1510,7 +1510,8 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, // Space reserved for stack-based arguments when making a (ABI-guaranteed) // tail call. unsigned TailCallArgReserveSize = -X86FI->getTCReturnAddrDelta(); - if (TailCallArgReserveSize && IsWin64Prologue) + if (TailCallArgReserveSize && IsWin64Prologue && + !MF.getFunction().getAttributes().hasAttrSomewhere(Attribute::SwiftAsync)) report_fatal_error("Can't handle guaranteed tail call under win64 yet"); const bool EmitStackProbeCall = diff --git a/llvm/test/Assembler/disubprogram-transparent-stepping.ll b/llvm/test/Assembler/disubprogram-transparent-stepping.ll new file mode 100644 index 0000000000000..51550c5eb1bc2 --- /dev/null +++ b/llvm/test/Assembler/disubprogram-transparent-stepping.ll @@ -0,0 +1,39 @@ +; This test verifies that the DISPFlagIsTransparentStepping attribute in a DISubprogram +; is assembled/disassembled correctly. +; +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s +; +; CHECK: !DISubprogram(name: "baz",{{.*}} DISPFlagIsTransparentStepping +; +; ModuleID = 't.c' +source_filename = "t.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx13.0.0" + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @baz() #0 !dbg !10 { +entry: + ret void, !dbg !14 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6} +!llvm.dbg.cu = !{!7} +!llvm.ident = !{!9} + +!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 2]} +!1 = !{i32 7, !"Dwarf Version", i32 4} +!2 = !{i32 2, !"Debug Info Version", i32 3} +!3 = !{i32 1, !"wchar_size", i32 4} +!4 = !{i32 8, !"PIC Level", i32 2} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{i32 7, !"frame-pointer", i32 1} +!7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !8, producer: "clang version 17.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!8 = !DIFile(filename: "t.c", directory: "/") +!9 = !{!"clang version 17.0.0"} +!10 = distinct !DISubprogram(name: "baz", scope: !8, file: !8, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagIsTransparentStepping, unit: !7, retainedNodes: !13) +!11 = !DISubroutineType(types: !12) +!12 = !{null} +!13 = !{} +!14 = !DILocation(line: 4, column: 1, scope: !10) diff --git a/llvm/test/DebugInfo/AArch64/disubprogram-transparent-stepping.ll b/llvm/test/DebugInfo/AArch64/disubprogram-transparent-stepping.ll new file mode 100644 index 0000000000000..0e93af5b4c728 --- /dev/null +++ b/llvm/test/DebugInfo/AArch64/disubprogram-transparent-stepping.ll @@ -0,0 +1,42 @@ +; This test verifies that the proper DWARF debug info is emitted +; for a trampoline function with no target. +; +; RUN: llc -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s +; +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("baz") +; CHECK: DW_AT_trampoline (true) +; +; ModuleID = 't.c' +source_filename = "t.c" +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx13.0.0" + +; Function Attrs: noinline nounwind optnone ssp uwtable(sync) +define void @baz() #0 !dbg !10 { +entry: + ret void, !dbg !14 +} + +attributes #0 = { noinline nounwind optnone ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } + +!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6} +!llvm.dbg.cu = !{!7} +!llvm.ident = !{!9} + +!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 13, i32 2]} +!1 = !{i32 7, !"Dwarf Version", i32 4} +!2 = !{i32 2, !"Debug Info Version", i32 3} +!3 = !{i32 1, !"wchar_size", i32 4} +!4 = !{i32 8, !"PIC Level", i32 2} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{i32 7, !"frame-pointer", i32 1} +!7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !8, producer: "clang version 17.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!8 = !DIFile(filename: "t.c", directory: "/") +!9 = !{!"clang version 17.0.0"} +!10 = distinct !DISubprogram(name: "baz", scope: !8, file: !8, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagIsTransparentStepping, unit: !7, retainedNodes: !13) +!11 = !DISubroutineType(types: !12) +!12 = !{null} +!13 = !{} +!14 = !DILocation(line: 4, column: 1, scope: !10) + diff --git a/llvm/test/tools/dsymutil/X86/verify.test b/llvm/test/tools/dsymutil/X86/verify.test index eb8aa045c0f7b..2a7b1938e843f 100644 --- a/llvm/test/tools/dsymutil/X86/verify.test +++ b/llvm/test/tools/dsymutil/X86/verify.test @@ -16,7 +16,8 @@ # RUN: dsymutil -verify-dwarf=input -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefix=QUIET-INPUT-FAIL # RUN: dsymutil -verify-dwarf=none -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=QUIET-SUCCESS # RUN: not dsymutil -verify-dwarf=bogus -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=BOGUS -# RUN: not dsymutil -verify-dwarf=all -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=QUIET-OUTPUT-FAIL,QUIET-INPUT-FAIL,VERBOSE-INPUT-FAIL +# RUN: not dsymutil -verify-dwarf=all -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=QUIET-OUTPUT-FAIL,QUIET-INPUT-FAIL +# RUN: not dsymutil -verify-dwarf=all -verbose -oso-prepend-path=%p/../Inputs -y %s -o %t 2>&1 | FileCheck %s --check-prefixes=VERBOSE-INPUT-FAIL # VERBOSE-INPUT-FAIL-DAG: error: Abbreviation declaration contains multiple DW_AT_language attributes. # QUIET-INPUT-FAIL-DAG: warning: input verification failed diff --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test index 03a57f62eedbc..bf256bd4a9b70 100644 --- a/llvm/test/tools/dsymutil/cmdline.test +++ b/llvm/test/tools/dsymutil/cmdline.test @@ -8,6 +8,7 @@ HELP: Dsymutil Options: CHECK: -accelerator CHECK: -arch CHECK: -dump-debug-map +CHECK: -fat64 CHECK: -flat CHECK: -gen-reproducer CHECK: -help diff --git a/llvm/test/tools/dsymutil/fat-header.test b/llvm/test/tools/dsymutil/fat-header.test new file mode 100644 index 0000000000000..91192b2a412f7 --- /dev/null +++ b/llvm/test/tools/dsymutil/fat-header.test @@ -0,0 +1,10 @@ +REQUIRES: system-darwin + +RUN: dsymutil -oso-prepend-path %p %p/Inputs/fat-test.arm.dylib -o %t.fat32.dSYM +RUN: llvm-objdump -m --universal-headers %t.fat32.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s -check-prefixes=FAT32 + +RUN: dsymutil -oso-prepend-path %p %p/Inputs/fat-test.arm.dylib -o %t.fat64.dSYM -fat64 +RUN: llvm-objdump -m --universal-headers %t.fat64.dSYM/Contents/Resources/DWARF/fat-test.arm.dylib | FileCheck %s -check-prefixes=FAT64 + +FAT32: fat_magic FAT_MAGIC +FAT64: fat_magic FAT_MAGIC_64 diff --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h index 03b9a64b6bec5..ac7ccd6c7e529 100644 --- a/llvm/tools/dsymutil/LinkUtils.h +++ b/llvm/tools/dsymutil/LinkUtils.h @@ -49,6 +49,9 @@ struct LinkOptions { /// function. bool KeepFunctionForStatic = false; + /// Use a 64-bit header when emitting universal binaries. + bool Fat64 = false; + /// Number of threads. unsigned Threads = 1; diff --git a/llvm/tools/dsymutil/MachODebugMapParser.cpp b/llvm/tools/dsymutil/MachODebugMapParser.cpp index 955272b72f566..1435bf2914387 100644 --- a/llvm/tools/dsymutil/MachODebugMapParser.cpp +++ b/llvm/tools/dsymutil/MachODebugMapParser.cpp @@ -113,6 +113,8 @@ class MachODebugMapParser { StringRef BinaryPath); void Warning(const Twine &Msg, StringRef File = StringRef()) { + assert(Result && + "The debug map must be initialized before calling this function"); WithColor::warning() << "(" << MachOUtils::getArchName( Result->getTriple().getArchName()) @@ -199,10 +201,9 @@ static std::string getArchName(const object::MachOObjectFile &Obj) { std::unique_ptr MachODebugMapParser::parseOneBinary(const MachOObjectFile &MainBinary, StringRef BinaryPath) { + Result = std::make_unique(MainBinary.getArchTriple(), BinaryPath, + MainBinary.getUuid()); loadMainBinarySymbols(MainBinary); - ArrayRef UUID = MainBinary.getUuid(); - Result = - std::make_unique(MainBinary.getArchTriple(), BinaryPath, UUID); MainBinaryStrings = MainBinary.getStringTableData(); for (const SymbolRef &Symbol : MainBinary.symbols()) { const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); diff --git a/llvm/tools/dsymutil/MachOUtils.cpp b/llvm/tools/dsymutil/MachOUtils.cpp index 3bf455eb4eae6..6fb01f38f5446 100644 --- a/llvm/tools/dsymutil/MachOUtils.cpp +++ b/llvm/tools/dsymutil/MachOUtils.cpp @@ -77,7 +77,8 @@ static bool runLipo(StringRef SDKPath, SmallVectorImpl &Args) { bool generateUniversalBinary(SmallVectorImpl &ArchFiles, StringRef OutputFileName, - const LinkOptions &Options, StringRef SDKPath) { + const LinkOptions &Options, StringRef SDKPath, + bool Fat64) { // No need to merge one file into a universal fat binary. if (ArchFiles.size() == 1) { if (auto E = ArchFiles.front().File->keep(OutputFileName)) { @@ -96,7 +97,7 @@ bool generateUniversalBinary(SmallVectorImpl &ArchFiles, for (auto &Thin : ArchFiles) Args.push_back(Thin.path()); - // Align segments to match dsymutil-classic alignment + // Align segments to match dsymutil-classic alignment. for (auto &Thin : ArchFiles) { Thin.Arch = getArchName(Thin.Arch); Args.push_back("-segalign"); @@ -104,6 +105,10 @@ bool generateUniversalBinary(SmallVectorImpl &ArchFiles, Args.push_back("20"); } + // Use a 64-bit fat header if requested. + if (Fat64) + Args.push_back("-fat64"); + Args.push_back("-output"); Args.push_back(OutputFileName.data()); diff --git a/llvm/tools/dsymutil/MachOUtils.h b/llvm/tools/dsymutil/MachOUtils.h index 8cc4e73e59f14..9d3581348853a 100644 --- a/llvm/tools/dsymutil/MachOUtils.h +++ b/llvm/tools/dsymutil/MachOUtils.h @@ -54,7 +54,7 @@ struct DwarfRelocationApplicationInfo { bool generateUniversalBinary(SmallVectorImpl &ArchFiles, StringRef OutputFileName, const LinkOptions &, - StringRef SDKPath); + StringRef SDKPath, bool Fat64 = false); bool generateDsymCompanion( llvm::IntrusiveRefCntPtr VFS, const DebugMap &DM, SymbolMapTranslator &Translator, MCStreamer &MS, raw_fd_ostream &OutFile, diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td index d500762fc830b..8af6dbef0c3d5 100644 --- a/llvm/tools/dsymutil/Options.td +++ b/llvm/tools/dsymutil/Options.td @@ -91,6 +91,10 @@ def: Flag<["-"], "f">, HelpText<"Alias for --flat">, Group; +def fat64: F<"fat64">, + HelpText<"Use a 64-bit header when emitting universal binaries.">, + Group; + def update: F<"update">, HelpText<"Updates existing dSYM files to contain the latest accelerator tables and other DWARF optimizations.">, Group; diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp index c54287c1e8e9a..9ea8aa0c4512f 100644 --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -297,6 +297,7 @@ static Expected getOptions(opt::InputArgList &Args) { Options.LinkOpts.Update = Args.hasArg(OPT_update); Options.LinkOpts.Verbose = Args.hasArg(OPT_verbose); Options.LinkOpts.Statistics = Args.hasArg(OPT_statistics); + Options.LinkOpts.Fat64 = Args.hasArg(OPT_fat64); Options.LinkOpts.KeepFunctionForStatic = Args.hasArg(OPT_keep_func_for_static); @@ -775,40 +776,47 @@ int dsymutil_main(int argc, char **argv) { return EXIT_FAILURE; if (NeedsTempFiles) { - // Universal Mach-O files can't have an archicture slice that starts - // beyond the 4GB boundary. "lipo" can creeate a 64 bit universal header, - // but not all tools can parse these files so we want to return an error - // if the file can't be encoded as a file with a 32 bit universal header. - // To detect this, we check the size of each architecture's skinny Mach-O - // file and add up the offsets. If they exceed 4GB, then we return an - // error. - - // First we compute the right offset where the first architecture will fit - // followin the 32 bit universal header. The 32 bit universal header - // starts with a uint32_t magic and a uint32_t number of architecture - // infos. Then it is followed by 5 uint32_t values for each architecture. - // So we set the start offset to the right value so we can calculate the - // exact offset that the first architecture slice can start at. - constexpr uint64_t MagicAndCountSize = 2 * 4; - constexpr uint64_t UniversalArchInfoSize = 5 * 4; - uint64_t FileOffset = MagicAndCountSize + - UniversalArchInfoSize * TempFiles.size(); - for (const auto &File: TempFiles) { - ErrorOr stat = Options.LinkOpts.VFS->status(File.path()); - if (!stat) - break; - if (FileOffset > UINT32_MAX) { - WithColor::error() << formatv( - "the universal binary has a slice with a starting offset ({0:x}) " - "that exceeds 4GB and will produce an invalid Mach-O file.", - FileOffset); - return EXIT_FAILURE; + const bool Fat64 = Options.LinkOpts.Fat64; + if (!Fat64) { + // Universal Mach-O files can't have an archicture slice that starts + // beyond the 4GB boundary. "lipo" can create a 64 bit universal + // header, but not all tools can parse these files so we want to return + // an error if the file can't be encoded as a file with a 32 bit + // universal header. To detect this, we check the size of each + // architecture's skinny Mach-O file and add up the offsets. If they + // exceed 4GB, then we return an error. + + // First we compute the right offset where the first architecture will + // fit followin the 32 bit universal header. The 32 bit universal header + // starts with a uint32_t magic and a uint32_t number of architecture + // infos. Then it is followed by 5 uint32_t values for each + // architecture. So we set the start offset to the right value so we can + // calculate the exact offset that the first architecture slice can + // start at. + constexpr uint64_t MagicAndCountSize = 2 * 4; + constexpr uint64_t UniversalArchInfoSize = 5 * 4; + uint64_t FileOffset = + MagicAndCountSize + UniversalArchInfoSize * TempFiles.size(); + for (const auto &File : TempFiles) { + ErrorOr stat = Options.LinkOpts.VFS->status(File.path()); + if (!stat) + break; + if (FileOffset > UINT32_MAX) { + WithColor::error() + << formatv("the universal binary has a slice with a starting " + "offset ({0:x}) that exceeds 4GB and will produce " + "an invalid Mach-O file. Use the -fat64 flag to " + "generate a universal binary with a 64-bit header " + "but note that not all tools support this format.", + FileOffset); + return EXIT_FAILURE; + } + FileOffset += stat->getSize(); } - FileOffset += stat->getSize(); } - if (!MachOUtils::generateUniversalBinary(TempFiles, - OutputLocationOrErr->DWARFFile, - Options.LinkOpts, SDKPath)) + if (!MachOUtils::generateUniversalBinary( + TempFiles, OutputLocationOrErr->DWARFFile, Options.LinkOpts, + SDKPath, Fat64)) return EXIT_FAILURE; } } diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 23d7db2394119..20b9cb3dda008 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -2319,6 +2319,7 @@ TEST_F(DISubprogramTest, get) { assert(!IsLocalToUnit && IsDefinition && !IsOptimized && "bools and SPFlags have to match"); SPFlags |= DISubprogram::SPFlagDefinition; + SPFlags |= DISubprogram::SPFlagIsTransparentStepping; auto *N = DISubprogram::get( Context, Scope, Name, LinkageName, File, Line, Type, ScopeLine, @@ -2402,12 +2403,17 @@ TEST_F(DISubprogramTest, get) { Flags, SPFlags ^ DISubprogram::SPFlagDefinition, Unit, TemplateParams, Declaration, RetainedNodes, ThrownTypes, Annotations, TargetFuncName)); - EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, ScopeLine + 1, ContainingType, - VirtualIndex, ThisAdjustment, Flags, SPFlags, - Unit, TemplateParams, Declaration, - RetainedNodes, ThrownTypes, Annotations, - TargetFuncName)); + EXPECT_NE(N, DISubprogram::get( + Context, Scope, Name, LinkageName, File, Line, Type, + ScopeLine, ContainingType, VirtualIndex, ThisAdjustment, + Flags, SPFlags ^ DISubprogram::SPFlagIsTransparentStepping, + Unit, TemplateParams, Declaration, RetainedNodes, + ThrownTypes, Annotations, TargetFuncName)); + EXPECT_NE(N, DISubprogram::get( + Context, Scope, Name, LinkageName, File, Line, Type, + ScopeLine + 1, ContainingType, VirtualIndex, ThisAdjustment, + Flags, SPFlags, Unit, TemplateParams, Declaration, + RetainedNodes, ThrownTypes, Annotations, TargetFuncName)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, Type, ScopeLine, getCompositeType(), VirtualIndex, ThisAdjustment, Flags, SPFlags, diff --git a/llvm/unittests/Support/VirtualOutputBackendsTest.cpp b/llvm/unittests/Support/VirtualOutputBackendsTest.cpp index 1055f448a349c..60c6c458c15fc 100644 --- a/llvm/unittests/Support/VirtualOutputBackendsTest.cpp +++ b/llvm/unittests/Support/VirtualOutputBackendsTest.cpp @@ -8,6 +8,8 @@ #include "llvm/Support/VirtualOutputBackends.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Support/BLAKE3.h" +#include "llvm/Support/HashingOutputBackend.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" @@ -765,4 +767,77 @@ TEST(VirtualOutputBackendAdaptors, makeMirroringOutputBackendCreateError) { FailedWithMessage(Error1->Msg)); } +TEST(OnDiskBackendTest, OnlyIfDifferent) { + OnDiskOutputBackendProvider Provider; + auto Backend = Provider.createBackend(); + std::string FilePath = Provider.getFilePathToCreate(); + StringRef Data = "some data"; + OutputConfig Config = OutputConfig().setOnlyIfDifferent(); + + OutputFile O1, O2, O3; + sys::fs::file_status Status1, Status2, Status3; + // Write first file. + EXPECT_THAT_ERROR(Backend->createFile(FilePath, Config).moveInto(O1), + Succeeded()); + O1 << Data; + EXPECT_THAT_ERROR(O1.keep(), Succeeded()); + EXPECT_FALSE(O1.isOpen()); + EXPECT_FALSE(sys::fs::status(FilePath, Status1, /*follow=*/false)); + + // Write second with same content. + EXPECT_THAT_ERROR(Backend->createFile(FilePath, Config).moveInto(O2), + Succeeded()); + O2 << Data; + EXPECT_THAT_ERROR(O2.keep(), Succeeded()); + EXPECT_FALSE(O2.isOpen()); + EXPECT_FALSE(sys::fs::status(FilePath, Status2, /*follow=*/false)); + + // Make sure the output path file is not modified with same content. + EXPECT_EQ(Status1.getUniqueID(), Status2.getUniqueID()); + + // Write third with different content. + EXPECT_THAT_ERROR(Backend->createFile(FilePath, Config).moveInto(O3), + Succeeded()); + O3 << Data << "\n"; + EXPECT_THAT_ERROR(O3.keep(), Succeeded()); + EXPECT_FALSE(O3.isOpen()); + EXPECT_FALSE(sys::fs::status(FilePath, Status3, /*follow=*/false)); + + // This should overwrite the file and create a different UniqueID. + EXPECT_NE(Status1.getUniqueID(), Status3.getUniqueID()); +} + +TEST(HashingBackendTest, HashOutput) { + HashingOutputBackend Backend; + OutputFile O1, O2, O3, O4, O5; + EXPECT_THAT_ERROR(Backend.createFile("file1").moveInto(O1), Succeeded()); + O1 << "some data"; + EXPECT_THAT_ERROR(O1.keep(), Succeeded()); + EXPECT_THAT_ERROR(Backend.createFile("file2").moveInto(O2), Succeeded()); + O2 << "some data"; + EXPECT_THAT_ERROR(O2.keep(), Succeeded()); + EXPECT_EQ(Backend.getHashValueForFile("file1"), + Backend.getHashValueForFile("file2")); + + EXPECT_THAT_ERROR(Backend.createFile("file3").moveInto(O3), Succeeded()); + O3 << "some "; + O3 << "data"; + EXPECT_THAT_ERROR(O3.keep(), Succeeded()); + EXPECT_EQ(Backend.getHashValueForFile("file1"), + Backend.getHashValueForFile("file3")); + + EXPECT_THAT_ERROR(Backend.createFile("file4").moveInto(O4), Succeeded()); + O4 << "same data"; + O4.getOS().pwrite("o", 1, 1); + EXPECT_THAT_ERROR(O4.keep(), Succeeded()); + EXPECT_EQ(Backend.getHashValueForFile("file1"), + Backend.getHashValueForFile("file4")); + + EXPECT_THAT_ERROR(Backend.createFile("file5").moveInto(O5), Succeeded()); + O5 << "different data"; + EXPECT_THAT_ERROR(O5.keep(), Succeeded()); + EXPECT_NE(Backend.getHashValueForFile("file1"), + Backend.getHashValueForFile("file5")); +} + } // end namespace diff --git a/llvm/unittests/Support/VirtualOutputConfigTest.cpp b/llvm/unittests/Support/VirtualOutputConfigTest.cpp index 11e0935e9e25a..f5545c10ec752 100644 --- a/llvm/unittests/Support/VirtualOutputConfigTest.cpp +++ b/llvm/unittests/Support/VirtualOutputConfigTest.cpp @@ -22,6 +22,7 @@ TEST(VirtualOutputConfigTest, construct) { EXPECT_TRUE(OutputConfig().getDiscardOnSignal()); EXPECT_TRUE(OutputConfig().getAtomicWrite()); EXPECT_TRUE(OutputConfig().getImplyCreateDirectories()); + EXPECT_FALSE(OutputConfig().getOnlyIfDifferent()); // Test inverted defaults. EXPECT_TRUE(OutputConfig().getNoText()); @@ -29,6 +30,7 @@ TEST(VirtualOutputConfigTest, construct) { EXPECT_FALSE(OutputConfig().getNoDiscardOnSignal()); EXPECT_FALSE(OutputConfig().getNoAtomicWrite()); EXPECT_FALSE(OutputConfig().getNoImplyCreateDirectories()); + EXPECT_TRUE(OutputConfig().getNoOnlyIfDifferent()); } TEST(VirtualOutputConfigTest, set) {