aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/ExpressionParser
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/ExpressionParser')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp525
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h173
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp183
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h131
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp26
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h577
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp1415
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h535
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp35
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h110
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp1501
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h399
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp31
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h43
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h50
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp2044
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h663
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.cpp13
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h54
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp1474
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h175
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp529
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h105
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp27
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h30
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp64
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h212
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp90
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h73
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp219
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h154
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp171
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h23
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp776
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h115
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp136
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h119
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp1002
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h276
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp87
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h50
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp191
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h113
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp158
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h90
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp297
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h66
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp569
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h127
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp1771
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h392
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h40
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp180
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h123
54 files changed, 18532 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
new file mode 100644
index 000000000000..3e2c208bd201
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
@@ -0,0 +1,525 @@
+//===-- ASTResultSynthesizer.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTResultSynthesizer.h"
+
+#include "ClangASTImporter.h"
+#include "ClangPersistentVariables.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+
+using namespace llvm;
+using namespace clang;
+using namespace lldb_private;
+
+ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
+ bool top_level, Target &target)
+ : 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;
+
+ m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
+}
+
+ASTResultSynthesizer::~ASTResultSynthesizer() = default;
+
+void ASTResultSynthesizer::Initialize(ASTContext &Context) {
+ m_ast_context = &Context;
+
+ if (m_passthrough)
+ m_passthrough->Initialize(Context);
+}
+
+void ASTResultSynthesizer::TransformTopLevelDecl(Decl *D) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D)) {
+ if (log && log->GetVerbose()) {
+ if (named_decl->getIdentifier())
+ LLDB_LOGF(log, "TransformTopLevelDecl(%s)",
+ named_decl->getIdentifier()->getNameStart());
+ else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
+ LLDB_LOGF(log, "TransformTopLevelDecl(%s)",
+ method_decl->getSelector().getAsString().c_str());
+ else
+ LLDB_LOGF(log, "TransformTopLevelDecl(<complex>)");
+ }
+
+ if (m_top_level) {
+ RecordPersistentDecl(named_decl);
+ }
+ }
+
+ if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D)) {
+ RecordDecl::decl_iterator decl_iterator;
+
+ for (decl_iterator = linkage_spec_decl->decls_begin();
+ decl_iterator != linkage_spec_decl->decls_end(); ++decl_iterator) {
+ TransformTopLevelDecl(*decl_iterator);
+ }
+ } else if (!m_top_level) {
+ if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D)) {
+ if (m_ast_context &&
+ !method_decl->getSelector().getAsString().compare("$__lldb_expr:")) {
+ RecordPersistentTypes(method_decl);
+ SynthesizeObjCMethodResult(method_decl);
+ }
+ } else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D)) {
+ // When completing user input the body of the function may be a nullptr.
+ if (m_ast_context && function_decl->hasBody() &&
+ !function_decl->getNameInfo().getAsString().compare("$__lldb_expr")) {
+ RecordPersistentTypes(function_decl);
+ SynthesizeFunctionResult(function_decl);
+ }
+ }
+ }
+}
+
+bool ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) {
+ DeclGroupRef::iterator decl_iterator;
+
+ for (decl_iterator = D.begin(); decl_iterator != D.end(); ++decl_iterator) {
+ Decl *decl = *decl_iterator;
+
+ TransformTopLevelDecl(decl);
+ }
+
+ if (m_passthrough)
+ return m_passthrough->HandleTopLevelDecl(D);
+ return true;
+}
+
+bool ASTResultSynthesizer::SynthesizeFunctionResult(FunctionDecl *FunDecl) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (!m_sema)
+ return false;
+
+ FunctionDecl *function_decl = FunDecl;
+
+ if (!function_decl)
+ return false;
+
+ if (log && log->GetVerbose()) {
+ std::string s;
+ raw_string_ostream os(s);
+
+ function_decl->print(os);
+
+ os.flush();
+
+ LLDB_LOGF(log, "Untransformed function AST:\n%s", s.c_str());
+ }
+
+ Stmt *function_body = function_decl->getBody();
+ CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
+
+ bool ret = SynthesizeBodyResult(compound_stmt, function_decl);
+
+ if (log && log->GetVerbose()) {
+ std::string s;
+ raw_string_ostream os(s);
+
+ function_decl->print(os);
+
+ os.flush();
+
+ LLDB_LOGF(log, "Transformed function AST:\n%s", s.c_str());
+ }
+
+ return ret;
+}
+
+bool ASTResultSynthesizer::SynthesizeObjCMethodResult(
+ ObjCMethodDecl *MethodDecl) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (!m_sema)
+ return false;
+
+ if (!MethodDecl)
+ return false;
+
+ if (log && log->GetVerbose()) {
+ std::string s;
+ raw_string_ostream os(s);
+
+ MethodDecl->print(os);
+
+ os.flush();
+
+ LLDB_LOGF(log, "Untransformed method AST:\n%s", s.c_str());
+ }
+
+ Stmt *method_body = MethodDecl->getBody();
+
+ if (!method_body)
+ return false;
+
+ CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);
+
+ bool ret = SynthesizeBodyResult(compound_stmt, MethodDecl);
+
+ if (log && log->GetVerbose()) {
+ std::string s;
+ raw_string_ostream os(s);
+
+ MethodDecl->print(os);
+
+ os.flush();
+
+ LLDB_LOGF(log, "Transformed method AST:\n%s", s.c_str());
+ }
+
+ return ret;
+}
+
+/// Returns true if LLDB can take the address of the given lvalue for the sake
+/// of capturing the expression result. Returns false if LLDB should instead
+/// store the expression result in a result variable.
+static bool CanTakeAddressOfLValue(const Expr *lvalue_expr) {
+ assert(lvalue_expr->getValueKind() == VK_LValue &&
+ "lvalue_expr not a lvalue");
+
+ QualType qt = lvalue_expr->getType();
+ // If the lvalue has const-qualified non-volatile integral or enum type, then
+ // the underlying value might come from a const static data member as
+ // described in C++11 [class.static.data]p3. If that's the case, then the
+ // value might not have an address if the user didn't also define the member
+ // in a namespace scope. Taking the address would cause that LLDB later fails
+ // to link the expression, so those lvalues should be stored in a result
+ // variable.
+ if (qt->isIntegralOrEnumerationType() && qt.isConstQualified() &&
+ !qt.isVolatileQualified())
+ return false;
+ return true;
+}
+
+bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
+ DeclContext *DC) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ ASTContext &Ctx(*m_ast_context);
+
+ if (!Body)
+ return false;
+
+ if (Body->body_empty())
+ return false;
+
+ Stmt **last_stmt_ptr = Body->body_end() - 1;
+ Stmt *last_stmt = *last_stmt_ptr;
+
+ while (isa<NullStmt>(last_stmt)) {
+ if (last_stmt_ptr != Body->body_begin()) {
+ last_stmt_ptr--;
+ last_stmt = *last_stmt_ptr;
+ } else {
+ return false;
+ }
+ }
+
+ Expr *last_expr = dyn_cast<Expr>(last_stmt);
+
+ if (!last_expr)
+ // No auxiliary variable necessary; expression returns void
+ return true;
+
+ // In C++11, last_expr can be a LValueToRvalue implicit cast. Strip that off
+ // if that's the case.
+
+ do {
+ ImplicitCastExpr *implicit_cast = dyn_cast<ImplicitCastExpr>(last_expr);
+
+ if (!implicit_cast)
+ break;
+
+ if (implicit_cast->getCastKind() != CK_LValueToRValue)
+ break;
+
+ last_expr = implicit_cast->getSubExpr();
+ } 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
+ // differently.
+ //
+ // For Lvalues
+ //
+ // - In AST result synthesis (here!) the expression E is transformed into an
+ // initialization T *$__lldb_expr_result_ptr = &E.
+ //
+ // - In structure allocation, a pointer-sized slot is allocated in the
+ // struct that is to be passed into the expression.
+ //
+ // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are
+ // redirected at an entry in the struct ($__lldb_arg) passed into the
+ // expression. (Other persistent variables are treated similarly, having
+ // been materialized as references, but in those cases the value of the
+ // reference itself is never modified.)
+ //
+ // - During materialization, $0 (the result persistent variable) is ignored.
+ //
+ // - During dematerialization, $0 is marked up as a load address with value
+ // equal to the contents of the structure entry.
+ //
+ // - Note: if we cannot take an address of the resulting Lvalue (e.g. it's
+ // a static const member without an out-of-class definition), then we
+ // follow the Rvalue route.
+ //
+ // For Rvalues
+ //
+ // - In AST result synthesis the expression E is transformed into an
+ // initialization static T $__lldb_expr_result = E.
+ //
+ // - In structure allocation, a pointer-sized slot is allocated in the
+ // struct that is to be passed into the expression.
+ //
+ // - In IR transformations, an instruction is inserted at the beginning of
+ // the function to dereference the pointer resident in the slot. Reads and
+ // writes to $__lldb_expr_result are redirected at that dereferenced
+ // version. Guard variables for the static variable are excised.
+ //
+ // - During materialization, $0 (the result persistent variable) is
+ // populated with the location of a newly-allocated area of memory.
+ //
+ // - During dematerialization, $0 is ignored.
+
+ bool is_lvalue = last_expr->getValueKind() == VK_LValue &&
+ last_expr->getObjectKind() == OK_Ordinary;
+
+ QualType expr_qual_type = last_expr->getType();
+ const clang::Type *expr_type = expr_qual_type.getTypePtr();
+
+ if (!expr_type)
+ return false;
+
+ if (expr_type->isVoidType())
+ return true;
+
+ if (log) {
+ std::string s = expr_qual_type.getAsString();
+
+ LLDB_LOGF(log, "Last statement is an %s with type: %s",
+ (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
+ }
+
+ clang::VarDecl *result_decl = nullptr;
+
+ if (is_lvalue && CanTakeAddressOfLValue(last_expr)) {
+ IdentifierInfo *result_ptr_id;
+
+ if (expr_type->isFunctionType())
+ result_ptr_id =
+ &Ctx.Idents.get("$__lldb_expr_result"); // functions actually should
+ // be treated like function
+ // pointers
+ else
+ result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr");
+
+ m_sema->RequireCompleteType(last_expr->getSourceRange().getBegin(),
+ expr_qual_type,
+ clang::diag::err_incomplete_type);
+
+ QualType ptr_qual_type;
+
+ 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, nullptr, SC_Static);
+
+ if (!result_decl)
+ return false;
+
+ ExprResult address_of_expr =
+ m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);
+ if (address_of_expr.get())
+ m_sema->AddInitializerToDecl(result_decl, address_of_expr.get(), true);
+ else
+ return false;
+ } else {
+ IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
+
+ result_decl =
+ VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), &result_id,
+ expr_qual_type, nullptr, SC_Static);
+
+ if (!result_decl)
+ return false;
+
+ m_sema->AddInitializerToDecl(result_decl, last_expr, true);
+ }
+
+ DC->addDecl(result_decl);
+
+ ///////////////////////////////
+ // call AddInitializerToDecl
+ //
+
+ // m_sema->AddInitializerToDecl(result_decl, last_expr);
+
+ /////////////////////////////////
+ // call ConvertDeclToDeclGroup
+ //
+
+ Sema::DeclGroupPtrTy result_decl_group_ptr;
+
+ result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);
+
+ ////////////////////////
+ // call ActOnDeclStmt
+ //
+
+ StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(
+ result_decl_group_ptr, SourceLocation(), SourceLocation()));
+
+ ////////////////////////////////////////////////
+ // replace the old statement with the new one
+ //
+
+ *last_stmt_ptr = static_cast<Stmt *>(result_initialization_stmt_result.get());
+
+ return true;
+}
+
+void ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx) {
+ if (m_passthrough)
+ m_passthrough->HandleTranslationUnit(Ctx);
+}
+
+void ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx) {
+ typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator;
+
+ for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()),
+ e = TypeDeclIterator(FunDeclCtx->decls_end());
+ i != e; ++i) {
+ MaybeRecordPersistentType(*i);
+ }
+}
+
+void ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D) {
+ if (!D->getIdentifier())
+ return;
+
+ StringRef name = D->getName();
+ if (name.empty() || name.front() != '$')
+ return;
+
+ LLDB_LOG(GetLog(LLDBLog::Expressions), "Recording persistent type {0}", name);
+
+ m_decls.push_back(D);
+}
+
+void ASTResultSynthesizer::RecordPersistentDecl(NamedDecl *D) {
+ lldbassert(m_top_level);
+
+ if (!D->getIdentifier())
+ return;
+
+ StringRef name = D->getName();
+ if (name.empty())
+ return;
+
+ LLDB_LOG(GetLog(LLDBLog::Expressions), "Recording persistent decl {0}", name);
+
+ m_decls.push_back(D);
+}
+
+void ASTResultSynthesizer::CommitPersistentDecls() {
+ auto *state =
+ m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC);
+ if (!state)
+ return;
+
+ auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
+
+ lldb::TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(
+ m_target, m_ast_context->getLangOpts());
+
+ for (clang::NamedDecl *decl : m_decls) {
+ StringRef name = decl->getName();
+
+ Decl *D_scratch = persistent_vars->GetClangASTImporter()->DeportDecl(
+ &scratch_ts_sp->getASTContext(), decl);
+
+ if (!D_scratch) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (log) {
+ std::string s;
+ llvm::raw_string_ostream ss(s);
+ decl->dump(ss);
+ ss.flush();
+
+ LLDB_LOGF(log, "Couldn't commit persistent decl: %s\n", s.c_str());
+ }
+
+ continue;
+ }
+
+ if (NamedDecl *NamedDecl_scratch = dyn_cast<NamedDecl>(D_scratch))
+ persistent_vars->RegisterPersistentDecl(ConstString(name),
+ NamedDecl_scratch, scratch_ts_sp);
+ }
+}
+
+void ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D) {
+ if (m_passthrough)
+ m_passthrough->HandleTagDeclDefinition(D);
+}
+
+void ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D) {
+ if (m_passthrough)
+ m_passthrough->CompleteTentativeDefinition(D);
+}
+
+void ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD) {
+ if (m_passthrough)
+ m_passthrough->HandleVTable(RD);
+}
+
+void ASTResultSynthesizer::PrintStats() {
+ if (m_passthrough)
+ m_passthrough->PrintStats();
+}
+
+void ASTResultSynthesizer::InitializeSema(Sema &S) {
+ m_sema = &S;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->InitializeSema(S);
+}
+
+void ASTResultSynthesizer::ForgetSema() {
+ m_sema = nullptr;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->ForgetSema();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h
new file mode 100644
index 000000000000..9de823bc75a7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h
@@ -0,0 +1,173 @@
+//===-- ASTResultSynthesizer.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H
+
+#include "lldb/Target/Target.h"
+#include "clang/Sema/SemaConsumer.h"
+
+namespace clang {
+class CompoundStmt;
+class DeclContext;
+class NamedDecl;
+class ObjCMethodDecl;
+class TypeDecl;
+} // namespace clang
+
+namespace lldb_private {
+
+/// \class ASTResultSynthesizer ASTResultSynthesizer.h
+/// "lldb/Expression/ASTResultSynthesizer.h" Adds a result variable
+/// declaration to the ASTs for an expression.
+///
+/// Users expect the expression "i + 3" to return a result, even if a result
+/// variable wasn't specifically declared. To fulfil this requirement, LLDB
+/// adds a result variable to the expression, transforming it to "int
+/// $__lldb_expr_result = i + 3." The IR transformers ensure that the
+/// resulting variable is mapped to the right piece of memory.
+/// 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
+ /// 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
+ /// If true, register all top-level Decls and don't try to handle the
+ /// main function.
+ ///
+ /// \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
+ /// 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
+ /// 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
+ /// 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
+ /// The Decl to hunt.
+ void TransformTopLevelDecl(clang::Decl *D);
+
+ /// Process an Objective-C method and produce the result variable and
+ /// initialization
+ ///
+ /// \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
+ /// The function to process.
+ bool SynthesizeFunctionResult(clang::FunctionDecl *FunDecl);
+
+ /// Process a function body and produce the result variable and
+ /// initialization
+ ///
+ /// \param[in] Body
+ /// The body of the function.
+ ///
+ /// \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
+ /// 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.
+ void MaybeRecordPersistentType(clang::TypeDecl *D);
+
+ /// Given a NamedDecl, register it as a pointer type in the target's scratch
+ /// AST context.
+ void RecordPersistentDecl(clang::NamedDecl *D);
+
+ clang::ASTContext
+ *m_ast_context; ///< The AST context to use for identifiers and types.
+ clang::ASTConsumer *m_passthrough; ///< The ASTConsumer down the chain, for
+ ///passthrough. NULL if it's a
+ ///SemaConsumer.
+ clang::SemaConsumer *m_passthrough_sema; ///< The SemaConsumer down the chain,
+ ///for passthrough. NULL if it's an
+ ///ASTConsumer.
+
+ std::vector<clang::NamedDecl *> m_decls; ///< Persistent declarations to
+ ///register assuming the expression
+ ///succeeds.
+
+ Target &m_target; ///< The target, which contains the persistent variable
+ ///store and the
+ clang::Sema *m_sema; ///< The Sema to use.
+ bool m_top_level;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
new file mode 100644
index 000000000000..a2722db5d24a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
@@ -0,0 +1,183 @@
+//===-- ASTStructExtractor.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTStructExtractor.h"
+
+#include "lldb/Utility/Log.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdlib>
+
+using namespace llvm;
+using namespace clang;
+using namespace lldb_private;
+
+ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough,
+ const char *struct_name,
+ ClangFunctionCaller &function)
+ : m_ast_context(nullptr), m_passthrough(passthrough),
+ m_passthrough_sema(nullptr), m_sema(nullptr), m_function(function),
+ m_struct_name(struct_name) {
+ if (!m_passthrough)
+ return;
+
+ m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
+}
+
+ASTStructExtractor::~ASTStructExtractor() = default;
+
+void ASTStructExtractor::Initialize(ASTContext &Context) {
+ m_ast_context = &Context;
+
+ if (m_passthrough)
+ m_passthrough->Initialize(Context);
+}
+
+void ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F) {
+ if (!F->hasBody())
+ return;
+
+ Stmt *body_stmt = F->getBody();
+ CompoundStmt *body_compound_stmt = dyn_cast<CompoundStmt>(body_stmt);
+
+ if (!body_compound_stmt)
+ return; // do we have to handle this?
+
+ RecordDecl *struct_decl = nullptr;
+
+ StringRef desired_name(m_struct_name);
+
+ for (CompoundStmt::const_body_iterator bi = body_compound_stmt->body_begin(),
+ be = body_compound_stmt->body_end();
+ bi != be; ++bi) {
+ Stmt *curr_stmt = *bi;
+ DeclStmt *curr_decl_stmt = dyn_cast<DeclStmt>(curr_stmt);
+ if (!curr_decl_stmt)
+ continue;
+ DeclGroupRef decl_group = curr_decl_stmt->getDeclGroup();
+ for (Decl *candidate_decl : decl_group) {
+ RecordDecl *candidate_record_decl = dyn_cast<RecordDecl>(candidate_decl);
+ if (!candidate_record_decl)
+ continue;
+ if (candidate_record_decl->getName() == desired_name) {
+ struct_decl = candidate_record_decl;
+ break;
+ }
+ }
+ if (struct_decl)
+ break;
+ }
+
+ if (!struct_decl)
+ return;
+
+ const ASTRecordLayout *struct_layout(
+ &m_ast_context->getASTRecordLayout(struct_decl));
+
+ if (!struct_layout)
+ return;
+
+ m_function.m_struct_size =
+ struct_layout->getSize()
+ .getQuantity(); // TODO Store m_struct_size as CharUnits
+ m_function.m_return_offset =
+ struct_layout->getFieldOffset(struct_layout->getFieldCount() - 1) / 8;
+ m_function.m_return_size =
+ struct_layout->getDataSize().getQuantity() - m_function.m_return_offset;
+
+ for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount();
+ field_index < num_fields; ++field_index) {
+ m_function.m_member_offsets.push_back(
+ struct_layout->getFieldOffset(field_index) / 8);
+ }
+
+ m_function.m_struct_valid = true;
+}
+
+void ASTStructExtractor::ExtractFromTopLevelDecl(Decl *D) {
+ LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
+
+ if (linkage_spec_decl) {
+ RecordDecl::decl_iterator decl_iterator;
+
+ for (decl_iterator = linkage_spec_decl->decls_begin();
+ decl_iterator != linkage_spec_decl->decls_end(); ++decl_iterator) {
+ ExtractFromTopLevelDecl(*decl_iterator);
+ }
+ }
+
+ FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
+
+ if (m_ast_context && function_decl &&
+ !m_function.m_wrapper_function_name.compare(
+ function_decl->getNameAsString())) {
+ ExtractFromFunctionDecl(function_decl);
+ }
+}
+
+bool ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D) {
+ DeclGroupRef::iterator decl_iterator;
+
+ for (decl_iterator = D.begin(); decl_iterator != D.end(); ++decl_iterator) {
+ Decl *decl = *decl_iterator;
+
+ ExtractFromTopLevelDecl(decl);
+ }
+
+ if (m_passthrough)
+ return m_passthrough->HandleTopLevelDecl(D);
+ return true;
+}
+
+void ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx) {
+ if (m_passthrough)
+ m_passthrough->HandleTranslationUnit(Ctx);
+}
+
+void ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D) {
+ if (m_passthrough)
+ m_passthrough->HandleTagDeclDefinition(D);
+}
+
+void ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D) {
+ if (m_passthrough)
+ m_passthrough->CompleteTentativeDefinition(D);
+}
+
+void ASTStructExtractor::HandleVTable(CXXRecordDecl *RD) {
+ if (m_passthrough)
+ m_passthrough->HandleVTable(RD);
+}
+
+void ASTStructExtractor::PrintStats() {
+ if (m_passthrough)
+ m_passthrough->PrintStats();
+}
+
+void ASTStructExtractor::InitializeSema(Sema &S) {
+ m_sema = &S;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->InitializeSema(S);
+}
+
+void ASTStructExtractor::ForgetSema() {
+ m_sema = nullptr;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->ForgetSema();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h
new file mode 100644
index 000000000000..c285f6408895
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h
@@ -0,0 +1,131 @@
+//===-- ASTStructExtractor.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H
+
+#include "ClangExpressionVariable.h"
+#include "ClangFunctionCaller.h"
+
+#include "clang/Sema/SemaConsumer.h"
+
+namespace lldb_private {
+
+/// \class ASTStructExtractor ASTStructExtractor.h
+/// "lldb/Expression/ASTStructExtractor.h" Extracts and describes the argument
+/// structure for a wrapped function.
+///
+/// This pass integrates with ClangFunctionCaller, which calls functions with
+/// custom sets of arguments. To avoid having to implement the full calling
+/// convention for the target's architecture, ClangFunctionCaller writes a
+/// simple wrapper function that takes a pointer to an argument structure that
+/// contains room for the address of the function to be called, the values of
+/// all its arguments, and room for the function's return value.
+///
+/// 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
+ /// 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
+ /// The name of the structure to extract from the wrapper 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
+ /// 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
+ /// 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
+ /// 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
+ /// 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
+ /// The Decl to hunt.
+ void ExtractFromTopLevelDecl(clang::Decl *D);
+
+ clang::ASTContext
+ *m_ast_context; ///< The AST context to use for identifiers and types.
+ clang::ASTConsumer *m_passthrough; ///< The ASTConsumer down the chain, for
+ ///passthrough. NULL if it's a
+ ///SemaConsumer.
+ clang::SemaConsumer *m_passthrough_sema; ///< The SemaConsumer down the chain,
+ ///for passthrough. NULL if it's an
+ ///ASTConsumer.
+ clang::Sema *m_sema; ///< The Sema to use.
+
+ ClangFunctionCaller &m_function; ///< The function to populate with
+ ///information about the argument structure.
+ std::string m_struct_name; ///< The name of the structure to extract.
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp
new file mode 100644
index 000000000000..a95fce1c5aa9
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp
@@ -0,0 +1,26 @@
+//===-- ASTUtils.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTUtils.h"
+
+lldb_private::ExternalASTSourceWrapper::~ExternalASTSourceWrapper() = default;
+
+void lldb_private::ExternalASTSourceWrapper::PrintStats() {
+ m_Source->PrintStats();
+}
+
+lldb_private::ASTConsumerForwarder::~ASTConsumerForwarder() = default;
+
+void lldb_private::ASTConsumerForwarder::PrintStats() { m_c->PrintStats(); }
+
+lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() = default;
+
+void lldb_private::SemaSourceWithPriorities::PrintStats() {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->PrintStats();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
new file mode 100644
index 000000000000..da2b1a15f746
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h
@@ -0,0 +1,577 @@
+//===-- 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 LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H
+
+#include "clang/Basic/ASTSourceDescriptor.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/MultiplexExternalSemaSource.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaConsumer.h"
+#include <optional>
+
+namespace clang {
+
+class Module;
+
+} // namespace clang
+
+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(clang::GlobalDeclID 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(const 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);
+ }
+
+ std::optional<clang::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(clang::GlobalDeclID 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 {
+ for (clang::ExternalSemaSource *S : Sources) {
+ S->CompleteType(Tag);
+ // Stop after the first source completed the type.
+ 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 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 // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
new file mode 100644
index 000000000000..44071d1ea71c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -0,0 +1,1415 @@
+//===-- ClangASTImporter.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTSource.h"
+#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include <memory>
+#include <optional>
+#include <type_traits>
+
+using namespace lldb_private;
+using namespace clang;
+
+CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast,
+ const CompilerType &src_type) {
+ clang::ASTContext &dst_clang_ast = dst_ast.getASTContext();
+
+ auto src_ast = src_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+ if (!src_ast)
+ return CompilerType();
+
+ clang::ASTContext &src_clang_ast = src_ast->getASTContext();
+
+ clang::QualType src_qual_type = ClangUtil::GetQualType(src_type);
+
+ ImporterDelegateSP delegate_sp(GetDelegate(&dst_clang_ast, &src_clang_ast));
+ if (!delegate_sp)
+ return CompilerType();
+
+ ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &dst_clang_ast);
+
+ llvm::Expected<QualType> ret_or_error = delegate_sp->Import(src_qual_type);
+ if (!ret_or_error) {
+ Log *log = GetLog(LLDBLog::Expressions);
+ LLDB_LOG_ERROR(log, ret_or_error.takeError(),
+ "Couldn't import type: {0}");
+ return CompilerType();
+ }
+
+ lldb::opaque_compiler_type_t dst_clang_type = ret_or_error->getAsOpaquePtr();
+
+ if (dst_clang_type)
+ return CompilerType(dst_ast.weak_from_this(), dst_clang_type);
+ return CompilerType();
+}
+
+clang::Decl *ClangASTImporter::CopyDecl(clang::ASTContext *dst_ast,
+ clang::Decl *decl) {
+ ImporterDelegateSP delegate_sp;
+
+ clang::ASTContext *src_ast = &decl->getASTContext();
+ delegate_sp = GetDelegate(dst_ast, src_ast);
+
+ ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, dst_ast);
+
+ if (!delegate_sp)
+ return nullptr;
+
+ llvm::Expected<clang::Decl *> result = delegate_sp->Import(decl);
+ if (!result) {
+ Log *log = GetLog(LLDBLog::Expressions);
+ LLDB_LOG_ERROR(log, result.takeError(), "Couldn't import decl: {0}");
+ if (log) {
+ lldb::user_id_t user_id = LLDB_INVALID_UID;
+ ClangASTMetadata *metadata = GetDeclMetadata(decl);
+ if (metadata)
+ user_id = metadata->GetUserID();
+
+ if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl))
+ LLDB_LOG(log,
+ " [ClangASTImporter] WARNING: Failed to import a {0} "
+ "'{1}', metadata {2}",
+ decl->getDeclKindName(), named_decl->getNameAsString(),
+ user_id);
+ else
+ LLDB_LOG(log,
+ " [ClangASTImporter] WARNING: Failed to import a {0}, "
+ "metadata {1}",
+ decl->getDeclKindName(), user_id);
+ }
+ return nullptr;
+ }
+
+ return *result;
+}
+
+class DeclContextOverride {
+private:
+ struct Backup {
+ clang::DeclContext *decl_context;
+ clang::DeclContext *lexical_decl_context;
+ };
+
+ llvm::DenseMap<clang::Decl *, Backup> m_backups;
+
+ void OverrideOne(clang::Decl *decl) {
+ if (m_backups.contains(decl)) {
+ return;
+ }
+
+ m_backups[decl] = {decl->getDeclContext(), decl->getLexicalDeclContext()};
+
+ decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl());
+ decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl());
+ }
+
+ bool ChainPassesThrough(
+ clang::Decl *decl, clang::DeclContext *base,
+ clang::DeclContext *(clang::Decl::*contextFromDecl)(),
+ clang::DeclContext *(clang::DeclContext::*contextFromContext)()) {
+ for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); decl_ctx;
+ decl_ctx = (decl_ctx->*contextFromContext)()) {
+ if (decl_ctx == base) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ clang::Decl *GetEscapedChild(clang::Decl *decl,
+ clang::DeclContext *base = nullptr) {
+ if (base) {
+ // decl's DeclContext chains must pass through base.
+
+ if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext,
+ &clang::DeclContext::getParent) ||
+ !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext,
+ &clang::DeclContext::getLexicalParent)) {
+ return decl;
+ }
+ } else {
+ base = clang::dyn_cast<clang::DeclContext>(decl);
+
+ if (!base) {
+ return nullptr;
+ }
+ }
+
+ if (clang::DeclContext *context =
+ clang::dyn_cast<clang::DeclContext>(decl)) {
+ for (clang::Decl *decl : context->decls()) {
+ if (clang::Decl *escaped_child = GetEscapedChild(decl)) {
+ return escaped_child;
+ }
+ }
+ }
+
+ return nullptr;
+ }
+
+ void Override(clang::Decl *decl) {
+ if (clang::Decl *escaped_child = GetEscapedChild(decl)) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] DeclContextOverride couldn't "
+ "override ({0}Decl*){1} - its child ({2}Decl*){3} escapes",
+ decl->getDeclKindName(), decl, escaped_child->getDeclKindName(),
+ escaped_child);
+ lldbassert(0 && "Couldn't override!");
+ }
+
+ OverrideOne(decl);
+ }
+
+public:
+ DeclContextOverride() = default;
+
+ void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) {
+ for (DeclContext *decl_context = decl->getLexicalDeclContext();
+ decl_context; decl_context = decl_context->getLexicalParent()) {
+ DeclContext *redecl_context = decl_context->getRedeclContext();
+
+ if (llvm::isa<FunctionDecl>(redecl_context) &&
+ llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) {
+ for (clang::Decl *child_decl : decl_context->decls()) {
+ Override(child_decl);
+ }
+ }
+ }
+ }
+
+ ~DeclContextOverride() {
+ for (const std::pair<clang::Decl *, Backup> &backup : m_backups) {
+ backup.first->setDeclContext(backup.second.decl_context);
+ backup.first->setLexicalDeclContext(backup.second.lexical_decl_context);
+ }
+ }
+};
+
+namespace {
+/// Completes all imported TagDecls at the end of the scope.
+///
+/// While in a CompleteTagDeclsScope, every decl that could be completed will
+/// be completed at the end of the scope (including all Decls that are
+/// imported while completing the original Decls).
+class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
+ ClangASTImporter::ImporterDelegateSP m_delegate;
+ /// List of declarations in the target context that need to be completed.
+ /// Every declaration should only be completed once and therefore should only
+ /// be once in this list.
+ llvm::SetVector<NamedDecl *> m_decls_to_complete;
+ /// Set of declarations that already were successfully completed (not just
+ /// added to m_decls_to_complete).
+ llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed;
+ clang::ASTContext *m_dst_ctx;
+ clang::ASTContext *m_src_ctx;
+ ClangASTImporter &importer;
+
+public:
+ /// Constructs a CompleteTagDeclsScope.
+ /// \param importer The ClangASTImporter that we should observe.
+ /// \param dst_ctx The ASTContext to which Decls are imported.
+ /// \param src_ctx The ASTContext from which Decls are imported.
+ explicit CompleteTagDeclsScope(ClangASTImporter &importer,
+ clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx)
+ : m_delegate(importer.GetDelegate(dst_ctx, src_ctx)), m_dst_ctx(dst_ctx),
+ m_src_ctx(src_ctx), importer(importer) {
+ m_delegate->SetImportListener(this);
+ }
+
+ ~CompleteTagDeclsScope() override {
+ ClangASTImporter::ASTContextMetadataSP to_context_md =
+ importer.GetContextMetadata(m_dst_ctx);
+
+ // Complete all decls we collected until now.
+ while (!m_decls_to_complete.empty()) {
+ NamedDecl *decl = m_decls_to_complete.pop_back_val();
+ m_decls_already_completed.insert(decl);
+
+ // The decl that should be completed has to be imported into the target
+ // context from some other context.
+ assert(to_context_md->hasOrigin(decl));
+ // We should only complete decls coming from the source context.
+ assert(to_context_md->getOrigin(decl).ctx == m_src_ctx);
+
+ Decl *original_decl = to_context_md->getOrigin(decl).decl;
+
+ // Complete the decl now.
+ TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
+ if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
+ if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
+ if (original_tag_decl->isCompleteDefinition()) {
+ m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
+ tag_decl->setCompleteDefinition(true);
+ }
+ }
+
+ tag_decl->setHasExternalLexicalStorage(false);
+ tag_decl->setHasExternalVisibleStorage(false);
+ } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
+ container_decl->setHasExternalLexicalStorage(false);
+ container_decl->setHasExternalVisibleStorage(false);
+ }
+
+ to_context_md->removeOrigin(decl);
+ }
+
+ // Stop listening to imported decls. We do this after clearing the
+ // Decls we needed to import to catch all Decls they might have pulled in.
+ m_delegate->RemoveImportListener();
+ }
+
+ void NewDeclImported(clang::Decl *from, clang::Decl *to) override {
+ // Filter out decls that we can't complete later.
+ if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to))
+ return;
+ RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from);
+ // We don't need to complete injected class name decls.
+ if (from_record_decl && from_record_decl->isInjectedClassName())
+ return;
+
+ NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to);
+ // Check if we already completed this type.
+ if (m_decls_already_completed.contains(to_named_decl))
+ return;
+ // Queue this type to be completed.
+ m_decls_to_complete.insert(to_named_decl);
+ }
+};
+} // namespace
+
+CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst,
+ const CompilerType &src_type) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ auto src_ctxt = src_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+ if (!src_ctxt)
+ return {};
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] DeportType called on ({0}Type*){1:x} "
+ "from (ASTContext*){2:x} to (ASTContext*){3:x}",
+ src_type.GetTypeName(), src_type.GetOpaqueQualType(),
+ &src_ctxt->getASTContext(), &dst.getASTContext());
+
+ DeclContextOverride decl_context_override;
+
+ if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>())
+ decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl());
+
+ CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(),
+ &src_ctxt->getASTContext());
+ return CopyType(dst, src_type);
+}
+
+clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx,
+ clang::Decl *decl) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ clang::ASTContext *src_ctx = &decl->getASTContext();
+ LLDB_LOG(log,
+ " [ClangASTImporter] DeportDecl called on ({0}Decl*){1:x} from "
+ "(ASTContext*){2:x} to (ASTContext*){3:x}",
+ decl->getDeclKindName(), decl, src_ctx, dst_ctx);
+
+ DeclContextOverride decl_context_override;
+
+ decl_context_override.OverrideAllDeclsFromContainingFunction(decl);
+
+ clang::Decl *result;
+ {
+ CompleteTagDeclsScope complete_scope(*this, dst_ctx, src_ctx);
+ result = CopyDecl(dst_ctx, decl);
+ }
+
+ if (!result)
+ return nullptr;
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] DeportDecl deported ({0}Decl*){1:x} to "
+ "({2}Decl*){3:x}",
+ decl->getDeclKindName(), decl, result->getDeclKindName(), result);
+
+ return result;
+}
+
+bool ClangASTImporter::CanImport(const CompilerType &type) {
+ if (!ClangUtil::IsClangType(type))
+ return false;
+
+ clang::QualType qual_type(
+ ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record: {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ if (GetDeclOrigin(cxx_record_decl).Valid())
+ return true;
+ }
+ } break;
+
+ case clang::Type::Enum: {
+ clang::EnumDecl *enum_decl =
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ if (enum_decl) {
+ if (GetDeclOrigin(enum_decl).Valid())
+ return true;
+ }
+ } break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface: {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ // We currently can't complete objective C types through the newly added
+ // ASTContext because it only supports TagDecl objects right now...
+ if (class_interface_decl) {
+ if (GetDeclOrigin(class_interface_decl).Valid())
+ return true;
+ }
+ }
+ } break;
+
+ case clang::Type::Typedef:
+ return CanImport(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getUnderlyingType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Auto:
+ return CanImport(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::AutoType>(qual_type)
+ ->getDeducedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Elaborated:
+ return CanImport(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::ElaboratedType>(qual_type)
+ ->getNamedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Paren:
+ return CanImport(CompilerType(
+ type.GetTypeSystem(),
+ llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool ClangASTImporter::Import(const CompilerType &type) {
+ if (!ClangUtil::IsClangType(type))
+ return false;
+
+ clang::QualType qual_type(
+ ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record: {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ if (GetDeclOrigin(cxx_record_decl).Valid())
+ return CompleteAndFetchChildren(qual_type);
+ }
+ } break;
+
+ case clang::Type::Enum: {
+ clang::EnumDecl *enum_decl =
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ if (enum_decl) {
+ if (GetDeclOrigin(enum_decl).Valid())
+ return CompleteAndFetchChildren(qual_type);
+ }
+ } break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface: {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ // We currently can't complete objective C types through the newly added
+ // ASTContext because it only supports TagDecl objects right now...
+ if (class_interface_decl) {
+ if (GetDeclOrigin(class_interface_decl).Valid())
+ return CompleteAndFetchChildren(qual_type);
+ }
+ }
+ } break;
+
+ case clang::Type::Typedef:
+ return Import(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getUnderlyingType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Auto:
+ return Import(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::AutoType>(qual_type)
+ ->getDeducedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Elaborated:
+ return Import(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::ElaboratedType>(qual_type)
+ ->getNamedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Paren:
+ return Import(CompilerType(
+ type.GetTypeSystem(),
+ llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) {
+ if (!CanImport(compiler_type))
+ return false;
+
+ if (Import(compiler_type)) {
+ TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
+ return true;
+ }
+
+ TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
+ false);
+ return false;
+}
+
+/// Copy layout information from \ref source_map to the \ref destination_map.
+///
+/// In the process of copying over layout info, we may need to import
+/// decls from the \ref source_map. This function will use the supplied
+/// \ref importer to import the necessary decls into \ref dest_ctx.
+///
+/// \param[in,out] dest_ctx Destination ASTContext into which we import
+/// decls from the \ref source_map.
+/// \param[out] destination_map A map from decls in \ref dest_ctx to an
+/// integral offest, which will be copies
+/// of the decl/offest pairs in \ref source_map
+/// if successful.
+/// \param[in] source_map A map from decls to integral offests. These will
+/// be copied into \ref destination_map.
+/// \param[in,out] importer Used to import decls into \ref dest_ctx.
+///
+/// \returns On success, will return 'true' and the offsets in \ref
+/// destination_map
+/// are usable copies of \ref source_map.
+template <class D, class O>
+static bool ImportOffsetMap(clang::ASTContext *dest_ctx,
+ llvm::DenseMap<const D *, O> &destination_map,
+ llvm::DenseMap<const D *, O> &source_map,
+ ClangASTImporter &importer) {
+ // When importing fields into a new record, clang has a hard requirement that
+ // fields be imported in field offset order. Since they are stored in a
+ // DenseMap with a pointer as the key type, this means we cannot simply
+ // iterate over the map, as the order will be non-deterministic. Instead we
+ // have to sort by the offset and then insert in sorted order.
+ typedef llvm::DenseMap<const D *, O> MapType;
+ typedef typename MapType::value_type PairType;
+ std::vector<PairType> sorted_items;
+ sorted_items.reserve(source_map.size());
+ sorted_items.assign(source_map.begin(), source_map.end());
+ llvm::sort(sorted_items, llvm::less_second());
+
+ for (const auto &item : sorted_items) {
+ DeclFromUser<D> user_decl(const_cast<D *>(item.first));
+ DeclFromParser<D> parser_decl(user_decl.Import(dest_ctx, importer));
+ if (parser_decl.IsInvalid())
+ return false;
+ destination_map.insert(
+ std::pair<const D *, O>(parser_decl.decl, item.second));
+ }
+
+ return true;
+}
+
+/// Given a CXXRecordDecl, will calculate and populate \ref base_offsets
+/// with the integral offsets of any of its (possibly virtual) base classes.
+///
+/// \param[in] record_layout ASTRecordLayout of \ref record.
+/// \param[in] record The record that we're calculating the base layouts of.
+/// \param[out] base_offsets Map of base-class decl to integral offset which
+/// this function will fill in.
+///
+/// \returns On success, will return 'true' and the offsets in \ref base_offsets
+/// are usable.
+template <bool IsVirtual>
+bool ExtractBaseOffsets(const ASTRecordLayout &record_layout,
+ DeclFromUser<const CXXRecordDecl> &record,
+ llvm::DenseMap<const clang::CXXRecordDecl *,
+ clang::CharUnits> &base_offsets) {
+ for (CXXRecordDecl::base_class_const_iterator
+ bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()),
+ be = (IsVirtual ? record->vbases_end() : record->bases_end());
+ bi != be; ++bi) {
+ if (!IsVirtual && bi->isVirtual())
+ continue;
+
+ const clang::Type *origin_base_type = bi->getType().getTypePtr();
+ const clang::RecordType *origin_base_record_type =
+ origin_base_type->getAs<RecordType>();
+
+ if (!origin_base_record_type)
+ return false;
+
+ DeclFromUser<RecordDecl> origin_base_record(
+ origin_base_record_type->getDecl());
+
+ if (origin_base_record.IsInvalid())
+ return false;
+
+ DeclFromUser<CXXRecordDecl> origin_base_cxx_record(
+ DynCast<CXXRecordDecl>(origin_base_record));
+
+ if (origin_base_cxx_record.IsInvalid())
+ return false;
+
+ CharUnits base_offset;
+
+ if (IsVirtual)
+ base_offset =
+ record_layout.getVBaseClassOffset(origin_base_cxx_record.decl);
+ else
+ base_offset =
+ record_layout.getBaseClassOffset(origin_base_cxx_record.decl);
+
+ base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>(
+ origin_base_cxx_record.decl, base_offset));
+ }
+
+ return true;
+}
+
+bool ClangASTImporter::importRecordLayoutFromOrigin(
+ const RecordDecl *record, uint64_t &size, uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets) {
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ clang::ASTContext &dest_ctx = record->getASTContext();
+ LLDB_LOG(log,
+ "LayoutRecordType on (ASTContext*){0:x} '{1}' for (RecordDecl*)"
+ "{2:x} [name = '{3}']",
+ &dest_ctx,
+ TypeSystemClang::GetASTContext(&dest_ctx)->getDisplayName(), record,
+ record->getName());
+
+ DeclFromParser<const RecordDecl> parser_record(record);
+ DeclFromUser<const RecordDecl> origin_record(parser_record.GetOrigin(*this));
+
+ if (origin_record.IsInvalid())
+ return false;
+
+ std::remove_reference_t<decltype(field_offsets)> origin_field_offsets;
+ std::remove_reference_t<decltype(base_offsets)> origin_base_offsets;
+ std::remove_reference_t<decltype(vbase_offsets)> origin_virtual_base_offsets;
+
+ TypeSystemClang::GetCompleteDecl(
+ &origin_record->getASTContext(),
+ const_cast<RecordDecl *>(origin_record.decl));
+
+ clang::RecordDecl *definition = origin_record.decl->getDefinition();
+ if (!definition || !definition->isCompleteDefinition())
+ return false;
+
+ const ASTRecordLayout &record_layout(
+ origin_record->getASTContext().getASTRecordLayout(origin_record.decl));
+
+ int field_idx = 0, field_count = record_layout.getFieldCount();
+
+ for (RecordDecl::field_iterator fi = origin_record->field_begin(),
+ fe = origin_record->field_end();
+ fi != fe; ++fi) {
+ if (field_idx >= field_count)
+ return false; // Layout didn't go well. Bail out.
+
+ uint64_t field_offset = record_layout.getFieldOffset(field_idx);
+
+ origin_field_offsets.insert(
+ std::pair<const FieldDecl *, uint64_t>(*fi, field_offset));
+
+ field_idx++;
+ }
+
+ DeclFromUser<const CXXRecordDecl> origin_cxx_record(
+ DynCast<const CXXRecordDecl>(origin_record));
+
+ if (origin_cxx_record.IsValid()) {
+ if (!ExtractBaseOffsets<false>(record_layout, origin_cxx_record,
+ origin_base_offsets) ||
+ !ExtractBaseOffsets<true>(record_layout, origin_cxx_record,
+ origin_virtual_base_offsets))
+ return false;
+ }
+
+ if (!ImportOffsetMap(&dest_ctx, field_offsets, origin_field_offsets, *this) ||
+ !ImportOffsetMap(&dest_ctx, base_offsets, origin_base_offsets, *this) ||
+ !ImportOffsetMap(&dest_ctx, vbase_offsets, origin_virtual_base_offsets,
+ *this))
+ return false;
+
+ size = record_layout.getSize().getQuantity() * dest_ctx.getCharWidth();
+ alignment =
+ record_layout.getAlignment().getQuantity() * dest_ctx.getCharWidth();
+
+ if (log) {
+ LLDB_LOG(log, "LRT returned:");
+ LLDB_LOG(log, "LRT Original = (RecordDecl*){0:x}",
+ static_cast<const void *>(origin_record.decl));
+ LLDB_LOG(log, "LRT Size = {0}", size);
+ LLDB_LOG(log, "LRT Alignment = {0}", alignment);
+ LLDB_LOG(log, "LRT Fields:");
+ for (RecordDecl::field_iterator fi = record->field_begin(),
+ fe = record->field_end();
+ fi != fe; ++fi) {
+ LLDB_LOG(
+ log,
+ "LRT (FieldDecl*){0:x}, Name = '{1}', Type = '{2}', Offset = "
+ "{3} bits",
+ *fi, fi->getName(), fi->getType().getAsString(), field_offsets[*fi]);
+ }
+ DeclFromParser<const CXXRecordDecl> parser_cxx_record =
+ DynCast<const CXXRecordDecl>(parser_record);
+ if (parser_cxx_record.IsValid()) {
+ LLDB_LOG(log, "LRT Bases:");
+ for (CXXRecordDecl::base_class_const_iterator
+ bi = parser_cxx_record->bases_begin(),
+ be = parser_cxx_record->bases_end();
+ bi != be; ++bi) {
+ bool is_virtual = bi->isVirtual();
+
+ QualType base_type = bi->getType();
+ const RecordType *base_record_type = base_type->getAs<RecordType>();
+ DeclFromParser<RecordDecl> base_record(base_record_type->getDecl());
+ DeclFromParser<CXXRecordDecl> base_cxx_record =
+ DynCast<CXXRecordDecl>(base_record);
+
+ LLDB_LOG(log,
+ "LRT {0}(CXXRecordDecl*){1:x}, Name = '{2}', Offset = "
+ "{3} chars",
+ (is_virtual ? "Virtual " : ""), base_cxx_record.decl,
+ base_cxx_record.decl->getName(),
+ (is_virtual
+ ? vbase_offsets[base_cxx_record.decl].getQuantity()
+ : base_offsets[base_cxx_record.decl].getQuantity()));
+ }
+ } else {
+ LLDB_LOG(log, "LRD Not a CXXRecord, so no bases");
+ }
+ }
+
+ return true;
+}
+
+bool ClangASTImporter::LayoutRecordType(
+ const clang::RecordDecl *record_decl, uint64_t &bit_size,
+ uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets) {
+ RecordDeclToLayoutMap::iterator pos =
+ m_record_decl_to_layout_map.find(record_decl);
+ base_offsets.clear();
+ vbase_offsets.clear();
+ if (pos != m_record_decl_to_layout_map.end()) {
+ bit_size = pos->second.bit_size;
+ alignment = pos->second.alignment;
+ field_offsets.swap(pos->second.field_offsets);
+ base_offsets.swap(pos->second.base_offsets);
+ vbase_offsets.swap(pos->second.vbase_offsets);
+ m_record_decl_to_layout_map.erase(pos);
+ return true;
+ }
+
+ // It's possible that we calculated the layout in a different
+ // ClangASTImporter instance. Try to import such layout if
+ // our decl has an origin.
+ if (auto origin = GetDeclOrigin(record_decl); origin.Valid())
+ if (importRecordLayoutFromOrigin(record_decl, bit_size, alignment,
+ field_offsets, base_offsets,
+ vbase_offsets))
+ return true;
+
+ bit_size = 0;
+ alignment = 0;
+ field_offsets.clear();
+
+ return false;
+}
+
+void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl,
+ const LayoutInfo &layout) {
+ m_record_decl_to_layout_map.insert(std::make_pair(decl, layout));
+}
+
+bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
+ DeclOrigin decl_origin = GetDeclOrigin(decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&decl->getASTContext(), decl_origin.ctx));
+
+ ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
+ &decl->getASTContext());
+ if (delegate_sp)
+ delegate_sp->ImportDefinitionTo(decl, decl_origin.decl);
+
+ return true;
+}
+
+bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl,
+ clang::TagDecl *origin_decl) {
+ clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext();
+
+ if (!TypeSystemClang::GetCompleteDecl(origin_ast_ctx, origin_decl))
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&decl->getASTContext(), origin_ast_ctx));
+
+ if (delegate_sp)
+ delegate_sp->ImportDefinitionTo(decl, origin_decl);
+
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ context_md->setOrigin(decl, DeclOrigin(origin_ast_ctx, origin_decl));
+ return true;
+}
+
+bool ClangASTImporter::CompleteObjCInterfaceDecl(
+ clang::ObjCInterfaceDecl *interface_decl) {
+ DeclOrigin decl_origin = GetDeclOrigin(interface_decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx));
+
+ if (delegate_sp)
+ delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);
+
+ if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass())
+ RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0));
+
+ return true;
+}
+
+bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) {
+ if (!RequireCompleteType(type))
+ return false;
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (const TagType *tag_type = type->getAs<TagType>()) {
+ TagDecl *tag_decl = tag_type->getDecl();
+
+ DeclOrigin decl_origin = GetDeclOrigin(tag_decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx));
+
+ ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
+ &tag_decl->getASTContext());
+
+ TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl);
+
+ for (Decl *origin_child_decl : origin_tag_decl->decls()) {
+ llvm::Expected<Decl *> imported_or_err =
+ delegate_sp->Import(origin_child_decl);
+ if (!imported_or_err) {
+ LLDB_LOG_ERROR(log, imported_or_err.takeError(),
+ "Couldn't import decl: {0}");
+ return false;
+ }
+ }
+
+ if (RecordDecl *record_decl = dyn_cast<RecordDecl>(origin_tag_decl))
+ record_decl->setHasLoadedFieldsFromExternalStorage(true);
+
+ return true;
+ }
+
+ if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
+ if (ObjCInterfaceDecl *objc_interface_decl =
+ objc_object_type->getInterface()) {
+ DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx));
+
+ ObjCInterfaceDecl *origin_interface_decl =
+ llvm::dyn_cast<ObjCInterfaceDecl>(decl_origin.decl);
+
+ for (Decl *origin_child_decl : origin_interface_decl->decls()) {
+ llvm::Expected<Decl *> imported_or_err =
+ delegate_sp->Import(origin_child_decl);
+ if (!imported_or_err) {
+ LLDB_LOG_ERROR(log, imported_or_err.takeError(),
+ "Couldn't import decl: {0}");
+ return false;
+ }
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool ClangASTImporter::RequireCompleteType(clang::QualType type) {
+ if (type.isNull())
+ return false;
+
+ if (const TagType *tag_type = type->getAs<TagType>()) {
+ TagDecl *tag_decl = tag_type->getDecl();
+
+ if (tag_decl->getDefinition() || tag_decl->isBeingDefined())
+ return true;
+
+ return CompleteTagDecl(tag_decl);
+ }
+ if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
+ if (ObjCInterfaceDecl *objc_interface_decl =
+ objc_object_type->getInterface())
+ return CompleteObjCInterfaceDecl(objc_interface_decl);
+ return false;
+ }
+ if (const ArrayType *array_type = type->getAsArrayTypeUnsafe())
+ return RequireCompleteType(array_type->getElementType());
+ if (const AtomicType *atomic_type = type->getAs<AtomicType>())
+ return RequireCompleteType(atomic_type->getPointeeType());
+
+ return true;
+}
+
+ClangASTMetadata *ClangASTImporter::GetDeclMetadata(const clang::Decl *decl) {
+ DeclOrigin decl_origin = GetDeclOrigin(decl);
+
+ if (decl_origin.Valid()) {
+ TypeSystemClang *ast = TypeSystemClang::GetASTContext(decl_origin.ctx);
+ return ast->GetMetadata(decl_origin.decl);
+ }
+ TypeSystemClang *ast = TypeSystemClang::GetASTContext(&decl->getASTContext());
+ return ast->GetMetadata(decl);
+}
+
+ClangASTImporter::DeclOrigin
+ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) {
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ return context_md->getOrigin(decl);
+}
+
+void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl,
+ clang::Decl *original_decl) {
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+ context_md->setOrigin(
+ decl, DeclOrigin(&original_decl->getASTContext(), original_decl));
+}
+
+void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl,
+ NamespaceMapSP &namespace_map) {
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ context_md->m_namespace_maps[decl] = namespace_map;
+}
+
+ClangASTImporter::NamespaceMapSP
+ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl) {
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps;
+
+ NamespaceMetaMap::iterator iter = namespace_maps.find(decl);
+
+ if (iter != namespace_maps.end())
+ return iter->second;
+ return NamespaceMapSP();
+}
+
+void ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl) {
+ assert(decl);
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ const DeclContext *parent_context = decl->getDeclContext();
+ const NamespaceDecl *parent_namespace =
+ dyn_cast<NamespaceDecl>(parent_context);
+ NamespaceMapSP parent_map;
+
+ if (parent_namespace)
+ parent_map = GetNamespaceMap(parent_namespace);
+
+ NamespaceMapSP new_map;
+
+ new_map = std::make_shared<NamespaceMap>();
+
+ if (context_md->m_map_completer) {
+ std::string namespace_string = decl->getDeclName().getAsString();
+
+ context_md->m_map_completer->CompleteNamespaceMap(
+ new_map, ConstString(namespace_string.c_str()), parent_map);
+ }
+
+ context_md->m_namespace_maps[decl] = new_map;
+}
+
+void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Forgetting destination (ASTContext*){0:x}",
+ dst_ast);
+
+ m_metadata_map.erase(dst_ast);
+}
+
+void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast,
+ clang::ASTContext *src_ast) {
+ ASTContextMetadataSP md = MaybeGetContextMetadata(dst_ast);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Forgetting source->dest "
+ "(ASTContext*){0:x}->(ASTContext*){1:x}",
+ src_ast, dst_ast);
+
+ if (!md)
+ return;
+
+ md->m_delegates.erase(src_ast);
+ md->removeOriginsWithContext(src_ast);
+}
+
+ClangASTImporter::MapCompleter::~MapCompleter() = default;
+
+llvm::Expected<Decl *>
+ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
+ if (m_std_handler) {
+ std::optional<Decl *> D = m_std_handler->Import(From);
+ if (D) {
+ // Make sure we don't use this decl later to map it back to it's original
+ // decl. The decl the CxxModuleHandler created has nothing to do with
+ // the one from debug info, and linking those two would just cause the
+ // ASTImporter to try 'updating' the module decl with the minimal one from
+ // the debug info.
+ m_decls_to_ignore.insert(*D);
+ return *D;
+ }
+ }
+
+ // Check which ASTContext this declaration originally came from.
+ DeclOrigin origin = m_main.GetDeclOrigin(From);
+
+ // Prevent infinite recursion when the origin tracking contains a cycle.
+ assert(origin.decl != From && "Origin points to itself?");
+
+ // If it originally came from the target ASTContext then we can just
+ // pretend that the original is the one we imported. This can happen for
+ // example when inspecting a persistent declaration from the scratch
+ // ASTContext (which will provide the declaration when parsing the
+ // expression and then we later try to copy the declaration back to the
+ // scratch ASTContext to store the result).
+ // Without this check we would ask the ASTImporter to import a declaration
+ // into the same ASTContext where it came from (which doesn't make a lot of
+ // sense).
+ if (origin.Valid() && origin.ctx == &getToContext()) {
+ RegisterImportedDecl(From, origin.decl);
+ return origin.decl;
+ }
+
+ // This declaration came originally from another ASTContext. Instead of
+ // copying our potentially incomplete 'From' Decl we instead go to the
+ // original ASTContext and copy the original to the target. This is not
+ // only faster than first completing our current decl and then copying it
+ // to the target, but it also prevents that indirectly copying the same
+ // declaration to the same target requires the ASTImporter to merge all
+ // the different decls that appear to come from different ASTContexts (even
+ // though all these different source ASTContexts just got a copy from
+ // one source AST).
+ if (origin.Valid()) {
+ auto R = m_main.CopyDecl(&getToContext(), origin.decl);
+ if (R) {
+ RegisterImportedDecl(From, R);
+ return R;
+ }
+ }
+
+ // If we have a forcefully completed type, try to find an actual definition
+ // for it in other modules.
+ const ClangASTMetadata *md = m_main.GetDeclMetadata(From);
+ auto *td = dyn_cast<TagDecl>(From);
+ if (td && md && md->IsForcefullyCompleted()) {
+ Log *log = GetLog(LLDBLog::Expressions);
+ LLDB_LOG(log,
+ "[ClangASTImporter] Searching for a complete definition of {0} in "
+ "other modules",
+ td->getName());
+ Expected<DeclContext *> dc_or_err = ImportContext(td->getDeclContext());
+ if (!dc_or_err)
+ return dc_or_err.takeError();
+ Expected<DeclarationName> dn_or_err = Import(td->getDeclName());
+ if (!dn_or_err)
+ return dn_or_err.takeError();
+ DeclContext *dc = *dc_or_err;
+ DeclContext::lookup_result lr = dc->lookup(*dn_or_err);
+ for (clang::Decl *candidate : lr) {
+ if (candidate->getKind() == From->getKind()) {
+ RegisterImportedDecl(From, candidate);
+ m_decls_to_ignore.insert(candidate);
+ return candidate;
+ }
+ }
+ LLDB_LOG(log, "[ClangASTImporter] Complete definition not found");
+ }
+
+ return ASTImporter::ImportImpl(From);
+}
+
+void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(
+ clang::Decl *to, clang::Decl *from) {
+ // We might have a forward declaration from a shared library that we
+ // gave external lexical storage so that Clang asks us about the full
+ // definition when it needs it. In this case the ASTImporter isn't aware
+ // that the forward decl from the shared library is the actual import
+ // target but would create a second declaration that would then be defined.
+ // We want that 'to' is actually complete after this function so let's
+ // tell the ASTImporter that 'to' was imported from 'from'.
+ MapImported(from, to);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (llvm::Error err = ImportDefinition(from)) {
+ LLDB_LOG_ERROR(log, std::move(err),
+ "[ClangASTImporter] Error during importing definition: {0}");
+ return;
+ }
+
+ if (clang::TagDecl *to_tag = dyn_cast<clang::TagDecl>(to)) {
+ if (clang::TagDecl *from_tag = dyn_cast<clang::TagDecl>(from)) {
+ to_tag->setCompleteDefinition(from_tag->isCompleteDefinition());
+
+ if (Log *log_ast = GetLog(LLDBLog::AST)) {
+ std::string name_string;
+ if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) {
+ llvm::raw_string_ostream name_stream(name_string);
+ from_named_decl->printName(name_stream);
+ name_stream.flush();
+ }
+ LLDB_LOG(log_ast,
+ "==== [ClangASTImporter][TUDecl: {0:x}] Imported "
+ "({1}Decl*){2:x}, named {3} (from "
+ "(Decl*){4:x})",
+ static_cast<void *>(to->getTranslationUnitDecl()),
+ from->getDeclKindName(), static_cast<void *>(to), name_string,
+ static_cast<void *>(from));
+
+ // Log the AST of the TU.
+ std::string ast_string;
+ llvm::raw_string_ostream ast_stream(ast_string);
+ to->getTranslationUnitDecl()->dump(ast_stream);
+ LLDB_LOG(log_ast, "{0}", ast_string);
+ }
+ }
+ }
+
+ // If we're dealing with an Objective-C class, ensure that the inheritance
+ // has been set up correctly. The ASTImporter may not do this correctly if
+ // the class was originally sourced from symbols.
+
+ if (ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to)) {
+ ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass();
+
+ if (to_superclass)
+ return; // we're not going to override it if it's set
+
+ ObjCInterfaceDecl *from_objc_interface = dyn_cast<ObjCInterfaceDecl>(from);
+
+ if (!from_objc_interface)
+ return;
+
+ ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass();
+
+ if (!from_superclass)
+ return;
+
+ llvm::Expected<Decl *> imported_from_superclass_decl =
+ Import(from_superclass);
+
+ if (!imported_from_superclass_decl) {
+ LLDB_LOG_ERROR(log, imported_from_superclass_decl.takeError(),
+ "Couldn't import decl: {0}");
+ return;
+ }
+
+ ObjCInterfaceDecl *imported_from_superclass =
+ dyn_cast<ObjCInterfaceDecl>(*imported_from_superclass_decl);
+
+ if (!imported_from_superclass)
+ return;
+
+ if (!to_objc_interface->hasDefinition())
+ to_objc_interface->startDefinition();
+
+ to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo(
+ m_source_ctx->getObjCInterfaceType(imported_from_superclass)));
+ }
+}
+
+/// Takes a CXXMethodDecl and completes the return type if necessary. This
+/// is currently only necessary for virtual functions with covariant return
+/// types where Clang's CodeGen expects that the underlying records are already
+/// completed.
+static void MaybeCompleteReturnType(ClangASTImporter &importer,
+ CXXMethodDecl *to_method) {
+ if (!to_method->isVirtual())
+ return;
+ QualType return_type = to_method->getReturnType();
+ if (!return_type->isPointerType() && !return_type->isReferenceType())
+ return;
+
+ clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl();
+ if (!rd)
+ return;
+ if (rd->getDefinition())
+ return;
+
+ importer.CompleteTagDecl(rd);
+}
+
+/// Recreate a module with its parents in \p to_source and return its id.
+static OptionalClangModuleID
+RemapModule(OptionalClangModuleID from_id,
+ ClangExternalASTSourceCallbacks &from_source,
+ ClangExternalASTSourceCallbacks &to_source) {
+ if (!from_id.HasValue())
+ return {};
+ clang::Module *module = from_source.getModule(from_id.GetValue());
+ OptionalClangModuleID parent = RemapModule(
+ from_source.GetIDForModule(module->Parent), from_source, to_source);
+ TypeSystemClang &to_ts = to_source.GetTypeSystem();
+ return to_ts.GetOrCreateClangModule(module->Name, parent, module->IsFramework,
+ module->IsExplicit);
+}
+
+void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
+ clang::Decl *to) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ // Some decls shouldn't be tracked here because they were not created by
+ // copying 'from' to 'to'. Just exit early for those.
+ if (m_decls_to_ignore.count(to))
+ return;
+
+ // Transfer module ownership information.
+ auto *from_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>(
+ getFromContext().getExternalSource());
+ // Can also be a ClangASTSourceProxy.
+ auto *to_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>(
+ getToContext().getExternalSource());
+ if (from_source && to_source) {
+ OptionalClangModuleID from_id(from->getOwningModuleID());
+ OptionalClangModuleID to_id =
+ RemapModule(from_id, *from_source, *to_source);
+ TypeSystemClang &to_ts = to_source->GetTypeSystem();
+ to_ts.SetOwningModule(to, to_id);
+ }
+
+ lldb::user_id_t user_id = LLDB_INVALID_UID;
+ ClangASTMetadata *metadata = m_main.GetDeclMetadata(from);
+ if (metadata)
+ user_id = metadata->GetUserID();
+
+ if (log) {
+ if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) {
+ std::string name_string;
+ llvm::raw_string_ostream name_stream(name_string);
+ from_named_decl->printName(name_stream);
+ name_stream.flush();
+
+ LLDB_LOG(
+ log,
+ " [ClangASTImporter] Imported ({0}Decl*){1:x}, named {2} (from "
+ "(Decl*){3:x}), metadata {4}",
+ from->getDeclKindName(), to, name_string, from, user_id);
+ } else {
+ LLDB_LOG(log,
+ " [ClangASTImporter] Imported ({0}Decl*){1:x} (from "
+ "(Decl*){2:x}), metadata {3}",
+ from->getDeclKindName(), to, from, user_id);
+ }
+ }
+
+ ASTContextMetadataSP to_context_md =
+ m_main.GetContextMetadata(&to->getASTContext());
+ ASTContextMetadataSP from_context_md =
+ m_main.MaybeGetContextMetadata(m_source_ctx);
+
+ if (from_context_md) {
+ DeclOrigin origin = from_context_md->getOrigin(from);
+
+ if (origin.Valid()) {
+ if (origin.ctx != &to->getASTContext()) {
+ if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID)
+ to_context_md->setOrigin(to, origin);
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Propagated origin "
+ "(Decl*){0:x}/(ASTContext*){1:x} from (ASTContext*){2:x} to "
+ "(ASTContext*){3:x}",
+ origin.decl, origin.ctx, &from->getASTContext(),
+ &to->getASTContext());
+ }
+ } else {
+ if (m_new_decl_listener)
+ m_new_decl_listener->NewDeclImported(from, to);
+
+ if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID)
+ to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from));
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Decl has no origin information in "
+ "(ASTContext*){0:x}",
+ &from->getASTContext());
+ }
+
+ if (auto *to_namespace = dyn_cast<clang::NamespaceDecl>(to)) {
+ auto *from_namespace = cast<clang::NamespaceDecl>(from);
+
+ NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps;
+
+ NamespaceMetaMap::iterator namespace_map_iter =
+ namespace_maps.find(from_namespace);
+
+ if (namespace_map_iter != namespace_maps.end())
+ to_context_md->m_namespace_maps[to_namespace] =
+ namespace_map_iter->second;
+ }
+ } else {
+ to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from));
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Sourced origin "
+ "(Decl*){0:x}/(ASTContext*){1:x} into (ASTContext*){2:x}",
+ from, m_source_ctx, &to->getASTContext());
+ }
+
+ if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) {
+ to_tag_decl->setHasExternalLexicalStorage();
+ to_tag_decl->getPrimaryContext()->setMustBuildLookupTable();
+ auto from_tag_decl = cast<TagDecl>(from);
+
+ LLDB_LOG(
+ log,
+ " [ClangASTImporter] To is a TagDecl - attributes {0}{1} [{2}->{3}]",
+ (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+ (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""),
+ (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
+ (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
+ }
+
+ if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) {
+ m_main.BuildNamespaceMap(to_namespace_decl);
+ to_namespace_decl->setHasExternalVisibleStorage();
+ }
+
+ if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) {
+ to_container_decl->setHasExternalLexicalStorage();
+ to_container_decl->setHasExternalVisibleStorage();
+
+ if (log) {
+ if (ObjCInterfaceDecl *to_interface_decl =
+ llvm::dyn_cast<ObjCInterfaceDecl>(to_container_decl)) {
+ LLDB_LOG(
+ log,
+ " [ClangASTImporter] To is an ObjCInterfaceDecl - attributes "
+ "{0}{1}{2}",
+ (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+ (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""),
+ (to_interface_decl->hasDefinition() ? " HasDefinition" : ""));
+ } else {
+ LLDB_LOG(
+ log, " [ClangASTImporter] To is an {0}Decl - attributes {1}{2}",
+ ((Decl *)to_container_decl)->getDeclKindName(),
+ (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+ (to_container_decl->hasExternalVisibleStorage() ? " Visible" : ""));
+ }
+ }
+ }
+
+ if (clang::CXXMethodDecl *to_method = dyn_cast<CXXMethodDecl>(to))
+ MaybeCompleteReturnType(m_main, to_method);
+}
+
+clang::Decl *
+ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) {
+ return m_main.GetDeclOrigin(To).decl;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
new file mode 100644
index 000000000000..bc962e544d2f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
@@ -0,0 +1,535 @@
+//===-- ClangASTImporter.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
+
+#include <map>
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-types.h"
+
+#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace lldb_private {
+
+class ClangASTMetadata;
+class TypeSystemClang;
+
+/// Manages and observes all Clang AST node importing in LLDB.
+///
+/// The ClangASTImporter takes care of two things:
+///
+/// 1. Keeps track of all ASTImporter instances in LLDB.
+///
+/// Clang's ASTImporter takes care of importing types from one ASTContext to
+/// another. This class expands this concept by allowing copying from several
+/// ASTContext instances to several other ASTContext instances. Instead of
+/// constructing a new ASTImporter manually to copy over a type/decl, this class
+/// can be asked to do this. It will construct a ASTImporter for the caller (and
+/// will cache the ASTImporter instance for later use) and then perform the
+/// import.
+///
+/// This mainly prevents that a caller might construct several ASTImporter
+/// instances for the same source/target ASTContext combination. As the
+/// ASTImporter has an internal state that keeps track of already imported
+/// declarations and so on, using only one ASTImporter instance is more
+/// efficient and less error-prone than using multiple.
+///
+/// 2. Keeps track of from where declarations were imported (origin-tracking).
+/// The ASTImporter instances in this class usually only performa a minimal
+/// import, i.e., only a shallow copy is made that is filled out on demand
+/// when more information is requested later on. This requires record-keeping
+/// of where any shallow clone originally came from so that the right original
+/// declaration can be found and used as the source of any missing information.
+class ClangASTImporter {
+public:
+ struct LayoutInfo {
+ LayoutInfo() = default;
+ typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ OffsetMap;
+
+ uint64_t bit_size = 0;
+ uint64_t alignment = 0;
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
+ OffsetMap base_offsets;
+ OffsetMap vbase_offsets;
+ };
+
+ ClangASTImporter()
+ : m_file_manager(clang::FileSystemOptions(),
+ FileSystem::Instance().GetVirtualFileSystem()) {}
+
+ /// Copies the given type and the respective declarations to the destination
+ /// type system.
+ ///
+ /// This function does a shallow copy and requires that the target AST
+ /// has an ExternalASTSource which queries this ClangASTImporter instance
+ /// for any additional information that is maybe lacking in the shallow copy.
+ /// This also means that the type system of src_type can *not* be deleted
+ /// after this function has been called. If you need to delete the source
+ /// type system you either need to delete the destination type system first
+ /// or use \ref ClangASTImporter::DeportType.
+ ///
+ /// \see ClangASTImporter::DeportType
+ CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type);
+
+ /// \see ClangASTImporter::CopyType
+ clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
+
+ /// Copies the given type and the respective declarations to the destination
+ /// type system.
+ ///
+ /// Unlike CopyType this function ensures that types/declarations which are
+ /// originally from the AST of src_type are fully copied over. The type
+ /// system of src_type can safely be deleted after calling this function.
+ /// \see ClangASTImporter::CopyType
+ CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type);
+
+ /// Copies the given decl to the destination type system.
+ /// \see ClangASTImporter::DeportType
+ clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
+
+ /// Sets the layout for the given RecordDecl. The layout will later be
+ /// used by Clang's during code generation. Not calling this function for
+ /// a RecordDecl will cause that Clang's codegen tries to layout the
+ /// record by itself.
+ ///
+ /// \param decl The RecordDecl to set the layout for.
+ /// \param layout The layout for the record.
+ void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout);
+
+ bool LayoutRecordType(
+ const clang::RecordDecl *record_decl, uint64_t &bit_size,
+ uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets);
+
+ /// If \ref record has a valid origin, this function copies that
+ /// origin's layout into this ClangASTImporter instance.
+ ///
+ /// \param[in] record The decl whose layout we're calculating.
+ /// \param[out] size Size of \ref record in bytes.
+ /// \param[out] alignment Alignment of \ref record in bytes.
+ /// \param[out] field_offsets Offsets of fields of \ref record.
+ /// \param[out] base_offsets Offsets of base classes of \ref record.
+ /// \param[out] vbase_offsets Offsets of virtual base classes of \ref record.
+ ///
+ /// \returns Returns 'false' if no valid origin was found for \ref record or
+ /// this function failed to import the layout from the origin. Otherwise,
+ /// returns 'true' and the offsets/size/alignment are valid for use.
+ bool importRecordLayoutFromOrigin(
+ const clang::RecordDecl *record, uint64_t &size, uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets);
+
+ /// Returns true iff the given type was copied from another TypeSystemClang
+ /// and the original type in this other TypeSystemClang might contain
+ /// additional information (e.g., the definition of a 'class' type) that could
+ /// be imported.
+ ///
+ /// \see ClangASTImporter::Import
+ bool CanImport(const CompilerType &type);
+
+ /// If the given type was copied from another TypeSystemClang then copy over
+ /// all missing information (e.g., the definition of a 'class' type).
+ ///
+ /// \return True iff an original type in another TypeSystemClang was found.
+ /// Note: Does *not* return false if an original type was found but
+ /// no information was imported over.
+ ///
+ /// \see ClangASTImporter::Import
+ bool Import(const CompilerType &type);
+
+ bool CompleteType(const CompilerType &compiler_type);
+
+ bool CompleteTagDecl(clang::TagDecl *decl);
+
+ bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin);
+
+ bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl);
+
+ bool CompleteAndFetchChildren(clang::QualType type);
+
+ bool RequireCompleteType(clang::QualType type);
+
+ /// Updates the internal origin-tracking information so that the given
+ /// 'original' decl is from now on used to import additional information
+ /// into the given decl.
+ ///
+ /// Usually the origin-tracking in the ClangASTImporter is automatically
+ /// updated when a declaration is imported, so the only valid reason to ever
+ /// call this is if there is a 'better' original decl and the target decl
+ /// is only a shallow clone that lacks any contents.
+ void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl);
+
+ ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl);
+
+ //
+ // Namespace maps
+ //
+
+ typedef std::pair<lldb::ModuleSP, CompilerDeclContext> NamespaceMapItem;
+ typedef std::vector<NamespaceMapItem> NamespaceMap;
+ typedef std::shared_ptr<NamespaceMap> NamespaceMapSP;
+
+ void RegisterNamespaceMap(const clang::NamespaceDecl *decl,
+ NamespaceMapSP &namespace_map);
+
+ NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl);
+
+ void BuildNamespaceMap(const clang::NamespaceDecl *decl);
+
+ //
+ // Completers for maps
+ //
+
+ class MapCompleter {
+ public:
+ virtual ~MapCompleter();
+
+ virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map,
+ ConstString name,
+ NamespaceMapSP &parent_map) const = 0;
+ };
+
+ void InstallMapCompleter(clang::ASTContext *dst_ctx,
+ MapCompleter &completer) {
+ ASTContextMetadataSP context_md;
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter == m_metadata_map.end()) {
+ context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
+ m_metadata_map[dst_ctx] = context_md;
+ } else {
+ context_md = context_md_iter->second;
+ }
+
+ context_md->m_map_completer = &completer;
+ }
+
+ void ForgetDestination(clang::ASTContext *dst_ctx);
+ void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx);
+
+ struct DeclOrigin {
+ DeclOrigin() = default;
+
+ DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl)
+ : ctx(_ctx), decl(_decl) {
+ // The decl has to be in its associated ASTContext.
+ assert(_decl == nullptr || &_decl->getASTContext() == _ctx);
+ }
+
+ DeclOrigin(const DeclOrigin &rhs) {
+ ctx = rhs.ctx;
+ decl = rhs.decl;
+ }
+
+ void operator=(const DeclOrigin &rhs) {
+ ctx = rhs.ctx;
+ decl = rhs.decl;
+ }
+
+ bool Valid() const { return (ctx != nullptr || decl != nullptr); }
+
+ clang::ASTContext *ctx = nullptr;
+ clang::Decl *decl = nullptr;
+ };
+
+ /// Listener interface used by the ASTImporterDelegate to inform other code
+ /// about decls that have been imported the first time.
+ struct NewDeclListener {
+ virtual ~NewDeclListener() = default;
+ /// A decl has been imported for the first time.
+ virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0;
+ };
+
+ /// ASTImporter that intercepts and records the import process of the
+ /// underlying ASTImporter.
+ ///
+ /// This class updates the map from declarations to their original
+ /// declarations and can record declarations that have been imported in a
+ /// certain interval.
+ ///
+ /// When intercepting a declaration import, the ASTImporterDelegate uses the
+ /// CxxModuleHandler to replace any missing or malformed declarations with
+ /// their counterpart from a C++ module.
+ struct ASTImporterDelegate : public clang::ASTImporter {
+ ASTImporterDelegate(ClangASTImporter &main, clang::ASTContext *target_ctx,
+ clang::ASTContext *source_ctx)
+ : clang::ASTImporter(*target_ctx, main.m_file_manager, *source_ctx,
+ main.m_file_manager, true /*minimal*/),
+ m_main(main), m_source_ctx(source_ctx) {
+ // Target and source ASTContext shouldn't be identical. Importing AST
+ // nodes within the same AST doesn't make any sense as the whole idea
+ // is to import them to a different AST.
+ lldbassert(target_ctx != source_ctx && "Can't import into itself");
+ // This is always doing a minimal import of any declarations. This means
+ // that there has to be an ExternalASTSource in the target ASTContext
+ // (that should implement the callbacks that complete any declarations
+ // on demand). Without an ExternalASTSource, this ASTImporter will just
+ // do a minimal import and the imported declarations won't be completed.
+ assert(target_ctx->getExternalSource() && "Missing ExternalSource");
+ setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal);
+ }
+
+ /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate
+ /// and deattaches it at the end of the scope. Supports being used multiple
+ /// times on the same ASTImporterDelegate instance in nested scopes.
+ class CxxModuleScope {
+ /// The handler we attach to the ASTImporterDelegate.
+ CxxModuleHandler m_handler;
+ /// The ASTImporterDelegate we are supposed to attach the handler to.
+ ASTImporterDelegate &m_delegate;
+ /// True iff we attached the handler to the ASTImporterDelegate.
+ bool m_valid = false;
+
+ public:
+ CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx)
+ : m_delegate(delegate) {
+ // If the delegate doesn't have a CxxModuleHandler yet, create one
+ // and attach it.
+ if (!delegate.m_std_handler) {
+ m_handler = CxxModuleHandler(delegate, dst_ctx);
+ m_valid = true;
+ delegate.m_std_handler = &m_handler;
+ }
+ }
+ ~CxxModuleScope() {
+ if (m_valid) {
+ // Make sure no one messed with the handler we placed.
+ assert(m_delegate.m_std_handler == &m_handler);
+ m_delegate.m_std_handler = nullptr;
+ }
+ }
+ };
+
+ void ImportDefinitionTo(clang::Decl *to, clang::Decl *from);
+
+ void Imported(clang::Decl *from, clang::Decl *to) override;
+
+ clang::Decl *GetOriginalDecl(clang::Decl *To) override;
+
+ void SetImportListener(NewDeclListener *listener) {
+ assert(m_new_decl_listener == nullptr && "Already attached a listener?");
+ m_new_decl_listener = listener;
+ }
+ void RemoveImportListener() { m_new_decl_listener = nullptr; }
+
+ protected:
+ llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override;
+
+ private:
+ /// Decls we should ignore when mapping decls back to their original
+ /// ASTContext. Used by the CxxModuleHandler to mark declarations that
+ /// were created from the 'std' C++ module to prevent that the Importer
+ /// tries to sync them with the broken equivalent in the debug info AST.
+ llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore;
+ ClangASTImporter &m_main;
+ clang::ASTContext *m_source_ctx;
+ CxxModuleHandler *m_std_handler = nullptr;
+ /// The currently attached listener.
+ NewDeclListener *m_new_decl_listener = nullptr;
+ };
+
+ typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP;
+ typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap;
+ typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP>
+ NamespaceMetaMap;
+
+ class ASTContextMetadata {
+ typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap;
+
+ public:
+ ASTContextMetadata(clang::ASTContext *dst_ctx) : m_dst_ctx(dst_ctx) {}
+
+ clang::ASTContext *m_dst_ctx;
+ DelegateMap m_delegates;
+
+ NamespaceMetaMap m_namespace_maps;
+ MapCompleter *m_map_completer = nullptr;
+
+ /// Sets the DeclOrigin for the given Decl and overwrites any existing
+ /// DeclOrigin.
+ void setOrigin(const clang::Decl *decl, DeclOrigin origin) {
+ // Setting the origin of any decl to itself (or to a different decl
+ // in the same ASTContext) doesn't make any sense. It will also cause
+ // ASTImporterDelegate::ImportImpl to infinite recurse when trying to find
+ // the 'original' Decl when importing code.
+ assert(&decl->getASTContext() != origin.ctx &&
+ "Trying to set decl origin to its own ASTContext?");
+ assert(decl != origin.decl && "Trying to set decl origin to itself?");
+ m_origins[decl] = origin;
+ }
+
+ /// Removes any tracked DeclOrigin for the given decl.
+ void removeOrigin(const clang::Decl *decl) { m_origins.erase(decl); }
+
+ /// Remove all DeclOrigin entries that point to the given ASTContext.
+ /// Useful when an ASTContext is about to be deleted and all the dangling
+ /// pointers to it need to be removed.
+ void removeOriginsWithContext(clang::ASTContext *ctx) {
+ for (OriginMap::iterator iter = m_origins.begin();
+ iter != m_origins.end();) {
+ if (iter->second.ctx == ctx)
+ m_origins.erase(iter++);
+ else
+ ++iter;
+ }
+ }
+
+ /// Returns the DeclOrigin for the given Decl or an invalid DeclOrigin
+ /// instance if there no known DeclOrigin for the given Decl.
+ DeclOrigin getOrigin(const clang::Decl *decl) const {
+ auto iter = m_origins.find(decl);
+ if (iter == m_origins.end())
+ return DeclOrigin();
+ return iter->second;
+ }
+
+ /// Returns true there is a known DeclOrigin for the given Decl.
+ bool hasOrigin(const clang::Decl *decl) const {
+ return getOrigin(decl).Valid();
+ }
+
+ private:
+ /// Maps declarations to the ASTContext/Decl from which they were imported
+ /// from. If a declaration is from an ASTContext which has been deleted
+ /// since the declaration was imported or the declaration wasn't created by
+ /// the ASTImporter, then it doesn't have a DeclOrigin and will not be
+ /// tracked here.
+ OriginMap m_origins;
+ };
+
+ typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP;
+ typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP>
+ ContextMetadataMap;
+
+ ContextMetadataMap m_metadata_map;
+
+ ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) {
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter == m_metadata_map.end()) {
+ ASTContextMetadataSP context_md =
+ ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
+ m_metadata_map[dst_ctx] = context_md;
+ return context_md;
+ }
+ return context_md_iter->second;
+ }
+
+ ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) {
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter != m_metadata_map.end())
+ return context_md_iter->second;
+ return ASTContextMetadataSP();
+ }
+
+ ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx) {
+ ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx);
+
+ DelegateMap &delegates = context_md->m_delegates;
+ DelegateMap::iterator delegate_iter = delegates.find(src_ctx);
+
+ if (delegate_iter == delegates.end()) {
+ ImporterDelegateSP delegate =
+ ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx));
+ delegates[src_ctx] = delegate;
+ return delegate;
+ }
+ return delegate_iter->second;
+ }
+
+ DeclOrigin GetDeclOrigin(const clang::Decl *decl);
+
+ clang::FileManager m_file_manager;
+ typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo>
+ RecordDeclToLayoutMap;
+
+ RecordDeclToLayoutMap m_record_decl_to_layout_map;
+};
+
+template <class D> class TaggedASTDecl {
+public:
+ TaggedASTDecl() : decl(nullptr) {}
+ TaggedASTDecl(D *_decl) : decl(_decl) {}
+ bool IsValid() const { return (decl != nullptr); }
+ bool IsInvalid() const { return !IsValid(); }
+ D *operator->() const { return decl; }
+ D *decl;
+};
+
+template <class D2, template <class D> class TD, class D1>
+TD<D2> DynCast(TD<D1> source) {
+ return TD<D2>(llvm::dyn_cast<D2>(source.decl));
+}
+
+template <class D = clang::Decl> class DeclFromParser;
+template <class D = clang::Decl> class DeclFromUser;
+
+template <class D> class DeclFromParser : public TaggedASTDecl<D> {
+public:
+ DeclFromParser() : TaggedASTDecl<D>() {}
+ DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) {}
+
+ DeclFromUser<D> GetOrigin(ClangASTImporter &importer);
+};
+
+template <class D> class DeclFromUser : public TaggedASTDecl<D> {
+public:
+ DeclFromUser() : TaggedASTDecl<D>() {}
+ DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) {}
+
+ DeclFromParser<D> Import(clang::ASTContext *dest_ctx,
+ ClangASTImporter &importer);
+};
+
+template <class D>
+DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTImporter &importer) {
+ ClangASTImporter::DeclOrigin origin = importer.GetDeclOrigin(this->decl);
+ if (!origin.Valid())
+ return DeclFromUser<D>();
+ return DeclFromUser<D>(llvm::dyn_cast<D>(origin.decl));
+}
+
+template <class D>
+DeclFromParser<D> DeclFromUser<D>::Import(clang::ASTContext *dest_ctx,
+ ClangASTImporter &importer) {
+ DeclFromParser<> parser_generic_decl(importer.CopyDecl(dest_ctx, this->decl));
+ if (parser_generic_decl.IsInvalid())
+ return DeclFromParser<D>();
+ return DeclFromParser<D>(llvm::dyn_cast<D>(parser_generic_decl.decl));
+}
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp
new file mode 100644
index 000000000000..42933c78b027
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp
@@ -0,0 +1,35 @@
+//===-- ClangASTMetadata.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb_private;
+
+void ClangASTMetadata::Dump(Stream *s) {
+ lldb::user_id_t uid = GetUserID();
+
+ if (uid != LLDB_INVALID_UID) {
+ s->Printf("uid=0x%" PRIx64, uid);
+ }
+
+ uint64_t isa_ptr = GetISAPtr();
+ if (isa_ptr != 0) {
+ s->Printf("isa_ptr=0x%" PRIx64, isa_ptr);
+ }
+
+ const char *obj_ptr_name = GetObjectPtrName();
+ if (obj_ptr_name) {
+ s->Printf("obj_ptr_name=\"%s\" ", obj_ptr_name);
+ }
+
+ if (m_is_dynamic_cxx) {
+ s->Printf("is_dynamic_cxx=%i ", m_is_dynamic_cxx);
+ }
+ s->EOL();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h
new file mode 100644
index 000000000000..d3bcde2ced79
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h
@@ -0,0 +1,110 @@
+//===-- ClangASTMetadata.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+namespace lldb_private {
+
+class ClangASTMetadata {
+public:
+ ClangASTMetadata()
+ : m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false),
+ m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true),
+ m_is_forcefully_completed(false) {}
+
+ bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; }
+
+ void SetIsDynamicCXXType(bool b) { m_is_dynamic_cxx = b; }
+
+ void SetUserID(lldb::user_id_t user_id) {
+ m_user_id = user_id;
+ m_union_is_user_id = true;
+ m_union_is_isa_ptr = false;
+ }
+
+ lldb::user_id_t GetUserID() const {
+ if (m_union_is_user_id)
+ return m_user_id;
+ else
+ return LLDB_INVALID_UID;
+ }
+
+ void SetISAPtr(uint64_t isa_ptr) {
+ m_isa_ptr = isa_ptr;
+ m_union_is_user_id = false;
+ m_union_is_isa_ptr = true;
+ }
+
+ uint64_t GetISAPtr() const {
+ if (m_union_is_isa_ptr)
+ return m_isa_ptr;
+ else
+ return 0;
+ }
+
+ void SetObjectPtrName(const char *name) {
+ m_has_object_ptr = true;
+ if (strcmp(name, "self") == 0)
+ m_is_self = true;
+ else if (strcmp(name, "this") == 0)
+ m_is_self = false;
+ else
+ m_has_object_ptr = false;
+ }
+
+ lldb::LanguageType GetObjectPtrLanguage() const {
+ if (m_has_object_ptr) {
+ if (m_is_self)
+ return lldb::eLanguageTypeObjC;
+ else
+ return lldb::eLanguageTypeC_plus_plus;
+ }
+ return lldb::eLanguageTypeUnknown;
+ }
+
+ const char *GetObjectPtrName() const {
+ if (m_has_object_ptr) {
+ if (m_is_self)
+ return "self";
+ else
+ return "this";
+ } else
+ return nullptr;
+ }
+
+ bool HasObjectPtr() const { return m_has_object_ptr; }
+
+ /// A type is "forcefully completed" if it was declared complete to satisfy an
+ /// AST invariant (e.g. base classes must be complete types), but in fact we
+ /// were not able to find a actual definition for it.
+ bool IsForcefullyCompleted() const { return m_is_forcefully_completed; }
+
+ void SetIsForcefullyCompleted(bool value = true) {
+ m_is_forcefully_completed = true;
+ }
+
+ void Dump(Stream *s);
+
+private:
+ union {
+ lldb::user_id_t m_user_id;
+ uint64_t m_isa_ptr;
+ };
+
+ bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1,
+ m_is_self : 1, m_is_dynamic_cxx : 1, m_is_forcefully_completed : 1;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
new file mode 100644
index 000000000000..1fdd272dcbec
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -0,0 +1,1501 @@
+//===-- ClangASTSource.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangASTSource.h"
+
+#include "ClangDeclVendor.h"
+#include "ClangModulesDeclVendor.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/SourceManager.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.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:
+ ScopedLexicalDeclEraser(std::set<const clang::Decl *> &decls,
+ const clang::Decl *decl)
+ : m_active_lexical_decls(decls), m_decl(decl) {}
+
+ ~ScopedLexicalDeclEraser() { m_active_lexical_decls.erase(m_decl); }
+
+private:
+ std::set<const clang::Decl *> &m_active_lexical_decls;
+ const clang::Decl *m_decl;
+};
+}
+
+ClangASTSource::ClangASTSource(
+ const lldb::TargetSP &target,
+ const std::shared_ptr<ClangASTImporter> &importer)
+ : m_lookups_enabled(false), m_target(target), m_ast_context(nullptr),
+ m_ast_importer_sp(importer), m_active_lexical_decls(),
+ m_active_lookups() {
+ assert(m_ast_importer_sp && "No ClangASTImporter passed to ClangASTSource?");
+}
+
+void ClangASTSource::InstallASTContext(TypeSystemClang &clang_ast_context) {
+ m_ast_context = &clang_ast_context.getASTContext();
+ m_clang_ast_context = &clang_ast_context;
+ m_file_manager = &m_ast_context->getSourceManager().getFileManager();
+ m_ast_importer_sp->InstallMapCompleter(m_ast_context, *this);
+}
+
+ClangASTSource::~ClangASTSource() {
+ m_ast_importer_sp->ForgetDestination(m_ast_context);
+
+ if (!m_target)
+ return;
+
+ // Unregister the current ASTContext as a source for all scratch
+ // ASTContexts in the ClangASTImporter. Without this the scratch AST might
+ // query the deleted ASTContext for additional type information.
+ // We unregister from *all* scratch ASTContexts in case a type got exported
+ // to a scratch AST that isn't the best fitting scratch ASTContext.
+ lldb::TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(
+ *m_target, ScratchTypeSystemClang::DefaultAST, false);
+
+ if (!scratch_ts_sp)
+ return;
+
+ ScratchTypeSystemClang *default_scratch_ast =
+ llvm::cast<ScratchTypeSystemClang>(scratch_ts_sp.get());
+ // Unregister from the default scratch AST (and all sub-ASTs).
+ default_scratch_ast->ForgetSource(m_ast_context, *m_ast_importer_sp);
+}
+
+void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) {
+ if (!m_ast_context)
+ return;
+
+ m_ast_context->getTranslationUnitDecl()->setHasExternalVisibleStorage();
+ m_ast_context->getTranslationUnitDecl()->setHasExternalLexicalStorage();
+}
+
+// The core lookup interface.
+bool ClangASTSource::FindExternalVisibleDeclsByName(
+ const DeclContext *decl_ctx, DeclarationName clang_decl_name) {
+ if (!m_ast_context) {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+
+ std::string decl_name(clang_decl_name.getAsString());
+
+ switch (clang_decl_name.getNameKind()) {
+ // Normal identifiers.
+ case DeclarationName::Identifier: {
+ clang::IdentifierInfo *identifier_info =
+ clang_decl_name.getAsIdentifierInfo();
+
+ if (!identifier_info || identifier_info->getBuiltinID() != 0) {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+ } break;
+
+ // Operator names.
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXLiteralOperatorName:
+ break;
+
+ // Using directives found in this context.
+ // Tell Sema we didn't find any or we'll end up getting asked a *lot*.
+ case DeclarationName::CXXUsingDirective:
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector: {
+ llvm::SmallVector<NamedDecl *, 1> method_decls;
+
+ NameSearchContext method_search_context(*m_clang_ast_context, method_decls,
+ clang_decl_name, decl_ctx);
+
+ FindObjCMethodDecls(method_search_context);
+
+ SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, method_decls);
+ return (method_decls.size() > 0);
+ }
+ // These aren't possible in the global context.
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ case DeclarationName::CXXDeductionGuideName:
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+
+ if (!GetLookupsEnabled()) {
+ // Wait until we see a '$' at the start of a name before we start doing any
+ // lookups so we can avoid lookup up all of the builtin types.
+ if (!decl_name.empty() && decl_name[0] == '$') {
+ SetLookupsEnabled(true);
+ } else {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+ }
+
+ ConstString const_decl_name(decl_name.c_str());
+
+ const char *uniqued_const_decl_name = const_decl_name.GetCString();
+ if (m_active_lookups.find(uniqued_const_decl_name) !=
+ m_active_lookups.end()) {
+ // We are currently looking up this name...
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+ m_active_lookups.insert(uniqued_const_decl_name);
+ llvm::SmallVector<NamedDecl *, 4> name_decls;
+ NameSearchContext name_search_context(*m_clang_ast_context, name_decls,
+ clang_decl_name, decl_ctx);
+ FindExternalVisibleDecls(name_search_context);
+ SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, name_decls);
+ m_active_lookups.erase(uniqued_const_decl_name);
+ return (name_decls.size() != 0);
+}
+
+TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (const NamespaceDecl *namespace_context =
+ dyn_cast<NamespaceDecl>(decl->getDeclContext())) {
+ ClangASTImporter::NamespaceMapSP namespace_map =
+ m_ast_importer_sp->GetNamespaceMap(namespace_context);
+
+ if (!namespace_map)
+ return nullptr;
+
+ LLDB_LOGV(log, " CTD Inspecting namespace map{0:x} ({1} entries)",
+ namespace_map.get(), namespace_map->size());
+
+ for (const ClangASTImporter::NamespaceMapItem &item : *namespace_map) {
+ LLDB_LOG(log, " CTD Searching namespace {0} in module {1}",
+ item.second.GetName(), item.first->GetFileSpec().GetFilename());
+
+ ConstString name(decl->getName());
+
+ // Create a type matcher using the CompilerDeclContext for the namespace
+ // as the context (item.second) and search for the name inside of this
+ // context.
+ TypeQuery query(item.second, name);
+ TypeResults results;
+ item.first->FindTypes(query, results);
+
+ for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types()) {
+ CompilerType clang_type(type_sp->GetFullCompilerType());
+
+ if (!ClangUtil::IsClangType(clang_type))
+ continue;
+
+ const TagType *tag_type =
+ ClangUtil::GetQualType(clang_type)->getAs<TagType>();
+
+ if (!tag_type)
+ continue;
+
+ TagDecl *candidate_tag_decl =
+ const_cast<TagDecl *>(tag_type->getDecl());
+
+ if (TypeSystemClang::GetCompleteDecl(
+ &candidate_tag_decl->getASTContext(), candidate_tag_decl))
+ return candidate_tag_decl;
+ }
+ }
+ } else {
+ const ModuleList &module_list = m_target->GetImages();
+ // Create a type matcher using a CompilerDecl. Each TypeSystem class knows
+ // how to fill out a CompilerContext array using a CompilerDecl.
+ TypeQuery query(CompilerDecl(m_clang_ast_context, (void *)decl));
+ TypeResults results;
+ module_list.FindTypes(nullptr, query, results);
+ for (const lldb::TypeSP &type_sp : results.GetTypeMap().Types()) {
+
+ CompilerType clang_type(type_sp->GetFullCompilerType());
+
+ if (!ClangUtil::IsClangType(clang_type))
+ continue;
+
+ const TagType *tag_type =
+ ClangUtil::GetQualType(clang_type)->getAs<TagType>();
+
+ if (!tag_type)
+ continue;
+
+ TagDecl *candidate_tag_decl = const_cast<TagDecl *>(tag_type->getDecl());
+
+ if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(),
+ candidate_tag_decl))
+ return candidate_tag_decl;
+ }
+ }
+ return nullptr;
+}
+
+void ClangASTSource::CompleteType(TagDecl *tag_decl) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (log) {
+ LLDB_LOG(log,
+ " CompleteTagDecl on (ASTContext*){0} Completing "
+ "(TagDecl*){1:x} named {2}",
+ m_clang_ast_context->getDisplayName(), tag_decl,
+ tag_decl->getName());
+
+ LLDB_LOG(log, " CTD Before:\n{0}", ClangUtil::DumpDecl(tag_decl));
+ }
+
+ auto iter = m_active_lexical_decls.find(tag_decl);
+ if (iter != m_active_lexical_decls.end())
+ return;
+ m_active_lexical_decls.insert(tag_decl);
+ ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl);
+
+ if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) {
+ // We couldn't complete the type. Maybe there's a definition somewhere
+ // else that can be completed.
+ if (TagDecl *alternate = FindCompleteType(tag_decl))
+ m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, alternate);
+ }
+
+ LLDB_LOG(log, " [CTD] After:\n{0}", ClangUtil::DumpDecl(tag_decl));
+}
+
+void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOG(log,
+ " [CompleteObjCInterfaceDecl] on (ASTContext*){0:x} '{1}' "
+ "Completing an ObjCInterfaceDecl named {1}",
+ m_ast_context, m_clang_ast_context->getDisplayName(),
+ interface_decl->getName());
+ LLDB_LOG(log, " [COID] Before:\n{0}",
+ ClangUtil::DumpDecl(interface_decl));
+
+ ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(interface_decl);
+
+ if (original.Valid()) {
+ if (ObjCInterfaceDecl *original_iface_decl =
+ dyn_cast<ObjCInterfaceDecl>(original.decl)) {
+ ObjCInterfaceDecl *complete_iface_decl =
+ GetCompleteObjCInterface(original_iface_decl);
+
+ if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) {
+ m_ast_importer_sp->SetDeclOrigin(interface_decl, complete_iface_decl);
+ }
+ }
+ }
+
+ m_ast_importer_sp->CompleteObjCInterfaceDecl(interface_decl);
+
+ if (interface_decl->getSuperClass() &&
+ interface_decl->getSuperClass() != interface_decl)
+ CompleteType(interface_decl->getSuperClass());
+
+ LLDB_LOG(log, " [COID] After:");
+ LLDB_LOG(log, " [COID] {0}", ClangUtil::DumpDecl(interface_decl));
+}
+
+clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface(
+ const clang::ObjCInterfaceDecl *interface_decl) {
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ return nullptr;
+
+ ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process));
+
+ if (!language_runtime)
+ return nullptr;
+
+ ConstString class_name(interface_decl->getNameAsString().c_str());
+
+ lldb::TypeSP complete_type_sp(
+ language_runtime->LookupInCompleteClassCache(class_name));
+
+ if (!complete_type_sp)
+ return nullptr;
+
+ TypeFromUser complete_type =
+ TypeFromUser(complete_type_sp->GetFullCompilerType());
+ lldb::opaque_compiler_type_t complete_opaque_type =
+ complete_type.GetOpaqueQualType();
+
+ if (!complete_opaque_type)
+ return nullptr;
+
+ const clang::Type *complete_clang_type =
+ QualType::getFromOpaquePtr(complete_opaque_type).getTypePtr();
+ const ObjCInterfaceType *complete_interface_type =
+ dyn_cast<ObjCInterfaceType>(complete_clang_type);
+
+ if (!complete_interface_type)
+ return nullptr;
+
+ ObjCInterfaceDecl *complete_iface_decl(complete_interface_type->getDecl());
+
+ return complete_iface_decl;
+}
+
+void ClangASTSource::FindExternalLexicalDecls(
+ const DeclContext *decl_context,
+ llvm::function_ref<bool(Decl::Kind)> predicate,
+ llvm::SmallVectorImpl<Decl *> &decls) {
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ const Decl *context_decl = dyn_cast<Decl>(decl_context);
+
+ if (!context_decl)
+ return;
+
+ auto iter = m_active_lexical_decls.find(context_decl);
+ if (iter != m_active_lexical_decls.end())
+ return;
+ m_active_lexical_decls.insert(context_decl);
+ ScopedLexicalDeclEraser eraser(m_active_lexical_decls, context_decl);
+
+ if (log) {
+ if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl))
+ LLDB_LOG(log,
+ "FindExternalLexicalDecls on (ASTContext*){0:x} '{1}' in "
+ "'{2}' ({3}Decl*){4}",
+ m_ast_context, m_clang_ast_context->getDisplayName(),
+ context_named_decl->getNameAsString().c_str(),
+ context_decl->getDeclKindName(),
+ static_cast<const void *>(context_decl));
+ else if (context_decl)
+ LLDB_LOG(log,
+ "FindExternalLexicalDecls on (ASTContext*){0:x} '{1}' in "
+ "({2}Decl*){3}",
+ m_ast_context, m_clang_ast_context->getDisplayName(),
+ context_decl->getDeclKindName(),
+ static_cast<const void *>(context_decl));
+ else
+ LLDB_LOG(log,
+ "FindExternalLexicalDecls on (ASTContext*){0:x} '{1}' in a "
+ "NULL context",
+ m_ast_context, m_clang_ast_context->getDisplayName());
+ }
+
+ ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(context_decl);
+
+ if (!original.Valid())
+ return;
+
+ LLDB_LOG(log, " FELD Original decl (ASTContext*){0:x} (Decl*){1:x}:\n{2}",
+ static_cast<void *>(original.ctx),
+ static_cast<void *>(original.decl),
+ ClangUtil::DumpDecl(original.decl));
+
+ if (ObjCInterfaceDecl *original_iface_decl =
+ dyn_cast<ObjCInterfaceDecl>(original.decl)) {
+ ObjCInterfaceDecl *complete_iface_decl =
+ GetCompleteObjCInterface(original_iface_decl);
+
+ if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) {
+ original.decl = complete_iface_decl;
+ original.ctx = &complete_iface_decl->getASTContext();
+
+ m_ast_importer_sp->SetDeclOrigin(context_decl, complete_iface_decl);
+ }
+ }
+
+ if (TagDecl *original_tag_decl = dyn_cast<TagDecl>(original.decl)) {
+ ExternalASTSource *external_source = original.ctx->getExternalSource();
+
+ if (external_source)
+ external_source->CompleteType(original_tag_decl);
+ }
+
+ const DeclContext *original_decl_context =
+ dyn_cast<DeclContext>(original.decl);
+
+ if (!original_decl_context)
+ return;
+
+ // Indicates whether we skipped any Decls of the original DeclContext.
+ bool SkippedDecls = false;
+ for (Decl *decl : original_decl_context->decls()) {
+ // 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) {
+ std::string ast_dump = ClangUtil::DumpDecl(decl);
+ if (const NamedDecl *context_named_decl =
+ dyn_cast<NamedDecl>(context_decl))
+ LLDB_LOG(log, " FELD Adding [to {0}Decl {1}] lexical {2}Decl {3}",
+ context_named_decl->getDeclKindName(),
+ context_named_decl->getName(), decl->getDeclKindName(),
+ ast_dump);
+ else
+ LLDB_LOG(log, " FELD Adding lexical {0}Decl {1}",
+ decl->getDeclKindName(), ast_dump);
+ }
+
+ Decl *copied_decl = CopyDecl(decl);
+
+ if (!copied_decl)
+ continue;
+
+ // FIXME: We should add the copied decl to the 'decls' list. This would
+ // add the copied Decl into the DeclContext and make sure that we
+ // correctly propagate that we added some Decls back to Clang.
+ // By leaving 'decls' empty we incorrectly return false from
+ // DeclContext::LoadLexicalDeclsFromExternalStorage which might cause
+ // lookup issues later on.
+ // We can't just add them for now as the ASTImporter already added the
+ // decl into the DeclContext and this would add it twice.
+
+ if (FieldDecl *copied_field = dyn_cast<FieldDecl>(copied_decl)) {
+ QualType copied_field_type = copied_field->getType();
+
+ m_ast_importer_sp->RequireCompleteType(copied_field_type);
+ }
+ } 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();
+ }
+}
+
+void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) {
+ assert(m_ast_context);
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (log) {
+ if (!context.m_decl_context)
+ LLDB_LOG(log,
+ "ClangASTSource::FindExternalVisibleDecls on "
+ "(ASTContext*){0:x} '{1}' for '{2}' in a NULL DeclContext",
+ m_ast_context, m_clang_ast_context->getDisplayName(), name);
+ else if (const NamedDecl *context_named_decl =
+ dyn_cast<NamedDecl>(context.m_decl_context))
+ LLDB_LOG(log,
+ "ClangASTSource::FindExternalVisibleDecls on "
+ "(ASTContext*){0:x} '{1}' for '{2}' in '{3}'",
+ m_ast_context, m_clang_ast_context->getDisplayName(), name,
+ context_named_decl->getName());
+ else
+ LLDB_LOG(log,
+ "ClangASTSource::FindExternalVisibleDecls on "
+ "(ASTContext*){0:x} '{1}' for '{2}' in a '{3}'",
+ m_ast_context, m_clang_ast_context->getDisplayName(), name,
+ context.m_decl_context->getDeclKindName());
+ }
+
+ if (isa<NamespaceDecl>(context.m_decl_context)) {
+ LookupInNamespace(context);
+ } else if (isa<ObjCInterfaceDecl>(context.m_decl_context)) {
+ FindObjCPropertyAndIvarDecls(context);
+ } else if (!isa<TranslationUnitDecl>(context.m_decl_context)) {
+ // we shouldn't be getting FindExternalVisibleDecls calls for these
+ return;
+ } else {
+ CompilerDeclContext namespace_decl;
+
+ LLDB_LOG(log, " CAS::FEVD Searching the root namespace");
+
+ FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl);
+ }
+
+ if (!context.m_namespace_map->empty()) {
+ if (log && log->GetVerbose())
+ LLDB_LOG(log, " CAS::FEVD Registering namespace map {0:x} ({1} entries)",
+ context.m_namespace_map.get(), context.m_namespace_map->size());
+
+ NamespaceDecl *clang_namespace_decl =
+ AddNamespace(context, context.m_namespace_map);
+
+ if (clang_namespace_decl)
+ clang_namespace_decl->setHasExternalVisibleStorage();
+ }
+}
+
+clang::Sema *ClangASTSource::getSema() {
+ return m_clang_ast_context->getSema();
+}
+
+bool ClangASTSource::IgnoreName(const ConstString name,
+ bool ignore_all_dollar_names) {
+ static const ConstString id_name("id");
+ static const ConstString Class_name("Class");
+
+ if (m_ast_context->getLangOpts().ObjC)
+ if (name == id_name || name == Class_name)
+ return true;
+
+ StringRef name_string_ref = name.GetStringRef();
+
+ // The ClangASTSource is not responsible for finding $-names.
+ return name_string_ref.empty() ||
+ (ignore_all_dollar_names && name_string_ref.starts_with("$")) ||
+ name_string_ref.starts_with("_$");
+}
+
+void ClangASTSource::FindExternalVisibleDecls(
+ NameSearchContext &context, lldb::ModuleSP module_sp,
+ CompilerDeclContext &namespace_decl) {
+ assert(m_ast_context);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ SymbolContextList sc_list;
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+ if (IgnoreName(name, true))
+ return;
+
+ if (!m_target)
+ return;
+
+ FillNamespaceMap(context, module_sp, namespace_decl);
+
+ if (context.m_found_type)
+ return;
+
+ lldb::TypeSP type_sp;
+ TypeResults results;
+ if (module_sp && namespace_decl) {
+ // Match the name in the specified decl context.
+ TypeQuery query(namespace_decl, name, TypeQueryOptions::e_find_one);
+ module_sp->FindTypes(query, results);
+ type_sp = results.GetFirstType();
+ } else {
+ // Match the exact name of the type at the root level.
+ TypeQuery query(name.GetStringRef(), TypeQueryOptions::e_exact_match |
+ TypeQueryOptions::e_find_one);
+ m_target->GetImages().FindTypes(nullptr, query, results);
+ type_sp = results.GetFirstType();
+ }
+
+ if (type_sp) {
+ if (log) {
+ const char *name_string = type_sp->GetName().GetCString();
+
+ LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name,
+ (name_string ? name_string : "<anonymous>"));
+ }
+
+ CompilerType full_type = type_sp->GetFullCompilerType();
+
+ CompilerType copied_clang_type(GuardedCopyType(full_type));
+
+ if (!copied_clang_type) {
+ LLDB_LOG(log, " CAS::FEVD - Couldn't export a type");
+ } else {
+
+ context.AddTypeDecl(copied_clang_type);
+
+ context.m_found_type = true;
+ }
+ }
+
+ if (!context.m_found_type) {
+ // Try the modules next.
+ FindDeclInModules(context, name);
+ }
+
+ if (!context.m_found_type && m_ast_context->getLangOpts().ObjC) {
+ FindDeclInObjCRuntime(context, name);
+ }
+}
+
+void ClangASTSource::FillNamespaceMap(
+ NameSearchContext &context, lldb::ModuleSP module_sp,
+ const CompilerDeclContext &namespace_decl) {
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+ if (IgnoreName(name, true))
+ return;
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (module_sp && namespace_decl) {
+ CompilerDeclContext found_namespace_decl;
+
+ if (SymbolFile *symbol_file = module_sp->GetSymbolFile()) {
+ found_namespace_decl = symbol_file->FindNamespace(name, namespace_decl);
+
+ if (found_namespace_decl) {
+ context.m_namespace_map->push_back(
+ std::pair<lldb::ModuleSP, CompilerDeclContext>(
+ module_sp, found_namespace_decl));
+
+ LLDB_LOG(log, " CAS::FEVD Found namespace {0} in module {1}", name,
+ module_sp->GetFileSpec().GetFilename());
+ }
+ }
+ return;
+ }
+
+ for (lldb::ModuleSP image : m_target->GetImages().Modules()) {
+ if (!image)
+ continue;
+
+ CompilerDeclContext found_namespace_decl;
+
+ SymbolFile *symbol_file = image->GetSymbolFile();
+
+ if (!symbol_file)
+ continue;
+
+ // If namespace_decl is not valid, 'FindNamespace' would look for
+ // any namespace called 'name' (ignoring parent contexts) and return
+ // the first one it finds. Thus if we're doing a qualified lookup only
+ // consider root namespaces. E.g., in an expression ::A::B::Foo, the
+ // lookup of ::A will result in a qualified lookup. Note, namespace
+ // disambiguation for function calls are handled separately in
+ // SearchFunctionsInSymbolContexts.
+ const bool find_root_namespaces =
+ context.m_decl_context &&
+ context.m_decl_context->shouldUseQualifiedLookup();
+ found_namespace_decl = symbol_file->FindNamespace(
+ name, namespace_decl, /* only root namespaces */ find_root_namespaces);
+
+ if (found_namespace_decl) {
+ context.m_namespace_map->push_back(
+ std::pair<lldb::ModuleSP, CompilerDeclContext>(image,
+ found_namespace_decl));
+
+ LLDB_LOG(log, " CAS::FEVD Found namespace {0} in module {1}", name,
+ image->GetFileSpec().GetFilename());
+ }
+ }
+}
+
+bool ClangASTSource::FindObjCMethodDeclsWithOrigin(
+ NameSearchContext &context, ObjCInterfaceDecl *original_interface_decl,
+ const char *log_info) {
+ const DeclarationName &decl_name(context.m_decl_name);
+ clang::ASTContext *original_ctx = &original_interface_decl->getASTContext();
+
+ Selector original_selector;
+
+ if (decl_name.isObjCZeroArgSelector()) {
+ const IdentifierInfo *ident =
+ &original_ctx->Idents.get(decl_name.getAsString());
+ original_selector = original_ctx->Selectors.getSelector(0, &ident);
+ } else if (decl_name.isObjCOneArgSelector()) {
+ const std::string &decl_name_string = decl_name.getAsString();
+ std::string decl_name_string_without_colon(decl_name_string.c_str(),
+ decl_name_string.length() - 1);
+ const IdentifierInfo *ident =
+ &original_ctx->Idents.get(decl_name_string_without_colon);
+ original_selector = original_ctx->Selectors.getSelector(1, &ident);
+ } else {
+ SmallVector<const IdentifierInfo *, 4> idents;
+
+ clang::Selector sel = decl_name.getObjCSelector();
+
+ unsigned num_args = sel.getNumArgs();
+
+ for (unsigned i = 0; i != num_args; ++i) {
+ idents.push_back(&original_ctx->Idents.get(sel.getNameForSlot(i)));
+ }
+
+ original_selector =
+ original_ctx->Selectors.getSelector(num_args, idents.data());
+ }
+
+ DeclarationName original_decl_name(original_selector);
+
+ llvm::SmallVector<NamedDecl *, 1> methods;
+
+ TypeSystemClang::GetCompleteDecl(original_ctx, original_interface_decl);
+
+ if (ObjCMethodDecl *instance_method_decl =
+ original_interface_decl->lookupInstanceMethod(original_selector)) {
+ methods.push_back(instance_method_decl);
+ } else if (ObjCMethodDecl *class_method_decl =
+ original_interface_decl->lookupClassMethod(
+ original_selector)) {
+ methods.push_back(class_method_decl);
+ }
+
+ if (methods.empty()) {
+ return false;
+ }
+
+ for (NamedDecl *named_decl : methods) {
+ if (!named_decl)
+ continue;
+
+ ObjCMethodDecl *result_method = dyn_cast<ObjCMethodDecl>(named_decl);
+
+ if (!result_method)
+ continue;
+
+ Decl *copied_decl = CopyDecl(result_method);
+
+ if (!copied_decl)
+ continue;
+
+ ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
+
+ if (!copied_method_decl)
+ continue;
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOG(log, " CAS::FOMD found ({0}) {1}", log_info,
+ ClangUtil::DumpDecl(copied_method_decl));
+
+ context.AddNamedDecl(copied_method_decl);
+ }
+
+ return true;
+}
+
+void ClangASTSource::FindDeclInModules(NameSearchContext &context,
+ ConstString name) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ std::shared_ptr<ClangModulesDeclVendor> modules_decl_vendor =
+ GetClangModulesDeclVendor();
+ if (!modules_decl_vendor)
+ return;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector<clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls))
+ return;
+
+ LLDB_LOG(log, " CAS::FEVD Matching entity found for \"{0}\" in the modules",
+ name);
+
+ clang::NamedDecl *const decl_from_modules = decls[0];
+
+ if (llvm::isa<clang::TypeDecl>(decl_from_modules) ||
+ llvm::isa<clang::ObjCContainerDecl>(decl_from_modules) ||
+ llvm::isa<clang::EnumConstantDecl>(decl_from_modules)) {
+ clang::Decl *copied_decl = CopyDecl(decl_from_modules);
+ clang::NamedDecl *copied_named_decl =
+ copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr;
+
+ if (!copied_named_decl) {
+ LLDB_LOG(log, " CAS::FEVD - Couldn't export a type from the modules");
+
+ return;
+ }
+
+ context.AddNamedDecl(copied_named_decl);
+
+ context.m_found_type = true;
+ }
+}
+
+void ClangASTSource::FindDeclInObjCRuntime(NameSearchContext &context,
+ ConstString name) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ return;
+
+ ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process));
+
+ if (!language_runtime)
+ return;
+
+ DeclVendor *decl_vendor = language_runtime->GetDeclVendor();
+
+ if (!decl_vendor)
+ return;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector<clang::NamedDecl *> decls;
+
+ auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor);
+ if (!clang_decl_vendor->FindDecls(name, append, max_matches, decls))
+ return;
+
+ LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\" in the runtime",
+ name);
+
+ clang::Decl *copied_decl = CopyDecl(decls[0]);
+ clang::NamedDecl *copied_named_decl =
+ copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr;
+
+ if (!copied_named_decl) {
+ LLDB_LOG(log, " CAS::FEVD - Couldn't export a type from the runtime");
+
+ return;
+ }
+
+ context.AddNamedDecl(copied_named_decl);
+}
+
+void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ const DeclarationName &decl_name(context.m_decl_name);
+ const DeclContext *decl_ctx(context.m_decl_context);
+
+ const ObjCInterfaceDecl *interface_decl =
+ dyn_cast<ObjCInterfaceDecl>(decl_ctx);
+
+ if (!interface_decl)
+ return;
+
+ do {
+ ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(interface_decl);
+
+ if (!original.Valid())
+ break;
+
+ ObjCInterfaceDecl *original_interface_decl =
+ dyn_cast<ObjCInterfaceDecl>(original.decl);
+
+ if (FindObjCMethodDeclsWithOrigin(context, original_interface_decl,
+ "at origin"))
+ return; // found it, no need to look any further
+ } while (false);
+
+ StreamString ss;
+
+ if (decl_name.isObjCZeroArgSelector()) {
+ ss.Printf("%s", decl_name.getAsString().c_str());
+ } else if (decl_name.isObjCOneArgSelector()) {
+ ss.Printf("%s", decl_name.getAsString().c_str());
+ } else {
+ clang::Selector sel = decl_name.getObjCSelector();
+
+ for (unsigned i = 0, e = sel.getNumArgs(); i != e; ++i) {
+ llvm::StringRef r = sel.getNameForSlot(i);
+ ss.Printf("%s:", r.str().c_str());
+ }
+ }
+ ss.Flush();
+
+ if (ss.GetString().contains("$__lldb"))
+ return; // we don't need any results
+
+ ConstString selector_name(ss.GetString());
+
+ LLDB_LOG(log,
+ "ClangASTSource::FindObjCMethodDecls on (ASTContext*){0:x} '{1}' "
+ "for selector [{2} {3}]",
+ m_ast_context, m_clang_ast_context->getDisplayName(),
+ interface_decl->getName(), selector_name);
+ SymbolContextList sc_list;
+
+ ModuleFunctionSearchOptions function_options;
+ function_options.include_symbols = false;
+ function_options.include_inlines = false;
+
+ std::string interface_name = interface_decl->getNameAsString();
+
+ do {
+ StreamString ms;
+ ms.Printf("-[%s %s]", interface_name.c_str(), selector_name.AsCString());
+ ms.Flush();
+ ConstString instance_method_name(ms.GetString());
+
+ sc_list.Clear();
+ m_target->GetImages().FindFunctions(instance_method_name,
+ lldb::eFunctionNameTypeFull,
+ function_options, sc_list);
+
+ if (sc_list.GetSize())
+ break;
+
+ ms.Clear();
+ ms.Printf("+[%s %s]", interface_name.c_str(), selector_name.AsCString());
+ ms.Flush();
+ ConstString class_method_name(ms.GetString());
+
+ sc_list.Clear();
+ m_target->GetImages().FindFunctions(class_method_name,
+ lldb::eFunctionNameTypeFull,
+ function_options, sc_list);
+
+ if (sc_list.GetSize())
+ break;
+
+ // Fall back and check for methods in categories. If we find methods this
+ // way, we need to check that they're actually in categories on the desired
+ // class.
+
+ SymbolContextList candidate_sc_list;
+
+ m_target->GetImages().FindFunctions(selector_name,
+ lldb::eFunctionNameTypeSelector,
+ function_options, candidate_sc_list);
+
+ for (const SymbolContext &candidate_sc : candidate_sc_list) {
+ if (!candidate_sc.function)
+ continue;
+
+ const char *candidate_name = candidate_sc.function->GetName().AsCString();
+
+ const char *cursor = candidate_name;
+
+ if (*cursor != '+' && *cursor != '-')
+ continue;
+
+ ++cursor;
+
+ if (*cursor != '[')
+ continue;
+
+ ++cursor;
+
+ size_t interface_len = interface_name.length();
+
+ if (strncmp(cursor, interface_name.c_str(), interface_len))
+ continue;
+
+ cursor += interface_len;
+
+ if (*cursor == ' ' || *cursor == '(')
+ sc_list.Append(candidate_sc);
+ }
+ } while (false);
+
+ if (sc_list.GetSize()) {
+ // We found a good function symbol. Use that.
+
+ for (const SymbolContext &sc : sc_list) {
+ if (!sc.function)
+ continue;
+
+ CompilerDeclContext function_decl_ctx = sc.function->GetDeclContext();
+ if (!function_decl_ctx)
+ continue;
+
+ ObjCMethodDecl *method_decl =
+ TypeSystemClang::DeclContextGetAsObjCMethodDecl(function_decl_ctx);
+
+ if (!method_decl)
+ continue;
+
+ ObjCInterfaceDecl *found_interface_decl =
+ method_decl->getClassInterface();
+
+ if (!found_interface_decl)
+ continue;
+
+ if (found_interface_decl->getName() == interface_decl->getName()) {
+ Decl *copied_decl = CopyDecl(method_decl);
+
+ if (!copied_decl)
+ continue;
+
+ ObjCMethodDecl *copied_method_decl =
+ dyn_cast<ObjCMethodDecl>(copied_decl);
+
+ if (!copied_method_decl)
+ continue;
+
+ LLDB_LOG(log, " CAS::FOMD found (in symbols)\n{0}",
+ ClangUtil::DumpDecl(copied_method_decl));
+
+ context.AddNamedDecl(copied_method_decl);
+ }
+ }
+
+ return;
+ }
+
+ // Try the debug information.
+
+ do {
+ ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(
+ const_cast<ObjCInterfaceDecl *>(interface_decl));
+
+ if (!complete_interface_decl)
+ break;
+
+ // We found the complete interface. The runtime never needs to be queried
+ // in this scenario.
+
+ DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(
+ complete_interface_decl);
+
+ if (complete_interface_decl == interface_decl)
+ break; // already checked this one
+
+ LLDB_LOG(log,
+ "CAS::FOPD trying origin "
+ "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}...",
+ complete_interface_decl, &complete_iface_decl->getASTContext());
+
+ FindObjCMethodDeclsWithOrigin(context, complete_interface_decl,
+ "in debug info");
+
+ return;
+ } while (false);
+
+ do {
+ // Check the modules only if the debug information didn't have a complete
+ // interface.
+
+ if (std::shared_ptr<ClangModulesDeclVendor> modules_decl_vendor =
+ GetClangModulesDeclVendor()) {
+ ConstString interface_name(interface_decl->getNameAsString().c_str());
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector<clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(interface_name, append, max_matches,
+ decls))
+ break;
+
+ ObjCInterfaceDecl *interface_decl_from_modules =
+ dyn_cast<ObjCInterfaceDecl>(decls[0]);
+
+ if (!interface_decl_from_modules)
+ break;
+
+ if (FindObjCMethodDeclsWithOrigin(context, interface_decl_from_modules,
+ "in modules"))
+ return;
+ }
+ } while (false);
+
+ do {
+ // Check the runtime only if the debug information didn't have a complete
+ // interface and the modules don't get us anywhere.
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ break;
+
+ ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process));
+
+ if (!language_runtime)
+ break;
+
+ DeclVendor *decl_vendor = language_runtime->GetDeclVendor();
+
+ if (!decl_vendor)
+ break;
+
+ ConstString interface_name(interface_decl->getNameAsString().c_str());
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector<clang::NamedDecl *> decls;
+
+ auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor);
+ if (!clang_decl_vendor->FindDecls(interface_name, append, max_matches,
+ decls))
+ break;
+
+ ObjCInterfaceDecl *runtime_interface_decl =
+ dyn_cast<ObjCInterfaceDecl>(decls[0]);
+
+ if (!runtime_interface_decl)
+ break;
+
+ FindObjCMethodDeclsWithOrigin(context, runtime_interface_decl,
+ "in runtime");
+ } while (false);
+}
+
+bool ClangASTSource::FindObjCPropertyAndIvarDeclsWithOrigin(
+ NameSearchContext &context,
+ DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (origin_iface_decl.IsInvalid())
+ return false;
+
+ std::string name_str = context.m_decl_name.getAsString();
+ StringRef name(name_str);
+ IdentifierInfo &name_identifier(
+ origin_iface_decl->getASTContext().Idents.get(name));
+
+ DeclFromUser<ObjCPropertyDecl> origin_property_decl(
+ origin_iface_decl->FindPropertyDeclaration(
+ &name_identifier, ObjCPropertyQueryKind::OBJC_PR_query_instance));
+
+ bool found = false;
+
+ if (origin_property_decl.IsValid()) {
+ DeclFromParser<ObjCPropertyDecl> parser_property_decl(
+ origin_property_decl.Import(m_ast_context, *m_ast_importer_sp));
+ if (parser_property_decl.IsValid()) {
+ LLDB_LOG(log, " CAS::FOPD found\n{0}",
+ ClangUtil::DumpDecl(parser_property_decl.decl));
+
+ context.AddNamedDecl(parser_property_decl.decl);
+ found = true;
+ }
+ }
+
+ DeclFromUser<ObjCIvarDecl> origin_ivar_decl(
+ origin_iface_decl->getIvarDecl(&name_identifier));
+
+ if (origin_ivar_decl.IsValid()) {
+ DeclFromParser<ObjCIvarDecl> parser_ivar_decl(
+ origin_ivar_decl.Import(m_ast_context, *m_ast_importer_sp));
+ if (parser_ivar_decl.IsValid()) {
+ LLDB_LOG(log, " CAS::FOPD found\n{0}",
+ ClangUtil::DumpDecl(parser_ivar_decl.decl));
+
+ context.AddNamedDecl(parser_ivar_decl.decl);
+ found = true;
+ }
+ }
+
+ return found;
+}
+
+void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl(
+ cast<ObjCInterfaceDecl>(context.m_decl_context));
+ DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl(
+ parser_iface_decl.GetOrigin(*m_ast_importer_sp));
+
+ ConstString class_name(parser_iface_decl->getNameAsString().c_str());
+
+ LLDB_LOG(log,
+ "ClangASTSource::FindObjCPropertyAndIvarDecls on "
+ "(ASTContext*){0:x} '{1}' for '{2}.{3}'",
+ m_ast_context, m_clang_ast_context->getDisplayName(),
+ parser_iface_decl->getName(), context.m_decl_name.getAsString());
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(context, origin_iface_decl))
+ return;
+
+ LLDB_LOG(log,
+ "CAS::FOPD couldn't find the property on origin "
+ "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}, searching "
+ "elsewhere...",
+ origin_iface_decl.decl, &origin_iface_decl->getASTContext());
+
+ SymbolContext null_sc;
+ TypeList type_list;
+
+ do {
+ ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(
+ const_cast<ObjCInterfaceDecl *>(parser_iface_decl.decl));
+
+ if (!complete_interface_decl)
+ break;
+
+ // We found the complete interface. The runtime never needs to be queried
+ // in this scenario.
+
+ DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(
+ complete_interface_decl);
+
+ if (complete_iface_decl.decl == origin_iface_decl.decl)
+ break; // already checked this one
+
+ LLDB_LOG(log,
+ "CAS::FOPD trying origin "
+ "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}...",
+ complete_iface_decl.decl, &complete_iface_decl->getASTContext());
+
+ FindObjCPropertyAndIvarDeclsWithOrigin(context, complete_iface_decl);
+
+ return;
+ } while (false);
+
+ do {
+ // Check the modules only if the debug information didn't have a complete
+ // interface.
+
+ std::shared_ptr<ClangModulesDeclVendor> modules_decl_vendor =
+ GetClangModulesDeclVendor();
+
+ if (!modules_decl_vendor)
+ break;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector<clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(class_name, append, max_matches, decls))
+ break;
+
+ DeclFromUser<const ObjCInterfaceDecl> interface_decl_from_modules(
+ dyn_cast<ObjCInterfaceDecl>(decls[0]));
+
+ if (!interface_decl_from_modules.IsValid())
+ break;
+
+ LLDB_LOG(log,
+ "CAS::FOPD[{0:x}] trying module "
+ "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}...",
+ interface_decl_from_modules.decl,
+ &interface_decl_from_modules->getASTContext());
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(context,
+ interface_decl_from_modules))
+ return;
+ } while (false);
+
+ do {
+ // Check the runtime only if the debug information didn't have a complete
+ // interface and nothing was in the modules.
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ return;
+
+ ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process));
+
+ if (!language_runtime)
+ return;
+
+ DeclVendor *decl_vendor = language_runtime->GetDeclVendor();
+
+ if (!decl_vendor)
+ break;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector<clang::NamedDecl *> decls;
+
+ auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor);
+ if (!clang_decl_vendor->FindDecls(class_name, append, max_matches, decls))
+ break;
+
+ DeclFromUser<const ObjCInterfaceDecl> interface_decl_from_runtime(
+ dyn_cast<ObjCInterfaceDecl>(decls[0]));
+
+ if (!interface_decl_from_runtime.IsValid())
+ break;
+
+ LLDB_LOG(log,
+ "CAS::FOPD[{0:x}] trying runtime "
+ "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}...",
+ interface_decl_from_runtime.decl,
+ &interface_decl_from_runtime->getASTContext());
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(context,
+ interface_decl_from_runtime))
+ return;
+ } while (false);
+}
+
+void ClangASTSource::LookupInNamespace(NameSearchContext &context) {
+ const NamespaceDecl *namespace_context =
+ dyn_cast<NamespaceDecl>(context.m_decl_context);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ ClangASTImporter::NamespaceMapSP namespace_map =
+ m_ast_importer_sp->GetNamespaceMap(namespace_context);
+
+ LLDB_LOGV(log, " CAS::FEVD Inspecting namespace map {0:x} ({1} entries)",
+ namespace_map.get(), namespace_map->size());
+
+ if (!namespace_map)
+ return;
+
+ for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(),
+ e = namespace_map->end();
+ i != e; ++i) {
+ LLDB_LOG(log, " CAS::FEVD Searching namespace {0} in module {1}",
+ i->second.GetName(), i->first->GetFileSpec().GetFilename());
+
+ FindExternalVisibleDecls(context, i->first, i->second);
+ }
+}
+
+bool ClangASTSource::layoutRecordType(
+ const RecordDecl *record, uint64_t &size, uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &virtual_base_offsets) {
+ return m_ast_importer_sp->importRecordLayoutFromOrigin(
+ record, size, alignment, field_offsets, base_offsets,
+ virtual_base_offsets);
+}
+
+void ClangASTSource::CompleteNamespaceMap(
+ ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name,
+ ClangASTImporter::NamespaceMapSP &parent_map) const {
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (log) {
+ if (parent_map && parent_map->size())
+ LLDB_LOG(log,
+ "CompleteNamespaceMap on (ASTContext*){0:x} '{1}' Searching "
+ "for namespace {2} in namespace {3}",
+ m_ast_context, m_clang_ast_context->getDisplayName(), name,
+ parent_map->begin()->second.GetName());
+ else
+ LLDB_LOG(log,
+ "CompleteNamespaceMap on (ASTContext*){0} '{1}' Searching "
+ "for namespace {2}",
+ m_ast_context, m_clang_ast_context->getDisplayName(), name);
+ }
+
+ if (parent_map) {
+ for (ClangASTImporter::NamespaceMap::iterator i = parent_map->begin(),
+ e = parent_map->end();
+ i != e; ++i) {
+ CompilerDeclContext found_namespace_decl;
+
+ lldb::ModuleSP module_sp = i->first;
+ CompilerDeclContext module_parent_namespace_decl = i->second;
+
+ SymbolFile *symbol_file = module_sp->GetSymbolFile();
+
+ if (!symbol_file)
+ continue;
+
+ found_namespace_decl =
+ symbol_file->FindNamespace(name, module_parent_namespace_decl);
+
+ if (!found_namespace_decl)
+ continue;
+
+ namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>(
+ module_sp, found_namespace_decl));
+
+ LLDB_LOG(log, " CMN Found namespace {0} in module {1}", name,
+ module_sp->GetFileSpec().GetFilename());
+ }
+ } else {
+ CompilerDeclContext null_namespace_decl;
+ for (lldb::ModuleSP image : m_target->GetImages().Modules()) {
+ if (!image)
+ continue;
+
+ CompilerDeclContext found_namespace_decl;
+
+ SymbolFile *symbol_file = image->GetSymbolFile();
+
+ if (!symbol_file)
+ continue;
+
+ found_namespace_decl =
+ symbol_file->FindNamespace(name, null_namespace_decl);
+
+ if (!found_namespace_decl)
+ continue;
+
+ namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>(
+ image, found_namespace_decl));
+
+ LLDB_LOG(log, " CMN[{0}] Found namespace {0} in module {1}", name,
+ image->GetFileSpec().GetFilename());
+ }
+ }
+}
+
+NamespaceDecl *ClangASTSource::AddNamespace(
+ NameSearchContext &context,
+ ClangASTImporter::NamespaceMapSP &namespace_decls) {
+ if (!namespace_decls)
+ return nullptr;
+
+ const CompilerDeclContext &namespace_decl = namespace_decls->begin()->second;
+
+ clang::ASTContext *src_ast =
+ TypeSystemClang::DeclContextGetTypeSystemClang(namespace_decl);
+ if (!src_ast)
+ return nullptr;
+ clang::NamespaceDecl *src_namespace_decl =
+ TypeSystemClang::DeclContextGetAsNamespaceDecl(namespace_decl);
+
+ if (!src_namespace_decl)
+ return nullptr;
+
+ Decl *copied_decl = CopyDecl(src_namespace_decl);
+
+ if (!copied_decl)
+ return nullptr;
+
+ NamespaceDecl *copied_namespace_decl = dyn_cast<NamespaceDecl>(copied_decl);
+
+ if (!copied_namespace_decl)
+ return nullptr;
+
+ context.m_decls.push_back(copied_namespace_decl);
+
+ m_ast_importer_sp->RegisterNamespaceMap(copied_namespace_decl,
+ namespace_decls);
+
+ return dyn_cast<NamespaceDecl>(copied_decl);
+}
+
+clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) {
+ return m_ast_importer_sp->CopyDecl(m_ast_context, src_decl);
+}
+
+ClangASTImporter::DeclOrigin ClangASTSource::GetDeclOrigin(const clang::Decl *decl) {
+ return m_ast_importer_sp->GetDeclOrigin(decl);
+}
+
+CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) {
+ auto ts = src_type.GetTypeSystem();
+ auto src_ast = ts.dyn_cast_or_null<TypeSystemClang>();
+ if (!src_ast)
+ return {};
+
+ QualType copied_qual_type = ClangUtil::GetQualType(
+ m_ast_importer_sp->CopyType(*m_clang_ast_context, src_type));
+
+ if (copied_qual_type.getAsOpaquePtr() &&
+ copied_qual_type->getCanonicalTypeInternal().isNull())
+ // this shouldn't happen, but we're hardening because the AST importer
+ // seems to be generating bad types on occasion.
+ return {};
+
+ return m_clang_ast_context->GetType(copied_qual_type);
+}
+
+std::shared_ptr<ClangModulesDeclVendor>
+ClangASTSource::GetClangModulesDeclVendor() {
+ auto persistent_vars = llvm::cast<ClangPersistentVariables>(
+ m_target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
+ return persistent_vars->GetClangModulesDeclVendor();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
new file mode 100644
index 000000000000..83c910477acc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
@@ -0,0 +1,399 @@
+//===-- ClangASTSource.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H
+
+#include <set>
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/NameSearchContext.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Target/Target.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/Basic/IdentifierTable.h"
+
+#include "llvm/ADT/SmallSet.h"
+
+namespace lldb_private {
+
+/// \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
+/// inside the expression, including variables, functions, and types. Clang
+/// 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 clang::ExternalASTSource,
+ public ClangASTImporter::MapCompleter {
+public:
+ /// Constructor
+ ///
+ /// Initializes class variables.
+ ///
+ /// \param[in] target
+ /// A reference to the target containing debug information to use.
+ ///
+ /// \param[in] importer
+ /// The ClangASTImporter to use.
+ ClangASTSource(const lldb::TargetSP &target,
+ const std::shared_ptr<ClangASTImporter> &importer);
+
+ /// Destructor
+ ~ClangASTSource() override;
+
+ /// Interface stubs.
+ clang::Decl *GetExternalDecl(clang::GlobalDeclID) 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 nullptr;
+ }
+ void MaterializeVisibleDecls(const clang::DeclContext *DC) {}
+
+ void InstallASTContext(TypeSystemClang &ast_context);
+
+ //
+ // 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
+ /// result.
+ ///
+ /// The work for this function is done by
+ /// void FindExternalVisibleDecls (NameSearchContext &);
+ ///
+ /// \param[in] DC
+ /// The DeclContext to register the found Decls in.
+ ///
+ /// \param[in] Name
+ /// The name to find entries for.
+ ///
+ /// \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
+ /// The DeclContext being searched.
+ ///
+ /// \param[in] IsKindWeWant
+ /// A callback function that returns true given the
+ /// DeclKinds of desired Decls, and false otherwise.
+ ///
+ /// \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
+ /// The record (in the parser's AST context) that needs to be
+ /// laid out.
+ ///
+ /// \param[out] Size
+ /// The total size of the record in bits.
+ ///
+ /// \param[out] Alignment
+ /// The alignment of the record in bits.
+ ///
+ /// \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
+ /// 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
+ /// 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
+ /// 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,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &VirtualBaseOffsets) override;
+
+ /// Complete a TagDecl.
+ ///
+ /// \param[in] Tag
+ /// The Decl to be completed in place.
+ void CompleteType(clang::TagDecl *Tag) override;
+
+ /// Complete an ObjCInterfaceDecl.
+ ///
+ /// \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] Consumer
+ /// 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
+ /// The map to be completed.
+ ///
+ /// \param[in] name
+ /// The name of the namespace to be found.
+ ///
+ /// \param[in] parent_map
+ /// The map for the namespace's parent namespace, if there is
+ /// one.
+ void CompleteNamespaceMap(
+ ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name,
+ ClangASTImporter::NamespaceMapSP &parent_map) const override;
+
+ //
+ // Helper APIs
+ //
+
+ clang::NamespaceDecl *
+ AddNamespace(NameSearchContext &context,
+ ClangASTImporter::NamespaceMapSP &namespace_decls);
+
+ /// The worker function for FindExternalVisibleDeclsByName.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext to use when filing results.
+ virtual void FindExternalVisibleDecls(NameSearchContext &context);
+
+ clang::Sema *getSema();
+
+ void SetLookupsEnabled(bool lookups_enabled) {
+ m_lookups_enabled = lookups_enabled;
+ }
+ bool GetLookupsEnabled() { return m_lookups_enabled; }
+
+ /// \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 clang::ExternalASTSource {
+ public:
+ ClangASTSourceProxy(ClangASTSource &original) : m_original(original) {}
+
+ bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+ clang::DeclarationName Name) override {
+ return m_original.FindExternalVisibleDeclsByName(DC, Name);
+ }
+
+ void FindExternalLexicalDecls(
+ const clang::DeclContext *DC,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
+ return m_original.FindExternalLexicalDecls(DC, IsKindWeWant, Decls);
+ }
+
+ void CompleteType(clang::TagDecl *Tag) override {
+ return m_original.CompleteType(Tag);
+ }
+
+ void CompleteType(clang::ObjCInterfaceDecl *Class) override {
+ return m_original.CompleteType(Class);
+ }
+
+ 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_original.layoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets);
+ }
+
+ void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
+ return m_original.StartTranslationUnit(Consumer);
+ }
+
+ private:
+ ClangASTSource &m_original;
+ };
+
+ clang::ExternalASTSource *CreateProxy() {
+ return new ClangASTSourceProxy(*this);
+ }
+
+protected:
+ /// Look for the complete version of an Objective-C interface, and return it
+ /// if found.
+ ///
+ /// \param[in] interface_decl
+ /// An ObjCInterfaceDecl that may not be the complete one.
+ ///
+ /// \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
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// \param[in] module
+ /// If non-NULL, the module to query.
+ ///
+ /// \param[in] namespace_decl
+ /// If valid and module is non-NULL, the parent namespace.
+ void FindExternalVisibleDecls(NameSearchContext &context,
+ lldb::ModuleSP module,
+ CompilerDeclContext &namespace_decl);
+
+ /// Find all Objective-C methods matching a given selector.
+ ///
+ /// \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
+ /// 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);
+
+ /// Performs lookup into a namespace.
+ ///
+ /// \param context
+ /// The NameSearchContext for a lookup inside a namespace.
+ void LookupInNamespace(NameSearchContext &context);
+
+ /// A wrapper for TypeSystemClang::CopyType that sets a flag that
+ /// indicates that we should not respond to queries during import.
+ ///
+ /// \param[in] src_type
+ /// The source type.
+ ///
+ /// \return
+ /// The imported type.
+ CompilerType GuardedCopyType(const CompilerType &src_type);
+
+ std::shared_ptr<ClangModulesDeclVendor> GetClangModulesDeclVendor();
+
+public:
+ /// Returns true if a name should be ignored by name lookup.
+ ///
+ /// \param[in] name
+ /// The name to be considered.
+ ///
+ /// \param[in] ignore_all_dollar_names
+ /// True if $-names of all sorts should be ignored.
+ ///
+ /// \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);
+
+ /// Copies a single Decl into the parser's AST context.
+ ///
+ /// \param[in] src_decl
+ /// The Decl to copy.
+ ///
+ /// \return
+ /// A copy of the Decl in m_ast_context, or NULL if the copy failed.
+ clang::Decl *CopyDecl(clang::Decl *src_decl);
+
+ /// Determined the origin of a single Decl, if it can be found.
+ ///
+ /// \param[in] decl
+ /// The Decl whose origin is to be found.
+ ///
+ /// \return
+ /// True if lookup succeeded; false otherwise.
+ ClangASTImporter::DeclOrigin GetDeclOrigin(const clang::Decl *decl);
+
+ /// Returns the TypeSystem that uses this ClangASTSource instance as it's
+ /// ExternalASTSource.
+ TypeSystemClang *GetTypeSystem() const { return m_clang_ast_context; }
+
+private:
+ bool FindObjCPropertyAndIvarDeclsWithOrigin(
+ NameSearchContext &context,
+ DeclFromUser<const clang::ObjCInterfaceDecl> &origin_iface_decl);
+
+protected:
+ bool FindObjCMethodDeclsWithOrigin(
+ NameSearchContext &context,
+ clang::ObjCInterfaceDecl *original_interface_decl, const char *log_info);
+
+ void FindDeclInModules(NameSearchContext &context, ConstString name);
+ void FindDeclInObjCRuntime(NameSearchContext &context, ConstString name);
+
+ /// Fills the namespace map of the given NameSearchContext.
+ ///
+ /// \param context The NameSearchContext with the namespace map to fill.
+ /// \param module_sp The module to search for namespaces or a nullptr if
+ /// the current target should be searched.
+ /// \param namespace_decl The DeclContext in which to search for namespaces.
+ void FillNamespaceMap(NameSearchContext &context, lldb::ModuleSP module_sp,
+ const CompilerDeclContext &namespace_decl);
+
+ clang::TagDecl *FindCompleteType(const clang::TagDecl *decl);
+
+ friend struct NameSearchContext;
+
+ bool m_lookups_enabled;
+
+ /// The target to use in finding variables and types.
+ const lldb::TargetSP m_target;
+ /// The AST context requests are coming in for.
+ clang::ASTContext *m_ast_context;
+ /// The TypeSystemClang for m_ast_context.
+ TypeSystemClang *m_clang_ast_context;
+ /// The file manager paired with the AST context.
+ clang::FileManager *m_file_manager;
+ /// The target's AST importer.
+ std::shared_ptr<ClangASTImporter> m_ast_importer_sp;
+ std::set<const clang::Decl *> m_active_lexical_decls;
+ std::set<const char *> m_active_lookups;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp
new file mode 100644
index 000000000000..867d4ff0a907
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp
@@ -0,0 +1,31 @@
+//===-- ClangDeclVendor.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include "lldb/Utility/ConstString.h"
+
+using namespace lldb_private;
+
+uint32_t ClangDeclVendor::FindDecls(ConstString name, bool append,
+ uint32_t max_matches,
+ std::vector<clang::NamedDecl *> &decls) {
+ if (!append)
+ decls.clear();
+
+ std::vector<CompilerDecl> compiler_decls;
+ uint32_t ret = FindDecls(name, /*append*/ false, max_matches, compiler_decls);
+ for (CompilerDecl compiler_decl : compiler_decls) {
+ clang::Decl *d = ClangUtil::GetDecl(compiler_decl);
+ clang::NamedDecl *nd = llvm::cast<clang::NamedDecl>(d);
+ decls.push_back(nd);
+ }
+ return ret;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h
new file mode 100644
index 000000000000..a9b2d4110ab2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h
@@ -0,0 +1,43 @@
+//===-- ClangDeclVendor.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDECLVENDOR_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDECLVENDOR_H
+
+#include "lldb/Symbol/DeclVendor.h"
+
+namespace clang {
+class NamedDecl;
+}
+
+namespace lldb_private {
+
+// A clang specialized extension to DeclVendor.
+class ClangDeclVendor : public DeclVendor {
+public:
+ ClangDeclVendor(DeclVendorKind kind) : DeclVendor(kind) {}
+
+ ~ClangDeclVendor() override = default;
+
+ using DeclVendor::FindDecls;
+
+ uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches,
+ std::vector<clang::NamedDecl *> &decls);
+
+ static bool classof(const DeclVendor *vendor) {
+ return vendor->GetKind() >= eClangDeclVendor &&
+ vendor->GetKind() < eLastClangDeclVendor;
+ }
+
+private:
+ ClangDeclVendor(const ClangDeclVendor &) = delete;
+ const ClangDeclVendor &operator=(const ClangDeclVendor &) = delete;
+};
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h
new file mode 100644
index 000000000000..21abd71cc34e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h
@@ -0,0 +1,50 @@
+//===-- ClangDiagnostic.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H
+
+#include <vector>
+
+#include "clang/Basic/Diagnostic.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+#include "lldb/Expression/DiagnosticManager.h"
+
+namespace lldb_private {
+
+class ClangDiagnostic : public Diagnostic {
+public:
+ typedef std::vector<clang::FixItHint> FixItList;
+
+ static inline bool classof(const ClangDiagnostic *) { return true; }
+ static inline bool classof(const Diagnostic *diag) {
+ return diag->getKind() == eDiagnosticOriginClang;
+ }
+
+ ClangDiagnostic(llvm::StringRef message, lldb::Severity severity,
+ uint32_t compiler_id)
+ : Diagnostic(message, severity, eDiagnosticOriginClang, compiler_id) {}
+
+ ~ClangDiagnostic() override = default;
+
+ bool HasFixIts() const override { return !m_fixit_vec.empty(); }
+
+ void AddFixitHint(const clang::FixItHint &fixit) {
+ m_fixit_vec.push_back(fixit);
+ }
+
+ const FixItList &FixIts() const { return m_fixit_vec; }
+private:
+ FixItList m_fixit_vec;
+};
+
+} // namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
new file mode 100644
index 000000000000..f994d0250433
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -0,0 +1,2044 @@
+//===-- ClangExpressionDeclMap.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionDeclMap.h"
+
+#include "ClangASTSource.h"
+#include "ClangExpressionUtil.h"
+#include "ClangExpressionVariable.h"
+#include "ClangModulesDeclVendor.h"
+#include "ClangPersistentVariables.h"
+#include "ClangUtil.h"
+
+#include "NameSearchContext.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/DiagnosticManager.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/CompilerDecl.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-private-types.h"
+#include "lldb/lldb-private.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclarationName.h"
+#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;
+using namespace clang;
+
+static const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars";
+
+namespace {
+/// A lambda is represented by Clang as an artifical class whose
+/// members are the lambda captures. If we capture a 'this' pointer,
+/// the artifical class will contain a member variable named 'this'.
+/// The function returns a ValueObject for the captured 'this' if such
+/// member exists. If no 'this' was captured, return a nullptr.
+lldb::ValueObjectSP GetCapturedThisValueObject(StackFrame *frame) {
+ assert(frame);
+
+ if (auto thisValSP = frame->FindVariable(ConstString("this")))
+ if (auto thisThisValSP = thisValSP->GetChildMemberWithName("this"))
+ return thisThisValSP;
+
+ return nullptr;
+}
+} // namespace
+
+ClangExpressionDeclMap::ClangExpressionDeclMap(
+ bool keep_result_in_memory,
+ Materializer::PersistentVariableDelegate *result_delegate,
+ const lldb::TargetSP &target,
+ const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj)
+ : ClangASTSource(target, importer), m_found_entities(), m_struct_members(),
+ m_keep_result_in_memory(keep_result_in_memory),
+ m_result_delegate(result_delegate), m_ctx_obj(ctx_obj), m_parser_vars(),
+ m_struct_vars() {
+ EnableStructVars();
+}
+
+ClangExpressionDeclMap::~ClangExpressionDeclMap() {
+ // Note: The model is now that the parser's AST context and all associated
+ // data does not vanish until the expression has been executed. This means
+ // that valuable lookup data (like namespaces) doesn't vanish, but
+
+ DidParse();
+ DisableStructVars();
+}
+
+bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx,
+ Materializer *materializer) {
+ EnableParserVars();
+ m_parser_vars->m_exe_ctx = exe_ctx;
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (exe_ctx.GetFramePtr())
+ m_parser_vars->m_sym_ctx =
+ exe_ctx.GetFramePtr()->GetSymbolContext(lldb::eSymbolContextEverything);
+ else if (exe_ctx.GetThreadPtr() &&
+ exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(0))
+ m_parser_vars->m_sym_ctx =
+ exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(0)->GetSymbolContext(
+ lldb::eSymbolContextEverything);
+ else if (exe_ctx.GetProcessPtr()) {
+ m_parser_vars->m_sym_ctx.Clear(true);
+ m_parser_vars->m_sym_ctx.target_sp = exe_ctx.GetTargetSP();
+ } else if (target) {
+ m_parser_vars->m_sym_ctx.Clear(true);
+ m_parser_vars->m_sym_ctx.target_sp = exe_ctx.GetTargetSP();
+ }
+
+ if (target) {
+ m_parser_vars->m_persistent_vars = llvm::cast<ClangPersistentVariables>(
+ target->GetPersistentExpressionStateForLanguage(eLanguageTypeC));
+
+ if (!ScratchTypeSystemClang::GetForTarget(*target))
+ return false;
+ }
+
+ m_parser_vars->m_target_info = GetTargetInfo();
+ m_parser_vars->m_materializer = materializer;
+
+ return true;
+}
+
+void ClangExpressionDeclMap::InstallCodeGenerator(
+ clang::ASTConsumer *code_gen) {
+ assert(m_parser_vars);
+ m_parser_vars->m_code_gen = code_gen;
+}
+
+void ClangExpressionDeclMap::InstallDiagnosticManager(
+ DiagnosticManager &diag_manager) {
+ assert(m_parser_vars);
+ m_parser_vars->m_diagnostics = &diag_manager;
+}
+
+void ClangExpressionDeclMap::DidParse() {
+ if (m_parser_vars && m_parser_vars->m_persistent_vars) {
+ for (size_t entity_index = 0, num_entities = m_found_entities.GetSize();
+ entity_index < num_entities; ++entity_index) {
+ ExpressionVariableSP var_sp(
+ m_found_entities.GetVariableAtIndex(entity_index));
+ if (var_sp)
+ llvm::cast<ClangExpressionVariable>(var_sp.get())
+ ->DisableParserVars(GetParserID());
+ }
+
+ for (size_t pvar_index = 0,
+ num_pvars = m_parser_vars->m_persistent_vars->GetSize();
+ pvar_index < num_pvars; ++pvar_index) {
+ ExpressionVariableSP pvar_sp(
+ m_parser_vars->m_persistent_vars->GetVariableAtIndex(pvar_index));
+ if (ClangExpressionVariable *clang_var =
+ llvm::dyn_cast<ClangExpressionVariable>(pvar_sp.get()))
+ clang_var->DisableParserVars(GetParserID());
+ }
+
+ DisableParserVars();
+ }
+}
+
+// Interface for IRForTarget
+
+ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() {
+ assert(m_parser_vars.get());
+
+ TargetInfo ret;
+
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process) {
+ ret.byte_order = process->GetByteOrder();
+ ret.address_byte_size = process->GetAddressByteSize();
+ } else {
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ ret.byte_order = target->GetArchitecture().GetByteOrder();
+ ret.address_byte_size = target->GetArchitecture().GetAddressByteSize();
+ }
+ }
+
+ return ret;
+}
+
+TypeFromUser ClangExpressionDeclMap::DeportType(TypeSystemClang &target,
+ TypeSystemClang &source,
+ TypeFromParser parser_type) {
+ assert(&target == GetScratchContext(*m_target).get());
+ assert((TypeSystem *)&source ==
+ parser_type.GetTypeSystem().GetSharedPointer().get());
+ assert(&source.getASTContext() == m_ast_context);
+
+ return TypeFromUser(m_ast_importer_sp->DeportType(target, parser_type));
+}
+
+bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl,
+ ConstString name,
+ TypeFromParser parser_type,
+ bool is_result,
+ bool is_lvalue) {
+ assert(m_parser_vars.get());
+ auto ast = parser_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+ if (ast == nullptr)
+ return false;
+
+ // Check if we already declared a persistent variable with the same name.
+ if (lldb::ExpressionVariableSP conflicting_var =
+ m_parser_vars->m_persistent_vars->GetVariable(name)) {
+ std::string msg = llvm::formatv("redefinition of persistent variable '{0}'",
+ name).str();
+ m_parser_vars->m_diagnostics->AddDiagnostic(
+ msg, lldb::eSeverityError, DiagnosticOrigin::eDiagnosticOriginLLDB);
+ return false;
+ }
+
+ if (m_parser_vars->m_materializer && is_result) {
+ Status err;
+
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target == nullptr)
+ return false;
+
+ auto clang_ast_context = GetScratchContext(*target);
+ if (!clang_ast_context)
+ return false;
+
+ TypeFromUser user_type = DeportType(*clang_ast_context, *ast, parser_type);
+
+ uint32_t offset = m_parser_vars->m_materializer->AddResultVariable(
+ user_type, is_lvalue, m_keep_result_in_memory, m_result_delegate, err);
+
+ ClangExpressionVariable *var = new ClangExpressionVariable(
+ exe_ctx.GetBestExecutionContextScope(), name, user_type,
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size);
+
+ m_found_entities.AddNewlyConstructedVariable(var);
+
+ var->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ var->GetParserVars(GetParserID());
+
+ parser_vars->m_named_decl = decl;
+
+ var->EnableJITVars(GetParserID());
+
+ ClangExpressionVariable::JITVars *jit_vars = var->GetJITVars(GetParserID());
+
+ jit_vars->m_offset = offset;
+
+ return true;
+ }
+
+ Log *log = GetLog(LLDBLog::Expressions);
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target == nullptr)
+ return false;
+
+ auto context = GetScratchContext(*target);
+ if (!context)
+ return false;
+
+ TypeFromUser user_type = DeportType(*context, *ast, parser_type);
+
+ if (!user_type.GetOpaqueQualType()) {
+ LLDB_LOG(log, "Persistent variable's type wasn't copied successfully");
+ return false;
+ }
+
+ if (!m_parser_vars->m_target_info.IsValid())
+ return false;
+
+ if (!m_parser_vars->m_persistent_vars)
+ return false;
+
+ ClangExpressionVariable *var = llvm::cast<ClangExpressionVariable>(
+ m_parser_vars->m_persistent_vars
+ ->CreatePersistentVariable(
+ exe_ctx.GetBestExecutionContextScope(), name, user_type,
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size)
+ .get());
+
+ if (!var)
+ return false;
+
+ var->m_frozen_sp->SetHasCompleteType();
+
+ if (is_result)
+ var->m_flags |= ClangExpressionVariable::EVNeedsFreezeDry;
+ else
+ var->m_flags |=
+ ClangExpressionVariable::EVKeepInTarget; // explicitly-declared
+ // persistent variables should
+ // persist
+
+ if (is_lvalue) {
+ var->m_flags |= ClangExpressionVariable::EVIsProgramReference;
+ } else {
+ var->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+ var->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+ }
+
+ if (m_keep_result_in_memory) {
+ var->m_flags |= ClangExpressionVariable::EVKeepInTarget;
+ }
+
+ LLDB_LOG(log, "Created persistent variable with flags {0:x}", var->m_flags);
+
+ var->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ var->GetParserVars(GetParserID());
+
+ parser_vars->m_named_decl = decl;
+
+ return true;
+}
+
+bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl,
+ ConstString name,
+ llvm::Value *value, size_t size,
+ lldb::offset_t alignment) {
+ assert(m_struct_vars.get());
+ assert(m_parser_vars.get());
+
+ bool is_persistent_variable = false;
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ m_struct_vars->m_struct_laid_out = false;
+
+ if (ClangExpressionVariable::FindVariableInList(m_struct_members, decl,
+ GetParserID()))
+ return true;
+
+ ClangExpressionVariable *var(ClangExpressionVariable::FindVariableInList(
+ m_found_entities, decl, GetParserID()));
+
+ if (!var && m_parser_vars->m_persistent_vars) {
+ var = ClangExpressionVariable::FindVariableInList(
+ *m_parser_vars->m_persistent_vars, decl, GetParserID());
+ is_persistent_variable = true;
+ }
+
+ if (!var)
+ return false;
+
+ LLDB_LOG(log, "Adding value for (NamedDecl*){0} [{1} - {2}] to the structure",
+ decl, name, var->GetName());
+
+ // We know entity->m_parser_vars is valid because we used a parser variable
+ // to find it
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ llvm::cast<ClangExpressionVariable>(var)->GetParserVars(GetParserID());
+
+ parser_vars->m_llvm_value = value;
+
+ if (ClangExpressionVariable::JITVars *jit_vars =
+ llvm::cast<ClangExpressionVariable>(var)->GetJITVars(GetParserID())) {
+ // We already laid this out; do not touch
+
+ LLDB_LOG(log, "Already placed at {0:x}", jit_vars->m_offset);
+ }
+
+ llvm::cast<ClangExpressionVariable>(var)->EnableJITVars(GetParserID());
+
+ ClangExpressionVariable::JITVars *jit_vars =
+ llvm::cast<ClangExpressionVariable>(var)->GetJITVars(GetParserID());
+
+ jit_vars->m_alignment = alignment;
+ jit_vars->m_size = size;
+
+ m_struct_members.AddVariable(var->shared_from_this());
+
+ if (m_parser_vars->m_materializer) {
+ uint32_t offset = 0;
+
+ Status err;
+
+ if (is_persistent_variable) {
+ ExpressionVariableSP var_sp(var->shared_from_this());
+ offset = m_parser_vars->m_materializer->AddPersistentVariable(
+ var_sp, nullptr, err);
+ } else {
+ if (const lldb_private::Symbol *sym = parser_vars->m_lldb_sym)
+ offset = m_parser_vars->m_materializer->AddSymbol(*sym, err);
+ else if (const RegisterInfo *reg_info = var->GetRegisterInfo())
+ offset = m_parser_vars->m_materializer->AddRegister(*reg_info, err);
+ else if (parser_vars->m_lldb_var)
+ offset = m_parser_vars->m_materializer->AddVariable(
+ parser_vars->m_lldb_var, err);
+ else if (parser_vars->m_lldb_valobj_provider) {
+ offset = m_parser_vars->m_materializer->AddValueObject(
+ name, parser_vars->m_lldb_valobj_provider, err);
+ }
+ }
+
+ if (!err.Success())
+ return false;
+
+ LLDB_LOG(log, "Placed at {0:x}", offset);
+
+ jit_vars->m_offset =
+ offset; // TODO DoStructLayout() should not change this.
+ }
+
+ return true;
+}
+
+bool ClangExpressionDeclMap::DoStructLayout() {
+ assert(m_struct_vars.get());
+
+ if (m_struct_vars->m_struct_laid_out)
+ return true;
+
+ if (!m_parser_vars->m_materializer)
+ return false;
+
+ m_struct_vars->m_struct_alignment =
+ m_parser_vars->m_materializer->GetStructAlignment();
+ m_struct_vars->m_struct_size =
+ m_parser_vars->m_materializer->GetStructByteSize();
+ m_struct_vars->m_struct_laid_out = true;
+ return true;
+}
+
+bool ClangExpressionDeclMap::GetStructInfo(uint32_t &num_elements, size_t &size,
+ lldb::offset_t &alignment) {
+ assert(m_struct_vars.get());
+
+ if (!m_struct_vars->m_struct_laid_out)
+ return false;
+
+ num_elements = m_struct_members.GetSize();
+ size = m_struct_vars->m_struct_size;
+ alignment = m_struct_vars->m_struct_alignment;
+
+ return true;
+}
+
+bool ClangExpressionDeclMap::GetStructElement(const NamedDecl *&decl,
+ llvm::Value *&value,
+ lldb::offset_t &offset,
+ ConstString &name,
+ uint32_t index) {
+ assert(m_struct_vars.get());
+
+ if (!m_struct_vars->m_struct_laid_out)
+ return false;
+
+ if (index >= m_struct_members.GetSize())
+ return false;
+
+ ExpressionVariableSP member_sp(m_struct_members.GetVariableAtIndex(index));
+
+ if (!member_sp)
+ return false;
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ llvm::cast<ClangExpressionVariable>(member_sp.get())
+ ->GetParserVars(GetParserID());
+ ClangExpressionVariable::JITVars *jit_vars =
+ llvm::cast<ClangExpressionVariable>(member_sp.get())
+ ->GetJITVars(GetParserID());
+
+ if (!parser_vars || !jit_vars || !member_sp->GetValueObject())
+ return false;
+
+ decl = parser_vars->m_named_decl;
+ value = parser_vars->m_llvm_value;
+ offset = jit_vars->m_offset;
+ name = member_sp->GetName();
+
+ return true;
+}
+
+bool ClangExpressionDeclMap::GetFunctionInfo(const NamedDecl *decl,
+ uint64_t &ptr) {
+ ClangExpressionVariable *entity(ClangExpressionVariable::FindVariableInList(
+ m_found_entities, decl, GetParserID()));
+
+ if (!entity)
+ return false;
+
+ // We know m_parser_vars is valid since we searched for the variable by its
+ // NamedDecl
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ entity->GetParserVars(GetParserID());
+
+ ptr = parser_vars->m_lldb_value.GetScalar().ULongLong();
+
+ return true;
+}
+
+addr_t ClangExpressionDeclMap::GetSymbolAddress(Target &target,
+ Process *process,
+ ConstString name,
+ lldb::SymbolType symbol_type,
+ lldb_private::Module *module) {
+ SymbolContextList sc_list;
+
+ if (module)
+ module->FindSymbolsWithNameAndType(name, symbol_type, sc_list);
+ else
+ target.GetImages().FindSymbolsWithNameAndType(name, symbol_type, sc_list);
+
+ addr_t symbol_load_addr = LLDB_INVALID_ADDRESS;
+
+ for (const SymbolContext &sym_ctx : sc_list) {
+ if (symbol_load_addr != 0 && symbol_load_addr != LLDB_INVALID_ADDRESS)
+ break;
+
+ const Address sym_address = sym_ctx.symbol->GetAddress();
+
+ if (!sym_address.IsValid())
+ continue;
+
+ switch (sym_ctx.symbol->GetType()) {
+ case eSymbolTypeCode:
+ case eSymbolTypeTrampoline:
+ symbol_load_addr = sym_address.GetCallableLoadAddress(&target);
+ break;
+
+ case eSymbolTypeResolver:
+ symbol_load_addr = sym_address.GetCallableLoadAddress(&target, true);
+ break;
+
+ case eSymbolTypeReExported: {
+ ConstString reexport_name = sym_ctx.symbol->GetReExportedSymbolName();
+ if (reexport_name) {
+ ModuleSP reexport_module_sp;
+ ModuleSpec reexport_module_spec;
+ reexport_module_spec.GetPlatformFileSpec() =
+ sym_ctx.symbol->GetReExportedSymbolSharedLibrary();
+ if (reexport_module_spec.GetPlatformFileSpec()) {
+ reexport_module_sp =
+ target.GetImages().FindFirstModule(reexport_module_spec);
+ if (!reexport_module_sp) {
+ reexport_module_spec.GetPlatformFileSpec().ClearDirectory();
+ reexport_module_sp =
+ target.GetImages().FindFirstModule(reexport_module_spec);
+ }
+ }
+ symbol_load_addr = GetSymbolAddress(
+ target, process, sym_ctx.symbol->GetReExportedSymbolName(),
+ symbol_type, reexport_module_sp.get());
+ }
+ } break;
+
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeVariable:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeInvalid:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeException:
+ case eSymbolTypeSourceFile:
+ case eSymbolTypeHeaderFile:
+ case eSymbolTypeObjectFile:
+ case eSymbolTypeCommonBlock:
+ case eSymbolTypeBlock:
+ case eSymbolTypeVariableType:
+ case eSymbolTypeLineEntry:
+ case eSymbolTypeLineHeader:
+ case eSymbolTypeScopeBegin:
+ case eSymbolTypeScopeEnd:
+ case eSymbolTypeAdditional:
+ case eSymbolTypeCompiler:
+ case eSymbolTypeInstrumentation:
+ case eSymbolTypeUndefined:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ symbol_load_addr = sym_address.GetLoadAddress(&target);
+ break;
+ }
+ }
+
+ if (symbol_load_addr == LLDB_INVALID_ADDRESS && process) {
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process);
+
+ if (runtime) {
+ symbol_load_addr = runtime->LookupRuntimeSymbol(name);
+ }
+ }
+
+ return symbol_load_addr;
+}
+
+addr_t ClangExpressionDeclMap::GetSymbolAddress(ConstString name,
+ lldb::SymbolType symbol_type) {
+ assert(m_parser_vars.get());
+
+ if (!m_parser_vars->m_exe_ctx.GetTargetPtr())
+ return false;
+
+ return GetSymbolAddress(m_parser_vars->m_exe_ctx.GetTargetRef(),
+ m_parser_vars->m_exe_ctx.GetProcessPtr(), name,
+ symbol_type);
+}
+
+lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable(
+ Target &target, ModuleSP &module, ConstString name,
+ const CompilerDeclContext &namespace_decl) {
+ VariableList vars;
+
+ if (module && namespace_decl)
+ module->FindGlobalVariables(name, namespace_decl, -1, vars);
+ else
+ target.GetImages().FindGlobalVariables(name, -1, vars);
+
+ if (vars.GetSize() == 0)
+ return VariableSP();
+ return vars.GetVariableAtIndex(0);
+}
+
+TypeSystemClang *ClangExpressionDeclMap::GetTypeSystemClang() {
+ StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+ if (frame == nullptr)
+ return nullptr;
+
+ SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
+ lldb::eSymbolContextBlock);
+ if (sym_ctx.block == nullptr)
+ return nullptr;
+
+ CompilerDeclContext frame_decl_context = sym_ctx.block->GetDeclContext();
+ if (!frame_decl_context)
+ return nullptr;
+
+ return llvm::dyn_cast_or_null<TypeSystemClang>(
+ frame_decl_context.GetTypeSystem());
+}
+
+// Interface for ClangASTSource
+
+void ClangExpressionDeclMap::FindExternalVisibleDecls(
+ NameSearchContext &context) {
+ assert(m_ast_context);
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (log) {
+ if (!context.m_decl_context)
+ LLDB_LOG(log,
+ "ClangExpressionDeclMap::FindExternalVisibleDecls for "
+ "'{0}' in a NULL DeclContext",
+ name);
+ else if (const NamedDecl *context_named_decl =
+ dyn_cast<NamedDecl>(context.m_decl_context))
+ LLDB_LOG(log,
+ "ClangExpressionDeclMap::FindExternalVisibleDecls for "
+ "'{0}' in '{1}'",
+ name, context_named_decl->getNameAsString());
+ else
+ LLDB_LOG(log,
+ "ClangExpressionDeclMap::FindExternalVisibleDecls for "
+ "'{0}' in a '{1}'",
+ name, context.m_decl_context->getDeclKindName());
+ }
+
+ if (const NamespaceDecl *namespace_context =
+ dyn_cast<NamespaceDecl>(context.m_decl_context)) {
+ if (namespace_context->getName().str() ==
+ std::string(g_lldb_local_vars_namespace_cstr)) {
+ CompilerDeclContext compiler_decl_ctx =
+ m_clang_ast_context->CreateDeclContext(
+ const_cast<clang::DeclContext *>(context.m_decl_context));
+ FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx);
+ return;
+ }
+
+ ClangASTImporter::NamespaceMapSP namespace_map =
+ m_ast_importer_sp->GetNamespaceMap(namespace_context);
+
+ if (!namespace_map)
+ return;
+
+ LLDB_LOGV(log, " CEDM::FEVD Inspecting (NamespaceMap*){0:x} ({1} entries)",
+ namespace_map.get(), namespace_map->size());
+
+ for (ClangASTImporter::NamespaceMapItem &n : *namespace_map) {
+ LLDB_LOG(log, " CEDM::FEVD Searching namespace {0} in module {1}",
+ n.second.GetName(), n.first->GetFileSpec().GetFilename());
+
+ FindExternalVisibleDecls(context, n.first, n.second);
+ }
+ } else if (isa<TranslationUnitDecl>(context.m_decl_context)) {
+ CompilerDeclContext namespace_decl;
+
+ LLDB_LOG(log, " CEDM::FEVD Searching the root namespace");
+
+ FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl);
+ }
+
+ ClangASTSource::FindExternalVisibleDecls(context);
+}
+
+void ClangExpressionDeclMap::MaybeRegisterFunctionBody(
+ FunctionDecl *copied_function_decl) {
+ if (copied_function_decl->getBody() && m_parser_vars->m_code_gen) {
+ clang::DeclGroupRef decl_group_ref(copied_function_decl);
+ m_parser_vars->m_code_gen->HandleTopLevelDecl(decl_group_ref);
+ }
+}
+
+clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) {
+ if (!m_parser_vars)
+ return nullptr;
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+ if (!target)
+ return nullptr;
+
+ ScratchTypeSystemClang::GetForTarget(*target);
+
+ if (!m_parser_vars->m_persistent_vars)
+ return nullptr;
+ return m_parser_vars->m_persistent_vars->GetPersistentDecl(name);
+}
+
+void ClangExpressionDeclMap::SearchPersistenDecls(NameSearchContext &context,
+ const ConstString name) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ NamedDecl *persistent_decl = GetPersistentDecl(name);
+
+ if (!persistent_decl)
+ return;
+
+ Decl *parser_persistent_decl = CopyDecl(persistent_decl);
+
+ if (!parser_persistent_decl)
+ return;
+
+ NamedDecl *parser_named_decl = dyn_cast<NamedDecl>(parser_persistent_decl);
+
+ if (!parser_named_decl)
+ return;
+
+ if (clang::FunctionDecl *parser_function_decl =
+ llvm::dyn_cast<clang::FunctionDecl>(parser_named_decl)) {
+ MaybeRegisterFunctionBody(parser_function_decl);
+ }
+
+ LLDB_LOG(log, " CEDM::FEVD Found persistent decl {0}", name);
+
+ context.AddNamedDecl(parser_named_decl);
+}
+
+void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+ SymbolContext sym_ctx;
+ if (frame != nullptr)
+ sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
+ lldb::eSymbolContextBlock);
+
+ if (m_ctx_obj) {
+ Status status;
+ lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status);
+ if (!ctx_obj_ptr || status.Fail())
+ return;
+
+ AddContextClassType(context, TypeFromUser(m_ctx_obj->GetCompilerType()));
+ return;
+ }
+
+ // Clang is looking for the type of "this"
+
+ if (frame == nullptr)
+ return;
+
+ // Find the block that defines the function represented by "sym_ctx"
+ Block *function_block = sym_ctx.GetFunctionBlock();
+
+ if (!function_block)
+ return;
+
+ CompilerDeclContext function_decl_ctx = function_block->GetDeclContext();
+
+ if (!function_decl_ctx)
+ return;
+
+ clang::CXXMethodDecl *method_decl =
+ TypeSystemClang::DeclContextGetAsCXXMethodDecl(function_decl_ctx);
+
+ if (method_decl) {
+ if (auto capturedThis = GetCapturedThisValueObject(frame)) {
+ // We're inside a lambda and we captured a 'this'.
+ // Import the outer class's AST instead of the
+ // (unnamed) lambda structure AST so unqualified
+ // member lookups are understood by the Clang parser.
+ //
+ // If we're in a lambda which didn't capture 'this',
+ // $__lldb_class will correspond to the lambda closure
+ // AST and references to captures will resolve like
+ // regular member varaiable accesses do.
+ TypeFromUser pointee_type =
+ capturedThis->GetCompilerType().GetPointeeType();
+
+ LLDB_LOG(log,
+ " CEDM::FEVD Adding captured type ({0} for"
+ " $__lldb_class: {1}",
+ capturedThis->GetTypeName(), capturedThis->GetName());
+
+ AddContextClassType(context, pointee_type);
+ return;
+ }
+
+ clang::CXXRecordDecl *class_decl = method_decl->getParent();
+
+ QualType class_qual_type(class_decl->getTypeForDecl(), 0);
+
+ TypeFromUser class_user_type(
+ class_qual_type.getAsOpaquePtr(),
+ function_decl_ctx.GetTypeSystem()->weak_from_this());
+
+ LLDB_LOG(log, " CEDM::FEVD Adding type for $__lldb_class: {0}",
+ class_qual_type.getAsString());
+
+ AddContextClassType(context, class_user_type);
+ return;
+ }
+
+ // This branch will get hit if we are executing code in the context of
+ // a function that claims to have an object pointer (through
+ // DW_AT_object_pointer?) but is not formally a method of the class.
+ // In that case, just look up the "this" variable in the current scope
+ // and use its type.
+ // FIXME: This code is formally correct, but clang doesn't currently
+ // emit DW_AT_object_pointer
+ // for C++ so it hasn't actually been tested.
+
+ VariableList *vars = frame->GetVariableList(false, nullptr);
+
+ lldb::VariableSP this_var = vars->FindVariable(ConstString("this"));
+
+ if (this_var && this_var->IsInScope(frame) &&
+ this_var->LocationIsValidForFrame(frame)) {
+ Type *this_type = this_var->GetType();
+
+ if (!this_type)
+ return;
+
+ TypeFromUser pointee_type =
+ this_type->GetForwardCompilerType().GetPointeeType();
+
+ LLDB_LOG(log, " FEVD Adding type for $__lldb_class: {0}",
+ ClangUtil::GetQualType(pointee_type).getAsString());
+
+ AddContextClassType(context, pointee_type);
+ }
+}
+
+void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+
+ 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()));
+ return;
+ }
+
+ // Clang is looking for the type of "*self"
+
+ if (!frame)
+ return;
+
+ SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
+ lldb::eSymbolContextBlock);
+
+ // Find the block that defines the function represented by "sym_ctx"
+ Block *function_block = sym_ctx.GetFunctionBlock();
+
+ if (!function_block)
+ return;
+
+ CompilerDeclContext function_decl_ctx = function_block->GetDeclContext();
+
+ if (!function_decl_ctx)
+ return;
+
+ clang::ObjCMethodDecl *method_decl =
+ TypeSystemClang::DeclContextGetAsObjCMethodDecl(function_decl_ctx);
+
+ if (method_decl) {
+ ObjCInterfaceDecl *self_interface = method_decl->getClassInterface();
+
+ if (!self_interface)
+ return;
+
+ const clang::Type *interface_type = self_interface->getTypeForDecl();
+
+ if (!interface_type)
+ return; // This is unlikely, but we have seen crashes where this
+ // occurred
+
+ TypeFromUser class_user_type(
+ QualType(interface_type, 0).getAsOpaquePtr(),
+ function_decl_ctx.GetTypeSystem()->weak_from_this());
+
+ LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_objc_class: {1}",
+ ClangUtil::ToString(interface_type));
+
+ AddOneType(context, class_user_type);
+ return;
+ }
+ // This branch will get hit if we are executing code in the context of
+ // a function that claims to have an object pointer (through
+ // DW_AT_object_pointer?) but is not formally a method of the class.
+ // In that case, just look up the "self" variable in the current scope
+ // and use its type.
+
+ VariableList *vars = frame->GetVariableList(false, nullptr);
+
+ lldb::VariableSP self_var = vars->FindVariable(ConstString("self"));
+
+ if (!self_var)
+ return;
+ if (!self_var->IsInScope(frame))
+ return;
+ if (!self_var->LocationIsValidForFrame(frame))
+ return;
+
+ Type *self_type = self_var->GetType();
+
+ if (!self_type)
+ return;
+
+ CompilerType self_clang_type = self_type->GetFullCompilerType();
+
+ if (TypeSystemClang::IsObjCClassType(self_clang_type)) {
+ return;
+ }
+ if (!TypeSystemClang::IsObjCObjectPointerType(self_clang_type))
+ return;
+ self_clang_type = self_clang_type.GetPointeeType();
+
+ if (!self_clang_type)
+ return;
+
+ LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_objc_class: {1}",
+ ClangUtil::ToString(self_type->GetFullCompilerType()));
+
+ TypeFromUser class_user_type(self_clang_type);
+
+ AddOneType(context, class_user_type);
+}
+
+void ClangExpressionDeclMap::LookupLocalVarNamespace(
+ SymbolContext &sym_ctx, NameSearchContext &name_context) {
+ if (sym_ctx.block == nullptr)
+ return;
+
+ CompilerDeclContext frame_decl_context = sym_ctx.block->GetDeclContext();
+ if (!frame_decl_context)
+ return;
+
+ TypeSystemClang *frame_ast = llvm::dyn_cast_or_null<TypeSystemClang>(
+ frame_decl_context.GetTypeSystem());
+ if (!frame_ast)
+ return;
+
+ clang::NamespaceDecl *namespace_decl =
+ m_clang_ast_context->GetUniqueNamespaceDeclaration(
+ g_lldb_local_vars_namespace_cstr, nullptr, OptionalClangModuleID());
+ if (!namespace_decl)
+ return;
+
+ name_context.AddNamedDecl(namespace_decl);
+ clang::DeclContext *ctxt = clang::Decl::castToDeclContext(namespace_decl);
+ ctxt->setHasExternalVisibleStorage(true);
+ name_context.m_found_local_vars_nsp = true;
+}
+
+void ClangExpressionDeclMap::LookupInModulesDeclVendor(
+ NameSearchContext &context, ConstString name) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (!m_target)
+ return;
+
+ std::shared_ptr<ClangModulesDeclVendor> modules_decl_vendor =
+ GetClangModulesDeclVendor();
+ if (!modules_decl_vendor)
+ return;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector<clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls))
+ return;
+
+ assert(!decls.empty() && "FindDecls returned true but no decls?");
+ clang::NamedDecl *const decl_from_modules = decls[0];
+
+ LLDB_LOG(log,
+ " CAS::FEVD Matching decl found for "
+ "\"{0}\" in the modules",
+ name);
+
+ clang::Decl *copied_decl = CopyDecl(decl_from_modules);
+ if (!copied_decl) {
+ LLDB_LOG(log, " CAS::FEVD - Couldn't export a "
+ "declaration from the modules");
+ return;
+ }
+
+ if (auto copied_function = dyn_cast<clang::FunctionDecl>(copied_decl)) {
+ MaybeRegisterFunctionBody(copied_function);
+
+ context.AddNamedDecl(copied_function);
+
+ context.m_found_function_with_type_info = true;
+ } else if (auto copied_var = dyn_cast<clang::VarDecl>(copied_decl)) {
+ context.AddNamedDecl(copied_var);
+ context.m_found_variable = true;
+ }
+}
+
+bool ClangExpressionDeclMap::LookupLocalVariable(
+ NameSearchContext &context, ConstString name, SymbolContext &sym_ctx,
+ const CompilerDeclContext &namespace_decl) {
+ if (sym_ctx.block == nullptr)
+ return false;
+
+ CompilerDeclContext decl_context = sym_ctx.block->GetDeclContext();
+ if (!decl_context)
+ return false;
+
+ // Make sure that the variables are parsed so that we have the
+ // declarations.
+ StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+ VariableListSP vars = frame->GetInScopeVariableList(true);
+ for (size_t i = 0; i < vars->GetSize(); i++)
+ vars->GetVariableAtIndex(i)->GetDecl();
+
+ // Search for declarations matching the name. Do not include imported
+ // decls in the search if we are looking for decls in the artificial
+ // namespace $__lldb_local_vars.
+ std::vector<CompilerDecl> found_decls =
+ decl_context.FindDeclByName(name, namespace_decl.IsValid());
+
+ VariableSP var;
+ bool variable_found = false;
+ for (CompilerDecl decl : found_decls) {
+ for (size_t vi = 0, ve = vars->GetSize(); vi != ve; ++vi) {
+ VariableSP candidate_var = vars->GetVariableAtIndex(vi);
+ if (candidate_var->GetDecl() == decl) {
+ var = candidate_var;
+ break;
+ }
+ }
+
+ if (var && !variable_found) {
+ variable_found = true;
+ ValueObjectSP valobj = ValueObjectVariable::Create(frame, var);
+ AddOneVariable(context, var, valobj);
+ context.m_found_variable = true;
+ }
+ }
+
+ // We're in a local_var_lookup but haven't found any local variables
+ // so far. When performing a variable lookup from within the context of
+ // a lambda, we count the lambda captures as local variables. Thus,
+ // see if we captured any variables with the requested 'name'.
+ if (!variable_found) {
+ auto find_capture = [](ConstString varname,
+ StackFrame *frame) -> ValueObjectSP {
+ if (auto lambda = ClangExpressionUtil::GetLambdaValueObject(frame)) {
+ if (auto capture = lambda->GetChildMemberWithName(varname)) {
+ return capture;
+ }
+ }
+
+ return nullptr;
+ };
+
+ if (auto capture = find_capture(name, frame)) {
+ variable_found = true;
+ context.m_found_variable = true;
+ AddOneVariable(context, std::move(capture), std::move(find_capture));
+ }
+ }
+
+ return variable_found;
+}
+
+/// Structure to hold the info needed when comparing function
+/// declarations.
+namespace {
+struct FuncDeclInfo {
+ ConstString m_name;
+ CompilerType m_copied_type;
+ uint32_t m_decl_lvl;
+ SymbolContext m_sym_ctx;
+};
+} // namespace
+
+SymbolContextList ClangExpressionDeclMap::SearchFunctionsInSymbolContexts(
+ const SymbolContextList &sc_list,
+ const CompilerDeclContext &frame_decl_context) {
+ // First, symplify things by looping through the symbol contexts to
+ // remove unwanted functions and separate out the functions we want to
+ // compare and prune into a separate list. Cache the info needed about
+ // the function declarations in a vector for efficiency.
+ SymbolContextList sc_sym_list;
+ std::vector<FuncDeclInfo> decl_infos;
+ decl_infos.reserve(sc_list.GetSize());
+ clang::DeclContext *frame_decl_ctx =
+ (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext();
+ TypeSystemClang *ast = llvm::dyn_cast_or_null<TypeSystemClang>(
+ frame_decl_context.GetTypeSystem());
+
+ for (const SymbolContext &sym_ctx : sc_list) {
+ FuncDeclInfo fdi;
+
+ // We don't know enough about symbols to compare them, but we should
+ // keep them in the list.
+ Function *function = sym_ctx.function;
+ if (!function) {
+ sc_sym_list.Append(sym_ctx);
+ continue;
+ }
+ // Filter out functions without declaration contexts, as well as
+ // class/instance methods, since they'll be skipped in the code that
+ // follows anyway.
+ CompilerDeclContext func_decl_context = function->GetDeclContext();
+ if (!func_decl_context || func_decl_context.IsClassMethod())
+ continue;
+ // We can only prune functions for which we can copy the type.
+ CompilerType func_clang_type = function->GetType()->GetFullCompilerType();
+ CompilerType copied_func_type = GuardedCopyType(func_clang_type);
+ if (!copied_func_type) {
+ sc_sym_list.Append(sym_ctx);
+ continue;
+ }
+
+ fdi.m_sym_ctx = sym_ctx;
+ fdi.m_name = function->GetName();
+ fdi.m_copied_type = copied_func_type;
+ fdi.m_decl_lvl = LLDB_INVALID_DECL_LEVEL;
+ if (fdi.m_copied_type && func_decl_context) {
+ // Call CountDeclLevels to get the number of parent scopes we have
+ // to look through before we find the function declaration. When
+ // comparing functions of the same type, the one with a lower count
+ // will be closer to us in the lookup scope and shadows the other.
+ clang::DeclContext *func_decl_ctx =
+ (clang::DeclContext *)func_decl_context.GetOpaqueDeclContext();
+ fdi.m_decl_lvl = ast->CountDeclLevels(frame_decl_ctx, func_decl_ctx,
+ &fdi.m_name, &fdi.m_copied_type);
+ }
+ decl_infos.emplace_back(fdi);
+ }
+
+ // Loop through the functions in our cache looking for matching types,
+ // then compare their scope levels to see which is closer.
+ std::multimap<CompilerType, const FuncDeclInfo *> matches;
+ for (const FuncDeclInfo &fdi : decl_infos) {
+ const CompilerType t = fdi.m_copied_type;
+ auto q = matches.find(t);
+ if (q != matches.end()) {
+ if (q->second->m_decl_lvl > fdi.m_decl_lvl)
+ // This function is closer; remove the old set.
+ matches.erase(t);
+ else if (q->second->m_decl_lvl < fdi.m_decl_lvl)
+ // The functions in our set are closer - skip this one.
+ continue;
+ }
+ matches.insert(std::make_pair(t, &fdi));
+ }
+
+ // Loop through our matches and add their symbol contexts to our list.
+ SymbolContextList sc_func_list;
+ for (const auto &q : matches)
+ sc_func_list.Append(q.second->m_sym_ctx);
+
+ // Rejoin the lists with the functions in front.
+ sc_func_list.Append(sc_sym_list);
+ return sc_func_list;
+}
+
+void ClangExpressionDeclMap::LookupFunction(
+ NameSearchContext &context, lldb::ModuleSP module_sp, ConstString name,
+ const CompilerDeclContext &namespace_decl) {
+ if (!m_parser_vars)
+ return;
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ std::vector<clang::NamedDecl *> decls_from_modules;
+
+ if (target) {
+ if (std::shared_ptr<ClangModulesDeclVendor> decl_vendor =
+ GetClangModulesDeclVendor()) {
+ decl_vendor->FindDecls(name, false, UINT32_MAX, decls_from_modules);
+ }
+ }
+
+ SymbolContextList sc_list;
+ if (namespace_decl && module_sp) {
+ ModuleFunctionSearchOptions function_options;
+ function_options.include_inlines = false;
+ function_options.include_symbols = false;
+
+ module_sp->FindFunctions(name, namespace_decl, eFunctionNameTypeBase,
+ function_options, sc_list);
+ } else if (target && !namespace_decl) {
+ ModuleFunctionSearchOptions function_options;
+ function_options.include_inlines = false;
+ function_options.include_symbols = true;
+
+ // TODO Fix FindFunctions so that it doesn't return
+ // instance methods for eFunctionNameTypeBase.
+
+ target->GetImages().FindFunctions(
+ name, eFunctionNameTypeFull | eFunctionNameTypeBase, function_options,
+ sc_list);
+ }
+
+ // If we found more than one function, see if we can use the frame's decl
+ // context to remove functions that are shadowed by other functions which
+ // match in type but are nearer in scope.
+ //
+ // AddOneFunction will not add a function whose type has already been
+ // added, so if there's another function in the list with a matching type,
+ // check to see if their decl context is a parent of the current frame's or
+ // was imported via a and using statement, and pick the best match
+ // according to lookup rules.
+ if (sc_list.GetSize() > 1) {
+ // Collect some info about our frame's context.
+ StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+ SymbolContext frame_sym_ctx;
+ if (frame != nullptr)
+ frame_sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
+ lldb::eSymbolContextBlock);
+ CompilerDeclContext frame_decl_context =
+ frame_sym_ctx.block != nullptr ? frame_sym_ctx.block->GetDeclContext()
+ : CompilerDeclContext();
+
+ // We can't do this without a compiler decl context for our frame.
+ if (frame_decl_context) {
+ sc_list = SearchFunctionsInSymbolContexts(sc_list, frame_decl_context);
+ }
+ }
+
+ if (sc_list.GetSize()) {
+ Symbol *extern_symbol = nullptr;
+ Symbol *non_extern_symbol = nullptr;
+
+ for (const SymbolContext &sym_ctx : sc_list) {
+ if (sym_ctx.function) {
+ CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext();
+
+ if (!decl_ctx)
+ continue;
+
+ // Filter out class/instance methods.
+ if (decl_ctx.IsClassMethod())
+ continue;
+
+ AddOneFunction(context, sym_ctx.function, nullptr);
+ context.m_found_function_with_type_info = true;
+ } else if (sym_ctx.symbol) {
+ Symbol *symbol = sym_ctx.symbol;
+ if (target && symbol->GetType() == eSymbolTypeReExported) {
+ symbol = symbol->ResolveReExportedSymbol(*target);
+ if (symbol == nullptr)
+ continue;
+ }
+
+ if (symbol->IsExternal())
+ extern_symbol = symbol;
+ else
+ non_extern_symbol = symbol;
+ }
+ }
+
+ if (!context.m_found_function_with_type_info) {
+ for (clang::NamedDecl *decl : decls_from_modules) {
+ if (llvm::isa<clang::FunctionDecl>(decl)) {
+ clang::NamedDecl *copied_decl =
+ llvm::cast_or_null<FunctionDecl>(CopyDecl(decl));
+ if (copied_decl) {
+ context.AddNamedDecl(copied_decl);
+ context.m_found_function_with_type_info = true;
+ }
+ }
+ }
+ }
+
+ if (!context.m_found_function_with_type_info) {
+ if (extern_symbol) {
+ AddOneFunction(context, nullptr, extern_symbol);
+ } else if (non_extern_symbol) {
+ AddOneFunction(context, nullptr, non_extern_symbol);
+ }
+ }
+ }
+}
+
+void ClangExpressionDeclMap::FindExternalVisibleDecls(
+ NameSearchContext &context, lldb::ModuleSP module_sp,
+ const CompilerDeclContext &namespace_decl) {
+ assert(m_ast_context);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+ if (IgnoreName(name, false))
+ return;
+
+ // Only look for functions by name out in our symbols if the function doesn't
+ // start with our phony prefix of '$'
+
+ Target *target = nullptr;
+ StackFrame *frame = nullptr;
+ SymbolContext sym_ctx;
+ if (m_parser_vars) {
+ target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+ frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+ }
+ if (frame != nullptr)
+ sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
+ lldb::eSymbolContextBlock);
+
+ // Try the persistent decls, which take precedence over all else.
+ if (!namespace_decl)
+ SearchPersistenDecls(context, name);
+
+ if (name.GetStringRef().starts_with("$") && !namespace_decl) {
+ if (name == "$__lldb_class") {
+ LookUpLldbClass(context);
+ return;
+ }
+
+ if (name == "$__lldb_objc_class") {
+ LookUpLldbObjCClass(context);
+ return;
+ }
+ if (name == g_lldb_local_vars_namespace_cstr) {
+ LookupLocalVarNamespace(sym_ctx, context);
+ return;
+ }
+
+ // any other $__lldb names should be weeded out now
+ if (name.GetStringRef().starts_with("$__lldb"))
+ return;
+
+ // No ParserVars means we can't do register or variable lookup.
+ if (!m_parser_vars || !m_parser_vars->m_persistent_vars)
+ return;
+
+ ExpressionVariableSP pvar_sp(
+ m_parser_vars->m_persistent_vars->GetVariable(name));
+
+ if (pvar_sp) {
+ AddOneVariable(context, pvar_sp);
+ return;
+ }
+
+ assert(name.GetStringRef().starts_with("$"));
+ llvm::StringRef reg_name = name.GetStringRef().substr(1);
+
+ if (m_parser_vars->m_exe_ctx.GetRegisterContext()) {
+ const RegisterInfo *reg_info(
+ m_parser_vars->m_exe_ctx.GetRegisterContext()->GetRegisterInfoByName(
+ reg_name));
+
+ if (reg_info) {
+ LLDB_LOG(log, " CEDM::FEVD Found register {0}", reg_info->name);
+
+ AddOneRegister(context, reg_info);
+ }
+ }
+ return;
+ }
+
+ bool local_var_lookup = !namespace_decl || (namespace_decl.GetName() ==
+ g_lldb_local_vars_namespace_cstr);
+ if (frame && local_var_lookup)
+ if (LookupLocalVariable(context, name, sym_ctx, namespace_decl))
+ return;
+
+ if (target) {
+ ValueObjectSP valobj;
+ VariableSP var;
+ var = FindGlobalVariable(*target, module_sp, name, namespace_decl);
+
+ if (var) {
+ valobj = ValueObjectVariable::Create(target, var);
+ AddOneVariable(context, var, valobj);
+ context.m_found_variable = true;
+ return;
+ }
+ }
+
+ LookupFunction(context, module_sp, name, namespace_decl);
+
+ // Try the modules next.
+ if (!context.m_found_function_with_type_info)
+ LookupInModulesDeclVendor(context, name);
+
+ if (target && !context.m_found_variable && !namespace_decl) {
+ // We couldn't find a non-symbol variable for this. Now we'll hunt for a
+ // generic data symbol, and -- if it is found -- treat it as a variable.
+ Status error;
+
+ const Symbol *data_symbol =
+ m_parser_vars->m_sym_ctx.FindBestGlobalDataSymbol(name, error);
+
+ if (!error.Success()) {
+ const unsigned diag_id =
+ m_ast_context->getDiagnostics().getCustomDiagID(
+ clang::DiagnosticsEngine::Level::Error, "%0");
+ m_ast_context->getDiagnostics().Report(diag_id) << error.AsCString();
+ }
+
+ if (data_symbol) {
+ std::string warning("got name from symbols: ");
+ warning.append(name.AsCString());
+ const unsigned diag_id =
+ m_ast_context->getDiagnostics().getCustomDiagID(
+ clang::DiagnosticsEngine::Level::Warning, "%0");
+ m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str();
+ AddOneGenericVariable(context, *data_symbol);
+ context.m_found_variable = true;
+ }
+ }
+}
+
+bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var,
+ lldb_private::Value &var_location,
+ TypeFromUser *user_type,
+ TypeFromParser *parser_type) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ Type *var_type = var->GetType();
+
+ if (!var_type) {
+ LLDB_LOG(log, "Skipped a definition because it has no type");
+ return false;
+ }
+
+ CompilerType var_clang_type = var_type->GetFullCompilerType();
+
+ if (!var_clang_type) {
+ LLDB_LOG(log, "Skipped a definition because it has no Clang type");
+ return false;
+ }
+
+ auto ts = var_type->GetForwardCompilerType().GetTypeSystem();
+ auto clang_ast = ts.dyn_cast_or_null<TypeSystemClang>();
+
+ if (!clang_ast) {
+ LLDB_LOG(log, "Skipped a definition because it has no Clang AST");
+ return false;
+ }
+
+ DWARFExpressionList &var_location_list = var->LocationExpressionList();
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+ Status err;
+
+ if (var->GetLocationIsConstantValueData()) {
+ DataExtractor const_value_extractor;
+ if (var_location_list.GetExpressionData(const_value_extractor)) {
+ var_location = Value(const_value_extractor.GetDataStart(),
+ const_value_extractor.GetByteSize());
+ var_location.SetValueType(Value::ValueType::HostAddress);
+ } else {
+ LLDB_LOG(log, "Error evaluating constant variable: {0}", err.AsCString());
+ return false;
+ }
+ }
+
+ CompilerType type_to_use = GuardedCopyType(var_clang_type);
+
+ if (!type_to_use) {
+ LLDB_LOG(log,
+ "Couldn't copy a variable's type into the parser's AST context");
+
+ return false;
+ }
+
+ if (parser_type)
+ *parser_type = TypeFromParser(type_to_use);
+
+ if (var_location.GetContextType() == Value::ContextType::Invalid)
+ var_location.SetCompilerType(type_to_use);
+
+ if (var_location.GetValueType() == Value::ValueType::FileAddress) {
+ SymbolContext var_sc;
+ var->CalculateSymbolContext(&var_sc);
+
+ if (!var_sc.module_sp)
+ return false;
+
+ Address so_addr(var_location.GetScalar().ULongLong(),
+ var_sc.module_sp->GetSectionList());
+
+ lldb::addr_t load_addr = so_addr.GetLoadAddress(target);
+
+ if (load_addr != LLDB_INVALID_ADDRESS) {
+ var_location.GetScalar() = load_addr;
+ var_location.SetValueType(Value::ValueType::LoadAddress);
+ }
+ }
+
+ if (user_type)
+ *user_type = TypeFromUser(var_clang_type);
+
+ return true;
+}
+
+ClangExpressionVariable::ParserVars *
+ClangExpressionDeclMap::AddExpressionVariable(NameSearchContext &context,
+ TypeFromParser const &pt,
+ ValueObjectSP valobj) {
+ clang::QualType parser_opaque_type =
+ QualType::getFromOpaquePtr(pt.GetOpaqueQualType());
+
+ if (parser_opaque_type.isNull())
+ return nullptr;
+
+ if (const clang::Type *parser_type = parser_opaque_type.getTypePtr()) {
+ if (const TagType *tag_type = dyn_cast<TagType>(parser_type))
+ CompleteType(tag_type->getDecl());
+ if (const ObjCObjectPointerType *objc_object_ptr_type =
+ dyn_cast<ObjCObjectPointerType>(parser_type))
+ CompleteType(objc_object_ptr_type->getInterfaceDecl());
+ }
+
+ bool is_reference = pt.IsReferenceType();
+
+ NamedDecl *var_decl = nullptr;
+ if (is_reference)
+ var_decl = context.AddVarDecl(pt);
+ else
+ var_decl = context.AddVarDecl(pt.GetLValueReferenceType());
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ ConstString entity_name(decl_name.c_str());
+ ClangExpressionVariable *entity(new ClangExpressionVariable(valobj));
+ m_found_entities.AddNewlyConstructedVariable(entity);
+
+ assert(entity);
+ entity->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars =
+ entity->GetParserVars(GetParserID());
+
+ parser_vars->m_named_decl = var_decl;
+
+ if (is_reference)
+ entity->m_flags |= ClangExpressionVariable::EVTypeIsReference;
+
+ return parser_vars;
+}
+
+void ClangExpressionDeclMap::AddOneVariable(
+ NameSearchContext &context, ValueObjectSP valobj,
+ ValueObjectProviderTy valobj_provider) {
+ assert(m_parser_vars.get());
+ assert(valobj);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ Value var_location = valobj->GetValue();
+
+ TypeFromUser user_type = valobj->GetCompilerType();
+
+ auto clang_ast =
+ user_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+
+ if (!clang_ast) {
+ LLDB_LOG(log, "Skipped a definition because it has no Clang AST");
+ return;
+ }
+
+ TypeFromParser parser_type = GuardedCopyType(user_type);
+
+ if (!parser_type) {
+ LLDB_LOG(log,
+ "Couldn't copy a variable's type into the parser's AST context");
+
+ return;
+ }
+
+ if (var_location.GetContextType() == Value::ContextType::Invalid)
+ var_location.SetCompilerType(parser_type);
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ AddExpressionVariable(context, parser_type, valobj);
+
+ if (!parser_vars)
+ return;
+
+ LLDB_LOG(log, " CEDM::FEVD Found variable {0}, returned\n{1} (original {2})",
+ context.m_decl_name, ClangUtil::DumpDecl(parser_vars->m_named_decl),
+ ClangUtil::ToString(user_type));
+
+ parser_vars->m_llvm_value = nullptr;
+ parser_vars->m_lldb_value = std::move(var_location);
+ parser_vars->m_lldb_valobj_provider = std::move(valobj_provider);
+}
+
+void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
+ VariableSP var,
+ ValueObjectSP valobj) {
+ assert(m_parser_vars.get());
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ TypeFromUser ut;
+ TypeFromParser pt;
+ Value var_location;
+
+ if (!GetVariableValue(var, var_location, &ut, &pt))
+ return;
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ AddExpressionVariable(context, pt, std::move(valobj));
+
+ if (!parser_vars)
+ return;
+
+ LLDB_LOG(log, " CEDM::FEVD Found variable {0}, returned\n{1} (original {2})",
+ context.m_decl_name, ClangUtil::DumpDecl(parser_vars->m_named_decl),
+ ClangUtil::ToString(ut));
+
+ parser_vars->m_llvm_value = nullptr;
+ parser_vars->m_lldb_value = var_location;
+ parser_vars->m_lldb_var = var;
+}
+
+void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
+ ExpressionVariableSP &pvar_sp) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ TypeFromUser user_type(
+ llvm::cast<ClangExpressionVariable>(pvar_sp.get())->GetTypeFromUser());
+
+ TypeFromParser parser_type(GuardedCopyType(user_type));
+
+ if (!parser_type.GetOpaqueQualType()) {
+ LLDB_LOG(log, " CEDM::FEVD Couldn't import type for pvar {0}",
+ pvar_sp->GetName());
+ return;
+ }
+
+ NamedDecl *var_decl =
+ context.AddVarDecl(parser_type.GetLValueReferenceType());
+
+ llvm::cast<ClangExpressionVariable>(pvar_sp.get())
+ ->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars =
+ llvm::cast<ClangExpressionVariable>(pvar_sp.get())
+ ->GetParserVars(GetParserID());
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = nullptr;
+ parser_vars->m_lldb_value.Clear();
+
+ LLDB_LOG(log, " CEDM::FEVD Added pvar {0}, returned\n{1}",
+ pvar_sp->GetName(), ClangUtil::DumpDecl(var_decl));
+}
+
+void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
+ const Symbol &symbol) {
+ assert(m_parser_vars.get());
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ if (target == nullptr)
+ return;
+
+ auto scratch_ast_context = GetScratchContext(*target);
+ if (!scratch_ast_context)
+ return;
+
+ TypeFromUser user_type(scratch_ast_context->GetBasicType(eBasicTypeVoid)
+ .GetPointerType()
+ .GetLValueReferenceType());
+ TypeFromParser parser_type(m_clang_ast_context->GetBasicType(eBasicTypeVoid)
+ .GetPointerType()
+ .GetLValueReferenceType());
+ NamedDecl *var_decl = context.AddVarDecl(parser_type);
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ ConstString entity_name(decl_name.c_str());
+ ClangExpressionVariable *entity(new ClangExpressionVariable(
+ m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), entity_name,
+ user_type, m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
+ m_found_entities.AddNewlyConstructedVariable(entity);
+
+ entity->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars =
+ entity->GetParserVars(GetParserID());
+
+ const Address symbol_address = symbol.GetAddress();
+ lldb::addr_t symbol_load_addr = symbol_address.GetLoadAddress(target);
+
+ // parser_vars->m_lldb_value.SetContext(Value::ContextType::ClangType,
+ // user_type.GetOpaqueQualType());
+ parser_vars->m_lldb_value.SetCompilerType(user_type);
+ parser_vars->m_lldb_value.GetScalar() = symbol_load_addr;
+ parser_vars->m_lldb_value.SetValueType(Value::ValueType::LoadAddress);
+
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = nullptr;
+ parser_vars->m_lldb_sym = &symbol;
+
+ LLDB_LOG(log, " CEDM::FEVD Found variable {0}, returned\n{1}", decl_name,
+ ClangUtil::DumpDecl(var_decl));
+}
+
+void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context,
+ const RegisterInfo *reg_info) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ CompilerType clang_type =
+ m_clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(
+ reg_info->encoding, reg_info->byte_size * 8);
+
+ if (!clang_type) {
+ LLDB_LOG(log, " Tried to add a type for {0}, but couldn't get one",
+ context.m_decl_name.getAsString());
+ return;
+ }
+
+ TypeFromParser parser_clang_type(clang_type);
+
+ NamedDecl *var_decl = context.AddVarDecl(parser_clang_type);
+
+ ClangExpressionVariable *entity(new ClangExpressionVariable(
+ m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(),
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
+ m_found_entities.AddNewlyConstructedVariable(entity);
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ entity->SetName(ConstString(decl_name.c_str()));
+ entity->SetRegisterInfo(reg_info);
+ entity->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars =
+ entity->GetParserVars(GetParserID());
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = nullptr;
+ parser_vars->m_lldb_value.Clear();
+ entity->m_flags |= ClangExpressionVariable::EVBareRegister;
+
+ LLDB_LOG(log, " CEDM::FEVD Added register {0}, returned\n{1}",
+ context.m_decl_name.getAsString(), ClangUtil::DumpDecl(var_decl));
+}
+
+void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context,
+ Function *function,
+ Symbol *symbol) {
+ assert(m_parser_vars.get());
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ NamedDecl *function_decl = nullptr;
+ Address fun_address;
+ CompilerType function_clang_type;
+
+ bool is_indirect_function = false;
+
+ if (function) {
+ Type *function_type = function->GetType();
+
+ const auto lang = function->GetCompileUnit()->GetLanguage();
+ const auto name = function->GetMangled().GetMangledName().AsCString();
+ const bool extern_c = (Language::LanguageIsC(lang) &&
+ !CPlusPlusLanguage::IsCPPMangledName(name)) ||
+ (Language::LanguageIsObjC(lang) &&
+ !Language::LanguageIsCPlusPlus(lang));
+
+ if (!extern_c) {
+ TypeSystem *type_system = function->GetDeclContext().GetTypeSystem();
+ if (llvm::isa<TypeSystemClang>(type_system)) {
+ clang::DeclContext *src_decl_context =
+ (clang::DeclContext *)function->GetDeclContext()
+ .GetOpaqueDeclContext();
+ clang::FunctionDecl *src_function_decl =
+ llvm::dyn_cast_or_null<clang::FunctionDecl>(src_decl_context);
+ if (src_function_decl &&
+ src_function_decl->getTemplateSpecializationInfo()) {
+ clang::FunctionTemplateDecl *function_template =
+ src_function_decl->getTemplateSpecializationInfo()->getTemplate();
+ clang::FunctionTemplateDecl *copied_function_template =
+ llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
+ CopyDecl(function_template));
+ if (copied_function_template) {
+ if (log) {
+ StreamString ss;
+
+ function->DumpSymbolContext(&ss);
+
+ LLDB_LOG(log,
+ " CEDM::FEVD Imported decl for function template"
+ " {0} (description {1}), returned\n{2}",
+ copied_function_template->getNameAsString(),
+ ss.GetData(),
+ ClangUtil::DumpDecl(copied_function_template));
+ }
+
+ context.AddNamedDecl(copied_function_template);
+ }
+ } else if (src_function_decl) {
+ if (clang::FunctionDecl *copied_function_decl =
+ llvm::dyn_cast_or_null<clang::FunctionDecl>(
+ CopyDecl(src_function_decl))) {
+ if (log) {
+ StreamString ss;
+
+ function->DumpSymbolContext(&ss);
+
+ LLDB_LOG(log,
+ " CEDM::FEVD Imported decl for function {0} "
+ "(description {1}), returned\n{2}",
+ copied_function_decl->getNameAsString(), ss.GetData(),
+ ClangUtil::DumpDecl(copied_function_decl));
+ }
+
+ context.AddNamedDecl(copied_function_decl);
+ return;
+ } else {
+ LLDB_LOG(log, " Failed to import the function decl for '{0}'",
+ src_function_decl->getName());
+ }
+ }
+ }
+ }
+
+ if (!function_type) {
+ LLDB_LOG(log, " Skipped a function because it has no type");
+ return;
+ }
+
+ function_clang_type = function_type->GetFullCompilerType();
+
+ if (!function_clang_type) {
+ LLDB_LOG(log, " Skipped a function because it has no Clang type");
+ return;
+ }
+
+ fun_address = function->GetAddressRange().GetBaseAddress();
+
+ CompilerType copied_function_type = GuardedCopyType(function_clang_type);
+ if (copied_function_type) {
+ function_decl = context.AddFunDecl(copied_function_type, extern_c);
+
+ if (!function_decl) {
+ LLDB_LOG(log, " Failed to create a function decl for '{0}' ({1:x})",
+ function_type->GetName(), function_type->GetID());
+
+ return;
+ }
+ } else {
+ // We failed to copy the type we found
+ LLDB_LOG(log,
+ " Failed to import the function type '{0}' ({1:x})"
+ " into the expression parser AST context",
+ function_type->GetName(), function_type->GetID());
+
+ return;
+ }
+ } else if (symbol) {
+ fun_address = symbol->GetAddress();
+ function_decl = context.AddGenericFunDecl();
+ is_indirect_function = symbol->IsIndirect();
+ } else {
+ LLDB_LOG(log, " AddOneFunction called with no function and no symbol");
+ return;
+ }
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ lldb::addr_t load_addr =
+ fun_address.GetCallableLoadAddress(target, is_indirect_function);
+
+ ClangExpressionVariable *entity(new ClangExpressionVariable(
+ m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(),
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
+ m_found_entities.AddNewlyConstructedVariable(entity);
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ entity->SetName(ConstString(decl_name.c_str()));
+ entity->SetCompilerType(function_clang_type);
+ entity->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars =
+ entity->GetParserVars(GetParserID());
+
+ if (load_addr != LLDB_INVALID_ADDRESS) {
+ parser_vars->m_lldb_value.SetValueType(Value::ValueType::LoadAddress);
+ parser_vars->m_lldb_value.GetScalar() = load_addr;
+ } else {
+ // We have to try finding a file address.
+
+ lldb::addr_t file_addr = fun_address.GetFileAddress();
+
+ parser_vars->m_lldb_value.SetValueType(Value::ValueType::FileAddress);
+ parser_vars->m_lldb_value.GetScalar() = file_addr;
+ }
+
+ parser_vars->m_named_decl = function_decl;
+ parser_vars->m_llvm_value = nullptr;
+
+ if (log) {
+ StreamString ss;
+
+ fun_address.Dump(&ss,
+ m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(),
+ Address::DumpStyleResolvedDescription);
+
+ LLDB_LOG(log,
+ " CEDM::FEVD Found {0} function {1} (description {2}), "
+ "returned\n{3}",
+ (function ? "specific" : "generic"), decl_name, ss.GetData(),
+ ClangUtil::DumpDecl(function_decl));
+ }
+}
+
+void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
+ const TypeFromUser &ut) {
+ CompilerType copied_clang_type = GuardedCopyType(ut);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (!copied_clang_type) {
+ LLDB_LOG(log,
+ "ClangExpressionDeclMap::AddThisType - Couldn't import the type");
+
+ return;
+ }
+
+ if (copied_clang_type.IsAggregateType() &&
+ copied_clang_type.GetCompleteType()) {
+ CompilerType void_clang_type =
+ m_clang_ast_context->GetBasicType(eBasicTypeVoid);
+ CompilerType void_ptr_clang_type = void_clang_type.GetPointerType();
+
+ CompilerType method_type = m_clang_ast_context->CreateFunctionType(
+ void_clang_type, &void_ptr_clang_type, 1, false, 0);
+
+ const bool is_virtual = false;
+ const bool is_static = false;
+ const bool is_inline = false;
+ const bool is_explicit = false;
+ const bool is_attr_used = true;
+ const bool is_artificial = false;
+
+ CXXMethodDecl *method_decl = m_clang_ast_context->AddMethodToCXXRecordType(
+ copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr,
+ method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline,
+ is_explicit, is_attr_used, is_artificial);
+
+ LLDB_LOG(log,
+ " CEDM::AddThisType Added function $__lldb_expr "
+ "(description {0}) for this type\n{1}",
+ ClangUtil::ToString(copied_clang_type),
+ ClangUtil::DumpDecl(method_decl));
+ }
+
+ if (!copied_clang_type.IsValid())
+ return;
+
+ TypeSourceInfo *type_source_info = m_ast_context->getTrivialTypeSourceInfo(
+ QualType::getFromOpaquePtr(copied_clang_type.GetOpaqueQualType()));
+
+ if (!type_source_info)
+ return;
+
+ // Construct a typedef type because if "*this" is a templated type we can't
+ // just return ClassTemplateSpecializationDecls in response to name queries.
+ // Using a typedef makes this much more robust.
+
+ TypedefDecl *typedef_decl = TypedefDecl::Create(
+ *m_ast_context, m_ast_context->getTranslationUnitDecl(), SourceLocation(),
+ SourceLocation(), context.m_decl_name.getAsIdentifierInfo(),
+ type_source_info);
+
+ if (!typedef_decl)
+ return;
+
+ context.AddNamedDecl(typedef_decl);
+}
+
+void ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
+ const TypeFromUser &ut) {
+ CompilerType copied_clang_type = GuardedCopyType(ut);
+
+ if (!copied_clang_type) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOG(log,
+ "ClangExpressionDeclMap::AddOneType - Couldn't import the type");
+
+ return;
+ }
+
+ context.AddTypeDecl(copied_clang_type);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
new file mode 100644
index 000000000000..d8d519693f10
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -0,0 +1,663 @@
+//===-- ClangExpressionDeclMap.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H
+
+#include <csignal>
+#include <cstdint>
+
+#include <memory>
+#include <vector>
+
+#include "ClangASTSource.h"
+#include "ClangExpressionVariable.h"
+
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/lldb-public.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace lldb_private {
+
+class ClangPersistentVariables;
+
+/// \class ClangExpressionDeclMap ClangExpressionDeclMap.h
+/// "lldb/Expression/ClangExpressionDeclMap.h" Manages named entities that are
+/// defined in LLDB's debug information.
+///
+/// The Clang parser uses the ClangASTSource as an interface to request named
+/// entities from outside an expression. The ClangASTSource reports back,
+/// listing all possible objects corresponding to a particular name. But it
+/// in turn relies on ClangExpressionDeclMap, which performs several important
+/// functions.
+///
+/// First, it records what variables and functions were looked up and what
+/// Decls were returned for them.
+///
+/// Second, it constructs a struct on behalf of IRForTarget, recording which
+/// variables should be placed where and relaying this information back so
+/// that IRForTarget can generate context-independent code.
+///
+/// Third, it "materializes" this struct on behalf of the expression command,
+/// finding the current values of each variable and placing them into the
+/// struct so that it can be passed to the JITted version of the IR.
+///
+/// Fourth and finally, it "dematerializes" the struct after the JITted code
+/// 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
+ /// If true, inhibits the normal deallocation of the memory for
+ /// the result persistent variable, and instead marks the variable
+ /// as persisting.
+ ///
+ /// \param[in] result_delegate
+ /// If non-NULL, use this delegate to report result values. This
+ /// allows the client ClangUserExpression to report a result.
+ ///
+ /// \param[in] target
+ /// The target to use when parsing.
+ ///
+ /// \param[in] importer
+ /// The ClangASTImporter 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,
+ const lldb::TargetSP &target,
+ const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj);
+
+ /// Destructor
+ ~ClangExpressionDeclMap() override;
+
+ /// Enable the state needed for parsing and IR transformation.
+ ///
+ /// \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
+ /// If non-NULL, the materializer to populate with information about
+ /// the variables to use
+ ///
+ /// \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);
+
+ void InstallDiagnosticManager(DiagnosticManager &diag_manager);
+
+ /// 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
+ /// The Clang declaration for the persistent variable, used for
+ /// lookup during parsing.
+ ///
+ /// \param[in] name
+ /// The name of the persistent variable, usually $something.
+ ///
+ /// \param[in] type
+ /// The type of the variable, in the Clang parser's context.
+ ///
+ /// \return
+ /// True on success; false otherwise.
+ bool AddPersistentVariable(const clang::NamedDecl *decl,
+ 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
+ /// The Clang declaration for the variable.
+ ///
+ /// \param[in] name
+ /// The name of the variable.
+ ///
+ /// \param[in] value
+ /// The LLVM IR value for this variable.
+ ///
+ /// \param[in] size
+ /// The size of the variable in bytes.
+ ///
+ /// \param[in] alignment
+ /// The required alignment of the variable in bytes.
+ ///
+ /// \return
+ /// True on success; false otherwise.
+ 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
+ /// 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
+ /// The number of elements in the struct.
+ ///
+ /// \param[out] size
+ /// The size of the struct, in bytes.
+ ///
+ /// \param[out] alignment
+ /// The alignment of the struct, in bytes.
+ ///
+ /// \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
+ /// 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
+ /// 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
+ /// 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
+ /// The name of the field as used in materialization.
+ ///
+ /// \param[in] index
+ /// The index of the field about which information is requested.
+ ///
+ /// \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
+ /// The parsed Decl for the Function, as generated by ClangASTSource
+ /// on ClangExpressionDeclMap's behalf.
+ ///
+ /// \param[out] ptr
+ /// The absolute address of the function in the target.
+ ///
+ /// \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
+ /// The target to find the symbol in. If not provided,
+ /// then the current parsing context's Target.
+ ///
+ /// \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
+ /// The name of the symbol.
+ ///
+ /// \param[in] module
+ /// The module to limit the search to. This can be NULL
+ ///
+ /// \return
+ /// Valid load address for the symbol
+ lldb::addr_t GetSymbolAddress(Target &target, Process *process,
+ ConstString name, lldb::SymbolType symbol_type,
+ Module *module = nullptr);
+
+ lldb::addr_t GetSymbolAddress(ConstString name,
+ lldb::SymbolType symbol_type);
+
+ struct TargetInfo {
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
+ size_t address_byte_size = 0;
+
+ TargetInfo() = default;
+
+ bool IsValid() {
+ return (byte_order != lldb::eByteOrderInvalid && address_byte_size != 0);
+ }
+ };
+ TargetInfo GetTargetInfo();
+
+ /// [Used by ClangASTSource] Find all entities matching a given name, using
+ /// a NameSearchContext to make Decls for them.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ 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
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// \param[in] module
+ /// If non-NULL, the module to query.
+ ///
+ /// \param[in] namespace_decl
+ /// If valid and module is non-NULL, the parent namespace.
+ void FindExternalVisibleDecls(NameSearchContext &context,
+ lldb::ModuleSP module,
+ const CompilerDeclContext &namespace_decl);
+
+protected:
+ /// Retrieves the declaration with the given name from the storage of
+ /// persistent declarations.
+ ///
+ /// \return
+ /// A persistent decl with the given name or a nullptr.
+ virtual clang::NamedDecl *GetPersistentDecl(ConstString name);
+
+private:
+ ExpressionVariableList
+ m_found_entities; ///< All entities that were looked up for the parser.
+ ExpressionVariableList
+ m_struct_members; ///< All entities that need to be placed in the struct.
+ bool m_keep_result_in_memory; ///< True if result persistent variables
+ ///generated by this expression should stay in
+ ///memory.
+ 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() = default;
+
+ Target *GetTarget() {
+ if (m_exe_ctx.GetTargetPtr())
+ return m_exe_ctx.GetTargetPtr();
+ else if (m_sym_ctx.target_sp)
+ return m_sym_ctx.target_sp.get();
+ return nullptr;
+ }
+
+ ExecutionContext m_exe_ctx; ///< The execution context to use when parsing.
+ SymbolContext m_sym_ctx; ///< The symbol context to use in finding variables
+ ///and types.
+ ClangPersistentVariables *m_persistent_vars =
+ nullptr; ///< The persistent variables for the process.
+ bool m_enable_lookups = false; ///< Set to true during parsing if we have
+ ///found the first "$__lldb" name.
+ TargetInfo m_target_info; ///< Basic information about the target.
+ Materializer *m_materializer = nullptr; ///< If non-NULL, the materializer
+ ///to use when reporting used
+ ///variables.
+ clang::ASTConsumer *m_code_gen = nullptr; ///< If non-NULL, a code generator
+ ///that receives new top-level
+ ///functions.
+ DiagnosticManager *m_diagnostics = nullptr;
+
+ private:
+ ParserVars(const ParserVars &) = delete;
+ const ParserVars &operator=(const ParserVars &) = delete;
+ };
+
+ std::unique_ptr<ParserVars> m_parser_vars;
+
+ /// Activate parser-specific variables
+ void EnableParserVars() {
+ if (!m_parser_vars.get())
+ m_parser_vars = std::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() = default;
+
+ lldb::offset_t m_struct_alignment =
+ 0; ///< The alignment of the struct in bytes.
+ size_t m_struct_size = 0; ///< The size of the struct in bytes.
+ bool m_struct_laid_out =
+ false; ///< True if the struct has been laid out and the
+ /// layout is valid (that is, no new fields have been
+ /// added since).
+ ConstString
+ m_result_name; ///< The name of the result variable ($1, for example)
+ };
+
+ 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(); }
+
+ lldb::TypeSystemClangSP GetScratchContext(Target &target) {
+ return ScratchTypeSystemClang::GetForTarget(target,
+ m_ast_context->getLangOpts());
+ }
+
+ /// Get this parser's ID for use in extracting parser- and JIT-specific data
+ /// from persistent variables.
+ uint64_t GetParserID() { return (uint64_t) this; }
+
+ /// Should be called on all copied functions.
+ void MaybeRegisterFunctionBody(clang::FunctionDecl *copied_function_decl);
+
+ /// Searches the persistent decls of the target for entities with the
+ /// given name.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// \param[in] name
+ /// The name of the entities that need to be found.
+ void SearchPersistenDecls(NameSearchContext &context, const ConstString name);
+
+ /// Handles looking up $__lldb_class which requires special treatment.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ void LookUpLldbClass(NameSearchContext &context);
+
+ /// Handles looking up $__lldb_objc_class which requires special treatment.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ void LookUpLldbObjCClass(NameSearchContext &context);
+
+ /// Handles looking up the synthetic namespace that contains our local
+ /// variables for the current frame.
+ ///
+ /// \param[in] sym_ctx
+ /// The current SymbolContext of this frame.
+ ///
+ /// \param[in] name_context
+ /// The NameSearchContext that can construct Decls for this name.
+ void LookupLocalVarNamespace(SymbolContext &sym_ctx,
+ NameSearchContext &name_context);
+
+ /// Lookup entities in the ClangModulesDeclVendor.
+ /// \param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// \param[in] name
+ /// The name of the entities that need to be found.
+ void LookupInModulesDeclVendor(NameSearchContext &context, ConstString name);
+
+ /// Looks up a local variable.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// \param[in] name
+ /// The name of the entities that need to be found.
+ ///
+ /// \param[in] sym_ctx
+ /// The current SymbolContext of this frame.
+ ///
+ /// \param[in] namespace_decl
+ /// The parent namespace if there is one.
+ ///
+ /// \return
+ /// True iff a local variable was found.
+ bool LookupLocalVariable(NameSearchContext &context, ConstString name,
+ SymbolContext &sym_ctx,
+ const CompilerDeclContext &namespace_decl);
+
+ /// Searches for functions in the given SymbolContextList.
+ ///
+ /// \param[in] sc_list
+ /// The SymbolContextList to search.
+ ///
+ /// \param[in] frame_decl_context
+ /// The current DeclContext of the current frame.
+ ///
+ /// \return
+ /// A SymbolContextList with any found functions in the front and
+ /// any unknown SymbolContexts which are not functions in the back.
+ /// The SymbolContexts for the functions are ordered by how close they are
+ /// to the DeclContext for the given frame DeclContext.
+ SymbolContextList SearchFunctionsInSymbolContexts(
+ const SymbolContextList &sc_list,
+ const CompilerDeclContext &frame_decl_context);
+
+ /// Looks up a function.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// \param[in] module_sp
+ /// If non-NULL, the module to query.
+ ///
+ /// \param[in] name
+ /// The name of the function that should be find.
+ ///
+ /// \param[in] namespace_decl
+ /// If valid and module is non-NULL, the parent namespace.
+ void LookupFunction(NameSearchContext &context, lldb::ModuleSP module_sp,
+ ConstString name,
+ const CompilerDeclContext &namespace_decl);
+
+ /// Given a target, find a variable that matches the given name and type.
+ ///
+ /// \param[in] target
+ /// The target to use as a basis for finding the variable.
+ ///
+ /// \param[in] module
+ /// If non-NULL, the module to search.
+ ///
+ /// \param[in] name
+ /// The name as a plain C string.
+ ///
+ /// \param[in] namespace_decl
+ /// If non-NULL and module is non-NULL, the parent namespace.
+ ///
+ /// \return
+ /// The LLDB Variable found, or NULL if none was found.
+ lldb::VariableSP
+ FindGlobalVariable(Target &target, lldb::ModuleSP &module, ConstString name,
+ const CompilerDeclContext &namespace_decl);
+
+ /// Get the value of a variable in a given execution context and return the
+ /// associated Types if needed.
+ ///
+ /// \param[in] var
+ /// The variable to evaluate.
+ ///
+ /// \param[out] var_location
+ /// The variable location value to fill in
+ ///
+ /// \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
+ /// 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.
+ ///
+ /// \return
+ /// Return true if the value was successfully filled in.
+ bool GetVariableValue(lldb::VariableSP &var,
+ lldb_private::Value &var_location,
+ TypeFromUser *found_type = nullptr,
+ TypeFromParser *parser_type = nullptr);
+
+ /// Use the NameSearchContext to generate a Decl for the given LLDB
+ /// ValueObject, and put it in the list of found entities.
+ ///
+ /// Helper function used by the other AddOneVariable APIs.
+ ///
+ /// \param[in,out] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] pt
+ /// The CompilerType of the variable we're adding a Decl for.
+ ///
+ /// \param[in] var
+ /// The LLDB ValueObject that needs a Decl.
+ ClangExpressionVariable::ParserVars *
+ AddExpressionVariable(NameSearchContext &context, TypeFromParser const &pt,
+ lldb::ValueObjectSP valobj);
+
+ /// Use the NameSearchContext to generate a Decl for the given LLDB
+ /// Variable, and put it in the Tuple list.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] var
+ /// The LLDB Variable that needs a Decl.
+ ///
+ /// \param[in] valobj
+ /// The LLDB ValueObject for that variable.
+ void AddOneVariable(NameSearchContext &context, lldb::VariableSP var,
+ lldb::ValueObjectSP valobj);
+
+ /// Use the NameSearchContext to generate a Decl for the given ValueObject
+ /// and put it in the list of found entities.
+ ///
+ /// \param[in,out] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] valobj
+ /// The ValueObject that needs a Decl.
+ ///
+ /// \param[in] valobj_provider Callback that fetches a ValueObjectSP
+ /// from the specified frame
+ void AddOneVariable(NameSearchContext &context, lldb::ValueObjectSP valobj,
+ ValueObjectProviderTy valobj_provider);
+
+ /// Use the NameSearchContext to generate a Decl for the given persistent
+ /// variable, and put it in the list of found entities.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] pvar_sp
+ /// The persistent variable that needs a Decl.
+ void AddOneVariable(NameSearchContext &context,
+ lldb::ExpressionVariableSP &pvar_sp);
+
+ /// 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.
+ void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol);
+
+ /// 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
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] fun
+ /// The Function that needs to be created. If non-NULL, this is
+ /// a fully-typed function.
+ ///
+ /// \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);
+
+ /// Use the NameSearchContext to generate a Decl for the given register.
+ ///
+ /// \param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] reg_info
+ /// The information corresponding to that register.
+ void AddOneRegister(NameSearchContext &context, const RegisterInfo *reg_info);
+
+ /// Use the NameSearchContext to generate a Decl for the given type. (Types
+ /// are not placed in the Tuple list.)
+ ///
+ /// \param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// \param[in] type
+ /// The type that needs to be created.
+ void AddOneType(NameSearchContext &context, const TypeFromUser &type);
+
+ /// Adds the class in which the expression is evaluated to the lookup and
+ /// prepares the class to be used as a context for expression evaluation (for
+ /// example, it creates a fake member function that will contain the
+ /// expression LLDB is trying to evaluate).
+ ///
+ /// \param[in] context
+ /// The NameSearchContext to which the class should be added as a lookup
+ /// result.
+ ///
+ /// \param[in] type
+ /// The type of the class that serves as the evaluation context.
+ void AddContextClassType(NameSearchContext &context,
+ const TypeFromUser &type);
+
+ /// Move a type out of the current ASTContext into another, but make sure to
+ /// export all components of the type also.
+ ///
+ /// \param[in] target
+ /// The TypeSystemClang to move to.
+ /// \param[in] source
+ /// The TypeSystemClang to move from. This is assumed to be going away.
+ /// \param[in] parser_type
+ /// The type as it appears in the source context.
+ ///
+ /// \return
+ /// Returns the moved type, or an empty type if there was a problem.
+ TypeFromUser DeportType(TypeSystemClang &target, TypeSystemClang &source,
+ TypeFromParser parser_type);
+
+ TypeSystemClang *GetTypeSystemClang();
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.cpp
new file mode 100644
index 000000000000..97f9d17958fa
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.cpp
@@ -0,0 +1,13 @@
+//===-- ClangExpressionHelper.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionHelper.h"
+
+using namespace lldb_private;
+
+char ClangExpressionHelper::ID;
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h
new file mode 100644
index 000000000000..e66d46c21ddf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h
@@ -0,0 +1,54 @@
+//===-- ClangExpressionHelper.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "lldb/Expression/ExpressionTypeSystemHelper.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+
+namespace clang {
+class ASTConsumer;
+}
+
+namespace lldb_private {
+
+class ClangExpressionDeclMap;
+
+// ClangExpressionHelper
+class ClangExpressionHelper
+ : public llvm::RTTIExtends<ClangExpressionHelper,
+ ExpressionTypeSystemHelper> {
+public:
+ // LLVM RTTI support
+ static char ID;
+
+ /// 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
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ virtual clang::ASTConsumer *
+ ASTTransformer(clang::ASTConsumer *passthrough) = 0;
+
+ virtual void CommitPersistentDecls() {}
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
new file mode 100644
index 000000000000..303e88feea20
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -0,0 +1,1474 @@
+//===-- ClangExpressionParser.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditedSource.h"
+#include "clang/Edit/EditsReceiver.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaConsumer.h"
+
+#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"
+
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/TargetParser/Host.h"
+
+#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 "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Language.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/LLDBLog.h"
+#include "lldb/Utility/Log.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>
+#include <optional>
+
+using namespace clang;
+using namespace llvm;
+using namespace lldb_private;
+
+//===----------------------------------------------------------------------===//
+// Utility Methods for Clang
+//===----------------------------------------------------------------------===//
+
+class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks {
+ ClangModulesDeclVendor &m_decl_vendor;
+ ClangPersistentVariables &m_persistent_vars;
+ clang::SourceManager &m_source_mgr;
+ StreamString m_error_stream;
+ bool m_has_errors = false;
+
+public:
+ LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor,
+ ClangPersistentVariables &persistent_vars,
+ clang::SourceManager &source_mgr)
+ : m_decl_vendor(decl_vendor), m_persistent_vars(persistent_vars),
+ m_source_mgr(source_mgr) {}
+
+ void moduleImport(SourceLocation import_location, clang::ModuleIdPath path,
+ const clang::Module * /*null*/) override {
+ // Ignore modules that are imported in the wrapper code as these are not
+ // loaded by the user.
+ llvm::StringRef filename =
+ m_source_mgr.getPresumedLoc(import_location).getFilename();
+ if (filename == ClangExpressionSourceCode::g_prefix_file_name)
+ return;
+
+ SourceModule module;
+
+ 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(module, &exported_modules, m_error_stream))
+ m_has_errors = true;
+
+ for (ClangModulesDeclVendor::ModuleID module : exported_modules)
+ m_persistent_vars.AddHandLoadedClangModule(module);
+ }
+
+ bool hasErrors() { return m_has_errors; }
+
+ llvm::StringRef getErrorString() { return m_error_stream.GetString(); }
+};
+
+static void AddAllFixIts(ClangDiagnostic *diag, const clang::Diagnostic &Info) {
+ for (auto &fix_it : Info.getFixItHints()) {
+ if (fix_it.isNull())
+ continue;
+ diag->AddFixitHint(fix_it);
+ }
+}
+
+class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
+public:
+ ClangDiagnosticManagerAdapter(DiagnosticOptions &opts) {
+ DiagnosticOptions *options = new DiagnosticOptions(opts);
+ options->ShowPresumedLoc = true;
+ options->ShowLevel = false;
+ m_os = std::make_shared<llvm::raw_string_ostream>(m_output);
+ m_passthrough =
+ std::make_shared<clang::TextDiagnosticPrinter>(*m_os, options);
+ }
+
+ void ResetManager(DiagnosticManager *manager = nullptr) {
+ m_manager = manager;
+ }
+
+ /// Returns the last ClangDiagnostic message that the DiagnosticManager
+ /// received or a nullptr if the DiagnosticMangager hasn't seen any
+ /// Clang diagnostics yet.
+ ClangDiagnostic *MaybeGetLastClangDiag() const {
+ if (m_manager->Diagnostics().empty())
+ return nullptr;
+ lldb_private::Diagnostic *diag = m_manager->Diagnostics().back().get();
+ ClangDiagnostic *clang_diag = dyn_cast<ClangDiagnostic>(diag);
+ return clang_diag;
+ }
+
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info) override {
+ if (!m_manager) {
+ // We have no DiagnosticManager before/after parsing but we still could
+ // receive diagnostics (e.g., by the ASTImporter failing to copy decls
+ // when we move the expression result ot the ScratchASTContext). Let's at
+ // least log these diagnostics until we find a way to properly render
+ // them and display them to the user.
+ Log *log = GetLog(LLDBLog::Expressions);
+ if (log) {
+ llvm::SmallVector<char, 32> diag_str;
+ Info.FormatDiagnostic(diag_str);
+ diag_str.push_back('\0');
+ const char *plain_diag = diag_str.data();
+ LLDB_LOG(log, "Received diagnostic outside parsing: {0}", plain_diag);
+ }
+ return;
+ }
+
+ // Update error/warning counters.
+ DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
+
+ // Render diagnostic message to m_output.
+ m_output.clear();
+ m_passthrough->HandleDiagnostic(DiagLevel, Info);
+ m_os->flush();
+
+ lldb::Severity severity;
+ bool make_new_diagnostic = true;
+
+ switch (DiagLevel) {
+ case DiagnosticsEngine::Level::Fatal:
+ case DiagnosticsEngine::Level::Error:
+ severity = lldb::eSeverityError;
+ break;
+ case DiagnosticsEngine::Level::Warning:
+ severity = lldb::eSeverityWarning;
+ break;
+ case DiagnosticsEngine::Level::Remark:
+ case DiagnosticsEngine::Level::Ignored:
+ severity = lldb::eSeverityInfo;
+ break;
+ case DiagnosticsEngine::Level::Note:
+ m_manager->AppendMessageToDiagnostic(m_output);
+ make_new_diagnostic = false;
+
+ // 'note:' diagnostics for errors and warnings can also contain Fix-Its.
+ // We add these Fix-Its to the last error diagnostic to make sure
+ // that we later have all Fix-Its related to an 'error' diagnostic when
+ // we apply them to the user expression.
+ auto *clang_diag = MaybeGetLastClangDiag();
+ // If we don't have a previous diagnostic there is nothing to do.
+ // If the previous diagnostic already has its own Fix-Its, assume that
+ // the 'note:' Fix-It is just an alternative way to solve the issue and
+ // ignore these Fix-Its.
+ if (!clang_diag || clang_diag->HasFixIts())
+ break;
+ // Ignore all Fix-Its that are not associated with an error.
+ if (clang_diag->GetSeverity() != lldb::eSeverityError)
+ break;
+ AddAllFixIts(clang_diag, Info);
+ break;
+ }
+ if (make_new_diagnostic) {
+ // ClangDiagnostic messages are expected to have no whitespace/newlines
+ // around them.
+ std::string stripped_output =
+ std::string(llvm::StringRef(m_output).trim());
+
+ auto new_diagnostic = std::make_unique<ClangDiagnostic>(
+ stripped_output, severity, Info.getID());
+
+ // Don't store away warning fixits, since the compiler doesn't have
+ // enough context in an expression for the warning to be useful.
+ // FIXME: Should we try to filter out FixIts that apply to our generated
+ // code, and not the user's expression?
+ if (severity == lldb::eSeverityError)
+ AddAllFixIts(new_diagnostic.get(), Info);
+
+ m_manager->AddDiagnostic(std::move(new_diagnostic));
+ }
+ }
+
+ void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override {
+ m_passthrough->BeginSourceFile(LO, PP);
+ }
+
+ void EndSourceFile() override { m_passthrough->EndSourceFile(); }
+
+private:
+ DiagnosticManager *m_manager = nullptr;
+ std::shared_ptr<clang::TextDiagnosticPrinter> m_passthrough;
+ /// Output stream of m_passthrough.
+ std::shared_ptr<llvm::raw_string_ostream> m_os;
+ /// Output string filled by m_os.
+ std::string m_output;
+};
+
+static void SetupModuleHeaderPaths(CompilerInstance *compiler,
+ std::vector<std::string> include_directories,
+ lldb::TargetSP target_sp) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ HeaderSearchOptions &search_opts = compiler->getHeaderSearchOpts();
+
+ for (const std::string &dir : include_directories) {
+ search_opts.AddPath(dir, frontend::System, false, true);
+ LLDB_LOG(log, "Added user include dir: {0}", dir);
+ }
+
+ llvm::SmallString<128> module_cache;
+ const auto &props = ModuleList::GetGlobalModuleListProperties();
+ props.GetClangModulesCachePath().GetPath(module_cache);
+ search_opts.ModuleCachePath = std::string(module_cache.str());
+ LLDB_LOG(log, "Using module cache path: {0}", module_cache.c_str());
+
+ search_opts.ResourceDir = GetClangResourceDir().GetPath();
+
+ search_opts.ImplicitModuleMaps = true;
+}
+
+/// Iff the given identifier is a C++ keyword, remove it from the
+/// identifier table (i.e., make the token a normal identifier).
+static void RemoveCppKeyword(IdentifierTable &idents, llvm::StringRef token) {
+ // FIXME: 'using' is used by LLDB for local variables, so we can't remove
+ // this keyword without breaking this functionality.
+ if (token == "using")
+ return;
+ // GCC's '__null' is used by LLDB to define NULL/Nil/nil.
+ if (token == "__null")
+ return;
+
+ LangOptions cpp_lang_opts;
+ cpp_lang_opts.CPlusPlus = true;
+ cpp_lang_opts.CPlusPlus11 = true;
+ cpp_lang_opts.CPlusPlus20 = true;
+
+ clang::IdentifierInfo &ii = idents.get(token);
+ // The identifier has to be a C++-exclusive keyword. if not, then there is
+ // nothing to do.
+ if (!ii.isCPlusPlusKeyword(cpp_lang_opts))
+ return;
+ // If the token is already an identifier, then there is nothing to do.
+ if (ii.getTokenID() == clang::tok::identifier)
+ return;
+ // Otherwise the token is a C++ keyword, so turn it back into a normal
+ // identifier.
+ ii.revertTokenIDToIdentifier();
+}
+
+/// Remove all C++ keywords from the given identifier table.
+static void RemoveAllCppKeywords(IdentifierTable &idents) {
+#define KEYWORD(NAME, FLAGS) RemoveCppKeyword(idents, llvm::StringRef(#NAME));
+#include "clang/Basic/TokenKinds.def"
+}
+
+/// Configures Clang diagnostics for the expression parser.
+static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) {
+ // List of Clang warning groups that are not useful when parsing expressions.
+ const std::vector<const char *> groupsToIgnore = {
+ "unused-value",
+ "odr",
+ "unused-getter-return-value",
+ };
+ for (const char *group : groupsToIgnore) {
+ compiler.getDiagnostics().setSeverityForGroup(
+ clang::diag::Flavor::WarningOrError, group,
+ clang::diag::Severity::Ignored, SourceLocation());
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Implementation of ClangExpressionParser
+//===----------------------------------------------------------------------===//
+
+ClangExpressionParser::ClangExpressionParser(
+ ExecutionContextScope *exe_scope, Expression &expr,
+ bool generate_debug_info, std::vector<std::string> include_directories,
+ std::string filename)
+ : ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(),
+ m_pp_callbacks(nullptr),
+ m_include_directories(std::move(include_directories)),
+ m_filename(std::move(filename)) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ // We can't compile expressions without a target. So if the exe_scope is
+ // null or doesn't have a target, then we just need to get out of here. I'll
+ // lldbassert and not make any of the compiler objects since
+ // I can't return errors directly from the constructor. Further calls will
+ // check if the compiler was made and
+ // bag out if it wasn't.
+
+ if (!exe_scope) {
+ lldbassert(exe_scope &&
+ "Can't make an expression parser with a null scope.");
+ return;
+ }
+
+ lldb::TargetSP target_sp;
+ target_sp = exe_scope->CalculateTarget();
+ if (!target_sp) {
+ lldbassert(target_sp.get() &&
+ "Can't make an expression parser with a null target.");
+ return;
+ }
+
+ // 1. Create a new compiler instance.
+ m_compiler = std::make_unique<CompilerInstance>();
+
+ // Make sure clang uses the same VFS as LLDB.
+ m_compiler->createFileManager(FileSystem::Instance().GetVirtualFileSystem());
+
+ // Defaults to lldb::eLanguageTypeUnknown.
+ lldb::LanguageType frame_lang = expr.Language().AsLanguageType();
+
+ std::string abi;
+ ArchSpec target_arch;
+ target_arch = target_sp->GetArchitecture();
+
+ const auto target_machine = target_arch.GetMachine();
+
+ // If the expression is being evaluated in the context of an existing stack
+ // frame, we introspect to see if the language runtime is available.
+
+ lldb::StackFrameSP frame_sp = exe_scope->CalculateStackFrame();
+ lldb::ProcessSP process_sp = exe_scope->CalculateProcess();
+
+ // Make sure the user hasn't provided a preferred execution language with
+ // `expression --language X -- ...`
+ if (frame_sp && frame_lang == lldb::eLanguageTypeUnknown)
+ frame_lang = frame_sp->GetLanguage().AsLanguageType();
+
+ if (process_sp && frame_lang != lldb::eLanguageTypeUnknown) {
+ LLDB_LOGF(log, "Frame has language of type %s",
+ Language::GetNameForLanguageType(frame_lang));
+ }
+
+ // 2. Configure the compiler with a set of default options that are
+ // appropriate for most situations.
+ if (target_arch.IsValid()) {
+ std::string triple = target_arch.GetTriple().str();
+ m_compiler->getTargetOpts().Triple = triple;
+ LLDB_LOGF(log, "Using %s as the target triple",
+ m_compiler->getTargetOpts().Triple.c_str());
+ } else {
+ // If we get here we don't have a valid target and just have to guess.
+ // Sometimes this will be ok to just use the host target triple (when we
+ // evaluate say "2+3", but other expressions like breakpoint conditions and
+ // other things that _are_ target specific really shouldn't just be using
+ // the host triple. In such a case the language runtime should expose an
+ // overridden options set (3), below.
+ m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+ LLDB_LOGF(log, "Using default target triple of %s",
+ m_compiler->getTargetOpts().Triple.c_str());
+ }
+ // Now add some special fixes for known architectures: Any arm32 iOS
+ // environment, but not on arm64
+ if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos &&
+ m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos &&
+ m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) {
+ m_compiler->getTargetOpts().ABI = "apcs-gnu";
+ }
+ // Supported subsets of x86
+ if (target_machine == llvm::Triple::x86 ||
+ target_machine == llvm::Triple::x86_64) {
+ m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse");
+ m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse2");
+ }
+
+ // Set the target CPU to generate code for. This will be empty for any CPU
+ // that doesn't really need to make a special
+ // CPU string.
+ m_compiler->getTargetOpts().CPU = target_arch.GetClangTargetCPU();
+
+ // Set the target ABI
+ abi = GetClangTargetABI(target_arch);
+ if (!abi.empty())
+ m_compiler->getTargetOpts().ABI = abi;
+
+ // 3. Create and install the target on the compiler.
+ m_compiler->createDiagnostics();
+ // Limit the number of error diagnostics we emit.
+ // A value of 0 means no limit for both LLDB and Clang.
+ m_compiler->getDiagnostics().setErrorLimit(target_sp->GetExprErrorLimit());
+
+ auto target_info = TargetInfo::CreateTargetInfo(
+ m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts);
+ if (log) {
+ LLDB_LOGF(log, "Target datalayout string: '%s'",
+ target_info->getDataLayoutString());
+ LLDB_LOGF(log, "Target ABI: '%s'", target_info->getABI().str().c_str());
+ LLDB_LOGF(log, "Target vector alignment: %d",
+ target_info->getMaxVectorAlign());
+ }
+ m_compiler->setTarget(target_info);
+
+ assert(m_compiler->hasTarget());
+
+ // 4. Set language options.
+ lldb::LanguageType language = expr.Language().AsLanguageType();
+ LangOptions &lang_opts = m_compiler->getLangOpts();
+
+ switch (language) {
+ case lldb::eLanguageTypeC:
+ case lldb::eLanguageTypeC89:
+ case lldb::eLanguageTypeC99:
+ case lldb::eLanguageTypeC11:
+ // FIXME: the following language option is a temporary workaround,
+ // to "ask for C, get C++."
+ // 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.
+ lang_opts.CPlusPlus = true;
+ break;
+ case lldb::eLanguageTypeObjC:
+ lang_opts.ObjC = true;
+ // FIXME: the following language option is a temporary workaround,
+ // to "ask for ObjC, get ObjC++" (see comment above).
+ 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
+ // cause compiler error when evaluating expressions (e.g. nullptr not found
+ // 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.
+ lang_opts.CPlusPlus11 = true;
+ break;
+ case lldb::eLanguageTypeC_plus_plus_20:
+ lang_opts.CPlusPlus20 = true;
+ [[fallthrough]];
+ case lldb::eLanguageTypeC_plus_plus_17:
+ // FIXME: add a separate case for CPlusPlus14. Currently folded into C++17
+ // because C++14 is the default standard for Clang but enabling CPlusPlus14
+ // expression evaluatino doesn't pass the test-suite cleanly.
+ lang_opts.CPlusPlus14 = true;
+ lang_opts.CPlusPlus17 = true;
+ [[fallthrough]];
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeC_plus_plus_11:
+ case lldb::eLanguageTypeC_plus_plus_14:
+ lang_opts.CPlusPlus11 = true;
+ m_compiler->getHeaderSearchOpts().UseLibcxx = true;
+ [[fallthrough]];
+ case lldb::eLanguageTypeC_plus_plus_03:
+ lang_opts.CPlusPlus = true;
+ if (process_sp
+ // We're stopped in a frame without debug-info. The user probably
+ // intends to make global queries (which should include Objective-C).
+ && !(frame_sp && frame_sp->HasDebugInformation()))
+ lang_opts.ObjC =
+ process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC) != nullptr;
+ break;
+ case lldb::eLanguageTypeObjC_plus_plus:
+ case lldb::eLanguageTypeUnknown:
+ default:
+ lang_opts.ObjC = true;
+ lang_opts.CPlusPlus = true;
+ lang_opts.CPlusPlus11 = true;
+ m_compiler->getHeaderSearchOpts().UseLibcxx = true;
+ break;
+ }
+
+ 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)
+ lang_opts.DebuggerCastResultToId = true;
+
+ 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.
+ 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.CPlusPlus11 = true;
+ lang_opts.BuiltinHeadersInSystemModules = true;
+
+ // The Darwin libc expects this macro to be set.
+ lang_opts.GNUCVersion = 40201;
+
+ SetupModuleHeaderPaths(m_compiler.get(), m_include_directories,
+ target_sp);
+ }
+
+ if (process_sp && lang_opts.ObjC) {
+ if (auto *runtime = ObjCLanguageRuntime::Get(*process_sp)) {
+ switch (runtime->GetRuntimeVersion()) {
+ case ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2:
+ lang_opts.ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7));
+ break;
+ case ObjCLanguageRuntime::ObjCRuntimeVersions::eObjC_VersionUnknown:
+ case ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V1:
+ lang_opts.ObjCRuntime.set(ObjCRuntime::FragileMacOSX,
+ VersionTuple(10, 7));
+ break;
+ case ObjCLanguageRuntime::ObjCRuntimeVersions::eGNUstep_libobjc2:
+ lang_opts.ObjCRuntime.set(ObjCRuntime::GNUstep, VersionTuple(2, 0));
+ break;
+ }
+
+ if (runtime->HasNewLiteralsAndIndexing())
+ lang_opts.DebuggerObjCLiteral = true;
+ }
+ }
+
+ 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.
+ lang_opts.NoBuiltin = true;
+
+ // Set CodeGen options
+ m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
+ m_compiler->getCodeGenOpts().InstrumentFunctions = false;
+ m_compiler->getCodeGenOpts().setFramePointer(
+ CodeGenOptions::FramePointerKind::All);
+ if (generate_debug_info)
+ m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
+ else
+ m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo);
+
+ // Disable some warnings.
+ SetupDefaultClangDiagnostics(*m_compiler);
+
+ // Inform the target of the language options
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ m_compiler->getTarget().adjust(m_compiler->getDiagnostics(),
+ m_compiler->getLangOpts());
+
+ // 5. Set up the diagnostic buffer for reporting errors
+
+ auto diag_mgr = new ClangDiagnosticManagerAdapter(
+ m_compiler->getDiagnostics().getDiagnosticOptions());
+ m_compiler->getDiagnostics().setClient(diag_mgr);
+
+ // 6. Set up the source management objects inside the compiler
+ m_compiler->createFileManager();
+ if (!m_compiler->hasSourceManager())
+ m_compiler->createSourceManager(m_compiler->getFileManager());
+ m_compiler->createPreprocessor(TU_Complete);
+
+ switch (language) {
+ case lldb::eLanguageTypeC:
+ case lldb::eLanguageTypeC89:
+ case lldb::eLanguageTypeC99:
+ case lldb::eLanguageTypeC11:
+ case lldb::eLanguageTypeObjC:
+ // This is not a C++ expression but we enabled C++ as explained above.
+ // Remove all C++ keywords from the PP so that the user can still use
+ // variables that have C++ keywords as names (e.g. 'int template;').
+ RemoveAllCppKeywords(m_compiler->getPreprocessor().getIdentifierTable());
+ break;
+ default:
+ break;
+ }
+
+ if (auto *clang_persistent_vars = llvm::cast<ClangPersistentVariables>(
+ target_sp->GetPersistentExpressionStateForLanguage(
+ lldb::eLanguageTypeC))) {
+ if (std::shared_ptr<ClangModulesDeclVendor> decl_vendor =
+ clang_persistent_vars->GetClangModulesDeclVendor()) {
+ std::unique_ptr<PPCallbacks> pp_callbacks(
+ new LLDBPreprocessorCallbacks(*decl_vendor, *clang_persistent_vars,
+ m_compiler->getSourceManager()));
+ m_pp_callbacks =
+ static_cast<LLDBPreprocessorCallbacks *>(pp_callbacks.get());
+ m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));
+ }
+ }
+
+ // 7. Most of this we get from the CompilerInstance, but we also want to give
+ // the context an ExternalASTSource.
+
+ auto &PP = m_compiler->getPreprocessor();
+ auto &builtin_context = PP.getBuiltinInfo();
+ builtin_context.initializeBuiltins(PP.getIdentifierTable(),
+ m_compiler->getLangOpts());
+
+ m_compiler->createASTContext();
+ clang::ASTContext &ast_context = m_compiler->getASTContext();
+
+ m_ast_context = std::make_shared<TypeSystemClang>(
+ "Expression ASTContext for '" + m_filename + "'", ast_context);
+
+ std::string module_name("$__lldb_module");
+
+ m_llvm_context = std::make_unique<LLVMContext>();
+ m_code_generator.reset(CreateLLVMCodeGen(
+ m_compiler->getDiagnostics(), module_name,
+ &m_compiler->getVirtualFileSystem(), m_compiler->getHeaderSearchOpts(),
+ m_compiler->getPreprocessorOpts(), m_compiler->getCodeGenOpts(),
+ *m_llvm_context));
+}
+
+ClangExpressionParser::~ClangExpressionParser() = default;
+
+namespace {
+
+/// \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;
+
+ std::string m_expr;
+ unsigned m_position = 0;
+ /// The printing policy we use when printing declarations for our completion
+ /// descriptions.
+ clang::PrintingPolicy m_desc_policy;
+
+ struct CompletionWithPriority {
+ CompletionResult::Completion completion;
+ /// See CodeCompletionResult::Priority;
+ unsigned Priority;
+
+ /// Establishes a deterministic order in a list of CompletionWithPriority.
+ /// The order returned here is the order in which the completions are
+ /// displayed to the user.
+ bool operator<(const CompletionWithPriority &o) const {
+ // High priority results should come first.
+ if (Priority != o.Priority)
+ return Priority > o.Priority;
+
+ // Identical priority, so just make sure it's a deterministic order.
+ return completion.GetUniqueKey() < o.completion.GetUniqueKey();
+ }
+ };
+
+ /// The stored completions.
+ /// Warning: These are in a non-deterministic order until they are sorted
+ /// and returned back to the caller.
+ std::vector<CompletionWithPriority> m_completions;
+
+ /// Returns true if the given character can be used in an identifier.
+ /// This also returns true for numbers because for completion we usually
+ /// just iterate backwards over iterators.
+ ///
+ /// Note: lldb uses '$' in its internal identifiers, so we also allow this.
+ static bool IsIdChar(char c) {
+ return c == '_' || std::isalnum(c) || c == '$';
+ }
+
+ /// Returns true if the given character is used to separate arguments
+ /// in the command line of lldb.
+ static bool IsTokenSeparator(char c) { return c == ' ' || c == '\t'; }
+
+ /// Drops all tokens in front of the expression that are unrelated for
+ /// the completion of the cmd line. 'unrelated' means here that the token
+ /// is not interested for the lldb completion API result.
+ StringRef dropUnrelatedFrontTokens(StringRef cmd) const {
+ if (cmd.empty())
+ return cmd;
+
+ // If we are at the start of a word, then all tokens are unrelated to
+ // the current completion logic.
+ if (IsTokenSeparator(cmd.back()))
+ return StringRef();
+
+ // Remove all previous tokens from the string as they are unrelated
+ // to completing the current token.
+ StringRef to_remove = cmd;
+ while (!to_remove.empty() && !IsTokenSeparator(to_remove.back())) {
+ to_remove = to_remove.drop_back();
+ }
+ cmd = cmd.drop_front(to_remove.size());
+
+ return cmd;
+ }
+
+ /// Removes the last identifier token from the given cmd line.
+ StringRef removeLastToken(StringRef cmd) const {
+ while (!cmd.empty() && IsIdChar(cmd.back())) {
+ cmd = cmd.drop_back();
+ }
+ return cmd;
+ }
+
+ /// Attempts to merge the given completion from the given position into the
+ /// existing command. Returns the completion string that can be returned to
+ /// the lldb completion API.
+ std::string mergeCompletion(StringRef existing, unsigned pos,
+ StringRef completion) const {
+ StringRef existing_command = existing.substr(0, pos);
+ // We rewrite the last token with the completion, so let's drop that
+ // token from the command.
+ existing_command = removeLastToken(existing_command);
+ // We also should remove all previous tokens from the command as they
+ // would otherwise be added to the completion that already has the
+ // completion.
+ existing_command = dropUnrelatedFrontTokens(existing_command);
+ return existing_command.str() + completion.str();
+ }
+
+public:
+ /// Constructs a CodeComplete consumer that can be attached to a Sema.
+ ///
+ /// \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
+ /// The character position of the user cursor in the `expr` parameter.
+ ///
+ CodeComplete(clang::LangOptions ops, std::string expr, unsigned position)
+ : CodeCompleteConsumer(CodeCompleteOptions()),
+ m_info(std::make_shared<GlobalCodeCompletionAllocator>()), m_expr(expr),
+ m_position(position), m_desc_policy(ops) {
+
+ // Ensure that the printing policy is producing a description that is as
+ // short as possible.
+ m_desc_policy.SuppressScope = true;
+ m_desc_policy.SuppressTagKeyword = true;
+ m_desc_policy.FullyQualifiedName = false;
+ m_desc_policy.TerseOutput = true;
+ m_desc_policy.IncludeNewlines = false;
+ m_desc_policy.UseVoidForZeroParams = false;
+ m_desc_policy.Bool = true;
+ }
+
+ /// \name Code-completion filtering
+ /// Check if the result should be filtered out.
+ bool isResultFilteredOut(StringRef Filter,
+ CodeCompletionResult Result) override {
+ // This code is mostly copied from CodeCompleteConsumer.
+ switch (Result.Kind) {
+ case CodeCompletionResult::RK_Declaration:
+ return !(
+ Result.Declaration->getIdentifier() &&
+ Result.Declaration->getIdentifier()->getName().starts_with(Filter));
+ case CodeCompletionResult::RK_Keyword:
+ return !StringRef(Result.Keyword).starts_with(Filter);
+ case CodeCompletionResult::RK_Macro:
+ return !Result.Macro->getName().starts_with(Filter);
+ case CodeCompletionResult::RK_Pattern:
+ return !StringRef(Result.Pattern->getAsString()).starts_with(Filter);
+ }
+ // If we trigger this assert or the above switch yields a warning, then
+ // CodeCompletionResult has been enhanced with more kinds of completion
+ // results. Expand the switch above in this case.
+ assert(false && "Unknown completion result type?");
+ // If we reach this, then we should just ignore whatever kind of unknown
+ // result we got back. We probably can't turn it into any kind of useful
+ // completion suggestion with the existing code.
+ return true;
+ }
+
+private:
+ /// Generate the completion strings for the given CodeCompletionResult.
+ /// Note that this function has to process results that could come in
+ /// non-deterministic order, so this function should have no side effects.
+ /// To make this easier to enforce, this function and all its parameters
+ /// should always be const-qualified.
+ /// \return Returns std::nullopt if no completion should be provided for the
+ /// given CodeCompletionResult.
+ std::optional<CompletionWithPriority>
+ getCompletionForResult(const CodeCompletionResult &R) const {
+ std::string ToInsert;
+ std::string Description;
+ // Handle the different completion kinds that come from the Sema.
+ switch (R.Kind) {
+ case CodeCompletionResult::RK_Declaration: {
+ const NamedDecl *D = R.Declaration;
+ ToInsert = R.Declaration->getNameAsString();
+ // If we have a function decl that has no arguments we want to
+ // complete the empty parantheses for the user. If the function has
+ // arguments, we at least complete the opening bracket.
+ if (const FunctionDecl *F = dyn_cast<FunctionDecl>(D)) {
+ if (F->getNumParams() == 0)
+ ToInsert += "()";
+ else
+ ToInsert += "(";
+ raw_string_ostream OS(Description);
+ F->print(OS, m_desc_policy, false);
+ OS.flush();
+ } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) {
+ Description = V->getType().getAsString(m_desc_policy);
+ } else if (const FieldDecl *F = dyn_cast<FieldDecl>(D)) {
+ Description = F->getType().getAsString(m_desc_policy);
+ } else if (const NamespaceDecl *N = dyn_cast<NamespaceDecl>(D)) {
+ // If we try to complete a namespace, then we can directly append
+ // the '::'.
+ if (!N->isAnonymousNamespace())
+ ToInsert += "::";
+ }
+ break;
+ }
+ case CodeCompletionResult::RK_Keyword:
+ ToInsert = R.Keyword;
+ break;
+ case CodeCompletionResult::RK_Macro:
+ ToInsert = R.Macro->getName().str();
+ break;
+ case CodeCompletionResult::RK_Pattern:
+ ToInsert = R.Pattern->getTypedText();
+ break;
+ }
+ // We also filter some internal lldb identifiers here. The user
+ // shouldn't see these.
+ if (llvm::StringRef(ToInsert).starts_with("$__lldb_"))
+ return std::nullopt;
+ if (ToInsert.empty())
+ return std::nullopt;
+ // Merge the suggested Token into the existing command line to comply
+ // with the kind of result the lldb API expects.
+ std::string CompletionSuggestion =
+ mergeCompletion(m_expr, m_position, ToInsert);
+
+ CompletionResult::Completion completion(CompletionSuggestion, Description,
+ CompletionMode::Normal);
+ return {{completion, R.Priority}};
+ }
+
+public:
+ /// Adds the completions to the given CompletionRequest.
+ void GetCompletions(CompletionRequest &request) {
+ // Bring m_completions into a deterministic order and pass it on to the
+ // CompletionRequest.
+ llvm::sort(m_completions);
+
+ for (const CompletionWithPriority &C : m_completions)
+ request.AddCompletion(C.completion.GetCompletion(),
+ C.completion.GetDescription(),
+ C.completion.GetMode());
+ }
+
+ /// \name Code-completion callbacks
+ /// Process the finalized code-completion results.
+ void ProcessCodeCompleteResults(Sema &SemaRef, CodeCompletionContext Context,
+ CodeCompletionResult *Results,
+ unsigned NumResults) override {
+
+ // The Sema put the incomplete token we try to complete in here during
+ // lexing, so we need to retrieve it here to know what we are completing.
+ StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter();
+
+ // Iterate over all the results. Filter out results we don't want and
+ // process the rest.
+ for (unsigned I = 0; I != NumResults; ++I) {
+ // Filter the results with the information from the Sema.
+ if (!Filter.empty() && isResultFilteredOut(Filter, Results[I]))
+ continue;
+
+ CodeCompletionResult &R = Results[I];
+ std::optional<CompletionWithPriority> CompletionAndPriority =
+ getCompletionForResult(R);
+ if (!CompletionAndPriority)
+ continue;
+ m_completions.push_back(*CompletionAndPriority);
+ }
+ }
+
+ /// \param S the semantic-analyzer object for which code-completion is being
+ /// done.
+ ///
+ /// \param CurrentArg the index of the current argument.
+ ///
+ /// \param Candidates an array of overload candidates.
+ ///
+ /// \param NumCandidates the number of overload candidates
+ void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates,
+ SourceLocation OpenParLoc,
+ bool Braced) override {
+ // At the moment we don't filter out any overloaded candidates.
+ }
+
+ CodeCompletionAllocator &getAllocator() override {
+ return m_info.getAllocator();
+ }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return m_info; }
+};
+} // namespace
+
+bool ClangExpressionParser::Complete(CompletionRequest &request, unsigned line,
+ unsigned pos, unsigned typed_pos) {
+ DiagnosticManager mgr;
+ // We need the raw user expression here because that's what the CodeComplete
+ // class uses to provide completion suggestions.
+ // However, the `Text` method only gives us the transformed expression here.
+ // 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.
+ ClangUserExpression *llvm_expr = cast<ClangUserExpression>(&m_expr);
+ CodeComplete CC(m_compiler->getLangOpts(), llvm_expr->GetUserText(),
+ typed_pos);
+ // We don't need a code generator for parsing.
+ m_code_generator.reset();
+ // Start parsing the expression with our custom code completion consumer.
+ ParseInternal(mgr, &CC, line, pos);
+ CC.GetCompletions(request);
+ return true;
+}
+
+unsigned ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) {
+ return ParseInternal(diagnostic_manager);
+}
+
+unsigned
+ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
+ CodeCompleteConsumer *completion_consumer,
+ unsigned completion_line,
+ unsigned completion_column) {
+ ClangDiagnosticManagerAdapter *adapter =
+ static_cast<ClangDiagnosticManagerAdapter *>(
+ m_compiler->getDiagnostics().getClient());
+
+ adapter->ResetManager(&diagnostic_manager);
+
+ const char *expr_text = m_expr.Text();
+
+ clang::SourceManager &source_mgr = m_compiler->getSourceManager();
+ bool created_main_file = false;
+
+ // Clang wants to do completion on a real file known by Clang's file manager,
+ // so we have to create one to make this work.
+ // TODO: We probably could also simulate to Clang's file manager that there
+ // is a real file that contains our code.
+ bool should_create_file = completion_consumer != nullptr;
+
+ // We also want a real file on disk if we generate full debug info.
+ should_create_file |= m_compiler->getCodeGenOpts().getDebugInfo() ==
+ codegenoptions::FullDebugInfo;
+
+ if (should_create_file) {
+ int temp_fd = -1;
+ llvm::SmallString<128> result_path;
+ if (FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir()) {
+ tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr");
+ std::string temp_source_path = tmpdir_file_spec.GetPath();
+ llvm::sys::fs::createUniqueFile(temp_source_path, temp_fd, result_path);
+ } else {
+ llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path);
+ }
+
+ if (temp_fd != -1) {
+ lldb_private::NativeFile file(temp_fd, File::eOpenOptionWriteOnly, true);
+ const size_t expr_text_len = strlen(expr_text);
+ size_t bytes_written = expr_text_len;
+ if (file.Write(expr_text, bytes_written).Success()) {
+ if (bytes_written == expr_text_len) {
+ file.Close();
+ if (auto fileEntry = m_compiler->getFileManager().getOptionalFileRef(
+ result_path)) {
+ source_mgr.setMainFileID(source_mgr.createFileID(
+ *fileEntry,
+ SourceLocation(), SrcMgr::C_User));
+ created_main_file = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!created_main_file) {
+ std::unique_ptr<MemoryBuffer> memory_buffer =
+ MemoryBuffer::getMemBufferCopy(expr_text, m_filename);
+ source_mgr.setMainFileID(source_mgr.createFileID(std::move(memory_buffer)));
+ }
+
+ adapter->BeginSourceFile(m_compiler->getLangOpts(),
+ &m_compiler->getPreprocessor());
+
+ ClangExpressionHelper *type_system_helper =
+ dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
+
+ // 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
+ // completion suggestions.
+ if (completion_consumer) {
+ auto main_file =
+ source_mgr.getFileEntryRefForID(source_mgr.getMainFileID());
+ auto &PP = m_compiler->getPreprocessor();
+ // Lines and columns start at 1 in Clang, but code completion positions are
+ // indexed from 0, so we need to add 1 to the line and column here.
+ ++completion_line;
+ ++completion_column;
+ 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) {
+ Consumer = std::make_unique<ASTConsumerForwarder>(ast_transformer);
+ } else if (m_code_generator) {
+ Consumer = std::make_unique<ASTConsumerForwarder>(m_code_generator.get());
+ } else {
+ Consumer = std::make_unique<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->createASTReader();
+ m_ast_context->setSema(&m_compiler->getSema());
+ }
+
+ ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();
+ if (decl_map) {
+ decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer());
+ decl_map->InstallDiagnosticManager(diagnostic_manager);
+
+ 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(*m_ast_context);
+ }
+
+ // 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);
+
+ adapter->EndSourceFile();
+
+ unsigned num_errors = adapter->getNumErrors();
+
+ if (m_pp_callbacks && m_pp_callbacks->hasErrors()) {
+ num_errors++;
+ diagnostic_manager.PutString(lldb::eSeverityError,
+ "while importing modules:");
+ diagnostic_manager.AppendMessageToDiagnostic(
+ m_pp_callbacks->getErrorString());
+ }
+
+ if (!num_errors) {
+ type_system_helper->CommitPersistentDecls();
+ }
+
+ adapter->ResetManager();
+
+ return num_errors;
+}
+
+std::string
+ClangExpressionParser::GetClangTargetABI(const ArchSpec &target_arch) {
+ std::string abi;
+
+ if (target_arch.IsMIPS()) {
+ switch (target_arch.GetFlags() & ArchSpec::eMIPSABI_mask) {
+ case ArchSpec::eMIPSABI_N64:
+ abi = "n64";
+ break;
+ case ArchSpec::eMIPSABI_N32:
+ abi = "n32";
+ break;
+ case ArchSpec::eMIPSABI_O32:
+ abi = "o32";
+ break;
+ default:
+ break;
+ }
+ }
+ return abi;
+}
+
+/// Applies the given Fix-It hint to the given commit.
+static void ApplyFixIt(const FixItHint &fixit, clang::edit::Commit &commit) {
+ // This is cobbed from clang::Rewrite::FixItRewriter.
+ if (fixit.CodeToInsert.empty()) {
+ if (fixit.InsertFromRange.isValid()) {
+ commit.insertFromRange(fixit.RemoveRange.getBegin(),
+ fixit.InsertFromRange, /*afterToken=*/false,
+ fixit.BeforePreviousInsertions);
+ return;
+ }
+ commit.remove(fixit.RemoveRange);
+ return;
+ }
+ if (fixit.RemoveRange.isTokenRange() ||
+ fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd()) {
+ commit.replace(fixit.RemoveRange, fixit.CodeToInsert);
+ return;
+ }
+ commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert,
+ /*afterToken=*/false, fixit.BeforePreviousInsertions);
+}
+
+bool ClangExpressionParser::RewriteExpression(
+ DiagnosticManager &diagnostic_manager) {
+ clang::SourceManager &source_manager = m_compiler->getSourceManager();
+ clang::edit::EditedSource editor(source_manager, m_compiler->getLangOpts(),
+ nullptr);
+ clang::edit::Commit commit(editor);
+ clang::Rewriter rewriter(source_manager, m_compiler->getLangOpts());
+
+ class RewritesReceiver : public edit::EditsReceiver {
+ Rewriter &rewrite;
+
+ public:
+ RewritesReceiver(Rewriter &in_rewrite) : rewrite(in_rewrite) {}
+
+ void insert(SourceLocation loc, StringRef text) override {
+ rewrite.InsertText(loc, text);
+ }
+ void replace(CharSourceRange range, StringRef text) override {
+ rewrite.ReplaceText(range.getBegin(), rewrite.getRangeSize(range), text);
+ }
+ };
+
+ RewritesReceiver rewrites_receiver(rewriter);
+
+ const DiagnosticList &diagnostics = diagnostic_manager.Diagnostics();
+ size_t num_diags = diagnostics.size();
+ if (num_diags == 0)
+ return false;
+
+ for (const auto &diag : diagnostic_manager.Diagnostics()) {
+ const auto *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag.get());
+ if (!diagnostic)
+ continue;
+ if (!diagnostic->HasFixIts())
+ continue;
+ for (const FixItHint &fixit : diagnostic->FixIts())
+ ApplyFixIt(fixit, commit);
+ }
+
+ // FIXME - do we want to try to propagate specific errors here?
+ if (!commit.isCommitable())
+ return false;
+ else if (!editor.commit(commit))
+ return false;
+
+ // Now play all the edits, and stash the result in the diagnostic manager.
+ editor.applyRewrites(rewrites_receiver);
+ RewriteBuffer &main_file_buffer =
+ rewriter.getEditBuffer(source_manager.getMainFileID());
+
+ std::string fixed_expression;
+ llvm::raw_string_ostream out_stream(fixed_expression);
+
+ main_file_buffer.write(out_stream);
+ out_stream.flush();
+ diagnostic_manager.SetFixedExpression(fixed_expression);
+
+ return true;
+}
+
+static bool FindFunctionInModule(ConstString &mangled_name,
+ llvm::Module *module, const char *orig_name) {
+ for (const auto &func : module->getFunctionList()) {
+ const StringRef &name = func.getName();
+ if (name.contains(orig_name)) {
+ mangled_name.SetString(name);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+lldb_private::Status ClangExpressionParser::DoPrepareForExecution(
+ lldb::addr_t &func_addr, lldb::addr_t &func_end,
+ lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx,
+ bool &can_interpret, ExecutionPolicy execution_policy) {
+ func_addr = LLDB_INVALID_ADDRESS;
+ func_end = LLDB_INVALID_ADDRESS;
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ lldb_private::Status err;
+
+ std::unique_ptr<llvm::Module> llvm_module_up(
+ m_code_generator->ReleaseModule());
+
+ if (!llvm_module_up) {
+ err.SetErrorToGenericError();
+ err.SetErrorString("IR doesn't contain a module");
+ return err;
+ }
+
+ ConstString function_name;
+
+ if (execution_policy != eExecutionPolicyTopLevel) {
+ // Find the actual name of the function (it's often mangled somehow)
+
+ if (!FindFunctionInModule(function_name, llvm_module_up.get(),
+ m_expr.FunctionName())) {
+ err.SetErrorToGenericError();
+ err.SetErrorStringWithFormat("Couldn't find %s() in the module",
+ m_expr.FunctionName());
+ return err;
+ } else {
+ LLDB_LOGF(log, "Found function %s for %s", function_name.AsCString(),
+ m_expr.FunctionName());
+ }
+ }
+
+ SymbolContext sc;
+
+ if (lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP()) {
+ sc = frame_sp->GetSymbolContext(lldb::eSymbolContextEverything);
+ } else if (lldb::TargetSP target_sp = exe_ctx.GetTargetSP()) {
+ sc.target_sp = target_sp;
+ }
+
+ LLVMUserExpression::IRPasses custom_passes;
+ {
+ auto lang = m_expr.Language();
+ LLDB_LOGF(log, "%s - Current expression language is %s\n", __FUNCTION__,
+ lang.GetDescription().data());
+ lldb::ProcessSP process_sp = exe_ctx.GetProcessSP();
+ if (process_sp && lang != lldb::eLanguageTypeUnknown) {
+ auto runtime = process_sp->GetLanguageRuntime(lang.AsLanguageType());
+ if (runtime)
+ runtime->GetIRPasses(custom_passes);
+ }
+ }
+
+ if (custom_passes.EarlyPasses) {
+ LLDB_LOGF(log,
+ "%s - Running Early IR Passes from LanguageRuntime on "
+ "expression module '%s'",
+ __FUNCTION__, m_expr.FunctionName());
+
+ custom_passes.EarlyPasses->run(*llvm_module_up);
+ }
+
+ 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());
+ ClangExpressionDeclMap *decl_map =
+ type_system_helper->DeclMap(); // result can be NULL
+
+ if (decl_map) {
+ StreamString error_stream;
+ IRForTarget ir_for_target(decl_map, m_expr.NeedsVariableResolution(),
+ *execution_unit_sp, error_stream,
+ function_name.AsCString());
+
+ if (!ir_for_target.runOnModule(*execution_unit_sp->GetModule())) {
+ err.SetErrorString(error_stream.GetString());
+ return err;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (execution_policy != eExecutionPolicyAlways &&
+ execution_policy != eExecutionPolicyTopLevel) {
+ lldb_private::Status interpret_error;
+
+ bool interpret_function_calls =
+ !process ? false : process->CanInterpretFunctionCalls();
+ can_interpret = IRInterpreter::CanInterpret(
+ *execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(),
+ interpret_error, interpret_function_calls);
+
+ if (!can_interpret && execution_policy == eExecutionPolicyNever) {
+ err.SetErrorStringWithFormat(
+ "Can't evaluate the expression without a running target due to: %s",
+ interpret_error.AsCString());
+ return err;
+ }
+ }
+
+ if (!process && execution_policy == eExecutionPolicyAlways) {
+ err.SetErrorString("Expression needed to run in the target, but the "
+ "target can't be run");
+ return err;
+ }
+
+ if (!process && execution_policy == eExecutionPolicyTopLevel) {
+ err.SetErrorString("Top-level code needs to be inserted into a runnable "
+ "target, but the target can't be run");
+ return err;
+ }
+
+ if (execution_policy == eExecutionPolicyAlways ||
+ (execution_policy != eExecutionPolicyTopLevel && !can_interpret)) {
+ if (m_expr.NeedsValidation() && process) {
+ if (!process->GetDynamicCheckers()) {
+ ClangDynamicCheckerFunctions *dynamic_checkers =
+ new ClangDynamicCheckerFunctions();
+
+ DiagnosticManager install_diags;
+ if (Error Err = dynamic_checkers->Install(install_diags, exe_ctx)) {
+ std::string ErrMsg = "couldn't install checkers: " + toString(std::move(Err));
+ if (install_diags.Diagnostics().size())
+ ErrMsg = ErrMsg + "\n" + install_diags.GetString().c_str();
+ err.SetErrorString(ErrMsg);
+ return err;
+ }
+
+ process->SetDynamicCheckers(dynamic_checkers);
+
+ LLDB_LOGF(log, "== [ClangExpressionParser::PrepareForExecution] "
+ "Finished installing dynamic checkers ==");
+ }
+
+ 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;
+ }
+
+ if (custom_passes.LatePasses) {
+ LLDB_LOGF(log,
+ "%s - Running Late IR Passes from LanguageRuntime on "
+ "expression module '%s'",
+ __FUNCTION__, m_expr.FunctionName());
+
+ custom_passes.LatePasses->run(*module);
+ }
+ }
+ }
+ }
+
+ if (execution_policy == eExecutionPolicyAlways ||
+ execution_policy == eExecutionPolicyTopLevel || !can_interpret) {
+ execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);
+ }
+ } else {
+ execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);
+ }
+
+ return err;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
new file mode 100644
index 000000000000..0852e928a9d4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -0,0 +1,175 @@
+//===-- ClangExpressionParser.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H
+
+#include "lldb/Expression/DiagnosticManager.h"
+#include "lldb/Expression/ExpressionParser.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-public.h"
+
+#include <string>
+#include <vector>
+
+namespace llvm {
+class LLVMContext;
+}
+
+namespace clang {
+class CodeGenerator;
+class CodeCompleteConsumer;
+class CompilerInstance;
+} // namespace clang
+
+namespace lldb_private {
+
+class IRExecutionUnit;
+class TypeSystemClang;
+
+/// \class ClangExpressionParser ClangExpressionParser.h
+/// "lldb/Expression/ClangExpressionParser.h" Encapsulates an instance of
+/// Clang that can parse expressions.
+///
+/// ClangExpressionParser is responsible for preparing an instance of
+/// ClangExpression for execution. ClangExpressionParser uses ClangExpression
+/// 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
+ /// 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
+ /// The expression to be parsed.
+ ///
+ /// @param[in] include_directories
+ /// List of include directories that should be used when parsing the
+ /// expression.
+ ///
+ /// @param[in] filename
+ /// Name of the source file that should be used when rendering
+ /// diagnostics (i.e. errors, warnings or notes from Clang).
+ ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr,
+ bool generate_debug_info,
+ std::vector<std::string> include_directories = {},
+ std::string filename = "<clang expression>");
+
+ /// 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
+ /// The diagnostic manager to report errors to.
+ ///
+ /// \return
+ /// The number of errors encountered during parsing. 0 means
+ /// success.
+ unsigned Parse(DiagnosticManager &diagnostic_manager);
+
+ bool RewriteExpression(DiagnosticManager &diagnostic_manager) override;
+
+ /// Ready an already-parsed expression for execution, possibly evaluating it
+ /// statically.
+ ///
+ /// \param[out] func_addr
+ /// The address to which the function has been written.
+ ///
+ /// \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
+ /// After parsing, ownership of the execution unit for
+ /// for the expression is handed to this shared pointer.
+ ///
+ /// \param[in] exe_ctx
+ /// The execution context to write the function into.
+ ///
+ /// \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
+ /// An error code indicating the success or failure of the operation.
+ /// Test with Success().
+ Status DoPrepareForExecution(
+ 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;
+
+ /// Returns a string representing current ABI.
+ ///
+ /// \param[in] target_arch
+ /// The target architecture.
+ ///
+ /// \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
+ /// The diagnostic manager that should receive the diagnostics
+ /// from the parsing process.
+ ///
+ /// \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
+ /// The line in which the completion marker should be placed.
+ /// The first line is represented by the value 0.
+ ///
+ /// \param[in] completion_column
+ /// The column in which the completion marker should be placed.
+ /// The first column is represented by the value 0.
+ ///
+ /// \return
+ /// The number of parsing errors.
+ unsigned ParseInternal(DiagnosticManager &diagnostic_manager,
+ clang::CodeCompleteConsumer *completion = nullptr,
+ unsigned completion_line = 0,
+ unsigned completion_column = 0);
+
+ std::unique_ptr<llvm::LLVMContext>
+ m_llvm_context; ///< The LLVM context to generate IR into
+ std::unique_ptr<clang::CompilerInstance>
+ m_compiler; ///< The Clang compiler used to parse expressions into IR
+ std::unique_ptr<clang::CodeGenerator>
+ m_code_generator; ///< The Clang object that generates IR
+
+ class LLDBPreprocessorCallbacks;
+ LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor
+ ///encounters module imports
+ std::shared_ptr<TypeSystemClang> m_ast_context;
+
+ std::vector<std::string> m_include_directories;
+ /// File name used for the user expression.
+ std::string m_filename;
+};
+}
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
new file mode 100644
index 000000000000..3b601726388d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -0,0 +1,529 @@
+//===-- ClangExpressionSourceCode.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionSourceCode.h"
+
+#include "ClangExpressionUtil.h"
+
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/ScopeExit.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"
+#include "lldb/lldb-forward.h"
+
+using namespace lldb_private;
+
+#define PREFIX_NAME "<lldb wrapper prefix>"
+#define SUFFIX_NAME "<lldb wrapper suffix>"
+
+const llvm::StringRef ClangExpressionSourceCode::g_prefix_file_name = PREFIX_NAME;
+
+const char *ClangExpressionSourceCode::g_expression_prefix =
+"#line 1 \"" PREFIX_NAME R"("
+#ifndef offsetof
+#define offsetof(t, d) __builtin_offsetof(t, d)
+#endif
+#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, ...);
+}
+)";
+
+const char *ClangExpressionSourceCode::g_expression_suffix =
+ "\n;\n#line 1 \"" SUFFIX_NAME "\"\n";
+
+namespace {
+
+class AddMacroState {
+ enum State {
+ CURRENT_FILE_NOT_YET_PUSHED,
+ CURRENT_FILE_PUSHED,
+ CURRENT_FILE_POPPED
+ };
+
+public:
+ AddMacroState(const FileSpec &current_file, const uint32_t current_file_line)
+ : 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 = CURRENT_FILE_NOT_YET_PUSHED;
+ 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;
+
+ // The macros directives below can potentially redefine builtin macros of the
+ // Clang instance which parses the user expression. The Clang diagnostics
+ // caused by this are not useful for the user as the source code here is
+ // generated by LLDB.
+ stream << "#pragma clang diagnostic push\n";
+ stream << "#pragma clang diagnostic ignored \"-Wmacro-redefined\"\n";
+ stream << "#pragma clang diagnostic ignored \"-Wbuiltin-macro-redefined\"\n";
+ auto pop_warning = llvm::make_scope_exit([&stream](){
+ stream << "#pragma clang diagnostic pop\n";
+ });
+
+ 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;
+ }
+ }
+}
+
+lldb_private::ClangExpressionSourceCode::ClangExpressionSourceCode(
+ llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix,
+ llvm::StringRef body, Wrapping wrap, WrapKind wrap_kind)
+ : ExpressionSourceCode(name, prefix, body, wrap), m_wrap_kind(wrap_kind) {
+ // Use #line markers to pretend that we have a single-line source file
+ // containing only the user expression. This will hide our wrapper code
+ // from the user when we render diagnostics with Clang.
+ m_start_marker = "#line 1 \"" + filename.str() + "\"\n";
+ m_end_marker = g_expression_suffix;
+}
+
+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.contains(token);
+ }
+};
+
+// If we're evaluating from inside a lambda that captures a 'this' pointer,
+// add a "using" declaration to 'stream' for each capture used in the
+// expression (tokenized by 'verifier').
+//
+// If no 'this' capture exists, generate no using declarations. Instead
+// capture lookups will get resolved by the same mechanism as class member
+// variable lookup. That's because Clang generates an unnamed structure
+// representing the lambda closure whose members are the captured variables.
+void AddLambdaCaptureDecls(StreamString &stream, StackFrame *frame,
+ TokenVerifier const &verifier) {
+ assert(frame);
+
+ if (auto thisValSP = ClangExpressionUtil::GetLambdaValueObject(frame)) {
+ uint32_t numChildren = thisValSP->GetNumChildrenIgnoringErrors();
+ for (uint32_t i = 0; i < numChildren; ++i) {
+ auto childVal = thisValSP->GetChildAtIndex(i);
+ ConstString childName(childVal ? childVal->GetName() : ConstString(""));
+
+ if (!childName.IsEmpty() && verifier.hasToken(childName.GetStringRef()) &&
+ childName != "this") {
+ stream.Printf("using $__lldb_local_vars::%s;\n",
+ childName.GetCString());
+ }
+ }
+ }
+}
+
+} // 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(buf->getMemBufferRef());
+
+ // Let's just enable the latest ObjC and C++ which should get most tokens
+ // right.
+ LangOptions Opts;
+ Opts.ObjC = true;
+ Opts.DollarIdents = true;
+ Opts.CPlusPlus20 = true;
+ Opts.LineComment = true;
+
+ Lexer lex(FID, buf->getMemBufferRef(), 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);
+ }
+}
+
+void ClangExpressionSourceCode::AddLocalVariableDecls(StreamString &stream,
+ const std::string &expr,
+ StackFrame *frame) const {
+ assert(frame);
+ TokenVerifier tokens(expr);
+
+ lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false, true);
+
+ 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();
+
+ if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction) {
+ AddLambdaCaptureDecls(stream, frame, tokens);
+
+ continue;
+ }
+
+ // 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;
+
+ const bool is_objc = m_wrap_kind == WrapKind::ObjCInstanceMethod ||
+ m_wrap_kind == WrapKind::ObjCStaticMethod;
+ if ((var_name == "self" || var_name == "_cmd") && is_objc)
+ continue;
+
+ stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString());
+ }
+}
+
+bool ClangExpressionSourceCode::GetText(
+ std::string &text, 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;
+ llvm::raw_string_ostream module_macros_stream(module_macros);
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64 ||
+ target->GetArchitecture().GetMachine() == llvm::Triple::aarch64_32) {
+ target_specific_defines = "typedef bool BOOL;\n";
+ }
+ if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) {
+ if (lldb::PlatformSP platform_sp = target->GetPlatform()) {
+ if (platform_sp->GetPluginName() == "ios-simulator") {
+ target_specific_defines = "typedef bool BOOL;\n";
+ }
+ }
+ }
+
+ auto *persistent_vars = llvm::cast<ClangPersistentVariables>(
+ target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
+ std::shared_ptr<ClangModulesDeclVendor> decl_vendor =
+ persistent_vars->GetClangModulesDeclVendor();
+ if (decl_vendor) {
+ 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_stream](llvm::StringRef token,
+ llvm::StringRef expansion) -> bool {
+ // Check if the macro hasn't already been defined in the
+ // g_expression_prefix (which defines a few builtin macros).
+ module_macros_stream << "#ifndef " << token << "\n";
+ module_macros_stream << expansion << "\n";
+ module_macros_stream << "#endif\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.GetFile(), sc.line_entry.line);
+ AddMacros(dm, sc.comp_unit, state, debug_macros_stream);
+ }
+ }
+
+ if (add_locals)
+ if (target->GetInjectLocalVariables(&exe_ctx)) {
+ AddLocalVariableDecls(lldb_local_var_decls,
+ force_add_all_locals ? "" : m_body, frame);
+ }
+ }
+
+ if (m_wrap) {
+ // 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", g_expression_prefix,
+ module_macros.c_str(), debug_macros_stream.GetData(),
+ 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;
+ tagged_body.append(m_start_marker);
+ tagged_body.append(m_body);
+ tagged_body.append(m_end_marker);
+
+ switch (m_wrap_kind) {
+ case WrapKind::Function:
+ 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 WrapKind::CppMemberFunction:
+ 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 WrapKind::ObjCInstanceMethod:
+ 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;
+
+ case WrapKind::ObjCStaticMethod:
+ 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 = std::string(wrap_stream.GetString());
+ } else {
+ text.append(m_body);
+ }
+
+ return true;
+}
+
+bool ClangExpressionSourceCode::GetOriginalBodyBounds(
+ std::string transformed_text, size_t &start_loc, size_t &end_loc) {
+ start_loc = transformed_text.find(m_start_marker);
+ if (start_loc == std::string::npos)
+ return false;
+ start_loc += m_start_marker.size();
+ end_loc = transformed_text.find(m_end_marker);
+ return end_loc != std::string::npos;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
new file mode 100644
index 000000000000..f721bb2f319e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
@@ -0,0 +1,105 @@
+//===-- 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 LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONSOURCECODE_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_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:
+ /// The file name we use for the wrapper code that we inject before
+ /// the user expression.
+ static const llvm::StringRef g_prefix_file_name;
+ static const char *g_expression_prefix;
+ static const char *g_expression_suffix;
+
+ /// The possible ways an expression can be wrapped.
+ enum class WrapKind {
+ /// Wrapped in a non-static member function of a C++ class.
+ CppMemberFunction,
+ /// Wrapped in an instance Objective-C method.
+ ObjCInstanceMethod,
+ /// Wrapped in a static Objective-C method.
+ ObjCStaticMethod,
+ /// Wrapped in a non-member function.
+ /// Note that this is also used for static member functions of a C++ class.
+ Function
+ };
+
+ static ClangExpressionSourceCode *CreateWrapped(llvm::StringRef filename,
+ llvm::StringRef prefix,
+ llvm::StringRef body,
+ WrapKind wrap_kind) {
+ return new ClangExpressionSourceCode(filename, "$__lldb_expr", prefix, body,
+ Wrap, wrap_kind);
+ }
+
+ /// Generates the source code that will evaluate the expression.
+ ///
+ /// \param text output parameter containing the source code string.
+ /// \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, 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.
+ bool GetOriginalBodyBounds(std::string transformed_text,
+ size_t &start_loc, size_t &end_loc);
+
+protected:
+ ClangExpressionSourceCode(llvm::StringRef filename, llvm::StringRef name,
+ llvm::StringRef prefix, llvm::StringRef body,
+ Wrapping wrap, WrapKind wrap_kind);
+
+private:
+ /// Writes "using" declarations for local variables into the specified stream.
+ ///
+ /// Behaviour is undefined if 'frame == nullptr'.
+ ///
+ /// \param[out] stream Stream that this function generates "using"
+ /// declarations into.
+ ///
+ /// \param[in] expr Expression source that we're evaluating.
+ ///
+ /// \param[in] frame StackFrame which carries information about the local
+ /// variables that we're generating "using" declarations for.
+ void AddLocalVariableDecls(StreamString &stream, const std::string &expr,
+ StackFrame *frame) const;
+
+ /// String marking the start of the user expression.
+ std::string m_start_marker;
+ /// String marking the end of the user expression.
+ std::string m_end_marker;
+ /// How the expression has been wrapped.
+ const WrapKind m_wrap_kind;
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp
new file mode 100644
index 000000000000..723a3d7e5984
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.cpp
@@ -0,0 +1,27 @@
+//===-- ClangExpressionUtil.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionUtil.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Utility/ConstString.h"
+
+namespace lldb_private {
+namespace ClangExpressionUtil {
+lldb::ValueObjectSP GetLambdaValueObject(StackFrame *frame) {
+ assert(frame);
+
+ if (auto this_val_sp = frame->FindVariable(ConstString("this")))
+ if (this_val_sp->GetChildMemberWithName("this"))
+ return this_val_sp;
+
+ return nullptr;
+}
+} // namespace ClangExpressionUtil
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h
new file mode 100644
index 000000000000..fb8b857256c0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionUtil.h
@@ -0,0 +1,30 @@
+//===-- ClangExpressionUtil.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONUTIL_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONUTIL_H
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+namespace ClangExpressionUtil {
+/// Returns a ValueObject for the lambda class in the current frame
+///
+/// To represent a lambda, Clang generates an artificial class
+/// whose members are the captures and whose operator() is the
+/// lambda implementation. If we capture a 'this' pointer,
+/// the artifical class will contain a member variable named 'this'.
+///
+/// This method returns the 'this' pointer to the artificial lambda
+/// class if a real 'this' was captured. Otherwise, returns nullptr.
+lldb::ValueObjectSP GetLambdaValueObject(StackFrame *frame);
+
+} // namespace ClangExpressionUtil
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
new file mode 100644
index 000000000000..ac3cb0b1bdf3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
@@ -0,0 +1,64 @@
+//===-- ClangExpressionVariable.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionVariable.h"
+
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Stream.h"
+#include "clang/AST/ASTContext.h"
+
+using namespace lldb_private;
+using namespace clang;
+
+char ClangExpressionVariable::ID;
+
+ClangExpressionVariable::ClangExpressionVariable(
+ ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size)
+ : m_parser_vars(), m_jit_vars() {
+ m_flags = EVNone;
+ m_frozen_sp =
+ ValueObjectConstResult::Create(exe_scope, byte_order, addr_byte_size);
+}
+
+ClangExpressionVariable::ClangExpressionVariable(
+ ExecutionContextScope *exe_scope, Value &value, ConstString name,
+ uint16_t flags)
+ : m_parser_vars(), m_jit_vars() {
+ m_flags = flags;
+ m_frozen_sp = ValueObjectConstResult::Create(exe_scope, value, name);
+}
+
+ClangExpressionVariable::ClangExpressionVariable(
+ const lldb::ValueObjectSP &valobj_sp)
+ : m_parser_vars(), m_jit_vars() {
+ m_flags = EVNone;
+ m_frozen_sp = valobj_sp;
+}
+
+ClangExpressionVariable::ClangExpressionVariable(
+ ExecutionContextScope *exe_scope, ConstString name,
+ const TypeFromUser &user_type, lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size)
+ : m_parser_vars(), m_jit_vars() {
+ m_flags = EVNone;
+ m_frozen_sp =
+ ValueObjectConstResult::Create(exe_scope, byte_order, addr_byte_size);
+ SetName(name);
+ SetCompilerType(user_type);
+}
+
+TypeFromUser ClangExpressionVariable::GetTypeFromUser() {
+ TypeFromUser tfu(m_frozen_sp->GetCompilerType());
+ return tfu;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
new file mode 100644
index 000000000000..193ada018fa4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
@@ -0,0 +1,212 @@
+//===-- ClangExpressionVariable.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H
+
+#include <csignal>
+#include <cstdint>
+#include <cstring>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "llvm/Support/Casting.h"
+
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-public.h"
+
+namespace llvm {
+class Value;
+}
+
+namespace clang {
+class NamedDecl;
+}
+
+namespace lldb_private {
+
+class ValueObjectConstResult;
+
+/// \class ClangExpressionVariable ClangExpressionVariable.h
+/// "lldb/Expression/ClangExpressionVariable.h" Encapsulates one variable for
+/// the expression parser.
+///
+/// The expression parser uses variables in three different contexts:
+///
+/// First, it stores persistent variables along with the process for use in
+/// expressions. These persistent variables contain their own data and are
+/// typed.
+///
+/// Second, in an interpreted expression, it stores the local variables for
+/// the expression along with the expression. These variables contain their
+/// own data and are typed.
+///
+/// Third, in a JIT-compiled expression, it stores the variables that the
+/// expression needs to have materialized and dematerialized at each
+/// execution. These do not contain their own data but are named and typed.
+///
+/// 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 llvm::RTTIExtends<ClangExpressionVariable, ExpressionVariable> {
+public:
+ // LLVM RTTI support
+ static char ID;
+
+ ClangExpressionVariable(ExecutionContextScope *exe_scope,
+ lldb::ByteOrder byte_order, uint32_t addr_byte_size);
+
+ ClangExpressionVariable(ExecutionContextScope *exe_scope, Value &value,
+ ConstString name, uint16_t flags = EVNone);
+
+ ClangExpressionVariable(const lldb::ValueObjectSP &valobj_sp);
+
+ ClangExpressionVariable(ExecutionContextScope *exe_scope,
+ 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.
+ ///
+ /// \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) {
+ lldb::ExpressionVariableSP var_sp;
+ for (size_t index = 0, size = list.GetSize(); index < size; ++index) {
+ var_sp = list.GetVariableAtIndex(index);
+
+ if (ClangExpressionVariable *clang_var =
+ llvm::dyn_cast<ClangExpressionVariable>(var_sp.get())) {
+ ClangExpressionVariable::ParserVars *parser_vars =
+ clang_var->GetParserVars(parser_id);
+
+ if (parser_vars && parser_vars->m_named_decl == decl)
+ return clang_var;
+ }
+ }
+ 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
+ /// The value to point at the data.
+ ///
+ /// \param[in] exe_ctx
+ /// The execution context to use to resolve \a value.
+ ///
+ /// \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() = default;
+
+ const clang::NamedDecl *m_named_decl =
+ nullptr; ///< The Decl corresponding to this variable
+ llvm::Value *m_llvm_value =
+ nullptr; ///< The IR value corresponding to this variable;
+ /// usually a GlobalValue
+ lldb_private::Value
+ m_lldb_value; ///< The value found in LLDB for this variable
+ lldb::VariableSP m_lldb_var; ///< The original variable for this variable
+ const lldb_private::Symbol *m_lldb_sym =
+ nullptr; ///< The original symbol for this
+ /// variable, if it was a symbol
+
+ /// Callback that provides a ValueObject for the
+ /// specified frame. Used by the materializer for
+ /// re-fetching ValueObjects when materializing
+ /// ivars.
+ ValueObjectProviderTy m_lldb_valobj_provider;
+ };
+
+private:
+ typedef std::map<uint64_t, ParserVars> ParserVarMap;
+ 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 nullptr;
+ else
+ return &i->second;
+ }
+
+ /// The following values are valid if the variable is used by JIT code
+ struct JITVars {
+ JITVars() = default;
+
+ lldb::offset_t m_alignment =
+ 0; ///< The required alignment of the variable, in bytes
+ size_t m_size = 0; ///< The space required for the variable, in bytes
+ lldb::offset_t m_offset =
+ 0; ///< The offset of the variable in the struct, in bytes
+ };
+
+private:
+ typedef std::map<uint64_t, JITVars> JITVarMap;
+ 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 nullptr;
+ else
+ return &i->second;
+ }
+
+ TypeFromUser GetTypeFromUser();
+
+ /// Members
+ ClangExpressionVariable(const ClangExpressionVariable &) = delete;
+ const ClangExpressionVariable &
+ operator=(const ClangExpressionVariable &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
new file mode 100644
index 000000000000..e746e6afe39b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
@@ -0,0 +1,90 @@
+//===-- ClangExternalASTSourceCallbacks.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/Module.h"
+#include <optional>
+
+using namespace lldb_private;
+
+char ClangExternalASTSourceCallbacks::ID;
+
+void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) {
+ m_ast.CompleteTagDecl(tag_decl);
+}
+
+void ClangExternalASTSourceCallbacks::CompleteType(
+ clang::ObjCInterfaceDecl *objc_decl) {
+ m_ast.CompleteObjCInterfaceDecl(objc_decl);
+}
+
+bool ClangExternalASTSourceCallbacks::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) {
+ return m_ast.LayoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets);
+}
+
+void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls(
+ const clang::DeclContext *decl_ctx,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &decls) {
+ if (decl_ctx) {
+ clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(
+ const_cast<clang::DeclContext *>(decl_ctx));
+ if (tag_decl)
+ CompleteType(tag_decl);
+ }
+}
+
+bool ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(
+ const clang::DeclContext *DC, clang::DeclarationName Name) {
+ llvm::SmallVector<clang::NamedDecl *, 4> decls;
+ // Objective-C methods are not added into the LookupPtr when they originate
+ // from an external source. SetExternalVisibleDeclsForName() adds them.
+ if (auto *oid = llvm::dyn_cast<clang::ObjCInterfaceDecl>(DC)) {
+ clang::ObjCContainerDecl::method_range noload_methods(oid->noload_decls());
+ for (auto *omd : noload_methods)
+ if (omd->getDeclName() == Name)
+ decls.push_back(omd);
+ }
+ return !SetExternalVisibleDeclsForName(DC, Name, decls).empty();
+}
+
+OptionalClangModuleID
+ClangExternalASTSourceCallbacks::RegisterModule(clang::Module *module) {
+ m_modules.push_back(module);
+ unsigned id = m_modules.size();
+ m_ids.insert({module, id});
+ return OptionalClangModuleID(id);
+}
+
+std::optional<clang::ASTSourceDescriptor>
+ClangExternalASTSourceCallbacks::getSourceDescriptor(unsigned id) {
+ if (clang::Module *module = getModule(id))
+ return {*module};
+ return {};
+}
+
+clang::Module *ClangExternalASTSourceCallbacks::getModule(unsigned id) {
+ if (id && id <= m_modules.size())
+ return m_modules[id - 1];
+ return nullptr;
+}
+
+OptionalClangModuleID
+ClangExternalASTSourceCallbacks::GetIDForModule(clang::Module *module) {
+ return OptionalClangModuleID(m_ids[module]);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
new file mode 100644
index 000000000000..6bd18186a567
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
@@ -0,0 +1,73 @@
+//===-- ClangExternalASTSourceCallbacks.h -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "clang/Basic/ASTSourceDescriptor.h"
+#include <optional>
+
+namespace clang {
+
+class Module;
+
+} // namespace clang
+
+namespace lldb_private {
+
+class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource {
+ /// LLVM RTTI support.
+ static char ID;
+
+public:
+ /// LLVM RTTI support.
+ bool isA(const void *ClassID) const override { return ClassID == &ID; }
+ static bool classof(const clang::ExternalASTSource *s) { return s->isA(&ID); }
+
+ ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {}
+
+ void FindExternalLexicalDecls(
+ const clang::DeclContext *DC,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &Result) override;
+
+ bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+ clang::DeclarationName Name) override;
+
+ void CompleteType(clang::TagDecl *tag_decl) override;
+
+ void CompleteType(clang::ObjCInterfaceDecl *objc_decl) 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;
+
+ TypeSystemClang &GetTypeSystem() const { return m_ast; }
+
+ /// Module-related methods.
+ /// \{
+ std::optional<clang::ASTSourceDescriptor>
+ getSourceDescriptor(unsigned ID) override;
+ clang::Module *getModule(unsigned ID) override;
+ OptionalClangModuleID RegisterModule(clang::Module *module);
+ OptionalClangModuleID GetIDForModule(clang::Module *module);
+ /// \}
+private:
+ TypeSystemClang &m_ast;
+ std::vector<clang::Module *> m_modules;
+ llvm::DenseMap<clang::Module *, unsigned> m_ids;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
new file mode 100644
index 000000000000..59321e375bdc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
@@ -0,0 +1,219 @@
+//===-- ClangFunctionCaller.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangFunctionCaller.h"
+
+#include "ASTStructExtractor.h"
+#include "ClangExpressionParser.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/IR/Module.h"
+#include "llvm/TargetParser/Triple.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+
+using namespace lldb_private;
+
+char ClangFunctionCaller::ID;
+
+// ClangFunctionCaller constructor
+ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope,
+ const CompilerType &return_type,
+ const Address &functionAddress,
+ const ValueList &arg_value_list,
+ const char *name)
+ : FunctionCaller(exe_scope, return_type, functionAddress, arg_value_list,
+ name),
+ m_type_system_helper(*this) {
+ m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());
+ // Can't make a ClangFunctionCaller without a process.
+ assert(m_jit_process_wp.lock());
+}
+
+// Destructor
+ClangFunctionCaller::~ClangFunctionCaller() = default;
+
+unsigned
+
+ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp,
+ DiagnosticManager &diagnostic_manager) {
+ if (m_compiled)
+ return 0;
+
+ // Compilation might call code, make sure to keep on the thread the caller
+ // indicated.
+ ThreadList::ExpressionExecutionThreadPusher execution_thread_pusher(
+ thread_to_use_sp);
+
+ // FIXME: How does clang tell us there's no return value? We need to handle
+ // that case.
+ unsigned num_errors = 0;
+
+ std::string return_type_str(
+ m_function_return_type.GetTypeName().AsCString(""));
+
+ // Cons up the function we're going to wrap our call in, then compile it...
+ // We declare the function "extern "C"" because the compiler might be in C++
+ // mode which would mangle the name and then we couldn't find it again...
+ m_wrapper_function_text.clear();
+ m_wrapper_function_text.append("extern \"C\" void ");
+ m_wrapper_function_text.append(m_wrapper_function_name);
+ m_wrapper_function_text.append(" (void *input)\n{\n struct ");
+ m_wrapper_function_text.append(m_wrapper_struct_name);
+ m_wrapper_function_text.append(" \n {\n");
+ m_wrapper_function_text.append(" ");
+ m_wrapper_function_text.append(return_type_str);
+ m_wrapper_function_text.append(" (*fn_ptr) (");
+
+ // Get the number of arguments. If we have a function type and it is
+ // prototyped, trust that, otherwise use the values we were given.
+
+ // FIXME: This will need to be extended to handle Variadic functions. We'll
+ // need
+ // to pull the defined arguments out of the function, then add the types from
+ // the arguments list for the variable arguments.
+
+ uint32_t num_args = UINT32_MAX;
+ bool trust_function = false;
+ // GetArgumentCount returns -1 for an unprototyped function.
+ CompilerType function_clang_type;
+ if (m_function_ptr) {
+ function_clang_type = m_function_ptr->GetCompilerType();
+ if (function_clang_type) {
+ int num_func_args = function_clang_type.GetFunctionArgumentCount();
+ if (num_func_args >= 0) {
+ trust_function = true;
+ num_args = num_func_args;
+ }
+ }
+ }
+
+ if (num_args == UINT32_MAX)
+ num_args = m_arg_values.GetSize();
+
+ std::string args_buffer; // This one stores the definition of all the args in
+ // "struct caller".
+ std::string args_list_buffer; // This one stores the argument list called from
+ // the structure.
+ for (size_t i = 0; i < num_args; i++) {
+ std::string type_name;
+
+ if (trust_function) {
+ type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i)
+ .GetTypeName()
+ .AsCString("");
+ } else {
+ CompilerType clang_qual_type =
+ m_arg_values.GetValueAtIndex(i)->GetCompilerType();
+ if (clang_qual_type) {
+ type_name = clang_qual_type.GetTypeName().AsCString("");
+ } else {
+ diagnostic_manager.Printf(
+ lldb::eSeverityError,
+ "Could not determine type of input value %" PRIu64 ".",
+ (uint64_t)i);
+ return 1;
+ }
+ }
+
+ m_wrapper_function_text.append(type_name);
+ if (i < num_args - 1)
+ m_wrapper_function_text.append(", ");
+
+ char arg_buf[32];
+ args_buffer.append(" ");
+ args_buffer.append(type_name);
+ snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i);
+ args_buffer.push_back(' ');
+ args_buffer.append(arg_buf);
+ args_buffer.append(";\n");
+
+ args_list_buffer.append("__lldb_fn_data->");
+ args_list_buffer.append(arg_buf);
+ if (i < num_args - 1)
+ args_list_buffer.append(", ");
+ }
+ m_wrapper_function_text.append(
+ ");\n"); // Close off the function calling prototype.
+
+ m_wrapper_function_text.append(args_buffer);
+
+ m_wrapper_function_text.append(" ");
+ m_wrapper_function_text.append(return_type_str);
+ m_wrapper_function_text.append(" return_value;");
+ m_wrapper_function_text.append("\n };\n struct ");
+ m_wrapper_function_text.append(m_wrapper_struct_name);
+ m_wrapper_function_text.append("* __lldb_fn_data = (struct ");
+ m_wrapper_function_text.append(m_wrapper_struct_name);
+ m_wrapper_function_text.append(" *) input;\n");
+
+ m_wrapper_function_text.append(
+ " __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr (");
+ m_wrapper_function_text.append(args_list_buffer);
+ m_wrapper_function_text.append(");\n}\n");
+
+ Log *log = GetLog(LLDBLog::Expressions);
+ LLDB_LOGF(log, "Expression: \n\n%s\n\n", m_wrapper_function_text.c_str());
+
+ // Okay, now compile this expression
+
+ lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
+ if (jit_process_sp) {
+ const bool generate_debug_info = true;
+ auto *clang_parser = new ClangExpressionParser(jit_process_sp.get(), *this,
+ generate_debug_info);
+ num_errors = clang_parser->Parse(diagnostic_manager);
+ m_parser.reset(clang_parser);
+ } else {
+ diagnostic_manager.PutString(lldb::eSeverityError,
+ "no process - unable to inject function");
+ num_errors = 1;
+ }
+
+ m_compiled = (num_errors == 0);
+
+ if (!m_compiled)
+ return num_errors;
+
+ return num_errors;
+}
+
+char ClangFunctionCaller::ClangFunctionCallerHelper::ID;
+
+clang::ASTConsumer *
+ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer(
+ clang::ASTConsumer *passthrough) {
+ m_struct_extractor = std::make_unique<ASTStructExtractor>(
+ passthrough, m_owner.GetWrapperStructName(), m_owner);
+
+ return m_struct_extractor.get();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h
new file mode 100644
index 000000000000..2a5c863b51a2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h
@@ -0,0 +1,154 @@
+//===-- ClangFunctionCaller.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H
+
+#include "ClangExpressionHelper.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Expression/FunctionCaller.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Target/Process.h"
+
+namespace lldb_private {
+
+class ASTStructExtractor;
+
+/// \class ClangFunctionCaller ClangFunctionCaller.h
+/// "lldb/Expression/ClangFunctionCaller.h" Encapsulates a function that can
+/// be called.
+///
+/// A given ClangFunctionCaller object can handle a single function signature.
+/// Once constructed, it can set up any number of concurrent calls to
+/// functions with that signature.
+///
+/// It performs the call by synthesizing a structure that contains the pointer
+/// to the function and the arguments that should be passed to that function,
+/// and producing a special-purpose JIT-compiled function that accepts a void*
+/// pointing to this struct as its only argument and calls the function in the
+/// struct with the written arguments. This method lets Clang handle the
+/// vagaries of function calling conventions.
+///
+/// The simplest use of the ClangFunctionCaller is to construct it with a
+/// function representative of the signature you want to use, then call
+/// ExecuteFunction(ExecutionContext &, Stream &, Value &).
+///
+/// If you need to reuse the arguments for several calls, you can call
+/// InsertFunction() followed by WriteFunctionArguments(), which will return
+/// the location of the args struct for the wrapper function in args_addr_ref.
+///
+/// If you need to call the function on the thread plan stack, you can also
+/// call InsertFunction() followed by GetThreadPlanToCallFunction().
+///
+/// Any of the methods that take arg_addr_ptr or arg_addr_ref can be passed a
+/// pointer set to LLDB_INVALID_ADDRESS and new structure will be allocated
+/// and its address returned in that variable.
+///
+/// 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;
+
+ class ClangFunctionCallerHelper
+ : public llvm::RTTIExtends<ClangFunctionCallerHelper,
+ ClangExpressionHelper> {
+ public:
+ // LLVM RTTI support
+ static char ID;
+
+ ClangFunctionCallerHelper(ClangFunctionCaller &owner) : m_owner(owner) {}
+
+ /// 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 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
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ clang::ASTConsumer *
+ ASTTransformer(clang::ASTConsumer *passthrough) override;
+
+ private:
+ ClangFunctionCaller &m_owner;
+ std::unique_ptr<ASTStructExtractor> m_struct_extractor; ///< The class that
+ ///generates the
+ ///argument struct
+ ///layout.
+ };
+
+ // LLVM RTTI support
+ static char ID;
+
+public:
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || FunctionCaller::isA(ClassID);
+ }
+ static bool classof(const Expression *obj) { return obj->isA(&ID); }
+
+ /// Constructor
+ ///
+ /// \param[in] exe_scope
+ /// An execution context scope that gets us at least a target and
+ /// process.
+ ///
+ /// \param[in] return_type
+ /// A compiler type for the function result. Should be
+ /// defined in ast_context.
+ ///
+ /// \param[in] function_address
+ /// The address of the function to call.
+ ///
+ /// \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,
+ const ValueList &arg_value_list, const char *name);
+
+ ~ClangFunctionCaller() override;
+
+ /// Compile the wrapper function
+ ///
+ /// \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
+ /// The diagnostic manager to report parser errors to.
+ ///
+ /// \return
+ /// The number of errors.
+ unsigned CompileFunction(lldb::ThreadSP thread_to_use_sp,
+ DiagnosticManager &diagnostic_manager) override;
+
+ ExpressionTypeSystemHelper *GetTypeSystemHelper() override {
+ return &m_type_system_helper;
+ }
+
+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.
+ ClangFunctionCallerHelper m_type_system_helper;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
new file mode 100644
index 000000000000..6064c02c7fd6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
@@ -0,0 +1,171 @@
+//===-- ClangHost.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangHost.h"
+
+#include "clang/Basic/Version.h"
+#include "clang/Config/config.h"
+#include "clang/Driver/Driver.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#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"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include <string>
+
+using namespace lldb_private;
+
+static bool VerifyClangPath(const llvm::Twine &clang_path) {
+ if (FileSystem::Instance().IsDirectory(clang_path))
+ return true;
+ Log *log = GetLog(LLDBLog::Host);
+ LLDB_LOGF(log,
+ "VerifyClangPath(): "
+ "failed to stat clang resource directory at \"%s\"",
+ clang_path.str().c_str());
+ return false;
+}
+
+///
+/// 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 = GetLog(LLDBLog::Host);
+ std::string raw_path = lldb_shlib_spec.GetPath();
+ llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path);
+ static const std::string clang_resource_path =
+ clang::driver::Driver::GetResourcesPath("bin/lldb", CLANG_RESOURCE_DIR);
+
+ 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 or
+ // $install_dir/bin/$CLANG_RESOURCE_DIR
+ clang_resource_path,
+ // 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_INSTALL_LIBDIR_BASENAME.
+ LLDB_INSTALL_LIBDIR_BASENAME "/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)) {
+ LLDB_LOG(log,
+ "DefaultComputeClangResourceDir: Setting ClangResourceDir "
+ "to \"{0}\", verify = {1}",
+ clang_dir.str(), verify ? "true" : "false");
+ file_spec.SetDirectory(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);
+ auto r_end = llvm::sys::path::rend(raw_path);
+
+ // Check for a Posix-style build of LLDB.
+ while (rev_it != r_end) {
+ if (*rev_it == "LLDB.framework")
+ break;
+ ++rev_it;
+ }
+
+ // We found a non-framework build of LLDB
+ if (rev_it == r_end)
+ 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
+ // directory. This allows LLDB and the Swift compiler to share the
+ // same Clang module cache.
+ llvm::SmallString<256> clang_path;
+ const char *swift_clang_resource_dir = "usr/lib/swift/clang";
+ auto parent = std::next(rev_it);
+ if (parent != r_end && *parent == "SharedFrameworks") {
+ // This is the top-level LLDB in the Xcode.app bundle.
+ // E.g., "Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A"
+ raw_path.resize(parent - r_end);
+ llvm::sys::path::append(clang_path, raw_path,
+ "Developer/Toolchains/XcodeDefault.xctoolchain",
+ swift_clang_resource_dir);
+ if (!verify || VerifyClangPath(clang_path)) {
+ file_spec.SetDirectory(clang_path);
+ FileSystem::Instance().Resolve(file_spec);
+ return true;
+ }
+ } else if (parent != r_end && *parent == "PrivateFrameworks" &&
+ std::distance(parent, r_end) > 2) {
+ ++parent;
+ ++parent;
+ if (*parent == "System") {
+ // This is LLDB inside an Xcode toolchain.
+ // E.g., "Xcode.app/Contents/Developer/Toolchains/" \
+ // "My.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework"
+ 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.SetDirectory(clang_path);
+ FileSystem::Instance().Resolve(file_spec);
+ return true;
+ }
+ }
+ }
+
+ // Fall back to the Clang resource directory inside the framework.
+ raw_path = lldb_shlib_spec.GetPath();
+ raw_path.resize(rev_it - r_end);
+ raw_path.append("LLDB.framework/Resources/Clang");
+ file_spec.SetDirectory(raw_path);
+ FileSystem::Instance().Resolve(file_spec);
+ return true;
+#endif // __APPLE__
+}
+
+FileSpec lldb_private::GetClangResourceDir() {
+ static FileSpec g_cached_resource_dir;
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
+ if (FileSpec lldb_file_spec = HostInfo::GetShlibDir())
+ ComputeClangResourceDirectory(lldb_file_spec, g_cached_resource_dir,
+ true);
+ Log *log = GetLog(LLDBLog::Host);
+ LLDB_LOGF(log, "GetClangResourceDir() => '%s'",
+ g_cached_resource_dir.GetPath().c_str());
+ });
+ return g_cached_resource_dir;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h
new file mode 100644
index 000000000000..d6809909a625
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h
@@ -0,0 +1,23 @@
+//===-- ClangHost.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H
+
+namespace lldb_private {
+
+class FileSpec;
+
+bool ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
+ FileSpec &file_spec, bool verify);
+
+FileSpec GetClangResourceDir();
+
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
new file mode 100644
index 000000000000..024fc75a5dd5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -0,0 +1,776 @@
+//===-- ClangModulesDeclVendor.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Serialization/ASTReader.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Threading.h"
+
+#include "ClangHost.h"
+#include "ClangModulesDeclVendor.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/Progress.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/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include <memory>
+
+using namespace lldb_private;
+
+namespace {
+/// Any Clang compiler requires a consumer for diagnostics. This one stores
+/// them as strings so we can provide them to the user in case a module failed
+/// to load.
+class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
+public:
+ StoringDiagnosticConsumer();
+
+ void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &info) override;
+
+ void ClearDiagnostics();
+
+ void DumpDiagnostics(Stream &error_stream);
+
+ void BeginSourceFile(const clang::LangOptions &LangOpts,
+ const clang::Preprocessor *PP = nullptr) override;
+ void EndSourceFile() override;
+
+private:
+ bool HandleModuleRemark(const clang::Diagnostic &info);
+ void SetCurrentModuleProgress(std::string module_name);
+
+ typedef std::pair<clang::DiagnosticsEngine::Level, std::string>
+ IDAndDiagnostic;
+ std::vector<IDAndDiagnostic> m_diagnostics;
+ /// The DiagnosticPrinter used for creating the full diagnostic messages
+ /// that are stored in m_diagnostics.
+ std::unique_ptr<clang::TextDiagnosticPrinter> m_diag_printer;
+ /// Output stream of m_diag_printer.
+ std::unique_ptr<llvm::raw_string_ostream> m_os;
+ /// Output string filled by m_os. Will be reused for different diagnostics.
+ std::string m_output;
+ /// A Progress with explicitly managed lifetime.
+ std::unique_ptr<Progress> m_current_progress_up;
+ std::vector<std::string> m_module_build_stack;
+};
+
+/// The private implementation of our ClangModulesDeclVendor. Contains all the
+/// Clang state required to load modules.
+class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
+public:
+ ClangModulesDeclVendorImpl(
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,
+ std::shared_ptr<clang::CompilerInvocation> compiler_invocation,
+ std::unique_ptr<clang::CompilerInstance> compiler_instance,
+ std::unique_ptr<clang::Parser> parser);
+
+ ~ClangModulesDeclVendorImpl() override = default;
+
+ 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(ConstString name, bool append, uint32_t max_matches,
+ std::vector<CompilerDecl> &decls) override;
+
+ void ForEachMacro(
+ const ModuleVector &modules,
+ std::function<bool(llvm::StringRef, llvm::StringRef)> handler) override;
+
+private:
+ typedef llvm::DenseSet<ModuleID> ExportedModuleSet;
+ void ReportModuleExportsHelper(ExportedModuleSet &exports,
+ clang::Module *module);
+
+ void ReportModuleExports(ModuleVector &exports, clang::Module *module);
+
+ clang::ModuleLoadResult DoGetModule(clang::ModuleIdPath path,
+ bool make_visible);
+
+ bool m_enabled = false;
+
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> m_diagnostics_engine;
+ std::shared_ptr<clang::CompilerInvocation> m_compiler_invocation;
+ std::unique_ptr<clang::CompilerInstance> m_compiler_instance;
+ std::unique_ptr<clang::Parser> m_parser;
+ size_t m_source_location_index =
+ 0; // used to give name components fake SourceLocations
+
+ typedef std::vector<ConstString> ImportedModule;
+ typedef std::map<ImportedModule, clang::Module *> ImportedModuleMap;
+ typedef llvm::DenseSet<ModuleID> ImportedModuleSet;
+ ImportedModuleMap m_imported_modules;
+ ImportedModuleSet m_user_imported_modules;
+ // We assume that every ASTContext has an TypeSystemClang, so we also store
+ // a custom TypeSystemClang for our internal ASTContext.
+ std::shared_ptr<TypeSystemClang> m_ast_context;
+};
+} // anonymous namespace
+
+StoringDiagnosticConsumer::StoringDiagnosticConsumer() {
+ auto *options = new clang::DiagnosticOptions();
+ m_os = std::make_unique<llvm::raw_string_ostream>(m_output);
+ m_diag_printer =
+ std::make_unique<clang::TextDiagnosticPrinter>(*m_os, options);
+}
+
+void StoringDiagnosticConsumer::HandleDiagnostic(
+ clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info) {
+ if (HandleModuleRemark(info))
+ return;
+
+ // Print the diagnostic to m_output.
+ m_output.clear();
+ m_diag_printer->HandleDiagnostic(DiagLevel, info);
+ m_os->flush();
+
+ // Store the diagnostic for later.
+ m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, m_output));
+}
+
+void StoringDiagnosticConsumer::ClearDiagnostics() { m_diagnostics.clear(); }
+
+void StoringDiagnosticConsumer::DumpDiagnostics(Stream &error_stream) {
+ for (IDAndDiagnostic &diag : m_diagnostics) {
+ switch (diag.first) {
+ default:
+ error_stream.PutCString(diag.second);
+ error_stream.PutChar('\n');
+ break;
+ case clang::DiagnosticsEngine::Level::Ignored:
+ break;
+ }
+ }
+}
+
+void StoringDiagnosticConsumer::BeginSourceFile(
+ const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) {
+ m_diag_printer->BeginSourceFile(LangOpts, PP);
+}
+
+void StoringDiagnosticConsumer::EndSourceFile() {
+ m_current_progress_up = nullptr;
+ m_diag_printer->EndSourceFile();
+}
+
+bool StoringDiagnosticConsumer::HandleModuleRemark(
+ const clang::Diagnostic &info) {
+ Log *log = GetLog(LLDBLog::Types | LLDBLog::Expressions);
+ switch (info.getID()) {
+ case clang::diag::remark_module_build: {
+ const auto &module_name = info.getArgStdStr(0);
+ SetCurrentModuleProgress(module_name);
+ m_module_build_stack.push_back(module_name);
+
+ const auto &module_path = info.getArgStdStr(1);
+ LLDB_LOG(log, "Building Clang module {0} as {1}", module_name, module_path);
+ return true;
+ }
+ case clang::diag::remark_module_build_done: {
+ // The current module is done.
+ m_module_build_stack.pop_back();
+ if (m_module_build_stack.empty()) {
+ m_current_progress_up = nullptr;
+ } else {
+ // When the just completed module began building, a module that depends on
+ // it ("module A") was effectively paused. Update the progress to re-show
+ // "module A" as continuing to be built.
+ const auto &resumed_module_name = m_module_build_stack.back();
+ SetCurrentModuleProgress(resumed_module_name);
+ }
+
+ const auto &module_name = info.getArgStdStr(0);
+ LLDB_LOG(log, "Finished building Clang module {0}", module_name);
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+void StoringDiagnosticConsumer::SetCurrentModuleProgress(
+ std::string module_name) {
+ if (!m_current_progress_up)
+ m_current_progress_up =
+ std::make_unique<Progress>("Building Clang modules");
+
+ m_current_progress_up->Increment(1, std::move(module_name));
+}
+
+ClangModulesDeclVendor::ClangModulesDeclVendor()
+ : ClangDeclVendor(eClangModuleDeclVendor) {}
+
+ClangModulesDeclVendor::~ClangModulesDeclVendor() = default;
+
+ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,
+ std::shared_ptr<clang::CompilerInvocation> compiler_invocation,
+ std::unique_ptr<clang::CompilerInstance> compiler_instance,
+ std::unique_ptr<clang::Parser> parser)
+ : m_diagnostics_engine(std::move(diagnostics_engine)),
+ m_compiler_invocation(std::move(compiler_invocation)),
+ m_compiler_instance(std::move(compiler_instance)),
+ m_parser(std::move(parser)) {
+
+ // Initialize our TypeSystemClang.
+ m_ast_context =
+ std::make_shared<TypeSystemClang>("ClangModulesDeclVendor ASTContext",
+ m_compiler_instance->getASTContext());
+}
+
+void ClangModulesDeclVendorImpl::ReportModuleExportsHelper(
+ ExportedModuleSet &exports, clang::Module *module) {
+ if (exports.count(reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module)))
+ return;
+
+ exports.insert(reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module));
+
+ llvm::SmallVector<clang::Module *, 2> sub_exports;
+
+ module->getExportedModules(sub_exports);
+
+ for (clang::Module *module : sub_exports)
+ ReportModuleExportsHelper(exports, module);
+}
+
+void ClangModulesDeclVendorImpl::ReportModuleExports(
+ ClangModulesDeclVendor::ModuleVector &exports, clang::Module *module) {
+ ExportedModuleSet exports_set;
+
+ ReportModuleExportsHelper(exports_set, module);
+
+ for (ModuleID module : exports_set)
+ exports.push_back(module);
+}
+
+bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
+ ModuleVector *exported_modules,
+ Stream &error_stream) {
+ // Fail early.
+
+ if (m_compiler_instance->hadModuleLoaderFatalFailure()) {
+ error_stream.PutCString("error: Couldn't load a module because the module "
+ "loader is in a fatal state.\n");
+ return false;
+ }
+
+ // Check if we've already imported this module.
+
+ std::vector<ConstString> imported_module;
+
+ for (ConstString path_component : module.path)
+ imported_module.push_back(path_component);
+
+ {
+ ImportedModuleMap::iterator mi = m_imported_modules.find(imported_module);
+
+ if (mi != m_imported_modules.end()) {
+ if (exported_modules)
+ ReportModuleExports(*exported_modules, mi->second);
+ return true;
+ }
+ }
+
+ 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().getOptionalDirectoryRef(
+ 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",
+ module.path.front().AsCString());
+ return false;
+ }
+
+ llvm::SmallVector<std::pair<clang::IdentifierInfo *, clang::SourceLocation>,
+ 4>
+ clang_path;
+
+ {
+ clang::SourceManager &source_manager =
+ m_compiler_instance->getASTContext().getSourceManager();
+
+ for (ConstString path_component : module.path) {
+ clang_path.push_back(std::make_pair(
+ &m_compiler_instance->getASTContext().Idents.get(
+ path_component.GetStringRef()),
+ source_manager.getLocForStartOfFile(source_manager.getMainFileID())
+ .getLocWithOffset(m_source_location_index++)));
+ }
+ }
+
+ StoringDiagnosticConsumer *diagnostic_consumer =
+ static_cast<StoringDiagnosticConsumer *>(
+ m_compiler_instance->getDiagnostics().getClient());
+
+ diagnostic_consumer->ClearDiagnostics();
+
+ clang::Module *top_level_module = DoGetModule(clang_path.front(), false);
+
+ if (!top_level_module) {
+ diagnostic_consumer->DumpDiagnostics(error_stream);
+ error_stream.Printf("error: Couldn't load top-level module %s\n",
+ module.path.front().AsCString());
+ return false;
+ }
+
+ clang::Module *submodule = top_level_module;
+
+ 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.GetCString());
+ return false;
+ }
+ }
+
+ clang::Module *requested_module = DoGetModule(clang_path, true);
+
+ if (requested_module != nullptr) {
+ if (exported_modules)
+ ReportModuleExports(*exported_modules, requested_module);
+
+ m_imported_modules[imported_module] = requested_module;
+
+ m_enabled = true;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool ClangModulesDeclVendor::LanguageSupportsClangModules(
+ lldb::LanguageType language) {
+ switch (language) {
+ default:
+ return false;
+ 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;
+ }
+}
+
+bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit(
+ CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules,
+ Stream &error_stream) {
+ if (LanguageSupportsClangModules(cu.GetLanguage())) {
+ for (auto &imported_module : cu.GetImportedModules())
+ if (!AddModule(imported_module, &exported_modules, error_stream))
+ return false;
+ }
+ return true;
+}
+
+// ClangImporter::lookupValue
+
+uint32_t
+ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append,
+ uint32_t max_matches,
+ std::vector<CompilerDecl> &decls) {
+ if (!m_enabled)
+ return 0;
+
+ if (!append)
+ decls.clear();
+
+ clang::IdentifierInfo &ident =
+ m_compiler_instance->getASTContext().Idents.get(name.GetStringRef());
+
+ clang::LookupResult lookup_result(
+ m_compiler_instance->getSema(), clang::DeclarationName(&ident),
+ clang::SourceLocation(), clang::Sema::LookupOrdinaryName);
+
+ m_compiler_instance->getSema().LookupName(
+ lookup_result,
+ m_compiler_instance->getSema().getScopeForContext(
+ m_compiler_instance->getASTContext().getTranslationUnitDecl()));
+
+ uint32_t num_matches = 0;
+
+ for (clang::NamedDecl *named_decl : lookup_result) {
+ if (num_matches >= max_matches)
+ return num_matches;
+
+ decls.push_back(m_ast_context->GetCompilerDecl(named_decl));
+ ++num_matches;
+ }
+
+ return num_matches;
+}
+
+void ClangModulesDeclVendorImpl::ForEachMacro(
+ const ClangModulesDeclVendor::ModuleVector &modules,
+ std::function<bool(llvm::StringRef, llvm::StringRef)> handler) {
+ if (!m_enabled)
+ return;
+
+ typedef std::map<ModuleID, ssize_t> ModulePriorityMap;
+ ModulePriorityMap module_priorities;
+
+ ssize_t priority = 0;
+
+ for (ModuleID module : modules)
+ module_priorities[module] = priority++;
+
+ if (m_compiler_instance->getPreprocessor().getExternalSource()) {
+ m_compiler_instance->getPreprocessor()
+ .getExternalSource()
+ ->ReadDefinedMacros();
+ }
+
+ for (clang::Preprocessor::macro_iterator
+ mi = m_compiler_instance->getPreprocessor().macro_begin(),
+ me = m_compiler_instance->getPreprocessor().macro_end();
+ mi != me; ++mi) {
+ const clang::IdentifierInfo *ii = nullptr;
+
+ {
+ if (clang::IdentifierInfoLookup *lookup =
+ m_compiler_instance->getPreprocessor()
+ .getIdentifierTable()
+ .getExternalIdentifierLookup()) {
+ lookup->get(mi->first->getName());
+ }
+ if (!ii)
+ ii = mi->first;
+ }
+
+ ssize_t found_priority = -1;
+ clang::MacroInfo *macro_info = nullptr;
+
+ for (clang::ModuleMacro *module_macro :
+ m_compiler_instance->getPreprocessor().getLeafModuleMacros(ii)) {
+ clang::Module *module = module_macro->getOwningModule();
+
+ {
+ ModulePriorityMap::iterator pi =
+ module_priorities.find(reinterpret_cast<ModuleID>(module));
+
+ if (pi != module_priorities.end() && pi->second > found_priority) {
+ macro_info = module_macro->getMacroInfo();
+ found_priority = pi->second;
+ }
+ }
+
+ clang::Module *top_level_module = module->getTopLevelModule();
+
+ if (top_level_module != module) {
+ ModulePriorityMap::iterator pi = module_priorities.find(
+ reinterpret_cast<ModuleID>(top_level_module));
+
+ if ((pi != module_priorities.end()) && pi->second > found_priority) {
+ macro_info = module_macro->getMacroInfo();
+ found_priority = pi->second;
+ }
+ }
+ }
+
+ if (macro_info) {
+ std::string macro_expansion = "#define ";
+ llvm::StringRef macro_identifier = mi->first->getName();
+ macro_expansion.append(macro_identifier.str());
+
+ {
+ if (macro_info->isFunctionLike()) {
+ macro_expansion.append("(");
+
+ bool first_arg = true;
+
+ for (auto pi = macro_info->param_begin(),
+ pe = macro_info->param_end();
+ pi != pe; ++pi) {
+ if (!first_arg)
+ macro_expansion.append(", ");
+ else
+ first_arg = false;
+
+ macro_expansion.append((*pi)->getName().str());
+ }
+
+ if (macro_info->isC99Varargs()) {
+ if (first_arg)
+ macro_expansion.append("...");
+ else
+ macro_expansion.append(", ...");
+ } else if (macro_info->isGNUVarargs())
+ macro_expansion.append("...");
+
+ macro_expansion.append(")");
+ }
+
+ macro_expansion.append(" ");
+
+ bool first_token = true;
+
+ for (clang::MacroInfo::const_tokens_iterator
+ ti = macro_info->tokens_begin(),
+ te = macro_info->tokens_end();
+ ti != te; ++ti) {
+ if (!first_token)
+ macro_expansion.append(" ");
+ else
+ first_token = false;
+
+ if (ti->isLiteral()) {
+ if (const char *literal_data = ti->getLiteralData()) {
+ std::string token_str(literal_data, ti->getLength());
+ macro_expansion.append(token_str);
+ } else {
+ bool invalid = false;
+ const char *literal_source =
+ m_compiler_instance->getSourceManager().getCharacterData(
+ ti->getLocation(), &invalid);
+
+ if (invalid) {
+ lldbassert(0 && "Unhandled token kind");
+ macro_expansion.append("<unknown literal value>");
+ } else {
+ macro_expansion.append(
+ std::string(literal_source, ti->getLength()));
+ }
+ }
+ } else if (const char *punctuator_spelling =
+ clang::tok::getPunctuatorSpelling(ti->getKind())) {
+ macro_expansion.append(punctuator_spelling);
+ } else if (const char *keyword_spelling =
+ clang::tok::getKeywordSpelling(ti->getKind())) {
+ macro_expansion.append(keyword_spelling);
+ } else {
+ switch (ti->getKind()) {
+ case clang::tok::TokenKind::identifier:
+ macro_expansion.append(ti->getIdentifierInfo()->getName().str());
+ break;
+ case clang::tok::TokenKind::raw_identifier:
+ macro_expansion.append(ti->getRawIdentifier().str());
+ break;
+ default:
+ macro_expansion.append(ti->getName());
+ break;
+ }
+ }
+ }
+
+ if (handler(macro_identifier, macro_expansion)) {
+ return;
+ }
+ }
+ }
+ }
+}
+
+clang::ModuleLoadResult
+ClangModulesDeclVendorImpl::DoGetModule(clang::ModuleIdPath path,
+ bool make_visible) {
+ clang::Module::NameVisibilityKind visibility =
+ make_visible ? clang::Module::AllVisible : clang::Module::Hidden;
+
+ const bool is_inclusion_directive = false;
+
+ return m_compiler_instance->loadModule(path.front().second, path, visibility,
+ is_inclusion_directive);
+}
+
+static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer";
+
+lldb_private::ClangModulesDeclVendor *
+ClangModulesDeclVendor::Create(Target &target) {
+ // FIXME we should insure programmatically that the expression parser's
+ // compiler and the modules runtime's
+ // compiler are both initialized in the same way – preferably by the same
+ // code.
+
+ if (!target.GetPlatform()->SupportsModules())
+ return nullptr;
+
+ const ArchSpec &arch = target.GetArchitecture();
+
+ std::vector<std::string> compiler_invocation_arguments = {
+ "clang",
+ "-fmodules",
+ "-fimplicit-module-maps",
+ "-fcxx-modules",
+ "-fsyntax-only",
+ "-femit-all-decls",
+ "-target",
+ arch.GetTriple().str(),
+ "-fmodules-validate-system-headers",
+ "-Werror=non-modular-include-in-framework-module",
+ "-Xclang=-fincremental-extensions",
+ "-Rmodule-build"};
+
+ target.GetPlatform()->AddClangModuleCompilationOptions(
+ &target, compiler_invocation_arguments);
+
+ compiler_invocation_arguments.push_back(ModuleImportBufferName);
+
+ // Add additional search paths with { "-I", path } or { "-F", path } here.
+
+ {
+ llvm::SmallString<128> path;
+ const auto &props = ModuleList::GetGlobalModuleListProperties();
+ props.GetClangModulesCachePath().GetPath(path);
+ std::string module_cache_argument("-fmodules-cache-path=");
+ module_cache_argument.append(std::string(path.str()));
+ compiler_invocation_arguments.push_back(module_cache_argument);
+ }
+
+ 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);
+
+ std::string search_path_argument = "-I";
+ search_path_argument.append(search_path.GetPath());
+
+ compiler_invocation_arguments.push_back(search_path_argument);
+ }
+
+ {
+ FileSpec clang_resource_dir = GetClangResourceDir();
+
+ if (FileSystem::Instance().IsDirectory(clang_resource_dir.GetPath())) {
+ compiler_invocation_arguments.push_back("-resource-dir");
+ compiler_invocation_arguments.push_back(clang_resource_dir.GetPath());
+ }
+ }
+
+ 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)
+ compiler_invocation_argument_cstrs.push_back(arg.c_str());
+
+ auto diag_options_up =
+ clang::CreateAndPopulateDiagOpts(compiler_invocation_argument_cstrs);
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
+ clang::CompilerInstance::createDiagnostics(diag_options_up.release(),
+ new StoringDiagnosticConsumer);
+
+ Log *log = GetLog(LLDBLog::Expressions);
+ LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}",
+ llvm::make_range(compiler_invocation_arguments.begin(),
+ compiler_invocation_arguments.end()));
+
+ clang::CreateInvocationOptions CIOpts;
+ CIOpts.Diags = diagnostics_engine;
+ std::shared_ptr<clang::CompilerInvocation> invocation =
+ clang::createInvocation(compiler_invocation_argument_cstrs,
+ std::move(CIOpts));
+
+ if (!invocation)
+ return nullptr;
+
+ std::unique_ptr<llvm::MemoryBuffer> source_buffer =
+ llvm::MemoryBuffer::getMemBuffer(
+ "extern int __lldb __attribute__((unavailable));",
+ ModuleImportBufferName);
+
+ invocation->getPreprocessorOpts().addRemappedFile(ModuleImportBufferName,
+ source_buffer.release());
+
+ std::unique_ptr<clang::CompilerInstance> instance(
+ new clang::CompilerInstance);
+
+ // Make sure clang uses the same VFS as LLDB.
+ instance->createFileManager(FileSystem::Instance().GetVirtualFileSystem());
+ instance->setDiagnostics(diagnostics_engine.get());
+ instance->setInvocation(invocation);
+
+ std::unique_ptr<clang::FrontendAction> action(new clang::SyntaxOnlyAction);
+
+ instance->setTarget(clang::TargetInfo::CreateTargetInfo(
+ *diagnostics_engine, instance->getInvocation().TargetOpts));
+
+ if (!instance->hasTarget())
+ return nullptr;
+
+ instance->getTarget().adjust(*diagnostics_engine, instance->getLangOpts());
+
+ if (!action->BeginSourceFile(*instance,
+ instance->getFrontendOpts().Inputs[0]))
+ return nullptr;
+
+ instance->createASTReader();
+
+ instance->createSema(action->getTranslationUnitKind(), nullptr);
+
+ const bool skipFunctionBodies = false;
+ std::unique_ptr<clang::Parser> parser(new clang::Parser(
+ instance->getPreprocessor(), instance->getSema(), skipFunctionBodies));
+
+ instance->getPreprocessor().EnterMainSourceFile();
+ parser->Initialize();
+
+ clang::Parser::DeclGroupPtrTy parsed;
+ auto ImportState = clang::Sema::ModuleImportState::NotACXX20Module;
+ while (!parser->ParseTopLevelDecl(parsed, ImportState))
+ ;
+
+ return new ClangModulesDeclVendorImpl(std::move(diagnostics_engine),
+ std::move(invocation),
+ std::move(instance), std::move(parser));
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
new file mode 100644
index 000000000000..d820552a2912
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
@@ -0,0 +1,115 @@
+//===-- ClangModulesDeclVendor.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H
+
+#include "lldb/Symbol/SourceModule.h"
+#include "lldb/Target/Platform.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h"
+
+#include <set>
+#include <vector>
+
+namespace lldb_private {
+
+class ClangModulesDeclVendor : public ClangDeclVendor {
+public:
+ // Constructors and Destructors
+ ClangModulesDeclVendor();
+
+ ~ClangModulesDeclVendor() override;
+
+ static bool classof(const DeclVendor *vendor) {
+ return vendor->GetKind() == eClangModuleDeclVendor;
+ }
+
+ static ClangModulesDeclVendor *Create(Target &target);
+
+ typedef std::vector<ConstString> ModulePath;
+ typedef uintptr_t ModuleID;
+ typedef std::vector<ModuleID> ModuleVector;
+
+ /// Add a module to the list of modules to search.
+ ///
+ /// \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
+ /// 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
+ /// A stream to populate with the output of the Clang parser when
+ /// it tries to load the module.
+ ///
+ /// \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(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
+ /// The compilation unit to scan for imported 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
+ /// A stream to populate with the output of the Clang parser when
+ /// it tries to load the modules.
+ ///
+ /// \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
+ /// 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
+ /// A function to call with the identifier of this macro and 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(llvm::StringRef, llvm::StringRef)> 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 given compile unit.
+ ///
+ /// \param[in] language
+ /// The language to query for.
+ ///
+ /// \return
+ /// True if Clang has modules for the given language.
+ static bool LanguageSupportsClangModules(lldb::LanguageType language);
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
new file mode 100644
index 000000000000..aa0e6e37d63e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
@@ -0,0 +1,136 @@
+//===-- ClangPersistentVariables.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangPersistentVariables.h"
+#include "ClangASTImporter.h"
+#include "ClangModulesDeclVendor.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "clang/AST/Decl.h"
+
+#include "llvm/ADT/StringMap.h"
+#include <optional>
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+char ClangPersistentVariables::ID;
+
+ClangPersistentVariables::ClangPersistentVariables(
+ std::shared_ptr<Target> target_sp)
+ : m_target_sp(target_sp) {}
+
+ExpressionVariableSP ClangPersistentVariables::CreatePersistentVariable(
+ const lldb::ValueObjectSP &valobj_sp) {
+ return AddNewlyConstructedVariable(new ClangExpressionVariable(valobj_sp));
+}
+
+ExpressionVariableSP ClangPersistentVariables::CreatePersistentVariable(
+ ExecutionContextScope *exe_scope, ConstString name,
+ const CompilerType &compiler_type, lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size) {
+ return AddNewlyConstructedVariable(new ClangExpressionVariable(
+ exe_scope, name, compiler_type, byte_order, addr_byte_size));
+}
+
+void ClangPersistentVariables::RemovePersistentVariable(
+ lldb::ExpressionVariableSP variable) {
+ RemoveVariable(variable);
+
+ // Check if the removed variable was the last one that was created. If yes,
+ // reuse the variable id for the next variable.
+
+ // Nothing to do if we have not assigned a variable id so far.
+ if (m_next_persistent_variable_id == 0)
+ return;
+
+ llvm::StringRef name = variable->GetName().GetStringRef();
+ // Remove the prefix from the variable that only the indes is left.
+ if (!name.consume_front(GetPersistentVariablePrefix(false)))
+ return;
+
+ // Check if the variable contained a variable id.
+ uint32_t variable_id;
+ if (name.getAsInteger(10, variable_id))
+ return;
+ // If it's the most recent variable id that was assigned, make sure that this
+ // variable id will be used for the next persistent variable.
+ if (variable_id == m_next_persistent_variable_id - 1)
+ m_next_persistent_variable_id--;
+}
+
+std::optional<CompilerType>
+ClangPersistentVariables::GetCompilerTypeFromPersistentDecl(
+ ConstString type_name) {
+ PersistentDecl p = m_persistent_decls.lookup(type_name.GetCString());
+
+ if (p.m_decl == nullptr)
+ return std::nullopt;
+
+ if (clang::TypeDecl *tdecl = llvm::dyn_cast<clang::TypeDecl>(p.m_decl)) {
+ opaque_compiler_type_t t = static_cast<opaque_compiler_type_t>(
+ const_cast<clang::Type *>(tdecl->getTypeForDecl()));
+ return CompilerType(p.m_context, t);
+ }
+ return std::nullopt;
+}
+
+void ClangPersistentVariables::RegisterPersistentDecl(
+ ConstString name, clang::NamedDecl *decl,
+ std::shared_ptr<TypeSystemClang> ctx) {
+ PersistentDecl p = {decl, ctx};
+ m_persistent_decls.insert(std::make_pair(name.GetCString(), p));
+
+ if (clang::EnumDecl *enum_decl = llvm::dyn_cast<clang::EnumDecl>(decl)) {
+ for (clang::EnumConstantDecl *enumerator_decl : enum_decl->enumerators()) {
+ p = {enumerator_decl, ctx};
+ m_persistent_decls.insert(std::make_pair(
+ ConstString(enumerator_decl->getNameAsString()).GetCString(), p));
+ }
+ }
+}
+
+clang::NamedDecl *
+ClangPersistentVariables::GetPersistentDecl(ConstString name) {
+ return m_persistent_decls.lookup(name.GetCString()).m_decl;
+}
+
+std::shared_ptr<ClangASTImporter>
+ClangPersistentVariables::GetClangASTImporter() {
+ if (!m_ast_importer_sp) {
+ m_ast_importer_sp = std::make_shared<ClangASTImporter>();
+ }
+ return m_ast_importer_sp;
+}
+
+std::shared_ptr<ClangModulesDeclVendor>
+ClangPersistentVariables::GetClangModulesDeclVendor() {
+ if (!m_modules_decl_vendor_sp) {
+ m_modules_decl_vendor_sp.reset(
+ ClangModulesDeclVendor::Create(*m_target_sp));
+ }
+ return m_modules_decl_vendor_sp;
+}
+
+ConstString
+ClangPersistentVariables::GetNextPersistentVariableName(bool is_error) {
+ llvm::SmallString<64> name;
+ {
+ llvm::raw_svector_ostream os(name);
+ os << GetPersistentVariablePrefix(is_error)
+ << m_next_persistent_variable_id++;
+ }
+ return ConstString(name);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h
new file mode 100644
index 000000000000..abeb431ccc08
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h
@@ -0,0 +1,119 @@
+//===-- ClangPersistentVariables.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H
+
+#include "llvm/ADT/DenseMap.h"
+
+#include "ClangExpressionVariable.h"
+#include "ClangModulesDeclVendor.h"
+
+#include "lldb/Expression/ExpressionVariable.h"
+#include <optional>
+
+namespace lldb_private {
+
+class ClangASTImporter;
+class ClangModulesDeclVendor;
+class Target;
+class TypeSystemClang;
+
+/// \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 llvm::RTTIExtends<ClangPersistentVariables,
+ PersistentExpressionState> {
+public:
+ // LLVM RTTI support
+ static char ID;
+
+ ClangPersistentVariables(std::shared_ptr<Target> target_sp);
+
+ ~ClangPersistentVariables() override = default;
+
+ std::shared_ptr<ClangASTImporter> GetClangASTImporter();
+ std::shared_ptr<ClangModulesDeclVendor> GetClangModulesDeclVendor();
+
+ lldb::ExpressionVariableSP
+ CreatePersistentVariable(const lldb::ValueObjectSP &valobj_sp) override;
+
+ lldb::ExpressionVariableSP CreatePersistentVariable(
+ ExecutionContextScope *exe_scope, ConstString name,
+ const CompilerType &compiler_type, lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size) override;
+
+ void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override;
+
+ ConstString GetNextPersistentVariableName(bool is_error = false) override;
+
+ /// Returns the next file name that should be used for user expressions.
+ std::string GetNextExprFileName() {
+ std::string name;
+ name.append("<user expression ");
+ name.append(std::to_string(m_next_user_file_id++));
+ name.append(">");
+ return name;
+ }
+
+ std::optional<CompilerType>
+ GetCompilerTypeFromPersistentDecl(ConstString type_name) override;
+
+ void RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl,
+ std::shared_ptr<TypeSystemClang> ctx);
+
+ clang::NamedDecl *GetPersistentDecl(ConstString name);
+
+ void AddHandLoadedClangModule(ClangModulesDeclVendor::ModuleID module) {
+ m_hand_loaded_clang_modules.push_back(module);
+ }
+
+ const ClangModulesDeclVendor::ModuleVector &GetHandLoadedClangModules() {
+ return m_hand_loaded_clang_modules;
+ }
+
+protected:
+ llvm::StringRef
+ GetPersistentVariablePrefix(bool is_error = false) const override {
+ return "$";
+ }
+
+private:
+ /// The counter used by GetNextExprFileName.
+ uint32_t m_next_user_file_id = 0;
+ // The counter used by GetNextPersistentVariableName
+ uint32_t m_next_persistent_variable_id = 0;
+
+ struct PersistentDecl {
+ /// The persistent decl.
+ clang::NamedDecl *m_decl = nullptr;
+ /// The TypeSystemClang for the ASTContext of m_decl.
+ lldb::TypeSystemWP m_context;
+ };
+
+ typedef llvm::DenseMap<const char *, PersistentDecl> PersistentDeclMap;
+ PersistentDeclMap
+ m_persistent_decls; ///< Persistent entities declared by the user.
+
+ ClangModulesDeclVendor::ModuleVector
+ m_hand_loaded_clang_modules; ///< These are Clang modules we hand-loaded;
+ ///these are the highest-
+ ///< priority source for macros.
+ std::shared_ptr<ClangASTImporter> m_ast_importer_sp;
+ std::shared_ptr<ClangModulesDeclVendor> m_modules_decl_vendor_sp;
+ std::shared_ptr<Target> m_target_sp;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
new file mode 100644
index 000000000000..35038a56440d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -0,0 +1,1002 @@
+//===-- ClangUserExpression.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdio>
+#include <sys/types.h>
+
+#include <cstdlib>
+#include <map>
+#include <string>
+
+#include "ClangUserExpression.h"
+
+#include "ASTResultSynthesizer.h"
+#include "ClangASTMetadata.h"
+#include "ClangDiagnostic.h"
+#include "ClangExpressionDeclMap.h"
+#include "ClangExpressionParser.h"
+#include "ClangModulesDeclVendor.h"
+#include "ClangPersistentVariables.h"
+#include "CppModuleConfiguration.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Expression/ExpressionSourceCode.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallUserExpression.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+
+using namespace lldb_private;
+
+char ClangUserExpression::ID;
+
+ClangUserExpression::ClangUserExpression(
+ ExecutionContextScope &exe_scope, llvm::StringRef expr,
+ llvm::StringRef prefix, SourceLanguage language, 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(), options.GetExecutionPolicy() ==
+ eExecutionPolicyTopLevel),
+ m_result_delegate(exe_scope.CalculateTarget()), m_ctx_obj(ctx_obj) {
+ switch (m_language.name) {
+ case llvm::dwarf::DW_LNAME_C_plus_plus:
+ m_allow_cxx = true;
+ break;
+ case llvm::dwarf::DW_LNAME_ObjC:
+ m_allow_objc = true;
+ break;
+ case llvm::dwarf::DW_LNAME_ObjC_plus_plus:
+ default:
+ m_allow_cxx = true;
+ m_allow_objc = true;
+ break;
+ }
+}
+
+ClangUserExpression::~ClangUserExpression() = default;
+
+void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOGF(log, "ClangUserExpression::ScanContext()");
+
+ m_target = exe_ctx.GetTargetPtr();
+
+ if (!(m_allow_cxx || m_allow_objc)) {
+ LLDB_LOGF(log, " [CUE::SC] Settings inhibit C++ and Objective-C");
+ return;
+ }
+
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame == nullptr) {
+ LLDB_LOGF(log, " [CUE::SC] Null stack frame");
+ return;
+ }
+
+ SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |
+ lldb::eSymbolContextBlock);
+
+ if (!sym_ctx.function) {
+ LLDB_LOGF(log, " [CUE::SC] Null function");
+ return;
+ }
+
+ // Find the block that defines the function represented by "sym_ctx"
+ Block *function_block = sym_ctx.GetFunctionBlock();
+
+ if (!function_block) {
+ LLDB_LOGF(log, " [CUE::SC] Null function block");
+ return;
+ }
+
+ CompilerDeclContext decl_context = function_block->GetDeclContext();
+
+ if (!decl_context) {
+ LLDB_LOGF(log, " [CUE::SC] Null decl context");
+ return;
+ }
+
+ 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 =
+ TypeSystemClang::DeclContextGetAsCXXMethodDecl(decl_context)) {
+ if (m_allow_cxx && method_decl->isInstance()) {
+ if (m_enforce_valid_object) {
+ lldb::VariableListSP variable_list_sp(
+ function_block->GetBlockVariableList(true));
+
+ const char *thisErrorString = "Stopped in a C++ method, but 'this' "
+ "isn't available; pretending we are in a "
+ "generic context";
+
+ if (!variable_list_sp) {
+ err.SetErrorString(thisErrorString);
+ return;
+ }
+
+ lldb::VariableSP this_var_sp(
+ variable_list_sp->FindVariable(ConstString("this")));
+
+ if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
+ !this_var_sp->LocationIsValidForFrame(frame)) {
+ err.SetErrorString(thisErrorString);
+ return;
+ }
+ }
+
+ m_in_cplusplus_method = true;
+ m_needs_object_ptr = true;
+ }
+ } else if (clang::ObjCMethodDecl *method_decl =
+ TypeSystemClang::DeclContextGetAsObjCMethodDecl(
+ decl_context)) {
+ if (m_allow_objc) {
+ if (m_enforce_valid_object) {
+ lldb::VariableListSP variable_list_sp(
+ function_block->GetBlockVariableList(true));
+
+ const char *selfErrorString = "Stopped in an Objective-C method, but "
+ "'self' isn't available; pretending we "
+ "are in a generic context";
+
+ if (!variable_list_sp) {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ lldb::VariableSP self_variable_sp =
+ variable_list_sp->FindVariable(ConstString("self"));
+
+ if (!self_variable_sp || !self_variable_sp->IsInScope(frame) ||
+ !self_variable_sp->LocationIsValidForFrame(frame)) {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+ }
+
+ m_in_objectivec_method = true;
+ m_needs_object_ptr = true;
+
+ if (!method_decl->isInstanceMethod())
+ m_in_static_method = true;
+ }
+ } else if (clang::FunctionDecl *function_decl =
+ TypeSystemClang::DeclContextGetAsFunctionDecl(decl_context)) {
+ // We might also have a function that said in the debug information that it
+ // captured an object pointer. The best way to deal with getting to the
+ // ivars at present is by pretending that this is a method of a class in
+ // whatever runtime the debug info says the object pointer belongs to. Do
+ // that here.
+
+ ClangASTMetadata *metadata =
+ TypeSystemClang::DeclContextGetMetaData(decl_context, function_decl);
+ if (metadata && metadata->HasObjectPtr()) {
+ lldb::LanguageType language = metadata->GetObjectPtrLanguage();
+ if (language == lldb::eLanguageTypeC_plus_plus) {
+ if (m_enforce_valid_object) {
+ lldb::VariableListSP variable_list_sp(
+ function_block->GetBlockVariableList(true));
+
+ const char *thisErrorString = "Stopped in a context claiming to "
+ "capture a C++ object pointer, but "
+ "'this' isn't available; pretending we "
+ "are in a generic context";
+
+ if (!variable_list_sp) {
+ err.SetErrorString(thisErrorString);
+ return;
+ }
+
+ lldb::VariableSP this_var_sp(
+ variable_list_sp->FindVariable(ConstString("this")));
+
+ if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
+ !this_var_sp->LocationIsValidForFrame(frame)) {
+ err.SetErrorString(thisErrorString);
+ return;
+ }
+ }
+
+ m_in_cplusplus_method = true;
+ m_needs_object_ptr = true;
+ } else if (language == lldb::eLanguageTypeObjC) {
+ if (m_enforce_valid_object) {
+ lldb::VariableListSP variable_list_sp(
+ function_block->GetBlockVariableList(true));
+
+ const char *selfErrorString =
+ "Stopped in a context claiming to capture an Objective-C object "
+ "pointer, but 'self' isn't available; pretending we are in a "
+ "generic context";
+
+ if (!variable_list_sp) {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ lldb::VariableSP self_variable_sp =
+ variable_list_sp->FindVariable(ConstString("self"));
+
+ if (!self_variable_sp || !self_variable_sp->IsInScope(frame) ||
+ !self_variable_sp->LocationIsValidForFrame(frame)) {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ Type *self_type = self_variable_sp->GetType();
+
+ if (!self_type) {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ CompilerType self_clang_type = self_type->GetForwardCompilerType();
+
+ if (!self_clang_type) {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ if (TypeSystemClang::IsObjCClassType(self_clang_type)) {
+ return;
+ } else if (TypeSystemClang::IsObjCObjectPointerType(
+ self_clang_type)) {
+ m_in_objectivec_method = true;
+ m_needs_object_ptr = true;
+ } else {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+ } else {
+ m_in_objectivec_method = true;
+ m_needs_object_ptr = true;
+ }
+ }
+ }
+ }
+}
+
+// This is a really nasty hack, meant to fix Objective-C expressions of the
+// form (int)[myArray count]. Right now, because the type information for
+// count is not available, [myArray count] returns id, which can't be directly
+// cast to int without causing a clang error.
+static void ApplyObjcCastHack(std::string &expr) {
+ const std::string from = "(int)[";
+ const std::string to = "(int)(long long)[";
+
+ size_t offset;
+
+ while ((offset = expr.find(from)) != expr.npos)
+ expr.replace(offset, from.size(), to);
+}
+
+bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_manager,
+ ExecutionContext &exe_ctx) {
+ if (Target *target = exe_ctx.GetTargetPtr()) {
+ if (PersistentExpressionState *persistent_state =
+ target->GetPersistentExpressionStateForLanguage(
+ lldb::eLanguageTypeC)) {
+ m_clang_state = llvm::cast<ClangPersistentVariables>(persistent_state);
+ m_result_delegate.RegisterPersistentState(persistent_state);
+ } else {
+ diagnostic_manager.PutString(
+ lldb::eSeverityError, "couldn't start parsing (no persistent data)");
+ return false;
+ }
+ } else {
+ diagnostic_manager.PutString(lldb::eSeverityError,
+ "error: couldn't start parsing (no target)");
+ return false;
+ }
+ return true;
+}
+
+static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target,
+ DiagnosticManager &diagnostic_manager) {
+ if (!target->GetEnableAutoImportClangModules())
+ return;
+
+ auto *persistent_state = llvm::cast<ClangPersistentVariables>(
+ target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
+ if (!persistent_state)
+ return;
+
+ std::shared_ptr<ClangModulesDeclVendor> decl_vendor =
+ persistent_state->GetClangModulesDeclVendor();
+ if (!decl_vendor)
+ 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;
+ StreamString error_stream;
+
+ ClangModulesDeclVendor::ModuleVector modules_for_macros =
+ persistent_state->GetHandLoadedClangModules();
+ if (decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros,
+ error_stream))
+ return;
+
+ // Failed to load some modules, so emit the error stream as a diagnostic.
+ if (!error_stream.Empty()) {
+ // The error stream already contains several Clang diagnostics that might
+ // be either errors or warnings, so just print them all as one remark
+ // diagnostic to prevent that the message starts with "error: error:".
+ diagnostic_manager.PutString(lldb::eSeverityInfo, error_stream.GetString());
+ return;
+ }
+
+ diagnostic_manager.PutString(lldb::eSeverityError,
+ "Unknown error while loading modules needed for "
+ "current compilation unit.");
+}
+
+ClangExpressionSourceCode::WrapKind ClangUserExpression::GetWrapKind() const {
+ assert(m_options.GetExecutionPolicy() != eExecutionPolicyTopLevel &&
+ "Top level expressions aren't wrapped.");
+ using Kind = ClangExpressionSourceCode::WrapKind;
+ if (m_in_cplusplus_method)
+ return Kind::CppMemberFunction;
+ else if (m_in_objectivec_method) {
+ if (m_in_static_method)
+ return Kind::ObjCStaticMethod;
+ return Kind::ObjCInstanceMethod;
+ }
+ // Not in any kind of 'special' function, so just wrap it in a normal C
+ // function.
+ return Kind::Function;
+}
+
+void ClangUserExpression::CreateSourceCode(
+ DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
+ std::vector<std::string> modules_to_import, bool for_completion) {
+
+ std::string prefix = m_expr_prefix;
+
+ if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
+ m_transformed_text = m_expr_text;
+ } else {
+ m_source_code.reset(ClangExpressionSourceCode::CreateWrapped(
+ m_filename, prefix, m_expr_text, GetWrapKind()));
+
+ if (!m_source_code->GetText(m_transformed_text, exe_ctx, !m_ctx_obj,
+ for_completion, modules_to_import)) {
+ diagnostic_manager.PutString(lldb::eSeverityError,
+ "couldn't construct expression body");
+ return;
+ }
+
+ // Find and store the start position of the original code inside the
+ // transformed code. We need this later for the code completion.
+ std::size_t original_start;
+ std::size_t original_end;
+ bool found_bounds = m_source_code->GetOriginalBodyBounds(
+ m_transformed_text, original_start, original_end);
+ 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;
+ }
+}
+
+/// Utility method that puts a message into the expression log and
+/// returns an invalid module configuration.
+static CppModuleConfiguration LogConfigError(const std::string &msg) {
+ Log *log = GetLog(LLDBLog::Expressions);
+ LLDB_LOG(log, "[C++ module config] {0}", msg);
+ return CppModuleConfiguration();
+}
+
+CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,
+ ExecutionContext &exe_ctx) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ // Don't do anything if this is not a C++ module configuration.
+ if (!SupportsCxxModuleImport(language))
+ return LogConfigError("Language doesn't support C++ modules");
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (!target)
+ return LogConfigError("No target");
+
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (!frame)
+ return LogConfigError("No frame");
+
+ Block *block = frame->GetFrameBlock();
+ if (!block)
+ return LogConfigError("No block");
+
+ SymbolContext sc;
+ block->CalculateSymbolContext(&sc);
+ if (!sc.comp_unit)
+ return LogConfigError("Couldn't calculate symbol context");
+
+ // Build a list of files we need to analyze to build the configuration.
+ FileSpecList files;
+ for (auto &f : sc.comp_unit->GetSupportFiles())
+ files.AppendIfUnique(f->Materialize());
+ // We also need to look at external modules in the case of -gmodules as they
+ // contain the support files for libc++ and the C library.
+ llvm::DenseSet<SymbolFile *> visited_symbol_files;
+ sc.comp_unit->ForEachExternalModule(
+ visited_symbol_files, [&files](Module &module) {
+ for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) {
+ const SupportFileList &support_files =
+ module.GetCompileUnitAtIndex(i)->GetSupportFiles();
+ for (auto &f : support_files) {
+ files.AppendIfUnique(f->Materialize());
+ }
+ }
+ return false;
+ });
+
+ LLDB_LOG(log, "[C++ module config] Found {0} support files to analyze",
+ files.GetSize());
+ if (log && log->GetVerbose()) {
+ for (auto &f : files)
+ LLDB_LOGV(log, "[C++ module config] Analyzing support file: {0}",
+ f.GetPath());
+ }
+
+ // Try to create a configuration from the files. If there is no valid
+ // configuration possible with the files, this just returns an invalid
+ // configuration.
+ return CppModuleConfiguration(files, target->GetArchitecture().GetTriple());
+}
+
+bool ClangUserExpression::PrepareForParsing(
+ DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
+ bool for_completion) {
+ InstallContext(exe_ctx);
+
+ if (!SetupPersistentState(diagnostic_manager, exe_ctx))
+ return false;
+
+ Status err;
+ ScanContext(exe_ctx, err);
+
+ if (!err.Success()) {
+ diagnostic_manager.PutString(lldb::eSeverityWarning, err.AsCString());
+ }
+
+ ////////////////////////////////////
+ // Generate the expression
+ //
+
+ ApplyObjcCastHack(m_expr_text);
+
+ SetupDeclVendor(exe_ctx, m_target, diagnostic_manager);
+
+ m_filename = m_clang_state->GetNextExprFileName();
+
+ if (m_target->GetImportStdModule() == eImportStdModuleTrue)
+ SetupCppModuleImports(exe_ctx);
+
+ CreateSourceCode(diagnostic_manager, exe_ctx, m_imported_cpp_modules,
+ for_completion);
+ return true;
+}
+
+bool ClangUserExpression::TryParse(
+ DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory,
+ bool generate_debug_info) {
+ m_materializer_up = std::make_unique<Materializer>();
+
+ ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory);
+
+ auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); });
+
+ if (!DeclMap()->WillParse(exe_ctx, GetMaterializer())) {
+ diagnostic_manager.PutString(
+ lldb::eSeverityError,
+ "current process state is unsuitable for expression parsing");
+ return false;
+ }
+
+ if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
+ DeclMap()->SetLookupsEnabled(true);
+ }
+
+ m_parser = std::make_unique<ClangExpressionParser>(
+ exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info,
+ m_include_directories, m_filename);
+
+ unsigned num_errors = m_parser->Parse(diagnostic_manager);
+
+ // Check here for FixItHints. If there are any try to apply the fixits and
+ // set the fixed text in m_fixed_text before returning an error.
+ if (num_errors) {
+ if (diagnostic_manager.HasFixIts()) {
+ if (m_parser->RewriteExpression(diagnostic_manager)) {
+ size_t fixed_start;
+ size_t fixed_end;
+ m_fixed_text = diagnostic_manager.GetFixedExpression();
+ // Retrieve the original expression in case we don't have a top level
+ // expression (which has no surrounding source code).
+ if (m_source_code && m_source_code->GetOriginalBodyBounds(
+ m_fixed_text, fixed_start, fixed_end))
+ m_fixed_text =
+ m_fixed_text.substr(fixed_start, fixed_end - fixed_start);
+ }
+ }
+ return false;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Prepare the output of the parser for execution, evaluating it statically
+ // if possible
+ //
+
+ {
+ Status jit_error = m_parser->PrepareForExecution(
+ m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
+ m_can_interpret, execution_policy);
+
+ if (!jit_error.Success()) {
+ const char *error_cstr = jit_error.AsCString();
+ if (error_cstr && error_cstr[0])
+ diagnostic_manager.PutString(lldb::eSeverityError, error_cstr);
+ else
+ diagnostic_manager.PutString(lldb::eSeverityError,
+ "expression can't be interpreted or run");
+ return false;
+ }
+ }
+ return true;
+}
+
+void ClangUserExpression::SetupCppModuleImports(ExecutionContext &exe_ctx) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ CppModuleConfiguration module_config =
+ GetModuleConfig(m_language.AsLanguageType(), exe_ctx);
+ m_imported_cpp_modules = module_config.GetImportedModules();
+ m_include_directories = module_config.GetIncludeDirs();
+
+ LLDB_LOG(log, "List of imported modules in expression: {0}",
+ llvm::make_range(m_imported_cpp_modules.begin(),
+ m_imported_cpp_modules.end()));
+ LLDB_LOG(log, "List of include directories gathered for modules: {0}",
+ llvm::make_range(m_include_directories.begin(),
+ m_include_directories.end()));
+}
+
+static bool shouldRetryWithCppModule(Target &target, ExecutionPolicy exe_policy) {
+ // Top-level expression don't yet support importing C++ modules.
+ if (exe_policy == ExecutionPolicy::eExecutionPolicyTopLevel)
+ return false;
+ return target.GetImportStdModule() == eImportStdModuleFallback;
+}
+
+bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
+ ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory,
+ bool generate_debug_info) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false))
+ return false;
+
+ LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str());
+
+ ////////////////////////////////////
+ // Set up the target and compiler
+ //
+
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target) {
+ diagnostic_manager.PutString(lldb::eSeverityError, "invalid target");
+ return false;
+ }
+
+ //////////////////////////
+ // Parse the expression
+ //
+
+ bool parse_success = TryParse(diagnostic_manager, exe_ctx, execution_policy,
+ keep_result_in_memory, generate_debug_info);
+ // If the expression failed to parse, check if retrying parsing with a loaded
+ // C++ module is possible.
+ if (!parse_success && shouldRetryWithCppModule(*target, execution_policy)) {
+ // Load the loaded C++ modules.
+ SetupCppModuleImports(exe_ctx);
+ // If we did load any modules, then retry parsing.
+ if (!m_imported_cpp_modules.empty()) {
+ // Create a dedicated diagnostic manager for the second parse attempt.
+ // These diagnostics are only returned to the caller if using the fallback
+ // actually succeeded in getting the expression to parse. This prevents
+ // that module-specific issues regress diagnostic quality with the
+ // fallback mode.
+ DiagnosticManager retry_manager;
+ // The module imports are injected into the source code wrapper,
+ // so recreate those.
+ CreateSourceCode(retry_manager, exe_ctx, m_imported_cpp_modules,
+ /*for_completion*/ false);
+ parse_success = TryParse(retry_manager, exe_ctx, execution_policy,
+ keep_result_in_memory, generate_debug_info);
+ // Return the parse diagnostics if we were successful.
+ if (parse_success)
+ diagnostic_manager = std::move(retry_manager);
+ }
+ }
+ if (!parse_success)
+ return false;
+
+ if (m_execution_unit_sp) {
+ bool register_execution_unit = false;
+
+ if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
+ register_execution_unit = true;
+ }
+
+ // If there is more than one external function in the execution unit, it
+ // needs to keep living even if it's not top level, because the result
+ // could refer to that function.
+
+ if (m_execution_unit_sp->GetJittedFunctions().size() > 1) {
+ register_execution_unit = true;
+ }
+
+ if (register_execution_unit) {
+ if (auto *persistent_state =
+ exe_ctx.GetTargetPtr()->GetPersistentExpressionStateForLanguage(
+ m_language.AsLanguageType()))
+ persistent_state->RegisterExecutionUnit(m_execution_unit_sp);
+ }
+ }
+
+ if (generate_debug_info) {
+ lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
+
+ if (jit_module_sp) {
+ ConstString const_func_name(FunctionName());
+ FileSpec jit_file;
+ jit_file.SetFilename(const_func_name);
+ jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());
+ m_jit_module_wp = jit_module_sp;
+ target->GetImages().Append(jit_module_sp);
+ }
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS)
+ m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+ return true;
+}
+
+/// Converts an absolute position inside a given code string into
+/// a column/line pair.
+///
+/// \param[in] abs_pos
+/// A absolute position in the code string that we want to convert
+/// to a column/line pair.
+///
+/// \param[in] code
+/// A multi-line string usually representing source code.
+///
+/// \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
+/// 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.
+ line = 0;
+ column = 0;
+
+ assert(abs_pos <= code.size() && "Absolute position outside code string?");
+
+ // We have to walk up to the position and count lines/columns.
+ for (std::size_t i = 0; i < abs_pos; ++i) {
+ // If we hit a line break, we go back to column 0 and enter a new line.
+ // We only handle \n because that's what we internally use to make new
+ // lines for our temporary code strings.
+ if (code[i] == '\n') {
+ ++line;
+ column = 0;
+ continue;
+ }
+ ++column;
+ }
+}
+
+bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
+ CompletionRequest &request,
+ unsigned complete_pos) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ // We don't want any visible feedback when completing an expression. Mostly
+ // because the results we get from an incomplete invocation are probably not
+ // correct.
+ DiagnosticManager diagnostic_manager;
+
+ if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ true))
+ return false;
+
+ LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str());
+
+ //////////////////////////
+ // Parse the expression
+ //
+
+ m_materializer_up = std::make_unique<Materializer>();
+
+ ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true);
+
+ auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); });
+
+ if (!DeclMap()->WillParse(exe_ctx, GetMaterializer())) {
+ diagnostic_manager.PutString(
+ lldb::eSeverityError,
+ "current process state is unsuitable for expression parsing");
+
+ return false;
+ }
+
+ if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
+ DeclMap()->SetLookupsEnabled(true);
+ }
+
+ ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
+ false);
+
+ // We have to find the source code location where the user text is inside
+ // the transformed expression code. When creating the transformed text, we
+ // already stored the absolute position in the m_transformed_text string. The
+ // only thing left to do is to transform it into the line:column format that
+ // Clang expects.
+
+ // The line and column of the user expression inside the transformed source
+ // code.
+ unsigned user_expr_line, user_expr_column;
+ if (m_user_expression_start_pos)
+ AbsPosToLineColumnPos(*m_user_expression_start_pos, m_transformed_text,
+ user_expr_line, user_expr_column);
+ else
+ return false;
+
+ // The actual column where we have to complete is the start column of the
+ // user expression + the offset inside the user code that we were given.
+ const unsigned completion_column = user_expr_column + complete_pos;
+ parser.Complete(request, user_expr_line, completion_column, complete_pos);
+
+ return true;
+}
+
+lldb::addr_t ClangUserExpression::GetCppObjectPointer(
+ lldb::StackFrameSP frame_sp, llvm::StringRef object_name, Status &err) {
+ auto valobj_sp =
+ GetObjectPointerValueObject(std::move(frame_sp), object_name, err);
+
+ // We're inside a C++ class method. This could potentially be an unnamed
+ // lambda structure. If the lambda captured a "this", that should be
+ // the object pointer.
+ if (auto thisChildSP = valobj_sp->GetChildMemberWithName("this")) {
+ valobj_sp = thisChildSP;
+ }
+
+ if (!err.Success() || !valobj_sp.get())
+ return LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (ret == LLDB_INVALID_ADDRESS) {
+ err.SetErrorStringWithFormatv(
+ "Couldn't load '{0}' because its value couldn't be evaluated",
+ object_name);
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ return ret;
+}
+
+bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx,
+ std::vector<lldb::addr_t> &args,
+ lldb::addr_t struct_address,
+ DiagnosticManager &diagnostic_manager) {
+ lldb::addr_t object_ptr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t cmd_ptr = LLDB_INVALID_ADDRESS;
+
+ if (m_needs_object_ptr) {
+ lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP();
+ if (!frame_sp)
+ return true;
+
+ if (!m_in_cplusplus_method && !m_in_objectivec_method) {
+ diagnostic_manager.PutString(
+ lldb::eSeverityError,
+ "need object pointer but don't know the language");
+ return false;
+ }
+
+ static constexpr llvm::StringLiteral g_cplusplus_object_name("this");
+ static constexpr llvm::StringLiteral g_objc_object_name("self");
+ llvm::StringRef object_name =
+ m_in_cplusplus_method ? g_cplusplus_object_name : g_objc_object_name;
+
+ Status 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 {
+ if (m_in_cplusplus_method) {
+ object_ptr =
+ GetCppObjectPointer(frame_sp, object_name, object_ptr_error);
+ } else {
+ object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
+ }
+ }
+
+ if (!object_ptr_error.Success()) {
+ exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Format(
+ "warning: `{0}' is not accessible (substituting 0). {1}\n",
+ object_name, object_ptr_error.AsCString());
+ object_ptr = 0;
+ }
+
+ if (m_in_objectivec_method) {
+ static constexpr llvm::StringLiteral cmd_name("_cmd");
+
+ cmd_ptr = GetObjectPointer(frame_sp, cmd_name, object_ptr_error);
+
+ if (!object_ptr_error.Success()) {
+ diagnostic_manager.Printf(
+ lldb::eSeverityWarning,
+ "couldn't get cmd pointer (substituting NULL): %s",
+ object_ptr_error.AsCString());
+ cmd_ptr = 0;
+ }
+ }
+
+ args.push_back(object_ptr);
+
+ if (m_in_objectivec_method)
+ args.push_back(cmd_ptr);
+
+ args.push_back(struct_address);
+ } else {
+ args.push_back(struct_address);
+ }
+ return true;
+}
+
+lldb::ExpressionVariableSP ClangUserExpression::GetResultAfterDematerialization(
+ ExecutionContextScope *exe_scope) {
+ return m_result_delegate.GetVariable();
+}
+
+char ClangUserExpression::ClangUserExpressionHelper::ID;
+
+void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(
+ ExecutionContext &exe_ctx,
+ Materializer::PersistentVariableDelegate &delegate,
+ bool keep_result_in_memory,
+ ValueObject *ctx_obj) {
+ std::shared_ptr<ClangASTImporter> ast_importer;
+ auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage(
+ lldb::eLanguageTypeC);
+ if (state) {
+ auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
+ ast_importer = persistent_vars->GetClangASTImporter();
+ }
+ m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>(
+ keep_result_in_memory, &delegate, exe_ctx.GetTargetSP(), ast_importer,
+ ctx_obj);
+}
+
+clang::ASTConsumer *
+ClangUserExpression::ClangUserExpressionHelper::ASTTransformer(
+ clang::ASTConsumer *passthrough) {
+ m_result_synthesizer_up = std::make_unique<ASTResultSynthesizer>(
+ passthrough, m_top_level, m_target);
+
+ return m_result_synthesizer_up.get();
+}
+
+void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() {
+ if (m_result_synthesizer_up) {
+ m_result_synthesizer_up->CommitPersistentDecls();
+ }
+}
+
+ConstString ClangUserExpression::ResultDelegate::GetName() {
+ return m_persistent_state->GetNextPersistentVariableName(false);
+}
+
+void ClangUserExpression::ResultDelegate::DidDematerialize(
+ lldb::ExpressionVariableSP &variable) {
+ m_variable = variable;
+}
+
+void ClangUserExpression::ResultDelegate::RegisterPersistentState(
+ PersistentExpressionState *persistent_state) {
+ m_persistent_state = persistent_state;
+}
+
+lldb::ExpressionVariableSP &ClangUserExpression::ResultDelegate::GetVariable() {
+ return m_variable;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
new file mode 100644
index 000000000000..09604feea5de
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -0,0 +1,276 @@
+//===-- ClangUserExpression.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H
+
+#include <optional>
+#include <vector>
+
+#include "ASTResultSynthesizer.h"
+#include "ASTStructExtractor.h"
+#include "ClangExpressionDeclMap.h"
+#include "ClangExpressionHelper.h"
+#include "ClangExpressionSourceCode.h"
+#include "ClangExpressionVariable.h"
+#include "IRForTarget.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Expression/LLVMUserExpression.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class ClangExpressionParser;
+
+/// \class ClangUserExpression ClangUserExpression.h
+/// "lldb/Expression/ClangUserExpression.h" Encapsulates a single expression
+/// for use with Clang
+///
+/// LLDB uses expressions for various purposes, notably to call functions
+/// 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 {
+ // LLVM RTTI support
+ static char ID;
+
+public:
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || LLVMUserExpression::isA(ClassID);
+ }
+ static bool classof(const Expression *obj) { return obj->isA(&ID); }
+
+ enum { kDefaultTimeout = 500000u };
+
+ class ClangUserExpressionHelper
+ : public llvm::RTTIExtends<ClangUserExpressionHelper,
+ ClangExpressionHelper> {
+ public:
+ // LLVM RTTI support
+ static char ID;
+
+ ClangUserExpressionHelper(Target &target, bool top_level)
+ : m_target(target), m_top_level(top_level) {}
+
+ /// 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();
+ }
+
+ void ResetDeclMap() { m_expr_decl_map_up.reset(); }
+
+ void ResetDeclMap(ExecutionContext &exe_ctx,
+ Materializer::PersistentVariableDelegate &result_delegate,
+ 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
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ clang::ASTConsumer *
+ ASTTransformer(clang::ASTConsumer *passthrough) override;
+
+ void CommitPersistentDecls() override;
+
+ private:
+ Target &m_target;
+ std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up;
+ std::unique_ptr<ASTStructExtractor> m_struct_extractor_up; ///< The class
+ ///that generates
+ ///the argument
+ ///struct layout.
+ std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer_up;
+ bool m_top_level;
+ };
+
+ /// Constructor
+ ///
+ /// \param[in] expr
+ /// The expression to parse.
+ ///
+ /// \param[in] prefix
+ /// If non-NULL, a C string containing translation-unit level
+ /// definitions to be included when the expression is parsed.
+ ///
+ /// \param[in] language
+ /// If not unknown, a language to use when parsing the
+ /// expression. Currently restricted to those languages
+ /// supported by Clang.
+ ///
+ /// \param[in] desired_type
+ /// If not eResultTypeAny, the type to use for the expression
+ /// result.
+ ///
+ /// \param[in] options
+ /// Additional options for the expression.
+ ///
+ /// \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, SourceLanguage language,
+ ResultType desired_type,
+ const EvaluateExpressionOptions &options,
+ ValueObject *ctx_obj);
+
+ ~ClangUserExpression() override;
+
+ /// Parse the expression
+ ///
+ /// \param[in] diagnostic_manager
+ /// A diagnostic manager to report parse errors and warnings to.
+ ///
+ /// \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
+ /// Determines whether interpretation is possible or mandatory.
+ ///
+ /// \param[in] keep_result_in_memory
+ /// True if the resulting persistent variable should reside in
+ /// target memory, if applicable.
+ ///
+ /// \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;
+
+ bool Complete(ExecutionContext &exe_ctx, CompletionRequest &request,
+ unsigned complete_pos) override;
+
+ ExpressionTypeSystemHelper *GetTypeSystemHelper() override {
+ return &m_type_system_helper;
+ }
+
+ ClangExpressionDeclMap *DeclMap() { return m_type_system_helper.DeclMap(); }
+
+ void ResetDeclMap() { m_type_system_helper.ResetDeclMap(); }
+
+ void ResetDeclMap(ExecutionContext &exe_ctx,
+ Materializer::PersistentVariableDelegate &result_delegate,
+ bool keep_result_in_memory) {
+ m_type_system_helper.ResetDeclMap(exe_ctx, result_delegate,
+ keep_result_in_memory,
+ m_ctx_obj);
+ }
+
+ lldb::ExpressionVariableSP
+ GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override;
+
+ /// Returns true iff this expression is using any imported C++ modules.
+ bool DidImportCxxModules() const { return !m_imported_cpp_modules.empty(); }
+
+private:
+ /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the
+ /// environment.
+
+ /// Contains the actual parsing implementation.
+ /// The parameter have the same meaning as in ClangUserExpression::Parse.
+ /// \see ClangUserExpression::Parse
+ bool TryParse(DiagnosticManager &diagnostic_manager,
+ ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory, bool generate_debug_info);
+
+ void SetupCppModuleImports(ExecutionContext &exe_ctx);
+
+ void ScanContext(ExecutionContext &exe_ctx,
+ lldb_private::Status &err) override;
+
+ bool AddArguments(ExecutionContext &exe_ctx, std::vector<lldb::addr_t> &args,
+ lldb::addr_t struct_address,
+ DiagnosticManager &diagnostic_manager) override;
+
+ void CreateSourceCode(DiagnosticManager &diagnostic_manager,
+ ExecutionContext &exe_ctx,
+ std::vector<std::string> modules_to_import,
+ bool for_completion);
+
+ lldb::addr_t GetCppObjectPointer(lldb::StackFrameSP frame,
+ llvm::StringRef object_name, Status &err);
+
+ /// Defines how the current expression should be wrapped.
+ ClangExpressionSourceCode::WrapKind GetWrapKind() const;
+ bool SetupPersistentState(DiagnosticManager &diagnostic_manager,
+ ExecutionContext &exe_ctx);
+ bool PrepareForParsing(DiagnosticManager &diagnostic_manager,
+ ExecutionContext &exe_ctx, bool for_completion);
+
+ ClangUserExpressionHelper m_type_system_helper;
+
+ class ResultDelegate : public Materializer::PersistentVariableDelegate {
+ public:
+ ResultDelegate(lldb::TargetSP target) : m_target_sp(target) {}
+ ConstString GetName() override;
+ void DidDematerialize(lldb::ExpressionVariableSP &variable) override;
+
+ void RegisterPersistentState(PersistentExpressionState *persistent_state);
+ lldb::ExpressionVariableSP &GetVariable();
+
+ private:
+ PersistentExpressionState *m_persistent_state;
+ lldb::ExpressionVariableSP m_variable;
+ lldb::TargetSP m_target_sp;
+ };
+
+ /// The include directories that should be used when parsing the expression.
+ std::vector<std::string> 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.
+ std::optional<size_t> m_user_expression_start_pos;
+ ResultDelegate m_result_delegate;
+ ClangPersistentVariables *m_clang_state;
+ std::unique_ptr<ClangExpressionSourceCode> m_source_code;
+ /// The parser instance we used to parse the expression.
+ std::unique_ptr<ClangExpressionParser> m_parser;
+ /// File name used for the expression.
+ std::string m_filename;
+
+ /// The object (if any) in which context the expression is evaluated.
+ /// See the comment to `UserExpression::Evaluate` for details.
+ ValueObject *m_ctx_obj;
+
+ /// A list of module names that should be imported when parsing.
+ /// \see CppModuleConfiguration::GetImportedModules
+ std::vector<std::string> m_imported_cpp_modules;
+
+ /// True if the expression parser should enforce the presence of a valid class
+ /// pointer in order to generate the expression as a method.
+ bool m_enforce_valid_object = true;
+ /// True if the expression is compiled as a C++ member function (true if it
+ /// was parsed when exe_ctx was in a C++ method).
+ bool m_in_cplusplus_method = false;
+ /// True if the expression is compiled as an Objective-C method (true if it
+ /// was parsed when exe_ctx was in an Objective-C method).
+ bool m_in_objectivec_method = false;
+ /// True if the expression is compiled as a static (or class) method
+ /// (currently true if it was parsed when exe_ctx was in an Objective-C class
+ /// method).
+ bool m_in_static_method = false;
+ /// True if "this" or "self" must be looked up and passed in. False if the
+ /// expression doesn't really use them and they can be NULL.
+ bool m_needs_object_ptr = false;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
new file mode 100644
index 000000000000..2e0bb318cb50
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
@@ -0,0 +1,87 @@
+//===-- ClangUtil.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// A collection of helper methods and data structures for manipulating clang
+// types and decls.
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+using namespace clang;
+using namespace lldb_private;
+
+bool ClangUtil::IsClangType(const CompilerType &ct) {
+ // Invalid types are never Clang types.
+ if (!ct)
+ return false;
+
+ if (!ct.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>())
+ return false;
+
+ if (!ct.GetOpaqueQualType())
+ return false;
+
+ return true;
+}
+
+clang::Decl *ClangUtil::GetDecl(const CompilerDecl &decl) {
+ assert(llvm::isa<TypeSystemClang>(decl.GetTypeSystem()));
+ return static_cast<clang::Decl *>(decl.GetOpaqueDecl());
+}
+
+QualType ClangUtil::GetQualType(const CompilerType &ct) {
+ // Make sure we have a clang type before making a clang::QualType
+ if (!IsClangType(ct))
+ return QualType();
+
+ return QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
+}
+
+QualType ClangUtil::GetCanonicalQualType(const CompilerType &ct) {
+ if (!IsClangType(ct))
+ return QualType();
+
+ return GetQualType(ct).getCanonicalType();
+}
+
+CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) {
+ if (!IsClangType(ct))
+ return ct;
+
+ QualType qual_type(GetQualType(ct));
+ qual_type.removeLocalFastQualifiers();
+ return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr());
+}
+
+clang::TagDecl *ClangUtil::GetAsTagDecl(const CompilerType &type) {
+ clang::QualType qual_type = ClangUtil::GetCanonicalQualType(type);
+ if (qual_type.isNull())
+ return nullptr;
+
+ return qual_type->getAsTagDecl();
+}
+
+std::string ClangUtil::DumpDecl(const clang::Decl *d) {
+ if (!d)
+ return "nullptr";
+
+ std::string result;
+ llvm::raw_string_ostream stream(result);
+ bool deserialize = false;
+ d->dump(stream, deserialize);
+
+ stream.flush();
+ return result;
+}
+
+std::string ClangUtil::ToString(const clang::Type *t) {
+ return clang::QualType(t, 0).getAsString();
+}
+
+std::string ClangUtil::ToString(const CompilerType &c) {
+ return ClangUtil::GetQualType(c).getAsString();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
new file mode 100644
index 000000000000..50cae42bc7c2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
@@ -0,0 +1,50 @@
+//===-- ClangUtil.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
+//
+// A collection of helper methods and data structures for manipulating clang
+// types and decls.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTIL_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTIL_H
+
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Type.h"
+
+#include "lldb/Symbol/CompilerType.h"
+
+namespace clang {
+class TagDecl;
+}
+
+namespace lldb_private {
+struct ClangUtil {
+ static bool IsClangType(const CompilerType &ct);
+
+ /// Returns the clang::Decl of the given CompilerDecl.
+ /// CompilerDecl has to be valid and represent a clang::Decl.
+ static clang::Decl *GetDecl(const CompilerDecl &decl);
+
+ static clang::QualType GetQualType(const CompilerType &ct);
+
+ static clang::QualType GetCanonicalQualType(const CompilerType &ct);
+
+ static CompilerType RemoveFastQualifiers(const CompilerType &ct);
+
+ static clang::TagDecl *GetAsTagDecl(const CompilerType &type);
+
+ /// Returns a textual representation of the given Decl's AST. Does not
+ /// deserialize any child nodes.
+ static std::string DumpDecl(const clang::Decl *d);
+ /// Returns a textual representation of the given type.
+ static std::string ToString(const clang::Type *t);
+ /// Returns a textual representation of the given CompilerType (assuming
+ /// its underlying type is a Clang type).
+ static std::string ToString(const CompilerType &c);
+};
+}
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
new file mode 100644
index 000000000000..1f44200c4cff
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
@@ -0,0 +1,191 @@
+//===-- ClangUtilityFunction.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangUtilityFunction.h"
+#include "ClangExpressionDeclMap.h"
+#include "ClangExpressionParser.h"
+#include "ClangExpressionSourceCode.h"
+#include "ClangPersistentVariables.h"
+
+#include <cstdio>
+#include <sys/types.h>
+
+
+#include "lldb/Core/Module.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb_private;
+
+char ClangUtilityFunction::ID;
+
+ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope,
+ std::string text, std::string name,
+ bool enable_debugging)
+ : UtilityFunction(
+ exe_scope,
+ std::string(ClangExpressionSourceCode::g_expression_prefix) + text +
+ std::string(ClangExpressionSourceCode::g_expression_suffix),
+ std::move(name), enable_debugging) {
+ // Write the source code to a file so that LLDB's source manager can display
+ // it when debugging the code.
+ if (enable_debugging) {
+ int temp_fd = -1;
+ llvm::SmallString<128> result_path;
+ llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path);
+ if (temp_fd != -1) {
+ lldb_private::NativeFile file(temp_fd, File::eOpenOptionWriteOnly, true);
+ text = "#line 1 \"" + std::string(result_path) + "\"\n" + text;
+ size_t bytes_written = text.size();
+ file.Write(text.c_str(), bytes_written);
+ if (bytes_written == text.size()) {
+ // If we successfully wrote the source to a temporary file, replace the
+ // function text with the next text containing the line directive.
+ m_function_text =
+ std::string(ClangExpressionSourceCode::g_expression_prefix) + text +
+ std::string(ClangExpressionSourceCode::g_expression_suffix);
+ }
+ file.Close();
+ }
+ }
+}
+
+ClangUtilityFunction::~ClangUtilityFunction() = default;
+
+/// Install the utility function into a process
+///
+/// \param[in] diagnostic_manager
+/// A diagnostic manager to report errors and warnings to.
+///
+/// \param[in] exe_ctx
+/// The execution context to install the utility function to.
+///
+/// \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) {
+ diagnostic_manager.PutString(lldb::eSeverityWarning, "already installed");
+ return false;
+ }
+
+ ////////////////////////////////////
+ // Set up the target and compiler
+ //
+
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target) {
+ diagnostic_manager.PutString(lldb::eSeverityError, "invalid target");
+ return false;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (!process) {
+ diagnostic_manager.PutString(lldb::eSeverityError, "invalid process");
+ return false;
+ }
+
+ // Since we might need to call allocate memory and maybe call code to make
+ // the caller, we need to be stopped.
+ if (process->GetState() != lldb::eStateStopped) {
+ diagnostic_manager.PutString(lldb::eSeverityError, "process running");
+ return false;
+ }
+ //////////////////////////
+ // Parse the expression
+ //
+
+ bool keep_result_in_memory = false;
+
+ ResetDeclMap(exe_ctx, keep_result_in_memory);
+
+ if (!DeclMap()->WillParse(exe_ctx, nullptr)) {
+ diagnostic_manager.PutString(
+ lldb::eSeverityError,
+ "current process state is unsuitable for expression parsing");
+ return false;
+ }
+
+ const bool generate_debug_info = true;
+ ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
+ generate_debug_info);
+
+ unsigned num_errors = parser.Parse(diagnostic_manager);
+
+ if (num_errors) {
+ ResetDeclMap();
+
+ return false;
+ }
+
+ //////////////////////////////////
+ // JIT the output of the parser
+ //
+
+ bool can_interpret = false; // should stay that way
+
+ Status jit_error = parser.PrepareForExecution(
+ m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
+ can_interpret, eExecutionPolicyAlways);
+
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
+ m_jit_process_wp = process->shared_from_this();
+ if (parser.GetGenerateDebugInfo()) {
+ lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
+
+ if (jit_module_sp) {
+ ConstString const_func_name(FunctionName());
+ FileSpec jit_file;
+ jit_file.SetFilename(const_func_name);
+ jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());
+ m_jit_module_wp = jit_module_sp;
+ target->GetImages().Append(jit_module_sp);
+ }
+ }
+ }
+
+ DeclMap()->DidParse();
+
+ ResetDeclMap();
+
+ if (jit_error.Success()) {
+ return true;
+ } else {
+ const char *error_cstr = jit_error.AsCString();
+ if (error_cstr && error_cstr[0]) {
+ diagnostic_manager.Printf(lldb::eSeverityError, "%s", error_cstr);
+ } else {
+ diagnostic_manager.PutString(lldb::eSeverityError,
+ "expression can't be interpreted or run");
+ }
+ return false;
+ }
+}
+
+char ClangUtilityFunction::ClangUtilityFunctionHelper::ID;
+
+void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(
+ ExecutionContext &exe_ctx, bool keep_result_in_memory) {
+ std::shared_ptr<ClangASTImporter> ast_importer;
+ auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage(
+ lldb::eLanguageTypeC);
+ if (state) {
+ auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
+ ast_importer = persistent_vars->GetClangASTImporter();
+ }
+ m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>(
+ keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer,
+ nullptr);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h
new file mode 100644
index 000000000000..72ff84f3ceaf
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h
@@ -0,0 +1,113 @@
+//===-- ClangUtilityFunction.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "ClangExpressionHelper.h"
+
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+/// \class ClangUtilityFunction ClangUtilityFunction.h
+/// "lldb/Expression/ClangUtilityFunction.h" Encapsulates a single expression
+/// for use with Clang
+///
+/// LLDB uses expressions for various purposes, notably to call functions
+/// and as a backend for the expr command. ClangUtilityFunction encapsulates
+/// a self-contained function meant to be used from other code. Utility
+/// 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 {
+ // LLVM RTTI support
+ static char ID;
+
+public:
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || UtilityFunction::isA(ClassID);
+ }
+ static bool classof(const Expression *obj) { return obj->isA(&ID); }
+
+ /// Constructor
+ ///
+ /// \param[in] text
+ /// The text of the function. Must be a full translation unit.
+ ///
+ /// \param[in] name
+ /// The name of the function, as used in the text.
+ ///
+ /// \param[in] enable_debugging
+ /// Enable debugging of this function.
+ ClangUtilityFunction(ExecutionContextScope &exe_scope, std::string text,
+ std::string name, bool enable_debugging);
+
+ ~ClangUtilityFunction() override;
+
+ ExpressionTypeSystemHelper *GetTypeSystemHelper() override {
+ return &m_type_system_helper;
+ }
+
+ ClangExpressionDeclMap *DeclMap() { return m_type_system_helper.DeclMap(); }
+
+ void ResetDeclMap() { m_type_system_helper.ResetDeclMap(); }
+
+ void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) {
+ m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory);
+ }
+
+ bool Install(DiagnosticManager &diagnostic_manager,
+ ExecutionContext &exe_ctx) override;
+
+private:
+ class ClangUtilityFunctionHelper
+ : public llvm::RTTIExtends<ClangUtilityFunctionHelper,
+ ClangExpressionHelper> {
+ public:
+ // LLVM RTTI support
+ static char ID;
+
+ /// 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();
+ }
+
+ void ResetDeclMap() { m_expr_decl_map_up.reset(); }
+
+ void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory);
+
+ /// Return the object that the parser should allow to access ASTs. May be
+ /// nullptr if the ASTs do not need to be transformed.
+ ///
+ /// \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;
+ }
+
+ private:
+ std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up;
+ };
+
+ /// The map to use when parsing and materializing the expression.
+ ClangUtilityFunctionHelper m_type_system_helper;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
new file mode 100644
index 000000000000..f3aabc12f92b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp
@@ -0,0 +1,158 @@
+//===-- CppModuleConfiguration.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CppModuleConfiguration.h"
+
+#include "ClangHost.h"
+#include "lldb/Host/FileSystem.h"
+#include "llvm/TargetParser/Triple.h"
+#include <optional>
+
+using namespace lldb_private;
+
+bool CppModuleConfiguration::SetOncePath::TrySet(llvm::StringRef path) {
+ // Setting for the first time always works.
+ if (m_first) {
+ m_path = path.str();
+ m_valid = true;
+ m_first = false;
+ return true;
+ }
+ // Changing the path to the same value is fine.
+ if (m_path == path)
+ return true;
+
+ // Changing the path after it was already set is not allowed.
+ m_valid = false;
+ return false;
+}
+
+static llvm::SmallVector<std::string, 2>
+getTargetIncludePaths(const llvm::Triple &triple) {
+ llvm::SmallVector<std::string, 2> paths;
+ if (!triple.str().empty()) {
+ paths.push_back("/usr/include/" + triple.str());
+ if (!triple.getArchName().empty() ||
+ triple.getOSAndEnvironmentName().empty())
+ paths.push_back(("/usr/include/" + triple.getArchName() + "-" +
+ triple.getOSAndEnvironmentName())
+ .str());
+ }
+ return paths;
+}
+
+/// Returns the include path matching the given pattern for the given file
+/// path (or std::nullopt if the path doesn't match the pattern).
+static std::optional<llvm::StringRef>
+guessIncludePath(llvm::StringRef path_to_file, llvm::StringRef pattern) {
+ if (pattern.empty())
+ return std::nullopt;
+ size_t pos = path_to_file.find(pattern);
+ if (pos == llvm::StringRef::npos)
+ return std::nullopt;
+
+ return path_to_file.substr(0, pos + pattern.size());
+}
+
+bool CppModuleConfiguration::analyzeFile(const FileSpec &f,
+ const llvm::Triple &triple) {
+ using namespace llvm::sys::path;
+ // Convert to slashes to make following operations simpler.
+ std::string dir_buffer = convert_to_slash(f.GetDirectory().GetStringRef());
+ llvm::StringRef posix_dir(dir_buffer);
+
+ // Check for /c++/vX/ that is used by libc++.
+ static llvm::Regex libcpp_regex(R"regex(/c[+][+]/v[0-9]/)regex");
+ // If the path is in the libc++ include directory use it as the found libc++
+ // path. Ignore subdirectories such as /c++/v1/experimental as those don't
+ // need to be specified in the header search.
+ if (libcpp_regex.match(convert_to_slash(f.GetPath())) &&
+ parent_path(posix_dir, Style::posix).ends_with("c++")) {
+ if (!m_std_inc.TrySet(posix_dir))
+ return false;
+ if (triple.str().empty())
+ return true;
+
+ posix_dir.consume_back("c++/v1");
+ // Check if this is a target-specific libc++ include directory.
+ return m_std_target_inc.TrySet(
+ (posix_dir + triple.str() + "/c++/v1").str());
+ }
+
+ std::optional<llvm::StringRef> inc_path;
+ // Target specific paths contains /usr/include, so we check them first
+ for (auto &path : getTargetIncludePaths(triple)) {
+ if ((inc_path = guessIncludePath(posix_dir, path)))
+ return m_c_target_inc.TrySet(*inc_path);
+ }
+ if ((inc_path = guessIncludePath(posix_dir, "/usr/include")))
+ return m_c_inc.TrySet(*inc_path);
+
+ // File wasn't interesting, continue analyzing.
+ return true;
+}
+
+/// Utility function for just appending two paths.
+static std::string MakePath(llvm::StringRef lhs, llvm::StringRef rhs) {
+ llvm::SmallString<256> result(lhs);
+ llvm::sys::path::append(result, rhs);
+ return std::string(result);
+}
+
+bool CppModuleConfiguration::hasValidConfig() {
+ // We need to have a C and C++ include dir for a valid configuration.
+ if (!m_c_inc.Valid() || !m_std_inc.Valid())
+ return false;
+
+ // Do some basic sanity checks on the directories that we don't activate
+ // the module when it's clear that it's not usable.
+ const std::vector<std::string> files_to_check = {
+ // * Check that the C library contains at least one random C standard
+ // library header.
+ MakePath(m_c_inc.Get(), "stdio.h"),
+ // * Without a libc++ modulemap file we can't have a 'std' module that
+ // could be imported.
+ MakePath(m_std_inc.Get(), "module.modulemap"),
+ // * Check for a random libc++ header (vector in this case) that has to
+ // exist in a working libc++ setup.
+ MakePath(m_std_inc.Get(), "vector"),
+ };
+
+ for (llvm::StringRef file_to_check : files_to_check) {
+ if (!FileSystem::Instance().Exists(file_to_check))
+ return false;
+ }
+
+ return true;
+}
+
+CppModuleConfiguration::CppModuleConfiguration(
+ const FileSpecList &support_files, const llvm::Triple &triple) {
+ // Analyze all files we were given to build the configuration.
+ bool error = !llvm::all_of(support_files, [&](auto &file) {
+ return CppModuleConfiguration::analyzeFile(file, triple);
+ });
+ // If we have a valid configuration at this point, set the
+ // include directories and module list that should be used.
+ if (!error && hasValidConfig()) {
+ // Calculate the resource directory for LLDB.
+ llvm::SmallString<256> resource_dir;
+ llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(),
+ "include");
+ m_resource_inc = std::string(resource_dir.str());
+
+ // This order matches the way Clang orders these directories.
+ m_include_dirs = {m_std_inc.Get().str(), m_resource_inc,
+ m_c_inc.Get().str()};
+ if (m_c_target_inc.Valid())
+ m_include_dirs.push_back(m_c_target_inc.Get().str());
+ if (m_std_target_inc.Valid())
+ m_include_dirs.push_back(m_std_target_inc.Get().str());
+ m_imported_modules = {"std"};
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h
new file mode 100644
index 000000000000..7be0ce6c7ae5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h
@@ -0,0 +1,90 @@
+//===-- CppModuleConfiguration.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CPPMODULECONFIGURATION_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CPPMODULECONFIGURATION_H
+
+#include <lldb/Utility/FileSpecList.h>
+#include <llvm/Support/Regex.h>
+
+namespace lldb_private {
+
+/// A Clang configuration when importing C++ modules.
+///
+/// This class computes a list of include paths and module names that can be
+/// imported given a list of source files. Currently only used when importing
+/// the 'std' module and its dependencies.
+class CppModuleConfiguration {
+ /// Utility class for a path that can only be set once.
+ class SetOncePath {
+ std::string m_path;
+ bool m_valid = false;
+ /// True iff this path hasn't been set yet.
+ bool m_first = true;
+
+ public:
+ /// Try setting the path. Returns true if the path was set and false if
+ /// the path was already set.
+ [[nodiscard]] bool TrySet(llvm::StringRef path);
+ /// Return the path if there is one.
+ llvm::StringRef Get() const {
+ assert(m_valid && "Called Get() on an invalid SetOncePath?");
+ return m_path;
+ }
+ /// Returns true iff this path was set exactly once so far.
+ bool Valid() const { return m_valid; }
+ };
+
+ /// If valid, the include path used for the std module.
+ SetOncePath m_std_inc;
+ /// If valid, the per-target include path used for the std module.
+ /// This is an optional path only required on some systems.
+ SetOncePath m_std_target_inc;
+ /// If valid, the include path to the C library (e.g. /usr/include).
+ SetOncePath m_c_inc;
+ /// If valid, the include path to target-specific C library files
+ /// (e.g. /usr/include/x86_64-linux-gnu).
+ /// This is an optional path only required on some systems.
+ SetOncePath m_c_target_inc;
+ /// The Clang resource include path for this configuration.
+ std::string m_resource_inc;
+
+ std::vector<std::string> m_include_dirs;
+ std::vector<std::string> m_imported_modules;
+
+ /// Analyze a given source file to build the current configuration.
+ /// Returns false iff there was a fatal error that makes analyzing any
+ /// further files pointless as the configuration is now invalid.
+ bool analyzeFile(const FileSpec &f, const llvm::Triple &triple);
+
+public:
+ /// Creates a configuration by analyzing the given list of used source files.
+ /// The triple (if valid) is used to search for target-specific include paths.
+ explicit CppModuleConfiguration(const FileSpecList &support_files,
+ const llvm::Triple &triple);
+ /// Creates an empty and invalid configuration.
+ CppModuleConfiguration() = default;
+
+ /// Returns true iff this is a valid configuration that can be used to
+ /// load and compile modules.
+ bool hasValidConfig();
+
+ /// Returns a list of include directories that should be used when using this
+ /// configuration (e.g. {"/usr/include", "/usr/include/c++/v1"}).
+ llvm::ArrayRef<std::string> GetIncludeDirs() const { return m_include_dirs; }
+
+ /// Returns a list of (top level) modules that should be imported when using
+ /// this configuration (e.g. {"std"}).
+ llvm::ArrayRef<std::string> GetImportedModules() const {
+ return m_imported_modules;
+ }
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
new file mode 100644
index 000000000000..c201153fd7ce
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
@@ -0,0 +1,297 @@
+//===-- CxxModuleHandler.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "clang/Sema/Lookup.h"
+#include "llvm/Support/Error.h"
+#include <optional>
+
+using namespace lldb_private;
+using namespace clang;
+
+CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target)
+ : m_importer(&importer),
+ m_sema(TypeSystemClang::GetASTContext(target)->getSema()) {
+
+ std::initializer_list<const char *> supported_names = {
+ // containers
+ "array",
+ "deque",
+ "forward_list",
+ "list",
+ "queue",
+ "stack",
+ "vector",
+ // pointers
+ "shared_ptr",
+ "unique_ptr",
+ "weak_ptr",
+ // iterator
+ "move_iterator",
+ "__wrap_iter",
+ // utility
+ "allocator",
+ "pair",
+ };
+ m_supported_templates.insert(supported_names.begin(), supported_names.end());
+}
+
+/// Builds a list of scopes that point into the given context.
+///
+/// \param sema The sema that will be using the scopes.
+/// \param ctxt The context that the scope should look into.
+/// \param result A list of scopes. The scopes need to be freed by the caller
+/// (except the TUScope which is owned by the sema).
+static void makeScopes(Sema &sema, DeclContext *ctxt,
+ std::vector<Scope *> &result) {
+ // FIXME: The result should be a list of unique_ptrs, but the TUScope makes
+ // this currently impossible as it's owned by the Sema.
+
+ if (auto parent = ctxt->getParent()) {
+ makeScopes(sema, parent, result);
+
+ Scope *scope =
+ new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics());
+ scope->setEntity(ctxt);
+ result.push_back(scope);
+ } else
+ result.push_back(sema.TUScope);
+}
+
+/// Uses the Sema to look up the given name in the given DeclContext.
+static std::unique_ptr<LookupResult>
+emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) {
+ IdentifierInfo &ident = sema.getASTContext().Idents.get(name);
+
+ std::unique_ptr<LookupResult> lookup_result;
+ lookup_result = std::make_unique<LookupResult>(sema, DeclarationName(&ident),
+ SourceLocation(),
+ Sema::LookupOrdinaryName);
+
+ // Usually during parsing we already encountered the scopes we would use. But
+ // here don't have these scopes so we have to emulate the behavior of the
+ // Sema during parsing.
+ std::vector<Scope *> scopes;
+ makeScopes(sema, ctxt, scopes);
+
+ // Now actually perform the lookup with the sema.
+ sema.LookupName(*lookup_result, scopes.back());
+
+ // Delete all the allocated scopes beside the translation unit scope (which
+ // has depth 0).
+ for (Scope *s : scopes)
+ if (s->getDepth() != 0)
+ delete s;
+
+ return lookup_result;
+}
+
+/// Error class for handling problems when finding a certain DeclContext.
+struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> {
+
+ static char ID;
+
+ MissingDeclContext(DeclContext *context, std::string error)
+ : m_context(context), m_error(error) {}
+
+ DeclContext *m_context;
+ std::string m_error;
+
+ void log(llvm::raw_ostream &OS) const override {
+ OS << llvm::formatv("error when reconstructing context of kind {0}:{1}",
+ m_context->getDeclKindName(), m_error);
+ }
+
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+
+char MissingDeclContext::ID = 0;
+
+/// Given a foreign decl context, this function finds the equivalent local
+/// decl context in the ASTContext of the given Sema. Potentially deserializes
+/// decls from the 'std' module if necessary.
+static llvm::Expected<DeclContext *>
+getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) {
+
+ // Inline namespaces don't matter for lookups, so let's skip them.
+ while (foreign_ctxt && foreign_ctxt->isInlineNamespace())
+ foreign_ctxt = foreign_ctxt->getParent();
+
+ // If the foreign context is the TU, we just return the local TU.
+ if (foreign_ctxt->isTranslationUnit())
+ return sema.getASTContext().getTranslationUnitDecl();
+
+ // Recursively find/build the parent DeclContext.
+ llvm::Expected<DeclContext *> parent =
+ getEqualLocalDeclContext(sema, foreign_ctxt->getParent());
+ if (!parent)
+ return parent;
+
+ // We currently only support building namespaces.
+ if (foreign_ctxt->isNamespace()) {
+ NamedDecl *ns = llvm::cast<NamedDecl>(foreign_ctxt);
+ llvm::StringRef ns_name = ns->getName();
+
+ auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent);
+ for (NamedDecl *named_decl : *lookup_result) {
+ if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl))
+ return DC->getPrimaryContext();
+ }
+ return llvm::make_error<MissingDeclContext>(
+ foreign_ctxt,
+ "Couldn't find namespace " + ns->getQualifiedNameAsString());
+ }
+
+ return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context ");
+}
+
+/// Returns true iff tryInstantiateStdTemplate supports instantiating a template
+/// with the given template arguments.
+static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) {
+ for (const TemplateArgument &arg : a) {
+ switch (arg.getKind()) {
+ case TemplateArgument::Type:
+ case TemplateArgument::Integral:
+ break;
+ default:
+ // TemplateArgument kind hasn't been handled yet.
+ return false;
+ }
+ }
+ return true;
+}
+
+/// Constructor function for Clang declarations. Ensures that the created
+/// declaration is registered with the ASTImporter.
+template <typename T, typename... Args>
+T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) {
+ T *to_d = T::Create(std::forward<Args>(args)...);
+ importer.RegisterImportedDecl(from_d, to_d);
+ return to_d;
+}
+
+std::optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ // If we don't have a template to instiantiate, then there is nothing to do.
+ auto td = dyn_cast<ClassTemplateSpecializationDecl>(d);
+ if (!td)
+ return std::nullopt;
+
+ // We only care about templates in the std namespace.
+ if (!td->getDeclContext()->isStdNamespace())
+ return std::nullopt;
+
+ // We have a list of supported template names.
+ if (!m_supported_templates.contains(td->getName()))
+ return std::nullopt;
+
+ // Early check if we even support instantiating this template. We do this
+ // before we import anything into the target AST.
+ auto &foreign_args = td->getTemplateInstantiationArgs();
+ if (!templateArgsAreSupported(foreign_args.asArray()))
+ return std::nullopt;
+
+ // Find the local DeclContext that corresponds to the DeclContext of our
+ // decl we want to import.
+ llvm::Expected<DeclContext *> to_context =
+ getEqualLocalDeclContext(*m_sema, td->getDeclContext());
+ if (!to_context) {
+ LLDB_LOG_ERROR(log, to_context.takeError(),
+ "Got error while searching equal local DeclContext for decl "
+ "'{1}':\n{0}",
+ td->getName());
+ return std::nullopt;
+ }
+
+ // Look up the template in our local context.
+ std::unique_ptr<LookupResult> lookup =
+ emulateLookupInCtxt(*m_sema, td->getName(), *to_context);
+
+ ClassTemplateDecl *new_class_template = nullptr;
+ for (auto LD : *lookup) {
+ if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD)))
+ break;
+ }
+ if (!new_class_template)
+ return std::nullopt;
+
+ // Import the foreign template arguments.
+ llvm::SmallVector<TemplateArgument, 4> imported_args;
+
+ // If this logic is changed, also update templateArgsAreSupported.
+ for (const TemplateArgument &arg : foreign_args.asArray()) {
+ switch (arg.getKind()) {
+ case TemplateArgument::Type: {
+ llvm::Expected<QualType> type = m_importer->Import(arg.getAsType());
+ if (!type) {
+ LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
+ return std::nullopt;
+ }
+ imported_args.push_back(
+ TemplateArgument(*type, /*isNullPtr*/ false, arg.getIsDefaulted()));
+ break;
+ }
+ case TemplateArgument::Integral: {
+ llvm::APSInt integral = arg.getAsIntegral();
+ llvm::Expected<QualType> type =
+ m_importer->Import(arg.getIntegralType());
+ if (!type) {
+ LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
+ return std::nullopt;
+ }
+ imported_args.push_back(TemplateArgument(d->getASTContext(), integral,
+ *type, arg.getIsDefaulted()));
+ break;
+ }
+ default:
+ assert(false && "templateArgsAreSupported not updated?");
+ }
+ }
+
+ // Find the class template specialization declaration that
+ // corresponds to these arguments.
+ void *InsertPos = nullptr;
+ ClassTemplateSpecializationDecl *result =
+ new_class_template->findSpecialization(imported_args, InsertPos);
+
+ if (result) {
+ // We found an existing specialization in the module that fits our arguments
+ // so we can treat it as the result and register it with the ASTImporter.
+ m_importer->RegisterImportedDecl(d, result);
+ return result;
+ }
+
+ // Instantiate the template.
+ result = createDecl<ClassTemplateSpecializationDecl>(
+ *m_importer, d, m_sema->getASTContext(),
+ new_class_template->getTemplatedDecl()->getTagKind(),
+ new_class_template->getDeclContext(),
+ new_class_template->getTemplatedDecl()->getLocation(),
+ new_class_template->getLocation(), new_class_template, imported_args,
+ nullptr);
+
+ new_class_template->AddSpecialization(result, InsertPos);
+ if (new_class_template->isOutOfLine())
+ result->setLexicalDeclContext(
+ new_class_template->getLexicalDeclContext());
+ return result;
+}
+
+std::optional<Decl *> CxxModuleHandler::Import(Decl *d) {
+ if (!isValid())
+ return {};
+
+ return tryInstantiateStdTemplate(d);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h
new file mode 100644
index 000000000000..24289c83e88e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h
@@ -0,0 +1,66 @@
+//===-- CxxModuleHandler.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/ADT/StringSet.h"
+#include <optional>
+
+namespace lldb_private {
+
+/// Handles importing decls into an ASTContext with an attached C++ module.
+///
+/// This class searches a C++ module (which must be attached to the target
+/// ASTContext) for an equivalent decl to the one that should be imported.
+/// If the decl that is found in the module is a suitable replacement
+/// for the decl that should be imported, the module decl will be treated as
+/// the result of the import process.
+///
+/// If the Decl that should be imported is a template specialization
+/// that doesn't exist yet in the target ASTContext (e.g. `std::vector<int>`),
+/// then this class tries to create the template specialization in the target
+/// ASTContext. This is only possible if the CxxModuleHandler can determine
+/// that instantiating this template is safe to do, e.g. because the target
+/// decl is a container class from the STL.
+class CxxModuleHandler {
+ /// The ASTImporter that should be used to import any Decls which aren't
+ /// directly handled by this class itself.
+ clang::ASTImporter *m_importer = nullptr;
+
+ /// The Sema instance of the target ASTContext.
+ clang::Sema *m_sema = nullptr;
+
+ /// List of template names this class currently supports. These are the
+ /// template names inside the 'std' namespace such as 'vector' or 'list'.
+ llvm::StringSet<> m_supported_templates;
+
+ /// Tries to manually instantiate the given foreign template in the target
+ /// context (designated by m_sema).
+ std::optional<clang::Decl *> tryInstantiateStdTemplate(clang::Decl *d);
+
+public:
+ CxxModuleHandler() = default;
+ CxxModuleHandler(clang::ASTImporter &importer, clang::ASTContext *target);
+
+ /// Attempts to import the given decl into the target ASTContext by
+ /// deserializing it from the 'std' module. This function returns a Decl if a
+ /// Decl has been deserialized from the 'std' module. Otherwise this function
+ /// returns nothing.
+ std::optional<clang::Decl *> Import(clang::Decl *d);
+
+ /// Returns true iff this instance is capable of importing any declarations
+ /// in the target ASTContext.
+ bool isValid() const { return m_sema != nullptr; }
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp
new file mode 100644
index 000000000000..bc0f5993aad0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp
@@ -0,0 +1,569 @@
+//===-- IRDynamicChecks.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "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/LLDBLog.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;
+
+llvm::Error ClangDynamicCheckerFunctions::Install(
+ DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+ Expected<std::unique_ptr<UtilityFunction>> utility_fn =
+ exe_ctx.GetTargetRef().CreateUtilityFunction(
+ g_valid_pointer_check_text, VALID_POINTER_CHECK_NAME,
+ lldb::eLanguageTypeC, exe_ctx);
+ if (!utility_fn)
+ return utility_fn.takeError();
+ m_valid_pointer_check = std::move(*utility_fn);
+
+ if (Process *process = exe_ctx.GetProcessPtr()) {
+ ObjCLanguageRuntime *objc_language_runtime =
+ ObjCLanguageRuntime::Get(*process);
+
+ if (objc_language_runtime) {
+ Expected<std::unique_ptr<UtilityFunction>> checker_fn =
+ objc_language_runtime->CreateObjectChecker(VALID_OBJC_OBJECT_CHECK_NAME, exe_ctx);
+ if (!checker_fn)
+ return checker_fn.takeError();
+ m_objc_object_check = std::move(*checker_fn);
+ }
+ }
+
+ return Error::success();
+}
+
+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) {}
+
+ 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 &inst) {
+ m_to_instrument.push_back(&inst);
+ }
+
+ /// 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::PointerType::getUnqual(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 = nullptr;
+ IntegerType *m_intptr_ty = nullptr;
+};
+
+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 = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOGF(log, "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 call the helper with the result
+ CallInst::Create(m_valid_pointer_check_func, dereferenced_ptr, "", inst);
+
+ return true;
+ }
+
+ bool InspectInstruction(llvm::Instruction &i) override {
+ if (isa<llvm::LoadInst>(&i) || isa<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 call the helper with the result
+
+ llvm::Value *arg_array[2];
+
+ arg_array[0] = target_object;
+ 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->getCalledOperand());
+ }
+
+ bool InspectInstruction(llvm::Instruction &i) override {
+ Log *log = GetLog(LLDBLog::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();
+
+ LLDB_LOGF(log, "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;
+ }
+
+ LLDB_LOGF(log,
+ "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 = GetLog(LLDBLog::Expressions);
+
+ llvm::Function *function = M.getFunction(StringRef(m_func_name));
+
+ if (!function) {
+ LLDB_LOGF(log, "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();
+
+ LLDB_LOGF(log, "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/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h
new file mode 100644
index 000000000000..ff20c1f08be0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h
@@ -0,0 +1,127 @@
+//===-- 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 LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRDYNAMICCHECKS_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_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
+ ~ClangDynamicCheckerFunctions() override;
+
+ 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
+ /// Either llvm::ErrorSuccess or Error with llvm::ErrorInfo
+ ///
+ llvm::Error 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.
+ 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 // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRDYNAMICCHECKS_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
new file mode 100644
index 000000000000..cc9bd14c6194
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
@@ -0,0 +1,1771 @@
+//===-- IRForTarget.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "IRForTarget.h"
+
+#include "ClangExpressionDeclMap.h"
+#include "ClangUtil.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/ValueSymbolTable.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO.h"
+
+#include "clang/AST/ASTContext.h"
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Scalar.h"
+#include "lldb/Utility/StreamString.h"
+
+#include <map>
+#include <optional>
+
+using namespace llvm;
+using lldb_private::LLDBLog;
+
+typedef SmallVector<Instruction *, 2> InstrList;
+
+IRForTarget::FunctionValueCache::FunctionValueCache(Maker const &maker)
+ : m_maker(maker), m_values() {}
+
+IRForTarget::FunctionValueCache::~FunctionValueCache() = default;
+
+llvm::Value *
+IRForTarget::FunctionValueCache::GetValue(llvm::Function *function) {
+ if (!m_values.count(function)) {
+ llvm::Value *ret = m_maker(function);
+ m_values[function] = ret;
+ return ret;
+ }
+ return m_values[function];
+}
+
+static llvm::Value *FindEntryInstruction(llvm::Function *function) {
+ if (function->empty())
+ return nullptr;
+
+ return function->getEntryBlock().getFirstNonPHIOrDbg();
+}
+
+IRForTarget::IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map,
+ bool resolve_vars,
+ lldb_private::IRExecutionUnit &execution_unit,
+ lldb_private::Stream &error_stream,
+ const char *func_name)
+ : m_resolve_vars(resolve_vars), m_func_name(func_name),
+ m_decl_map(decl_map), m_error_stream(error_stream),
+ m_execution_unit(execution_unit),
+ m_entry_instruction_finder(FindEntryInstruction) {}
+
+/* Handy utility functions used at several places in the code */
+
+static std::string PrintValue(const Value *value, bool truncate = false) {
+ std::string s;
+ if (value) {
+ raw_string_ostream rso(s);
+ value->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ }
+ return s;
+}
+
+static std::string PrintType(const llvm::Type *type, bool truncate = false) {
+ std::string s;
+ raw_string_ostream rso(s);
+ type->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ return s;
+}
+
+bool IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function) {
+ llvm_function.setLinkage(GlobalValue::ExternalLinkage);
+
+ return true;
+}
+
+clang::NamedDecl *IRForTarget::DeclForGlobal(const GlobalValue *global_val,
+ Module *module) {
+ NamedMDNode *named_metadata =
+ module->getNamedMetadata("clang.global.decl.ptrs");
+
+ if (!named_metadata)
+ return nullptr;
+
+ unsigned num_nodes = named_metadata->getNumOperands();
+ unsigned node_index;
+
+ for (node_index = 0; node_index < num_nodes; ++node_index) {
+ llvm::MDNode *metadata_node =
+ dyn_cast<llvm::MDNode>(named_metadata->getOperand(node_index));
+ if (!metadata_node)
+ return nullptr;
+
+ if (metadata_node->getNumOperands() != 2)
+ continue;
+
+ if (mdconst::dyn_extract_or_null<GlobalValue>(
+ metadata_node->getOperand(0)) != global_val)
+ continue;
+
+ ConstantInt *constant_int =
+ mdconst::dyn_extract<ConstantInt>(metadata_node->getOperand(1));
+
+ if (!constant_int)
+ return nullptr;
+
+ uintptr_t ptr = constant_int->getZExtValue();
+
+ return reinterpret_cast<clang::NamedDecl *>(ptr);
+ }
+
+ return nullptr;
+}
+
+clang::NamedDecl *IRForTarget::DeclForGlobal(GlobalValue *global_val) {
+ return DeclForGlobal(global_val, m_module);
+}
+
+/// Returns true iff the mangled symbol is for a static guard variable.
+static bool isGuardVariableSymbol(llvm::StringRef mangled_symbol,
+ bool check_ms_abi = true) {
+ bool result =
+ mangled_symbol.starts_with("_ZGV"); // Itanium ABI guard variable
+ if (check_ms_abi)
+ result |= mangled_symbol.ends_with("@4IA"); // Microsoft ABI
+ return result;
+}
+
+bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ if (!m_resolve_vars)
+ return true;
+
+ // Find the result variable. If it doesn't exist, we can give up right here.
+
+ ValueSymbolTable &value_symbol_table = m_module->getValueSymbolTable();
+
+ llvm::StringRef result_name;
+ bool found_result = false;
+
+ for (StringMapEntry<llvm::Value *> &value_symbol : value_symbol_table) {
+ result_name = value_symbol.first();
+
+ // Check if this is a guard variable. It seems this causes some hiccups
+ // on Windows, so let's only check for Itanium guard variables.
+ bool is_guard_var = isGuardVariableSymbol(result_name, /*MS ABI*/ false);
+
+ if (result_name.contains("$__lldb_expr_result_ptr") && !is_guard_var) {
+ found_result = true;
+ m_result_is_pointer = true;
+ break;
+ }
+
+ if (result_name.contains("$__lldb_expr_result") && !is_guard_var) {
+ found_result = true;
+ m_result_is_pointer = false;
+ break;
+ }
+ }
+
+ if (!found_result) {
+ LLDB_LOG(log, "Couldn't find result variable");
+
+ return true;
+ }
+
+ LLDB_LOG(log, "Result name: \"{0}\"", result_name);
+
+ Value *result_value = m_module->getNamedValue(result_name);
+
+ if (!result_value) {
+ LLDB_LOG(log, "Result variable had no data");
+
+ m_error_stream.Format("Internal error [IRForTarget]: Result variable's "
+ "name ({0}) exists, but not its definition\n",
+ result_name);
+
+ return false;
+ }
+
+ LLDB_LOG(log, "Found result in the IR: \"{0}\"",
+ PrintValue(result_value, false));
+
+ GlobalVariable *result_global = dyn_cast<GlobalVariable>(result_value);
+
+ if (!result_global) {
+ LLDB_LOG(log, "Result variable isn't a GlobalVariable");
+
+ m_error_stream.Format("Internal error [IRForTarget]: Result variable ({0}) "
+ "is defined, but is not a global variable\n",
+ result_name);
+
+ return false;
+ }
+
+ clang::NamedDecl *result_decl = DeclForGlobal(result_global);
+ if (!result_decl) {
+ LLDB_LOG(log, "Result variable doesn't have a corresponding Decl");
+
+ m_error_stream.Format("Internal error [IRForTarget]: Result variable ({0}) "
+ "does not have a corresponding Clang entity\n",
+ result_name);
+
+ return false;
+ }
+
+ if (log) {
+ std::string decl_desc_str;
+ raw_string_ostream decl_desc_stream(decl_desc_str);
+ result_decl->print(decl_desc_stream);
+ decl_desc_stream.flush();
+
+ LLDB_LOG(log, "Found result decl: \"{0}\"", decl_desc_str);
+ }
+
+ clang::VarDecl *result_var = dyn_cast<clang::VarDecl>(result_decl);
+ if (!result_var) {
+ LLDB_LOG(log, "Result variable Decl isn't a VarDecl");
+
+ m_error_stream.Format("Internal error [IRForTarget]: Result variable "
+ "({0})'s corresponding Clang entity isn't a "
+ "variable\n",
+ result_name);
+
+ return false;
+ }
+
+ // Get the next available result name from m_decl_map and create the
+ // persistent variable for it
+
+ // If the result is an Lvalue, it is emitted as a pointer; see
+ // ASTResultSynthesizer::SynthesizeBodyResult.
+ if (m_result_is_pointer) {
+ clang::QualType pointer_qual_type = result_var->getType();
+ const clang::Type *pointer_type = pointer_qual_type.getTypePtr();
+
+ const clang::PointerType *pointer_pointertype =
+ pointer_type->getAs<clang::PointerType>();
+ const clang::ObjCObjectPointerType *pointer_objcobjpointertype =
+ pointer_type->getAs<clang::ObjCObjectPointerType>();
+
+ if (pointer_pointertype) {
+ clang::QualType element_qual_type = pointer_pointertype->getPointeeType();
+
+ m_result_type = lldb_private::TypeFromParser(
+ m_decl_map->GetTypeSystem()->GetType(element_qual_type));
+ } else if (pointer_objcobjpointertype) {
+ clang::QualType element_qual_type =
+ clang::QualType(pointer_objcobjpointertype->getObjectType(), 0);
+
+ m_result_type = lldb_private::TypeFromParser(
+ m_decl_map->GetTypeSystem()->GetType(element_qual_type));
+ } else {
+ LLDB_LOG(log, "Expected result to have pointer type, but it did not");
+
+ m_error_stream.Format("Internal error [IRForTarget]: Lvalue result ({0}) "
+ "is not a pointer variable\n",
+ result_name);
+
+ return false;
+ }
+ } else {
+ m_result_type = lldb_private::TypeFromParser(
+ m_decl_map->GetTypeSystem()->GetType(result_var->getType()));
+ }
+
+ lldb::TargetSP target_sp(m_execution_unit.GetTarget());
+ std::optional<uint64_t> bit_size = m_result_type.GetBitSize(target_sp.get());
+ if (!bit_size) {
+ lldb_private::StreamString type_desc_stream;
+ m_result_type.DumpTypeDescription(&type_desc_stream);
+
+ LLDB_LOG(log, "Result type has unknown size");
+
+ m_error_stream.Printf("Error [IRForTarget]: Size of result type '%s' "
+ "couldn't be determined\n",
+ type_desc_stream.GetData());
+ return false;
+ }
+
+ if (log) {
+ lldb_private::StreamString type_desc_stream;
+ m_result_type.DumpTypeDescription(&type_desc_stream);
+
+ LLDB_LOG(log, "Result decl type: \"{0}\"", type_desc_stream.GetData());
+ }
+
+ m_result_name = lldb_private::ConstString("$RESULT_NAME");
+
+ LLDB_LOG(log, "Creating a new result global: \"{0}\" with size {1}",
+ m_result_name,
+ m_result_type.GetByteSize(target_sp.get()).value_or(0));
+
+ // Construct a new result global and set up its metadata
+
+ GlobalVariable *new_result_global = new GlobalVariable(
+ (*m_module), result_global->getValueType(), 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
+ // don't need to. We point the metadata at the old VarDecl. This creates an
+ // odd anomaly: a variable with a Value whose name is something like $0 and a
+ // Decl whose name is $__lldb_expr_result. This condition is handled in
+ // ClangExpressionDeclMap::DoMaterialize, and the name of the variable is
+ // fixed up.
+
+ ConstantInt *new_constant_int =
+ ConstantInt::get(llvm::Type::getInt64Ty(m_module->getContext()),
+ reinterpret_cast<uintptr_t>(result_decl), false);
+
+ llvm::Metadata *values[2];
+ values[0] = ConstantAsMetadata::get(new_result_global);
+ values[1] = ConstantAsMetadata::get(new_constant_int);
+
+ ArrayRef<Metadata *> value_ref(values, 2);
+
+ MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
+ NamedMDNode *named_metadata =
+ m_module->getNamedMetadata("clang.global.decl.ptrs");
+ named_metadata->addOperand(persistent_global_md);
+
+ LLDB_LOG(log, "Replacing \"{0}\" with \"{1}\"", PrintValue(result_global),
+ PrintValue(new_result_global));
+
+ if (result_global->use_empty()) {
+ // We need to synthesize a store for this variable, because otherwise
+ // there's nothing to put into its equivalent persistent variable.
+
+ BasicBlock &entry_block(llvm_function.getEntryBlock());
+ Instruction *first_entry_instruction(entry_block.getFirstNonPHIOrDbg());
+
+ if (!first_entry_instruction)
+ return false;
+
+ if (!result_global->hasInitializer()) {
+ LLDB_LOG(log, "Couldn't find initializer for unused variable");
+
+ m_error_stream.Format("Internal error [IRForTarget]: Result variable "
+ "({0}) has no writes and no initializer\n",
+ result_name);
+
+ return false;
+ }
+
+ Constant *initializer = result_global->getInitializer();
+
+ StoreInst *synthesized_store =
+ new StoreInst(initializer, new_result_global, first_entry_instruction);
+
+ LLDB_LOG(log, "Synthesized result store \"{0}\"\n",
+ PrintValue(synthesized_store));
+ } else {
+ result_global->replaceAllUsesWith(new_result_global);
+ }
+
+ if (!m_decl_map->AddPersistentVariable(
+ result_decl, m_result_name, m_result_type, true, m_result_is_pointer))
+ return false;
+
+ result_global->eraseFromParent();
+
+ return true;
+}
+
+bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str,
+ llvm::GlobalVariable *cstr) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ Type *ns_str_ty = ns_str->getType();
+
+ Type *i8_ptr_ty = PointerType::getUnqual(m_module->getContext());
+ Type *i32_ty = Type::getInt32Ty(m_module->getContext());
+ Type *i8_ty = Type::getInt8Ty(m_module->getContext());
+
+ if (!m_CFStringCreateWithBytes) {
+ lldb::addr_t CFStringCreateWithBytes_addr;
+
+ static lldb_private::ConstString g_CFStringCreateWithBytes_str(
+ "CFStringCreateWithBytes");
+
+ bool missing_weak = false;
+ CFStringCreateWithBytes_addr =
+ m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str,
+ missing_weak);
+ if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS || missing_weak) {
+ LLDB_LOG(log, "Couldn't find CFStringCreateWithBytes in the target");
+
+ m_error_stream.Printf("Error [IRForTarget]: Rewriting an Objective-C "
+ "constant string requires "
+ "CFStringCreateWithBytes\n");
+
+ return false;
+ }
+
+ LLDB_LOG(log, "Found CFStringCreateWithBytes at {0}",
+ CFStringCreateWithBytes_addr);
+
+ // Build the function type:
+ //
+ // CFStringRef CFStringCreateWithBytes (
+ // CFAllocatorRef alloc,
+ // const UInt8 *bytes,
+ // CFIndex numBytes,
+ // CFStringEncoding encoding,
+ // Boolean isExternalRepresentation
+ // );
+ //
+ // We make the following substitutions:
+ //
+ // CFStringRef -> i8*
+ // CFAllocatorRef -> i8*
+ // UInt8 * -> i8*
+ // CFIndex -> long (i32 or i64, as appropriate; we ask the module for its
+ // pointer size for now) CFStringEncoding -> i32 Boolean -> i8
+
+ Type *arg_type_array[5];
+
+ arg_type_array[0] = i8_ptr_ty;
+ arg_type_array[1] = i8_ptr_ty;
+ arg_type_array[2] = m_intptr_ty;
+ arg_type_array[3] = i32_ty;
+ arg_type_array[4] = i8_ty;
+
+ ArrayRef<Type *> CFSCWB_arg_types(arg_type_array, 5);
+
+ 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 = {
+ CFSCWB_ty, ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty)};
+ }
+
+ ConstantDataSequential *string_array = nullptr;
+
+ if (cstr)
+ string_array = dyn_cast<ConstantDataSequential>(cstr->getInitializer());
+
+ Constant *alloc_arg = Constant::getNullValue(i8_ptr_ty);
+ Constant *bytes_arg = cstr ? cstr : Constant::getNullValue(i8_ptr_ty);
+ Constant *numBytes_arg = ConstantInt::get(
+ m_intptr_ty, cstr ? (string_array->getNumElements() - 1) * string_array->getElementByteSize() : 0, false);
+ int encoding_flags = 0;
+ switch (cstr ? string_array->getElementByteSize() : 1) {
+ case 1:
+ encoding_flags = 0x08000100; /* 0x08000100 is kCFStringEncodingUTF8 */
+ break;
+ case 2:
+ encoding_flags = 0x0100; /* 0x0100 is kCFStringEncodingUTF16 */
+ break;
+ case 4:
+ encoding_flags = 0x0c000100; /* 0x0c000100 is kCFStringEncodingUTF32 */
+ break;
+ default:
+ encoding_flags = 0x0600; /* fall back to 0x0600, kCFStringEncodingASCII */
+ LLDB_LOG(log, "Encountered an Objective-C constant string with unusual "
+ "element size {0}",
+ string_array->getElementByteSize());
+ }
+ Constant *encoding_arg = ConstantInt::get(i32_ty, encoding_flags, false);
+ Constant *isExternal_arg =
+ ConstantInt::get(i8_ty, 0x0, false); /* 0x0 is false */
+
+ Value *argument_array[5];
+
+ argument_array[0] = alloc_arg;
+ argument_array[1] = bytes_arg;
+ argument_array[2] = numBytes_arg;
+ argument_array[3] = encoding_arg;
+ argument_array[4] = isExternal_arg;
+
+ ArrayRef<Value *> CFSCWB_arguments(argument_array, 5);
+
+ FunctionValueCache CFSCWB_Caller(
+ [this, &CFSCWB_arguments](llvm::Function *function) -> llvm::Value * {
+ return CallInst::Create(
+ m_CFStringCreateWithBytes, CFSCWB_arguments,
+ "CFStringCreateWithBytes",
+ llvm::cast<Instruction>(
+ m_entry_instruction_finder.GetValue(function)));
+ });
+
+ if (!UnfoldConstant(ns_str, nullptr, CFSCWB_Caller, m_entry_instruction_finder,
+ m_error_stream)) {
+ LLDB_LOG(log, "Couldn't replace the NSString with the result of the call");
+
+ m_error_stream.Printf("error [IRForTarget internal]: Couldn't replace an "
+ "Objective-C constant string with a dynamic "
+ "string\n");
+
+ return false;
+ }
+
+ ns_str->eraseFromParent();
+
+ return true;
+}
+
+bool IRForTarget::RewriteObjCConstStrings() {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ ValueSymbolTable &value_symbol_table = m_module->getValueSymbolTable();
+
+ for (StringMapEntry<llvm::Value *> &value_symbol : value_symbol_table) {
+ llvm::StringRef value_name = value_symbol.first();
+
+ if (value_name.contains("_unnamed_cfstring_")) {
+ Value *nsstring_value = value_symbol.second;
+
+ GlobalVariable *nsstring_global =
+ dyn_cast<GlobalVariable>(nsstring_value);
+
+ if (!nsstring_global) {
+ LLDB_LOG(log, "NSString variable is not a GlobalVariable");
+
+ m_error_stream.Printf("Internal error [IRForTarget]: An Objective-C "
+ "constant string is not a global variable\n");
+
+ return false;
+ }
+
+ if (!nsstring_global->hasInitializer()) {
+ LLDB_LOG(log, "NSString variable does not have an initializer");
+
+ m_error_stream.Printf("Internal error [IRForTarget]: An Objective-C "
+ "constant string does not have an initializer\n");
+
+ return false;
+ }
+
+ ConstantStruct *nsstring_struct =
+ dyn_cast<ConstantStruct>(nsstring_global->getInitializer());
+
+ if (!nsstring_struct) {
+ LLDB_LOG(log,
+ "NSString variable's initializer is not a ConstantStruct");
+
+ m_error_stream.Printf("Internal error [IRForTarget]: An Objective-C "
+ "constant string is not a structure constant\n");
+
+ return false;
+ }
+
+ // We expect the following structure:
+ //
+ // struct {
+ // int *isa;
+ // int flags;
+ // char *str;
+ // long length;
+ // };
+
+ if (nsstring_struct->getNumOperands() != 4) {
+
+ LLDB_LOG(log,
+ "NSString variable's initializer structure has an "
+ "unexpected number of members. Should be 4, is {0}",
+ nsstring_struct->getNumOperands());
+
+ m_error_stream.Printf("Internal error [IRForTarget]: The struct for an "
+ "Objective-C constant string is not as "
+ "expected\n");
+
+ return false;
+ }
+
+ Constant *nsstring_member = nsstring_struct->getOperand(2);
+
+ if (!nsstring_member) {
+ LLDB_LOG(log, "NSString initializer's str element was empty");
+
+ m_error_stream.Printf("Internal error [IRForTarget]: An Objective-C "
+ "constant string does not have a string "
+ "initializer\n");
+
+ return false;
+ }
+
+ auto *cstr_global = dyn_cast<GlobalVariable>(nsstring_member);
+ if (!cstr_global) {
+ LLDB_LOG(log,
+ "NSString initializer's str element is not a GlobalVariable");
+
+ m_error_stream.Printf("Internal error [IRForTarget]: Unhandled"
+ "constant string initializer\n");
+
+ return false;
+ }
+
+ if (!cstr_global->hasInitializer()) {
+ LLDB_LOG(log, "NSString initializer's str element does not have an "
+ "initializer");
+
+ m_error_stream.Printf("Internal error [IRForTarget]: An Objective-C "
+ "constant string's string initializer doesn't "
+ "point to initialized data\n");
+
+ return false;
+ }
+
+ /*
+ if (!cstr_array)
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element is not a
+ ConstantArray");
+
+ if (m_error_stream)
+ m_error_stream.Printf("Internal error [IRForTarget]: An
+ Objective-C constant string's string initializer doesn't point to an
+ array\n");
+
+ return false;
+ }
+
+ if (!cstr_array->isCString())
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element is not a C
+ string array");
+
+ if (m_error_stream)
+ m_error_stream.Printf("Internal error [IRForTarget]: An
+ Objective-C constant string's string initializer doesn't point to a C
+ string\n");
+
+ return false;
+ }
+ */
+
+ ConstantDataArray *cstr_array =
+ dyn_cast<ConstantDataArray>(cstr_global->getInitializer());
+
+ if (cstr_array)
+ LLDB_LOG(log, "Found NSString constant {0}, which contains \"{1}\"",
+ value_name, cstr_array->getAsString());
+ else
+ LLDB_LOG(log, "Found NSString constant {0}, which contains \"\"",
+ value_name);
+
+ if (!cstr_array)
+ cstr_global = nullptr;
+
+ if (!RewriteObjCConstString(nsstring_global, cstr_global)) {
+ LLDB_LOG(log, "Error rewriting the constant string");
+
+ // We don't print an error message here because RewriteObjCConstString
+ // has done so for us.
+
+ return false;
+ }
+ }
+ }
+
+ for (StringMapEntry<llvm::Value *> &value_symbol : value_symbol_table) {
+ llvm::StringRef value_name = value_symbol.first();
+
+ if (value_name == "__CFConstantStringClassReference") {
+ GlobalVariable *gv = dyn_cast<GlobalVariable>(value_symbol.second);
+
+ if (!gv) {
+ LLDB_LOG(log,
+ "__CFConstantStringClassReference is not a global variable");
+
+ m_error_stream.Printf("Internal error [IRForTarget]: Found a "
+ "CFConstantStringClassReference, but it is not a "
+ "global object\n");
+
+ return false;
+ }
+
+ gv->eraseFromParent();
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+static bool IsObjCSelectorRef(Value *value) {
+ GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value);
+
+ return !(
+ !global_variable || !global_variable->hasName() ||
+ !global_variable->getName().starts_with("OBJC_SELECTOR_REFERENCES_"));
+}
+
+// This function does not report errors; its callers are responsible.
+bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ LoadInst *load = dyn_cast<LoadInst>(selector_load);
+
+ if (!load)
+ return false;
+
+ // Unpack the message name from the selector. In LLVM IR, an objc_msgSend
+ // gets represented as
+ //
+ // %sel = load ptr, ptr @OBJC_SELECTOR_REFERENCES_, align 8
+ // call i8 @objc_msgSend(ptr %obj, ptr %sel, ...)
+ //
+ // where %obj is the object pointer and %sel is the selector.
+ //
+ // @"OBJC_SELECTOR_REFERENCES_" is a pointer to a character array called
+ // @"\01L_OBJC_METH_VAR_NAME_".
+ // @"\01L_OBJC_METH_VAR_NAME_" contains the string.
+
+ // Find the pointer's initializer and get the string from its target.
+
+ GlobalVariable *_objc_selector_references_ =
+ dyn_cast<GlobalVariable>(load->getPointerOperand());
+
+ if (!_objc_selector_references_ ||
+ !_objc_selector_references_->hasInitializer())
+ return false;
+
+ Constant *osr_initializer = _objc_selector_references_->getInitializer();
+ if (!osr_initializer)
+ return false;
+
+ // Find the string's initializer (a ConstantArray) and get the string from it
+
+ GlobalVariable *_objc_meth_var_name_ =
+ dyn_cast<GlobalVariable>(osr_initializer);
+
+ if (!_objc_meth_var_name_ || !_objc_meth_var_name_->hasInitializer())
+ return false;
+
+ Constant *omvn_initializer = _objc_meth_var_name_->getInitializer();
+
+ ConstantDataArray *omvn_initializer_array =
+ dyn_cast<ConstantDataArray>(omvn_initializer);
+
+ if (!omvn_initializer_array->isString())
+ return false;
+
+ std::string omvn_initializer_string =
+ std::string(omvn_initializer_array->getAsString());
+
+ LLDB_LOG(log, "Found Objective-C selector reference \"{0}\"",
+ omvn_initializer_string);
+
+ // Construct a call to sel_registerName
+
+ 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,
+ missing_weak);
+ if (sel_registerName_addr == LLDB_INVALID_ADDRESS || missing_weak)
+ return false;
+
+ LLDB_LOG(log, "Found sel_registerName at {0}", sel_registerName_addr);
+
+ // Build the function type: struct objc_selector
+ // *sel_registerName(uint8_t*)
+
+ // The below code would be "more correct," but in actuality what's required
+ // is uint8_t*
+ // Type *sel_type = StructType::get(m_module->getContext());
+ // Type *sel_ptr_type = PointerType::getUnqual(sel_type);
+ Type *sel_ptr_type = PointerType::getUnqual(m_module->getContext());
+
+ Type *type_array[1];
+
+ type_array[0] = llvm::PointerType::getUnqual(m_module->getContext());
+
+ ArrayRef<Type *> srN_arg_types(type_array, 1);
+
+ 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 = {srN_type,
+ ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty)};
+ }
+
+ CallInst *srN_call =
+ CallInst::Create(m_sel_registerName, _objc_meth_var_name_,
+ "sel_registerName", selector_load);
+
+ // Replace the load with the call in all users
+
+ selector_load->replaceAllUsesWith(srN_call);
+
+ selector_load->eraseFromParent();
+
+ return true;
+}
+
+bool IRForTarget::RewriteObjCSelectors(BasicBlock &basic_block) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ InstrList selector_loads;
+
+ for (Instruction &inst : basic_block) {
+ if (LoadInst *load = dyn_cast<LoadInst>(&inst))
+ if (IsObjCSelectorRef(load->getPointerOperand()))
+ selector_loads.push_back(&inst);
+ }
+
+ for (Instruction *inst : selector_loads) {
+ if (!RewriteObjCSelector(inst)) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Couldn't change a "
+ "static reference to an Objective-C selector to a "
+ "dynamic reference\n");
+
+ LLDB_LOG(log, "Couldn't rewrite a reference to an Objective-C selector");
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ AllocaInst *alloc = dyn_cast<AllocaInst>(persistent_alloc);
+
+ MDNode *alloc_md = alloc->getMetadata("clang.decl.ptr");
+
+ if (!alloc_md || !alloc_md->getNumOperands())
+ return false;
+
+ ConstantInt *constant_int =
+ mdconst::dyn_extract<ConstantInt>(alloc_md->getOperand(0));
+
+ if (!constant_int)
+ return false;
+
+ // We attempt to register this as a new persistent variable with the DeclMap.
+
+ uintptr_t ptr = constant_int->getZExtValue();
+
+ clang::VarDecl *decl = reinterpret_cast<clang::VarDecl *>(ptr);
+
+ lldb_private::TypeFromParser result_decl_type(
+ m_decl_map->GetTypeSystem()->GetType(decl->getType()));
+
+ StringRef decl_name(decl->getName());
+ lldb_private::ConstString persistent_variable_name(decl_name.data(),
+ decl_name.size());
+ if (!m_decl_map->AddPersistentVariable(decl, persistent_variable_name,
+ result_decl_type, false, false))
+ return false;
+
+ GlobalVariable *persistent_global = new GlobalVariable(
+ (*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
+ // external variable. That means we need to make the metadata valid.
+
+ NamedMDNode *named_metadata =
+ m_module->getOrInsertNamedMetadata("clang.global.decl.ptrs");
+
+ llvm::Metadata *values[2];
+ values[0] = ConstantAsMetadata::get(persistent_global);
+ values[1] = ConstantAsMetadata::get(constant_int);
+
+ ArrayRef<llvm::Metadata *> value_ref(values, 2);
+
+ MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
+ named_metadata->addOperand(persistent_global_md);
+
+ // Now, since the variable is a pointer variable, we will drop in a load of
+ // that pointer variable.
+
+ LoadInst *persistent_load = new LoadInst(persistent_global->getValueType(),
+ persistent_global, "", alloc);
+
+ LLDB_LOG(log, "Replacing \"{0}\" with \"{1}\"", PrintValue(alloc),
+ PrintValue(persistent_load));
+
+ alloc->replaceAllUsesWith(persistent_load);
+ alloc->eraseFromParent();
+
+ return true;
+}
+
+bool IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block) {
+ if (!m_resolve_vars)
+ return true;
+
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ InstrList pvar_allocs;
+
+ for (Instruction &inst : basic_block) {
+
+ if (AllocaInst *alloc = dyn_cast<AllocaInst>(&inst)) {
+ llvm::StringRef alloc_name = alloc->getName();
+
+ if (alloc_name.starts_with("$") && !alloc_name.starts_with("$__lldb")) {
+ if (alloc_name.find_first_of("0123456789") == 1) {
+ LLDB_LOG(log, "Rejecting a numeric persistent variable.");
+
+ m_error_stream.Printf("Error [IRForTarget]: Names starting with $0, "
+ "$1, ... are reserved for use as result "
+ "names\n");
+
+ return false;
+ }
+
+ pvar_allocs.push_back(alloc);
+ }
+ }
+ }
+
+ for (Instruction *inst : pvar_allocs) {
+ if (!RewritePersistentAlloc(inst)) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Couldn't rewrite "
+ "the creation of a persistent variable\n");
+
+ LLDB_LOG(log, "Couldn't rewrite the creation of a persistent variable");
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ LLDB_LOG(log, "MaybeHandleVariable ({0})", PrintValue(llvm_value_ptr));
+
+ if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(llvm_value_ptr)) {
+ switch (constant_expr->getOpcode()) {
+ default:
+ break;
+ case Instruction::GetElementPtr:
+ case Instruction::BitCast:
+ Value *s = constant_expr->getOperand(0);
+ if (!MaybeHandleVariable(s))
+ return false;
+ }
+ } else if (GlobalVariable *global_variable =
+ dyn_cast<GlobalVariable>(llvm_value_ptr)) {
+ if (!GlobalValue::isExternalLinkage(global_variable->getLinkage()))
+ return true;
+
+ clang::NamedDecl *named_decl = DeclForGlobal(global_variable);
+
+ if (!named_decl) {
+ if (IsObjCSelectorRef(llvm_value_ptr))
+ return true;
+
+ if (!global_variable->hasExternalLinkage())
+ return true;
+
+ LLDB_LOG(log, "Found global variable \"{0}\" without metadata",
+ global_variable->getName());
+
+ return false;
+ }
+
+ llvm::StringRef name(named_decl->getName());
+
+ clang::ValueDecl *value_decl = dyn_cast<clang::ValueDecl>(named_decl);
+ if (value_decl == nullptr)
+ return false;
+
+ lldb_private::CompilerType compiler_type =
+ m_decl_map->GetTypeSystem()->GetType(value_decl->getType());
+
+ const Type *value_type = nullptr;
+
+ if (name.starts_with("$")) {
+ // The $__lldb_expr_result name indicates the return value has allocated
+ // as a static variable. Per the comment at
+ // ASTResultSynthesizer::SynthesizeBodyResult, accesses to this static
+ // variable need to be redirected to the result of dereferencing a
+ // pointer that is passed in as one of the arguments.
+ //
+ // Consequently, when reporting the size of the type, we report a pointer
+ // type pointing to the type of $__lldb_expr_result, not the type itself.
+ //
+ // We also do this for any user-declared persistent variables.
+ compiler_type = compiler_type.GetPointerType();
+ value_type = PointerType::get(global_variable->getType(), 0);
+ } else {
+ value_type = global_variable->getType();
+ }
+
+ auto *target = m_execution_unit.GetTarget().get();
+ std::optional<uint64_t> value_size = compiler_type.GetByteSize(target);
+ if (!value_size)
+ return false;
+ std::optional<size_t> opt_alignment = compiler_type.GetTypeBitAlign(target);
+ if (!opt_alignment)
+ return false;
+ lldb::offset_t value_alignment = (*opt_alignment + 7ull) / 8ull;
+
+ LLDB_LOG(log,
+ "Type of \"{0}\" is [clang \"{1}\", llvm \"{2}\"] [size {3}, "
+ "align {4}]",
+ name,
+ lldb_private::ClangUtil::GetQualType(compiler_type).getAsString(),
+ PrintType(value_type), *value_size, value_alignment);
+
+ if (named_decl)
+ m_decl_map->AddValueToStruct(named_decl, lldb_private::ConstString(name),
+ llvm_value_ptr, *value_size,
+ value_alignment);
+ } else if (isa<llvm::Function>(llvm_value_ptr)) {
+ LLDB_LOG(log, "Function pointers aren't handled right now");
+
+ return false;
+ }
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool IRForTarget::HandleSymbol(Value *symbol) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ lldb_private::ConstString name(symbol->getName().str().c_str());
+
+ lldb::addr_t symbol_addr =
+ m_decl_map->GetSymbolAddress(name, lldb::eSymbolTypeAny);
+
+ if (symbol_addr == LLDB_INVALID_ADDRESS) {
+ LLDB_LOG(log, "Symbol \"{0}\" had no address", name);
+
+ return false;
+ }
+
+ LLDB_LOG(log, "Found \"{0}\" at {1}", name, symbol_addr);
+
+ Type *symbol_type = symbol->getType();
+
+ Constant *symbol_addr_int = ConstantInt::get(m_intptr_ty, symbol_addr, false);
+
+ Value *symbol_addr_ptr =
+ ConstantExpr::getIntToPtr(symbol_addr_int, symbol_type);
+
+ LLDB_LOG(log, "Replacing {0} with {1}", PrintValue(symbol),
+ PrintValue(symbol_addr_ptr));
+
+ symbol->replaceAllUsesWith(symbol_addr_ptr);
+
+ return true;
+}
+
+bool IRForTarget::MaybeHandleCallArguments(CallInst *Old) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ LLDB_LOG(log, "MaybeHandleCallArguments({0})", PrintValue(Old));
+
+ for (unsigned op_index = 0, num_ops = Old->arg_size();
+ op_index < num_ops; ++op_index)
+ // conservatively believe that this is a store
+ if (!MaybeHandleVariable(Old->getArgOperand(op_index))) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Couldn't rewrite "
+ "one of the arguments of a function call.\n");
+
+ return false;
+ }
+
+ return true;
+}
+
+bool IRForTarget::HandleObjCClass(Value *classlist_reference) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ GlobalVariable *global_variable =
+ dyn_cast<GlobalVariable>(classlist_reference);
+
+ if (!global_variable)
+ return false;
+
+ Constant *initializer = global_variable->getInitializer();
+
+ if (!initializer)
+ return false;
+
+ if (!initializer->hasName())
+ return false;
+
+ StringRef name(initializer->getName());
+ lldb_private::ConstString name_cstr(name.str().c_str());
+ lldb::addr_t class_ptr =
+ m_decl_map->GetSymbolAddress(name_cstr, lldb::eSymbolTypeObjCClass);
+
+ LLDB_LOG(log, "Found reference to Objective-C class {0} ({1})", name,
+ (unsigned long long)class_ptr);
+
+ if (class_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (global_variable->use_empty())
+ return false;
+
+ SmallVector<LoadInst *, 2> load_instructions;
+
+ for (llvm::User *u : global_variable->users()) {
+ if (LoadInst *load_instruction = dyn_cast<LoadInst>(u))
+ load_instructions.push_back(load_instruction);
+ }
+
+ if (load_instructions.empty())
+ return false;
+
+ Constant *class_addr = ConstantInt::get(m_intptr_ty, (uint64_t)class_ptr);
+
+ for (LoadInst *load_instruction : load_instructions) {
+ Constant *class_bitcast =
+ ConstantExpr::getIntToPtr(class_addr, load_instruction->getType());
+
+ load_instruction->replaceAllUsesWith(class_bitcast);
+
+ load_instruction->eraseFromParent();
+ }
+
+ return true;
+}
+
+bool IRForTarget::RemoveCXAAtExit(BasicBlock &basic_block) {
+ std::vector<CallInst *> calls_to_remove;
+
+ for (Instruction &inst : basic_block) {
+ CallInst *call = dyn_cast<CallInst>(&inst);
+
+ // MaybeHandleCallArguments handles error reporting; we are silent here
+ if (!call)
+ continue;
+
+ bool remove = false;
+
+ llvm::Function *func = call->getCalledFunction();
+
+ if (func && func->getName() == "__cxa_atexit")
+ remove = true;
+
+ llvm::Value *val = call->getCalledOperand();
+
+ if (val && val->getName() == "__cxa_atexit")
+ remove = true;
+
+ if (remove)
+ calls_to_remove.push_back(call);
+ }
+
+ for (CallInst *ci : calls_to_remove)
+ ci->eraseFromParent();
+
+ return true;
+}
+
+bool IRForTarget::ResolveCalls(BasicBlock &basic_block) {
+ // Prepare the current basic block for execution in the remote process
+
+ for (Instruction &inst : basic_block) {
+ CallInst *call = dyn_cast<CallInst>(&inst);
+
+ // MaybeHandleCallArguments handles error reporting; we are silent here
+ if (call && !MaybeHandleCallArguments(call))
+ return false;
+ }
+
+ return true;
+}
+
+bool IRForTarget::ResolveExternals(Function &llvm_function) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ for (GlobalVariable &global_var : m_module->globals()) {
+ llvm::StringRef global_name = global_var.getName();
+
+ LLDB_LOG(log, "Examining {0}, DeclForGlobalValue returns {1}", global_name,
+ static_cast<void *>(DeclForGlobal(&global_var)));
+
+ if (global_name.starts_with("OBJC_IVAR")) {
+ if (!HandleSymbol(&global_var)) {
+ m_error_stream.Format("Error [IRForTarget]: Couldn't find Objective-C "
+ "indirect ivar symbol {0}\n",
+ global_name);
+
+ return false;
+ }
+ } else if (global_name.contains("OBJC_CLASSLIST_REFERENCES_$")) {
+ if (!HandleObjCClass(&global_var)) {
+ m_error_stream.Printf("Error [IRForTarget]: Couldn't resolve the class "
+ "for an Objective-C static method call\n");
+
+ return false;
+ }
+ } else if (global_name.contains("OBJC_CLASSLIST_SUP_REFS_$")) {
+ if (!HandleObjCClass(&global_var)) {
+ m_error_stream.Printf("Error [IRForTarget]: Couldn't resolve the class "
+ "for an Objective-C static method call\n");
+
+ return false;
+ }
+ } else if (DeclForGlobal(&global_var)) {
+ if (!MaybeHandleVariable(&global_var)) {
+ m_error_stream.Format("Internal error [IRForTarget]: Couldn't rewrite "
+ "external variable {0}\n",
+ global_name);
+
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool isGuardVariableRef(Value *V) {
+ GlobalVariable *GV = dyn_cast<GlobalVariable>(V);
+
+ if (!GV || !GV->hasName() || !isGuardVariableSymbol(GV->getName()))
+ return false;
+
+ return true;
+}
+
+void IRForTarget::TurnGuardLoadIntoZero(llvm::Instruction *guard_load) {
+ Constant *zero(Constant::getNullValue(guard_load->getType()));
+ guard_load->replaceAllUsesWith(zero);
+ guard_load->eraseFromParent();
+}
+
+static void ExciseGuardStore(Instruction *guard_store) {
+ guard_store->eraseFromParent();
+}
+
+bool IRForTarget::RemoveGuards(BasicBlock &basic_block) {
+ // Eliminate any reference to guard variables found.
+
+ InstrList guard_loads;
+ InstrList guard_stores;
+
+ for (Instruction &inst : basic_block) {
+
+ if (LoadInst *load = dyn_cast<LoadInst>(&inst))
+ if (isGuardVariableRef(load->getPointerOperand()))
+ guard_loads.push_back(&inst);
+
+ if (StoreInst *store = dyn_cast<StoreInst>(&inst))
+ if (isGuardVariableRef(store->getPointerOperand()))
+ guard_stores.push_back(&inst);
+ }
+
+ for (Instruction *inst : guard_loads)
+ TurnGuardLoadIntoZero(inst);
+
+ for (Instruction *inst : guard_stores)
+ ExciseGuardStore(inst);
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool IRForTarget::UnfoldConstant(Constant *old_constant,
+ llvm::Function *llvm_function,
+ FunctionValueCache &value_maker,
+ FunctionValueCache &entry_instruction_finder,
+ lldb_private::Stream &error_stream) {
+ SmallVector<User *, 16> users;
+
+ // We do this because the use list might change, invalidating our iterator.
+ // Much better to keep a work list ourselves.
+ for (llvm::User *u : old_constant->users())
+ users.push_back(u);
+
+ for (size_t i = 0; i < users.size(); ++i) {
+ User *user = users[i];
+
+ if (Constant *constant = dyn_cast<Constant>(user)) {
+ // synthesize a new non-constant equivalent of the constant
+
+ if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant)) {
+ switch (constant_expr->getOpcode()) {
+ default:
+ error_stream.Printf("error [IRForTarget internal]: Unhandled "
+ "constant expression type: \"%s\"",
+ PrintValue(constant_expr).c_str());
+ return false;
+ case Instruction::BitCast: {
+ FunctionValueCache bit_cast_maker(
+ [&value_maker, &entry_instruction_finder, old_constant,
+ constant_expr](llvm::Function *function) -> llvm::Value * {
+ // UnaryExpr
+ // OperandList[0] is value
+
+ if (constant_expr->getOperand(0) != old_constant)
+ return constant_expr;
+
+ return new BitCastInst(
+ value_maker.GetValue(function), constant_expr->getType(),
+ "", llvm::cast<Instruction>(
+ entry_instruction_finder.GetValue(function)));
+ });
+
+ if (!UnfoldConstant(constant_expr, llvm_function, bit_cast_maker,
+ entry_instruction_finder, error_stream))
+ return false;
+ } break;
+ case Instruction::GetElementPtr: {
+ // GetElementPtrConstantExpr
+ // OperandList[0] is base
+ // OperandList[1]... are indices
+
+ FunctionValueCache get_element_pointer_maker(
+ [&value_maker, &entry_instruction_finder, old_constant,
+ constant_expr](llvm::Function *function) -> llvm::Value * {
+ auto *gep = cast<llvm::GEPOperator>(constant_expr);
+ Value *ptr = gep->getPointerOperand();
+
+ if (ptr == old_constant)
+ ptr = value_maker.GetValue(function);
+
+ std::vector<Value *> index_vector;
+ for (Value *operand : gep->indices()) {
+ if (operand == old_constant)
+ operand = value_maker.GetValue(function);
+
+ index_vector.push_back(operand);
+ }
+
+ ArrayRef<Value *> indices(index_vector);
+
+ return GetElementPtrInst::Create(
+ gep->getSourceElementType(), ptr, indices, "",
+ llvm::cast<Instruction>(
+ entry_instruction_finder.GetValue(function)));
+ });
+
+ if (!UnfoldConstant(constant_expr, llvm_function,
+ get_element_pointer_maker,
+ entry_instruction_finder, error_stream))
+ return false;
+ } break;
+ }
+ } else {
+ error_stream.Printf(
+ "error [IRForTarget internal]: Unhandled constant type: \"%s\"",
+ PrintValue(constant).c_str());
+ return false;
+ }
+ } else {
+ if (Instruction *inst = llvm::dyn_cast<Instruction>(user)) {
+ if (llvm_function && inst->getParent()->getParent() != llvm_function) {
+ error_stream.PutCString("error: Capturing non-local variables in "
+ "expressions is unsupported.\n");
+ return false;
+ }
+ inst->replaceUsesOfWith(
+ old_constant, value_maker.GetValue(inst->getParent()->getParent()));
+ } else {
+ error_stream.Printf(
+ "error [IRForTarget internal]: Unhandled non-constant type: \"%s\"",
+ PrintValue(user).c_str());
+ return false;
+ }
+ }
+ }
+
+ if (!isa<GlobalValue>(old_constant)) {
+ old_constant->destroyConstant();
+ }
+
+ return true;
+}
+
+bool IRForTarget::ReplaceVariables(Function &llvm_function) {
+ if (!m_resolve_vars)
+ return true;
+
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ m_decl_map->DoStructLayout();
+
+ LLDB_LOG(log, "Element arrangement:");
+
+ uint32_t num_elements;
+ uint32_t element_index;
+
+ size_t size;
+ lldb::offset_t alignment;
+
+ if (!m_decl_map->GetStructInfo(num_elements, size, alignment))
+ return false;
+
+ Function::arg_iterator iter(llvm_function.arg_begin());
+
+ if (iter == llvm_function.arg_end()) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Wrapper takes no "
+ "arguments (should take at least a struct pointer)");
+
+ return false;
+ }
+
+ Argument *argument = &*iter;
+
+ if (argument->getName() == "this") {
+ ++iter;
+
+ if (iter == llvm_function.arg_end()) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Wrapper takes only "
+ "'this' argument (should take a struct pointer "
+ "too)");
+
+ return false;
+ }
+
+ argument = &*iter;
+ } else if (argument->getName() == "self") {
+ ++iter;
+
+ if (iter == llvm_function.arg_end()) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Wrapper takes only "
+ "'self' argument (should take '_cmd' and a struct "
+ "pointer too)");
+
+ return false;
+ }
+
+ if (iter->getName() != "_cmd") {
+ m_error_stream.Format("Internal error [IRForTarget]: Wrapper takes '{0}' "
+ "after 'self' argument (should take '_cmd')",
+ iter->getName());
+
+ return false;
+ }
+
+ ++iter;
+
+ if (iter == llvm_function.arg_end()) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Wrapper takes only "
+ "'self' and '_cmd' arguments (should take a struct "
+ "pointer too)");
+
+ return false;
+ }
+
+ argument = &*iter;
+ }
+
+ if (argument->getName() != "$__lldb_arg") {
+ m_error_stream.Format("Internal error [IRForTarget]: Wrapper takes an "
+ "argument named '{0}' instead of the struct pointer",
+ argument->getName());
+
+ return false;
+ }
+
+ LLDB_LOG(log, "Arg: \"{0}\"", PrintValue(argument));
+
+ BasicBlock &entry_block(llvm_function.getEntryBlock());
+ Instruction *FirstEntryInstruction(entry_block.getFirstNonPHIOrDbg());
+
+ if (!FirstEntryInstruction) {
+ m_error_stream.Printf("Internal error [IRForTarget]: Couldn't find the "
+ "first instruction in the wrapper for use in "
+ "rewriting");
+
+ return false;
+ }
+
+ LLVMContext &context(m_module->getContext());
+ IntegerType *offset_type(Type::getInt32Ty(context));
+
+ if (!offset_type) {
+ m_error_stream.Printf(
+ "Internal error [IRForTarget]: Couldn't produce an offset type");
+
+ return false;
+ }
+
+ for (element_index = 0; element_index < num_elements; ++element_index) {
+ const clang::NamedDecl *decl = nullptr;
+ Value *value = nullptr;
+ lldb::offset_t offset;
+ lldb_private::ConstString name;
+
+ if (!m_decl_map->GetStructElement(decl, value, offset, name,
+ element_index)) {
+ m_error_stream.Printf(
+ "Internal error [IRForTarget]: Structure information is incomplete");
+
+ return false;
+ }
+
+ LLDB_LOG(log, " \"{0}\" (\"{1}\") placed at {2}", name,
+ decl->getNameAsString(), offset);
+
+ if (value) {
+ LLDB_LOG(log, " Replacing [{0}]", PrintValue(value));
+
+ FunctionValueCache body_result_maker(
+ [this, name, offset_type, offset, argument,
+ value](llvm::Function *function) -> llvm::Value * {
+ // Per the comment at ASTResultSynthesizer::SynthesizeBodyResult,
+ // in cases where the result variable is an rvalue, we have to
+ // synthesize a dereference of the appropriate structure entry in
+ // order to produce the static variable that the AST thinks it is
+ // accessing.
+
+ llvm::Instruction *entry_instruction = llvm::cast<Instruction>(
+ m_entry_instruction_finder.GetValue(function));
+
+ Type *int8Ty = Type::getInt8Ty(function->getContext());
+ ConstantInt *offset_int(
+ ConstantInt::get(offset_type, offset, true));
+ GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(
+ int8Ty, argument, offset_int, "", entry_instruction);
+
+ if (name == m_result_name && !m_result_is_pointer) {
+ LoadInst *load = new LoadInst(value->getType(), get_element_ptr,
+ "", entry_instruction);
+
+ return load;
+ } else {
+ return get_element_ptr;
+ }
+ });
+
+ if (Constant *constant = dyn_cast<Constant>(value)) {
+ if (!UnfoldConstant(constant, &llvm_function, body_result_maker,
+ m_entry_instruction_finder, m_error_stream)) {
+ return false;
+ }
+ } else if (Instruction *instruction = dyn_cast<Instruction>(value)) {
+ if (instruction->getParent()->getParent() != &llvm_function) {
+ m_error_stream.PutCString("error: Capturing non-local variables in "
+ "expressions is unsupported.\n");
+ return false;
+ }
+ value->replaceAllUsesWith(
+ body_result_maker.GetValue(instruction->getParent()->getParent()));
+ } else {
+ LLDB_LOG(log, "Unhandled non-constant type: \"{0}\"",
+ PrintValue(value));
+ return false;
+ }
+
+ if (GlobalVariable *var = dyn_cast<GlobalVariable>(value))
+ var->eraseFromParent();
+ }
+ }
+
+ LLDB_LOG(log, "Total structure [align {0}, size {1}]", (int64_t)alignment,
+ (uint64_t)size);
+
+ return true;
+}
+
+bool IRForTarget::runOnModule(Module &llvm_module) {
+ lldb_private::Log *log(GetLog(LLDBLog::Expressions));
+
+ m_module = &llvm_module;
+ m_target_data = std::make_unique<DataLayout>(m_module);
+ m_intptr_ty = llvm::Type::getIntNTy(m_module->getContext(),
+ m_target_data->getPointerSizeInBits());
+
+ if (log) {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ m_module->print(oss, nullptr);
+
+ oss.flush();
+
+ LLDB_LOG(log, "Module as passed in to IRForTarget: \n\"{0}\"", s);
+ }
+
+ Function *const main_function =
+ m_func_name.IsEmpty() ? nullptr
+ : m_module->getFunction(m_func_name.GetStringRef());
+
+ if (!m_func_name.IsEmpty() && !main_function) {
+ LLDB_LOG(log, "Couldn't find \"{0}()\" in the module", m_func_name);
+
+ m_error_stream.Format("Internal error [IRForTarget]: Couldn't find wrapper "
+ "'{0}' in the module",
+ m_func_name);
+
+ return false;
+ }
+
+ if (main_function) {
+ if (!FixFunctionLinkage(*main_function)) {
+ LLDB_LOG(log, "Couldn't fix the linkage for the function");
+
+ return false;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////
+ // Replace $__lldb_expr_result with a persistent variable
+ //
+
+ if (main_function) {
+ if (!CreateResultVariable(*main_function)) {
+ LLDB_LOG(log, "CreateResultVariable() failed");
+
+ // CreateResultVariable() reports its own errors, so we don't do so here
+
+ return false;
+ }
+ }
+
+ if (log && log->GetVerbose()) {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ m_module->print(oss, nullptr);
+
+ oss.flush();
+
+ LLDB_LOG(log, "Module after creating the result variable: \n\"{0}\"", s);
+ }
+
+ for (llvm::Function &function : *m_module) {
+ for (BasicBlock &bb : function) {
+ if (!RemoveGuards(bb)) {
+ LLDB_LOG(log, "RemoveGuards() failed");
+
+ // RemoveGuards() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!RewritePersistentAllocs(bb)) {
+ LLDB_LOG(log, "RewritePersistentAllocs() failed");
+
+ // RewritePersistentAllocs() reports its own errors, so we don't do so
+ // here
+
+ return false;
+ }
+
+ if (!RemoveCXAAtExit(bb)) {
+ LLDB_LOG(log, "RemoveCXAAtExit() failed");
+
+ // RemoveCXAAtExit() reports its own errors, so we don't do so here
+
+ return false;
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Fix all Objective-C constant strings to use NSStringWithCString:encoding:
+ //
+
+ if (!RewriteObjCConstStrings()) {
+ LLDB_LOG(log, "RewriteObjCConstStrings() failed");
+
+ // RewriteObjCConstStrings() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ for (llvm::Function &function : *m_module) {
+ for (llvm::BasicBlock &bb : function) {
+ if (!RewriteObjCSelectors(bb)) {
+ LLDB_LOG(log, "RewriteObjCSelectors() failed");
+
+ // RewriteObjCSelectors() reports its own errors, so we don't do so
+ // here
+
+ return false;
+ }
+ }
+ }
+
+ for (llvm::Function &function : *m_module) {
+ for (BasicBlock &bb : function) {
+ if (!ResolveCalls(bb)) {
+ LLDB_LOG(log, "ResolveCalls() failed");
+
+ // ResolveCalls() reports its own errors, so we don't do so here
+
+ return false;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Run function-level passes that only make sense on the main function
+ //
+
+ if (main_function) {
+ if (!ResolveExternals(*main_function)) {
+ LLDB_LOG(log, "ResolveExternals() failed");
+
+ // ResolveExternals() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!ReplaceVariables(*main_function)) {
+ LLDB_LOG(log, "ReplaceVariables() failed");
+
+ // ReplaceVariables() reports its own errors, so we don't do so here
+
+ return false;
+ }
+ }
+
+ if (log && log->GetVerbose()) {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ m_module->print(oss, nullptr);
+
+ oss.flush();
+
+ LLDB_LOG(log, "Module after preparing for execution: \n\"{0}\"", s);
+ }
+
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h
new file mode 100644
index 000000000000..a924187ba04c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h
@@ -0,0 +1,392 @@
+//===-- IRForTarget.h ---------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H
+
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
+#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>
+#include <map>
+
+namespace llvm {
+class BasicBlock;
+class CallInst;
+class Constant;
+class ConstantInt;
+class Function;
+class GlobalValue;
+class GlobalVariable;
+class Instruction;
+class Module;
+class StoreInst;
+class DataLayout;
+class Value;
+}
+
+namespace clang {
+class NamedDecl;
+}
+
+namespace lldb_private {
+class ClangExpressionDeclMap;
+class IRExecutionUnit;
+class IRMemoryMap;
+}
+
+/// \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
+/// contexts: interpreted by LLDB as a DWARF location expression, or compiled
+/// by the JIT and inserted into the target process for execution.
+///
+/// IRForTarget makes the second possible, by applying a series of
+/// transformations to the IR which make it relocatable. These
+/// transformations are discussed in more detail next to their relevant
+/// functions.
+class IRForTarget {
+public:
+ enum class LookupResult { Success, Fail, Ignore };
+
+ /// Constructor
+ ///
+ /// \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
+ /// True if the external variable references (including persistent
+ /// variables) should be resolved. If not, only external functions
+ /// are resolved.
+ ///
+ /// \param[in] execution_unit
+ /// The holder for raw data associated with the expression.
+ ///
+ /// \param[in] error_stream
+ /// If non-NULL, a stream on which errors can be printed.
+ ///
+ /// \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");
+
+ /// Run this IR transformer on a single module
+ ///
+ /// Implementation of the llvm::ModulePass::runOnModule() function.
+ ///
+ /// \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.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool runOnModule(llvm::Module &llvm_module);
+
+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
+ /// The function whose linkage is to be fixed.
+ ///
+ /// \return
+ /// True on success; false otherwise.
+ bool FixFunctionLinkage(llvm::Function &llvm_function);
+
+ /// 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] global_val
+ /// The global entity to search for
+ ///
+ /// \param[in] module
+ /// The module containing metadata to search
+ ///
+ /// \return
+ /// The corresponding variable declaration
+public:
+ static clang::NamedDecl *DeclForGlobal(const llvm::GlobalValue *global_val,
+ llvm::Module *module);
+
+private:
+ clang::NamedDecl *DeclForGlobal(llvm::GlobalValue *global);
+
+ /// The top-level pass implementation
+ ///
+ /// \param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// \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
+ /// The constant NSString to be transformed
+ ///
+ /// \param[in] CStr
+ /// The constant C string inside the NSString. This will be
+ /// passed as the bytes argument to CFStringCreateWithBytes.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool RewriteObjCConstString(llvm::GlobalVariable *NSStr,
+ llvm::GlobalVariable *CStr);
+
+ /// The top-level pass implementation
+ ///
+ /// \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
+ /// assumption that the Objective-C runtime will scan the appropriate
+ /// 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
+ /// The load of the statically-allocated selector.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool RewriteObjCSelector(llvm::Instruction *selector_load);
+
+ /// The top-level pass implementation
+ ///
+ /// \param[in] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool RewriteObjCSelectors(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.
+ /// Before transformation, these persistent variables look like normal
+ /// 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
+ /// The allocation of the persistent variable.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool RewritePersistentAlloc(llvm::Instruction *persistent_alloc);
+
+ /// The top-level pass implementation
+ ///
+ /// \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.
+
+ /// Handle a single externally-defined variable
+ ///
+ /// \param[in] value
+ /// The variable.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool MaybeHandleVariable(llvm::Value *value);
+
+ /// Handle a single externally-defined symbol
+ ///
+ /// \param[in] symbol
+ /// The symbol.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool HandleSymbol(llvm::Value *symbol);
+
+ /// Handle a single externally-defined Objective-C class
+ ///
+ /// \param[in] classlist_reference
+ /// The reference, usually "01L_OBJC_CLASSLIST_REFERENCES_$_n"
+ /// where n (if present) is an index.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool HandleObjCClass(llvm::Value *classlist_reference);
+
+ /// Handle all the arguments to a function call
+ ///
+ /// \param[in] call_inst
+ /// The call instruction.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool MaybeHandleCallArguments(llvm::CallInst *call_inst);
+
+ /// Resolve variable references in calls to external functions
+ ///
+ /// \param[in] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// \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] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// \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] llvm_function
+ /// The function currently being processed.
+ ///
+ /// \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
+ /// The load instruction to zero out.
+ void TurnGuardLoadIntoZero(llvm::Instruction *guard_load);
+
+ /// The top-level pass implementation
+ ///
+ /// \param[in] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// \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
+ /// The function currently being processed.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool ReplaceVariables(llvm::Function &llvm_function);
+
+ /// True if external variable references and persistent variable references
+ /// should be resolved
+ bool m_resolve_vars;
+ /// The name of the function to translate
+ lldb_private::ConstString m_func_name;
+ /// The name of the result variable ($0, $1, ...)
+ lldb_private::ConstString m_result_name;
+ /// The type of the result variable.
+ lldb_private::TypeFromParser m_result_type;
+ /// The module being processed, or NULL if that has not been determined yet.
+ llvm::Module *m_module = nullptr;
+ /// The target data for the module being processed, or NULL if there is no
+ /// module.
+ std::unique_ptr<llvm::DataLayout> m_target_data;
+ /// The DeclMap containing the Decls
+ lldb_private::ClangExpressionDeclMap *m_decl_map;
+ /// The address of the function CFStringCreateWithBytes, cast to the
+ /// appropriate function pointer type
+ llvm::FunctionCallee m_CFStringCreateWithBytes;
+ /// The address of the function sel_registerName, cast to the appropriate
+ /// function pointer type.
+ llvm::FunctionCallee m_sel_registerName;
+ /// The type of an integer large enough to hold a pointer.
+ llvm::IntegerType *m_intptr_ty = nullptr;
+ /// The stream on which errors should be printed.
+ lldb_private::Stream &m_error_stream;
+ /// The execution unit containing the IR being created.
+ lldb_private::IRExecutionUnit &m_execution_unit;
+ /// True if the function's result in the AST is a pointer (see comments in
+ /// ASTResultSynthesizer::SynthesizeBodyResult)
+ bool m_result_is_pointer = false;
+
+ class FunctionValueCache {
+ public:
+ typedef std::function<llvm::Value *(llvm::Function *)> Maker;
+
+ FunctionValueCache(Maker const &maker);
+ ~FunctionValueCache();
+ llvm::Value *GetValue(llvm::Function *function);
+
+ private:
+ Maker const m_maker;
+ typedef std::map<llvm::Function *, llvm::Value *> FunctionValueMap;
+ FunctionValueMap m_values;
+ };
+
+ FunctionValueCache m_entry_instruction_finder;
+
+ /// 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
+ /// basic block [FirstEntryInstruction].
+ ///
+ /// UnfoldConstant reads through the uses of Old and replaces Old in those
+ /// uses with New. Where those uses are constants, the function generates
+ /// new instructions to compute the result of the new, non-constant
+ /// expression and places them before FirstEntryInstruction. These
+ /// instructions replace the constant uses, so UnfoldConstant calls itself
+ /// recursively for those.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ static bool UnfoldConstant(llvm::Constant *old_constant,
+ llvm::Function *llvm_function,
+ FunctionValueCache &value_maker,
+ FunctionValueCache &entry_instruction_finder,
+ lldb_private::Stream &error_stream);
+};
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h
new file mode 100644
index 000000000000..4fe727460fdb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h
@@ -0,0 +1,40 @@
+//===-- 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 LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_MODULEDEPENDENCYCOLLECTOR_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_MODULEDEPENDENCYCOLLECTOR_H
+
+#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileCollector.h"
+
+namespace lldb_private {
+class ModuleDependencyCollectorAdaptor
+ : public clang::ModuleDependencyCollector {
+public:
+ ModuleDependencyCollectorAdaptor(
+ std::shared_ptr<llvm::FileCollectorBase> file_collector)
+ : clang::ModuleDependencyCollector(""), m_file_collector(file_collector) {
+ }
+
+ void addFile(llvm::StringRef Filename,
+ llvm::StringRef FileDst = {}) override {
+ if (m_file_collector)
+ 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:
+ std::shared_ptr<llvm::FileCollectorBase> m_file_collector;
+};
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
new file mode 100644
index 000000000000..da59855a9f16
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
@@ -0,0 +1,180 @@
+//===-- NameSearchContext.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NameSearchContext.h"
+#include "ClangUtil.h"
+#include "lldb/Utility/LLDBLog.h"
+
+using namespace clang;
+using namespace lldb_private;
+
+clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) {
+ assert(type && "Type for variable must be valid!");
+
+ if (!type.IsValid())
+ return nullptr;
+
+ auto lldb_ast = type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+ if (!lldb_ast)
+ return nullptr;
+
+ IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo();
+
+ clang::ASTContext &ast = lldb_ast->getASTContext();
+
+ clang::NamedDecl *Decl = VarDecl::Create(
+ ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(),
+ SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static);
+ m_decls.push_back(Decl);
+
+ return Decl;
+}
+
+clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
+ bool extern_c) {
+ assert(type && "Type for variable must be valid!");
+
+ if (!type.IsValid())
+ return nullptr;
+
+ if (m_function_types.count(type))
+ return nullptr;
+
+ auto lldb_ast = type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+ if (!lldb_ast)
+ return nullptr;
+
+ m_function_types.insert(type);
+
+ QualType qual_type(ClangUtil::GetQualType(type));
+
+ clang::ASTContext &ast = lldb_ast->getASTContext();
+
+ const bool isInlineSpecified = false;
+ const bool hasWrittenPrototype = true;
+ const bool isConstexprSpecified = false;
+
+ clang::DeclContext *context = const_cast<DeclContext *>(m_decl_context);
+
+ if (extern_c) {
+ context = LinkageSpecDecl::Create(ast, context, SourceLocation(),
+ SourceLocation(),
+ clang::LinkageSpecLanguageIDs::C, false);
+ // FIXME: The LinkageSpecDecl here should be added to m_decl_context.
+ }
+
+ // Pass the identifier info for functions the decl_name is needed for
+ // operators
+ clang::DeclarationName decl_name =
+ m_decl_name.getNameKind() == DeclarationName::Identifier
+ ? m_decl_name.getAsIdentifierInfo()
+ : m_decl_name;
+
+ clang::FunctionDecl *func_decl = FunctionDecl::Create(
+ ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type,
+ nullptr, SC_Extern, /*UsesFPIntrin=*/false, isInlineSpecified, hasWrittenPrototype,
+ isConstexprSpecified ? ConstexprSpecKind::Constexpr
+ : ConstexprSpecKind::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
+ // this, we raid the function's FunctionProtoType for types.
+
+ const FunctionProtoType *func_proto_type =
+ qual_type.getTypePtr()->getAs<FunctionProtoType>();
+
+ if (func_proto_type) {
+ unsigned NumArgs = func_proto_type->getNumParams();
+ unsigned ArgIndex;
+
+ SmallVector<ParmVarDecl *, 5> parm_var_decls;
+
+ 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(), nullptr,
+ arg_qual_type, nullptr, SC_Static, nullptr));
+ }
+
+ func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls));
+ } else {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ LLDB_LOG(log, "Function type wasn't a FunctionProtoType");
+ }
+
+ // If this is an operator (e.g. operator new or operator==), only insert the
+ // declaration we inferred from the symbol if we can provide the correct
+ // number of arguments. We shouldn't really inject random decl(s) for
+ // functions that are analyzed semantically in a special way, otherwise we
+ // will crash in clang.
+ clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
+ if (func_proto_type &&
+ TypeSystemClang::IsOperator(decl_name.getAsString().c_str(), op_kind)) {
+ if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
+ false, op_kind, func_proto_type->getNumParams()))
+ return nullptr;
+ }
+ m_decls.push_back(func_decl);
+
+ return func_decl;
+}
+
+clang::NamedDecl *NameSearchContext::AddGenericFunDecl() {
+ FunctionProtoType::ExtProtoInfo proto_info;
+
+ proto_info.Variadic = true;
+
+ QualType generic_function_type(
+ GetASTContext().getFunctionType(GetASTContext().UnknownAnyTy, // result
+ ArrayRef<QualType>(), // argument types
+ proto_info));
+
+ return AddFunDecl(m_clang_ts.GetType(generic_function_type), true);
+}
+
+clang::NamedDecl *
+NameSearchContext::AddTypeDecl(const CompilerType &clang_type) {
+ if (ClangUtil::IsClangType(clang_type)) {
+ QualType qual_type = ClangUtil::GetQualType(clang_type);
+
+ if (const TypedefType *typedef_type =
+ llvm::dyn_cast<TypedefType>(qual_type)) {
+ TypedefNameDecl *typedef_name_decl = typedef_type->getDecl();
+
+ m_decls.push_back(typedef_name_decl);
+
+ return (NamedDecl *)typedef_name_decl;
+ } else if (const TagType *tag_type = qual_type->getAs<TagType>()) {
+ TagDecl *tag_decl = tag_type->getDecl();
+
+ m_decls.push_back(tag_decl);
+
+ return tag_decl;
+ } else if (const ObjCObjectType *objc_object_type =
+ qual_type->getAs<ObjCObjectType>()) {
+ ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface();
+
+ m_decls.push_back((NamedDecl *)interface_decl);
+
+ return (NamedDecl *)interface_decl;
+ }
+ }
+ return nullptr;
+}
+
+void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) {
+ for (clang::NamedDecl *decl : result)
+ m_decls.push_back(decl);
+}
+
+void NameSearchContext::AddNamedDecl(clang::NamedDecl *decl) {
+ m_decls.push_back(decl);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h
new file mode 100644
index 000000000000..9a3320636081
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h
@@ -0,0 +1,123 @@
+//===-- NameSearchContext.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H
+#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "llvm/ADT/SmallSet.h"
+
+namespace lldb_private {
+
+/// \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 {
+ /// The type system of the AST from which the lookup originated.
+ TypeSystemClang &m_clang_ts;
+ /// The list of declarations already constructed.
+ llvm::SmallVectorImpl<clang::NamedDecl *> &m_decls;
+ /// The mapping of all namespaces found for this request back to their
+ /// modules.
+ ClangASTImporter::NamespaceMapSP m_namespace_map;
+ /// The name being looked for.
+ const clang::DeclarationName m_decl_name;
+ /// The DeclContext to put declarations into.
+ const clang::DeclContext *m_decl_context;
+ /// All the types of functions that have been reported, so we don't
+ /// report conflicts.
+ llvm::SmallSet<CompilerType, 5> m_function_types;
+
+ bool m_found_variable = false;
+ bool m_found_function_with_type_info = false;
+ bool m_found_local_vars_nsp = false;
+ bool m_found_type = false;
+
+ /// Constructor
+ ///
+ /// Initializes class variables.
+ ///
+ /// \param[in] clang_ts
+ /// The TypeSystemClang from which the request originates.
+ ///
+ /// \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
+ /// The name being searched for (always an Identifier).
+ ///
+ /// \param[in] dc
+ /// The DeclContext to register Decls in.
+ NameSearchContext(TypeSystemClang &clang_ts,
+ llvm::SmallVectorImpl<clang::NamedDecl *> &decls,
+ clang::DeclarationName name, const clang::DeclContext *dc)
+ : m_clang_ts(clang_ts), m_decls(decls),
+ m_namespace_map(std::make_shared<ClangASTImporter::NamespaceMap>()),
+ m_decl_name(name), m_decl_context(dc) {
+ ;
+ }
+
+ /// Create a VarDecl with the name being searched for and the provided type
+ /// and register it in the right places.
+ ///
+ /// \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
+ /// The opaque QualType for the FunDecl being registered.
+ ///
+ /// \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
+ /// 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
+ /// 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
+ /// The NamedDecl, usually returned as the result
+ /// of querying a DeclContext.
+ void AddNamedDecl(clang::NamedDecl *decl);
+
+private:
+ clang::ASTContext &GetASTContext() const {
+ return m_clang_ts.getASTContext();
+ }
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H