summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Expression
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Expression')
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ASTDumper.cpp132
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ASTResultSynthesizer.cpp512
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ASTStructExtractor.cpp220
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ClangASTSource.cpp1866
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ClangExpressionDeclMap.cpp1956
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ClangExpressionParser.cpp595
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ClangExpressionVariable.cpp136
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ClangFunction.cpp633
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ClangPersistentVariables.cpp89
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ClangUserExpression.cpp1091
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ClangUtilityFunction.cpp169
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp2691
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp142
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp659
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp704
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRForTarget.cpp2879
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp1379
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp758
-rw-r--r--contrib/llvm/tools/lldb/source/Expression/Materializer.cpp1414
19 files changed, 18025 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Expression/ASTDumper.cpp b/contrib/llvm/tools/lldb/source/Expression/ASTDumper.cpp
new file mode 100644
index 0000000..5210d14
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ASTDumper.cpp
@@ -0,0 +1,132 @@
+//===-- 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 "lldb/Core/Log.h"
+#include "lldb/Expression/ASTDumper.h"
+#include "lldb/Symbol/ClangASTType.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::clang_type_t type)
+{
+ m_dump = clang::QualType::getFromOpaquePtr(type).getAsString();
+}
+
+ASTDumper::ASTDumper (const ClangASTType &clang_type)
+{
+ m_dump = clang_type.GetQualType().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/contrib/llvm/tools/lldb/source/Expression/ASTResultSynthesizer.cpp b/contrib/llvm/tools/lldb/source/Expression/ASTResultSynthesizer.cpp
new file mode 100644
index 0000000..76c2577
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ASTResultSynthesizer.cpp
@@ -0,0 +1,512 @@
+//===-- 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 "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/Expression/ClangPersistentVariables.h"
+#include "lldb/Expression/ASTResultSynthesizer.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.take(), 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.take());
+
+ 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))
+ m_target.GetPersistentVariables().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, bool DefinitionRequired)
+{
+ if (m_passthrough)
+ m_passthrough->HandleVTable(RD, DefinitionRequired);
+}
+
+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/contrib/llvm/tools/lldb/source/Expression/ASTStructExtractor.cpp b/contrib/llvm/tools/lldb/source/Expression/ASTStructExtractor.cpp
new file mode 100644
index 0000000..d1f2192
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ASTStructExtractor.cpp
@@ -0,0 +1,220 @@
+//===-- 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 "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"
+#include "lldb/Expression/ASTStructExtractor.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace lldb_private;
+
+ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough,
+ const char *struct_name,
+ ClangFunction &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, bool DefinitionRequired)
+{
+ if (m_passthrough)
+ m_passthrough->HandleVTable(RD, DefinitionRequired);
+}
+
+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/contrib/llvm/tools/lldb/source/Expression/ClangASTSource.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangASTSource.cpp
new file mode 100644
index 0000000..49513d7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ClangASTSource.cpp
@@ -0,0 +1,1866 @@
+//===-- 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 "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/Expression/ASTDumper.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace clang;
+using namespace lldb_private;
+
+ClangASTSource::~ClangASTSource()
+{
+ m_ast_importer->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->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. Not important for now.
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXLiteralOperatorName:
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ // 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,
+ m_ast_context,
+ tag_decl,
+ tag_decl->getName().str().c_str());
+
+ log->Printf(" CTD[%u] Before:", current_id);
+ ASTDumper dumper((Decl*)tag_decl);
+ dumper.ToLog(log, " [CTD] ");
+ }
+
+ if (!m_ast_importer->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->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CTD[%u] Inspecting namespace map %p (%d entries)",
+ current_id,
+ 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 && !found;
+ ++i)
+ {
+ if (log)
+ log->Printf(" CTD[%u] Searching namespace %s in module %s",
+ current_id,
+ i->second.GetNamespaceDecl()->getNameAsString().c_str(),
+ 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;
+
+ ClangASTType clang_type (type->GetClangFullType());
+
+ if (!clang_type)
+ continue;
+
+ const TagType *tag_type = clang_type.GetQualType()->getAs<TagType>();
+
+ if (!tag_type)
+ continue;
+
+ TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
+
+ if (m_ast_importer->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
+ found = true;
+ }
+ }
+ }
+ else
+ {
+ TypeList types;
+
+ SymbolContext null_sc;
+ ConstString name(tag_decl->getName().str().c_str());
+ ClangNamespaceDecl 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;
+
+ ClangASTType clang_type (type->GetClangFullType());
+
+ if (!clang_type)
+ continue;
+
+ const TagType *tag_type = clang_type.GetQualType()->getAs<TagType>();
+
+ if (!tag_type)
+ continue;
+
+ TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
+
+ if (m_ast_importer->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", m_ast_context, interface_decl->getName().str().c_str());
+ log->Printf(" [COID] Before:");
+ ASTDumper dumper((Decl*)interface_decl);
+ dumper.ToLog(log, " [COID] ");
+ }
+
+ m_ast_importer->CompleteObjCInterfaceDecl (interface_decl);
+
+ 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->GetClangFullType());
+ lldb::clang_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;
+}
+
+clang::ExternalLoadResult
+ClangASTSource::FindExternalLexicalDecls (const DeclContext *decl_context,
+ bool (*predicate)(Decl::Kind),
+ 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 ELR_Failure;
+
+ 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 with %s predicate",
+ current_id,
+ m_ast_context,
+ context_named_decl->getNameAsString().c_str(),
+ context_decl->getDeclKindName(),
+ context_decl,
+ (predicate ? "non-null" : "null"));
+ else if(context_decl)
+ log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in (%sDecl*)%p with %s predicate",
+ current_id,
+ m_ast_context,
+ context_decl->getDeclKindName(),
+ context_decl,
+ (predicate ? "non-null" : "null"));
+ else
+ log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in a NULL context with %s predicate",
+ current_id,
+ m_ast_context,
+ (predicate ? "non-null" : "null"));
+ }
+
+ Decl *original_decl = NULL;
+ ASTContext *original_ctx = NULL;
+
+ if (!m_ast_importer->ResolveDeclOrigin(context_decl, &original_decl, &original_ctx))
+ return ELR_Failure;
+
+ if (log)
+ {
+ log->Printf(" FELD[%u] Original decl (ASTContext*)%p (Decl*)%p:", current_id, original_ctx, 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->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 ELR_Failure;
+
+ for (TagDecl::decl_iterator iter = original_decl_context->decls_begin();
+ iter != original_decl_context->decls_end();
+ ++iter)
+ {
+ Decl *decl = *iter;
+
+ if (!predicate || 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->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->RequireCompleteType(copied_field_type);
+ }
+
+ decls.push_back(copied_decl);
+
+ 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 ELR_AlreadyLoaded;
+}
+
+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, 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, 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, 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->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CAS::FEVD[%u] Inspecting namespace map %p (%d entries)",
+ current_id,
+ 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(" CAS::FEVD[%u] Searching namespace %s in module %s",
+ current_id,
+ i->second.GetNamespaceDecl()->getNameAsString().c_str(),
+ 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
+ {
+ ClangNamespaceDecl 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,
+ context.m_namespace_map.get(),
+ (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,
+ ClangNamespaceDecl &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)
+ {
+ ClangNamespaceDecl 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, ClangNamespaceDecl>(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;
+
+ ClangNamespaceDecl 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, ClangNamespaceDecl>(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);
+
+ if (types.GetSize())
+ {
+ lldb::TypeSP type_sp = types.GetTypeAtIndex(0);
+
+ 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>"));
+ }
+
+ ClangASTType full_type = type_sp->GetClangFullType();
+
+ ClangASTType copied_clang_type (GuardedCopyType(full_type));
+
+ if (!copied_clang_type)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a type",
+ current_id);
+
+ break;
+ }
+
+ context.AddTypeDecl(copied_clang_type);
+ }
+ else
+ {
+ 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;
+
+ TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+
+ if (!type_vendor)
+ break;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <ClangASTType> types;
+
+ if (!type_vendor->FindTypes(name,
+ append,
+ max_matches,
+ types))
+ break;
+
+ if (log)
+ {
+ log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\" in the runtime",
+ current_id,
+ name.GetCString());
+ }
+
+ ClangASTType copied_clang_type (GuardedCopyType(types[0]));
+
+ if (!copied_clang_type)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the runtime",
+ current_id);
+
+ break;
+ }
+
+ context.AddTypeDecl(copied_clang_type);
+ }
+ 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);
+
+ ObjCInterfaceDecl::lookup_result result = original_interface_decl->lookup(original_decl_name);
+
+ if (result.empty())
+ return false;
+
+ if (!result[0])
+ return false;
+
+ ObjCMethodDecl *result_method = dyn_cast<ObjCMethodDecl>(result[0]);
+
+ if (!result_method)
+ return false;
+
+ Decl *copied_decl = ast_importer->CopyDecl(ast_context, &result_method->getASTContext(), result_method);
+
+ if (!copied_decl)
+ return false;
+
+ ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
+
+ if (!copied_method_decl)
+ return false;
+
+ 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->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,
+ "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();
+
+ ConstString selector_name(ss.GetData());
+
+ if (log)
+ log->Printf("ClangASTSource::FindObjCMethodDecls[%d] on (ASTContext*)%p for selector [%s %s]",
+ current_id,
+ 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;
+
+ DeclContext *function_ctx = sc.function->GetClangDeclContext();
+
+ if (!function_ctx)
+ continue;
+
+ ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(function_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->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,
+ complete_interface_decl,
+ &complete_iface_decl->getASTContext());
+
+ FindObjCMethodDeclsWithOrigin(current_id,
+ context,
+ complete_interface_decl,
+ m_ast_context,
+ m_ast_importer,
+ "in debug info");
+
+ return;
+ }
+ while (0);
+
+ do
+ {
+ // Check the runtime only if the debug information didn't have a complete interface.
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ break;
+
+ ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+
+ if (!language_runtime)
+ break;
+
+ TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+
+ if (!type_vendor)
+ break;
+
+ ConstString interface_name(interface_decl->getNameAsString().c_str());
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <ClangASTType> types;
+
+ if (!type_vendor->FindTypes(interface_name,
+ append,
+ max_matches,
+ types))
+ break;
+
+ const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
+
+ const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);
+
+ if (!runtime_interface_type)
+ break;
+
+ ObjCInterfaceDecl *runtime_interface_decl = runtime_interface_type->getDecl();
+
+ FindObjCMethodDeclsWithOrigin(current_id,
+ context,
+ runtime_interface_decl,
+ m_ast_context,
+ m_ast_importer,
+ "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));
+
+ ConstString class_name(parser_iface_decl->getNameAsString().c_str());
+
+ if (log)
+ log->Printf("ClangASTSource::FindObjCPropertyAndIvarDecls[%d] on (ASTContext*)%p for '%s.%s'",
+ current_id,
+ 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,
+ 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,
+ origin_iface_decl.decl,
+ &origin_iface_decl->getASTContext());
+
+ SymbolContext null_sc;
+ TypeList type_list;
+
+ do
+ {
+ ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(parser_iface_decl.decl));
+
+ if (!complete_interface_decl)
+ break;
+
+ // We found the complete interface. The runtime never needs to be queried in this scenario.
+
+ DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);
+
+ if (complete_iface_decl.decl == origin_iface_decl.decl)
+ break; // already checked this one
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ complete_iface_decl.decl,
+ &complete_iface_decl->getASTContext());
+
+ FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer,
+ complete_iface_decl);
+
+ return;
+ }
+ while(0);
+
+ do
+ {
+ // Check the runtime only if the debug information didn't have a complete interface.
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ return;
+
+ ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+
+ if (!language_runtime)
+ return;
+
+ TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+
+ if (!type_vendor)
+ break;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <ClangASTType> types;
+
+ if (!type_vendor->FindTypes(class_name,
+ append,
+ max_matches,
+ types))
+ break;
+
+ const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
+
+ const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);
+
+ if (!runtime_interface_type)
+ break;
+
+ DeclFromUser<const ObjCInterfaceDecl> runtime_iface_decl(runtime_interface_type->getDecl());
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying runtime (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ runtime_iface_decl.decl,
+ &runtime_iface_decl->getASTContext());
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer,
+ runtime_iface_decl))
+ 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)
+{
+ typedef llvm::DenseMap <const D*, O> MapType;
+
+ for (typename MapType::iterator fi = source_map.begin(), fe = source_map.end();
+ fi != fe;
+ ++fi)
+ {
+ DeclFromUser <D> user_decl(const_cast<D*>(fi->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, fi->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,
+ m_ast_context,
+ record,
+ record->getNameAsString().c_str());
+ }
+
+
+ DeclFromParser <const RecordDecl> parser_record(record);
+ DeclFromUser <const RecordDecl> origin_record(parser_record.GetOrigin(m_ast_importer));
+
+ 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));
+
+ if (!origin_record.decl->getDefinition())
+ 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, parser_ast_context) ||
+ !ImportOffsetMap(base_offsets, origin_base_offsets, m_ast_importer, parser_ast_context) ||
+ !ImportOffsetMap(virtual_base_offsets, origin_virtual_base_offsets, m_ast_importer, 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, 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,
+ *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 " : ""),
+ 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,
+ m_ast_context,
+ name.GetCString(),
+ parent_map->begin()->second.GetNamespaceDecl()->getDeclName().getAsString().c_str());
+ else
+ log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s",
+ current_id,
+ m_ast_context,
+ name.GetCString());
+ }
+
+
+ if (parent_map)
+ {
+ for (ClangASTImporter::NamespaceMap::iterator i = parent_map->begin(), e = parent_map->end();
+ i != e;
+ ++i)
+ {
+ ClangNamespaceDecl found_namespace_decl;
+
+ lldb::ModuleSP module_sp = i->first;
+ ClangNamespaceDecl 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, ClangNamespaceDecl>(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());
+
+ ClangNamespaceDecl 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;
+
+ ClangNamespaceDecl 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, ClangNamespaceDecl>(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 NULL;
+
+ const ClangNamespaceDecl &namespace_decl = namespace_decls->begin()->second;
+
+ Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, namespace_decl.GetASTContext(), namespace_decl.GetNamespaceDecl());
+
+ if (!copied_decl)
+ return NULL;
+
+ NamespaceDecl *copied_namespace_decl = dyn_cast<NamespaceDecl>(copied_decl);
+
+ if (!copied_namespace_decl)
+ return NULL;
+
+ context.m_decls.push_back(copied_namespace_decl);
+
+ m_ast_importer->RegisterNamespaceMap(copied_namespace_decl, namespace_decls);
+
+ return dyn_cast<NamespaceDecl>(copied_decl);
+}
+
+ClangASTType
+ClangASTSource::GuardedCopyType (const ClangASTType &src_type)
+{
+ ClangASTMetrics::RegisterLLDBImport();
+
+ SetImportInProgress(true);
+
+ QualType copied_qual_type = m_ast_importer->CopyType (m_ast_context, src_type.GetASTContext(), src_type.GetQualType());
+
+ 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 ClangASTType();
+
+ return ClangASTType(m_ast_context, copied_qual_type);
+}
+
+clang::NamedDecl *
+NameSearchContext::AddVarDecl(const ClangASTType &type)
+{
+ assert (type && "Type for variable must be valid!");
+
+ if (!type.IsValid())
+ return NULL;
+
+ IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo();
+
+ clang::ASTContext *ast = type.GetASTContext();
+
+ clang::NamedDecl *Decl = VarDecl::Create(*ast,
+ const_cast<DeclContext*>(m_decl_context),
+ SourceLocation(),
+ SourceLocation(),
+ ii,
+ type.GetQualType(),
+ 0,
+ SC_Static);
+ m_decls.push_back(Decl);
+
+ return Decl;
+}
+
+clang::NamedDecl *
+NameSearchContext::AddFunDecl (const ClangASTType &type)
+{
+ assert (type && "Type for variable must be valid!");
+
+ if (!type.IsValid())
+ return NULL;
+
+ if (m_function_types.count(type))
+ return NULL;
+
+ m_function_types.insert(type);
+
+ QualType qual_type (type.GetQualType());
+
+ clang::ASTContext *ast = type.GetASTContext();
+
+ const bool isInlineSpecified = false;
+ const bool hasWrittenPrototype = true;
+ const bool isConstexprSpecified = false;
+
+ clang::FunctionDecl *func_decl = FunctionDecl::Create (*ast,
+ const_cast<DeclContext*>(m_decl_context),
+ SourceLocation(),
+ SourceLocation(),
+ m_decl_name.getAsIdentifierInfo(),
+ qual_type,
+ NULL,
+ SC_Static,
+ 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->getNumArgs();
+ unsigned ArgIndex;
+
+ SmallVector<ParmVarDecl *, 5> parm_var_decls;
+
+ for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex)
+ {
+ QualType arg_qual_type (func_proto_type->getArgType(ArgIndex));
+
+ parm_var_decls.push_back(ParmVarDecl::Create (*ast,
+ const_cast<DeclContext*>(m_decl_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(ClangASTType (m_ast_source.m_ast_context, generic_function_type));
+}
+
+clang::NamedDecl *
+NameSearchContext::AddTypeDecl(const ClangASTType &clang_type)
+{
+ if (clang_type)
+ {
+ QualType qual_type = clang_type.GetQualType();
+
+ 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::DeclContextLookupConstResult result)
+{
+ for (clang::NamedDecl *decl : result)
+ m_decls.push_back (decl);
+}
+
+void
+NameSearchContext::AddNamedDecl (clang::NamedDecl *decl)
+{
+ m_decls.push_back (decl);
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangExpressionDeclMap.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionDeclMap.cpp
new file mode 100644
index 0000000..072e781
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionDeclMap.cpp
@@ -0,0 +1,1956 @@
+//===-- 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 "lldb/Expression/ClangExpressionDeclMap.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#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/RegisterValue.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ASTDumper.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangNamespaceDecl.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/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"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace clang;
+
+ClangExpressionDeclMap::ClangExpressionDeclMap (bool keep_result_in_memory, ExecutionContext &exe_ctx) :
+ ClangASTSource (exe_ctx.GetTargetSP()),
+ m_found_entities (),
+ m_struct_members (),
+ m_keep_result_in_memory (keep_result_in_memory),
+ 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 = &target->GetPersistentVariables();
+
+ if (!target->GetScratchClangASTContext())
+ return false;
+ }
+
+ m_parser_vars->m_target_info = GetTargetInfo();
+ m_parser_vars->m_materializer = materializer;
+
+ return true;
+}
+
+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)
+ {
+ ClangExpressionVariableSP var_sp(m_found_entities.GetVariableAtIndex(entity_index));
+ if (var_sp)
+ var_sp->DisableParserVars(GetParserID());
+ }
+
+ for (size_t pvar_index = 0, num_pvars = m_parser_vars->m_persistent_vars->GetSize();
+ pvar_index < num_pvars;
+ ++pvar_index)
+ {
+ ClangExpressionVariableSP pvar_sp(m_parser_vars->m_persistent_vars->GetVariableAtIndex(pvar_index));
+ if (pvar_sp)
+ pvar_sp->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());
+
+ 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 == NULL)
+ return false;
+
+ ASTContext *context(target->GetScratchClangASTContext()->getASTContext());
+
+ TypeFromUser user_type(m_ast_importer->DeportType(context,
+ parser_type.GetASTContext(),
+ parser_type.GetOpaqueQualType()),
+ context);
+
+ uint32_t offset = m_parser_vars->m_materializer->AddResultVariable(user_type, is_lvalue, m_keep_result_in_memory, err);
+
+ ClangExpressionVariableSP var_sp = m_found_entities.CreateVariable(exe_ctx.GetBestExecutionContextScope(),
+ name,
+ user_type,
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size);
+
+ if (!var_sp)
+ return false;
+
+ var_sp->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
+
+ parser_vars->m_named_decl = decl;
+ parser_vars->m_parser_type = parser_type;
+
+ var_sp->EnableJITVars(GetParserID());
+
+ ClangExpressionVariable::JITVars *jit_vars = var_sp->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;
+
+ ASTContext *context(target->GetScratchClangASTContext()->getASTContext());
+
+ TypeFromUser user_type(m_ast_importer->DeportType(context,
+ parser_type.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;
+
+ ClangExpressionVariableSP var_sp = 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);
+
+ if (!var_sp)
+ return false;
+
+ var_sp->m_frozen_sp->SetHasCompleteType();
+
+ if (is_result)
+ var_sp->m_flags |= ClangExpressionVariable::EVNeedsFreezeDry;
+ else
+ var_sp->m_flags |= ClangExpressionVariable::EVKeepInTarget; // explicitly-declared persistent variables should persist
+
+ if (is_lvalue)
+ {
+ var_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference;
+ }
+ else
+ {
+ var_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+ var_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+ }
+
+ if (m_keep_result_in_memory)
+ {
+ var_sp->m_flags |= ClangExpressionVariable::EVKeepInTarget;
+ }
+
+ if (log)
+ log->Printf("Created persistent variable with flags 0x%hx", var_sp->m_flags);
+
+ var_sp->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars = var_sp->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,
+ off_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 (m_struct_members.GetVariable(decl, GetParserID()))
+ return true;
+
+ ClangExpressionVariableSP var_sp (m_found_entities.GetVariable(decl, GetParserID()));
+
+ if (!var_sp)
+ {
+ var_sp = m_parser_vars->m_persistent_vars->GetVariable(decl, GetParserID());
+ is_persistent_variable = true;
+ }
+
+ if (!var_sp)
+ return false;
+
+ if (log)
+ log->Printf("Adding value for (NamedDecl*)%p [%s - %s] to the structure",
+ decl,
+ name.GetCString(),
+ var_sp->GetName().GetCString());
+
+ // We know entity->m_parser_vars is valid because we used a parser variable
+ // to find it
+
+ ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
+
+ parser_vars->m_llvm_value = value;
+
+ if (ClangExpressionVariable::JITVars *jit_vars = var_sp->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);
+ }
+
+ var_sp->EnableJITVars(GetParserID());
+
+ ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID());
+
+ jit_vars->m_alignment = alignment;
+ jit_vars->m_size = size;
+
+ m_struct_members.AddVariable(var_sp);
+
+ if (m_parser_vars->m_materializer)
+ {
+ uint32_t offset = 0;
+
+ Error err;
+
+ if (is_persistent_variable)
+ {
+ offset = m_parser_vars->m_materializer->AddPersistentVariable(var_sp, 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_sp->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,
+ off_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,
+ off_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;
+
+ ClangExpressionVariableSP member_sp(m_struct_members.GetVariableAtIndex(index));
+
+ if (!member_sp)
+ return false;
+
+ ClangExpressionVariable::ParserVars *parser_vars = member_sp->GetParserVars(GetParserID());
+ ClangExpressionVariable::JITVars *jit_vars = member_sp->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
+)
+{
+ ClangExpressionVariableSP entity_sp(m_found_entities.GetVariable(decl, GetParserID()));
+
+ if (!entity_sp)
+ return false;
+
+ // We know m_parser_vars is valid since we searched for the variable by
+ // its NamedDecl
+
+ ClangExpressionVariable::ParserVars *parser_vars = entity_sp->GetParserVars(GetParserID());
+
+ ptr = parser_vars->m_lldb_value.GetScalar().ULongLong();
+
+ return true;
+}
+
+static void
+FindCodeSymbolInContext
+(
+ const ConstString &name,
+ SymbolContext &sym_ctx,
+ SymbolContextList &sc_list
+)
+{
+ SymbolContextList temp_sc_list;
+ if (sym_ctx.module_sp)
+ sym_ctx.module_sp->FindSymbolsWithNameAndType(name, eSymbolTypeAny, temp_sc_list);
+
+ if (!sc_list.GetSize() && sym_ctx.target_sp)
+ sym_ctx.target_sp->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, temp_sc_list);
+
+ unsigned temp_sc_list_size = temp_sc_list.GetSize();
+ for (unsigned i = 0; i < temp_sc_list_size; i++)
+ {
+ SymbolContext sym_ctx;
+ temp_sc_list.GetContextAtIndex(i, sym_ctx);
+ if (sym_ctx.symbol)
+ {
+ switch (sym_ctx.symbol->GetType())
+ {
+ case eSymbolTypeCode:
+ case eSymbolTypeResolver:
+ sc_list.Append(sym_ctx);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+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, sc_list);
+
+ if (!sc_list.GetSize())
+ {
+ // 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, sc_list);
+ }
+ }
+
+ if (!sc_list.GetSize())
+ return false;
+
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(0, sym_ctx);
+
+ const Address *func_so_addr = NULL;
+ bool is_indirect_function = false;
+
+ if (sym_ctx.function)
+ func_so_addr = &sym_ctx.function->GetAddressRange().GetBaseAddress();
+ else if (sym_ctx.symbol) {
+ func_so_addr = &sym_ctx.symbol->GetAddress();
+ is_indirect_function = sym_ctx.symbol->IsIndirect();
+ } else
+ return false;
+
+ if (!func_so_addr || !func_so_addr->IsValid())
+ return false;
+
+ func_addr = func_so_addr->GetCallableLoadAddress (target, is_indirect_function);
+
+ return true;
+}
+
+addr_t
+ClangExpressionDeclMap::GetSymbolAddress (Target &target, Process *process, const ConstString &name, lldb::SymbolType symbol_type)
+{
+ SymbolContextList sc_list;
+
+ 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 || !sym_address->IsValid())
+ continue;
+
+ if (sym_address)
+ {
+ 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 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)
+{
+ SymbolContextList sc_list;
+
+ 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 && 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 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,
+ ClangNamespaceDecl *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()->GetClangFullType()))
+ 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->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CEDM::FEVD[%u] Inspecting (NamespaceMap*)%p (%d entries)",
+ current_id,
+ 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.GetNamespaceDecl()->getNameAsString().c_str(),
+ i->first->GetFileSpec().GetFilename().GetCString());
+
+ FindExternalVisibleDecls(context,
+ i->first,
+ i->second,
+ current_id);
+ }
+ }
+ else if (isa<TranslationUnitDecl>(context.m_decl_context))
+ {
+ ClangNamespaceDecl 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,
+ ClangNamespaceDecl &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();
+ 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;
+
+ SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction);
+
+ if (!sym_ctx.function)
+ return;
+
+ // Get the block that defines the function
+ Block *function_block = sym_ctx.GetFunctionBlock();
+
+ if (!function_block)
+ return;
+
+ clang::DeclContext *decl_context = function_block->GetClangDeclContext();
+
+ if (!decl_context)
+ return;
+
+ clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl_context);
+
+ 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(),
+ &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());
+ }
+
+ TypeFromParser class_type = CopyClassType(class_user_type, current_id);
+
+ if (!class_type.IsValid())
+ return;
+
+ TypeSourceInfo *type_source_info = m_ast_context->getTrivialTypeSourceInfo(QualType::getFromOpaquePtr(class_type.GetOpaqueQualType()));
+
+ if (!type_source_info)
+ return;
+
+ 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);
+
+ 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(),
+ &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 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;
+
+ ClangASTType pointee_type = this_type->GetClangForwardType().GetPointeeType();
+
+ if (pointee_type.IsValid())
+ {
+ if (log)
+ {
+ ASTDumper ast_dumper(this_type->GetClangFullType());
+ log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ TypeFromUser class_user_type(pointee_type);
+ AddOneType(context, class_user_type, current_id);
+
+
+ TypeFromUser this_user_type(this_type->GetClangFullType());
+ 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);
+
+ if (!sym_ctx.function)
+ return;
+
+ // Get the block that defines the function
+ Block *function_block = sym_ctx.GetFunctionBlock();
+
+ if (!function_block)
+ return;
+
+ clang::DeclContext *decl_context = function_block->GetClangDeclContext();
+
+ if (!decl_context)
+ return;
+
+ clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_context);
+
+ 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(),
+ &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(),
+ &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(),
+ &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 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;
+
+ ClangASTType self_clang_type = self_type->GetClangFullType();
+
+ if (self_clang_type.IsObjCClassType())
+ {
+ return;
+ }
+ else if (self_clang_type.IsObjCObjectPointerType())
+ {
+ self_clang_type = self_clang_type.GetPointeeType();
+
+ if (!self_clang_type)
+ return;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(self_type->GetClangFullType());
+ 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->GetClangFullType());
+
+ 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->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);
+
+ ClangExpressionVariableSP 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;
+ Error err;
+
+ if (frame && !namespace_decl)
+ {
+ valobj = frame->GetValueForVariableExpressionPath(name_unique_cstr,
+ eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember ||
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess ||
+ StackFrame::eExpressionPathOptionsNoFragileObjcIvar ||
+ StackFrame::eExpressionPathOptionsNoSyntheticChildren ||
+ StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
+ var,
+ err);
+
+ // If we found a variable in scope, no need to pull up function names
+ if (err.Success() && var)
+ {
+ AddOneVariable(context, var, valobj, current_id);
+ context.m_found.variable = true;
+ 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;
+ }
+ }
+
+ 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 (sc_list.GetSize())
+ {
+ Symbol *generic_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)
+ {
+ clang::DeclContext *decl_ctx = sym_ctx.function->GetClangDeclContext();
+
+ if (!decl_ctx)
+ continue;
+
+ // Filter out class/instance methods.
+ if (dyn_cast<clang::ObjCMethodDecl>(decl_ctx))
+ continue;
+ if (dyn_cast<clang::CXXMethodDecl>(decl_ctx))
+ 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->IsExternal())
+ generic_symbol = sym_ctx.symbol;
+ else
+ non_extern_symbol = sym_ctx.symbol;
+ }
+ }
+
+ if (!context.m_found.function_with_type_info)
+ {
+ if (generic_symbol)
+ {
+ AddOneFunction (context, NULL, generic_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 (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)
+ {
+ AddOneGenericVariable(context, *data_symbol, current_id);
+ context.m_found.variable = true;
+ }
+ }
+ }
+ }
+}
+
+static clang_type_t
+MaybePromoteToBlockPointerType
+(
+ ASTContext *ast_context,
+ clang_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;
+ }
+
+ ClangASTType var_clang_type = var_type->GetClangFullType();
+
+ if (!var_clang_type)
+ {
+ if (log)
+ log->PutCString("Skipped a definition because it has no Clang type");
+ return false;
+ }
+
+ // commented out because of <rdar://problem/11024417>
+ ASTContext *ast = var_type->GetClangASTContext().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();
+
+ lldb::addr_t loclist_base_load_addr = LLDB_INVALID_ADDRESS;
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ if (var_location_expr.IsLocationList())
+ {
+ SymbolContext var_sc;
+ var->CalculateSymbolContext (&var_sc);
+ loclist_base_load_addr = var_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (target);
+ }
+ 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;
+ }
+ }
+
+ ClangASTType 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.SetClangType(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());
+ }
+
+
+ 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());
+ ClangExpressionVariableSP entity(m_found_entities.CreateVariable (valobj));
+
+ assert (entity.get());
+ 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,
+ ClangExpressionVariableSP &pvar_sp,
+ unsigned int current_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ TypeFromUser user_type (pvar_sp->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());
+
+ pvar_sp->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars = pvar_sp->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());
+ ClangExpressionVariableSP entity(m_found_entities.CreateVariable (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));
+ assert (entity.get());
+
+ 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.SetClangType(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();
+
+ ASTContext *scratch_ast_context = target->GetScratchClangASTContext()->getASTContext();
+
+ for (size_t index = 0, num_entities = m_found_entities.GetSize();
+ index < num_entities;
+ ++index)
+ {
+ ClangExpressionVariableSP entity = m_found_entities.GetVariableAtIndex(index);
+
+ ClangExpressionVariable::ParserVars *parser_vars = entity->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(), &var_decl->getASTContext());
+
+ lldb::clang_type_t copied_type = m_ast_importer->CopyType(scratch_ast_context, &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::ClangExpressionVariableSP();
+ }
+
+ TypeFromUser user_type(copied_type, scratch_ast_context);
+
+// parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, user_type.GetOpaqueQualType());
+ parser_vars->m_lldb_value.SetClangType(user_type);
+ parser_vars->m_parser_type = parser_type;
+
+ entity->SetClangType(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));
+
+ ClangASTType 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);
+
+ ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(),
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
+ assert (entity.get());
+
+ 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;
+ const Address *fun_address = NULL;
+ ClangASTType 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->GetClangFullType();
+
+ if (!function_clang_type)
+ {
+ if (log)
+ log->PutCString(" Skipped a function because it has no Clang type");
+ return;
+ }
+
+ fun_address = &function->GetAddressRange().GetBaseAddress();
+
+ ClangASTType 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);
+
+ ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope (),
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
+ assert (entity.get());
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ entity->SetName(ConstString(decl_name.c_str()));
+ entity->SetClangType (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());
+ }
+}
+
+TypeFromParser
+ClangExpressionDeclMap::CopyClassType(TypeFromUser &ut,
+ unsigned int current_id)
+{
+ ClangASTType copied_clang_type = GuardedCopyType(ut);
+
+ if (!copied_clang_type)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("ClangExpressionDeclMap::CopyClassType - Couldn't import the type");
+
+ return TypeFromParser();
+ }
+
+ if (copied_clang_type.IsAggregateType() && copied_clang_type.GetCompleteType ())
+ {
+ ClangASTType void_clang_type = ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid);
+ ClangASTType void_ptr_clang_type = void_clang_type.GetPointerType();
+
+ ClangASTType 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;
+
+ copied_clang_type.AddMethodToCXXRecordType ("$__lldb_expr",
+ method_type,
+ lldb::eAccessPublic,
+ is_virtual,
+ is_static,
+ is_inline,
+ is_explicit,
+ is_attr_used,
+ is_artificial);
+ }
+
+ return TypeFromParser(copied_clang_type);
+}
+
+void
+ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
+ TypeFromUser &ut,
+ unsigned int current_id)
+{
+ ClangASTType 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/contrib/llvm/tools/lldb/source/Expression/ClangExpressionParser.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionParser.cpp
new file mode 100644
index 0000000..98c0bfd
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionParser.cpp
@@ -0,0 +1,595 @@
+//===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Expression/ClangExpressionParser.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRDynamicChecks.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Driver/CC1Options.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"
+
+#if defined(__FreeBSD__)
+#define USE_STANDARD_JIT
+#endif
+
+#if defined (USE_STANDARD_JIT)
+#include "llvm/ExecutionEngine/JIT.h"
+#else
+#include "llvm/ExecutionEngine/MCJIT.h"
+#endif
+#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"
+
+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();
+}
+
+
+//===----------------------------------------------------------------------===//
+// Main driver for Clang
+//===----------------------------------------------------------------------===//
+
+static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+
+ Diags.Report(diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ assert(0);
+}
+
+static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
+ using namespace clang::frontend;
+
+ switch (CI.getFrontendOpts().ProgramAction) {
+ default:
+ llvm_unreachable("Invalid program action!");
+
+ case ASTDump: return new ASTDumpAction();
+ case ASTPrint: return new ASTPrintAction();
+ case ASTDumpXML: return new ASTDumpXMLAction();
+ case ASTView: return new ASTViewAction();
+ case DumpRawTokens: return new DumpRawTokensAction();
+ case DumpTokens: return new DumpTokensAction();
+ case EmitAssembly: return new EmitAssemblyAction();
+ case EmitBC: return new EmitBCAction();
+ case EmitHTML: return new HTMLPrintAction();
+ case EmitLLVM: return new EmitLLVMAction();
+ case EmitLLVMOnly: return new EmitLLVMOnlyAction();
+ case EmitCodeGenOnly: return new EmitCodeGenOnlyAction();
+ case EmitObj: return new EmitObjAction();
+ case FixIt: return new FixItAction();
+ case GeneratePCH: return new GeneratePCHAction();
+ case GeneratePTH: return new GeneratePTHAction();
+ case InitOnly: return new InitOnlyAction();
+ case ParseSyntaxOnly: return new SyntaxOnlyAction();
+
+ case PluginAction: {
+ for (FrontendPluginRegistry::iterator it =
+ FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end();
+ it != ie; ++it) {
+ if (it->getName() == CI.getFrontendOpts().ActionName) {
+ llvm::OwningPtr<PluginASTAction> P(it->instantiate());
+ if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs))
+ return 0;
+ return P.take();
+ }
+ }
+
+ CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name)
+ << CI.getFrontendOpts().ActionName;
+ return 0;
+ }
+
+ case PrintDeclContext: return new DeclContextPrintAction();
+ case PrintPreamble: return new PrintPreambleAction();
+ case PrintPreprocessedInput: return new PrintPreprocessedAction();
+ case RewriteMacros: return new RewriteMacrosAction();
+ case RewriteObjC: return new RewriteObjCAction();
+ case RewriteTest: return new RewriteTestAction();
+ //case RunAnalysis: return new AnalysisAction();
+ case RunPreprocessorOnly: return new PreprocessOnlyAction();
+ }
+}
+
+static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
+ // Create the underlying action.
+ FrontendAction *Act = CreateFrontendBaseAction(CI);
+ if (!Act)
+ return 0;
+
+ // If there are any AST files to merge, create a frontend action
+ // adaptor to perform the merge.
+ if (!CI.getFrontendOpts().ASTMergeFiles.empty())
+ Act = new ASTMergeAction(Act, CI.getFrontendOpts().ASTMergeFiles);
+
+ return Act;
+}
+
+//===----------------------------------------------------------------------===//
+// Implementation of ClangExpressionParser
+//===----------------------------------------------------------------------===//
+
+ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
+ ClangExpression &expr) :
+ m_expr (expr),
+ m_compiler (),
+ m_code_generator ()
+{
+ // Initialize targets first, so that --version shows registered targets.
+ static struct InitializeLLVM {
+ InitializeLLVM() {
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllDisassemblers();
+
+ llvm::DisablePrettyStackTrace = true;
+ }
+ } InitializeLLVM;
+
+ // 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();
+
+ int dash_count = 0;
+ for (size_t i = 0; i < triple.size(); ++i)
+ {
+ if (triple[i] == '-')
+ dash_count++;
+ if (dash_count == 3)
+ {
+ triple.resize(i);
+ break;
+ }
+ }
+
+ 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");
+ }
+
+ if (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->getTargetOpts()));
+
+ assert (m_compiler->hasTarget());
+
+ // 3. Set options.
+
+ lldb::LanguageType language = expr.Language();
+
+ switch (language)
+ {
+ case lldb::eLanguageTypeC:
+ break;
+ case lldb::eLanguageTypeObjC:
+ m_compiler->getLangOpts().ObjC1 = true;
+ m_compiler->getLangOpts().ObjC2 = true;
+ break;
+ case lldb::eLanguageTypeC_plus_plus:
+ m_compiler->getLangOpts().CPlusPlus = true;
+ m_compiler->getLangOpts().CPlusPlus11 = true;
+ break;
+ case lldb::eLanguageTypeObjC_plus_plus:
+ default:
+ m_compiler->getLangOpts().ObjC1 = true;
+ m_compiler->getLangOpts().ObjC2 = true;
+ m_compiler->getLangOpts().CPlusPlus = true;
+ m_compiler->getLangOpts().CPlusPlus11 = 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() == ClangExpression::eResultTypeId)
+ m_compiler->getLangOpts().DebuggerCastResultToId = true;
+
+ // 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() == 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;
+
+ // Disable some warnings.
+ m_compiler->getDiagnostics().setDiagnosticGroupMapping("unused-value", clang::diag::MAP_IGNORE, SourceLocation());
+ m_compiler->getDiagnostics().setDiagnosticGroupMapping("odr", clang::diag::MAP_IGNORE, 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().setForcedLangOptions(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();
+
+ // 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->getTarget(),
+ m_compiler->getPreprocessor().getIdentifierTable(),
+ *m_selector_table.get(),
+ *m_builtin_context.get(),
+ 0));
+
+ ClangExpressionDeclMap *decl_map = m_expr.DeclMap();
+
+ if (decl_map)
+ {
+ llvm::OwningPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy());
+ decl_map->InstallASTContext(ast_context.get());
+ ast_context->setExternalSource(ast_source);
+ }
+
+ 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->getCodeGenOpts(),
+ m_compiler->getTargetOpts(),
+ *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());
+
+ MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(m_expr.Text(), __FUNCTION__);
+ m_compiler->getSourceManager().createMainFileIDForMemBuffer (memory_buffer);
+
+ diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor());
+
+ ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get());
+
+ if (ast_transformer)
+ ParseAST(m_compiler->getPreprocessor(), ast_transformer, m_compiler->getASTContext());
+ else
+ ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), m_compiler->getASTContext());
+
+ diag_buf->EndSourceFile();
+
+ TextDiagnosticBuffer::const_iterator diag_iterator;
+
+ int num_errors = 0;
+
+ 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());
+
+ num_errors = 0;
+
+ 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 (m_expr.DeclMap() && !m_expr.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,
+ std::unique_ptr<IRExecutionUnit> &execution_unit_ap,
+ 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));
+
+ std::unique_ptr<llvm::ExecutionEngine> execution_engine_ap;
+
+ Error err;
+
+ std::unique_ptr<llvm::Module> module_ap (m_code_generator->ReleaseModule());
+
+ if (!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, 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());
+ }
+
+ m_execution_unit.reset(new IRExecutionUnit(m_llvm_context, // handed off here
+ module_ap, // handed off here
+ function_name,
+ exe_ctx.GetTargetSP(),
+ m_compiler->getTargetOpts().Features));
+
+ ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL
+
+ if (decl_map)
+ {
+ Stream *error_stream = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ error_stream = &target->GetDebugger().GetErrorStream();
+
+ IRForTarget ir_for_target(decl_map,
+ m_expr.NeedsVariableResolution(),
+ *m_execution_unit,
+ error_stream,
+ function_name.AsCString());
+
+ bool ir_can_run = ir_for_target.runOnModule(*m_execution_unit->GetModule());
+
+ Error interpret_error;
+
+ can_interpret = IRInterpreter::CanInterpret(*m_execution_unit->GetModule(), *m_execution_unit->GetFunction(), interpret_error);
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ 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(*m_execution_unit->GetModule()))
+ {
+ err.SetErrorToGenericError();
+ err.SetErrorString("Couldn't add dynamic checks to the expression");
+ return err;
+ }
+ }
+
+ m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
+ }
+ }
+ else
+ {
+ m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
+ }
+
+ execution_unit_ap.reset (m_execution_unit.release());
+
+ return err;
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangExpressionVariable.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionVariable.cpp
new file mode 100644
index 0000000..0d355ce
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionVariable.cpp
@@ -0,0 +1,136 @@
+//===-- 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 "lldb/Expression/ClangExpressionVariable.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#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;
+
+ClangExpressionVariable::ClangExpressionVariable(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size) :
+ m_parser_vars(),
+ m_jit_vars (),
+ m_flags (EVNone),
+ m_frozen_sp (ValueObjectConstResult::Create (exe_scope, byte_order, addr_byte_size))
+{
+}
+
+ClangExpressionVariable::ClangExpressionVariable (const lldb::ValueObjectSP &valobj_sp) :
+ m_parser_vars(),
+ m_jit_vars (),
+ m_flags (EVNone),
+ m_frozen_sp (valobj_sp)
+{
+}
+
+//----------------------------------------------------------------------
+/// Return the variable's size in bytes
+//----------------------------------------------------------------------
+size_t
+ClangExpressionVariable::GetByteSize ()
+{
+ return m_frozen_sp->GetByteSize();
+}
+
+const ConstString &
+ClangExpressionVariable::GetName ()
+{
+ return m_frozen_sp->GetName();
+}
+
+lldb::ValueObjectSP
+ClangExpressionVariable::GetValueObject()
+{
+ return m_frozen_sp;
+}
+
+RegisterInfo *
+ClangExpressionVariable::GetRegisterInfo()
+{
+ return m_frozen_sp->GetValue().GetRegisterInfo();
+}
+
+void
+ClangExpressionVariable::SetRegisterInfo (const RegisterInfo *reg_info)
+{
+ return m_frozen_sp->GetValue().SetContext (Value::eContextTypeRegisterInfo, const_cast<RegisterInfo *>(reg_info));
+}
+
+ClangASTType
+ClangExpressionVariable::GetClangType()
+{
+ return m_frozen_sp->GetClangType();
+}
+
+void
+ClangExpressionVariable::SetClangType(const ClangASTType &clang_type)
+{
+ m_frozen_sp->GetValue().SetClangType(clang_type);
+}
+
+
+TypeFromUser
+ClangExpressionVariable::GetTypeFromUser()
+{
+ TypeFromUser tfu (m_frozen_sp->GetClangType());
+ return tfu;
+}
+
+uint8_t *
+ClangExpressionVariable::GetValueBytes()
+{
+ const size_t byte_size = m_frozen_sp->GetByteSize();
+ if (byte_size > 0)
+ {
+ if (m_frozen_sp->GetDataExtractor().GetByteSize() < byte_size)
+ {
+ m_frozen_sp->GetValue().ResizeData(byte_size);
+ m_frozen_sp->GetValue().GetData (m_frozen_sp->GetDataExtractor());
+ }
+ return const_cast<uint8_t *>(m_frozen_sp->GetDataExtractor().GetDataStart());
+ }
+ return NULL;
+}
+
+void
+ClangExpressionVariable::SetName (const ConstString &name)
+{
+ m_frozen_sp->SetName (name);
+}
+
+void
+ClangExpressionVariable::ValueUpdated ()
+{
+ m_frozen_sp->ValueUpdated ();
+}
+
+void
+ClangExpressionVariable::TransferAddress (bool force)
+{
+ if (m_live_sp.get() == NULL)
+ return;
+
+ if (m_frozen_sp.get() == NULL)
+ return;
+
+ if (force || (m_frozen_sp->GetLiveAddress() == LLDB_INVALID_ADDRESS))
+ m_frozen_sp->SetLiveAddress(m_live_sp->GetLiveAddress());
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangFunction.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangFunction.cpp
new file mode 100644
index 0000000..177138d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ClangFunction.cpp
@@ -0,0 +1,633 @@
+//===-- ClangFunction.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/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/Expression/ASTStructExtractor.h"
+#include "lldb/Expression/ClangExpressionParser.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ClangFunction constructor
+//----------------------------------------------------------------------
+ClangFunction::ClangFunction
+(
+ ExecutionContextScope &exe_scope,
+ const ClangASTType &return_type,
+ const Address& functionAddress,
+ const ValueList &arg_value_list
+) :
+ m_function_ptr (NULL),
+ m_function_addr (functionAddress),
+ m_function_return_type(return_type),
+ m_wrapper_function_name ("__lldb_caller_function"),
+ m_wrapper_struct_name ("__lldb_caller_struct"),
+ m_wrapper_args_addrs (),
+ m_arg_values (arg_value_list),
+ m_compiled (false),
+ m_JITted (false)
+{
+ m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());
+ // Can't make a ClangFunction without a process.
+ assert (m_jit_process_wp.lock());
+}
+
+ClangFunction::ClangFunction
+(
+ ExecutionContextScope &exe_scope,
+ Function &function,
+ ClangASTContext *ast_context,
+ const ValueList &arg_value_list
+) :
+ m_function_ptr (&function),
+ m_function_addr (),
+ m_function_return_type (),
+ m_clang_ast_context (ast_context),
+ m_wrapper_function_name ("__lldb_function_caller"),
+ m_wrapper_struct_name ("__lldb_caller_struct"),
+ m_wrapper_args_addrs (),
+ m_arg_values (arg_value_list),
+ m_compiled (false),
+ m_JITted (false)
+{
+ m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());
+ // Can't make a ClangFunction without a process.
+ assert (m_jit_process_wp.lock());
+
+ m_function_addr = m_function_ptr->GetAddressRange().GetBaseAddress();
+ m_function_return_type = m_function_ptr->GetClangType().GetFunctionReturnType();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ClangFunction::~ClangFunction()
+{
+}
+
+unsigned
+ClangFunction::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());
+
+ // 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.
+ ClangASTType function_clang_type;
+ if (m_function_ptr)
+ {
+ function_clang_type = m_function_ptr->GetClangType();
+ 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();
+ }
+ else
+ {
+ ClangASTType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetClangType ();
+ if (clang_qual_type)
+ {
+ type_name = clang_qual_type.GetTypeName();
+ }
+ else
+ {
+ errors.Printf("Could not determine type of input value %lu.", 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)
+ {
+ m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this));
+
+ 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;
+}
+
+bool
+ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
+{
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (!process)
+ return false;
+
+ lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
+
+ if (process != jit_process_sp.get())
+ return false;
+
+ if (!m_compiled)
+ return false;
+
+ if (m_JITted)
+ return true;
+
+ bool can_interpret = false; // should stay that way
+
+ Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr,
+ m_jit_end_addr,
+ m_execution_unit_ap,
+ exe_ctx,
+ can_interpret,
+ eExecutionPolicyAlways));
+
+ if (!jit_error.Success())
+ return false;
+
+ if (process && m_jit_start_addr)
+ m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+
+ m_JITted = true;
+
+ return true;
+}
+
+bool
+ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors)
+{
+ return WriteFunctionArguments(exe_ctx, args_addr_ref, m_function_addr, m_arg_values, errors);
+}
+
+// FIXME: Assure that the ValueList we were passed in is consistent with the one that defined this function.
+
+bool
+ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx,
+ lldb::addr_t &args_addr_ref,
+ Address function_address,
+ ValueList &arg_values,
+ Stream &errors)
+{
+ // All the information to reconstruct the struct is provided by the
+ // StructExtractor.
+ if (!m_struct_valid)
+ {
+ errors.Printf("Argument information was not correctly parsed, so the function cannot be called.");
+ return false;
+ }
+
+ Error error;
+ using namespace clang;
+ ExecutionResults return_value = eExecutionSetupError;
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == NULL)
+ return return_value;
+
+ lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
+
+ if (process != jit_process_sp.get())
+ return false;
+
+ if (args_addr_ref == LLDB_INVALID_ADDRESS)
+ {
+ args_addr_ref = process->AllocateMemory(m_struct_size, lldb::ePermissionsReadable|lldb::ePermissionsWritable, error);
+ if (args_addr_ref == LLDB_INVALID_ADDRESS)
+ return false;
+ m_wrapper_args_addrs.push_back (args_addr_ref);
+ }
+ else
+ {
+ // Make sure this is an address that we've already handed out.
+ if (find (m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr_ref) == m_wrapper_args_addrs.end())
+ {
+ return false;
+ }
+ }
+
+ // TODO: verify fun_addr needs to be a callable address
+ Scalar fun_addr (function_address.GetCallableLoadAddress(exe_ctx.GetTargetPtr()));
+ uint64_t first_offset = m_member_offsets[0];
+ process->WriteScalarToMemory(args_addr_ref + first_offset, fun_addr, process->GetAddressByteSize(), error);
+
+ // FIXME: We will need to extend this for Variadic functions.
+
+ Error value_error;
+
+ size_t num_args = arg_values.GetSize();
+ if (num_args != m_arg_values.GetSize())
+ {
+ errors.Printf ("Wrong number of arguments - was: %lu should be: %lu", num_args, m_arg_values.GetSize());
+ return false;
+ }
+
+ for (size_t i = 0; i < num_args; i++)
+ {
+ // FIXME: We should sanity check sizes.
+
+ uint64_t offset = m_member_offsets[i+1]; // Clang sizes are in bytes.
+ Value *arg_value = arg_values.GetValueAtIndex(i);
+
+ // FIXME: For now just do scalars:
+
+ // Special case: if it's a pointer, don't do anything (the ABI supports passing cstrings)
+
+ if (arg_value->GetValueType() == Value::eValueTypeHostAddress &&
+ arg_value->GetContextType() == Value::eContextTypeInvalid &&
+ arg_value->GetClangType().IsPointerType())
+ continue;
+
+ const Scalar &arg_scalar = arg_value->ResolveValue(&exe_ctx);
+
+ if (!process->WriteScalarToMemory(args_addr_ref + offset, arg_scalar, arg_scalar.GetByteSize(), error))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors)
+{
+ using namespace clang;
+
+ if (CompileFunction(errors) != 0)
+ return false;
+ if (!WriteFunctionWrapper(exe_ctx, errors))
+ return false;
+ if (!WriteFunctionArguments(exe_ctx, args_addr_ref, errors))
+ return false;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf ("Call Address: 0x%" PRIx64 " Struct Address: 0x%" PRIx64 ".\n", m_jit_start_addr, args_addr_ref);
+
+ return true;
+}
+
+ThreadPlan *
+ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
+ lldb::addr_t func_addr,
+ lldb::addr_t &args_addr,
+ Stream &errors,
+ bool stop_others,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ lldb::addr_t *this_arg,
+ lldb::addr_t *cmd_arg)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ if (log)
+ log->Printf("-- [ClangFunction::GetThreadPlanToCallFunction] Creating thread plan to call function --");
+
+ // FIXME: Use the errors Stream for better error reporting.
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (thread == NULL)
+ {
+ errors.Printf("Can't call a function without a valid thread.");
+ return NULL;
+ }
+
+ // Okay, now run the function:
+
+ Address wrapper_address (func_addr);
+ ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread,
+ wrapper_address,
+ ClangASTType(),
+ args_addr,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
+ this_arg,
+ cmd_arg);
+ new_plan->SetIsMasterPlan(true);
+ new_plan->SetOkayToDiscard (false);
+ return new_plan;
+}
+
+bool
+ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr, Value &ret_value)
+{
+ // Read the return value - it is the last field in the struct:
+ // FIXME: How does clang tell us there's no return value? We need to handle that case.
+ // FIXME: Create our ThreadPlanCallFunction with the return ClangASTType, and then use GetReturnValueObject
+ // to fetch the value. That way we can fetch any values we need.
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ if (log)
+ log->Printf("-- [ClangFunction::FetchFunctionResults] Fetching function results --");
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == NULL)
+ return false;
+
+ lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
+
+ if (process != jit_process_sp.get())
+ return false;
+
+ Error error;
+ ret_value.GetScalar() = process->ReadUnsignedIntegerFromMemory (args_addr + m_return_offset, m_return_size, 0, error);
+
+ if (error.Fail())
+ return false;
+
+ ret_value.SetClangType(m_function_return_type);
+ ret_value.SetValueType(Value::eValueTypeScalar);
+ return true;
+}
+
+void
+ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr)
+{
+ std::list<lldb::addr_t>::iterator pos;
+ pos = std::find(m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr);
+ if (pos != m_wrapper_args_addrs.end())
+ m_wrapper_args_addrs.erase(pos);
+
+ exe_ctx.GetProcessRef().DeallocateMemory(args_addr);
+}
+
+ExecutionResults
+ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, Value &results)
+{
+ return ExecuteFunction (exe_ctx, errors, 1000, true, results);
+}
+
+ExecutionResults
+ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, bool stop_others, Value &results)
+{
+ const bool try_all_threads = false;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ return ExecuteFunction (exe_ctx, NULL, errors, stop_others, 0UL, try_all_threads,
+ unwind_on_error, ignore_breakpoints, results);
+}
+
+ExecutionResults
+ClangFunction::ExecuteFunction(
+ ExecutionContext &exe_ctx,
+ Stream &errors,
+ uint32_t timeout_usec,
+ bool try_all_threads,
+ Value &results)
+{
+ const bool stop_others = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ return ExecuteFunction (exe_ctx, NULL, errors, stop_others, timeout_usec,
+ try_all_threads, unwind_on_error, ignore_breakpoints, results);
+}
+
+// This is the static function
+ExecutionResults
+ClangFunction::ExecuteFunction (
+ ExecutionContext &exe_ctx,
+ lldb::addr_t function_address,
+ lldb::addr_t &void_arg,
+ bool stop_others,
+ bool try_all_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ uint32_t timeout_usec,
+ Stream &errors,
+ lldb::addr_t *this_arg)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ if (log)
+ log->Printf("== [ClangFunction::ExecuteFunction] Executing function ==");
+
+ lldb::ThreadPlanSP call_plan_sp (ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
+ function_address,
+ void_arg,
+ errors,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
+ this_arg));
+ if (!call_plan_sp)
+ return eExecutionSetupError;
+
+ // <rdar://problem/12027563> we need to make sure we record the fact that we are running an expression here
+ // otherwise this fact will fail to be recorded when fetching an Objective-C object description
+ if (exe_ctx.GetProcessPtr())
+ exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
+
+ ExecutionResults results = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, call_plan_sp,
+ stop_others,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ errors);
+
+ if (log)
+ {
+ if (results != eExecutionCompleted)
+ {
+ log->Printf("== [ClangFunction::ExecuteFunction] Execution completed abnormally ==");
+ }
+ else
+ {
+ log->Printf("== [ClangFunction::ExecuteFunction] Execution completed normally ==");
+ }
+ }
+
+ if (exe_ctx.GetProcessPtr())
+ exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
+
+ return results;
+}
+
+ExecutionResults
+ClangFunction::ExecuteFunction(
+ ExecutionContext &exe_ctx,
+ lldb::addr_t *args_addr_ptr,
+ Stream &errors,
+ bool stop_others,
+ uint32_t timeout_usec,
+ bool try_all_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ Value &results)
+{
+ using namespace clang;
+ ExecutionResults return_value = eExecutionSetupError;
+
+ lldb::addr_t args_addr;
+
+ if (args_addr_ptr != NULL)
+ args_addr = *args_addr_ptr;
+ else
+ args_addr = LLDB_INVALID_ADDRESS;
+
+ if (CompileFunction(errors) != 0)
+ return eExecutionSetupError;
+
+ if (args_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (!InsertFunction(exe_ctx, args_addr, errors))
+ return eExecutionSetupError;
+ }
+
+ return_value = ClangFunction::ExecuteFunction (exe_ctx,
+ m_jit_start_addr,
+ args_addr,
+ stop_others,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ errors);
+
+ if (args_addr_ptr != NULL)
+ *args_addr_ptr = args_addr;
+
+ if (return_value != eExecutionCompleted)
+ return return_value;
+
+ FetchFunctionResults(exe_ctx, args_addr, results);
+
+ if (args_addr_ptr == NULL)
+ DeallocateFunctionResults(exe_ctx, args_addr);
+
+ return eExecutionCompleted;
+}
+
+clang::ASTConsumer *
+ClangFunction::ASTTransformer (clang::ASTConsumer *passthrough)
+{
+ return new ASTStructExtractor(passthrough, m_wrapper_struct_name.c_str(), *this);
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangPersistentVariables.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangPersistentVariables.cpp
new file mode 100644
index 0000000..db062d2
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ClangPersistentVariables.cpp
@@ -0,0 +1,89 @@
+//===-- 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 "lldb/Expression/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 () :
+ ClangExpressionVariableList(),
+ m_next_persistent_variable_id (0)
+{
+}
+
+ClangExpressionVariableSP
+ClangPersistentVariables::CreatePersistentVariable (const lldb::ValueObjectSP &valobj_sp)
+{
+ ClangExpressionVariableSP var_sp (CreateVariable(valobj_sp));
+ return var_sp;
+}
+
+ClangExpressionVariableSP
+ClangPersistentVariables::CreatePersistentVariable (ExecutionContextScope *exe_scope,
+ const ConstString &name,
+ const TypeFromUser& user_type,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size)
+{
+ ClangExpressionVariableSP var_sp (GetVariable(name));
+
+ if (!var_sp)
+ var_sp = CreateVariable(exe_scope, name, user_type, byte_order, addr_byte_size);
+
+ return var_sp;
+}
+
+void
+ClangPersistentVariables::RemovePersistentVariable (lldb::ClangExpressionVariableSP 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/contrib/llvm/tools/lldb/source/Expression/ClangUserExpression.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangUserExpression.cpp
new file mode 100644
index 0000000..7f09f6f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ClangUserExpression.cpp
@@ -0,0 +1,1091 @@
+//===-- ClangUserExpression.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 <string>
+#include <map>
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Expression/ASTResultSynthesizer.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionParser.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Expression/ExpressionSourceCode.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Function.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 (const char *expr,
+ const char *expr_prefix,
+ lldb::LanguageType language,
+ ResultType desired_type) :
+ ClangExpression (),
+ m_stack_frame_bottom (LLDB_INVALID_ADDRESS),
+ m_stack_frame_top (LLDB_INVALID_ADDRESS),
+ m_expr_text (expr),
+ m_expr_prefix (expr_prefix ? expr_prefix : ""),
+ m_language (language),
+ m_transformed_text (),
+ m_desired_type (desired_type),
+ m_enforce_valid_object (true),
+ m_cplusplus (false),
+ m_objectivec (false),
+ m_static_method(false),
+ m_needs_object_ptr (false),
+ m_const_object (false),
+ m_target (NULL),
+ m_can_interpret (false),
+ m_materialized_address (LLDB_INVALID_ADDRESS)
+{
+ 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 ()
+{
+}
+
+clang::ASTConsumer *
+ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough)
+{
+ ClangASTContext *clang_ast_context = m_target->GetScratchClangASTContext();
+
+ if (!clang_ast_context)
+ return NULL;
+
+ if (!m_result_synthesizer.get())
+ m_result_synthesizer.reset(new ASTResultSynthesizer(passthrough,
+ *m_target));
+
+ return m_result_synthesizer.get();
+}
+
+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;
+ }
+
+ clang::DeclContext *decl_context = function_block->GetClangDeclContext();
+
+ if (!decl_context)
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Null decl context");
+ return;
+ }
+
+ if (clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(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_cplusplus = true;
+ m_needs_object_ptr = true;
+ }
+ }
+ else if (clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(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_objectivec = true;
+ m_needs_object_ptr = true;
+
+ if (!method_decl->isInstanceMethod())
+ m_static_method = true;
+ }
+ }
+ else if (clang::FunctionDecl *function_decl = llvm::dyn_cast<clang::FunctionDecl>(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 it 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::GetMetadata (&decl_context->getParentASTContext(), 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_cplusplus = 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;
+ }
+
+ ClangASTType self_clang_type = self_type->GetClangForwardType();
+
+ if (!self_clang_type)
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ if (self_clang_type.IsObjCClassType())
+ {
+ return;
+ }
+ else if (self_clang_type.IsObjCObjectPointerType())
+ {
+ m_objectivec = true;
+ m_needs_object_ptr = true;
+ }
+ else
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+ }
+ else
+ {
+ m_objectivec = true;
+ m_needs_object_ptr = true;
+ }
+ }
+ }
+ }
+}
+
+void
+ClangUserExpression::InstallContext (ExecutionContext &exe_ctx)
+{
+ m_process_wp = exe_ctx.GetProcessSP();
+
+ lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP();
+
+ if (frame_sp)
+ m_address = frame_sp->GetFrameCodeAddress();
+}
+
+bool
+ClangUserExpression::LockAndCheckContext (ExecutionContext &exe_ctx,
+ lldb::TargetSP &target_sp,
+ lldb::ProcessSP &process_sp,
+ lldb::StackFrameSP &frame_sp)
+{
+ lldb::ProcessSP expected_process_sp = m_process_wp.lock();
+ process_sp = exe_ctx.GetProcessSP();
+
+ if (process_sp != expected_process_sp)
+ return false;
+
+ process_sp = exe_ctx.GetProcessSP();
+ target_sp = exe_ctx.GetTargetSP();
+ frame_sp = exe_ctx.GetFrameSP();
+
+ if (m_address.IsValid())
+ {
+ if (!frame_sp)
+ return false;
+ else
+ return (0 == Address::CompareLoadAddress(m_address, frame_sp->GetFrameCodeAddress(), target_sp.get()));
+ }
+
+ return true;
+}
+
+bool
+ClangUserExpression::MatchesContext (ExecutionContext &exe_ctx)
+{
+ lldb::TargetSP target_sp;
+ lldb::ProcessSP process_sp;
+ lldb::StackFrameSP frame_sp;
+
+ return LockAndCheckContext(exe_ctx, target_sp, process_sp, frame_sp);
+}
+
+// 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
+}
+
+// Another hack, meant to allow use of unichar despite it not being available in
+// the type information. Although we could special-case it in type lookup,
+// hopefully we'll figure out a way to #include the same environment as is
+// present in the original source file rather than try to hack specific type
+// definitions in as needed.
+static void
+ApplyUnicharHack(std::string &expr)
+{
+#define UNICHAR_HACK_FROM "unichar"
+#define UNICHAR_HACK_TO "unsigned short"
+
+ size_t from_offset;
+
+ while ((from_offset = expr.find(UNICHAR_HACK_FROM)) != expr.npos)
+ expr.replace(from_offset, sizeof(UNICHAR_HACK_FROM) - 1, UNICHAR_HACK_TO);
+
+#undef UNICHAR_HACK_TO
+#undef UNICHAR_HACK_FROM
+}
+
+bool
+ClangUserExpression::Parse (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Error err;
+
+ InstallContext(exe_ctx);
+
+ 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::unique_ptr<ExpressionSourceCode> source_code (ExpressionSourceCode::CreateWrapped(m_expr_prefix.c_str(), m_expr_text.c_str()));
+
+ lldb::LanguageType lang_type;
+
+ if (m_cplusplus)
+ lang_type = lldb::eLanguageTypeC_plus_plus;
+ else if(m_objectivec)
+ lang_type = lldb::eLanguageTypeObjC;
+ else
+ lang_type = lldb::eLanguageTypeC;
+
+ if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method))
+ {
+ 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());
+
+ m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx));
+
+ 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]() { m_expr_decl_map.reset(); });
+
+ if (!m_expr_decl_map->WillParse(exe_ctx, m_materializer_ap.get()))
+ {
+ error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
+ return false;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+ ExecutionContextScope *exe_scope = process;
+
+ if (!exe_scope)
+ exe_scope = exe_ctx.GetTargetPtr();
+
+ ClangExpressionParser parser(exe_scope, *this);
+
+ unsigned num_errors = parser.Parse (error_stream);
+
+ if (num_errors)
+ {
+ error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
+
+ m_expr_decl_map->DidParse();
+
+ 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_ap,
+ exe_ctx,
+ m_can_interpret,
+ execution_policy);
+
+ 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;
+ }
+}
+
+static lldb::addr_t
+GetObjectPointer (lldb::StackFrameSP frame_sp,
+ ConstString &object_name,
+ Error &err)
+{
+ err.Clear();
+
+ if (!frame_sp)
+ {
+ err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ lldb::VariableSP var_sp;
+ lldb::ValueObjectSP valobj_sp;
+
+ valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(),
+ lldb::eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember ||
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess ||
+ StackFrame::eExpressionPathOptionsNoFragileObjcIvar ||
+ StackFrame::eExpressionPathOptionsNoSyntheticChildren ||
+ StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
+ var_sp,
+ err);
+
+ if (!err.Success())
+ return LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (ret == LLDB_INVALID_ADDRESS)
+ {
+ err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ return ret;
+}
+
+bool
+ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb::addr_t &struct_address,
+ lldb::addr_t &object_ptr,
+ lldb::addr_t &cmd_ptr)
+{
+ lldb::TargetSP target;
+ lldb::ProcessSP process;
+ lldb::StackFrameSP frame;
+
+ if (!LockAndCheckContext(exe_ctx,
+ target,
+ process,
+ frame))
+ {
+ error_stream.Printf("The context has changed before we could JIT the expression!\n");
+ return false;
+ }
+
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
+ {
+ if (m_needs_object_ptr)
+ {
+ ConstString object_name;
+
+ if (m_cplusplus)
+ {
+ object_name.SetCString("this");
+ }
+ else if (m_objectivec)
+ {
+ 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, 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_objectivec)
+ {
+ ConstString cmd_name("_cmd");
+
+ cmd_ptr = GetObjectPointer(frame, 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 (m_materialized_address == LLDB_INVALID_ADDRESS)
+ {
+ Error alloc_error;
+
+ IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror;
+
+ m_materialized_address = m_execution_unit_ap->Malloc(m_materializer_ap->GetStructByteSize(),
+ m_materializer_ap->GetStructAlignment(),
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ policy,
+ alloc_error);
+
+ if (!alloc_error.Success())
+ {
+ error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString());
+ return false;
+ }
+ }
+
+ struct_address = m_materialized_address;
+
+ if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS)
+ {
+ Error alloc_error;
+
+ const size_t stack_frame_size = 512 * 1024;
+
+ m_stack_frame_bottom = m_execution_unit_ap->Malloc(stack_frame_size,
+ 8,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ IRMemoryMap::eAllocationPolicyHostOnly,
+ alloc_error);
+
+ m_stack_frame_top = m_stack_frame_bottom + stack_frame_size;
+
+ if (!alloc_error.Success())
+ {
+ error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString());
+ return false;
+ }
+ }
+
+ Error materialize_error;
+
+ m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_ap, struct_address, materialize_error);
+
+ if (!materialize_error.Success())
+ {
+ error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString());
+ return false;
+ }
+ }
+ return true;
+}
+
+ThreadPlan *
+ClangUserExpression::GetThreadPlanToExecuteJITExpression (Stream &error_stream,
+ ExecutionContext &exe_ctx)
+{
+ lldb::addr_t struct_address;
+
+ lldb::addr_t object_ptr = 0;
+ lldb::addr_t cmd_ptr = 0;
+
+ PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr);
+
+ // FIXME: This should really return a ThreadPlanCallUserExpression, in order to make sure that we don't release the
+ // ClangUserExpression resources before the thread plan finishes execution in the target. But because we are
+ // forcing unwind_on_error to be true here, in practical terms that can't happen.
+
+ const bool stop_others = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = false;
+ return ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
+ m_jit_start_addr,
+ struct_address,
+ error_stream,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
+ (m_needs_object_ptr ? &object_ptr : NULL),
+ (m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL);
+}
+
+bool
+ClangUserExpression::FinalizeJITExecution (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb::ClangExpressionVariableSP &result,
+ lldb::addr_t function_stack_bottom,
+ lldb::addr_t function_stack_top)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("-- [ClangUserExpression::FinalizeJITExecution] Dematerializing after execution --");
+
+ if (!m_dematerializer_sp)
+ {
+ error_stream.Printf ("Couldn't apply expression side effects : no dematerializer is present");
+ return false;
+ }
+
+ Error dematerialize_error;
+
+ m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_bottom, function_stack_top);
+
+ if (!dematerialize_error.Success())
+ {
+ error_stream.Printf ("Couldn't apply expression side effects : %s\n", dematerialize_error.AsCString("unknown error"));
+ return false;
+ }
+
+ if (result)
+ result->TransferAddress();
+
+ m_dematerializer_sp.reset();
+
+ return true;
+}
+
+ExecutionResults
+ClangUserExpression::Execute (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me,
+ lldb::ClangExpressionVariableSP &result,
+ bool run_others,
+ uint32_t timeout_usec)
+{
+ // The expression log is quite verbose, and if you're just tracking the execution of the
+ // expression, it's quite convenient to have these logs come out with the STEP log as well.
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
+ {
+ lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t object_ptr = 0;
+ lldb::addr_t cmd_ptr = 0;
+
+ if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr))
+ {
+ error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__);
+ return eExecutionSetupError;
+ }
+
+ lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS;
+ lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS;
+
+ if (m_can_interpret)
+ {
+ llvm::Module *module = m_execution_unit_ap->GetModule();
+ llvm::Function *function = m_execution_unit_ap->GetFunction();
+
+ if (!module || !function)
+ {
+ error_stream.Printf("Supposed to interpret, but nothing is there");
+ return eExecutionSetupError;
+ }
+
+ Error interpreter_error;
+
+ llvm::SmallVector <lldb::addr_t, 3> args;
+
+ if (m_needs_object_ptr)
+ {
+ args.push_back(object_ptr);
+
+ if (m_objectivec)
+ args.push_back(cmd_ptr);
+ }
+
+ args.push_back(struct_address);
+
+ function_stack_bottom = m_stack_frame_bottom;
+ function_stack_top = m_stack_frame_top;
+
+ IRInterpreter::Interpret (*module,
+ *function,
+ args,
+ *m_execution_unit_ap.get(),
+ interpreter_error,
+ function_stack_bottom,
+ function_stack_top);
+
+ if (!interpreter_error.Success())
+ {
+ error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString());
+ return eExecutionDiscarded;
+ }
+ }
+ else
+ {
+ const bool stop_others = true;
+ const bool try_all_threads = run_others;
+
+ Address wrapper_address (m_jit_start_addr);
+ lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
+ wrapper_address,
+ struct_address,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
+ (m_needs_object_ptr ? &object_ptr : NULL),
+ ((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL),
+ shared_ptr_to_me));
+
+ if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
+ return eExecutionSetupError;
+
+ lldb::addr_t function_stack_pointer = static_cast<ThreadPlanCallFunction *>(call_plan_sp.get())->GetFunctionStackPointer();
+
+ function_stack_bottom = function_stack_pointer - Host::GetPageSize();
+ function_stack_top = function_stack_pointer;
+
+ if (log)
+ log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --");
+
+ if (exe_ctx.GetProcessPtr())
+ exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
+
+ ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_others,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_stream);
+
+ if (exe_ctx.GetProcessPtr())
+ exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
+
+ if (log)
+ log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --");
+
+ if (execution_result == eExecutionInterrupted || execution_result == eExecutionHitBreakpoint)
+ {
+ const char *error_desc = NULL;
+
+ if (call_plan_sp)
+ {
+ lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo();
+ if (real_stop_info_sp)
+ error_desc = real_stop_info_sp->GetDescription();
+ }
+ if (error_desc)
+ error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc);
+ else
+ error_stream.Printf ("Execution was interrupted.");
+
+ if ((execution_result == eExecutionInterrupted && unwind_on_error)
+ || (execution_result == eExecutionHitBreakpoint && ignore_breakpoints))
+ error_stream.Printf ("\nThe process has been returned to the state before expression evaluation.");
+ else
+ error_stream.Printf ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation.");
+
+ return execution_result;
+ }
+ else if (execution_result != eExecutionCompleted)
+ {
+ error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result));
+ return execution_result;
+ }
+ }
+
+ if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_bottom, function_stack_top))
+ {
+ return eExecutionCompleted;
+ }
+ else
+ {
+ return eExecutionSetupError;
+ }
+ }
+ else
+ {
+ error_stream.Printf("Expression can't be run, because there is no JIT compiled function");
+ return eExecutionSetupError;
+ }
+}
+
+ExecutionResults
+ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ lldb::LanguageType language,
+ ResultType desired_type,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ const char *expr_cstr,
+ const char *expr_prefix,
+ lldb::ValueObjectSP &result_valobj_sp,
+ bool run_others,
+ uint32_t timeout_usec)
+{
+ Error error;
+ return EvaluateWithError (exe_ctx,
+ execution_policy,
+ language,
+ desired_type,
+ unwind_on_error,
+ ignore_breakpoints,
+ expr_cstr,
+ expr_prefix,
+ result_valobj_sp,
+ error,
+ run_others,
+ timeout_usec);
+}
+
+ExecutionResults
+ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ lldb::LanguageType language,
+ ResultType desired_type,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ const char *expr_cstr,
+ const char *expr_prefix,
+ lldb::ValueObjectSP &result_valobj_sp,
+ Error &error,
+ bool run_others,
+ uint32_t timeout_usec)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ ExecutionResults execution_results = eExecutionSetupError;
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == NULL || process->GetState() != lldb::eStateStopped)
+ {
+ if (execution_policy == eExecutionPolicyAlways)
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
+
+ error.SetErrorString ("expression needed to run but couldn't");
+
+ return execution_results;
+ }
+ }
+
+ if (process == NULL || !process->CanJIT())
+ execution_policy = eExecutionPolicyNever;
+
+ ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, expr_prefix, language, desired_type));
+
+ StreamString error_stream;
+
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr);
+
+ const bool keep_expression_in_memory = true;
+
+ if (!user_expression_sp->Parse (error_stream, exe_ctx, execution_policy, keep_expression_in_memory))
+ {
+ if (error_stream.GetString().empty())
+ error.SetErrorString ("expression failed to parse, unknown error");
+ else
+ error.SetErrorString (error_stream.GetString().c_str());
+ }
+ else
+ {
+ lldb::ClangExpressionVariableSP expr_result;
+
+ if (execution_policy == eExecutionPolicyNever &&
+ !user_expression_sp->CanInterpret())
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
+
+ if (error_stream.GetString().empty())
+ error.SetErrorString ("expression needed to run but couldn't");
+ }
+ else
+ {
+ error_stream.GetString().clear();
+
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Executing expression ==");
+
+ execution_results = user_expression_sp->Execute (error_stream,
+ exe_ctx,
+ unwind_on_error,
+ ignore_breakpoints,
+ user_expression_sp,
+ expr_result,
+ run_others,
+ timeout_usec);
+
+ if (execution_results != eExecutionCompleted)
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally ==");
+
+ if (error_stream.GetString().empty())
+ error.SetErrorString ("expression failed to execute, unknown error");
+ else
+ error.SetErrorString (error_stream.GetString().c_str());
+ }
+ else
+ {
+ if (expr_result)
+ {
+ result_valobj_sp = expr_result->GetValueObject();
+
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==", result_valobj_sp->GetValueAsCString());
+ }
+ else
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with no result ==");
+
+ error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric);
+ }
+ }
+ }
+ }
+
+ if (result_valobj_sp.get() == NULL)
+ result_valobj_sp = ValueObjectConstResult::Create (NULL, error);
+
+ return execution_results;
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangUtilityFunction.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangUtilityFunction.cpp
new file mode 100644
index 0000000..c911c27
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ClangUtilityFunction.cpp
@@ -0,0 +1,169 @@
+//===-- ClangUserExpression.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 "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionParser.h"
+#include "lldb/Expression/ClangUtilityFunction.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 (const char *text,
+ const char *name) :
+ ClangExpression (),
+ m_function_text (ExpressionSourceCode::g_expression_prefix),
+ m_function_name (name)
+{
+ if (text && text[0])
+ m_function_text.append (text);
+}
+
+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;
+
+ m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx));
+
+ if (!m_expr_decl_map->WillParse(exe_ctx, NULL))
+ {
+ error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
+ return false;
+ }
+
+ ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this);
+
+ unsigned num_errors = parser.Parse (error_stream);
+
+ if (num_errors)
+ {
+ error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
+
+ m_expr_decl_map.reset();
+
+ 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_ap,
+ exe_ctx,
+ can_interpret,
+ eExecutionPolicyAlways);
+
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
+ m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+
+#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
+
+ m_expr_decl_map->DidParse();
+
+ m_expr_decl_map.reset();
+
+ 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;
+ }
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp b/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp
new file mode 100644
index 0000000..e2ae19e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp
@@ -0,0 +1,2691 @@
+//===-- DWARFExpression.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Expression/DWARFExpression.h"
+
+#include <vector>
+
+#include "lldb/Core/DataEncoder.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/VMRange.h"
+
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StackID.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+DW_OP_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x03: return "DW_OP_addr";
+ case 0x06: return "DW_OP_deref";
+ case 0x08: return "DW_OP_const1u";
+ case 0x09: return "DW_OP_const1s";
+ case 0x0a: return "DW_OP_const2u";
+ case 0x0b: return "DW_OP_const2s";
+ case 0x0c: return "DW_OP_const4u";
+ case 0x0d: return "DW_OP_const4s";
+ case 0x0e: return "DW_OP_const8u";
+ case 0x0f: return "DW_OP_const8s";
+ case 0x10: return "DW_OP_constu";
+ case 0x11: return "DW_OP_consts";
+ case 0x12: return "DW_OP_dup";
+ case 0x13: return "DW_OP_drop";
+ case 0x14: return "DW_OP_over";
+ case 0x15: return "DW_OP_pick";
+ case 0x16: return "DW_OP_swap";
+ case 0x17: return "DW_OP_rot";
+ case 0x18: return "DW_OP_xderef";
+ case 0x19: return "DW_OP_abs";
+ case 0x1a: return "DW_OP_and";
+ case 0x1b: return "DW_OP_div";
+ case 0x1c: return "DW_OP_minus";
+ case 0x1d: return "DW_OP_mod";
+ case 0x1e: return "DW_OP_mul";
+ case 0x1f: return "DW_OP_neg";
+ case 0x20: return "DW_OP_not";
+ case 0x21: return "DW_OP_or";
+ case 0x22: return "DW_OP_plus";
+ case 0x23: return "DW_OP_plus_uconst";
+ case 0x24: return "DW_OP_shl";
+ case 0x25: return "DW_OP_shr";
+ case 0x26: return "DW_OP_shra";
+ case 0x27: return "DW_OP_xor";
+ case 0x2f: return "DW_OP_skip";
+ case 0x28: return "DW_OP_bra";
+ case 0x29: return "DW_OP_eq";
+ case 0x2a: return "DW_OP_ge";
+ case 0x2b: return "DW_OP_gt";
+ case 0x2c: return "DW_OP_le";
+ case 0x2d: return "DW_OP_lt";
+ case 0x2e: return "DW_OP_ne";
+ case 0x30: return "DW_OP_lit0";
+ case 0x31: return "DW_OP_lit1";
+ case 0x32: return "DW_OP_lit2";
+ case 0x33: return "DW_OP_lit3";
+ case 0x34: return "DW_OP_lit4";
+ case 0x35: return "DW_OP_lit5";
+ case 0x36: return "DW_OP_lit6";
+ case 0x37: return "DW_OP_lit7";
+ case 0x38: return "DW_OP_lit8";
+ case 0x39: return "DW_OP_lit9";
+ case 0x3a: return "DW_OP_lit10";
+ case 0x3b: return "DW_OP_lit11";
+ case 0x3c: return "DW_OP_lit12";
+ case 0x3d: return "DW_OP_lit13";
+ case 0x3e: return "DW_OP_lit14";
+ case 0x3f: return "DW_OP_lit15";
+ case 0x40: return "DW_OP_lit16";
+ case 0x41: return "DW_OP_lit17";
+ case 0x42: return "DW_OP_lit18";
+ case 0x43: return "DW_OP_lit19";
+ case 0x44: return "DW_OP_lit20";
+ case 0x45: return "DW_OP_lit21";
+ case 0x46: return "DW_OP_lit22";
+ case 0x47: return "DW_OP_lit23";
+ case 0x48: return "DW_OP_lit24";
+ case 0x49: return "DW_OP_lit25";
+ case 0x4a: return "DW_OP_lit26";
+ case 0x4b: return "DW_OP_lit27";
+ case 0x4c: return "DW_OP_lit28";
+ case 0x4d: return "DW_OP_lit29";
+ case 0x4e: return "DW_OP_lit30";
+ case 0x4f: return "DW_OP_lit31";
+ case 0x50: return "DW_OP_reg0";
+ case 0x51: return "DW_OP_reg1";
+ case 0x52: return "DW_OP_reg2";
+ case 0x53: return "DW_OP_reg3";
+ case 0x54: return "DW_OP_reg4";
+ case 0x55: return "DW_OP_reg5";
+ case 0x56: return "DW_OP_reg6";
+ case 0x57: return "DW_OP_reg7";
+ case 0x58: return "DW_OP_reg8";
+ case 0x59: return "DW_OP_reg9";
+ case 0x5a: return "DW_OP_reg10";
+ case 0x5b: return "DW_OP_reg11";
+ case 0x5c: return "DW_OP_reg12";
+ case 0x5d: return "DW_OP_reg13";
+ case 0x5e: return "DW_OP_reg14";
+ case 0x5f: return "DW_OP_reg15";
+ case 0x60: return "DW_OP_reg16";
+ case 0x61: return "DW_OP_reg17";
+ case 0x62: return "DW_OP_reg18";
+ case 0x63: return "DW_OP_reg19";
+ case 0x64: return "DW_OP_reg20";
+ case 0x65: return "DW_OP_reg21";
+ case 0x66: return "DW_OP_reg22";
+ case 0x67: return "DW_OP_reg23";
+ case 0x68: return "DW_OP_reg24";
+ case 0x69: return "DW_OP_reg25";
+ case 0x6a: return "DW_OP_reg26";
+ case 0x6b: return "DW_OP_reg27";
+ case 0x6c: return "DW_OP_reg28";
+ case 0x6d: return "DW_OP_reg29";
+ case 0x6e: return "DW_OP_reg30";
+ case 0x6f: return "DW_OP_reg31";
+ case 0x70: return "DW_OP_breg0";
+ case 0x71: return "DW_OP_breg1";
+ case 0x72: return "DW_OP_breg2";
+ case 0x73: return "DW_OP_breg3";
+ case 0x74: return "DW_OP_breg4";
+ case 0x75: return "DW_OP_breg5";
+ case 0x76: return "DW_OP_breg6";
+ case 0x77: return "DW_OP_breg7";
+ case 0x78: return "DW_OP_breg8";
+ case 0x79: return "DW_OP_breg9";
+ case 0x7a: return "DW_OP_breg10";
+ case 0x7b: return "DW_OP_breg11";
+ case 0x7c: return "DW_OP_breg12";
+ case 0x7d: return "DW_OP_breg13";
+ case 0x7e: return "DW_OP_breg14";
+ case 0x7f: return "DW_OP_breg15";
+ case 0x80: return "DW_OP_breg16";
+ case 0x81: return "DW_OP_breg17";
+ case 0x82: return "DW_OP_breg18";
+ case 0x83: return "DW_OP_breg19";
+ case 0x84: return "DW_OP_breg20";
+ case 0x85: return "DW_OP_breg21";
+ case 0x86: return "DW_OP_breg22";
+ case 0x87: return "DW_OP_breg23";
+ case 0x88: return "DW_OP_breg24";
+ case 0x89: return "DW_OP_breg25";
+ case 0x8a: return "DW_OP_breg26";
+ case 0x8b: return "DW_OP_breg27";
+ case 0x8c: return "DW_OP_breg28";
+ case 0x8d: return "DW_OP_breg29";
+ case 0x8e: return "DW_OP_breg30";
+ case 0x8f: return "DW_OP_breg31";
+ case 0x90: return "DW_OP_regx";
+ case 0x91: return "DW_OP_fbreg";
+ case 0x92: return "DW_OP_bregx";
+ case 0x93: return "DW_OP_piece";
+ case 0x94: return "DW_OP_deref_size";
+ case 0x95: return "DW_OP_xderef_size";
+ case 0x96: return "DW_OP_nop";
+ case 0x97: return "DW_OP_push_object_address";
+ case 0x98: return "DW_OP_call2";
+ case 0x99: return "DW_OP_call4";
+ case 0x9a: return "DW_OP_call_ref";
+// case DW_OP_APPLE_array_ref: return "DW_OP_APPLE_array_ref";
+// case DW_OP_APPLE_extern: return "DW_OP_APPLE_extern";
+ case DW_OP_APPLE_uninit: return "DW_OP_APPLE_uninit";
+// case DW_OP_APPLE_assign: return "DW_OP_APPLE_assign";
+// case DW_OP_APPLE_address_of: return "DW_OP_APPLE_address_of";
+// case DW_OP_APPLE_value_of: return "DW_OP_APPLE_value_of";
+// case DW_OP_APPLE_deref_type: return "DW_OP_APPLE_deref_type";
+// case DW_OP_APPLE_expr_local: return "DW_OP_APPLE_expr_local";
+// case DW_OP_APPLE_constf: return "DW_OP_APPLE_constf";
+// case DW_OP_APPLE_scalar_cast: return "DW_OP_APPLE_scalar_cast";
+// case DW_OP_APPLE_clang_cast: return "DW_OP_APPLE_clang_cast";
+// case DW_OP_APPLE_clear: return "DW_OP_APPLE_clear";
+// case DW_OP_APPLE_error: return "DW_OP_APPLE_error";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFExpression constructor
+//----------------------------------------------------------------------
+DWARFExpression::DWARFExpression() :
+ m_data(),
+ m_reg_kind (eRegisterKindDWARF),
+ m_loclist_slide (LLDB_INVALID_ADDRESS)
+{
+}
+
+DWARFExpression::DWARFExpression(const DWARFExpression& rhs) :
+ m_data(rhs.m_data),
+ m_reg_kind (rhs.m_reg_kind),
+ m_loclist_slide(rhs.m_loclist_slide)
+{
+}
+
+
+DWARFExpression::DWARFExpression(const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) :
+ m_data(data, data_offset, data_length),
+ m_reg_kind (eRegisterKindDWARF),
+ m_loclist_slide(LLDB_INVALID_ADDRESS)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DWARFExpression::~DWARFExpression()
+{
+}
+
+
+bool
+DWARFExpression::IsValid() const
+{
+ return m_data.GetByteSize() > 0;
+}
+
+void
+DWARFExpression::SetOpcodeData (const DataExtractor& data)
+{
+ m_data = data;
+}
+
+void
+DWARFExpression::CopyOpcodeData (const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length)
+{
+ const uint8_t *bytes = data.PeekData(data_offset, data_length);
+ if (bytes)
+ {
+ m_data.SetData(DataBufferSP(new DataBufferHeap(bytes, data_length)));
+ m_data.SetByteOrder(data.GetByteOrder());
+ m_data.SetAddressByteSize(data.GetAddressByteSize());
+ }
+}
+
+void
+DWARFExpression::SetOpcodeData (const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length)
+{
+ m_data.SetData(data, data_offset, data_length);
+}
+
+void
+DWARFExpression::DumpLocation (Stream *s, lldb::offset_t offset, lldb::offset_t length, lldb::DescriptionLevel level, ABI *abi) const
+{
+ if (!m_data.ValidOffsetForDataOfSize(offset, length))
+ return;
+ const lldb::offset_t start_offset = offset;
+ const lldb::offset_t end_offset = offset + length;
+ while (m_data.ValidOffset(offset) && offset < end_offset)
+ {
+ const lldb::offset_t op_offset = offset;
+ const uint8_t op = m_data.GetU8(&offset);
+
+ switch (level)
+ {
+ default:
+ break;
+
+ case lldb::eDescriptionLevelBrief:
+ if (offset > start_offset)
+ s->PutChar(' ');
+ break;
+
+ case lldb::eDescriptionLevelFull:
+ case lldb::eDescriptionLevelVerbose:
+ if (offset > start_offset)
+ s->EOL();
+ s->Indent();
+ if (level == lldb::eDescriptionLevelFull)
+ break;
+ // Fall through for verbose and print offset and DW_OP prefix..
+ s->Printf("0x%8.8" PRIx64 ": %s", op_offset, op >= DW_OP_APPLE_uninit ? "DW_OP_APPLE_" : "DW_OP_");
+ break;
+ }
+
+ switch (op)
+ {
+ case DW_OP_addr: *s << "DW_OP_addr(" << m_data.GetAddress(&offset) << ") "; break; // 0x03 1 address
+ case DW_OP_deref: *s << "DW_OP_deref"; break; // 0x06
+ case DW_OP_const1u: s->Printf("DW_OP_const1u(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x08 1 1-byte constant
+ case DW_OP_const1s: s->Printf("DW_OP_const1s(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x09 1 1-byte constant
+ case DW_OP_const2u: s->Printf("DW_OP_const2u(0x%4.4x) ", m_data.GetU16(&offset)); break; // 0x0a 1 2-byte constant
+ case DW_OP_const2s: s->Printf("DW_OP_const2s(0x%4.4x) ", m_data.GetU16(&offset)); break; // 0x0b 1 2-byte constant
+ case DW_OP_const4u: s->Printf("DW_OP_const4u(0x%8.8x) ", m_data.GetU32(&offset)); break; // 0x0c 1 4-byte constant
+ case DW_OP_const4s: s->Printf("DW_OP_const4s(0x%8.8x) ", m_data.GetU32(&offset)); break; // 0x0d 1 4-byte constant
+ case DW_OP_const8u: s->Printf("DW_OP_const8u(0x%16.16" PRIx64 ") ", m_data.GetU64(&offset)); break; // 0x0e 1 8-byte constant
+ case DW_OP_const8s: s->Printf("DW_OP_const8s(0x%16.16" PRIx64 ") ", m_data.GetU64(&offset)); break; // 0x0f 1 8-byte constant
+ case DW_OP_constu: s->Printf("DW_OP_constu(0x%" PRIx64 ") ", m_data.GetULEB128(&offset)); break; // 0x10 1 ULEB128 constant
+ case DW_OP_consts: s->Printf("DW_OP_consts(0x%" PRId64 ") ", m_data.GetSLEB128(&offset)); break; // 0x11 1 SLEB128 constant
+ case DW_OP_dup: s->PutCString("DW_OP_dup"); break; // 0x12
+ case DW_OP_drop: s->PutCString("DW_OP_drop"); break; // 0x13
+ case DW_OP_over: s->PutCString("DW_OP_over"); break; // 0x14
+ case DW_OP_pick: s->Printf("DW_OP_pick(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x15 1 1-byte stack index
+ case DW_OP_swap: s->PutCString("DW_OP_swap"); break; // 0x16
+ case DW_OP_rot: s->PutCString("DW_OP_rot"); break; // 0x17
+ case DW_OP_xderef: s->PutCString("DW_OP_xderef"); break; // 0x18
+ case DW_OP_abs: s->PutCString("DW_OP_abs"); break; // 0x19
+ case DW_OP_and: s->PutCString("DW_OP_and"); break; // 0x1a
+ case DW_OP_div: s->PutCString("DW_OP_div"); break; // 0x1b
+ case DW_OP_minus: s->PutCString("DW_OP_minus"); break; // 0x1c
+ case DW_OP_mod: s->PutCString("DW_OP_mod"); break; // 0x1d
+ case DW_OP_mul: s->PutCString("DW_OP_mul"); break; // 0x1e
+ case DW_OP_neg: s->PutCString("DW_OP_neg"); break; // 0x1f
+ case DW_OP_not: s->PutCString("DW_OP_not"); break; // 0x20
+ case DW_OP_or: s->PutCString("DW_OP_or"); break; // 0x21
+ case DW_OP_plus: s->PutCString("DW_OP_plus"); break; // 0x22
+ case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend
+ s->Printf("DW_OP_plus_uconst(0x%" PRIx64 ") ", m_data.GetULEB128(&offset));
+ break;
+
+ case DW_OP_shl: s->PutCString("DW_OP_shl"); break; // 0x24
+ case DW_OP_shr: s->PutCString("DW_OP_shr"); break; // 0x25
+ case DW_OP_shra: s->PutCString("DW_OP_shra"); break; // 0x26
+ case DW_OP_xor: s->PutCString("DW_OP_xor"); break; // 0x27
+ case DW_OP_skip: s->Printf("DW_OP_skip(0x%4.4x)", m_data.GetU16(&offset)); break; // 0x2f 1 signed 2-byte constant
+ case DW_OP_bra: s->Printf("DW_OP_bra(0x%4.4x)", m_data.GetU16(&offset)); break; // 0x28 1 signed 2-byte constant
+ case DW_OP_eq: s->PutCString("DW_OP_eq"); break; // 0x29
+ case DW_OP_ge: s->PutCString("DW_OP_ge"); break; // 0x2a
+ case DW_OP_gt: s->PutCString("DW_OP_gt"); break; // 0x2b
+ case DW_OP_le: s->PutCString("DW_OP_le"); break; // 0x2c
+ case DW_OP_lt: s->PutCString("DW_OP_lt"); break; // 0x2d
+ case DW_OP_ne: s->PutCString("DW_OP_ne"); break; // 0x2e
+
+ case DW_OP_lit0: // 0x30
+ case DW_OP_lit1: // 0x31
+ case DW_OP_lit2: // 0x32
+ case DW_OP_lit3: // 0x33
+ case DW_OP_lit4: // 0x34
+ case DW_OP_lit5: // 0x35
+ case DW_OP_lit6: // 0x36
+ case DW_OP_lit7: // 0x37
+ case DW_OP_lit8: // 0x38
+ case DW_OP_lit9: // 0x39
+ case DW_OP_lit10: // 0x3A
+ case DW_OP_lit11: // 0x3B
+ case DW_OP_lit12: // 0x3C
+ case DW_OP_lit13: // 0x3D
+ case DW_OP_lit14: // 0x3E
+ case DW_OP_lit15: // 0x3F
+ case DW_OP_lit16: // 0x40
+ case DW_OP_lit17: // 0x41
+ case DW_OP_lit18: // 0x42
+ case DW_OP_lit19: // 0x43
+ case DW_OP_lit20: // 0x44
+ case DW_OP_lit21: // 0x45
+ case DW_OP_lit22: // 0x46
+ case DW_OP_lit23: // 0x47
+ case DW_OP_lit24: // 0x48
+ case DW_OP_lit25: // 0x49
+ case DW_OP_lit26: // 0x4A
+ case DW_OP_lit27: // 0x4B
+ case DW_OP_lit28: // 0x4C
+ case DW_OP_lit29: // 0x4D
+ case DW_OP_lit30: // 0x4E
+ case DW_OP_lit31: s->Printf("DW_OP_lit%i", op - DW_OP_lit0); break; // 0x4f
+
+ case DW_OP_reg0: // 0x50
+ case DW_OP_reg1: // 0x51
+ case DW_OP_reg2: // 0x52
+ case DW_OP_reg3: // 0x53
+ case DW_OP_reg4: // 0x54
+ case DW_OP_reg5: // 0x55
+ case DW_OP_reg6: // 0x56
+ case DW_OP_reg7: // 0x57
+ case DW_OP_reg8: // 0x58
+ case DW_OP_reg9: // 0x59
+ case DW_OP_reg10: // 0x5A
+ case DW_OP_reg11: // 0x5B
+ case DW_OP_reg12: // 0x5C
+ case DW_OP_reg13: // 0x5D
+ case DW_OP_reg14: // 0x5E
+ case DW_OP_reg15: // 0x5F
+ case DW_OP_reg16: // 0x60
+ case DW_OP_reg17: // 0x61
+ case DW_OP_reg18: // 0x62
+ case DW_OP_reg19: // 0x63
+ case DW_OP_reg20: // 0x64
+ case DW_OP_reg21: // 0x65
+ case DW_OP_reg22: // 0x66
+ case DW_OP_reg23: // 0x67
+ case DW_OP_reg24: // 0x68
+ case DW_OP_reg25: // 0x69
+ case DW_OP_reg26: // 0x6A
+ case DW_OP_reg27: // 0x6B
+ case DW_OP_reg28: // 0x6C
+ case DW_OP_reg29: // 0x6D
+ case DW_OP_reg30: // 0x6E
+ case DW_OP_reg31: // 0x6F
+ {
+ uint32_t reg_num = op - DW_OP_reg0;
+ if (abi)
+ {
+ RegisterInfo reg_info;
+ if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
+ {
+ if (reg_info.name)
+ {
+ s->PutCString (reg_info.name);
+ break;
+ }
+ else if (reg_info.alt_name)
+ {
+ s->PutCString (reg_info.alt_name);
+ break;
+ }
+ }
+ }
+ s->Printf("DW_OP_reg%u", reg_num); break;
+ }
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ {
+ uint32_t reg_num = op - DW_OP_breg0;
+ int64_t reg_offset = m_data.GetSLEB128(&offset);
+ if (abi)
+ {
+ RegisterInfo reg_info;
+ if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
+ {
+ if (reg_info.name)
+ {
+ s->Printf("[%s%+" PRIi64 "]", reg_info.name, reg_offset);
+ break;
+ }
+ else if (reg_info.alt_name)
+ {
+ s->Printf("[%s%+" PRIi64 "]", reg_info.alt_name, reg_offset);
+ break;
+ }
+ }
+ }
+ s->Printf("DW_OP_breg%i(0x%" PRIx64 ")", reg_num, reg_offset);
+ }
+ break;
+
+ case DW_OP_regx: // 0x90 1 ULEB128 register
+ {
+ uint32_t reg_num = m_data.GetULEB128(&offset);
+ if (abi)
+ {
+ RegisterInfo reg_info;
+ if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
+ {
+ if (reg_info.name)
+ {
+ s->PutCString (reg_info.name);
+ break;
+ }
+ else if (reg_info.alt_name)
+ {
+ s->PutCString (reg_info.alt_name);
+ break;
+ }
+ }
+ }
+ s->Printf("DW_OP_regx(%" PRIu32 ")", reg_num); break;
+ }
+ break;
+ case DW_OP_fbreg: // 0x91 1 SLEB128 offset
+ s->Printf("DW_OP_fbreg(%" PRIi64 ")",m_data.GetSLEB128(&offset));
+ break;
+ case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset
+ {
+ uint32_t reg_num = m_data.GetULEB128(&offset);
+ int64_t reg_offset = m_data.GetSLEB128(&offset);
+ if (abi)
+ {
+ RegisterInfo reg_info;
+ if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
+ {
+ if (reg_info.name)
+ {
+ s->Printf("[%s%+" PRIi64 "]", reg_info.name, reg_offset);
+ break;
+ }
+ else if (reg_info.alt_name)
+ {
+ s->Printf("[%s%+" PRIi64 "]", reg_info.alt_name, reg_offset);
+ break;
+ }
+ }
+ }
+ s->Printf("DW_OP_bregx(reg=%" PRIu32 ",offset=%" PRIi64 ")", reg_num, reg_offset);
+ }
+ break;
+ case DW_OP_piece: // 0x93 1 ULEB128 size of piece addressed
+ s->Printf("DW_OP_piece(0x%" PRIx64 ")", m_data.GetULEB128(&offset));
+ break;
+ case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved
+ s->Printf("DW_OP_deref_size(0x%2.2x)", m_data.GetU8(&offset));
+ break;
+ case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved
+ s->Printf("DW_OP_xderef_size(0x%2.2x)", m_data.GetU8(&offset));
+ break;
+ case DW_OP_nop: s->PutCString("DW_OP_nop"); break; // 0x96
+ case DW_OP_push_object_address: s->PutCString("DW_OP_push_object_address"); break; // 0x97 DWARF3
+ case DW_OP_call2: // 0x98 DWARF3 1 2-byte offset of DIE
+ s->Printf("DW_OP_call2(0x%4.4x)", m_data.GetU16(&offset));
+ break;
+ case DW_OP_call4: // 0x99 DWARF3 1 4-byte offset of DIE
+ s->Printf("DW_OP_call4(0x%8.8x)", m_data.GetU32(&offset));
+ break;
+ case DW_OP_call_ref: // 0x9a DWARF3 1 4- or 8-byte offset of DIE
+ s->Printf("DW_OP_call_ref(0x%8.8" PRIx64 ")", m_data.GetAddress(&offset));
+ break;
+// case DW_OP_form_tls_address: s << "form_tls_address"; break; // 0x9b DWARF3
+// case DW_OP_call_frame_cfa: s << "call_frame_cfa"; break; // 0x9c DWARF3
+// case DW_OP_bit_piece: // 0x9d DWARF3 2
+// s->Printf("DW_OP_bit_piece(0x%x, 0x%x)", m_data.GetULEB128(&offset), m_data.GetULEB128(&offset));
+// break;
+// case DW_OP_lo_user: s->PutCString("DW_OP_lo_user"); break; // 0xe0
+// case DW_OP_hi_user: s->PutCString("DW_OP_hi_user"); break; // 0xff
+// case DW_OP_APPLE_extern:
+// s->Printf("DW_OP_APPLE_extern(%" PRIu64 ")", m_data.GetULEB128(&offset));
+// break;
+// case DW_OP_APPLE_array_ref:
+// s->PutCString("DW_OP_APPLE_array_ref");
+// break;
+ case DW_OP_APPLE_uninit:
+ s->PutCString("DW_OP_APPLE_uninit"); // 0xF0
+ break;
+// case DW_OP_APPLE_assign: // 0xF1 - pops value off and assigns it to second item on stack (2nd item must have assignable context)
+// s->PutCString("DW_OP_APPLE_assign");
+// break;
+// case DW_OP_APPLE_address_of: // 0xF2 - gets the address of the top stack item (top item must be a variable, or have value_type that is an address already)
+// s->PutCString("DW_OP_APPLE_address_of");
+// break;
+// case DW_OP_APPLE_value_of: // 0xF3 - pops the value off the stack and pushes the value of that object (top item must be a variable, or expression local)
+// s->PutCString("DW_OP_APPLE_value_of");
+// break;
+// case DW_OP_APPLE_deref_type: // 0xF4 - gets the address of the top stack item (top item must be a variable, or a clang type)
+// s->PutCString("DW_OP_APPLE_deref_type");
+// break;
+// case DW_OP_APPLE_expr_local: // 0xF5 - ULEB128 expression local index
+// s->Printf("DW_OP_APPLE_expr_local(%" PRIu64 ")", m_data.GetULEB128(&offset));
+// break;
+// case DW_OP_APPLE_constf: // 0xF6 - 1 byte float size, followed by constant float data
+// {
+// uint8_t float_length = m_data.GetU8(&offset);
+// s->Printf("DW_OP_APPLE_constf(<%u> ", float_length);
+// m_data.Dump(s, offset, eFormatHex, float_length, 1, UINT32_MAX, DW_INVALID_ADDRESS, 0, 0);
+// s->PutChar(')');
+// // Consume the float data
+// m_data.GetData(&offset, float_length);
+// }
+// break;
+// case DW_OP_APPLE_scalar_cast:
+// s->Printf("DW_OP_APPLE_scalar_cast(%s)", Scalar::GetValueTypeAsCString ((Scalar::Type)m_data.GetU8(&offset)));
+// break;
+// case DW_OP_APPLE_clang_cast:
+// {
+// clang::Type *clang_type = (clang::Type *)m_data.GetMaxU64(&offset, sizeof(void*));
+// s->Printf("DW_OP_APPLE_clang_cast(%p)", clang_type);
+// }
+// break;
+// case DW_OP_APPLE_clear:
+// s->PutCString("DW_OP_APPLE_clear");
+// break;
+// case DW_OP_APPLE_error: // 0xFF - Stops expression evaluation and returns an error (no args)
+// s->PutCString("DW_OP_APPLE_error");
+// break;
+ }
+ }
+}
+
+void
+DWARFExpression::SetLocationListSlide (addr_t slide)
+{
+ m_loclist_slide = slide;
+}
+
+int
+DWARFExpression::GetRegisterKind ()
+{
+ return m_reg_kind;
+}
+
+void
+DWARFExpression::SetRegisterKind (RegisterKind reg_kind)
+{
+ m_reg_kind = reg_kind;
+}
+
+bool
+DWARFExpression::IsLocationList() const
+{
+ return m_loclist_slide != LLDB_INVALID_ADDRESS;
+}
+
+void
+DWARFExpression::GetDescription (Stream *s, lldb::DescriptionLevel level, addr_t location_list_base_addr, ABI *abi) const
+{
+ if (IsLocationList())
+ {
+ // We have a location list
+ lldb::offset_t offset = 0;
+ uint32_t count = 0;
+ addr_t curr_base_addr = location_list_base_addr;
+ while (m_data.ValidOffset(offset))
+ {
+ lldb::addr_t begin_addr_offset = m_data.GetAddress(&offset);
+ lldb::addr_t end_addr_offset = m_data.GetAddress(&offset);
+ if (begin_addr_offset < end_addr_offset)
+ {
+ if (count > 0)
+ s->PutCString(", ");
+ VMRange addr_range(curr_base_addr + begin_addr_offset, curr_base_addr + end_addr_offset);
+ addr_range.Dump(s, 0, 8);
+ s->PutChar('{');
+ lldb::offset_t location_length = m_data.GetU16(&offset);
+ DumpLocation (s, offset, location_length, level, abi);
+ s->PutChar('}');
+ offset += location_length;
+ }
+ else if (begin_addr_offset == 0 && end_addr_offset == 0)
+ {
+ // The end of the location list is marked by both the start and end offset being zero
+ break;
+ }
+ else
+ {
+ if ((m_data.GetAddressByteSize() == 4 && (begin_addr_offset == UINT32_MAX)) ||
+ (m_data.GetAddressByteSize() == 8 && (begin_addr_offset == UINT64_MAX)))
+ {
+ curr_base_addr = end_addr_offset + location_list_base_addr;
+ // We have a new base address
+ if (count > 0)
+ s->PutCString(", ");
+ *s << "base_addr = " << end_addr_offset;
+ }
+ }
+
+ count++;
+ }
+ }
+ else
+ {
+ // We have a normal location that contains DW_OP location opcodes
+ DumpLocation (s, 0, m_data.GetByteSize(), level, abi);
+ }
+}
+
+static bool
+ReadRegisterValueAsScalar
+(
+ RegisterContext *reg_ctx,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ Error *error_ptr,
+ Value &value
+)
+{
+ if (reg_ctx == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("No register context in frame.\n");
+ }
+ else
+ {
+ uint32_t native_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num);
+ if (native_reg == LLDB_INVALID_REGNUM)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Unable to convert register kind=%u reg_num=%u to a native register number.\n", reg_kind, reg_num);
+ }
+ else
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(native_reg);
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ if (reg_value.GetScalarValue(value.GetScalar()))
+ {
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeRegisterInfo,
+ const_cast<RegisterInfo *>(reg_info));
+ if (error_ptr)
+ error_ptr->Clear();
+ return true;
+ }
+ else
+ {
+ // If we get this error, then we need to implement a value
+ // buffer in the dwarf expression evaluation function...
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("register %s can't be converted to a scalar value",
+ reg_info->name);
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("register %s is not available", reg_info->name);
+ }
+ }
+ }
+ return false;
+}
+
+//bool
+//DWARFExpression::LocationListContainsLoadAddress (Process* process, const Address &addr) const
+//{
+// return LocationListContainsLoadAddress(process, addr.GetLoadAddress(process));
+//}
+//
+//bool
+//DWARFExpression::LocationListContainsLoadAddress (Process* process, addr_t load_addr) const
+//{
+// if (load_addr == LLDB_INVALID_ADDRESS)
+// return false;
+//
+// if (IsLocationList())
+// {
+// lldb::offset_t offset = 0;
+//
+// addr_t loc_list_base_addr = m_loclist_slide.GetLoadAddress(process);
+//
+// if (loc_list_base_addr == LLDB_INVALID_ADDRESS)
+// return false;
+//
+// while (m_data.ValidOffset(offset))
+// {
+// // We need to figure out what the value is for the location.
+// addr_t lo_pc = m_data.GetAddress(&offset);
+// addr_t hi_pc = m_data.GetAddress(&offset);
+// if (lo_pc == 0 && hi_pc == 0)
+// break;
+// else
+// {
+// lo_pc += loc_list_base_addr;
+// hi_pc += loc_list_base_addr;
+//
+// if (lo_pc <= load_addr && load_addr < hi_pc)
+// return true;
+//
+// offset += m_data.GetU16(&offset);
+// }
+// }
+// }
+// return false;
+//}
+
+static offset_t
+GetOpcodeDataSize (const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op)
+{
+ lldb::offset_t offset = data_offset;
+ switch (op)
+ {
+ case DW_OP_addr:
+ case DW_OP_call_ref: // 0x9a 1 address sized offset of DIE (DWARF3)
+ return data.GetAddressByteSize();
+
+ // Opcodes with no arguments
+ case DW_OP_deref: // 0x06
+ case DW_OP_dup: // 0x12
+ case DW_OP_drop: // 0x13
+ case DW_OP_over: // 0x14
+ case DW_OP_swap: // 0x16
+ case DW_OP_rot: // 0x17
+ case DW_OP_xderef: // 0x18
+ case DW_OP_abs: // 0x19
+ case DW_OP_and: // 0x1a
+ case DW_OP_div: // 0x1b
+ case DW_OP_minus: // 0x1c
+ case DW_OP_mod: // 0x1d
+ case DW_OP_mul: // 0x1e
+ case DW_OP_neg: // 0x1f
+ case DW_OP_not: // 0x20
+ case DW_OP_or: // 0x21
+ case DW_OP_plus: // 0x22
+ case DW_OP_shl: // 0x24
+ case DW_OP_shr: // 0x25
+ case DW_OP_shra: // 0x26
+ case DW_OP_xor: // 0x27
+ case DW_OP_eq: // 0x29
+ case DW_OP_ge: // 0x2a
+ case DW_OP_gt: // 0x2b
+ case DW_OP_le: // 0x2c
+ case DW_OP_lt: // 0x2d
+ case DW_OP_ne: // 0x2e
+ case DW_OP_lit0: // 0x30
+ case DW_OP_lit1: // 0x31
+ case DW_OP_lit2: // 0x32
+ case DW_OP_lit3: // 0x33
+ case DW_OP_lit4: // 0x34
+ case DW_OP_lit5: // 0x35
+ case DW_OP_lit6: // 0x36
+ case DW_OP_lit7: // 0x37
+ case DW_OP_lit8: // 0x38
+ case DW_OP_lit9: // 0x39
+ case DW_OP_lit10: // 0x3A
+ case DW_OP_lit11: // 0x3B
+ case DW_OP_lit12: // 0x3C
+ case DW_OP_lit13: // 0x3D
+ case DW_OP_lit14: // 0x3E
+ case DW_OP_lit15: // 0x3F
+ case DW_OP_lit16: // 0x40
+ case DW_OP_lit17: // 0x41
+ case DW_OP_lit18: // 0x42
+ case DW_OP_lit19: // 0x43
+ case DW_OP_lit20: // 0x44
+ case DW_OP_lit21: // 0x45
+ case DW_OP_lit22: // 0x46
+ case DW_OP_lit23: // 0x47
+ case DW_OP_lit24: // 0x48
+ case DW_OP_lit25: // 0x49
+ case DW_OP_lit26: // 0x4A
+ case DW_OP_lit27: // 0x4B
+ case DW_OP_lit28: // 0x4C
+ case DW_OP_lit29: // 0x4D
+ case DW_OP_lit30: // 0x4E
+ case DW_OP_lit31: // 0x4f
+ case DW_OP_reg0: // 0x50
+ case DW_OP_reg1: // 0x51
+ case DW_OP_reg2: // 0x52
+ case DW_OP_reg3: // 0x53
+ case DW_OP_reg4: // 0x54
+ case DW_OP_reg5: // 0x55
+ case DW_OP_reg6: // 0x56
+ case DW_OP_reg7: // 0x57
+ case DW_OP_reg8: // 0x58
+ case DW_OP_reg9: // 0x59
+ case DW_OP_reg10: // 0x5A
+ case DW_OP_reg11: // 0x5B
+ case DW_OP_reg12: // 0x5C
+ case DW_OP_reg13: // 0x5D
+ case DW_OP_reg14: // 0x5E
+ case DW_OP_reg15: // 0x5F
+ case DW_OP_reg16: // 0x60
+ case DW_OP_reg17: // 0x61
+ case DW_OP_reg18: // 0x62
+ case DW_OP_reg19: // 0x63
+ case DW_OP_reg20: // 0x64
+ case DW_OP_reg21: // 0x65
+ case DW_OP_reg22: // 0x66
+ case DW_OP_reg23: // 0x67
+ case DW_OP_reg24: // 0x68
+ case DW_OP_reg25: // 0x69
+ case DW_OP_reg26: // 0x6A
+ case DW_OP_reg27: // 0x6B
+ case DW_OP_reg28: // 0x6C
+ case DW_OP_reg29: // 0x6D
+ case DW_OP_reg30: // 0x6E
+ case DW_OP_reg31: // 0x6F
+ case DW_OP_nop: // 0x96
+ case DW_OP_push_object_address: // 0x97 DWARF3
+ case DW_OP_form_tls_address: // 0x9b DWARF3
+ case DW_OP_call_frame_cfa: // 0x9c DWARF3
+ case DW_OP_stack_value: // 0x9f DWARF4
+ return 0;
+
+ // Opcodes with a single 1 byte arguments
+ case DW_OP_const1u: // 0x08 1 1-byte constant
+ case DW_OP_const1s: // 0x09 1 1-byte constant
+ case DW_OP_pick: // 0x15 1 1-byte stack index
+ case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved
+ case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved
+ return 1;
+
+ // Opcodes with a single 2 byte arguments
+ case DW_OP_const2u: // 0x0a 1 2-byte constant
+ case DW_OP_const2s: // 0x0b 1 2-byte constant
+ case DW_OP_skip: // 0x2f 1 signed 2-byte constant
+ case DW_OP_bra: // 0x28 1 signed 2-byte constant
+ case DW_OP_call2: // 0x98 1 2-byte offset of DIE (DWARF3)
+ return 2;
+
+ // Opcodes with a single 4 byte arguments
+ case DW_OP_const4u: // 0x0c 1 4-byte constant
+ case DW_OP_const4s: // 0x0d 1 4-byte constant
+ case DW_OP_call4: // 0x99 1 4-byte offset of DIE (DWARF3)
+ return 4;
+
+ // Opcodes with a single 8 byte arguments
+ case DW_OP_const8u: // 0x0e 1 8-byte constant
+ case DW_OP_const8s: // 0x0f 1 8-byte constant
+ return 8;
+
+ // All opcodes that have a single ULEB (signed or unsigned) argument
+ case DW_OP_constu: // 0x10 1 ULEB128 constant
+ case DW_OP_consts: // 0x11 1 SLEB128 constant
+ case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend
+ case DW_OP_breg0: // 0x70 1 ULEB128 register
+ case DW_OP_breg1: // 0x71 1 ULEB128 register
+ case DW_OP_breg2: // 0x72 1 ULEB128 register
+ case DW_OP_breg3: // 0x73 1 ULEB128 register
+ case DW_OP_breg4: // 0x74 1 ULEB128 register
+ case DW_OP_breg5: // 0x75 1 ULEB128 register
+ case DW_OP_breg6: // 0x76 1 ULEB128 register
+ case DW_OP_breg7: // 0x77 1 ULEB128 register
+ case DW_OP_breg8: // 0x78 1 ULEB128 register
+ case DW_OP_breg9: // 0x79 1 ULEB128 register
+ case DW_OP_breg10: // 0x7a 1 ULEB128 register
+ case DW_OP_breg11: // 0x7b 1 ULEB128 register
+ case DW_OP_breg12: // 0x7c 1 ULEB128 register
+ case DW_OP_breg13: // 0x7d 1 ULEB128 register
+ case DW_OP_breg14: // 0x7e 1 ULEB128 register
+ case DW_OP_breg15: // 0x7f 1 ULEB128 register
+ case DW_OP_breg16: // 0x80 1 ULEB128 register
+ case DW_OP_breg17: // 0x81 1 ULEB128 register
+ case DW_OP_breg18: // 0x82 1 ULEB128 register
+ case DW_OP_breg19: // 0x83 1 ULEB128 register
+ case DW_OP_breg20: // 0x84 1 ULEB128 register
+ case DW_OP_breg21: // 0x85 1 ULEB128 register
+ case DW_OP_breg22: // 0x86 1 ULEB128 register
+ case DW_OP_breg23: // 0x87 1 ULEB128 register
+ case DW_OP_breg24: // 0x88 1 ULEB128 register
+ case DW_OP_breg25: // 0x89 1 ULEB128 register
+ case DW_OP_breg26: // 0x8a 1 ULEB128 register
+ case DW_OP_breg27: // 0x8b 1 ULEB128 register
+ case DW_OP_breg28: // 0x8c 1 ULEB128 register
+ case DW_OP_breg29: // 0x8d 1 ULEB128 register
+ case DW_OP_breg30: // 0x8e 1 ULEB128 register
+ case DW_OP_breg31: // 0x8f 1 ULEB128 register
+ case DW_OP_regx: // 0x90 1 ULEB128 register
+ case DW_OP_fbreg: // 0x91 1 SLEB128 offset
+ case DW_OP_piece: // 0x93 1 ULEB128 size of piece addressed
+ data.Skip_LEB128(&offset);
+ return offset - data_offset;
+
+ // All opcodes that have a 2 ULEB (signed or unsigned) arguments
+ case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset
+ case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
+ data.Skip_LEB128(&offset);
+ data.Skip_LEB128(&offset);
+ return offset - data_offset;
+
+ case DW_OP_implicit_value: // 0x9e ULEB128 size followed by block of that size (DWARF4)
+ {
+ uint64_t block_len = data.Skip_LEB128(&offset);
+ offset += block_len;
+ return offset - data_offset;
+ }
+
+ default:
+ break;
+ }
+ return LLDB_INVALID_OFFSET;
+}
+
+lldb::addr_t
+DWARFExpression::GetLocation_DW_OP_addr (uint32_t op_addr_idx, bool &error) const
+{
+ error = false;
+ if (IsLocationList())
+ return LLDB_INVALID_ADDRESS;
+ lldb::offset_t offset = 0;
+ uint32_t curr_op_addr_idx = 0;
+ while (m_data.ValidOffset(offset))
+ {
+ const uint8_t op = m_data.GetU8(&offset);
+
+ if (op == DW_OP_addr)
+ {
+ const lldb::addr_t op_file_addr = m_data.GetAddress(&offset);
+ if (curr_op_addr_idx == op_addr_idx)
+ return op_file_addr;
+ else
+ ++curr_op_addr_idx;
+ }
+ else
+ {
+ const offset_t op_arg_size = GetOpcodeDataSize (m_data, offset, op);
+ if (op_arg_size == LLDB_INVALID_OFFSET)
+ {
+ error = true;
+ break;
+ }
+ offset += op_arg_size;
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+DWARFExpression::Update_DW_OP_addr (lldb::addr_t file_addr)
+{
+ if (IsLocationList())
+ return false;
+ lldb::offset_t offset = 0;
+ while (m_data.ValidOffset(offset))
+ {
+ const uint8_t op = m_data.GetU8(&offset);
+
+ if (op == DW_OP_addr)
+ {
+ const uint32_t addr_byte_size = m_data.GetAddressByteSize();
+ // We have to make a copy of the data as we don't know if this
+ // data is from a read only memory mapped buffer, so we duplicate
+ // all of the data first, then modify it, and if all goes well,
+ // we then replace the data for this expression
+
+ // So first we copy the data into a heap buffer
+ std::unique_ptr<DataBufferHeap> head_data_ap (new DataBufferHeap (m_data.GetDataStart(),
+ m_data.GetByteSize()));
+
+ // Make en encoder so we can write the address into the buffer using
+ // the correct byte order (endianness)
+ DataEncoder encoder (head_data_ap->GetBytes(),
+ head_data_ap->GetByteSize(),
+ m_data.GetByteOrder(),
+ addr_byte_size);
+
+ // Replace the address in the new buffer
+ if (encoder.PutMaxU64 (offset, addr_byte_size, file_addr) == UINT32_MAX)
+ return false;
+
+ // All went well, so now we can reset the data using a shared
+ // pointer to the heap data so "m_data" will now correctly
+ // manage the heap data.
+ m_data.SetData (DataBufferSP (head_data_ap.release()));
+ return true;
+ }
+ else
+ {
+ const offset_t op_arg_size = GetOpcodeDataSize (m_data, offset, op);
+ if (op_arg_size == LLDB_INVALID_OFFSET)
+ break;
+ offset += op_arg_size;
+ }
+ }
+ return false;
+}
+
+bool
+DWARFExpression::LocationListContainsAddress (lldb::addr_t loclist_base_addr, lldb::addr_t addr) const
+{
+ if (addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (IsLocationList())
+ {
+ lldb::offset_t offset = 0;
+
+ if (loclist_base_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ while (m_data.ValidOffset(offset))
+ {
+ // We need to figure out what the value is for the location.
+ addr_t lo_pc = m_data.GetAddress(&offset);
+ addr_t hi_pc = m_data.GetAddress(&offset);
+ if (lo_pc == 0 && hi_pc == 0)
+ break;
+ else
+ {
+ lo_pc += loclist_base_addr - m_loclist_slide;
+ hi_pc += loclist_base_addr - m_loclist_slide;
+
+ if (lo_pc <= addr && addr < hi_pc)
+ return true;
+
+ offset += m_data.GetU16(&offset);
+ }
+ }
+ }
+ return false;
+}
+
+bool
+DWARFExpression::GetLocation (addr_t base_addr, addr_t pc, lldb::offset_t &offset, lldb::offset_t &length)
+{
+ offset = 0;
+ if (!IsLocationList())
+ {
+ length = m_data.GetByteSize();
+ return true;
+ }
+
+ if (base_addr != LLDB_INVALID_ADDRESS && pc != LLDB_INVALID_ADDRESS)
+ {
+ addr_t curr_base_addr = base_addr;
+
+ while (m_data.ValidOffset(offset))
+ {
+ // We need to figure out what the value is for the location.
+ addr_t lo_pc = m_data.GetAddress(&offset);
+ addr_t hi_pc = m_data.GetAddress(&offset);
+ if (lo_pc == 0 && hi_pc == 0)
+ {
+ break;
+ }
+ else
+ {
+ lo_pc += curr_base_addr - m_loclist_slide;
+ hi_pc += curr_base_addr - m_loclist_slide;
+
+ length = m_data.GetU16(&offset);
+
+ if (length > 0 && lo_pc <= pc && pc < hi_pc)
+ return true;
+
+ offset += length;
+ }
+ }
+ }
+ offset = LLDB_INVALID_OFFSET;
+ length = 0;
+ return false;
+}
+
+bool
+DWARFExpression::DumpLocationForAddress (Stream *s,
+ lldb::DescriptionLevel level,
+ addr_t base_addr,
+ addr_t address,
+ ABI *abi)
+{
+ lldb::offset_t offset = 0;
+ lldb::offset_t length = 0;
+
+ if (GetLocation (base_addr, address, offset, length))
+ {
+ if (length > 0)
+ {
+ DumpLocation(s, offset, length, level, abi);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContextScope *exe_scope,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ lldb::addr_t loclist_base_load_addr,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+) const
+{
+ ExecutionContext exe_ctx (exe_scope);
+ return Evaluate(&exe_ctx, expr_locals, decl_map, NULL, loclist_base_load_addr, initial_value_ptr, result, error_ptr);
+}
+
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContext *exe_ctx,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ RegisterContext *reg_ctx,
+ lldb::addr_t loclist_base_load_addr,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+) const
+{
+ if (IsLocationList())
+ {
+ lldb::offset_t offset = 0;
+ addr_t pc;
+ StackFrame *frame = NULL;
+ if (reg_ctx)
+ pc = reg_ctx->GetPC();
+ else
+ {
+ frame = exe_ctx->GetFramePtr();
+ if (!frame)
+ return false;
+ RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
+ if (!reg_ctx_sp)
+ return false;
+ pc = reg_ctx_sp->GetPC();
+ }
+
+ if (loclist_base_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (pc == LLDB_INVALID_ADDRESS)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid PC in frame.");
+ return false;
+ }
+
+ addr_t curr_loclist_base_load_addr = loclist_base_load_addr;
+
+ while (m_data.ValidOffset(offset))
+ {
+ // We need to figure out what the value is for the location.
+ addr_t lo_pc = m_data.GetAddress(&offset);
+ addr_t hi_pc = m_data.GetAddress(&offset);
+ if (lo_pc == 0 && hi_pc == 0)
+ {
+ break;
+ }
+ else
+ {
+ lo_pc += curr_loclist_base_load_addr - m_loclist_slide;
+ hi_pc += curr_loclist_base_load_addr - m_loclist_slide;
+
+ uint16_t length = m_data.GetU16(&offset);
+
+ if (length > 0 && lo_pc <= pc && pc < hi_pc)
+ {
+ return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, m_data, offset, length, m_reg_kind, initial_value_ptr, result, error_ptr);
+ }
+ offset += length;
+ }
+ }
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString ("variable not available");
+ return false;
+ }
+
+ // Not a location list, just a single expression.
+ return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, m_data, 0, m_data.GetByteSize(), m_reg_kind, initial_value_ptr, result, error_ptr);
+}
+
+
+
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContext *exe_ctx,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ RegisterContext *reg_ctx,
+ const DataExtractor& opcodes,
+ const lldb::offset_t opcodes_offset,
+ const lldb::offset_t opcodes_length,
+ const uint32_t reg_kind,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+)
+{
+
+ if (opcodes_length == 0)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("no location, value may have been optimized out");
+ return false;
+ }
+ std::vector<Value> stack;
+
+ Process *process = NULL;
+ StackFrame *frame = NULL;
+
+ if (exe_ctx)
+ {
+ process = exe_ctx->GetProcessPtr();
+ frame = exe_ctx->GetFramePtr();
+ }
+ if (reg_ctx == NULL && frame)
+ reg_ctx = frame->GetRegisterContext().get();
+
+ if (initial_value_ptr)
+ stack.push_back(*initial_value_ptr);
+
+ lldb::offset_t offset = opcodes_offset;
+ const lldb::offset_t end_offset = opcodes_offset + opcodes_length;
+ Value tmp;
+ uint32_t reg_num;
+
+ // Make sure all of the data is available in opcodes.
+ if (!opcodes.ValidOffsetForDataOfSize(opcodes_offset, opcodes_length))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("invalid offset and/or length for opcodes buffer.");
+ return false;
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+
+ while (opcodes.ValidOffset(offset) && offset < end_offset)
+ {
+ const lldb::offset_t op_offset = offset;
+ const uint8_t op = opcodes.GetU8(&offset);
+
+ if (log && log->GetVerbose())
+ {
+ size_t count = stack.size();
+ log->Printf("Stack before operation has %lu values:", count);
+ for (size_t i=0; i<count; ++i)
+ {
+ StreamString new_value;
+ new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
+ stack[i].Dump(&new_value);
+ log->Printf(" %s", new_value.GetData());
+ }
+ log->Printf("0x%8.8" PRIx64 ": %s", op_offset, DW_OP_value_to_name(op));
+ }
+ switch (op)
+ {
+ //----------------------------------------------------------------------
+ // The DW_OP_addr operation has a single operand that encodes a machine
+ // address and whose size is the size of an address on the target machine.
+ //----------------------------------------------------------------------
+ case DW_OP_addr:
+ stack.push_back(Scalar(opcodes.GetAddress(&offset)));
+ stack.back().SetValueType (Value::eValueTypeFileAddress);
+ break;
+
+ //----------------------------------------------------------------------
+ // The DW_OP_addr_sect_offset4 is used for any location expressions in
+ // shared libraries that have a location like:
+ // DW_OP_addr(0x1000)
+ // If this address resides in a shared library, then this virtual
+ // address won't make sense when it is evaluated in the context of a
+ // running process where shared libraries have been slid. To account for
+ // this, this new address type where we can store the section pointer
+ // and a 4 byte offset.
+ //----------------------------------------------------------------------
+// case DW_OP_addr_sect_offset4:
+// {
+// result_type = eResultTypeFileAddress;
+// lldb::Section *sect = (lldb::Section *)opcodes.GetMaxU64(&offset, sizeof(void *));
+// lldb::addr_t sect_offset = opcodes.GetU32(&offset);
+//
+// Address so_addr (sect, sect_offset);
+// lldb::addr_t load_addr = so_addr.GetLoadAddress();
+// if (load_addr != LLDB_INVALID_ADDRESS)
+// {
+// // We successfully resolve a file address to a load
+// // address.
+// stack.push_back(load_addr);
+// break;
+// }
+// else
+// {
+// // We were able
+// if (error_ptr)
+// error_ptr->SetErrorStringWithFormat ("Section %s in %s is not currently loaded.\n", sect->GetName().AsCString(), sect->GetModule()->GetFileSpec().GetFilename().AsCString());
+// return false;
+// }
+// }
+// break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_deref
+ // OPERANDS: none
+ // DESCRIPTION: Pops the top stack entry and treats it as an address.
+ // The value retrieved from that address is pushed. The size of the
+ // data retrieved from the dereferenced address is the size of an
+ // address on the target machine.
+ //----------------------------------------------------------------------
+ case DW_OP_deref:
+ {
+ Value::ValueType value_type = stack.back().GetValueType();
+ switch (value_type)
+ {
+ case Value::eValueTypeHostAddress:
+ {
+ void *src = (void *)stack.back().GetScalar().ULongLong();
+ intptr_t ptr;
+ ::memcpy (&ptr, src, sizeof(void *));
+ stack.back().GetScalar() = ptr;
+ stack.back().ClearContext();
+ }
+ break;
+ case Value::eValueTypeLoadAddress:
+ if (exe_ctx)
+ {
+ if (process)
+ {
+ lldb::addr_t pointer_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ uint8_t addr_bytes[sizeof(lldb::addr_t)];
+ uint32_t addr_size = process->GetAddressByteSize();
+ Error error;
+ if (process->ReadMemory(pointer_addr, &addr_bytes, addr_size, error) == addr_size)
+ {
+ DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), addr_size);
+ lldb::offset_t addr_data_offset = 0;
+ stack.back().GetScalar() = addr_data.GetPointer(&addr_data_offset);
+ stack.back().ClearContext();
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Failed to dereference pointer from 0x%" PRIx64 " for DW_OP_deref: %s\n",
+ pointer_addr,
+ error.AsCString());
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL process for DW_OP_deref.\n");
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_deref.\n");
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_deref_size
+ // OPERANDS: 1
+ // 1 - uint8_t that specifies the size of the data to dereference.
+ // DESCRIPTION: Behaves like the DW_OP_deref operation: it pops the top
+ // stack entry and treats it as an address. The value retrieved from that
+ // address is pushed. In the DW_OP_deref_size operation, however, the
+ // size in bytes of the data retrieved from the dereferenced address is
+ // specified by the single operand. This operand is a 1-byte unsigned
+ // integral constant whose value may not be larger than the size of an
+ // address on the target machine. The data retrieved is zero extended
+ // to the size of an address on the target machine before being pushed
+ // on the expression stack.
+ //----------------------------------------------------------------------
+ case DW_OP_deref_size:
+ {
+ uint8_t size = opcodes.GetU8(&offset);
+ Value::ValueType value_type = stack.back().GetValueType();
+ switch (value_type)
+ {
+ case Value::eValueTypeHostAddress:
+ {
+ void *src = (void *)stack.back().GetScalar().ULongLong();
+ intptr_t ptr;
+ ::memcpy (&ptr, src, sizeof(void *));
+ // I can't decide whether the size operand should apply to the bytes in their
+ // lldb-host endianness or the target endianness.. I doubt this'll ever come up
+ // but I'll opt for assuming big endian regardless.
+ switch (size)
+ {
+ case 1: ptr = ptr & 0xff; break;
+ case 2: ptr = ptr & 0xffff; break;
+ case 3: ptr = ptr & 0xffffff; break;
+ case 4: ptr = ptr & 0xffffffff; break;
+ // the casts are added to work around the case where intptr_t is a 32 bit quantity;
+ // presumably we won't hit the 5..7 cases if (void*) is 32-bits in this program.
+ case 5: ptr = (intptr_t) ptr & 0xffffffffffULL; break;
+ case 6: ptr = (intptr_t) ptr & 0xffffffffffffULL; break;
+ case 7: ptr = (intptr_t) ptr & 0xffffffffffffffULL; break;
+ default: break;
+ }
+ stack.back().GetScalar() = ptr;
+ stack.back().ClearContext();
+ }
+ break;
+ case Value::eValueTypeLoadAddress:
+ if (exe_ctx)
+ {
+ if (process)
+ {
+ lldb::addr_t pointer_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ uint8_t addr_bytes[sizeof(lldb::addr_t)];
+ Error error;
+ if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) == size)
+ {
+ DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), size);
+ lldb::offset_t addr_data_offset = 0;
+ switch (size)
+ {
+ case 1: stack.back().GetScalar() = addr_data.GetU8(&addr_data_offset); break;
+ case 2: stack.back().GetScalar() = addr_data.GetU16(&addr_data_offset); break;
+ case 4: stack.back().GetScalar() = addr_data.GetU32(&addr_data_offset); break;
+ case 8: stack.back().GetScalar() = addr_data.GetU64(&addr_data_offset); break;
+ default: stack.back().GetScalar() = addr_data.GetPointer(&addr_data_offset);
+ }
+ stack.back().ClearContext();
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Failed to dereference pointer from 0x%" PRIx64 " for DW_OP_deref: %s\n",
+ pointer_addr,
+ error.AsCString());
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL process for DW_OP_deref.\n");
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_deref.\n");
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_xderef_size
+ // OPERANDS: 1
+ // 1 - uint8_t that specifies the size of the data to dereference.
+ // DESCRIPTION: Behaves like the DW_OP_xderef operation: the entry at
+ // the top of the stack is treated as an address. The second stack
+ // entry is treated as an "address space identifier" for those
+ // architectures that support multiple address spaces. The top two
+ // stack elements are popped, a data item is retrieved through an
+ // implementation-defined address calculation and pushed as the new
+ // stack top. In the DW_OP_xderef_size operation, however, the size in
+ // bytes of the data retrieved from the dereferenced address is
+ // specified by the single operand. This operand is a 1-byte unsigned
+ // integral constant whose value may not be larger than the size of an
+ // address on the target machine. The data retrieved is zero extended
+ // to the size of an address on the target machine before being pushed
+ // on the expression stack.
+ //----------------------------------------------------------------------
+ case DW_OP_xderef_size:
+ if (error_ptr)
+ error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef_size.");
+ return false;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_xderef
+ // OPERANDS: none
+ // DESCRIPTION: Provides an extended dereference mechanism. The entry at
+ // the top of the stack is treated as an address. The second stack entry
+ // is treated as an "address space identifier" for those architectures
+ // that support multiple address spaces. The top two stack elements are
+ // popped, a data item is retrieved through an implementation-defined
+ // address calculation and pushed as the new stack top. The size of the
+ // data retrieved from the dereferenced address is the size of an address
+ // on the target machine.
+ //----------------------------------------------------------------------
+ case DW_OP_xderef:
+ if (error_ptr)
+ error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // All DW_OP_constXXX opcodes have a single operand as noted below:
+ //
+ // Opcode Operand 1
+ // --------------- ----------------------------------------------------
+ // DW_OP_const1u 1-byte unsigned integer constant
+ // DW_OP_const1s 1-byte signed integer constant
+ // DW_OP_const2u 2-byte unsigned integer constant
+ // DW_OP_const2s 2-byte signed integer constant
+ // DW_OP_const4u 4-byte unsigned integer constant
+ // DW_OP_const4s 4-byte signed integer constant
+ // DW_OP_const8u 8-byte unsigned integer constant
+ // DW_OP_const8s 8-byte signed integer constant
+ // DW_OP_constu unsigned LEB128 integer constant
+ // DW_OP_consts signed LEB128 integer constant
+ //----------------------------------------------------------------------
+ case DW_OP_const1u : stack.push_back(Scalar(( uint8_t)opcodes.GetU8 (&offset))); break;
+ case DW_OP_const1s : stack.push_back(Scalar(( int8_t)opcodes.GetU8 (&offset))); break;
+ case DW_OP_const2u : stack.push_back(Scalar((uint16_t)opcodes.GetU16 (&offset))); break;
+ case DW_OP_const2s : stack.push_back(Scalar(( int16_t)opcodes.GetU16 (&offset))); break;
+ case DW_OP_const4u : stack.push_back(Scalar((uint32_t)opcodes.GetU32 (&offset))); break;
+ case DW_OP_const4s : stack.push_back(Scalar(( int32_t)opcodes.GetU32 (&offset))); break;
+ case DW_OP_const8u : stack.push_back(Scalar((uint64_t)opcodes.GetU64 (&offset))); break;
+ case DW_OP_const8s : stack.push_back(Scalar(( int64_t)opcodes.GetU64 (&offset))); break;
+ case DW_OP_constu : stack.push_back(Scalar(opcodes.GetULEB128 (&offset))); break;
+ case DW_OP_consts : stack.push_back(Scalar(opcodes.GetSLEB128 (&offset))); break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_dup
+ // OPERANDS: none
+ // DESCRIPTION: duplicates the value at the top of the stack
+ //----------------------------------------------------------------------
+ case DW_OP_dup:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack empty for DW_OP_dup.");
+ return false;
+ }
+ else
+ stack.push_back(stack.back());
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_drop
+ // OPERANDS: none
+ // DESCRIPTION: pops the value at the top of the stack
+ //----------------------------------------------------------------------
+ case DW_OP_drop:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack empty for DW_OP_drop.");
+ return false;
+ }
+ else
+ stack.pop_back();
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_over
+ // OPERANDS: none
+ // DESCRIPTION: Duplicates the entry currently second in the stack at
+ // the top of the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_over:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_over.");
+ return false;
+ }
+ else
+ stack.push_back(stack[stack.size() - 2]);
+ break;
+
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_pick
+ // OPERANDS: uint8_t index into the current stack
+ // DESCRIPTION: The stack entry with the specified index (0 through 255,
+ // inclusive) is pushed on the stack
+ //----------------------------------------------------------------------
+ case DW_OP_pick:
+ {
+ uint8_t pick_idx = opcodes.GetU8(&offset);
+ if (pick_idx < stack.size())
+ stack.push_back(stack[pick_idx]);
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Index %u out of range for DW_OP_pick.\n", pick_idx);
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_swap
+ // OPERANDS: none
+ // DESCRIPTION: swaps the top two stack entries. The entry at the top
+ // of the stack becomes the second stack entry, and the second entry
+ // becomes the top of the stack
+ //----------------------------------------------------------------------
+ case DW_OP_swap:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_swap.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.back() = stack[stack.size() - 2];
+ stack[stack.size() - 2] = tmp;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_rot
+ // OPERANDS: none
+ // DESCRIPTION: Rotates the first three stack entries. The entry at
+ // the top of the stack becomes the third stack entry, the second
+ // entry becomes the top of the stack, and the third entry becomes
+ // the second entry.
+ //----------------------------------------------------------------------
+ case DW_OP_rot:
+ if (stack.size() < 3)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 3 items for DW_OP_rot.");
+ return false;
+ }
+ else
+ {
+ size_t last_idx = stack.size() - 1;
+ Value old_top = stack[last_idx];
+ stack[last_idx] = stack[last_idx - 1];
+ stack[last_idx - 1] = stack[last_idx - 2];
+ stack[last_idx - 2] = old_top;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_abs
+ // OPERANDS: none
+ // DESCRIPTION: pops the top stack entry, interprets it as a signed
+ // value and pushes its absolute value. If the absolute value can not be
+ // represented, the result is undefined.
+ //----------------------------------------------------------------------
+ case DW_OP_abs:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_abs.");
+ return false;
+ }
+ else if (stack.back().ResolveValue(exe_ctx).AbsoluteValue() == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Failed to take the absolute value of the first stack item.");
+ return false;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_and
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, performs a bitwise and
+ // operation on the two, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_and:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_and.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) & tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_div
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, divides the former second
+ // entry by the former top of the stack using signed division, and
+ // pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_div:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_div.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ if (tmp.ResolveValue(exe_ctx).IsZero())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Divide by zero.");
+ return false;
+ }
+ else
+ {
+ stack.pop_back();
+ stack.back() = stack.back().ResolveValue(exe_ctx) / tmp.ResolveValue(exe_ctx);
+ if (!stack.back().ResolveValue(exe_ctx).IsValid())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Divide failed.");
+ return false;
+ }
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_minus
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, subtracts the former top
+ // of the stack from the former second entry, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_minus:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_minus.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) - tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_mod
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values and pushes the result of
+ // the calculation: former second stack entry modulo the former top of
+ // the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_mod:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_mod.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) % tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_mul
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, multiplies them
+ // together, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_mul:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_mul.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) * tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_neg
+ // OPERANDS: none
+ // DESCRIPTION: pops the top stack entry, and pushes its negation.
+ //----------------------------------------------------------------------
+ case DW_OP_neg:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_neg.");
+ return false;
+ }
+ else
+ {
+ if (stack.back().ResolveValue(exe_ctx).UnaryNegate() == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Unary negate failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_not
+ // OPERANDS: none
+ // DESCRIPTION: pops the top stack entry, and pushes its bitwise
+ // complement
+ //----------------------------------------------------------------------
+ case DW_OP_not:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_not.");
+ return false;
+ }
+ else
+ {
+ if (stack.back().ResolveValue(exe_ctx).OnesComplement() == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Logical NOT failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_or
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, performs a bitwise or
+ // operation on the two, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_or:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_or.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) | tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_plus
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, adds them together, and
+ // pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_plus:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_plus.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) + tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_plus_uconst
+ // OPERANDS: none
+ // DESCRIPTION: pops the top stack entry, adds it to the unsigned LEB128
+ // constant operand and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_plus_uconst:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_plus_uconst.");
+ return false;
+ }
+ else
+ {
+ const uint64_t uconst_value = opcodes.GetULEB128(&offset);
+ // Implicit conversion from a UINT to a Scalar...
+ stack.back().ResolveValue(exe_ctx) += uconst_value;
+ if (!stack.back().ResolveValue(exe_ctx).IsValid())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("DW_OP_plus_uconst failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_shl
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, shifts the former
+ // second entry left by the number of bits specified by the former top
+ // of the stack, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_shl:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shl.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) <<= tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_shr
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, shifts the former second
+ // entry right logically (filling with zero bits) by the number of bits
+ // specified by the former top of the stack, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_shr:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shr.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ if (stack.back().ResolveValue(exe_ctx).ShiftRightLogical(tmp.ResolveValue(exe_ctx)) == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("DW_OP_shr failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_shra
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, shifts the former second
+ // entry right arithmetically (divide the magnitude by 2, keep the same
+ // sign for the result) by the number of bits specified by the former
+ // top of the stack, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_shra:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shra.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) >>= tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_xor
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, performs the bitwise
+ // exclusive-or operation on the two, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_xor:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_xor.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) ^ tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_skip
+ // OPERANDS: int16_t
+ // DESCRIPTION: An unconditional branch. Its single operand is a 2-byte
+ // signed integer constant. The 2-byte constant is the number of bytes
+ // of the DWARF expression to skip forward or backward from the current
+ // operation, beginning after the 2-byte constant.
+ //----------------------------------------------------------------------
+ case DW_OP_skip:
+ {
+ int16_t skip_offset = (int16_t)opcodes.GetU16(&offset);
+ lldb::offset_t new_offset = offset + skip_offset;
+ if (new_offset >= opcodes_offset && new_offset < end_offset)
+ offset = new_offset;
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid opcode offset in DW_OP_skip.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_bra
+ // OPERANDS: int16_t
+ // DESCRIPTION: A conditional branch. Its single operand is a 2-byte
+ // signed integer constant. This operation pops the top of stack. If
+ // the value popped is not the constant 0, the 2-byte constant operand
+ // is the number of bytes of the DWARF expression to skip forward or
+ // backward from the current operation, beginning after the 2-byte
+ // constant.
+ //----------------------------------------------------------------------
+ case DW_OP_bra:
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ int16_t bra_offset = (int16_t)opcodes.GetU16(&offset);
+ Scalar zero(0);
+ if (tmp.ResolveValue(exe_ctx) != zero)
+ {
+ lldb::offset_t new_offset = offset + bra_offset;
+ if (new_offset >= opcodes_offset && new_offset < end_offset)
+ offset = new_offset;
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid opcode offset in DW_OP_bra.");
+ return false;
+ }
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_eq
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // equals (==) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_eq:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_eq.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) == tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_ge
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // greater than or equal to (>=) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_ge:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_ge.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) >= tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_gt
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // greater than (>) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_gt:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_gt.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) > tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_le
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // less than or equal to (<=) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_le:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_le.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) <= tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_lt
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // less than (<) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_lt:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_lt.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) < tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_ne
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // not equal (!=) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_ne:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_ne.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) != tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_litn
+ // OPERANDS: none
+ // DESCRIPTION: encode the unsigned literal values from 0 through 31.
+ // STACK RESULT: push the unsigned literal constant value onto the top
+ // of the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ stack.push_back(Scalar(op - DW_OP_lit0));
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_regN
+ // OPERANDS: none
+ // DESCRIPTION: Push the value in register n on the top of the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ {
+ reg_num = op - DW_OP_reg0;
+
+ if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ stack.push_back(tmp);
+ else
+ return false;
+ }
+ break;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_regx
+ // OPERANDS:
+ // ULEB128 literal operand that encodes the register.
+ // DESCRIPTION: Push the value in register on the top of the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_regx:
+ {
+ reg_num = opcodes.GetULEB128(&offset);
+ if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ stack.push_back(tmp);
+ else
+ return false;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_bregN
+ // OPERANDS:
+ // SLEB128 offset from register N
+ // DESCRIPTION: Value is in memory at the address specified by register
+ // N plus an offset.
+ //----------------------------------------------------------------------
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ {
+ reg_num = op - DW_OP_breg0;
+
+ if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ {
+ int64_t breg_offset = opcodes.GetSLEB128(&offset);
+ tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset;
+ tmp.ClearContext();
+ stack.push_back(tmp);
+ stack.back().SetValueType (Value::eValueTypeLoadAddress);
+ }
+ else
+ return false;
+ }
+ break;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_bregx
+ // OPERANDS: 2
+ // ULEB128 literal operand that encodes the register.
+ // SLEB128 offset from register N
+ // DESCRIPTION: Value is in memory at the address specified by register
+ // N plus an offset.
+ //----------------------------------------------------------------------
+ case DW_OP_bregx:
+ {
+ reg_num = opcodes.GetULEB128(&offset);
+
+ if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ {
+ int64_t breg_offset = opcodes.GetSLEB128(&offset);
+ tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset;
+ tmp.ClearContext();
+ stack.push_back(tmp);
+ stack.back().SetValueType (Value::eValueTypeLoadAddress);
+ }
+ else
+ return false;
+ }
+ break;
+
+ case DW_OP_fbreg:
+ if (exe_ctx)
+ {
+ if (frame)
+ {
+ Scalar value;
+ if (frame->GetFrameBaseValue(value, error_ptr))
+ {
+ int64_t fbreg_offset = opcodes.GetSLEB128(&offset);
+ value += fbreg_offset;
+ stack.push_back(value);
+ stack.back().SetValueType (Value::eValueTypeLoadAddress);
+ }
+ else
+ return false;
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Invalid stack frame in context for DW_OP_fbreg opcode.");
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_fbreg.\n");
+ return false;
+ }
+
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_nop
+ // OPERANDS: none
+ // DESCRIPTION: A place holder. It has no effect on the location stack
+ // or any of its values.
+ //----------------------------------------------------------------------
+ case DW_OP_nop:
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_piece
+ // OPERANDS: 1
+ // ULEB128: byte size of the piece
+ // DESCRIPTION: The operand describes the size in bytes of the piece of
+ // the object referenced by the DWARF expression whose result is at the
+ // top of the stack. If the piece is located in a register, but does not
+ // occupy the entire register, the placement of the piece within that
+ // register is defined by the ABI.
+ //
+ // Many compilers store a single variable in sets of registers, or store
+ // a variable partially in memory and partially in registers.
+ // DW_OP_piece provides a way of describing how large a part of a
+ // variable a particular DWARF expression refers to.
+ //----------------------------------------------------------------------
+ case DW_OP_piece:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_piece.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_push_object_address
+ // OPERANDS: none
+ // DESCRIPTION: Pushes the address of the object currently being
+ // evaluated as part of evaluation of a user presented expression.
+ // This object may correspond to an independent variable described by
+ // its own DIE or it may be a component of an array, structure, or class
+ // whose address has been dynamically determined by an earlier step
+ // during user expression evaluation.
+ //----------------------------------------------------------------------
+ case DW_OP_push_object_address:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_push_object_address.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_call2
+ // OPERANDS:
+ // uint16_t compile unit relative offset of a DIE
+ // DESCRIPTION: Performs subroutine calls during evaluation
+ // of a DWARF expression. The operand is the 2-byte unsigned offset
+ // of a debugging information entry in the current compilation unit.
+ //
+ // Operand interpretation is exactly like that for DW_FORM_ref2.
+ //
+ // This operation transfers control of DWARF expression evaluation
+ // to the DW_AT_location attribute of the referenced DIE. If there is
+ // no such attribute, then there is no effect. Execution of the DWARF
+ // expression of a DW_AT_location attribute may add to and/or remove from
+ // values on the stack. Execution returns to the point following the call
+ // when the end of the attribute is reached. Values on the stack at the
+ // time of the call may be used as parameters by the called expression
+ // and values left on the stack by the called expression may be used as
+ // return values by prior agreement between the calling and called
+ // expressions.
+ //----------------------------------------------------------------------
+ case DW_OP_call2:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call2.");
+ return false;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_call4
+ // OPERANDS: 1
+ // uint32_t compile unit relative offset of a DIE
+ // DESCRIPTION: Performs a subroutine call during evaluation of a DWARF
+ // expression. For DW_OP_call4, the operand is a 4-byte unsigned offset
+ // of a debugging information entry in the current compilation unit.
+ //
+ // Operand interpretation DW_OP_call4 is exactly like that for
+ // DW_FORM_ref4.
+ //
+ // This operation transfers control of DWARF expression evaluation
+ // to the DW_AT_location attribute of the referenced DIE. If there is
+ // no such attribute, then there is no effect. Execution of the DWARF
+ // expression of a DW_AT_location attribute may add to and/or remove from
+ // values on the stack. Execution returns to the point following the call
+ // when the end of the attribute is reached. Values on the stack at the
+ // time of the call may be used as parameters by the called expression
+ // and values left on the stack by the called expression may be used as
+ // return values by prior agreement between the calling and called
+ // expressions.
+ //----------------------------------------------------------------------
+ case DW_OP_call4:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call4.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_stack_value
+ // OPERANDS: None
+ // DESCRIPTION: Specifies that the object does not exist in memory but
+ // rather is a constant value. The value from the top of the stack is
+ // the value to be used. This is the actual object value and not the
+ // location.
+ //----------------------------------------------------------------------
+ case DW_OP_stack_value:
+ stack.back().SetValueType(Value::eValueTypeScalar);
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_call_frame_cfa
+ // OPERANDS: None
+ // DESCRIPTION: Specifies a DWARF expression that pushes the value of
+ // the canonical frame address consistent with the call frame information
+ // located in .debug_frame (or in the FDEs of the eh_frame section).
+ //----------------------------------------------------------------------
+ case DW_OP_call_frame_cfa:
+ if (frame)
+ {
+ // Note that we don't have to parse FDEs because this DWARF expression
+ // is commonly evaluated with a valid stack frame.
+ StackID id = frame->GetStackID();
+ addr_t cfa = id.GetCallFrameAddress();
+ if (cfa != LLDB_INVALID_ADDRESS)
+ {
+ stack.push_back(Scalar(cfa));
+ stack.back().SetValueType (Value::eValueTypeHostAddress);
+ }
+ else
+ if (error_ptr)
+ error_ptr->SetErrorString ("Stack frame does not include a canonical frame address for DW_OP_call_frame_cfa opcode.");
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Invalid stack frame in context for DW_OP_call_frame_cfa opcode.");
+ return false;
+ }
+ break;
+ default:
+ if (log)
+ log->Printf("Unhandled opcode %s in DWARFExpression.", DW_OP_value_to_name(op));
+ break;
+ }
+ }
+
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Stack empty after evaluation.");
+ return false;
+ }
+ else if (log && log->GetVerbose())
+ {
+ size_t count = stack.size();
+ log->Printf("Stack after operation has %lu values:", count);
+ for (size_t i=0; i<count; ++i)
+ {
+ StreamString new_value;
+ new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
+ stack[i].Dump(&new_value);
+ log->Printf(" %s", new_value.GetData());
+ }
+ }
+
+ result = stack.back();
+ return true; // Return true on success
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp b/contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp
new file mode 100644
index 0000000..aef3b9e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/ExpressionSourceCode.cpp
@@ -0,0 +1,142 @@
+//===-- ExpressionSourceCode.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Expression/ExpressionSourceCode.h"
+
+#include "lldb/Core/StreamString.h"
+
+using namespace lldb_private;
+
+const char *
+ExpressionSourceCode::g_expression_prefix = R"(
+#undef NULL
+#undef Nil
+#undef nil
+#undef YES
+#undef NO
+#define NULL (__null)
+#define Nil (__null)
+#define nil (__null)
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+typedef signed char BOOL;
+typedef signed __INT8_TYPE__ int8_t;
+typedef unsigned __INT8_TYPE__ uint8_t;
+typedef signed __INT16_TYPE__ int16_t;
+typedef unsigned __INT16_TYPE__ uint16_t;
+typedef signed __INT32_TYPE__ int32_t;
+typedef unsigned __INT32_TYPE__ uint32_t;
+typedef signed __INT64_TYPE__ int64_t;
+typedef unsigned __INT64_TYPE__ uint64_t;
+typedef signed __INTPTR_TYPE__ intptr_t;
+typedef unsigned __INTPTR_TYPE__ uintptr_t;
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef unsigned short unichar;
+)";
+
+
+bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method) const
+{
+ if (m_wrap)
+ {
+ switch (wrapping_language)
+ {
+ default:
+ return false;
+ case lldb::eLanguageTypeC:
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeObjC:
+ break;
+ }
+
+ StreamString wrap_stream;
+
+ switch (wrapping_language)
+ {
+ default:
+ break;
+ case lldb::eLanguageTypeC:
+ wrap_stream.Printf("%s \n"
+ "%s \n"
+ "void \n"
+ "%s(void *$__lldb_arg) \n"
+ "{ \n"
+ " %s; \n"
+ "} \n",
+ g_expression_prefix,
+ m_prefix.c_str(),
+ m_name.c_str(),
+ m_body.c_str());
+ break;
+ case lldb::eLanguageTypeC_plus_plus:
+ wrap_stream.Printf("%s \n"
+ "%s \n"
+ "void \n"
+ "$__lldb_class::%s(void *$__lldb_arg) %s\n"
+ "{ \n"
+ " %s; \n"
+ "} \n",
+ g_expression_prefix,
+ m_prefix.c_str(),
+ m_name.c_str(),
+ (const_object ? "const" : ""),
+ m_body.c_str());
+ break;
+ case lldb::eLanguageTypeObjC:
+ if (static_method)
+ {
+ wrap_stream.Printf("%s \n"
+ "%s \n"
+ "@interface $__lldb_objc_class ($__lldb_category) \n"
+ "+(void)%s:(void *)$__lldb_arg; \n"
+ "@end \n"
+ "@implementation $__lldb_objc_class ($__lldb_category) \n"
+ "+(void)%s:(void *)$__lldb_arg \n"
+ "{ \n"
+ " %s; \n"
+ "} \n"
+ "@end \n",
+ g_expression_prefix,
+ m_prefix.c_str(),
+ m_name.c_str(),
+ m_name.c_str(),
+ m_body.c_str());
+ }
+ else
+ {
+ wrap_stream.Printf("%s \n"
+ "%s \n"
+ "@interface $__lldb_objc_class ($__lldb_category) \n"
+ "-(void)%s:(void *)$__lldb_arg; \n"
+ "@end \n"
+ "@implementation $__lldb_objc_class ($__lldb_category) \n"
+ "-(void)%s:(void *)$__lldb_arg \n"
+ "{ \n"
+ " %s; \n"
+ "} \n"
+ "@end \n",
+ g_expression_prefix,
+ m_prefix.c_str(),
+ m_name.c_str(),
+ m_name.c_str(),
+ m_body.c_str());
+ }
+ break;
+ }
+
+ text = wrap_stream.GetString();
+ }
+ else
+ {
+ text.append(m_body);
+ }
+
+ return true;
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp b/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp
new file mode 100644
index 0000000..4030f14
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp
@@ -0,0 +1,659 @@
+//===-- IRDynamicChecks.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Expression/IRDynamicChecks.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Expression/ClangUtilityFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Value.h"
+
+using namespace llvm;
+using namespace lldb_private;
+
+static char ID;
+
+#define VALID_POINTER_CHECK_NAME "$__lldb_valid_pointer_check"
+#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"
+
+static const char g_valid_pointer_check_text[] =
+"extern \"C\" void\n"
+"$__lldb_valid_pointer_check (unsigned char *$__lldb_arg_ptr)\n"
+"{\n"
+" unsigned char $__lldb_local_val = *$__lldb_arg_ptr;\n"
+"}";
+
+DynamicCheckerFunctions::DynamicCheckerFunctions ()
+{
+}
+
+DynamicCheckerFunctions::~DynamicCheckerFunctions ()
+{
+}
+
+bool
+DynamicCheckerFunctions::Install(Stream &error_stream,
+ ExecutionContext &exe_ctx)
+{
+ m_valid_pointer_check.reset(new ClangUtilityFunction(g_valid_pointer_check_text,
+ VALID_POINTER_CHECK_NAME));
+ if (!m_valid_pointer_check->Install(error_stream, exe_ctx))
+ return false;
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process)
+ {
+ ObjCLanguageRuntime *objc_language_runtime = process->GetObjCLanguageRuntime();
+
+ if (objc_language_runtime)
+ {
+ m_objc_object_check.reset(objc_language_runtime->CreateObjectChecker(VALID_OBJC_OBJECT_CHECK_NAME));
+
+ if (!m_objc_object_check->Install(error_stream, exe_ctx))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+DynamicCheckerFunctions::DoCheckersExplainStop (lldb::addr_t addr, Stream &message)
+{
+ // FIXME: We have to get the checkers to know why they scotched the call in more detail,
+ // so we can print a better message here.
+ if (m_valid_pointer_check.get() != NULL && m_valid_pointer_check->ContainsAddress(addr))
+ {
+ message.Printf ("Attempted to dereference an invalid pointer.");
+ return true;
+ }
+ else if (m_objc_object_check.get() != NULL && m_objc_object_check->ContainsAddress(addr))
+ {
+ message.Printf ("Attempted to dereference an invalid ObjC Object or send it an unrecognized selector");
+ return true;
+ }
+ return false;
+}
+
+
+static std::string
+PrintValue(llvm::Value *V, bool truncate = false)
+{
+ std::string s;
+ raw_string_ostream rso(s);
+ V->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ return s;
+}
+
+//----------------------------------------------------------------------
+/// @class Instrumenter IRDynamicChecks.cpp
+/// @brief Finds and instruments individual LLVM IR instructions
+///
+/// When instrumenting LLVM IR, it is frequently desirable to first search
+/// for instructions, and then later modify them. This way iterators
+/// remain intact, and multiple passes can look at the same code base without
+/// treading on each other's toes.
+///
+/// The Instrumenter class implements this functionality. A client first
+/// calls Inspect on a function, which populates a list of instructions to
+/// be instrumented. Then, later, when all passes' Inspect functions have
+/// been called, the client calls Instrument, which adds the desired
+/// instrumentation.
+///
+/// A subclass of Instrumenter must override InstrumentInstruction, which
+/// is responsible for adding whatever instrumentation is necessary.
+///
+/// A subclass of Instrumenter may override:
+///
+/// - InspectInstruction [default: does nothing]
+///
+/// - InspectBasicBlock [default: iterates through the instructions in a
+/// basic block calling InspectInstruction]
+///
+/// - InspectFunction [default: iterates through the basic blocks in a
+/// function calling InspectBasicBlock]
+//----------------------------------------------------------------------
+class Instrumenter {
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] module
+ /// The module being instrumented.
+ //------------------------------------------------------------------
+ Instrumenter (llvm::Module &module,
+ DynamicCheckerFunctions &checker_functions) :
+ m_module(module),
+ m_checker_functions(checker_functions),
+ m_i8ptr_ty(NULL)
+ {
+ }
+
+ virtual~Instrumenter ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Inspect a function to find instructions to instrument
+ ///
+ /// @param[in] function
+ /// The function to inspect.
+ ///
+ /// @return
+ /// True on success; false on error.
+ //------------------------------------------------------------------
+ bool Inspect (llvm::Function &function)
+ {
+ return InspectFunction(function);
+ }
+
+ //------------------------------------------------------------------
+ /// Instrument all the instructions found by Inspect()
+ ///
+ /// @return
+ /// True on success; false on error.
+ //------------------------------------------------------------------
+ bool Instrument ()
+ {
+ for (InstIterator ii = m_to_instrument.begin(), last_ii = m_to_instrument.end();
+ ii != last_ii;
+ ++ii)
+ {
+ if (!InstrumentInstruction(*ii))
+ return false;
+ }
+
+ return true;
+ }
+protected:
+ //------------------------------------------------------------------
+ /// Add instrumentation to a single instruction
+ ///
+ /// @param[in] inst
+ /// The instruction to be instrumented.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;
+
+ //------------------------------------------------------------------
+ /// Register a single instruction to be instrumented
+ ///
+ /// @param[in] inst
+ /// The instruction to be instrumented.
+ //------------------------------------------------------------------
+ void RegisterInstruction(llvm::Instruction &i)
+ {
+ m_to_instrument.push_back(&i);
+ }
+
+ //------------------------------------------------------------------
+ /// Determine whether a single instruction is interesting to
+ /// instrument, and, if so, call RegisterInstruction
+ ///
+ /// @param[in] i
+ /// The instruction to be inspected.
+ ///
+ /// @return
+ /// False if there was an error scanning; true otherwise.
+ //------------------------------------------------------------------
+ virtual bool InspectInstruction(llvm::Instruction &i)
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Scan a basic block to see if any instructions are interesting
+ ///
+ /// @param[in] bb
+ /// The basic block to be inspected.
+ ///
+ /// @return
+ /// False if there was an error scanning; true otherwise.
+ //------------------------------------------------------------------
+ virtual bool InspectBasicBlock(llvm::BasicBlock &bb)
+ {
+ for (llvm::BasicBlock::iterator ii = bb.begin(), last_ii = bb.end();
+ ii != last_ii;
+ ++ii)
+ {
+ if (!InspectInstruction(*ii))
+ return false;
+ }
+
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Scan a function to see if any instructions are interesting
+ ///
+ /// @param[in] f
+ /// The function to be inspected.
+ ///
+ /// @return
+ /// False if there was an error scanning; true otherwise.
+ //------------------------------------------------------------------
+ virtual bool InspectFunction(llvm::Function &f)
+ {
+ for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end();
+ bbi != last_bbi;
+ ++bbi)
+ {
+ if (!InspectBasicBlock(*bbi))
+ return false;
+ }
+
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Build a function pointer for a function with signature
+ /// void (*)(uint8_t*) with a given address
+ ///
+ /// @param[in] start_address
+ /// The address of the function.
+ ///
+ /// @return
+ /// The function pointer, for use in a CallInst.
+ //------------------------------------------------------------------
+ llvm::Value *BuildPointerValidatorFunc(lldb::addr_t start_address)
+ {
+ IntegerType *intptr_ty = llvm::Type::getIntNTy(m_module.getContext(),
+ (m_module.getPointerSize() == llvm::Module::Pointer64) ? 64 : 32);
+
+ llvm::Type *param_array[1];
+
+ param_array[0] = const_cast<llvm::PointerType*>(GetI8PtrTy());
+
+ ArrayRef<llvm::Type*> params(param_array, 1);
+
+ FunctionType *fun_ty = FunctionType::get(llvm::Type::getVoidTy(m_module.getContext()), params, true);
+ PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
+ Constant *fun_addr_int = ConstantInt::get(intptr_ty, start_address, false);
+ return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
+ }
+
+ //------------------------------------------------------------------
+ /// Build a function pointer for a function with signature
+ /// void (*)(uint8_t*, uint8_t*) with a given address
+ ///
+ /// @param[in] start_address
+ /// The address of the function.
+ ///
+ /// @return
+ /// The function pointer, for use in a CallInst.
+ //------------------------------------------------------------------
+ llvm::Value *BuildObjectCheckerFunc(lldb::addr_t start_address)
+ {
+ IntegerType *intptr_ty = llvm::Type::getIntNTy(m_module.getContext(),
+ (m_module.getPointerSize() == llvm::Module::Pointer64) ? 64 : 32);
+
+ llvm::Type *param_array[2];
+
+ param_array[0] = const_cast<llvm::PointerType*>(GetI8PtrTy());
+ param_array[1] = const_cast<llvm::PointerType*>(GetI8PtrTy());
+
+ ArrayRef<llvm::Type*> params(param_array, 2);
+
+ FunctionType *fun_ty = FunctionType::get(llvm::Type::getVoidTy(m_module.getContext()), params, true);
+ PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
+ Constant *fun_addr_int = ConstantInt::get(intptr_ty, start_address, false);
+ return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
+ }
+
+ PointerType *GetI8PtrTy()
+ {
+ if (!m_i8ptr_ty)
+ m_i8ptr_ty = llvm::Type::getInt8PtrTy(m_module.getContext());
+
+ return m_i8ptr_ty;
+ }
+
+ typedef std::vector <llvm::Instruction *> InstVector;
+ typedef InstVector::iterator InstIterator;
+
+ InstVector m_to_instrument; ///< List of instructions the inspector found
+ llvm::Module &m_module; ///< The module which is being instrumented
+ DynamicCheckerFunctions &m_checker_functions; ///< The dynamic checker functions for the process
+private:
+ PointerType *m_i8ptr_ty;
+};
+
+class ValidPointerChecker : public Instrumenter
+{
+public:
+ ValidPointerChecker (llvm::Module &module,
+ DynamicCheckerFunctions &checker_functions) :
+ Instrumenter(module, checker_functions),
+ m_valid_pointer_check_func(NULL)
+ {
+ }
+
+ virtual ~ValidPointerChecker ()
+ {
+ }
+private:
+ bool InstrumentInstruction(llvm::Instruction *inst)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("Instrumenting load/store instruction: %s\n",
+ PrintValue(inst).c_str());
+
+ if (!m_valid_pointer_check_func)
+ m_valid_pointer_check_func = BuildPointerValidatorFunc(m_checker_functions.m_valid_pointer_check->StartAddress());
+
+ llvm::Value *dereferenced_ptr = NULL;
+
+ if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst> (inst))
+ dereferenced_ptr = li->getPointerOperand();
+ else if (llvm::StoreInst *si = dyn_cast<llvm::StoreInst> (inst))
+ dereferenced_ptr = si->getPointerOperand();
+ else
+ return false;
+
+ // Insert an instruction to cast the loaded value to int8_t*
+
+ BitCastInst *bit_cast = new BitCastInst(dereferenced_ptr,
+ GetI8PtrTy(),
+ "",
+ inst);
+
+ // Insert an instruction to call the helper with the result
+
+ llvm::Value *arg_array[1];
+
+ arg_array[0] = bit_cast;
+
+ llvm::ArrayRef<llvm::Value *> args(arg_array, 1);
+
+ CallInst::Create(m_valid_pointer_check_func,
+ args,
+ "",
+ inst);
+
+ return true;
+ }
+
+ bool InspectInstruction(llvm::Instruction &i)
+ {
+ if (dyn_cast<llvm::LoadInst> (&i) ||
+ dyn_cast<llvm::StoreInst> (&i))
+ RegisterInstruction(i);
+
+ return true;
+ }
+
+ llvm::Value *m_valid_pointer_check_func;
+};
+
+class ObjcObjectChecker : public Instrumenter
+{
+public:
+ ObjcObjectChecker(llvm::Module &module,
+ DynamicCheckerFunctions &checker_functions) :
+ Instrumenter(module, checker_functions),
+ m_objc_object_check_func(NULL)
+ {
+ }
+
+ virtual
+ ~ObjcObjectChecker ()
+ {
+ }
+
+ enum msgSend_type
+ {
+ eMsgSend = 0,
+ eMsgSendSuper,
+ eMsgSendSuper_stret,
+ eMsgSend_fpret,
+ eMsgSend_stret
+ };
+
+ std::map <llvm::Instruction *, msgSend_type> msgSend_types;
+
+private:
+ bool InstrumentInstruction(llvm::Instruction *inst)
+ {
+ CallInst *call_inst = dyn_cast<CallInst>(inst);
+
+ if (!call_inst)
+ return false; // call_inst really shouldn't be NULL, because otherwise InspectInstruction wouldn't have registered it
+
+ if (!m_objc_object_check_func)
+ m_objc_object_check_func = BuildObjectCheckerFunc(m_checker_functions.m_objc_object_check->StartAddress());
+
+ // id objc_msgSend(id theReceiver, SEL theSelector, ...)
+
+ llvm::Value *target_object;
+ llvm::Value *selector;
+
+ switch (msgSend_types[inst])
+ {
+ case eMsgSend:
+ case eMsgSend_fpret:
+ target_object = call_inst->getArgOperand(0);
+ selector = call_inst->getArgOperand(1);
+ break;
+ case eMsgSend_stret:
+ target_object = call_inst->getArgOperand(1);
+ selector = call_inst->getArgOperand(2);
+ break;
+ case eMsgSendSuper:
+ case eMsgSendSuper_stret:
+ return true;
+ }
+
+ // These objects should always be valid according to Sean Calannan
+ assert (target_object);
+ assert (selector);
+
+ // Insert an instruction to cast the receiver id to int8_t*
+
+ BitCastInst *bit_cast = new BitCastInst(target_object,
+ GetI8PtrTy(),
+ "",
+ inst);
+
+ // Insert an instruction to call the helper with the result
+
+ llvm::Value *arg_array[2];
+
+ arg_array[0] = bit_cast;
+ arg_array[1] = selector;
+
+ ArrayRef<llvm::Value*> args(arg_array, 2);
+
+ CallInst::Create(m_objc_object_check_func,
+ args,
+ "",
+ inst);
+
+ return true;
+ }
+
+ bool InspectInstruction(llvm::Instruction &i)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ CallInst *call_inst = dyn_cast<CallInst>(&i);
+
+ if (call_inst)
+ {
+ // This metadata is set by IRForTarget::MaybeHandleCall().
+
+ MDNode *metadata = call_inst->getMetadata("lldb.call.realName");
+
+ if (!metadata)
+ return true;
+
+ if (metadata->getNumOperands() != 1)
+ {
+ if (log)
+ log->Printf("Function call metadata has %d operands for [%p] %s", metadata->getNumOperands(), call_inst, PrintValue(call_inst).c_str());
+ return false;
+ }
+
+ MDString *real_name = dyn_cast<MDString>(metadata->getOperand(0));
+
+ if (!real_name)
+ {
+ if (log)
+ log->Printf("Function call metadata is not an MDString for [%p] %s", call_inst, PrintValue(call_inst).c_str());
+ return false;
+ }
+
+ std::string name_str = real_name->getString();
+ const char* name_cstr = name_str.c_str();
+
+ if (log)
+ log->Printf("Found call to %s: %s\n", name_cstr, PrintValue(call_inst).c_str());
+
+ if (name_str.find("objc_msgSend") == std::string::npos)
+ return true;
+
+ if (!strcmp(name_cstr, "objc_msgSend"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSend_stret"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend_stret;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSend_fpret"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend_fpret;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSendSuper"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSendSuper;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSendSuper_stret"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSendSuper_stret;
+ return true;
+ }
+
+ if (log)
+ log->Printf("Function name '%s' contains 'objc_msgSend' but is not handled", name_str.c_str());
+
+ return true;
+ }
+
+ return true;
+ }
+
+ llvm::Value *m_objc_object_check_func;
+};
+
+IRDynamicChecks::IRDynamicChecks(DynamicCheckerFunctions &checker_functions,
+ const char *func_name) :
+ ModulePass(ID),
+ m_func_name(func_name),
+ m_checker_functions(checker_functions)
+{
+}
+
+IRDynamicChecks::~IRDynamicChecks()
+{
+}
+
+bool
+IRDynamicChecks::runOnModule(llvm::Module &M)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str()));
+
+ if (!function)
+ {
+ if (log)
+ log->Printf("Couldn't find %s() in the module", m_func_name.c_str());
+
+ return false;
+ }
+
+ if (m_checker_functions.m_valid_pointer_check.get())
+ {
+ ValidPointerChecker vpc(M, m_checker_functions);
+
+ if (!vpc.Inspect(*function))
+ return false;
+
+ if (!vpc.Instrument())
+ return false;
+ }
+
+ if (m_checker_functions.m_objc_object_check.get())
+ {
+ ObjcObjectChecker ooc(M, m_checker_functions);
+
+ if (!ooc.Inspect(*function))
+ return false;
+
+ if (!ooc.Instrument())
+ return false;
+ }
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ M.print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf ("Module after dynamic checks: \n%s", s.c_str());
+ }
+
+ return true;
+}
+
+void
+IRDynamicChecks::assignPassManager(PMStack &PMS,
+ PassManagerType T)
+{
+}
+
+PassManagerType
+IRDynamicChecks::getPotentialPassManagerType() const
+{
+ return PMT_ModulePassManager;
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp b/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp
new file mode 100644
index 0000000..16ef6e5
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp
@@ -0,0 +1,704 @@
+//===-- IRExecutionUnit.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 "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/SourceMgr.h"
+// Project includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+IRExecutionUnit::IRExecutionUnit (std::unique_ptr<llvm::LLVMContext> &context_ap,
+ std::unique_ptr<llvm::Module> &module_ap,
+ ConstString &name,
+ const lldb::TargetSP &target_sp,
+ std::vector<std::string> &cpu_features) :
+ IRMemoryMap(target_sp),
+ m_context_ap(context_ap.release()),
+ m_module_ap(module_ap.release()),
+ m_module(m_module_ap.get()),
+ m_cpu_features(cpu_features),
+ m_name(name),
+ m_did_jit(false),
+ m_function_load_addr(LLDB_INVALID_ADDRESS),
+ m_function_end_load_addr(LLDB_INVALID_ADDRESS)
+{
+}
+
+lldb::addr_t
+IRExecutionUnit::WriteNow (const uint8_t *bytes,
+ size_t size,
+ Error &error)
+{
+ lldb::addr_t allocation_process_addr = Malloc (size,
+ 8,
+ lldb::ePermissionsWritable | lldb::ePermissionsReadable,
+ eAllocationPolicyMirror,
+ error);
+
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+
+ WriteMemory(allocation_process_addr, bytes, size, error);
+
+ if (!error.Success())
+ {
+ Error err;
+ Free (allocation_process_addr, err);
+
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ DataBufferHeap my_buffer(size, 0);
+ Error err;
+ ReadMemory(my_buffer.GetBytes(), allocation_process_addr, size, err);
+
+ if (err.Success())
+ {
+ DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8);
+
+ StreamString ss;
+
+ my_extractor.Dump(&ss, 0, lldb::eFormatBytesWithASCII, 1, my_buffer.GetByteSize(), 32, allocation_process_addr, 0, 0);
+
+ log->PutCString(ss.GetData());
+ }
+ }
+
+ return allocation_process_addr;
+}
+
+void
+IRExecutionUnit::FreeNow (lldb::addr_t allocation)
+{
+ if (allocation == LLDB_INVALID_ADDRESS)
+ return;
+
+ Error err;
+
+ Free(allocation, err);
+}
+
+Error
+IRExecutionUnit::DisassembleFunction (Stream &stream,
+ lldb::ProcessSP &process_wp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ExecutionContext exe_ctx(process_wp);
+
+ Error ret;
+
+ ret.Clear();
+
+ lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS;
+
+ for (JittedFunction &function : m_jitted_functions)
+ {
+ if (strstr(function.m_name.c_str(), m_name.AsCString()))
+ {
+ func_local_addr = function.m_local_addr;
+ func_remote_addr = function.m_remote_addr;
+ }
+ }
+
+ if (func_local_addr == LLDB_INVALID_ADDRESS)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", m_name.AsCString());
+ return ret;
+ }
+
+ if (log)
+ log->Printf("Found function, has local address 0x%" PRIx64 " and remote address 0x%" PRIx64, (uint64_t)func_local_addr, (uint64_t)func_remote_addr);
+
+ std::pair <lldb::addr_t, lldb::addr_t> func_range;
+
+ func_range = GetRemoteRangeForLocal(func_local_addr);
+
+ if (func_range.first == 0 && func_range.second == 0)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorStringWithFormat("Couldn't find code range for function %s", m_name.AsCString());
+ return ret;
+ }
+
+ if (log)
+ log->Printf("Function's code range is [0x%" PRIx64 "+0x%" PRIx64 "]", func_range.first, func_range.second);
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (!target)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorString("Couldn't find the target");
+ return ret;
+ }
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second, 0));
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Error err;
+ process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err);
+
+ if (!err.Success())
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error"));
+ return ret;
+ }
+
+ ArchSpec arch(target->GetArchitecture());
+
+ const char *plugin_name = NULL;
+ const char *flavor_string = NULL;
+ lldb::DisassemblerSP disassembler_sp = Disassembler::FindPlugin(arch, flavor_string, plugin_name);
+
+ if (!disassembler_sp)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.GetArchitectureName());
+ return ret;
+ }
+
+ if (!process)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorString("Couldn't find the process");
+ return ret;
+ }
+
+ DataExtractor extractor(buffer_sp,
+ process->GetByteOrder(),
+ target->GetArchitecture().GetAddressByteSize());
+
+ if (log)
+ {
+ log->Printf("Function data has contents:");
+ extractor.PutToLog (log,
+ 0,
+ extractor.GetByteSize(),
+ func_remote_addr,
+ 16,
+ DataExtractor::TypeUInt8);
+ }
+
+ disassembler_sp->DecodeInstructions (Address (func_remote_addr), extractor, 0, UINT32_MAX, false, false);
+
+ InstructionList &instruction_list = disassembler_sp->GetInstructionList();
+ const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize();
+
+ for (size_t instruction_index = 0, num_instructions = instruction_list.GetSize();
+ instruction_index < num_instructions;
+ ++instruction_index)
+ {
+ Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index).get();
+ instruction->Dump (&stream,
+ max_opcode_byte_size,
+ true,
+ true,
+ &exe_ctx);
+ stream.PutChar('\n');
+ }
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disassembler_sp->GetInstructionList().Clear();
+ return ret;
+}
+
+static void ReportInlineAsmError(const llvm::SMDiagnostic &diagnostic, void *Context, unsigned LocCookie)
+{
+ Error *err = static_cast<Error*>(Context);
+
+ if (err && err->Success())
+ {
+ err->SetErrorToGenericError();
+ err->SetErrorStringWithFormat("Inline assembly error: %s", diagnostic.getMessage().str().c_str());
+ }
+}
+
+void
+IRExecutionUnit::GetRunnableInfo(Error &error,
+ lldb::addr_t &func_addr,
+ lldb::addr_t &func_end)
+{
+ lldb::ProcessSP process_sp(GetProcessWP().lock());
+
+ func_addr = LLDB_INVALID_ADDRESS;
+ func_end = LLDB_INVALID_ADDRESS;
+
+ if (!process_sp)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write the JIT compiled code into the process because the process is invalid");
+ return;
+ }
+
+ if (m_did_jit)
+ {
+ func_addr = m_function_load_addr;
+ func_end = m_function_end_load_addr;
+
+ return;
+ };
+
+ m_did_jit = true;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ std::string error_string;
+
+ if (log)
+ {
+ std::string s;
+ llvm::raw_string_ostream oss(s);
+
+ m_module->print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf ("Module being sent to JIT: \n%s", s.c_str());
+ }
+
+ llvm::Triple triple(m_module->getTargetTriple());
+ llvm::Function *function = m_module->getFunction (m_name.AsCString());
+ llvm::Reloc::Model relocModel;
+ llvm::CodeModel::Model codeModel;
+
+ if (triple.isOSBinFormatELF())
+ {
+ relocModel = llvm::Reloc::Static;
+ // This will be small for 32-bit and large for 64-bit.
+ codeModel = llvm::CodeModel::JITDefault;
+ }
+ else
+ {
+ relocModel = llvm::Reloc::PIC_;
+ codeModel = llvm::CodeModel::Small;
+ }
+
+ m_module_ap->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, &error);
+
+ llvm::EngineBuilder builder(m_module_ap.get());
+
+ builder.setEngineKind(llvm::EngineKind::JIT)
+ .setErrorStr(&error_string)
+ .setRelocationModel(relocModel)
+ .setJITMemoryManager(new MemoryManager(*this))
+ .setOptLevel(llvm::CodeGenOpt::Less)
+ .setAllocateGVsWithCode(true)
+ .setCodeModel(codeModel)
+ .setUseMCJIT(true);
+
+ llvm::StringRef mArch;
+ llvm::StringRef mCPU;
+ llvm::SmallVector<std::string, 0> mAttrs;
+
+ for (std::string &feature : m_cpu_features)
+ mAttrs.push_back(feature);
+
+ llvm::TargetMachine *target_machine = builder.selectTarget(triple,
+ mArch,
+ mCPU,
+ mAttrs);
+
+ m_execution_engine_ap.reset(builder.create(target_machine));
+
+ if (!m_execution_engine_ap.get())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str());
+ return;
+ }
+ else
+ {
+ m_module_ap.release(); // ownership was transferred
+ }
+
+ m_execution_engine_ap->DisableLazyCompilation();
+
+ // We don't actually need the function pointer here, this just forces it to get resolved.
+
+ void *fun_ptr = m_execution_engine_ap->getPointerToFunction(function);
+
+ if (!error.Success())
+ {
+ // We got an error through our callback!
+ return;
+ }
+
+ if (!function)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString());
+ return;
+ }
+
+ if (!fun_ptr)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", m_name.AsCString());
+ return;
+ }
+
+ m_jitted_functions.push_back (JittedFunction(m_name.AsCString(), (lldb::addr_t)fun_ptr));
+
+ CommitAllocations(process_sp);
+ ReportAllocations(*m_execution_engine_ap);
+ WriteData(process_sp);
+
+ for (JittedFunction &jitted_function : m_jitted_functions)
+ {
+ jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr);
+
+ if (!jitted_function.m_name.compare(m_name.AsCString()))
+ {
+ AddrRange func_range = GetRemoteRangeForLocal(jitted_function.m_local_addr);
+ m_function_end_load_addr = func_range.first + func_range.second;
+ m_function_load_addr = jitted_function.m_remote_addr;
+ }
+ }
+
+ if (log)
+ {
+ log->Printf("Code can be run in the target.");
+
+ StreamString disassembly_stream;
+
+ Error err = DisassembleFunction(disassembly_stream, process_sp);
+
+ if (!err.Success())
+ {
+ log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error"));
+ }
+ else
+ {
+ log->Printf("Function disassembly:\n%s", disassembly_stream.GetData());
+ }
+ }
+
+ func_addr = m_function_load_addr;
+ func_end = m_function_end_load_addr;
+
+ return;
+}
+
+IRExecutionUnit::~IRExecutionUnit ()
+{
+ m_module_ap.reset();
+ m_execution_engine_ap.reset();
+ m_context_ap.reset();
+}
+
+IRExecutionUnit::MemoryManager::MemoryManager (IRExecutionUnit &parent) :
+ m_default_mm_ap (llvm::JITMemoryManager::CreateDefaultMemManager()),
+ m_parent (parent)
+{
+}
+
+void
+IRExecutionUnit::MemoryManager::setMemoryWritable ()
+{
+ m_default_mm_ap->setMemoryWritable();
+}
+
+void
+IRExecutionUnit::MemoryManager::setMemoryExecutable ()
+{
+ m_default_mm_ap->setMemoryExecutable();
+}
+
+
+uint8_t *
+IRExecutionUnit::MemoryManager::startFunctionBody(const llvm::Function *F,
+ uintptr_t &ActualSize)
+{
+ return m_default_mm_ap->startFunctionBody(F, ActualSize);
+}
+
+uint8_t *
+IRExecutionUnit::MemoryManager::allocateStub(const llvm::GlobalValue* F,
+ unsigned StubSize,
+ unsigned Alignment)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ uint8_t *return_value = m_default_mm_ap->allocateStub(F, StubSize, Alignment);
+
+ m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ StubSize,
+ Alignment));
+
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::allocateStub (F=%p, StubSize=%u, Alignment=%u) = %p",
+ F, StubSize, Alignment, return_value);
+ }
+
+ return return_value;
+}
+
+void
+IRExecutionUnit::MemoryManager::endFunctionBody(const llvm::Function *F,
+ uint8_t *FunctionStart,
+ uint8_t *FunctionEnd)
+{
+ m_default_mm_ap->endFunctionBody(F, FunctionStart, FunctionEnd);
+}
+
+uint8_t *
+IRExecutionUnit::MemoryManager::allocateSpace(intptr_t Size, unsigned Alignment)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment);
+
+ m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ Size,
+ Alignment));
+
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::allocateSpace(Size=%" PRIu64 ", Alignment=%u) = %p",
+ (uint64_t)Size, Alignment, return_value);
+ }
+
+ return return_value;
+}
+
+uint8_t *
+IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size,
+ unsigned Alignment,
+ unsigned SectionID)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ uint8_t *return_value = m_default_mm_ap->allocateCodeSection(Size, Alignment, SectionID);
+
+ m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
+ lldb::ePermissionsReadable | lldb::ePermissionsExecutable,
+ Size,
+ Alignment,
+ SectionID));
+
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
+ (uint64_t)Size, Alignment, SectionID, return_value);
+ }
+
+ return return_value;
+}
+
+uint8_t *
+IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size,
+ unsigned Alignment,
+ unsigned SectionID,
+ bool IsReadOnly)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, IsReadOnly);
+
+ m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ Size,
+ Alignment,
+ SectionID));
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
+ (uint64_t)Size, Alignment, SectionID, return_value);
+ }
+
+ return return_value;
+}
+
+uint8_t *
+IRExecutionUnit::MemoryManager::allocateGlobal(uintptr_t Size,
+ unsigned Alignment)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment);
+
+ m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ Size,
+ Alignment));
+
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::allocateGlobal(Size=0x%" PRIx64 ", Alignment=%u) = %p",
+ (uint64_t)Size, Alignment, return_value);
+ }
+
+ return return_value;
+}
+
+void
+IRExecutionUnit::MemoryManager::deallocateFunctionBody(void *Body)
+{
+ m_default_mm_ap->deallocateFunctionBody(Body);
+}
+
+lldb::addr_t
+IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ for (AllocationRecord &record : m_records)
+ {
+ if (local_address >= record.m_host_address &&
+ local_address < record.m_host_address + record.m_size)
+ {
+ if (record.m_process_address == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t ret = record.m_process_address + (local_address - record.m_host_address);
+
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::GetRemoteAddressForLocal() found 0x%" PRIx64 " in [0x%" PRIx64 "..0x%" PRIx64 "], and returned 0x%" PRIx64 " from [0x%" PRIx64 "..0x%" PRIx64 "].",
+ local_address,
+ (uint64_t)record.m_host_address,
+ (uint64_t)record.m_host_address + (uint64_t)record.m_size,
+ ret,
+ record.m_process_address,
+ record.m_process_address + record.m_size);
+ }
+
+ return ret;
+ }
+ }
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+IRExecutionUnit::AddrRange
+IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address)
+{
+ for (AllocationRecord &record : m_records)
+ {
+ if (local_address >= record.m_host_address &&
+ local_address < record.m_host_address + record.m_size)
+ {
+ if (record.m_process_address == LLDB_INVALID_ADDRESS)
+ return AddrRange(0, 0);
+
+ return AddrRange(record.m_process_address, record.m_size);
+ }
+ }
+
+ return AddrRange (0, 0);
+}
+
+bool
+IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
+{
+ bool ret = true;
+
+ lldb_private::Error err;
+
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_process_address != LLDB_INVALID_ADDRESS)
+ continue;
+
+
+ record.m_process_address = Malloc(record.m_size,
+ record.m_alignment,
+ record.m_permissions,
+ eAllocationPolicyProcessOnly,
+ err);
+
+ if (!err.Success())
+ {
+ ret = false;
+ break;
+ }
+ }
+
+ if (!ret)
+ {
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_process_address != LLDB_INVALID_ADDRESS)
+ {
+ Free(record.m_process_address, err);
+ record.m_process_address = LLDB_INVALID_ADDRESS;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void
+IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine)
+{
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_process_address == LLDB_INVALID_ADDRESS)
+ continue;
+
+ if (record.m_section_id == eSectionIDInvalid)
+ continue;
+
+ engine.mapSectionAddress((void*)record.m_host_address, record.m_process_address);
+ }
+
+ // Trigger re-application of relocations.
+ engine.finalizeObject();
+}
+
+bool
+IRExecutionUnit::WriteData (lldb::ProcessSP &process_sp)
+{
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_process_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb_private::Error err;
+
+ WriteMemory (record.m_process_address, (uint8_t*)record.m_host_address, record.m_size, err);
+ }
+
+ return true;
+}
+
+void
+IRExecutionUnit::AllocationRecord::dump (Log *log)
+{
+ if (!log)
+ return;
+
+ log->Printf("[0x%llx+0x%llx]->0x%llx (alignment %d, section ID %d)",
+ (unsigned long long)m_host_address,
+ (unsigned long long)m_size,
+ (unsigned long long)m_process_address,
+ (unsigned)m_alignment,
+ (unsigned)m_section_id);
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/IRForTarget.cpp b/contrib/llvm/tools/lldb/source/Expression/IRForTarget.cpp
new file mode 100644
index 0000000..cac3fdf
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/IRForTarget.cpp
@@ -0,0 +1,2879 @@
+//===-- 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 "lldb/Expression/IRForTarget.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/PassManager.h"
+#include "llvm/Transforms/IPO.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/ClangExpressionDeclMap.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTType.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;
+}
+
+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_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;
+}
+
+bool
+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 false;
+ 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;
+ }
+
+ 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))
+ {
+ lldb_private::ConstString altnernate_name;
+ bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr);
+ if (!found_it)
+ {
+ // Check for an alternate mangling for "std::basic_string<char>"
+ // that is part of the itanium C++ name mangling scheme
+ const char *name_cstr = name.GetCString();
+ if (name_cstr && strncmp(name_cstr, "_ZNKSbIcE", strlen("_ZNKSbIcE")) == 0)
+ {
+ std::string alternate_mangling("_ZNKSs");
+ alternate_mangling.append (name_cstr + strlen("_ZNKSbIcE"));
+ altnernate_name.SetCString(alternate_mangling.c_str());
+ found_it = m_decl_map->GetFunctionAddress (altnernate_name, fun_addr);
+ }
+ }
+
+ if (!found_it)
+ {
+ lldb_private::Mangled mangled_name(name);
+ lldb_private::Mangled alt_mangled_name(altnernate_name);
+ if (log)
+ {
+ if (alt_mangled_name)
+ log->Printf("Function \"%s\" (alternate name \"%s\") has no address",
+ mangled_name.GetName().GetCString(),
+ alt_mangled_name.GetName().GetCString());
+ else
+ log->Printf("Function \"%s\" had no address",
+ mangled_name.GetName().GetCString());
+ }
+
+ if (m_error_stream)
+ {
+ if (alt_mangled_name)
+ m_error_stream->Printf("error: call to a function '%s' (alternate name '%s') that is not present in the target\n",
+ mangled_name.GetName().GetCString(),
+ alt_mangled_name.GetName().GetCString());
+ else 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().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().GetCString());
+ }
+ return false;
+ }
+ }
+ }
+ 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 false;
+ }
+ }
+
+ if (log)
+ log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), fun_addr);
+
+ return true;
+}
+
+llvm::Constant *
+IRForTarget::BuildFunctionPointer (llvm::Type *type,
+ uint64_t ptr)
+{
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+ PointerType *fun_ptr_ty = PointerType::getUnqual(type);
+ Constant *fun_addr_int = ConstantInt::get(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 (Value::use_iterator i = function_ptr->use_begin(), e = function_ptr->use_end();
+ i != e;
+ ++i)
+ {
+ Value *user = *i;
+
+ 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->hasNUses(0))
+ continue; // ignore
+
+ uint64_t addr = LLDB_INVALID_ADDRESS;
+ lldb_private::ConstString name;
+ Constant **value_ptr = NULL;
+
+ if (!GetFunctionAddress(fun,
+ addr,
+ name,
+ value_ptr))
+ return false; // GetFunctionAddress reports its own errors
+
+ 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(Attribute::NoBuiltin)) {
+ Attribute builtin = Attribute::get(fun->getContext(), Attribute::Builtin);
+
+ for (auto u = fun->use_begin(), e = fun->use_end(); u != e; ++u) {
+ if (auto call = dyn_cast<CallInst>(*u)) {
+ call->removeAttribute(AttributeSet::FunctionIndex, builtin);
+ }
+ }
+ }
+
+ fun->replaceAllUsesWith(value);
+ }
+
+ 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)
+ {
+ MDNode *metadata_node = named_metadata->getOperand(node_index);
+
+ if (!metadata_node)
+ return NULL;
+
+ if (metadata_node->getNumOperands() != 2)
+ continue;
+
+ if (metadata_node->getOperand(0) != global_val)
+ continue;
+
+ ConstantInt *constant_int = dyn_cast<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(),
+ &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(),
+ &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(),
+ &result_decl->getASTContext());
+ }
+
+ if (m_result_type.GetBitSize() == 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());
+
+ // 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::Value* values[2];
+ values[0] = new_result_global;
+ values[1] = new_constant_int;
+
+ ArrayRef<Value*> 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->hasNUses(0))
+ {
+ // 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;
+}
+
+#if 0
+static void DebugUsers(Log *log, Value *value, uint8_t depth)
+{
+ if (!depth)
+ return;
+
+ depth--;
+
+ if (log)
+ log->Printf(" <Begin %d users>", value->getNumUses());
+
+ for (Value::use_iterator ui = value->use_begin(), ue = value->use_end();
+ ui != ue;
+ ++ui)
+ {
+ if (log)
+ log->Printf(" <Use %p> %s", *ui, PrintValue(*ui).c_str());
+ DebugUsers(log, *ui, depth);
+ }
+
+ if (log)
+ log->Printf(" <End uses>");
+}
+#endif
+
+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());
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize()
+ == Module::Pointer64) ? 64 : 32);
+ 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] = 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(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(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("\01L_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** @"\01L_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.
+ //
+ // @"\01L_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
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+ PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type);
+ Constant *srN_addr_int = ConstantInt::get(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 = dyn_cast<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(),
+ &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::Value* values[2];
+ values[0] = persistent_global;
+ values[1] = constant_int;
+
+ ArrayRef<llvm::Value*> 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)", 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::ClangASTType clang_type(&value_decl->getASTContext(), value_decl->getType());
+
+ const Type *value_type = NULL;
+
+ if (name[0] == '$')
+ {
+ // The $__lldb_expr_result name indicates the 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.
+ clang_type = clang_type.GetPointerType();
+ value_type = PointerType::get(global_variable->getType(), 0);
+ }
+ else
+ {
+ value_type = global_variable->getType();
+ }
+
+ const uint64_t value_size = clang_type.GetByteSize();
+ off_t value_alignment = (clang_type.GetTypeBitAlign() + 7ull) / 8ull;
+
+ if (log)
+ {
+ log->Printf("Type of \"%s\" is [clang \"%s\", llvm \"%s\"] [size %" PRIu64 ", align %" PRId64 "]",
+ name.c_str(),
+ clang_type.GetQualType().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();
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+
+ Constant *symbol_addr_int = ConstantInt::get(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_begin() == global_variable->use_end())
+ return false;
+
+ SmallVector<LoadInst *, 2> load_instructions;
+
+ for (Value::use_iterator i = global_variable->use_begin(), e = global_variable->use_end();
+ i != e;
+ ++i)
+ {
+ if (LoadInst *load_instruction = dyn_cast<LoadInst>(*i))
+ load_instructions.push_back(load_instruction);
+ }
+
+ if (load_instructions.empty())
+ return false;
+
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize()
+ == Module::Pointer64) ? 64 : 32);
+
+ Constant *class_addr = ConstantInt::get(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 (Module::global_iterator global = m_module->global_begin(), end = m_module->global_end();
+ global != end;
+ ++global)
+ {
+ if (!global)
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: global variable is NULL");
+
+ return false;
+ }
+
+ std::string global_name = (*global).getName().str();
+
+ if (log)
+ log->Printf("Examining %s, DeclForGlobalValue returns %p",
+ global_name.c_str(),
+ DeclForGlobal(global));
+
+ if (global_name.find("OBJC_IVAR") == 0)
+ {
+ if (!HandleSymbol(global))
+ {
+ 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))
+ {
+ 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))
+ {
+ 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))
+ {
+ if (!MaybeHandleVariable (global))
+ {
+ 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 (Module::global_iterator gi = m_module->global_begin(), ge = m_module->global_end();
+ gi != ge;
+ ++gi)
+ {
+ GlobalVariable *gv = gi;
+
+ 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 (GlobalVariable::use_iterator ui = gv->use_begin(), ue = gv->use_end();
+ ui != ue;
+ ++ui)
+ {
+ if (log)
+ log->Printf("Found use %s", PrintValue(*ui).c_str());
+
+ ConstantExpr *const_expr = dyn_cast<ConstantExpr>(*ui);
+ StoreInst *store_inst = dyn_cast<StoreInst>(*ui);
+
+ 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 (Instruction::op_iterator oi = inst.op_begin(), oe = inst.op_end();
+ oi != oe;
+ ++oi)
+ {
+ Value *operand_val = oi->get();
+
+ 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 %lu and raw data %s", operand_data_size, s.c_str());
+ }
+
+ lldb_private::DataBufferHeap data(operand_data_size, 0);
+
+ if (lldb::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);
+ offset = aligned_offset;
+
+ 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"))
+ return false;
+
+ return true;
+}
+
+void
+IRForTarget::TurnGuardLoadIntoZero(llvm::Instruction* guard_load)
+{
+ Constant* zero(ConstantInt::get(Type::getInt8Ty(m_module->getContext()), 0, true));
+
+ Value::use_iterator ui;
+
+ for (ui = guard_load->use_begin();
+ ui != guard_load->use_end();
+ ++ui)
+ {
+ if (isa<Constant>(*ui))
+ {
+ // do nothing for the moment
+ }
+ else
+ {
+ ui->replaceUsesOfWith(guard_load, 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));
+
+ Value::use_iterator ui;
+
+ 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 (ui = old_constant->use_begin();
+ ui != old_constant->use_end();
+ ++ui)
+ users.push_back(*ui);
+
+ 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(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;
+ off_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;
+ off_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 %" PRId64,
+ 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(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 %lu]", alignment, size);
+
+ return true;
+}
+
+llvm::Constant *
+IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset)
+{
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+
+ llvm::Constant *offset_int = ConstantInt::get(intptr_ty, offset);
+
+ llvm::Constant *offset_array[1];
+
+ offset_array[0] = offset_int;
+
+ llvm::ArrayRef<llvm::Constant *> offsets(offset_array, 1);
+
+ llvm::Constant *reloc_getelementptr = ConstantExpr::getGetElementPtr(m_reloc_placeholder, offsets);
+ llvm::Constant *reloc_getbitcast = ConstantExpr::getBitCast(reloc_getelementptr, type);
+
+ return reloc_getbitcast;
+}
+
+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;
+
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+
+ Constant *relocated_addr = ConstantInt::get(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 (Module::global_iterator gi = llvm_module.global_begin(), ge = llvm_module.global_end();
+ gi != ge;
+ ++gi)
+ {
+ GlobalVariable *global_var = dyn_cast<GlobalVariable>(gi);
+
+ 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 (Module::global_iterator gi = llvm_module.global_begin(), ge = llvm_module.global_end();
+ gi != ge;
+ ++gi)
+ {
+ GlobalVariable *global_var = dyn_cast<GlobalVariable>(gi);
+
+ GlobalValue::use_iterator ui = global_var->use_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));
+
+ 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 *intptr_ty = Type::getInt8Ty(m_module->getContext());
+
+ m_reloc_placeholder = new llvm::GlobalVariable((*m_module),
+ intptr_ty,
+ false /* IsConstant */,
+ GlobalVariable::InternalLinkage,
+ Constant::getNullValue(intptr_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/contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp b/contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp
new file mode 100644
index 0000000..dcbf584
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/IRInterpreter.cpp
@@ -0,0 +1,1379 @@
+//===-- IRInterpreter.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/IRMemoryMap.h"
+#include "lldb/Expression/IRInterpreter.h"
+
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <map>
+
+using namespace llvm;
+
+static std::string
+PrintValue(const Value *value, bool truncate = false)
+{
+ std::string s;
+ raw_string_ostream rso(s);
+ value->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+
+ size_t offset;
+ while ((offset = s.find('\n')) != s.npos)
+ s.erase(offset, 1);
+ while (s[0] == ' ' || s[0] == '\t')
+ s.erase(0, 1);
+
+ return s;
+}
+
+static std::string
+PrintType(const 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;
+}
+
+class InterpreterStackFrame
+{
+public:
+ typedef std::map <const Value*, lldb::addr_t> ValueMap;
+
+ ValueMap m_values;
+ DataLayout &m_target_data;
+ lldb_private::IRMemoryMap &m_memory_map;
+ const BasicBlock *m_bb;
+ BasicBlock::const_iterator m_ii;
+ BasicBlock::const_iterator m_ie;
+
+ lldb::addr_t m_frame_process_address;
+ size_t m_frame_size;
+ lldb::addr_t m_stack_pointer;
+
+ lldb::ByteOrder m_byte_order;
+ size_t m_addr_byte_size;
+
+ InterpreterStackFrame (DataLayout &target_data,
+ lldb_private::IRMemoryMap &memory_map,
+ lldb::addr_t stack_frame_bottom,
+ lldb::addr_t stack_frame_top) :
+ m_target_data (target_data),
+ m_memory_map (memory_map)
+ {
+ m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig);
+ m_addr_byte_size = (target_data.getPointerSize(0));
+
+ m_frame_process_address = stack_frame_bottom;
+ m_frame_size = stack_frame_top - stack_frame_bottom;
+ m_stack_pointer = stack_frame_top;
+ }
+
+ ~InterpreterStackFrame ()
+ {
+ }
+
+ void Jump (const BasicBlock *bb)
+ {
+ m_bb = bb;
+ m_ii = m_bb->begin();
+ m_ie = m_bb->end();
+ }
+
+ std::string SummarizeValue (const Value *value)
+ {
+ lldb_private::StreamString ss;
+
+ ss.Printf("%s", PrintValue(value).c_str());
+
+ ValueMap::iterator i = m_values.find(value);
+
+ if (i != m_values.end())
+ {
+ lldb::addr_t addr = i->second;
+
+ ss.Printf(" 0x%llx", (unsigned long long)addr);
+ }
+
+ return ss.GetString();
+ }
+
+ bool AssignToMatchType (lldb_private::Scalar &scalar, uint64_t u64value, Type *type)
+ {
+ size_t type_size = m_target_data.getTypeStoreSize(type);
+
+ switch (type_size)
+ {
+ case 1:
+ scalar = (uint8_t)u64value;
+ break;
+ case 2:
+ scalar = (uint16_t)u64value;
+ break;
+ case 4:
+ scalar = (uint32_t)u64value;
+ break;
+ case 8:
+ scalar = (uint64_t)u64value;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ bool EvaluateValue (lldb_private::Scalar &scalar, const Value *value, Module &module)
+ {
+ const Constant *constant = dyn_cast<Constant>(value);
+
+ if (constant)
+ {
+ APInt value_apint;
+
+ if (!ResolveConstantValue(value_apint, constant))
+ return false;
+
+ return AssignToMatchType(scalar, value_apint.getLimitedValue(), value->getType());
+ }
+ else
+ {
+ lldb::addr_t process_address = ResolveValue(value, module);
+ size_t value_size = m_target_data.getTypeStoreSize(value->getType());
+
+ lldb_private::DataExtractor value_extractor;
+ lldb_private::Error extract_error;
+
+ m_memory_map.GetMemoryData(value_extractor, process_address, value_size, extract_error);
+
+ if (!extract_error.Success())
+ return false;
+
+ lldb::offset_t offset = 0;
+ if (value_size == 1 || value_size == 2 || value_size == 4 || value_size == 8)
+ {
+ uint64_t u64value = value_extractor.GetMaxU64(&offset, value_size);
+ return AssignToMatchType(scalar, u64value, value->getType());
+ }
+ }
+
+ return false;
+ }
+
+ bool AssignValue (const Value *value, lldb_private::Scalar &scalar, Module &module)
+ {
+ lldb::addr_t process_address = ResolveValue (value, module);
+
+ if (process_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb_private::Scalar cast_scalar;
+
+ if (!AssignToMatchType(cast_scalar, scalar.GetRawBits64(0), value->getType()))
+ return false;
+
+ size_t value_byte_size = m_target_data.getTypeStoreSize(value->getType());
+
+ lldb_private::DataBufferHeap buf(value_byte_size, 0);
+
+ lldb_private::Error get_data_error;
+
+ if (!cast_scalar.GetAsMemoryData(buf.GetBytes(), buf.GetByteSize(), m_byte_order, get_data_error))
+ return false;
+
+ lldb_private::Error write_error;
+
+ m_memory_map.WriteMemory(process_address, buf.GetBytes(), buf.GetByteSize(), write_error);
+
+ return write_error.Success();
+ }
+
+ bool ResolveConstantValue (APInt &value, const Constant *constant)
+ {
+ switch (constant->getValueID())
+ {
+ default:
+ break;
+ case Value::ConstantIntVal:
+ if (const ConstantInt *constant_int = dyn_cast<ConstantInt>(constant))
+ {
+ value = constant_int->getValue();
+ return true;
+ }
+ break;
+ case Value::ConstantFPVal:
+ if (const ConstantFP *constant_fp = dyn_cast<ConstantFP>(constant))
+ {
+ value = constant_fp->getValueAPF().bitcastToAPInt();
+ return true;
+ }
+ break;
+ case Value::ConstantExprVal:
+ if (const ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant))
+ {
+ switch (constant_expr->getOpcode())
+ {
+ default:
+ return false;
+ case Instruction::IntToPtr:
+ case Instruction::PtrToInt:
+ case Instruction::BitCast:
+ return ResolveConstantValue(value, constant_expr->getOperand(0));
+ case Instruction::GetElementPtr:
+ {
+ ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin();
+ ConstantExpr::const_op_iterator op_end = constant_expr->op_end();
+
+ Constant *base = dyn_cast<Constant>(*op_cursor);
+
+ if (!base)
+ return false;
+
+ if (!ResolveConstantValue(value, base))
+ return false;
+
+ op_cursor++;
+
+ if (op_cursor == op_end)
+ return true; // no offset to apply!
+
+ SmallVector <Value *, 8> indices (op_cursor, op_end);
+
+ uint64_t offset = m_target_data.getIndexedOffset(base->getType(), indices);
+
+ const bool is_signed = true;
+ value += APInt(value.getBitWidth(), offset, is_signed);
+
+ return true;
+ }
+ }
+ }
+ break;
+ case Value::ConstantPointerNullVal:
+ if (isa<ConstantPointerNull>(constant))
+ {
+ value = APInt(m_target_data.getPointerSizeInBits(), 0);
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ bool MakeArgument(const Argument *value, uint64_t address)
+ {
+ lldb::addr_t data_address = Malloc(value->getType());
+
+ if (data_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb_private::Error write_error;
+
+ m_memory_map.WritePointerToMemory(data_address, address, write_error);
+
+ if (!write_error.Success())
+ {
+ lldb_private::Error free_error;
+ m_memory_map.Free(data_address, free_error);
+ return false;
+ }
+
+ m_values[value] = data_address;
+
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ log->Printf("Made an allocation for argument %s", PrintValue(value).c_str());
+ log->Printf(" Data region : %llx", (unsigned long long)address);
+ log->Printf(" Ref region : %llx", (unsigned long long)data_address);
+ }
+
+ return true;
+ }
+
+ bool ResolveConstant (lldb::addr_t process_address, const Constant *constant)
+ {
+ APInt resolved_value;
+
+ if (!ResolveConstantValue(resolved_value, constant))
+ return false;
+
+ const uint64_t *raw_data = resolved_value.getRawData();
+
+ size_t constant_size = m_target_data.getTypeStoreSize(constant->getType());
+
+ lldb_private::Error write_error;
+
+ m_memory_map.WriteMemory(process_address, (uint8_t*)raw_data, constant_size, write_error);
+
+ return write_error.Success();
+ }
+
+ lldb::addr_t Malloc (size_t size, uint8_t byte_alignment)
+ {
+ lldb::addr_t ret = m_stack_pointer;
+
+ ret -= size;
+ ret -= (ret % byte_alignment);
+
+ if (ret < m_frame_process_address)
+ return LLDB_INVALID_ADDRESS;
+
+ m_stack_pointer = ret;
+ return ret;
+ }
+
+ lldb::addr_t MallocPointer ()
+ {
+ return Malloc(m_target_data.getPointerSize(), m_target_data.getPointerPrefAlignment());
+ }
+
+ lldb::addr_t Malloc (llvm::Type *type)
+ {
+ lldb_private::Error alloc_error;
+
+ return Malloc(m_target_data.getTypeAllocSize(type), m_target_data.getPrefTypeAlignment(type));
+ }
+
+ std::string PrintData (lldb::addr_t addr, llvm::Type *type)
+ {
+ size_t length = m_target_data.getTypeStoreSize(type);
+
+ lldb_private::DataBufferHeap buf(length, 0);
+
+ lldb_private::Error read_error;
+
+ m_memory_map.ReadMemory(buf.GetBytes(), addr, length, read_error);
+
+ if (!read_error.Success())
+ return std::string("<couldn't read data>");
+
+ lldb_private::StreamString ss;
+
+ for (size_t i = 0; i < length; i++)
+ {
+ if ((!(i & 0xf)) && i)
+ ss.Printf("%02hhx - ", buf.GetBytes()[i]);
+ else
+ ss.Printf("%02hhx ", buf.GetBytes()[i]);
+ }
+
+ return ss.GetString();
+ }
+
+ lldb::addr_t ResolveValue (const Value *value, Module &module)
+ {
+ ValueMap::iterator i = m_values.find(value);
+
+ if (i != m_values.end())
+ return i->second;
+
+ // Fall back and allocate space [allocation type Alloca]
+
+ lldb::addr_t data_address = Malloc(value->getType());
+
+ if (const Constant *constant = dyn_cast<Constant>(value))
+ {
+ if (!ResolveConstant (data_address, constant))
+ {
+ lldb_private::Error free_error;
+ m_memory_map.Free(data_address, free_error);
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+
+ m_values[value] = data_address;
+ return data_address;
+ }
+};
+
+static const char *unsupported_opcode_error = "Interpreter doesn't handle one of the expression's opcodes";
+static const char *unsupported_operand_error = "Interpreter doesn't handle one of the expression's operands";
+//static const char *interpreter_initialization_error = "Interpreter couldn't be initialized";
+static const char *interpreter_internal_error = "Interpreter encountered an internal error";
+static const char *bad_value_error = "Interpreter couldn't resolve a value during execution";
+static const char *memory_allocation_error = "Interpreter couldn't allocate memory";
+static const char *memory_write_error = "Interpreter couldn't write to memory";
+static const char *memory_read_error = "Interpreter couldn't read from memory";
+static const char *infinite_loop_error = "Interpreter ran for too many cycles";
+//static const char *bad_result_error = "Result of expression is in bad memory";
+
+bool
+IRInterpreter::CanInterpret (llvm::Module &module,
+ llvm::Function &function,
+ lldb_private::Error &error)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ bool saw_function_with_body = false;
+
+ for (Module::iterator fi = module.begin(), fe = module.end();
+ fi != fe;
+ ++fi)
+ {
+ if (fi->begin() != fi->end())
+ {
+ if (saw_function_with_body)
+ return false;
+ saw_function_with_body = true;
+ }
+ }
+
+ for (Function::iterator bbi = function.begin(), bbe = function.end();
+ bbi != bbe;
+ ++bbi)
+ {
+ for (BasicBlock::iterator ii = bbi->begin(), ie = bbi->end();
+ ii != ie;
+ ++ii)
+ {
+ switch (ii->getOpcode())
+ {
+ default:
+ {
+ if (log)
+ log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(unsupported_opcode_error);
+ return false;
+ }
+ case Instruction::Add:
+ case Instruction::Alloca:
+ case Instruction::BitCast:
+ case Instruction::Br:
+ case Instruction::GetElementPtr:
+ break;
+ case Instruction::ICmp:
+ {
+ ICmpInst *icmp_inst = dyn_cast<ICmpInst>(ii);
+
+ if (!icmp_inst)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ switch (icmp_inst->getPredicate())
+ {
+ default:
+ {
+ if (log)
+ log->Printf("Unsupported ICmp predicate: %s", PrintValue(ii).c_str());
+
+ error.SetErrorToGenericError();
+ error.SetErrorString(unsupported_opcode_error);
+ return false;
+ }
+ case CmpInst::ICMP_EQ:
+ case CmpInst::ICMP_NE:
+ case CmpInst::ICMP_UGT:
+ case CmpInst::ICMP_UGE:
+ case CmpInst::ICMP_ULT:
+ case CmpInst::ICMP_ULE:
+ case CmpInst::ICMP_SGT:
+ case CmpInst::ICMP_SGE:
+ case CmpInst::ICMP_SLT:
+ case CmpInst::ICMP_SLE:
+ break;
+ }
+ }
+ break;
+ case Instruction::And:
+ case Instruction::AShr:
+ case Instruction::IntToPtr:
+ case Instruction::PtrToInt:
+ case Instruction::Load:
+ case Instruction::LShr:
+ case Instruction::Mul:
+ case Instruction::Or:
+ case Instruction::Ret:
+ case Instruction::SDiv:
+ case Instruction::SExt:
+ case Instruction::Shl:
+ case Instruction::SRem:
+ case Instruction::Store:
+ case Instruction::Sub:
+ case Instruction::UDiv:
+ case Instruction::URem:
+ case Instruction::Xor:
+ case Instruction::ZExt:
+ break;
+ }
+
+ for (int oi = 0, oe = ii->getNumOperands();
+ oi != oe;
+ ++oi)
+ {
+ Value *operand = ii->getOperand(oi);
+ Type *operand_type = operand->getType();
+
+ switch (operand_type->getTypeID())
+ {
+ default:
+ break;
+ case Type::VectorTyID:
+ {
+ if (log)
+ log->Printf("Unsupported operand type: %s", PrintType(operand_type).c_str());
+ error.SetErrorString(unsupported_operand_error);
+ return false;
+ }
+ }
+ }
+ }
+
+ }
+
+ return true;}
+
+bool
+IRInterpreter::Interpret (llvm::Module &module,
+ llvm::Function &function,
+ llvm::ArrayRef<lldb::addr_t> args,
+ lldb_private::IRMemoryMap &memory_map,
+ lldb_private::Error &error,
+ lldb::addr_t stack_frame_bottom,
+ lldb::addr_t stack_frame_top)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ module.print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf("Module as passed in to IRInterpreter::Interpret: \n\"%s\"", s.c_str());
+ }
+
+ DataLayout data_layout(&module);
+
+ InterpreterStackFrame frame(data_layout, memory_map, stack_frame_bottom, stack_frame_top);
+
+ if (frame.m_frame_process_address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorString("Couldn't allocate stack frame");
+ }
+
+ int arg_index = 0;
+
+ for (llvm::Function::arg_iterator ai = function.arg_begin(), ae = function.arg_end();
+ ai != ae;
+ ++ai, ++arg_index)
+ {
+ if (args.size() < arg_index)
+ {
+ error.SetErrorString ("Not enough arguments passed in to function");
+ return false;
+ }
+
+ lldb::addr_t ptr = args[arg_index];
+
+ frame.MakeArgument(ai, ptr);
+ }
+
+ uint32_t num_insts = 0;
+
+ frame.Jump(function.begin());
+
+ while (frame.m_ii != frame.m_ie && (++num_insts < 4096))
+ {
+ const Instruction *inst = frame.m_ii;
+
+ if (log)
+ log->Printf("Interpreting %s", PrintValue(inst).c_str());
+
+ switch (inst->getOpcode())
+ {
+ default:
+ break;
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Mul:
+ case Instruction::SDiv:
+ case Instruction::UDiv:
+ case Instruction::SRem:
+ case Instruction::URem:
+ case Instruction::Shl:
+ case Instruction::LShr:
+ case Instruction::AShr:
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ {
+ const BinaryOperator *bin_op = dyn_cast<BinaryOperator>(inst);
+
+ if (!bin_op)
+ {
+ if (log)
+ log->Printf("getOpcode() returns %s, but instruction is not a BinaryOperator", inst->getOpcodeName());
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *lhs = inst->getOperand(0);
+ Value *rhs = inst->getOperand(1);
+
+ lldb_private::Scalar L;
+ lldb_private::Scalar R;
+
+ if (!frame.EvaluateValue(L, lhs, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(lhs).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (!frame.EvaluateValue(R, rhs, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(rhs).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ lldb_private::Scalar result;
+
+ switch (inst->getOpcode())
+ {
+ default:
+ break;
+ case Instruction::Add:
+ result = L + R;
+ break;
+ case Instruction::Mul:
+ result = L * R;
+ break;
+ case Instruction::Sub:
+ result = L - R;
+ break;
+ case Instruction::SDiv:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = L / R;
+ break;
+ case Instruction::UDiv:
+ result = L.GetRawBits64(0) / R.GetRawBits64(1);
+ break;
+ case Instruction::SRem:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = L % R;
+ break;
+ case Instruction::URem:
+ result = L.GetRawBits64(0) % R.GetRawBits64(1);
+ break;
+ case Instruction::Shl:
+ result = L << R;
+ break;
+ case Instruction::AShr:
+ result = L >> R;
+ break;
+ case Instruction::LShr:
+ result = L;
+ result.ShiftRightLogical(R);
+ break;
+ case Instruction::And:
+ result = L & R;
+ break;
+ case Instruction::Or:
+ result = L | R;
+ break;
+ case Instruction::Xor:
+ result = L ^ R;
+ break;
+ }
+
+ frame.AssignValue(inst, result, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted a %s", inst->getOpcodeName());
+ log->Printf(" L : %s", frame.SummarizeValue(lhs).c_str());
+ log->Printf(" R : %s", frame.SummarizeValue(rhs).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::Alloca:
+ {
+ const AllocaInst *alloca_inst = dyn_cast<AllocaInst>(inst);
+
+ if (!alloca_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Alloca, but instruction is not an AllocaInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ if (alloca_inst->isArrayAllocation())
+ {
+ if (log)
+ log->Printf("AllocaInsts are not handled if isArrayAllocation() is true");
+ error.SetErrorToGenericError();
+ error.SetErrorString(unsupported_opcode_error);
+ return false;
+ }
+
+ // The semantics of Alloca are:
+ // Create a region R of virtual memory of type T, backed by a data buffer
+ // Create a region P of virtual memory of type T*, backed by a data buffer
+ // Write the virtual address of R into P
+
+ Type *T = alloca_inst->getAllocatedType();
+ Type *Tptr = alloca_inst->getType();
+
+ lldb::addr_t R = frame.Malloc(T);
+
+ if (R == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("Couldn't allocate memory for an AllocaInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_allocation_error);
+ return false;
+ }
+
+ lldb::addr_t P = frame.Malloc(Tptr);
+
+ if (P == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("Couldn't allocate the result pointer for an AllocaInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_allocation_error);
+ return false;
+ }
+
+ lldb_private::Error write_error;
+
+ memory_map.WritePointerToMemory(P, R, write_error);
+
+ if (!write_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't write the result pointer for an AllocaInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_write_error);
+ lldb_private::Error free_error;
+ memory_map.Free(P, free_error);
+ memory_map.Free(R, free_error);
+ return false;
+ }
+
+ frame.m_values[alloca_inst] = P;
+
+ if (log)
+ {
+ log->Printf("Interpreted an AllocaInst");
+ log->Printf(" R : 0x%" PRIx64, R);
+ log->Printf(" P : 0x%" PRIx64, P);
+ }
+ }
+ break;
+ case Instruction::BitCast:
+ case Instruction::ZExt:
+ {
+ const CastInst *cast_inst = dyn_cast<CastInst>(inst);
+
+ if (!cast_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns %s, but instruction is not a BitCastInst", cast_inst->getOpcodeName());
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *source = cast_inst->getOperand(0);
+
+ lldb_private::Scalar S;
+
+ if (!frame.EvaluateValue(S, source, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(source).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ frame.AssignValue(inst, S, module);
+ }
+ break;
+ case Instruction::SExt:
+ {
+ const CastInst *cast_inst = dyn_cast<CastInst>(inst);
+
+ if (!cast_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns %s, but instruction is not a BitCastInst", cast_inst->getOpcodeName());
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *source = cast_inst->getOperand(0);
+
+ lldb_private::Scalar S;
+
+ if (!frame.EvaluateValue(S, source, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(source).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ S.MakeSigned();
+
+ lldb_private::Scalar S_signextend(S.SLongLong());
+
+ frame.AssignValue(inst, S_signextend, module);
+ }
+ break;
+ case Instruction::Br:
+ {
+ const BranchInst *br_inst = dyn_cast<BranchInst>(inst);
+
+ if (!br_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Br, but instruction is not a BranchInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ if (br_inst->isConditional())
+ {
+ Value *condition = br_inst->getCondition();
+
+ lldb_private::Scalar C;
+
+ if (!frame.EvaluateValue(C, condition, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(condition).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (C.GetRawBits64(0))
+ frame.Jump(br_inst->getSuccessor(0));
+ else
+ frame.Jump(br_inst->getSuccessor(1));
+
+ if (log)
+ {
+ log->Printf("Interpreted a BrInst with a condition");
+ log->Printf(" cond : %s", frame.SummarizeValue(condition).c_str());
+ }
+ }
+ else
+ {
+ frame.Jump(br_inst->getSuccessor(0));
+
+ if (log)
+ {
+ log->Printf("Interpreted a BrInst with no condition");
+ }
+ }
+ }
+ continue;
+ case Instruction::GetElementPtr:
+ {
+ const GetElementPtrInst *gep_inst = dyn_cast<GetElementPtrInst>(inst);
+
+ if (!gep_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns GetElementPtr, but instruction is not a GetElementPtrInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ const Value *pointer_operand = gep_inst->getPointerOperand();
+ Type *pointer_type = pointer_operand->getType();
+
+ lldb_private::Scalar P;
+
+ if (!frame.EvaluateValue(P, pointer_operand, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(pointer_operand).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ typedef SmallVector <Value *, 8> IndexVector;
+ typedef IndexVector::iterator IndexIterator;
+
+ SmallVector <Value *, 8> indices (gep_inst->idx_begin(),
+ gep_inst->idx_end());
+
+ SmallVector <Value *, 8> const_indices;
+
+ for (IndexIterator ii = indices.begin(), ie = indices.end();
+ ii != ie;
+ ++ii)
+ {
+ ConstantInt *constant_index = dyn_cast<ConstantInt>(*ii);
+
+ if (!constant_index)
+ {
+ lldb_private::Scalar I;
+
+ if (!frame.EvaluateValue(I, *ii, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(*ii).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (log)
+ log->Printf("Evaluated constant index %s as %llu", PrintValue(*ii).c_str(), I.ULongLong(LLDB_INVALID_ADDRESS));
+
+ constant_index = cast<ConstantInt>(ConstantInt::get((*ii)->getType(), I.ULongLong(LLDB_INVALID_ADDRESS)));
+ }
+
+ const_indices.push_back(constant_index);
+ }
+
+ uint64_t offset = data_layout.getIndexedOffset(pointer_type, const_indices);
+
+ lldb_private::Scalar Poffset = P + offset;
+
+ frame.AssignValue(inst, Poffset, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted a GetElementPtrInst");
+ log->Printf(" P : %s", frame.SummarizeValue(pointer_operand).c_str());
+ log->Printf(" Poffset : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::ICmp:
+ {
+ const ICmpInst *icmp_inst = dyn_cast<ICmpInst>(inst);
+
+ if (!icmp_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns ICmp, but instruction is not an ICmpInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ CmpInst::Predicate predicate = icmp_inst->getPredicate();
+
+ Value *lhs = inst->getOperand(0);
+ Value *rhs = inst->getOperand(1);
+
+ lldb_private::Scalar L;
+ lldb_private::Scalar R;
+
+ if (!frame.EvaluateValue(L, lhs, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(lhs).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (!frame.EvaluateValue(R, rhs, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(rhs).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ lldb_private::Scalar result;
+
+ switch (predicate)
+ {
+ default:
+ return false;
+ case CmpInst::ICMP_EQ:
+ result = (L == R);
+ break;
+ case CmpInst::ICMP_NE:
+ result = (L != R);
+ break;
+ case CmpInst::ICMP_UGT:
+ result = (L.GetRawBits64(0) > R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_UGE:
+ result = (L.GetRawBits64(0) >= R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_ULT:
+ result = (L.GetRawBits64(0) < R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_ULE:
+ result = (L.GetRawBits64(0) <= R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_SGT:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = (L > R);
+ break;
+ case CmpInst::ICMP_SGE:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = (L >= R);
+ break;
+ case CmpInst::ICMP_SLT:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = (L < R);
+ break;
+ case CmpInst::ICMP_SLE:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = (L <= R);
+ break;
+ }
+
+ frame.AssignValue(inst, result, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted an ICmpInst");
+ log->Printf(" L : %s", frame.SummarizeValue(lhs).c_str());
+ log->Printf(" R : %s", frame.SummarizeValue(rhs).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::IntToPtr:
+ {
+ const IntToPtrInst *int_to_ptr_inst = dyn_cast<IntToPtrInst>(inst);
+
+ if (!int_to_ptr_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns IntToPtr, but instruction is not an IntToPtrInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *src_operand = int_to_ptr_inst->getOperand(0);
+
+ lldb_private::Scalar I;
+
+ if (!frame.EvaluateValue(I, src_operand, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(src_operand).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ frame.AssignValue(inst, I, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted an IntToPtr");
+ log->Printf(" Src : %s", frame.SummarizeValue(src_operand).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::PtrToInt:
+ {
+ const PtrToIntInst *ptr_to_int_inst = dyn_cast<PtrToIntInst>(inst);
+
+ if (!ptr_to_int_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns PtrToInt, but instruction is not an PtrToIntInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *src_operand = ptr_to_int_inst->getOperand(0);
+
+ lldb_private::Scalar I;
+
+ if (!frame.EvaluateValue(I, src_operand, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(src_operand).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ frame.AssignValue(inst, I, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted a PtrToInt");
+ log->Printf(" Src : %s", frame.SummarizeValue(src_operand).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::Load:
+ {
+ const LoadInst *load_inst = dyn_cast<LoadInst>(inst);
+
+ if (!load_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Load, but instruction is not a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ // The semantics of Load are:
+ // Create a region D that will contain the loaded data
+ // Resolve the region P containing a pointer
+ // Dereference P to get the region R that the data should be loaded from
+ // Transfer a unit of type type(D) from R to D
+
+ const Value *pointer_operand = load_inst->getPointerOperand();
+
+ Type *pointer_ty = pointer_operand->getType();
+ PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
+ if (!pointer_ptr_ty)
+ {
+ if (log)
+ log->Printf("getPointerOperand()->getType() is not a PointerType");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+ Type *target_ty = pointer_ptr_ty->getElementType();
+
+ lldb::addr_t D = frame.ResolveValue(load_inst, module);
+ lldb::addr_t P = frame.ResolveValue(pointer_operand, module);
+
+ if (D == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("LoadInst's value doesn't resolve to anything");
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (P == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("LoadInst's pointer doesn't resolve to anything");
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ lldb::addr_t R;
+ lldb_private::Error read_error;
+ memory_map.ReadPointerFromMemory(&R, P, read_error);
+
+ if (!read_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't read the address to be loaded for a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ size_t target_size = data_layout.getTypeStoreSize(target_ty);
+ lldb_private::DataBufferHeap buffer(target_size, 0);
+
+ read_error.Clear();
+ memory_map.ReadMemory(buffer.GetBytes(), R, buffer.GetByteSize(), read_error);
+ if (!read_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't read from a region on behalf of a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ lldb_private::Error write_error;
+ memory_map.WriteMemory(D, buffer.GetBytes(), buffer.GetByteSize(), write_error);
+ if (!write_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't write to a region on behalf of a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ if (log)
+ {
+ log->Printf("Interpreted a LoadInst");
+ log->Printf(" P : 0x%" PRIx64, P);
+ log->Printf(" R : 0x%" PRIx64, R);
+ log->Printf(" D : 0x%" PRIx64, D);
+ }
+ }
+ break;
+ case Instruction::Ret:
+ {
+ return true;
+ }
+ case Instruction::Store:
+ {
+ const StoreInst *store_inst = dyn_cast<StoreInst>(inst);
+
+ if (!store_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Store, but instruction is not a StoreInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ // The semantics of Store are:
+ // Resolve the region D containing the data to be stored
+ // Resolve the region P containing a pointer
+ // Dereference P to get the region R that the data should be stored in
+ // Transfer a unit of type type(D) from D to R
+
+ const Value *value_operand = store_inst->getValueOperand();
+ const Value *pointer_operand = store_inst->getPointerOperand();
+
+ Type *pointer_ty = pointer_operand->getType();
+ PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
+ if (!pointer_ptr_ty)
+ return false;
+ Type *target_ty = pointer_ptr_ty->getElementType();
+
+ lldb::addr_t D = frame.ResolveValue(value_operand, module);
+ lldb::addr_t P = frame.ResolveValue(pointer_operand, module);
+
+ if (D == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("StoreInst's value doesn't resolve to anything");
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (P == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("StoreInst's pointer doesn't resolve to anything");
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ lldb::addr_t R;
+ lldb_private::Error read_error;
+ memory_map.ReadPointerFromMemory(&R, P, read_error);
+
+ if (!read_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't read the address to be loaded for a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ size_t target_size = data_layout.getTypeStoreSize(target_ty);
+ lldb_private::DataBufferHeap buffer(target_size, 0);
+
+ read_error.Clear();
+ memory_map.ReadMemory(buffer.GetBytes(), D, buffer.GetByteSize(), read_error);
+ if (!read_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't read from a region on behalf of a StoreInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ lldb_private::Error write_error;
+ memory_map.WriteMemory(R, buffer.GetBytes(), buffer.GetByteSize(), write_error);
+ if (!write_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't write to a region on behalf of a StoreInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_write_error);
+ return false;
+ }
+
+ if (log)
+ {
+ log->Printf("Interpreted a StoreInst");
+ log->Printf(" D : 0x%" PRIx64, D);
+ log->Printf(" P : 0x%" PRIx64, P);
+ log->Printf(" R : 0x%" PRIx64, R);
+ }
+ }
+ break;
+ }
+
+ ++frame.m_ii;
+ }
+
+ if (num_insts >= 4096)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString(infinite_loop_error);
+ return false;
+ }
+
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp b/contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp
new file mode 100644
index 0000000..ef362ba
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/IRMemoryMap.cpp
@@ -0,0 +1,758 @@
+//===-- IRMemoryMap.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Expression/IRMemoryMap.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+IRMemoryMap::IRMemoryMap (lldb::TargetSP target_sp) :
+ m_target_wp(target_sp)
+{
+ if (target_sp)
+ m_process_wp = target_sp->GetProcessSP();
+}
+
+IRMemoryMap::~IRMemoryMap ()
+{
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ {
+ AllocationMap::iterator iter;
+
+ Error err;
+
+ while ((iter = m_allocations.begin()) != m_allocations.end())
+ {
+ err.Clear();
+ if (iter->second.m_leak)
+ m_allocations.erase(iter);
+ else
+ Free(iter->first, err);
+ }
+ }
+}
+
+lldb::addr_t
+IRMemoryMap::FindSpace (size_t size)
+{
+ lldb::TargetSP target_sp = m_target_wp.lock();
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ lldb::addr_t ret = LLDB_INVALID_ADDRESS;
+
+ if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
+ {
+ Error alloc_error;
+
+ ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error);
+
+ if (!alloc_error.Success())
+ return LLDB_INVALID_ADDRESS;
+ else
+ return ret;
+ }
+
+ for (int iterations = 0; iterations < 16; ++iterations)
+ {
+ lldb::addr_t candidate = LLDB_INVALID_ADDRESS;
+
+ switch (target_sp->GetArchitecture().GetAddressByteSize())
+ {
+ case 4:
+ {
+ uint32_t random_data = random();
+ candidate = random_data;
+ candidate &= ~0xfffull;
+ break;
+ }
+ case 8:
+ {
+ uint32_t random_low = random();
+ uint32_t random_high = random();
+ candidate = random_high;
+ candidate <<= 32ull;
+ candidate |= random_low;
+ candidate &= ~0xfffull;
+ break;
+ }
+ }
+
+ if (IntersectsAllocation(candidate, size))
+ continue;
+
+ ret = candidate;
+
+ return ret;
+ }
+
+ return ret;
+}
+
+IRMemoryMap::AllocationMap::iterator
+IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size)
+{
+ if (addr == LLDB_INVALID_ADDRESS)
+ return m_allocations.end();
+
+ AllocationMap::iterator iter = m_allocations.lower_bound (addr);
+
+ if (iter == m_allocations.end() ||
+ iter->first > addr)
+ {
+ if (iter == m_allocations.begin())
+ return m_allocations.end();
+ iter--;
+ }
+
+ if (iter->first <= addr && iter->first + iter->second.m_size >= addr + size)
+ return iter;
+
+ return m_allocations.end();
+}
+
+bool
+IRMemoryMap::IntersectsAllocation (lldb::addr_t addr, size_t size)
+{
+ if (addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ AllocationMap::iterator iter = m_allocations.lower_bound (addr);
+
+ if (iter == m_allocations.end() ||
+ iter->first > addr)
+ {
+ if (iter == m_allocations.begin())
+ return false;
+
+ iter--;
+ }
+
+ while (iter != m_allocations.end() && iter->second.m_process_alloc < addr + size)
+ {
+ if (iter->second.m_process_start + iter->second.m_size > addr)
+ return true;
+
+ ++iter;
+ }
+
+ return false;
+}
+
+lldb::ByteOrder
+IRMemoryMap::GetByteOrder()
+{
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ return process_sp->GetByteOrder();
+
+ lldb::TargetSP target_sp = m_target_wp.lock();
+
+ if (target_sp)
+ return target_sp->GetArchitecture().GetByteOrder();
+
+ return lldb::eByteOrderInvalid;
+}
+
+uint32_t
+IRMemoryMap::GetAddressByteSize()
+{
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ return process_sp->GetAddressByteSize();
+
+ lldb::TargetSP target_sp = m_target_wp.lock();
+
+ if (target_sp)
+ return target_sp->GetArchitecture().GetAddressByteSize();
+
+ return UINT32_MAX;
+}
+
+ExecutionContextScope *
+IRMemoryMap::GetBestExecutionContextScope()
+{
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ return process_sp.get();
+
+ lldb::TargetSP target_sp = m_target_wp.lock();
+
+ if (target_sp)
+ return target_sp.get();
+
+ return NULL;
+}
+
+IRMemoryMap::Allocation::Allocation (lldb::addr_t process_alloc,
+ lldb::addr_t process_start,
+ size_t size,
+ uint32_t permissions,
+ uint8_t alignment,
+ AllocationPolicy policy) :
+ m_process_alloc (process_alloc),
+ m_process_start (process_start),
+ m_size (size),
+ m_permissions (permissions),
+ m_alignment (alignment),
+ m_policy (policy),
+ m_leak (false)
+{
+ switch (policy)
+ {
+ default:
+ assert (0 && "We cannot reach this!");
+ case eAllocationPolicyHostOnly:
+ m_data.SetByteSize(size);
+ memset(m_data.GetBytes(), 0, size);
+ break;
+ case eAllocationPolicyProcessOnly:
+ break;
+ case eAllocationPolicyMirror:
+ m_data.SetByteSize(size);
+ memset(m_data.GetBytes(), 0, size);
+ break;
+ }
+}
+
+lldb::addr_t
+IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error)
+{
+ error.Clear();
+
+ lldb::ProcessSP process_sp;
+ lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS;
+ lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS;
+
+ size_t alignment_mask = alignment - 1;
+ size_t allocation_size;
+
+ if (size == 0)
+ allocation_size = alignment;
+ else
+ allocation_size = (size & alignment_mask) ? ((size + alignment) & (~alignment_mask)) : size;
+
+ switch (policy)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: invalid allocation policy");
+ return LLDB_INVALID_ADDRESS;
+ case eAllocationPolicyHostOnly:
+ allocation_address = FindSpace(allocation_size);
+ if (allocation_address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: address space is full");
+ return LLDB_INVALID_ADDRESS;
+ }
+ break;
+ case eAllocationPolicyMirror:
+ process_sp = m_process_wp.lock();
+ if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
+ {
+ allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+ }
+ else
+ {
+ policy = eAllocationPolicyHostOnly;
+ allocation_address = FindSpace(allocation_size);
+ if (allocation_address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: address space is full");
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ break;
+ case eAllocationPolicyProcessOnly:
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ if (process_sp->CanJIT() && process_sp->IsAlive())
+ {
+ allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: process doesn't support allocating memory");
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: process doesn't exist, and this memory must be in the process");
+ return LLDB_INVALID_ADDRESS;
+ }
+ break;
+ }
+
+
+ lldb::addr_t mask = alignment - 1;
+ aligned_address = (allocation_address + mask) & (~mask);
+
+ m_allocations[aligned_address] = Allocation(allocation_address,
+ aligned_address,
+ allocation_size,
+ permissions,
+ alignment,
+ policy);
+
+ if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ const char * policy_string;
+
+ switch (policy)
+ {
+ default:
+ policy_string = "<invalid policy>";
+ break;
+ case eAllocationPolicyHostOnly:
+ policy_string = "eAllocationPolicyHostOnly";
+ break;
+ case eAllocationPolicyProcessOnly:
+ policy_string = "eAllocationPolicyProcessOnly";
+ break;
+ case eAllocationPolicyMirror:
+ policy_string = "eAllocationPolicyMirror";
+ break;
+ }
+
+ log->Printf("IRMemoryMap::Malloc (%" PRIu64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", %s) -> 0x%" PRIx64,
+ (uint64_t)allocation_size,
+ (uint64_t)alignment,
+ (uint64_t)permissions,
+ policy_string,
+ aligned_address);
+ }
+
+ return aligned_address;
+}
+
+void
+IRMemoryMap::Leak (lldb::addr_t process_address, Error &error)
+{
+ error.Clear();
+
+ AllocationMap::iterator iter = m_allocations.find(process_address);
+
+ if (iter == m_allocations.end())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't leak: allocation doesn't exist");
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ allocation.m_leak = true;
+}
+
+void
+IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
+{
+ error.Clear();
+
+ AllocationMap::iterator iter = m_allocations.find(process_address);
+
+ if (iter == m_allocations.end())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't free: allocation doesn't exist");
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ switch (allocation.m_policy)
+ {
+ default:
+ case eAllocationPolicyHostOnly:
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ if (process_sp->CanJIT() && process_sp->IsAlive())
+ process_sp->DeallocateMemory(allocation.m_process_alloc); // FindSpace allocated this for real
+ }
+
+ break;
+ }
+ case eAllocationPolicyMirror:
+ case eAllocationPolicyProcessOnly:
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp)
+ process_sp->DeallocateMemory(allocation.m_process_alloc);
+ }
+ }
+
+ if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("IRMemoryMap::Free (0x%" PRIx64 ") freed [0x%" PRIx64 "..0x%" PRIx64 ")",
+ (uint64_t)process_address,
+ iter->second.m_process_start,
+ iter->second.m_process_start + iter->second.m_size);
+ }
+
+ m_allocations.erase(iter);
+}
+
+void
+IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error)
+{
+ error.Clear();
+
+ AllocationMap::iterator iter = FindAllocation(process_address, size);
+
+ if (iter == m_allocations.end())
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ {
+ process_sp->WriteMemory(process_address, bytes, size, error);
+ return;
+ }
+
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write: no allocation contains the target range and the process doesn't exist");
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ uint64_t offset = process_address - allocation.m_process_start;
+
+ lldb::ProcessSP process_sp;
+
+ switch (allocation.m_policy)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write: invalid allocation policy");
+ return;
+ case eAllocationPolicyHostOnly:
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write: data buffer is empty");
+ return;
+ }
+ ::memcpy (allocation.m_data.GetBytes() + offset, bytes, size);
+ break;
+ case eAllocationPolicyMirror:
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write: data buffer is empty");
+ return;
+ }
+ ::memcpy (allocation.m_data.GetBytes() + offset, bytes, size);
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ process_sp->WriteMemory(process_address, bytes, size, error);
+ if (!error.Success())
+ return;
+ }
+ break;
+ case eAllocationPolicyProcessOnly:
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ process_sp->WriteMemory(process_address, bytes, size, error);
+ if (!error.Success())
+ return;
+ }
+ break;
+ }
+
+ if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("IRMemoryMap::WriteMemory (0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRId64 ") went to [0x%" PRIx64 "..0x%" PRIx64 ")",
+ (uint64_t)process_address,
+ (uint64_t)bytes,
+ (uint64_t)size,
+ (uint64_t)allocation.m_process_start,
+ (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size);
+ }
+}
+
+void
+IRMemoryMap::WriteScalarToMemory (lldb::addr_t process_address, Scalar &scalar, size_t size, Error &error)
+{
+ error.Clear();
+
+ if (size == UINT32_MAX)
+ size = scalar.GetByteSize();
+
+ if (size > 0)
+ {
+ uint8_t buf[32];
+ const size_t mem_size = scalar.GetAsMemoryData (buf, size, GetByteOrder(), error);
+ if (mem_size > 0)
+ {
+ return WriteMemory(process_address, buf, mem_size, error);
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Couldn't write scalar: failed to get scalar as memory data");
+ }
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Couldn't write scalar: its size was zero");
+ }
+ return;
+}
+
+void
+IRMemoryMap::WritePointerToMemory (lldb::addr_t process_address, lldb::addr_t address, Error &error)
+{
+ error.Clear();
+
+ Scalar scalar(address);
+
+ WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
+}
+
+void
+IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error)
+{
+ error.Clear();
+
+ AllocationMap::iterator iter = FindAllocation(process_address, size);
+
+ if (iter == m_allocations.end())
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ {
+ process_sp->ReadMemory(process_address, bytes, size, error);
+ return;
+ }
+
+ lldb::TargetSP target_sp = m_target_wp.lock();
+
+ if (target_sp)
+ {
+ Address absolute_address(process_address);
+ target_sp->ReadMemory(absolute_address, false, bytes, size, error);
+ return;
+ }
+
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: no allocation contains the target range, and neither the process nor the target exist");
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ uint64_t offset = process_address - allocation.m_process_start;
+
+ lldb::ProcessSP process_sp;
+
+ switch (allocation.m_policy)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: invalid allocation policy");
+ return;
+ case eAllocationPolicyHostOnly:
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: data buffer is empty");
+ return;
+ }
+ ::memcpy (bytes, allocation.m_data.GetBytes() + offset, size);
+ break;
+ case eAllocationPolicyMirror:
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ process_sp->ReadMemory(process_address, bytes, size, error);
+ if (!error.Success())
+ return;
+ }
+ else
+ {
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: data buffer is empty");
+ return;
+ }
+ ::memcpy (bytes, allocation.m_data.GetBytes() + offset, size);
+ }
+ break;
+ case eAllocationPolicyProcessOnly:
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ process_sp->ReadMemory(process_address, bytes, size, error);
+ if (!error.Success())
+ return;
+ }
+ break;
+ }
+
+ if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("IRMemoryMap::ReadMemory (0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRId64 ") came from [0x%" PRIx64 "..0x%" PRIx64 ")",
+ (uint64_t)process_address,
+ (uint64_t)bytes,
+ (uint64_t)size,
+ (uint64_t)allocation.m_process_start,
+ (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size);
+ }
+}
+
+void
+IRMemoryMap::ReadScalarFromMemory (Scalar &scalar, lldb::addr_t process_address, size_t size, Error &error)
+{
+ error.Clear();
+
+ if (size > 0)
+ {
+ DataBufferHeap buf(size, 0);
+ ReadMemory(buf.GetBytes(), process_address, size, error);
+
+ if (!error.Success())
+ return;
+
+ DataExtractor extractor(buf.GetBytes(), buf.GetByteSize(), GetByteOrder(), GetAddressByteSize());
+
+ lldb::offset_t offset = 0;
+
+ switch (size)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Couldn't read scalar: unsupported size %" PRIu64, (uint64_t)size);
+ return;
+ case 1: scalar = extractor.GetU8(&offset); break;
+ case 2: scalar = extractor.GetU16(&offset); break;
+ case 4: scalar = extractor.GetU32(&offset); break;
+ case 8: scalar = extractor.GetU64(&offset); break;
+ }
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Couldn't read scalar: its size was zero");
+ }
+ return;
+}
+
+void
+IRMemoryMap::ReadPointerFromMemory (lldb::addr_t *address, lldb::addr_t process_address, Error &error)
+{
+ error.Clear();
+
+ Scalar pointer_scalar;
+ ReadScalarFromMemory(pointer_scalar, process_address, GetAddressByteSize(), error);
+
+ if (!error.Success())
+ return;
+
+ *address = pointer_scalar.ULongLong();
+
+ return;
+}
+
+void
+IRMemoryMap::GetMemoryData (DataExtractor &extractor, lldb::addr_t process_address, size_t size, Error &error)
+{
+ error.Clear();
+
+ if (size > 0)
+ {
+ AllocationMap::iterator iter = FindAllocation(process_address, size);
+
+ if (iter == m_allocations.end())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Couldn't find an allocation containing [0x%" PRIx64 "..0x%" PRIx64 ")", process_address, process_address + size);
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ switch (allocation.m_policy)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't get memory data: invalid allocation policy");
+ return;
+ case eAllocationPolicyProcessOnly:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't get memory data: memory is only in the target");
+ return;
+ case eAllocationPolicyMirror:
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't get memory data: data buffer is empty");
+ return;
+ }
+ if (process_sp)
+ {
+ process_sp->ReadMemory(allocation.m_process_start, allocation.m_data.GetBytes(), allocation.m_data.GetByteSize(), error);
+ if (!error.Success())
+ return;
+ uint64_t offset = process_address - allocation.m_process_start;
+ extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size, GetByteOrder(), GetAddressByteSize());
+ return;
+ }
+ }
+ case eAllocationPolicyHostOnly:
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't get memory data: data buffer is empty");
+ return;
+ }
+ uint64_t offset = process_address - allocation.m_process_start;
+ extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size, GetByteOrder(), GetAddressByteSize());
+ return;
+ }
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Couldn't get memory data: its size was zero");
+ return;
+ }
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp b/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp
new file mode 100644
index 0000000..8a1900e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp
@@ -0,0 +1,1414 @@
+//===-- Materializer.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb_private;
+
+uint32_t
+Materializer::AddStructMember (Entity &entity)
+{
+ uint32_t size = entity.GetSize();
+ uint32_t alignment = entity.GetAlignment();
+
+ uint32_t ret;
+
+ if (m_current_offset == 0)
+ m_struct_alignment = alignment;
+
+ if (m_current_offset % alignment)
+ m_current_offset += (alignment - (m_current_offset % alignment));
+
+ ret = m_current_offset;
+
+ m_current_offset += size;
+
+ return ret;
+}
+
+void
+Materializer::Entity::SetSizeAndAlignmentFromType (ClangASTType &type)
+{
+ m_size = type.GetByteSize();
+
+ uint32_t bit_alignment = type.GetTypeBitAlign();
+
+ if (bit_alignment % 8)
+ {
+ bit_alignment += 8;
+ bit_alignment &= ~((uint32_t)0x111u);
+ }
+
+ m_alignment = bit_alignment / 8;
+}
+
+class EntityPersistentVariable : public Materializer::Entity
+{
+public:
+ EntityPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp) :
+ Entity(),
+ m_persistent_variable_sp(persistent_variable_sp)
+ {
+ // Hard-coding to maximum size of a pointer since persistent variables are materialized by reference
+ m_size = 8;
+ m_alignment = 8;
+ }
+
+ void MakeAllocation (IRMemoryMap &map, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ // Allocate a spare memory area to store the persistent variable's contents.
+
+ Error allocate_error;
+
+ lldb::addr_t mem = map.Malloc(m_persistent_variable_sp->GetByteSize(),
+ 8,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ IRMemoryMap::eAllocationPolicyMirror,
+ allocate_error);
+
+ if (!allocate_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't allocate a memory area to store %s: %s", m_persistent_variable_sp->GetName().GetCString(), allocate_error.AsCString());
+ return;
+ }
+
+ if (log)
+ log->Printf("Allocated %s (0x%" PRIx64 ") sucessfully", m_persistent_variable_sp->GetName().GetCString(), mem);
+
+ // Put the location of the spare memory into the live data of the ValueObject.
+
+ m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create (map.GetBestExecutionContextScope(),
+ m_persistent_variable_sp->GetTypeFromUser(),
+ m_persistent_variable_sp->GetName(),
+ mem,
+ eAddressTypeLoad,
+ m_persistent_variable_sp->GetByteSize());
+
+ // Clear the flag if the variable will never be deallocated.
+
+ if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVKeepInTarget)
+ {
+ Error leak_error;
+ map.Leak(mem, leak_error);
+ m_persistent_variable_sp->m_flags &= ~ClangExpressionVariable::EVNeedsAllocation;
+ }
+
+ // Write the contents of the variable to the area.
+
+ Error write_error;
+
+ map.WriteMemory (mem,
+ m_persistent_variable_sp->GetValueBytes(),
+ m_persistent_variable_sp->GetByteSize(),
+ write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat ("couldn't write %s to the target: %s", m_persistent_variable_sp->GetName().AsCString(),
+ write_error.AsCString());
+ return;
+ }
+ }
+
+ void DestroyAllocation (IRMemoryMap &map, Error &err)
+ {
+ Error deallocate_error;
+
+ map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue().GetScalar().ULongLong(), deallocate_error);
+
+ m_persistent_variable_sp->m_live_sp.reset();
+
+ if (!deallocate_error.Success())
+ {
+ err.SetErrorStringWithFormat ("couldn't deallocate memory for %s: %s", m_persistent_variable_sp->GetName().GetCString(), deallocate_error.AsCString());
+ }
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64 ", m_name = %s, m_flags = 0x%hx]",
+ (uint64_t)load_addr,
+ m_persistent_variable_sp->GetName().AsCString(),
+ m_persistent_variable_sp->m_flags);
+ }
+
+ if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVNeedsAllocation)
+ {
+ MakeAllocation(map, err);
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+
+ if (!err.Success())
+ return;
+ }
+
+ if ((m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsProgramReference && m_persistent_variable_sp->m_live_sp) ||
+ m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsLLDBAllocated)
+ {
+ Error write_error;
+
+ map.WriteScalarToMemory(load_addr,
+ m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
+ map.GetAddressByteSize(),
+ write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the location of %s to memory: %s", m_persistent_variable_sp->GetName().AsCString(), write_error.AsCString());
+ }
+ }
+ else
+ {
+ err.SetErrorStringWithFormat("no materialization happened for persistent variable %s", m_persistent_variable_sp->GetName().AsCString());
+ return;
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64 ", m_name = %s, m_flags = 0x%hx]",
+ (uint64_t)process_address + m_offset,
+ m_persistent_variable_sp->GetName().AsCString(),
+ m_persistent_variable_sp->m_flags);
+ }
+
+ if ((m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsLLDBAllocated) ||
+ (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsProgramReference))
+ {
+ if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsProgramReference &&
+ !m_persistent_variable_sp->m_live_sp)
+ {
+ // If the reference comes from the program, then the ClangExpressionVariable's
+ // live variable data hasn't been set up yet. Do this now.
+
+ lldb::addr_t location;
+ Error read_error;
+
+ map.ReadPointerFromMemory(&location, load_addr, read_error);
+
+ if (!read_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't read the address of program-allocated variable %s: %s", m_persistent_variable_sp->GetName().GetCString(), read_error.AsCString());
+ return;
+ }
+
+ m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create (map.GetBestExecutionContextScope (),
+ m_persistent_variable_sp->GetTypeFromUser(),
+ m_persistent_variable_sp->GetName(),
+ location,
+ eAddressTypeLoad,
+ m_persistent_variable_sp->GetByteSize());
+
+ if (frame_top != LLDB_INVALID_ADDRESS &&
+ frame_bottom != LLDB_INVALID_ADDRESS &&
+ location >= frame_bottom &&
+ location <= frame_top)
+ {
+ // If the variable is resident in the stack frame created by the expression,
+ // then it cannot be relied upon to stay around. We treat it as needing
+ // reallocation.
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsFreezeDry;
+ m_persistent_variable_sp->m_flags &= ~ClangExpressionVariable::EVIsProgramReference;
+ }
+ }
+
+ lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue().GetScalar().ULongLong();
+
+ if (!m_persistent_variable_sp->m_live_sp)
+ {
+ err.SetErrorStringWithFormat("couldn't find the memory area used to store %s", m_persistent_variable_sp->GetName().GetCString());
+ return;
+ }
+
+ if (m_persistent_variable_sp->m_live_sp->GetValue().GetValueAddressType() != eAddressTypeLoad)
+ {
+ err.SetErrorStringWithFormat("the address of the memory area for %s is in an incorrect format", m_persistent_variable_sp->GetName().GetCString());
+ return;
+ }
+
+ if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVNeedsFreezeDry ||
+ m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVKeepInTarget)
+ {
+ if (log)
+ log->Printf("Dematerializing %s from 0x%" PRIx64 " (size = %llu)", m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem, (unsigned long long)m_persistent_variable_sp->GetByteSize());
+
+ // Read the contents of the spare memory area
+
+ m_persistent_variable_sp->ValueUpdated ();
+
+ Error read_error;
+
+ map.ReadMemory(m_persistent_variable_sp->GetValueBytes(),
+ mem,
+ m_persistent_variable_sp->GetByteSize(),
+ read_error);
+
+ if (!read_error.Success())
+ {
+ err.SetErrorStringWithFormat ("couldn't read the contents of %s from memory: %s", m_persistent_variable_sp->GetName().GetCString(), read_error.AsCString());
+ return;
+ }
+
+ m_persistent_variable_sp->m_flags &= ~ClangExpressionVariable::EVNeedsFreezeDry;
+ }
+ }
+ else
+ {
+ err.SetErrorStringWithFormat("no dematerialization happened for persistent variable %s", m_persistent_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ lldb::ProcessSP process_sp = map.GetBestExecutionContextScope()->CalculateProcess();
+ if (!process_sp ||
+ !process_sp->CanJIT())
+ {
+ // Allocations are not persistent so persistent variables cannot stay materialized.
+
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+
+ DestroyAllocation(map, err);
+ if (!err.Success())
+ return;
+ }
+ else if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVNeedsAllocation &&
+ !(m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVKeepInTarget))
+ {
+ DestroyAllocation(map, err);
+ if (!err.Success())
+ return;
+ }
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ Error err;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n", load_addr, m_persistent_variable_sp->GetName().AsCString());
+
+ {
+ dump_stream.Printf("Pointer:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ {
+ dump_stream.Printf("Target:\n");
+
+ lldb::addr_t target_address;
+
+ map.ReadPointerFromMemory (&target_address, load_addr, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataBufferHeap data (m_persistent_variable_sp->GetByteSize(), 0);
+
+ map.ReadMemory(data.GetBytes(), target_address, m_persistent_variable_sp->GetByteSize(), err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, target_address);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ }
+private:
+ lldb::ClangExpressionVariableSP m_persistent_variable_sp;
+};
+
+uint32_t
+Materializer::AddPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntityPersistentVariable (persistent_variable_sp));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
+class EntityVariable : public Materializer::Entity
+{
+public:
+ EntityVariable (lldb::VariableSP &variable_sp) :
+ Entity(),
+ m_variable_sp(variable_sp),
+ m_is_reference(false),
+ m_temporary_allocation(LLDB_INVALID_ADDRESS),
+ m_temporary_allocation_size(0)
+ {
+ // Hard-coding to maximum size of a pointer since all variables are materialized by reference
+ m_size = 8;
+ m_alignment = 8;
+ m_is_reference = m_variable_sp->GetType()->GetClangForwardType().IsReferenceType();
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+ if (log)
+ {
+ log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64 ", m_variable_sp = %s]",
+ (uint64_t)load_addr,
+ m_variable_sp->GetName().AsCString());
+ }
+
+ ExecutionContextScope *scope = frame_sp.get();
+
+ if (!scope)
+ scope = map.GetBestExecutionContextScope();
+
+ lldb::ValueObjectSP valobj_sp = ValueObjectVariable::Create(scope, m_variable_sp);
+
+ if (!valobj_sp)
+ {
+ err.SetErrorStringWithFormat("couldn't get a value object for variable %s", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ if (m_is_reference)
+ {
+ DataExtractor valobj_extractor;
+ valobj_sp->GetData(valobj_extractor);
+ lldb::offset_t offset = 0;
+ lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
+
+ Error write_error;
+ map.WritePointerToMemory(load_addr, reference_addr, write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the contents of reference variable %s to memory: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
+ return;
+ }
+ }
+ else
+ {
+ Error get_address_error;
+ lldb::ValueObjectSP addr_of_valobj_sp = valobj_sp->AddressOf(get_address_error);
+ if (get_address_error.Success())
+ {
+ DataExtractor valobj_extractor;
+ addr_of_valobj_sp->GetData(valobj_extractor);
+ lldb::offset_t offset = 0;
+ lldb::addr_t addr_of_valobj_addr = valobj_extractor.GetAddress(&offset);
+
+ Error write_error;
+ map.WritePointerToMemory(load_addr, addr_of_valobj_addr, write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the address of variable %s to memory: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
+ return;
+ }
+ }
+ else
+ {
+ DataExtractor data;
+ valobj_sp->GetData(data);
+
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ err.SetErrorStringWithFormat("trying to create a temporary region for %s but one exists", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ if (data.GetByteSize() != m_variable_sp->GetType()->GetByteSize())
+ {
+ if (data.GetByteSize() == 0 && m_variable_sp->LocationExpression().IsValid() == false)
+ {
+ err.SetErrorStringWithFormat("the variable '%s' has no location, it may have been optimized out", m_variable_sp->GetName().AsCString());
+ }
+ else
+ {
+ err.SetErrorStringWithFormat("size of variable %s disagrees with the ValueObject's size", m_variable_sp->GetName().AsCString());
+ }
+ return;
+ }
+
+ size_t bit_align = m_variable_sp->GetType()->GetClangLayoutType().GetTypeBitAlign();
+ size_t byte_align = (bit_align + 7) / 8;
+
+ Error alloc_error;
+
+ m_temporary_allocation = map.Malloc(data.GetByteSize(), byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error);
+ m_temporary_allocation_size = data.GetByteSize();
+
+ if (!alloc_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't allocate a temporary region for %s: %s", m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
+ return;
+ }
+
+ Error write_error;
+
+ map.WriteMemory(m_temporary_allocation, data.GetDataStart(), data.GetByteSize(), write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write to the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
+ return;
+ }
+
+ Error pointer_write_error;
+
+ map.WritePointerToMemory(load_addr, m_temporary_allocation, pointer_write_error);
+
+ if (!pointer_write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the address of the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), pointer_write_error.AsCString());
+ }
+ }
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+ if (log)
+ {
+ log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64 ", m_variable_sp = %s]",
+ (uint64_t)load_addr,
+ m_variable_sp->GetName().AsCString());
+ }
+
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ ExecutionContextScope *scope = frame_sp.get();
+
+ if (!scope)
+ scope = map.GetBestExecutionContextScope();
+
+ lldb::ValueObjectSP valobj_sp = ValueObjectVariable::Create(scope, m_variable_sp);
+
+ if (!valobj_sp)
+ {
+ err.SetErrorStringWithFormat("couldn't get a value object for variable %s", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ lldb_private::DataExtractor data;
+
+ Error extract_error;
+
+ map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(), extract_error);
+
+ if (!extract_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't get the data for variable %s", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ Error set_error;
+
+ valobj_sp->SetData(data, set_error);
+
+ if (!set_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the new contents of %s back into the variable", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ Error free_error;
+
+ map.Free(m_temporary_allocation, free_error);
+
+ if (!free_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't free the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), free_error.AsCString());
+ return;
+ }
+
+ m_temporary_allocation = LLDB_INVALID_ADDRESS;
+ m_temporary_allocation_size = 0;
+ }
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+ dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
+
+ Error err;
+
+ lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
+
+ {
+ dump_stream.Printf("Pointer:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ lldb::offset_t offset;
+
+ ptr = extractor.GetPointer(&offset);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
+ {
+ dump_stream.Printf("Points to process memory:\n");
+ }
+ else
+ {
+ dump_stream.Printf("Temporary allocation:\n");
+ }
+
+ if (ptr == LLDB_INVALID_ADDRESS)
+ {
+ dump_stream.Printf(" <could not be be found>\n");
+ }
+ else
+ {
+ DataBufferHeap data (m_temporary_allocation_size, 0);
+
+ map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ Error free_error;
+
+ map.Free(m_temporary_allocation, free_error);
+
+ m_temporary_allocation = LLDB_INVALID_ADDRESS;
+ m_temporary_allocation_size = 0;
+ }
+
+ }
+private:
+ lldb::VariableSP m_variable_sp;
+ bool m_is_reference;
+ lldb::addr_t m_temporary_allocation;
+ size_t m_temporary_allocation_size;
+};
+
+uint32_t
+Materializer::AddVariable (lldb::VariableSP &variable_sp, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntityVariable (variable_sp));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
+class EntityResultVariable : public Materializer::Entity
+{
+public:
+ EntityResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory) :
+ Entity(),
+ m_type(type),
+ m_is_program_reference(is_program_reference),
+ m_keep_in_memory(keep_in_memory),
+ m_temporary_allocation(LLDB_INVALID_ADDRESS),
+ m_temporary_allocation_size(0)
+ {
+ // Hard-coding to maximum size of a pointer since all results are materialized by reference
+ m_size = 8;
+ m_alignment = 8;
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ if (!m_is_program_reference)
+ {
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ err.SetErrorString("Trying to create a temporary region for the result but one exists");
+ return;
+ }
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ size_t byte_size = m_type.GetByteSize();
+ size_t bit_align = m_type.GetTypeBitAlign();
+ size_t byte_align = (bit_align + 7) / 8;
+
+ Error alloc_error;
+
+ m_temporary_allocation = map.Malloc(byte_size, byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error);
+ m_temporary_allocation_size = byte_size;
+
+ if (!alloc_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't allocate a temporary region for the result: %s", alloc_error.AsCString());
+ return;
+ }
+
+ Error pointer_write_error;
+
+ map.WritePointerToMemory(load_addr, m_temporary_allocation, pointer_write_error);
+
+ if (!pointer_write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the address of the temporary region for the result: %s", pointer_write_error.AsCString());
+ }
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ err.SetErrorString("Tried to detmaterialize a result variable with the normal Dematerialize method");
+ }
+
+ void Dematerialize (lldb::ClangExpressionVariableSP &result_variable_sp,
+ lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ err.Clear();
+
+ ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
+
+ if (!exe_scope)
+ {
+ err.SetErrorString("Couldn't dematerialize a result variable: invalid execution context scope");
+ return;
+ }
+
+ lldb::addr_t address;
+ Error read_error;
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ map.ReadPointerFromMemory (&address, load_addr, read_error);
+
+ if (!read_error.Success())
+ {
+ err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its address");
+ return;
+ }
+
+ lldb::TargetSP target_sp = exe_scope->CalculateTarget();
+
+ if (!target_sp)
+ {
+ err.SetErrorString("Couldn't dematerialize a result variable: no target");
+ return;
+ }
+
+ ConstString name = target_sp->GetPersistentVariables().GetNextPersistentVariableName();
+
+ lldb::ClangExpressionVariableSP ret;
+
+ ret = target_sp->GetPersistentVariables().CreateVariable(exe_scope,
+ name,
+ m_type,
+ map.GetByteOrder(),
+ map.GetAddressByteSize());
+
+ if (!ret)
+ {
+ err.SetErrorStringWithFormat("couldn't dematerialize a result variable: failed to make persistent variable %s", name.AsCString());
+ return;
+ }
+
+ lldb::ProcessSP process_sp = map.GetBestExecutionContextScope()->CalculateProcess();
+
+ bool can_persist = (m_is_program_reference && process_sp && process_sp->CanJIT() && !(address >= frame_bottom && address < frame_top));
+
+ if (can_persist && m_keep_in_memory)
+ {
+ ret->m_live_sp = ValueObjectConstResult::Create(exe_scope,
+ m_type,
+ name,
+ address,
+ eAddressTypeLoad,
+ ret->GetByteSize());
+ }
+
+ ret->ValueUpdated();
+
+ const size_t pvar_byte_size = ret->GetByteSize();
+ uint8_t *pvar_data = ret->GetValueBytes();
+
+ map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
+
+ if (!read_error.Success())
+ {
+ err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its memory");
+ return;
+ }
+
+ result_variable_sp = ret;
+
+ if (!can_persist || !m_keep_in_memory)
+ {
+ ret->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ Error free_error;
+ map.Free(m_temporary_allocation, free_error);
+ }
+ }
+ else
+ {
+ ret->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+ }
+
+ m_temporary_allocation = LLDB_INVALID_ADDRESS;
+ m_temporary_allocation_size = 0;
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
+
+ Error err;
+
+ lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
+
+ {
+ dump_stream.Printf("Pointer:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ lldb::offset_t offset;
+
+ ptr = extractor.GetPointer(&offset);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
+ {
+ dump_stream.Printf("Points to process memory:\n");
+ }
+ else
+ {
+ dump_stream.Printf("Temporary allocation:\n");
+ }
+
+ if (ptr == LLDB_INVALID_ADDRESS)
+ {
+ dump_stream.Printf(" <could not be be found>\n");
+ }
+ else
+ {
+ DataBufferHeap data (m_temporary_allocation_size, 0);
+
+ map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ Error free_error;
+
+ map.Free(m_temporary_allocation, free_error);
+ }
+
+ m_temporary_allocation = LLDB_INVALID_ADDRESS;
+ m_temporary_allocation_size = 0;
+ }
+private:
+ TypeFromUser m_type;
+ bool m_is_program_reference;
+ bool m_keep_in_memory;
+
+ lldb::addr_t m_temporary_allocation;
+ size_t m_temporary_allocation_size;
+};
+
+uint32_t
+Materializer::AddResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntityResultVariable (type, is_program_reference, keep_in_memory));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ m_result_entity = iter->get();
+ return ret;
+}
+
+class EntitySymbol : public Materializer::Entity
+{
+public:
+ EntitySymbol (const Symbol &symbol) :
+ Entity(),
+ m_symbol(symbol)
+ {
+ // Hard-coding to maximum size of a symbol
+ m_size = 8;
+ m_alignment = 8;
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64 ", m_symbol = %s]",
+ (uint64_t)load_addr,
+ m_symbol.GetName().AsCString());
+ }
+
+ Address &sym_address = m_symbol.GetAddress();
+
+ ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
+
+ lldb::TargetSP target_sp;
+
+ if (exe_scope)
+ target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
+
+ if (!target_sp)
+ {
+ err.SetErrorStringWithFormat("couldn't resolve symbol %s because there is no target", m_symbol.GetName().AsCString());
+ return;
+ }
+
+ lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
+
+ if (resolved_address == LLDB_INVALID_ADDRESS)
+ resolved_address = sym_address.GetFileAddress();
+
+ Error pointer_write_error;
+
+ map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
+
+ if (!pointer_write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the address of symbol %s: %s", m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
+ return;
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64 ", m_symbol = %s]",
+ (uint64_t)load_addr,
+ m_symbol.GetName().AsCString());
+ }
+
+ // no work needs to be done
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ Error err;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, m_symbol.GetName().AsCString());
+
+ {
+ dump_stream.Printf("Pointer:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ }
+private:
+ Symbol m_symbol;
+};
+
+uint32_t
+Materializer::AddSymbol (const Symbol &symbol_sp, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntitySymbol (symbol_sp));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
+class EntityRegister : public Materializer::Entity
+{
+public:
+ EntityRegister (const RegisterInfo &register_info) :
+ Entity(),
+ m_register_info(register_info)
+ {
+ // Hard-coding alignment conservatively
+ m_size = m_register_info.byte_size;
+ m_alignment = m_register_info.byte_size;
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64 ", m_register_info = %s]",
+ (uint64_t)load_addr,
+ m_register_info.name);
+ }
+
+ RegisterValue reg_value;
+
+ if (!frame_sp.get())
+ {
+ err.SetErrorStringWithFormat("couldn't materialize register %s without a stack frame", m_register_info.name);
+ return;
+ }
+
+ lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
+
+ if (!reg_context_sp->ReadRegister(&m_register_info, reg_value))
+ {
+ err.SetErrorStringWithFormat("couldn't read the value of register %s", m_register_info.name);
+ return;
+ }
+
+ DataExtractor register_data;
+
+ if (!reg_value.GetData(register_data))
+ {
+ err.SetErrorStringWithFormat("couldn't get the data for register %s", m_register_info.name);
+ return;
+ }
+
+ if (register_data.GetByteSize() != m_register_info.byte_size)
+ {
+ err.SetErrorStringWithFormat("data for register %s had size %llu but we expected %llu", m_register_info.name, (unsigned long long)register_data.GetByteSize(), (unsigned long long)m_register_info.byte_size);
+ return;
+ }
+
+ m_register_contents.reset(new DataBufferHeap(register_data.GetDataStart(), register_data.GetByteSize()));
+
+ Error write_error;
+
+ map.WriteMemory(load_addr, register_data.GetDataStart(), register_data.GetByteSize(), write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the contents of register %s: %s", m_register_info.name, write_error.AsCString());
+ return;
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64 ", m_register_info = %s]",
+ (uint64_t)load_addr,
+ m_register_info.name);
+ }
+
+ Error extract_error;
+
+ DataExtractor register_data;
+
+ if (!frame_sp.get())
+ {
+ err.SetErrorStringWithFormat("couldn't dematerialize register %s without a stack frame", m_register_info.name);
+ return;
+ }
+
+ lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
+
+ map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, extract_error);
+
+ if (!extract_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't get the data for register %s: %s", m_register_info.name, extract_error.AsCString());
+ return;
+ }
+
+ if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), register_data.GetByteSize()))
+ {
+ // No write required, and in particular we avoid errors if the register wasn't writable
+
+ m_register_contents.reset();
+ return;
+ }
+
+ m_register_contents.reset();
+
+ RegisterValue register_value (const_cast<uint8_t*>(register_data.GetDataStart()), register_data.GetByteSize(), register_data.GetByteOrder());
+
+ if (!reg_context_sp->WriteRegister(&m_register_info, register_value))
+ {
+ err.SetErrorStringWithFormat("couldn't write the value of register %s", m_register_info.name);
+ return;
+ }
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ Error err;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+
+ dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, m_register_info.name);
+
+ {
+ dump_stream.Printf("Value:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ }
+private:
+ RegisterInfo m_register_info;
+ lldb::DataBufferSP m_register_contents;
+};
+
+uint32_t
+Materializer::AddRegister (const RegisterInfo &register_info, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntityRegister (register_info));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
+Materializer::Materializer () :
+ m_dematerializer_wp(),
+ m_result_entity(NULL),
+ m_current_offset(0),
+ m_struct_alignment(8)
+{
+}
+
+Materializer::~Materializer ()
+{
+ DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
+
+ if (dematerializer_sp)
+ dematerializer_sp->Wipe();
+}
+
+Materializer::DematerializerSP
+Materializer::Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &error)
+{
+ ExecutionContextScope *exe_scope = frame_sp.get();
+
+ if (!exe_scope)
+ exe_scope = map.GetBestExecutionContextScope();
+
+ DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
+
+ if (dematerializer_sp)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't materialize: already materialized");
+ }
+
+ DematerializerSP ret(new Dematerializer(*this, frame_sp, map, process_address));
+
+ if (!exe_scope)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't materialize: target doesn't exist");
+ }
+
+ for (EntityUP &entity_up : m_entities)
+ {
+ entity_up->Materialize(frame_sp, map, process_address, error);
+
+ if (!error.Success())
+ return DematerializerSP();
+ }
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 ") materialized:", frame_sp.get(), process_address);
+ for (EntityUP &entity_up : m_entities)
+ entity_up->DumpToLog(map, process_address, log);
+ }
+
+ m_dematerializer_wp = ret;
+
+ return ret;
+}
+
+void
+Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpressionVariableSP &result_sp, lldb::addr_t frame_bottom, lldb::addr_t frame_top)
+{
+ lldb::StackFrameSP frame_sp;
+
+ lldb::ThreadSP thread_sp = m_thread_wp.lock();
+ if (thread_sp)
+ frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
+
+ ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
+
+ if (!IsValid())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
+ }
+
+ if (!exe_scope)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't dematerialize: target is gone");
+ }
+ else
+ {
+ if (Log *log =lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address = 0x%" PRIx64 ") about to dematerialize:", frame_sp.get(), m_process_address);
+ for (EntityUP &entity_up : m_materializer->m_entities)
+ entity_up->DumpToLog(*m_map, m_process_address, log);
+ }
+
+ for (EntityUP &entity_up : m_materializer->m_entities)
+ {
+ if (entity_up.get() == m_materializer->m_result_entity)
+ {
+ static_cast<EntityResultVariable*>(m_materializer->m_result_entity)->Dematerialize (result_sp, frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
+ }
+ else
+ {
+ entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
+ }
+
+ if (!error.Success())
+ break;
+ }
+ }
+
+ Wipe();
+}
+
+void
+Materializer::Dematerializer::Wipe ()
+{
+ if (!IsValid())
+ return;
+
+ for (EntityUP &entity_up : m_materializer->m_entities)
+ {
+ entity_up->Wipe (*m_map, m_process_address);
+ }
+
+ m_materializer = NULL;
+ m_map = NULL;
+ m_process_address = LLDB_INVALID_ADDRESS;
+}
OpenPOWER on IntegriCloud