diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:51:52 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:51:52 +0000 |
commit | 5f29bb8a675e8f96452b632e7129113f7dec850e (patch) | |
tree | 3d3f2a0d3ad10872a4dcaba8ec8d1d20c87ab147 /source/Plugins/ExpressionParser | |
parent | 88c643b6fec27eec436c8d138fee6346e92337d6 (diff) |
Notes
Diffstat (limited to 'source/Plugins/ExpressionParser')
37 files changed, 3236 insertions, 1304 deletions
diff --git a/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp b/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp index 0d619e4174e0..369f88327dd9 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp +++ b/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp @@ -1,9 +1,8 @@ //===-- ASTDumper.cpp -------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -86,7 +85,7 @@ void ASTDumper::ToLog(Log *log, const char *prefix) { memcpy(str, m_dump.c_str(), len); - char *end = NULL; + char *end = nullptr; end = strchr(str, '\n'); diff --git a/source/Plugins/ExpressionParser/Clang/ASTDumper.h b/source/Plugins/ExpressionParser/Clang/ASTDumper.h index 58ba19739e5b..ddf055d9c0c3 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTDumper.h +++ b/source/Plugins/ExpressionParser/Clang/ASTDumper.h @@ -1,9 +1,8 @@ //===-- ASTDumper.h ---------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index c2bc18a04e95..526ef90782ef 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -1,9 +1,8 @@ //===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -35,8 +34,9 @@ using namespace lldb_private; ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough, bool top_level, Target &target) - : m_ast_context(NULL), m_passthrough(passthrough), m_passthrough_sema(NULL), - m_target(target), m_sema(NULL), m_top_level(top_level) { + : m_ast_context(nullptr), m_passthrough(passthrough), + m_passthrough_sema(nullptr), m_target(target), m_sema(nullptr), + m_top_level(top_level) { if (!m_passthrough) return; @@ -239,7 +239,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, break; last_expr = implicit_cast->getSubExpr(); - } while (0); + } while (false); // is_lvalue is used to record whether the expression returns an assignable // Lvalue or an Rvalue. This is relevant because they are handled @@ -312,7 +312,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, (is_lvalue ? "lvalue" : "rvalue"), s.c_str()); } - clang::VarDecl *result_decl = NULL; + clang::VarDecl *result_decl = nullptr; if (is_lvalue) { IdentifierInfo *result_ptr_id; @@ -330,14 +330,14 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, QualType ptr_qual_type; - if (expr_qual_type->getAs<ObjCObjectType>() != NULL) + if (expr_qual_type->getAs<ObjCObjectType>() != nullptr) ptr_qual_type = Ctx.getObjCObjectPointerType(expr_qual_type); else ptr_qual_type = Ctx.getPointerType(expr_qual_type); result_decl = VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), - result_ptr_id, ptr_qual_type, NULL, SC_Static); + result_ptr_id, ptr_qual_type, nullptr, SC_Static); if (!result_decl) return false; @@ -351,8 +351,9 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, } else { IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result"); - result_decl = VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), - &result_id, expr_qual_type, NULL, SC_Static); + result_decl = + VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), &result_id, + expr_qual_type, nullptr, SC_Static); if (!result_decl) return false; @@ -508,7 +509,7 @@ void ASTResultSynthesizer::InitializeSema(Sema &S) { } void ASTResultSynthesizer::ForgetSema() { - m_sema = NULL; + m_sema = nullptr; if (m_passthrough_sema) m_passthrough_sema->ForgetSema(); diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h index 859a1dfa5f73..670ba6dce72e 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h +++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h @@ -1,9 +1,8 @@ //===-- ASTResultSynthesizer.h ----------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -16,8 +15,7 @@ namespace lldb_private { -//---------------------------------------------------------------------- -/// @class ASTResultSynthesizer ASTResultSynthesizer.h +/// \class ASTResultSynthesizer ASTResultSynthesizer.h /// "lldb/Expression/ASTResultSynthesizer.h" Adds a result variable /// declaration to the ASTs for an expression. /// @@ -29,165 +27,126 @@ namespace lldb_private { /// ASTResultSynthesizer's job is to add the variable and its initialization /// to the ASTs for the expression, and it does so by acting as a SemaConsumer /// for Clang. -//---------------------------------------------------------------------- class ASTResultSynthesizer : public clang::SemaConsumer { public: - //---------------------------------------------------------------------- /// Constructor /// - /// @param[in] passthrough + /// \param[in] passthrough /// Since the ASTs must typically go through to the Clang code generator /// in order to produce LLVM IR, this SemaConsumer must allow them to /// pass to the next step in the chain after processing. Passthrough is /// the next ASTConsumer, or NULL if none is required. /// - /// @param[in] top_level + /// \param[in] top_level /// If true, register all top-level Decls and don't try to handle the /// main function. /// - /// @param[in] target + /// \param[in] target /// The target, which contains the persistent variable store and the /// AST importer. - //---------------------------------------------------------------------- ASTResultSynthesizer(clang::ASTConsumer *passthrough, bool top_level, Target &target); - //---------------------------------------------------------------------- /// Destructor - //---------------------------------------------------------------------- ~ASTResultSynthesizer() override; - //---------------------------------------------------------------------- /// Link this consumer with a particular AST context /// - /// @param[in] Context + /// \param[in] Context /// This AST context will be used for types and identifiers, and also /// forwarded to the passthrough consumer, if one exists. - //---------------------------------------------------------------------- void Initialize(clang::ASTContext &Context) override; - //---------------------------------------------------------------------- /// Examine a list of Decls to find the function $__lldb_expr and transform /// its code /// - /// @param[in] D + /// \param[in] D /// The list of Decls to search. These may contain LinkageSpecDecls, /// which need to be searched recursively. That job falls to /// TransformTopLevelDecl. - //---------------------------------------------------------------------- bool HandleTopLevelDecl(clang::DeclGroupRef D) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void HandleTranslationUnit(clang::ASTContext &Ctx) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void HandleTagDeclDefinition(clang::TagDecl *D) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void CompleteTentativeDefinition(clang::VarDecl *D) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void HandleVTable(clang::CXXRecordDecl *RD) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void PrintStats() override; - //---------------------------------------------------------------------- /// Set the Sema object to use when performing transforms, and pass it on /// - /// @param[in] S + /// \param[in] S /// The Sema to use. Because Sema isn't externally visible, this class /// casts it to an Action for actual use. - //---------------------------------------------------------------------- void InitializeSema(clang::Sema &S) override; - //---------------------------------------------------------------------- /// Reset the Sema to NULL now that transformations are done - //---------------------------------------------------------------------- void ForgetSema() override; - //---------------------------------------------------------------------- /// The parse has succeeded, so record its persistent decls - //---------------------------------------------------------------------- void CommitPersistentDecls(); private: - //---------------------------------------------------------------------- /// Hunt the given Decl for FunctionDecls named $__lldb_expr, recursing as /// necessary through LinkageSpecDecls, and calling SynthesizeResult on /// anything that was found /// - /// @param[in] D + /// \param[in] D /// The Decl to hunt. - //---------------------------------------------------------------------- void TransformTopLevelDecl(clang::Decl *D); - //---------------------------------------------------------------------- /// Process an Objective-C method and produce the result variable and /// initialization /// - /// @param[in] MethodDecl + /// \param[in] MethodDecl /// The method to process. - //---------------------------------------------------------------------- bool SynthesizeObjCMethodResult(clang::ObjCMethodDecl *MethodDecl); - //---------------------------------------------------------------------- /// Process a function and produce the result variable and initialization /// - /// @param[in] FunDecl + /// \param[in] FunDecl /// The function to process. - //---------------------------------------------------------------------- bool SynthesizeFunctionResult(clang::FunctionDecl *FunDecl); - //---------------------------------------------------------------------- /// Process a function body and produce the result variable and /// initialization /// - /// @param[in] Body + /// \param[in] Body /// The body of the function. /// - /// @param[in] DC + /// \param[in] DC /// The DeclContext of the function, into which the result variable /// is inserted. - //---------------------------------------------------------------------- bool SynthesizeBodyResult(clang::CompoundStmt *Body, clang::DeclContext *DC); - //---------------------------------------------------------------------- /// Given a DeclContext for a function or method, find all types declared in /// the context and record any persistent types found. /// - /// @param[in] FunDeclCtx + /// \param[in] FunDeclCtx /// The context for the function to process. - //---------------------------------------------------------------------- void RecordPersistentTypes(clang::DeclContext *FunDeclCtx); - //---------------------------------------------------------------------- /// Given a TypeDecl, if it declares a type whose name starts with a dollar /// sign, register it as a pointer type in the target's scratch /// AST context. /// - /// @param[in] Body + /// \param[in] Body /// The body of the function. - //---------------------------------------------------------------------- void MaybeRecordPersistentType(clang::TypeDecl *D); - //---------------------------------------------------------------------- /// Given a NamedDecl, register it as a pointer type in the target's scratch /// AST context. /// - /// @param[in] Body + /// \param[in] Body /// The body of the function. - //---------------------------------------------------------------------- void RecordPersistentDecl(clang::NamedDecl *D); clang::ASTContext diff --git a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp index 2faeecdf724e..190eacaa2b62 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp +++ b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp @@ -1,9 +1,8 @@ //===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -30,9 +29,9 @@ using namespace lldb_private; ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough, const char *struct_name, ClangFunctionCaller &function) - : m_ast_context(NULL), m_passthrough(passthrough), m_passthrough_sema(NULL), - m_sema(NULL), m_action(NULL), m_function(function), - m_struct_name(struct_name) { + : m_ast_context(nullptr), m_passthrough(passthrough), + m_passthrough_sema(nullptr), m_sema(nullptr), m_action(nullptr), + m_function(function), m_struct_name(struct_name) { if (!m_passthrough) return; @@ -58,7 +57,7 @@ void ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F) { if (!body_compound_stmt) return; // do we have to handle this? - RecordDecl *struct_decl = NULL; + RecordDecl *struct_decl = nullptr; StringRef desired_name(m_struct_name); @@ -178,8 +177,8 @@ void ASTStructExtractor::InitializeSema(Sema &S) { } void ASTStructExtractor::ForgetSema() { - m_sema = NULL; - m_action = NULL; + m_sema = nullptr; + m_action = nullptr; if (m_passthrough_sema) m_passthrough_sema->ForgetSema(); diff --git a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h index 65f4b00a8651..7aef2e254e1f 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h +++ b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h @@ -1,9 +1,8 @@ //===-- ASTStructExtractor.h ------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -18,8 +17,7 @@ namespace lldb_private { -//---------------------------------------------------------------------- -/// @class ASTStructExtractor ASTStructExtractor.h +/// \class ASTStructExtractor ASTStructExtractor.h /// "lldb/Expression/ASTStructExtractor.h" Extracts and describes the argument /// structure for a wrapped function. /// @@ -33,112 +31,85 @@ namespace lldb_private { /// The definition of this struct is itself in the body of the wrapper /// function, so Clang does the structure layout itself. ASTStructExtractor /// reads through the AST for the wrapper function and finds the struct. -//---------------------------------------------------------------------- class ASTStructExtractor : public clang::SemaConsumer { public: - //---------------------------------------------------------------------- /// Constructor /// - /// @param[in] passthrough + /// \param[in] passthrough /// Since the ASTs must typically go through to the Clang code generator /// in order to produce LLVM IR, this SemaConsumer must allow them to /// pass to the next step in the chain after processing. Passthrough is /// the next ASTConsumer, or NULL if none is required. /// - /// @param[in] struct_name + /// \param[in] struct_name /// The name of the structure to extract from the wrapper function. /// - /// @param[in] function + /// \param[in] function /// The caller object whose members should be populated with information /// about the argument struct. ClangFunctionCaller friends /// ASTStructExtractor /// for this purpose. - //---------------------------------------------------------------------- ASTStructExtractor(clang::ASTConsumer *passthrough, const char *struct_name, ClangFunctionCaller &function); - //---------------------------------------------------------------------- /// Destructor - //---------------------------------------------------------------------- ~ASTStructExtractor() override; - //---------------------------------------------------------------------- /// Link this consumer with a particular AST context /// - /// @param[in] Context + /// \param[in] Context /// This AST context will be used for types and identifiers, and also /// forwarded to the passthrough consumer, if one exists. - //---------------------------------------------------------------------- void Initialize(clang::ASTContext &Context) override; - //---------------------------------------------------------------------- /// Examine a list of Decls to find the function $__lldb_expr and transform /// its code /// - /// @param[in] D + /// \param[in] D /// The list of Decls to search. These may contain LinkageSpecDecls, /// which need to be searched recursively. That job falls to /// TransformTopLevelDecl. - //---------------------------------------------------------------------- bool HandleTopLevelDecl(clang::DeclGroupRef D) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void HandleTranslationUnit(clang::ASTContext &Ctx) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void HandleTagDeclDefinition(clang::TagDecl *D) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void CompleteTentativeDefinition(clang::VarDecl *D) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void HandleVTable(clang::CXXRecordDecl *RD) override; - //---------------------------------------------------------------------- /// Passthrough stub - //---------------------------------------------------------------------- void PrintStats() override; - //---------------------------------------------------------------------- /// Set the Sema object to use when performing transforms, and pass it on /// - /// @param[in] S + /// \param[in] S /// The Sema to use. Because Sema isn't externally visible, this class /// casts it to an Action for actual use. - //---------------------------------------------------------------------- void InitializeSema(clang::Sema &S) override; - //---------------------------------------------------------------------- /// Reset the Sema to NULL now that transformations are done - //---------------------------------------------------------------------- void ForgetSema() override; private: - //---------------------------------------------------------------------- /// Hunt the given FunctionDecl for the argument struct and place /// information about it into m_function /// - /// @param[in] F + /// \param[in] F /// The FunctionDecl to hunt. - //---------------------------------------------------------------------- void ExtractFromFunctionDecl(clang::FunctionDecl *F); - //---------------------------------------------------------------------- /// Hunt the given Decl for FunctionDecls named the same as the wrapper /// function name, recursing as necessary through LinkageSpecDecls, and /// calling ExtractFromFunctionDecl on anything that was found /// - /// @param[in] D + /// \param[in] D /// The Decl to hunt. - //---------------------------------------------------------------------- void ExtractFromTopLevelDecl(clang::Decl *D); clang::ASTContext diff --git a/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp b/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp new file mode 100644 index 000000000000..bbdf4e31c5a4 --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp @@ -0,0 +1,26 @@ +//===-- ASTUtils.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 +// +//===----------------------------------------------------------------------===// + +#include "ASTUtils.h" + +lldb_private::ExternalASTSourceWrapper::~ExternalASTSourceWrapper() {} + +void lldb_private::ExternalASTSourceWrapper::PrintStats() { + m_Source->PrintStats(); +} + +lldb_private::ASTConsumerForwarder::~ASTConsumerForwarder() {} + +void lldb_private::ASTConsumerForwarder::PrintStats() { m_c->PrintStats(); } + +lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() {} + +void lldb_private::SemaSourceWithPriorities::PrintStats() { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->PrintStats(); +} diff --git a/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/source/Plugins/ExpressionParser/Clang/ASTUtils.h new file mode 100644 index 000000000000..d429e8c3855f --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/ASTUtils.h @@ -0,0 +1,579 @@ +//===-- ASTUtils.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 liblldb_ASTUtils_h_ +#define liblldb_ASTUtils_h_ + +#include "clang/Sema/Lookup.h" +#include "clang/Sema/MultiplexExternalSemaSource.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaConsumer.h" + +namespace lldb_private { + +/// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take +/// ownership of the provided source. +class ExternalASTSourceWrapper : public clang::ExternalSemaSource { + ExternalASTSource *m_Source; + +public: + ExternalASTSourceWrapper(ExternalASTSource *Source) : m_Source(Source) { + assert(m_Source && "Can't wrap nullptr ExternalASTSource"); + } + + ~ExternalASTSourceWrapper() override; + + clang::Decl *GetExternalDecl(uint32_t ID) override { + return m_Source->GetExternalDecl(ID); + } + + clang::Selector GetExternalSelector(uint32_t ID) override { + return m_Source->GetExternalSelector(ID); + } + + uint32_t GetNumExternalSelectors() override { + return m_Source->GetNumExternalSelectors(); + } + + clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override { + return m_Source->GetExternalDeclStmt(Offset); + } + + clang::CXXCtorInitializer ** + GetExternalCXXCtorInitializers(uint64_t Offset) override { + return m_Source->GetExternalCXXCtorInitializers(Offset); + } + + clang::CXXBaseSpecifier * + GetExternalCXXBaseSpecifiers(uint64_t Offset) override { + return m_Source->GetExternalCXXBaseSpecifiers(Offset); + } + + void updateOutOfDateIdentifier(clang::IdentifierInfo &II) override { + m_Source->updateOutOfDateIdentifier(II); + } + + bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC, + clang::DeclarationName Name) override { + return m_Source->FindExternalVisibleDeclsByName(DC, Name); + } + + void completeVisibleDeclsMap(const clang::DeclContext *DC) override { + m_Source->completeVisibleDeclsMap(DC); + } + + clang::Module *getModule(unsigned ID) override { + return m_Source->getModule(ID); + } + + llvm::Optional<ASTSourceDescriptor> + getSourceDescriptor(unsigned ID) override { + return m_Source->getSourceDescriptor(ID); + } + + ExtKind hasExternalDefinitions(const clang::Decl *D) override { + return m_Source->hasExternalDefinitions(D); + } + + void FindExternalLexicalDecls( + const clang::DeclContext *DC, + llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant, + llvm::SmallVectorImpl<clang::Decl *> &Result) override { + m_Source->FindExternalLexicalDecls(DC, IsKindWeWant, Result); + } + + void + FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length, + llvm::SmallVectorImpl<clang::Decl *> &Decls) override { + m_Source->FindFileRegionDecls(File, Offset, Length, Decls); + } + + void CompleteRedeclChain(const clang::Decl *D) override { + m_Source->CompleteRedeclChain(D); + } + + void CompleteType(clang::TagDecl *Tag) override { + m_Source->CompleteType(Tag); + } + + void CompleteType(clang::ObjCInterfaceDecl *Class) override { + m_Source->CompleteType(Class); + } + + void ReadComments() override { m_Source->ReadComments(); } + + void StartedDeserializing() override { m_Source->StartedDeserializing(); } + + void FinishedDeserializing() override { m_Source->FinishedDeserializing(); } + + void StartTranslationUnit(clang::ASTConsumer *Consumer) override { + m_Source->StartTranslationUnit(Consumer); + } + + void PrintStats() override; + + bool layoutRecordType( + const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &BaseOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &VirtualBaseOffsets) override { + return m_Source->layoutRecordType(Record, Size, Alignment, FieldOffsets, + BaseOffsets, VirtualBaseOffsets); + } +}; + +/// Wraps an ASTConsumer into an SemaConsumer. Doesn't take ownership of the +/// provided consumer. If the provided ASTConsumer is also a SemaConsumer, +/// the wrapper will also forward SemaConsumer functions. +class ASTConsumerForwarder : public clang::SemaConsumer { + clang::ASTConsumer *m_c; + clang::SemaConsumer *m_sc; + +public: + ASTConsumerForwarder(clang::ASTConsumer *c) : m_c(c) { + m_sc = llvm::dyn_cast<clang::SemaConsumer>(m_c); + } + + ~ASTConsumerForwarder() override; + + void Initialize(clang::ASTContext &Context) override { + m_c->Initialize(Context); + } + + bool HandleTopLevelDecl(clang::DeclGroupRef D) override { + return m_c->HandleTopLevelDecl(D); + } + + void HandleInlineFunctionDefinition(clang::FunctionDecl *D) override { + m_c->HandleInlineFunctionDefinition(D); + } + + void HandleInterestingDecl(clang::DeclGroupRef D) override { + m_c->HandleInterestingDecl(D); + } + + void HandleTranslationUnit(clang::ASTContext &Ctx) override { + m_c->HandleTranslationUnit(Ctx); + } + + void HandleTagDeclDefinition(clang::TagDecl *D) override { + m_c->HandleTagDeclDefinition(D); + } + + void HandleTagDeclRequiredDefinition(const clang::TagDecl *D) override { + m_c->HandleTagDeclRequiredDefinition(D); + } + + void HandleCXXImplicitFunctionInstantiation(clang::FunctionDecl *D) override { + m_c->HandleCXXImplicitFunctionInstantiation(D); + } + + void HandleTopLevelDeclInObjCContainer(clang::DeclGroupRef D) override { + m_c->HandleTopLevelDeclInObjCContainer(D); + } + + void HandleImplicitImportDecl(clang::ImportDecl *D) override { + m_c->HandleImplicitImportDecl(D); + } + + void CompleteTentativeDefinition(clang::VarDecl *D) override { + m_c->CompleteTentativeDefinition(D); + } + + void AssignInheritanceModel(clang::CXXRecordDecl *RD) override { + m_c->AssignInheritanceModel(RD); + } + + void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *D) override { + m_c->HandleCXXStaticMemberVarInstantiation(D); + } + + void HandleVTable(clang::CXXRecordDecl *RD) override { + m_c->HandleVTable(RD); + } + + clang::ASTMutationListener *GetASTMutationListener() override { + return m_c->GetASTMutationListener(); + } + + clang::ASTDeserializationListener *GetASTDeserializationListener() override { + return m_c->GetASTDeserializationListener(); + } + + void PrintStats() override; + + void InitializeSema(clang::Sema &S) override { + if (m_sc) + m_sc->InitializeSema(S); + } + + /// Inform the semantic consumer that Sema is no longer available. + void ForgetSema() override { + if (m_sc) + m_sc->ForgetSema(); + } + + bool shouldSkipFunctionBody(clang::Decl *D) override { + return m_c->shouldSkipFunctionBody(D); + } +}; + +/// A ExternalSemaSource multiplexer that prioritizes its sources. +/// +/// This ExternalSemaSource will forward all requests to its attached sources. +/// However, unlike a normal multiplexer it will not forward a request to all +/// sources, but instead give priority to certain sources. If a source with a +/// higher priority can fulfill a request, all sources with a lower priority +/// will not receive the request. +/// +/// This class is mostly use to multiplex between sources of different +/// 'quality', e.g. a C++ modules and debug information. The C++ module will +/// provide more accurate replies to the requests, but might not be able to +/// answer all requests. The debug information will be used as a fallback then +/// to provide information that is not in the C++ module. +class SemaSourceWithPriorities : public clang::ExternalSemaSource { + +private: + /// The sources ordered in decreasing priority. + llvm::SmallVector<clang::ExternalSemaSource *, 2> Sources; + +public: + /// Construct a SemaSourceWithPriorities with a 'high quality' source that + /// has the higher priority and a 'low quality' source that will be used + /// as a fallback. + SemaSourceWithPriorities(clang::ExternalSemaSource &high_quality_source, + clang::ExternalSemaSource &low_quality_source) { + Sources.push_back(&high_quality_source); + Sources.push_back(&low_quality_source); + } + + ~SemaSourceWithPriorities() override; + + void addSource(clang::ExternalSemaSource &source) { + Sources.push_back(&source); + } + + //===--------------------------------------------------------------------===// + // ExternalASTSource. + //===--------------------------------------------------------------------===// + + clang::Decl *GetExternalDecl(uint32_t ID) override { + for (size_t i = 0; i < Sources.size(); ++i) + if (clang::Decl *Result = Sources[i]->GetExternalDecl(ID)) + return Result; + return nullptr; + } + + void CompleteRedeclChain(const clang::Decl *D) override { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->CompleteRedeclChain(D); + } + + clang::Selector GetExternalSelector(uint32_t ID) override { + clang::Selector Sel; + for (size_t i = 0; i < Sources.size(); ++i) { + Sel = Sources[i]->GetExternalSelector(ID); + if (!Sel.isNull()) + return Sel; + } + return Sel; + } + + uint32_t GetNumExternalSelectors() override { + for (size_t i = 0; i < Sources.size(); ++i) + if (uint32_t total = Sources[i]->GetNumExternalSelectors()) + return total; + return 0; + } + + clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override { + for (size_t i = 0; i < Sources.size(); ++i) + if (clang::Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset)) + return Result; + return nullptr; + } + + clang::CXXBaseSpecifier * + GetExternalCXXBaseSpecifiers(uint64_t Offset) override { + for (size_t i = 0; i < Sources.size(); ++i) + if (clang::CXXBaseSpecifier *R = + Sources[i]->GetExternalCXXBaseSpecifiers(Offset)) + return R; + return nullptr; + } + + clang::CXXCtorInitializer ** + GetExternalCXXCtorInitializers(uint64_t Offset) override { + for (auto *S : Sources) + if (auto *R = S->GetExternalCXXCtorInitializers(Offset)) + return R; + return nullptr; + } + + ExtKind hasExternalDefinitions(const clang::Decl *D) override { + for (const auto &S : Sources) + if (auto EK = S->hasExternalDefinitions(D)) + if (EK != EK_ReplyHazy) + return EK; + return EK_ReplyHazy; + } + + bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC, + clang::DeclarationName Name) override { + for (size_t i = 0; i < Sources.size(); ++i) + if (Sources[i]->FindExternalVisibleDeclsByName(DC, Name)) + return true; + return false; + } + + void completeVisibleDeclsMap(const clang::DeclContext *DC) override { + // FIXME: Only one source should be able to complete the decls map. + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->completeVisibleDeclsMap(DC); + } + + void FindExternalLexicalDecls( + const clang::DeclContext *DC, + llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant, + llvm::SmallVectorImpl<clang::Decl *> &Result) override { + for (size_t i = 0; i < Sources.size(); ++i) { + Sources[i]->FindExternalLexicalDecls(DC, IsKindWeWant, Result); + if (!Result.empty()) + return; + } + } + + void + FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length, + llvm::SmallVectorImpl<clang::Decl *> &Decls) override { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->FindFileRegionDecls(File, Offset, Length, Decls); + } + + void CompleteType(clang::TagDecl *Tag) override { + while (!Tag->isCompleteDefinition()) + for (size_t i = 0; i < Sources.size(); ++i) { + // FIXME: We are technically supposed to loop here too until + // Tag->isCompleteDefinition() is true, but if our low quality source + // is failing to complete the tag this code will deadlock. + Sources[i]->CompleteType(Tag); + if (Tag->isCompleteDefinition()) + break; + } + } + + void CompleteType(clang::ObjCInterfaceDecl *Class) override { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->CompleteType(Class); + } + + void ReadComments() override { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadComments(); + } + + void StartedDeserializing() override { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->StartedDeserializing(); + } + + void FinishedDeserializing() override { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->FinishedDeserializing(); + } + + void StartTranslationUnit(clang::ASTConsumer *Consumer) override { + for (size_t i = 0; i < Sources.size(); ++i) + Sources[i]->StartTranslationUnit(Consumer); + } + + void PrintStats() override; + + clang::Module *getModule(unsigned ID) override { + for (size_t i = 0; i < Sources.size(); ++i) + if (auto M = Sources[i]->getModule(ID)) + return M; + return nullptr; + } + + bool DeclIsFromPCHWithObjectFile(const clang::Decl *D) override { + for (auto *S : Sources) + if (S->DeclIsFromPCHWithObjectFile(D)) + return true; + return false; + } + + bool layoutRecordType( + const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &BaseOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &VirtualBaseOffsets) override { + for (size_t i = 0; i < Sources.size(); ++i) + if (Sources[i]->layoutRecordType(Record, Size, Alignment, FieldOffsets, + BaseOffsets, VirtualBaseOffsets)) + return true; + return false; + } + + void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override { + for (auto &Source : Sources) + Source->getMemoryBufferSizes(sizes); + } + + //===--------------------------------------------------------------------===// + // ExternalSemaSource. + //===--------------------------------------------------------------------===// + + void InitializeSema(clang::Sema &S) override { + for (auto &Source : Sources) + Source->InitializeSema(S); + } + + void ForgetSema() override { + for (auto &Source : Sources) + Source->ForgetSema(); + } + + void ReadMethodPool(clang::Selector Sel) override { + for (auto &Source : Sources) + Source->ReadMethodPool(Sel); + } + + void updateOutOfDateSelector(clang::Selector Sel) override { + for (auto &Source : Sources) + Source->updateOutOfDateSelector(Sel); + } + + void ReadKnownNamespaces( + llvm::SmallVectorImpl<clang::NamespaceDecl *> &Namespaces) override { + for (auto &Source : Sources) + Source->ReadKnownNamespaces(Namespaces); + } + + void ReadUndefinedButUsed( + llvm::MapVector<clang::NamedDecl *, clang::SourceLocation> &Undefined) + override { + for (auto &Source : Sources) + Source->ReadUndefinedButUsed(Undefined); + } + + void ReadMismatchingDeleteExpressions( + llvm::MapVector<clang::FieldDecl *, + llvm::SmallVector<std::pair<clang::SourceLocation, bool>, + 4>> &Exprs) override { + for (auto &Source : Sources) + Source->ReadMismatchingDeleteExpressions(Exprs); + } + + bool LookupUnqualified(clang::LookupResult &R, clang::Scope *S) override { + for (auto &Source : Sources) { + Source->LookupUnqualified(R, S); + if (!R.empty()) + break; + } + + return !R.empty(); + } + + void ReadTentativeDefinitions( + llvm::SmallVectorImpl<clang::VarDecl *> &Defs) override { + for (auto &Source : Sources) + Source->ReadTentativeDefinitions(Defs); + } + + void ReadUnusedFileScopedDecls( + llvm::SmallVectorImpl<const clang::DeclaratorDecl *> &Decls) override { + for (auto &Source : Sources) + Source->ReadUnusedFileScopedDecls(Decls); + } + + void ReadDelegatingConstructors( + llvm::SmallVectorImpl<clang::CXXConstructorDecl *> &Decls) override { + for (auto &Source : Sources) + Source->ReadDelegatingConstructors(Decls); + } + + void ReadExtVectorDecls( + llvm::SmallVectorImpl<clang::TypedefNameDecl *> &Decls) override { + for (auto &Source : Sources) + Source->ReadExtVectorDecls(Decls); + } + + void ReadUnusedLocalTypedefNameCandidates( + llvm::SmallSetVector<const clang::TypedefNameDecl *, 4> &Decls) override { + for (auto &Source : Sources) + Source->ReadUnusedLocalTypedefNameCandidates(Decls); + } + + void ReadReferencedSelectors( + llvm::SmallVectorImpl<std::pair<clang::Selector, clang::SourceLocation>> + &Sels) override { + for (auto &Source : Sources) + Source->ReadReferencedSelectors(Sels); + } + + void ReadWeakUndeclaredIdentifiers( + llvm::SmallVectorImpl<std::pair<clang::IdentifierInfo *, clang::WeakInfo>> + &WI) override { + for (auto &Source : Sources) + Source->ReadWeakUndeclaredIdentifiers(WI); + } + + void ReadUsedVTables( + llvm::SmallVectorImpl<clang::ExternalVTableUse> &VTables) override { + for (auto &Source : Sources) + Source->ReadUsedVTables(VTables); + } + + void ReadPendingInstantiations( + llvm::SmallVectorImpl< + std::pair<clang::ValueDecl *, clang::SourceLocation>> &Pending) + override { + for (auto &Source : Sources) + Source->ReadPendingInstantiations(Pending); + } + + void ReadLateParsedTemplates( + llvm::MapVector<const clang::FunctionDecl *, + std::unique_ptr<clang::LateParsedTemplate>> &LPTMap) + override { + for (auto &Source : Sources) + Source->ReadLateParsedTemplates(LPTMap); + } + + clang::TypoCorrection + CorrectTypo(const clang::DeclarationNameInfo &Typo, int LookupKind, + clang::Scope *S, clang::CXXScopeSpec *SS, + clang::CorrectionCandidateCallback &CCC, + clang::DeclContext *MemberContext, bool EnteringContext, + const clang::ObjCObjectPointerType *OPT) override { + for (auto &Source : Sources) { + if (clang::TypoCorrection C = + Source->CorrectTypo(Typo, LookupKind, S, SS, CCC, + MemberContext, EnteringContext, OPT)) + return C; + } + return clang::TypoCorrection(); + } + + bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc, + clang::QualType T) override { + for (auto &Source : Sources) { + if (Source->MaybeDiagnoseMissingCompleteType(Loc, T)) + return true; + } + return false; + } +}; + +} // namespace lldb_private +#endif // liblldb_ASTUtils_h_ diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 84771e59531d..c5778f86bb62 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -1,9 +1,8 @@ //===-- ClangASTSource.cpp ---------------------------------------*- C++-*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -21,21 +20,21 @@ #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TaggedASTType.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Log.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" +#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" + +#include <memory> #include <vector> using namespace clang; using namespace lldb_private; -//------------------------------------------------------------------ // Scoped class that will remove an active lexical decl from the set when it // goes out of scope. -//------------------------------------------------------------------ namespace { class ScopedLexicalDeclEraser { public: @@ -53,7 +52,7 @@ private: ClangASTSource::ClangASTSource(const lldb::TargetSP &target) : m_import_in_progress(false), m_lookups_enabled(false), m_target(target), - m_ast_context(NULL), m_active_lexical_decls(), m_active_lookups() { + m_ast_context(nullptr), m_active_lexical_decls(), m_active_lookups() { if (!target->GetUseModernTypeLookup()) { m_ast_importer_sp = m_target->GetClangASTImporter(); } @@ -92,7 +91,7 @@ void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context, if (!process) break; - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); + ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); if (!language_runtime) break; @@ -103,7 +102,7 @@ void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context, break; sources.push_back(runtime_decl_vendor->GetImporterSource()); - } while (0); + } while (false); do { DeclVendor *modules_decl_vendor = @@ -113,7 +112,7 @@ void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context, break; sources.push_back(modules_decl_vendor->GetImporterSource()); - } while (0); + } while (false); if (!is_shared_context) { // Update the scratch AST context's merger to reflect any new sources we @@ -127,7 +126,9 @@ void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context, sources.push_back({*scratch_ast_context->getASTContext(), *scratch_ast_context->getFileManager(), scratch_ast_context->GetOriginMap()}); - } while (0); + } + while (false) + ; m_merger_up = llvm::make_unique<clang::ExternalASTMerger>(target, sources); @@ -443,8 +444,8 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { return; } - Decl *original_decl = NULL; - ASTContext *original_ctx = NULL; + Decl *original_decl = nullptr; + ASTContext *original_ctx = nullptr; if (m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl, &original_ctx)) { @@ -477,12 +478,12 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface( lldb::ProcessSP process(m_target->GetProcessSP()); if (!process) - return NULL; + return nullptr; - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); + ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); if (!language_runtime) - return NULL; + return nullptr; ConstString class_name(interface_decl->getNameAsString().c_str()); @@ -490,7 +491,7 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface( language_runtime->LookupInCompleteClassCache(class_name)); if (!complete_type_sp) - return NULL; + return nullptr; TypeFromUser complete_type = TypeFromUser(complete_type_sp->GetFullCompilerType()); @@ -498,7 +499,7 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface( complete_type.GetOpaqueQualType(); if (!complete_opaque_type) - return NULL; + return nullptr; const clang::Type *complete_clang_type = QualType::getFromOpaquePtr(complete_opaque_type).getTypePtr(); @@ -506,7 +507,7 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface( dyn_cast<ObjCInterfaceType>(complete_clang_type); if (!complete_interface_type) - return NULL; + return nullptr; ObjCInterfaceDecl *complete_iface_decl(complete_interface_type->getDecl()); @@ -571,8 +572,8 @@ void ClangASTSource::FindExternalLexicalDecls( current_id, static_cast<const void *>(m_ast_context)); } - Decl *original_decl = NULL; - ASTContext *original_ctx = NULL; + Decl *original_decl = nullptr; + ASTContext *original_ctx = nullptr; if (!m_ast_importer_sp->ResolveDeclOrigin(context_decl, &original_decl, &original_ctx)) @@ -611,10 +612,15 @@ void ClangASTSource::FindExternalLexicalDecls( if (!original_decl_context) return; + // Indicates whether we skipped any Decls of the original DeclContext. + bool SkippedDecls = false; for (TagDecl::decl_iterator iter = original_decl_context->decls_begin(); iter != original_decl_context->decls_end(); ++iter) { Decl *decl = *iter; + // The predicate function returns true if the passed declaration kind is + // the one we are looking for. + // See clang::ExternalASTSource::FindExternalLexicalDecls() if (predicate(decl->getKind())) { if (log) { ASTDumper ast_dumper(decl); @@ -639,21 +645,22 @@ void ClangASTSource::FindExternalLexicalDecls( m_ast_importer_sp->RequireCompleteType(copied_field_type); } - - DeclContext *decl_context_non_const = - const_cast<DeclContext *>(decl_context); - - if (copied_decl->getDeclContext() != decl_context) { - if (copied_decl->getDeclContext()->containsDecl(copied_decl)) - copied_decl->getDeclContext()->removeDecl(copied_decl); - copied_decl->setDeclContext(decl_context_non_const); - } - - if (!decl_context_non_const->containsDecl(copied_decl)) - decl_context_non_const->addDeclInternal(copied_decl); + } else { + SkippedDecls = true; } } + // CopyDecl may build a lookup table which may set up ExternalLexicalStorage + // to false. However, since we skipped some of the external Decls we must + // set it back! + if (SkippedDecls) { + decl_context->setHasExternalLexicalStorage(true); + // This sets HasLazyExternalLexicalLookups to true. By setting this bit we + // ensure that the lookup table is rebuilt, which means the external source + // is consulted again when a clang::DeclContext::lookup is called. + const_cast<DeclContext *>(decl_context)->setMustBuildLookupTable(); + } + return; } @@ -708,7 +715,7 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { return; // otherwise we may need to fall back } - context.m_namespace_map.reset(new ClangASTImporter::NamespaceMap); + context.m_namespace_map = std::make_shared<ClangASTImporter::NamespaceMap>(); if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context)) { @@ -763,6 +770,10 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { } } +clang::Sema *ClangASTSource::getSema() { + return ClangASTContext::GetASTContext(m_ast_context)->getSema(); +} + bool ClangASTSource::IgnoreName(const ConstString name, bool ignore_all_dollar_names) { static const ConstString id_name("id"); @@ -932,7 +943,7 @@ void ClangASTSource::FindExternalVisibleDecls( context.m_found.type = true; } } - } while (0); + } while (false); } if (!context.m_found.type) { @@ -946,7 +957,7 @@ void ClangASTSource::FindExternalVisibleDecls( break; ObjCLanguageRuntime *language_runtime( - process->GetObjCLanguageRuntime()); + ObjCLanguageRuntime::Get(*process)); if (!language_runtime) break; @@ -983,17 +994,17 @@ void ClangASTSource::FindExternalVisibleDecls( } context.AddNamedDecl(copied_named_decl); - } while (0); + } while (false); } - } while (0); + } while (false); } template <class D> class TaggedASTDecl { public: - TaggedASTDecl() : decl(NULL) {} + TaggedASTDecl() : decl(nullptr) {} TaggedASTDecl(D *_decl) : decl(_decl) {} - bool IsValid() const { return (decl != NULL); } + bool IsValid() const { return (decl != nullptr); } bool IsInvalid() const { return !IsValid(); } D *operator->() const { return decl; } D *decl; @@ -1026,7 +1037,7 @@ public: template <class D> DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTSource &source) { DeclFromUser<> origin_decl; - source.ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL); + source.ResolveDeclOrigin(this->decl, &origin_decl.decl, nullptr); if (origin_decl.IsInvalid()) return DeclFromUser<D>(); return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl)); @@ -1156,8 +1167,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { return; do { - Decl *original_decl = NULL; - ASTContext *original_ctx = NULL; + Decl *original_decl = nullptr; + ASTContext *original_ctx = nullptr; m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl, &original_ctx); @@ -1171,7 +1182,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (FindObjCMethodDeclsWithOrigin(current_id, context, original_interface_decl, "at origin")) return; // found it, no need to look any further - } while (0); + } while (false); StreamString ss; @@ -1276,7 +1287,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (*cursor == ' ' || *cursor == '(') sc_list.Append(candidate_sc); } - } while (0); + } while (false); if (sc_list.GetSize()) { // We found a good function symbol. Use that. @@ -1359,7 +1370,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { "in debug info"); return; - } while (0); + } while (false); do { // Check the modules only if the debug information didn't have a complete @@ -1386,7 +1397,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { current_id, context, interface_decl_from_modules, "in modules")) return; } - } while (0); + } while (false); do { // Check the runtime only if the debug information didn't have a complete @@ -1397,7 +1408,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (!process) break; - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); + ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); if (!language_runtime) break; @@ -1423,7 +1434,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { FindObjCMethodDeclsWithOrigin(current_id, context, runtime_interface_decl, "in runtime"); - } while (0); + } while (false); } static bool FindObjCPropertyAndIvarDeclsWithOrigin( @@ -1542,7 +1553,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { complete_iface_decl); return; - } while (0); + } while (false); do { // Check the modules only if the debug information didn't have a complete @@ -1578,7 +1589,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, context, *this, interface_decl_from_modules)) return; - } while (0); + } while (false); do { // Check the runtime only if the debug information didn't have a complete @@ -1589,7 +1600,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (!process) return; - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); + ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); if (!language_runtime) return; @@ -1623,7 +1634,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (FindObjCPropertyAndIvarDeclsWithOrigin( current_id, context, *this, interface_decl_from_runtime)) return; - } while (0); + } while (false); } typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap; @@ -1836,7 +1847,7 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, } void ClangASTSource::CompleteNamespaceMap( - ClangASTImporter::NamespaceMapSP &namespace_map, const ConstString &name, + ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name, ClangASTImporter::NamespaceMapSP &parent_map) const { static unsigned int invocation_id = 0; unsigned int current_id = invocation_id++; @@ -1966,7 +1977,14 @@ clang::QualType ClangASTSource::CopyTypeWithMerger( return QualType(); } - return merger.ImporterForOrigin(from_context).Import(type); + if (llvm::Expected<QualType> type_or_error = + merger.ImporterForOrigin(from_context).Import(type)) { + return *type_or_error; + } else { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG_ERROR(log, type_or_error.takeError(), "Couldn't import type: {0}"); + return QualType(); + } } clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) { @@ -1979,7 +1997,16 @@ clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) { return nullptr; } - return m_merger_up->ImporterForOrigin(from_context).Import(src_decl); + if (llvm::Expected<Decl *> decl_or_error = + m_merger_up->ImporterForOrigin(from_context).Import(src_decl)) { + return *decl_or_error; + } else { + Log *log = + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG_ERROR(log, decl_or_error.takeError(), + "Couldn't import decl: {0}"); + return nullptr; + } } else { lldbassert(0 && "No mechanism for copying a decl!"); return nullptr; @@ -2045,12 +2072,12 @@ clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { assert(type && "Type for variable must be valid!"); if (!type.IsValid()) - return NULL; + return nullptr; ClangASTContext *lldb_ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); if (!lldb_ast) - return NULL; + return nullptr; IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo(); @@ -2058,7 +2085,7 @@ clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { clang::NamedDecl *Decl = VarDecl::Create( *ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), - SourceLocation(), ii, ClangUtil::GetQualType(type), 0, SC_Static); + SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static); m_decls.push_back(Decl); return Decl; @@ -2069,15 +2096,15 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, assert(type && "Type for variable must be valid!"); if (!type.IsValid()) - return NULL; + return nullptr; if (m_function_types.count(type)) - return NULL; + return nullptr; ClangASTContext *lldb_ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); if (!lldb_ast) - return NULL; + return nullptr; m_function_types.insert(type); @@ -2106,8 +2133,8 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, clang::FunctionDecl *func_decl = FunctionDecl::Create( *ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, - NULL, SC_Extern, isInlineSpecified, hasWrittenPrototype, - isConstexprSpecified); + nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, + isConstexprSpecified ? CSK_constexpr : CSK_unspecified); // We have to do more than just synthesize the FunctionDecl. We have to // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do @@ -2125,9 +2152,10 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) { QualType arg_qual_type(func_proto_type->getParamType(ArgIndex)); - parm_var_decls.push_back(ParmVarDecl::Create( - *ast, const_cast<DeclContext *>(context), SourceLocation(), - SourceLocation(), NULL, arg_qual_type, NULL, SC_Static, NULL)); + parm_var_decls.push_back( + ParmVarDecl::Create(*ast, const_cast<DeclContext *>(context), + SourceLocation(), SourceLocation(), nullptr, + arg_qual_type, nullptr, SC_Static, nullptr)); } func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls)); @@ -2148,7 +2176,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, ClangASTContext::IsOperator(decl_name.getAsString().c_str(), op_kind)) { if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount( false, op_kind, func_proto_type->getNumParams())) - return NULL; + return nullptr; } m_decls.push_back(func_decl); @@ -2196,7 +2224,7 @@ NameSearchContext::AddTypeDecl(const CompilerType &clang_type) { return (NamedDecl *)interface_decl; } } - return NULL; + return nullptr; } void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) { diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index a42422b0f97f..7a8bacf48a8f 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -1,9 +1,8 @@ //===-- ClangASTSource.h ----------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -23,8 +22,7 @@ namespace lldb_private { -//---------------------------------------------------------------------- -/// @class ClangASTSource ClangASTSource.h "lldb/Expression/ClangASTSource.h" +/// \class ClangASTSource ClangASTSource.h "lldb/Expression/ClangASTSource.h" /// Provider for named objects defined in the debug info for Clang /// /// As Clang parses an expression, it may encounter names that are not defined @@ -32,37 +30,30 @@ namespace lldb_private { /// knows the name it is looking for, but nothing else. The ExternalSemaSource /// class provides Decls (VarDecl, FunDecl, TypeDecl) to Clang for these /// names, consulting the ClangExpressionDeclMap to do the actual lookups. -//---------------------------------------------------------------------- class ClangASTSource : public ClangExternalASTSourceCommon, public ClangASTImporter::MapCompleter { public: - //------------------------------------------------------------------ /// Constructor /// /// Initializes class variables. /// - /// @param[in] target + /// \param[in] target /// A reference to the target containing debug information to use. - //------------------------------------------------------------------ ClangASTSource(const lldb::TargetSP &target); - //------------------------------------------------------------------ /// Destructor - //------------------------------------------------------------------ ~ClangASTSource() override; - //------------------------------------------------------------------ /// Interface stubs. - //------------------------------------------------------------------ - clang::Decl *GetExternalDecl(uint32_t) override { return NULL; } - clang::Stmt *GetExternalDeclStmt(uint64_t) override { return NULL; } + clang::Decl *GetExternalDecl(uint32_t) override { return nullptr; } + clang::Stmt *GetExternalDeclStmt(uint64_t) override { return nullptr; } clang::Selector GetExternalSelector(uint32_t) override { return clang::Selector(); } uint32_t GetNumExternalSelectors() override { return 0; } clang::CXXBaseSpecifier * GetExternalCXXBaseSpecifiers(uint64_t Offset) override { - return NULL; + return nullptr; } void MaterializeVisibleDecls(const clang::DeclContext *DC) { return; } @@ -74,7 +65,6 @@ public: // APIs for ExternalASTSource // - //------------------------------------------------------------------ /// Look up all Decls that match a particular name. Only handles /// Identifiers and DeclContexts that are either NamespaceDecls or /// TranslationUnitDecls. Calls SetExternalVisibleDeclsForName with the @@ -83,69 +73,64 @@ public: /// The work for this function is done by /// void FindExternalVisibleDecls (NameSearchContext &); /// - /// @param[in] DC + /// \param[in] DC /// The DeclContext to register the found Decls in. /// - /// @param[in] Name + /// \param[in] Name /// The name to find entries for. /// - /// @return + /// \return /// Whatever SetExternalVisibleDeclsForName returns. - //------------------------------------------------------------------ bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC, clang::DeclarationName Name) override; - //------------------------------------------------------------------ /// Enumerate all Decls in a given lexical context. /// - /// @param[in] DC + /// \param[in] DC /// The DeclContext being searched. /// - /// @param[in] isKindWeWant + /// \param[in] isKindWeWant /// A callback function that returns true given the /// DeclKinds of desired Decls, and false otherwise. /// - /// @param[in] Decls + /// \param[in] Decls /// A vector that is filled in with matching Decls. - //------------------------------------------------------------------ void FindExternalLexicalDecls( const clang::DeclContext *DC, llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant, llvm::SmallVectorImpl<clang::Decl *> &Decls) override; - //------------------------------------------------------------------ /// Specify the layout of the contents of a RecordDecl. /// - /// @param[in] Record + /// \param[in] Record /// The record (in the parser's AST context) that needs to be /// laid out. /// - /// @param[out] Size + /// \param[out] Size /// The total size of the record in bits. /// - /// @param[out] Alignment + /// \param[out] Alignment /// The alignment of the record in bits. /// - /// @param[in] FieldOffsets + /// \param[in] FieldOffsets /// A map that must be populated with pairs of the record's /// fields (in the parser's AST context) and their offsets /// (measured in bits). /// - /// @param[in] BaseOffsets + /// \param[in] BaseOffsets /// A map that must be populated with pairs of the record's /// C++ concrete base classes (in the parser's AST context, /// and only if the record is a CXXRecordDecl and has base /// classes) and their offsets (measured in bytes). /// - /// @param[in] VirtualBaseOffsets + /// \param[in] VirtualBaseOffsets /// A map that must be populated with pairs of the record's /// C++ virtual base classes (in the parser's AST context, /// and only if the record is a CXXRecordDecl and has base /// classes) and their offsets (measured in bytes). /// - /// @return + /// \return /// True <=> the layout is valid. - //----------------------------------------------------------------- bool layoutRecordType( const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, @@ -154,52 +139,44 @@ public: llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets) override; - //------------------------------------------------------------------ /// Complete a TagDecl. /// - /// @param[in] Tag + /// \param[in] Tag /// The Decl to be completed in place. - //------------------------------------------------------------------ void CompleteType(clang::TagDecl *Tag) override; - //------------------------------------------------------------------ /// Complete an ObjCInterfaceDecl. /// - /// @param[in] Class + /// \param[in] Class /// The Decl to be completed in place. - //------------------------------------------------------------------ void CompleteType(clang::ObjCInterfaceDecl *Class) override; - //------------------------------------------------------------------ /// Called on entering a translation unit. Tells Clang by calling /// setHasExternalVisibleStorage() and setHasExternalLexicalStorage() that /// this object has something to say about undefined names. /// - /// @param[in] ASTConsumer + /// \param[in] ASTConsumer /// Unused. - //------------------------------------------------------------------ void StartTranslationUnit(clang::ASTConsumer *Consumer) override; // // APIs for NamespaceMapCompleter // - //------------------------------------------------------------------ /// Look up the modules containing a given namespace and put the appropriate /// entries in the namespace map. /// - /// @param[in] namespace_map + /// \param[in] namespace_map /// The map to be completed. /// - /// @param[in] name + /// \param[in] name /// The name of the namespace to be found. /// - /// @param[in] parent_map + /// \param[in] parent_map /// The map for the namespace's parent namespace, if there is /// one. - //------------------------------------------------------------------ void CompleteNamespaceMap( - ClangASTImporter::NamespaceMapSP &namespace_map, const ConstString &name, + ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name, ClangASTImporter::NamespaceMapSP &parent_map) const override; // @@ -210,14 +187,14 @@ public: AddNamespace(NameSearchContext &context, ClangASTImporter::NamespaceMapSP &namespace_decls); - //------------------------------------------------------------------ /// The worker function for FindExternalVisibleDeclsByName. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext to use when filing results. - //------------------------------------------------------------------ virtual void FindExternalVisibleDecls(NameSearchContext &context); + clang::Sema *getSema(); + void SetImportInProgress(bool import_in_progress) { m_import_in_progress = import_in_progress; } @@ -228,13 +205,11 @@ public: } bool GetLookupsEnabled() { return m_lookups_enabled; } - //---------------------------------------------------------------------- - /// @class ClangASTSourceProxy ClangASTSource.h + /// \class ClangASTSourceProxy ClangASTSource.h /// "lldb/Expression/ClangASTSource.h" Proxy for ClangASTSource /// /// Clang AST contexts like to own their AST sources, so this is a state- /// free proxy object. - //---------------------------------------------------------------------- class ClangASTSourceProxy : public ClangExternalASTSourceCommon { public: ClangASTSourceProxy(ClangASTSource &original) : m_original(original) {} @@ -295,157 +270,135 @@ public: } protected: - //------------------------------------------------------------------ /// Look for the complete version of an Objective-C interface, and return it /// if found. /// - /// @param[in] interface_decl + /// \param[in] interface_decl /// An ObjCInterfaceDecl that may not be the complete one. /// - /// @return + /// \return /// NULL if the complete interface couldn't be found; /// the complete interface otherwise. - //------------------------------------------------------------------ clang::ObjCInterfaceDecl * GetCompleteObjCInterface(const clang::ObjCInterfaceDecl *interface_decl); - //------------------------------------------------------------------ /// Find all entities matching a given name in a given module, using a /// NameSearchContext to make Decls for them. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// - /// @param[in] module + /// \param[in] module /// If non-NULL, the module to query. /// - /// @param[in] namespace_decl + /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. /// - /// @param[in] current_id + /// \param[in] current_id /// The ID for the current FindExternalVisibleDecls invocation, /// for logging purposes. - //------------------------------------------------------------------ void FindExternalVisibleDecls(NameSearchContext &context, lldb::ModuleSP module, CompilerDeclContext &namespace_decl, unsigned int current_id); - //------------------------------------------------------------------ /// Find all Objective-C methods matching a given selector. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// Its m_decl_name contains the selector and its m_decl_context /// is the containing object. - //------------------------------------------------------------------ void FindObjCMethodDecls(NameSearchContext &context); - //------------------------------------------------------------------ /// Find all Objective-C properties and ivars with a given name. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// Its m_decl_name contains the name and its m_decl_context /// is the containing object. - //------------------------------------------------------------------ void FindObjCPropertyAndIvarDecls(NameSearchContext &context); - //------------------------------------------------------------------ /// A wrapper for ClangASTContext::CopyType that sets a flag that /// indicates that we should not respond to queries during import. /// - /// @param[in] dest_context + /// \param[in] dest_context /// The target AST context, typically the parser's AST context. /// - /// @param[in] source_context + /// \param[in] source_context /// The source AST context, typically the AST context of whatever /// symbol file the type was found in. /// - /// @param[in] src_type + /// \param[in] src_type /// The source type. /// - /// @return + /// \return /// The imported type. - //------------------------------------------------------------------ CompilerType GuardedCopyType(const CompilerType &src_type); public: - //------------------------------------------------------------------ /// Returns true if a name should be ignored by name lookup. /// - /// @param[in] name + /// \param[in] name /// The name to be considered. /// - /// @param[in] ignore_all_dollar_nmmes + /// \param[in] ignore_all_dollar_nmmes /// True if $-names of all sorts should be ignored. /// - /// @return + /// \return /// True if the name is one of a class of names that are ignored by /// global lookup for performance reasons. - //------------------------------------------------------------------ bool IgnoreName(const ConstString name, bool ignore_all_dollar_names); public: - //------------------------------------------------------------------ /// Copies a single Decl into the parser's AST context. /// - /// @param[in] src_decl + /// \param[in] src_decl /// The Decl to copy. /// - /// @return + /// \return /// A copy of the Decl in m_ast_context, or NULL if the copy failed. - //------------------------------------------------------------------ clang::Decl *CopyDecl(clang::Decl *src_decl); - //------------------------------------------------------------------ /// Copies a single Type to the target of the given ExternalASTMerger. /// - /// @param[in] src_context + /// \param[in] src_context /// The ASTContext containing the type. /// - /// @param[in] merger + /// \param[in] merger /// The merger to use. This isn't just *m_merger_up because it might be /// the persistent AST context's merger. /// - /// @param[in] type + /// \param[in] type /// The type to copy. /// - /// @return + /// \return /// A copy of the Type in the merger's target context. - //------------------------------------------------------------------ clang::QualType CopyTypeWithMerger(clang::ASTContext &src_context, clang::ExternalASTMerger &merger, clang::QualType type); - //------------------------------------------------------------------ /// Determined the origin of a single Decl, if it can be found. /// - /// @param[in] decl + /// \param[in] decl /// The Decl whose origin is to be found. /// - /// @param[out] original_decl + /// \param[out] original_decl /// A pointer whose target is filled in with the original Decl. /// - /// @param[in] original_ctx + /// \param[in] original_ctx /// A pointer whose target is filled in with the original's ASTContext. /// - /// @return + /// \return /// True if lookup succeeded; false otherwise. - //------------------------------------------------------------------ bool ResolveDeclOrigin(const clang::Decl *decl, clang::Decl **original_decl, clang::ASTContext **original_ctx); - //------------------------------------------------------------------ /// Returns m_merger_up. Only call this if the target is configured to use /// modern lookup, - //------------------------------------------------------------------ clang::ExternalASTMerger &GetMergerUnchecked(); - //------------------------------------------------------------------ /// Returns true if there is a merger. This only occurs if the target is /// using modern lookup. - //------------------------------------------------------------------ bool HasMerger() { return (bool)m_merger_up; } protected: @@ -471,15 +424,13 @@ protected: std::set<const char *> m_active_lookups; }; -//---------------------------------------------------------------------- -/// @class NameSearchContext ClangASTSource.h +/// \class NameSearchContext ClangASTSource.h /// "lldb/Expression/ClangASTSource.h" Container for all objects relevant to a /// single name lookup /// /// LLDB needs to create Decls for entities it finds. This class communicates /// what name is being searched for and provides helper functions to construct /// Decls given appropriate type information. -//---------------------------------------------------------------------- struct NameSearchContext { ClangASTSource &m_ast_source; ///< The AST source making the request llvm::SmallVectorImpl<clang::NamedDecl *> @@ -504,24 +455,22 @@ struct NameSearchContext { bool type : 1; } m_found; - //------------------------------------------------------------------ /// Constructor /// /// Initializes class variables. /// - /// @param[in] astSource + /// \param[in] astSource /// A reference to the AST source making a request. /// - /// @param[in] decls + /// \param[in] decls /// A reference to a list into which new Decls will be placed. This /// list is typically empty when the function is called. /// - /// @param[in] name + /// \param[in] name /// The name being searched for (always an Identifier). /// - /// @param[in] dc + /// \param[in] dc /// The DeclContext to register Decls in. - //------------------------------------------------------------------ NameSearchContext(ClangASTSource &astSource, llvm::SmallVectorImpl<clang::NamedDecl *> &decls, clang::DeclarationName &name, const clang::DeclContext *dc) @@ -530,59 +479,47 @@ struct NameSearchContext { memset(&m_found, 0, sizeof(m_found)); } - //------------------------------------------------------------------ /// Create a VarDecl with the name being searched for and the provided type /// and register it in the right places. /// - /// @param[in] type + /// \param[in] type /// The opaque QualType for the VarDecl being registered. - //------------------------------------------------------------------ clang::NamedDecl *AddVarDecl(const CompilerType &type); - //------------------------------------------------------------------ /// Create a FunDecl with the name being searched for and the provided type /// and register it in the right places. /// - /// @param[in] type + /// \param[in] type /// The opaque QualType for the FunDecl being registered. /// - /// @param[in] extern_c + /// \param[in] extern_c /// If true, build an extern "C" linkage specification for this. - //------------------------------------------------------------------ clang::NamedDecl *AddFunDecl(const CompilerType &type, bool extern_c = false); - //------------------------------------------------------------------ /// Create a FunDecl with the name being searched for and generic type (i.e. /// intptr_t NAME_GOES_HERE(...)) and register it in the right places. - //------------------------------------------------------------------ clang::NamedDecl *AddGenericFunDecl(); - //------------------------------------------------------------------ /// Create a TypeDecl with the name being searched for and the provided type /// and register it in the right places. /// - /// @param[in] compiler_type + /// \param[in] compiler_type /// The opaque QualType for the TypeDecl being registered. - //------------------------------------------------------------------ clang::NamedDecl *AddTypeDecl(const CompilerType &compiler_type); - //------------------------------------------------------------------ /// Add Decls from the provided DeclContextLookupResult to the list of /// results. /// - /// @param[in] result + /// \param[in] result /// The DeclContextLookupResult, usually returned as the result /// of querying a DeclContext. - //------------------------------------------------------------------ void AddLookupResult(clang::DeclContextLookupResult result); - //------------------------------------------------------------------ /// Add a NamedDecl to the list of results. /// - /// @param[in] decl + /// \param[in] decl /// The NamedDecl, usually returned as the result /// of querying a DeclContext. - //------------------------------------------------------------------ void AddNamedDecl(clang::NamedDecl *decl); }; diff --git a/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h b/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h index 9ea4e3aa7dab..db50c2aa3e90 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h +++ b/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h @@ -1,9 +1,8 @@ //===-- ClangDiagnostic.h ---------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -34,7 +33,7 @@ public: uint32_t compiler_id) : Diagnostic(message, severity, eDiagnosticOriginClang, compiler_id) {} - virtual ~ClangDiagnostic() = default; + ~ClangDiagnostic() override = default; bool HasFixIts() const override { return !m_fixit_vec.empty(); } diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 9c2f8c4b6c92..a49a7029e0d2 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1,9 +1,8 @@ //===-- ClangExpressionDeclMap.cpp -----------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -33,9 +32,7 @@ #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/Variable.h" #include "lldb/Symbol/VariableList.h" -#include "lldb/Target/CPPLanguageRuntime.h" #include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" @@ -54,6 +51,8 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" +#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" using namespace lldb; using namespace lldb_private; @@ -66,10 +65,11 @@ const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars"; ClangExpressionDeclMap::ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, - ExecutionContext &exe_ctx) + ExecutionContext &exe_ctx, ValueObject *ctx_obj) : ClangASTSource(exe_ctx.GetTargetSP()), m_found_entities(), m_struct_members(), m_keep_result_in_memory(keep_result_in_memory), - m_result_delegate(result_delegate), m_parser_vars(), m_struct_vars() { + m_result_delegate(result_delegate), m_ctx_obj(ctx_obj), m_parser_vars(), + m_struct_vars() { EnableStructVars(); } @@ -132,7 +132,7 @@ void ClangExpressionDeclMap::DidParse() { if (log) ClangASTMetrics::DumpCounters(log); - if (m_parser_vars.get()) { + if (m_parser_vars) { for (size_t entity_index = 0, num_entities = m_found_entities.GetSize(); entity_index < num_entities; ++entity_index) { ExpressionVariableSP var_sp( @@ -272,9 +272,15 @@ static clang::QualType ExportAllDeclaredTypes( merger.AddSources(importer_source); clang::ASTImporter &exporter = merger.ImporterForOrigin(source); CompleteAllDeclContexts(exporter, file, root); - clang::QualType ret = exporter.Import(root); + llvm::Expected<clang::QualType> ret_or_error = exporter.Import(root); merger.RemoveSources(importer_source); - return ret; + if (ret_or_error) { + return *ret_or_error; + } else { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG_ERROR(log, ret_or_error.takeError(), "Couldn't import type: {0}"); + return clang::QualType(); + } } TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target, @@ -309,7 +315,7 @@ TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target, } bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, - const ConstString &name, + ConstString name, TypeFromParser parser_type, bool is_result, bool is_lvalue) { @@ -361,7 +367,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; Target *target = exe_ctx.GetTargetPtr(); - if (target == NULL) + if (target == nullptr) return false; ClangASTContext *context(target->GetScratchClangASTContext()); @@ -424,7 +430,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, } bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, - const ConstString &name, + ConstString name, llvm::Value *value, size_t size, lldb::offset_t alignment) { assert(m_struct_vars.get()); @@ -604,7 +610,7 @@ bool ClangExpressionDeclMap::GetFunctionInfo(const NamedDecl *decl, addr_t ClangExpressionDeclMap::GetSymbolAddress(Target &target, Process *process, - const ConstString &name, + ConstString name, lldb::SymbolType symbol_type, lldb_private::Module *module) { SymbolContextList sc_list; @@ -692,7 +698,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(Target &target, } if (symbol_load_addr == LLDB_INVALID_ADDRESS && process) { - ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime(); + ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process); if (runtime) { symbol_load_addr = runtime->LookupRuntimeSymbol(name); @@ -702,7 +708,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(Target &target, return symbol_load_addr; } -addr_t ClangExpressionDeclMap::GetSymbolAddress(const ConstString &name, +addr_t ClangExpressionDeclMap::GetSymbolAddress(ConstString name, lldb::SymbolType symbol_type) { assert(m_parser_vars.get()); @@ -715,7 +721,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(const ConstString &name, } lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( - Target &target, ModuleSP &module, const ConstString &name, + Target &target, ModuleSP &module, ConstString name, CompilerDeclContext *namespace_decl, TypeFromUser *type) { VariableList vars; @@ -921,16 +927,31 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( name.GetCString()); context.AddNamedDecl(parser_named_decl); - } while (0); + } while (false); } if (name.GetCString()[0] == '$' && !namespace_decl) { static ConstString g_lldb_class_name("$__lldb_class"); if (name == g_lldb_class_name) { + if (m_ctx_obj) { + Status status; + lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status); + if (!ctx_obj_ptr || status.Fail()) + return; + + AddThisType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), + current_id); + + m_struct_vars->m_object_pointer_type = + TypeFromUser(ctx_obj_ptr->GetCompilerType()); + + return; + } + // Clang is looking for the type of "this" - if (frame == NULL) + if (frame == nullptr) return; // Find the block that defines the function represented by "sym_ctx" @@ -1020,6 +1041,21 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( static ConstString g_lldb_objc_class_name("$__lldb_objc_class"); if (name == g_lldb_objc_class_name) { + if (m_ctx_obj) { + Status status; + lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status); + if (!ctx_obj_ptr || status.Fail()) + return; + + AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), + current_id); + + m_struct_vars->m_object_pointer_type = + TypeFromUser(ctx_obj_ptr->GetCompilerType()); + + return; + } + // Clang is looking for the type of "*self" if (!frame) @@ -1241,7 +1277,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( } } if (target) { - var = FindGlobalVariable(*target, module_sp, name, &namespace_decl, NULL); + var = FindGlobalVariable(*target, module_sp, name, &namespace_decl, + nullptr); if (var) { valobj = ValueObjectVariable::Create(target, var); @@ -1398,8 +1435,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( } if (sc_list.GetSize()) { - Symbol *extern_symbol = NULL; - Symbol *non_extern_symbol = NULL; + Symbol *extern_symbol = nullptr; + Symbol *non_extern_symbol = nullptr; for (uint32_t index = 0, num_indices = sc_list.GetSize(); index < num_indices; ++index) { @@ -1416,13 +1453,13 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr)) continue; - AddOneFunction(context, sym_ctx.function, NULL, current_id); + AddOneFunction(context, sym_ctx.function, nullptr, current_id); context.m_found.function_with_type_info = true; context.m_found.function = true; } else if (sym_ctx.symbol) { if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target) { sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target); - if (sym_ctx.symbol == NULL) + if (sym_ctx.symbol == nullptr) continue; } @@ -1448,10 +1485,10 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( if (!context.m_found.function_with_type_info) { if (extern_symbol) { - AddOneFunction(context, NULL, extern_symbol, current_id); + AddOneFunction(context, nullptr, extern_symbol, current_id); context.m_found.function = true; } else if (non_extern_symbol) { - AddOneFunction(context, NULL, non_extern_symbol, current_id); + AddOneFunction(context, nullptr, non_extern_symbol, current_id); context.m_found.function = true; } } @@ -1525,7 +1562,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( context.m_found.variable = true; } } - } while (0); + } while (false); } if (target && !context.m_found.variable && !namespace_decl) { @@ -1687,7 +1724,7 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, bool is_reference = pt.IsReferenceType(); - NamedDecl *var_decl = NULL; + NamedDecl *var_decl = nullptr; if (is_reference) var_decl = context.AddVarDecl(pt); else @@ -1704,7 +1741,7 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, entity->GetParserVars(GetParserID()); parser_vars->m_parser_type = pt; parser_vars->m_named_decl = var_decl; - parser_vars->m_llvm_value = NULL; + parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value = var_location; parser_vars->m_lldb_var = var; @@ -1747,7 +1784,7 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, ->GetParserVars(GetParserID()); parser_vars->m_parser_type = parser_type; parser_vars->m_named_decl = var_decl; - parser_vars->m_llvm_value = NULL; + parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value.Clear(); if (log) { @@ -1766,7 +1803,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); - if (target == NULL) + if (target == nullptr) return; ASTContext *scratch_ast_context = @@ -1805,7 +1842,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, parser_vars->m_parser_type = parser_type; parser_vars->m_named_decl = var_decl; - parser_vars->m_llvm_value = NULL; + parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_sym = &symbol; if (log) { @@ -1853,7 +1890,7 @@ bool ClangExpressionDeclMap::ResolveUnknownTypes() { var_type.getAsOpaquePtr(), ClangASTContext::GetASTContext(&var_decl->getASTContext())); - lldb::opaque_compiler_type_t copied_type = 0; + lldb::opaque_compiler_type_t copied_type = nullptr; if (m_ast_importer_sp) { copied_type = m_ast_importer_sp->CopyType( scratch_ast_context->getASTContext(), &var_decl->getASTContext(), @@ -1926,7 +1963,7 @@ void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, entity->GetParserVars(GetParserID()); parser_vars->m_parser_type = parser_clang_type; parser_vars->m_named_decl = var_decl; - parser_vars->m_llvm_value = NULL; + parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value.Clear(); entity->m_flags |= ClangExpressionVariable::EVBareRegister; @@ -1945,7 +1982,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - NamedDecl *function_decl = NULL; + NamedDecl *function_decl = nullptr; Address fun_address; CompilerType function_clang_type; @@ -2105,7 +2142,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, } parser_vars->m_named_decl = function_decl; - parser_vars->m_llvm_value = NULL; + parser_vars->m_llvm_value = nullptr; if (log) { std::string function_str = @@ -2125,7 +2162,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, } void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, - TypeFromUser &ut, + const TypeFromUser &ut, unsigned int current_id) { CompilerType copied_clang_type = GuardedCopyType(ut); @@ -2158,7 +2195,7 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, CXXMethodDecl *method_decl = ClangASTContext::GetASTContext(m_ast_context) ->AddMethodToCXXRecordType( - copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", NULL, + copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr, method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline, is_explicit, is_attr_used, is_artificial); @@ -2199,7 +2236,7 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, } void ClangExpressionDeclMap::AddOneType(NameSearchContext &context, - TypeFromUser &ut, + const TypeFromUser &ut, unsigned int current_id) { CompilerType copied_clang_type = GuardedCopyType(ut); diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index 93fa57876bce..03b73e6be391 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -1,9 +1,8 @@ //===-- ClangExpressionDeclMap.h --------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -30,8 +29,7 @@ namespace lldb_private { -//---------------------------------------------------------------------- -/// @class ClangExpressionDeclMap ClangExpressionDeclMap.h +/// \class ClangExpressionDeclMap ClangExpressionDeclMap.h /// "lldb/Expression/ClangExpressionDeclMap.h" Manages named entities that are /// defined in LLDB's debug information. /// @@ -54,236 +52,213 @@ namespace lldb_private { /// /// Fourth and finally, it "dematerializes" the struct after the JITted code /// has has executed, placing the new values back where it found the old ones. -//---------------------------------------------------------------------- class ClangExpressionDeclMap : public ClangASTSource { public: - //------------------------------------------------------------------ /// Constructor /// /// Initializes class variables. /// - /// @param[in] keep_result_in_memory + /// \param[in] keep_result_in_memory /// If true, inhibits the normal deallocation of the memory for /// the result persistent variable, and instead marks the variable /// as persisting. /// - /// @param[in] delegate + /// \param[in] delegate /// If non-NULL, use this delegate to report result values. This /// allows the client ClangUserExpression to report a result. /// - /// @param[in] exe_ctx + /// \param[in] exe_ctx /// The execution context to use when parsing. - //------------------------------------------------------------------ + /// + /// \param[in] ctx_obj + /// If not empty, then expression is evaluated in context of this object. + /// See the comment to `UserExpression::Evaluate` for details. ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, - ExecutionContext &exe_ctx); + ExecutionContext &exe_ctx, + ValueObject *ctx_obj); - //------------------------------------------------------------------ /// Destructor - //------------------------------------------------------------------ ~ClangExpressionDeclMap() override; - //------------------------------------------------------------------ /// Enable the state needed for parsing and IR transformation. /// - /// @param[in] exe_ctx + /// \param[in] exe_ctx /// The execution context to use when finding types for variables. /// Also used to find a "scratch" AST context to store result types. /// - /// @param[in] materializer + /// \param[in] materializer /// If non-NULL, the materializer to populate with information about /// the variables to use /// - /// @return + /// \return /// True if parsing is possible; false if it is unsafe to continue. - //------------------------------------------------------------------ bool WillParse(ExecutionContext &exe_ctx, Materializer *materializer); void InstallCodeGenerator(clang::ASTConsumer *code_gen); - //------------------------------------------------------------------ /// [Used by ClangExpressionParser] For each variable that had an unknown /// type at the beginning of parsing, determine its final type now. /// - /// @return + /// \return /// True on success; false otherwise. - //------------------------------------------------------------------ bool ResolveUnknownTypes(); - //------------------------------------------------------------------ /// Disable the state needed for parsing and IR transformation. - //------------------------------------------------------------------ void DidParse(); - //------------------------------------------------------------------ /// [Used by IRForTarget] Add a variable to the list of persistent /// variables for the process. /// - /// @param[in] decl + /// \param[in] decl /// The Clang declaration for the persistent variable, used for /// lookup during parsing. /// - /// @param[in] name + /// \param[in] name /// The name of the persistent variable, usually $something. /// - /// @param[in] type + /// \param[in] type /// The type of the variable, in the Clang parser's context. /// - /// @return + /// \return /// True on success; false otherwise. - //------------------------------------------------------------------ bool AddPersistentVariable(const clang::NamedDecl *decl, - const ConstString &name, TypeFromParser type, + ConstString name, TypeFromParser type, bool is_result, bool is_lvalue); - //------------------------------------------------------------------ /// [Used by IRForTarget] Add a variable to the struct that needs to /// be materialized each time the expression runs. /// - /// @param[in] decl + /// \param[in] decl /// The Clang declaration for the variable. /// - /// @param[in] name + /// \param[in] name /// The name of the variable. /// - /// @param[in] value + /// \param[in] value /// The LLVM IR value for this variable. /// - /// @param[in] size + /// \param[in] size /// The size of the variable in bytes. /// - /// @param[in] alignment + /// \param[in] alignment /// The required alignment of the variable in bytes. /// - /// @return + /// \return /// True on success; false otherwise. - //------------------------------------------------------------------ - bool AddValueToStruct(const clang::NamedDecl *decl, const ConstString &name, + bool AddValueToStruct(const clang::NamedDecl *decl, ConstString name, llvm::Value *value, size_t size, lldb::offset_t alignment); - //------------------------------------------------------------------ /// [Used by IRForTarget] Finalize the struct, laying out the position of /// each object in it. /// - /// @return + /// \return /// True on success; false otherwise. - //------------------------------------------------------------------ bool DoStructLayout(); - //------------------------------------------------------------------ /// [Used by IRForTarget] Get general information about the laid-out struct /// after DoStructLayout() has been called. /// - /// @param[out] num_elements + /// \param[out] num_elements /// The number of elements in the struct. /// - /// @param[out] size + /// \param[out] size /// The size of the struct, in bytes. /// - /// @param[out] alignment + /// \param[out] alignment /// The alignment of the struct, in bytes. /// - /// @return + /// \return /// True if the information could be retrieved; false otherwise. - //------------------------------------------------------------------ bool GetStructInfo(uint32_t &num_elements, size_t &size, lldb::offset_t &alignment); - //------------------------------------------------------------------ /// [Used by IRForTarget] Get specific information about one field of the /// laid-out struct after DoStructLayout() has been called. /// - /// @param[out] decl + /// \param[out] decl /// The parsed Decl for the field, as generated by ClangASTSource /// on ClangExpressionDeclMap's behalf. In the case of the result /// value, this will have the name $__lldb_result even if the /// result value ends up having the name $1. This is an /// implementation detail of IRForTarget. /// - /// @param[out] value + /// \param[out] value /// The IR value for the field (usually a GlobalVariable). In /// the case of the result value, this will have the correct /// name ($1, for instance). This is an implementation detail /// of IRForTarget. /// - /// @param[out] offset + /// \param[out] offset /// The offset of the field from the beginning of the struct. /// As long as the struct is aligned according to its required /// alignment, this offset will align the field correctly. /// - /// @param[out] name + /// \param[out] name /// The name of the field as used in materialization. /// - /// @param[in] index + /// \param[in] index /// The index of the field about which information is requested. /// - /// @return + /// \return /// True if the information could be retrieved; false otherwise. - //------------------------------------------------------------------ bool GetStructElement(const clang::NamedDecl *&decl, llvm::Value *&value, lldb::offset_t &offset, ConstString &name, uint32_t index); - //------------------------------------------------------------------ /// [Used by IRForTarget] Get information about a function given its Decl. /// - /// @param[in] decl + /// \param[in] decl /// The parsed Decl for the Function, as generated by ClangASTSource /// on ClangExpressionDeclMap's behalf. /// - /// @param[out] ptr + /// \param[out] ptr /// The absolute address of the function in the target. /// - /// @return + /// \return /// True if the information could be retrieved; false otherwise. - //------------------------------------------------------------------ bool GetFunctionInfo(const clang::NamedDecl *decl, uint64_t &ptr); - //------------------------------------------------------------------ /// [Used by IRForTarget] Get the address of a symbol given nothing but its /// name. /// - /// @param[in] target + /// \param[in] target /// The target to find the symbol in. If not provided, /// then the current parsing context's Target. /// - /// @param[in] process + /// \param[in] process /// The process to use. For Objective-C symbols, the process's /// Objective-C language runtime may be queried if the process /// is non-NULL. /// - /// @param[in] name + /// \param[in] name /// The name of the symbol. /// - /// @param[in] module + /// \param[in] module /// The module to limit the search to. This can be NULL /// - /// @return + /// \return /// Valid load address for the symbol - //------------------------------------------------------------------ lldb::addr_t GetSymbolAddress(Target &target, Process *process, - const ConstString &name, - lldb::SymbolType symbol_type, - Module *module = NULL); + ConstString name, lldb::SymbolType symbol_type, + Module *module = nullptr); - lldb::addr_t GetSymbolAddress(const ConstString &name, + lldb::addr_t GetSymbolAddress(ConstString name, lldb::SymbolType symbol_type); - //------------------------------------------------------------------ /// [Used by IRInterpreter] Get basic target information. /// - /// @param[out] byte_order + /// \param[out] byte_order /// The byte order of the target. /// - /// @param[out] address_byte_size + /// \param[out] address_byte_size /// The size of a pointer in bytes. /// - /// @return + /// \return /// True if the information could be determined; false /// otherwise. - //------------------------------------------------------------------ struct TargetInfo { lldb::ByteOrder byte_order; size_t address_byte_size; @@ -296,38 +271,34 @@ public: }; TargetInfo GetTargetInfo(); - //------------------------------------------------------------------ /// [Used by ClangASTSource] Find all entities matching a given name, using /// a NameSearchContext to make Decls for them. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// - /// @return + /// \return /// True on success; false otherwise. - //------------------------------------------------------------------ void FindExternalVisibleDecls(NameSearchContext &context) override; - //------------------------------------------------------------------ /// Find all entities matching a given name in a given module/namespace, /// using a NameSearchContext to make Decls for them. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext that can construct Decls for this name. /// - /// @param[in] module + /// \param[in] module /// If non-NULL, the module to query. /// - /// @param[in] namespace_decl + /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. /// - /// @param[in] current_id + /// \param[in] current_id /// The ID for the current FindExternalVisibleDecls invocation, /// for logging purposes. /// - /// @return + /// \return /// True on success; false otherwise. - //------------------------------------------------------------------ void FindExternalVisibleDecls(NameSearchContext &context, lldb::ModuleSP module, CompilerDeclContext &namespace_decl, @@ -344,10 +315,12 @@ private: Materializer::PersistentVariableDelegate *m_result_delegate; ///< If non-NULL, used to report expression results to ///ClangUserExpression. + ValueObject *m_ctx_obj; ///< If not empty, then expression is + ///evaluated in context of this object. + ///For details see the comment to + ///`UserExpression::Evaluate`. - //---------------------------------------------------------------------- /// The following values should not live beyond parsing - //---------------------------------------------------------------------- class ParserVars { public: ParserVars() {} @@ -357,7 +330,7 @@ private: return m_exe_ctx.GetTargetPtr(); else if (m_sym_ctx.target_sp) m_sym_ctx.target_sp.get(); - return NULL; + return nullptr; } ExecutionContext m_exe_ctx; ///< The execution context to use when parsing. @@ -380,27 +353,21 @@ private: std::unique_ptr<ParserVars> m_parser_vars; - //---------------------------------------------------------------------- /// Activate parser-specific variables - //---------------------------------------------------------------------- void EnableParserVars() { if (!m_parser_vars.get()) m_parser_vars = llvm::make_unique<ParserVars>(); } - //---------------------------------------------------------------------- /// Deallocate parser-specific variables - //---------------------------------------------------------------------- void DisableParserVars() { m_parser_vars.reset(); } - //---------------------------------------------------------------------- /// The following values contain layout information for the materialized /// struct, but are not specific to a single materialization - //---------------------------------------------------------------------- struct StructVars { StructVars() : m_struct_alignment(0), m_struct_size(0), m_struct_laid_out(false), - m_result_name(), m_object_pointer_type(NULL, NULL) {} + m_result_name(), m_object_pointer_type(nullptr, nullptr) {} lldb::offset_t m_struct_alignment; ///< The alignment of the struct in bytes. @@ -416,202 +383,176 @@ private: std::unique_ptr<StructVars> m_struct_vars; - //---------------------------------------------------------------------- /// Activate struct variables - //---------------------------------------------------------------------- void EnableStructVars() { if (!m_struct_vars.get()) m_struct_vars.reset(new struct StructVars); } - //---------------------------------------------------------------------- /// Deallocate struct variables - //---------------------------------------------------------------------- void DisableStructVars() { m_struct_vars.reset(); } - //---------------------------------------------------------------------- /// Get this parser's ID for use in extracting parser- and JIT-specific data /// from persistent variables. - //---------------------------------------------------------------------- uint64_t GetParserID() { return (uint64_t) this; } - //------------------------------------------------------------------ /// Given a target, find a variable that matches the given name and type. /// - /// @param[in] target + /// \param[in] target /// The target to use as a basis for finding the variable. /// - /// @param[in] module + /// \param[in] module /// If non-NULL, the module to search. /// - /// @param[in] name + /// \param[in] name /// The name as a plain C string. /// - /// @param[in] namespace_decl + /// \param[in] namespace_decl /// If non-NULL and module is non-NULL, the parent namespace. /// - /// @param[in] type + /// \param[in] type /// The required type for the variable. This function may be called /// during parsing, in which case we don't know its type; hence the /// default. /// - /// @return + /// \return /// The LLDB Variable found, or NULL if none was found. - //------------------------------------------------------------------ lldb::VariableSP FindGlobalVariable(Target &target, lldb::ModuleSP &module, - const ConstString &name, + ConstString name, CompilerDeclContext *namespace_decl, - TypeFromUser *type = NULL); + TypeFromUser *type = nullptr); - //------------------------------------------------------------------ /// Get the value of a variable in a given execution context and return the /// associated Types if needed. /// - /// @param[in] var + /// \param[in] var /// The variable to evaluate. /// - /// @param[out] var_location + /// \param[out] var_location /// The variable location value to fill in /// - /// @param[out] found_type + /// \param[out] found_type /// The type of the found value, as it was found in the user process. /// This is only useful when the variable is being inspected on behalf /// of the parser, hence the default. /// - /// @param[out] parser_type + /// \param[out] parser_type /// The type of the found value, as it was copied into the parser's /// AST context. This is only useful when the variable is being /// inspected on behalf of the parser, hence the default. /// - /// @param[in] decl + /// \param[in] decl /// The Decl to be looked up. /// - /// @return + /// \return /// Return true if the value was successfully filled in. - //------------------------------------------------------------------ bool GetVariableValue(lldb::VariableSP &var, lldb_private::Value &var_location, - TypeFromUser *found_type = NULL, - TypeFromParser *parser_type = NULL); + TypeFromUser *found_type = nullptr, + TypeFromParser *parser_type = nullptr); - //------------------------------------------------------------------ /// Use the NameSearchContext to generate a Decl for the given LLDB /// Variable, and put it in the Tuple list. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// - /// @param[in] var + /// \param[in] var /// The LLDB Variable that needs a Decl. /// - /// @param[in] valobj + /// \param[in] valobj /// The LLDB ValueObject for that variable. - //------------------------------------------------------------------ void AddOneVariable(NameSearchContext &context, lldb::VariableSP var, lldb::ValueObjectSP valobj, unsigned int current_id); - //------------------------------------------------------------------ /// Use the NameSearchContext to generate a Decl for the given persistent /// variable, and put it in the list of found entities. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// - /// @param[in] pvar + /// \param[in] pvar /// The persistent variable that needs a Decl. /// - /// @param[in] current_id + /// \param[in] current_id /// The ID of the current invocation of FindExternalVisibleDecls /// for logging purposes. - //------------------------------------------------------------------ void AddOneVariable(NameSearchContext &context, lldb::ExpressionVariableSP &pvar_sp, unsigned int current_id); - //------------------------------------------------------------------ /// Use the NameSearchContext to generate a Decl for the given LLDB symbol /// (treated as a variable), and put it in the list of found entities. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// - /// @param[in] var + /// \param[in] var /// The LLDB Variable that needs a Decl. - //------------------------------------------------------------------ void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol, unsigned int current_id); - //------------------------------------------------------------------ /// Use the NameSearchContext to generate a Decl for the given function. /// (Functions are not placed in the Tuple list.) Can handle both fully /// typed functions and generic functions. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// - /// @param[in] fun + /// \param[in] fun /// The Function that needs to be created. If non-NULL, this is /// a fully-typed function. /// - /// @param[in] sym + /// \param[in] sym /// The Symbol that corresponds to a function that needs to be /// created with generic type (unitptr_t foo(...)). - //------------------------------------------------------------------ void AddOneFunction(NameSearchContext &context, Function *fun, Symbol *sym, unsigned int current_id); - //------------------------------------------------------------------ /// Use the NameSearchContext to generate a Decl for the given register. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// - /// @param[in] reg_info + /// \param[in] reg_info /// The information corresponding to that register. - //------------------------------------------------------------------ void AddOneRegister(NameSearchContext &context, const RegisterInfo *reg_info, unsigned int current_id); - //------------------------------------------------------------------ /// Use the NameSearchContext to generate a Decl for the given type. (Types /// are not placed in the Tuple list.) /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// - /// @param[in] type + /// \param[in] type /// The type that needs to be created. - //------------------------------------------------------------------ - void AddOneType(NameSearchContext &context, TypeFromUser &type, + void AddOneType(NameSearchContext &context, const TypeFromUser &type, unsigned int current_id); - //------------------------------------------------------------------ /// Generate a Decl for "*this" and add a member function declaration to it /// for the expression, then report it. /// - /// @param[in] context + /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// - /// @param[in] type + /// \param[in] type /// The type for *this. - //------------------------------------------------------------------ - void AddThisType(NameSearchContext &context, TypeFromUser &type, + void AddThisType(NameSearchContext &context, const TypeFromUser &type, unsigned int current_id); - //------------------------------------------------------------------ /// Move a type out of the current ASTContext into another, but make sure to /// export all components of the type also. /// - /// @param[in] target + /// \param[in] target /// The ClangASTContext to move to. - /// @param[in] source + /// \param[in] source /// The ClangASTContext to move from. This is assumed to be going away. - /// @param[in] parser_type + /// \param[in] parser_type /// The type as it appears in the source context. /// - /// @return + /// \return /// Returns the moved type, or an empty type if there was a problem. - //------------------------------------------------------------------ TypeFromUser DeportType(ClangASTContext &target, ClangASTContext &source, TypeFromParser parser_type); diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h index b5b640c9185f..48da5abb9126 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h @@ -1,9 +1,8 @@ //===-- ClangExpressionHelper.h ---------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -24,9 +23,7 @@ namespace lldb_private { class RecordingMemoryManager; -//---------------------------------------------------------------------- // ClangExpressionHelper -//---------------------------------------------------------------------- class ClangExpressionHelper : public ExpressionTypeSystemHelper { public: static bool classof(const ExpressionTypeSystemHelper *ts) { @@ -37,25 +34,19 @@ public: : ExpressionTypeSystemHelper( ExpressionTypeSystemHelper::LLVMCastKind::eKindClangHelper) {} - //------------------------------------------------------------------ /// Destructor - //------------------------------------------------------------------ virtual ~ClangExpressionHelper() {} - //------------------------------------------------------------------ /// Return the object that the parser should use when resolving external /// values. May be NULL if everything should be self-contained. - //------------------------------------------------------------------ virtual ClangExpressionDeclMap *DeclMap() = 0; - //------------------------------------------------------------------ /// Return the object that the parser should allow to access ASTs. /// May be NULL if the ASTs do not need to be transformed. /// - /// @param[in] passthrough + /// \param[in] passthrough /// The ASTConsumer that the returned transformer should send /// the ASTs to after transformation. - //------------------------------------------------------------------ virtual clang::ASTConsumer * ASTTransformer(clang::ASTConsumer *passthrough) = 0; diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 6650c0db967f..7d13891ded8d 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -1,19 +1,16 @@ //===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 <cctype> #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/DiagnosticIDs.h" -#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" @@ -39,15 +36,11 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/TargetSelect.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wglobal-constructors" -#include "llvm/ExecutionEngine/MCJIT.h" -#pragma clang diagnostic pop - #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/DynamicLibrary.h" @@ -58,19 +51,25 @@ #include "ClangDiagnostic.h" #include "ClangExpressionParser.h" +#include "ClangUserExpression.h" +#include "ASTUtils.h" #include "ClangASTSource.h" +#include "ClangDiagnostic.h" #include "ClangExpressionDeclMap.h" #include "ClangExpressionHelper.h" +#include "ClangExpressionParser.h" +#include "ClangHost.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" +#include "IRDynamicChecks.h" #include "IRForTarget.h" +#include "ModuleDependencyCollector.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" -#include "lldb/Expression/IRDynamicChecks.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/File.h" @@ -79,17 +78,22 @@ #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Language.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" +#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" + +#include <cctype> +#include <memory> + using namespace clang; using namespace llvm; using namespace lldb_private; @@ -111,24 +115,19 @@ public: void moduleImport(SourceLocation import_location, clang::ModuleIdPath path, const clang::Module * /*null*/) override { - std::vector<ConstString> string_path; + SourceModule module; - for (const std::pair<IdentifierInfo *, SourceLocation> &component : path) { - string_path.push_back(ConstString(component.first->getName())); - } + for (const std::pair<IdentifierInfo *, SourceLocation> &component : path) + module.path.push_back(ConstString(component.first->getName())); StreamString error_stream; ClangModulesDeclVendor::ModuleVector exported_modules; - - if (!m_decl_vendor.AddModule(string_path, &exported_modules, - m_error_stream)) { + if (!m_decl_vendor.AddModule(module, &exported_modules, m_error_stream)) m_has_errors = true; - } - for (ClangModulesDeclVendor::ModuleID module : exported_modules) { + for (ClangModulesDeclVendor::ModuleID module : exported_modules) m_persistent_vars.AddHandLoadedClangModule(module); - } } bool hasErrors() { return m_has_errors; } @@ -150,7 +149,7 @@ public: } void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, - const clang::Diagnostic &Info) { + const clang::Diagnostic &Info) override { if (m_manager) { llvm::SmallVector<char, 32> diag_str; Info.FormatDiagnostic(diag_str); @@ -214,15 +213,58 @@ private: std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough; }; +static void +SetupModuleHeaderPaths(CompilerInstance *compiler, + std::vector<ConstString> include_directories, + lldb::TargetSP target_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + HeaderSearchOptions &search_opts = compiler->getHeaderSearchOpts(); + + for (ConstString dir : include_directories) { + search_opts.AddPath(dir.AsCString(), frontend::System, false, true); + LLDB_LOG(log, "Added user include dir: {0}", dir); + } + + llvm::SmallString<128> module_cache; + auto props = ModuleList::GetGlobalModuleListProperties(); + props.GetClangModulesCachePath().GetPath(module_cache); + search_opts.ModuleCachePath = module_cache.str(); + LLDB_LOG(log, "Using module cache path: {0}", module_cache.c_str()); + + FileSpec clang_resource_dir = GetClangResourceDir(); + std::string resource_dir = clang_resource_dir.GetPath(); + if (FileSystem::Instance().IsDirectory(resource_dir)) { + search_opts.ResourceDir = resource_dir; + std::string resource_include = resource_dir + "/include"; + search_opts.AddPath(resource_include, frontend::System, false, true); + + LLDB_LOG(log, "Added resource include dir: {0}", resource_include); + } + + search_opts.ImplicitModuleMaps = true; + + std::vector<std::string> system_include_directories = + target_sp->GetPlatform()->GetSystemIncludeDirectories( + lldb::eLanguageTypeC_plus_plus); + + for (const std::string &include_dir : system_include_directories) { + search_opts.AddPath(include_dir, frontend::System, false, true); + + LLDB_LOG(log, "Added system include dir: {0}", include_dir); + } +} + //===----------------------------------------------------------------------===// // Implementation of ClangExpressionParser //===----------------------------------------------------------------------===// -ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, - Expression &expr, - bool generate_debug_info) +ClangExpressionParser::ClangExpressionParser( + ExecutionContextScope *exe_scope, Expression &expr, + bool generate_debug_info, std::vector<ConstString> include_directories) : ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(), - m_pp_callbacks(nullptr) { + m_pp_callbacks(nullptr), + m_include_directories(std::move(include_directories)) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // We can't compile expressions without a target. So if the exe_scope is @@ -249,6 +291,22 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // 1. Create a new compiler instance. m_compiler.reset(new CompilerInstance()); + + // When capturing a reproducer, hook up the file collector with clang to + // collector modules and headers. + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>(); + m_compiler->setModuleDepCollector( + std::make_shared<ModuleDependencyCollectorAdaptor>( + fp.GetFileCollector())); + DependencyOutputOptions &opts = m_compiler->getDependencyOutputOpts(); + opts.IncludeSystemHeaders = true; + opts.IncludeModuleFiles = true; + } + + // Make sure clang uses the same VFS as LLDB. + m_compiler->createFileManager(FileSystem::Instance().GetVirtualFileSystem()); + lldb::LanguageType frame_lang = expr.Language(); // defaults to lldb::eLanguageTypeUnknown bool overridden_target_opts = false; @@ -363,6 +421,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // 5. Set language options. lldb::LanguageType language = expr.Language(); + LangOptions &lang_opts = m_compiler->getLangOpts(); switch (language) { case lldb::eLanguageTypeC: @@ -374,13 +433,13 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // For now, the expression parser must use C++ anytime the language is a C // family language, because the expression parser uses features of C++ to // capture values. - m_compiler->getLangOpts().CPlusPlus = true; + lang_opts.CPlusPlus = true; break; case lldb::eLanguageTypeObjC: - m_compiler->getLangOpts().ObjC = true; + lang_opts.ObjC = true; // FIXME: the following language option is a temporary workaround, // to "ask for ObjC, get ObjC++" (see comment above). - m_compiler->getLangOpts().CPlusPlus = true; + lang_opts.CPlusPlus = true; // Clang now sets as default C++14 as the default standard (with // GNU extensions), so we do the same here to avoid mismatches that @@ -388,71 +447,92 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, // as it's a C++11 feature). Currently lldb evaluates C++14 as C++11 (see // two lines below) so we decide to be consistent with that, but this could // be re-evaluated in the future. - m_compiler->getLangOpts().CPlusPlus11 = true; + lang_opts.CPlusPlus11 = true; break; case lldb::eLanguageTypeC_plus_plus: case lldb::eLanguageTypeC_plus_plus_11: case lldb::eLanguageTypeC_plus_plus_14: - m_compiler->getLangOpts().CPlusPlus11 = true; + lang_opts.CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; LLVM_FALLTHROUGH; case lldb::eLanguageTypeC_plus_plus_03: - m_compiler->getLangOpts().CPlusPlus = true; + lang_opts.CPlusPlus = true; if (process_sp) - m_compiler->getLangOpts().ObjC = + lang_opts.ObjC = process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC) != nullptr; break; case lldb::eLanguageTypeObjC_plus_plus: case lldb::eLanguageTypeUnknown: default: - m_compiler->getLangOpts().ObjC = true; - m_compiler->getLangOpts().CPlusPlus = true; - m_compiler->getLangOpts().CPlusPlus11 = true; + lang_opts.ObjC = true; + lang_opts.CPlusPlus = true; + lang_opts.CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; break; } - m_compiler->getLangOpts().Bool = true; - m_compiler->getLangOpts().WChar = true; - m_compiler->getLangOpts().Blocks = true; - m_compiler->getLangOpts().DebuggerSupport = + lang_opts.Bool = true; + lang_opts.WChar = true; + lang_opts.Blocks = true; + lang_opts.DebuggerSupport = true; // Features specifically for debugger clients if (expr.DesiredResultType() == Expression::eResultTypeId) - m_compiler->getLangOpts().DebuggerCastResultToId = true; + lang_opts.DebuggerCastResultToId = true; - m_compiler->getLangOpts().CharIsSigned = - ArchSpec(m_compiler->getTargetOpts().Triple.c_str()) - .CharIsSignedByDefault(); + lang_opts.CharIsSigned = ArchSpec(m_compiler->getTargetOpts().Triple.c_str()) + .CharIsSignedByDefault(); // Spell checking is a nice feature, but it ends up completing a lot of types // that we didn't strictly speaking need to complete. As a result, we spend a // long time parsing and importing debug information. - m_compiler->getLangOpts().SpellChecking = false; + lang_opts.SpellChecking = false; + + auto *clang_expr = dyn_cast<ClangUserExpression>(&m_expr); + if (clang_expr && clang_expr->DidImportCxxModules()) { + LLDB_LOG(log, "Adding lang options for importing C++ modules"); + + lang_opts.Modules = true; + // We want to implicitly build modules. + lang_opts.ImplicitModules = true; + // To automatically import all submodules when we import 'std'. + lang_opts.ModulesLocalVisibility = false; + + // We use the @import statements, so we need this: + // FIXME: We could use the modules-ts, but that currently doesn't work. + lang_opts.ObjC = true; + + // Options we need to parse libc++ code successfully. + // FIXME: We should ask the driver for the appropriate default flags. + lang_opts.GNUMode = true; + lang_opts.GNUKeywords = true; + lang_opts.DoubleSquareBracketAttributes = true; + lang_opts.CPlusPlus11 = true; + + SetupModuleHeaderPaths(m_compiler.get(), m_include_directories, + target_sp); + } - if (process_sp && m_compiler->getLangOpts().ObjC) { - if (process_sp->GetObjCLanguageRuntime()) { - if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == + if (process_sp && lang_opts.ObjC) { + if (auto *runtime = ObjCLanguageRuntime::Get(*process_sp)) { + if (runtime->GetRuntimeVersion() == ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2) - m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX, - VersionTuple(10, 7)); + lang_opts.ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7)); else - m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX, - VersionTuple(10, 7)); + lang_opts.ObjCRuntime.set(ObjCRuntime::FragileMacOSX, + VersionTuple(10, 7)); - if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing()) - m_compiler->getLangOpts().DebuggerObjCLiteral = true; + if (runtime->HasNewLiteralsAndIndexing()) + lang_opts.DebuggerObjCLiteral = true; } } - m_compiler->getLangOpts().ThreadsafeStatics = false; - m_compiler->getLangOpts().AccessControl = - false; // Debuggers get universal access - m_compiler->getLangOpts().DollarIdents = - true; // $ indicates a persistent variable name + lang_opts.ThreadsafeStatics = false; + lang_opts.AccessControl = false; // Debuggers get universal access + lang_opts.DollarIdents = true; // $ indicates a persistent variable name // We enable all builtin functions beside the builtins from libc/libm (e.g. // 'fopen'). Those libc functions are already correctly handled by LLDB, and // additionally enabling them as expandable builtins is breaking Clang. - m_compiler->getLangOpts().NoBuiltin = true; + lang_opts.NoBuiltin = true; // Set CodeGen options m_compiler->getCodeGenOpts().EmitDeclMetadata = true; @@ -483,14 +563,9 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, m_compiler->getDiagnostics().setClient(new ClangDiagnosticManagerAdapter); // 7. Set up the source management objects inside the compiler - - clang::FileSystemOptions file_system_options; - m_file_manager.reset(new clang::FileManager(file_system_options)); - - if (!m_compiler->hasSourceManager()) - m_compiler->createSourceManager(*m_file_manager.get()); - m_compiler->createFileManager(); + if (!m_compiler->hasSourceManager()) + m_compiler->createSourceManager(m_compiler->getFileManager()); m_compiler->createPreprocessor(TU_Complete); if (ClangModulesDeclVendor *decl_vendor = @@ -517,17 +592,6 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope, m_compiler->createASTContext(); clang::ASTContext &ast_context = m_compiler->getASTContext(); - ClangExpressionHelper *type_system_helper = - dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); - ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); - - if (decl_map) { - llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source( - decl_map->CreateProxy()); - decl_map->InstallASTContext(ast_context, m_compiler->getFileManager()); - ast_context.setExternalSource(ast_source); - } - m_ast_context.reset( new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str())); m_ast_context->setASTContext(&ast_context); @@ -545,13 +609,11 @@ ClangExpressionParser::~ClangExpressionParser() {} namespace { -//---------------------------------------------------------------------- -/// @class CodeComplete +/// \class CodeComplete /// /// A code completion consumer for the clang Sema that is responsible for /// creating the completion suggestions when a user requests completion /// of an incomplete `expr` invocation. -//---------------------------------------------------------------------- class CodeComplete : public CodeCompleteConsumer { CodeCompletionTUInfo m_info; @@ -624,20 +686,20 @@ class CodeComplete : public CodeCompleteConsumer { public: /// Constructs a CodeComplete consumer that can be attached to a Sema. - /// @param[out] matches + /// \param[out] matches /// The list of matches that the lldb completion API expects as a result. /// This may already contain matches, so it's only allowed to append /// to this variable. - /// @param[out] expr + /// \param[out] expr /// The whole expression string that we are currently parsing. This /// string needs to be equal to the input the user typed, and NOT the /// final code that Clang is parsing. - /// @param[out] position + /// \param[out] position /// The character position of the user cursor in the `expr` parameter. /// CodeComplete(CompletionRequest &request, clang::LangOptions ops, std::string expr, unsigned position) - : CodeCompleteConsumer(CodeCompleteOptions(), false), + : CodeCompleteConsumer(CodeCompleteOptions()), m_info(std::make_shared<GlobalCodeCompletionAllocator>()), m_expr(expr), m_position(position), m_request(request), m_desc_policy(ops) { @@ -653,7 +715,7 @@ public: } /// Deregisters and destroys this code-completion consumer. - virtual ~CodeComplete() {} + ~CodeComplete() override {} /// \name Code-completion filtering /// Check if the result should be filtered out. @@ -788,8 +850,8 @@ bool ClangExpressionParser::Complete(CompletionRequest &request, unsigned line, // To actually get the raw user input here, we have to cast our expression to // the LLVMUserExpression which exposes the right API. This should never fail // as we always have a ClangUserExpression whenever we call this. - LLVMUserExpression &llvm_expr = *static_cast<LLVMUserExpression *>(&m_expr); - CodeComplete CC(request, m_compiler->getLangOpts(), llvm_expr.GetUserText(), + ClangUserExpression *llvm_expr = cast<ClangUserExpression>(&m_expr); + CodeComplete CC(request, m_compiler->getLangOpts(), llvm_expr->GetUserText(), typed_pos); // We don't need a code generator for parsing. m_code_generator.reset(); @@ -848,9 +910,9 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, if (file.Write(expr_text, bytes_written).Success()) { if (bytes_written == expr_text_len) { file.Close(); - source_mgr.setMainFileID( - source_mgr.createFileID(m_file_manager->getFile(result_path), - SourceLocation(), SrcMgr::C_User)); + source_mgr.setMainFileID(source_mgr.createFileID( + m_compiler->getFileManager().getFile(result_path), + SourceLocation(), SrcMgr::C_User)); created_main_file = true; } } @@ -859,7 +921,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, if (!created_main_file) { std::unique_ptr<MemoryBuffer> memory_buffer = - MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__); + MemoryBuffer::getMemBufferCopy(expr_text, "<lldb-expr>"); source_mgr.setMainFileID(source_mgr.createFileID(std::move(memory_buffer))); } @@ -869,12 +931,6 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); - ASTConsumer *ast_transformer = - type_system_helper->ASTTransformer(m_code_generator.get()); - - if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap()) - decl_map->InstallCodeGenerator(m_code_generator.get()); - // If we want to parse for code completion, we need to attach our code // completion consumer to the Sema and specify a completion position. // While parsing the Sema will call this consumer with the provided @@ -889,18 +945,72 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, PP.SetCodeCompletionPoint(main_file, completion_line, completion_column); } + ASTConsumer *ast_transformer = + type_system_helper->ASTTransformer(m_code_generator.get()); + + std::unique_ptr<clang::ASTConsumer> Consumer; if (ast_transformer) { - ast_transformer->Initialize(m_compiler->getASTContext()); - ParseAST(m_compiler->getPreprocessor(), ast_transformer, - m_compiler->getASTContext(), false, TU_Complete, - completion_consumer); + Consumer.reset(new ASTConsumerForwarder(ast_transformer)); + } else if (m_code_generator) { + Consumer.reset(new ASTConsumerForwarder(m_code_generator.get())); } else { - m_code_generator->Initialize(m_compiler->getASTContext()); - ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), - m_compiler->getASTContext(), false, TU_Complete, - completion_consumer); + Consumer.reset(new ASTConsumer()); + } + + clang::ASTContext &ast_context = m_compiler->getASTContext(); + + m_compiler->setSema(new Sema(m_compiler->getPreprocessor(), ast_context, + *Consumer, TU_Complete, completion_consumer)); + m_compiler->setASTConsumer(std::move(Consumer)); + + if (ast_context.getLangOpts().Modules) { + m_compiler->createModuleManager(); + m_ast_context->setSema(&m_compiler->getSema()); } + ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); + if (decl_map) { + decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer()); + + clang::ExternalASTSource *ast_source = decl_map->CreateProxy(); + + if (ast_context.getExternalSource()) { + auto module_wrapper = + new ExternalASTSourceWrapper(ast_context.getExternalSource()); + + auto ast_source_wrapper = new ExternalASTSourceWrapper(ast_source); + + auto multiplexer = + new SemaSourceWithPriorities(*module_wrapper, *ast_source_wrapper); + IntrusiveRefCntPtr<ExternalASTSource> Source(multiplexer); + ast_context.setExternalSource(Source); + } else { + ast_context.setExternalSource(ast_source); + } + decl_map->InstallASTContext(ast_context, m_compiler->getFileManager()); + } + + // Check that the ASTReader is properly attached to ASTContext and Sema. + if (ast_context.getLangOpts().Modules) { + assert(m_compiler->getASTContext().getExternalSource() && + "ASTContext doesn't know about the ASTReader?"); + assert(m_compiler->getSema().getExternalSource() && + "Sema doesn't know about the ASTReader?"); + } + + { + llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema( + &m_compiler->getSema()); + ParseAST(m_compiler->getSema(), false, false); + } + + // Make sure we have no pointer to the Sema we are about to destroy. + if (ast_context.getLangOpts().Modules) + m_ast_context->setSema(nullptr); + // Destroy the Sema. This is necessary because we want to emulate the + // original behavior of ParseAST (which also destroys the Sema after parsing). + m_compiler->setSema(nullptr); + diag_buf->EndSourceFile(); unsigned num_errors = diag_buf->getNumErrors(); @@ -1050,10 +1160,10 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( lldb_private::Status err; - std::unique_ptr<llvm::Module> llvm_module_ap( + std::unique_ptr<llvm::Module> llvm_module_up( m_code_generator->ReleaseModule()); - if (!llvm_module_ap.get()) { + if (!llvm_module_up) { err.SetErrorToGenericError(); err.SetErrorString("IR doesn't contain a module"); return err; @@ -1064,7 +1174,7 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( if (execution_policy != eExecutionPolicyTopLevel) { // Find the actual name of the function (it's often mangled somehow) - if (!FindFunctionInModule(function_name, llvm_module_ap.get(), + if (!FindFunctionInModule(function_name, llvm_module_up.get(), m_expr.FunctionName())) { err.SetErrorToGenericError(); err.SetErrorStringWithFormat("Couldn't find %s() in the module", @@ -1105,14 +1215,14 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( "expression module '%s'", __FUNCTION__, m_expr.FunctionName()); - custom_passes.EarlyPasses->run(*llvm_module_ap); + custom_passes.EarlyPasses->run(*llvm_module_up); } - execution_unit_sp.reset( - new IRExecutionUnit(m_llvm_context, // handed off here - llvm_module_ap, // handed off here - function_name, exe_ctx.GetTargetSP(), sc, - m_compiler->getTargetOpts().Features)); + execution_unit_sp = std::make_shared<IRExecutionUnit>( + m_llvm_context, // handed off here + llvm_module_up, // handed off here + function_name, exe_ctx.GetTargetSP(), sc, + m_compiler->getTargetOpts().Features); ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); @@ -1120,7 +1230,7 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( type_system_helper->DeclMap(); // result can be NULL if (decl_map) { - Stream *error_stream = NULL; + Stream *error_stream = nullptr; Target *target = exe_ctx.GetTargetPtr(); error_stream = target->GetDebugger().GetErrorFile().get(); @@ -1172,8 +1282,8 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( (execution_policy != eExecutionPolicyTopLevel && !can_interpret)) { if (m_expr.NeedsValidation() && process) { if (!process->GetDynamicCheckers()) { - DynamicCheckerFunctions *dynamic_checkers = - new DynamicCheckerFunctions(); + ClangDynamicCheckerFunctions *dynamic_checkers = + new ClangDynamicCheckerFunctions(); DiagnosticManager install_diagnostics; @@ -1189,27 +1299,30 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( process->SetDynamicCheckers(dynamic_checkers); if (log) - log->Printf("== [ClangUserExpression::Evaluate] Finished " - "installing dynamic checkers =="); + log->Printf("== [ClangExpressionParser::PrepareForExecution] " + "Finished installing dynamic checkers =="); } - IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), - function_name.AsCString()); + if (auto *checker_funcs = llvm::dyn_cast<ClangDynamicCheckerFunctions>( + process->GetDynamicCheckers())) { + IRDynamicChecks ir_dynamic_checks(*checker_funcs, + function_name.AsCString()); - llvm::Module *module = execution_unit_sp->GetModule(); - if (!module || !ir_dynamic_checks.runOnModule(*module)) { - err.SetErrorToGenericError(); - err.SetErrorString("Couldn't add dynamic checks to the expression"); - return err; - } + llvm::Module *module = execution_unit_sp->GetModule(); + if (!module || !ir_dynamic_checks.runOnModule(*module)) { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't add dynamic checks to the expression"); + return err; + } - if (custom_passes.LatePasses) { - if (log) - log->Printf("%s - Running Late IR Passes from LanguageRuntime on " - "expression module '%s'", - __FUNCTION__, m_expr.FunctionName()); + if (custom_passes.LatePasses) { + if (log) + log->Printf("%s - Running Late IR Passes from LanguageRuntime on " + "expression module '%s'", + __FUNCTION__, m_expr.FunctionName()); - custom_passes.LatePasses->run(*module); + custom_passes.LatePasses->run(*module); + } } } } diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 03ff55f614d5..a42c2190ffb8 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -1,9 +1,8 @@ //===-- ClangExpressionParser.h ---------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -28,8 +27,7 @@ namespace lldb_private { class IRExecutionUnit; -//---------------------------------------------------------------------- -/// @class ClangExpressionParser ClangExpressionParser.h +/// \class ClangExpressionParser ClangExpressionParser.h /// "lldb/Expression/ClangExpressionParser.h" Encapsulates an instance of /// Clang that can parse expressions. /// @@ -38,140 +36,130 @@ class IRExecutionUnit; /// as a glorified parameter list, performing the required parsing and /// conversion to formats (DWARF bytecode, or JIT compiled machine code) that /// can be executed. -//---------------------------------------------------------------------- class ClangExpressionParser : public ExpressionParser { public: - //------------------------------------------------------------------ /// Constructor /// /// Initializes class variables. /// - /// @param[in] exe_scope, + /// \param[in] exe_scope, /// If non-NULL, an execution context scope that can help to /// correctly create an expression with a valid process for /// optional tuning Objective-C runtime support. Can be NULL. /// - /// @param[in] expr + /// \param[in] expr /// The expression to be parsed. - //------------------------------------------------------------------ + /// + /// @param[in] include_directories + /// List of include directories that should be used when parsing the + /// expression. ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr, - bool generate_debug_info); + bool generate_debug_info, + std::vector<ConstString> include_directories = {}); - //------------------------------------------------------------------ /// Destructor - //------------------------------------------------------------------ ~ClangExpressionParser() override; bool Complete(CompletionRequest &request, unsigned line, unsigned pos, unsigned typed_pos) override; - //------------------------------------------------------------------ /// Parse a single expression and convert it to IR using Clang. Don't wrap /// the expression in anything at all. /// - /// @param[in] diagnostic_manager + /// \param[in] diagnostic_manager /// The diagnostic manager to report errors to. /// - /// @return + /// \return /// The number of errors encountered during parsing. 0 means /// success. - //------------------------------------------------------------------ unsigned Parse(DiagnosticManager &diagnostic_manager) override; bool RewriteExpression(DiagnosticManager &diagnostic_manager) override; - //------------------------------------------------------------------ /// Ready an already-parsed expression for execution, possibly evaluating it /// statically. /// - /// @param[out] func_addr + /// \param[out] func_addr /// The address to which the function has been written. /// - /// @param[out] func_end + /// \param[out] func_end /// The end of the function's allocated memory region. (func_addr /// and func_end do not delimit an allocated region; the allocated /// region may begin before func_addr.) /// - /// @param[in] execution_unit_sp + /// \param[in] execution_unit_sp /// After parsing, ownership of the execution unit for /// for the expression is handed to this shared pointer. /// - /// @param[in] exe_ctx + /// \param[in] exe_ctx /// The execution context to write the function into. /// - /// @param[out] evaluated_statically + /// \param[out] evaluated_statically /// Set to true if the expression could be interpreted statically; /// untouched otherwise. /// - /// @param[out] const_result + /// \param[out] const_result /// If the result of the expression is constant, and the /// expression has no side effects, this is set to the result of the /// expression. /// - /// @param[in] execution_policy + /// \param[in] execution_policy /// Determines whether the expression must be JIT-compiled, must be /// evaluated statically, or whether this decision may be made /// opportunistically. /// - /// @return + /// \return /// An error code indicating the success or failure of the operation. /// Test with Success(). - //------------------------------------------------------------------ Status PrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end, lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx, bool &can_interpret, lldb_private::ExecutionPolicy execution_policy) override; - //------------------------------------------------------------------ /// Run all static initializers for an execution unit. /// - /// @param[in] execution_unit_sp + /// \param[in] execution_unit_sp /// The execution unit. /// - /// @param[in] exe_ctx + /// \param[in] exe_ctx /// The execution context to use when running them. Thread can't be null. /// - /// @return + /// \return /// The error code indicating the - //------------------------------------------------------------------ Status RunStaticInitializers(lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx); - //------------------------------------------------------------------ /// Returns a string representing current ABI. /// - /// @param[in] target_arch + /// \param[in] target_arch /// The target architecture. /// - /// @return + /// \return /// A string representing target ABI for the current architecture. - //------------------------------------------------------------------- std::string GetClangTargetABI(const ArchSpec &target_arch); private: - //------------------------------------------------------------------ /// Parses the expression. /// - /// @param[in] diagnostic_manager + /// \param[in] diagnostic_manager /// The diagnostic manager that should receive the diagnostics /// from the parsing process. /// - /// @param[in] completion + /// \param[in] completion /// The completion consumer that should be used during parsing /// (or a nullptr if no consumer should be attached). /// - /// @param[in] completion_line + /// \param[in] completion_line /// The line in which the completion marker should be placed. /// The first line is represented by the value 0. /// - /// @param[in] completion_column + /// \param[in] completion_column /// The column in which the completion marker should be placed. /// The first column is represented by the value 0. /// - /// @return + /// \return /// The number of parsing errors. - //------------------------------------------------------------------- unsigned ParseInternal(DiagnosticManager &diagnostic_manager, clang::CodeCompleteConsumer *completion = nullptr, unsigned completion_line = 0, @@ -179,8 +167,6 @@ private: std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into - std::unique_ptr<clang::FileManager> - m_file_manager; ///< The Clang file manager object used by the compiler std::unique_ptr<clang::CompilerInstance> m_compiler; ///< The Clang compiler used to parse expressions into IR std::unique_ptr<clang::CodeGenerator> @@ -190,6 +176,8 @@ private: LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor ///encounters module imports std::unique_ptr<ClangASTContext> m_ast_context; + + std::vector<ConstString> m_include_directories; }; } diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp new file mode 100644 index 000000000000..f513b1eea360 --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -0,0 +1,497 @@ +//===-- ClangExpressionSourceCode.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 +// +//===----------------------------------------------------------------------===// + +#include "ClangExpressionSourceCode.h" + +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Lexer.h" +#include "llvm/ADT/StringRef.h" + +#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/DebugMacros.h" +#include "lldb/Symbol/TypeSystem.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Language.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb_private; + +const char *ClangExpressionSourceCode::g_expression_prefix = R"( +#ifndef NULL +#define NULL (__null) +#endif +#ifndef Nil +#define Nil (__null) +#endif +#ifndef nil +#define nil (__null) +#endif +#ifndef YES +#define YES ((BOOL)1) +#endif +#ifndef NO +#define NO ((BOOL)0) +#endif +typedef __INT8_TYPE__ int8_t; +typedef __UINT8_TYPE__ uint8_t; +typedef __INT16_TYPE__ int16_t; +typedef __UINT16_TYPE__ uint16_t; +typedef __INT32_TYPE__ int32_t; +typedef __UINT32_TYPE__ uint32_t; +typedef __INT64_TYPE__ int64_t; +typedef __UINT64_TYPE__ uint64_t; +typedef __INTPTR_TYPE__ intptr_t; +typedef __UINTPTR_TYPE__ uintptr_t; +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef unsigned short unichar; +extern "C" +{ + int printf(const char * __restrict, ...); +} +)"; + +static const char *c_start_marker = " /*LLDB_BODY_START*/\n "; +static const char *c_end_marker = ";\n /*LLDB_BODY_END*/\n"; + +namespace { + +class AddMacroState { + enum State { + CURRENT_FILE_NOT_YET_PUSHED, + CURRENT_FILE_PUSHED, + CURRENT_FILE_POPPED + }; + +public: + AddMacroState(const FileSpec ¤t_file, const uint32_t current_file_line) + : m_state(CURRENT_FILE_NOT_YET_PUSHED), m_current_file(current_file), + m_current_file_line(current_file_line) {} + + void StartFile(const FileSpec &file) { + m_file_stack.push_back(file); + if (file == m_current_file) + m_state = CURRENT_FILE_PUSHED; + } + + void EndFile() { + if (m_file_stack.size() == 0) + return; + + FileSpec old_top = m_file_stack.back(); + m_file_stack.pop_back(); + if (old_top == m_current_file) + m_state = CURRENT_FILE_POPPED; + } + + // An entry is valid if it occurs before the current line in the current + // file. + bool IsValidEntry(uint32_t line) { + switch (m_state) { + case CURRENT_FILE_NOT_YET_PUSHED: + return true; + case CURRENT_FILE_PUSHED: + // If we are in file included in the current file, the entry should be + // added. + if (m_file_stack.back() != m_current_file) + return true; + + return line < m_current_file_line; + default: + return false; + } + } + +private: + std::vector<FileSpec> m_file_stack; + State m_state; + FileSpec m_current_file; + uint32_t m_current_file_line; +}; + +} // anonymous namespace + +static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, + AddMacroState &state, StreamString &stream) { + if (dm == nullptr) + return; + + for (size_t i = 0; i < dm->GetNumMacroEntries(); i++) { + const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i); + uint32_t line; + + switch (entry.GetType()) { + case DebugMacroEntry::DEFINE: + if (state.IsValidEntry(entry.GetLineNumber())) + stream.Printf("#define %s\n", entry.GetMacroString().AsCString()); + else + return; + break; + case DebugMacroEntry::UNDEF: + if (state.IsValidEntry(entry.GetLineNumber())) + stream.Printf("#undef %s\n", entry.GetMacroString().AsCString()); + else + return; + break; + case DebugMacroEntry::START_FILE: + line = entry.GetLineNumber(); + if (state.IsValidEntry(line)) + state.StartFile(entry.GetFileSpec(comp_unit)); + else + return; + break; + case DebugMacroEntry::END_FILE: + state.EndFile(); + break; + case DebugMacroEntry::INDIRECT: + AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream); + break; + default: + // This is an unknown/invalid entry. Ignore. + break; + } + } +} + +namespace { +/// Allows checking if a token is contained in a given expression. +class TokenVerifier { + /// The tokens we found in the expression. + llvm::StringSet<> m_tokens; + +public: + TokenVerifier(std::string body); + /// Returns true iff the given expression body contained a token with the + /// given content. + bool hasToken(llvm::StringRef token) const { + return m_tokens.find(token) != m_tokens.end(); + } +}; +} // namespace + +TokenVerifier::TokenVerifier(std::string body) { + using namespace clang; + + // We only care about tokens and not their original source locations. If we + // move the whole expression to only be in one line we can simplify the + // following code that extracts the token contents. + std::replace(body.begin(), body.end(), '\n', ' '); + std::replace(body.begin(), body.end(), '\r', ' '); + + FileSystemOptions file_opts; + FileManager file_mgr(file_opts, + FileSystem::Instance().GetVirtualFileSystem()); + + // Let's build the actual source code Clang needs and setup some utility + // objects. + llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts( + new DiagnosticOptions()); + DiagnosticsEngine diags(diag_ids, diags_opts); + clang::SourceManager SM(diags, file_mgr); + auto buf = llvm::MemoryBuffer::getMemBuffer(body); + + FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get()); + + // Let's just enable the latest ObjC and C++ which should get most tokens + // right. + LangOptions Opts; + Opts.ObjC = true; + Opts.DollarIdents = true; + Opts.CPlusPlus17 = true; + Opts.LineComment = true; + + Lexer lex(FID, buf.get(), SM, Opts); + + Token token; + bool exit = false; + while (!exit) { + // Returns true if this is the last token we get from the lexer. + exit = lex.LexFromRawLexer(token); + + // Extract the column number which we need to extract the token content. + // Our expression is just one line, so we don't need to handle any line + // numbers here. + bool invalid = false; + unsigned start = SM.getSpellingColumnNumber(token.getLocation(), &invalid); + if (invalid) + continue; + // Column numbers start at 1, but indexes in our string start at 0. + --start; + + // Annotations don't have a length, so let's skip them. + if (token.isAnnotation()) + continue; + + // Extract the token string from our source code and store it. + std::string token_str = body.substr(start, token.getLength()); + if (token_str.empty()) + continue; + m_tokens.insert(token_str); + } +} + +static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, + StreamString &stream, + const std::string &expr, + lldb::LanguageType wrapping_language) { + TokenVerifier tokens(expr); + + for (size_t i = 0; i < var_list_sp->GetSize(); i++) { + lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i); + + ConstString var_name = var_sp->GetName(); + + + // We can check for .block_descriptor w/o checking for langauge since this + // is not a valid identifier in either C or C++. + if (!var_name || var_name == ".block_descriptor") + continue; + + if (!expr.empty() && !tokens.hasToken(var_name.GetStringRef())) + continue; + + if ((var_name == "self" || var_name == "_cmd") && + (wrapping_language == lldb::eLanguageTypeObjC || + wrapping_language == lldb::eLanguageTypeObjC_plus_plus)) + continue; + + if (var_name == "this" && + wrapping_language == lldb::eLanguageTypeC_plus_plus) + continue; + + stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString()); + } +} + +bool ClangExpressionSourceCode::GetText( + std::string &text, lldb::LanguageType wrapping_language, bool static_method, + ExecutionContext &exe_ctx, bool add_locals, bool force_add_all_locals, + llvm::ArrayRef<std::string> modules) const { + const char *target_specific_defines = "typedef signed char BOOL;\n"; + std::string module_macros; + + Target *target = exe_ctx.GetTargetPtr(); + if (target) { + if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64) { + target_specific_defines = "typedef bool BOOL;\n"; + } + if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) { + if (lldb::PlatformSP platform_sp = target->GetPlatform()) { + static ConstString g_platform_ios_simulator("ios-simulator"); + if (platform_sp->GetPluginName() == g_platform_ios_simulator) { + target_specific_defines = "typedef bool BOOL;\n"; + } + } + } + + if (ClangModulesDeclVendor *decl_vendor = + target->GetClangModulesDeclVendor()) { + ClangPersistentVariables *persistent_vars = + llvm::cast<ClangPersistentVariables>( + target->GetPersistentExpressionStateForLanguage( + lldb::eLanguageTypeC)); + const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = + persistent_vars->GetHandLoadedClangModules(); + ClangModulesDeclVendor::ModuleVector modules_for_macros; + + for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) { + modules_for_macros.push_back(module); + } + + if (target->GetEnableAutoImportClangModules()) { + if (StackFrame *frame = exe_ctx.GetFramePtr()) { + if (Block *block = frame->GetFrameBlock()) { + SymbolContext sc; + + block->CalculateSymbolContext(&sc); + + if (sc.comp_unit) { + StreamString error_stream; + + decl_vendor->AddModulesForCompileUnit( + *sc.comp_unit, modules_for_macros, error_stream); + } + } + } + } + + decl_vendor->ForEachMacro( + modules_for_macros, + [&module_macros](const std::string &expansion) -> bool { + module_macros.append(expansion); + module_macros.append("\n"); + return false; + }); + } + } + + StreamString debug_macros_stream; + StreamString lldb_local_var_decls; + if (StackFrame *frame = exe_ctx.GetFramePtr()) { + const SymbolContext &sc = frame->GetSymbolContext( + lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry); + + if (sc.comp_unit && sc.line_entry.IsValid()) { + DebugMacros *dm = sc.comp_unit->GetDebugMacros(); + if (dm) { + AddMacroState state(sc.line_entry.file, sc.line_entry.line); + AddMacros(dm, sc.comp_unit, state, debug_macros_stream); + } + } + + if (add_locals) + if (target->GetInjectLocalVariables(&exe_ctx)) { + lldb::VariableListSP var_list_sp = + frame->GetInScopeVariableList(false, true); + AddLocalVariableDecls(var_list_sp, lldb_local_var_decls, + force_add_all_locals ? "" : m_body, + wrapping_language); + } + } + + if (m_wrap) { + switch (wrapping_language) { + default: + return false; + case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC_plus_plus: + case lldb::eLanguageTypeObjC: + break; + } + + // Generate a list of @import statements that will import the specified + // module into our expression. + std::string module_imports; + for (const std::string &module : modules) { + module_imports.append("@import "); + module_imports.append(module); + module_imports.append(";\n"); + } + + StreamString wrap_stream; + + wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), + debug_macros_stream.GetData(), g_expression_prefix, + target_specific_defines, m_prefix.c_str()); + + // First construct a tagged form of the user expression so we can find it + // later: + std::string tagged_body; + switch (wrapping_language) { + default: + tagged_body = m_body; + break; + case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC_plus_plus: + case lldb::eLanguageTypeObjC: + tagged_body.append(c_start_marker); + tagged_body.append(m_body); + tagged_body.append(c_end_marker); + break; + } + switch (wrapping_language) { + default: + break; + case lldb::eLanguageTypeC: + wrap_stream.Printf("%s" + "void \n" + "%s(void *$__lldb_arg) \n" + "{ \n" + " %s; \n" + "%s" + "} \n", + module_imports.c_str(), m_name.c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); + break; + case lldb::eLanguageTypeC_plus_plus: + wrap_stream.Printf("%s" + "void \n" + "$__lldb_class::%s(void *$__lldb_arg) \n" + "{ \n" + " %s; \n" + "%s" + "} \n", + module_imports.c_str(), m_name.c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); + break; + case lldb::eLanguageTypeObjC: + if (static_method) { + wrap_stream.Printf( + "%s" + "@interface $__lldb_objc_class ($__lldb_category) \n" + "+(void)%s:(void *)$__lldb_arg; \n" + "@end \n" + "@implementation $__lldb_objc_class ($__lldb_category) \n" + "+(void)%s:(void *)$__lldb_arg \n" + "{ \n" + " %s; \n" + "%s" + "} \n" + "@end \n", + module_imports.c_str(), m_name.c_str(), m_name.c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); + } else { + wrap_stream.Printf( + "%s" + "@interface $__lldb_objc_class ($__lldb_category) \n" + "-(void)%s:(void *)$__lldb_arg; \n" + "@end \n" + "@implementation $__lldb_objc_class ($__lldb_category) \n" + "-(void)%s:(void *)$__lldb_arg \n" + "{ \n" + " %s; \n" + "%s" + "} \n" + "@end \n", + module_imports.c_str(), m_name.c_str(), m_name.c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); + } + break; + } + + text = wrap_stream.GetString(); + } else { + text.append(m_body); + } + + return true; +} + +bool ClangExpressionSourceCode::GetOriginalBodyBounds( + std::string transformed_text, lldb::LanguageType wrapping_language, + size_t &start_loc, size_t &end_loc) { + const char *start_marker; + const char *end_marker; + + switch (wrapping_language) { + default: + return false; + case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC_plus_plus: + case lldb::eLanguageTypeObjC: + start_marker = c_start_marker; + end_marker = c_end_marker; + break; + } + + start_loc = transformed_text.find(start_marker); + if (start_loc == std::string::npos) + return false; + start_loc += strlen(start_marker); + end_loc = transformed_text.find(end_marker); + return end_loc != std::string::npos; +} diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h new file mode 100644 index 000000000000..894290295837 --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h @@ -0,0 +1,71 @@ +//===-- ClangExpressionSourceCode.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 liblldb_ClangExpressionSourceCode_h +#define liblldb_ClangExpressionSourceCode_h + +#include "lldb/Expression/Expression.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/lldb-enumerations.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" + +#include <string> + +namespace lldb_private { + +class ExecutionContext; + +class ClangExpressionSourceCode : public ExpressionSourceCode { +public: + static const char *g_expression_prefix; + + static ClangExpressionSourceCode *CreateWrapped(const char *prefix, + const char *body) { + return new ClangExpressionSourceCode("$__lldb_expr", prefix, body, true); + } + + uint32_t GetNumBodyLines(); + + /// Generates the source code that will evaluate the expression. + /// + /// \param text output parameter containing the source code string. + /// \param wrapping_language If the expression is supossed to be wrapped, + /// then this is the language that should be used for that. + /// \param static_method True iff the expression is valuated inside a static + /// Objective-C method. + /// \param exe_ctx The execution context in which the expression will be + /// evaluated. + /// \param add_locals True iff local variables should be injected into the + /// expression source code. + /// \param force_add_all_locals True iff all local variables should be + /// injected even if they are not used in the expression. + /// \param modules A list of (C++) modules that the expression should import. + /// + /// \return true iff the source code was successfully generated. + bool GetText(std::string &text, lldb::LanguageType wrapping_language, + bool static_method, ExecutionContext &exe_ctx, bool add_locals, + bool force_add_all_locals, + llvm::ArrayRef<std::string> modules) const; + + // Given a string returned by GetText, find the beginning and end of the body + // passed to CreateWrapped. Return true if the bounds could be found. This + // will also work on text with FixItHints applied. + static bool GetOriginalBodyBounds(std::string transformed_text, + lldb::LanguageType wrapping_language, + size_t &start_loc, size_t &end_loc); + +protected: + ClangExpressionSourceCode(const char *name, const char *prefix, const char *body, + bool wrap) : + ExpressionSourceCode(name, prefix, body, wrap) {} +}; + +} // namespace lldb_private + +#endif diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp index 624cbf2a1a4f..b5a2c80b5349 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp @@ -1,9 +1,8 @@ //===-- ClangExpressionVariable.cpp -----------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -32,7 +31,7 @@ ClangExpressionVariable::ClangExpressionVariable( } ClangExpressionVariable::ClangExpressionVariable( - ExecutionContextScope *exe_scope, Value &value, const ConstString &name, + ExecutionContextScope *exe_scope, Value &value, ConstString name, uint16_t flags) : ExpressionVariable(LLVMCastKind::eKindClang), m_parser_vars(), m_jit_vars() { @@ -49,7 +48,7 @@ ClangExpressionVariable::ClangExpressionVariable( } ClangExpressionVariable::ClangExpressionVariable( - ExecutionContextScope *exe_scope, const ConstString &name, + ExecutionContextScope *exe_scope, ConstString name, const TypeFromUser &user_type, lldb::ByteOrder byte_order, uint32_t addr_byte_size) : ExpressionVariable(LLVMCastKind::eKindClang), m_parser_vars(), diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index 6886f0940adb..eb7f74f20a20 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -1,9 +1,8 @@ //===-- ClangExpressionVariable.h -------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -35,8 +34,7 @@ namespace lldb_private { class ValueObjectConstResult; -//---------------------------------------------------------------------- -/// @class ClangExpressionVariable ClangExpressionVariable.h +/// \class ClangExpressionVariable ClangExpressionVariable.h /// "lldb/Expression/ClangExpressionVariable.h" Encapsulates one variable for /// the expression parser. /// @@ -56,36 +54,31 @@ class ValueObjectConstResult; /// /// This class supports all of these use cases using simple type polymorphism, /// and provides necessary support methods. Its interface is RTTI-neutral. -//---------------------------------------------------------------------- class ClangExpressionVariable : public ExpressionVariable { public: ClangExpressionVariable(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size); ClangExpressionVariable(ExecutionContextScope *exe_scope, Value &value, - const ConstString &name, uint16_t flags = EVNone); + ConstString name, uint16_t flags = EVNone); ClangExpressionVariable(const lldb::ValueObjectSP &valobj_sp); ClangExpressionVariable(ExecutionContextScope *exe_scope, - const ConstString &name, + ConstString name, const TypeFromUser &user_type, lldb::ByteOrder byte_order, uint32_t addr_byte_size); - //---------------------------------------------------------------------- /// Utility functions for dealing with ExpressionVariableLists in Clang- /// specific ways - //---------------------------------------------------------------------- - //---------------------------------------------------------------------- /// Finds a variable by NamedDecl in the list. /// - /// @param[in] name + /// \param[in] name /// The name of the requested variable. /// - /// @return + /// \return /// The variable requested, or NULL if that variable is not in the list. - //---------------------------------------------------------------------- static ClangExpressionVariable * FindVariableInList(ExpressionVariableList &list, const clang::NamedDecl *decl, uint64_t parser_id) { @@ -105,31 +98,27 @@ public: return nullptr; } - //---------------------------------------------------------------------- /// If the variable contains its own data, make a Value point at it. If \a /// exe_ctx in not NULL, the value will be resolved in with that execution /// context. /// - /// @param[in] value + /// \param[in] value /// The value to point at the data. /// - /// @param[in] exe_ctx + /// \param[in] exe_ctx /// The execution context to use to resolve \a value. /// - /// @return + /// \return /// True on success; false otherwise (in particular, if this variable /// does not contain its own data). - //---------------------------------------------------------------------- bool PointValueAtData(Value &value, ExecutionContext *exe_ctx); - //---------------------------------------------------------------------- /// The following values should not live beyond parsing - //---------------------------------------------------------------------- class ParserVars { public: ParserVars() - : m_parser_type(), m_named_decl(NULL), m_llvm_value(NULL), - m_lldb_value(), m_lldb_var(), m_lldb_sym(NULL) {} + : m_parser_type(), m_named_decl(nullptr), m_llvm_value(nullptr), + m_lldb_value(), m_lldb_var(), m_lldb_sym(nullptr) {} TypeFromParser m_parser_type; ///< The type of the variable according to the parser @@ -149,34 +138,26 @@ private: ParserVarMap m_parser_vars; public: - //---------------------------------------------------------------------- /// Make this variable usable by the parser by allocating space for parser- /// specific variables - //---------------------------------------------------------------------- void EnableParserVars(uint64_t parser_id) { m_parser_vars.insert(std::make_pair(parser_id, ParserVars())); } - //---------------------------------------------------------------------- /// Deallocate parser-specific variables - //---------------------------------------------------------------------- void DisableParserVars(uint64_t parser_id) { m_parser_vars.erase(parser_id); } - //---------------------------------------------------------------------- /// Access parser-specific variables - //---------------------------------------------------------------------- ParserVars *GetParserVars(uint64_t parser_id) { ParserVarMap::iterator i = m_parser_vars.find(parser_id); if (i == m_parser_vars.end()) - return NULL; + return nullptr; else return &i->second; } - //---------------------------------------------------------------------- /// The following values are valid if the variable is used by JIT code - //---------------------------------------------------------------------- struct JITVars { JITVars() : m_alignment(0), m_size(0), m_offset(0) {} @@ -192,40 +173,32 @@ private: JITVarMap m_jit_vars; public: - //---------------------------------------------------------------------- /// Make this variable usable for materializing for the JIT by allocating /// space for JIT-specific variables - //---------------------------------------------------------------------- void EnableJITVars(uint64_t parser_id) { m_jit_vars.insert(std::make_pair(parser_id, JITVars())); } - //---------------------------------------------------------------------- /// Deallocate JIT-specific variables - //---------------------------------------------------------------------- void DisableJITVars(uint64_t parser_id) { m_jit_vars.erase(parser_id); } JITVars *GetJITVars(uint64_t parser_id) { JITVarMap::iterator i = m_jit_vars.find(parser_id); if (i == m_jit_vars.end()) - return NULL; + return nullptr; else return &i->second; } TypeFromUser GetTypeFromUser(); - //------------------------------------------------------------------ // llvm casting support - //------------------------------------------------------------------ static bool classof(const ExpressionVariable *ev) { return ev->getKind() == ExpressionVariable::eKindClang; } - //---------------------------------------------------------------------- /// Members - //---------------------------------------------------------------------- DISALLOW_COPY_AND_ASSIGN(ClangExpressionVariable); }; diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 8ec9ff2235f5..eabc96aa8e51 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -1,9 +1,8 @@ //===-- ClangFunctionCaller.cpp ---------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -43,9 +42,7 @@ using namespace lldb_private; -//---------------------------------------------------------------------- // ClangFunctionCaller constructor -//---------------------------------------------------------------------- ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope, const CompilerType &return_type, const Address &functionAddress, @@ -59,9 +56,7 @@ ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope, assert(m_jit_process_wp.lock()); } -//---------------------------------------------------------------------- // Destructor -//---------------------------------------------------------------------- ClangFunctionCaller::~ClangFunctionCaller() {} unsigned diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h index 9d933bfa6095..24f6f2eb91b3 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h @@ -1,9 +1,8 @@ //===-- ClangFunctionCaller.h -----------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -25,8 +24,7 @@ namespace lldb_private { class ASTStructExtractor; class ClangExpressionParser; -//---------------------------------------------------------------------- -/// @class ClangFunctionCaller ClangFunctionCaller.h +/// \class ClangFunctionCaller ClangFunctionCaller.h /// "lldb/Expression/ClangFunctionCaller.h" Encapsulates a function that can /// be called. /// @@ -58,30 +56,30 @@ class ClangExpressionParser; /// /// Any of the methods that take arg_addr_ptr can be passed NULL, and the /// argument space will be managed for you. -//---------------------------------------------------------------------- class ClangFunctionCaller : public FunctionCaller { friend class ASTStructExtractor; + /// LLVM-style RTTI support. + static bool classof(const Expression *E) { + return E->getKind() == eKindClangFunctionCaller; + } + class ClangFunctionCallerHelper : public ClangExpressionHelper { public: ClangFunctionCallerHelper(ClangFunctionCaller &owner) : m_owner(owner) {} ~ClangFunctionCallerHelper() override = default; - //------------------------------------------------------------------ /// Return the object that the parser should use when resolving external /// values. May be NULL if everything should be self-contained. - //------------------------------------------------------------------ - ClangExpressionDeclMap *DeclMap() override { return NULL; } + ClangExpressionDeclMap *DeclMap() override { return nullptr; } - //------------------------------------------------------------------ /// Return the object that the parser should allow to access ASTs. May be /// NULL if the ASTs do not need to be transformed. /// - /// @param[in] passthrough + /// \param[in] passthrough /// The ASTConsumer that the returned transformer should send /// the ASTs to after transformation. - //------------------------------------------------------------------ clang::ASTConsumer * ASTTransformer(clang::ASTConsumer *passthrough) override; @@ -94,27 +92,25 @@ class ClangFunctionCaller : public FunctionCaller { }; public: - //------------------------------------------------------------------ /// Constructor /// - /// @param[in] exe_scope + /// \param[in] exe_scope /// An execution context scope that gets us at least a target and /// process. /// - /// @param[in] ast_context + /// \param[in] ast_context /// The AST context to evaluate argument types in. /// - /// @param[in] return_qualtype + /// \param[in] return_qualtype /// An opaque Clang QualType for the function result. Should be /// defined in ast_context. /// - /// @param[in] function_address + /// \param[in] function_address /// The address of the function to call. /// - /// @param[in] arg_value_list + /// \param[in] arg_value_list /// The default values to use when calling this function. Can /// be overridden using WriteFunctionArguments(). - //------------------------------------------------------------------ ClangFunctionCaller(ExecutionContextScope &exe_scope, const CompilerType &return_type, const Address &function_address, @@ -122,20 +118,18 @@ public: ~ClangFunctionCaller() override; - //------------------------------------------------------------------ /// Compile the wrapper function /// - /// @param[in] thread_to_use_sp + /// \param[in] thread_to_use_sp /// Compilation might end up calling functions. Pass in the thread you /// want the compilation to use. If you pass in an empty ThreadSP it will /// use the currently selected thread. /// - /// @param[in] diagnostic_manager + /// \param[in] diagnostic_manager /// The diagnostic manager to report parser errors to. /// - /// @return + /// \return /// The number of errors. - //------------------------------------------------------------------ unsigned CompileFunction(lldb::ThreadSP thread_to_use_sp, DiagnosticManager &diagnostic_manager) override; @@ -147,9 +141,7 @@ protected: const char *GetWrapperStructName() { return m_wrapper_struct_name.c_str(); } private: - //------------------------------------------------------------------ // For ClangFunctionCaller only - //------------------------------------------------------------------ // Note: the parser needs to be destructed before the execution unit, so // declare the execution unit first. diff --git a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 44a13353818a..65c547391831 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -1,9 +1,8 @@ //===-- ClangHost.cpp -------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -17,11 +16,9 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" +#include "lldb/Host/Config.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#if !defined(_WIN32) -#include "lldb/Host/posix/HostInfoPosix.h" -#endif #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" @@ -29,18 +26,6 @@ using namespace lldb_private; -#if defined(_WIN32) -static bool ComputeClangDirectory(FileSpec &file_spec) { return false; } -#else -static bool DefaultComputeClangDirectory(FileSpec &file_spec) { - return HostInfoPosix::ComputePathRelativeToLibrary( - file_spec, (llvm::Twine("/lib") + CLANG_LIBDIR_SUFFIX + "/clang/" + - CLANG_VERSION_STRING) - .str()); -} - -#if defined(__APPLE__) - static bool VerifyClangPath(const llvm::Twine &clang_path) { if (FileSystem::Instance().IsDirectory(clang_path)) return true; @@ -52,8 +37,55 @@ static bool VerifyClangPath(const llvm::Twine &clang_path) { return false; } -bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, +/// +/// This will compute the clang resource directory assuming that clang was +/// installed with the same prefix as lldb. +/// +/// If verify is true, the first candidate resource directory will be returned. +/// This mode is only used for testing. +/// +static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, + FileSpec &file_spec, + bool verify) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + std::string raw_path = lldb_shlib_spec.GetPath(); + llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path); + + static const llvm::StringRef kResourceDirSuffixes[] = { + // LLVM.org's build of LLDB uses the clang resource directory placed + // in $install_dir/lib{,64}/clang/$clang_version. + "lib" CLANG_LIBDIR_SUFFIX "/clang/" CLANG_VERSION_STRING, + // swift-lldb uses the clang resource directory copied from swift, which + // by default is placed in $install_dir/lib{,64}/lldb/clang. LLDB places + // it there, so we use LLDB_LIBDIR_SUFFIX. + "lib" LLDB_LIBDIR_SUFFIX "/lldb/clang", + }; + + for (const auto &Suffix : kResourceDirSuffixes) { + llvm::SmallString<256> clang_dir(parent_dir); + llvm::SmallString<32> relative_path(Suffix); + llvm::sys::path::native(relative_path); + llvm::sys::path::append(clang_dir, relative_path); + if (!verify || VerifyClangPath(clang_dir)) { + if (log) + log->Printf("DefaultComputeClangResourceDir: Setting ClangResourceDir " + "to \"%s\", verify = %s", + clang_dir.str().str().c_str(), verify ? "true" : "false"); + file_spec.GetDirectory().SetString(clang_dir); + FileSystem::Instance().Resolve(file_spec); + return true; + } + } + + return false; +} + +bool lldb_private::ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, FileSpec &file_spec, bool verify) { +#if !defined(__APPLE__) + return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec, + verify); +#else std::string raw_path = lldb_shlib_spec.GetPath(); auto rev_it = llvm::sys::path::rbegin(raw_path); @@ -66,8 +98,10 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, ++rev_it; } + // We found a non-framework build of LLDB if (rev_it == r_end) - return DefaultComputeClangDirectory(file_spec); + return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec, + verify); // Inside Xcode and in Xcode toolchains LLDB is always in lockstep // with the Swift compiler, so it can reuse its Clang resource @@ -84,7 +118,7 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, "Developer/Toolchains/XcodeDefault.xctoolchain", swift_clang_resource_dir); if (!verify || VerifyClangPath(clang_path)) { - file_spec.SetFile(clang_path.c_str(), FileSpec::Style::native); + file_spec.GetDirectory().SetString(clang_path.c_str()); FileSystem::Instance().Resolve(file_spec); return true; } @@ -99,7 +133,7 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, raw_path.resize(parent - r_end); llvm::sys::path::append(clang_path, raw_path, swift_clang_resource_dir); if (!verify || VerifyClangPath(clang_path)) { - file_spec.SetFile(clang_path.c_str(), FileSpec::Style::native); + file_spec.GetDirectory().SetString(clang_path.c_str()); FileSystem::Instance().Resolve(file_spec); return true; } @@ -112,30 +146,19 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec, // Fall back to the Clang resource directory inside the framework. raw_path.append("LLDB.framework/Resources/Clang"); - file_spec.SetFile(raw_path.c_str(), FileSpec::Style::native); + file_spec.GetDirectory().SetString(raw_path.c_str()); FileSystem::Instance().Resolve(file_spec); return true; -} - -static bool ComputeClangDirectory(FileSpec &file_spec) { - if (FileSpec lldb_file_spec = HostInfo::GetShlibDir()) - return ComputeClangDirectory(lldb_file_spec, file_spec, true); - return false; -} -#else // __APPLE__ - -// All non-Apple posix systems. -static bool ComputeClangDirectory(FileSpec &file_spec) { - return DefaultComputeClangDirectory(file_spec); -} #endif // __APPLE__ -#endif // _WIN32 +} FileSpec lldb_private::GetClangResourceDir() { static FileSpec g_cached_resource_dir; static llvm::once_flag g_once_flag; llvm::call_once(g_once_flag, []() { - ::ComputeClangDirectory(g_cached_resource_dir); + if (FileSpec lldb_file_spec = HostInfo::GetShlibDir()) + ComputeClangResourceDirectory(lldb_file_spec, g_cached_resource_dir, + true); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("GetClangResourceDir() => '%s'", diff --git a/source/Plugins/ExpressionParser/Clang/ClangHost.h b/source/Plugins/ExpressionParser/Clang/ClangHost.h index 4fe423adb1a5..9d49188178cd 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangHost.h +++ b/source/Plugins/ExpressionParser/Clang/ClangHost.h @@ -1,9 +1,8 @@ //===-- ClangHost.h ---------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -14,10 +13,8 @@ namespace lldb_private { class FileSpec; -#if defined(__APPLE__) -bool ComputeClangDirectory(FileSpec &lldb_shlib_spec, FileSpec &file_spec, - bool verify); -#endif +bool ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, + FileSpec &file_spec, bool verify); FileSpec GetClangResourceDir(); diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index ced21dfe0dda..4a220790e50d 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -1,9 +1,8 @@ //===-- ClangModulesDeclVendor.cpp ------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -23,15 +22,18 @@ #include "ClangHost.h" #include "ClangModulesDeclVendor.h" +#include "ModuleDependencyCollector.h" #include "lldb/Core/ModuleList.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Target.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" using namespace lldb_private; @@ -70,13 +72,13 @@ public: ~ClangModulesDeclVendorImpl() override = default; - bool AddModule(ModulePath &path, ModuleVector *exported_modules, + bool AddModule(const SourceModule &module, ModuleVector *exported_modules, Stream &error_stream) override; bool AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules, Stream &error_stream) override; - uint32_t FindDecls(const ConstString &name, bool append, uint32_t max_matches, + uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector<clang::NamedDecl *> &decls) override; void ForEachMacro(const ModuleVector &modules, @@ -183,7 +185,7 @@ void ClangModulesDeclVendorImpl::ReportModuleExports( } } -bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path, +bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, ModuleVector *exported_modules, Stream &error_stream) { // Fail early. @@ -198,7 +200,7 @@ bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path, std::vector<ConstString> imported_module; - for (ConstString path_component : path) { + for (ConstString path_component : module.path) { imported_module.push_back(path_component); } @@ -213,11 +215,42 @@ bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path, } } - if (!m_compiler_instance->getPreprocessor() - .getHeaderSearchInfo() - .lookupModule(path[0].GetStringRef())) { + clang::HeaderSearch &HS = + m_compiler_instance->getPreprocessor().getHeaderSearchInfo(); + + if (module.search_path) { + auto path_begin = llvm::sys::path::begin(module.search_path.GetStringRef()); + auto path_end = llvm::sys::path::end(module.search_path.GetStringRef()); + auto sysroot_begin = llvm::sys::path::begin(module.sysroot.GetStringRef()); + auto sysroot_end = llvm::sys::path::end(module.sysroot.GetStringRef()); + // FIXME: Use C++14 std::equal(it, it, it, it) variant once it's available. + bool is_system_module = (std::distance(path_begin, path_end) >= + std::distance(sysroot_begin, sysroot_end)) && + std::equal(sysroot_begin, sysroot_end, path_begin); + // No need to inject search paths to modules in the sysroot. + if (!is_system_module) { + auto error = [&]() { + error_stream.Printf("error: No module map file in %s\n", + module.search_path.AsCString()); + return false; + }; + + bool is_system = true; + bool is_framework = false; + auto *dir = + HS.getFileMgr().getDirectory(module.search_path.GetStringRef()); + if (!dir) + return error(); + auto *file = HS.lookupModuleMapFile(dir, is_framework); + if (!file) + return error(); + if (!HS.loadModuleMapFile(file, is_system)) + return error(); + } + } + if (!HS.lookupModule(module.path.front().GetStringRef())) { error_stream.Printf("error: Header search couldn't locate module %s\n", - path[0].AsCString()); + module.path.front().AsCString()); return false; } @@ -229,7 +262,7 @@ bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path, clang::SourceManager &source_manager = m_compiler_instance->getASTContext().getSourceManager(); - for (ConstString path_component : path) { + for (ConstString path_component : module.path) { clang_path.push_back(std::make_pair( &m_compiler_instance->getASTContext().Idents.get( path_component.GetStringRef()), @@ -249,19 +282,18 @@ bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path, if (!top_level_module) { diagnostic_consumer->DumpDiagnostics(error_stream); error_stream.Printf("error: Couldn't load top-level module %s\n", - path[0].AsCString()); + module.path.front().AsCString()); return false; } clang::Module *submodule = top_level_module; - for (size_t ci = 1; ci < path.size(); ++ci) { - llvm::StringRef component = path[ci].GetStringRef(); - submodule = submodule->findSubmodule(component.str()); + for (auto &component : llvm::ArrayRef<ConstString>(module.path).drop_front()) { + submodule = submodule->findSubmodule(component.GetStringRef()); if (!submodule) { diagnostic_consumer->DumpDiagnostics(error_stream); error_stream.Printf("error: Couldn't load submodule %s\n", - component.str().c_str()); + component.GetCString()); return false; } } @@ -288,12 +320,16 @@ bool ClangModulesDeclVendor::LanguageSupportsClangModules( switch (language) { default: return false; - // C++ and friends to be added case lldb::LanguageType::eLanguageTypeC: case lldb::LanguageType::eLanguageTypeC11: case lldb::LanguageType::eLanguageTypeC89: case lldb::LanguageType::eLanguageTypeC99: + case lldb::LanguageType::eLanguageTypeC_plus_plus: + case lldb::LanguageType::eLanguageTypeC_plus_plus_03: + case lldb::LanguageType::eLanguageTypeC_plus_plus_11: + case lldb::LanguageType::eLanguageTypeC_plus_plus_14: case lldb::LanguageType::eLanguageTypeObjC: + case lldb::LanguageType::eLanguageTypeObjC_plus_plus: return true; } } @@ -302,28 +338,17 @@ bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit( CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules, Stream &error_stream) { if (LanguageSupportsClangModules(cu.GetLanguage())) { - std::vector<ConstString> imported_modules = cu.GetImportedModules(); - - for (ConstString imported_module : imported_modules) { - std::vector<ConstString> path; - - path.push_back(imported_module); - - if (!AddModule(path, &exported_modules, error_stream)) { + for (auto &imported_module : cu.GetImportedModules()) + if (!AddModule(imported_module, &exported_modules, error_stream)) return false; - } - } - - return true; } - return true; } // ClangImporter::lookupValue uint32_t -ClangModulesDeclVendorImpl::FindDecls(const ConstString &name, bool append, +ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector<clang::NamedDecl *> &decls) { if (!m_enabled) { @@ -583,7 +608,7 @@ ClangModulesDeclVendor::Create(Target &target) { compiler_invocation_arguments.push_back(module_cache_argument); } - FileSpecList &module_search_paths = target.GetClangModuleSearchPaths(); + FileSpecList module_search_paths = target.GetClangModuleSearchPaths(); for (size_t spi = 0, spe = module_search_paths.GetSize(); spi < spe; ++spi) { const FileSpec &search_path = module_search_paths.GetFileSpecAtIndex(spi); @@ -610,9 +635,13 @@ ClangModulesDeclVendor::Create(Target &target) { std::vector<const char *> compiler_invocation_argument_cstrs; compiler_invocation_argument_cstrs.reserve( compiler_invocation_arguments.size()); - for (const std::string &arg : compiler_invocation_arguments) { + for (const std::string &arg : compiler_invocation_arguments) compiler_invocation_argument_cstrs.push_back(arg.c_str()); - } + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}", + llvm::make_range(compiler_invocation_arguments.begin(), + compiler_invocation_arguments.end())); std::shared_ptr<clang::CompilerInvocation> invocation = clang::createInvocationFromCommandLine(compiler_invocation_argument_cstrs, @@ -632,6 +661,20 @@ ClangModulesDeclVendor::Create(Target &target) { std::unique_ptr<clang::CompilerInstance> instance( new clang::CompilerInstance); + // When capturing a reproducer, hook up the file collector with clang to + // collector modules and headers. + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>(); + instance->setModuleDepCollector( + std::make_shared<ModuleDependencyCollectorAdaptor>( + fp.GetFileCollector())); + clang::DependencyOutputOptions &opts = instance->getDependencyOutputOpts(); + opts.IncludeSystemHeaders = true; + opts.IncludeModuleFiles = true; + } + + // Make sure clang uses the same VFS as LLDB. + instance->createFileManager(FileSystem::Instance().GetVirtualFileSystem()); instance->setDiagnostics(diagnostics_engine.get()); instance->setInvocation(invocation); diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h index 23769ccfb0c0..d5c8757bdcd0 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h +++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h @@ -1,9 +1,8 @@ //===-- ClangModulesDeclVendor.h --------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -12,6 +11,7 @@ #include "lldb/Core/ClangForward.h" #include "lldb/Symbol/DeclVendor.h" +#include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Platform.h" #include <set> @@ -21,9 +21,7 @@ namespace lldb_private { class ClangModulesDeclVendor : public DeclVendor { public: - //------------------------------------------------------------------ // Constructors and Destructors - //------------------------------------------------------------------ ClangModulesDeclVendor(); ~ClangModulesDeclVendor() override; @@ -34,84 +32,77 @@ public: typedef uintptr_t ModuleID; typedef std::vector<ModuleID> ModuleVector; - //------------------------------------------------------------------ /// Add a module to the list of modules to search. /// - /// @param[in] path + /// \param[in] module /// The path to the exact module to be loaded. E.g., if the desired /// module is std.io, then this should be { "std", "io" }. /// - /// @param[in] exported_modules + /// \param[in] exported_modules /// If non-NULL, a pointer to a vector to populate with the ID of every /// module that is re-exported by the specified module. /// - /// @param[in] error_stream + /// \param[in] error_stream /// A stream to populate with the output of the Clang parser when /// it tries to load the module. /// - /// @return + /// \return /// True if the module could be loaded; false if not. If the /// compiler encountered a fatal error during a previous module /// load, then this will always return false for this ModuleImporter. - //------------------------------------------------------------------ - virtual bool AddModule(ModulePath &path, ModuleVector *exported_modules, + virtual bool AddModule(const SourceModule &module, + ModuleVector *exported_modules, Stream &error_stream) = 0; - //------------------------------------------------------------------ /// Add all modules referred to in a given compilation unit to the list /// of modules to search. /// - /// @param[in] cu + /// \param[in] cu /// The compilation unit to scan for imported modules. /// - /// @param[in] exported_modules + /// \param[in] exported_modules /// A vector to populate with the ID of each module loaded (directly /// and via re-exports) in this way. /// - /// @param[in] error_stream + /// \param[in] error_stream /// A stream to populate with the output of the Clang parser when /// it tries to load the modules. /// - /// @return + /// \return /// True if all modules referred to by the compilation unit could be /// loaded; false if one could not be loaded. If the compiler /// encountered a fatal error during a previous module /// load, then this will always return false for this ModuleImporter. - //------------------------------------------------------------------ virtual bool AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules, Stream &error_stream) = 0; - //------------------------------------------------------------------ /// Enumerate all the macros that are defined by a given set of modules /// that are already imported. /// - /// @param[in] modules + /// \param[in] modules /// The unique IDs for all modules to query. Later modules have higher /// priority, just as if you @imported them in that order. This matters /// if module A #defines a macro and module B #undefs it. /// - /// @param[in] handler + /// \param[in] handler /// A function to call with the text of each #define (including the /// #define directive). #undef directives are not included; we simply /// elide any corresponding #define. If this function returns true, /// we stop the iteration immediately. - //------------------------------------------------------------------ virtual void ForEachMacro(const ModuleVector &modules, std::function<bool(const std::string &)> handler) = 0; - //------------------------------------------------------------------ /// Query whether Clang supports modules for a particular language. /// LLDB uses this to decide whether to try to find the modules loaded - /// by a gaiven compile unit. + /// by a given compile unit. /// - /// @param[in] language + /// \param[in] language /// The language to query for. /// - /// @return + /// \return /// True if Clang has modules for the given language. - //------------------------------------------------------------------ static bool LanguageSupportsClangModules(lldb::LanguageType language); }; diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index bb73d55a9a41..742a14992dc9 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -1,15 +1,15 @@ //===-- ClangPersistentVariables.cpp ----------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 "ClangPersistentVariables.h" #include "lldb/Core/Value.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" @@ -32,7 +32,7 @@ ExpressionVariableSP ClangPersistentVariables::CreatePersistentVariable( } ExpressionVariableSP ClangPersistentVariables::CreatePersistentVariable( - ExecutionContextScope *exe_scope, const ConstString &name, + ExecutionContextScope *exe_scope, ConstString name, const CompilerType &compiler_type, lldb::ByteOrder byte_order, uint32_t addr_byte_size) { return AddNewlyConstructedVariable(new ClangExpressionVariable( @@ -49,11 +49,26 @@ void ClangPersistentVariables::RemovePersistentVariable( return; name++; - if (strtoul(name, NULL, 0) == m_next_persistent_variable_id - 1) + if (strtoul(name, nullptr, 0) == m_next_persistent_variable_id - 1) m_next_persistent_variable_id--; } -void ClangPersistentVariables::RegisterPersistentDecl(const ConstString &name, +llvm::Optional<CompilerType> +ClangPersistentVariables::GetCompilerTypeFromPersistentDecl( + ConstString type_name) { + CompilerType compiler_type; + if (clang::TypeDecl *tdecl = llvm::dyn_cast_or_null<clang::TypeDecl>( + GetPersistentDecl(type_name))) { + compiler_type.SetCompilerType( + ClangASTContext::GetASTContext(&tdecl->getASTContext()), + reinterpret_cast<lldb::opaque_compiler_type_t>( + const_cast<clang::Type *>(tdecl->getTypeForDecl()))); + return compiler_type; + } + return llvm::None; +} + +void ClangPersistentVariables::RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl) { m_persistent_decls.insert( std::pair<const char *, clang::NamedDecl *>(name.GetCString(), decl)); @@ -68,12 +83,12 @@ void ClangPersistentVariables::RegisterPersistentDecl(const ConstString &name, } clang::NamedDecl * -ClangPersistentVariables::GetPersistentDecl(const ConstString &name) { +ClangPersistentVariables::GetPersistentDecl(ConstString name) { PersistentDeclMap::const_iterator i = m_persistent_decls.find(name.GetCString()); if (i == m_persistent_decls.end()) - return NULL; + return nullptr; else return i->second; } diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index c4438c7e2203..b39f89ad7eef 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -1,9 +1,8 @@ //===-- ClangPersistentVariables.h ------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -19,24 +18,20 @@ namespace lldb_private { -//---------------------------------------------------------------------- -/// @class ClangPersistentVariables ClangPersistentVariables.h +/// \class ClangPersistentVariables ClangPersistentVariables.h /// "lldb/Expression/ClangPersistentVariables.h" Manages persistent values /// that need to be preserved between expression invocations. /// /// A list of variables that can be accessed and updated by any expression. See /// ClangPersistentVariable for more discussion. Also provides an increasing, /// 0-based counter for naming result variables. -//---------------------------------------------------------------------- class ClangPersistentVariables : public PersistentExpressionState { public: ClangPersistentVariables(); ~ClangPersistentVariables() override = default; - //------------------------------------------------------------------ // llvm casting support - //------------------------------------------------------------------ static bool classof(const PersistentExpressionState *pv) { return pv->getKind() == PersistentExpressionState::eKindClang; } @@ -45,7 +40,7 @@ public: CreatePersistentVariable(const lldb::ValueObjectSP &valobj_sp) override; lldb::ExpressionVariableSP CreatePersistentVariable( - ExecutionContextScope *exe_scope, const ConstString &name, + ExecutionContextScope *exe_scope, ConstString name, const CompilerType &compiler_type, lldb::ByteOrder byte_order, uint32_t addr_byte_size) override; @@ -55,9 +50,12 @@ public: return "$"; } - void RegisterPersistentDecl(const ConstString &name, clang::NamedDecl *decl); + llvm::Optional<CompilerType> + GetCompilerTypeFromPersistentDecl(ConstString type_name) override; + + void RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl); - clang::NamedDecl *GetPersistentDecl(const ConstString &name); + clang::NamedDecl *GetPersistentDecl(ConstString name); void AddHandLoadedClangModule(ClangModulesDeclVendor::ModuleID module) { m_hand_loaded_clang_modules.push_back(module); diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index f42955df07aa..2dae5b7022f3 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -1,9 +1,8 @@ //===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -22,6 +21,7 @@ #include "ClangDiagnostic.h" #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" +#include "ClangExpressionSourceCode.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" @@ -37,6 +37,7 @@ #include "lldb/Symbol/Block.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" @@ -55,18 +56,20 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "llvm/ADT/ScopeExit.h" + using namespace lldb_private; ClangUserExpression::ClangUserExpression( ExecutionContextScope &exe_scope, llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, - ResultType desired_type, const EvaluateExpressionOptions &options) + ResultType desired_type, const EvaluateExpressionOptions &options, + ValueObject *ctx_obj) : LLVMUserExpression(exe_scope, expr, prefix, language, desired_type, - options), - m_type_system_helper(*m_target_wp.lock().get(), - options.GetExecutionPolicy() == - eExecutionPolicyTopLevel), - m_result_delegate(exe_scope.CalculateTarget()) { + options, eKindClangUserExpression), + m_type_system_helper(*m_target_wp.lock(), options.GetExecutionPolicy() == + eExecutionPolicyTopLevel), + m_result_delegate(exe_scope.CalculateTarget()), m_ctx_obj(ctx_obj) { switch (m_language) { case lldb::eLanguageTypeC_plus_plus: m_allow_cxx = true; @@ -99,7 +102,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { } StackFrame *frame = exe_ctx.GetFramePtr(); - if (frame == NULL) { + if (frame == nullptr) { if (log) log->Printf(" [CUE::SC] Null stack frame"); return; @@ -131,7 +134,27 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { return; } - if (clang::CXXMethodDecl *method_decl = + if (m_ctx_obj) { + switch (m_ctx_obj->GetObjectRuntimeLanguage()) { + case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC89: + case lldb::eLanguageTypeC99: + case lldb::eLanguageTypeC11: + case lldb::eLanguageTypeC_plus_plus: + case lldb::eLanguageTypeC_plus_plus_03: + case lldb::eLanguageTypeC_plus_plus_11: + case lldb::eLanguageTypeC_plus_plus_14: + m_in_cplusplus_method = true; + break; + case lldb::eLanguageTypeObjC: + case lldb::eLanguageTypeObjC_plus_plus: + m_in_objectivec_method = true; + break; + default: + break; + } + m_needs_object_ptr = true; + } else if (clang::CXXMethodDecl *method_decl = ClangASTContext::DeclContextGetAsCXXMethodDecl(decl_context)) { if (m_allow_cxx && method_decl->isInstance()) { if (m_enforce_valid_object) { @@ -307,21 +330,6 @@ static void ApplyObjcCastHack(std::string &expr) { #undef OBJC_CAST_HACK_FROM } -namespace { -// Utility guard that calls a callback when going out of scope. -class OnExit { -public: - typedef std::function<void(void)> Callback; - - OnExit(Callback const &callback) : m_callback(callback) {} - - ~OnExit() { m_callback(); } - -private: - Callback m_callback; -}; -} // namespace - bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { if (Target *target = exe_ctx.GetTargetPtr()) { @@ -377,7 +385,8 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) { } void ClangUserExpression::UpdateLanguageForExpr( - DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + std::vector<std::string> modules_to_import, bool for_completion) { m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown; std::string prefix = m_expr_prefix; @@ -385,8 +394,8 @@ void ClangUserExpression::UpdateLanguageForExpr( if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { m_transformed_text = m_expr_text; } else { - std::unique_ptr<ExpressionSourceCode> source_code( - ExpressionSourceCode::CreateWrapped(prefix.c_str(), + std::unique_ptr<ClangExpressionSourceCode> source_code( + ClangExpressionSourceCode::CreateWrapped(prefix.c_str(), m_expr_text.c_str())); if (m_in_cplusplus_method) @@ -397,7 +406,8 @@ void ClangUserExpression::UpdateLanguageForExpr( m_expr_lang = lldb::eLanguageTypeC; if (!source_code->GetText(m_transformed_text, m_expr_lang, - m_in_static_method, exe_ctx)) { + m_in_static_method, exe_ctx, !m_ctx_obj, + for_completion, modules_to_import)) { diagnostic_manager.PutString(eDiagnosticSeverityError, "couldn't construct expression body"); return; @@ -409,14 +419,73 @@ void ClangUserExpression::UpdateLanguageForExpr( std::size_t original_end; bool found_bounds = source_code->GetOriginalBodyBounds( m_transformed_text, m_expr_lang, original_start, original_end); - if (found_bounds) { + if (found_bounds) m_user_expression_start_pos = original_start; + } +} + +static bool SupportsCxxModuleImport(lldb::LanguageType language) { + switch (language) { + case lldb::eLanguageTypeC_plus_plus: + case lldb::eLanguageTypeC_plus_plus_03: + case lldb::eLanguageTypeC_plus_plus_11: + case lldb::eLanguageTypeC_plus_plus_14: + case lldb::eLanguageTypeObjC_plus_plus: + return true; + default: + return false; + } +} + +std::vector<std::string> +ClangUserExpression::GetModulesToImport(ExecutionContext &exe_ctx) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (!SupportsCxxModuleImport(Language())) + return {}; + + Target *target = exe_ctx.GetTargetPtr(); + if (!target || !target->GetEnableImportStdModule()) + return {}; + + StackFrame *frame = exe_ctx.GetFramePtr(); + if (!frame) + return {}; + + Block *block = frame->GetFrameBlock(); + if (!block) + return {}; + + SymbolContext sc; + block->CalculateSymbolContext(&sc); + if (!sc.comp_unit) + return {}; + + if (log) { + for (const SourceModule &m : sc.comp_unit->GetImportedModules()) { + LLDB_LOG(log, "Found module in compile unit: {0:$[.]} - include dir: {1}", + llvm::make_range(m.path.begin(), m.path.end()), m.search_path); } } + + for (const SourceModule &m : sc.comp_unit->GetImportedModules()) + m_include_directories.push_back(m.search_path); + + // Check if we imported 'std' or any of its submodules. + // We currently don't support importing any other modules in the expression + // parser. + for (const SourceModule &m : sc.comp_unit->GetImportedModules()) + if (!m.path.empty() && m.path.front() == "std") + return {"std"}; + + return {}; } bool ClangUserExpression::PrepareForParsing( - DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + bool for_completion) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + InstallContext(exe_ctx); if (!SetupPersistentState(diagnostic_manager, exe_ctx)) @@ -437,7 +506,14 @@ bool ClangUserExpression::PrepareForParsing( SetupDeclVendor(exe_ctx, m_target); - UpdateLanguageForExpr(diagnostic_manager, exe_ctx); + std::vector<std::string> used_modules = GetModulesToImport(exe_ctx); + m_imported_cpp_modules = !used_modules.empty(); + + LLDB_LOG(log, "List of imported modules in expression: {0}", + llvm::make_range(used_modules.begin(), used_modules.end())); + + UpdateLanguageForExpr(diagnostic_manager, exe_ctx, used_modules, + for_completion); return true; } @@ -448,7 +524,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, bool generate_debug_info) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (!PrepareForParsing(diagnostic_manager, exe_ctx)) + if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false)) return false; if (log) @@ -469,13 +545,13 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // Parse the expression // - m_materializer_ap.reset(new Materializer()); + m_materializer_up.reset(new Materializer()); ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory); - OnExit on_exit([this]() { ResetDeclMap(); }); + auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); }); - if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) { + if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) { diagnostic_manager.PutString( eDiagnosticSeverityError, "current process state is unsuitable for expression parsing"); @@ -496,7 +572,8 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // succeeds or the rewrite parser we might make if it fails. But the // parser_sp will never be empty. - ClangExpressionParser parser(exe_scope, *this, generate_debug_info); + ClangExpressionParser parser(exe_scope, *this, generate_debug_info, + m_include_directories); unsigned num_errors = parser.Parse(diagnostic_manager); @@ -509,7 +586,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, size_t fixed_end; const std::string &fixed_expression = diagnostic_manager.GetFixedExpression(); - if (ExpressionSourceCode::GetOriginalBodyBounds( + if (ClangExpressionSourceCode::GetOriginalBodyBounds( fixed_expression, m_expr_lang, fixed_start, fixed_end)) m_fixed_text = fixed_expression.substr(fixed_start, fixed_end - fixed_start); @@ -518,7 +595,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, return false; } - ////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// // Prepare the output of the parser for execution, evaluating it statically // if possible // @@ -597,25 +674,23 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, return true; } -//------------------------------------------------------------------ /// Converts an absolute position inside a given code string into /// a column/line pair. /// -/// @param[in] abs_pos +/// \param[in] abs_pos /// A absolute position in the code string that we want to convert /// to a column/line pair. /// -/// @param[in] code +/// \param[in] code /// A multi-line string usually representing source code. /// -/// @param[out] line +/// \param[out] line /// The line in the code that contains the given absolute position. /// The first line in the string is indexed as 1. /// -/// @param[out] column +/// \param[out] column /// The column in the line that contains the absolute position. /// The first character in a line is indexed as 0. -//------------------------------------------------------------------ static void AbsPosToLineColumnPos(size_t abs_pos, llvm::StringRef code, unsigned &line, unsigned &column) { // Reset to code position to beginning of the file. @@ -648,7 +723,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, // correct. DiagnosticManager diagnostic_manager; - if (!PrepareForParsing(diagnostic_manager, exe_ctx)) + if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ true)) return false; if (log) @@ -658,13 +733,13 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, // Parse the expression // - m_materializer_ap.reset(new Materializer()); + m_materializer_up.reset(new Materializer()); ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true); - OnExit on_exit([this]() { ResetDeclMap(); }); + auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); }); - if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) { + if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) { diagnostic_manager.PutString( eDiagnosticSeverityError, "current process state is unsuitable for expression parsing"); @@ -734,7 +809,15 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, Status object_ptr_error; - object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error); + if (m_ctx_obj) { + AddressType address_type; + object_ptr = m_ctx_obj->GetAddressOf(false, &address_type); + if (object_ptr == LLDB_INVALID_ADDRESS || + address_type != eAddressTypeLoad) + object_ptr_error.SetErrorString("Can't get context object's " + "debuggee address"); + } else + object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error); if (!object_ptr_error.Success()) { exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf( @@ -777,9 +860,11 @@ lldb::ExpressionVariableSP ClangUserExpression::GetResultAfterDematerialization( void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap( ExecutionContext &exe_ctx, Materializer::PersistentVariableDelegate &delegate, - bool keep_result_in_memory) { + bool keep_result_in_memory, + ValueObject *ctx_obj) { m_expr_decl_map_up.reset( - new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx)); + new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx, + ctx_obj)); } clang::ASTConsumer * @@ -792,7 +877,7 @@ ClangUserExpression::ClangUserExpressionHelper::ASTTransformer( } void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() { - if (m_result_synthesizer_up.get()) { + if (m_result_synthesizer_up) { m_result_synthesizer_up->CommitPersistentDecls(); } } diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index 7e4cba661850..24c152bdb45d 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -1,9 +1,8 @@ //===-- ClangUserExpression.h -----------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -29,8 +28,7 @@ namespace lldb_private { -//---------------------------------------------------------------------- -/// @class ClangUserExpression ClangUserExpression.h +/// \class ClangUserExpression ClangUserExpression.h /// "lldb/Expression/ClangUserExpression.h" Encapsulates a single expression /// for use with Clang /// @@ -38,9 +36,13 @@ namespace lldb_private { /// and as a backend for the expr command. ClangUserExpression encapsulates /// the objects needed to parse and interpret or JIT an expression. It uses /// the Clang parser to produce LLVM IR from the expression. -//---------------------------------------------------------------------- class ClangUserExpression : public LLVMUserExpression { public: + /// LLVM-style RTTI support. + static bool classof(const Expression *E) { + return E->getKind() == eKindClangUserExpression; + } + enum { kDefaultTimeout = 500000u }; class ClangUserExpressionHelper : public ClangExpressionHelper { @@ -50,10 +52,8 @@ public: ~ClangUserExpressionHelper() override = default; - //------------------------------------------------------------------ /// Return the object that the parser should use when resolving external /// values. May be NULL if everything should be self-contained. - //------------------------------------------------------------------ ClangExpressionDeclMap *DeclMap() override { return m_expr_decl_map_up.get(); } @@ -62,16 +62,15 @@ public: void ResetDeclMap(ExecutionContext &exe_ctx, Materializer::PersistentVariableDelegate &result_delegate, - bool keep_result_in_memory); + bool keep_result_in_memory, + ValueObject *ctx_obj); - //------------------------------------------------------------------ /// Return the object that the parser should allow to access ASTs. May be /// NULL if the ASTs do not need to be transformed. /// - /// @param[in] passthrough + /// \param[in] passthrough /// The ASTConsumer that the returned transformer should send /// the ASTs to after transformation. - //------------------------------------------------------------------ clang::ASTConsumer * ASTTransformer(clang::ASTConsumer *passthrough) override; @@ -88,53 +87,55 @@ public: bool m_top_level; }; - //------------------------------------------------------------------ /// Constructor /// - /// @param[in] expr + /// \param[in] expr /// The expression to parse. /// - /// @param[in] expr_prefix + /// \param[in] expr_prefix /// If non-NULL, a C string containing translation-unit level /// definitions to be included when the expression is parsed. /// - /// @param[in] language + /// \param[in] language /// If not eLanguageTypeUnknown, a language to use when parsing /// the expression. Currently restricted to those languages /// supported by Clang. /// - /// @param[in] desired_type + /// \param[in] desired_type /// If not eResultTypeAny, the type to use for the expression /// result. - //------------------------------------------------------------------ + /// + /// \param[in] ctx_obj + /// The object (if any) in which context the expression + /// must be evaluated. For details see the comment to + /// `UserExpression::Evaluate`. ClangUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, ResultType desired_type, - const EvaluateExpressionOptions &options); + const EvaluateExpressionOptions &options, + ValueObject *ctx_obj); ~ClangUserExpression() override; - //------------------------------------------------------------------ /// Parse the expression /// - /// @param[in] diagnostic_manager + /// \param[in] diagnostic_manager /// A diagnostic manager to report parse errors and warnings to. /// - /// @param[in] exe_ctx + /// \param[in] exe_ctx /// The execution context to use when looking up entities that /// are needed for parsing (locations of functions, types of /// variables, persistent variables, etc.) /// - /// @param[in] execution_policy + /// \param[in] execution_policy /// Determines whether interpretation is possible or mandatory. /// - /// @param[in] keep_result_in_memory + /// \param[in] keep_result_in_memory /// True if the resulting persistent variable should reside in /// target memory, if applicable. /// - /// @return + /// \return /// True on success (no errors); false otherwise. - //------------------------------------------------------------------ bool Parse(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, bool generate_debug_info) override; @@ -154,17 +155,18 @@ public: Materializer::PersistentVariableDelegate &result_delegate, bool keep_result_in_memory) { m_type_system_helper.ResetDeclMap(exe_ctx, result_delegate, - keep_result_in_memory); + keep_result_in_memory, + m_ctx_obj); } lldb::ExpressionVariableSP GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override; + bool DidImportCxxModules() const { return m_imported_cpp_modules; } + private: - //------------------------------------------------------------------ /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the /// environment. - //------------------------------------------------------------------ void ScanContext(ExecutionContext &exe_ctx, lldb_private::Status &err) override; @@ -173,12 +175,15 @@ private: lldb::addr_t struct_address, DiagnosticManager &diagnostic_manager) override; + std::vector<std::string> GetModulesToImport(ExecutionContext &exe_ctx); void UpdateLanguageForExpr(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx); + ExecutionContext &exe_ctx, + std::vector<std::string> modules_to_import, + bool for_completion); bool SetupPersistentState(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx); bool PrepareForParsing(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx); + ExecutionContext &exe_ctx, bool for_completion); ClangUserExpressionHelper m_type_system_helper; @@ -199,12 +204,21 @@ private: /// The language type of the current expression. lldb::LanguageType m_expr_lang = lldb::eLanguageTypeUnknown; + /// The include directories that should be used when parsing the expression. + std::vector<ConstString> m_include_directories; /// The absolute character position in the transformed source code where the /// user code (as typed by the user) starts. If the variable is empty, then we /// were not able to calculate this position. llvm::Optional<size_t> m_user_expression_start_pos; ResultDelegate m_result_delegate; + + /// The object (if any) in which context the expression is evaluated. + /// See the comment to `UserExpression::Evaluate` for details. + ValueObject *m_ctx_obj; + + /// True iff this expression explicitly imported C++ modules. + bool m_imported_cpp_modules = false; }; } // namespace lldb_private diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index fe6ca450a79d..5eec224477fc 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -1,15 +1,15 @@ //===-- ClangUtilityFunction.cpp ---------------------------------*- C++-*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 "ClangUtilityFunction.h" #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" +#include "ClangExpressionSourceCode.h" #include <stdio.h> #if HAVE_SYS_TYPES_H @@ -19,7 +19,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" -#include "lldb/Expression/ExpressionSourceCode.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Host/Host.h" #include "lldb/Target/ExecutionContext.h" @@ -30,33 +29,33 @@ using namespace lldb_private; -//------------------------------------------------------------------ /// Constructor /// -/// @param[in] text +/// \param[in] text /// The text of the function. Must be a full translation unit. /// -/// @param[in] name +/// \param[in] name /// The name of the function, as used in the text. -//------------------------------------------------------------------ ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope, const char *text, const char *name) - : UtilityFunction(exe_scope, text, name) {} + : UtilityFunction(exe_scope, text, name, eKindClangUtilityFunction) { + m_function_text.assign(ClangExpressionSourceCode::g_expression_prefix); + if (text && text[0]) + m_function_text.append(text); +} ClangUtilityFunction::~ClangUtilityFunction() {} -//------------------------------------------------------------------ /// Install the utility function into a process /// -/// @param[in] diagnostic_manager +/// \param[in] diagnostic_manager /// A diagnostic manager to report errors and warnings to. /// -/// @param[in] exe_ctx +/// \param[in] exe_ctx /// The execution context to install the utility function to. /// -/// @return +/// \return /// True on success (no errors); false otherwise. -//------------------------------------------------------------------ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { if (m_jit_start_addr != LLDB_INVALID_ADDRESS) { @@ -91,7 +90,7 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, ResetDeclMap(exe_ctx, keep_result_in_memory); - if (!DeclMap()->WillParse(exe_ctx, NULL)) { + if (!DeclMap()->WillParse(exe_ctx, nullptr)) { diagnostic_manager.PutString( eDiagnosticSeverityError, "current process state is unsuitable for expression parsing"); @@ -157,5 +156,6 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap( ExecutionContext &exe_ctx, bool keep_result_in_memory) { m_expr_decl_map_up.reset( - new ClangExpressionDeclMap(keep_result_in_memory, nullptr, exe_ctx)); + new ClangExpressionDeclMap(keep_result_in_memory, nullptr, exe_ctx, + nullptr)); } diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index b0650f0eda02..70ebb2f3ad8a 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -1,9 +1,8 @@ //===-- ClangUtilityFunction.h ----------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -23,8 +22,7 @@ namespace lldb_private { -//---------------------------------------------------------------------- -/// @class ClangUtilityFunction ClangUtilityFunction.h +/// \class ClangUtilityFunction ClangUtilityFunction.h /// "lldb/Expression/ClangUtilityFunction.h" Encapsulates a single expression /// for use with Clang /// @@ -34,19 +32,21 @@ namespace lldb_private { /// functions can perform error-checking for ClangUserExpressions, or can /// simply provide a way to push a function into the target for the debugger /// to call later on. -//---------------------------------------------------------------------- class ClangUtilityFunction : public UtilityFunction { public: + /// LLVM-style RTTI support. + static bool classof(const Expression *E) { + return E->getKind() == eKindClangUtilityFunction; + } + class ClangUtilityFunctionHelper : public ClangExpressionHelper { public: ClangUtilityFunctionHelper() {} ~ClangUtilityFunctionHelper() override {} - //------------------------------------------------------------------ /// Return the object that the parser should use when resolving external /// values. May be NULL if everything should be self-contained. - //------------------------------------------------------------------ ClangExpressionDeclMap *DeclMap() override { return m_expr_decl_map_up.get(); } @@ -55,14 +55,12 @@ public: void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory); - //------------------------------------------------------------------ /// Return the object that the parser should allow to access ASTs. May be /// NULL if the ASTs do not need to be transformed. /// - /// @param[in] passthrough + /// \param[in] passthrough /// The ASTConsumer that the returned transformer should send /// the ASTs to after transformation. - //------------------------------------------------------------------ clang::ASTConsumer * ASTTransformer(clang::ASTConsumer *passthrough) override { return nullptr; @@ -71,15 +69,13 @@ public: private: std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up; }; - //------------------------------------------------------------------ /// Constructor /// - /// @param[in] text + /// \param[in] text /// The text of the function. Must be a full translation unit. /// - /// @param[in] name + /// \param[in] name /// The name of the function, as used in the text. - //------------------------------------------------------------------ ClangUtilityFunction(ExecutionContextScope &exe_scope, const char *text, const char *name); diff --git a/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp b/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp new file mode 100644 index 000000000000..f8e004fe7d4a --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp @@ -0,0 +1,595 @@ +//===-- IRDynamicChecks.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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/raw_ostream.h" + +#include "IRDynamicChecks.h" + +#include "lldb/Expression/UtilityFunction.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Log.h" + +#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" + +using namespace llvm; +using namespace lldb_private; + +static char ID; + +#define VALID_POINTER_CHECK_NAME "_$__lldb_valid_pointer_check" +#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check" + +static const char g_valid_pointer_check_text[] = + "extern \"C\" void\n" + "_$__lldb_valid_pointer_check (unsigned char *$__lldb_arg_ptr)\n" + "{\n" + " unsigned char $__lldb_local_val = *$__lldb_arg_ptr;\n" + "}"; + +ClangDynamicCheckerFunctions::ClangDynamicCheckerFunctions() + : DynamicCheckerFunctions(DCF_Clang) {} + +ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default; + +bool ClangDynamicCheckerFunctions::Install( + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { + Status error; + m_valid_pointer_check.reset( + exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( + g_valid_pointer_check_text, lldb::eLanguageTypeC, + VALID_POINTER_CHECK_NAME, error)); + if (error.Fail()) + return false; + + if (!m_valid_pointer_check->Install(diagnostic_manager, exe_ctx)) + return false; + + Process *process = exe_ctx.GetProcessPtr(); + + if (process) { + ObjCLanguageRuntime *objc_language_runtime = + ObjCLanguageRuntime::Get(*process); + + if (objc_language_runtime) { + m_objc_object_check.reset(objc_language_runtime->CreateObjectChecker( + VALID_OBJC_OBJECT_CHECK_NAME)); + + if (!m_objc_object_check->Install(diagnostic_manager, exe_ctx)) + return false; + } + } + + return true; +} + +bool ClangDynamicCheckerFunctions::DoCheckersExplainStop(lldb::addr_t addr, + Stream &message) { + // FIXME: We have to get the checkers to know why they scotched the call in + // more detail, + // so we can print a better message here. + if (m_valid_pointer_check && m_valid_pointer_check->ContainsAddress(addr)) { + message.Printf("Attempted to dereference an invalid pointer."); + return true; + } else if (m_objc_object_check && + m_objc_object_check->ContainsAddress(addr)) { + message.Printf("Attempted to dereference an invalid ObjC Object or send it " + "an unrecognized selector"); + return true; + } + return false; +} + +static std::string PrintValue(llvm::Value *V, bool truncate = false) { + std::string s; + raw_string_ostream rso(s); + V->print(rso); + rso.flush(); + if (truncate) + s.resize(s.length() - 1); + return s; +} + +/// \class Instrumenter IRDynamicChecks.cpp +/// Finds and instruments individual LLVM IR instructions +/// +/// When instrumenting LLVM IR, it is frequently desirable to first search for +/// instructions, and then later modify them. This way iterators remain +/// intact, and multiple passes can look at the same code base without +/// treading on each other's toes. +/// +/// The Instrumenter class implements this functionality. A client first +/// calls Inspect on a function, which populates a list of instructions to be +/// instrumented. Then, later, when all passes' Inspect functions have been +/// called, the client calls Instrument, which adds the desired +/// instrumentation. +/// +/// A subclass of Instrumenter must override InstrumentInstruction, which +/// is responsible for adding whatever instrumentation is necessary. +/// +/// A subclass of Instrumenter may override: +/// +/// - InspectInstruction [default: does nothing] +/// +/// - InspectBasicBlock [default: iterates through the instructions in a +/// basic block calling InspectInstruction] +/// +/// - InspectFunction [default: iterates through the basic blocks in a +/// function calling InspectBasicBlock] +class Instrumenter { +public: + /// Constructor + /// + /// \param[in] module + /// The module being instrumented. + Instrumenter(llvm::Module &module, + std::shared_ptr<UtilityFunction> checker_function) + : m_module(module), m_checker_function(checker_function), + m_i8ptr_ty(nullptr), m_intptr_ty(nullptr) {} + + virtual ~Instrumenter() = default; + + /// Inspect a function to find instructions to instrument + /// + /// \param[in] function + /// The function to inspect. + /// + /// \return + /// True on success; false on error. + bool Inspect(llvm::Function &function) { return InspectFunction(function); } + + /// Instrument all the instructions found by Inspect() + /// + /// \return + /// True on success; false on error. + bool Instrument() { + for (InstIterator ii = m_to_instrument.begin(), + last_ii = m_to_instrument.end(); + ii != last_ii; ++ii) { + if (!InstrumentInstruction(*ii)) + return false; + } + + return true; + } + +protected: + /// Add instrumentation to a single instruction + /// + /// \param[in] inst + /// The instruction to be instrumented. + /// + /// \return + /// True on success; false otherwise. + virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0; + + /// Register a single instruction to be instrumented + /// + /// \param[in] inst + /// The instruction to be instrumented. + void RegisterInstruction(llvm::Instruction &i) { + m_to_instrument.push_back(&i); + } + + /// Determine whether a single instruction is interesting to instrument, + /// and, if so, call RegisterInstruction + /// + /// \param[in] i + /// The instruction to be inspected. + /// + /// \return + /// False if there was an error scanning; true otherwise. + virtual bool InspectInstruction(llvm::Instruction &i) { return true; } + + /// Scan a basic block to see if any instructions are interesting + /// + /// \param[in] bb + /// The basic block to be inspected. + /// + /// \return + /// False if there was an error scanning; true otherwise. + virtual bool InspectBasicBlock(llvm::BasicBlock &bb) { + for (llvm::BasicBlock::iterator ii = bb.begin(), last_ii = bb.end(); + ii != last_ii; ++ii) { + if (!InspectInstruction(*ii)) + return false; + } + + return true; + } + + /// Scan a function to see if any instructions are interesting + /// + /// \param[in] f + /// The function to be inspected. + /// + /// \return + /// False if there was an error scanning; true otherwise. + virtual bool InspectFunction(llvm::Function &f) { + for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end(); + bbi != last_bbi; ++bbi) { + if (!InspectBasicBlock(*bbi)) + return false; + } + + return true; + } + + /// Build a function pointer for a function with signature void + /// (*)(uint8_t*) with a given address + /// + /// \param[in] start_address + /// The address of the function. + /// + /// \return + /// The function pointer, for use in a CallInst. + llvm::FunctionCallee BuildPointerValidatorFunc(lldb::addr_t start_address) { + llvm::Type *param_array[1]; + + param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy()); + + ArrayRef<llvm::Type *> params(param_array, 1); + + FunctionType *fun_ty = FunctionType::get( + llvm::Type::getVoidTy(m_module.getContext()), params, true); + PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty); + Constant *fun_addr_int = + ConstantInt::get(GetIntptrTy(), start_address, false); + return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)}; + } + + /// Build a function pointer for a function with signature void + /// (*)(uint8_t*, uint8_t*) with a given address + /// + /// \param[in] start_address + /// The address of the function. + /// + /// \return + /// The function pointer, for use in a CallInst. + llvm::FunctionCallee BuildObjectCheckerFunc(lldb::addr_t start_address) { + llvm::Type *param_array[2]; + + param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy()); + param_array[1] = const_cast<llvm::PointerType *>(GetI8PtrTy()); + + ArrayRef<llvm::Type *> params(param_array, 2); + + FunctionType *fun_ty = FunctionType::get( + llvm::Type::getVoidTy(m_module.getContext()), params, true); + PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty); + Constant *fun_addr_int = + ConstantInt::get(GetIntptrTy(), start_address, false); + return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)}; + } + + PointerType *GetI8PtrTy() { + if (!m_i8ptr_ty) + m_i8ptr_ty = llvm::Type::getInt8PtrTy(m_module.getContext()); + + return m_i8ptr_ty; + } + + IntegerType *GetIntptrTy() { + if (!m_intptr_ty) { + llvm::DataLayout data_layout(&m_module); + + m_intptr_ty = llvm::Type::getIntNTy(m_module.getContext(), + data_layout.getPointerSizeInBits()); + } + + return m_intptr_ty; + } + + typedef std::vector<llvm::Instruction *> InstVector; + typedef InstVector::iterator InstIterator; + + InstVector m_to_instrument; ///< List of instructions the inspector found + llvm::Module &m_module; ///< The module which is being instrumented + std::shared_ptr<UtilityFunction> + m_checker_function; ///< The dynamic checker function for the process + +private: + PointerType *m_i8ptr_ty; + IntegerType *m_intptr_ty; +}; + +class ValidPointerChecker : public Instrumenter { +public: + ValidPointerChecker(llvm::Module &module, + std::shared_ptr<UtilityFunction> checker_function) + : Instrumenter(module, checker_function), + m_valid_pointer_check_func(nullptr) {} + + ~ValidPointerChecker() override = default; + +protected: + bool InstrumentInstruction(llvm::Instruction *inst) override { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + log->Printf("Instrumenting load/store instruction: %s\n", + PrintValue(inst).c_str()); + + if (!m_valid_pointer_check_func) + m_valid_pointer_check_func = + BuildPointerValidatorFunc(m_checker_function->StartAddress()); + + llvm::Value *dereferenced_ptr = nullptr; + + if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst>(inst)) + dereferenced_ptr = li->getPointerOperand(); + else if (llvm::StoreInst *si = dyn_cast<llvm::StoreInst>(inst)) + dereferenced_ptr = si->getPointerOperand(); + else + return false; + + // Insert an instruction to cast the loaded value to int8_t* + + BitCastInst *bit_cast = + new BitCastInst(dereferenced_ptr, GetI8PtrTy(), "", inst); + + // Insert an instruction to call the helper with the result + + llvm::Value *arg_array[1]; + + arg_array[0] = bit_cast; + + llvm::ArrayRef<llvm::Value *> args(arg_array, 1); + + CallInst::Create(m_valid_pointer_check_func, args, "", inst); + + return true; + } + + bool InspectInstruction(llvm::Instruction &i) override { + if (dyn_cast<llvm::LoadInst>(&i) || dyn_cast<llvm::StoreInst>(&i)) + RegisterInstruction(i); + + return true; + } + +private: + llvm::FunctionCallee m_valid_pointer_check_func; +}; + +class ObjcObjectChecker : public Instrumenter { +public: + ObjcObjectChecker(llvm::Module &module, + std::shared_ptr<UtilityFunction> checker_function) + : Instrumenter(module, checker_function), + m_objc_object_check_func(nullptr) {} + + ~ObjcObjectChecker() override = default; + + enum msgSend_type { + eMsgSend = 0, + eMsgSendSuper, + eMsgSendSuper_stret, + eMsgSend_fpret, + eMsgSend_stret + }; + + std::map<llvm::Instruction *, msgSend_type> msgSend_types; + +protected: + bool InstrumentInstruction(llvm::Instruction *inst) override { + CallInst *call_inst = dyn_cast<CallInst>(inst); + + if (!call_inst) + return false; // call_inst really shouldn't be nullptr, because otherwise + // InspectInstruction wouldn't have registered it + + if (!m_objc_object_check_func) + m_objc_object_check_func = + BuildObjectCheckerFunc(m_checker_function->StartAddress()); + + // id objc_msgSend(id theReceiver, SEL theSelector, ...) + + llvm::Value *target_object; + llvm::Value *selector; + + switch (msgSend_types[inst]) { + case eMsgSend: + case eMsgSend_fpret: + // On arm64, clang uses objc_msgSend for scalar and struct return + // calls. The call instruction will record which was used. + if (call_inst->hasStructRetAttr()) { + target_object = call_inst->getArgOperand(1); + selector = call_inst->getArgOperand(2); + } else { + target_object = call_inst->getArgOperand(0); + selector = call_inst->getArgOperand(1); + } + break; + case eMsgSend_stret: + target_object = call_inst->getArgOperand(1); + selector = call_inst->getArgOperand(2); + break; + case eMsgSendSuper: + case eMsgSendSuper_stret: + return true; + } + + // These objects should always be valid according to Sean Calannan + assert(target_object); + assert(selector); + + // Insert an instruction to cast the receiver id to int8_t* + + BitCastInst *bit_cast = + new BitCastInst(target_object, GetI8PtrTy(), "", inst); + + // Insert an instruction to call the helper with the result + + llvm::Value *arg_array[2]; + + arg_array[0] = bit_cast; + arg_array[1] = selector; + + ArrayRef<llvm::Value *> args(arg_array, 2); + + CallInst::Create(m_objc_object_check_func, args, "", inst); + + return true; + } + + static llvm::Function *GetFunction(llvm::Value *value) { + if (llvm::Function *function = llvm::dyn_cast<llvm::Function>(value)) { + return function; + } + + if (llvm::ConstantExpr *const_expr = + llvm::dyn_cast<llvm::ConstantExpr>(value)) { + switch (const_expr->getOpcode()) { + default: + return nullptr; + case llvm::Instruction::BitCast: + return GetFunction(const_expr->getOperand(0)); + } + } + + return nullptr; + } + + static llvm::Function *GetCalledFunction(llvm::CallInst *inst) { + return GetFunction(inst->getCalledValue()); + } + + bool InspectInstruction(llvm::Instruction &i) override { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + CallInst *call_inst = dyn_cast<CallInst>(&i); + + if (call_inst) { + const llvm::Function *called_function = GetCalledFunction(call_inst); + + if (!called_function) + return true; + + std::string name_str = called_function->getName().str(); + const char *name_cstr = name_str.c_str(); + + if (log) + log->Printf("Found call to %s: %s\n", name_cstr, + PrintValue(call_inst).c_str()); + + if (name_str.find("objc_msgSend") == std::string::npos) + return true; + + if (!strcmp(name_cstr, "objc_msgSend")) { + RegisterInstruction(i); + msgSend_types[&i] = eMsgSend; + return true; + } + + if (!strcmp(name_cstr, "objc_msgSend_stret")) { + RegisterInstruction(i); + msgSend_types[&i] = eMsgSend_stret; + return true; + } + + if (!strcmp(name_cstr, "objc_msgSend_fpret")) { + RegisterInstruction(i); + msgSend_types[&i] = eMsgSend_fpret; + return true; + } + + if (!strcmp(name_cstr, "objc_msgSendSuper")) { + RegisterInstruction(i); + msgSend_types[&i] = eMsgSendSuper; + return true; + } + + if (!strcmp(name_cstr, "objc_msgSendSuper_stret")) { + RegisterInstruction(i); + msgSend_types[&i] = eMsgSendSuper_stret; + return true; + } + + if (log) + log->Printf( + "Function name '%s' contains 'objc_msgSend' but is not handled", + name_str.c_str()); + + return true; + } + + return true; + } + +private: + llvm::FunctionCallee m_objc_object_check_func; +}; + +IRDynamicChecks::IRDynamicChecks( + ClangDynamicCheckerFunctions &checker_functions, const char *func_name) + : ModulePass(ID), m_func_name(func_name), + m_checker_functions(checker_functions) {} + +IRDynamicChecks::~IRDynamicChecks() = default; + +bool IRDynamicChecks::runOnModule(llvm::Module &M) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + llvm::Function *function = M.getFunction(StringRef(m_func_name)); + + if (!function) { + if (log) + log->Printf("Couldn't find %s() in the module", m_func_name.c_str()); + + return false; + } + + if (m_checker_functions.m_valid_pointer_check) { + ValidPointerChecker vpc(M, m_checker_functions.m_valid_pointer_check); + + if (!vpc.Inspect(*function)) + return false; + + if (!vpc.Instrument()) + return false; + } + + if (m_checker_functions.m_objc_object_check) { + ObjcObjectChecker ooc(M, m_checker_functions.m_objc_object_check); + + if (!ooc.Inspect(*function)) + return false; + + if (!ooc.Instrument()) + return false; + } + + if (log && log->GetVerbose()) { + std::string s; + raw_string_ostream oss(s); + + M.print(oss, nullptr); + + oss.flush(); + + log->Printf("Module after dynamic checks: \n%s", s.c_str()); + } + + return true; +} + +void IRDynamicChecks::assignPassManager(PMStack &PMS, PassManagerType T) {} + +PassManagerType IRDynamicChecks::getPotentialPassManagerType() const { + return PMT_ModulePassManager; +} diff --git a/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h b/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h new file mode 100644 index 000000000000..60c0691b21c1 --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h @@ -0,0 +1,131 @@ +//===-- IRDynamicChecks.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 liblldb_IRDynamicChecks_h_ +#define liblldb_IRDynamicChecks_h_ + +#include "lldb/Expression/DynamicCheckerFunctions.h" +#include "lldb/lldb-types.h" +#include "llvm/Pass.h" + +namespace llvm { +class BasicBlock; +class Module; +} + +namespace lldb_private { + +class ExecutionContext; +class Stream; + +class ClangDynamicCheckerFunctions + : public lldb_private::DynamicCheckerFunctions { +public: + /// Constructor + ClangDynamicCheckerFunctions(); + + /// Destructor + virtual ~ClangDynamicCheckerFunctions(); + + static bool classof(const DynamicCheckerFunctions *checker_funcs) { + return checker_funcs->GetKind() == DCF_Clang; + } + + /// Install the utility functions into a process. This binds the instance + /// of DynamicCheckerFunctions to that process. + /// + /// \param[in] diagnostic_manager + /// A diagnostic manager to report errors to. + /// + /// \param[in] exe_ctx + /// The execution context to install the functions into. + /// + /// \return + /// True on success; false on failure, or if the functions have + /// already been installed. + bool Install(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx) override; + + bool DoCheckersExplainStop(lldb::addr_t addr, Stream &message) override; + + std::shared_ptr<UtilityFunction> m_valid_pointer_check; + std::shared_ptr<UtilityFunction> m_objc_object_check; +}; + +/// \class IRDynamicChecks IRDynamicChecks.h +/// "lldb/Expression/IRDynamicChecks.h" Adds dynamic checks to a user-entered +/// expression to reduce its likelihood of crashing +/// +/// When an IR function is executed in the target process, it may cause +/// crashes or hangs by dereferencing NULL pointers, trying to call +/// Objective-C methods on objects that do not respond to them, and so forth. +/// +/// IRDynamicChecks adds calls to the functions in DynamicCheckerFunctions to +/// appropriate locations in an expression's IR. +class IRDynamicChecks : public llvm::ModulePass { +public: + /// Constructor + /// + /// \param[in] checker_functions + /// The checker functions for the target process. + /// + /// \param[in] func_name + /// The name of the function to prepare for execution in the target. + /// + /// \param[in] decl_map + /// The mapping used to look up entities in the target process. In + /// this case, used to find objc_msgSend + IRDynamicChecks(ClangDynamicCheckerFunctions &checker_functions, + const char *func_name = "$__lldb_expr"); + + /// Destructor + ~IRDynamicChecks() override; + + /// Run this IR transformer on a single module + /// + /// \param[in] M + /// The module to run on. This module is searched for the function + /// $__lldb_expr, and that function is passed to the passes one by + /// one. + /// + /// \return + /// True on success; false otherwise + bool runOnModule(llvm::Module &M) override; + + /// Interface stub + void assignPassManager( + llvm::PMStack &PMS, + llvm::PassManagerType T = llvm::PMT_ModulePassManager) override; + + /// Returns PMT_ModulePassManager + llvm::PassManagerType getPotentialPassManagerType() const override; + +private: + /// A basic block-level pass to find all pointer dereferences and + /// validate them before use. + + /// The top-level pass implementation + /// + /// \param[in] M + /// The module currently being processed. + /// + /// \param[in] BB + /// The basic block currently being processed. + /// + /// \return + /// True on success; false otherwise + bool FindDataLoads(llvm::Module &M, llvm::BasicBlock &BB); + + std::string m_func_name; ///< The name of the function to add checks to + ClangDynamicCheckerFunctions + &m_checker_functions; ///< The checker functions for the process +}; + +} // namespace lldb_private + +#endif // liblldb_IRDynamicChecks_h_ diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 3a7cd58b70ab..07acb2e1030f 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -1,9 +1,8 @@ //===-- IRForTarget.cpp -----------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -61,7 +60,7 @@ IRForTarget::FunctionValueCache::GetValue(llvm::Function *function) { static llvm::Value *FindEntryInstruction(llvm::Function *function) { if (function->empty()) - return NULL; + return nullptr; return function->getEntryBlock().getFirstNonPHIOrDbg(); } @@ -72,11 +71,12 @@ IRForTarget::IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map, lldb_private::Stream &error_stream, const char *func_name) : ModulePass(ID), m_resolve_vars(resolve_vars), m_func_name(func_name), - m_module(NULL), m_decl_map(decl_map), m_CFStringCreateWithBytes(NULL), - m_sel_registerName(NULL), m_objc_getClass(NULL), m_intptr_ty(NULL), - m_error_stream(error_stream), - m_execution_unit(execution_unit), m_result_store(NULL), - m_result_is_pointer(false), m_reloc_placeholder(NULL), + m_module(nullptr), m_decl_map(decl_map), + m_CFStringCreateWithBytes(nullptr), m_sel_registerName(nullptr), + m_objc_getClass(nullptr), m_intptr_ty(nullptr), + m_error_stream(error_stream), m_execution_unit(execution_unit), + m_result_store(nullptr), m_result_is_pointer(false), + m_reloc_placeholder(nullptr), m_entry_instruction_finder(FindEntryInstruction) {} /* Handy utility functions used at several places in the code */ @@ -117,7 +117,7 @@ clang::NamedDecl *IRForTarget::DeclForGlobal(const GlobalValue *global_val, module->getNamedMetadata("clang.global.decl.ptrs"); if (!named_metadata) - return NULL; + return nullptr; unsigned num_nodes = named_metadata->getNumOperands(); unsigned node_index; @@ -126,7 +126,7 @@ clang::NamedDecl *IRForTarget::DeclForGlobal(const GlobalValue *global_val, llvm::MDNode *metadata_node = dyn_cast<llvm::MDNode>(named_metadata->getOperand(node_index)); if (!metadata_node) - return NULL; + return nullptr; if (metadata_node->getNumOperands() != 2) continue; @@ -139,14 +139,14 @@ clang::NamedDecl *IRForTarget::DeclForGlobal(const GlobalValue *global_val, mdconst::dyn_extract<ConstantInt>(metadata_node->getOperand(1)); if (!constant_int) - return NULL; + return nullptr; uintptr_t ptr = constant_int->getZExtValue(); return reinterpret_cast<clang::NamedDecl *>(ptr); } - return NULL; + return nullptr; } clang::NamedDecl *IRForTarget::DeclForGlobal(GlobalValue *global_val) { @@ -165,7 +165,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { ValueSymbolTable &value_symbol_table = m_module->getValueSymbolTable(); std::string result_name_str; - const char *result_name = NULL; + const char *result_name = nullptr; for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end(); @@ -343,8 +343,8 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { GlobalVariable *new_result_global = new GlobalVariable( (*m_module), result_global->getType()->getElementType(), - false, /* not constant */ - GlobalValue::ExternalLinkage, NULL, /* no initializer */ + false, /* not constant */ + GlobalValue::ExternalLinkage, nullptr, /* no initializer */ m_result_name.GetCString()); // It's too late in compilation to create a new VarDecl for this, but we @@ -433,9 +433,11 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str, static lldb_private::ConstString g_CFStringCreateWithBytes_str( "CFStringCreateWithBytes"); + bool missing_weak = false; CFStringCreateWithBytes_addr = - m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str); - if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS) { + m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str, + missing_weak); + if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS || missing_weak) { if (log) log->PutCString("Couldn't find CFStringCreateWithBytes in the target"); @@ -478,18 +480,18 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str, ArrayRef<Type *> CFSCWB_arg_types(arg_type_array, 5); - llvm::Type *CFSCWB_ty = + llvm::FunctionType *CFSCWB_ty = FunctionType::get(ns_str_ty, CFSCWB_arg_types, false); // Build the constant containing the pointer to the function PointerType *CFSCWB_ptr_ty = PointerType::getUnqual(CFSCWB_ty); Constant *CFSCWB_addr_int = ConstantInt::get(m_intptr_ty, CFStringCreateWithBytes_addr, false); - m_CFStringCreateWithBytes = - ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty); + m_CFStringCreateWithBytes = { + CFSCWB_ty, ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty)}; } - ConstantDataSequential *string_array = NULL; + ConstantDataSequential *string_array = nullptr; if (cstr) string_array = dyn_cast<ConstantDataSequential>(cstr->getInitializer()); @@ -734,7 +736,7 @@ bool IRForTarget::RewriteObjCConstStrings() { } if (!cstr_array) - cstr_global = NULL; + cstr_global = nullptr; if (!RewriteObjCConstString(nsstring_global, cstr_global)) { if (log) @@ -857,9 +859,11 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) { if (!m_sel_registerName) { lldb::addr_t sel_registerName_addr; + bool missing_weak = false; static lldb_private::ConstString g_sel_registerName_str("sel_registerName"); - sel_registerName_addr = m_execution_unit.FindSymbol(g_sel_registerName_str); - if (sel_registerName_addr == LLDB_INVALID_ADDRESS) + sel_registerName_addr = m_execution_unit.FindSymbol(g_sel_registerName_str, + missing_weak); + if (sel_registerName_addr == LLDB_INVALID_ADDRESS || missing_weak) return false; if (log) @@ -881,14 +885,15 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) { ArrayRef<Type *> srN_arg_types(type_array, 1); - llvm::Type *srN_type = + llvm::FunctionType *srN_type = FunctionType::get(sel_ptr_type, srN_arg_types, false); // Build the constant containing the pointer to the function PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type); Constant *srN_addr_int = ConstantInt::get(m_intptr_ty, sel_registerName_addr, false); - m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty); + m_sel_registerName = {srN_type, + ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty)}; } Value *argument_array[1]; @@ -1026,9 +1031,11 @@ bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) { if (!m_objc_getClass) { lldb::addr_t objc_getClass_addr; + bool missing_weak = false; static lldb_private::ConstString g_objc_getClass_str("objc_getClass"); - objc_getClass_addr = m_execution_unit.FindSymbol(g_objc_getClass_str); - if (objc_getClass_addr == LLDB_INVALID_ADDRESS) + objc_getClass_addr = m_execution_unit.FindSymbol(g_objc_getClass_str, + missing_weak); + if (objc_getClass_addr == LLDB_INVALID_ADDRESS || missing_weak) return false; if (log) @@ -1043,14 +1050,15 @@ bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) { ArrayRef<Type *> ogC_arg_types(type_array, 1); - llvm::Type *ogC_type = + llvm::FunctionType *ogC_type = FunctionType::get(class_type, ogC_arg_types, false); // Build the constant containing the pointer to the function PointerType *ogC_ptr_ty = PointerType::getUnqual(ogC_type); Constant *ogC_addr_int = ConstantInt::get(m_intptr_ty, objc_getClass_addr, false); - m_objc_getClass = ConstantExpr::getIntToPtr(ogC_addr_int, ogC_ptr_ty); + m_objc_getClass = {ogC_type, + ConstantExpr::getIntToPtr(ogC_addr_int, ogC_ptr_ty)}; } Value *argument_array[1]; @@ -1148,8 +1156,8 @@ bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) { return false; GlobalVariable *persistent_global = new GlobalVariable( - (*m_module), alloc->getType(), false, /* not constant */ - GlobalValue::ExternalLinkage, NULL, /* no initializer */ + (*m_module), alloc->getType(), false, /* not constant */ + GlobalValue::ExternalLinkage, nullptr, /* no initializer */ alloc->getName().str()); // What we're going to do here is make believe this was a regular old @@ -1345,13 +1353,13 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { std::string name(named_decl->getName().str()); clang::ValueDecl *value_decl = dyn_cast<clang::ValueDecl>(named_decl); - if (value_decl == NULL) + if (value_decl == nullptr) return false; lldb_private::CompilerType compiler_type(&value_decl->getASTContext(), value_decl->getType()); - const Type *value_type = NULL; + const Type *value_type = nullptr; if (name[0] == '$') { // The $__lldb_expr_result name indicates the return value has allocated @@ -1629,12 +1637,12 @@ bool IRForTarget::ResolveExternals(Function &llvm_function) { } static bool isGuardVariableRef(Value *V) { - Constant *Old = NULL; + Constant *Old = nullptr; if (!(Old = dyn_cast<Constant>(V))) return false; - ConstantExpr *CE = NULL; + ConstantExpr *CE = nullptr; if ((CE = dyn_cast<ConstantExpr>(V))) { if (CE->getOpcode() != Instruction::BitCast) @@ -1929,8 +1937,8 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { } for (element_index = 0; element_index < num_elements; ++element_index) { - const clang::NamedDecl *decl = NULL; - Value *value = NULL; + const clang::NamedDecl *decl = nullptr; + Value *value = nullptr; lldb::offset_t offset; lldb_private::ConstString name; @@ -2050,7 +2058,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) { std::string s; raw_string_ostream oss(s); - m_module->print(oss, NULL); + m_module->print(oss, nullptr); oss.flush(); @@ -2087,7 +2095,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) { m_reloc_placeholder = new llvm::GlobalVariable( (*m_module), int8_ty, false /* IsConstant */, GlobalVariable::InternalLinkage, Constant::getNullValue(int8_ty), - "reloc_placeholder", NULL /* InsertBefore */, + "reloc_placeholder", nullptr /* InsertBefore */, GlobalVariable::NotThreadLocal /* ThreadLocal */, 0 /* AddressSpace */); //////////////////////////////////////////////////////////// @@ -2109,7 +2117,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) { std::string s; raw_string_ostream oss(s); - m_module->print(oss, NULL); + m_module->print(oss, nullptr); oss.flush(); @@ -2244,7 +2252,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) { std::string s; raw_string_ostream oss(s); - m_module->print(oss, NULL); + m_module->print(oss, nullptr); oss.flush(); diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/source/Plugins/ExpressionParser/Clang/IRForTarget.h index c6c44b46023c..f87fd8ac32cb 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.h +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.h @@ -1,10 +1,9 @@ //===-- IRForTarget.h ---------------------------------------------*- C++ //-*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -17,6 +16,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/lldb-public.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/Pass.h" #include <functional> @@ -31,11 +31,9 @@ class Function; class GlobalValue; class GlobalVariable; class Instruction; -class IntegerType; class Module; class StoreInst; class DataLayout; -class Type; class Value; } @@ -45,8 +43,7 @@ class IRExecutionUnit; class IRMemoryMap; } -//---------------------------------------------------------------------- -/// @class IRForTarget IRForTarget.h "lldb/Expression/IRForTarget.h" +/// \class IRForTarget IRForTarget.h "lldb/Expression/IRForTarget.h" /// Transforms the IR for a function to run in the target /// /// Once an expression has been parsed and converted to IR, it can run in two @@ -57,168 +54,143 @@ class IRMemoryMap; /// transformations to the IR which make it relocatable. These /// transformations are discussed in more detail next to their relevant /// functions. -//---------------------------------------------------------------------- class IRForTarget : public llvm::ModulePass { public: enum class LookupResult { Success, Fail, Ignore }; - //------------------------------------------------------------------ /// Constructor /// - /// @param[in] decl_map + /// \param[in] decl_map /// The list of externally-referenced variables for the expression, /// for use in looking up globals and allocating the argument /// struct. See the documentation for ClangExpressionDeclMap. /// - /// @param[in] resolve_vars + /// \param[in] resolve_vars /// True if the external variable references (including persistent /// variables) should be resolved. If not, only external functions /// are resolved. /// - /// @param[in] execution_policy + /// \param[in] execution_policy /// Determines whether an IR interpreter can be used to statically /// evaluate the expression. /// - /// @param[in] const_result + /// \param[in] const_result /// This variable is populated with the statically-computed result /// of the function, if it has no side-effects and the result can /// be computed statically. /// - /// @param[in] execution_unit + /// \param[in] execution_unit /// The holder for raw data associated with the expression. /// - /// @param[in] error_stream + /// \param[in] error_stream /// If non-NULL, a stream on which errors can be printed. /// - /// @param[in] func_name + /// \param[in] func_name /// The name of the function to prepare for execution in the target. - //------------------------------------------------------------------ IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map, bool resolve_vars, lldb_private::IRExecutionUnit &execution_unit, lldb_private::Stream &error_stream, const char *func_name = "$__lldb_expr"); - //------------------------------------------------------------------ /// Destructor - //------------------------------------------------------------------ ~IRForTarget() override; - //------------------------------------------------------------------ /// Run this IR transformer on a single module /// /// Implementation of the llvm::ModulePass::runOnModule() function. /// - /// @param[in] llvm_module + /// \param[in] llvm_module /// The module to run on. This module is searched for the function /// $__lldb_expr, and that function is passed to the passes one by /// one. /// - /// @param[in] interpreter_error + /// \param[in] interpreter_error /// An error. If the expression fails to be interpreted, this error /// is set to a reason why. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool runOnModule(llvm::Module &llvm_module) override; - //------------------------------------------------------------------ /// Interface stub /// /// Implementation of the llvm::ModulePass::assignPassManager() function. - //------------------------------------------------------------------ void assignPassManager(llvm::PMStack &pass_mgr_stack, llvm::PassManagerType pass_mgr_type = llvm::PMT_ModulePassManager) override; - //------------------------------------------------------------------ /// Returns PMT_ModulePassManager /// /// Implementation of the llvm::ModulePass::getPotentialPassManagerType() /// function. - //------------------------------------------------------------------ llvm::PassManagerType getPotentialPassManagerType() const override; private: - //------------------------------------------------------------------ /// Ensures that the current function's linkage is set to external. /// Otherwise the JIT may not return an address for it. /// - /// @param[in] llvm_function + /// \param[in] llvm_function /// The function whose linkage is to be fixed. /// - /// @return + /// \return /// True on success; false otherwise. - //------------------------------------------------------------------ bool FixFunctionLinkage(llvm::Function &llvm_function); - //------------------------------------------------------------------ /// A module-level pass to replace all function pointers with their /// integer equivalents. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @param[in] llvm_module + /// \param[in] llvm_module /// The module currently being processed. /// - /// @param[in] llvm_function + /// \param[in] llvm_function /// The function currently being processed. /// - /// @return + /// \return /// True on success; false otherwise. - //------------------------------------------------------------------ bool HasSideEffects(llvm::Function &llvm_function); - //------------------------------------------------------------------ /// A function-level pass to check whether the function has side /// effects. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// Get the address of a function, and a location to put the complete Value /// of the function if one is available. /// - /// @param[in] function + /// \param[in] function /// The function to find the location of. /// - /// @param[out] ptr + /// \param[out] ptr /// The location of the function in the target. /// - /// @param[out] name + /// \param[out] name /// The resolved name of the function (matters for intrinsics). /// - /// @param[out] value_ptr + /// \param[out] value_ptr /// A variable to put the function's completed Value* in, or NULL /// if the Value* shouldn't be stored anywhere. /// - /// @return + /// \return /// The pointer. - //------------------------------------------------------------------ LookupResult GetFunctionAddress(llvm::Function *function, uint64_t &ptr, lldb_private::ConstString &name, llvm::Constant **&value_ptr); - //------------------------------------------------------------------ /// A function-level pass to take the generated global value /// $__lldb_expr_result and make it into a persistent variable. Also see /// ASTResultSynthesizer. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// Find the NamedDecl corresponding to a Value. This interface is exposed /// for the IR interpreter. /// - /// @param[in] module + /// \param[in] module /// The module containing metadata to search /// - /// @param[in] global + /// \param[in] global /// The global entity to search for /// - /// @return + /// \return /// The corresponding variable declaration - //------------------------------------------------------------------ public: static clang::NamedDecl *DeclForGlobal(const llvm::GlobalValue *global_val, llvm::Module *module); @@ -226,75 +198,62 @@ public: private: clang::NamedDecl *DeclForGlobal(llvm::GlobalValue *global); - //------------------------------------------------------------------ /// Set the constant result variable m_const_result to the provided /// constant, assuming it can be evaluated. The result variable will be /// reset to NULL later if the expression has side effects. /// - /// @param[in] initializer + /// \param[in] initializer /// The constant initializer for the variable. /// - /// @param[in] name + /// \param[in] name /// The name of the result variable. /// - /// @param[in] type + /// \param[in] type /// The Clang type of the result variable. - //------------------------------------------------------------------ void MaybeSetConstantResult(llvm::Constant *initializer, - const lldb_private::ConstString &name, + lldb_private::ConstString name, lldb_private::TypeFromParser type); - //------------------------------------------------------------------ /// If the IR represents a cast of a variable, set m_const_result to the /// result of the cast. The result variable will be reset to /// NULL latger if the expression has side effects. /// - /// @param[in] type + /// \param[in] type /// The Clang type of the result variable. - //------------------------------------------------------------------ void MaybeSetCastResult(lldb_private::TypeFromParser type); - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @param[in] llvm_function + /// \param[in] llvm_function /// The function currently being processed. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool CreateResultVariable(llvm::Function &llvm_function); - //------------------------------------------------------------------ /// A module-level pass to find Objective-C constant strings and /// transform them to calls to CFStringCreateWithBytes. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// Rewrite a single Objective-C constant string. /// - /// @param[in] NSStr + /// \param[in] NSStr /// The constant NSString to be transformed /// - /// @param[in] CStr + /// \param[in] CStr /// The constant C string inside the NSString. This will be /// passed as the bytes argument to CFStringCreateWithBytes. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool RewriteObjCConstString(llvm::GlobalVariable *NSStr, llvm::GlobalVariable *CStr); - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool RewriteObjCConstStrings(); - //------------------------------------------------------------------ /// A basic block-level pass to find all Objective-C method calls and /// rewrite them to use sel_registerName instead of statically allocated /// selectors. The reason is that the selectors are created on the @@ -302,59 +261,47 @@ private: /// section and prepare them. This doesn't happen when code is copied into /// the target, though, and there's no easy way to induce the runtime to /// scan them. So instead we get our selectors from sel_registerName. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// Replace a single selector reference /// - /// @param[in] selector_load + /// \param[in] selector_load /// The load of the statically-allocated selector. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool RewriteObjCSelector(llvm::Instruction *selector_load); - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @param[in] basic_block + /// \param[in] basic_block /// The basic block currently being processed. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool RewriteObjCSelectors(llvm::BasicBlock &basic_block); - //------------------------------------------------------------------ /// A basic block-level pass to find all Objective-C class references that /// use the old-style Objective-C runtime and rewrite them to use /// class_getClass instead of statically allocated class references. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// Replace a single old-style class reference /// - /// @param[in] selector_load + /// \param[in] selector_load /// The load of the statically-allocated selector. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool RewriteObjCClassReference(llvm::Instruction *class_load); - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @param[in] basic_block + /// \param[in] basic_block /// The basic block currently being processed. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool RewriteObjCClassReferences(llvm::BasicBlock &basic_block); - //------------------------------------------------------------------ /// A basic block-level pass to find all newly-declared persistent /// variables and register them with the ClangExprDeclMap. This allows them /// to be materialized and dematerialized like normal external variables. @@ -362,182 +309,147 @@ private: /// locals, so they have an allocation. This pass excises these allocations /// and makes references look like external references where they will be /// resolved -- like all other external references -- by ResolveExternals(). - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// Handle a single allocation of a persistent variable /// - /// @param[in] persistent_alloc + /// \param[in] persistent_alloc /// The allocation of the persistent variable. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool RewritePersistentAlloc(llvm::Instruction *persistent_alloc); - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @param[in] basic_block + /// \param[in] basic_block /// The basic block currently being processed. - //------------------------------------------------------------------ bool RewritePersistentAllocs(llvm::BasicBlock &basic_block); - //------------------------------------------------------------------ /// A function-level pass to find all external variables and functions /// used in the IR. Each found external variable is added to the struct, /// and each external function is resolved in place, its call replaced with /// a call to a function pointer whose value is the address of the function /// in the target process. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// Write an initializer to a memory array of assumed sufficient size. /// - /// @param[in] data + /// \param[in] data /// A pointer to the data to write to. /// - /// @param[in] initializer + /// \param[in] initializer /// The initializer itself. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool MaterializeInitializer(uint8_t *data, llvm::Constant *initializer); - //------------------------------------------------------------------ /// Move an internal variable into the static allocation section. /// - /// @param[in] global_variable + /// \param[in] global_variable /// The variable. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool MaterializeInternalVariable(llvm::GlobalVariable *global_variable); - //------------------------------------------------------------------ /// Handle a single externally-defined variable /// - /// @param[in] value + /// \param[in] value /// The variable. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool MaybeHandleVariable(llvm::Value *value); - //------------------------------------------------------------------ /// Handle a single externally-defined symbol /// - /// @param[in] symbol + /// \param[in] symbol /// The symbol. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool HandleSymbol(llvm::Value *symbol); - //------------------------------------------------------------------ /// Handle a single externally-defined Objective-C class /// - /// @param[in] classlist_reference + /// \param[in] classlist_reference /// The reference, usually "01L_OBJC_CLASSLIST_REFERENCES_$_n" /// where n (if present) is an index. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool HandleObjCClass(llvm::Value *classlist_reference); - //------------------------------------------------------------------ /// Handle all the arguments to a function call /// - /// @param[in] C + /// \param[in] C /// The call instruction. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool MaybeHandleCallArguments(llvm::CallInst *call_inst); - //------------------------------------------------------------------ /// Resolve variable references in calls to external functions /// - /// @param[in] basic_block + /// \param[in] basic_block /// The basic block currently being processed. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool ResolveCalls(llvm::BasicBlock &basic_block); - //------------------------------------------------------------------ /// Remove calls to __cxa_atexit, which should never be generated by /// expressions. /// - /// @param[in] call_inst + /// \param[in] call_inst /// The call instruction. /// - /// @return + /// \return /// True if the scan was successful; false if some operation /// failed - //------------------------------------------------------------------ bool RemoveCXAAtExit(llvm::BasicBlock &basic_block); - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @param[in] basic_block + /// \param[in] basic_block /// The function currently being processed. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool ResolveExternals(llvm::Function &llvm_function); - //------------------------------------------------------------------ /// A basic block-level pass to excise guard variables from the code. /// The result for the function is passed through Clang as a static /// variable. Static variables normally have guard variables to ensure that /// they are only initialized once. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// Rewrite a load to a guard variable to return constant 0. /// - /// @param[in] guard_load + /// \param[in] guard_load /// The load instruction to zero out. - //------------------------------------------------------------------ void TurnGuardLoadIntoZero(llvm::Instruction *guard_load); - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @param[in] basic_block + /// \param[in] basic_block /// The basic block currently being processed. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool RemoveGuards(llvm::BasicBlock &basic_block); - //------------------------------------------------------------------ /// A function-level pass to make all external variable references /// point at the correct offsets from the void* passed into the function. /// ClangExpressionDeclMap::DoStructLayout() must be called beforehand, so /// that the offsets are valid. - //------------------------------------------------------------------ - //------------------------------------------------------------------ /// The top-level pass implementation /// - /// @param[in] llvm_function + /// \param[in] llvm_function /// The function currently being processed. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool ReplaceVariables(llvm::Function &llvm_function); /// Flags @@ -557,18 +469,16 @@ private: ///module. lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls - llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function - ///CFStringCreateWithBytes, cast to - ///the - /// appropriate function pointer type - llvm::Constant *m_sel_registerName; ///< The address of the function - ///sel_registerName, cast to the - ///appropriate - /// function pointer type - llvm::Constant *m_objc_getClass; ///< The address of the function - ///objc_getClass, cast to the - ///appropriate - /// function pointer type + llvm::FunctionCallee + m_CFStringCreateWithBytes; ///< The address of the function + /// CFStringCreateWithBytes, cast to the + /// appropriate function pointer type + llvm::FunctionCallee m_sel_registerName; ///< The address of the function + /// sel_registerName, cast to the + /// appropriate function pointer type + llvm::FunctionCallee m_objc_getClass; ///< The address of the function + /// objc_getClass, cast to the + /// appropriate function pointer type llvm::IntegerType *m_intptr_ty; ///< The type of an integer large enough to hold a pointer. lldb_private::Stream @@ -589,7 +499,6 @@ private: ///final /// location of the static allocation. - //------------------------------------------------------------------ /// UnfoldConstant operates on a constant [Old] which has just been replaced /// with a value [New]. We assume that new_value has been properly placed /// early in the function, in front of the first instruction in the entry @@ -602,12 +511,11 @@ private: /// instructions replace the constant uses, so UnfoldConstant calls itself /// recursively for those. /// - /// @param[in] llvm_function + /// \param[in] llvm_function /// The function currently being processed. /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ class FunctionValueCache { public: @@ -631,32 +539,28 @@ private: FunctionValueCache &entry_instruction_finder, lldb_private::Stream &error_stream); - //------------------------------------------------------------------ /// Construct a reference to m_reloc_placeholder with a given type and /// offset. This typically happens after inserting data into /// m_data_allocator. /// - /// @param[in] type + /// \param[in] type /// The type of the value being loaded. /// - /// @param[in] offset + /// \param[in] offset /// The offset of the value from the base of m_data_allocator. /// - /// @return + /// \return /// The Constant for the reference, usually a ConstantExpr. - //------------------------------------------------------------------ llvm::Constant *BuildRelocation(llvm::Type *type, uint64_t offset); - //------------------------------------------------------------------ /// Commit the allocation in m_data_allocator and use its final location to /// replace m_reloc_placeholder. /// - /// @param[in] module + /// \param[in] module /// The module that m_data_allocator resides in /// - /// @return + /// \return /// True on success; false otherwise - //------------------------------------------------------------------ bool CompleteDataAllocation(); }; diff --git a/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h new file mode 100644 index 000000000000..0e959f86fd2a --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h @@ -0,0 +1,38 @@ +//===-- ModuleDependencyCollector.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 liblldb_ModuleDependencyCollector_h_ +#define liblldb_ModuleDependencyCollector_h_ + +#include "lldb/Utility/FileCollector.h" +#include "clang/Frontend/Utils.h" +#include "llvm/ADT/StringRef.h" + +namespace lldb_private { +class ModuleDependencyCollectorAdaptor + : public clang::ModuleDependencyCollector { +public: + ModuleDependencyCollectorAdaptor(FileCollector &file_collector) + : clang::ModuleDependencyCollector(""), m_file_collector(file_collector) { + } + + void addFile(llvm::StringRef Filename, + llvm::StringRef FileDst = {}) override { + m_file_collector.AddFile(Filename); + } + + bool insertSeen(llvm::StringRef Filename) override { return false; } + void addFileMapping(llvm::StringRef VPath, llvm::StringRef RPath) override {} + void writeFileMap() override {} + +private: + FileCollector &m_file_collector; +}; +} // namespace lldb_private + +#endif |