summaryrefslogtreecommitdiffstats
path: root/source/Plugins/ExpressionParser
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2015-12-30 11:55:28 +0000
committerdim <dim@FreeBSD.org>2015-12-30 11:55:28 +0000
commit66b75430a93929d6fc6ed63db14ca28e3ad5b1f6 (patch)
tree9ed5e1a91f242e2cb5911577356e487a55c01b78 /source/Plugins/ExpressionParser
parent23814158e5384f73c6fa951b66d5f807f9c24a2b (diff)
downloadFreeBSD-src-66b75430a93929d6fc6ed63db14ca28e3ad5b1f6.zip
FreeBSD-src-66b75430a93929d6fc6ed63db14ca28e3ad5b1f6.tar.gz
Vendor import of stripped lldb trunk r256633:
https://llvm.org/svn/llvm-project/lldb/trunk@256633
Diffstat (limited to 'source/Plugins/ExpressionParser')
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTDumper.cpp134
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTDumper.h42
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp514
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h185
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp221
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h158
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp2101
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangASTSource.h526
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp2351
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h714
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h79
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp657
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h136
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp76
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h265
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp221
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h173
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp731
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h128
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp84
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h106
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp673
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUserExpression.h218
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp189
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h137
-rw-r--r--source/Plugins/ExpressionParser/Clang/IRForTarget.cpp2820
-rw-r--r--source/Plugins/ExpressionParser/Clang/IRForTarget.h745
-rw-r--r--source/Plugins/ExpressionParser/Go/GoAST.h3225
-rw-r--r--source/Plugins/ExpressionParser/Go/GoLexer.cpp402
-rw-r--r--source/Plugins/ExpressionParser/Go/GoLexer.h201
-rw-r--r--source/Plugins/ExpressionParser/Go/GoParser.cpp1035
-rw-r--r--source/Plugins/ExpressionParser/Go/GoParser.h165
-rw-r--r--source/Plugins/ExpressionParser/Go/GoUserExpression.cpp756
-rw-r--r--source/Plugins/ExpressionParser/Go/GoUserExpression.h98
-rw-r--r--source/Plugins/ExpressionParser/Go/gen_go_ast.py356
35 files changed, 20622 insertions, 0 deletions
diff --git a/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp b/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp
new file mode 100644
index 0000000..9763106
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp
@@ -0,0 +1,134 @@
+//===-- ASTDumper.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTDumper.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompilerType.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lldb_private;
+
+ASTDumper::ASTDumper (clang::Decl *decl)
+{
+ clang::DeclContext *decl_ctx = llvm::dyn_cast<clang::DeclContext>(decl);
+
+ bool has_external_lexical_storage;
+ bool has_external_visible_storage;
+
+ if (decl_ctx)
+ {
+ has_external_lexical_storage = decl_ctx->hasExternalLexicalStorage();
+ has_external_visible_storage = decl_ctx->hasExternalVisibleStorage();
+ decl_ctx->setHasExternalLexicalStorage(false);
+ decl_ctx->setHasExternalVisibleStorage(false);
+ }
+
+ llvm::raw_string_ostream os(m_dump);
+ decl->print (os);
+ os.flush();
+
+ if (decl_ctx)
+ {
+ decl_ctx->setHasExternalLexicalStorage(has_external_lexical_storage);
+ decl_ctx->setHasExternalVisibleStorage(has_external_visible_storage);
+ }
+}
+
+ASTDumper::ASTDumper (clang::DeclContext *decl_ctx)
+{
+ bool has_external_lexical_storage = decl_ctx->hasExternalLexicalStorage();
+ bool has_external_visible_storage = decl_ctx->hasExternalVisibleStorage();
+
+ decl_ctx->setHasExternalLexicalStorage(false);
+ decl_ctx->setHasExternalVisibleStorage(false);
+
+ if (clang::Decl *decl = llvm::dyn_cast<clang::Decl>(decl_ctx))
+ {
+ llvm::raw_string_ostream os(m_dump);
+ decl->print (os);
+ os.flush();
+ }
+ else
+ {
+ m_dump.assign("<DeclContext is not a Decl>");
+ }
+
+ decl_ctx->setHasExternalLexicalStorage(has_external_lexical_storage);
+ decl_ctx->setHasExternalVisibleStorage(has_external_visible_storage);
+}
+
+ASTDumper::ASTDumper (const clang::Type *type)
+{
+ m_dump = clang::QualType(type, 0).getAsString();
+}
+
+ASTDumper::ASTDumper (clang::QualType type)
+{
+ m_dump = type.getAsString();
+}
+
+ASTDumper::ASTDumper (lldb::opaque_compiler_type_t type)
+{
+ m_dump = clang::QualType::getFromOpaquePtr(type).getAsString();
+}
+
+ASTDumper::ASTDumper (const CompilerType &compiler_type)
+{
+ m_dump = ClangASTContext::GetQualType(compiler_type).getAsString();
+}
+
+
+const char *
+ASTDumper::GetCString()
+{
+ return m_dump.c_str();
+}
+
+void ASTDumper::ToSTDERR()
+{
+ fprintf(stderr, "%s\n", m_dump.c_str());
+}
+
+void ASTDumper::ToLog(Log *log, const char *prefix)
+{
+ size_t len = m_dump.length() + 1;
+
+ char *alloc = (char*)malloc(len);
+ char *str = alloc;
+
+ memcpy(str, m_dump.c_str(), len);
+
+ char *end = NULL;
+
+ end = strchr(str, '\n');
+
+ while (end)
+ {
+ *end = '\0';
+
+ log->Printf("%s%s", prefix, str);
+
+ *end = '\n';
+
+ str = end + 1;
+ end = strchr(str, '\n');
+ }
+
+ log->Printf("%s%s", prefix, str);
+
+ free(alloc);
+}
+
+void ASTDumper::ToStream(lldb::StreamSP &stream)
+{
+ stream->PutCString(m_dump.c_str());
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ASTDumper.h b/source/Plugins/ExpressionParser/Clang/ASTDumper.h
new file mode 100644
index 0000000..c8dc684
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ASTDumper.h
@@ -0,0 +1,42 @@
+//===-- ASTDumper.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ASTDumper_h_
+#define liblldb_ASTDumper_h_
+
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/TypeVisitor.h"
+
+#include "lldb/Core/Stream.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace lldb_private
+{
+
+class ASTDumper
+{
+public:
+ ASTDumper (clang::Decl *decl);
+ ASTDumper (clang::DeclContext *decl_ctx);
+ ASTDumper (const clang::Type *type);
+ ASTDumper (clang::QualType type);
+ ASTDumper (lldb::opaque_compiler_type_t type);
+ ASTDumper (const CompilerType &compiler_type);
+
+ const char *GetCString();
+ void ToSTDERR();
+ void ToLog(Log *log, const char *prefix);
+ void ToStream(lldb::StreamSP &stream);
+private:
+ std::string m_dump;
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
new file mode 100644
index 0000000..02505bd
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
@@ -0,0 +1,514 @@
+//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTResultSynthesizer.h"
+
+#include "ClangPersistentVariables.h"
+
+#include "stdlib.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 "lldb/Core/Log.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Target/Target.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace lldb_private;
+
+ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
+ Target &target) :
+ m_ast_context (NULL),
+ m_passthrough (passthrough),
+ m_passthrough_sema (NULL),
+ m_target (target),
+ m_sema (NULL)
+{
+ if (!m_passthrough)
+ return;
+
+ m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
+}
+
+ASTResultSynthesizer::~ASTResultSynthesizer()
+{
+}
+
+void
+ASTResultSynthesizer::Initialize(ASTContext &Context)
+{
+ m_ast_context = &Context;
+
+ if (m_passthrough)
+ m_passthrough->Initialize(Context);
+}
+
+void
+ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D))
+ {
+ if (log && log->GetVerbose())
+ {
+ if (named_decl->getIdentifier())
+ log->Printf("TransformTopLevelDecl(%s)", named_decl->getIdentifier()->getNameStart());
+ else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
+ log->Printf("TransformTopLevelDecl(%s)", method_decl->getSelector().getAsString().c_str());
+ else
+ log->Printf("TransformTopLevelDecl(<complex>)");
+ }
+
+ }
+
+ 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 (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))
+ {
+ if (m_ast_context &&
+ !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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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();
+
+ log->Printf ("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();
+
+ log->Printf ("Transformed function AST:\n%s", s.c_str());
+ }
+
+ return ret;
+}
+
+bool
+ASTResultSynthesizer::SynthesizeObjCMethodResult (ObjCMethodDecl *MethodDecl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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();
+
+ log->Printf ("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();
+
+ log->Printf("Transformed method AST:\n%s", s.c_str());
+ }
+
+ return ret;
+}
+
+bool
+ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
+ DeclContext *DC)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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 (dyn_cast<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 (0);
+
+ // 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.
+ //
+ // 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->getValueKind() == VK_XValue) &&
+ (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();
+
+ log->Printf("Last statement is an %s with type: %s", (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
+ }
+
+ clang::VarDecl *result_decl = NULL;
+
+ if (is_lvalue)
+ {
+ 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(SourceLocation(), expr_qual_type, clang::diag::err_incomplete_type);
+
+ QualType ptr_qual_type;
+
+ if (expr_qual_type->getAs<ObjCObjectType>() != NULL)
+ ptr_qual_type = Ctx.getObjCObjectPointerType(expr_qual_type);
+ else
+ ptr_qual_type = Ctx.getPointerType(expr_qual_type);
+
+ result_decl = VarDecl::Create(Ctx,
+ DC,
+ SourceLocation(),
+ SourceLocation(),
+ result_ptr_id,
+ ptr_qual_type,
+ NULL,
+ SC_Static);
+
+ if (!result_decl)
+ return false;
+
+ ExprResult address_of_expr = m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);
+
+ m_sema->AddInitializerToDecl(result_decl, address_of_expr.get(), true, false);
+ }
+ else
+ {
+ IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
+
+ result_decl = VarDecl::Create(Ctx,
+ DC,
+ SourceLocation(),
+ SourceLocation(),
+ &result_id,
+ expr_qual_type,
+ NULL,
+ SC_Static);
+
+ if (!result_decl)
+ return false;
+
+ m_sema->AddInitializerToDecl(result_decl, last_expr, true, false);
+ }
+
+ 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 = reinterpret_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.size() == 0 || name[0] != '$')
+ return;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ConstString name_cs(name.str().c_str());
+
+ if (log)
+ log->Printf ("Recording persistent type %s\n", name_cs.GetCString());
+
+ Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl(m_target.GetScratchClangASTContext()->getASTContext(),
+ m_ast_context,
+ D);
+
+ if (TypeDecl *TypeDecl_scratch = dyn_cast<TypeDecl>(D_scratch))
+ llvm::cast<ClangPersistentVariables>(m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC))->RegisterPersistentType(name_cs, TypeDecl_scratch);
+}
+
+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 = NULL;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->ForgetSema();
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h
new file mode 100644
index 0000000..9f7bbe0
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h
@@ -0,0 +1,185 @@
+//===-- ASTResultSynthesizer.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ASTResultSynthesizer_h_
+#define liblldb_ASTResultSynthesizer_h_
+
+#include "clang/Sema/SemaConsumer.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Target/Target.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ASTResultSynthesizer ASTResultSynthesizer.h "lldb/Expression/ASTResultSynthesizer.h"
+/// @brief 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] target
+ /// The target, which contains the persistent variable store and the
+ /// AST importer.
+ //----------------------------------------------------------------------
+ ASTResultSynthesizer(clang::ASTConsumer *passthrough,
+ 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;
+
+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.
+ ///
+ /// @param[in] Body
+ /// The body of the function.
+ //----------------------------------------------------------------------
+ void MaybeRecordPersistentType(clang::TypeDecl *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.
+ Target &m_target; ///< The target, which contains the persistent variable store and the
+ clang::Sema *m_sema; ///< The Sema to use.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ASTResultSynthesizer_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
new file mode 100644
index 0000000..38a2b6b
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
@@ -0,0 +1,221 @@
+//===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTStructExtractor.h"
+
+#include "stdlib.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 "lldb/Core/Log.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace lldb_private;
+
+ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough,
+ const char *struct_name,
+ ClangFunctionCaller &function) :
+ m_ast_context (NULL),
+ m_passthrough (passthrough),
+ m_passthrough_sema (NULL),
+ m_sema (NULL),
+ m_action (NULL),
+ m_function (function),
+ m_struct_name (struct_name)
+{
+ if (!m_passthrough)
+ return;
+
+ m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
+}
+
+ASTStructExtractor::~ASTStructExtractor()
+{
+}
+
+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 = NULL;
+
+ StringRef desired_name(m_struct_name.c_str());
+
+ 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().c_str()))
+ {
+ 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;
+ m_action = reinterpret_cast<Action*>(m_sema);
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->InitializeSema(S);
+}
+
+void
+ASTStructExtractor::ForgetSema()
+{
+ m_sema = NULL;
+ m_action = NULL;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->ForgetSema();
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h
new file mode 100644
index 0000000..2152cff
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h
@@ -0,0 +1,158 @@
+//===-- ASTStructExtractor.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ASTStructExtractor_h_
+#define liblldb_ASTStructExtractor_h_
+
+#include "ClangExpressionVariable.h"
+#include "ClangFunctionCaller.h"
+
+#include "clang/Sema/SemaConsumer.h"
+#include "lldb/Core/ClangForward.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ASTStructExtractor ASTStructExtractor.h "lldb/Expression/ASTStructExtractor.h"
+/// @brief 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.
+ clang::Action *m_action; ///< The Sema to use, cast to an Action so it's usable.
+
+ 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 // liblldb_ASTStructExtractor_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
new file mode 100644
index 0000000..d2ea439
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -0,0 +1,2101 @@
+//===-- ClangASTSource.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangASTSource.h"
+
+#include "ASTDumper.h"
+#include "ClangModulesDeclVendor.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+#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()
+{
+ m_ast_importer_sp->ForgetDestination(m_ast_context);
+
+ // We are in the process of destruction, don't create clang ast context on demand
+ // by passing false to Target::GetScratchClangASTContext(create_on_demand).
+ ClangASTContext *scratch_clang_ast_context = m_target->GetScratchClangASTContext(false);
+
+ if (!scratch_clang_ast_context)
+ return;
+
+ clang::ASTContext *scratch_ast_context = scratch_clang_ast_context->getASTContext();
+
+ if (!scratch_ast_context)
+ return;
+
+ if (m_ast_context != scratch_ast_context)
+ m_ast_importer_sp->ForgetSource(scratch_ast_context, m_ast_context);
+}
+
+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;
+ }
+
+ if (GetImportInProgress())
+ {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+
+ std::string decl_name (clang_decl_name.getAsString());
+
+// if (m_decl_map.DoingASTImport ())
+// return DeclContext::lookup_result();
+//
+ 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 (*this, 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:
+ 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);
+// static uint32_t g_depth = 0;
+// ++g_depth;
+// printf("[%5u] FindExternalVisibleDeclsByName() \"%s\"\n", g_depth, uniqued_const_decl_name);
+ llvm::SmallVector<NamedDecl*, 4> name_decls;
+ NameSearchContext name_search_context(*this, name_decls, clang_decl_name, decl_ctx);
+ FindExternalVisibleDecls(name_search_context);
+ SetExternalVisibleDeclsForName (decl_ctx, clang_decl_name, name_decls);
+// --g_depth;
+ m_active_lookups.erase (uniqued_const_decl_name);
+ return (name_decls.size() != 0);
+}
+
+void
+ClangASTSource::CompleteType (TagDecl *tag_decl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ if (log)
+ {
+ log->Printf(" CompleteTagDecl[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s",
+ current_id, static_cast<void*>(m_ast_context),
+ static_cast<void*>(tag_decl),
+ tag_decl->getName().str().c_str());
+
+ log->Printf(" CTD[%u] Before:", current_id);
+ ASTDumper dumper((Decl*)tag_decl);
+ dumper.ToLog(log, " [CTD] ");
+ }
+
+ 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 (log)
+ log->Printf(" CTD[%u] Type could not be completed in the module in which it was first found.", current_id);
+
+ bool found = false;
+
+ DeclContext *decl_ctx = tag_decl->getDeclContext();
+
+ if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(decl_ctx))
+ {
+ ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CTD[%u] Inspecting namespace map %p (%d entries)",
+ current_id, static_cast<void*>(namespace_map.get()),
+ static_cast<int>(namespace_map->size()));
+
+ if (!namespace_map)
+ return;
+
+ for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
+ i != e && !found;
+ ++i)
+ {
+ if (log)
+ log->Printf(" CTD[%u] Searching namespace %s in module %s",
+ current_id,
+ i->second.GetName().AsCString(),
+ i->first->GetFileSpec().GetFilename().GetCString());
+
+ TypeList types;
+
+ SymbolContext null_sc;
+ ConstString name(tag_decl->getName().str().c_str());
+
+ i->first->FindTypesInNamespace(null_sc, name, &i->second, UINT32_MAX, types);
+
+ for (uint32_t ti = 0, te = types.GetSize();
+ ti != te && !found;
+ ++ti)
+ {
+ lldb::TypeSP type = types.GetTypeAtIndex(ti);
+
+ if (!type)
+ continue;
+
+ CompilerType clang_type (type->GetFullCompilerType ());
+
+ if (!clang_type)
+ continue;
+
+ const TagType *tag_type = ClangASTContext::GetQualType(clang_type)->getAs<TagType>();
+
+ if (!tag_type)
+ continue;
+
+ TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
+
+ if (m_ast_importer_sp->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
+ found = true;
+ }
+ }
+ }
+ else
+ {
+ TypeList types;
+
+ SymbolContext null_sc;
+ ConstString name(tag_decl->getName().str().c_str());
+ CompilerDeclContext namespace_decl;
+
+ const ModuleList &module_list = m_target->GetImages();
+
+ bool exact_match = false;
+ module_list.FindTypes (null_sc, name, exact_match, UINT32_MAX, types);
+
+ for (uint32_t ti = 0, te = types.GetSize();
+ ti != te && !found;
+ ++ti)
+ {
+ lldb::TypeSP type = types.GetTypeAtIndex(ti);
+
+ if (!type)
+ continue;
+
+ CompilerType clang_type (type->GetFullCompilerType ());
+
+ if (!clang_type)
+ continue;
+
+ const TagType *tag_type = ClangASTContext::GetQualType(clang_type)->getAs<TagType>();
+
+ if (!tag_type)
+ continue;
+
+ TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
+
+ // We have found a type by basename and we need to make sure the decl contexts
+ // are the same before we can try to complete this type with another
+ if (!ClangASTContext::DeclsAreEquivalent (tag_decl, candidate_tag_decl))
+ continue;
+
+ if (m_ast_importer_sp->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
+ found = true;
+ }
+ }
+ }
+
+ if (log)
+ {
+ log->Printf(" [CTD] After:");
+ ASTDumper dumper((Decl*)tag_decl);
+ dumper.ToLog(log, " [CTD] ");
+ }
+}
+
+void
+ClangASTSource::CompleteType (clang::ObjCInterfaceDecl *interface_decl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ log->Printf(" [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing an ObjCInterfaceDecl named %s",
+ static_cast<void*>(m_ast_context),
+ interface_decl->getName().str().c_str());
+ log->Printf(" [COID] Before:");
+ ASTDumper dumper((Decl*)interface_decl);
+ dumper.ToLog(log, " [COID] ");
+ }
+
+ Decl *original_decl = NULL;
+ ASTContext *original_ctx = NULL;
+
+ if (m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl, &original_ctx))
+ {
+ 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, original_iface_decl);
+ }
+ }
+ }
+
+ m_ast_importer_sp->CompleteObjCInterfaceDecl (interface_decl);
+
+ if (interface_decl->getSuperClass() &&
+ interface_decl->getSuperClass() != interface_decl)
+ CompleteType(interface_decl->getSuperClass());
+
+ if (log)
+ {
+ log->Printf(" [COID] After:");
+ ASTDumper dumper((Decl*)interface_decl);
+ dumper.ToLog(log, " [COID] ");
+ }
+}
+
+clang::ObjCInterfaceDecl *
+ClangASTSource::GetCompleteObjCInterface (clang::ObjCInterfaceDecl *interface_decl)
+{
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ return NULL;
+
+ ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+
+ if (!language_runtime)
+ return NULL;
+
+ ConstString class_name(interface_decl->getNameAsString().c_str());
+
+ lldb::TypeSP complete_type_sp(language_runtime->LookupInCompleteClassCache(class_name));
+
+ if (!complete_type_sp)
+ return NULL;
+
+ TypeFromUser complete_type = TypeFromUser(complete_type_sp->GetFullCompilerType ());
+ lldb::opaque_compiler_type_t complete_opaque_type = complete_type.GetOpaqueQualType();
+
+ if (!complete_opaque_type)
+ return NULL;
+
+ 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 NULL;
+
+ 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)
+{
+ ClangASTMetrics::RegisterLexicalQuery();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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);
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ if (log)
+ {
+ if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl))
+ log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in '%s' (%sDecl*)%p",
+ current_id, static_cast<void*>(m_ast_context),
+ context_named_decl->getNameAsString().c_str(),
+ context_decl->getDeclKindName(),
+ static_cast<const void*>(context_decl));
+ else if(context_decl)
+ log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in (%sDecl*)%p",
+ current_id, static_cast<void*>(m_ast_context),
+ context_decl->getDeclKindName(),
+ static_cast<const void*>(context_decl));
+ else
+ log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in a NULL context",
+ current_id, static_cast<const void*>(m_ast_context));
+ }
+
+ Decl *original_decl = NULL;
+ ASTContext *original_ctx = NULL;
+
+ if (!m_ast_importer_sp->ResolveDeclOrigin(context_decl, &original_decl, &original_ctx))
+ return;
+
+ if (log)
+ {
+ log->Printf(" FELD[%u] Original decl (ASTContext*)%p (Decl*)%p:",
+ current_id, static_cast<void*>(original_ctx),
+ static_cast<void*>(original_decl));
+ ASTDumper(original_decl).ToLog(log, " ");
+ }
+
+ 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, original_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;
+
+ for (TagDecl::decl_iterator iter = original_decl_context->decls_begin();
+ iter != original_decl_context->decls_end();
+ ++iter)
+ {
+ Decl *decl = *iter;
+
+ if (predicate(decl->getKind()))
+ {
+ if (log)
+ {
+ ASTDumper ast_dumper(decl);
+ if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl))
+ log->Printf(" FELD[%d] Adding [to %sDecl %s] lexical %sDecl %s", current_id, context_named_decl->getDeclKindName(), context_named_decl->getNameAsString().c_str(), decl->getDeclKindName(), ast_dumper.GetCString());
+ else
+ log->Printf(" FELD[%d] Adding lexical %sDecl %s", current_id, decl->getDeclKindName(), ast_dumper.GetCString());
+ }
+
+ Decl *copied_decl = m_ast_importer_sp->CopyDecl(m_ast_context, original_ctx, decl);
+
+ if (!copied_decl)
+ continue;
+
+ if (FieldDecl *copied_field = dyn_cast<FieldDecl>(copied_decl))
+ {
+ QualType copied_field_type = copied_field->getType();
+
+ m_ast_importer_sp->RequireCompleteType(copied_field_type);
+ }
+
+ DeclContext *decl_context_non_const = const_cast<DeclContext *>(decl_context);
+
+ if (copied_decl->getDeclContext() != decl_context)
+ {
+ if (copied_decl->getDeclContext()->containsDecl(copied_decl))
+ copied_decl->getDeclContext()->removeDecl(copied_decl);
+ copied_decl->setDeclContext(decl_context_non_const);
+ }
+
+ if (!decl_context_non_const->containsDecl(copied_decl))
+ decl_context_non_const->addDeclInternal(copied_decl);
+ }
+ }
+
+ return;
+}
+
+void
+ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context)
+{
+ assert (m_ast_context);
+
+ ClangASTMetrics::RegisterVisibleQuery();
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ if (log)
+ {
+ if (!context.m_decl_context)
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a NULL DeclContext",
+ current_id, static_cast<void*>(m_ast_context),
+ name.GetCString());
+ else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context))
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in '%s'",
+ current_id, static_cast<void*>(m_ast_context),
+ name.GetCString(),
+ context_named_decl->getNameAsString().c_str());
+ else
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a '%s'",
+ current_id, static_cast<void*>(m_ast_context),
+ name.GetCString(),
+ context.m_decl_context->getDeclKindName());
+ }
+
+ context.m_namespace_map.reset(new ClangASTImporter::NamespaceMap);
+
+ if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context))
+ {
+ ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CAS::FEVD[%u] Inspecting namespace map %p (%d entries)",
+ current_id, static_cast<void*>(namespace_map.get()),
+ static_cast<int>(namespace_map->size()));
+
+ if (!namespace_map)
+ return;
+
+ for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
+ i != e;
+ ++i)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] Searching namespace %s in module %s",
+ current_id,
+ i->second.GetName().AsCString(),
+ i->first->GetFileSpec().GetFilename().GetCString());
+
+ FindExternalVisibleDecls(context,
+ i->first,
+ i->second,
+ current_id);
+ }
+ }
+ 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;
+
+ if (log)
+ log->Printf(" CAS::FEVD[%u] Searching the root namespace", current_id);
+
+ FindExternalVisibleDecls(context,
+ lldb::ModuleSP(),
+ namespace_decl,
+ current_id);
+ }
+
+ if (!context.m_namespace_map->empty())
+ {
+ if (log && log->GetVerbose())
+ log->Printf(" CAS::FEVD[%u] Registering namespace map %p (%d entries)",
+ current_id,
+ static_cast<void*>(context.m_namespace_map.get()),
+ static_cast<int>(context.m_namespace_map->size()));
+
+ NamespaceDecl *clang_namespace_decl = AddNamespace(context, context.m_namespace_map);
+
+ if (clang_namespace_decl)
+ clang_namespace_decl->setHasExternalVisibleStorage();
+ }
+}
+
+void
+ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
+ lldb::ModuleSP module_sp,
+ CompilerDeclContext &namespace_decl,
+ unsigned int current_id)
+{
+ assert (m_ast_context);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ SymbolContextList sc_list;
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ const char *name_unique_cstr = name.GetCString();
+
+ static ConstString id_name("id");
+ static ConstString Class_name("Class");
+
+ if (name == id_name || name == Class_name)
+ return;
+
+ if (name_unique_cstr == NULL)
+ return;
+
+ // The ClangASTSource is not responsible for finding $-names.
+ if (name_unique_cstr[0] == '$')
+ return;
+
+ if (module_sp && namespace_decl)
+ {
+ CompilerDeclContext found_namespace_decl;
+
+ SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor();
+
+ if (symbol_vendor)
+ {
+ SymbolContext null_sc;
+
+ found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &namespace_decl);
+
+ if (found_namespace_decl)
+ {
+ context.m_namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>(module_sp, found_namespace_decl));
+
+ if (log)
+ log->Printf(" CAS::FEVD[%u] Found namespace %s in module %s",
+ current_id,
+ name.GetCString(),
+ module_sp->GetFileSpec().GetFilename().GetCString());
+ }
+ }
+ }
+ else
+ {
+ const ModuleList &target_images = m_target->GetImages();
+ Mutex::Locker modules_locker (target_images.GetMutex());
+
+ for (size_t i = 0, e = target_images.GetSize(); i < e; ++i)
+ {
+ lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i);
+
+ if (!image)
+ continue;
+
+ CompilerDeclContext found_namespace_decl;
+
+ SymbolVendor *symbol_vendor = image->GetSymbolVendor();
+
+ if (!symbol_vendor)
+ continue;
+
+ SymbolContext null_sc;
+
+ found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &namespace_decl);
+
+ if (found_namespace_decl)
+ {
+ context.m_namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>(image, found_namespace_decl));
+
+ if (log)
+ log->Printf(" CAS::FEVD[%u] Found namespace %s in module %s",
+ current_id,
+ name.GetCString(),
+ image->GetFileSpec().GetFilename().GetCString());
+ }
+ }
+ }
+
+ do
+ {
+ TypeList types;
+ SymbolContext null_sc;
+ const bool exact_match = false;
+
+ if (module_sp && namespace_decl)
+ module_sp->FindTypesInNamespace(null_sc, name, &namespace_decl, 1, types);
+ else
+ m_target->GetImages().FindTypes(null_sc, name, exact_match, 1, types);
+
+ bool found_a_type = false;
+
+ if (size_t num_types = types.GetSize())
+ {
+ for (size_t ti = 0; ti < num_types; ++ti)
+ {
+ lldb::TypeSP type_sp = types.GetTypeAtIndex(ti);
+
+ if (log)
+ {
+ const char *name_string = type_sp->GetName().GetCString();
+
+ log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\": %s",
+ current_id,
+ name.GetCString(),
+ (name_string ? name_string : "<anonymous>"));
+ }
+
+ CompilerType full_type = type_sp->GetFullCompilerType();
+
+ CompilerType copied_clang_type (GuardedCopyType(full_type));
+
+ if (!copied_clang_type)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a type",
+ current_id);
+
+ continue;
+ }
+
+ context.AddTypeDecl(copied_clang_type);
+
+ found_a_type = true;
+ break;
+ }
+ }
+
+ if (!found_a_type)
+ {
+ // Try the modules next.
+
+ do
+ {
+ if (ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor())
+ {
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(name,
+ append,
+ max_matches,
+ decls))
+ break;
+
+ if (log)
+ {
+ log->Printf(" CAS::FEVD[%u] Matching entity found for \"%s\" in the modules",
+ current_id,
+ name.GetCString());
+ }
+
+ 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 = m_ast_importer_sp->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules);
+ clang::NamedDecl *copied_named_decl = copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr;
+
+ if (!copied_named_decl)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the modules",
+ current_id);
+
+ break;
+ }
+
+ context.AddNamedDecl(copied_named_decl);
+
+ found_a_type = true;
+ }
+ }
+ } while (0);
+ }
+
+ if (!found_a_type)
+ {
+ do
+ {
+ // Couldn't find any types elsewhere. Try the Objective-C runtime if one exists.
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ break;
+
+ ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+
+ if (!language_runtime)
+ break;
+
+ DeclVendor *decl_vendor = language_runtime->GetDeclVendor();
+
+ if (!decl_vendor)
+ break;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <clang::NamedDecl *> decls;
+
+ if (!decl_vendor->FindDecls(name,
+ append,
+ max_matches,
+ decls))
+ break;
+
+ if (log)
+ {
+ log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\" in the runtime",
+ current_id,
+ name.GetCString());
+ }
+
+ clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl(m_ast_context, &decls[0]->getASTContext(), decls[0]);
+ clang::NamedDecl *copied_named_decl = copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr;
+
+ if (!copied_named_decl)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the runtime",
+ current_id);
+
+ break;
+ }
+
+ context.AddNamedDecl(copied_named_decl);
+ }
+ while(0);
+ }
+
+ } while(0);
+}
+
+template <class D> class TaggedASTDecl {
+public:
+ TaggedASTDecl() : decl(NULL) { }
+ TaggedASTDecl(D *_decl) : decl(_decl) { }
+ bool IsValid() const { return (decl != NULL); }
+ 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> (dyn_cast<D2>(source.decl));
+}
+
+template <class D = Decl> class DeclFromParser;
+template <class D = 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(ClangASTImporter *importer, ASTContext &dest_ctx);
+};
+
+template <class D>
+DeclFromUser<D>
+DeclFromParser<D>::GetOrigin(ClangASTImporter *importer)
+{
+ DeclFromUser <> origin_decl;
+ importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL);
+ if (origin_decl.IsInvalid())
+ return DeclFromUser<D>();
+ return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl));
+}
+
+template <class D>
+DeclFromParser<D>
+DeclFromUser<D>::Import(ClangASTImporter *importer, ASTContext &dest_ctx)
+{
+ DeclFromParser <> parser_generic_decl(importer->CopyDecl(&dest_ctx, &this->decl->getASTContext(), this->decl));
+ if (parser_generic_decl.IsInvalid())
+ return DeclFromParser<D>();
+ return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl));
+}
+
+static bool
+FindObjCMethodDeclsWithOrigin (unsigned int current_id,
+ NameSearchContext &context,
+ ObjCInterfaceDecl *original_interface_decl,
+ clang::ASTContext *ast_context,
+ ClangASTImporter *ast_importer,
+ 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())
+ {
+ 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);
+ IdentifierInfo *ident = &original_ctx->Idents.get(decl_name_string_without_colon.c_str());
+ original_selector = original_ctx->Selectors.getSelector(1, &ident);
+ }
+ else
+ {
+ SmallVector<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;
+
+ ClangASTContext::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 = ast_importer->CopyDecl(ast_context, &result_method->getASTContext(), result_method);
+
+ if (!copied_decl)
+ continue;
+
+ ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
+
+ if (!copied_method_decl)
+ continue;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ ASTDumper dumper((Decl*)copied_method_decl);
+ log->Printf(" CAS::FOMD[%d] found (%s) %s", current_id, log_info, dumper.GetCString());
+ }
+
+ context.AddNamedDecl(copied_method_decl);
+ }
+
+ return true;
+}
+
+void
+ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ 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
+ {
+ Decl *original_decl = NULL;
+ ASTContext *original_ctx = NULL;
+
+ m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl, &original_ctx);
+
+ if (!original_decl)
+ break;
+
+ ObjCInterfaceDecl *original_interface_decl = dyn_cast<ObjCInterfaceDecl>(original_decl);
+
+ if (FindObjCMethodDeclsWithOrigin(current_id,
+ context,
+ original_interface_decl,
+ m_ast_context,
+ m_ast_importer_sp.get(),
+ "at origin"))
+ return; // found it, no need to look any further
+ } while (0);
+
+ 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 (strstr(ss.GetData(), "$__lldb"))
+ return; // we don't need any results
+
+ ConstString selector_name(ss.GetData());
+
+ if (log)
+ log->Printf("ClangASTSource::FindObjCMethodDecls[%d] on (ASTContext*)%p for selector [%s %s]",
+ current_id, static_cast<void*>(m_ast_context),
+ interface_decl->getNameAsString().c_str(),
+ selector_name.AsCString());
+ SymbolContextList sc_list;
+
+ const bool include_symbols = false;
+ const bool include_inlines = false;
+ const bool append = 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.GetData());
+
+ m_target->GetImages().FindFunctions(instance_method_name, lldb::eFunctionNameTypeFull, include_symbols, include_inlines, append, 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.GetData());
+
+ m_target->GetImages().FindFunctions(class_method_name, lldb::eFunctionNameTypeFull, include_symbols, include_inlines, append, 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, include_symbols, include_inlines, append, candidate_sc_list);
+
+ for (uint32_t ci = 0, ce = candidate_sc_list.GetSize();
+ ci != ce;
+ ++ci)
+ {
+ SymbolContext candidate_sc;
+
+ if (!candidate_sc_list.GetContextAtIndex(ci, candidate_sc))
+ continue;
+
+ 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 (0);
+
+ if (sc_list.GetSize())
+ {
+ // We found a good function symbol. Use that.
+
+ for (uint32_t i = 0, e = sc_list.GetSize();
+ i != e;
+ ++i)
+ {
+ SymbolContext sc;
+
+ if (!sc_list.GetContextAtIndex(i, sc))
+ continue;
+
+ if (!sc.function)
+ continue;
+
+ CompilerDeclContext function_decl_ctx = sc.function->GetDeclContext();
+ if (!function_decl_ctx)
+ continue;
+
+ ObjCMethodDecl *method_decl = ClangASTContext::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 = m_ast_importer_sp->CopyDecl(m_ast_context, &method_decl->getASTContext(), method_decl);
+
+ if (!copied_decl)
+ continue;
+
+ ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
+
+ if (!copied_method_decl)
+ continue;
+
+ if (log)
+ {
+ ASTDumper dumper((Decl*)copied_method_decl);
+ log->Printf(" CAS::FOMD[%d] found (in symbols) %s", current_id, dumper.GetCString());
+ }
+
+ 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
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id, static_cast<void*>(complete_interface_decl),
+ static_cast<void*>(&complete_iface_decl->getASTContext()));
+
+ FindObjCMethodDeclsWithOrigin(current_id,
+ context,
+ complete_interface_decl,
+ m_ast_context,
+ m_ast_importer_sp.get(),
+ "in debug info");
+
+ return;
+ }
+ while (0);
+
+ do
+ {
+ // Check the modules only if the debug information didn't have a complete interface.
+
+ if (ClangModulesDeclVendor *modules_decl_vendor = m_target->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(current_id,
+ context,
+ interface_decl_from_modules,
+ m_ast_context,
+ m_ast_importer_sp.get(),
+ "in modules"))
+ return;
+ }
+ }
+ while (0);
+
+ 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(process->GetObjCLanguageRuntime());
+
+ 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;
+
+ if (!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(current_id,
+ context,
+ runtime_interface_decl,
+ m_ast_context,
+ m_ast_importer_sp.get(),
+ "in runtime");
+ }
+ while(0);
+}
+
+static bool
+FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id,
+ NameSearchContext &context,
+ clang::ASTContext &ast_context,
+ ClangASTImporter *ast_importer,
+ DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (origin_iface_decl.IsInvalid())
+ return false;
+
+ std::string name_str = context.m_decl_name.getAsString();
+ StringRef name(name_str.c_str());
+ IdentifierInfo &name_identifier(origin_iface_decl->getASTContext().Idents.get(name));
+
+ DeclFromUser<ObjCPropertyDecl> origin_property_decl(origin_iface_decl->FindPropertyDeclaration(&name_identifier));
+
+ bool found = false;
+
+ if (origin_property_decl.IsValid())
+ {
+ DeclFromParser<ObjCPropertyDecl> parser_property_decl(origin_property_decl.Import(ast_importer, ast_context));
+ if (parser_property_decl.IsValid())
+ {
+ if (log)
+ {
+ ASTDumper dumper((Decl*)parser_property_decl.decl);
+ log->Printf(" CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
+ }
+
+ 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(ast_importer, ast_context));
+ if (parser_ivar_decl.IsValid())
+ {
+ if (log)
+ {
+ ASTDumper dumper((Decl*)parser_ivar_decl.decl);
+ log->Printf(" CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
+ }
+
+ context.AddNamedDecl(parser_ivar_decl.decl);
+ found = true;
+ }
+ }
+
+ return found;
+}
+
+void
+ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ 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.get()));
+
+ ConstString class_name(parser_iface_decl->getNameAsString().c_str());
+
+ if (log)
+ log->Printf("ClangASTSource::FindObjCPropertyAndIvarDecls[%d] on (ASTContext*)%p for '%s.%s'",
+ current_id, static_cast<void*>(m_ast_context),
+ parser_iface_decl->getNameAsString().c_str(),
+ context.m_decl_name.getAsString().c_str());
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer_sp.get(),
+ origin_iface_decl))
+ return;
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] couldn't find the property on origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p, searching elsewhere...",
+ current_id, static_cast<const void*>(origin_iface_decl.decl),
+ static_cast<void*>(&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
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ static_cast<const void*>(complete_iface_decl.decl),
+ static_cast<void*>(&complete_iface_decl->getASTContext()));
+
+ FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer_sp.get(),
+ complete_iface_decl);
+
+ return;
+ }
+ while(0);
+
+ do
+ {
+ // Check the modules only if the debug information didn't have a complete interface.
+
+ ClangModulesDeclVendor *modules_decl_vendor = m_target->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;
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying module (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ static_cast<const void*>(interface_decl_from_modules.decl),
+ static_cast<void*>(&interface_decl_from_modules->getASTContext()));
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer_sp.get(),
+ interface_decl_from_modules))
+ return;
+ }
+ while(0);
+
+ 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(process->GetObjCLanguageRuntime());
+
+ 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;
+
+ if (!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;
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying runtime (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ static_cast<const void*>(interface_decl_from_runtime.decl),
+ static_cast<void*>(&interface_decl_from_runtime->getASTContext()));
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer_sp.get(),
+ interface_decl_from_runtime))
+ return;
+ }
+ while(0);
+}
+
+typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap;
+typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetMap;
+
+template <class D, class O>
+static bool
+ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, llvm::DenseMap<const D *, O> &source_map,
+ ClangASTImporter *importer, ASTContext &dest_ctx)
+{
+ // 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());
+ std::sort(sorted_items.begin(), sorted_items.end(),
+ [](const PairType &lhs, const PairType &rhs)
+ {
+ return lhs.second < rhs.second;
+ });
+
+ for (const auto &item : sorted_items)
+ {
+ DeclFromUser<D> user_decl(const_cast<D *>(item.first));
+ DeclFromParser <D> parser_decl(user_decl.Import(importer, dest_ctx));
+ if (parser_decl.IsInvalid())
+ return false;
+ destination_map.insert(std::pair<const D *, O>(parser_decl.decl, item.second));
+ }
+
+ return true;
+}
+
+template <bool IsVirtual>
+bool
+ExtractBaseOffsets(const ASTRecordLayout &record_layout, DeclFromUser<const CXXRecordDecl> &record,
+ BaseOffsetMap &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
+ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, uint64_t &alignment,
+ FieldOffsetMap &field_offsets, BaseOffsetMap &base_offsets,
+ BaseOffsetMap &virtual_base_offsets)
+{
+ ClangASTMetrics::RegisterRecordLayout();
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("LayoutRecordType[%u] on (ASTContext*)%p for (RecordDecl*)%p [name = '%s']",
+ current_id, static_cast<void*>(m_ast_context),
+ static_cast<const void*>(record),
+ record->getNameAsString().c_str());
+
+ DeclFromParser <const RecordDecl> parser_record(record);
+ DeclFromUser <const RecordDecl> origin_record(parser_record.GetOrigin(m_ast_importer_sp.get()));
+
+ if (origin_record.IsInvalid())
+ return false;
+
+ FieldOffsetMap origin_field_offsets;
+ BaseOffsetMap origin_base_offsets;
+ BaseOffsetMap origin_virtual_base_offsets;
+
+ ClangASTContext::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++;
+ }
+
+ ASTContext &parser_ast_context(record->getASTContext());
+
+ 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(field_offsets, origin_field_offsets, m_ast_importer_sp.get(), parser_ast_context) ||
+ !ImportOffsetMap(base_offsets, origin_base_offsets, m_ast_importer_sp.get(), parser_ast_context) ||
+ !ImportOffsetMap(virtual_base_offsets, origin_virtual_base_offsets, m_ast_importer_sp.get(), parser_ast_context))
+ return false;
+
+ size = record_layout.getSize().getQuantity() * m_ast_context->getCharWidth();
+ alignment = record_layout.getAlignment().getQuantity() * m_ast_context->getCharWidth();
+
+ if (log)
+ {
+ log->Printf("LRT[%u] returned:", current_id);
+ log->Printf("LRT[%u] Original = (RecordDecl*)%p", current_id,
+ static_cast<const void*>(origin_record.decl));
+ log->Printf("LRT[%u] Size = %" PRId64, current_id, size);
+ log->Printf("LRT[%u] Alignment = %" PRId64, current_id, alignment);
+ log->Printf("LRT[%u] Fields:", current_id);
+ for (RecordDecl::field_iterator fi = record->field_begin(), fe = record->field_end();
+ fi != fe;
+ ++fi)
+ {
+ log->Printf("LRT[%u] (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 " bits", current_id,
+ static_cast<void *>(*fi), fi->getNameAsString().c_str(), field_offsets[*fi]);
+ }
+ DeclFromParser <const CXXRecordDecl> parser_cxx_record = DynCast<const CXXRecordDecl>(parser_record);
+ if (parser_cxx_record.IsValid())
+ {
+ log->Printf("LRT[%u] Bases:", current_id);
+ 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);
+
+ log->Printf("LRT[%u] %s(CXXRecordDecl*)%p, Name = '%s', Offset = %" PRId64 " chars", current_id,
+ (is_virtual ? "Virtual " : ""), static_cast<void *>(base_cxx_record.decl),
+ base_cxx_record.decl->getNameAsString().c_str(),
+ (is_virtual ? virtual_base_offsets[base_cxx_record.decl].getQuantity()
+ : base_offsets[base_cxx_record.decl].getQuantity()));
+ }
+ }
+ else
+ {
+ log->Printf("LRD[%u] Not a CXXRecord, so no bases", current_id);
+ }
+ }
+
+ return true;
+}
+
+void
+ClangASTSource::CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespace_map,
+ const ConstString &name,
+ ClangASTImporter::NamespaceMapSP &parent_map) const
+{
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ if (parent_map && parent_map->size())
+ log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s in namespace %s",
+ current_id, static_cast<void*>(m_ast_context),
+ name.GetCString(),
+ parent_map->begin()->second.GetName().AsCString());
+ else
+ log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s",
+ current_id, static_cast<void*>(m_ast_context),
+ name.GetCString());
+ }
+
+ 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;
+
+ SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor();
+
+ if (!symbol_vendor)
+ continue;
+
+ SymbolContext null_sc;
+
+ found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &module_parent_namespace_decl);
+
+ if (!found_namespace_decl)
+ continue;
+
+ namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>(module_sp, found_namespace_decl));
+
+ if (log)
+ log->Printf(" CMN[%u] Found namespace %s in module %s",
+ current_id,
+ name.GetCString(),
+ module_sp->GetFileSpec().GetFilename().GetCString());
+ }
+ }
+ else
+ {
+ const ModuleList &target_images = m_target->GetImages();
+ Mutex::Locker modules_locker(target_images.GetMutex());
+
+ CompilerDeclContext null_namespace_decl;
+
+ for (size_t i = 0, e = target_images.GetSize(); i < e; ++i)
+ {
+ lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i);
+
+ if (!image)
+ continue;
+
+ CompilerDeclContext found_namespace_decl;
+
+ SymbolVendor *symbol_vendor = image->GetSymbolVendor();
+
+ if (!symbol_vendor)
+ continue;
+
+ SymbolContext null_sc;
+
+ found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &null_namespace_decl);
+
+ if (!found_namespace_decl)
+ continue;
+
+ namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>(image, found_namespace_decl));
+
+ if (log)
+ log->Printf(" CMN[%u] Found namespace %s in module %s",
+ current_id,
+ name.GetCString(),
+ image->GetFileSpec().GetFilename().GetCString());
+ }
+ }
+}
+
+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 = ClangASTContext::DeclContextGetClangASTContext(namespace_decl);
+ if (!src_ast)
+ return nullptr;
+ clang::NamespaceDecl *src_namespace_decl = ClangASTContext::DeclContextGetAsNamespaceDecl(namespace_decl);
+
+ if (!src_namespace_decl)
+ return nullptr;
+
+ Decl *copied_decl = m_ast_importer_sp->CopyDecl(m_ast_context, src_ast, 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);
+}
+
+CompilerType
+ClangASTSource::GuardedCopyType (const CompilerType &src_type)
+{
+ ClangASTContext *src_ast = llvm::dyn_cast_or_null<ClangASTContext>(src_type.GetTypeSystem());
+ if (src_ast == nullptr)
+ return CompilerType();
+
+ ClangASTMetrics::RegisterLLDBImport();
+
+ SetImportInProgress(true);
+
+ QualType copied_qual_type = m_ast_importer_sp->CopyType (m_ast_context, src_ast->getASTContext(), ClangASTContext::GetQualType(src_type));
+
+ SetImportInProgress(false);
+
+ 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 CompilerType();
+
+ return CompilerType(m_ast_context, copied_qual_type);
+}
+
+clang::NamedDecl *
+NameSearchContext::AddVarDecl(const CompilerType &type)
+{
+ assert (type && "Type for variable must be valid!");
+
+ if (!type.IsValid())
+ return NULL;
+
+ ClangASTContext* lldb_ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem());
+ if (!lldb_ast)
+ return NULL;
+
+ 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,
+ ClangASTContext::GetQualType(type),
+ 0,
+ 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 NULL;
+
+ if (m_function_types.count(type))
+ return NULL;
+
+ ClangASTContext* lldb_ast = llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem());
+ if (!lldb_ast)
+ return NULL;
+
+ m_function_types.insert(type);
+
+ QualType qual_type (ClangASTContext::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::LinkageSpecDecl::LanguageIDs::lang_c,
+ false);
+ }
+
+ // 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,
+ NULL,
+ SC_Extern,
+ isInlineSpecified,
+ hasWrittenPrototype,
+ isConstexprSpecified);
+
+ // 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(),
+ NULL,
+ arg_qual_type,
+ NULL,
+ SC_Static,
+ NULL));
+ }
+
+ func_decl->setParams(ArrayRef<ParmVarDecl*>(parm_var_decls));
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("Function type wasn't a FunctionProtoType");
+ }
+
+ 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(m_ast_source.m_ast_context->getFunctionType (m_ast_source.m_ast_context->UnknownAnyTy, // result
+ ArrayRef<QualType>(), // argument types
+ proto_info));
+
+ return AddFunDecl(CompilerType (m_ast_source.m_ast_context, generic_function_type), true);
+}
+
+clang::NamedDecl *
+NameSearchContext::AddTypeDecl(const CompilerType &clang_type)
+{
+ if (clang_type)
+ {
+ QualType qual_type = ClangASTContext::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 NULL;
+}
+
+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/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
new file mode 100644
index 0000000..bb63847
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
@@ -0,0 +1,526 @@
+//===-- ClangASTSource.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangASTSource_h_
+#define liblldb_ClangASTSource_h_
+
+#include <set>
+
+#include "clang/Basic/IdentifierTable.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Target/Target.h"
+
+#include "llvm/ADT/SmallSet.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ClangASTSource ClangASTSource.h "lldb/Expression/ClangASTSource.h"
+/// @brief 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 ClangExternalASTSourceCommon,
+ public ClangASTImporter::MapCompleter
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// Initializes class variables.
+ ///
+ /// @param[in] declMap
+ /// A reference to the LLDB object that handles entity lookup.
+ //------------------------------------------------------------------
+ ClangASTSource (const lldb::TargetSP &target) :
+ m_import_in_progress (false),
+ m_lookups_enabled (false),
+ m_target (target),
+ m_ast_context (NULL),
+ m_active_lexical_decls (),
+ m_active_lookups ()
+ {
+ m_ast_importer_sp = m_target->GetClangASTImporter();
+ }
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~ClangASTSource() override;
+
+ //------------------------------------------------------------------
+ /// Interface stubs.
+ //------------------------------------------------------------------
+ clang::Decl *GetExternalDecl (uint32_t) override { return NULL; }
+ clang::Stmt *GetExternalDeclStmt (uint64_t) override { return NULL; }
+ clang::Selector GetExternalSelector (uint32_t) override { return clang::Selector(); }
+ uint32_t GetNumExternalSelectors () override { return 0; }
+ clang::CXXBaseSpecifier *GetExternalCXXBaseSpecifiers (uint64_t Offset) override
+ { return NULL; }
+ void MaterializeVisibleDecls (const clang::DeclContext *DC)
+ { return; }
+
+ void InstallASTContext (clang::ASTContext *ast_context)
+ {
+ m_ast_context = ast_context;
+ m_ast_importer_sp->InstallMapCompleter(ast_context, *this);
+ }
+
+ //
+ // 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] ASTConsumer
+ /// Unused.
+ //------------------------------------------------------------------
+ void StartTranslationUnit(clang::ASTConsumer *Consumer) override;
+
+ //
+ // APIs for NamespaceMapCompleter
+ //
+
+ //------------------------------------------------------------------
+ /// Look up the modules containing a given namespace and put the
+ /// appropriate entries in the namespace map.
+ ///
+ /// @param[in] namespace_map
+ /// 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, const 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);
+
+ void SetImportInProgress (bool import_in_progress) { m_import_in_progress = import_in_progress; }
+ bool GetImportInProgress () { return m_import_in_progress; }
+
+ void SetLookupsEnabled (bool lookups_enabled) { m_lookups_enabled = lookups_enabled; }
+ bool GetLookupsEnabled () { return m_lookups_enabled; }
+
+ //----------------------------------------------------------------------
+ /// @class ClangASTSourceProxy ClangASTSource.h "lldb/Expression/ClangASTSource.h"
+ /// @brief Proxy for ClangASTSource
+ ///
+ /// Clang AST contexts like to own their AST sources, so this is a
+ /// state-free proxy object.
+ //----------------------------------------------------------------------
+ class ClangASTSourceProxy : public ClangExternalASTSourceCommon
+ {
+ public:
+ ClangASTSourceProxy (ClangASTSource &original) :
+ m_original(original)
+ {
+ }
+
+ 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);
+ }
+
+ ClangASTMetadata *
+ GetMetadata(const void * object)
+ {
+ return m_original.GetMetadata(object);
+ }
+
+ void
+ SetMetadata(const void * object, ClangASTMetadata &metadata)
+ {
+ return m_original.SetMetadata(object, metadata);
+ }
+
+ bool
+ HasMetadata(const void * object)
+ {
+ return m_original.HasMetadata(object);
+ }
+ 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 (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.
+ ///
+ /// @param[in] current_id
+ /// The ID for the current FindExternalVisibleDecls invocation,
+ /// for logging purposes.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ void
+ FindExternalVisibleDecls (NameSearchContext &context,
+ lldb::ModuleSP module,
+ CompilerDeclContext &namespace_decl,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Find all Objective-C methods matching a given selector.
+ ///
+ /// @param[in] context
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// A wrapper for ClangASTContext::CopyType that sets a flag that
+ /// indicates that we should not respond to queries during import.
+ ///
+ /// @param[in] dest_context
+ /// The target AST context, typically the parser's AST context.
+ ///
+ /// @param[in] source_context
+ /// The source AST context, typically the AST context of whatever
+ /// symbol file the type was found in.
+ ///
+ /// @param[in] src_type
+ /// The source type.
+ ///
+ /// @return
+ /// The imported type.
+ //------------------------------------------------------------------
+ CompilerType
+ GuardedCopyType (const CompilerType &src_type);
+
+ friend struct NameSearchContext;
+
+ bool m_import_in_progress;
+ bool m_lookups_enabled;
+
+ const lldb::TargetSP m_target; ///< The target to use in finding variables and types.
+ clang::ASTContext *m_ast_context; ///< The AST context requests are coming in for.
+ lldb::ClangASTImporterSP m_ast_importer_sp; ///< The target's AST importer.
+ std::set<const clang::Decl *> m_active_lexical_decls;
+ std::set<const char *> m_active_lookups;
+};
+
+//----------------------------------------------------------------------
+/// @class NameSearchContext ClangASTSource.h "lldb/Expression/ClangASTSource.h"
+/// @brief Container for all objects relevant to a single name lookup
+///
+/// LLDB needs to create Decls for entities it finds. This class communicates
+/// what name is being searched for and provides helper functions to construct
+/// Decls given appropriate type information.
+//----------------------------------------------------------------------
+struct NameSearchContext {
+ ClangASTSource &m_ast_source; ///< The AST source making the request
+ llvm::SmallVectorImpl<clang::NamedDecl*> &m_decls; ///< The list of declarations already constructed
+ ClangASTImporter::NamespaceMapSP m_namespace_map; ///< The mapping of all namespaces found for this request back to their modules
+ const clang::DeclarationName &m_decl_name; ///< The name being looked for
+ const clang::DeclContext *m_decl_context; ///< The DeclContext to put declarations into
+ llvm::SmallSet <CompilerType, 5> m_function_types; ///< All the types of functions that have been reported, so we don't report conflicts
+
+ struct {
+ bool variable : 1;
+ bool function_with_type_info : 1;
+ bool function : 1;
+ } m_found;
+
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// Initializes class variables.
+ ///
+ /// @param[in] astSource
+ /// A reference to the AST source making a request.
+ ///
+ /// @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 (ClangASTSource &astSource,
+ llvm::SmallVectorImpl<clang::NamedDecl*> &decls,
+ clang::DeclarationName &name,
+ const clang::DeclContext *dc) :
+ m_ast_source(astSource),
+ m_decls(decls),
+ m_decl_name(name),
+ m_decl_context(dc)
+ {
+ memset(&m_found, 0, sizeof(m_found));
+ }
+
+ //------------------------------------------------------------------
+ /// Create a VarDecl with the name being searched for and the provided
+ /// type and register it in the right places.
+ ///
+ /// @param[in] type
+ /// 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);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangASTSource_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
new file mode 100644
index 0000000..c9bc4b6
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -0,0 +1,2351 @@
+//===-- ClangExpressionDeclMap.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionDeclMap.h"
+
+#include "ASTDumper.h"
+#include "ClangASTSource.h"
+#include "ClangModulesDeclVendor.h"
+#include "ClangPersistentVariables.h"
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Decl.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompilerDecl.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.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/CPPLanguageRuntime.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace clang;
+
+ClangExpressionDeclMap::ClangExpressionDeclMap (bool keep_result_in_memory,
+ Materializer::PersistentVariableDelegate *result_delegate,
+ ExecutionContext &exe_ctx) :
+ ClangASTSource (exe_ctx.GetTargetSP()),
+ m_found_entities (),
+ m_struct_members (),
+ m_keep_result_in_memory (keep_result_in_memory),
+ m_result_delegate (result_delegate),
+ m_parser_vars (),
+ m_struct_vars ()
+{
+ 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)
+{
+ ClangASTMetrics::ClearLocalCounters();
+
+ 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 (!target->GetScratchClangASTContext())
+ 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::DidParse()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ ClangASTMetrics::DumpCounters(log);
+
+ if (m_parser_vars.get())
+ {
+ 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;
+}
+
+bool
+ClangExpressionDeclMap::AddPersistentVariable
+(
+ const NamedDecl *decl,
+ const ConstString &name,
+ TypeFromParser parser_type,
+ bool is_result,
+ bool is_lvalue
+)
+{
+ assert (m_parser_vars.get());
+
+ ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(parser_type.GetTypeSystem());
+ if (ast == nullptr)
+ return false;
+
+ if (m_parser_vars->m_materializer && is_result)
+ {
+ Error err;
+
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target == nullptr)
+ return false;
+
+ ClangASTContext *context(target->GetScratchClangASTContext());
+
+ TypeFromUser user_type(m_ast_importer_sp->DeportType(context->getASTContext(),
+ ast->getASTContext(),
+ parser_type.GetOpaqueQualType()),
+ context);
+
+ 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;
+ parser_vars->m_parser_type = parser_type;
+
+ var->EnableJITVars(GetParserID());
+
+ ClangExpressionVariable::JITVars *jit_vars = var->GetJITVars(GetParserID());
+
+ jit_vars->m_offset = offset;
+
+ return true;
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target == NULL)
+ return false;
+
+ ClangASTContext *context(target->GetScratchClangASTContext());
+
+ TypeFromUser user_type(m_ast_importer_sp->DeportType(context->getASTContext(),
+ ast->getASTContext(),
+ parser_type.GetOpaqueQualType()),
+ context);
+
+ if (!user_type.GetOpaqueQualType())
+ {
+ if (log)
+ log->Printf("Persistent variable's type wasn't copied successfully");
+ return false;
+ }
+
+ if (!m_parser_vars->m_target_info.IsValid())
+ 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;
+ }
+
+ if (log)
+ log->Printf("Created persistent variable with flags 0x%hx", var->m_flags);
+
+ var->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars = var->GetParserVars(GetParserID());
+
+ parser_vars->m_named_decl = decl;
+ parser_vars->m_parser_type = parser_type;
+
+ return true;
+}
+
+bool
+ClangExpressionDeclMap::AddValueToStruct
+(
+ const NamedDecl *decl,
+ const 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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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)
+ {
+ var = ClangExpressionVariable::FindVariableInList(*m_parser_vars->m_persistent_vars, decl, GetParserID());
+ is_persistent_variable = true;
+ }
+
+ if (!var)
+ return false;
+
+ if (log)
+ log->Printf("Adding value for (NamedDecl*)%p [%s - %s] to the structure",
+ static_cast<const void*>(decl), name.GetCString(),
+ var->GetName().GetCString());
+
+ // 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
+
+ if (log)
+ log->Printf("Already placed at 0x%llx", (unsigned long long)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;
+
+ Error 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);
+ }
+
+ if (!err.Success())
+ return false;
+
+ if (log)
+ log->Printf("Placed at 0x%llx", (unsigned long long)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;
+}
+
+static void
+FindCodeSymbolInContext
+(
+ const ConstString &name,
+ SymbolContext &sym_ctx,
+ uint32_t name_type_mask,
+ SymbolContextList &sc_list
+)
+{
+ sc_list.Clear();
+ SymbolContextList temp_sc_list;
+ if (sym_ctx.module_sp)
+ sym_ctx.module_sp->FindFunctions(name,
+ NULL,
+ name_type_mask,
+ true, // include_symbols
+ false, // include_inlines
+ true, // append
+ temp_sc_list);
+ if (temp_sc_list.GetSize() == 0)
+ {
+ if (sym_ctx.target_sp)
+ sym_ctx.target_sp->GetImages().FindFunctions(name,
+ name_type_mask,
+ true, // include_symbols
+ false, // include_inlines
+ true, // append
+ temp_sc_list);
+ }
+
+ SymbolContextList internal_symbol_sc_list;
+ unsigned temp_sc_list_size = temp_sc_list.GetSize();
+ for (unsigned i = 0; i < temp_sc_list_size; i++)
+ {
+ SymbolContext sc;
+ temp_sc_list.GetContextAtIndex(i, sc);
+ if (sc.function)
+ {
+ sc_list.Append(sc);
+ }
+ else if (sc.symbol)
+ {
+ if (sc.symbol->IsExternal())
+ {
+ sc_list.Append(sc);
+ }
+ else
+ {
+ internal_symbol_sc_list.Append(sc);
+ }
+ }
+ }
+
+ // If we had internal symbols and we didn't find any external symbols or
+ // functions in debug info, then fallback to the internal symbols
+ if (sc_list.GetSize() == 0 && internal_symbol_sc_list.GetSize())
+ {
+ sc_list = internal_symbol_sc_list;
+ }
+}
+
+bool
+ClangExpressionDeclMap::GetFunctionAddress
+(
+ const ConstString &name,
+ uint64_t &func_addr
+)
+{
+ assert (m_parser_vars.get());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+ Target *target = exe_ctx.GetTargetPtr();
+ // Back out in all cases where we're not fully initialized
+ if (target == NULL)
+ return false;
+ if (!m_parser_vars->m_sym_ctx.target_sp)
+ return false;
+
+ SymbolContextList sc_list;
+
+ FindCodeSymbolInContext(name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list);
+
+ uint32_t sc_list_size = sc_list.GetSize();
+
+ if (sc_list_size == 0)
+ {
+ SymbolContext &sc = m_parser_vars->m_sym_ctx;
+ if (sc.comp_unit)
+ {
+ LanguageType lang_type = sc.comp_unit->GetLanguage();
+ if (Language::LanguageIsCPlusPlus(lang_type) &&
+ CPlusPlusLanguage::IsCPPMangledName(name.AsCString()))
+ {
+ // 1. Demangle the name
+ Mangled mangled(name, true);
+ ConstString demangled = mangled.GetDemangledName(lang_type);
+
+ if (demangled)
+ {
+ FindCodeSymbolInContext(
+ demangled, m_parser_vars->m_sym_ctx, eFunctionNameTypeFull, sc_list);
+ sc_list_size = sc_list.GetSize();
+ }
+ }
+ }
+ }
+
+ if (sc_list_size == 0)
+ {
+ // We occasionally get debug information in which a const function is reported
+ // as non-const, so the mangled name is wrong. This is a hack to compensate.
+
+ if (!strncmp(name.GetCString(), "_ZN", 3) &&
+ strncmp(name.GetCString(), "_ZNK", 4))
+ {
+ std::string fixed_scratch("_ZNK");
+ fixed_scratch.append(name.GetCString() + 3);
+ ConstString fixed_name(fixed_scratch.c_str());
+
+ if (log)
+ log->Printf("Failed to find symbols given non-const name %s; trying %s", name.GetCString(), fixed_name.GetCString());
+
+ FindCodeSymbolInContext(
+ fixed_name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list);
+ sc_list_size = sc_list.GetSize();
+ }
+ }
+
+ lldb::addr_t intern_callable_load_addr = LLDB_INVALID_ADDRESS;
+
+ for (uint32_t i=0; i<sc_list_size; ++i)
+ {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(i, sym_ctx);
+
+
+ lldb::addr_t callable_load_addr = LLDB_INVALID_ADDRESS;
+
+ if (sym_ctx.function)
+ {
+ const Address func_so_addr = sym_ctx.function->GetAddressRange().GetBaseAddress();
+ if (func_so_addr.IsValid())
+ {
+ callable_load_addr = func_so_addr.GetCallableLoadAddress(target, false);
+ }
+ }
+ else if (sym_ctx.symbol)
+ {
+ if (sym_ctx.symbol->IsExternal())
+ callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target);
+ else
+ {
+ if (intern_callable_load_addr == LLDB_INVALID_ADDRESS)
+ intern_callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target);
+ }
+ }
+
+ if (callable_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ func_addr = callable_load_addr;
+ return true;
+ }
+ }
+
+ // See if we found an internal symbol
+ if (intern_callable_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ func_addr = intern_callable_load_addr;
+ return true;
+ }
+
+ return false;
+}
+
+addr_t
+ClangExpressionDeclMap::GetSymbolAddress (Target &target,
+ Process *process,
+ const 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);
+
+ const uint32_t num_matches = sc_list.GetSize();
+ addr_t symbol_load_addr = LLDB_INVALID_ADDRESS;
+
+ for (uint32_t i=0; i<num_matches && (symbol_load_addr == 0 || symbol_load_addr == LLDB_INVALID_ADDRESS); i++)
+ {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(i, sym_ctx);
+
+ 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().GetDirectory().Clear();
+ 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 = process->GetObjCLanguageRuntime();
+
+ if (runtime)
+ {
+ symbol_load_addr = runtime->LookupRuntimeSymbol(name);
+ }
+ }
+
+ return symbol_load_addr;
+}
+
+addr_t
+ClangExpressionDeclMap::GetSymbolAddress (const 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);
+}
+
+const Symbol *
+ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
+ const ConstString &name,
+ lldb_private::Module *module)
+{
+ SymbolContextList sc_list;
+
+ if (module)
+ module->FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list);
+ else
+ target.GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list);
+
+ const uint32_t matches = sc_list.GetSize();
+ for (uint32_t i=0; i<matches; ++i)
+ {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(i, sym_ctx);
+ if (sym_ctx.symbol)
+ {
+ const Symbol *symbol = sym_ctx.symbol;
+ const Address sym_address = symbol->GetAddress();
+
+ if (sym_address.IsValid())
+ {
+ switch (symbol->GetType())
+ {
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ if (symbol->GetDemangledNameIsSynthesized())
+ {
+ // If the demangled name was synthesized, then don't use it
+ // for expressions. Only let the symbol match if the mangled
+ // named matches for these symbols.
+ if (symbol->GetMangled().GetMangledName() != name)
+ break;
+ }
+ return symbol;
+
+ case eSymbolTypeReExported:
+ {
+ ConstString reexport_name = symbol->GetReExportedSymbolName();
+ if (reexport_name)
+ {
+ ModuleSP reexport_module_sp;
+ ModuleSpec reexport_module_spec;
+ reexport_module_spec.GetPlatformFileSpec() = symbol->GetReExportedSymbolSharedLibrary();
+ if (reexport_module_spec.GetPlatformFileSpec())
+ {
+ reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec);
+ if (!reexport_module_sp)
+ {
+ reexport_module_spec.GetPlatformFileSpec().GetDirectory().Clear();
+ reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec);
+ }
+ }
+ // Don't allow us to try and resolve a re-exported symbol if it is the same
+ // as the current symbol
+ if (name == symbol->GetReExportedSymbolName() && module == reexport_module_sp.get())
+ return NULL;
+
+ return FindGlobalDataSymbol(target, symbol->GetReExportedSymbolName(), reexport_module_sp.get());
+ }
+ }
+ break;
+
+ case eSymbolTypeCode: // We already lookup functions elsewhere
+ case eSymbolTypeVariable:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeTrampoline:
+ case eSymbolTypeInvalid:
+ 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 eSymbolTypeResolver:
+ break;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+lldb::VariableSP
+ClangExpressionDeclMap::FindGlobalVariable
+(
+ Target &target,
+ ModuleSP &module,
+ const ConstString &name,
+ CompilerDeclContext *namespace_decl,
+ TypeFromUser *type
+)
+{
+ VariableList vars;
+
+ if (module && namespace_decl)
+ module->FindGlobalVariables (name, namespace_decl, true, -1, vars);
+ else
+ target.GetImages().FindGlobalVariables(name, true, -1, vars);
+
+ if (vars.GetSize())
+ {
+ if (type)
+ {
+ for (size_t i = 0; i < vars.GetSize(); ++i)
+ {
+ VariableSP var_sp = vars.GetVariableAtIndex(i);
+
+ if (ClangASTContext::AreTypesSame(*type, var_sp->GetType()->GetFullCompilerType ()))
+ return var_sp;
+ }
+ }
+ else
+ {
+ return vars.GetVariableAtIndex(0);
+ }
+ }
+
+ return VariableSP();
+}
+
+// Interface for ClangASTSource
+
+void
+ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context)
+{
+ assert (m_ast_context);
+
+ ClangASTMetrics::RegisterVisibleQuery();
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (GetImportInProgress())
+ {
+ if (log && log->GetVerbose())
+ log->Printf("Ignoring a query during an import");
+ return;
+ }
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ if (log)
+ {
+ if (!context.m_decl_context)
+ log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for '%s' in a NULL DeclContext", current_id, name.GetCString());
+ else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context))
+ log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for '%s' in '%s'", current_id, name.GetCString(), context_named_decl->getNameAsString().c_str());
+ else
+ log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for '%s' in a '%s'", current_id, name.GetCString(), context.m_decl_context->getDeclKindName());
+ }
+
+ if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context))
+ {
+ ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CEDM::FEVD[%u] Inspecting (NamespaceMap*)%p (%d entries)",
+ current_id, static_cast<void*>(namespace_map.get()),
+ (int)namespace_map->size());
+
+ if (!namespace_map)
+ return;
+
+ for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
+ i != e;
+ ++i)
+ {
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Searching namespace %s in module %s",
+ current_id,
+ i->second.GetName().AsCString(),
+ i->first->GetFileSpec().GetFilename().GetCString());
+
+ FindExternalVisibleDecls(context,
+ i->first,
+ i->second,
+ current_id);
+ }
+ }
+ else if (isa<TranslationUnitDecl>(context.m_decl_context))
+ {
+ CompilerDeclContext namespace_decl;
+
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Searching the root namespace", current_id);
+
+ FindExternalVisibleDecls(context,
+ lldb::ModuleSP(),
+ namespace_decl,
+ current_id);
+ }
+
+ if (!context.m_found.variable)
+ ClangASTSource::FindExternalVisibleDecls(context);
+}
+
+void
+ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
+ lldb::ModuleSP module_sp,
+ CompilerDeclContext &namespace_decl,
+ unsigned int current_id)
+{
+ assert (m_ast_context);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ SymbolContextList sc_list;
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ const char *name_unique_cstr = name.GetCString();
+
+ if (name_unique_cstr == NULL)
+ return;
+
+ static ConstString id_name("id");
+ static ConstString Class_name("Class");
+
+ if (name == id_name || name == Class_name)
+ return;
+
+ // Only look for functions by name out in our symbols if the function
+ // doesn't start with our phony prefix of '$'
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+ StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+ SymbolContext sym_ctx;
+ if (frame != nullptr)
+ sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction|lldb::eSymbolContextBlock);
+ if (name_unique_cstr[0] == '$' && !namespace_decl)
+ {
+ static ConstString g_lldb_class_name ("$__lldb_class");
+
+ if (name == g_lldb_class_name)
+ {
+ // Clang is looking for the type of "this"
+
+ if (frame == NULL)
+ 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 = ClangASTContext::DeclContextGetAsCXXMethodDecl(function_decl_ctx);
+
+ if (method_decl)
+ {
+ clang::CXXRecordDecl *class_decl = method_decl->getParent();
+
+ QualType class_qual_type(class_decl->getTypeForDecl(), 0);
+
+ TypeFromUser class_user_type (class_qual_type.getAsOpaquePtr(),
+ ClangASTContext::GetASTContext(&class_decl->getASTContext()));
+
+ if (log)
+ {
+ ASTDumper ast_dumper(class_qual_type);
+ log->Printf(" CEDM::FEVD[%u] Adding type for $__lldb_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ AddThisType(context, class_user_type, current_id);
+
+ if (method_decl->isInstance())
+ {
+ // self is a pointer to the object
+
+ QualType class_pointer_type = method_decl->getASTContext().getPointerType(class_qual_type);
+
+ TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(),
+ ClangASTContext::GetASTContext(&method_decl->getASTContext()));
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+ }
+ }
+ else
+ {
+ // 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);
+
+ 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();
+
+ if (pointee_type.IsValid())
+ {
+ if (log)
+ {
+ ASTDumper ast_dumper(pointee_type);
+ log->Printf(" FEVD[%u] Adding type for $__lldb_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ AddThisType(context, pointee_type, current_id);
+ TypeFromUser this_user_type(this_type->GetFullCompilerType ());
+ m_struct_vars->m_object_pointer_type = this_user_type;
+ return;
+ }
+ }
+ }
+
+ return;
+ }
+
+ static ConstString g_lldb_objc_class_name ("$__lldb_objc_class");
+ if (name == g_lldb_objc_class_name)
+ {
+ // 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 = ClangASTContext::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(),
+ ClangASTContext::GetASTContext(&method_decl->getASTContext()));
+
+ if (log)
+ {
+ ASTDumper ast_dumper(interface_type);
+ log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ AddOneType(context, class_user_type, current_id);
+
+ if (method_decl->isInstanceMethod())
+ {
+ // self is a pointer to the object
+
+ QualType class_pointer_type = method_decl->getASTContext().getObjCObjectPointerType(QualType(interface_type, 0));
+
+ TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(),
+ ClangASTContext::GetASTContext(&method_decl->getASTContext()));
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+ }
+ else
+ {
+ // self is a Class pointer
+ QualType class_type = method_decl->getASTContext().getObjCClassType();
+
+ TypeFromUser self_user_type(class_type.getAsOpaquePtr(),
+ ClangASTContext::GetASTContext(&method_decl->getASTContext()));
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+ }
+
+ return;
+ }
+ else
+ {
+ // 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);
+
+ lldb::VariableSP self_var = vars->FindVariable(ConstString("self"));
+
+ if (self_var &&
+ self_var->IsInScope(frame) &&
+ self_var->LocationIsValidForFrame (frame))
+ {
+ Type *self_type = self_var->GetType();
+
+ if (!self_type)
+ return;
+
+ CompilerType self_clang_type = self_type->GetFullCompilerType ();
+
+ if (ClangASTContext::IsObjCClassType(self_clang_type))
+ {
+ return;
+ }
+ else if (ClangASTContext::IsObjCObjectPointerType(self_clang_type))
+ {
+ self_clang_type = self_clang_type.GetPointeeType();
+
+ if (!self_clang_type)
+ return;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(self_type->GetFullCompilerType ());
+ log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ TypeFromUser class_user_type (self_clang_type);
+
+ AddOneType(context, class_user_type, current_id);
+
+ TypeFromUser self_user_type(self_type->GetFullCompilerType ());
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+ return;
+ }
+ }
+ }
+
+ return;
+ }
+
+ // any other $__lldb names should be weeded out now
+ if (!::strncmp(name_unique_cstr, "$__lldb", sizeof("$__lldb") - 1))
+ return;
+
+ do
+ {
+ if (!target)
+ break;
+
+ ClangASTContext *scratch_clang_ast_context = target->GetScratchClangASTContext();
+
+ if (!scratch_clang_ast_context)
+ break;
+
+ ASTContext *scratch_ast_context = scratch_clang_ast_context->getASTContext();
+
+ if (!scratch_ast_context)
+ break;
+
+ TypeDecl *ptype_type_decl = m_parser_vars->m_persistent_vars->GetPersistentType(name);
+
+ if (!ptype_type_decl)
+ break;
+
+ Decl *parser_ptype_decl = m_ast_importer_sp->CopyDecl(m_ast_context, scratch_ast_context, ptype_type_decl);
+
+ if (!parser_ptype_decl)
+ break;
+
+ TypeDecl *parser_ptype_type_decl = dyn_cast<TypeDecl>(parser_ptype_decl);
+
+ if (!parser_ptype_type_decl)
+ break;
+
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Found persistent type %s", current_id, name.GetCString());
+
+ context.AddNamedDecl(parser_ptype_type_decl);
+ } while (0);
+
+ ExpressionVariableSP pvar_sp(m_parser_vars->m_persistent_vars->GetVariable(name));
+
+ if (pvar_sp)
+ {
+ AddOneVariable(context, pvar_sp, current_id);
+ return;
+ }
+
+ const char *reg_name(&name.GetCString()[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)
+ {
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Found register %s", current_id, reg_info->name);
+
+ AddOneRegister(context, reg_info, current_id);
+ }
+ }
+ }
+ else
+ {
+ ValueObjectSP valobj;
+ VariableSP var;
+
+ if (frame && !namespace_decl)
+ {
+ CompilerDeclContext compiler_decl_context = sym_ctx.block != nullptr ? sym_ctx.block->GetDeclContext() : CompilerDeclContext();
+
+ if (compiler_decl_context)
+ {
+ // Make sure that the variables are parsed so that we have the declarations
+ VariableListSP vars = frame->GetInScopeVariableList(true);
+ for (size_t i = 0; i < vars->GetSize(); i++)
+ vars->GetVariableAtIndex(i)->GetDecl();
+
+ // Search for declarations matching the name
+ std::vector<CompilerDecl> found_decls = compiler_decl_context.FindDeclByName(name);
+
+ bool variable_found = false;
+ for (CompilerDecl decl : found_decls)
+ {
+ var = decl.GetAsVariable();
+ if (var)
+ {
+ variable_found = true;
+ valobj = ValueObjectVariable::Create(frame, var);
+ AddOneVariable(context, var, valobj, current_id);
+ context.m_found.variable = true;
+ }
+ }
+ if (variable_found)
+ return;
+ }
+ }
+ if (target)
+ {
+ var = FindGlobalVariable (*target,
+ module_sp,
+ name,
+ &namespace_decl,
+ NULL);
+
+ if (var)
+ {
+ valobj = ValueObjectVariable::Create(target, var);
+ AddOneVariable(context, var, valobj, current_id);
+ context.m_found.variable = true;
+ return;
+ }
+ }
+
+ std::vector<clang::NamedDecl *> decls_from_modules;
+
+ if (target)
+ {
+ if (ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor())
+ {
+ decl_vendor->FindDecls(name, false, UINT32_MAX, decls_from_modules);
+ }
+ }
+
+ if (!context.m_found.variable)
+ {
+ const bool include_inlines = false;
+ const bool append = false;
+
+ if (namespace_decl && module_sp)
+ {
+ const bool include_symbols = false;
+
+ module_sp->FindFunctions(name,
+ &namespace_decl,
+ eFunctionNameTypeBase,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ }
+ else if (target && !namespace_decl)
+ {
+ const bool include_symbols = true;
+
+ // TODO Fix FindFunctions so that it doesn't return
+ // instance methods for eFunctionNameTypeBase.
+
+ target->GetImages().FindFunctions(name,
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ 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)
+ {
+ clang::DeclContext *frame_decl_ctx = (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext();
+ ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(frame_decl_context.GetTypeSystem());
+
+ // Structure to hold the info needed when comparing function
+ // declarations.
+ struct FuncDeclInfo
+ {
+ ConstString m_name;
+ CompilerType m_copied_type;
+ uint32_t m_decl_lvl;
+ SymbolContext m_sym_ctx;
+ };
+
+ // 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;
+ uint32_t num_indices = sc_list.GetSize();
+ std::vector<FuncDeclInfo> fdi_cache;
+ fdi_cache.reserve(num_indices);
+ for (uint32_t index = 0; index < num_indices; ++index)
+ {
+ FuncDeclInfo fdi;
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(index, sym_ctx);
+
+ // 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(nullptr, nullptr, nullptr))
+ 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);
+ }
+ fdi_cache.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 : fdi_cache)
+ {
+ 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_list = sc_func_list;
+ sc_list.Append(sc_sym_list);
+ }
+ }
+
+ if (sc_list.GetSize())
+ {
+ Symbol *extern_symbol = NULL;
+ Symbol *non_extern_symbol = NULL;
+
+ for (uint32_t index = 0, num_indices = sc_list.GetSize();
+ index < num_indices;
+ ++index)
+ {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(index, sym_ctx);
+
+ if (sym_ctx.function)
+ {
+ CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext();
+
+ if (!decl_ctx)
+ continue;
+
+ // Filter out class/instance methods.
+ if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr))
+ continue;
+
+ AddOneFunction(context, sym_ctx.function, NULL, current_id);
+ context.m_found.function_with_type_info = true;
+ context.m_found.function = true;
+ }
+ else if (sym_ctx.symbol)
+ {
+ if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target)
+ {
+ sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target);
+ if (sym_ctx.symbol == NULL)
+ continue;
+ }
+
+ if (sym_ctx.symbol->IsExternal())
+ extern_symbol = sym_ctx.symbol;
+ else
+ non_extern_symbol = sym_ctx.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<FunctionDecl>(m_ast_importer_sp->CopyDecl(m_ast_context, &decl->getASTContext(), 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, NULL, extern_symbol, current_id);
+ context.m_found.function = true;
+ }
+ else if (non_extern_symbol)
+ {
+ AddOneFunction (context, NULL, non_extern_symbol, current_id);
+ context.m_found.function = true;
+ }
+ }
+ }
+
+ if (!context.m_found.function_with_type_info)
+ {
+ // Try the modules next.
+
+ do
+ {
+ if (ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor())
+ {
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <clang::NamedDecl *> decls;
+
+ if (!modules_decl_vendor->FindDecls(name,
+ append,
+ max_matches,
+ decls))
+ break;
+
+ clang::NamedDecl *const decl_from_modules = decls[0];
+
+ if (llvm::isa<clang::FunctionDecl>(decl_from_modules))
+ {
+ if (log)
+ {
+ log->Printf(" CAS::FEVD[%u] Matching function found for \"%s\" in the modules",
+ current_id,
+ name.GetCString());
+ }
+
+ clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules);
+ clang::FunctionDecl *copied_function_decl = copied_decl ? dyn_cast<clang::FunctionDecl>(copied_decl) : nullptr;
+
+ if (!copied_function_decl)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a function declaration from the modules",
+ current_id);
+
+ break;
+ }
+
+ if (copied_function_decl->getBody() && m_parser_vars->m_code_gen)
+ {
+ DeclGroupRef decl_group_ref(copied_function_decl);
+ m_parser_vars->m_code_gen->HandleTopLevelDecl(decl_group_ref);
+ }
+
+ context.AddNamedDecl(copied_function_decl);
+
+ context.m_found.function_with_type_info = true;
+ context.m_found.function = true;
+ }
+ else if (llvm::isa<clang::VarDecl>(decl_from_modules))
+ {
+ if (log)
+ {
+ log->Printf(" CAS::FEVD[%u] Matching variable found for \"%s\" in the modules",
+ current_id,
+ name.GetCString());
+ }
+
+ clang::Decl *copied_decl = m_ast_importer_sp->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules);
+ clang::VarDecl *copied_var_decl = copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl) : nullptr;
+
+ if (!copied_var_decl)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a variable declaration from the modules",
+ current_id);
+
+ break;
+ }
+
+ context.AddNamedDecl(copied_var_decl);
+
+ context.m_found.variable = true;
+ }
+ }
+ } while (0);
+ }
+
+ 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.
+
+ const Symbol *data_symbol = FindGlobalDataSymbol(*target, name);
+
+ 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, current_id);
+ context.m_found.variable = true;
+ }
+ }
+ }
+ }
+}
+
+//static opaque_compiler_type_t
+//MaybePromoteToBlockPointerType
+//(
+// ASTContext *ast_context,
+// opaque_compiler_type_t candidate_type
+//)
+//{
+// if (!candidate_type)
+// return candidate_type;
+//
+// QualType candidate_qual_type = QualType::getFromOpaquePtr(candidate_type);
+//
+// const PointerType *candidate_pointer_type = dyn_cast<PointerType>(candidate_qual_type);
+//
+// if (!candidate_pointer_type)
+// return candidate_type;
+//
+// QualType pointee_qual_type = candidate_pointer_type->getPointeeType();
+//
+// const RecordType *pointee_record_type = dyn_cast<RecordType>(pointee_qual_type);
+//
+// if (!pointee_record_type)
+// return candidate_type;
+//
+// RecordDecl *pointee_record_decl = pointee_record_type->getDecl();
+//
+// if (!pointee_record_decl->isRecord())
+// return candidate_type;
+//
+// if (!pointee_record_decl->getName().startswith(llvm::StringRef("__block_literal_")))
+// return candidate_type;
+//
+// QualType generic_function_type = ast_context->getFunctionNoProtoType(ast_context->UnknownAnyTy);
+// QualType block_pointer_type = ast_context->getBlockPointerType(generic_function_type);
+//
+// return block_pointer_type.getAsOpaquePtr();
+//}
+
+bool
+ClangExpressionDeclMap::GetVariableValue (VariableSP &var,
+ lldb_private::Value &var_location,
+ TypeFromUser *user_type,
+ TypeFromParser *parser_type)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Type *var_type = var->GetType();
+
+ if (!var_type)
+ {
+ if (log)
+ log->PutCString("Skipped a definition because it has no type");
+ return false;
+ }
+
+ CompilerType var_clang_type = var_type->GetFullCompilerType ();
+
+ if (!var_clang_type)
+ {
+ if (log)
+ log->PutCString("Skipped a definition because it has no Clang type");
+ return false;
+ }
+
+ ClangASTContext *clang_ast = llvm::dyn_cast_or_null<ClangASTContext>(var_type->GetForwardCompilerType().GetTypeSystem());
+
+ if (!clang_ast)
+ {
+ if (log)
+ log->PutCString("Skipped a definition because it has no Clang AST");
+ return false;
+ }
+
+
+ ASTContext *ast = clang_ast->getASTContext();
+
+ if (!ast)
+ {
+ if (log)
+ log->PutCString("There is no AST context for the current execution context");
+ return false;
+ }
+ //var_clang_type = MaybePromoteToBlockPointerType (ast, var_clang_type);
+
+ DWARFExpression &var_location_expr = var->LocationExpression();
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+ Error err;
+
+ if (var->GetLocationIsConstantValueData())
+ {
+ DataExtractor const_value_extractor;
+
+ if (var_location_expr.GetExpressionData(const_value_extractor))
+ {
+ var_location = Value(const_value_extractor.GetDataStart(), const_value_extractor.GetByteSize());
+ var_location.SetValueType(Value::eValueTypeHostAddress);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Error evaluating constant variable: %s", err.AsCString());
+ return false;
+ }
+ }
+
+ CompilerType type_to_use = GuardedCopyType(var_clang_type);
+
+ if (!type_to_use)
+ {
+ if (log)
+ log->Printf("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::eContextTypeInvalid)
+ var_location.SetCompilerType(type_to_use);
+
+ if (var_location.GetValueType() == Value::eValueTypeFileAddress)
+ {
+ 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::eValueTypeLoadAddress);
+ }
+ }
+
+ if (user_type)
+ *user_type = TypeFromUser(var_clang_type);
+
+ return true;
+}
+
+void
+ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP var, ValueObjectSP valobj, unsigned int current_id)
+{
+ assert (m_parser_vars.get());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ TypeFromUser ut;
+ TypeFromParser pt;
+ Value var_location;
+
+ if (!GetVariableValue (var, var_location, &ut, &pt))
+ return;
+
+ clang::QualType parser_opaque_type = QualType::getFromOpaquePtr(pt.GetOpaqueQualType());
+
+ if (parser_opaque_type.isNull())
+ return;
+
+ 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 = NULL;
+ 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_parser_type = pt;
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = NULL;
+ parser_vars->m_lldb_value = var_location;
+ parser_vars->m_lldb_var = var;
+
+ if (is_reference)
+ entity->m_flags |= ClangExpressionVariable::EVTypeIsReference;
+
+ if (log)
+ {
+ ASTDumper orig_dumper(ut.GetOpaqueQualType());
+ ASTDumper ast_dumper(var_decl);
+ log->Printf(" CEDM::FEVD[%u] Found variable %s, returned %s (original %s)", current_id, decl_name.c_str(), ast_dumper.GetCString(), orig_dumper.GetCString());
+ }
+}
+
+void
+ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
+ ExpressionVariableSP &pvar_sp,
+ unsigned int current_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ TypeFromUser user_type (llvm::cast<ClangExpressionVariable>(pvar_sp.get())->GetTypeFromUser());
+
+ TypeFromParser parser_type (GuardedCopyType(user_type));
+
+ if (!parser_type.GetOpaqueQualType())
+ {
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Couldn't import type for pvar %s", current_id, pvar_sp->GetName().GetCString());
+ 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_parser_type = parser_type;
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = NULL;
+ parser_vars->m_lldb_value.Clear();
+
+ if (log)
+ {
+ ASTDumper ast_dumper(var_decl);
+ log->Printf(" CEDM::FEVD[%u] Added pvar %s, returned %s", current_id, pvar_sp->GetName().GetCString(), ast_dumper.GetCString());
+ }
+}
+
+void
+ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
+ const Symbol &symbol,
+ unsigned int current_id)
+{
+ assert(m_parser_vars.get());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ if (target == NULL)
+ return;
+
+ ASTContext *scratch_ast_context = target->GetScratchClangASTContext()->getASTContext();
+
+ TypeFromUser user_type (ClangASTContext::GetBasicType(scratch_ast_context, eBasicTypeVoid).GetPointerType().GetLValueReferenceType());
+ TypeFromParser parser_type (ClangASTContext::GetBasicType(m_ast_context, 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::eContextTypeClangType, 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::eValueTypeLoadAddress);
+
+ parser_vars->m_parser_type = parser_type;
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = NULL;
+ parser_vars->m_lldb_sym = &symbol;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(var_decl);
+
+ log->Printf(" CEDM::FEVD[%u] Found variable %s, returned %s", current_id, decl_name.c_str(), ast_dumper.GetCString());
+ }
+}
+
+bool
+ClangExpressionDeclMap::ResolveUnknownTypes()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ ClangASTContext *scratch_ast_context = target->GetScratchClangASTContext();
+
+ for (size_t index = 0, num_entities = m_found_entities.GetSize();
+ index < num_entities;
+ ++index)
+ {
+ ExpressionVariableSP entity = m_found_entities.GetVariableAtIndex(index);
+
+ ClangExpressionVariable::ParserVars *parser_vars = llvm::cast<ClangExpressionVariable>(entity.get())->GetParserVars(GetParserID());
+
+ if (entity->m_flags & ClangExpressionVariable::EVUnknownType)
+ {
+ const NamedDecl *named_decl = parser_vars->m_named_decl;
+ const VarDecl *var_decl = dyn_cast<VarDecl>(named_decl);
+
+ if (!var_decl)
+ {
+ if (log)
+ log->Printf("Entity of unknown type does not have a VarDecl");
+ return false;
+ }
+
+ if (log)
+ {
+ ASTDumper ast_dumper(const_cast<VarDecl*>(var_decl));
+ log->Printf("Variable of unknown type now has Decl %s", ast_dumper.GetCString());
+ }
+
+ QualType var_type = var_decl->getType();
+ TypeFromParser parser_type(var_type.getAsOpaquePtr(), ClangASTContext::GetASTContext(&var_decl->getASTContext()));
+
+ lldb::opaque_compiler_type_t copied_type = m_ast_importer_sp->CopyType(scratch_ast_context->getASTContext(), &var_decl->getASTContext(), var_type.getAsOpaquePtr());
+
+ if (!copied_type)
+ {
+ if (log)
+ log->Printf("ClangExpressionDeclMap::ResolveUnknownType - Couldn't import the type for a variable");
+
+ return (bool) lldb::ExpressionVariableSP();
+ }
+
+ TypeFromUser user_type(copied_type, scratch_ast_context);
+
+// parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, user_type.GetOpaqueQualType());
+ parser_vars->m_lldb_value.SetCompilerType(user_type);
+ parser_vars->m_parser_type = parser_type;
+
+ entity->SetCompilerType(user_type);
+
+ entity->m_flags &= ~(ClangExpressionVariable::EVUnknownType);
+ }
+ }
+
+ return true;
+}
+
+void
+ClangExpressionDeclMap::AddOneRegister (NameSearchContext &context,
+ const RegisterInfo *reg_info,
+ unsigned int current_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ CompilerType clang_type = ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (m_ast_context,
+ reg_info->encoding,
+ reg_info->byte_size * 8);
+
+ if (!clang_type)
+ {
+ if (log)
+ log->Printf(" Tried to add a type for %s, but couldn't get one", context.m_decl_name.getAsString().c_str());
+ 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_parser_type = parser_clang_type;
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = NULL;
+ parser_vars->m_lldb_value.Clear();
+ entity->m_flags |= ClangExpressionVariable::EVBareRegister;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(var_decl);
+ log->Printf(" CEDM::FEVD[%d] Added register %s, returned %s", current_id, context.m_decl_name.getAsString().c_str(), ast_dumper.GetCString());
+ }
+}
+
+void
+ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
+ Function* function,
+ Symbol* symbol,
+ unsigned int current_id)
+{
+ assert (m_parser_vars.get());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ NamedDecl *function_decl = NULL;
+ Address fun_address;
+ CompilerType function_clang_type;
+
+ bool is_indirect_function = false;
+
+ if (function)
+ {
+ Type *function_type = function->GetType();
+
+ if (!function_type)
+ {
+ if (log)
+ log->PutCString(" Skipped a function because it has no type");
+ return;
+ }
+
+ function_clang_type = function_type->GetFullCompilerType ();
+
+ if (!function_clang_type)
+ {
+ if (log)
+ log->PutCString(" 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);
+
+ if (!function_decl)
+ {
+ if (log)
+ {
+ log->Printf (" Failed to create a function decl for '%s' {0x%8.8" PRIx64 "}",
+ function_type->GetName().GetCString(),
+ function_type->GetID());
+ }
+
+ return;
+ }
+ }
+ else
+ {
+ // We failed to copy the type we found
+ if (log)
+ {
+ log->Printf (" Failed to import the function type '%s' {0x%8.8" PRIx64 "} into the expression parser AST contenxt",
+ function_type->GetName().GetCString(),
+ function_type->GetID());
+ }
+
+ return;
+ }
+ }
+ else if (symbol)
+ {
+ fun_address = symbol->GetAddress();
+ function_decl = context.AddGenericFunDecl();
+ is_indirect_function = symbol->IsIndirect();
+ }
+ else
+ {
+ if (log)
+ log->PutCString(" 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::eValueTypeLoadAddress);
+ 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::eValueTypeFileAddress);
+ parser_vars->m_lldb_value.GetScalar() = file_addr;
+ }
+
+
+ parser_vars->m_named_decl = function_decl;
+ parser_vars->m_llvm_value = NULL;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(function_decl);
+
+ StreamString ss;
+
+ fun_address.Dump(&ss, m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription);
+
+ log->Printf(" CEDM::FEVD[%u] Found %s function %s (description %s), returned %s",
+ current_id,
+ (function ? "specific" : "generic"),
+ decl_name.c_str(),
+ ss.GetData(),
+ ast_dumper.GetCString());
+ }
+}
+
+void
+ClangExpressionDeclMap::AddThisType(NameSearchContext &context,
+ TypeFromUser &ut,
+ unsigned int current_id)
+{
+ CompilerType copied_clang_type = GuardedCopyType(ut);
+
+ if (!copied_clang_type)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("ClangExpressionDeclMap::AddThisType - Couldn't import the type");
+
+ return;
+ }
+
+ if (copied_clang_type.IsAggregateType() && copied_clang_type.GetCompleteType ())
+ {
+ CompilerType void_clang_type = ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid);
+ CompilerType void_ptr_clang_type = void_clang_type.GetPointerType();
+
+ CompilerType method_type = ClangASTContext::CreateFunctionType (m_ast_context,
+ void_clang_type,
+ &void_ptr_clang_type,
+ 1,
+ false,
+ copied_clang_type.GetTypeQualifiers());
+
+ 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;
+
+ ClangASTContext::GetASTContext(m_ast_context)->
+ AddMethodToCXXRecordType (copied_clang_type.GetOpaqueQualType(),
+ "$__lldb_expr",
+ method_type,
+ lldb::eAccessPublic,
+ is_virtual,
+ is_static,
+ is_inline,
+ is_explicit,
+ is_attr_used,
+ is_artificial);
+ }
+
+ 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);
+
+ return;
+}
+
+void
+ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
+ TypeFromUser &ut,
+ unsigned int current_id)
+{
+ CompilerType copied_clang_type = GuardedCopyType(ut);
+
+ if (!copied_clang_type)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("ClangExpressionDeclMap::AddOneType - Couldn't import the type");
+
+ return;
+ }
+
+ context.AddTypeDecl(copied_clang_type);
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
new file mode 100644
index 0000000..b3f890c
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -0,0 +1,714 @@
+//===-- ClangExpressionDeclMap.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangExpressionDeclMap_h_
+#define liblldb_ClangExpressionDeclMap_h_
+
+// C Includes
+#include <signal.h>
+#include <stdint.h>
+
+// C++ Includes
+#include <vector>
+
+#include "ClangExpressionVariable.h"
+#include "ClangASTSource.h"
+
+// Other libraries and framework includes
+// Project includes
+#include "llvm/ADT/DenseMap.h"
+#include "clang/AST/Decl.h"
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ClangExpressionDeclMap ClangExpressionDeclMap.h "lldb/Expression/ClangExpressionDeclMap.h"
+/// @brief 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
+/// 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] delegate
+ /// If non-NULL, use this delegate to report result values. This
+ /// allows the client ClangUserExpression to report a result.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to use when parsing.
+ //------------------------------------------------------------------
+ ClangExpressionDeclMap (bool keep_result_in_memory,
+ Materializer::PersistentVariableDelegate *result_delegate,
+ ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ /// 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);
+
+ //------------------------------------------------------------------
+ /// [Used by ClangExpressionParser] For each variable that had an unknown
+ /// type at the beginning of parsing, determine its final type now.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ResolveUnknownTypes();
+
+ //------------------------------------------------------------------
+ /// Disable the state needed for parsing and IR transformation.
+ //------------------------------------------------------------------
+ void
+ DidParse ();
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Add a variable to the list of persistent
+ /// variables for the process.
+ ///
+ /// @param[in] decl
+ /// 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,
+ const 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,
+ const 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 function given nothing
+ /// but its name. Some functions are needed but didn't get Decls made
+ /// during parsing -- specifically, sel_registerName is never called
+ /// in the generated IR but we need to call it nonetheless.
+ ///
+ /// @param[in] name
+ /// The name of the function.
+ ///
+ /// @param[out] ptr
+ /// The absolute address of the function in the target.
+ ///
+ /// @return
+ /// True if the address could be retrieved; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetFunctionAddress (const ConstString &name,
+ 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,
+ const ConstString &name,
+ lldb::SymbolType symbol_type,
+ Module *module = NULL);
+
+ lldb::addr_t
+ GetSymbolAddress (const ConstString &name,
+ lldb::SymbolType symbol_type);
+
+ //------------------------------------------------------------------
+ /// [Used by IRInterpreter] Get basic target information.
+ ///
+ /// @param[out] byte_order
+ /// The byte order of the target.
+ ///
+ /// @param[out] address_byte_size
+ /// The size of a pointer in bytes.
+ ///
+ /// @return
+ /// True if the information could be determined; false
+ /// otherwise.
+ //------------------------------------------------------------------
+ struct TargetInfo
+ {
+ lldb::ByteOrder byte_order;
+ size_t address_byte_size;
+
+ TargetInfo() :
+ byte_order(lldb::eByteOrderInvalid),
+ address_byte_size(0)
+ {
+ }
+
+ 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.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ void
+ FindExternalVisibleDecls(NameSearchContext &context) override;
+
+ //------------------------------------------------------------------
+ /// Find all entities matching a given name in a given module/namespace,
+ /// using a NameSearchContext to make Decls for them.
+ ///
+ /// @param[in] context
+ /// 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.
+ ///
+ /// @param[in] name
+ /// The name as a plain C string. The NameSearchContext contains
+ /// a DeclarationName for the name so at first the name may seem
+ /// redundant, but ClangExpressionDeclMap operates in RTTI land so
+ /// it can't access DeclarationName.
+ ///
+ /// @param[in] current_id
+ /// The ID for the current FindExternalVisibleDecls invocation,
+ /// for logging purposes.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ void
+ FindExternalVisibleDecls (NameSearchContext &context,
+ lldb::ModuleSP module,
+ CompilerDeclContext &namespace_decl,
+ unsigned int current_id);
+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.
+
+ //----------------------------------------------------------------------
+ /// The following values should not live beyond parsing
+ //----------------------------------------------------------------------
+ class ParserVars
+ {
+ public:
+ ParserVars(ClangExpressionDeclMap &decl_map) :
+ m_decl_map(decl_map)
+ {
+ }
+
+ Target *
+ GetTarget()
+ {
+ if (m_exe_ctx.GetTargetPtr())
+ return m_exe_ctx.GetTargetPtr();
+ else if (m_sym_ctx.target_sp)
+ m_sym_ctx.target_sp.get();
+ return NULL;
+ }
+
+ 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.
+ private:
+ ClangExpressionDeclMap &m_decl_map;
+ DISALLOW_COPY_AND_ASSIGN (ParserVars);
+ };
+
+ std::unique_ptr<ParserVars> m_parser_vars;
+
+ //----------------------------------------------------------------------
+ /// Activate parser-specific variables
+ //----------------------------------------------------------------------
+ void
+ EnableParserVars()
+ {
+ if (!m_parser_vars.get())
+ m_parser_vars.reset(new ParserVars(*this));
+ }
+
+ //----------------------------------------------------------------------
+ /// Deallocate parser-specific variables
+ //----------------------------------------------------------------------
+ void
+ DisableParserVars()
+ {
+ m_parser_vars.reset();
+ }
+
+ //----------------------------------------------------------------------
+ /// The following values contain layout information for the materialized
+ /// struct, but are not specific to a single materialization
+ //----------------------------------------------------------------------
+ struct StructVars {
+ StructVars() :
+ m_struct_alignment(0),
+ m_struct_size(0),
+ m_struct_laid_out(false),
+ m_result_name(),
+ m_object_pointer_type(NULL, NULL)
+ {
+ }
+
+ lldb::offset_t m_struct_alignment; ///< The alignment of the struct in bytes.
+ size_t m_struct_size; ///< The size of the struct in bytes.
+ bool m_struct_laid_out; ///< 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)
+ TypeFromUser m_object_pointer_type; ///< The type of the "this" variable, if one exists
+ };
+
+ std::unique_ptr<StructVars> m_struct_vars;
+
+ //----------------------------------------------------------------------
+ /// Activate struct variables
+ //----------------------------------------------------------------------
+ void
+ EnableStructVars()
+ {
+ if (!m_struct_vars.get())
+ m_struct_vars.reset(new struct StructVars);
+ }
+
+ //----------------------------------------------------------------------
+ /// Deallocate struct variables
+ //----------------------------------------------------------------------
+ void
+ DisableStructVars()
+ {
+ m_struct_vars.reset();
+ }
+
+ //----------------------------------------------------------------------
+ /// Get this parser's ID for use in extracting parser- and JIT-specific
+ /// data from persistent variables.
+ //----------------------------------------------------------------------
+ uint64_t
+ GetParserID()
+ {
+ return (uint64_t)this;
+ }
+
+ //------------------------------------------------------------------
+ /// Given a target, find a data symbol that has the given name.
+ ///
+ /// @param[in] target
+ /// The target to use as the basis for the search.
+ ///
+ /// @param[in] name
+ /// The name as a plain C string.
+ ///
+ /// @param[in] module
+ /// The module to limit the search to. This can be NULL
+ ///
+ /// @return
+ /// The LLDB Symbol found, or NULL if none was found.
+ //------------------------------------------------------------------
+ const Symbol *
+ FindGlobalDataSymbol (Target &target,
+ const ConstString &name,
+ Module *module = NULL);
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @param[in] type
+ /// The required type for the variable. This function may be called
+ /// during parsing, in which case we don't know its type; hence the
+ /// default.
+ ///
+ /// @return
+ /// The LLDB Variable found, or NULL if none was found.
+ //------------------------------------------------------------------
+ lldb::VariableSP
+ FindGlobalVariable (Target &target,
+ lldb::ModuleSP &module,
+ const ConstString &name,
+ CompilerDeclContext *namespace_decl,
+ TypeFromUser *type = NULL);
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @param[in] decl
+ /// The Decl to be looked up.
+ ///
+ /// @return
+ /// Return true if the value was successfully filled in.
+ //------------------------------------------------------------------
+ bool
+ GetVariableValue (lldb::VariableSP &var,
+ lldb_private::Value &var_location,
+ TypeFromUser *found_type = NULL,
+ TypeFromParser *parser_type = NULL);
+
+ //------------------------------------------------------------------
+ /// 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,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given
+ /// persistent variable, and put it in the list of found entities.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] pvar
+ /// The persistent variable that needs a Decl.
+ ///
+ /// @param[in] current_id
+ /// The ID of the current invocation of FindExternalVisibleDecls
+ /// for logging purposes.
+ //------------------------------------------------------------------
+ void
+ AddOneVariable (NameSearchContext &context,
+ lldb::ExpressionVariableSP &pvar_sp,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given LLDB
+ /// symbol (treated as a variable), and put it in the list of found
+ /// entities.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] var
+ /// The LLDB Variable that needs a Decl.
+ //------------------------------------------------------------------
+ void
+ AddOneGenericVariable (NameSearchContext &context,
+ const Symbol &symbol,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given
+ /// function. (Functions are not placed in the Tuple list.) Can
+ /// handle both fully typed functions and generic functions.
+ ///
+ /// @param[in] context
+ /// 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,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// 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,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given
+ /// type. (Types are not placed in the Tuple list.)
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] type
+ /// The type that needs to be created.
+ //------------------------------------------------------------------
+ void
+ AddOneType (NameSearchContext &context,
+ TypeFromUser &type,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Generate a Decl for "*this" and add a member function declaration
+ /// to it for the expression, then report it.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] type
+ /// The type for *this.
+ //------------------------------------------------------------------
+ void
+ AddThisType(NameSearchContext &context,
+ TypeFromUser &type,
+ unsigned int current_id);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpressionDeclMap_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h
new file mode 100644
index 0000000..bb620de
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h
@@ -0,0 +1,79 @@
+//===-- ClangExpression.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangExpression_h_
+#define liblldb_ClangExpression_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Expression/ExpressionTypeSystemHelper.h"
+
+namespace lldb_private {
+
+class RecordingMemoryManager;
+
+//----------------------------------------------------------------------
+// ClangExpressionHelper
+//----------------------------------------------------------------------
+class ClangExpressionHelper : public ExpressionTypeSystemHelper
+{
+public:
+ static bool classof(const ExpressionTypeSystemHelper *ts)
+ {
+ return ts->getKind() == eKindClangHelper;
+ }
+
+ ClangExpressionHelper () :
+ ExpressionTypeSystemHelper(ExpressionTypeSystemHelper::LLVMCastKind::eKindClangHelper)
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual ~ClangExpressionHelper ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when resolving external
+ /// values. May be NULL if everything should be self-contained.
+ //------------------------------------------------------------------
+ virtual ClangExpressionDeclMap *
+ DeclMap () = 0;
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should allow to access ASTs.
+ /// May be NULL if the ASTs do not need to be transformed.
+ ///
+ /// @param[in] passthrough
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ //------------------------------------------------------------------
+ virtual clang::ASTConsumer *
+ ASTTransformer (clang::ASTConsumer *passthrough) = 0;
+
+
+protected:
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpression_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
new file mode 100644
index 0000000..72c33fe
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -0,0 +1,657 @@
+//===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/Basic/FileManager.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/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/Frontend/FrontendActions.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "llvm/ExecutionEngine/MCJIT.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Signals.h"
+
+// Project includes
+#include "ClangExpressionParser.h"
+
+#include "ClangASTSource.h"
+#include "ClangExpressionHelper.h"
+#include "ClangExpressionDeclMap.h"
+#include "ClangModulesDeclVendor.h"
+#include "ClangPersistentVariables.h"
+#include "IRForTarget.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRDynamicChecks.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace clang;
+using namespace llvm;
+using namespace lldb_private;
+
+//===----------------------------------------------------------------------===//
+// Utility Methods for Clang
+//===----------------------------------------------------------------------===//
+
+std::string GetBuiltinIncludePath(const char *Argv0) {
+ SmallString<128> P(llvm::sys::fs::getMainExecutable(
+ Argv0, (void *)(intptr_t) GetBuiltinIncludePath));
+
+ if (!P.empty()) {
+ llvm::sys::path::remove_filename(P); // Remove /clang from foo/bin/clang
+ llvm::sys::path::remove_filename(P); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ llvm::sys::path::append(P, "lib", "clang", CLANG_VERSION_STRING,
+ "include");
+ }
+
+ return P.str();
+}
+
+class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks
+{
+ ClangModulesDeclVendor &m_decl_vendor;
+ ClangPersistentVariables &m_persistent_vars;
+ StreamString m_error_stream;
+ bool m_has_errors = false;
+
+public:
+ LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor,
+ ClangPersistentVariables &persistent_vars) :
+ m_decl_vendor(decl_vendor),
+ m_persistent_vars(persistent_vars)
+ {
+ }
+
+ void
+ moduleImport(SourceLocation import_location,
+ clang::ModuleIdPath path,
+ const clang::Module * /*null*/) override
+ {
+ std::vector<ConstString> string_path;
+
+ for (const std::pair<IdentifierInfo *, SourceLocation> &component : path)
+ {
+ string_path.push_back(ConstString(component.first->getName()));
+ }
+
+ StreamString error_stream;
+
+ ClangModulesDeclVendor::ModuleVector exported_modules;
+
+ if (!m_decl_vendor.AddModule(string_path, &exported_modules, m_error_stream))
+ {
+ m_has_errors = true;
+ }
+
+ for (ClangModulesDeclVendor::ModuleID module : exported_modules)
+ {
+ m_persistent_vars.AddHandLoadedClangModule(module);
+ }
+ }
+
+ bool hasErrors()
+ {
+ return m_has_errors;
+ }
+
+ const std::string &getErrorString()
+ {
+ return m_error_stream.GetString();
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Implementation of ClangExpressionParser
+//===----------------------------------------------------------------------===//
+
+ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
+ Expression &expr,
+ bool generate_debug_info) :
+ ExpressionParser (exe_scope, expr, generate_debug_info),
+ m_compiler (),
+ m_code_generator (),
+ m_pp_callbacks(nullptr)
+{
+ // 1. Create a new compiler instance.
+ m_compiler.reset(new CompilerInstance());
+
+ // 2. Install the target.
+
+ lldb::TargetSP target_sp;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+
+ // TODO: figure out what to really do when we don't have a valid target.
+ // 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. This needs to be fixed in a better way.
+ if (target_sp && target_sp->GetArchitecture().IsValid())
+ {
+ std::string triple = target_sp->GetArchitecture().GetTriple().str();
+ m_compiler->getTargetOpts().Triple = triple;
+ }
+ else
+ {
+ m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+ }
+
+ if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 ||
+ target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
+ {
+ m_compiler->getTargetOpts().Features.push_back("+sse");
+ m_compiler->getTargetOpts().Features.push_back("+sse2");
+ }
+
+ // 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";
+ }
+
+ m_compiler->createDiagnostics();
+
+ // Create the target instance.
+ m_compiler->setTarget(TargetInfo::CreateTargetInfo(
+ m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts));
+
+ assert (m_compiler->hasTarget());
+
+ // 3. Set options.
+
+ lldb::LanguageType language = expr.Language();
+
+ 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.
+ m_compiler->getLangOpts().CPlusPlus = true;
+ break;
+ case lldb::eLanguageTypeObjC:
+ m_compiler->getLangOpts().ObjC1 = true;
+ m_compiler->getLangOpts().ObjC2 = true;
+ // FIXME: the following language option is a temporary workaround,
+ // to "ask for ObjC, get ObjC++" (see comment above).
+ m_compiler->getLangOpts().CPlusPlus = true;
+ break;
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeC_plus_plus_11:
+ case lldb::eLanguageTypeC_plus_plus_14:
+ m_compiler->getLangOpts().CPlusPlus11 = true;
+ m_compiler->getHeaderSearchOpts().UseLibcxx = true;
+ // fall thru ...
+ case lldb::eLanguageTypeC_plus_plus_03:
+ m_compiler->getLangOpts().CPlusPlus = true;
+ // FIXME: the following language option is a temporary workaround,
+ // to "ask for C++, get ObjC++". Apple hopes to remove this requirement
+ // on non-Apple platforms, but for now it is needed.
+ m_compiler->getLangOpts().ObjC1 = true;
+ break;
+ case lldb::eLanguageTypeObjC_plus_plus:
+ case lldb::eLanguageTypeUnknown:
+ default:
+ m_compiler->getLangOpts().ObjC1 = true;
+ m_compiler->getLangOpts().ObjC2 = true;
+ m_compiler->getLangOpts().CPlusPlus = true;
+ m_compiler->getLangOpts().CPlusPlus11 = true;
+ m_compiler->getHeaderSearchOpts().UseLibcxx = true;
+ break;
+ }
+
+ m_compiler->getLangOpts().Bool = true;
+ m_compiler->getLangOpts().WChar = true;
+ m_compiler->getLangOpts().Blocks = true;
+ m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients
+ if (expr.DesiredResultType() == Expression::eResultTypeId)
+ m_compiler->getLangOpts().DebuggerCastResultToId = true;
+
+ m_compiler->getLangOpts().CharIsSigned =
+ ArchSpec(m_compiler->getTargetOpts().Triple.c_str()).CharIsSignedByDefault();
+
+ // Spell checking is a nice feature, but it ends up completing a
+ // lot of types that we didn't strictly speaking need to complete.
+ // As a result, we spend a long time parsing and importing debug
+ // information.
+ m_compiler->getLangOpts().SpellChecking = false;
+
+ lldb::ProcessSP process_sp;
+ if (exe_scope)
+ process_sp = exe_scope->CalculateProcess();
+
+ if (process_sp && m_compiler->getLangOpts().ObjC1)
+ {
+ if (process_sp->GetObjCLanguageRuntime())
+ {
+ if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2)
+ m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7));
+ else
+ m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX, VersionTuple(10, 7));
+
+ if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing())
+ m_compiler->getLangOpts().DebuggerObjCLiteral = true;
+ }
+ }
+
+ m_compiler->getLangOpts().ThreadsafeStatics = false;
+ m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access
+ m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name
+
+ // Set CodeGen options
+ m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
+ m_compiler->getCodeGenOpts().InstrumentFunctions = false;
+ m_compiler->getCodeGenOpts().DisableFPElim = true;
+ m_compiler->getCodeGenOpts().OmitLeafFramePointer = false;
+ if (generate_debug_info)
+ m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::FullDebugInfo);
+ else
+ m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::NoDebugInfo);
+
+ // Disable some warnings.
+ m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError,
+ "unused-value", clang::diag::Severity::Ignored, SourceLocation());
+ m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError,
+ "odr", clang::diag::Severity::Ignored, SourceLocation());
+
+ // 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->getLangOpts());
+
+ // 4. Set up the diagnostic buffer for reporting errors
+
+ m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer);
+
+ // 5. Set up the source management objects inside the compiler
+
+ clang::FileSystemOptions file_system_options;
+ m_file_manager.reset(new clang::FileManager(file_system_options));
+
+ if (!m_compiler->hasSourceManager())
+ m_compiler->createSourceManager(*m_file_manager.get());
+
+ m_compiler->createFileManager();
+ m_compiler->createPreprocessor(TU_Complete);
+
+ if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor())
+ {
+ ClangPersistentVariables *clang_persistent_vars = llvm::cast<ClangPersistentVariables>(target_sp->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
+ std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor, *clang_persistent_vars));
+ m_pp_callbacks = static_cast<LLDBPreprocessorCallbacks*>(pp_callbacks.get());
+ m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));
+ }
+
+ // 6. Most of this we get from the CompilerInstance, but we
+ // also want to give the context an ExternalASTSource.
+ m_selector_table.reset(new SelectorTable());
+ m_builtin_context.reset(new Builtin::Context());
+
+ std::unique_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(),
+ m_compiler->getSourceManager(),
+ m_compiler->getPreprocessor().getIdentifierTable(),
+ *m_selector_table.get(),
+ *m_builtin_context.get()));
+
+ ast_context->InitBuiltinTypes(m_compiler->getTarget());
+
+ ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
+ ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();
+
+ if (decl_map)
+ {
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy());
+ decl_map->InstallASTContext(ast_context.get());
+ ast_context->setExternalSource(ast_source);
+ }
+
+ m_ast_context.reset(new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str()));
+ m_ast_context->setASTContext(ast_context.get());
+ m_compiler->setASTContext(ast_context.release());
+
+ std::string module_name("$__lldb_module");
+
+ m_llvm_context.reset(new LLVMContext());
+ m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(),
+ module_name,
+ m_compiler->getHeaderSearchOpts(),
+ m_compiler->getPreprocessorOpts(),
+ m_compiler->getCodeGenOpts(),
+ *m_llvm_context));
+}
+
+ClangExpressionParser::~ClangExpressionParser()
+{
+}
+
+unsigned
+ClangExpressionParser::Parse (Stream &stream)
+{
+ TextDiagnosticBuffer *diag_buf = static_cast<TextDiagnosticBuffer*>(m_compiler->getDiagnostics().getClient());
+
+ diag_buf->FlushDiagnostics (m_compiler->getDiagnostics());
+
+ const char *expr_text = m_expr.Text();
+
+ clang::SourceManager &SourceMgr = m_compiler->getSourceManager();
+ bool created_main_file = false;
+ if (m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo)
+ {
+ std::string temp_source_path;
+
+ int temp_fd = -1;
+ llvm::SmallString<PATH_MAX> result_path;
+ FileSpec tmpdir_file_spec;
+ if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+ {
+ tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr");
+ 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::File file (temp_fd, 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();
+ SourceMgr.setMainFileID(SourceMgr.createFileID(
+ m_file_manager->getFile(result_path),
+ SourceLocation(), SrcMgr::C_User));
+ created_main_file = true;
+ }
+ }
+ }
+ }
+
+ if (!created_main_file)
+ {
+ std::unique_ptr<MemoryBuffer> memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__);
+ SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(memory_buffer)));
+ }
+
+ diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor());
+
+ ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
+
+ ASTConsumer *ast_transformer = type_system_helper->ASTTransformer(m_code_generator.get());
+
+ if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap())
+ decl_map->InstallCodeGenerator(m_code_generator.get());
+
+ if (ast_transformer)
+ {
+ ast_transformer->Initialize(m_compiler->getASTContext());
+ ParseAST(m_compiler->getPreprocessor(), ast_transformer, m_compiler->getASTContext());
+ }
+ else
+ {
+ m_code_generator->Initialize(m_compiler->getASTContext());
+ ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), m_compiler->getASTContext());
+ }
+
+ diag_buf->EndSourceFile();
+
+ TextDiagnosticBuffer::const_iterator diag_iterator;
+
+ int num_errors = 0;
+
+ if (m_pp_callbacks && m_pp_callbacks->hasErrors())
+ {
+ num_errors++;
+
+ stream.PutCString(m_pp_callbacks->getErrorString().c_str());
+ }
+
+ for (diag_iterator = diag_buf->warn_begin();
+ diag_iterator != diag_buf->warn_end();
+ ++diag_iterator)
+ stream.Printf("warning: %s\n", (*diag_iterator).second.c_str());
+
+ for (diag_iterator = diag_buf->err_begin();
+ diag_iterator != diag_buf->err_end();
+ ++diag_iterator)
+ {
+ num_errors++;
+ stream.Printf("error: %s\n", (*diag_iterator).second.c_str());
+ }
+
+ for (diag_iterator = diag_buf->note_begin();
+ diag_iterator != diag_buf->note_end();
+ ++diag_iterator)
+ stream.Printf("note: %s\n", (*diag_iterator).second.c_str());
+
+ if (!num_errors)
+ {
+ if (type_system_helper->DeclMap() && !type_system_helper->DeclMap()->ResolveUnknownTypes())
+ {
+ stream.Printf("error: Couldn't infer the type of a variable\n");
+ num_errors++;
+ }
+ }
+
+ return num_errors;
+}
+
+static bool FindFunctionInModule (ConstString &mangled_name,
+ llvm::Module *module,
+ const char *orig_name)
+{
+ for (llvm::Module::iterator fi = module->getFunctionList().begin(), fe = module->getFunctionList().end();
+ fi != fe;
+ ++fi)
+ {
+ if (fi->getName().str().find(orig_name) != std::string::npos)
+ {
+ mangled_name.SetCString(fi->getName().str().c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Error
+ClangExpressionParser::PrepareForExecution (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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Error err;
+
+ std::unique_ptr<llvm::Module> llvm_module_ap (m_code_generator->ReleaseModule());
+
+ if (!llvm_module_ap.get())
+ {
+ err.SetErrorToGenericError();
+ err.SetErrorString("IR doesn't contain a module");
+ return err;
+ }
+
+ // Find the actual name of the function (it's often mangled somehow)
+
+ ConstString function_name;
+
+ if (!FindFunctionInModule(function_name, llvm_module_ap.get(), m_expr.FunctionName()))
+ {
+ err.SetErrorToGenericError();
+ err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName());
+ return err;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName());
+ }
+
+ execution_unit_sp.reset(new IRExecutionUnit (m_llvm_context, // handed off here
+ llvm_module_ap, // handed off here
+ function_name,
+ exe_ctx.GetTargetSP(),
+ 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)
+ {
+ Stream *error_stream = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ error_stream = target->GetDebugger().GetErrorFile().get();
+
+ IRForTarget ir_for_target(decl_map,
+ m_expr.NeedsVariableResolution(),
+ *execution_unit_sp,
+ error_stream,
+ function_name.AsCString());
+
+ bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule());
+
+ Error interpret_error;
+ Process *process = exe_ctx.GetProcessPtr();
+
+ 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 (!ir_can_run)
+ {
+ err.SetErrorString("The expression could not be prepared to run in the target");
+ return err;
+ }
+
+ if (!can_interpret && execution_policy == eExecutionPolicyNever)
+ {
+ err.SetErrorStringWithFormat("Can't run the expression locally: %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 (execution_policy == eExecutionPolicyAlways || !can_interpret)
+ {
+ if (m_expr.NeedsValidation() && process)
+ {
+ if (!process->GetDynamicCheckers())
+ {
+ DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions();
+
+ StreamString install_errors;
+
+ if (!dynamic_checkers->Install(install_errors, exe_ctx))
+ {
+ if (install_errors.GetString().empty())
+ err.SetErrorString ("couldn't install checkers, unknown error");
+ else
+ err.SetErrorString (install_errors.GetString().c_str());
+
+ return err;
+ }
+
+ process->SetDynamicCheckers(dynamic_checkers);
+
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Finished installing dynamic checkers ==");
+ }
+
+ IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString());
+
+ if (!ir_dynamic_checks.runOnModule(*execution_unit_sp->GetModule()))
+ {
+ err.SetErrorToGenericError();
+ err.SetErrorString("Couldn't add dynamic checks to the expression");
+ return err;
+ }
+ }
+
+ execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);
+ }
+ }
+ else
+ {
+ execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);
+ }
+
+ return err;
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
new file mode 100644
index 0000000..3c05538
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -0,0 +1,136 @@
+//===-- ClangExpressionParser.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangExpressionParser_h_
+#define liblldb_ClangExpressionParser_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Expression/ExpressionParser.h"
+
+#include <string>
+#include <vector>
+
+namespace lldb_private
+{
+
+class IRExecutionUnit;
+
+//----------------------------------------------------------------------
+/// @class ClangExpressionParser ClangExpressionParser.h "lldb/Expression/ClangExpressionParser.h"
+/// @brief 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.
+ //------------------------------------------------------------------
+ ClangExpressionParser (ExecutionContextScope *exe_scope,
+ Expression &expr,
+ bool generate_debug_info);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~ClangExpressionParser () override;
+
+ //------------------------------------------------------------------
+ /// Parse a single expression and convert it to IR using Clang. Don't
+ /// wrap the expression in anything at all.
+ ///
+ /// @param[in] stream
+ /// The stream to print errors to.
+ ///
+ /// @return
+ /// The number of errors encountered during parsing. 0 means
+ /// success.
+ //------------------------------------------------------------------
+ unsigned
+ Parse (Stream &stream) 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[out] evaluated_statically
+ /// Set to true if the expression could be interpreted statically;
+ /// untouched otherwise.
+ ///
+ /// @param[out] const_result
+ /// If the result of the expression is constant, and the
+ /// expression has no side effects, this is set to the result of the
+ /// expression.
+ ///
+ /// @param[in] execution_policy
+ /// 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().
+ //------------------------------------------------------------------
+ Error
+ PrepareForExecution (lldb::addr_t &func_addr,
+ lldb::addr_t &func_end,
+ lldb::IRExecutionUnitSP &execution_unit_sp,
+ ExecutionContext &exe_ctx,
+ bool &can_interpret,
+ lldb_private::ExecutionPolicy execution_policy) override;
+
+private:
+ std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into
+ std::unique_ptr<clang::FileManager> m_file_manager; ///< The Clang file manager object used by the compiler
+ std::unique_ptr<clang::CompilerInstance> m_compiler; ///< The Clang compiler used to parse expressions into IR
+ std::unique_ptr<clang::Builtin::Context> m_builtin_context; ///< Context for Clang built-ins
+ std::unique_ptr<clang::SelectorTable> m_selector_table; ///< Selector table for Objective-C methods
+ 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::unique_ptr<ClangASTContext> m_ast_context;
+};
+
+}
+
+#endif // liblldb_ClangExpressionParser_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
new file mode 100644
index 0000000..908546b
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
@@ -0,0 +1,76 @@
+//===-- ClangExpressionVariable.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionVariable.h"
+
+#include "clang/AST/ASTContext.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb_private;
+using namespace clang;
+
+const char *g_clang_expression_variable_kind_name = "ClangExpressionVariable";
+
+ClangExpressionVariable::ClangExpressionVariable(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size) :
+ ExpressionVariable(LLVMCastKind::eKindClang),
+ 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,
+ const ConstString &name,
+ uint16_t flags) :
+ ExpressionVariable(LLVMCastKind::eKindClang),
+ 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) :
+ ExpressionVariable(LLVMCastKind::eKindClang),
+ m_parser_vars(),
+ m_jit_vars ()
+{
+ m_flags = EVNone;
+ m_frozen_sp = valobj_sp;
+}
+
+ClangExpressionVariable::ClangExpressionVariable(ExecutionContextScope *exe_scope,
+ const ConstString &name,
+ const TypeFromUser& user_type,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size) :
+ ExpressionVariable(LLVMCastKind::eKindClang),
+ 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/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
new file mode 100644
index 0000000..a459614
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
@@ -0,0 +1,265 @@
+//===-- ClangExpressionVariable.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangExpressionVariable_h_
+#define liblldb_ClangExpressionVariable_h_
+
+// C Includes
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+
+// C++ Includes
+#include <map>
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+#include "llvm/Support/Casting.h"
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Symbol/TaggedASTType.h"
+
+namespace llvm {
+ class Value;
+}
+
+namespace lldb_private {
+
+class ValueObjectConstResult;
+
+//----------------------------------------------------------------------
+/// @class ClangExpressionVariable ClangExpressionVariable.h "lldb/Expression/ClangExpressionVariable.h"
+/// @brief 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 ExpressionVariable
+{
+public:
+ ClangExpressionVariable(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size);
+
+ ClangExpressionVariable (ExecutionContextScope *exe_scope,
+ Value &value,
+ const ConstString &name,
+ uint16_t flags = EVNone);
+
+ ClangExpressionVariable(const lldb::ValueObjectSP &valobj_sp);
+
+ ClangExpressionVariable(ExecutionContextScope *exe_scope,
+ const ConstString &name,
+ const TypeFromUser& user_type,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size);
+
+ //----------------------------------------------------------------------
+ /// Utility functions for dealing with ExpressionVariableLists in Clang-specific ways
+ //----------------------------------------------------------------------
+
+ //----------------------------------------------------------------------
+ /// Finds a variable by NamedDecl in the list.
+ ///
+ /// @param[in] name
+ /// The name of the requested variable.
+ ///
+ /// @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() :
+ m_parser_type(),
+ m_named_decl (NULL),
+ m_llvm_value (NULL),
+ m_lldb_value (),
+ m_lldb_var (),
+ m_lldb_sym (NULL)
+ {
+ }
+
+ TypeFromParser m_parser_type; ///< The type of the variable according to the parser
+ const clang::NamedDecl *m_named_decl; ///< The Decl corresponding to this variable
+ llvm::Value *m_llvm_value; ///< 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; ///< The original symbol for this variable, if it was a symbol
+ };
+
+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 NULL;
+ else
+ return &i->second;
+ }
+
+ //----------------------------------------------------------------------
+ /// The following values are valid if the variable is used by JIT code
+ //----------------------------------------------------------------------
+ struct JITVars {
+ JITVars () :
+ m_alignment (0),
+ m_size (0),
+ m_offset (0)
+ {
+ }
+
+ lldb::offset_t m_alignment; ///< The required alignment of the variable, in bytes
+ size_t m_size; ///< The space required for the variable, in bytes
+ lldb::offset_t m_offset; ///< 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 NULL;
+ else
+ return &i->second;
+ }
+
+ TypeFromUser
+ GetTypeFromUser ();
+
+ //------------------------------------------------------------------
+ // llvm casting support
+ //------------------------------------------------------------------
+ static bool classof(const ExpressionVariable *ev)
+ {
+ return ev->getKind() == ExpressionVariable::eKindClang;
+ }
+
+ //----------------------------------------------------------------------
+ /// Members
+ //----------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ClangExpressionVariable);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpressionVariable_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
new file mode 100644
index 0000000..0d0d747
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
@@ -0,0 +1,221 @@
+//===-- ClangFunctionCallerCaller.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangFunctionCaller.h"
+
+#include "ASTStructExtractor.h"
+#include "ClangExpressionParser.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#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/ADT/Triple.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/IR/Module.h"
+
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/ClangASTContext.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"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// 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()
+{
+}
+
+unsigned
+ClangFunctionCaller::CompileFunction (Stream &errors)
+{
+ if (m_compiled)
+ return 0;
+
+ // 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
+ {
+ errors.Printf("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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ if (log)
+ log->Printf ("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;
+ m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, generate_debug_info));
+
+ num_errors = m_parser->Parse (errors);
+ }
+ else
+ {
+ errors.Printf("no process - unable to inject function");
+ num_errors = 1;
+ }
+
+ m_compiled = (num_errors == 0);
+
+ if (!m_compiled)
+ return num_errors;
+
+ return num_errors;
+}
+
+clang::ASTConsumer *
+ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer (clang::ASTConsumer *passthrough)
+{
+ m_struct_extractor.reset(new ASTStructExtractor(passthrough, m_owner.GetWrapperStructName(), m_owner));
+
+ return m_struct_extractor.get();
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h
new file mode 100644
index 0000000..3e30f81
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h
@@ -0,0 +1,173 @@
+//===-- ClangFunctionCaller.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangFunctionCaller_h_
+#define liblldb_ClangFunctionCaller_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "ClangExpressionHelper.h"
+
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ArchSpec.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 ClangExpressionParser;
+
+//----------------------------------------------------------------------
+/// @class ClangFunctionCaller ClangFunctionCaller.h "lldb/Expression/ClangFunctionCaller.h"
+/// @brief 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 ClangExpressionHelper
+ {
+ public:
+ ClangFunctionCallerHelper (ClangFunctionCaller &owner) :
+ m_owner(owner)
+ {
+ }
+
+ ~ClangFunctionCallerHelper() override = default;
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when resolving external
+ /// values. May be NULL if everything should be self-contained.
+ //------------------------------------------------------------------
+ ClangExpressionDeclMap *
+ DeclMap() override
+ {
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// 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.
+ };
+
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] exe_scope
+ /// An execution context scope that gets us at least a target and
+ /// process.
+ ///
+ /// @param[in] ast_context
+ /// The AST context to evaluate argument types in.
+ ///
+ /// @param[in] return_qualtype
+ /// An opaque Clang QualType 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] errors
+ /// The stream to print parser errors to.
+ ///
+ /// @return
+ /// The number of errors.
+ //------------------------------------------------------------------
+ unsigned
+ CompileFunction (Stream &errors) 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 // liblldb_ClangFunctionCaller_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
new file mode 100644
index 0000000..05d8a320
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -0,0 +1,731 @@
+//===-- ClangModulesDeclVendor.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+#include <mutex>
+
+// Other libraries and framework includes
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Serialization/ASTReader.h"
+
+// Project includes
+#include "ClangModulesDeclVendor.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+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);
+
+ private:
+ typedef std::pair<clang::DiagnosticsEngine::Level, std::string> IDAndDiagnostic;
+ std::vector<IDAndDiagnostic> m_diagnostics;
+ Log * m_log;
+ };
+
+ // 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,
+ llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation,
+ std::unique_ptr<clang::CompilerInstance> &&compiler_instance,
+ std::unique_ptr<clang::Parser> &&parser);
+
+ ~ClangModulesDeclVendorImpl() override = default;
+
+ bool
+ AddModule(ModulePath &path,
+ ModuleVector *exported_modules,
+ Stream &error_stream) override;
+
+ bool
+ AddModulesForCompileUnit(CompileUnit &cu,
+ ModuleVector &exported_modules,
+ Stream &error_stream) override;
+
+ uint32_t
+ FindDecls(const ConstString &name,
+ bool append,
+ uint32_t max_matches,
+ std::vector <clang::NamedDecl*> &decls) override;
+
+ void
+ ForEachMacro(const ModuleVector &modules,
+ std::function<bool (const std::string &)> handler) override;
+
+ private:
+ void
+ ReportModuleExportsHelper (std::set<ClangModulesDeclVendor::ModuleID> &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;
+ llvm::IntrusiveRefCntPtr<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 std::set<ModuleID> ImportedModuleSet;
+ ImportedModuleMap m_imported_modules;
+ ImportedModuleSet m_user_imported_modules;
+ };
+} // anonymous namespace
+
+StoringDiagnosticConsumer::StoringDiagnosticConsumer ()
+{
+ m_log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+}
+
+void
+StoringDiagnosticConsumer::HandleDiagnostic (clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info)
+{
+ llvm::SmallVector<char, 256> diagnostic_string;
+
+ info.FormatDiagnostic(diagnostic_string);
+
+ m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, std::string(diagnostic_string.data(), diagnostic_string.size())));
+}
+
+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.c_str());
+ error_stream.PutChar('\n');
+ break;
+ case clang::DiagnosticsEngine::Level::Ignored:
+ break;
+ }
+ }
+}
+
+static FileSpec
+GetResourceDir ()
+{
+ static FileSpec g_cached_resource_dir;
+
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, [](){
+ HostInfo::GetLLDBPath (lldb::ePathTypeClangDir, g_cached_resource_dir);
+ });
+
+ return g_cached_resource_dir;
+}
+
+ClangModulesDeclVendor::ClangModulesDeclVendor()
+{
+}
+
+ClangModulesDeclVendor::~ClangModulesDeclVendor()
+{
+}
+
+ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> &diagnostics_engine,
+ llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation,
+ std::unique_ptr<clang::CompilerInstance> &&compiler_instance,
+ std::unique_ptr<clang::Parser> &&parser) :
+ ClangModulesDeclVendor(),
+ m_diagnostics_engine(diagnostics_engine),
+ m_compiler_invocation(compiler_invocation),
+ m_compiler_instance(std::move(compiler_instance)),
+ m_parser(std::move(parser)),
+ m_imported_modules()
+{
+}
+
+void
+ClangModulesDeclVendorImpl::ReportModuleExportsHelper (std::set<ClangModulesDeclVendor::ModuleID> &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)
+{
+ std::set<ClangModulesDeclVendor::ModuleID> exports_set;
+
+ ReportModuleExportsHelper(exports_set, module);
+
+ for (ModuleID module : exports_set)
+ {
+ exports.push_back(module);
+ }
+}
+
+bool
+ClangModulesDeclVendorImpl::AddModule(ModulePath &path,
+ 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 : 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;
+ }
+ }
+
+ if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0].GetStringRef()))
+ {
+ error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].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 : 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", path[0].AsCString());
+ return false;
+ }
+
+ clang::Module *submodule = top_level_module;
+
+ for (size_t ci = 1; ci < path.size(); ++ci)
+ {
+ llvm::StringRef component = path[ci].GetStringRef();
+ submodule = submodule->findSubmodule(component.str());
+ if (!submodule)
+ {
+ diagnostic_consumer->DumpDiagnostics(error_stream);
+ error_stream.Printf("error: Couldn't load submodule %s\n", component.str().c_str());
+ 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;
+ // C++ and friends to be added
+ case lldb::LanguageType::eLanguageTypeC:
+ case lldb::LanguageType::eLanguageTypeC11:
+ case lldb::LanguageType::eLanguageTypeC89:
+ case lldb::LanguageType::eLanguageTypeC99:
+ case lldb::LanguageType::eLanguageTypeObjC:
+ return true;
+ }
+}
+
+bool
+ClangModulesDeclVendorImpl::AddModulesForCompileUnit(CompileUnit &cu,
+ ClangModulesDeclVendor::ModuleVector &exported_modules,
+ Stream &error_stream)
+{
+ if (LanguageSupportsClangModules(cu.GetLanguage()))
+ {
+ std::vector<ConstString> imported_modules = cu.GetImportedModules();
+
+ for (ConstString imported_module : imported_modules)
+ {
+ std::vector<ConstString> path;
+
+ path.push_back(imported_module);
+
+ if (!AddModule(path, &exported_modules, error_stream))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return true;
+}
+
+// ClangImporter::lookupValue
+
+uint32_t
+ClangModulesDeclVendorImpl::FindDecls (const ConstString &name,
+ bool append,
+ uint32_t max_matches,
+ std::vector <clang::NamedDecl*> &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(named_decl);
+ ++num_matches;
+ }
+
+ return num_matches;
+}
+
+void
+ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVector &modules,
+ std::function<bool (const std::string &)> 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 ";
+ macro_expansion.append(mi->first->getName().str().c_str());
+
+ {
+ if (macro_info->isFunctionLike())
+ {
+ macro_expansion.append("(");
+
+ bool first_arg = true;
+
+ for (clang::MacroInfo::arg_iterator ai = macro_info->arg_begin(),
+ ae = macro_info->arg_end();
+ ai != ae;
+ ++ai)
+ {
+ if (!first_arg)
+ {
+ macro_expansion.append(", ");
+ }
+ else
+ {
+ first_arg = false;
+ }
+
+ macro_expansion.append((*ai)->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::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(!"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());
+ default:
+ macro_expansion.append(ti->getName());
+ break;
+ }
+ }
+ }
+
+ if (handler(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 =
+ {
+ "-fmodules",
+ "-fcxx-modules",
+ "-fsyntax-only",
+ "-femit-all-decls",
+ "-target", arch.GetTriple().str(),
+ "-fmodules-validate-system-headers",
+ "-Werror=non-modular-include-in-framework-module"
+ };
+
+ 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> DefaultModuleCache;
+ const bool erased_on_reboot = false;
+ llvm::sys::path::system_temp_directory(erased_on_reboot, DefaultModuleCache);
+ llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang");
+ llvm::sys::path::append(DefaultModuleCache, "ModuleCache");
+ std::string module_cache_argument("-fmodules-cache-path=");
+ module_cache_argument.append(DefaultModuleCache.str().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 = GetResourceDir();
+
+ if (clang_resource_dir.IsDirectory())
+ {
+ compiler_invocation_arguments.push_back("-resource-dir");
+ compiler_invocation_arguments.push_back(clang_resource_dir.GetPath());
+ }
+ }
+
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine = clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions,
+ new StoringDiagnosticConsumer);
+
+ std::vector<const char *> compiler_invocation_argument_cstrs;
+
+ for (const std::string &arg : compiler_invocation_arguments) {
+ compiler_invocation_argument_cstrs.push_back(arg.c_str());
+ }
+
+ llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> invocation(clang::createInvocationFromCommandLine(compiler_invocation_argument_cstrs, diagnostics_engine));
+
+ 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);
+
+ instance->setDiagnostics(diagnostics_engine.get());
+ instance->setInvocation(invocation.get());
+
+ 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(instance->getLangOpts());
+
+ if (!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0]))
+ return nullptr;
+
+ instance->getPreprocessor().enableIncrementalProcessing();
+
+ instance->createModuleManager();
+
+ 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;
+
+ while (!parser->ParseTopLevelDecl(parsed));
+
+ return new ClangModulesDeclVendorImpl (diagnostics_engine, invocation, std::move(instance), std::move(parser));
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
new file mode 100644
index 0000000..df3b205
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
@@ -0,0 +1,128 @@
+//===-- ClangModulesDeclVendor.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangModulesDeclVendor_h
+#define liblldb_ClangModulesDeclVendor_h
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Symbol/DeclVendor.h"
+#include "lldb/Target/Platform.h"
+
+#include <set>
+#include <vector>
+
+namespace lldb_private
+{
+
+class ClangModulesDeclVendor : public DeclVendor
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ClangModulesDeclVendor();
+
+ ~ClangModulesDeclVendor() override;
+
+ 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] path
+ /// 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(ModulePath &path,
+ 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 text of each #define (including the
+ /// #define directive). #undef directives are not included; we simply
+ /// elide any corresponding #define. If this function returns true,
+ /// we stop the iteration immediately.
+ //------------------------------------------------------------------
+ virtual void
+ ForEachMacro(const ModuleVector &modules,
+ std::function<bool (const std::string &)> handler) = 0;
+
+ //------------------------------------------------------------------
+ /// Query whether Clang supports modules for a particular language.
+ /// LLDB uses this to decide whether to try to find the modules loaded
+ /// by a gaiven compile unit.
+ ///
+ /// @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 // liblldb_ClangModulesDeclVendor_h
diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
new file mode 100644
index 0000000..9bf9d43
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
@@ -0,0 +1,84 @@
+//===-- ClangPersistentVariables.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangPersistentVariables.h"
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+
+#include "llvm/ADT/StringMap.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ClangPersistentVariables::ClangPersistentVariables () :
+ lldb_private::PersistentExpressionState(LLVMCastKind::eKindClang),
+ m_next_persistent_variable_id (0)
+{
+}
+
+ExpressionVariableSP
+ClangPersistentVariables::CreatePersistentVariable (const lldb::ValueObjectSP &valobj_sp)
+{
+ return AddNewlyConstructedVariable(new ClangExpressionVariable(valobj_sp));
+}
+
+ExpressionVariableSP
+ClangPersistentVariables::CreatePersistentVariable (ExecutionContextScope *exe_scope,
+ const 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);
+
+ const char *name = variable->GetName().AsCString();
+
+ if (*name != '$')
+ return;
+ name++;
+
+ if (strtoul(name, NULL, 0) == m_next_persistent_variable_id - 1)
+ m_next_persistent_variable_id--;
+}
+
+ConstString
+ClangPersistentVariables::GetNextPersistentVariableName ()
+{
+ char name_cstr[256];
+ ::snprintf (name_cstr, sizeof(name_cstr), "$%u", m_next_persistent_variable_id++);
+ ConstString name(name_cstr);
+ return name;
+}
+
+void
+ClangPersistentVariables::RegisterPersistentType (const ConstString &name,
+ clang::TypeDecl *type_decl)
+{
+ m_persistent_types.insert(std::pair<const char*, clang::TypeDecl*>(name.GetCString(), type_decl));
+}
+
+clang::TypeDecl *
+ClangPersistentVariables::GetPersistentType (const ConstString &name)
+{
+ PersistentTypeMap::const_iterator i = m_persistent_types.find(name.GetCString());
+
+ if (i == m_persistent_types.end())
+ return NULL;
+ else
+ return i->second;
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h
new file mode 100644
index 0000000..0e03d01
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h
@@ -0,0 +1,106 @@
+//===-- ClangPersistentVariables.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangPersistentVariables_h_
+#define liblldb_ClangPersistentVariables_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ADT/DenseMap.h"
+
+// Project includes
+#include "ClangExpressionVariable.h"
+#include "ClangModulesDeclVendor.h"
+
+#include "lldb/Expression/ExpressionVariable.h"
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+/// @class ClangPersistentVariables ClangPersistentVariables.h "lldb/Expression/ClangPersistentVariables.h"
+/// @brief Manages persistent values that need to be preserved between expression invocations.
+///
+/// A list of variables that can be accessed and updated by any expression. See
+/// ClangPersistentVariable for more discussion. Also provides an increasing,
+/// 0-based counter for naming result variables.
+//----------------------------------------------------------------------
+class ClangPersistentVariables : public PersistentExpressionState
+{
+public:
+ ClangPersistentVariables();
+
+ ~ClangPersistentVariables() override = default;
+
+ //------------------------------------------------------------------
+ // llvm casting support
+ //------------------------------------------------------------------
+ static bool classof(const PersistentExpressionState *pv)
+ {
+ return pv->getKind() == PersistentExpressionState::eKindClang;
+ }
+
+ lldb::ExpressionVariableSP
+ CreatePersistentVariable (const lldb::ValueObjectSP &valobj_sp) override;
+
+ lldb::ExpressionVariableSP
+ CreatePersistentVariable (ExecutionContextScope *exe_scope,
+ const ConstString &name,
+ const CompilerType& compiler_type,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size) override;
+
+ //----------------------------------------------------------------------
+ /// Return the next entry in the sequence of strings "$0", "$1", ... for
+ /// use naming persistent expression convenience variables.
+ ///
+ /// @return
+ /// A string that contains the next persistent variable name.
+ //----------------------------------------------------------------------
+ ConstString
+ GetNextPersistentVariableName () override;
+
+ void
+ RemovePersistentVariable (lldb::ExpressionVariableSP variable) override;
+
+ lldb::addr_t
+ LookupSymbol (const ConstString &name) override { return LLDB_INVALID_ADDRESS; }
+
+ void
+ RegisterPersistentType (const ConstString &name,
+ clang::TypeDecl *tag_decl);
+
+ clang::TypeDecl *
+ GetPersistentType (const 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;
+ }
+
+private:
+ uint32_t m_next_persistent_variable_id; ///< The counter used by GetNextResultName().
+
+ typedef llvm::DenseMap<const char *, clang::TypeDecl *> PersistentTypeMap;
+ PersistentTypeMap m_persistent_types; ///< The persistent types 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.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangPersistentVariables_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
new file mode 100644
index 0000000..11f7f84
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -0,0 +1,673 @@
+//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <cstdlib>
+#include <string>
+#include <map>
+
+#include "ClangUserExpression.h"
+
+#include "ASTResultSynthesizer.h"
+#include "ClangExpressionDeclMap.h"
+#include "ClangExpressionParser.h"
+#include "ClangModulesDeclVendor.h"
+#include "ClangPersistentVariables.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.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/ClangASTContext.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.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 "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+
+using namespace lldb_private;
+
+ClangUserExpression::ClangUserExpression (ExecutionContextScope &exe_scope,
+ const char *expr,
+ const char *expr_prefix,
+ lldb::LanguageType language,
+ ResultType desired_type,
+ const EvaluateExpressionOptions &options) :
+ LLVMUserExpression (exe_scope, expr, expr_prefix, language, desired_type, options),
+ m_type_system_helper(*m_target_wp.lock().get())
+{
+ switch (m_language)
+ {
+ case lldb::eLanguageTypeC_plus_plus:
+ m_allow_cxx = true;
+ break;
+ case lldb::eLanguageTypeObjC:
+ m_allow_objc = true;
+ break;
+ case lldb::eLanguageTypeObjC_plus_plus:
+ default:
+ m_allow_cxx = true;
+ m_allow_objc = true;
+ break;
+ }
+}
+
+ClangUserExpression::~ClangUserExpression ()
+{
+}
+
+void
+ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("ClangUserExpression::ScanContext()");
+
+ m_target = exe_ctx.GetTargetPtr();
+
+ if (!(m_allow_cxx || m_allow_objc))
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Settings inhibit C++ and Objective-C");
+ return;
+ }
+
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame == NULL)
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Null stack frame");
+ return;
+ }
+
+ SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | lldb::eSymbolContextBlock);
+
+ if (!sym_ctx.function)
+ {
+ if (log)
+ log->Printf(" [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)
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Null function block");
+ return;
+ }
+
+ CompilerDeclContext decl_context = function_block->GetDeclContext();
+
+ if (!decl_context)
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Null decl context");
+ return;
+ }
+
+ if (clang::CXXMethodDecl *method_decl = ClangASTContext::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 = ClangASTContext::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 = ClangASTContext::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 = ClangASTContext::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 (ClangASTContext::IsObjCClassType(self_clang_type))
+ {
+ return;
+ }
+ else if (ClangASTContext::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)
+{
+#define OBJC_CAST_HACK_FROM "(int)["
+#define OBJC_CAST_HACK_TO "(int)(long long)["
+
+ size_t from_offset;
+
+ while ((from_offset = expr.find(OBJC_CAST_HACK_FROM)) != expr.npos)
+ expr.replace(from_offset, sizeof(OBJC_CAST_HACK_FROM) - 1, OBJC_CAST_HACK_TO);
+
+#undef OBJC_CAST_HACK_TO
+#undef OBJC_CAST_HACK_FROM
+}
+
+bool
+ClangUserExpression::Parse (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory,
+ bool generate_debug_info)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Error err;
+
+ InstallContext(exe_ctx);
+
+ if (Target *target = exe_ctx.GetTargetPtr())
+ {
+ if (PersistentExpressionState *persistent_state = target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC))
+ {
+ m_result_delegate.RegisterPersistentState(persistent_state);
+ }
+ else
+ {
+ error_stream.PutCString ("error: couldn't start parsing (no persistent data)");
+ return false;
+ }
+ }
+ else
+ {
+ error_stream.PutCString ("error: couldn't start parsing (no target)");
+ return false;
+ }
+
+ ScanContext(exe_ctx, err);
+
+ if (!err.Success())
+ {
+ error_stream.Printf("warning: %s\n", err.AsCString());
+ }
+
+ StreamString m_transformed_stream;
+
+ ////////////////////////////////////
+ // Generate the expression
+ //
+
+ ApplyObjcCastHack(m_expr_text);
+ //ApplyUnicharHack(m_expr_text);
+
+ std::string prefix = m_expr_prefix;
+
+ if (ClangModulesDeclVendor *decl_vendor = m_target->GetClangModulesDeclVendor())
+ {
+ const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = llvm::cast<ClangPersistentVariables>(m_target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC))->GetHandLoadedClangModules();
+ ClangModulesDeclVendor::ModuleVector modules_for_macros;
+
+ for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules)
+ {
+ modules_for_macros.push_back(module);
+ }
+
+ if (m_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);
+ }
+ }
+ }
+ }
+ }
+
+ std::unique_ptr<ExpressionSourceCode> source_code (ExpressionSourceCode::CreateWrapped(prefix.c_str(), m_expr_text.c_str()));
+
+ lldb::LanguageType lang_type;
+
+ if (m_in_cplusplus_method)
+ lang_type = lldb::eLanguageTypeC_plus_plus;
+ else if (m_in_objectivec_method)
+ lang_type = lldb::eLanguageTypeObjC;
+ else
+ lang_type = lldb::eLanguageTypeC;
+
+ if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_in_static_method, exe_ctx))
+ {
+ error_stream.PutCString ("error: couldn't construct expression body");
+ return false;
+ }
+
+ if (log)
+ log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str());
+
+ ////////////////////////////////////
+ // Set up the target and compiler
+ //
+
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ {
+ error_stream.PutCString ("error: invalid target\n");
+ return false;
+ }
+
+ //////////////////////////
+ // Parse the expression
+ //
+
+ m_materializer_ap.reset(new Materializer());
+
+ ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory);
+
+ class OnExit
+ {
+ public:
+ typedef std::function <void (void)> Callback;
+
+ OnExit (Callback const &callback) :
+ m_callback(callback)
+ {
+ }
+
+ ~OnExit ()
+ {
+ m_callback();
+ }
+ private:
+ Callback m_callback;
+ };
+
+ OnExit on_exit([this]() { ResetDeclMap(); });
+
+ if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get()))
+ {
+ error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
+
+ ResetDeclMap(); // We are being careful here in the case of breakpoint conditions.
+
+ return false;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+ ExecutionContextScope *exe_scope = process;
+
+ if (!exe_scope)
+ exe_scope = exe_ctx.GetTargetPtr();
+
+ ClangExpressionParser parser(exe_scope, *this, generate_debug_info);
+
+ unsigned num_errors = parser.Parse (error_stream);
+
+ if (num_errors)
+ {
+ error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
+
+ ResetDeclMap(); // We are being careful here in the case of breakpoint conditions.
+
+ return false;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ // Prepare the output of the parser for execution, evaluating it statically if possible
+ //
+
+ Error jit_error = parser.PrepareForExecution (m_jit_start_addr,
+ m_jit_end_addr,
+ m_execution_unit_sp,
+ exe_ctx,
+ m_can_interpret,
+ execution_policy);
+
+ 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.GetFilename() = const_func_name;
+ jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString());
+ m_jit_module_wp = jit_module_sp;
+ target->GetImages().Append(jit_module_sp);
+ }
+// lldb_private::ObjectFile *jit_obj_file = jit_module_sp->GetObjectFile();
+// StreamFile strm (stdout, false);
+// if (jit_obj_file)
+// {
+// jit_obj_file->GetSectionList();
+// jit_obj_file->GetSymtab();
+// jit_obj_file->Dump(&strm);
+// }
+// lldb_private::SymbolVendor *jit_sym_vendor = jit_module_sp->GetSymbolVendor();
+// if (jit_sym_vendor)
+// {
+// lldb_private::SymbolContextList sc_list;
+// jit_sym_vendor->FindFunctions(const_func_name, NULL, lldb::eFunctionNameTypeFull, true, false, sc_list);
+// sc_list.Dump(&strm, target);
+// jit_sym_vendor->Dump(&strm);
+// }
+ }
+
+ ResetDeclMap(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions.
+
+ if (jit_error.Success())
+ {
+ if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS)
+ m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+ return true;
+ }
+ else
+ {
+ const char *error_cstr = jit_error.AsCString();
+ if (error_cstr && error_cstr[0])
+ error_stream.Printf ("error: %s\n", error_cstr);
+ else
+ error_stream.Printf ("error: expression can't be interpreted or run\n");
+ return false;
+ }
+}
+
+bool
+ClangUserExpression::AddArguments (ExecutionContext &exe_ctx,
+ std::vector<lldb::addr_t> &args,
+ lldb::addr_t struct_address,
+ Stream &error_stream)
+{
+ 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;
+
+ ConstString object_name;
+
+ if (m_in_cplusplus_method)
+ {
+ object_name.SetCString("this");
+ }
+ else if (m_in_objectivec_method)
+ {
+ object_name.SetCString("self");
+ }
+ else
+ {
+ error_stream.Printf("Need object pointer but don't know the language\n");
+ return false;
+ }
+
+ Error object_ptr_error;
+
+ object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
+
+ if (!object_ptr_error.Success())
+ {
+ error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString());
+ object_ptr = 0;
+ }
+
+ if (m_in_objectivec_method)
+ {
+ ConstString cmd_name("_cmd");
+
+ cmd_ptr = GetObjectPointer(frame_sp, cmd_name, object_ptr_error);
+
+ if (!object_ptr_error.Success())
+ {
+ error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString());
+ cmd_ptr = 0;
+ }
+ }
+ if (object_ptr)
+ 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();
+}
+
+void
+ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(ExecutionContext &exe_ctx, Materializer::PersistentVariableDelegate &delegate, bool keep_result_in_memory)
+{
+ m_expr_decl_map_up.reset(new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx));
+}
+
+clang::ASTConsumer *
+ClangUserExpression::ClangUserExpressionHelper::ASTTransformer (clang::ASTConsumer *passthrough)
+{
+ m_result_synthesizer_up.reset(new ASTResultSynthesizer(passthrough,
+ m_target));
+
+ return m_result_synthesizer_up.get();
+}
+
+ClangUserExpression::ResultDelegate::ResultDelegate()
+{
+}
+
+ConstString
+ClangUserExpression::ResultDelegate::GetName()
+{
+ return m_persistent_state->GetNextPersistentVariableName();
+}
+
+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/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
new file mode 100644
index 0000000..f2bfe31
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -0,0 +1,218 @@
+//===-- ClangUserExpression.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangUserExpression_h_
+#define liblldb_ClangUserExpression_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "ASTStructExtractor.h"
+#include "ASTResultSynthesizer.h"
+#include "ClangExpressionDeclMap.h"
+#include "ClangExpressionHelper.h"
+#include "ClangExpressionVariable.h"
+#include "IRForTarget.h"
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Expression/LLVMUserExpression.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+/// @class ClangUserExpression ClangUserExpression.h "lldb/Expression/ClangUserExpression.h"
+/// @brief 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
+{
+public:
+ enum { kDefaultTimeout = 500000u };
+
+ class ClangUserExpressionHelper : public ClangExpressionHelper
+ {
+ public:
+ ClangUserExpressionHelper (Target &target) :
+ m_target(target)
+ {
+ }
+
+ ~ClangUserExpressionHelper() override = default;
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when resolving external
+ /// values. May be NULL if everything should be self-contained.
+ //------------------------------------------------------------------
+ ClangExpressionDeclMap *
+ DeclMap() override
+ {
+ return m_expr_decl_map_up.get();
+ }
+
+ void
+ ResetDeclMap()
+ {
+ m_expr_decl_map_up.reset();
+ }
+
+ void
+ ResetDeclMap (ExecutionContext & exe_ctx, Materializer::PersistentVariableDelegate &result_delegate, bool keep_result_in_memory);
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should allow to access ASTs.
+ /// May be NULL if the ASTs do not need to be transformed.
+ ///
+ /// @param[in] passthrough
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ //------------------------------------------------------------------
+ clang::ASTConsumer *
+ ASTTransformer(clang::ASTConsumer *passthrough) 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;
+ };
+
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] expr
+ /// The expression to parse.
+ ///
+ /// @param[in] expr_prefix
+ /// If non-NULL, a C string containing translation-unit level
+ /// definitions to be included when the expression is parsed.
+ ///
+ /// @param[in] language
+ /// If not eLanguageTypeUnknown, 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.
+ //------------------------------------------------------------------
+ ClangUserExpression (ExecutionContextScope &exe_scope,
+ const char *expr,
+ const char *expr_prefix,
+ lldb::LanguageType language,
+ ResultType desired_type,
+ const EvaluateExpressionOptions &options);
+
+ ~ClangUserExpression() override;
+
+ //------------------------------------------------------------------
+ /// Parse the expression
+ ///
+ /// @param[in] error_stream
+ /// A stream to print 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 (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory,
+ bool generate_debug_info) 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);
+ }
+
+ lldb::ExpressionVariableSP
+ GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override;
+
+private:
+ //------------------------------------------------------------------
+ /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the environment.
+ //------------------------------------------------------------------
+
+ void
+ ScanContext (ExecutionContext &exe_ctx,
+ lldb_private::Error &err) override;
+
+ bool
+ AddArguments (ExecutionContext &exe_ctx,
+ std::vector<lldb::addr_t> &args,
+ lldb::addr_t struct_address,
+ Stream &error_stream) override;
+
+ ClangUserExpressionHelper m_type_system_helper;
+
+ class ResultDelegate : public Materializer::PersistentVariableDelegate
+ {
+ public:
+ ResultDelegate();
+ 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;
+ };
+
+ ResultDelegate m_result_delegate;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangUserExpression_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
new file mode 100644
index 0000000..fe044c1
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
@@ -0,0 +1,189 @@
+//===-- ClangUserExpression.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionDeclMap.h"
+#include "ClangExpressionParser.h"
+#include "ClangUtilityFunction.h"
+
+// C Includes
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+// C++ Includes
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Expression/ExpressionSourceCode.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+/// 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.
+//------------------------------------------------------------------
+ClangUtilityFunction::ClangUtilityFunction (ExecutionContextScope &exe_scope,
+ const char *text,
+ const char *name) :
+ UtilityFunction (exe_scope, text, name)
+{
+}
+
+ClangUtilityFunction::~ClangUtilityFunction ()
+{
+}
+
+//------------------------------------------------------------------
+/// Install the utility function into a process
+///
+/// @param[in] error_stream
+/// A stream to print parse 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 (Stream &error_stream,
+ ExecutionContext &exe_ctx)
+{
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
+ {
+ error_stream.PutCString("error: already installed\n");
+ return false;
+ }
+
+ ////////////////////////////////////
+ // Set up the target and compiler
+ //
+
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ {
+ error_stream.PutCString ("error: invalid target\n");
+ return false;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (!process)
+ {
+ error_stream.PutCString ("error: invalid process\n");
+ return false;
+ }
+
+ //////////////////////////
+ // Parse the expression
+ //
+
+ bool keep_result_in_memory = false;
+
+ ResetDeclMap(exe_ctx, keep_result_in_memory);
+
+ if (!DeclMap()->WillParse(exe_ctx, NULL))
+ {
+ error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
+ return false;
+ }
+
+ const bool generate_debug_info = true;
+ ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info);
+
+ unsigned num_errors = parser.Parse (error_stream);
+
+ if (num_errors)
+ {
+ error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
+
+ ResetDeclMap();
+
+ return false;
+ }
+
+ //////////////////////////////////
+ // JIT the output of the parser
+ //
+
+ bool can_interpret = false; // should stay that way
+
+ Error 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.GetFilename() = const_func_name;
+ jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString());
+ m_jit_module_wp = jit_module_sp;
+ target->GetImages().Append(jit_module_sp);
+ }
+ }
+ }
+
+#if 0
+ // jingham: look here
+ StreamFile logfile ("/tmp/exprs.txt", "a");
+ logfile.Printf ("0x%16.16" PRIx64 ": func = %s, source =\n%s\n",
+ m_jit_start_addr,
+ m_function_name.c_str(),
+ m_function_text.c_str());
+#endif
+
+ DeclMap()->DidParse();
+
+ ResetDeclMap();
+
+ if (jit_error.Success())
+ {
+ return true;
+ }
+ else
+ {
+ const char *error_cstr = jit_error.AsCString();
+ if (error_cstr && error_cstr[0])
+ error_stream.Printf ("error: %s\n", error_cstr);
+ else
+ error_stream.Printf ("error: expression can't be interpreted or run\n");
+ return false;
+ }
+}
+
+void
+ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory)
+{
+ m_expr_decl_map_up.reset(new ClangExpressionDeclMap(keep_result_in_memory, nullptr, exe_ctx));
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h
new file mode 100644
index 0000000..7483971
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h
@@ -0,0 +1,137 @@
+//===-- ClangUtilityFunction.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangUtilityFunction_h_
+#define liblldb_ClangUtilityFunction_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "ClangExpressionHelper.h"
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Expression/UtilityFunction.h"
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+/// @class ClangUtilityFunction ClangUtilityFunction.h "lldb/Expression/ClangUtilityFunction.h"
+/// @brief 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
+{
+public:
+ class ClangUtilityFunctionHelper : public ClangExpressionHelper
+ {
+ public:
+ ClangUtilityFunctionHelper ()
+ {
+ }
+
+ ~ClangUtilityFunctionHelper() override {}
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when resolving external
+ /// values. May be NULL if everything should be self-contained.
+ //------------------------------------------------------------------
+ ClangExpressionDeclMap *
+ DeclMap() override
+ {
+ return m_expr_decl_map_up.get();
+ }
+
+ 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 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
+ {
+ return nullptr;
+ }
+ private:
+ std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up;
+ };
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+ ClangUtilityFunction (ExecutionContextScope &exe_scope,
+ const char *text,
+ const char *name);
+
+ ~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 (Stream &error_stream, ExecutionContext &exe_ctx) override;
+
+private:
+ ClangUtilityFunctionHelper m_type_system_helper; ///< The map to use when parsing and materializing the expression.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangUtilityFunction_h_
diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
new file mode 100644
index 0000000..37b7bd1d
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
@@ -0,0 +1,2820 @@
+//===-- IRForTarget.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IRForTarget.h"
+
+#include "ClangExpressionDeclMap.h"
+
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/ValueSymbolTable.h"
+
+#include "clang/AST/ASTContext.h"
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+
+#include <map>
+
+using namespace llvm;
+
+static char ID;
+
+IRForTarget::StaticDataAllocator::StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit) :
+ m_execution_unit(execution_unit),
+ m_stream_string(lldb_private::Stream::eBinary, execution_unit.GetAddressByteSize(), execution_unit.GetByteOrder()),
+ m_allocation(LLDB_INVALID_ADDRESS)
+{
+}
+
+IRForTarget::FunctionValueCache::FunctionValueCache(Maker const &maker) :
+ m_maker(maker),
+ m_values()
+{
+}
+
+IRForTarget::FunctionValueCache::~FunctionValueCache()
+{
+}
+
+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];
+}
+
+lldb::addr_t
+IRForTarget::StaticDataAllocator::Allocate()
+{
+ lldb_private::Error err;
+
+ if (m_allocation != LLDB_INVALID_ADDRESS)
+ {
+ m_execution_unit.FreeNow(m_allocation);
+ m_allocation = LLDB_INVALID_ADDRESS;
+ }
+
+ m_allocation = m_execution_unit.WriteNow((const uint8_t*)m_stream_string.GetData(), m_stream_string.GetSize(), err);
+
+ return m_allocation;
+}
+
+lldb::TargetSP
+IRForTarget::StaticDataAllocator::GetTarget()
+{
+ return m_execution_unit.GetTarget();
+}
+
+static llvm::Value *
+FindEntryInstruction (llvm::Function *function)
+{
+ if (function->empty())
+ return NULL;
+
+ 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) :
+ ModulePass(ID),
+ m_resolve_vars(resolve_vars),
+ m_func_name(func_name),
+ m_module(NULL),
+ m_decl_map(decl_map),
+ m_data_allocator(execution_unit),
+ m_CFStringCreateWithBytes(NULL),
+ m_sel_registerName(NULL),
+ m_intptr_ty(NULL),
+ m_error_stream(error_stream),
+ m_result_store(NULL),
+ m_result_is_pointer(false),
+ m_reloc_placeholder(NULL),
+ 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;
+}
+
+IRForTarget::~IRForTarget()
+{
+}
+
+bool
+IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function)
+{
+ llvm_function.setLinkage(GlobalValue::ExternalLinkage);
+
+ std::string name = llvm_function.getName().str();
+
+ return true;
+}
+
+IRForTarget::LookupResult
+IRForTarget::GetFunctionAddress (llvm::Function *fun,
+ uint64_t &fun_addr,
+ lldb_private::ConstString &name,
+ Constant **&value_ptr)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ fun_addr = LLDB_INVALID_ADDRESS;
+ name.Clear();
+ value_ptr = NULL;
+
+ if (fun->isIntrinsic())
+ {
+ Intrinsic::ID intrinsic_id = (Intrinsic::ID)fun->getIntrinsicID();
+
+ switch (intrinsic_id)
+ {
+ default:
+ if (log)
+ log->Printf("Unresolved intrinsic \"%s\"", Intrinsic::getName(intrinsic_id).c_str());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Call to unhandled compiler intrinsic '%s'\n", Intrinsic::getName(intrinsic_id).c_str());
+
+ return LookupResult::Fail;
+ case Intrinsic::memcpy:
+ {
+ static lldb_private::ConstString g_memcpy_str ("memcpy");
+ name = g_memcpy_str;
+ }
+ break;
+ case Intrinsic::memset:
+ {
+ static lldb_private::ConstString g_memset_str ("memset");
+ name = g_memset_str;
+ }
+ break;
+ case Intrinsic::dbg_declare:
+ case Intrinsic::dbg_value:
+ return LookupResult::Ignore;
+ }
+
+ if (log && name)
+ log->Printf("Resolved intrinsic name \"%s\"", name.GetCString());
+ }
+ else
+ {
+ name.SetCStringWithLength (fun->getName().data(), fun->getName().size());
+ }
+
+ // Find the address of the function.
+
+ clang::NamedDecl *fun_decl = DeclForGlobal (fun);
+
+ if (fun_decl)
+ {
+ if (!m_decl_map->GetFunctionInfo (fun_decl, fun_addr))
+ {
+ std::vector<lldb_private::ConstString> alternates;
+ bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr);
+ if (!found_it)
+ {
+ if (log)
+ log->Printf("Address of function \"%s\" not found.\n", name.GetCString());
+ // Check for an alternate mangling for names from the standard library.
+ // For example, "std::basic_string<...>" has an alternate mangling scheme per
+ // the Itanium C++ ABI.
+ lldb::ProcessSP process_sp = m_data_allocator.GetTarget()->GetProcessSP();
+ if (process_sp)
+ {
+ lldb_private::CPPLanguageRuntime *cpp_runtime = process_sp->GetCPPLanguageRuntime();
+ if (cpp_runtime && cpp_runtime->GetAlternateManglings(name, alternates))
+ {
+ for (size_t i = 0; i < alternates.size(); ++i)
+ {
+ const lldb_private::ConstString &alternate_name = alternates[i];
+ if (log)
+ log->Printf("Looking up address of function \"%s\" with alternate name \"%s\"",
+ name.GetCString(), alternate_name.GetCString());
+ if ((found_it = m_decl_map->GetFunctionAddress (alternate_name, fun_addr)))
+ {
+ if (log)
+ log->Printf("Found address of function \"%s\" with alternate name \"%s\"",
+ name.GetCString(), alternate_name.GetCString());
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found_it)
+ {
+ lldb_private::Mangled mangled_name(name);
+ if (m_error_stream)
+ {
+ if (mangled_name.GetMangledName())
+ m_error_stream->Printf("error: call to a function '%s' ('%s') that is not present in the target\n",
+ mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString(),
+ mangled_name.GetMangledName().GetCString());
+ else
+ m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n",
+ mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString());
+ }
+ return LookupResult::Fail;
+ }
+ }
+ }
+ else
+ {
+ if (!m_decl_map->GetFunctionAddress (name, fun_addr))
+ {
+ if (log)
+ log->Printf ("Metadataless function \"%s\" had no address", name.GetCString());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Call to a symbol-only function '%s' that is not present in the target\n", name.GetCString());
+
+ return LookupResult::Fail;
+ }
+ }
+
+ if (log)
+ log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), fun_addr);
+
+ return LookupResult::Success;
+}
+
+llvm::Constant *
+IRForTarget::BuildFunctionPointer (llvm::Type *type,
+ uint64_t ptr)
+{
+ PointerType *fun_ptr_ty = PointerType::getUnqual(type);
+ Constant *fun_addr_int = ConstantInt::get(m_intptr_ty, ptr, false);
+ return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
+}
+
+void
+IRForTarget::RegisterFunctionMetadata(LLVMContext &context,
+ llvm::Value *function_ptr,
+ const char *name)
+{
+ for (llvm::User *user : function_ptr->users())
+ {
+ if (Instruction *user_inst = dyn_cast<Instruction>(user))
+ {
+ MDString* md_name = MDString::get(context, StringRef(name));
+
+ MDNode *metadata = MDNode::get(context, md_name);
+
+ user_inst->setMetadata("lldb.call.realName", metadata);
+ }
+ else
+ {
+ RegisterFunctionMetadata (context, user, name);
+ }
+ }
+}
+
+bool
+IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ for (llvm::Module::iterator fi = llvm_module.begin();
+ fi != llvm_module.end();
+ ++fi)
+ {
+ Function *fun = &*fi;
+
+ bool is_decl = fun->isDeclaration();
+
+ if (log)
+ log->Printf("Examining %s function %s", (is_decl ? "declaration" : "non-declaration"), fun->getName().str().c_str());
+
+ if (!is_decl)
+ continue;
+
+ if (fun->use_empty())
+ continue; // ignore
+
+ uint64_t addr = LLDB_INVALID_ADDRESS;
+ lldb_private::ConstString name;
+ Constant **value_ptr = NULL;
+
+ LookupResult result = GetFunctionAddress(fun,
+ addr,
+ name,
+ value_ptr);
+
+ switch (result)
+ {
+ case LookupResult::Fail:
+ return false; // GetFunctionAddress reports its own errors
+
+ case LookupResult::Ignore:
+ break; // Nothing to do
+
+ case LookupResult::Success:
+ {
+ Constant *value = BuildFunctionPointer(fun->getFunctionType(), addr);
+
+ RegisterFunctionMetadata (llvm_module.getContext(), fun, name.AsCString());
+
+ if (value_ptr)
+ *value_ptr = value;
+
+ // If we are replacing a function with the nobuiltin attribute, it may
+ // be called with the builtin attribute on call sites. Remove any such
+ // attributes since it's illegal to have a builtin call to something
+ // other than a nobuiltin function.
+ if (fun->hasFnAttribute(llvm::Attribute::NoBuiltin)) {
+ llvm::Attribute builtin = llvm::Attribute::get(fun->getContext(), llvm::Attribute::Builtin);
+
+ for (auto u : fun->users()) {
+ if (auto call = dyn_cast<CallInst>(u)) {
+ call->removeAttribute(AttributeSet::FunctionIndex, builtin);
+ }
+ }
+ }
+
+ fun->replaceAllUsesWith(value);
+ }
+ break;
+ }
+ }
+
+ 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 NULL;
+
+ 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 NULL;
+
+ 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 NULL;
+
+ uintptr_t ptr = constant_int->getZExtValue();
+
+ return reinterpret_cast<clang::NamedDecl *>(ptr);
+ }
+
+ return NULL;
+}
+
+clang::NamedDecl *
+IRForTarget::DeclForGlobal (GlobalValue *global_val)
+{
+ return DeclForGlobal(global_val, m_module);
+}
+
+bool
+IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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();
+
+ std::string result_name_str;
+ const char *result_name = NULL;
+
+ for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
+ vi != ve;
+ ++vi)
+ {
+ result_name_str = vi->first().str();
+ const char *value_name = result_name_str.c_str();
+
+ if (strstr(value_name, "$__lldb_expr_result_ptr") &&
+ strncmp(value_name, "_ZGV", 4))
+ {
+ result_name = value_name;
+ m_result_is_pointer = true;
+ break;
+ }
+
+ if (strstr(value_name, "$__lldb_expr_result") &&
+ strncmp(value_name, "_ZGV", 4))
+ {
+ result_name = value_name;
+ m_result_is_pointer = false;
+ break;
+ }
+ }
+
+ if (!result_name)
+ {
+ if (log)
+ log->PutCString("Couldn't find result variable");
+
+ return true;
+ }
+
+ if (log)
+ log->Printf("Result name: \"%s\"", result_name);
+
+ Value *result_value = m_module->getNamedValue(result_name);
+
+ if (!result_value)
+ {
+ if (log)
+ log->PutCString("Result variable had no data");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable's name (%s) exists, but not its definition\n", result_name);
+
+ return false;
+ }
+
+ if (log)
+ log->Printf("Found result in the IR: \"%s\"", PrintValue(result_value, false).c_str());
+
+ GlobalVariable *result_global = dyn_cast<GlobalVariable>(result_value);
+
+ if (!result_global)
+ {
+ if (log)
+ log->PutCString("Result variable isn't a GlobalVariable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) is defined, but is not a global variable\n", result_name);
+
+ return false;
+ }
+
+ clang::NamedDecl *result_decl = DeclForGlobal (result_global);
+ if (!result_decl)
+ {
+ if (log)
+ log->PutCString("Result variable doesn't have a corresponding Decl");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) 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();
+
+ log->Printf("Found result decl: \"%s\"", decl_desc_str.c_str());
+ }
+
+ clang::VarDecl *result_var = dyn_cast<clang::VarDecl>(result_decl);
+ if (!result_var)
+ {
+ if (log)
+ log->PutCString("Result variable Decl isn't a VarDecl");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s)'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(element_qual_type.getAsOpaquePtr(),
+ lldb_private::ClangASTContext::GetASTContext(&result_decl->getASTContext()));
+ }
+ else if (pointer_objcobjpointertype)
+ {
+ clang::QualType element_qual_type = clang::QualType(pointer_objcobjpointertype->getObjectType(), 0);
+
+ m_result_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
+ lldb_private::ClangASTContext::GetASTContext(&result_decl->getASTContext()));
+ }
+ else
+ {
+ if (log)
+ log->PutCString("Expected result to have pointer type, but it did not");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Lvalue result (%s) is not a pointer variable\n", result_name);
+
+ return false;
+ }
+ }
+ else
+ {
+ m_result_type = lldb_private::TypeFromParser(result_var->getType().getAsOpaquePtr(),
+ lldb_private::ClangASTContext::GetASTContext(&result_decl->getASTContext()));
+ }
+
+
+ lldb::TargetSP target_sp (m_data_allocator.GetTarget());
+ lldb_private::ExecutionContext exe_ctx (target_sp, true);
+ if (m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()) == 0)
+ {
+ lldb_private::StreamString type_desc_stream;
+ m_result_type.DumpTypeDescription(&type_desc_stream);
+
+ if (log)
+ log->Printf("Result type has size 0");
+
+ if (m_error_stream)
+ 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);
+
+ log->Printf("Result decl type: \"%s\"", type_desc_stream.GetData());
+ }
+
+ m_result_name = lldb_private::ConstString("$RESULT_NAME");
+
+ if (log)
+ log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64,
+ m_result_name.GetCString(),
+ m_result_type.GetByteSize(nullptr));
+
+ // Construct a new result global and set up its metadata
+
+ GlobalVariable *new_result_global = new GlobalVariable((*m_module),
+ result_global->getType()->getElementType(),
+ false, /* not constant */
+ GlobalValue::ExternalLinkage,
+ NULL, /* 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<uint64_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);
+
+ if (log)
+ log->Printf("Replacing \"%s\" with \"%s\"",
+ PrintValue(result_global).c_str(),
+ PrintValue(new_result_global).c_str());
+
+ 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())
+ {
+ if (log)
+ log->Printf("Couldn't find initializer for unused variable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) 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);
+
+ if (log)
+ log->Printf("Synthesized result store \"%s\"\n", PrintValue(synthesized_store).c_str());
+ }
+ 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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Type *ns_str_ty = ns_str->getType();
+
+ Type *i8_ptr_ty = Type::getInt8PtrTy(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");
+
+ if (!m_decl_map->GetFunctionAddress (g_CFStringCreateWithBytes_str, CFStringCreateWithBytes_addr))
+ {
+ if (log)
+ log->PutCString("Couldn't find CFStringCreateWithBytes in the target");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Rewriting an Objective-C constant string requires CFStringCreateWithBytes\n");
+
+ return false;
+ }
+
+ if (log)
+ log->Printf("Found CFStringCreateWithBytes at 0x%" PRIx64, 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::Type *CFSCWB_ty = FunctionType::get(ns_str_ty, CFSCWB_arg_types, false);
+
+ // Build the constant containing the pointer to the function
+ PointerType *CFSCWB_ptr_ty = PointerType::getUnqual(CFSCWB_ty);
+ Constant *CFSCWB_addr_int = ConstantInt::get(m_intptr_ty, CFStringCreateWithBytes_addr, false);
+ m_CFStringCreateWithBytes = ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty);
+ }
+
+ ConstantDataSequential *string_array = NULL;
+
+ if (cstr)
+ string_array = dyn_cast<ConstantDataSequential>(cstr->getInitializer());
+
+ Constant *alloc_arg = Constant::getNullValue(i8_ptr_ty);
+ Constant *bytes_arg = cstr ? ConstantExpr::getBitCast(cstr, i8_ptr_ty) : Constant::getNullValue(i8_ptr_ty);
+ Constant *numBytes_arg = ConstantInt::get(m_intptr_ty, cstr ? string_array->getNumElements() - 1 : 0, false);
+ Constant *encoding_arg = ConstantInt::get(i32_ty, 0x0600, false); /* 0x0600 is kCFStringEncodingASCII */
+ 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, CFSCWB_Caller, m_entry_instruction_finder))
+ {
+ if (log)
+ log->PutCString("Couldn't replace the NSString with the result of the call");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: 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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable();
+
+ for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
+ vi != ve;
+ ++vi)
+ {
+ std::string value_name = vi->first().str();
+ const char *value_name_cstr = value_name.c_str();
+
+ if (strstr(value_name_cstr, "_unnamed_cfstring_"))
+ {
+ Value *nsstring_value = vi->second;
+
+ GlobalVariable *nsstring_global = dyn_cast<GlobalVariable>(nsstring_value);
+
+ if (!nsstring_global)
+ {
+ if (log)
+ log->PutCString("NSString variable is not a GlobalVariable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string is not a global variable\n");
+
+ return false;
+ }
+
+ if (!nsstring_global->hasInitializer())
+ {
+ if (log)
+ log->PutCString("NSString variable does not have an initializer");
+
+ if (m_error_stream)
+ 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)
+ {
+ if (log)
+ log->PutCString("NSString variable's initializer is not a ConstantStruct");
+
+ if (m_error_stream)
+ 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)
+ {
+ if (log)
+ log->Printf("NSString variable's initializer structure has an unexpected number of members. Should be 4, is %d", nsstring_struct->getNumOperands());
+
+ if (m_error_stream)
+ 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)
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element was empty");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string does not have a string initializer\n");
+
+ return false;
+ }
+
+ ConstantExpr *nsstring_expr = dyn_cast<ConstantExpr>(nsstring_member);
+
+ if (!nsstring_expr)
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element is not a ConstantExpr");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer is not constant\n");
+
+ return false;
+ }
+
+ if (nsstring_expr->getOpcode() != Instruction::GetElementPtr)
+ {
+ if (log)
+ log->Printf("NSString initializer's str element is not a GetElementPtr expression, it's a %s", nsstring_expr->getOpcodeName());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer is not an array\n");
+
+ return false;
+ }
+
+ Constant *nsstring_cstr = nsstring_expr->getOperand(0);
+
+ GlobalVariable *cstr_global = dyn_cast<GlobalVariable>(nsstring_cstr);
+
+ if (!cstr_global)
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element is not a GlobalVariable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to a global\n");
+
+ return false;
+ }
+
+ if (!cstr_global->hasInitializer())
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element does not have an initializer");
+
+ if (m_error_stream)
+ 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 (log)
+ {
+ if (cstr_array)
+ log->Printf("Found NSString constant %s, which contains \"%s\"", value_name_cstr, cstr_array->getAsString().str().c_str());
+ else
+ log->Printf("Found NSString constant %s, which contains \"\"", value_name_cstr);
+ }
+
+ if (!cstr_array)
+ cstr_global = NULL;
+
+ if (!RewriteObjCConstString(nsstring_global, cstr_global))
+ {
+ if (log)
+ log->PutCString("Error rewriting the constant string");
+
+ // We don't print an error message here because RewriteObjCConstString has done so for us.
+
+ return false;
+ }
+ }
+ }
+
+ for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
+ vi != ve;
+ ++vi)
+ {
+ std::string value_name = vi->first().str();
+ const char *value_name_cstr = value_name.c_str();
+
+ if (!strcmp(value_name_cstr, "__CFConstantStringClassReference"))
+ {
+ GlobalVariable *gv = dyn_cast<GlobalVariable>(vi->second);
+
+ if (!gv)
+ {
+ if (log)
+ log->PutCString("__CFConstantStringClassReference is not a global variable");
+
+ if (m_error_stream)
+ 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);
+
+ if (!global_variable || !global_variable->hasName() || !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_"))
+ return false;
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool
+IRForTarget::RewriteObjCSelector (Instruction* selector_load)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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
+ //
+ // %tmp = load i8** @"OBJC_SELECTOR_REFERENCES_" ; <i8*>
+ // %call = call i8* (i8*, i8*, ...)* @objc_msgSend(i8* %obj, i8* %tmp, ...) ; <i8*>
+ //
+ // where %obj is the object pointer and %tmp is the selector.
+ //
+ // @"OBJC_SELECTOR_REFERENCES_" is a pointer to a character array called @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_".
+ // @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_" contains the string.
+
+ // Find the pointer's initializer (a ConstantExpr with opcode GetElementPtr) 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();
+
+ ConstantExpr *osr_initializer_expr = dyn_cast<ConstantExpr>(osr_initializer);
+
+ if (!osr_initializer_expr || osr_initializer_expr->getOpcode() != Instruction::GetElementPtr)
+ return false;
+
+ Value *osr_initializer_base = osr_initializer_expr->getOperand(0);
+
+ if (!osr_initializer_base)
+ 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_base);
+
+ 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 = omvn_initializer_array->getAsString();
+
+ if (log)
+ log->Printf("Found Objective-C selector reference \"%s\"", omvn_initializer_string.c_str());
+
+ // Construct a call to sel_registerName
+
+ if (!m_sel_registerName)
+ {
+ lldb::addr_t sel_registerName_addr;
+
+ static lldb_private::ConstString g_sel_registerName_str ("sel_registerName");
+ if (!m_decl_map->GetFunctionAddress (g_sel_registerName_str, sel_registerName_addr))
+ return false;
+
+ if (log)
+ log->Printf("Found sel_registerName at 0x%" PRIx64, 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 = Type::getInt8PtrTy(m_module->getContext());
+
+ Type *type_array[1];
+
+ type_array[0] = llvm::Type::getInt8PtrTy(m_module->getContext());
+
+ ArrayRef<Type *> srN_arg_types(type_array, 1);
+
+ llvm::Type *srN_type = FunctionType::get(sel_ptr_type, srN_arg_types, false);
+
+ // Build the constant containing the pointer to the function
+ PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type);
+ Constant *srN_addr_int = ConstantInt::get(m_intptr_ty, sel_registerName_addr, false);
+ m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty);
+ }
+
+ Value *argument_array[1];
+
+ Constant *omvn_pointer = ConstantExpr::getBitCast(_objc_meth_var_name_, Type::getInt8PtrTy(m_module->getContext()));
+
+ argument_array[0] = omvn_pointer;
+
+ ArrayRef<Value *> srN_arguments(argument_array, 1);
+
+ CallInst *srN_call = CallInst::Create(m_sel_registerName,
+ srN_arguments,
+ "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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ BasicBlock::iterator ii;
+
+ typedef SmallVector <Instruction*, 2> InstrList;
+ typedef InstrList::iterator InstrIterator;
+
+ InstrList selector_loads;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ if (LoadInst *load = dyn_cast<LoadInst>(&inst))
+ if (IsObjCSelectorRef(load->getPointerOperand()))
+ selector_loads.push_back(&inst);
+ }
+
+ InstrIterator iter;
+
+ for (iter = selector_loads.begin();
+ iter != selector_loads.end();
+ ++iter)
+ {
+ if (!RewriteObjCSelector(*iter))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't change a static reference to an Objective-C selector to a dynamic reference\n");
+
+ if (log)
+ log->PutCString("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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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 (decl->getType().getAsOpaquePtr(),
+ lldb_private::ClangASTContext::GetASTContext(&decl->getASTContext()));
+
+ 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,
+ NULL, /* no initializer */
+ alloc->getName().str().c_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, "", alloc);
+
+ if (log)
+ log->Printf("Replacing \"%s\" with \"%s\"",
+ PrintValue(alloc).c_str(),
+ PrintValue(persistent_load).c_str());
+
+ 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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ BasicBlock::iterator ii;
+
+ typedef SmallVector <Instruction*, 2> InstrList;
+ typedef InstrList::iterator InstrIterator;
+
+ InstrList pvar_allocs;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ if (AllocaInst *alloc = dyn_cast<AllocaInst>(&inst))
+ {
+ llvm::StringRef alloc_name = alloc->getName();
+
+ if (alloc_name.startswith("$") &&
+ !alloc_name.startswith("$__lldb"))
+ {
+ if (alloc_name.find_first_of("0123456789") == 1)
+ {
+ if (log)
+ log->Printf("Rejecting a numeric persistent variable.");
+
+ if (m_error_stream)
+ 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);
+ }
+ }
+ }
+
+ InstrIterator iter;
+
+ for (iter = pvar_allocs.begin();
+ iter != pvar_allocs.end();
+ ++iter)
+ {
+ if (!RewritePersistentAlloc(*iter))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite the creation of a persistent variable\n");
+
+ if (log)
+ log->PutCString("Couldn't rewrite the creation of a persistent variable");
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer)
+{
+ if (!initializer)
+ return true;
+
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log && log->GetVerbose())
+ log->Printf(" MaterializeInitializer(%p, %s)", (void *)data, PrintValue(initializer).c_str());
+
+ Type *initializer_type = initializer->getType();
+
+ if (ConstantInt *int_initializer = dyn_cast<ConstantInt>(initializer))
+ {
+ memcpy (data, int_initializer->getValue().getRawData(), m_target_data->getTypeStoreSize(initializer_type));
+ return true;
+ }
+ else if (ConstantDataArray *array_initializer = dyn_cast<ConstantDataArray>(initializer))
+ {
+ if (array_initializer->isString())
+ {
+ std::string array_initializer_string = array_initializer->getAsString();
+ memcpy (data, array_initializer_string.c_str(), m_target_data->getTypeStoreSize(initializer_type));
+ }
+ else
+ {
+ ArrayType *array_initializer_type = array_initializer->getType();
+ Type *array_element_type = array_initializer_type->getElementType();
+
+ size_t element_size = m_target_data->getTypeAllocSize(array_element_type);
+
+ for (unsigned i = 0; i < array_initializer->getNumOperands(); ++i)
+ {
+ Value *operand_value = array_initializer->getOperand(i);
+ Constant *operand_constant = dyn_cast<Constant>(operand_value);
+
+ if (!operand_constant)
+ return false;
+
+ if (!MaterializeInitializer(data + (i * element_size), operand_constant))
+ return false;
+ }
+ }
+ return true;
+ }
+ else if (ConstantStruct *struct_initializer = dyn_cast<ConstantStruct>(initializer))
+ {
+ StructType *struct_initializer_type = struct_initializer->getType();
+ const StructLayout *struct_layout = m_target_data->getStructLayout(struct_initializer_type);
+
+ for (unsigned i = 0;
+ i < struct_initializer->getNumOperands();
+ ++i)
+ {
+ if (!MaterializeInitializer(data + struct_layout->getElementOffset(i), struct_initializer->getOperand(i)))
+ return false;
+ }
+ return true;
+ }
+ else if (isa<ConstantAggregateZero>(initializer))
+ {
+ memset(data, 0, m_target_data->getTypeStoreSize(initializer_type));
+ return true;
+ }
+ return false;
+}
+
+bool
+IRForTarget::MaterializeInternalVariable (GlobalVariable *global_variable)
+{
+ if (GlobalVariable::isExternalLinkage(global_variable->getLinkage()))
+ return false;
+
+ if (global_variable == m_reloc_placeholder)
+ return true;
+
+ uint64_t offset = m_data_allocator.GetStream().GetSize();
+
+ llvm::Type *variable_type = global_variable->getType();
+
+ Constant *initializer = global_variable->getInitializer();
+
+ llvm::Type *initializer_type = initializer->getType();
+
+ size_t size = m_target_data->getTypeAllocSize(initializer_type);
+ size_t align = m_target_data->getPrefTypeAlignment(initializer_type);
+
+ const size_t mask = (align - 1);
+ uint64_t aligned_offset = (offset + mask) & ~mask;
+ m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0);
+ offset = aligned_offset;
+
+ lldb_private::DataBufferHeap data(size, '\0');
+
+ if (initializer)
+ if (!MaterializeInitializer(data.GetBytes(), initializer))
+ return false;
+
+ m_data_allocator.GetStream().Write(data.GetBytes(), data.GetByteSize());
+
+ Constant *new_pointer = BuildRelocation(variable_type, offset);
+
+ global_variable->replaceAllUsesWith(new_pointer);
+
+ global_variable->eraseFromParent();
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool
+IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("MaybeHandleVariable (%s)", PrintValue(llvm_value_ptr).c_str());
+
+ 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 MaterializeInternalVariable(global_variable);
+
+ clang::NamedDecl *named_decl = DeclForGlobal(global_variable);
+
+ if (!named_decl)
+ {
+ if (IsObjCSelectorRef(llvm_value_ptr))
+ return true;
+
+ if (!global_variable->hasExternalLinkage())
+ return true;
+
+ if (log)
+ log->Printf("Found global variable \"%s\" without metadata", global_variable->getName().str().c_str());
+
+ return false;
+ }
+
+ std::string name (named_decl->getName().str());
+
+ clang::ValueDecl *value_decl = dyn_cast<clang::ValueDecl>(named_decl);
+ if (value_decl == NULL)
+ return false;
+
+ lldb_private::CompilerType compiler_type(&value_decl->getASTContext(), value_decl->getType());
+
+ const Type *value_type = NULL;
+
+ if (name[0] == '$')
+ {
+ // 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();
+ }
+
+ const uint64_t value_size = compiler_type.GetByteSize(nullptr);
+ lldb::offset_t value_alignment = (compiler_type.GetTypeBitAlign() + 7ull) / 8ull;
+
+ if (log)
+ {
+ log->Printf("Type of \"%s\" is [clang \"%s\", llvm \"%s\"] [size %" PRIu64 ", align %" PRIu64 "]",
+ name.c_str(),
+ lldb_private::ClangASTContext::GetQualType(compiler_type).getAsString().c_str(),
+ PrintType(value_type).c_str(),
+ value_size,
+ value_alignment);
+ }
+
+
+ if (named_decl && !m_decl_map->AddValueToStruct(named_decl,
+ lldb_private::ConstString (name.c_str()),
+ llvm_value_ptr,
+ value_size,
+ value_alignment))
+ {
+ if (!global_variable->hasExternalLinkage())
+ return true;
+ else if (HandleSymbol (global_variable))
+ return true;
+ else
+ return false;
+ }
+ }
+ else if (dyn_cast<llvm::Function>(llvm_value_ptr))
+ {
+ if (log)
+ log->Printf("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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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)
+ {
+ if (log)
+ log->Printf ("Symbol \"%s\" had no address", name.GetCString());
+
+ return false;
+ }
+
+ if (log)
+ log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), 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);
+
+ if (log)
+ log->Printf("Replacing %s with %s", PrintValue(symbol).c_str(), PrintValue(symbol_addr_ptr).c_str());
+
+ symbol->replaceAllUsesWith(symbol_addr_ptr);
+
+ return true;
+}
+
+bool
+IRForTarget::MaybeHandleCallArguments (CallInst *Old)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("MaybeHandleCallArguments(%s)", PrintValue(Old).c_str());
+
+ for (unsigned op_index = 0, num_ops = Old->getNumArgOperands();
+ op_index < num_ops;
+ ++op_index)
+ if (!MaybeHandleVariable(Old->getArgOperand(op_index))) // conservatively believe that this is a store
+ {
+ if (m_error_stream)
+ 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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_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);
+
+ if (log)
+ log->Printf("Found reference to Objective-C class %s (0x%llx)", name_cstr.AsCString(), (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)
+{
+ BasicBlock::iterator ii;
+
+ std::vector<CallInst *> calls_to_remove;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ 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->getCalledValue();
+
+ if (val && val->getName() == "__cxa_atexit")
+ remove = true;
+
+ if (remove)
+ calls_to_remove.push_back(call);
+ }
+
+ for (std::vector<CallInst *>::iterator ci = calls_to_remove.begin(), ce = calls_to_remove.end();
+ ci != ce;
+ ++ci)
+ {
+ (*ci)->eraseFromParent();
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::ResolveCalls(BasicBlock &basic_block)
+{
+ /////////////////////////////////////////////////////////////////////////
+ // Prepare the current basic block for execution in the remote process
+ //
+
+ BasicBlock::iterator ii;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ 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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ for (GlobalVariable &global_var : m_module->globals())
+ {
+ std::string global_name = global_var.getName().str();
+
+ if (log)
+ log->Printf("Examining %s, DeclForGlobalValue returns %p",
+ global_name.c_str(),
+ static_cast<void*>(DeclForGlobal(&global_var)));
+
+ if (global_name.find("OBJC_IVAR") == 0)
+ {
+ if (!HandleSymbol(&global_var))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Couldn't find Objective-C indirect ivar symbol %s\n", global_name.c_str());
+
+ return false;
+ }
+ }
+ else if (global_name.find("OBJC_CLASSLIST_REFERENCES_$") != global_name.npos)
+ {
+ if (!HandleObjCClass(&global_var))
+ {
+ if (m_error_stream)
+ 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.find("OBJC_CLASSLIST_SUP_REFS_$") != global_name.npos)
+ {
+ if (!HandleObjCClass(&global_var))
+ {
+ if (m_error_stream)
+ 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))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite external variable %s\n", global_name.c_str());
+
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::ReplaceStrings ()
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ typedef std::map <GlobalVariable *, size_t> OffsetsTy;
+
+ OffsetsTy offsets;
+
+ for (GlobalVariable &gv : m_module->globals())
+ {
+ if (!gv.hasInitializer())
+ continue;
+
+ Constant *gc = gv.getInitializer();
+
+ std::string str;
+
+ if (gc->isNullValue())
+ {
+ Type *gc_type = gc->getType();
+
+ ArrayType *gc_array_type = dyn_cast<ArrayType>(gc_type);
+
+ if (!gc_array_type)
+ continue;
+
+ Type *gc_element_type = gc_array_type->getElementType();
+
+ IntegerType *gc_integer_type = dyn_cast<IntegerType>(gc_element_type);
+
+ if (gc_integer_type->getBitWidth() != 8)
+ continue;
+
+ str = "";
+ }
+ else
+ {
+ ConstantDataArray *gc_array = dyn_cast<ConstantDataArray>(gc);
+
+ if (!gc_array)
+ continue;
+
+ if (!gc_array->isCString())
+ continue;
+
+ if (log)
+ log->Printf("Found a GlobalVariable with string initializer %s", PrintValue(gc).c_str());
+
+ str = gc_array->getAsString();
+ }
+
+ offsets[&gv] = m_data_allocator.GetStream().GetSize();
+
+ m_data_allocator.GetStream().Write(str.c_str(), str.length() + 1);
+ }
+
+ Type *char_ptr_ty = Type::getInt8PtrTy(m_module->getContext());
+
+ for (OffsetsTy::iterator oi = offsets.begin(), oe = offsets.end();
+ oi != oe;
+ ++oi)
+ {
+ GlobalVariable *gv = oi->first;
+ size_t offset = oi->second;
+
+ Constant *new_initializer = BuildRelocation(char_ptr_ty, offset);
+
+ if (log)
+ log->Printf("Replacing GV %s with %s", PrintValue(gv).c_str(), PrintValue(new_initializer).c_str());
+
+ for (llvm::User *u : gv->users())
+ {
+ if (log)
+ log->Printf("Found use %s", PrintValue(u).c_str());
+
+ ConstantExpr *const_expr = dyn_cast<ConstantExpr>(u);
+ StoreInst *store_inst = dyn_cast<StoreInst>(u);
+
+ if (const_expr)
+ {
+ if (const_expr->getOpcode() != Instruction::GetElementPtr)
+ {
+ if (log)
+ log->Printf("Use (%s) of string variable is not a GetElementPtr constant", PrintValue(const_expr).c_str());
+
+ return false;
+ }
+
+ Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, const_expr->getOperand(0)->getType());
+ Constant *new_gep = const_expr->getWithOperandReplaced(0, bit_cast);
+
+ const_expr->replaceAllUsesWith(new_gep);
+ }
+ else if (store_inst)
+ {
+ Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, store_inst->getValueOperand()->getType());
+
+ store_inst->setOperand(0, bit_cast);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Use (%s) of string variable is neither a constant nor a store", PrintValue(const_expr).c_str());
+
+ return false;
+ }
+ }
+
+ gv->eraseFromParent();
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ typedef SmallVector <Value*, 2> ConstantList;
+ typedef SmallVector <llvm::Instruction*, 2> UserList;
+ typedef ConstantList::iterator ConstantIterator;
+ typedef UserList::iterator UserIterator;
+
+ ConstantList static_constants;
+ UserList static_users;
+
+ for (BasicBlock::iterator ii = basic_block.begin(), ie = basic_block.end();
+ ii != ie;
+ ++ii)
+ {
+ llvm::Instruction &inst = *ii;
+
+ for (Value *operand_val : inst.operand_values())
+ {
+ ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
+
+ if (operand_constant_fp/* && operand_constant_fp->getType()->isX86_FP80Ty()*/)
+ {
+ static_constants.push_back(operand_val);
+ static_users.push_back(&*ii);
+ }
+ }
+ }
+
+ ConstantIterator constant_iter;
+ UserIterator user_iter;
+
+ for (constant_iter = static_constants.begin(), user_iter = static_users.begin();
+ constant_iter != static_constants.end();
+ ++constant_iter, ++user_iter)
+ {
+ Value *operand_val = *constant_iter;
+ llvm::Instruction *inst = *user_iter;
+
+ ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
+
+ if (operand_constant_fp)
+ {
+ Type *operand_type = operand_constant_fp->getType();
+
+ APFloat operand_apfloat = operand_constant_fp->getValueAPF();
+ APInt operand_apint = operand_apfloat.bitcastToAPInt();
+
+ const uint8_t* operand_raw_data = (const uint8_t*)operand_apint.getRawData();
+ size_t operand_data_size = operand_apint.getBitWidth() / 8;
+
+ if (log)
+ {
+ std::string s;
+ raw_string_ostream ss(s);
+ for (size_t index = 0;
+ index < operand_data_size;
+ ++index)
+ {
+ ss << (uint32_t)operand_raw_data[index];
+ ss << " ";
+ }
+ ss.flush();
+
+ log->Printf("Found ConstantFP with size %" PRIu64 " and raw data %s", (uint64_t)operand_data_size, s.c_str());
+ }
+
+ lldb_private::DataBufferHeap data(operand_data_size, 0);
+
+ if (lldb_private::endian::InlHostByteOrder() != m_data_allocator.GetStream().GetByteOrder())
+ {
+ uint8_t *data_bytes = data.GetBytes();
+
+ for (size_t index = 0;
+ index < operand_data_size;
+ ++index)
+ {
+ data_bytes[index] = operand_raw_data[operand_data_size - (1 + index)];
+ }
+ }
+ else
+ {
+ memcpy(data.GetBytes(), operand_raw_data, operand_data_size);
+ }
+
+ uint64_t offset = m_data_allocator.GetStream().GetSize();
+
+ size_t align = m_target_data->getPrefTypeAlignment(operand_type);
+
+ const size_t mask = (align - 1);
+ uint64_t aligned_offset = (offset + mask) & ~mask;
+ m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0);
+
+ m_data_allocator.GetStream().Write(data.GetBytes(), operand_data_size);
+
+ llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo();
+
+ Constant *new_pointer = BuildRelocation(fp_ptr_ty, aligned_offset);
+
+ llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst);
+
+ operand_constant_fp->replaceAllUsesWith(fp_load);
+ }
+ }
+
+ return true;
+}
+
+static bool isGuardVariableRef(Value *V)
+{
+ Constant *Old = NULL;
+
+ if (!(Old = dyn_cast<Constant>(V)))
+ return false;
+
+ ConstantExpr *CE = NULL;
+
+ if ((CE = dyn_cast<ConstantExpr>(V)))
+ {
+ if (CE->getOpcode() != Instruction::BitCast)
+ return false;
+
+ Old = CE->getOperand(0);
+ }
+
+ GlobalVariable *GV = dyn_cast<GlobalVariable>(Old);
+
+ if (!GV || !GV->hasName() ||
+ (!GV->getName().startswith("_ZGV") && // Itanium ABI guard variable
+ !GV->getName().endswith("@4IA"))) // Microsoft ABI guard variable
+ {
+ 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.
+ //
+
+ BasicBlock::iterator ii;
+
+ typedef SmallVector <Instruction*, 2> InstrList;
+ typedef InstrList::iterator InstrIterator;
+
+ InstrList guard_loads;
+ InstrList guard_stores;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ 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);
+ }
+
+ InstrIterator iter;
+
+ for (iter = guard_loads.begin();
+ iter != guard_loads.end();
+ ++iter)
+ TurnGuardLoadIntoZero(*iter);
+
+ for (iter = guard_stores.begin();
+ iter != guard_stores.end();
+ ++iter)
+ ExciseGuardStore(*iter);
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool
+IRForTarget::UnfoldConstant(Constant *old_constant,
+ FunctionValueCache &value_maker,
+ FunctionValueCache &entry_instruction_finder)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ 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:
+ if (log)
+ log->Printf("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, bit_cast_maker, entry_instruction_finder))
+ 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* {
+ Value *ptr = constant_expr->getOperand(0);
+
+ if (ptr == old_constant)
+ ptr = value_maker.GetValue(function);
+
+ std::vector<Value*> index_vector;
+
+ unsigned operand_index;
+ unsigned num_operands = constant_expr->getNumOperands();
+
+ for (operand_index = 1;
+ operand_index < num_operands;
+ ++operand_index)
+ {
+ Value *operand = constant_expr->getOperand(operand_index);
+
+ if (operand == old_constant)
+ operand = value_maker.GetValue(function);
+
+ index_vector.push_back(operand);
+ }
+
+ ArrayRef <Value*> indices(index_vector);
+
+ return GetElementPtrInst::Create(nullptr, ptr, indices, "", llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
+ });
+
+ if (!UnfoldConstant(constant_expr, get_element_pointer_maker, entry_instruction_finder))
+ return false;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("Unhandled constant type: \"%s\"", PrintValue(constant).c_str());
+ return false;
+ }
+ }
+ else
+ {
+ if (Instruction *inst = llvm::dyn_cast<Instruction>(user))
+ {
+ inst->replaceUsesOfWith(old_constant, value_maker.GetValue(inst->getParent()->getParent()));
+ }
+ else
+ {
+ if (log)
+ log->Printf("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(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ m_decl_map->DoStructLayout();
+
+ if (log)
+ log->Printf("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.getArgumentList().begin());
+
+ if (iter == llvm_function.getArgumentList().end())
+ {
+ if (m_error_stream)
+ 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().equals("this"))
+ {
+ ++iter;
+
+ if (iter == llvm_function.getArgumentList().end())
+ {
+ if (m_error_stream)
+ 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().equals("self"))
+ {
+ ++iter;
+
+ if (iter == llvm_function.getArgumentList().end())
+ {
+ if (m_error_stream)
+ 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().equals("_cmd"))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes '%s' after 'self' argument (should take '_cmd')", iter->getName().str().c_str());
+
+ return false;
+ }
+
+ ++iter;
+
+ if (iter == llvm_function.getArgumentList().end())
+ {
+ if (m_error_stream)
+ 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().equals("$__lldb_arg"))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes an argument named '%s' instead of the struct pointer", argument->getName().str().c_str());
+
+ return false;
+ }
+
+ if (log)
+ log->Printf("Arg: \"%s\"", PrintValue(argument).c_str());
+
+ BasicBlock &entry_block(llvm_function.getEntryBlock());
+ Instruction *FirstEntryInstruction(entry_block.getFirstNonPHIOrDbg());
+
+ if (!FirstEntryInstruction)
+ {
+ if (m_error_stream)
+ 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)
+ {
+ if (m_error_stream)
+ 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 = NULL;
+ Value *value = NULL;
+ lldb::offset_t offset;
+ lldb_private::ConstString name;
+
+ if (!m_decl_map->GetStructElement (decl, value, offset, name, element_index))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Structure information is incomplete");
+
+ return false;
+ }
+
+ if (log)
+ log->Printf(" \"%s\" (\"%s\") placed at %" PRIu64,
+ name.GetCString(),
+ decl->getNameAsString().c_str(),
+ offset);
+
+ if (value)
+ {
+ if (log)
+ log->Printf(" Replacing [%s]", PrintValue(value).c_str());
+
+ 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));
+
+ ConstantInt *offset_int(ConstantInt::get(offset_type, offset, true));
+ GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(nullptr,
+ argument,
+ offset_int,
+ "",
+ entry_instruction);
+
+ if (name == m_result_name && !m_result_is_pointer)
+ {
+ BitCastInst *bit_cast = new BitCastInst(get_element_ptr,
+ value->getType()->getPointerTo(),
+ "",
+ entry_instruction);
+
+ LoadInst *load = new LoadInst(bit_cast, "", entry_instruction);
+
+ return load;
+ }
+ else
+ {
+ BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", entry_instruction);
+
+ return bit_cast;
+ }
+ });
+
+ if (Constant *constant = dyn_cast<Constant>(value))
+ {
+ UnfoldConstant(constant, body_result_maker, m_entry_instruction_finder);
+ }
+ else if (Instruction *instruction = dyn_cast<Instruction>(value))
+ {
+ value->replaceAllUsesWith(body_result_maker.GetValue(instruction->getParent()->getParent()));
+ }
+ else
+ {
+ if (log)
+ log->Printf("Unhandled non-constant type: \"%s\"", PrintValue(value).c_str());
+ return false;
+ }
+
+ if (GlobalVariable *var = dyn_cast<GlobalVariable>(value))
+ var->eraseFromParent();
+ }
+ }
+
+ if (log)
+ log->Printf("Total structure [align %" PRId64 ", size %" PRIu64 "]", (int64_t)alignment, (uint64_t)size);
+
+ return true;
+}
+
+llvm::Constant *
+IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset)
+{
+ llvm::Constant *offset_int = ConstantInt::get(m_intptr_ty, offset);
+
+ llvm::Constant *offset_array[1];
+
+ offset_array[0] = offset_int;
+
+ llvm::ArrayRef<llvm::Constant *> offsets(offset_array, 1);
+ llvm::Type *char_type = llvm::Type::getInt8Ty(m_module->getContext());
+ llvm::Type *char_pointer_type = char_type->getPointerTo();
+
+ llvm::Constant *reloc_placeholder_bitcast = ConstantExpr::getBitCast(m_reloc_placeholder, char_pointer_type);
+ llvm::Constant *reloc_getelementptr = ConstantExpr::getGetElementPtr(char_type, reloc_placeholder_bitcast, offsets);
+ llvm::Constant *reloc_bitcast = ConstantExpr::getBitCast(reloc_getelementptr, type);
+
+ return reloc_bitcast;
+}
+
+bool
+IRForTarget::CompleteDataAllocation ()
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (!m_data_allocator.GetStream().GetSize())
+ return true;
+
+ lldb::addr_t allocation = m_data_allocator.Allocate();
+
+ if (log)
+ {
+ if (allocation)
+ log->Printf("Allocated static data at 0x%llx", (unsigned long long)allocation);
+ else
+ log->Printf("Failed to allocate static data");
+ }
+
+ if (!allocation || allocation == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Constant *relocated_addr = ConstantInt::get(m_intptr_ty, (uint64_t)allocation);
+ Constant *relocated_bitcast = ConstantExpr::getIntToPtr(relocated_addr, llvm::Type::getInt8PtrTy(m_module->getContext()));
+
+ m_reloc_placeholder->replaceAllUsesWith(relocated_bitcast);
+
+ m_reloc_placeholder->eraseFromParent();
+
+ return true;
+}
+
+bool
+IRForTarget::StripAllGVs (Module &llvm_module)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ std::vector<GlobalVariable *> global_vars;
+ std::set<GlobalVariable *>erased_vars;
+
+ bool erased = true;
+
+ while (erased)
+ {
+ erased = false;
+
+ for (GlobalVariable &global_var : llvm_module.globals())
+ {
+ global_var.removeDeadConstantUsers();
+
+ if (global_var.use_empty())
+ {
+ if (log)
+ log->Printf("Did remove %s",
+ PrintValue(&global_var).c_str());
+ global_var.eraseFromParent();
+ erased = true;
+ break;
+ }
+ }
+ }
+
+ for (GlobalVariable &global_var : llvm_module.globals())
+ {
+ GlobalValue::user_iterator ui = global_var.user_begin();
+
+ if (log)
+ log->Printf("Couldn't remove %s because of %s",
+ PrintValue(&global_var).c_str(),
+ PrintValue(*ui).c_str());
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::runOnModule (Module &llvm_module)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ m_module = &llvm_module;
+ m_target_data.reset(new 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, NULL);
+
+ oss.flush();
+
+ log->Printf("Module as passed in to IRForTarget: \n\"%s\"", s.c_str());
+ }
+
+ Function* main_function = m_module->getFunction(StringRef(m_func_name.c_str()));
+
+ if (!main_function)
+ {
+ if (log)
+ log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str());
+
+ return false;
+ }
+
+ if (!FixFunctionLinkage (*main_function))
+ {
+ if (log)
+ log->Printf("Couldn't fix the linkage for the function");
+
+ return false;
+ }
+
+ llvm::Type *int8_ty = Type::getInt8Ty(m_module->getContext());
+
+ m_reloc_placeholder = new llvm::GlobalVariable((*m_module),
+ int8_ty,
+ false /* IsConstant */,
+ GlobalVariable::InternalLinkage,
+ Constant::getNullValue(int8_ty),
+ "reloc_placeholder",
+ NULL /* InsertBefore */,
+ GlobalVariable::NotThreadLocal /* ThreadLocal */,
+ 0 /* AddressSpace */);
+
+ ////////////////////////////////////////////////////////////
+ // Replace $__lldb_expr_result with a persistent variable
+ //
+
+ if (!CreateResultVariable(*main_function))
+ {
+ if (log)
+ log->Printf("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, NULL);
+
+ oss.flush();
+
+ log->Printf("Module after creating the result variable: \n\"%s\"", s.c_str());
+ }
+
+ for (Module::iterator fi = m_module->begin(), fe = m_module->end();
+ fi != fe;
+ ++fi)
+ {
+ llvm::Function *function = &*fi;
+
+ if (function->begin() == function->end())
+ continue;
+
+ Function::iterator bbi;
+
+ for (bbi = function->begin();
+ bbi != function->end();
+ ++bbi)
+ {
+ if (!RemoveGuards(*bbi))
+ {
+ if (log)
+ log->Printf("RemoveGuards() failed");
+
+ // RemoveGuards() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!RewritePersistentAllocs(*bbi))
+ {
+ if (log)
+ log->Printf("RewritePersistentAllocs() failed");
+
+ // RewritePersistentAllocs() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!RemoveCXAAtExit(*bbi))
+ {
+ if (log)
+ log->Printf("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())
+ {
+ if (log)
+ log->Printf("RewriteObjCConstStrings() failed");
+
+ // RewriteObjCConstStrings() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ ///////////////////////////////
+ // Resolve function pointers
+ //
+
+ if (!ResolveFunctionPointers(llvm_module))
+ {
+ if (log)
+ log->Printf("ResolveFunctionPointers() failed");
+
+ // ResolveFunctionPointers() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ for (Module::iterator fi = m_module->begin(), fe = m_module->end();
+ fi != fe;
+ ++fi)
+ {
+ llvm::Function *function = &*fi;
+
+ for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
+ bbi != bbe;
+ ++bbi)
+ {
+ if (!RewriteObjCSelectors(*bbi))
+ {
+ if (log)
+ log->Printf("RewriteObjCSelectors() failed");
+
+ // RewriteObjCSelectors() reports its own errors, so we don't do so here
+
+ return false;
+ }
+ }
+ }
+
+ for (Module::iterator fi = m_module->begin(), fe = m_module->end();
+ fi != fe;
+ ++fi)
+ {
+ llvm::Function *function = &*fi;
+
+ for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
+ bbi != bbe;
+ ++bbi)
+ {
+ if (!ResolveCalls(*bbi))
+ {
+ if (log)
+ log->Printf("ResolveCalls() failed");
+
+ // ResolveCalls() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!ReplaceStaticLiterals(*bbi))
+ {
+ if (log)
+ log->Printf("ReplaceStaticLiterals() failed");
+
+ return false;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Run function-level passes that only make sense on the main function
+ //
+
+ if (!ResolveExternals(*main_function))
+ {
+ if (log)
+ log->Printf("ResolveExternals() failed");
+
+ // ResolveExternals() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!ReplaceVariables(*main_function))
+ {
+ if (log)
+ log->Printf("ReplaceVariables() failed");
+
+ // ReplaceVariables() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!ReplaceStrings())
+ {
+ if (log)
+ log->Printf("ReplaceStrings() failed");
+
+ return false;
+ }
+
+ if (!CompleteDataAllocation())
+ {
+ if (log)
+ log->Printf("CompleteDataAllocation() failed");
+
+ return false;
+ }
+
+ if (!StripAllGVs(llvm_module))
+ {
+ if (log)
+ log->Printf("StripAllGVs() failed");
+ }
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ m_module->print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf("Module after preparing for execution: \n\"%s\"", s.c_str());
+ }
+
+ return true;
+}
+
+void
+IRForTarget::assignPassManager (PMStack &pass_mgr_stack, PassManagerType pass_mgr_type)
+{
+}
+
+PassManagerType
+IRForTarget::getPotentialPassManagerType() const
+{
+ return PMT_ModulePassManager;
+}
diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/source/Plugins/ExpressionParser/Clang/IRForTarget.h
new file mode 100644
index 0000000..fb4abcc
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.h
@@ -0,0 +1,745 @@
+//===-- IRForTarget.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_IRForTarget_h_
+#define liblldb_IRForTarget_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "llvm/Pass.h"
+
+#include <map>
+#include <functional>
+
+namespace llvm {
+ class BasicBlock;
+ class CallInst;
+ class Constant;
+ class ConstantInt;
+ class Function;
+ class GlobalValue;
+ class GlobalVariable;
+ class Instruction;
+ class IntegerType;
+ class Module;
+ class StoreInst;
+ class DataLayout;
+ class Type;
+ class Value;
+}
+
+namespace lldb_private {
+ class ClangExpressionDeclMap;
+ class IRExecutionUnit;
+ class IRMemoryMap;
+}
+
+//----------------------------------------------------------------------
+/// @class IRForTarget IRForTarget.h "lldb/Expression/IRForTarget.h"
+/// @brief 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 llvm::ModulePass
+{
+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_policy
+ /// Determines whether an IR interpreter can be used to statically
+ /// evaluate the expression.
+ ///
+ /// @param[in] const_result
+ /// This variable is populated with the statically-computed result
+ /// of the function, if it has no side-effects and the result can
+ /// be computed statically.
+ ///
+ /// @param[in] execution_unit
+ /// 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");
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~IRForTarget() override;
+
+ //------------------------------------------------------------------
+ /// 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.
+ ///
+ /// @param[in] interpreter_error
+ /// An error. If the expression fails to be interpreted, this error
+ /// is set to a reason why.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ runOnModule(llvm::Module &llvm_module) override;
+
+ //------------------------------------------------------------------
+ /// Interface stub
+ ///
+ /// Implementation of the llvm::ModulePass::assignPassManager()
+ /// function.
+ //------------------------------------------------------------------
+ void
+ assignPassManager(llvm::PMStack &pass_mgr_stack,
+ llvm::PassManagerType pass_mgr_type = llvm::PMT_ModulePassManager) override;
+
+ //------------------------------------------------------------------
+ /// Returns PMT_ModulePassManager
+ ///
+ /// Implementation of the llvm::ModulePass::getPotentialPassManagerType()
+ /// function.
+ //------------------------------------------------------------------
+ llvm::PassManagerType
+ getPotentialPassManagerType() const override;
+
+private:
+ //------------------------------------------------------------------
+ /// Ensures that the current function's linkage is set to external.
+ /// Otherwise the JIT may not return an address for it.
+ ///
+ /// @param[in] llvm_function
+ /// The function whose linkage is to be fixed.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ FixFunctionLinkage (llvm::Function &llvm_function);
+
+ //------------------------------------------------------------------
+ /// A module-level pass to replace all function pointers with their
+ /// integer equivalents.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] llvm_module
+ /// The module currently being processed.
+ ///
+ /// @param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ HasSideEffects (llvm::Function &llvm_function);
+
+ //------------------------------------------------------------------
+ /// A function-level pass to check whether the function has side
+ /// effects.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Get the address of a function, and a location to put the complete
+ /// Value of the function if one is available.
+ ///
+ /// @param[in] function
+ /// The function to find the location of.
+ ///
+ /// @param[out] ptr
+ /// The location of the function in the target.
+ ///
+ /// @param[out] name
+ /// The resolved name of the function (matters for intrinsics).
+ ///
+ /// @param[out] value_ptr
+ /// A variable to put the function's completed Value* in, or NULL
+ /// if the Value* shouldn't be stored anywhere.
+ ///
+ /// @return
+ /// The pointer.
+ //------------------------------------------------------------------
+ LookupResult
+ GetFunctionAddress (llvm::Function *function,
+ uint64_t &ptr,
+ lldb_private::ConstString &name,
+ llvm::Constant **&value_ptr);
+
+ //------------------------------------------------------------------
+ /// Build a function pointer given a type and a raw pointer.
+ ///
+ /// @param[in] type
+ /// The type of the function pointer to be built.
+ ///
+ /// @param[in] ptr
+ /// The value of the pointer.
+ ///
+ /// @return
+ /// The pointer.
+ //------------------------------------------------------------------
+ llvm::Constant *
+ BuildFunctionPointer (llvm::Type *type,
+ uint64_t ptr);
+
+ void
+ RegisterFunctionMetadata (llvm::LLVMContext &context,
+ llvm::Value *function_ptr,
+ const char *name);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True if the function has side effects (or if this cannot
+ /// be determined); false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ResolveFunctionPointers (llvm::Module &llvm_module);
+
+ //------------------------------------------------------------------
+ /// A function-level pass to take the generated global value
+ /// $__lldb_expr_result and make it into a persistent variable.
+ /// Also see ASTResultSynthesizer.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Find the NamedDecl corresponding to a Value. This interface is
+ /// exposed for the IR interpreter.
+ ///
+ /// @param[in] module
+ /// The module containing metadata to search
+ ///
+ /// @param[in] global
+ /// The global entity to search for
+ ///
+ /// @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);
+
+ //------------------------------------------------------------------
+ /// Set the constant result variable m_const_result to the provided
+ /// constant, assuming it can be evaluated. The result variable
+ /// will be reset to NULL later if the expression has side effects.
+ ///
+ /// @param[in] initializer
+ /// The constant initializer for the variable.
+ ///
+ /// @param[in] name
+ /// The name of the result variable.
+ ///
+ /// @param[in] type
+ /// The Clang type of the result variable.
+ //------------------------------------------------------------------
+ void
+ MaybeSetConstantResult (llvm::Constant *initializer,
+ const lldb_private::ConstString &name,
+ lldb_private::TypeFromParser type);
+
+ //------------------------------------------------------------------
+ /// If the IR represents a cast of a variable, set m_const_result
+ /// to the result of the cast. The result variable will be reset to
+ /// NULL latger if the expression has side effects.
+ ///
+ /// @param[in] type
+ /// The Clang type of the result variable.
+ //------------------------------------------------------------------
+ void
+ MaybeSetCastResult (lldb_private::TypeFromParser type);
+
+ //------------------------------------------------------------------
+ /// 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.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Write an initializer to a memory array of assumed sufficient
+ /// size.
+ ///
+ /// @param[in] data
+ /// A pointer to the data to write to.
+ ///
+ /// @param[in] initializer
+ /// The initializer itself.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ MaterializeInitializer (uint8_t *data, llvm::Constant *initializer);
+
+ //------------------------------------------------------------------
+ /// Move an internal variable into the static allocation section.
+ ///
+ /// @param[in] global_variable
+ /// The variable.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ MaterializeInternalVariable (llvm::GlobalVariable *global_variable);
+
+ //------------------------------------------------------------------
+ /// 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] C
+ /// 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] call_inst
+ /// The call instruction.
+ ///
+ /// @return
+ /// True if the scan was successful; false if some operation
+ /// failed
+ //------------------------------------------------------------------
+ bool
+ RemoveCXAAtExit (llvm::BasicBlock &basic_block);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] basic_block
+ /// 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 module-level pass to allocate all string literals in a separate
+ /// allocation and redirect references to them.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ ReplaceStrings ();
+
+ //------------------------------------------------------------------
+ /// A basic block-level pass to find all literals that will be
+ /// allocated as statics by the JIT (in contrast to the Strings,
+ /// which already are statics) and synthesize loads for them.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ ReplaceStaticLiterals (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);
+
+ //------------------------------------------------------------------
+ /// A module-level pass to remove all global variables from the
+ /// module since it no longer should export or import any symbols.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] llvm_module
+ /// The module currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ StripAllGVs (llvm::Module &llvm_module);
+
+ class StaticDataAllocator {
+ public:
+ StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit);
+ lldb_private::StreamString &GetStream()
+ {
+ return m_stream_string;
+ }
+ lldb::addr_t Allocate();
+
+ lldb::TargetSP
+ GetTarget();
+ private:
+ lldb_private::IRExecutionUnit &m_execution_unit;
+ lldb_private::StreamString m_stream_string;
+ lldb::addr_t m_allocation;
+ };
+
+ /// Flags
+ bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved
+ std::string m_func_name; ///< The name of the function to translate
+ lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...)
+ lldb_private::TypeFromParser m_result_type; ///< The type of the result variable.
+ llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet.
+ std::unique_ptr<llvm::DataLayout> m_target_data; ///< The target data for the module being processed, or NULL if there is no module.
+ lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls
+ StaticDataAllocator m_data_allocator; ///< The allocator to use for constant strings
+ llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type
+ llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type
+ llvm::IntegerType *m_intptr_ty; ///< The type of an integer large enough to hold a pointer.
+ lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed
+
+ llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL.
+ bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in ASTResultSynthesizer::SynthesizeBodyResult)
+
+ llvm::GlobalVariable *m_reloc_placeholder; ///< A placeholder that will be replaced by a pointer to the final location of the static allocation.
+
+ //------------------------------------------------------------------
+ /// UnfoldConstant operates on a constant [Old] which has just been
+ /// replaced with a value [New]. We assume that new_value has
+ /// been properly placed early in the function, in front of the
+ /// first instruction in the entry 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.
+ ///
+ /// @param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+
+ 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;
+
+ static bool
+ UnfoldConstant (llvm::Constant *old_constant,
+ FunctionValueCache &value_maker,
+ FunctionValueCache &entry_instruction_finder);
+
+ //------------------------------------------------------------------
+ /// Construct a reference to m_reloc_placeholder with a given type
+ /// and offset. This typically happens after inserting data into
+ /// m_data_allocator.
+ ///
+ /// @param[in] type
+ /// The type of the value being loaded.
+ ///
+ /// @param[in] offset
+ /// The offset of the value from the base of m_data_allocator.
+ ///
+ /// @return
+ /// The Constant for the reference, usually a ConstantExpr.
+ //------------------------------------------------------------------
+ llvm::Constant *
+ BuildRelocation(llvm::Type *type,
+ uint64_t offset);
+
+ //------------------------------------------------------------------
+ /// Commit the allocation in m_data_allocator and use its final
+ /// location to replace m_reloc_placeholder.
+ ///
+ /// @param[in] module
+ /// The module that m_data_allocator resides in
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ CompleteDataAllocation ();
+
+};
+
+#endif // liblldb_IRForTarget_h_
diff --git a/source/Plugins/ExpressionParser/Go/GoAST.h b/source/Plugins/ExpressionParser/Go/GoAST.h
new file mode 100644
index 0000000..6d51240
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/GoAST.h
@@ -0,0 +1,3225 @@
+//===-- GoAST.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// DO NOT EDIT.
+// Generated by gen_go_ast.py
+
+#ifndef liblldb_GoAST_h
+#define liblldb_GoAST_h
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "llvm/Support/Casting.h"
+#include "Plugins/ExpressionParser/Go/GoLexer.h"
+
+namespace lldb_private
+{
+
+class GoASTNode
+{
+ public:
+ typedef GoLexer::TokenType TokenType;
+ typedef GoLexer::Token Token;
+ enum ChanDir
+ {
+ eChanBidir,
+ eChanSend,
+ eChanRecv,
+ };
+ enum NodeKind
+ {
+ eBadDecl,
+ eFuncDecl,
+ eGenDecl,
+ eArrayType,
+ eBadExpr,
+ eBasicLit,
+ eBinaryExpr,
+ eIdent,
+ eCallExpr,
+ eChanType,
+ eCompositeLit,
+ eEllipsis,
+ eFuncType,
+ eFuncLit,
+ eIndexExpr,
+ eInterfaceType,
+ eKeyValueExpr,
+ eMapType,
+ eParenExpr,
+ eSelectorExpr,
+ eSliceExpr,
+ eStarExpr,
+ eStructType,
+ eTypeAssertExpr,
+ eUnaryExpr,
+ eImportSpec,
+ eTypeSpec,
+ eValueSpec,
+ eAssignStmt,
+ eBadStmt,
+ eBlockStmt,
+ eBranchStmt,
+ eCaseClause,
+ eCommClause,
+ eDeclStmt,
+ eDeferStmt,
+ eEmptyStmt,
+ eExprStmt,
+ eForStmt,
+ eGoStmt,
+ eIfStmt,
+ eIncDecStmt,
+ eLabeledStmt,
+ eRangeStmt,
+ eReturnStmt,
+ eSelectStmt,
+ eSendStmt,
+ eSwitchStmt,
+ eTypeSwitchStmt,
+ eField,
+ eFieldList,
+ };
+
+ virtual ~GoASTNode() = default;
+
+ NodeKind
+ GetKind() const
+ {
+ return m_kind;
+ }
+
+ virtual const char *GetKindName() const = 0;
+
+ template <typename V> void WalkChildren(V &v);
+
+ protected:
+ explicit GoASTNode(NodeKind kind) : m_kind(kind) { }
+
+ private:
+ const NodeKind m_kind;
+
+ GoASTNode(const GoASTNode &) = delete;
+ const GoASTNode &operator=(const GoASTNode &) = delete;
+};
+
+
+class GoASTDecl : public GoASTNode
+{
+ public:
+ template <typename R, typename V> R Visit(V *v) const;
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() >= eBadDecl && n->GetKind() <= eGenDecl;
+ }
+
+ protected:
+ explicit GoASTDecl(NodeKind kind) : GoASTNode(kind) { }
+ private:
+
+ GoASTDecl(const GoASTDecl &) = delete;
+ const GoASTDecl &operator=(const GoASTDecl &) = delete;
+};
+
+class GoASTExpr : public GoASTNode
+{
+ public:
+ template <typename R, typename V> R Visit(V *v) const;
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() >= eArrayType && n->GetKind() <= eUnaryExpr;
+ }
+
+ protected:
+ explicit GoASTExpr(NodeKind kind) : GoASTNode(kind) { }
+ private:
+
+ GoASTExpr(const GoASTExpr &) = delete;
+ const GoASTExpr &operator=(const GoASTExpr &) = delete;
+};
+
+class GoASTSpec : public GoASTNode
+{
+ public:
+ template <typename R, typename V> R Visit(V *v) const;
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() >= eImportSpec && n->GetKind() <= eValueSpec;
+ }
+
+ protected:
+ explicit GoASTSpec(NodeKind kind) : GoASTNode(kind) { }
+ private:
+
+ GoASTSpec(const GoASTSpec &) = delete;
+ const GoASTSpec &operator=(const GoASTSpec &) = delete;
+};
+
+class GoASTStmt : public GoASTNode
+{
+ public:
+ template <typename R, typename V> R Visit(V *v) const;
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() >= eAssignStmt && n->GetKind() <= eTypeSwitchStmt;
+ }
+
+ protected:
+ explicit GoASTStmt(NodeKind kind) : GoASTNode(kind) { }
+ private:
+
+ GoASTStmt(const GoASTStmt &) = delete;
+ const GoASTStmt &operator=(const GoASTStmt &) = delete;
+};
+
+
+class GoASTArrayType : public GoASTExpr
+{
+ public:
+ GoASTArrayType(GoASTExpr *len, GoASTExpr *elt) : GoASTExpr(eArrayType), m_len_up(len), m_elt_up(elt) {}
+ ~GoASTArrayType() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "ArrayType";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eArrayType;
+ }
+
+ const GoASTExpr *
+ GetLen() const
+ {
+ return m_len_up.get();
+ }
+ void
+ SetLen(GoASTExpr *len)
+ {
+ m_len_up.reset(len);
+ }
+
+ const GoASTExpr *
+ GetElt() const
+ {
+ return m_elt_up.get();
+ }
+ void
+ SetElt(GoASTExpr *elt)
+ {
+ m_elt_up.reset(elt);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_len_up;
+ std::unique_ptr<GoASTExpr> m_elt_up;
+
+ GoASTArrayType(const GoASTArrayType &) = delete;
+ const GoASTArrayType &operator=(const GoASTArrayType &) = delete;
+};
+
+class GoASTAssignStmt : public GoASTStmt
+{
+ public:
+ explicit GoASTAssignStmt(bool define) : GoASTStmt(eAssignStmt), m_define(define) {}
+ ~GoASTAssignStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "AssignStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eAssignStmt;
+ }
+
+ size_t
+ NumLhs() const
+ {
+ return m_lhs.size();
+ }
+ const GoASTExpr *
+ GetLhs(int i) const
+ {
+ return m_lhs[i].get();
+ }
+ void
+ AddLhs(GoASTExpr *lhs)
+ {
+ m_lhs.push_back(std::unique_ptr<GoASTExpr>(lhs));
+ }
+
+ size_t
+ NumRhs() const
+ {
+ return m_rhs.size();
+ }
+ const GoASTExpr *
+ GetRhs(int i) const
+ {
+ return m_rhs[i].get();
+ }
+ void
+ AddRhs(GoASTExpr *rhs)
+ {
+ m_rhs.push_back(std::unique_ptr<GoASTExpr>(rhs));
+ }
+
+ bool
+ GetDefine() const
+ {
+ return m_define;
+ }
+ void
+ SetDefine(bool define)
+ {
+ m_define = define;
+ }
+
+ private:
+ friend class GoASTNode;
+ std::vector<std::unique_ptr<GoASTExpr> > m_lhs;
+ std::vector<std::unique_ptr<GoASTExpr> > m_rhs;
+ bool m_define;
+
+ GoASTAssignStmt(const GoASTAssignStmt &) = delete;
+ const GoASTAssignStmt &operator=(const GoASTAssignStmt &) = delete;
+};
+
+class GoASTBadDecl : public GoASTDecl
+{
+ public:
+ GoASTBadDecl() : GoASTDecl(eBadDecl) {}
+ ~GoASTBadDecl() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "BadDecl";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eBadDecl;
+ }
+
+ GoASTBadDecl(const GoASTBadDecl &) = delete;
+ const GoASTBadDecl &operator=(const GoASTBadDecl &) = delete;
+};
+
+class GoASTBadExpr : public GoASTExpr
+{
+ public:
+ GoASTBadExpr() : GoASTExpr(eBadExpr) {}
+ ~GoASTBadExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "BadExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eBadExpr;
+ }
+
+ GoASTBadExpr(const GoASTBadExpr &) = delete;
+ const GoASTBadExpr &operator=(const GoASTBadExpr &) = delete;
+};
+
+class GoASTBadStmt : public GoASTStmt
+{
+ public:
+ GoASTBadStmt() : GoASTStmt(eBadStmt) {}
+ ~GoASTBadStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "BadStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eBadStmt;
+ }
+
+ GoASTBadStmt(const GoASTBadStmt &) = delete;
+ const GoASTBadStmt &operator=(const GoASTBadStmt &) = delete;
+};
+
+class GoASTBasicLit : public GoASTExpr
+{
+ public:
+ explicit GoASTBasicLit(Token value) : GoASTExpr(eBasicLit), m_value(value) {}
+ ~GoASTBasicLit() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "BasicLit";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eBasicLit;
+ }
+
+ Token
+ GetValue() const
+ {
+ return m_value;
+ }
+ void
+ SetValue(Token value)
+ {
+ m_value = value;
+ }
+
+ private:
+ friend class GoASTNode;
+ Token m_value;
+
+ GoASTBasicLit(const GoASTBasicLit &) = delete;
+ const GoASTBasicLit &operator=(const GoASTBasicLit &) = delete;
+};
+
+class GoASTBinaryExpr : public GoASTExpr
+{
+ public:
+ GoASTBinaryExpr(GoASTExpr *x, GoASTExpr *y, TokenType op) : GoASTExpr(eBinaryExpr), m_x_up(x), m_y_up(y), m_op(op) {}
+ ~GoASTBinaryExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "BinaryExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eBinaryExpr;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ const GoASTExpr *
+ GetY() const
+ {
+ return m_y_up.get();
+ }
+ void
+ SetY(GoASTExpr *y)
+ {
+ m_y_up.reset(y);
+ }
+
+ TokenType
+ GetOp() const
+ {
+ return m_op;
+ }
+ void
+ SetOp(TokenType op)
+ {
+ m_op = op;
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+ std::unique_ptr<GoASTExpr> m_y_up;
+ TokenType m_op;
+
+ GoASTBinaryExpr(const GoASTBinaryExpr &) = delete;
+ const GoASTBinaryExpr &operator=(const GoASTBinaryExpr &) = delete;
+};
+
+class GoASTBlockStmt : public GoASTStmt
+{
+ public:
+ GoASTBlockStmt() : GoASTStmt(eBlockStmt) {}
+ ~GoASTBlockStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "BlockStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eBlockStmt;
+ }
+
+ size_t
+ NumList() const
+ {
+ return m_list.size();
+ }
+ const GoASTStmt *
+ GetList(int i) const
+ {
+ return m_list[i].get();
+ }
+ void
+ AddList(GoASTStmt *list)
+ {
+ m_list.push_back(std::unique_ptr<GoASTStmt>(list));
+ }
+
+ private:
+ friend class GoASTNode;
+ std::vector<std::unique_ptr<GoASTStmt> > m_list;
+
+ GoASTBlockStmt(const GoASTBlockStmt &) = delete;
+ const GoASTBlockStmt &operator=(const GoASTBlockStmt &) = delete;
+};
+
+class GoASTIdent : public GoASTExpr
+{
+ public:
+ explicit GoASTIdent(Token name) : GoASTExpr(eIdent), m_name(name) {}
+ ~GoASTIdent() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "Ident";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eIdent;
+ }
+
+ Token
+ GetName() const
+ {
+ return m_name;
+ }
+ void
+ SetName(Token name)
+ {
+ m_name = name;
+ }
+
+ private:
+ friend class GoASTNode;
+ Token m_name;
+
+ GoASTIdent(const GoASTIdent &) = delete;
+ const GoASTIdent &operator=(const GoASTIdent &) = delete;
+};
+
+class GoASTBranchStmt : public GoASTStmt
+{
+ public:
+ GoASTBranchStmt(GoASTIdent *label, TokenType tok) : GoASTStmt(eBranchStmt), m_label_up(label), m_tok(tok) {}
+ ~GoASTBranchStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "BranchStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eBranchStmt;
+ }
+
+ const GoASTIdent *
+ GetLabel() const
+ {
+ return m_label_up.get();
+ }
+ void
+ SetLabel(GoASTIdent *label)
+ {
+ m_label_up.reset(label);
+ }
+
+ TokenType
+ GetTok() const
+ {
+ return m_tok;
+ }
+ void
+ SetTok(TokenType tok)
+ {
+ m_tok = tok;
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTIdent> m_label_up;
+ TokenType m_tok;
+
+ GoASTBranchStmt(const GoASTBranchStmt &) = delete;
+ const GoASTBranchStmt &operator=(const GoASTBranchStmt &) = delete;
+};
+
+class GoASTCallExpr : public GoASTExpr
+{
+ public:
+ explicit GoASTCallExpr(bool ellipsis) : GoASTExpr(eCallExpr), m_ellipsis(ellipsis) {}
+ ~GoASTCallExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "CallExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eCallExpr;
+ }
+
+ const GoASTExpr *
+ GetFun() const
+ {
+ return m_fun_up.get();
+ }
+ void
+ SetFun(GoASTExpr *fun)
+ {
+ m_fun_up.reset(fun);
+ }
+
+ size_t
+ NumArgs() const
+ {
+ return m_args.size();
+ }
+ const GoASTExpr *
+ GetArgs(int i) const
+ {
+ return m_args[i].get();
+ }
+ void
+ AddArgs(GoASTExpr *args)
+ {
+ m_args.push_back(std::unique_ptr<GoASTExpr>(args));
+ }
+
+ bool
+ GetEllipsis() const
+ {
+ return m_ellipsis;
+ }
+ void
+ SetEllipsis(bool ellipsis)
+ {
+ m_ellipsis = ellipsis;
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_fun_up;
+ std::vector<std::unique_ptr<GoASTExpr> > m_args;
+ bool m_ellipsis;
+
+ GoASTCallExpr(const GoASTCallExpr &) = delete;
+ const GoASTCallExpr &operator=(const GoASTCallExpr &) = delete;
+};
+
+class GoASTCaseClause : public GoASTStmt
+{
+ public:
+ GoASTCaseClause() : GoASTStmt(eCaseClause) {}
+ ~GoASTCaseClause() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "CaseClause";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eCaseClause;
+ }
+
+ size_t
+ NumList() const
+ {
+ return m_list.size();
+ }
+ const GoASTExpr *
+ GetList(int i) const
+ {
+ return m_list[i].get();
+ }
+ void
+ AddList(GoASTExpr *list)
+ {
+ m_list.push_back(std::unique_ptr<GoASTExpr>(list));
+ }
+
+ size_t
+ NumBody() const
+ {
+ return m_body.size();
+ }
+ const GoASTStmt *
+ GetBody(int i) const
+ {
+ return m_body[i].get();
+ }
+ void
+ AddBody(GoASTStmt *body)
+ {
+ m_body.push_back(std::unique_ptr<GoASTStmt>(body));
+ }
+
+ private:
+ friend class GoASTNode;
+ std::vector<std::unique_ptr<GoASTExpr> > m_list;
+ std::vector<std::unique_ptr<GoASTStmt> > m_body;
+
+ GoASTCaseClause(const GoASTCaseClause &) = delete;
+ const GoASTCaseClause &operator=(const GoASTCaseClause &) = delete;
+};
+
+class GoASTChanType : public GoASTExpr
+{
+ public:
+ GoASTChanType(ChanDir dir, GoASTExpr *value) : GoASTExpr(eChanType), m_dir(dir), m_value_up(value) {}
+ ~GoASTChanType() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "ChanType";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eChanType;
+ }
+
+ ChanDir
+ GetDir() const
+ {
+ return m_dir;
+ }
+ void
+ SetDir(ChanDir dir)
+ {
+ m_dir = dir;
+ }
+
+ const GoASTExpr *
+ GetValue() const
+ {
+ return m_value_up.get();
+ }
+ void
+ SetValue(GoASTExpr *value)
+ {
+ m_value_up.reset(value);
+ }
+
+ private:
+ friend class GoASTNode;
+ ChanDir m_dir;
+ std::unique_ptr<GoASTExpr> m_value_up;
+
+ GoASTChanType(const GoASTChanType &) = delete;
+ const GoASTChanType &operator=(const GoASTChanType &) = delete;
+};
+
+class GoASTCommClause : public GoASTStmt
+{
+ public:
+ GoASTCommClause() : GoASTStmt(eCommClause) {}
+ ~GoASTCommClause() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "CommClause";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eCommClause;
+ }
+
+ const GoASTStmt *
+ GetComm() const
+ {
+ return m_comm_up.get();
+ }
+ void
+ SetComm(GoASTStmt *comm)
+ {
+ m_comm_up.reset(comm);
+ }
+
+ size_t
+ NumBody() const
+ {
+ return m_body.size();
+ }
+ const GoASTStmt *
+ GetBody(int i) const
+ {
+ return m_body[i].get();
+ }
+ void
+ AddBody(GoASTStmt *body)
+ {
+ m_body.push_back(std::unique_ptr<GoASTStmt>(body));
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTStmt> m_comm_up;
+ std::vector<std::unique_ptr<GoASTStmt> > m_body;
+
+ GoASTCommClause(const GoASTCommClause &) = delete;
+ const GoASTCommClause &operator=(const GoASTCommClause &) = delete;
+};
+
+class GoASTCompositeLit : public GoASTExpr
+{
+ public:
+ GoASTCompositeLit() : GoASTExpr(eCompositeLit) {}
+ ~GoASTCompositeLit() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "CompositeLit";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eCompositeLit;
+ }
+
+ const GoASTExpr *
+ GetType() const
+ {
+ return m_type_up.get();
+ }
+ void
+ SetType(GoASTExpr *type)
+ {
+ m_type_up.reset(type);
+ }
+
+ size_t
+ NumElts() const
+ {
+ return m_elts.size();
+ }
+ const GoASTExpr *
+ GetElts(int i) const
+ {
+ return m_elts[i].get();
+ }
+ void
+ AddElts(GoASTExpr *elts)
+ {
+ m_elts.push_back(std::unique_ptr<GoASTExpr>(elts));
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_type_up;
+ std::vector<std::unique_ptr<GoASTExpr> > m_elts;
+
+ GoASTCompositeLit(const GoASTCompositeLit &) = delete;
+ const GoASTCompositeLit &operator=(const GoASTCompositeLit &) = delete;
+};
+
+class GoASTDeclStmt : public GoASTStmt
+{
+ public:
+ explicit GoASTDeclStmt(GoASTDecl *decl) : GoASTStmt(eDeclStmt), m_decl_up(decl) {}
+ ~GoASTDeclStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "DeclStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eDeclStmt;
+ }
+
+ const GoASTDecl *
+ GetDecl() const
+ {
+ return m_decl_up.get();
+ }
+ void
+ SetDecl(GoASTDecl *decl)
+ {
+ m_decl_up.reset(decl);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTDecl> m_decl_up;
+
+ GoASTDeclStmt(const GoASTDeclStmt &) = delete;
+ const GoASTDeclStmt &operator=(const GoASTDeclStmt &) = delete;
+};
+
+class GoASTDeferStmt : public GoASTStmt
+{
+ public:
+ explicit GoASTDeferStmt(GoASTCallExpr *call) : GoASTStmt(eDeferStmt), m_call_up(call) {}
+ ~GoASTDeferStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "DeferStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eDeferStmt;
+ }
+
+ const GoASTCallExpr *
+ GetCall() const
+ {
+ return m_call_up.get();
+ }
+ void
+ SetCall(GoASTCallExpr *call)
+ {
+ m_call_up.reset(call);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTCallExpr> m_call_up;
+
+ GoASTDeferStmt(const GoASTDeferStmt &) = delete;
+ const GoASTDeferStmt &operator=(const GoASTDeferStmt &) = delete;
+};
+
+class GoASTEllipsis : public GoASTExpr
+{
+ public:
+ explicit GoASTEllipsis(GoASTExpr *elt) : GoASTExpr(eEllipsis), m_elt_up(elt) {}
+ ~GoASTEllipsis() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "Ellipsis";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eEllipsis;
+ }
+
+ const GoASTExpr *
+ GetElt() const
+ {
+ return m_elt_up.get();
+ }
+ void
+ SetElt(GoASTExpr *elt)
+ {
+ m_elt_up.reset(elt);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_elt_up;
+
+ GoASTEllipsis(const GoASTEllipsis &) = delete;
+ const GoASTEllipsis &operator=(const GoASTEllipsis &) = delete;
+};
+
+class GoASTEmptyStmt : public GoASTStmt
+{
+ public:
+ GoASTEmptyStmt() : GoASTStmt(eEmptyStmt) {}
+ ~GoASTEmptyStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "EmptyStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eEmptyStmt;
+ }
+
+ GoASTEmptyStmt(const GoASTEmptyStmt &) = delete;
+ const GoASTEmptyStmt &operator=(const GoASTEmptyStmt &) = delete;
+};
+
+class GoASTExprStmt : public GoASTStmt
+{
+ public:
+ explicit GoASTExprStmt(GoASTExpr *x) : GoASTStmt(eExprStmt), m_x_up(x) {}
+ ~GoASTExprStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "ExprStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eExprStmt;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+
+ GoASTExprStmt(const GoASTExprStmt &) = delete;
+ const GoASTExprStmt &operator=(const GoASTExprStmt &) = delete;
+};
+
+class GoASTField : public GoASTNode
+{
+ public:
+ GoASTField() : GoASTNode(eField) {}
+ ~GoASTField() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "Field";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eField;
+ }
+
+ size_t
+ NumNames() const
+ {
+ return m_names.size();
+ }
+ const GoASTIdent *
+ GetNames(int i) const
+ {
+ return m_names[i].get();
+ }
+ void
+ AddNames(GoASTIdent *names)
+ {
+ m_names.push_back(std::unique_ptr<GoASTIdent>(names));
+ }
+
+ const GoASTExpr *
+ GetType() const
+ {
+ return m_type_up.get();
+ }
+ void
+ SetType(GoASTExpr *type)
+ {
+ m_type_up.reset(type);
+ }
+
+ const GoASTBasicLit *
+ GetTag() const
+ {
+ return m_tag_up.get();
+ }
+ void
+ SetTag(GoASTBasicLit *tag)
+ {
+ m_tag_up.reset(tag);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::vector<std::unique_ptr<GoASTIdent> > m_names;
+ std::unique_ptr<GoASTExpr> m_type_up;
+ std::unique_ptr<GoASTBasicLit> m_tag_up;
+
+ GoASTField(const GoASTField &) = delete;
+ const GoASTField &operator=(const GoASTField &) = delete;
+};
+
+class GoASTFieldList : public GoASTNode
+{
+ public:
+ GoASTFieldList() : GoASTNode(eFieldList) {}
+ ~GoASTFieldList() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "FieldList";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eFieldList;
+ }
+
+ size_t
+ NumList() const
+ {
+ return m_list.size();
+ }
+ const GoASTField *
+ GetList(int i) const
+ {
+ return m_list[i].get();
+ }
+ void
+ AddList(GoASTField *list)
+ {
+ m_list.push_back(std::unique_ptr<GoASTField>(list));
+ }
+
+ private:
+ friend class GoASTNode;
+ std::vector<std::unique_ptr<GoASTField> > m_list;
+
+ GoASTFieldList(const GoASTFieldList &) = delete;
+ const GoASTFieldList &operator=(const GoASTFieldList &) = delete;
+};
+
+class GoASTForStmt : public GoASTStmt
+{
+ public:
+ GoASTForStmt(GoASTStmt *init, GoASTExpr *cond, GoASTStmt *post, GoASTBlockStmt *body) : GoASTStmt(eForStmt), m_init_up(init), m_cond_up(cond), m_post_up(post), m_body_up(body) {}
+ ~GoASTForStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "ForStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eForStmt;
+ }
+
+ const GoASTStmt *
+ GetInit() const
+ {
+ return m_init_up.get();
+ }
+ void
+ SetInit(GoASTStmt *init)
+ {
+ m_init_up.reset(init);
+ }
+
+ const GoASTExpr *
+ GetCond() const
+ {
+ return m_cond_up.get();
+ }
+ void
+ SetCond(GoASTExpr *cond)
+ {
+ m_cond_up.reset(cond);
+ }
+
+ const GoASTStmt *
+ GetPost() const
+ {
+ return m_post_up.get();
+ }
+ void
+ SetPost(GoASTStmt *post)
+ {
+ m_post_up.reset(post);
+ }
+
+ const GoASTBlockStmt *
+ GetBody() const
+ {
+ return m_body_up.get();
+ }
+ void
+ SetBody(GoASTBlockStmt *body)
+ {
+ m_body_up.reset(body);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTStmt> m_init_up;
+ std::unique_ptr<GoASTExpr> m_cond_up;
+ std::unique_ptr<GoASTStmt> m_post_up;
+ std::unique_ptr<GoASTBlockStmt> m_body_up;
+
+ GoASTForStmt(const GoASTForStmt &) = delete;
+ const GoASTForStmt &operator=(const GoASTForStmt &) = delete;
+};
+
+class GoASTFuncType : public GoASTExpr
+{
+ public:
+ GoASTFuncType(GoASTFieldList *params, GoASTFieldList *results) : GoASTExpr(eFuncType), m_params_up(params), m_results_up(results) {}
+ ~GoASTFuncType() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "FuncType";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eFuncType;
+ }
+
+ const GoASTFieldList *
+ GetParams() const
+ {
+ return m_params_up.get();
+ }
+ void
+ SetParams(GoASTFieldList *params)
+ {
+ m_params_up.reset(params);
+ }
+
+ const GoASTFieldList *
+ GetResults() const
+ {
+ return m_results_up.get();
+ }
+ void
+ SetResults(GoASTFieldList *results)
+ {
+ m_results_up.reset(results);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTFieldList> m_params_up;
+ std::unique_ptr<GoASTFieldList> m_results_up;
+
+ GoASTFuncType(const GoASTFuncType &) = delete;
+ const GoASTFuncType &operator=(const GoASTFuncType &) = delete;
+};
+
+class GoASTFuncDecl : public GoASTDecl
+{
+ public:
+ GoASTFuncDecl(GoASTFieldList *recv, GoASTIdent *name, GoASTFuncType *type, GoASTBlockStmt *body) : GoASTDecl(eFuncDecl), m_recv_up(recv), m_name_up(name), m_type_up(type), m_body_up(body) {}
+ ~GoASTFuncDecl() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "FuncDecl";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eFuncDecl;
+ }
+
+ const GoASTFieldList *
+ GetRecv() const
+ {
+ return m_recv_up.get();
+ }
+ void
+ SetRecv(GoASTFieldList *recv)
+ {
+ m_recv_up.reset(recv);
+ }
+
+ const GoASTIdent *
+ GetName() const
+ {
+ return m_name_up.get();
+ }
+ void
+ SetName(GoASTIdent *name)
+ {
+ m_name_up.reset(name);
+ }
+
+ const GoASTFuncType *
+ GetType() const
+ {
+ return m_type_up.get();
+ }
+ void
+ SetType(GoASTFuncType *type)
+ {
+ m_type_up.reset(type);
+ }
+
+ const GoASTBlockStmt *
+ GetBody() const
+ {
+ return m_body_up.get();
+ }
+ void
+ SetBody(GoASTBlockStmt *body)
+ {
+ m_body_up.reset(body);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTFieldList> m_recv_up;
+ std::unique_ptr<GoASTIdent> m_name_up;
+ std::unique_ptr<GoASTFuncType> m_type_up;
+ std::unique_ptr<GoASTBlockStmt> m_body_up;
+
+ GoASTFuncDecl(const GoASTFuncDecl &) = delete;
+ const GoASTFuncDecl &operator=(const GoASTFuncDecl &) = delete;
+};
+
+class GoASTFuncLit : public GoASTExpr
+{
+ public:
+ GoASTFuncLit(GoASTFuncType *type, GoASTBlockStmt *body) : GoASTExpr(eFuncLit), m_type_up(type), m_body_up(body) {}
+ ~GoASTFuncLit() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "FuncLit";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eFuncLit;
+ }
+
+ const GoASTFuncType *
+ GetType() const
+ {
+ return m_type_up.get();
+ }
+ void
+ SetType(GoASTFuncType *type)
+ {
+ m_type_up.reset(type);
+ }
+
+ const GoASTBlockStmt *
+ GetBody() const
+ {
+ return m_body_up.get();
+ }
+ void
+ SetBody(GoASTBlockStmt *body)
+ {
+ m_body_up.reset(body);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTFuncType> m_type_up;
+ std::unique_ptr<GoASTBlockStmt> m_body_up;
+
+ GoASTFuncLit(const GoASTFuncLit &) = delete;
+ const GoASTFuncLit &operator=(const GoASTFuncLit &) = delete;
+};
+
+class GoASTGenDecl : public GoASTDecl
+{
+ public:
+ explicit GoASTGenDecl(TokenType tok) : GoASTDecl(eGenDecl), m_tok(tok) {}
+ ~GoASTGenDecl() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "GenDecl";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eGenDecl;
+ }
+
+ TokenType
+ GetTok() const
+ {
+ return m_tok;
+ }
+ void
+ SetTok(TokenType tok)
+ {
+ m_tok = tok;
+ }
+
+ size_t
+ NumSpecs() const
+ {
+ return m_specs.size();
+ }
+ const GoASTSpec *
+ GetSpecs(int i) const
+ {
+ return m_specs[i].get();
+ }
+ void
+ AddSpecs(GoASTSpec *specs)
+ {
+ m_specs.push_back(std::unique_ptr<GoASTSpec>(specs));
+ }
+
+ private:
+ friend class GoASTNode;
+ TokenType m_tok;
+ std::vector<std::unique_ptr<GoASTSpec> > m_specs;
+
+ GoASTGenDecl(const GoASTGenDecl &) = delete;
+ const GoASTGenDecl &operator=(const GoASTGenDecl &) = delete;
+};
+
+class GoASTGoStmt : public GoASTStmt
+{
+ public:
+ explicit GoASTGoStmt(GoASTCallExpr *call) : GoASTStmt(eGoStmt), m_call_up(call) {}
+ ~GoASTGoStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "GoStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eGoStmt;
+ }
+
+ const GoASTCallExpr *
+ GetCall() const
+ {
+ return m_call_up.get();
+ }
+ void
+ SetCall(GoASTCallExpr *call)
+ {
+ m_call_up.reset(call);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTCallExpr> m_call_up;
+
+ GoASTGoStmt(const GoASTGoStmt &) = delete;
+ const GoASTGoStmt &operator=(const GoASTGoStmt &) = delete;
+};
+
+class GoASTIfStmt : public GoASTStmt
+{
+ public:
+ GoASTIfStmt(GoASTStmt *init, GoASTExpr *cond, GoASTBlockStmt *body, GoASTStmt *els) : GoASTStmt(eIfStmt), m_init_up(init), m_cond_up(cond), m_body_up(body), m_els_up(els) {}
+ ~GoASTIfStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "IfStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eIfStmt;
+ }
+
+ const GoASTStmt *
+ GetInit() const
+ {
+ return m_init_up.get();
+ }
+ void
+ SetInit(GoASTStmt *init)
+ {
+ m_init_up.reset(init);
+ }
+
+ const GoASTExpr *
+ GetCond() const
+ {
+ return m_cond_up.get();
+ }
+ void
+ SetCond(GoASTExpr *cond)
+ {
+ m_cond_up.reset(cond);
+ }
+
+ const GoASTBlockStmt *
+ GetBody() const
+ {
+ return m_body_up.get();
+ }
+ void
+ SetBody(GoASTBlockStmt *body)
+ {
+ m_body_up.reset(body);
+ }
+
+ const GoASTStmt *
+ GetEls() const
+ {
+ return m_els_up.get();
+ }
+ void
+ SetEls(GoASTStmt *els)
+ {
+ m_els_up.reset(els);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTStmt> m_init_up;
+ std::unique_ptr<GoASTExpr> m_cond_up;
+ std::unique_ptr<GoASTBlockStmt> m_body_up;
+ std::unique_ptr<GoASTStmt> m_els_up;
+
+ GoASTIfStmt(const GoASTIfStmt &) = delete;
+ const GoASTIfStmt &operator=(const GoASTIfStmt &) = delete;
+};
+
+class GoASTImportSpec : public GoASTSpec
+{
+ public:
+ GoASTImportSpec(GoASTIdent *name, GoASTBasicLit *path) : GoASTSpec(eImportSpec), m_name_up(name), m_path_up(path) {}
+ ~GoASTImportSpec() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "ImportSpec";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eImportSpec;
+ }
+
+ const GoASTIdent *
+ GetName() const
+ {
+ return m_name_up.get();
+ }
+ void
+ SetName(GoASTIdent *name)
+ {
+ m_name_up.reset(name);
+ }
+
+ const GoASTBasicLit *
+ GetPath() const
+ {
+ return m_path_up.get();
+ }
+ void
+ SetPath(GoASTBasicLit *path)
+ {
+ m_path_up.reset(path);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTIdent> m_name_up;
+ std::unique_ptr<GoASTBasicLit> m_path_up;
+
+ GoASTImportSpec(const GoASTImportSpec &) = delete;
+ const GoASTImportSpec &operator=(const GoASTImportSpec &) = delete;
+};
+
+class GoASTIncDecStmt : public GoASTStmt
+{
+ public:
+ GoASTIncDecStmt(GoASTExpr *x, TokenType tok) : GoASTStmt(eIncDecStmt), m_x_up(x), m_tok(tok) {}
+ ~GoASTIncDecStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "IncDecStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eIncDecStmt;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ TokenType
+ GetTok() const
+ {
+ return m_tok;
+ }
+ void
+ SetTok(TokenType tok)
+ {
+ m_tok = tok;
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+ TokenType m_tok;
+
+ GoASTIncDecStmt(const GoASTIncDecStmt &) = delete;
+ const GoASTIncDecStmt &operator=(const GoASTIncDecStmt &) = delete;
+};
+
+class GoASTIndexExpr : public GoASTExpr
+{
+ public:
+ GoASTIndexExpr(GoASTExpr *x, GoASTExpr *index) : GoASTExpr(eIndexExpr), m_x_up(x), m_index_up(index) {}
+ ~GoASTIndexExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "IndexExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eIndexExpr;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ const GoASTExpr *
+ GetIndex() const
+ {
+ return m_index_up.get();
+ }
+ void
+ SetIndex(GoASTExpr *index)
+ {
+ m_index_up.reset(index);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+ std::unique_ptr<GoASTExpr> m_index_up;
+
+ GoASTIndexExpr(const GoASTIndexExpr &) = delete;
+ const GoASTIndexExpr &operator=(const GoASTIndexExpr &) = delete;
+};
+
+class GoASTInterfaceType : public GoASTExpr
+{
+ public:
+ explicit GoASTInterfaceType(GoASTFieldList *methods) : GoASTExpr(eInterfaceType), m_methods_up(methods) {}
+ ~GoASTInterfaceType() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "InterfaceType";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eInterfaceType;
+ }
+
+ const GoASTFieldList *
+ GetMethods() const
+ {
+ return m_methods_up.get();
+ }
+ void
+ SetMethods(GoASTFieldList *methods)
+ {
+ m_methods_up.reset(methods);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTFieldList> m_methods_up;
+
+ GoASTInterfaceType(const GoASTInterfaceType &) = delete;
+ const GoASTInterfaceType &operator=(const GoASTInterfaceType &) = delete;
+};
+
+class GoASTKeyValueExpr : public GoASTExpr
+{
+ public:
+ GoASTKeyValueExpr(GoASTExpr *key, GoASTExpr *value) : GoASTExpr(eKeyValueExpr), m_key_up(key), m_value_up(value) {}
+ ~GoASTKeyValueExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "KeyValueExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eKeyValueExpr;
+ }
+
+ const GoASTExpr *
+ GetKey() const
+ {
+ return m_key_up.get();
+ }
+ void
+ SetKey(GoASTExpr *key)
+ {
+ m_key_up.reset(key);
+ }
+
+ const GoASTExpr *
+ GetValue() const
+ {
+ return m_value_up.get();
+ }
+ void
+ SetValue(GoASTExpr *value)
+ {
+ m_value_up.reset(value);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_key_up;
+ std::unique_ptr<GoASTExpr> m_value_up;
+
+ GoASTKeyValueExpr(const GoASTKeyValueExpr &) = delete;
+ const GoASTKeyValueExpr &operator=(const GoASTKeyValueExpr &) = delete;
+};
+
+class GoASTLabeledStmt : public GoASTStmt
+{
+ public:
+ GoASTLabeledStmt(GoASTIdent *label, GoASTStmt *stmt) : GoASTStmt(eLabeledStmt), m_label_up(label), m_stmt_up(stmt) {}
+ ~GoASTLabeledStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "LabeledStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eLabeledStmt;
+ }
+
+ const GoASTIdent *
+ GetLabel() const
+ {
+ return m_label_up.get();
+ }
+ void
+ SetLabel(GoASTIdent *label)
+ {
+ m_label_up.reset(label);
+ }
+
+ const GoASTStmt *
+ GetStmt() const
+ {
+ return m_stmt_up.get();
+ }
+ void
+ SetStmt(GoASTStmt *stmt)
+ {
+ m_stmt_up.reset(stmt);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTIdent> m_label_up;
+ std::unique_ptr<GoASTStmt> m_stmt_up;
+
+ GoASTLabeledStmt(const GoASTLabeledStmt &) = delete;
+ const GoASTLabeledStmt &operator=(const GoASTLabeledStmt &) = delete;
+};
+
+class GoASTMapType : public GoASTExpr
+{
+ public:
+ GoASTMapType(GoASTExpr *key, GoASTExpr *value) : GoASTExpr(eMapType), m_key_up(key), m_value_up(value) {}
+ ~GoASTMapType() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "MapType";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eMapType;
+ }
+
+ const GoASTExpr *
+ GetKey() const
+ {
+ return m_key_up.get();
+ }
+ void
+ SetKey(GoASTExpr *key)
+ {
+ m_key_up.reset(key);
+ }
+
+ const GoASTExpr *
+ GetValue() const
+ {
+ return m_value_up.get();
+ }
+ void
+ SetValue(GoASTExpr *value)
+ {
+ m_value_up.reset(value);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_key_up;
+ std::unique_ptr<GoASTExpr> m_value_up;
+
+ GoASTMapType(const GoASTMapType &) = delete;
+ const GoASTMapType &operator=(const GoASTMapType &) = delete;
+};
+
+class GoASTParenExpr : public GoASTExpr
+{
+ public:
+ explicit GoASTParenExpr(GoASTExpr *x) : GoASTExpr(eParenExpr), m_x_up(x) {}
+ ~GoASTParenExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "ParenExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eParenExpr;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+
+ GoASTParenExpr(const GoASTParenExpr &) = delete;
+ const GoASTParenExpr &operator=(const GoASTParenExpr &) = delete;
+};
+
+class GoASTRangeStmt : public GoASTStmt
+{
+ public:
+ GoASTRangeStmt(GoASTExpr *key, GoASTExpr *value, bool define, GoASTExpr *x, GoASTBlockStmt *body) : GoASTStmt(eRangeStmt), m_key_up(key), m_value_up(value), m_define(define), m_x_up(x), m_body_up(body) {}
+ ~GoASTRangeStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "RangeStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eRangeStmt;
+ }
+
+ const GoASTExpr *
+ GetKey() const
+ {
+ return m_key_up.get();
+ }
+ void
+ SetKey(GoASTExpr *key)
+ {
+ m_key_up.reset(key);
+ }
+
+ const GoASTExpr *
+ GetValue() const
+ {
+ return m_value_up.get();
+ }
+ void
+ SetValue(GoASTExpr *value)
+ {
+ m_value_up.reset(value);
+ }
+
+ bool
+ GetDefine() const
+ {
+ return m_define;
+ }
+ void
+ SetDefine(bool define)
+ {
+ m_define = define;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ const GoASTBlockStmt *
+ GetBody() const
+ {
+ return m_body_up.get();
+ }
+ void
+ SetBody(GoASTBlockStmt *body)
+ {
+ m_body_up.reset(body);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_key_up;
+ std::unique_ptr<GoASTExpr> m_value_up;
+ bool m_define;
+ std::unique_ptr<GoASTExpr> m_x_up;
+ std::unique_ptr<GoASTBlockStmt> m_body_up;
+
+ GoASTRangeStmt(const GoASTRangeStmt &) = delete;
+ const GoASTRangeStmt &operator=(const GoASTRangeStmt &) = delete;
+};
+
+class GoASTReturnStmt : public GoASTStmt
+{
+ public:
+ GoASTReturnStmt() : GoASTStmt(eReturnStmt) {}
+ ~GoASTReturnStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "ReturnStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eReturnStmt;
+ }
+
+ size_t
+ NumResults() const
+ {
+ return m_results.size();
+ }
+ const GoASTExpr *
+ GetResults(int i) const
+ {
+ return m_results[i].get();
+ }
+ void
+ AddResults(GoASTExpr *results)
+ {
+ m_results.push_back(std::unique_ptr<GoASTExpr>(results));
+ }
+
+ private:
+ friend class GoASTNode;
+ std::vector<std::unique_ptr<GoASTExpr> > m_results;
+
+ GoASTReturnStmt(const GoASTReturnStmt &) = delete;
+ const GoASTReturnStmt &operator=(const GoASTReturnStmt &) = delete;
+};
+
+class GoASTSelectStmt : public GoASTStmt
+{
+ public:
+ explicit GoASTSelectStmt(GoASTBlockStmt *body) : GoASTStmt(eSelectStmt), m_body_up(body) {}
+ ~GoASTSelectStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "SelectStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eSelectStmt;
+ }
+
+ const GoASTBlockStmt *
+ GetBody() const
+ {
+ return m_body_up.get();
+ }
+ void
+ SetBody(GoASTBlockStmt *body)
+ {
+ m_body_up.reset(body);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTBlockStmt> m_body_up;
+
+ GoASTSelectStmt(const GoASTSelectStmt &) = delete;
+ const GoASTSelectStmt &operator=(const GoASTSelectStmt &) = delete;
+};
+
+class GoASTSelectorExpr : public GoASTExpr
+{
+ public:
+ GoASTSelectorExpr(GoASTExpr *x, GoASTIdent *sel) : GoASTExpr(eSelectorExpr), m_x_up(x), m_sel_up(sel) {}
+ ~GoASTSelectorExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "SelectorExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eSelectorExpr;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ const GoASTIdent *
+ GetSel() const
+ {
+ return m_sel_up.get();
+ }
+ void
+ SetSel(GoASTIdent *sel)
+ {
+ m_sel_up.reset(sel);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+ std::unique_ptr<GoASTIdent> m_sel_up;
+
+ GoASTSelectorExpr(const GoASTSelectorExpr &) = delete;
+ const GoASTSelectorExpr &operator=(const GoASTSelectorExpr &) = delete;
+};
+
+class GoASTSendStmt : public GoASTStmt
+{
+ public:
+ GoASTSendStmt(GoASTExpr *chan, GoASTExpr *value) : GoASTStmt(eSendStmt), m_chan_up(chan), m_value_up(value) {}
+ ~GoASTSendStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "SendStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eSendStmt;
+ }
+
+ const GoASTExpr *
+ GetChan() const
+ {
+ return m_chan_up.get();
+ }
+ void
+ SetChan(GoASTExpr *chan)
+ {
+ m_chan_up.reset(chan);
+ }
+
+ const GoASTExpr *
+ GetValue() const
+ {
+ return m_value_up.get();
+ }
+ void
+ SetValue(GoASTExpr *value)
+ {
+ m_value_up.reset(value);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_chan_up;
+ std::unique_ptr<GoASTExpr> m_value_up;
+
+ GoASTSendStmt(const GoASTSendStmt &) = delete;
+ const GoASTSendStmt &operator=(const GoASTSendStmt &) = delete;
+};
+
+class GoASTSliceExpr : public GoASTExpr
+{
+ public:
+ GoASTSliceExpr(GoASTExpr *x, GoASTExpr *low, GoASTExpr *high, GoASTExpr *max, bool slice3) : GoASTExpr(eSliceExpr), m_x_up(x), m_low_up(low), m_high_up(high), m_max_up(max), m_slice3(slice3) {}
+ ~GoASTSliceExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "SliceExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eSliceExpr;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ const GoASTExpr *
+ GetLow() const
+ {
+ return m_low_up.get();
+ }
+ void
+ SetLow(GoASTExpr *low)
+ {
+ m_low_up.reset(low);
+ }
+
+ const GoASTExpr *
+ GetHigh() const
+ {
+ return m_high_up.get();
+ }
+ void
+ SetHigh(GoASTExpr *high)
+ {
+ m_high_up.reset(high);
+ }
+
+ const GoASTExpr *
+ GetMax() const
+ {
+ return m_max_up.get();
+ }
+ void
+ SetMax(GoASTExpr *max)
+ {
+ m_max_up.reset(max);
+ }
+
+ bool
+ GetSlice3() const
+ {
+ return m_slice3;
+ }
+ void
+ SetSlice3(bool slice3)
+ {
+ m_slice3 = slice3;
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+ std::unique_ptr<GoASTExpr> m_low_up;
+ std::unique_ptr<GoASTExpr> m_high_up;
+ std::unique_ptr<GoASTExpr> m_max_up;
+ bool m_slice3;
+
+ GoASTSliceExpr(const GoASTSliceExpr &) = delete;
+ const GoASTSliceExpr &operator=(const GoASTSliceExpr &) = delete;
+};
+
+class GoASTStarExpr : public GoASTExpr
+{
+ public:
+ explicit GoASTStarExpr(GoASTExpr *x) : GoASTExpr(eStarExpr), m_x_up(x) {}
+ ~GoASTStarExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "StarExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eStarExpr;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+
+ GoASTStarExpr(const GoASTStarExpr &) = delete;
+ const GoASTStarExpr &operator=(const GoASTStarExpr &) = delete;
+};
+
+class GoASTStructType : public GoASTExpr
+{
+ public:
+ explicit GoASTStructType(GoASTFieldList *fields) : GoASTExpr(eStructType), m_fields_up(fields) {}
+ ~GoASTStructType() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "StructType";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eStructType;
+ }
+
+ const GoASTFieldList *
+ GetFields() const
+ {
+ return m_fields_up.get();
+ }
+ void
+ SetFields(GoASTFieldList *fields)
+ {
+ m_fields_up.reset(fields);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTFieldList> m_fields_up;
+
+ GoASTStructType(const GoASTStructType &) = delete;
+ const GoASTStructType &operator=(const GoASTStructType &) = delete;
+};
+
+class GoASTSwitchStmt : public GoASTStmt
+{
+ public:
+ GoASTSwitchStmt(GoASTStmt *init, GoASTExpr *tag, GoASTBlockStmt *body) : GoASTStmt(eSwitchStmt), m_init_up(init), m_tag_up(tag), m_body_up(body) {}
+ ~GoASTSwitchStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "SwitchStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eSwitchStmt;
+ }
+
+ const GoASTStmt *
+ GetInit() const
+ {
+ return m_init_up.get();
+ }
+ void
+ SetInit(GoASTStmt *init)
+ {
+ m_init_up.reset(init);
+ }
+
+ const GoASTExpr *
+ GetTag() const
+ {
+ return m_tag_up.get();
+ }
+ void
+ SetTag(GoASTExpr *tag)
+ {
+ m_tag_up.reset(tag);
+ }
+
+ const GoASTBlockStmt *
+ GetBody() const
+ {
+ return m_body_up.get();
+ }
+ void
+ SetBody(GoASTBlockStmt *body)
+ {
+ m_body_up.reset(body);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTStmt> m_init_up;
+ std::unique_ptr<GoASTExpr> m_tag_up;
+ std::unique_ptr<GoASTBlockStmt> m_body_up;
+
+ GoASTSwitchStmt(const GoASTSwitchStmt &) = delete;
+ const GoASTSwitchStmt &operator=(const GoASTSwitchStmt &) = delete;
+};
+
+class GoASTTypeAssertExpr : public GoASTExpr
+{
+ public:
+ GoASTTypeAssertExpr(GoASTExpr *x, GoASTExpr *type) : GoASTExpr(eTypeAssertExpr), m_x_up(x), m_type_up(type) {}
+ ~GoASTTypeAssertExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "TypeAssertExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eTypeAssertExpr;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ const GoASTExpr *
+ GetType() const
+ {
+ return m_type_up.get();
+ }
+ void
+ SetType(GoASTExpr *type)
+ {
+ m_type_up.reset(type);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTExpr> m_x_up;
+ std::unique_ptr<GoASTExpr> m_type_up;
+
+ GoASTTypeAssertExpr(const GoASTTypeAssertExpr &) = delete;
+ const GoASTTypeAssertExpr &operator=(const GoASTTypeAssertExpr &) = delete;
+};
+
+class GoASTTypeSpec : public GoASTSpec
+{
+ public:
+ GoASTTypeSpec(GoASTIdent *name, GoASTExpr *type) : GoASTSpec(eTypeSpec), m_name_up(name), m_type_up(type) {}
+ ~GoASTTypeSpec() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "TypeSpec";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eTypeSpec;
+ }
+
+ const GoASTIdent *
+ GetName() const
+ {
+ return m_name_up.get();
+ }
+ void
+ SetName(GoASTIdent *name)
+ {
+ m_name_up.reset(name);
+ }
+
+ const GoASTExpr *
+ GetType() const
+ {
+ return m_type_up.get();
+ }
+ void
+ SetType(GoASTExpr *type)
+ {
+ m_type_up.reset(type);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTIdent> m_name_up;
+ std::unique_ptr<GoASTExpr> m_type_up;
+
+ GoASTTypeSpec(const GoASTTypeSpec &) = delete;
+ const GoASTTypeSpec &operator=(const GoASTTypeSpec &) = delete;
+};
+
+class GoASTTypeSwitchStmt : public GoASTStmt
+{
+ public:
+ GoASTTypeSwitchStmt(GoASTStmt *init, GoASTStmt *assign, GoASTBlockStmt *body) : GoASTStmt(eTypeSwitchStmt), m_init_up(init), m_assign_up(assign), m_body_up(body) {}
+ ~GoASTTypeSwitchStmt() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "TypeSwitchStmt";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eTypeSwitchStmt;
+ }
+
+ const GoASTStmt *
+ GetInit() const
+ {
+ return m_init_up.get();
+ }
+ void
+ SetInit(GoASTStmt *init)
+ {
+ m_init_up.reset(init);
+ }
+
+ const GoASTStmt *
+ GetAssign() const
+ {
+ return m_assign_up.get();
+ }
+ void
+ SetAssign(GoASTStmt *assign)
+ {
+ m_assign_up.reset(assign);
+ }
+
+ const GoASTBlockStmt *
+ GetBody() const
+ {
+ return m_body_up.get();
+ }
+ void
+ SetBody(GoASTBlockStmt *body)
+ {
+ m_body_up.reset(body);
+ }
+
+ private:
+ friend class GoASTNode;
+ std::unique_ptr<GoASTStmt> m_init_up;
+ std::unique_ptr<GoASTStmt> m_assign_up;
+ std::unique_ptr<GoASTBlockStmt> m_body_up;
+
+ GoASTTypeSwitchStmt(const GoASTTypeSwitchStmt &) = delete;
+ const GoASTTypeSwitchStmt &operator=(const GoASTTypeSwitchStmt &) = delete;
+};
+
+class GoASTUnaryExpr : public GoASTExpr
+{
+ public:
+ GoASTUnaryExpr(TokenType op, GoASTExpr *x) : GoASTExpr(eUnaryExpr), m_op(op), m_x_up(x) {}
+ ~GoASTUnaryExpr() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "UnaryExpr";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eUnaryExpr;
+ }
+
+ TokenType
+ GetOp() const
+ {
+ return m_op;
+ }
+ void
+ SetOp(TokenType op)
+ {
+ m_op = op;
+ }
+
+ const GoASTExpr *
+ GetX() const
+ {
+ return m_x_up.get();
+ }
+ void
+ SetX(GoASTExpr *x)
+ {
+ m_x_up.reset(x);
+ }
+
+ private:
+ friend class GoASTNode;
+ TokenType m_op;
+ std::unique_ptr<GoASTExpr> m_x_up;
+
+ GoASTUnaryExpr(const GoASTUnaryExpr &) = delete;
+ const GoASTUnaryExpr &operator=(const GoASTUnaryExpr &) = delete;
+};
+
+class GoASTValueSpec : public GoASTSpec
+{
+ public:
+ GoASTValueSpec() : GoASTSpec(eValueSpec) {}
+ ~GoASTValueSpec() override = default;
+
+ const char *
+ GetKindName() const override
+ {
+ return "ValueSpec";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == eValueSpec;
+ }
+
+ size_t
+ NumNames() const
+ {
+ return m_names.size();
+ }
+ const GoASTIdent *
+ GetNames(int i) const
+ {
+ return m_names[i].get();
+ }
+ void
+ AddNames(GoASTIdent *names)
+ {
+ m_names.push_back(std::unique_ptr<GoASTIdent>(names));
+ }
+
+ const GoASTExpr *
+ GetType() const
+ {
+ return m_type_up.get();
+ }
+ void
+ SetType(GoASTExpr *type)
+ {
+ m_type_up.reset(type);
+ }
+
+ size_t
+ NumValues() const
+ {
+ return m_values.size();
+ }
+ const GoASTExpr *
+ GetValues(int i) const
+ {
+ return m_values[i].get();
+ }
+ void
+ AddValues(GoASTExpr *values)
+ {
+ m_values.push_back(std::unique_ptr<GoASTExpr>(values));
+ }
+
+ private:
+ friend class GoASTNode;
+ std::vector<std::unique_ptr<GoASTIdent> > m_names;
+ std::unique_ptr<GoASTExpr> m_type_up;
+ std::vector<std::unique_ptr<GoASTExpr> > m_values;
+
+ GoASTValueSpec(const GoASTValueSpec &) = delete;
+ const GoASTValueSpec &operator=(const GoASTValueSpec &) = delete;
+};
+
+
+template <typename R, typename V>
+R GoASTDecl::Visit(V* v) const
+{
+ switch(GetKind())
+ {
+ case eBadDecl:
+ return v->VisitBadDecl(llvm::cast<const GoASTBadDecl>(this));
+ case eFuncDecl:
+ return v->VisitFuncDecl(llvm::cast<const GoASTFuncDecl>(this));
+ case eGenDecl:
+ return v->VisitGenDecl(llvm::cast<const GoASTGenDecl>(this));
+ default:
+ assert(false && "Invalid kind");
+ }
+}
+
+template <typename R, typename V>
+R GoASTExpr::Visit(V* v) const
+{
+ switch(GetKind())
+ {
+ case eArrayType:
+ return v->VisitArrayType(llvm::cast<const GoASTArrayType>(this));
+ case eBadExpr:
+ return v->VisitBadExpr(llvm::cast<const GoASTBadExpr>(this));
+ case eBasicLit:
+ return v->VisitBasicLit(llvm::cast<const GoASTBasicLit>(this));
+ case eBinaryExpr:
+ return v->VisitBinaryExpr(llvm::cast<const GoASTBinaryExpr>(this));
+ case eIdent:
+ return v->VisitIdent(llvm::cast<const GoASTIdent>(this));
+ case eCallExpr:
+ return v->VisitCallExpr(llvm::cast<const GoASTCallExpr>(this));
+ case eChanType:
+ return v->VisitChanType(llvm::cast<const GoASTChanType>(this));
+ case eCompositeLit:
+ return v->VisitCompositeLit(llvm::cast<const GoASTCompositeLit>(this));
+ case eEllipsis:
+ return v->VisitEllipsis(llvm::cast<const GoASTEllipsis>(this));
+ case eFuncType:
+ return v->VisitFuncType(llvm::cast<const GoASTFuncType>(this));
+ case eFuncLit:
+ return v->VisitFuncLit(llvm::cast<const GoASTFuncLit>(this));
+ case eIndexExpr:
+ return v->VisitIndexExpr(llvm::cast<const GoASTIndexExpr>(this));
+ case eInterfaceType:
+ return v->VisitInterfaceType(llvm::cast<const GoASTInterfaceType>(this));
+ case eKeyValueExpr:
+ return v->VisitKeyValueExpr(llvm::cast<const GoASTKeyValueExpr>(this));
+ case eMapType:
+ return v->VisitMapType(llvm::cast<const GoASTMapType>(this));
+ case eParenExpr:
+ return v->VisitParenExpr(llvm::cast<const GoASTParenExpr>(this));
+ case eSelectorExpr:
+ return v->VisitSelectorExpr(llvm::cast<const GoASTSelectorExpr>(this));
+ case eSliceExpr:
+ return v->VisitSliceExpr(llvm::cast<const GoASTSliceExpr>(this));
+ case eStarExpr:
+ return v->VisitStarExpr(llvm::cast<const GoASTStarExpr>(this));
+ case eStructType:
+ return v->VisitStructType(llvm::cast<const GoASTStructType>(this));
+ case eTypeAssertExpr:
+ return v->VisitTypeAssertExpr(llvm::cast<const GoASTTypeAssertExpr>(this));
+ case eUnaryExpr:
+ return v->VisitUnaryExpr(llvm::cast<const GoASTUnaryExpr>(this));
+ default:
+ assert(false && "Invalid kind");
+ }
+}
+
+template <typename R, typename V>
+R GoASTSpec::Visit(V* v) const
+{
+ switch(GetKind())
+ {
+ case eImportSpec:
+ return v->VisitImportSpec(llvm::cast<const GoASTImportSpec>(this));
+ case eTypeSpec:
+ return v->VisitTypeSpec(llvm::cast<const GoASTTypeSpec>(this));
+ case eValueSpec:
+ return v->VisitValueSpec(llvm::cast<const GoASTValueSpec>(this));
+ default:
+ assert(false && "Invalid kind");
+ }
+}
+
+template <typename R, typename V>
+R GoASTStmt::Visit(V* v) const
+{
+ switch(GetKind())
+ {
+ case eAssignStmt:
+ return v->VisitAssignStmt(llvm::cast<const GoASTAssignStmt>(this));
+ case eBadStmt:
+ return v->VisitBadStmt(llvm::cast<const GoASTBadStmt>(this));
+ case eBlockStmt:
+ return v->VisitBlockStmt(llvm::cast<const GoASTBlockStmt>(this));
+ case eBranchStmt:
+ return v->VisitBranchStmt(llvm::cast<const GoASTBranchStmt>(this));
+ case eCaseClause:
+ return v->VisitCaseClause(llvm::cast<const GoASTCaseClause>(this));
+ case eCommClause:
+ return v->VisitCommClause(llvm::cast<const GoASTCommClause>(this));
+ case eDeclStmt:
+ return v->VisitDeclStmt(llvm::cast<const GoASTDeclStmt>(this));
+ case eDeferStmt:
+ return v->VisitDeferStmt(llvm::cast<const GoASTDeferStmt>(this));
+ case eEmptyStmt:
+ return v->VisitEmptyStmt(llvm::cast<const GoASTEmptyStmt>(this));
+ case eExprStmt:
+ return v->VisitExprStmt(llvm::cast<const GoASTExprStmt>(this));
+ case eForStmt:
+ return v->VisitForStmt(llvm::cast<const GoASTForStmt>(this));
+ case eGoStmt:
+ return v->VisitGoStmt(llvm::cast<const GoASTGoStmt>(this));
+ case eIfStmt:
+ return v->VisitIfStmt(llvm::cast<const GoASTIfStmt>(this));
+ case eIncDecStmt:
+ return v->VisitIncDecStmt(llvm::cast<const GoASTIncDecStmt>(this));
+ case eLabeledStmt:
+ return v->VisitLabeledStmt(llvm::cast<const GoASTLabeledStmt>(this));
+ case eRangeStmt:
+ return v->VisitRangeStmt(llvm::cast<const GoASTRangeStmt>(this));
+ case eReturnStmt:
+ return v->VisitReturnStmt(llvm::cast<const GoASTReturnStmt>(this));
+ case eSelectStmt:
+ return v->VisitSelectStmt(llvm::cast<const GoASTSelectStmt>(this));
+ case eSendStmt:
+ return v->VisitSendStmt(llvm::cast<const GoASTSendStmt>(this));
+ case eSwitchStmt:
+ return v->VisitSwitchStmt(llvm::cast<const GoASTSwitchStmt>(this));
+ case eTypeSwitchStmt:
+ return v->VisitTypeSwitchStmt(llvm::cast<const GoASTTypeSwitchStmt>(this));
+ default:
+ assert(false && "Invalid kind");
+ }
+}
+
+template <typename V>
+void GoASTNode::WalkChildren(V &v)
+{
+ switch (m_kind)
+ {
+
+
+ case eArrayType:
+ {
+ GoASTArrayType *n = llvm::cast<GoASTArrayType>(this);
+ (void)n;
+ v(n->m_len_up.get());
+ v(n->m_elt_up.get());
+ return;
+ }
+ case eAssignStmt:
+ {
+ GoASTAssignStmt *n = llvm::cast<GoASTAssignStmt>(this);
+ (void)n;
+ for (auto& e : n->m_lhs) { v(e.get()); }
+ for (auto& e : n->m_rhs) { v(e.get()); }
+ return;
+ }
+ case eBasicLit:
+ {
+ GoASTBasicLit *n = llvm::cast<GoASTBasicLit>(this);
+ (void)n;
+ return;
+ }
+ case eBinaryExpr:
+ {
+ GoASTBinaryExpr *n = llvm::cast<GoASTBinaryExpr>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ v(n->m_y_up.get());
+ return;
+ }
+ case eBlockStmt:
+ {
+ GoASTBlockStmt *n = llvm::cast<GoASTBlockStmt>(this);
+ (void)n;
+ for (auto& e : n->m_list) { v(e.get()); }
+ return;
+ }
+ case eIdent:
+ {
+ GoASTIdent *n = llvm::cast<GoASTIdent>(this);
+ (void)n;
+ return;
+ }
+ case eBranchStmt:
+ {
+ GoASTBranchStmt *n = llvm::cast<GoASTBranchStmt>(this);
+ (void)n;
+ v(n->m_label_up.get());
+ return;
+ }
+ case eCallExpr:
+ {
+ GoASTCallExpr *n = llvm::cast<GoASTCallExpr>(this);
+ (void)n;
+ v(n->m_fun_up.get());
+ for (auto& e : n->m_args) { v(e.get()); }
+ return;
+ }
+ case eCaseClause:
+ {
+ GoASTCaseClause *n = llvm::cast<GoASTCaseClause>(this);
+ (void)n;
+ for (auto& e : n->m_list) { v(e.get()); }
+ for (auto& e : n->m_body) { v(e.get()); }
+ return;
+ }
+ case eChanType:
+ {
+ GoASTChanType *n = llvm::cast<GoASTChanType>(this);
+ (void)n;
+ v(n->m_value_up.get());
+ return;
+ }
+ case eCommClause:
+ {
+ GoASTCommClause *n = llvm::cast<GoASTCommClause>(this);
+ (void)n;
+ v(n->m_comm_up.get());
+ for (auto& e : n->m_body) { v(e.get()); }
+ return;
+ }
+ case eCompositeLit:
+ {
+ GoASTCompositeLit *n = llvm::cast<GoASTCompositeLit>(this);
+ (void)n;
+ v(n->m_type_up.get());
+ for (auto& e : n->m_elts) { v(e.get()); }
+ return;
+ }
+ case eDeclStmt:
+ {
+ GoASTDeclStmt *n = llvm::cast<GoASTDeclStmt>(this);
+ (void)n;
+ v(n->m_decl_up.get());
+ return;
+ }
+ case eDeferStmt:
+ {
+ GoASTDeferStmt *n = llvm::cast<GoASTDeferStmt>(this);
+ (void)n;
+ v(n->m_call_up.get());
+ return;
+ }
+ case eEllipsis:
+ {
+ GoASTEllipsis *n = llvm::cast<GoASTEllipsis>(this);
+ (void)n;
+ v(n->m_elt_up.get());
+ return;
+ }
+ case eExprStmt:
+ {
+ GoASTExprStmt *n = llvm::cast<GoASTExprStmt>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ return;
+ }
+ case eField:
+ {
+ GoASTField *n = llvm::cast<GoASTField>(this);
+ (void)n;
+ for (auto& e : n->m_names) { v(e.get()); }
+ v(n->m_type_up.get());
+ v(n->m_tag_up.get());
+ return;
+ }
+ case eFieldList:
+ {
+ GoASTFieldList *n = llvm::cast<GoASTFieldList>(this);
+ (void)n;
+ for (auto& e : n->m_list) { v(e.get()); }
+ return;
+ }
+ case eForStmt:
+ {
+ GoASTForStmt *n = llvm::cast<GoASTForStmt>(this);
+ (void)n;
+ v(n->m_init_up.get());
+ v(n->m_cond_up.get());
+ v(n->m_post_up.get());
+ v(n->m_body_up.get());
+ return;
+ }
+ case eFuncType:
+ {
+ GoASTFuncType *n = llvm::cast<GoASTFuncType>(this);
+ (void)n;
+ v(n->m_params_up.get());
+ v(n->m_results_up.get());
+ return;
+ }
+ case eFuncDecl:
+ {
+ GoASTFuncDecl *n = llvm::cast<GoASTFuncDecl>(this);
+ (void)n;
+ v(n->m_recv_up.get());
+ v(n->m_name_up.get());
+ v(n->m_type_up.get());
+ v(n->m_body_up.get());
+ return;
+ }
+ case eFuncLit:
+ {
+ GoASTFuncLit *n = llvm::cast<GoASTFuncLit>(this);
+ (void)n;
+ v(n->m_type_up.get());
+ v(n->m_body_up.get());
+ return;
+ }
+ case eGenDecl:
+ {
+ GoASTGenDecl *n = llvm::cast<GoASTGenDecl>(this);
+ (void)n;
+ for (auto& e : n->m_specs) { v(e.get()); }
+ return;
+ }
+ case eGoStmt:
+ {
+ GoASTGoStmt *n = llvm::cast<GoASTGoStmt>(this);
+ (void)n;
+ v(n->m_call_up.get());
+ return;
+ }
+ case eIfStmt:
+ {
+ GoASTIfStmt *n = llvm::cast<GoASTIfStmt>(this);
+ (void)n;
+ v(n->m_init_up.get());
+ v(n->m_cond_up.get());
+ v(n->m_body_up.get());
+ v(n->m_els_up.get());
+ return;
+ }
+ case eImportSpec:
+ {
+ GoASTImportSpec *n = llvm::cast<GoASTImportSpec>(this);
+ (void)n;
+ v(n->m_name_up.get());
+ v(n->m_path_up.get());
+ return;
+ }
+ case eIncDecStmt:
+ {
+ GoASTIncDecStmt *n = llvm::cast<GoASTIncDecStmt>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ return;
+ }
+ case eIndexExpr:
+ {
+ GoASTIndexExpr *n = llvm::cast<GoASTIndexExpr>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ v(n->m_index_up.get());
+ return;
+ }
+ case eInterfaceType:
+ {
+ GoASTInterfaceType *n = llvm::cast<GoASTInterfaceType>(this);
+ (void)n;
+ v(n->m_methods_up.get());
+ return;
+ }
+ case eKeyValueExpr:
+ {
+ GoASTKeyValueExpr *n = llvm::cast<GoASTKeyValueExpr>(this);
+ (void)n;
+ v(n->m_key_up.get());
+ v(n->m_value_up.get());
+ return;
+ }
+ case eLabeledStmt:
+ {
+ GoASTLabeledStmt *n = llvm::cast<GoASTLabeledStmt>(this);
+ (void)n;
+ v(n->m_label_up.get());
+ v(n->m_stmt_up.get());
+ return;
+ }
+ case eMapType:
+ {
+ GoASTMapType *n = llvm::cast<GoASTMapType>(this);
+ (void)n;
+ v(n->m_key_up.get());
+ v(n->m_value_up.get());
+ return;
+ }
+ case eParenExpr:
+ {
+ GoASTParenExpr *n = llvm::cast<GoASTParenExpr>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ return;
+ }
+ case eRangeStmt:
+ {
+ GoASTRangeStmt *n = llvm::cast<GoASTRangeStmt>(this);
+ (void)n;
+ v(n->m_key_up.get());
+ v(n->m_value_up.get());
+ v(n->m_x_up.get());
+ v(n->m_body_up.get());
+ return;
+ }
+ case eReturnStmt:
+ {
+ GoASTReturnStmt *n = llvm::cast<GoASTReturnStmt>(this);
+ (void)n;
+ for (auto& e : n->m_results) { v(e.get()); }
+ return;
+ }
+ case eSelectStmt:
+ {
+ GoASTSelectStmt *n = llvm::cast<GoASTSelectStmt>(this);
+ (void)n;
+ v(n->m_body_up.get());
+ return;
+ }
+ case eSelectorExpr:
+ {
+ GoASTSelectorExpr *n = llvm::cast<GoASTSelectorExpr>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ v(n->m_sel_up.get());
+ return;
+ }
+ case eSendStmt:
+ {
+ GoASTSendStmt *n = llvm::cast<GoASTSendStmt>(this);
+ (void)n;
+ v(n->m_chan_up.get());
+ v(n->m_value_up.get());
+ return;
+ }
+ case eSliceExpr:
+ {
+ GoASTSliceExpr *n = llvm::cast<GoASTSliceExpr>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ v(n->m_low_up.get());
+ v(n->m_high_up.get());
+ v(n->m_max_up.get());
+ return;
+ }
+ case eStarExpr:
+ {
+ GoASTStarExpr *n = llvm::cast<GoASTStarExpr>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ return;
+ }
+ case eStructType:
+ {
+ GoASTStructType *n = llvm::cast<GoASTStructType>(this);
+ (void)n;
+ v(n->m_fields_up.get());
+ return;
+ }
+ case eSwitchStmt:
+ {
+ GoASTSwitchStmt *n = llvm::cast<GoASTSwitchStmt>(this);
+ (void)n;
+ v(n->m_init_up.get());
+ v(n->m_tag_up.get());
+ v(n->m_body_up.get());
+ return;
+ }
+ case eTypeAssertExpr:
+ {
+ GoASTTypeAssertExpr *n = llvm::cast<GoASTTypeAssertExpr>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ v(n->m_type_up.get());
+ return;
+ }
+ case eTypeSpec:
+ {
+ GoASTTypeSpec *n = llvm::cast<GoASTTypeSpec>(this);
+ (void)n;
+ v(n->m_name_up.get());
+ v(n->m_type_up.get());
+ return;
+ }
+ case eTypeSwitchStmt:
+ {
+ GoASTTypeSwitchStmt *n = llvm::cast<GoASTTypeSwitchStmt>(this);
+ (void)n;
+ v(n->m_init_up.get());
+ v(n->m_assign_up.get());
+ v(n->m_body_up.get());
+ return;
+ }
+ case eUnaryExpr:
+ {
+ GoASTUnaryExpr *n = llvm::cast<GoASTUnaryExpr>(this);
+ (void)n;
+ v(n->m_x_up.get());
+ return;
+ }
+ case eValueSpec:
+ {
+ GoASTValueSpec *n = llvm::cast<GoASTValueSpec>(this);
+ (void)n;
+ for (auto& e : n->m_names) { v(e.get()); }
+ v(n->m_type_up.get());
+ for (auto& e : n->m_values) { v(e.get()); }
+ return;
+ }
+
+ case eEmptyStmt:
+ case eBadDecl:
+ case eBadExpr:
+ case eBadStmt:
+ break;
+ }
+}
+
+} // namespace lldb_private
+
+#endif
+
diff --git a/source/Plugins/ExpressionParser/Go/GoLexer.cpp b/source/Plugins/ExpressionParser/Go/GoLexer.cpp
new file mode 100644
index 0000000..6de0f56
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/GoLexer.cpp
@@ -0,0 +1,402 @@
+//===-- GoLexer.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+
+#include "GoLexer.h"
+
+using namespace lldb_private;
+
+llvm::StringMap<GoLexer::TokenType> *GoLexer::m_keywords;
+
+GoLexer::GoLexer(const char *src) : m_src(src), m_end(src + strlen(src)), m_last_token(TOK_INVALID, "")
+{
+}
+
+bool
+GoLexer::SkipWhitespace()
+{
+ bool saw_newline = false;
+ for (; m_src < m_end; ++m_src)
+ {
+ if (*m_src == '\n')
+ saw_newline = true;
+ if (*m_src == '/' && !SkipComment())
+ return saw_newline;
+ else if (!IsWhitespace(*m_src))
+ return saw_newline;
+ }
+ return saw_newline;
+}
+
+bool
+GoLexer::SkipComment()
+{
+ if (m_src[0] == '/' && m_src[1] == '/')
+ {
+ for (const char *c = m_src + 2; c < m_end; ++c)
+ {
+ if (*c == '\n')
+ {
+ m_src = c - 1;
+ return true;
+ }
+ }
+ return true;
+ }
+ else if (m_src[0] == '/' && m_src[1] == '*')
+ {
+ for (const char *c = m_src + 2; c < m_end; ++c)
+ {
+ if (c[0] == '*' && c[1] == '/')
+ {
+ m_src = c + 1;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+const GoLexer::Token &
+GoLexer::Lex()
+{
+ bool newline = SkipWhitespace();
+ const char *start = m_src;
+ m_last_token.m_type = InternalLex(newline);
+ m_last_token.m_value = llvm::StringRef(start, m_src - start);
+ return m_last_token;
+}
+
+GoLexer::TokenType
+GoLexer::InternalLex(bool newline)
+{
+ if (m_src >= m_end)
+ {
+ return TOK_EOF;
+ }
+ if (newline)
+ {
+ switch (m_last_token.m_type)
+ {
+ case TOK_IDENTIFIER:
+ case LIT_FLOAT:
+ case LIT_IMAGINARY:
+ case LIT_INTEGER:
+ case LIT_RUNE:
+ case LIT_STRING:
+ case KEYWORD_BREAK:
+ case KEYWORD_CONTINUE:
+ case KEYWORD_FALLTHROUGH:
+ case KEYWORD_RETURN:
+ case OP_PLUS_PLUS:
+ case OP_MINUS_MINUS:
+ case OP_RPAREN:
+ case OP_RBRACK:
+ case OP_RBRACE:
+ return OP_SEMICOLON;
+ default:
+ break;
+ }
+ }
+ char c = *m_src;
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return DoNumber();
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case '&':
+ case '|':
+ case '^':
+ case '<':
+ case '>':
+ case '!':
+ case ':':
+ case ';':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case ',':
+ case '=':
+ return DoOperator();
+ case '.':
+ if (IsDecimal(m_src[1]))
+ return DoNumber();
+ return DoOperator();
+ case '$':
+ // For lldb persistent vars.
+ return DoIdent();
+ case '"':
+ case '`':
+ return DoString();
+ case '\'':
+ return DoRune();
+ default:
+ break;
+ }
+ if (IsLetterOrDigit(c))
+ return DoIdent();
+ ++m_src;
+ return TOK_INVALID;
+}
+
+GoLexer::TokenType
+GoLexer::DoOperator()
+{
+ TokenType t = TOK_INVALID;
+ if (m_end - m_src > 2)
+ {
+ t = LookupKeyword(llvm::StringRef(m_src, 3));
+ if (t != TOK_INVALID)
+ m_src += 3;
+ }
+ if (t == TOK_INVALID && m_end - m_src > 1)
+ {
+ t = LookupKeyword(llvm::StringRef(m_src, 2));
+ if (t != TOK_INVALID)
+ m_src += 2;
+ }
+ if (t == TOK_INVALID)
+ {
+ t = LookupKeyword(llvm::StringRef(m_src, 1));
+ ++m_src;
+ }
+ return t;
+}
+
+GoLexer::TokenType
+GoLexer::DoIdent()
+{
+ const char *start = m_src++;
+ while (m_src < m_end && IsLetterOrDigit(*m_src))
+ {
+ ++m_src;
+ }
+ TokenType kw = LookupKeyword(llvm::StringRef(start, m_src - start));
+ if (kw != TOK_INVALID)
+ return kw;
+ return TOK_IDENTIFIER;
+}
+
+GoLexer::TokenType
+GoLexer::DoNumber()
+{
+ if (m_src[0] == '0' && (m_src[1] == 'x' || m_src[1] == 'X'))
+ {
+ m_src += 2;
+ while (IsHexChar(*m_src))
+ ++m_src;
+ return LIT_INTEGER;
+ }
+ bool dot_ok = true;
+ bool e_ok = true;
+ while (true)
+ {
+ while (IsDecimal(*m_src))
+ ++m_src;
+ switch (*m_src)
+ {
+ case 'i':
+ ++m_src;
+ return LIT_IMAGINARY;
+ case '.':
+ if (!dot_ok)
+ return LIT_FLOAT;
+ ++m_src;
+ dot_ok = false;
+ break;
+ case 'e':
+ case 'E':
+ if (!e_ok)
+ return LIT_FLOAT;
+ dot_ok = e_ok = false;
+ ++m_src;
+ if (*m_src == '+' || *m_src == '-')
+ ++m_src;
+ break;
+ default:
+ if (dot_ok)
+ return LIT_INTEGER;
+ return LIT_FLOAT;
+ }
+ }
+}
+
+GoLexer::TokenType
+GoLexer::DoRune()
+{
+ while (++m_src < m_end)
+ {
+ switch (*m_src)
+ {
+ case '\'':
+ ++m_src;
+ return LIT_RUNE;
+ case '\n':
+ return TOK_INVALID;
+ case '\\':
+ if (m_src[1] == '\n')
+ return TOK_INVALID;
+ ++m_src;
+ }
+ }
+ return TOK_INVALID;
+}
+
+GoLexer::TokenType
+GoLexer::DoString()
+{
+ if (*m_src == '`')
+ {
+ while (++m_src < m_end)
+ {
+ if (*m_src == '`')
+ {
+ ++m_src;
+ return LIT_STRING;
+ }
+ }
+ return TOK_INVALID;
+ }
+ while (++m_src < m_end)
+ {
+ switch (*m_src)
+ {
+ case '"':
+ ++m_src;
+ return LIT_STRING;
+ case '\n':
+ return TOK_INVALID;
+ case '\\':
+ if (m_src[1] == '\n')
+ return TOK_INVALID;
+ ++m_src;
+ }
+ }
+ return TOK_INVALID;
+}
+
+GoLexer::TokenType
+GoLexer::LookupKeyword(llvm::StringRef id)
+{
+ if (m_keywords == nullptr)
+ m_keywords = InitKeywords();
+ const auto &it = m_keywords->find(id);
+ if (it == m_keywords->end())
+ return TOK_INVALID;
+ return it->second;
+}
+
+llvm::StringRef
+GoLexer::LookupToken(TokenType t)
+{
+ if (m_keywords == nullptr)
+ m_keywords = InitKeywords();
+ for (const auto &e : *m_keywords)
+ {
+ if (e.getValue() == t)
+ return e.getKey();
+ }
+ return "";
+}
+
+llvm::StringMap<GoLexer::TokenType> *
+GoLexer::InitKeywords()
+{
+ auto &result = *new llvm::StringMap<TokenType>(128);
+ result["break"] = KEYWORD_BREAK;
+ result["default"] = KEYWORD_DEFAULT;
+ result["func"] = KEYWORD_FUNC;
+ result["interface"] = KEYWORD_INTERFACE;
+ result["select"] = KEYWORD_SELECT;
+ result["case"] = KEYWORD_CASE;
+ result["defer"] = KEYWORD_DEFER;
+ result["go"] = KEYWORD_GO;
+ result["map"] = KEYWORD_MAP;
+ result["struct"] = KEYWORD_STRUCT;
+ result["chan"] = KEYWORD_CHAN;
+ result["else"] = KEYWORD_ELSE;
+ result["goto"] = KEYWORD_GOTO;
+ result["package"] = KEYWORD_PACKAGE;
+ result["switch"] = KEYWORD_SWITCH;
+ result["const"] = KEYWORD_CONST;
+ result["fallthrough"] = KEYWORD_FALLTHROUGH;
+ result["if"] = KEYWORD_IF;
+ result["range"] = KEYWORD_RANGE;
+ result["type"] = KEYWORD_TYPE;
+ result["continue"] = KEYWORD_CONTINUE;
+ result["for"] = KEYWORD_FOR;
+ result["import"] = KEYWORD_IMPORT;
+ result["return"] = KEYWORD_RETURN;
+ result["var"] = KEYWORD_VAR;
+ result["+"] = OP_PLUS;
+ result["-"] = OP_MINUS;
+ result["*"] = OP_STAR;
+ result["/"] = OP_SLASH;
+ result["%"] = OP_PERCENT;
+ result["&"] = OP_AMP;
+ result["|"] = OP_PIPE;
+ result["^"] = OP_CARET;
+ result["<<"] = OP_LSHIFT;
+ result[">>"] = OP_RSHIFT;
+ result["&^"] = OP_AMP_CARET;
+ result["+="] = OP_PLUS_EQ;
+ result["-="] = OP_MINUS_EQ;
+ result["*="] = OP_STAR_EQ;
+ result["/="] = OP_SLASH_EQ;
+ result["%="] = OP_PERCENT_EQ;
+ result["&="] = OP_AMP_EQ;
+ result["|="] = OP_PIPE_EQ;
+ result["^="] = OP_CARET_EQ;
+ result["<<="] = OP_LSHIFT_EQ;
+ result[">>="] = OP_RSHIFT_EQ;
+ result["&^="] = OP_AMP_CARET_EQ;
+ result["&&"] = OP_AMP_AMP;
+ result["||"] = OP_PIPE_PIPE;
+ result["<-"] = OP_LT_MINUS;
+ result["++"] = OP_PLUS_PLUS;
+ result["--"] = OP_MINUS_MINUS;
+ result["=="] = OP_EQ_EQ;
+ result["<"] = OP_LT;
+ result[">"] = OP_GT;
+ result["="] = OP_EQ;
+ result["!"] = OP_BANG;
+ result["!="] = OP_BANG_EQ;
+ result["<="] = OP_LT_EQ;
+ result[">="] = OP_GT_EQ;
+ result[":="] = OP_COLON_EQ;
+ result["..."] = OP_DOTS;
+ result["("] = OP_LPAREN;
+ result["["] = OP_LBRACK;
+ result["{"] = OP_LBRACE;
+ result[","] = OP_COMMA;
+ result["."] = OP_DOT;
+ result[")"] = OP_RPAREN;
+ result["]"] = OP_RBRACK;
+ result["}"] = OP_RBRACE;
+ result[";"] = OP_SEMICOLON;
+ result[":"] = OP_COLON;
+ return &result;
+}
diff --git a/source/Plugins/ExpressionParser/Go/GoLexer.h b/source/Plugins/ExpressionParser/Go/GoLexer.h
new file mode 100644
index 0000000..e8e1635
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/GoLexer.h
@@ -0,0 +1,201 @@
+//===-- GoLexer.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GoLexer_h
+#define liblldb_GoLexer_h
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringMap.h"
+
+namespace lldb_private
+{
+
+class GoLexer
+{
+ public:
+ explicit GoLexer(const char *src);
+
+ enum TokenType
+ {
+ TOK_EOF,
+ TOK_INVALID,
+ TOK_IDENTIFIER,
+ LIT_INTEGER,
+ LIT_FLOAT,
+ LIT_IMAGINARY,
+ LIT_RUNE,
+ LIT_STRING,
+ KEYWORD_BREAK,
+ KEYWORD_DEFAULT,
+ KEYWORD_FUNC,
+ KEYWORD_INTERFACE,
+ KEYWORD_SELECT,
+ KEYWORD_CASE,
+ KEYWORD_DEFER,
+ KEYWORD_GO,
+ KEYWORD_MAP,
+ KEYWORD_STRUCT,
+ KEYWORD_CHAN,
+ KEYWORD_ELSE,
+ KEYWORD_GOTO,
+ KEYWORD_PACKAGE,
+ KEYWORD_SWITCH,
+ KEYWORD_CONST,
+ KEYWORD_FALLTHROUGH,
+ KEYWORD_IF,
+ KEYWORD_RANGE,
+ KEYWORD_TYPE,
+ KEYWORD_CONTINUE,
+ KEYWORD_FOR,
+ KEYWORD_IMPORT,
+ KEYWORD_RETURN,
+ KEYWORD_VAR,
+ OP_PLUS,
+ OP_MINUS,
+ OP_STAR,
+ OP_SLASH,
+ OP_PERCENT,
+ OP_AMP,
+ OP_PIPE,
+ OP_CARET,
+ OP_LSHIFT,
+ OP_RSHIFT,
+ OP_AMP_CARET,
+ OP_PLUS_EQ,
+ OP_MINUS_EQ,
+ OP_STAR_EQ,
+ OP_SLASH_EQ,
+ OP_PERCENT_EQ,
+ OP_AMP_EQ,
+ OP_PIPE_EQ,
+ OP_CARET_EQ,
+ OP_LSHIFT_EQ,
+ OP_RSHIFT_EQ,
+ OP_AMP_CARET_EQ,
+ OP_AMP_AMP,
+ OP_PIPE_PIPE,
+ OP_LT_MINUS,
+ OP_PLUS_PLUS,
+ OP_MINUS_MINUS,
+ OP_EQ_EQ,
+ OP_LT,
+ OP_GT,
+ OP_EQ,
+ OP_BANG,
+ OP_BANG_EQ,
+ OP_LT_EQ,
+ OP_GT_EQ,
+ OP_COLON_EQ,
+ OP_DOTS,
+ OP_LPAREN,
+ OP_LBRACK,
+ OP_LBRACE,
+ OP_COMMA,
+ OP_DOT,
+ OP_RPAREN,
+ OP_RBRACK,
+ OP_RBRACE,
+ OP_SEMICOLON,
+ OP_COLON,
+ };
+
+ struct Token
+ {
+ explicit Token(TokenType t, llvm::StringRef text) : m_type(t), m_value(text) {}
+ TokenType m_type;
+ llvm::StringRef m_value;
+ };
+
+ const Token &Lex();
+
+ size_t
+ BytesRemaining() const
+ {
+ return m_end - m_src;
+ }
+ llvm::StringRef
+ GetString(int len) const
+ {
+ return llvm::StringRef(m_src, len);
+ }
+
+ static TokenType LookupKeyword(llvm::StringRef id);
+ static llvm::StringRef LookupToken(TokenType t);
+
+ private:
+ bool
+ IsDecimal(char c)
+ {
+ return c >= '0' && c <= '9';
+ }
+ bool
+ IsHexChar(char c)
+ {
+ if (c >= '0' && c <= '9')
+ return true;
+ if (c >= 'A' && c <= 'F')
+ return true;
+ if (c >= 'a' && c <= 'f')
+ return true;
+ return false;
+ }
+ bool
+ IsLetterOrDigit(char c)
+ {
+ if (c >= 'a' && c <= 'z')
+ return true;
+ if (c >= 'A' && c <= 'Z')
+ return true;
+ if (c == '_')
+ return true;
+ if (c >= '0' && c <= '9')
+ return true;
+ // Treat all non-ascii chars as letters for simplicity.
+ return 0 != (c & 0x80);
+ }
+ bool
+ IsWhitespace(char c)
+ {
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ return true;
+ }
+ return false;
+ }
+
+ bool SkipWhitespace();
+ bool SkipComment();
+
+ TokenType InternalLex(bool newline);
+
+ TokenType DoOperator();
+
+ TokenType DoIdent();
+
+ TokenType DoNumber();
+
+ TokenType DoRune();
+
+ TokenType DoString();
+
+ static llvm::StringMap<TokenType> *InitKeywords();
+
+ static llvm::StringMap<TokenType> *m_keywords;
+
+ const char *m_src;
+ const char *m_end;
+ Token m_last_token;
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/source/Plugins/ExpressionParser/Go/GoParser.cpp b/source/Plugins/ExpressionParser/Go/GoParser.cpp
new file mode 100644
index 0000000..0f136f7
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/GoParser.cpp
@@ -0,0 +1,1035 @@
+//===-- GoParser.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+
+#include "GoParser.h"
+
+#include "lldb/Core/Error.h"
+#include "llvm/ADT/SmallString.h"
+#include "Plugins/ExpressionParser/Go/GoAST.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+namespace
+{
+llvm::StringRef
+DescribeToken(GoLexer::TokenType t)
+{
+ switch (t)
+ {
+ case GoLexer::TOK_EOF:
+ return "<eof>";
+ case GoLexer::TOK_IDENTIFIER:
+ return "identifier";
+ case GoLexer::LIT_FLOAT:
+ return "float";
+ case GoLexer::LIT_IMAGINARY:
+ return "imaginary";
+ case GoLexer::LIT_INTEGER:
+ return "integer";
+ case GoLexer::LIT_RUNE:
+ return "rune";
+ case GoLexer::LIT_STRING:
+ return "string";
+ default:
+ return GoLexer::LookupToken(t);
+ }
+}
+} // namespace
+
+class GoParser::Rule
+{
+ public:
+ Rule(llvm::StringRef name, GoParser *p) : m_name(name), m_parser(p), m_pos(p->m_pos) {}
+
+ std::nullptr_t
+ error()
+ {
+ if (!m_parser->m_failed)
+ {
+ // Set m_error in case this is the top level.
+ if (m_parser->m_last_tok == GoLexer::TOK_INVALID)
+ m_parser->m_error = m_parser->m_last;
+ else
+ m_parser->m_error = DescribeToken(m_parser->m_last_tok);
+ // And set m_last in case it isn't.
+ m_parser->m_last = m_name;
+ m_parser->m_last_tok = GoLexer::TOK_INVALID;
+ m_parser->m_pos = m_pos;
+ }
+ return nullptr;
+ }
+
+ private:
+ llvm::StringRef m_name;
+ GoParser *m_parser;
+ size_t m_pos;
+};
+
+GoParser::GoParser(const char *src) : m_lexer(src), m_pos(0), m_failed(false)
+{
+}
+
+GoASTStmt *
+GoParser::Statement()
+{
+ Rule r("Statement", this);
+ GoLexer::TokenType t = peek();
+ GoASTStmt *ret = nullptr;
+ switch (t)
+ {
+ case GoLexer::TOK_EOF:
+ case GoLexer::OP_SEMICOLON:
+ case GoLexer::OP_RPAREN:
+ case GoLexer::OP_RBRACE:
+ case GoLexer::TOK_INVALID:
+ return EmptyStmt();
+ case GoLexer::OP_LBRACE:
+ return Block();
+
+ /* TODO:
+ case GoLexer::KEYWORD_GO:
+ return GoStmt();
+ case GoLexer::KEYWORD_RETURN:
+ return ReturnStmt();
+ case GoLexer::KEYWORD_BREAK:
+ case GoLexer::KEYWORD_CONTINUE:
+ case GoLexer::KEYWORD_GOTO:
+ case GoLexer::KEYWORD_FALLTHROUGH:
+ return BranchStmt();
+ case GoLexer::KEYWORD_IF:
+ return IfStmt();
+ case GoLexer::KEYWORD_SWITCH:
+ return SwitchStmt();
+ case GoLexer::KEYWORD_SELECT:
+ return SelectStmt();
+ case GoLexer::KEYWORD_FOR:
+ return ForStmt();
+ case GoLexer::KEYWORD_DEFER:
+ return DeferStmt();
+ case GoLexer::KEYWORD_CONST:
+ case GoLexer::KEYWORD_TYPE:
+ case GoLexer::KEYWORD_VAR:
+ return DeclStmt();
+ case GoLexer::TOK_IDENTIFIER:
+ if ((ret = LabeledStmt()) ||
+ (ret = ShortVarDecl()))
+ {
+ return ret;
+ }
+*/
+ default:
+ break;
+ }
+ GoASTExpr *expr = Expression();
+ if (expr == nullptr)
+ return r.error();
+ if (/*(ret = SendStmt(expr)) ||*/
+ (ret = IncDecStmt(expr)) || (ret = Assignment(expr)) || (ret = ExpressionStmt(expr)))
+ {
+ return ret;
+ }
+ delete expr;
+ return r.error();
+}
+
+GoASTStmt *
+GoParser::ExpressionStmt(GoASTExpr *e)
+{
+ if (Semicolon())
+ return new GoASTExprStmt(e);
+ return nullptr;
+}
+
+GoASTStmt *
+GoParser::IncDecStmt(GoASTExpr *e)
+{
+ Rule r("IncDecStmt", this);
+ if (match(GoLexer::OP_PLUS_PLUS))
+ return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_PLUS_PLUS) : r.error();
+ if (match(GoLexer::OP_MINUS_MINUS))
+ return Semicolon() ? new GoASTIncDecStmt(e, GoLexer::OP_MINUS_MINUS) : r.error();
+ return nullptr;
+}
+
+GoASTStmt *
+GoParser::Assignment(lldb_private::GoASTExpr *e)
+{
+ Rule r("Assignment", this);
+ std::vector<std::unique_ptr<GoASTExpr>> lhs;
+ for (GoASTExpr *l = MoreExpressionList(); l; l = MoreExpressionList())
+ lhs.push_back(std::unique_ptr<GoASTExpr>(l));
+ switch (peek())
+ {
+ case GoLexer::OP_EQ:
+ case GoLexer::OP_PLUS_EQ:
+ case GoLexer::OP_MINUS_EQ:
+ case GoLexer::OP_PIPE_EQ:
+ case GoLexer::OP_CARET_EQ:
+ case GoLexer::OP_STAR_EQ:
+ case GoLexer::OP_SLASH_EQ:
+ case GoLexer::OP_PERCENT_EQ:
+ case GoLexer::OP_LSHIFT_EQ:
+ case GoLexer::OP_RSHIFT_EQ:
+ case GoLexer::OP_AMP_EQ:
+ case GoLexer::OP_AMP_CARET_EQ:
+ break;
+ default:
+ return r.error();
+ }
+ // We don't want to own e until we know this is an assignment.
+ std::unique_ptr<GoASTAssignStmt> stmt(new GoASTAssignStmt(false));
+ stmt->AddLhs(e);
+ for (auto &l : lhs)
+ stmt->AddLhs(l.release());
+ for (GoASTExpr *r = Expression(); r; r = MoreExpressionList())
+ stmt->AddRhs(r);
+ if (!Semicolon() || stmt->NumRhs() == 0)
+ return new GoASTBadStmt;
+ return stmt.release();
+}
+
+GoASTStmt *
+GoParser::EmptyStmt()
+{
+ if (match(GoLexer::TOK_EOF))
+ return nullptr;
+ if (Semicolon())
+ return new GoASTEmptyStmt;
+ return nullptr;
+}
+
+GoASTStmt *
+GoParser::GoStmt()
+{
+ if (match(GoLexer::KEYWORD_GO))
+ {
+ if (GoASTCallExpr *e = llvm::dyn_cast_or_null<GoASTCallExpr>(Expression()))
+ {
+ return FinishStmt(new GoASTGoStmt(e));
+ }
+ m_last = "call expression";
+ m_failed = true;
+ return new GoASTBadStmt();
+ }
+ return nullptr;
+}
+
+GoASTStmt *
+GoParser::ReturnStmt()
+{
+ if (match(GoLexer::KEYWORD_RETURN))
+ {
+ std::unique_ptr<GoASTReturnStmt> r(new GoASTReturnStmt());
+ for (GoASTExpr *e = Expression(); e; e = MoreExpressionList())
+ r->AddResults(e);
+ return FinishStmt(r.release());
+ }
+ return nullptr;
+}
+
+GoASTStmt *
+GoParser::BranchStmt()
+{
+ GoLexer::Token *tok;
+ if ((tok = match(GoLexer::KEYWORD_BREAK)) || (tok = match(GoLexer::KEYWORD_CONTINUE)) ||
+ (tok = match(GoLexer::KEYWORD_GOTO)))
+ {
+ auto *e = Identifier();
+ if (tok->m_type == GoLexer::KEYWORD_GOTO && !e)
+ return syntaxerror();
+ return FinishStmt(new GoASTBranchStmt(e, tok->m_type));
+ }
+ if ((tok = match(GoLexer::KEYWORD_FALLTHROUGH)))
+ return FinishStmt(new GoASTBranchStmt(nullptr, tok->m_type));
+
+ return nullptr;
+}
+
+GoASTIdent *
+GoParser::Identifier()
+{
+ if (auto *tok = match(GoLexer::TOK_IDENTIFIER))
+ return new GoASTIdent(*tok);
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::MoreExpressionList()
+{
+ if (match(GoLexer::OP_COMMA))
+ {
+ auto *e = Expression();
+ if (!e)
+ return syntaxerror();
+ return e;
+ }
+ return nullptr;
+}
+
+GoASTIdent *
+GoParser::MoreIdentifierList()
+{
+ if (match(GoLexer::OP_COMMA))
+ {
+ auto *i = Identifier();
+ if (!i)
+ return syntaxerror();
+ return i;
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::Expression()
+{
+ Rule r("Expression", this);
+ if (GoASTExpr *ret = OrExpr())
+ return ret;
+ return r.error();
+}
+
+GoASTExpr *
+GoParser::UnaryExpr()
+{
+ switch (peek())
+ {
+ case GoLexer::OP_PLUS:
+ case GoLexer::OP_MINUS:
+ case GoLexer::OP_BANG:
+ case GoLexer::OP_CARET:
+ case GoLexer::OP_STAR:
+ case GoLexer::OP_AMP:
+ case GoLexer::OP_LT_MINUS:
+ {
+ const GoLexer::Token t = next();
+ if (GoASTExpr *e = UnaryExpr())
+ {
+ if (t.m_type == GoLexer::OP_STAR)
+ return new GoASTStarExpr(e);
+ else
+ return new GoASTUnaryExpr(t.m_type, e);
+ }
+ return syntaxerror();
+ }
+ default:
+ return PrimaryExpr();
+ }
+}
+
+GoASTExpr *
+GoParser::OrExpr()
+{
+ std::unique_ptr<GoASTExpr> l(AndExpr());
+ if (l)
+ {
+ while (match(GoLexer::OP_PIPE_PIPE))
+ {
+ GoASTExpr *r = AndExpr();
+ if (r)
+ l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_PIPE_PIPE));
+ else
+ return syntaxerror();
+ }
+ return l.release();
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::AndExpr()
+{
+ std::unique_ptr<GoASTExpr> l(RelExpr());
+ if (l)
+ {
+ while (match(GoLexer::OP_AMP_AMP))
+ {
+ GoASTExpr *r = RelExpr();
+ if (r)
+ l.reset(new GoASTBinaryExpr(l.release(), r, GoLexer::OP_AMP_AMP));
+ else
+ return syntaxerror();
+ }
+ return l.release();
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::RelExpr()
+{
+ std::unique_ptr<GoASTExpr> l(AddExpr());
+ if (l)
+ {
+ for (GoLexer::Token *t; (t = match(GoLexer::OP_EQ_EQ)) || (t = match(GoLexer::OP_BANG_EQ)) ||
+ (t = match(GoLexer::OP_LT)) || (t = match(GoLexer::OP_LT_EQ)) ||
+ (t = match(GoLexer::OP_GT)) || (t = match(GoLexer::OP_GT_EQ));)
+ {
+ GoLexer::TokenType op = t->m_type;
+ GoASTExpr *r = AddExpr();
+ if (r)
+ l.reset(new GoASTBinaryExpr(l.release(), r, op));
+ else
+ return syntaxerror();
+ }
+ return l.release();
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::AddExpr()
+{
+ std::unique_ptr<GoASTExpr> l(MulExpr());
+ if (l)
+ {
+ for (GoLexer::Token *t; (t = match(GoLexer::OP_PLUS)) || (t = match(GoLexer::OP_MINUS)) ||
+ (t = match(GoLexer::OP_PIPE)) || (t = match(GoLexer::OP_CARET));)
+ {
+ GoLexer::TokenType op = t->m_type;
+ GoASTExpr *r = MulExpr();
+ if (r)
+ l.reset(new GoASTBinaryExpr(l.release(), r, op));
+ else
+ return syntaxerror();
+ }
+ return l.release();
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::MulExpr()
+{
+ std::unique_ptr<GoASTExpr> l(UnaryExpr());
+ if (l)
+ {
+ for (GoLexer::Token *t; (t = match(GoLexer::OP_STAR)) || (t = match(GoLexer::OP_SLASH)) ||
+ (t = match(GoLexer::OP_PERCENT)) || (t = match(GoLexer::OP_LSHIFT)) ||
+ (t = match(GoLexer::OP_RSHIFT)) || (t = match(GoLexer::OP_AMP)) ||
+ (t = match(GoLexer::OP_AMP_CARET));)
+ {
+ GoLexer::TokenType op = t->m_type;
+ GoASTExpr *r = UnaryExpr();
+ if (r)
+ l.reset(new GoASTBinaryExpr(l.release(), r, op));
+ else
+ return syntaxerror();
+ }
+ return l.release();
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::PrimaryExpr()
+{
+ GoASTExpr *l;
+ GoASTExpr *r;
+ (l = Conversion()) || (l = Operand());
+ if (!l)
+ return nullptr;
+ while ((r = Selector(l)) || (r = IndexOrSlice(l)) || (r = TypeAssertion(l)) || (r = Arguments(l)))
+ {
+ l = r;
+ }
+ return l;
+}
+
+GoASTExpr *
+GoParser::Operand()
+{
+ GoLexer::Token *lit;
+ if ((lit = match(GoLexer::LIT_INTEGER)) || (lit = match(GoLexer::LIT_FLOAT)) ||
+ (lit = match(GoLexer::LIT_IMAGINARY)) || (lit = match(GoLexer::LIT_RUNE)) || (lit = match(GoLexer::LIT_STRING)))
+ return new GoASTBasicLit(*lit);
+ if (match(GoLexer::OP_LPAREN))
+ {
+ GoASTExpr *e;
+ if (!((e = Expression()) && match(GoLexer::OP_RPAREN)))
+ return syntaxerror();
+ return e;
+ }
+ // MethodExpr should be handled by Selector
+ if (GoASTExpr *e = CompositeLit())
+ return e;
+ if (GoASTExpr *n = Name())
+ return n;
+ return FunctionLit();
+}
+
+GoASTExpr *
+GoParser::FunctionLit()
+{
+ if (!match(GoLexer::KEYWORD_FUNC))
+ return nullptr;
+ auto *sig = Signature();
+ if (!sig)
+ return syntaxerror();
+ auto *body = Block();
+ if (!body)
+ {
+ delete sig;
+ return syntaxerror();
+ }
+ return new GoASTFuncLit(sig, body);
+}
+
+GoASTBlockStmt *
+GoParser::Block()
+{
+ if (!match(GoLexer::OP_LBRACE))
+ return nullptr;
+ std::unique_ptr<GoASTBlockStmt> block(new GoASTBlockStmt);
+ for (auto *s = Statement(); s; s = Statement())
+ block->AddList(s);
+ if (!match(GoLexer::OP_RBRACE))
+ return syntaxerror();
+ return block.release();
+}
+
+GoASTExpr *
+GoParser::CompositeLit()
+{
+ Rule r("CompositeLit", this);
+ GoASTExpr *type;
+ (type = StructType()) || (type = ArrayOrSliceType(true)) || (type = MapType()) || (type = Name());
+ if (!type)
+ return r.error();
+ GoASTCompositeLit *lit = LiteralValue();
+ if (!lit)
+ return r.error();
+ lit->SetType(type);
+ return lit;
+}
+
+GoASTCompositeLit *
+GoParser::LiteralValue()
+{
+ if (!match(GoLexer::OP_LBRACE))
+ return nullptr;
+ std::unique_ptr<GoASTCompositeLit> lit(new GoASTCompositeLit);
+ for (GoASTExpr *e = Element(); e; e = Element())
+ {
+ lit->AddElts(e);
+ if (!match(GoLexer::OP_COMMA))
+ break;
+ }
+ if (!mustMatch(GoLexer::OP_RBRACE))
+ return nullptr;
+ return lit.release();
+}
+
+GoASTExpr *
+GoParser::Element()
+{
+ GoASTExpr *key;
+ if (!((key = Expression()) || (key = LiteralValue())))
+ return nullptr;
+ if (!match(GoLexer::OP_COLON))
+ return key;
+ GoASTExpr *value;
+ if ((value = Expression()) || (value = LiteralValue()))
+ return new GoASTKeyValueExpr(key, value);
+ delete key;
+ return syntaxerror();
+}
+
+GoASTExpr *
+GoParser::Selector(GoASTExpr *e)
+{
+ Rule r("Selector", this);
+ if (match(GoLexer::OP_DOT))
+ {
+ if (auto *name = Identifier())
+ return new GoASTSelectorExpr(e, name);
+ }
+ return r.error();
+}
+
+GoASTExpr *
+GoParser::IndexOrSlice(GoASTExpr *e)
+{
+ Rule r("IndexOrSlice", this);
+ if (match(GoLexer::OP_LBRACK))
+ {
+ std::unique_ptr<GoASTExpr> i1(Expression()), i2, i3;
+ bool slice = false;
+ if (match(GoLexer::OP_COLON))
+ {
+ slice = true;
+ i2.reset(Expression());
+ if (i2 && match(GoLexer::OP_COLON))
+ {
+ i3.reset(Expression());
+ if (!i3)
+ return syntaxerror();
+ }
+ }
+ if (!(slice || i1))
+ return syntaxerror();
+ if (!mustMatch(GoLexer::OP_RBRACK))
+ return nullptr;
+ if (slice)
+ {
+ bool slice3 = i3.get();
+ return new GoASTSliceExpr(e, i1.release(), i2.release(), i3.release(), slice3);
+ }
+ return new GoASTIndexExpr(e, i1.release());
+ }
+ return r.error();
+}
+
+GoASTExpr *
+GoParser::TypeAssertion(GoASTExpr *e)
+{
+ Rule r("TypeAssertion", this);
+ if (match(GoLexer::OP_DOT) && match(GoLexer::OP_LPAREN))
+ {
+ if (auto *t = Type())
+ {
+ if (!mustMatch(GoLexer::OP_RPAREN))
+ return nullptr;
+ return new GoASTTypeAssertExpr(e, t);
+ }
+ return syntaxerror();
+ }
+ return r.error();
+}
+
+GoASTExpr *
+GoParser::Arguments(GoASTExpr *e)
+{
+ if (match(GoLexer::OP_LPAREN))
+ {
+ std::unique_ptr<GoASTCallExpr> call(new GoASTCallExpr(false));
+ GoASTExpr *arg;
+ // ( ExpressionList | Type [ "," ExpressionList ] )
+ for ((arg = Expression()) || (arg = Type()); arg; arg = MoreExpressionList())
+ {
+ call->AddArgs(arg);
+ }
+ if (match(GoLexer::OP_DOTS))
+ call->SetEllipsis(true);
+
+ // Eat trailing comma
+ match(GoLexer::OP_COMMA);
+
+ if (!mustMatch(GoLexer::OP_RPAREN))
+ return nullptr;
+ call->SetFun(e);
+ return call.release();
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::Conversion()
+{
+ Rule r("Conversion", this);
+ if (GoASTExpr *t = Type2())
+ {
+ if (match(GoLexer::OP_LPAREN))
+ {
+ GoASTExpr *v = Expression();
+ if (!v)
+ return syntaxerror();
+ match(GoLexer::OP_COMMA);
+ if (!mustMatch(GoLexer::OP_RPAREN))
+ return r.error();
+ GoASTCallExpr *call = new GoASTCallExpr(false);
+ call->SetFun(t);
+ call->AddArgs(v);
+ return call;
+ }
+ }
+ return r.error();
+}
+
+GoASTExpr *
+GoParser::Type2()
+{
+ switch (peek())
+ {
+ case GoLexer::OP_LBRACK:
+ return ArrayOrSliceType(false);
+ case GoLexer::KEYWORD_STRUCT:
+ return StructType();
+ case GoLexer::KEYWORD_FUNC:
+ return FunctionType();
+ case GoLexer::KEYWORD_INTERFACE:
+ return InterfaceType();
+ case GoLexer::KEYWORD_MAP:
+ return MapType();
+ case GoLexer::KEYWORD_CHAN:
+ return ChanType2();
+ default:
+ return nullptr;
+ }
+}
+
+GoASTExpr *
+GoParser::ArrayOrSliceType(bool allowEllipsis)
+{
+ Rule r("ArrayType", this);
+ if (match(GoLexer::OP_LBRACK))
+ {
+ std::unique_ptr<GoASTExpr> len;
+ if (allowEllipsis && match(GoLexer::OP_DOTS))
+ {
+ len.reset(new GoASTEllipsis(nullptr));
+ }
+ else
+ {
+ len.reset(Expression());
+ }
+
+ if (!match(GoLexer::OP_RBRACK))
+ return r.error();
+ GoASTExpr *elem = Type();
+ if (!elem)
+ return syntaxerror();
+ return new GoASTArrayType(len.release(), elem);
+ }
+ return r.error();
+}
+
+GoASTExpr *
+GoParser::StructType()
+{
+ if (!(match(GoLexer::KEYWORD_STRUCT) && mustMatch(GoLexer::OP_LBRACE)))
+ return nullptr;
+ std::unique_ptr<GoASTFieldList> fields(new GoASTFieldList);
+ while (auto *field = FieldDecl())
+ fields->AddList(field);
+ if (!mustMatch(GoLexer::OP_RBRACE))
+ return nullptr;
+ return new GoASTStructType(fields.release());
+}
+
+GoASTField *
+GoParser::FieldDecl()
+{
+ std::unique_ptr<GoASTField> f(new GoASTField);
+ GoASTExpr *t = FieldNamesAndType(f.get());
+ if (!t)
+ t = AnonymousFieldType();
+ if (!t)
+ return nullptr;
+
+ if (auto *tok = match(GoLexer::LIT_STRING))
+ f->SetTag(new GoASTBasicLit(*tok));
+ if (!Semicolon())
+ return syntaxerror();
+ return f.release();
+}
+
+GoASTExpr *
+GoParser::FieldNamesAndType(GoASTField *field)
+{
+ Rule r("FieldNames", this);
+ for (auto *id = Identifier(); id; id = MoreIdentifierList())
+ field->AddNames(id);
+ if (m_failed)
+ return nullptr;
+ GoASTExpr *t = Type();
+ if (t)
+ return t;
+ return r.error();
+}
+
+GoASTExpr *
+GoParser::AnonymousFieldType()
+{
+ bool pointer = match(GoLexer::OP_STAR);
+ GoASTExpr *t = Type();
+ if (!t)
+ return nullptr;
+ if (pointer)
+ return new GoASTStarExpr(t);
+ return t;
+}
+
+GoASTExpr *
+GoParser::FunctionType()
+{
+ if (!match(GoLexer::KEYWORD_FUNC))
+ return nullptr;
+ return Signature();
+}
+
+GoASTFuncType *
+GoParser::Signature()
+{
+ auto *params = Params();
+ if (!params)
+ return syntaxerror();
+ auto *result = Params();
+ if (!result)
+ {
+ if (auto *t = Type())
+ {
+ result = new GoASTFieldList;
+ auto *f = new GoASTField;
+ f->SetType(t);
+ result->AddList(f);
+ }
+ }
+ return new GoASTFuncType(params, result);
+}
+
+GoASTFieldList *
+GoParser::Params()
+{
+ if (!match(GoLexer::OP_LPAREN))
+ return nullptr;
+ std::unique_ptr<GoASTFieldList> l(new GoASTFieldList);
+ while (GoASTField *p = ParamDecl())
+ {
+ l->AddList(p);
+ if (!match(GoLexer::OP_COMMA))
+ break;
+ }
+ if (!mustMatch(GoLexer::OP_RPAREN))
+ return nullptr;
+ return l.release();
+}
+
+GoASTField *
+GoParser::ParamDecl()
+{
+ std::unique_ptr<GoASTField> field(new GoASTField);
+ GoASTIdent *id = Identifier();
+ if (id)
+ {
+ // Try `IdentifierList [ "..." ] Type`.
+ // If that fails, backtrack and try `[ "..." ] Type`.
+ Rule r("NamedParam", this);
+ for (; id; id = MoreIdentifierList())
+ field->AddNames(id);
+ GoASTExpr *t = ParamType();
+ if (t)
+ {
+ field->SetType(t);
+ return field.release();
+ }
+ field.reset(new GoASTField);
+ r.error();
+ }
+ GoASTExpr *t = ParamType();
+ if (t)
+ {
+ field->SetType(t);
+ return field.release();
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::ParamType()
+{
+ bool dots = match(GoLexer::OP_DOTS);
+ GoASTExpr *t = Type();
+ if (!dots)
+ return t;
+ if (!t)
+ return syntaxerror();
+ return new GoASTEllipsis(t);
+}
+
+GoASTExpr *
+GoParser::InterfaceType()
+{
+ if (!match(GoLexer::KEYWORD_INTERFACE) || !mustMatch(GoLexer::OP_LBRACE))
+ return nullptr;
+ std::unique_ptr<GoASTFieldList> methods(new GoASTFieldList);
+ while (true)
+ {
+ Rule r("MethodSpec", this);
+ // ( identifier Signature | TypeName ) ;
+ std::unique_ptr<GoASTIdent> id(Identifier());
+ if (!id)
+ break;
+ GoASTExpr *type = Signature();
+ if (!type)
+ {
+ r.error();
+ id.reset();
+ type = Name();
+ }
+ if (!Semicolon())
+ return syntaxerror();
+ auto *f = new GoASTField;
+ if (id)
+ f->AddNames(id.release());
+ f->SetType(type);
+ methods->AddList(f);
+ }
+ if (!mustMatch(GoLexer::OP_RBRACE))
+ return nullptr;
+ return new GoASTInterfaceType(methods.release());
+}
+
+GoASTExpr *
+GoParser::MapType()
+{
+ if (!(match(GoLexer::KEYWORD_MAP) && mustMatch(GoLexer::OP_LBRACK)))
+ return nullptr;
+ std::unique_ptr<GoASTExpr> key(Type());
+ if (!key)
+ return syntaxerror();
+ if (!mustMatch(GoLexer::OP_RBRACK))
+ return nullptr;
+ auto *elem = Type();
+ if (!elem)
+ return syntaxerror();
+ return new GoASTMapType(key.release(), elem);
+}
+
+GoASTExpr *
+GoParser::ChanType()
+{
+ Rule r("chan", this);
+ if (match(GoLexer::OP_LT_MINUS))
+ {
+ if (match(GoLexer::KEYWORD_CHAN))
+ {
+ auto *elem = Type();
+ if (!elem)
+ return syntaxerror();
+ return new GoASTChanType(GoASTNode::eChanRecv, elem);
+ }
+ return r.error();
+ }
+ return ChanType2();
+}
+
+GoASTExpr *
+GoParser::ChanType2()
+{
+ if (!match(GoLexer::KEYWORD_CHAN))
+ return nullptr;
+ auto dir = GoASTNode::eChanBidir;
+ if (match(GoLexer::OP_LT_MINUS))
+ dir = GoASTNode::eChanSend;
+ auto *elem = Type();
+ if (!elem)
+ return syntaxerror();
+ return new GoASTChanType(dir, elem);
+}
+
+GoASTExpr *
+GoParser::Type()
+{
+ if (GoASTExpr *t = Type2())
+ return t;
+ if (GoASTExpr *t = Name())
+ return t;
+ if (GoASTExpr *t = ChanType())
+ return t;
+ if (match(GoLexer::OP_STAR))
+ {
+ GoASTExpr *t = Type();
+ if (!t)
+ return syntaxerror();
+ return new GoASTStarExpr(t);
+ }
+ if (match(GoLexer::OP_LPAREN))
+ {
+ std::unique_ptr<GoASTExpr> t(Type());
+ if (!t || !match(GoLexer::OP_RPAREN))
+ return syntaxerror();
+ return t.release();
+ }
+ return nullptr;
+}
+
+bool
+GoParser::Semicolon()
+{
+ if (match(GoLexer::OP_SEMICOLON))
+ return true;
+ switch (peek())
+ {
+ case GoLexer::OP_RPAREN:
+ case GoLexer::OP_RBRACE:
+ case GoLexer::TOK_EOF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+GoASTExpr *
+GoParser::Name()
+{
+ if (auto *id = Identifier())
+ {
+ if (GoASTExpr *qual = QualifiedIdent(id))
+ return qual;
+ return id;
+ }
+ return nullptr;
+}
+
+GoASTExpr *
+GoParser::QualifiedIdent(lldb_private::GoASTIdent *p)
+{
+ Rule r("QualifiedIdent", this);
+ llvm::SmallString<32> path(p->GetName().m_value);
+ GoLexer::Token *next;
+ bool have_slashes = false;
+ // LLDB extension: support full/package/path.name
+ while (match(GoLexer::OP_SLASH) && (next = match(GoLexer::TOK_IDENTIFIER)))
+ {
+ have_slashes = true;
+ path.append("/");
+ path.append(next->m_value);
+ }
+ if (match(GoLexer::OP_DOT))
+ {
+ auto *name = Identifier();
+ if (name)
+ {
+ if (have_slashes)
+ {
+ p->SetName(GoLexer::Token(GoLexer::TOK_IDENTIFIER, CopyString(path)));
+ }
+ return new GoASTSelectorExpr(p, name);
+ }
+ }
+ return r.error();
+}
+
+llvm::StringRef
+GoParser::CopyString(llvm::StringRef s)
+{
+ return m_strings.insert(std::make_pair(s, 'x')).first->getKey();
+}
+
+void
+GoParser::GetError(Error &error)
+{
+ llvm::StringRef want;
+ if (m_failed)
+ want = m_last_tok == GoLexer::TOK_INVALID ? DescribeToken(m_last_tok) : m_last;
+ else
+ want = m_error;
+ size_t len = m_lexer.BytesRemaining();
+ if (len > 10)
+ len = 10;
+ llvm::StringRef got;
+ if (len == 0)
+ got = "<eof>";
+ else
+ got = m_lexer.GetString(len);
+ error.SetErrorStringWithFormat("Syntax error: expected %s before '%s'.", want.str().c_str(), got.str().c_str());
+}
diff --git a/source/Plugins/ExpressionParser/Go/GoParser.h b/source/Plugins/ExpressionParser/Go/GoParser.h
new file mode 100644
index 0000000..9ceb670
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/GoParser.h
@@ -0,0 +1,165 @@
+//===-- GoParser.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GoParser_h
+#define liblldb_GoParser_h
+
+#include "lldb/lldb-private.h"
+#include "Plugins/ExpressionParser/Go/GoAST.h"
+#include "Plugins/ExpressionParser/Go/GoLexer.h"
+
+namespace lldb_private
+{
+class GoParser
+{
+ public:
+ explicit GoParser(const char *src);
+
+ GoASTStmt *Statement();
+
+ GoASTStmt *GoStmt();
+ GoASTStmt *ReturnStmt();
+ GoASTStmt *BranchStmt();
+ GoASTStmt *EmptyStmt();
+ GoASTStmt *ExpressionStmt(GoASTExpr *e);
+ GoASTStmt *IncDecStmt(GoASTExpr *e);
+ GoASTStmt *Assignment(GoASTExpr *e);
+ GoASTBlockStmt *Block();
+
+ GoASTExpr *MoreExpressionList(); // ["," Expression]
+ GoASTIdent *MoreIdentifierList(); // ["," Identifier]
+
+ GoASTExpr *Expression();
+ GoASTExpr *UnaryExpr();
+ GoASTExpr *OrExpr();
+ GoASTExpr *AndExpr();
+ GoASTExpr *RelExpr();
+ GoASTExpr *AddExpr();
+ GoASTExpr *MulExpr();
+ GoASTExpr *PrimaryExpr();
+ GoASTExpr *Operand();
+ GoASTExpr *Conversion();
+
+ GoASTExpr *Selector(GoASTExpr *e);
+ GoASTExpr *IndexOrSlice(GoASTExpr *e);
+ GoASTExpr *TypeAssertion(GoASTExpr *e);
+ GoASTExpr *Arguments(GoASTExpr *e);
+
+ GoASTExpr *Type();
+ GoASTExpr *Type2();
+ GoASTExpr *ArrayOrSliceType(bool allowEllipsis);
+ GoASTExpr *StructType();
+ GoASTExpr *FunctionType();
+ GoASTExpr *InterfaceType();
+ GoASTExpr *MapType();
+ GoASTExpr *ChanType();
+ GoASTExpr *ChanType2();
+
+ GoASTExpr *Name();
+ GoASTExpr *QualifiedIdent(GoASTIdent *p);
+ GoASTIdent *Identifier();
+
+ GoASTField *FieldDecl();
+ GoASTExpr *AnonymousFieldType();
+ GoASTExpr *FieldNamesAndType(GoASTField *f);
+
+ GoASTFieldList *Params();
+ GoASTField *ParamDecl();
+ GoASTExpr *ParamType();
+ GoASTFuncType *Signature();
+ GoASTExpr *CompositeLit();
+ GoASTExpr *FunctionLit();
+ GoASTExpr *Element();
+ GoASTCompositeLit *LiteralValue();
+
+ bool
+ Failed() const
+ {
+ return m_failed;
+ }
+ bool
+ AtEOF() const
+ {
+ return m_lexer.BytesRemaining() == 0 && m_pos == m_tokens.size();
+ }
+
+ void GetError(Error &error);
+
+ private:
+ class Rule;
+ friend class Rule;
+
+ std::nullptr_t
+ syntaxerror()
+ {
+ m_failed = true;
+ return nullptr;
+ }
+ GoLexer::Token &
+ next()
+ {
+ if (m_pos >= m_tokens.size())
+ {
+ if (m_pos != 0 &&
+ (m_tokens.back().m_type == GoLexer::TOK_EOF || m_tokens.back().m_type == GoLexer::TOK_INVALID))
+ return m_tokens.back();
+ m_pos = m_tokens.size();
+ m_tokens.push_back(m_lexer.Lex());
+ }
+ return m_tokens[m_pos++];
+ }
+ GoLexer::TokenType
+ peek()
+ {
+ GoLexer::Token &tok = next();
+ --m_pos;
+ return tok.m_type;
+ }
+ GoLexer::Token *
+ match(GoLexer::TokenType t)
+ {
+ GoLexer::Token &tok = next();
+ if (tok.m_type == t)
+ return &tok;
+ --m_pos;
+ m_last_tok = t;
+ return nullptr;
+ }
+ GoLexer::Token *
+ mustMatch(GoLexer::TokenType t)
+ {
+ GoLexer::Token *tok = match(t);
+ if (tok)
+ return tok;
+ return syntaxerror();
+ }
+ bool Semicolon();
+
+ GoASTStmt *
+ FinishStmt(GoASTStmt *s)
+ {
+ if (!Semicolon())
+ m_failed = true;
+ return s;
+ }
+
+ llvm::StringRef CopyString(llvm::StringRef s);
+
+ GoLexer m_lexer;
+ std::vector<GoLexer::Token> m_tokens;
+ size_t m_pos;
+ llvm::StringRef m_error;
+ llvm::StringRef m_last;
+ GoLexer::TokenType m_last_tok;
+ llvm::StringMap<uint8_t> m_strings;
+ bool m_failed;
+};
+}
+
+#endif
diff --git a/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp b/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp
new file mode 100644
index 0000000..3f12a2b
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/GoUserExpression.cpp
@@ -0,0 +1,756 @@
+//===-- GoUserExpression.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+// C++ Includes
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringMap.h"
+
+// Project includes
+#include "GoUserExpression.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataEncoder.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/GoASTContext.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/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallUserExpression.h"
+
+#include "Plugins/ExpressionParser/Go/GoAST.h"
+#include "Plugins/ExpressionParser/Go/GoParser.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+class GoUserExpression::GoInterpreter
+{
+ public:
+ GoInterpreter(ExecutionContext &exe_ctx, const char *expr)
+ : m_exe_ctx(exe_ctx), m_frame(exe_ctx.GetFrameSP()), m_parser(expr)
+ {
+ if (m_frame)
+ {
+ const SymbolContext &ctx = m_frame->GetSymbolContext(eSymbolContextFunction);
+ ConstString fname = ctx.GetFunctionName();
+ if (fname.GetLength() > 0)
+ {
+ size_t dot = fname.GetStringRef().find('.');
+ if (dot != llvm::StringRef::npos)
+ m_package = llvm::StringRef(fname.AsCString(), dot);
+ }
+ }
+ }
+
+ void
+ set_use_dynamic(DynamicValueType use_dynamic)
+ {
+ m_use_dynamic = use_dynamic;
+ }
+
+ bool Parse();
+ lldb::ValueObjectSP Evaluate(ExecutionContext &exe_ctx);
+ lldb::ValueObjectSP EvaluateStatement(const GoASTStmt *s);
+ lldb::ValueObjectSP EvaluateExpr(const GoASTExpr *e);
+
+ ValueObjectSP
+ VisitBadExpr(const GoASTBadExpr *e)
+ {
+ m_parser.GetError(m_error);
+ return nullptr;
+ }
+
+ ValueObjectSP VisitParenExpr(const GoASTParenExpr *e);
+ ValueObjectSP VisitIdent(const GoASTIdent *e);
+ ValueObjectSP VisitStarExpr(const GoASTStarExpr *e);
+ ValueObjectSP VisitSelectorExpr(const GoASTSelectorExpr *e);
+ ValueObjectSP VisitBasicLit(const GoASTBasicLit *e);
+ ValueObjectSP VisitIndexExpr(const GoASTIndexExpr *e);
+ ValueObjectSP VisitUnaryExpr(const GoASTUnaryExpr *e);
+ ValueObjectSP VisitCallExpr(const GoASTCallExpr *e);
+
+ ValueObjectSP
+ VisitTypeAssertExpr(const GoASTTypeAssertExpr *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitBinaryExpr(const GoASTBinaryExpr *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitArrayType(const GoASTArrayType *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitChanType(const GoASTChanType *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitCompositeLit(const GoASTCompositeLit *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitEllipsis(const GoASTEllipsis *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitFuncType(const GoASTFuncType *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitFuncLit(const GoASTFuncLit *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitInterfaceType(const GoASTInterfaceType *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitKeyValueExpr(const GoASTKeyValueExpr *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitMapType(const GoASTMapType *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitSliceExpr(const GoASTSliceExpr *e)
+ {
+ return NotImplemented(e);
+ }
+
+ ValueObjectSP
+ VisitStructType(const GoASTStructType *e)
+ {
+ return NotImplemented(e);
+ }
+
+ CompilerType EvaluateType(const GoASTExpr *e);
+
+ Error &
+ error()
+ {
+ return m_error;
+ }
+
+ private:
+ std::nullptr_t
+ NotImplemented(const GoASTExpr *e)
+ {
+ m_error.SetErrorStringWithFormat("%s node not implemented", e->GetKindName());
+ return nullptr;
+ }
+
+ ExecutionContext m_exe_ctx;
+ lldb::StackFrameSP m_frame;
+ GoParser m_parser;
+ DynamicValueType m_use_dynamic;
+ Error m_error;
+ llvm::StringRef m_package;
+ std::vector<std::unique_ptr<GoASTStmt>> m_statements;
+};
+
+VariableSP
+FindGlobalVariable(TargetSP target, llvm::Twine name)
+{
+ ConstString fullname(name.str());
+ VariableList variable_list;
+ const bool append = true;
+ if (!target)
+ {
+ return nullptr;
+ }
+ const uint32_t match_count = target->GetImages().FindGlobalVariables(fullname, append, 1, variable_list);
+ if (match_count == 1)
+ {
+ return variable_list.GetVariableAtIndex(0);
+ }
+ return nullptr;
+}
+
+CompilerType
+LookupType(TargetSP target, ConstString name)
+{
+ if (!target)
+ return CompilerType();
+ SymbolContext sc;
+ TypeList type_list;
+ uint32_t num_matches = target->GetImages().FindTypes(sc, name, false, 2, type_list);
+ if (num_matches > 0)
+ {
+ return type_list.GetTypeAtIndex(0)->GetFullCompilerType();
+ }
+ return CompilerType();
+}
+
+GoUserExpression::GoUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix,
+ lldb::LanguageType language, ResultType desired_type,
+ const EvaluateExpressionOptions &options)
+ : UserExpression(exe_scope, expr, expr_prefix, language, desired_type, options)
+{
+}
+
+bool
+GoUserExpression::Parse(Stream &error_stream, ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory, bool generate_debug_info)
+{
+ InstallContext(exe_ctx);
+ m_interpreter.reset(new GoInterpreter(exe_ctx, GetUserText()));
+ if (m_interpreter->Parse())
+ return true;
+ const char *error_cstr = m_interpreter->error().AsCString();
+ if (error_cstr && error_cstr[0])
+ error_stream.Printf("error: %s\n", error_cstr);
+ else
+ error_stream.Printf("error: expression can't be interpreted or run\n");
+ return false;
+}
+
+lldb::ExpressionResults
+GoUserExpression::Execute(Stream &error_stream, ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options,
+ lldb::UserExpressionSP &shared_ptr_to_me, lldb::ExpressionVariableSP &result)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy();
+ lldb::ExpressionResults execution_results = lldb::eExpressionSetupError;
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (target == nullptr || process == nullptr || process->GetState() != lldb::eStateStopped)
+ {
+ if (execution_policy == eExecutionPolicyAlways)
+ {
+ if (log)
+ log->Printf("== [GoUserExpression::Evaluate] Expression may not run, but is not constant ==");
+
+ error_stream.Printf("expression needed to run but couldn't");
+
+ return execution_results;
+ }
+ }
+
+ m_interpreter->set_use_dynamic(options.GetUseDynamic());
+ ValueObjectSP result_val_sp = m_interpreter->Evaluate(exe_ctx);
+ Error err = m_interpreter->error();
+ m_interpreter.reset();
+
+ if (!result_val_sp)
+ {
+ const char *error_cstr = err.AsCString();
+ if (error_cstr && error_cstr[0])
+ error_stream.Printf("error: %s\n", error_cstr);
+ else
+ error_stream.Printf("error: expression can't be interpreted or run\n");
+ return lldb::eExpressionDiscarded;
+ }
+ result.reset(new ExpressionVariable(ExpressionVariable::eKindGo));
+ result->m_live_sp = result->m_frozen_sp = result_val_sp;
+ result->m_flags |= ExpressionVariable::EVIsProgramReference;
+ PersistentExpressionState *pv = target->GetPersistentExpressionStateForLanguage(eLanguageTypeGo);
+ if (pv != nullptr)
+ {
+ result->SetName(pv->GetNextPersistentVariableName());
+ pv->AddVariable(result);
+ }
+ return lldb::eExpressionCompleted;
+}
+
+bool
+GoUserExpression::GoInterpreter::Parse()
+{
+ for (std::unique_ptr<GoASTStmt> stmt(m_parser.Statement()); stmt; stmt.reset(m_parser.Statement()))
+ {
+ if (m_parser.Failed())
+ break;
+ m_statements.emplace_back(std::move(stmt));
+ }
+ if (m_parser.Failed() || !m_parser.AtEOF())
+ m_parser.GetError(m_error);
+
+ return m_error.Success();
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::Evaluate(ExecutionContext &exe_ctx)
+{
+ m_exe_ctx = exe_ctx;
+ ValueObjectSP result;
+ for (const std::unique_ptr<GoASTStmt> &stmt : m_statements)
+ {
+ result = EvaluateStatement(stmt.get());
+ if (m_error.Fail())
+ return nullptr;
+ }
+ return result;
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::EvaluateStatement(const lldb_private::GoASTStmt *stmt)
+{
+ ValueObjectSP result;
+ switch (stmt->GetKind())
+ {
+ case GoASTNode::eBlockStmt:
+ {
+ const GoASTBlockStmt *block = llvm::cast<GoASTBlockStmt>(stmt);
+ for (size_t i = 0; i < block->NumList(); ++i)
+ result = EvaluateStatement(block->GetList(i));
+ break;
+ }
+ case GoASTNode::eBadStmt:
+ m_parser.GetError(m_error);
+ break;
+ case GoASTNode::eExprStmt:
+ {
+ const GoASTExprStmt *expr = llvm::cast<GoASTExprStmt>(stmt);
+ return EvaluateExpr(expr->GetX());
+ }
+ default:
+ m_error.SetErrorStringWithFormat("%s node not supported", stmt->GetKindName());
+ }
+ return result;
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::EvaluateExpr(const lldb_private::GoASTExpr *e)
+{
+ if (e)
+ return e->Visit<ValueObjectSP>(this);
+ return ValueObjectSP();
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::VisitParenExpr(const lldb_private::GoASTParenExpr *e)
+{
+ return EvaluateExpr(e->GetX());
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::VisitIdent(const GoASTIdent *e)
+{
+ ValueObjectSP val;
+ if (m_frame)
+ {
+ VariableSP var_sp;
+ std::string varname = e->GetName().m_value.str();
+ if (varname.size() > 1 && varname[0] == '$')
+ {
+ RegisterContextSP reg_ctx_sp = m_frame->GetRegisterContext();
+ const RegisterInfo *reg = reg_ctx_sp->GetRegisterInfoByName(varname.c_str() + 1);
+ if (reg)
+ {
+ std::string type;
+ switch (reg->encoding)
+ {
+ case lldb::eEncodingSint:
+ type.append("int");
+ break;
+ case lldb::eEncodingUint:
+ type.append("uint");
+ break;
+ case lldb::eEncodingIEEE754:
+ type.append("float");
+ break;
+ default:
+ m_error.SetErrorString("Invaild register encoding");
+ return nullptr;
+ }
+ switch (reg->byte_size)
+ {
+ case 8:
+ type.append("64");
+ break;
+ case 4:
+ type.append("32");
+ break;
+ case 2:
+ type.append("16");
+ break;
+ case 1:
+ type.append("8");
+ break;
+ default:
+ m_error.SetErrorString("Invaild register size");
+ return nullptr;
+ }
+ ValueObjectSP regVal =
+ ValueObjectRegister::Create(m_frame.get(), reg_ctx_sp, reg->kinds[eRegisterKindLLDB]);
+ CompilerType goType = LookupType(m_frame->CalculateTarget(), ConstString(type));
+ if (regVal)
+ {
+ regVal = regVal->Cast(goType);
+ return regVal;
+ }
+ }
+ m_error.SetErrorString("Invaild register name");
+ return nullptr;
+ }
+ VariableListSP var_list_sp(m_frame->GetInScopeVariableList(false));
+ if (var_list_sp)
+ {
+ var_sp = var_list_sp->FindVariable(ConstString(varname));
+ if (var_sp)
+ val = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic);
+ else
+ {
+ // When a variable is on the heap instead of the stack, go records a variable
+ // '&x' instead of 'x'.
+ var_sp = var_list_sp->FindVariable(ConstString("&" + varname));
+ if (var_sp)
+ {
+ val = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic);
+ if (val)
+ val = val->Dereference(m_error);
+ if (m_error.Fail())
+ return nullptr;
+ }
+ }
+ }
+ if (!val)
+ {
+ m_error.Clear();
+ TargetSP target = m_frame->CalculateTarget();
+ if (!target)
+ {
+ m_error.SetErrorString("No target");
+ return nullptr;
+ }
+ var_sp = FindGlobalVariable(target, m_package + "." + e->GetName().m_value);
+ if (var_sp)
+ return m_frame->TrackGlobalVariable(var_sp, m_use_dynamic);
+ }
+ }
+ if (!val)
+ m_error.SetErrorStringWithFormat("Unknown variable %s", e->GetName().m_value.str().c_str());
+ return val;
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::VisitStarExpr(const GoASTStarExpr *e)
+{
+ ValueObjectSP target = EvaluateExpr(e->GetX());
+ if (!target)
+ return nullptr;
+ return target->Dereference(m_error);
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::VisitSelectorExpr(const lldb_private::GoASTSelectorExpr *e)
+{
+ ValueObjectSP target = EvaluateExpr(e->GetX());
+ if (target)
+ {
+ if (target->GetCompilerType().IsPointerType())
+ {
+ target = target->Dereference(m_error);
+ if (m_error.Fail())
+ return nullptr;
+ }
+ ConstString field(e->GetSel()->GetName().m_value);
+ ValueObjectSP result = target->GetChildMemberWithName(field, true);
+ if (!result)
+ m_error.SetErrorStringWithFormat("Unknown child %s", field.AsCString());
+ return result;
+ }
+ if (const GoASTIdent *package = llvm::dyn_cast<GoASTIdent>(e->GetX()))
+ {
+ if (VariableSP global = FindGlobalVariable(m_exe_ctx.GetTargetSP(),
+ package->GetName().m_value + "." + e->GetSel()->GetName().m_value))
+ {
+ if (m_frame)
+ {
+ m_error.Clear();
+ return m_frame->GetValueObjectForFrameVariable(global, m_use_dynamic);
+ }
+ }
+ }
+ if (const GoASTBasicLit *packageLit = llvm::dyn_cast<GoASTBasicLit>(e->GetX()))
+ {
+ if (packageLit->GetValue().m_type == GoLexer::LIT_STRING)
+ {
+ std::string value = packageLit->GetValue().m_value.str();
+ value = value.substr(1, value.size() - 2);
+ if (VariableSP global =
+ FindGlobalVariable(m_exe_ctx.GetTargetSP(), value + "." + e->GetSel()->GetName().m_value))
+ {
+ if (m_frame)
+ {
+ m_error.Clear();
+ return m_frame->TrackGlobalVariable(global, m_use_dynamic);
+ }
+ }
+ }
+ }
+ // EvaluateExpr should have already set m_error.
+ return target;
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::VisitBasicLit(const lldb_private::GoASTBasicLit *e)
+{
+ std::string value = e->GetValue().m_value.str();
+ if (e->GetValue().m_type != GoLexer::LIT_INTEGER)
+ {
+ m_error.SetErrorStringWithFormat("Unsupported literal %s", value.c_str());
+ return nullptr;
+ }
+ errno = 0;
+ int64_t intvalue = strtol(value.c_str(), nullptr, 0);
+ if (errno != 0)
+ {
+ m_error.SetErrorToErrno();
+ return nullptr;
+ }
+ DataBufferSP buf(new DataBufferHeap(sizeof(intvalue), 0));
+ TargetSP target = m_exe_ctx.GetTargetSP();
+ if (!target)
+ {
+ m_error.SetErrorString("No target");
+ return nullptr;
+ }
+ ByteOrder order = target->GetArchitecture().GetByteOrder();
+ uint8_t addr_size = target->GetArchitecture().GetAddressByteSize();
+ DataEncoder enc(buf, order, addr_size);
+ enc.PutU64(0, static_cast<uint64_t>(intvalue));
+ DataExtractor data(buf, order, addr_size);
+
+ CompilerType type = LookupType(target, ConstString("int64"));
+ return ValueObject::CreateValueObjectFromData(nullptr, data, m_exe_ctx, type);
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::VisitIndexExpr(const lldb_private::GoASTIndexExpr *e)
+{
+ ValueObjectSP target = EvaluateExpr(e->GetX());
+ if (!target)
+ return nullptr;
+ ValueObjectSP index = EvaluateExpr(e->GetIndex());
+ if (!index)
+ return nullptr;
+ bool is_signed;
+ if (!index->GetCompilerType().IsIntegerType(is_signed))
+ {
+ m_error.SetErrorString("Unsupported index");
+ return nullptr;
+ }
+ size_t idx;
+ if (is_signed)
+ idx = index->GetValueAsSigned(0);
+ else
+ idx = index->GetValueAsUnsigned(0);
+ if (GoASTContext::IsGoSlice(target->GetCompilerType()))
+ {
+ target = target->GetStaticValue();
+ ValueObjectSP cap = target->GetChildMemberWithName(ConstString("cap"), true);
+ if (cap)
+ {
+ uint64_t capval = cap->GetValueAsUnsigned(0);
+ if (idx >= capval)
+ {
+ m_error.SetErrorStringWithFormat("Invalid index %" PRIu64 " , cap = %" PRIu64, uint64_t(idx), capval);
+ return nullptr;
+ }
+ }
+ target = target->GetChildMemberWithName(ConstString("array"), true);
+ if (target && m_use_dynamic != eNoDynamicValues)
+ {
+ ValueObjectSP dynamic = target->GetDynamicValue(m_use_dynamic);
+ if (dynamic)
+ target = dynamic;
+ }
+ if (!target)
+ return nullptr;
+ return target->GetSyntheticArrayMember(idx, true);
+ }
+ return target->GetChildAtIndex(idx, true);
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::VisitUnaryExpr(const GoASTUnaryExpr *e)
+{
+ ValueObjectSP x = EvaluateExpr(e->GetX());
+ if (!x)
+ return nullptr;
+ switch (e->GetOp())
+ {
+ case GoLexer::OP_AMP:
+ {
+ CompilerType type = x->GetCompilerType().GetPointerType();
+ uint64_t address = x->GetAddressOf();
+ return ValueObject::CreateValueObjectFromAddress(nullptr, address, m_exe_ctx, type);
+ }
+ case GoLexer::OP_PLUS:
+ return x;
+ default:
+ m_error.SetErrorStringWithFormat("Operator %s not supported",
+ GoLexer::LookupToken(e->GetOp()).str().c_str());
+ return nullptr;
+ }
+}
+
+CompilerType
+GoUserExpression::GoInterpreter::EvaluateType(const GoASTExpr *e)
+{
+ TargetSP target = m_exe_ctx.GetTargetSP();
+ if (auto *id = llvm::dyn_cast<GoASTIdent>(e))
+ {
+ CompilerType result = LookupType(target, ConstString(id->GetName().m_value));
+ if (result.IsValid())
+ return result;
+ std::string fullname = (m_package + "." + id->GetName().m_value).str();
+ result = LookupType(target, ConstString(fullname));
+ if (!result)
+ m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str());
+ return result;
+ }
+ if (auto *sel = llvm::dyn_cast<GoASTSelectorExpr>(e))
+ {
+ std::string package;
+ if (auto *pkg_node = llvm::dyn_cast<GoASTIdent>(sel->GetX()))
+ {
+ package = pkg_node->GetName().m_value.str();
+ }
+ else if (auto *str_node = llvm::dyn_cast<GoASTBasicLit>(sel->GetX()))
+ {
+ if (str_node->GetValue().m_type == GoLexer::LIT_STRING)
+ {
+ package = str_node->GetValue().m_value.substr(1).str();
+ package.resize(package.length() - 1);
+ }
+ }
+ if (package.empty())
+ {
+ m_error.SetErrorStringWithFormat("Invalid %s in type expression", sel->GetX()->GetKindName());
+ return CompilerType();
+ }
+ std::string fullname = (package + "." + sel->GetSel()->GetName().m_value).str();
+ CompilerType result = LookupType(target, ConstString(fullname));
+ if (!result)
+ m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str());
+ return result;
+ }
+ if (auto *star = llvm::dyn_cast<GoASTStarExpr>(e))
+ {
+ CompilerType elem = EvaluateType(star->GetX());
+ return elem.GetPointerType();
+ }
+ if (auto *paren = llvm::dyn_cast<GoASTParenExpr>(e))
+ return EvaluateType(paren->GetX());
+ if (auto *array = llvm::dyn_cast<GoASTArrayType>(e))
+ {
+ CompilerType elem = EvaluateType(array->GetElt());
+ }
+
+ m_error.SetErrorStringWithFormat("Invalid %s in type expression", e->GetKindName());
+ return CompilerType();
+}
+
+ValueObjectSP
+GoUserExpression::GoInterpreter::VisitCallExpr(const lldb_private::GoASTCallExpr *e)
+{
+ ValueObjectSP x = EvaluateExpr(e->GetFun());
+ if (x || e->NumArgs() != 1)
+ {
+ m_error.SetErrorStringWithFormat("Code execution not supported");
+ return nullptr;
+ }
+ m_error.Clear();
+ CompilerType type = EvaluateType(e->GetFun());
+ if (!type)
+ {
+ return nullptr;
+ }
+ ValueObjectSP value = EvaluateExpr(e->GetArgs(0));
+ if (!value)
+ return nullptr;
+ // TODO: Handle special conversions
+ return value->Cast(type);
+}
+
+GoPersistentExpressionState::GoPersistentExpressionState() : PersistentExpressionState(eKindGo)
+{
+}
+
+ConstString
+GoPersistentExpressionState::GetNextPersistentVariableName()
+{
+ char name_cstr[256];
+ // We can't use the same variable format as clang.
+ ::snprintf(name_cstr, sizeof(name_cstr), "$go%u", m_next_persistent_variable_id++);
+ ConstString name(name_cstr);
+ return name;
+}
+
+void
+GoPersistentExpressionState::RemovePersistentVariable(lldb::ExpressionVariableSP variable)
+{
+ RemoveVariable(variable);
+
+ const char *name = variable->GetName().AsCString();
+
+ if (*(name++) != '$')
+ return;
+ if (*(name++) != 'g')
+ return;
+ if (*(name++) != 'o')
+ return;
+
+ if (strtoul(name, nullptr, 0) == m_next_persistent_variable_id - 1)
+ m_next_persistent_variable_id--;
+}
diff --git a/source/Plugins/ExpressionParser/Go/GoUserExpression.h b/source/Plugins/ExpressionParser/Go/GoUserExpression.h
new file mode 100644
index 0000000..b429c68
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/GoUserExpression.h
@@ -0,0 +1,98 @@
+//===-- GoUserExpression.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GoUserExpression_h_
+#define liblldb_GoUserExpression_h_
+
+// C Includes
+// C++ Includes
+#include <memory>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Expression/UserExpression.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private
+{
+class GoParser;
+
+class GoPersistentExpressionState : public PersistentExpressionState
+{
+ public:
+ GoPersistentExpressionState();
+
+ ConstString GetNextPersistentVariableName() override;
+
+ void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override;
+
+ lldb::addr_t
+ LookupSymbol(const ConstString &name) override
+ {
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ static bool
+ classof(const PersistentExpressionState *pv)
+ {
+ return pv->getKind() == PersistentExpressionState::eKindGo;
+ }
+
+ private:
+ uint32_t m_next_persistent_variable_id; ///< The counter used by GetNextResultName().
+};
+
+//----------------------------------------------------------------------
+/// @class GoUserExpression GoUserExpression.h "lldb/Expression/GoUserExpression.h"
+/// @brief Encapsulates a single expression for use with Go
+///
+/// LLDB uses expressions for various purposes, notably to call functions
+/// and as a backend for the expr command. GoUserExpression encapsulates
+/// the objects needed to parse and interpret an expression.
+//----------------------------------------------------------------------
+class GoUserExpression : public UserExpression
+{
+ public:
+ GoUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix,
+ lldb::LanguageType language, ResultType desired_type, const EvaluateExpressionOptions &options);
+
+ bool
+ Parse(Stream &error_stream, ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory, bool generate_debug_info) override;
+
+ lldb::ExpressionResults
+ Execute(Stream &error_stream, ExecutionContext &exe_ctx,
+ const EvaluateExpressionOptions &options,
+ lldb::UserExpressionSP &shared_ptr_to_me,
+ lldb::ExpressionVariableSP &result) override;
+
+ bool
+ CanInterpret() override
+ {
+ return true;
+ }
+ bool
+ FinalizeJITExecution(Stream &error_stream, ExecutionContext &exe_ctx, lldb::ExpressionVariableSP &result,
+ lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS,
+ lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) override
+ {
+ return true;
+ }
+
+ private:
+ class GoInterpreter;
+ std::unique_ptr<GoInterpreter> m_interpreter;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_GoUserExpression_h_
diff --git a/source/Plugins/ExpressionParser/Go/gen_go_ast.py b/source/Plugins/ExpressionParser/Go/gen_go_ast.py
new file mode 100644
index 0000000..05b589a
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Go/gen_go_ast.py
@@ -0,0 +1,356 @@
+import StringIO
+
+def addNodes():
+ addNode("ArrayType", "Expr", "len", "Expr", "elt", "Expr")
+ addNode("AssignStmt", "Stmt", "lhs", "[]Expr", "rhs", "[]Expr", "define", "bool")
+ addNode("BadDecl", "Decl")
+ addNode("BadExpr", "Expr")
+ addNode("BadStmt", "Stmt")
+ addNode("BasicLit", "Expr", "value", "Token")
+ addNode("BinaryExpr", "Expr", "x", "Expr", "y", "Expr", "op", "TokenType")
+ addNode("BlockStmt", "Stmt", "list", "[]Stmt")
+ addNode("Ident", "Expr", "name", "Token")
+ addNode("BranchStmt", "Stmt", "label", "Ident", "tok", "TokenType")
+ addNode("CallExpr", "Expr", "fun", "Expr", "args", "[]Expr", "ellipsis", "bool")
+ addNode("CaseClause", "Stmt", "list", "[]Expr", "body", "[]Stmt")
+ addNode("ChanType", "Expr", "dir", "ChanDir", "value", "Expr")
+ addNode("CommClause", "Stmt", "comm", "Stmt", "body", "[]Stmt")
+ addNode("CompositeLit", "Expr", "type", "Expr", "elts", "[]Expr")
+ addNode("DeclStmt", "Stmt", "decl", "Decl")
+ addNode("DeferStmt", "Stmt", "call", "CallExpr")
+ addNode("Ellipsis", "Expr", "elt", "Expr")
+ addNode("EmptyStmt", "Stmt")
+ addNode("ExprStmt", "Stmt", "x", "Expr")
+ addNode("Field", "Node", "names", "[]Ident", "type", "Expr", "tag", "BasicLit")
+ addNode("FieldList", "Node", "list", "[]Field")
+ addNode("ForStmt", "Stmt", "init", "Stmt", "cond", "Expr", "post", "Stmt", "body", "BlockStmt")
+ addNode("FuncType", "Expr", "params", "FieldList", "results", "FieldList")
+ addNode("FuncDecl", "Decl", "recv", "FieldList", "name", "Ident", "type", "FuncType", "body", "BlockStmt")
+ addNode("FuncLit", "Expr", "type", "FuncType", "body", "BlockStmt")
+ addNode("GenDecl", "Decl", "tok", "TokenType", "specs", "[]Spec")
+ addNode("GoStmt", "Stmt", "call", "CallExpr")
+ addNode("IfStmt", "Stmt", "init", "Stmt", "cond", "Expr", "body", "BlockStmt", "els", "Stmt")
+ addNode("ImportSpec", "Spec", "name", "Ident", "path", "BasicLit")
+ addNode("IncDecStmt", "Stmt", "x", "Expr", "tok", "TokenType")
+ addNode("IndexExpr", "Expr", "x", "Expr", "index", "Expr")
+ addNode("InterfaceType", "Expr", "methods", "FieldList")
+ addNode("KeyValueExpr", "Expr", "key", "Expr", "value", "Expr")
+ addNode("LabeledStmt", "Stmt", "label", "Ident", "stmt", "Stmt")
+ addNode("MapType", "Expr", "key", "Expr", "value", "Expr")
+ addNode("ParenExpr", "Expr", "x", "Expr")
+ addNode("RangeStmt", "Stmt", "key", "Expr", "value", "Expr", "define", "bool", "x", "Expr", "body", "BlockStmt")
+ addNode("ReturnStmt", "Stmt", "results", "[]Expr")
+ addNode("SelectStmt", "Stmt", "body", "BlockStmt")
+ addNode("SelectorExpr", "Expr", "x", "Expr", "sel", "Ident")
+ addNode("SendStmt", "Stmt", "chan", "Expr", "value", "Expr")
+ addNode("SliceExpr", "Expr", "x", "Expr", "low", "Expr", "high", "Expr", "max", "Expr", "slice3", "bool")
+ addNode("StarExpr", "Expr", "x", "Expr")
+ addNode("StructType", "Expr", "fields", "FieldList")
+ addNode("SwitchStmt", "Stmt", "init", "Stmt", "tag", "Expr", "body", "BlockStmt")
+ addNode("TypeAssertExpr", "Expr", "x", "Expr", "type", "Expr")
+ addNode("TypeSpec", "Spec", "name", "Ident", "type", "Expr")
+ addNode("TypeSwitchStmt", "Stmt", "init", "Stmt", "assign", "Stmt", "body", "BlockStmt")
+ addNode("UnaryExpr", "Expr", "op", "TokenType", "x", "Expr")
+ addNode("ValueSpec", "Spec", "names", "[]Ident", "type", "Expr", "values", "[]Expr")
+ addParent("Decl", "Node")
+ addParent("Expr", "Node")
+ addParent("Spec", "Node")
+ addParent("Stmt", "Node")
+
+
+class Member(object):
+ def __init__(self, name, typename):
+ self.title = name.title()
+ self.sname = name
+ self.mname = 'm_' + name
+ self.is_list = typename.startswith("[]")
+ self.is_value = isValueType(typename)
+ if self.is_value:
+ self.argtype = typename
+ self.mtype = typename
+ elif self.is_list:
+ self.argtype = 'GoAST' + typename[2:]
+ self.mtype = 'std::vector<std::unique_ptr<%s> >' % self.argtype
+ else:
+ self.argtype = 'GoAST' + typename
+ self.mtype = 'std::unique_ptr<%s>' % self.argtype
+ self.mname = self.mname + '_up'
+
+
+kinds = {}
+parentClasses = StringIO.StringIO()
+childClasses = StringIO.StringIO()
+walker = StringIO.StringIO()
+
+def startClass(name, parent, out):
+ out.write("""
+class GoAST%s : public GoAST%s
+{
+ public:
+""" % (name, parent))
+
+def endClass(name, out):
+ out.write("""
+ %(name)s(const %(name)s &) = delete;
+ const %(name)s &operator=(const %(name)s &) = delete;
+};
+""" % {'name': 'GoAST' + name})
+
+def addNode(name, parent, *children):
+ startClass(name, parent, childClasses)
+ l = kinds.setdefault(parent, [])
+ l.append(name)
+ children = createMembers(name, children)
+ addConstructor(name, parent, children)
+ childClasses.write("""
+ const char *
+ GetKindName() const override
+ {
+ return "%(name)s";
+ }
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() == e%(name)s;
+ }
+ """ % {'name':name})
+ addChildren(name, children)
+ endClass(name, childClasses)
+
+def isValueType(typename):
+ if typename[0].islower():
+ return True
+ if typename[0].isupper():
+ return typename.startswith('Token') or typename == 'ChanDir'
+ return False
+
+
+def createMembers(name, children):
+ l = len(children)
+ if (l % 2) != 0:
+ raise Exception("Invalid children for %s: %s" % (name, children))
+ return [Member(children[i], children[i + 1]) for i in xrange(0, l, 2)]
+
+
+def addConstructor(name, parent, children):
+ for c in children:
+ if c.is_list:
+ children = [x for x in children if x.is_value]
+ break
+ childClasses.write(' ')
+ if len(children) == 1:
+ childClasses.write('explicit ')
+ childClasses.write('GoAST%s(' % name)
+ for i in xrange(len(children)):
+ if i > 0:
+ childClasses.write(', ')
+
+ c = children[i]
+ if c.is_value:
+ childClasses.write(c.argtype)
+ childClasses.write(' ')
+ else:
+ childClasses.write('%s *' % c.argtype)
+ childClasses.write(c.sname)
+ childClasses.write(') : GoAST%s(e%s)' % (parent, name))
+ for c in children:
+ childClasses.write(', ')
+ childClasses.write('%(mname)s(%(sname)s)' % c.__dict__)
+ childClasses.write(""" {}
+ ~GoAST%s() override = default;
+""" % name)
+
+
+def addChildren(name, children):
+ if len(children) == 0:
+ return
+ walker.write("""
+ case e%(n)s:
+ {
+ GoAST%(n)s *n = llvm::cast<GoAST%(n)s>(this);
+ (void)n;""" % {'n':name})
+ for c in children:
+ if c.is_list:
+ childClasses.write("""
+ size_t
+ Num%(title)s() const
+ {
+ return %(mname)s.size();
+ }
+ const %(argtype)s *
+ Get%(title)s(int i) const
+ {
+ return %(mname)s[i].get();
+ }
+ void
+ Add%(title)s(%(argtype)s *%(sname)s)
+ {
+ %(mname)s.push_back(std::unique_ptr<%(argtype)s>(%(sname)s));
+ }
+""" % c.__dict__)
+ walker.write("""
+ for (auto& e : n->%s) { v(e.get()); }""" % c.mname)
+ else:
+ const = ''
+ get = ''
+ set = ''
+ t = c.argtype
+ if isValueType(t):
+ set = '%(mname)s = %(sname)s' % c.__dict__
+ t = t + ' '
+ else:
+ t = t + ' *'
+ const = 'const '
+ get = '.get()'
+ set = '%(mname)s.reset(%(sname)s)' % c.__dict__
+ walker.write("""
+ v(n->%s.get());""" % c.mname)
+ childClasses.write("""
+ %(const)s%(type)s
+ Get%(title)s() const
+ {
+ return %(mname)s%(get)s;
+ }
+ void
+ Set%(title)s(%(type)s%(sname)s)
+ {
+ %(set)s;
+ }
+""" % {'const':const, 'title': c.title, 'sname': c.sname, 'get': get, 'set': set, 'type': t, 'mname': c.mname})
+ childClasses.write('\n private:\n friend class GoASTNode;\n')
+ walker.write("""
+ return;
+ }""")
+ for c in children:
+ childClasses.write(' %s %s;\n' %(c.mtype, c.mname))
+
+
+def addParent(name, parent):
+ startClass(name, parent, parentClasses)
+ l = kinds[name]
+ minName = l[0]
+ maxName = l[-1]
+ parentClasses.write(""" template <typename R, typename V> R Visit(V *v) const;
+
+ static bool
+ classof(const GoASTNode *n)
+ {
+ return n->GetKind() >= e%s && n->GetKind() <= e%s;
+ }
+
+ protected:
+ explicit GoAST%s(NodeKind kind) : GoASTNode(kind) { }
+ private:
+""" % (minName, maxName, name))
+ endClass(name, parentClasses)
+
+addNodes()
+
+print """//===-- GoAST.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// DO NOT EDIT.
+// Generated by gen_go_ast.py
+
+#ifndef liblldb_GoAST_h
+#define liblldb_GoAST_h
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "llvm/Support/Casting.h"
+#include "Plugins/ExpressionParser/Go/GoLexer.h"
+
+namespace lldb_private
+{
+
+class GoASTNode
+{
+ public:
+ typedef GoLexer::TokenType TokenType;
+ typedef GoLexer::Token Token;
+ enum ChanDir
+ {
+ eChanBidir,
+ eChanSend,
+ eChanRecv,
+ };
+ enum NodeKind
+ {"""
+for l in kinds.itervalues():
+ for x in l:
+ print " e%s," % x
+print """ };
+
+ virtual ~GoASTNode() = default;
+
+ NodeKind
+ GetKind() const
+ {
+ return m_kind;
+ }
+
+ virtual const char *GetKindName() const = 0;
+
+ template <typename V> void WalkChildren(V &v);
+
+ protected:
+ explicit GoASTNode(NodeKind kind) : m_kind(kind) { }
+
+ private:
+ const NodeKind m_kind;
+
+ GoASTNode(const GoASTNode &) = delete;
+ const GoASTNode &operator=(const GoASTNode &) = delete;
+};
+"""
+
+
+print parentClasses.getvalue()
+print childClasses.getvalue()
+
+for k, l in kinds.iteritems():
+ if k == 'Node':
+ continue
+ print """
+template <typename R, typename V>
+R GoAST%s::Visit(V* v) const
+{
+ switch(GetKind())
+ {""" % k
+ for subtype in l:
+ print """ case e%(n)s:
+ return v->Visit%(n)s(llvm::cast<const GoAST%(n)s>(this));""" % {'n':subtype}
+
+ print """ default:
+ assert(false && "Invalid kind");
+ }
+}"""
+
+print """
+template <typename V>
+void GoASTNode::WalkChildren(V &v)
+{
+ switch (m_kind)
+ {
+"""
+print walker.getvalue()
+print"""
+ case eEmptyStmt:
+ case eBadDecl:
+ case eBadExpr:
+ case eBadStmt:
+ break;
+ }
+}
+
+} // namespace lldb_private
+
+#endif
+"""
OpenPOWER on IntegriCloud