diff options
Diffstat (limited to 'source/Expression')
26 files changed, 2431 insertions, 11517 deletions
diff --git a/source/Expression/ASTDumper.cpp b/source/Expression/ASTDumper.cpp deleted file mode 100644 index 5210d14..0000000 --- a/source/Expression/ASTDumper.cpp +++ /dev/null @@ -1,132 +0,0 @@ -//===-- 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/source/Expression/ASTResultSynthesizer.cpp b/source/Expression/ASTResultSynthesizer.cpp deleted file mode 100644 index c3d42cb..0000000 --- a/source/Expression/ASTResultSynthesizer.cpp +++ /dev/null @@ -1,512 +0,0 @@ -//===-- 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.get(), true, false); - } - else - { - IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result"); - - result_decl = VarDecl::Create(Ctx, - DC, - SourceLocation(), - SourceLocation(), - &result_id, - expr_qual_type, - NULL, - SC_Static); - - if (!result_decl) - return false; - - m_sema->AddInitializerToDecl(result_decl, last_expr, true, false); - } - - DC->addDecl(result_decl); - - /////////////////////////////// - // call AddInitializerToDecl - // - - //m_sema->AddInitializerToDecl(result_decl, last_expr); - - ///////////////////////////////// - // call ConvertDeclToDeclGroup - // - - Sema::DeclGroupPtrTy result_decl_group_ptr; - - result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl); - - //////////////////////// - // call ActOnDeclStmt - // - - StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(result_decl_group_ptr, - SourceLocation(), - SourceLocation())); - - //////////////////////////////////////////////// - // replace the old statement with the new one - // - - *last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.get()); - - return true; -} - -void -ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx) -{ - if (m_passthrough) - m_passthrough->HandleTranslationUnit(Ctx); -} - -void -ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx) -{ - typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator; - - for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()), - e = TypeDeclIterator(FunDeclCtx->decls_end()); - i != e; - ++i) - { - MaybeRecordPersistentType(*i); - } -} - -void -ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D) -{ - if (!D->getIdentifier()) - return; - - StringRef name = D->getName(); - - if (name.size() == 0 || name[0] != '$') - return; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - ConstString name_cs(name.str().c_str()); - - if (log) - log->Printf ("Recording persistent type %s\n", name_cs.GetCString()); - - Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl(m_target.GetScratchClangASTContext()->getASTContext(), - m_ast_context, - D); - - if (TypeDecl *TypeDecl_scratch = dyn_cast<TypeDecl>(D_scratch)) - 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) -{ - if (m_passthrough) - m_passthrough->HandleVTable(RD); -} - -void -ASTResultSynthesizer::PrintStats() -{ - if (m_passthrough) - m_passthrough->PrintStats(); -} - -void -ASTResultSynthesizer::InitializeSema(Sema &S) -{ - m_sema = &S; - - if (m_passthrough_sema) - m_passthrough_sema->InitializeSema(S); -} - -void -ASTResultSynthesizer::ForgetSema() -{ - m_sema = NULL; - - if (m_passthrough_sema) - m_passthrough_sema->ForgetSema(); -} diff --git a/source/Expression/ASTStructExtractor.cpp b/source/Expression/ASTStructExtractor.cpp deleted file mode 100644 index 98628db..0000000 --- a/source/Expression/ASTStructExtractor.cpp +++ /dev/null @@ -1,220 +0,0 @@ -//===-- 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) -{ - if (m_passthrough) - m_passthrough->HandleVTable(RD); -} - -void -ASTStructExtractor::PrintStats() -{ - if (m_passthrough) - m_passthrough->PrintStats(); -} - -void -ASTStructExtractor::InitializeSema(Sema &S) -{ - m_sema = &S; - m_action = reinterpret_cast<Action*>(m_sema); - - if (m_passthrough_sema) - m_passthrough_sema->InitializeSema(S); -} - -void -ASTStructExtractor::ForgetSema() -{ - m_sema = NULL; - m_action = NULL; - - if (m_passthrough_sema) - m_passthrough_sema->ForgetSema(); -} diff --git a/source/Expression/ClangASTSource.cpp b/source/Expression/ClangASTSource.cpp deleted file mode 100644 index 3988cd6..0000000 --- a/source/Expression/ClangASTSource.cpp +++ /dev/null @@ -1,2075 +0,0 @@ -//===-- 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/Expression/ClangModulesDeclVendor.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangNamespaceDecl.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/SymbolVendor.h" -#include "lldb/Symbol/TaggedASTType.h" -#include "lldb/Target/ObjCLanguageRuntime.h" -#include "lldb/Target/Target.h" - -#include <vector> - -using namespace clang; -using namespace lldb_private; - -//------------------------------------------------------------------ -// Scoped class that will remove an active lexical decl from the set -// when it goes out of scope. -//------------------------------------------------------------------ -namespace { - class ScopedLexicalDeclEraser - { - public: - ScopedLexicalDeclEraser(std::set<const clang::Decl *> &decls, - const clang::Decl *decl) - : m_active_lexical_decls(decls), m_decl(decl) - { - } - - ~ScopedLexicalDeclEraser() - { - m_active_lexical_decls.erase(m_decl); - } - - private: - std::set<const clang::Decl *> &m_active_lexical_decls; - const clang::Decl *m_decl; - }; -} - -ClangASTSource::~ClangASTSource() -{ - m_ast_importer->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, static_cast<void*>(m_ast_context), - static_cast<void*>(tag_decl), - tag_decl->getName().str().c_str()); - - log->Printf(" CTD[%u] Before:", current_id); - ASTDumper dumper((Decl*)tag_decl); - dumper.ToLog(log, " [CTD] "); - } - - auto iter = m_active_lexical_decls.find(tag_decl); - if (iter != m_active_lexical_decls.end()) - return; - m_active_lexical_decls.insert(tag_decl); - ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl); - - if (!m_ast_importer->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, static_cast<void*>(namespace_map.get()), - static_cast<int>(namespace_map->size())); - - if (!namespace_map) - return; - - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end(); - i != e && !found; - ++i) - { - if (log) - log->Printf(" CTD[%u] Searching namespace %s in module %s", - current_id, - i->second.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", - static_cast<void*>(m_ast_context), - interface_decl->getName().str().c_str()); - log->Printf(" [COID] Before:"); - ASTDumper dumper((Decl*)interface_decl); - dumper.ToLog(log, " [COID] "); - } - - Decl *original_decl = NULL; - ASTContext *original_ctx = NULL; - - if (m_ast_importer->ResolveDeclOrigin(interface_decl, &original_decl, &original_ctx)) - { - if (ObjCInterfaceDecl *original_iface_decl = dyn_cast<ObjCInterfaceDecl>(original_decl)) - { - ObjCInterfaceDecl *complete_iface_decl = GetCompleteObjCInterface(original_iface_decl); - - if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) - { - m_ast_importer->SetDeclOrigin(interface_decl, original_iface_decl); - } - } - } - - m_ast_importer->CompleteObjCInterfaceDecl (interface_decl); - - if (interface_decl->getSuperClass() && - interface_decl->getSuperClass() != interface_decl) - CompleteType(interface_decl->getSuperClass()); - - if (log) - { - log->Printf(" [COID] After:"); - ASTDumper dumper((Decl*)interface_decl); - dumper.ToLog(log, " [COID] "); - } -} - -clang::ObjCInterfaceDecl * -ClangASTSource::GetCompleteObjCInterface (clang::ObjCInterfaceDecl *interface_decl) -{ - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - return NULL; - - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); - - if (!language_runtime) - return NULL; - - ConstString class_name(interface_decl->getNameAsString().c_str()); - - lldb::TypeSP complete_type_sp(language_runtime->LookupInCompleteClassCache(class_name)); - - if (!complete_type_sp) - return NULL; - - TypeFromUser complete_type = TypeFromUser(complete_type_sp->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; - - auto iter = m_active_lexical_decls.find(context_decl); - if (iter != m_active_lexical_decls.end()) - return ELR_Failure; - m_active_lexical_decls.insert(context_decl); - ScopedLexicalDeclEraser eraser(m_active_lexical_decls, context_decl); - - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - - if (log) - { - if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl)) - log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in '%s' (%sDecl*)%p with %s predicate", - current_id, static_cast<void*>(m_ast_context), - context_named_decl->getNameAsString().c_str(), - context_decl->getDeclKindName(), - static_cast<const void*>(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, static_cast<void*>(m_ast_context), - context_decl->getDeclKindName(), - static_cast<const void*>(context_decl), - (predicate ? "non-null" : "null")); - else - log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in a NULL context with %s predicate", - current_id, static_cast<const void*>(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, static_cast<void*>(original_ctx), - static_cast<void*>(original_decl)); - ASTDumper(original_decl).ToLog(log, " "); - } - - if (ObjCInterfaceDecl *original_iface_decl = dyn_cast<ObjCInterfaceDecl>(original_decl)) - { - ObjCInterfaceDecl *complete_iface_decl = GetCompleteObjCInterface(original_iface_decl); - - if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) - { - original_decl = complete_iface_decl; - original_ctx = &complete_iface_decl->getASTContext(); - - m_ast_importer->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, static_cast<void*>(m_ast_context), - name.GetCString()); - else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context)) - log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in '%s'", - current_id, static_cast<void*>(m_ast_context), - name.GetCString(), - context_named_decl->getNameAsString().c_str()); - else - log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a '%s'", - current_id, static_cast<void*>(m_ast_context), - name.GetCString(), - context.m_decl_context->getDeclKindName()); - } - - context.m_namespace_map.reset(new ClangASTImporter::NamespaceMap); - - if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context)) - { - ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer->GetNamespaceMap(namespace_context); - - if (log && log->GetVerbose()) - log->Printf(" CAS::FEVD[%u] Inspecting namespace map %p (%d entries)", - current_id, static_cast<void*>(namespace_map.get()), - static_cast<int>(namespace_map->size())); - - if (!namespace_map) - return; - - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end(); - i != e; - ++i) - { - if (log) - log->Printf(" CAS::FEVD[%u] Searching namespace %s in module %s", - current_id, - i->second.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, - static_cast<void*>(context.m_namespace_map.get()), - static_cast<int>(context.m_namespace_map->size())); - - NamespaceDecl *clang_namespace_decl = AddNamespace(context, context.m_namespace_map); - - if (clang_namespace_decl) - clang_namespace_decl->setHasExternalVisibleStorage(); - } -} - -void -ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context, - lldb::ModuleSP module_sp, - 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); - - bool found_a_type = false; - - 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); - - found_a_type = true; - } - - if (!found_a_type) - { - // Try the modules next. - - do - { - if (ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor()) - { - bool append = false; - uint32_t max_matches = 1; - std::vector <clang::NamedDecl *> decls; - - if (!modules_decl_vendor->FindDecls(name, - append, - max_matches, - decls)) - break; - - if (log) - { - log->Printf(" CAS::FEVD[%u] Matching entity found for \"%s\" in the modules", - current_id, - name.GetCString()); - } - - clang::NamedDecl *const decl_from_modules = decls[0]; - - if (llvm::isa<clang::TypeDecl>(decl_from_modules) || - llvm::isa<clang::ObjCContainerDecl>(decl_from_modules) || - llvm::isa<clang::EnumConstantDecl>(decl_from_modules)) - { - clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules); - clang::NamedDecl *copied_named_decl = copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; - - if (!copied_named_decl) - { - if (log) - log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the modules", - current_id); - - break; - } - - context.AddNamedDecl(copied_named_decl); - - found_a_type = true; - } - } - } while (0); - } - - if (!found_a_type) - { - do - { - // Couldn't find any types elsewhere. Try the Objective-C runtime if one exists. - - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - break; - - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); - - if (!language_runtime) - break; - - DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); - - if (!decl_vendor) - break; - - bool append = false; - uint32_t max_matches = 1; - std::vector <clang::NamedDecl *> decls; - - if (!decl_vendor->FindDecls(name, - append, - max_matches, - decls)) - break; - - if (log) - { - log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\" in the runtime", - current_id, - name.GetCString()); - } - - clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decls[0]->getASTContext(), decls[0]); - clang::NamedDecl *copied_named_decl = copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; - - if (!copied_named_decl) - { - if (log) - log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the runtime", - current_id); - - break; - } - - context.AddNamedDecl(copied_named_decl); - } - while(0); - } - - } while(0); -} - -template <class D> class TaggedASTDecl { -public: - TaggedASTDecl() : decl(NULL) { } - TaggedASTDecl(D *_decl) : decl(_decl) { } - bool IsValid() const { return (decl != NULL); } - bool IsInvalid() const { return !IsValid(); } - D *operator->() const { return decl; } - D *decl; -}; - -template <class D2, template <class D> class TD, class D1> -TD<D2> -DynCast(TD<D1> source) -{ - return TD<D2> (dyn_cast<D2>(source.decl)); -} - -template <class D = Decl> class DeclFromParser; -template <class D = Decl> class DeclFromUser; - -template <class D> class DeclFromParser : public TaggedASTDecl<D> { -public: - DeclFromParser() : TaggedASTDecl<D>() { } - DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) { } - - DeclFromUser<D> GetOrigin(ClangASTImporter *importer); -}; - -template <class D> class DeclFromUser : public TaggedASTDecl<D> { -public: - DeclFromUser() : TaggedASTDecl<D>() { } - DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) { } - - DeclFromParser<D> Import(ClangASTImporter *importer, ASTContext &dest_ctx); -}; - -template <class D> -DeclFromUser<D> -DeclFromParser<D>::GetOrigin(ClangASTImporter *importer) -{ - DeclFromUser <> origin_decl; - importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL); - if (origin_decl.IsInvalid()) - return DeclFromUser<D>(); - return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl)); -} - -template <class D> -DeclFromParser<D> -DeclFromUser<D>::Import(ClangASTImporter *importer, ASTContext &dest_ctx) -{ - DeclFromParser <> parser_generic_decl(importer->CopyDecl(&dest_ctx, &this->decl->getASTContext(), this->decl)); - if (parser_generic_decl.IsInvalid()) - return DeclFromParser<D>(); - return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl)); -} - -static bool -FindObjCMethodDeclsWithOrigin (unsigned int current_id, - NameSearchContext &context, - ObjCInterfaceDecl *original_interface_decl, - clang::ASTContext *ast_context, - ClangASTImporter *ast_importer, - const char *log_info) -{ - const DeclarationName &decl_name(context.m_decl_name); - clang::ASTContext *original_ctx = &original_interface_decl->getASTContext(); - - Selector original_selector; - - if (decl_name.isObjCZeroArgSelector()) - { - IdentifierInfo *ident = &original_ctx->Idents.get(decl_name.getAsString()); - original_selector = original_ctx->Selectors.getSelector(0, &ident); - } - else if (decl_name.isObjCOneArgSelector()) - { - const std::string &decl_name_string = decl_name.getAsString(); - std::string decl_name_string_without_colon(decl_name_string.c_str(), decl_name_string.length() - 1); - IdentifierInfo *ident = &original_ctx->Idents.get(decl_name_string_without_colon.c_str()); - original_selector = original_ctx->Selectors.getSelector(1, &ident); - } - else - { - SmallVector<IdentifierInfo *, 4> idents; - - clang::Selector sel = decl_name.getObjCSelector(); - - unsigned num_args = sel.getNumArgs(); - - for (unsigned i = 0; - i != num_args; - ++i) - { - idents.push_back(&original_ctx->Idents.get(sel.getNameForSlot(i))); - } - - original_selector = original_ctx->Selectors.getSelector(num_args, idents.data()); - } - - DeclarationName original_decl_name(original_selector); - - llvm::SmallVector<NamedDecl *, 1> methods; - - ClangASTContext::GetCompleteDecl(original_ctx, original_interface_decl); - - if (ObjCMethodDecl *instance_method_decl = original_interface_decl->lookupInstanceMethod(original_selector)) - { - methods.push_back(instance_method_decl); - } - else if (ObjCMethodDecl *class_method_decl = original_interface_decl->lookupClassMethod(original_selector)) - { - methods.push_back(class_method_decl); - } - - if (methods.empty()) - { - return false; - } - - for (NamedDecl *named_decl : methods) - { - if (!named_decl) - continue; - - ObjCMethodDecl *result_method = dyn_cast<ObjCMethodDecl>(named_decl); - - if (!result_method) - continue; - - Decl *copied_decl = ast_importer->CopyDecl(ast_context, &result_method->getASTContext(), result_method); - - if (!copied_decl) - continue; - - ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl); - - if (!copied_method_decl) - continue; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - { - ASTDumper dumper((Decl*)copied_method_decl); - log->Printf(" CAS::FOMD[%d] found (%s) %s", current_id, log_info, dumper.GetCString()); - } - - context.AddNamedDecl(copied_method_decl); - } - - return true; -} - -void -ClangASTSource::FindObjCMethodDecls (NameSearchContext &context) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - - const DeclarationName &decl_name(context.m_decl_name); - const DeclContext *decl_ctx(context.m_decl_context); - - const ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl_ctx); - - if (!interface_decl) - return; - - do - { - Decl *original_decl = NULL; - ASTContext *original_ctx = NULL; - - m_ast_importer->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(); - - if (strstr(ss.GetData(), "$__lldb")) - return; // we don't need any results - - ConstString selector_name(ss.GetData()); - - if (log) - log->Printf("ClangASTSource::FindObjCMethodDecls[%d] on (ASTContext*)%p for selector [%s %s]", - current_id, static_cast<void*>(m_ast_context), - interface_decl->getNameAsString().c_str(), - selector_name.AsCString()); - SymbolContextList sc_list; - - const bool include_symbols = false; - const bool include_inlines = false; - const bool append = false; - - std::string interface_name = interface_decl->getNameAsString(); - - do - { - StreamString ms; - ms.Printf("-[%s %s]", interface_name.c_str(), selector_name.AsCString()); - ms.Flush(); - ConstString instance_method_name(ms.GetData()); - - m_target->GetImages().FindFunctions(instance_method_name, lldb::eFunctionNameTypeFull, include_symbols, include_inlines, append, sc_list); - - if (sc_list.GetSize()) - break; - - ms.Clear(); - ms.Printf("+[%s %s]", interface_name.c_str(), selector_name.AsCString()); - ms.Flush(); - ConstString class_method_name(ms.GetData()); - - m_target->GetImages().FindFunctions(class_method_name, lldb::eFunctionNameTypeFull, include_symbols, include_inlines, append, sc_list); - - if (sc_list.GetSize()) - break; - - // Fall back and check for methods in categories. If we find methods this way, we need to check that they're actually in - // categories on the desired class. - - SymbolContextList candidate_sc_list; - - m_target->GetImages().FindFunctions(selector_name, lldb::eFunctionNameTypeSelector, include_symbols, include_inlines, append, candidate_sc_list); - - for (uint32_t ci = 0, ce = candidate_sc_list.GetSize(); - ci != ce; - ++ci) - { - SymbolContext candidate_sc; - - if (!candidate_sc_list.GetContextAtIndex(ci, candidate_sc)) - continue; - - if (!candidate_sc.function) - continue; - - const char *candidate_name = candidate_sc.function->GetName().AsCString(); - - const char *cursor = candidate_name; - - if (*cursor != '+' && *cursor != '-') - continue; - - ++cursor; - - if (*cursor != '[') - continue; - - ++cursor; - - size_t interface_len = interface_name.length(); - - if (strncmp(cursor, interface_name.c_str(), interface_len)) - continue; - - cursor += interface_len; - - if (*cursor == ' ' || *cursor == '(') - sc_list.Append(candidate_sc); - } - } - while (0); - - if (sc_list.GetSize()) - { - // We found a good function symbol. Use that. - - for (uint32_t i = 0, e = sc_list.GetSize(); - i != e; - ++i) - { - SymbolContext sc; - - if (!sc_list.GetContextAtIndex(i, sc)) - continue; - - if (!sc.function) - continue; - - 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, static_cast<void*>(complete_interface_decl), - static_cast<void*>(&complete_iface_decl->getASTContext())); - - FindObjCMethodDeclsWithOrigin(current_id, - context, - complete_interface_decl, - m_ast_context, - m_ast_importer, - "in debug info"); - - return; - } - while (0); - - do - { - // Check the modules only if the debug information didn't have a complete interface. - - if (ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor()) - { - ConstString interface_name(interface_decl->getNameAsString().c_str()); - bool append = false; - uint32_t max_matches = 1; - std::vector <clang::NamedDecl *> decls; - - if (!modules_decl_vendor->FindDecls(interface_name, - append, - max_matches, - decls)) - break; - - ObjCInterfaceDecl *interface_decl_from_modules = dyn_cast<ObjCInterfaceDecl>(decls[0]); - - if (!interface_decl_from_modules) - break; - - if (FindObjCMethodDeclsWithOrigin(current_id, - context, - interface_decl_from_modules, - m_ast_context, - m_ast_importer, - "in modules")) - return; - } - } - while (0); - - do - { - // Check the runtime only if the debug information didn't have a complete interface and the modules don't get us anywhere. - - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - break; - - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); - - if (!language_runtime) - break; - - DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); - - if (!decl_vendor) - break; - - ConstString interface_name(interface_decl->getNameAsString().c_str()); - bool append = false; - uint32_t max_matches = 1; - std::vector <clang::NamedDecl *> decls; - - if (!decl_vendor->FindDecls(interface_name, - append, - max_matches, - decls)) - break; - - ObjCInterfaceDecl *runtime_interface_decl = dyn_cast<ObjCInterfaceDecl>(decls[0]); - - if (!runtime_interface_decl) - break; - - FindObjCMethodDeclsWithOrigin(current_id, - context, - runtime_interface_decl, - m_ast_context, - m_ast_importer, - "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, static_cast<void*>(m_ast_context), - parser_iface_decl->getNameAsString().c_str(), - context.m_decl_name.getAsString().c_str()); - - if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, - context, - *m_ast_context, - m_ast_importer, - origin_iface_decl)) - return; - - if (log) - log->Printf("CAS::FOPD[%d] couldn't find the property on origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p, searching elsewhere...", - current_id, static_cast<const void*>(origin_iface_decl.decl), - static_cast<void*>(&origin_iface_decl->getASTContext())); - - SymbolContext null_sc; - TypeList type_list; - - do - { - ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(parser_iface_decl.decl)); - - if (!complete_interface_decl) - break; - - // We found the complete interface. The runtime never needs to be queried in this scenario. - - DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl); - - if (complete_iface_decl.decl == origin_iface_decl.decl) - break; // already checked this one - - if (log) - log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, - static_cast<const void*>(complete_iface_decl.decl), - static_cast<void*>(&complete_iface_decl->getASTContext())); - - FindObjCPropertyAndIvarDeclsWithOrigin(current_id, - context, - *m_ast_context, - m_ast_importer, - complete_iface_decl); - - return; - } - while(0); - - do - { - // Check the modules only if the debug information didn't have a complete interface. - - ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor(); - - if (!modules_decl_vendor) - break; - - bool append = false; - uint32_t max_matches = 1; - std::vector <clang::NamedDecl *> decls; - - if (!modules_decl_vendor->FindDecls(class_name, - append, - max_matches, - decls)) - break; - - DeclFromUser<const ObjCInterfaceDecl> interface_decl_from_modules(dyn_cast<ObjCInterfaceDecl>(decls[0])); - - if (!interface_decl_from_modules.IsValid()) - break; - - if (log) - log->Printf("CAS::FOPD[%d] trying module (ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, - static_cast<const void*>(interface_decl_from_modules.decl), - static_cast<void*>(&interface_decl_from_modules->getASTContext())); - - if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, - context, - *m_ast_context, - m_ast_importer, - interface_decl_from_modules)) - return; - } - while(0); - - do - { - // Check the runtime only if the debug information didn't have a complete interface - // and nothing was in the modules. - - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - return; - - ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime()); - - if (!language_runtime) - return; - - DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); - - if (!decl_vendor) - break; - - bool append = false; - uint32_t max_matches = 1; - std::vector <clang::NamedDecl *> decls; - - if (!decl_vendor->FindDecls(class_name, - append, - max_matches, - decls)) - break; - - DeclFromUser<const ObjCInterfaceDecl> interface_decl_from_runtime(dyn_cast<ObjCInterfaceDecl>(decls[0])); - - if (!interface_decl_from_runtime.IsValid()) - break; - - if (log) - log->Printf("CAS::FOPD[%d] trying runtime (ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, - static_cast<const void*>(interface_decl_from_runtime.decl), - static_cast<void*>(&interface_decl_from_runtime->getASTContext())); - - if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, - context, - *m_ast_context, - m_ast_importer, - interface_decl_from_runtime)) - return; - } - while(0); -} - -typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap; -typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetMap; - -template <class D, class O> -static bool -ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, llvm::DenseMap<const D *, O> &source_map, - ClangASTImporter *importer, ASTContext &dest_ctx) -{ - // When importing fields into a new record, clang has a hard requirement that - // fields be imported in field offset order. Since they are stored in a DenseMap - // with a pointer as the key type, this means we cannot simply iterate over the - // map, as the order will be non-deterministic. Instead we have to sort by the offset - // and then insert in sorted order. - typedef llvm::DenseMap<const D *, O> MapType; - typedef typename MapType::value_type PairType; - std::vector<PairType> sorted_items; - sorted_items.reserve(source_map.size()); - sorted_items.assign(source_map.begin(), source_map.end()); - std::sort(sorted_items.begin(), sorted_items.end(), - [](const PairType &lhs, const PairType &rhs) - { - return lhs.second < rhs.second; - }); - - for (const auto &item : sorted_items) - { - DeclFromUser<D> user_decl(const_cast<D *>(item.first)); - DeclFromParser <D> parser_decl(user_decl.Import(importer, dest_ctx)); - if (parser_decl.IsInvalid()) - return false; - destination_map.insert(std::pair<const D *, O>(parser_decl.decl, item.second)); - } - - return true; -} - -template <bool IsVirtual> -bool -ExtractBaseOffsets(const ASTRecordLayout &record_layout, DeclFromUser<const CXXRecordDecl> &record, - BaseOffsetMap &base_offsets) -{ - for (CXXRecordDecl::base_class_const_iterator bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()), - be = (IsVirtual ? record->vbases_end() : record->bases_end()); - bi != be; ++bi) - { - if (!IsVirtual && bi->isVirtual()) - continue; - - const clang::Type *origin_base_type = bi->getType().getTypePtr(); - const clang::RecordType *origin_base_record_type = origin_base_type->getAs<RecordType>(); - - if (!origin_base_record_type) - return false; - - DeclFromUser <RecordDecl> origin_base_record(origin_base_record_type->getDecl()); - - if (origin_base_record.IsInvalid()) - return false; - - DeclFromUser <CXXRecordDecl> origin_base_cxx_record(DynCast<CXXRecordDecl>(origin_base_record)); - - if (origin_base_cxx_record.IsInvalid()) - return false; - - CharUnits base_offset; - - if (IsVirtual) - base_offset = record_layout.getVBaseClassOffset(origin_base_cxx_record.decl); - else - base_offset = record_layout.getBaseClassOffset(origin_base_cxx_record.decl); - - base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>(origin_base_cxx_record.decl, base_offset)); - } - - return true; -} - -bool -ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, uint64_t &alignment, - FieldOffsetMap &field_offsets, BaseOffsetMap &base_offsets, - BaseOffsetMap &virtual_base_offsets) -{ - ClangASTMetrics::RegisterRecordLayout(); - - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - log->Printf("LayoutRecordType[%u] on (ASTContext*)%p for (RecordDecl*)%p [name = '%s']", - current_id, static_cast<void*>(m_ast_context), - static_cast<const void*>(record), - record->getNameAsString().c_str()); - - DeclFromParser <const RecordDecl> parser_record(record); - DeclFromUser <const RecordDecl> origin_record(parser_record.GetOrigin(m_ast_importer)); - - 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, - static_cast<const void*>(origin_record.decl)); - log->Printf("LRT[%u] Size = %" PRId64, current_id, size); - log->Printf("LRT[%u] Alignment = %" PRId64, current_id, alignment); - log->Printf("LRT[%u] Fields:", current_id); - for (RecordDecl::field_iterator fi = record->field_begin(), fe = record->field_end(); - fi != fe; - ++fi) - { - log->Printf("LRT[%u] (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 " bits", current_id, - static_cast<void *>(*fi), fi->getNameAsString().c_str(), field_offsets[*fi]); - } - DeclFromParser <const CXXRecordDecl> parser_cxx_record = DynCast<const CXXRecordDecl>(parser_record); - if (parser_cxx_record.IsValid()) - { - log->Printf("LRT[%u] Bases:", current_id); - for (CXXRecordDecl::base_class_const_iterator bi = parser_cxx_record->bases_begin(), be = parser_cxx_record->bases_end(); - bi != be; - ++bi) - { - bool is_virtual = bi->isVirtual(); - - QualType base_type = bi->getType(); - const RecordType *base_record_type = base_type->getAs<RecordType>(); - DeclFromParser <RecordDecl> base_record(base_record_type->getDecl()); - DeclFromParser <CXXRecordDecl> base_cxx_record = DynCast<CXXRecordDecl>(base_record); - - log->Printf("LRT[%u] %s(CXXRecordDecl*)%p, Name = '%s', Offset = %" PRId64 " chars", current_id, - (is_virtual ? "Virtual " : ""), static_cast<void *>(base_cxx_record.decl), - base_cxx_record.decl->getNameAsString().c_str(), - (is_virtual ? virtual_base_offsets[base_cxx_record.decl].getQuantity() - : base_offsets[base_cxx_record.decl].getQuantity())); - } - } - else - { - log->Printf("LRD[%u] Not a CXXRecord, so no bases", current_id); - } - } - - return true; -} - -void -ClangASTSource::CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespace_map, - const ConstString &name, - ClangASTImporter::NamespaceMapSP &parent_map) const -{ - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - { - if (parent_map && parent_map->size()) - log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s in namespace %s", - current_id, static_cast<void*>(m_ast_context), - name.GetCString(), - parent_map->begin()->second.GetNamespaceDecl()->getDeclName().getAsString().c_str()); - else - log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s", - current_id, static_cast<void*>(m_ast_context), - name.GetCString()); - } - - if (parent_map) - { - for (ClangASTImporter::NamespaceMap::iterator i = parent_map->begin(), e = parent_map->end(); - i != e; - ++i) - { - 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, bool extern_c) -{ - 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::DeclContext *context = const_cast<DeclContext*>(m_decl_context); - - if (extern_c) { - context = LinkageSpecDecl::Create(*ast, - context, - SourceLocation(), - SourceLocation(), - clang::LinkageSpecDecl::LanguageIDs::lang_c, - false); - } - - clang::FunctionDecl *func_decl = FunctionDecl::Create (*ast, - context, - SourceLocation(), - SourceLocation(), - m_decl_name.getAsIdentifierInfo(), - qual_type, - NULL, - SC_Extern, - isInlineSpecified, - hasWrittenPrototype, - isConstexprSpecified); - - // We have to do more than just synthesize the FunctionDecl. We have to - // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do - // this, we raid the function's FunctionProtoType for types. - - const FunctionProtoType *func_proto_type = qual_type.getTypePtr()->getAs<FunctionProtoType>(); - - if (func_proto_type) - { - unsigned NumArgs = func_proto_type->getNumParams(); - unsigned ArgIndex; - - SmallVector<ParmVarDecl *, 5> parm_var_decls; - - for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) - { - QualType arg_qual_type (func_proto_type->getParamType(ArgIndex)); - - parm_var_decls.push_back(ParmVarDecl::Create (*ast, - const_cast<DeclContext*>(context), - SourceLocation(), - SourceLocation(), - NULL, - arg_qual_type, - NULL, - SC_Static, - NULL)); - } - - func_decl->setParams(ArrayRef<ParmVarDecl*>(parm_var_decls)); - } - else - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - log->Printf("Function type wasn't a FunctionProtoType"); - } - - m_decls.push_back(func_decl); - - return func_decl; -} - -clang::NamedDecl * -NameSearchContext::AddGenericFunDecl() -{ - FunctionProtoType::ExtProtoInfo proto_info; - - proto_info.Variadic = true; - - QualType generic_function_type(m_ast_source.m_ast_context->getFunctionType (m_ast_source.m_ast_context->UnknownAnyTy, // result - ArrayRef<QualType>(), // argument types - proto_info)); - - return AddFunDecl(ClangASTType (m_ast_source.m_ast_context, generic_function_type), true); -} - -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::DeclContextLookupResult result) -{ - for (clang::NamedDecl *decl : result) - m_decls.push_back (decl); -} - -void -NameSearchContext::AddNamedDecl (clang::NamedDecl *decl) -{ - m_decls.push_back (decl); -} diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp deleted file mode 100644 index 2c66a0a..0000000 --- a/source/Expression/ClangExpressionDeclMap.cpp +++ /dev/null @@ -1,2171 +0,0 @@ -//===-- 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" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclarationName.h" -#include "clang/AST/Decl.h" -#include "lldb/lldb-private.h" -#include "lldb/Core/Address.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Log.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/RegisterValue.h" -#include "lldb/Core/ValueObjectConstResult.h" -#include "lldb/Core/ValueObjectVariable.h" -#include "lldb/Expression/ASTDumper.h" -#include "lldb/Expression/ClangASTSource.h" -#include "lldb/Expression/ClangModulesDeclVendor.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/CPPLanguageRuntime.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/ObjCLanguageRuntime.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/StackFrame.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" - -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::InstallCodeGenerator (clang::ASTConsumer *code_gen) -{ - assert(m_parser_vars); - m_parser_vars->m_code_gen = code_gen; -} - -void -ClangExpressionDeclMap::DidParse() -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - ClangASTMetrics::DumpCounters(log); - - if (m_parser_vars.get()) - { - for (size_t entity_index = 0, num_entities = m_found_entities.GetSize(); - entity_index < num_entities; - ++entity_index) - { - 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, - lldb::offset_t alignment -) -{ - assert (m_struct_vars.get()); - assert (m_parser_vars.get()); - - bool is_persistent_variable = false; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - m_struct_vars->m_struct_laid_out = false; - - if (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", - static_cast<const void*>(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, - lldb::offset_t &alignment -) -{ - assert (m_struct_vars.get()); - - if (!m_struct_vars->m_struct_laid_out) - return false; - - num_elements = m_struct_members.GetSize(); - size = m_struct_vars->m_struct_size; - alignment = m_struct_vars->m_struct_alignment; - - return true; -} - -bool -ClangExpressionDeclMap::GetStructElement -( - const NamedDecl *&decl, - llvm::Value *&value, - lldb::offset_t &offset, - ConstString &name, - uint32_t index -) -{ - assert (m_struct_vars.get()); - - if (!m_struct_vars->m_struct_laid_out) - return false; - - if (index >= m_struct_members.GetSize()) - return false; - - 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 -) -{ - sc_list.Clear(); - SymbolContextList temp_sc_list; - if (sym_ctx.module_sp) - sym_ctx.module_sp->FindFunctions(name, - NULL, - eFunctionNameTypeAuto, - true, // include_symbols - false, // include_inlines - true, // append - temp_sc_list); - if (temp_sc_list.GetSize() == 0) - { - if (sym_ctx.target_sp) - sym_ctx.target_sp->GetImages().FindFunctions(name, - eFunctionNameTypeAuto, - true, // include_symbols - false, // include_inlines - true, // append - temp_sc_list); - } - - SymbolContextList internal_symbol_sc_list; - unsigned temp_sc_list_size = temp_sc_list.GetSize(); - for (unsigned i = 0; i < temp_sc_list_size; i++) - { - SymbolContext sc; - temp_sc_list.GetContextAtIndex(i, sc); - if (sc.function) - { - sc_list.Append(sc); - } - else if (sc.symbol) - { - if (sc.symbol->IsExternal()) - { - sc_list.Append(sc); - } - else - { - internal_symbol_sc_list.Append(sc); - } - } - } - - // If we had internal symbols and we didn't find any external symbols or - // functions in debug info, then fallback to the internal symbols - if (sc_list.GetSize() == 0 && internal_symbol_sc_list.GetSize()) - { - sc_list = internal_symbol_sc_list; - } -} - -bool -ClangExpressionDeclMap::GetFunctionAddress -( - const ConstString &name, - uint64_t &func_addr -) -{ - assert (m_parser_vars.get()); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; - Target *target = exe_ctx.GetTargetPtr(); - // Back out in all cases where we're not fully initialized - if (target == NULL) - return false; - if (!m_parser_vars->m_sym_ctx.target_sp) - return false; - - SymbolContextList sc_list; - - FindCodeSymbolInContext(name, m_parser_vars->m_sym_ctx, sc_list); - - uint32_t sc_list_size = sc_list.GetSize(); - - if (sc_list_size == 0) - { - // We occasionally get debug information in which a const function is reported - // as non-const, so the mangled name is wrong. This is a hack to compensate. - - if (!strncmp(name.GetCString(), "_ZN", 3) && - strncmp(name.GetCString(), "_ZNK", 4)) - { - std::string fixed_scratch("_ZNK"); - fixed_scratch.append(name.GetCString() + 3); - ConstString fixed_name(fixed_scratch.c_str()); - - if (log) - log->Printf("Failed to find symbols given non-const name %s; trying %s", name.GetCString(), fixed_name.GetCString()); - - FindCodeSymbolInContext(fixed_name, m_parser_vars->m_sym_ctx, sc_list); - sc_list_size = sc_list.GetSize(); - } - } - - lldb::addr_t intern_callable_load_addr = LLDB_INVALID_ADDRESS; - - for (uint32_t i=0; i<sc_list_size; ++i) - { - SymbolContext sym_ctx; - sc_list.GetContextAtIndex(i, sym_ctx); - - - lldb::addr_t callable_load_addr = LLDB_INVALID_ADDRESS; - - if (sym_ctx.function) - { - const Address func_so_addr = sym_ctx.function->GetAddressRange().GetBaseAddress(); - if (func_so_addr.IsValid()) - { - callable_load_addr = func_so_addr.GetCallableLoadAddress(target, false); - } - } - else if (sym_ctx.symbol) - { - if (sym_ctx.symbol->IsExternal()) - callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target); - else - { - if (intern_callable_load_addr == LLDB_INVALID_ADDRESS) - intern_callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target); - } - } - - if (callable_load_addr != LLDB_INVALID_ADDRESS) - { - func_addr = callable_load_addr; - return true; - } - } - - // See if we found an internal symbol - if (intern_callable_load_addr != LLDB_INVALID_ADDRESS) - { - func_addr = intern_callable_load_addr; - return true; - } - - return false; -} - -addr_t -ClangExpressionDeclMap::GetSymbolAddress (Target &target, - Process *process, - const ConstString &name, - lldb::SymbolType symbol_type, - lldb_private::Module *module) -{ - SymbolContextList sc_list; - - if (module) - module->FindSymbolsWithNameAndType(name, symbol_type, sc_list); - else - target.GetImages().FindSymbolsWithNameAndType(name, symbol_type, sc_list); - - const uint32_t num_matches = sc_list.GetSize(); - addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; - - for (uint32_t i=0; i<num_matches && (symbol_load_addr == 0 || symbol_load_addr == LLDB_INVALID_ADDRESS); i++) - { - SymbolContext sym_ctx; - sc_list.GetContextAtIndex(i, sym_ctx); - - const Address sym_address = sym_ctx.symbol->GetAddress(); - - if (!sym_address.IsValid()) - continue; - - switch (sym_ctx.symbol->GetType()) - { - case eSymbolTypeCode: - case eSymbolTypeTrampoline: - symbol_load_addr = sym_address.GetCallableLoadAddress (&target); - break; - - case eSymbolTypeResolver: - symbol_load_addr = sym_address.GetCallableLoadAddress (&target, true); - break; - - case eSymbolTypeReExported: - { - ConstString reexport_name = sym_ctx.symbol->GetReExportedSymbolName(); - if (reexport_name) - { - ModuleSP reexport_module_sp; - ModuleSpec reexport_module_spec; - reexport_module_spec.GetPlatformFileSpec() = sym_ctx.symbol->GetReExportedSymbolSharedLibrary(); - if (reexport_module_spec.GetPlatformFileSpec()) - { - reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec); - if (!reexport_module_sp) - { - reexport_module_spec.GetPlatformFileSpec().GetDirectory().Clear(); - reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec); - } - } - symbol_load_addr = GetSymbolAddress(target, process, sym_ctx.symbol->GetReExportedSymbolName(), symbol_type, reexport_module_sp.get()); - } - } - break; - - case eSymbolTypeData: - case eSymbolTypeRuntime: - case eSymbolTypeVariable: - case eSymbolTypeLocal: - case eSymbolTypeParam: - case eSymbolTypeInvalid: - case eSymbolTypeAbsolute: - case eSymbolTypeException: - case eSymbolTypeSourceFile: - case eSymbolTypeHeaderFile: - case eSymbolTypeObjectFile: - case eSymbolTypeCommonBlock: - case eSymbolTypeBlock: - case eSymbolTypeVariableType: - case eSymbolTypeLineEntry: - case eSymbolTypeLineHeader: - case eSymbolTypeScopeBegin: - case eSymbolTypeScopeEnd: - case eSymbolTypeAdditional: - case eSymbolTypeCompiler: - case eSymbolTypeInstrumentation: - case eSymbolTypeUndefined: - case eSymbolTypeObjCClass: - case eSymbolTypeObjCMetaClass: - case eSymbolTypeObjCIVar: - symbol_load_addr = sym_address.GetLoadAddress (&target); - break; - } - } - - if (symbol_load_addr == LLDB_INVALID_ADDRESS && process) - { - ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime(); - - if (runtime) - { - symbol_load_addr = runtime->LookupRuntimeSymbol(name); - } - } - - return symbol_load_addr; -} - -addr_t -ClangExpressionDeclMap::GetSymbolAddress (const ConstString &name, lldb::SymbolType symbol_type) -{ - assert (m_parser_vars.get()); - - if (!m_parser_vars->m_exe_ctx.GetTargetPtr()) - return false; - - return GetSymbolAddress(m_parser_vars->m_exe_ctx.GetTargetRef(), m_parser_vars->m_exe_ctx.GetProcessPtr(), name, symbol_type); -} - -const Symbol * -ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target, - const ConstString &name, - lldb_private::Module *module) -{ - SymbolContextList sc_list; - - if (module) - module->FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list); - else - target.GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list); - - const uint32_t matches = sc_list.GetSize(); - for (uint32_t i=0; i<matches; ++i) - { - SymbolContext sym_ctx; - sc_list.GetContextAtIndex(i, sym_ctx); - if (sym_ctx.symbol) - { - const Symbol *symbol = sym_ctx.symbol; - const Address sym_address = symbol->GetAddress(); - - if (sym_address.IsValid()) - { - switch (symbol->GetType()) - { - case eSymbolTypeData: - case eSymbolTypeRuntime: - case eSymbolTypeAbsolute: - case eSymbolTypeObjCClass: - case eSymbolTypeObjCMetaClass: - case eSymbolTypeObjCIVar: - if (symbol->GetDemangledNameIsSynthesized()) - { - // If the demangled name was synthesized, then don't use it - // for expressions. Only let the symbol match if the mangled - // named matches for these symbols. - if (symbol->GetMangled().GetMangledName() != name) - break; - } - return symbol; - - case eSymbolTypeReExported: - { - ConstString reexport_name = symbol->GetReExportedSymbolName(); - if (reexport_name) - { - ModuleSP reexport_module_sp; - ModuleSpec reexport_module_spec; - reexport_module_spec.GetPlatformFileSpec() = symbol->GetReExportedSymbolSharedLibrary(); - if (reexport_module_spec.GetPlatformFileSpec()) - { - reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec); - if (!reexport_module_sp) - { - reexport_module_spec.GetPlatformFileSpec().GetDirectory().Clear(); - reexport_module_sp = target.GetImages().FindFirstModule(reexport_module_spec); - } - } - // Don't allow us to try and resolve a re-exported symbol if it is the same - // as the current symbol - if (name == symbol->GetReExportedSymbolName() && module == reexport_module_sp.get()) - return NULL; - - return FindGlobalDataSymbol(target, symbol->GetReExportedSymbolName(), reexport_module_sp.get()); - } - } - break; - - case eSymbolTypeCode: // We already lookup functions elsewhere - case eSymbolTypeVariable: - case eSymbolTypeLocal: - case eSymbolTypeParam: - case eSymbolTypeTrampoline: - case eSymbolTypeInvalid: - case eSymbolTypeException: - case eSymbolTypeSourceFile: - case eSymbolTypeHeaderFile: - case eSymbolTypeObjectFile: - case eSymbolTypeCommonBlock: - case eSymbolTypeBlock: - case eSymbolTypeVariableType: - case eSymbolTypeLineEntry: - case eSymbolTypeLineHeader: - case eSymbolTypeScopeBegin: - case eSymbolTypeScopeEnd: - case eSymbolTypeAdditional: - case eSymbolTypeCompiler: - case eSymbolTypeInstrumentation: - case eSymbolTypeUndefined: - case eSymbolTypeResolver: - break; - } - } - } - } - - return NULL; -} - -lldb::VariableSP -ClangExpressionDeclMap::FindGlobalVariable -( - Target &target, - ModuleSP &module, - const ConstString &name, - 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, static_cast<void*>(namespace_map.get()), - (int)namespace_map->size()); - - if (!namespace_map) - return; - - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end(); - i != e; - ++i) - { - if (log) - log->Printf(" CEDM::FEVD[%u] Searching namespace %s in module %s", - current_id, - i->second.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 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 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::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; - } - } - - std::vector<clang::NamedDecl *> decls_from_modules; - - if (target) - { - if (ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor()) - { - decl_vendor->FindDecls(name, false, UINT32_MAX, decls_from_modules); - } - } - - if (!context.m_found.variable) - { - const bool include_inlines = false; - const bool append = false; - - if (namespace_decl && module_sp) - { - const bool include_symbols = false; - - module_sp->FindFunctions(name, - &namespace_decl, - eFunctionNameTypeBase, - include_symbols, - include_inlines, - append, - sc_list); - } - else if (target && !namespace_decl) - { - const bool include_symbols = true; - - // TODO Fix FindFunctions so that it doesn't return - // instance methods for eFunctionNameTypeBase. - - target->GetImages().FindFunctions(name, - eFunctionNameTypeFull, - include_symbols, - include_inlines, - append, - sc_list); - } - - if (sc_list.GetSize()) - { - Symbol *extern_symbol = NULL; - Symbol *non_extern_symbol = NULL; - - for (uint32_t index = 0, num_indices = sc_list.GetSize(); - index < num_indices; - ++index) - { - SymbolContext sym_ctx; - sc_list.GetContextAtIndex(index, sym_ctx); - - if (sym_ctx.function) - { - 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->GetType() == eSymbolTypeReExported && target) - { - sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target); - if (sym_ctx.symbol == NULL) - continue; - } - - if (sym_ctx.symbol->IsExternal()) - extern_symbol = sym_ctx.symbol; - else - non_extern_symbol = sym_ctx.symbol; - } - } - - if (!context.m_found.function_with_type_info) - { - for (clang::NamedDecl *decl : decls_from_modules) - { - if (llvm::isa<clang::FunctionDecl>(decl)) - { - clang::NamedDecl *copied_decl = llvm::cast<FunctionDecl>(m_ast_importer->CopyDecl(m_ast_context, &decl->getASTContext(), decl)); - context.AddNamedDecl(copied_decl); - context.m_found.function_with_type_info = true; - } - } - } - - if (!context.m_found.function_with_type_info) - { - if (extern_symbol) - { - AddOneFunction (context, NULL, extern_symbol, current_id); - context.m_found.function = true; - } - else if (non_extern_symbol) - { - AddOneFunction (context, NULL, non_extern_symbol, current_id); - context.m_found.function = true; - } - } - } - - if (!context.m_found.function_with_type_info) - { - // Try the modules next. - - do - { - if (ClangModulesDeclVendor *modules_decl_vendor = m_target->GetClangModulesDeclVendor()) - { - bool append = false; - uint32_t max_matches = 1; - std::vector <clang::NamedDecl *> decls; - - if (!modules_decl_vendor->FindDecls(name, - append, - max_matches, - decls)) - break; - - clang::NamedDecl *const decl_from_modules = decls[0]; - - if (llvm::isa<clang::FunctionDecl>(decl_from_modules)) - { - if (log) - { - log->Printf(" CAS::FEVD[%u] Matching function found for \"%s\" in the modules", - current_id, - name.GetCString()); - } - - clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules); - clang::FunctionDecl *copied_function_decl = copied_decl ? dyn_cast<clang::FunctionDecl>(copied_decl) : nullptr; - - if (!copied_function_decl) - { - if (log) - log->Printf(" CAS::FEVD[%u] - Couldn't export a function declaration from the modules", - current_id); - - break; - } - - if (copied_function_decl->getBody() && m_parser_vars->m_code_gen) - { - DeclGroupRef decl_group_ref(copied_function_decl); - m_parser_vars->m_code_gen->HandleTopLevelDecl(decl_group_ref); - } - - context.AddNamedDecl(copied_function_decl); - - context.m_found.function_with_type_info = true; - context.m_found.function = true; - } - else if (llvm::isa<clang::VarDecl>(decl_from_modules)) - { - if (log) - { - log->Printf(" CAS::FEVD[%u] Matching variable found for \"%s\" in the modules", - current_id, - name.GetCString()); - } - - clang::Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &decl_from_modules->getASTContext(), decl_from_modules); - clang::VarDecl *copied_var_decl = copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl) : nullptr; - - if (!copied_var_decl) - { - if (log) - log->Printf(" CAS::FEVD[%u] - Couldn't export a variable declaration from the modules", - current_id); - - break; - } - - context.AddNamedDecl(copied_var_decl); - - context.m_found.variable = true; - } - } - } while (0); - } - - if (target && !context.m_found.variable && !namespace_decl) - { - // We couldn't find a non-symbol variable for this. Now we'll hunt for a generic - // data symbol, and -- if it is found -- treat it as a variable. - - const Symbol *data_symbol = FindGlobalDataSymbol(*target, name); - - if (data_symbol) - { - std::string warning("got name from symbols: "); - warning.append(name.AsCString()); - const unsigned diag_id = m_ast_context->getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Level::Warning, "%0"); - m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str(); - AddOneGenericVariable(context, *data_symbol, current_id); - context.m_found.variable = true; - } - } - } - } -} - -//static 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; - } - - 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(); - - Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); - Error err; - - if (var->GetLocationIsConstantValueData()) - { - DataExtractor const_value_extractor; - - if (var_location_expr.GetExpressionData(const_value_extractor)) - { - var_location = Value(const_value_extractor.GetDataStart(), const_value_extractor.GetByteSize()); - var_location.SetValueType(Value::eValueTypeHostAddress); - } - else - { - if (log) - log->Printf("Error evaluating constant variable: %s", err.AsCString()); - return false; - } - } - - 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()); - if (const ObjCObjectPointerType *objc_object_ptr_type = dyn_cast<ObjCObjectPointerType>(parser_type)) - CompleteType(objc_object_ptr_type->getInterfaceDecl()); - } - - - bool is_reference = pt.IsReferenceType(); - - NamedDecl *var_decl = NULL; - if (is_reference) - var_decl = context.AddVarDecl(pt); - else - var_decl = context.AddVarDecl(pt.GetLValueReferenceType()); - - std::string decl_name(context.m_decl_name.getAsString()); - ConstString entity_name(decl_name.c_str()); - 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; - Address fun_address; - 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/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp deleted file mode 100644 index 2b344b0..0000000 --- a/source/Expression/ClangExpressionParser.cpp +++ /dev/null @@ -1,621 +0,0 @@ -//===-- 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/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/Log.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/Stream.h" -#include "lldb/Core/StreamFile.h" -#include "lldb/Core/StreamString.h" -#include "lldb/Expression/ClangASTSource.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangExpressionDeclMap.h" -#include "lldb/Expression/ClangModulesDeclVendor.h" -#include "lldb/Expression/ClangPersistentVariables.h" -#include "lldb/Expression/IRExecutionUnit.h" -#include "lldb/Expression/IRDynamicChecks.h" -#include "lldb/Expression/IRInterpreter.h" -#include "lldb/Host/File.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/SymbolVendor.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/Frontend/CompilerInstance.h" -#include "clang/Frontend/CompilerInvocation.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/FrontendPluginRegistry.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/ParseAST.h" -#include "clang/Rewrite/Frontend/FrontendActions.h" -#include "clang/Sema/SemaConsumer.h" -#include "clang/StaticAnalyzer/Frontend/FrontendActions.h" - -#include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/TargetSelect.h" - -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/Signals.h" - -using namespace clang; -using namespace llvm; -using namespace lldb_private; - -//===----------------------------------------------------------------------===// -// Utility Methods for Clang -//===----------------------------------------------------------------------===// - -std::string GetBuiltinIncludePath(const char *Argv0) { - SmallString<128> P(llvm::sys::fs::getMainExecutable( - Argv0, (void *)(intptr_t) GetBuiltinIncludePath)); - - if (!P.empty()) { - llvm::sys::path::remove_filename(P); // Remove /clang from foo/bin/clang - llvm::sys::path::remove_filename(P); // Remove /bin from foo/bin - - // Get foo/lib/clang/<version>/include - llvm::sys::path::append(P, "lib", "clang", CLANG_VERSION_STRING, - "include"); - } - - return P.str(); -} - -class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks -{ - ClangModulesDeclVendor &m_decl_vendor; - ClangPersistentVariables &m_persistent_vars; - StreamString m_error_stream; - bool m_has_errors = false; -public: - LLDBPreprocessorCallbacks(ClangModulesDeclVendor &decl_vendor, - ClangPersistentVariables &persistent_vars) : - m_decl_vendor(decl_vendor), - m_persistent_vars(persistent_vars) - { - } - - virtual void moduleImport(SourceLocation import_location, - ModuleIdPath path, - const clang::Module * /*null*/) - { - std::vector<ConstString> string_path; - - for (const std::pair<IdentifierInfo *, SourceLocation> &component : path) - { - string_path.push_back(ConstString(component.first->getName())); - } - - StreamString error_stream; - - ClangModulesDeclVendor::ModuleVector exported_modules; - - if (!m_decl_vendor.AddModule(string_path, &exported_modules, m_error_stream)) - { - m_has_errors = true; - } - - for (ClangModulesDeclVendor::ModuleID module : exported_modules) - { - m_persistent_vars.AddHandLoadedClangModule(module); - } - } - - bool hasErrors() - { - return m_has_errors; - } - - const std::string &getErrorString() - { - return m_error_stream.GetString(); - } -}; - -//===----------------------------------------------------------------------===// -// Implementation of ClangExpressionParser -//===----------------------------------------------------------------------===// - -ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, - ClangExpression &expr, - bool generate_debug_info) : - m_expr (expr), - m_compiler (), - m_code_generator (), - m_pp_callbacks(nullptr) -{ - // 1. Create a new compiler instance. - m_compiler.reset(new CompilerInstance()); - - // 2. Install the target. - - lldb::TargetSP target_sp; - if (exe_scope) - target_sp = exe_scope->CalculateTarget(); - - // TODO: figure out what to really do when we don't have a valid target. - // Sometimes this will be ok to just use the host target triple (when we - // evaluate say "2+3", but other expressions like breakpoint conditions - // and other things that _are_ target specific really shouldn't just be - // using the host triple. This needs to be fixed in a better way. - if (target_sp && target_sp->GetArchitecture().IsValid()) - { - std::string triple = target_sp->GetArchitecture().GetTriple().str(); - m_compiler->getTargetOpts().Triple = triple; - } - else - { - m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); - } - - if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 || - target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64) - { - m_compiler->getTargetOpts().Features.push_back("+sse"); - m_compiler->getTargetOpts().Features.push_back("+sse2"); - } - - // Any arm32 iOS environment, but not on arm64 - if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos && - m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos && - m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) - { - m_compiler->getTargetOpts().ABI = "apcs-gnu"; - } - - m_compiler->createDiagnostics(); - - // Create the target instance. - m_compiler->setTarget(TargetInfo::CreateTargetInfo( - m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts)); - - assert (m_compiler->hasTarget()); - - // 3. Set options. - - lldb::LanguageType language = expr.Language(); - - switch (language) - { - case lldb::eLanguageTypeC: - 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; - m_compiler->getHeaderSearchOpts().UseLibcxx = 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; - m_compiler->getHeaderSearchOpts().UseLibcxx = true; - break; - } - - m_compiler->getLangOpts().Bool = true; - m_compiler->getLangOpts().WChar = true; - m_compiler->getLangOpts().Blocks = true; - m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients - if (expr.DesiredResultType() == ClangExpression::eResultTypeId) - m_compiler->getLangOpts().DebuggerCastResultToId = true; - - m_compiler->getLangOpts().CharIsSigned = - ArchSpec(m_compiler->getTargetOpts().Triple.c_str()).CharIsSignedByDefault(); - - // Spell checking is a nice feature, but it ends up completing a - // lot of types that we didn't strictly speaking need to complete. - // As a result, we spend a long time parsing and importing debug - // information. - m_compiler->getLangOpts().SpellChecking = false; - - lldb::ProcessSP process_sp; - if (exe_scope) - process_sp = exe_scope->CalculateProcess(); - - if (process_sp && m_compiler->getLangOpts().ObjC1) - { - if (process_sp->GetObjCLanguageRuntime()) - { - if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == eAppleObjC_V2) - m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7)); - else - m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX, VersionTuple(10, 7)); - - if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing()) - m_compiler->getLangOpts().DebuggerObjCLiteral = true; - } - } - - m_compiler->getLangOpts().ThreadsafeStatics = false; - m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access - m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name - - // Set CodeGen options - m_compiler->getCodeGenOpts().EmitDeclMetadata = true; - m_compiler->getCodeGenOpts().InstrumentFunctions = false; - m_compiler->getCodeGenOpts().DisableFPElim = true; - m_compiler->getCodeGenOpts().OmitLeafFramePointer = false; - if (generate_debug_info) - m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::FullDebugInfo); - else - m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::NoDebugInfo); - - // Disable some warnings. - m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError, - "unused-value", clang::diag::Severity::Ignored, SourceLocation()); - m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError, - "odr", clang::diag::Severity::Ignored, SourceLocation()); - - // Inform the target of the language options - // - // FIXME: We shouldn't need to do this, the target should be immutable once - // created. This complexity should be lifted elsewhere. - m_compiler->getTarget().adjust(m_compiler->getLangOpts()); - - // 4. Set up the diagnostic buffer for reporting errors - - m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer); - - // 5. Set up the source management objects inside the compiler - - clang::FileSystemOptions file_system_options; - m_file_manager.reset(new clang::FileManager(file_system_options)); - - if (!m_compiler->hasSourceManager()) - m_compiler->createSourceManager(*m_file_manager.get()); - - m_compiler->createFileManager(); - m_compiler->createPreprocessor(TU_Complete); - - if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor()) - { - std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor, target_sp->GetPersistentVariables())); - m_pp_callbacks = static_cast<LLDBPreprocessorCallbacks*>(pp_callbacks.get()); - m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); - } - - // 6. Most of this we get from the CompilerInstance, but we - // also want to give the context an ExternalASTSource. - m_selector_table.reset(new SelectorTable()); - m_builtin_context.reset(new Builtin::Context()); - - std::unique_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(), - m_compiler->getSourceManager(), - m_compiler->getPreprocessor().getIdentifierTable(), - *m_selector_table.get(), - *m_builtin_context.get())); - - ast_context->InitBuiltinTypes(m_compiler->getTarget()); - - ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); - - if (decl_map) - { - llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy()); - decl_map->InstallASTContext(ast_context.get()); - ast_context->setExternalSource(ast_source); - } - - m_compiler->setASTContext(ast_context.release()); - - std::string module_name("$__lldb_module"); - - m_llvm_context.reset(new LLVMContext()); - m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(), - module_name, - m_compiler->getHeaderSearchOpts(), - m_compiler->getPreprocessorOpts(), - m_compiler->getCodeGenOpts(), - *m_llvm_context)); -} - -ClangExpressionParser::~ClangExpressionParser() -{ -} - -unsigned -ClangExpressionParser::Parse (Stream &stream) -{ - TextDiagnosticBuffer *diag_buf = static_cast<TextDiagnosticBuffer*>(m_compiler->getDiagnostics().getClient()); - - diag_buf->FlushDiagnostics (m_compiler->getDiagnostics()); - - const char *expr_text = m_expr.Text(); - - clang::SourceManager &SourceMgr = m_compiler->getSourceManager(); - bool created_main_file = false; - if (m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo) - { - std::string temp_source_path; - - int temp_fd = -1; - llvm::SmallString<PATH_MAX> result_path; - FileSpec tmpdir_file_spec; - if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) - { - tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr"); - temp_source_path = std::move(tmpdir_file_spec.GetPath()); - llvm::sys::fs::createUniqueFile(temp_source_path, temp_fd, result_path); - } - else - { - llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path); - } - - if (temp_fd != -1) - { - lldb_private::File file (temp_fd, true); - const size_t expr_text_len = strlen(expr_text); - size_t bytes_written = expr_text_len; - if (file.Write(expr_text, bytes_written).Success()) - { - if (bytes_written == expr_text_len) - { - file.Close(); - SourceMgr.setMainFileID(SourceMgr.createFileID( - m_file_manager->getFile(result_path), - SourceLocation(), SrcMgr::C_User)); - created_main_file = true; - } - } - } - } - - if (!created_main_file) - { - std::unique_ptr<MemoryBuffer> memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__); - SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(memory_buffer))); - } - - diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor()); - - ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get()); - - if (ClangExpressionDeclMap *decl_map = m_expr.DeclMap()) - decl_map->InstallCodeGenerator(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; - - if (m_pp_callbacks && m_pp_callbacks->hasErrors()) - { - num_errors++; - - stream.PutCString(m_pp_callbacks->getErrorString().c_str()); - } - - for (diag_iterator = diag_buf->warn_begin(); - diag_iterator != diag_buf->warn_end(); - ++diag_iterator) - stream.Printf("warning: %s\n", (*diag_iterator).second.c_str()); - - for (diag_iterator = diag_buf->err_begin(); - diag_iterator != diag_buf->err_end(); - ++diag_iterator) - { - num_errors++; - stream.Printf("error: %s\n", (*diag_iterator).second.c_str()); - } - - for (diag_iterator = diag_buf->note_begin(); - diag_iterator != diag_buf->note_end(); - ++diag_iterator) - stream.Printf("note: %s\n", (*diag_iterator).second.c_str()); - - if (!num_errors) - { - if (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::shared_ptr<IRExecutionUnit> &execution_unit_sp, - ExecutionContext &exe_ctx, - bool &can_interpret, - ExecutionPolicy execution_policy) -{ - func_addr = LLDB_INVALID_ADDRESS; - func_end = LLDB_INVALID_ADDRESS; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - Error err; - - std::unique_ptr<llvm::Module> llvm_module_ap (m_code_generator->ReleaseModule()); - - if (!llvm_module_ap.get()) - { - err.SetErrorToGenericError(); - err.SetErrorString("IR doesn't contain a module"); - return err; - } - - // Find the actual name of the function (it's often mangled somehow) - - ConstString function_name; - - if (!FindFunctionInModule(function_name, llvm_module_ap.get(), m_expr.FunctionName())) - { - err.SetErrorToGenericError(); - err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName()); - return err; - } - else - { - if (log) - log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName()); - } - - execution_unit_sp.reset(new IRExecutionUnit (m_llvm_context, // handed off here - llvm_module_ap, // handed off here - function_name, - exe_ctx.GetTargetSP(), - m_compiler->getTargetOpts().Features)); - - 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().GetErrorFile().get(); - - IRForTarget ir_for_target(decl_map, - m_expr.NeedsVariableResolution(), - *execution_unit_sp, - error_stream, - function_name.AsCString()); - - bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule()); - - Error interpret_error; - Process *process = exe_ctx.GetProcessPtr(); - - bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls(); - can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error, interpret_function_calls); - - - if (!ir_can_run) - { - err.SetErrorString("The expression could not be prepared to run in the target"); - return err; - } - - if (!can_interpret && execution_policy == eExecutionPolicyNever) - { - err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString()); - return err; - } - - if (!process && execution_policy == eExecutionPolicyAlways) - { - err.SetErrorString("Expression needed to run in the target, but the target can't be run"); - return err; - } - - if (execution_policy == eExecutionPolicyAlways || !can_interpret) - { - if (m_expr.NeedsValidation() && process) - { - if (!process->GetDynamicCheckers()) - { - DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); - - StreamString install_errors; - - if (!dynamic_checkers->Install(install_errors, exe_ctx)) - { - if (install_errors.GetString().empty()) - err.SetErrorString ("couldn't install checkers, unknown error"); - else - err.SetErrorString (install_errors.GetString().c_str()); - - return err; - } - - process->SetDynamicCheckers(dynamic_checkers); - - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Finished installing dynamic checkers =="); - } - - IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString()); - - if (!ir_dynamic_checks.runOnModule(*execution_unit_sp->GetModule())) - { - err.SetErrorToGenericError(); - err.SetErrorString("Couldn't add dynamic checks to the expression"); - return err; - } - } - - execution_unit_sp->GetRunnableInfo(err, func_addr, func_end); - } - } - else - { - execution_unit_sp->GetRunnableInfo(err, func_addr, func_end); - } - - return err; -} - -bool -ClangExpressionParser::GetGenerateDebugInfo () const -{ - if (m_compiler) - return m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo; - return false; -} diff --git a/source/Expression/ClangExpressionVariable.cpp b/source/Expression/ClangExpressionVariable.cpp deleted file mode 100644 index e86016e..0000000 --- a/source/Expression/ClangExpressionVariable.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//===-- 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" -#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 (ExecutionContextScope *exe_scope, - Value &value, - const ConstString &name, - uint16_t flags) : - m_parser_vars(), - m_jit_vars (), - m_flags (flags), - m_frozen_sp (ValueObjectConstResult::Create (exe_scope, value, name)) -{ -} - -ClangExpressionVariable::ClangExpressionVariable (const lldb::ValueObjectSP &valobj_sp) : - m_parser_vars(), - m_jit_vars (), - m_flags (EVNone), - m_frozen_sp (valobj_sp) -{ -} - -//---------------------------------------------------------------------- -/// 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/source/Expression/ClangModulesDeclVendor.cpp b/source/Expression/ClangModulesDeclVendor.cpp deleted file mode 100644 index e825363..0000000 --- a/source/Expression/ClangModulesDeclVendor.cpp +++ /dev/null @@ -1,731 +0,0 @@ -//===-- ClangModulesDeclVendor.cpp ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <mutex> // std::once - -#include "lldb/Expression/ClangModulesDeclVendor.h" - -#include "lldb/Core/Log.h" -#include "lldb/Core/StreamString.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/CompileUnit.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/LLDBAssert.h" - -#include "clang/Basic/TargetInfo.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/Parser.h" -#include "clang/Sema/Lookup.h" -#include "clang/Serialization/ASTReader.h" - - -using namespace lldb_private; - -namespace { - // Any Clang compiler requires a consumer for diagnostics. This one stores them as strings - // so we can provide them to the user in case a module failed to load. - class StoringDiagnosticConsumer : public clang::DiagnosticConsumer - { - public: - StoringDiagnosticConsumer (); - void - HandleDiagnostic (clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info); - - void - ClearDiagnostics (); - - void - DumpDiagnostics (Stream &error_stream); - private: - typedef std::pair<clang::DiagnosticsEngine::Level, std::string> IDAndDiagnostic; - std::vector<IDAndDiagnostic> m_diagnostics; - Log * m_log; - }; - - // The private implementation of our ClangModulesDeclVendor. Contains all the Clang state required - // to load modules. - class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor - { - public: - ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> &diagnostics_engine, - llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation, - std::unique_ptr<clang::CompilerInstance> &&compiler_instance, - std::unique_ptr<clang::Parser> &&parser); - - virtual bool - AddModule(ModulePath &path, - ModuleVector *exported_modules, - Stream &error_stream) override; - - virtual bool - AddModulesForCompileUnit(CompileUnit &cu, - ModuleVector &exported_modules, - Stream &error_stream) override; - - virtual uint32_t - FindDecls (const ConstString &name, - bool append, - uint32_t max_matches, - std::vector <clang::NamedDecl*> &decls) override; - - virtual void - ForEachMacro(const ModuleVector &modules, - std::function<bool (const std::string &)> handler) override; - - ~ClangModulesDeclVendorImpl(); - - private: - void - ReportModuleExportsHelper (std::set<ClangModulesDeclVendor::ModuleID> &exports, - clang::Module *module); - - void - ReportModuleExports (ModuleVector &exports, - clang::Module *module); - - clang::ModuleLoadResult - DoGetModule(clang::ModuleIdPath path, bool make_visible); - - bool m_enabled = false; - - llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> m_diagnostics_engine; - llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> m_compiler_invocation; - std::unique_ptr<clang::CompilerInstance> m_compiler_instance; - std::unique_ptr<clang::Parser> m_parser; - size_t m_source_location_index = 0; // used to give name components fake SourceLocations - - typedef std::vector<ConstString> ImportedModule; - typedef std::map<ImportedModule, clang::Module *> ImportedModuleMap; - typedef std::set<ModuleID> ImportedModuleSet; - ImportedModuleMap m_imported_modules; - ImportedModuleSet m_user_imported_modules; - }; -} - -StoringDiagnosticConsumer::StoringDiagnosticConsumer () -{ - m_log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); -} - -void -StoringDiagnosticConsumer::HandleDiagnostic (clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info) -{ - llvm::SmallVector<char, 256> diagnostic_string; - - info.FormatDiagnostic(diagnostic_string); - - m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, std::string(diagnostic_string.data(), diagnostic_string.size()))); -} - -void -StoringDiagnosticConsumer::ClearDiagnostics () -{ - m_diagnostics.clear(); -} - -void -StoringDiagnosticConsumer::DumpDiagnostics (Stream &error_stream) -{ - for (IDAndDiagnostic &diag : m_diagnostics) - { - switch (diag.first) - { - default: - error_stream.PutCString(diag.second.c_str()); - error_stream.PutChar('\n'); - break; - case clang::DiagnosticsEngine::Level::Ignored: - break; - } - } -} - -static FileSpec -GetResourceDir () -{ - static FileSpec g_cached_resource_dir; - - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, [](){ - HostInfo::GetLLDBPath (lldb::ePathTypeClangDir, g_cached_resource_dir); - }); - - return g_cached_resource_dir; -} - - -ClangModulesDeclVendor::ClangModulesDeclVendor() -{ -} - -ClangModulesDeclVendor::~ClangModulesDeclVendor() -{ -} - -ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> &diagnostics_engine, - llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> &compiler_invocation, - std::unique_ptr<clang::CompilerInstance> &&compiler_instance, - std::unique_ptr<clang::Parser> &&parser) : - ClangModulesDeclVendor(), - m_diagnostics_engine(diagnostics_engine), - m_compiler_invocation(compiler_invocation), - m_compiler_instance(std::move(compiler_instance)), - m_parser(std::move(parser)), - m_imported_modules() -{ -} - -void -ClangModulesDeclVendorImpl::ReportModuleExportsHelper (std::set<ClangModulesDeclVendor::ModuleID> &exports, - clang::Module *module) -{ - if (exports.count(reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module))) - return; - - exports.insert(reinterpret_cast<ClangModulesDeclVendor::ModuleID>(module)); - - llvm::SmallVector<clang::Module*, 2> sub_exports; - - module->getExportedModules(sub_exports); - - for (clang::Module *module : sub_exports) - { - ReportModuleExportsHelper(exports, module); - } -} - -void -ClangModulesDeclVendorImpl::ReportModuleExports (ClangModulesDeclVendor::ModuleVector &exports, - clang::Module *module) -{ - std::set<ClangModulesDeclVendor::ModuleID> exports_set; - - ReportModuleExportsHelper(exports_set, module); - - for (ModuleID module : exports_set) - { - exports.push_back(module); - } -} - -bool -ClangModulesDeclVendorImpl::AddModule(ModulePath &path, - ModuleVector *exported_modules, - Stream &error_stream) -{ - // Fail early. - - if (m_compiler_instance->hadModuleLoaderFatalFailure()) - { - error_stream.PutCString("error: Couldn't load a module because the module loader is in a fatal state.\n"); - return false; - } - - // Check if we've already imported this module. - - std::vector<ConstString> imported_module; - - for (ConstString path_component : path) - { - imported_module.push_back(path_component); - } - - { - ImportedModuleMap::iterator mi = m_imported_modules.find(imported_module); - - if (mi != m_imported_modules.end()) - { - if (exported_modules) - { - ReportModuleExports(*exported_modules, mi->second); - } - return true; - } - } - - if (!m_compiler_instance->getPreprocessor().getHeaderSearchInfo().lookupModule(path[0].GetStringRef())) - { - error_stream.Printf("error: Header search couldn't locate module %s\n", path[0].AsCString()); - return false; - } - - llvm::SmallVector<std::pair<clang::IdentifierInfo *, clang::SourceLocation>, 4> clang_path; - - { - clang::SourceManager &source_manager = m_compiler_instance->getASTContext().getSourceManager(); - - for (ConstString path_component : path) - { - clang_path.push_back(std::make_pair(&m_compiler_instance->getASTContext().Idents.get(path_component.GetStringRef()), - source_manager.getLocForStartOfFile(source_manager.getMainFileID()).getLocWithOffset(m_source_location_index++))); - } - } - - StoringDiagnosticConsumer *diagnostic_consumer = static_cast<StoringDiagnosticConsumer *>(m_compiler_instance->getDiagnostics().getClient()); - - diagnostic_consumer->ClearDiagnostics(); - - clang::Module *top_level_module = DoGetModule(clang_path.front(), false); - - if (!top_level_module) - { - diagnostic_consumer->DumpDiagnostics(error_stream); - error_stream.Printf("error: Couldn't load top-level module %s\n", path[0].AsCString()); - return false; - } - - clang::Module *submodule = top_level_module; - - for (size_t ci = 1; ci < path.size(); ++ci) - { - llvm::StringRef component = path[ci].GetStringRef(); - submodule = submodule->findSubmodule(component.str()); - if (!submodule) - { - diagnostic_consumer->DumpDiagnostics(error_stream); - error_stream.Printf("error: Couldn't load submodule %s\n", component.str().c_str()); - return false; - } - } - - clang::Module *requested_module = DoGetModule(clang_path, true); - - if (requested_module != nullptr) - { - if (exported_modules) - { - ReportModuleExports(*exported_modules, requested_module); - } - - m_imported_modules[imported_module] = requested_module; - - m_enabled = true; - - return true; - } - - return false; -} - - -bool -ClangModulesDeclVendor::LanguageSupportsClangModules (lldb::LanguageType language) -{ - switch (language) - { - default: - return false; - // C++ and friends to be added - case lldb::LanguageType::eLanguageTypeC: - case lldb::LanguageType::eLanguageTypeC11: - case lldb::LanguageType::eLanguageTypeC89: - case lldb::LanguageType::eLanguageTypeC99: - case lldb::LanguageType::eLanguageTypeObjC: - return true; - } -} - -bool -ClangModulesDeclVendorImpl::AddModulesForCompileUnit(CompileUnit &cu, - ClangModulesDeclVendor::ModuleVector &exported_modules, - Stream &error_stream) -{ - if (LanguageSupportsClangModules(cu.GetLanguage())) - { - std::vector<ConstString> imported_modules = cu.GetImportedModules(); - - for (ConstString imported_module : imported_modules) - { - std::vector<ConstString> path; - - path.push_back(imported_module); - - if (!AddModule(path, &exported_modules, error_stream)) - { - return false; - } - } - - return true; - } - - return true; -} - -// ClangImporter::lookupValue - -uint32_t -ClangModulesDeclVendorImpl::FindDecls (const ConstString &name, - bool append, - uint32_t max_matches, - std::vector <clang::NamedDecl*> &decls) -{ - if (!m_enabled) - { - return 0; - } - - if (!append) - decls.clear(); - - clang::IdentifierInfo &ident = m_compiler_instance->getASTContext().Idents.get(name.GetStringRef()); - - clang::LookupResult lookup_result(m_compiler_instance->getSema(), - clang::DeclarationName(&ident), - clang::SourceLocation(), - clang::Sema::LookupOrdinaryName); - - m_compiler_instance->getSema().LookupName(lookup_result, m_compiler_instance->getSema().getScopeForContext(m_compiler_instance->getASTContext().getTranslationUnitDecl())); - - uint32_t num_matches = 0; - - for (clang::NamedDecl *named_decl : lookup_result) - { - if (num_matches >= max_matches) - return num_matches; - - decls.push_back(named_decl); - ++num_matches; - } - - return num_matches; -} - -void -ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVector &modules, - std::function<bool (const std::string &)> handler) -{ - if (!m_enabled) - { - return; - } - - typedef std::map<ModuleID, ssize_t> ModulePriorityMap; - ModulePriorityMap module_priorities; - - ssize_t priority = 0; - - for (ModuleID module : modules) - { - module_priorities[module] = priority++; - } - - if (m_compiler_instance->getPreprocessor().getExternalSource()) - { - m_compiler_instance->getPreprocessor().getExternalSource()->ReadDefinedMacros(); - } - - for (clang::Preprocessor::macro_iterator mi = m_compiler_instance->getPreprocessor().macro_begin(), - me = m_compiler_instance->getPreprocessor().macro_end(); - mi != me; - ++mi) - { - const clang::IdentifierInfo *ii = nullptr; - - { - if (clang::IdentifierInfoLookup *lookup = m_compiler_instance->getPreprocessor().getIdentifierTable().getExternalIdentifierLookup()) - { - lookup->get(mi->first->getName()); - } - if (!ii) - { - ii = mi->first; - } - } - - ssize_t found_priority = -1; - clang::MacroInfo *macro_info = nullptr; - - for (clang::ModuleMacro *module_macro : m_compiler_instance->getPreprocessor().getLeafModuleMacros(ii)) - { - clang::Module *module = module_macro->getOwningModule(); - - { - ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast<ModuleID>(module)); - - if (pi != module_priorities.end() && pi->second > found_priority) - { - macro_info = module_macro->getMacroInfo(); - found_priority = pi->second; - } - } - - clang::Module *top_level_module = module->getTopLevelModule(); - - if (top_level_module != module) - { - ModulePriorityMap::iterator pi = module_priorities.find(reinterpret_cast<ModuleID>(top_level_module)); - - if ((pi != module_priorities.end()) && pi->second > found_priority) - { - macro_info = module_macro->getMacroInfo(); - found_priority = pi->second; - } - } - } - - if (macro_info) - { - std::string macro_expansion = "#define "; - macro_expansion.append(mi->first->getName().str().c_str()); - - { - if (macro_info->isFunctionLike()) - { - macro_expansion.append("("); - - bool first_arg = true; - - for (clang::MacroInfo::arg_iterator ai = macro_info->arg_begin(), - ae = macro_info->arg_end(); - ai != ae; - ++ai) - { - if (!first_arg) - { - macro_expansion.append(", "); - } - else - { - first_arg = false; - } - - macro_expansion.append((*ai)->getName().str()); - } - - if (macro_info->isC99Varargs()) - { - if (first_arg) - { - macro_expansion.append("..."); - } - else - { - macro_expansion.append(", ..."); - } - } - else if (macro_info->isGNUVarargs()) - { - macro_expansion.append("..."); - } - - macro_expansion.append(")"); - } - - macro_expansion.append(" "); - - bool first_token = true; - - for (clang::MacroInfo::tokens_iterator ti = macro_info->tokens_begin(), - te = macro_info->tokens_end(); - ti != te; - ++ti) - { - if (!first_token) - { - macro_expansion.append(" "); - } - else - { - first_token = false; - } - - if (ti->isLiteral()) - { - if (const char *literal_data = ti->getLiteralData()) - { - std::string token_str(literal_data, ti->getLength()); - macro_expansion.append(token_str); - } - else - { - bool invalid = false; - const char *literal_source = m_compiler_instance->getSourceManager().getCharacterData(ti->getLocation(), &invalid); - - if (invalid) - { - lldbassert(!"Unhandled token kind"); - macro_expansion.append("<unknown literal value>"); - } - else - { - macro_expansion.append(std::string(literal_source, ti->getLength())); - } - } - } - else if (const char *punctuator_spelling = clang::tok::getPunctuatorSpelling(ti->getKind())) - { - macro_expansion.append(punctuator_spelling); - } - else if (const char *keyword_spelling = clang::tok::getKeywordSpelling(ti->getKind())) - { - macro_expansion.append(keyword_spelling); - } - else - { - switch (ti->getKind()) - { - case clang::tok::TokenKind::identifier: - macro_expansion.append(ti->getIdentifierInfo()->getName().str()); - break; - case clang::tok::TokenKind::raw_identifier: - macro_expansion.append(ti->getRawIdentifier().str()); - default: - macro_expansion.append(ti->getName()); - break; - } - } - } - - if (handler(macro_expansion)) - { - return; - } - } - } - } -} - -ClangModulesDeclVendorImpl::~ClangModulesDeclVendorImpl() -{ -} - -clang::ModuleLoadResult -ClangModulesDeclVendorImpl::DoGetModule(clang::ModuleIdPath path, - bool make_visible) -{ - clang::Module::NameVisibilityKind visibility = make_visible ? clang::Module::AllVisible : clang::Module::Hidden; - - const bool is_inclusion_directive = false; - - return m_compiler_instance->loadModule(path.front().second, path, visibility, is_inclusion_directive); -} - -static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer"; - -lldb_private::ClangModulesDeclVendor * -ClangModulesDeclVendor::Create(Target &target) -{ - // FIXME we should insure programmatically that the expression parser's compiler and the modules runtime's - // compiler are both initialized in the same way – preferably by the same code. - - if (!target.GetPlatform()->SupportsModules()) - return nullptr; - - const ArchSpec &arch = target.GetArchitecture(); - - std::vector<std::string> compiler_invocation_arguments = - { - "-fmodules", - "-fcxx-modules", - "-fsyntax-only", - "-femit-all-decls", - "-target", arch.GetTriple().str(), - "-fmodules-validate-system-headers", - "-Werror=non-modular-include-in-framework-module" - }; - - target.GetPlatform()->AddClangModuleCompilationOptions(&target, compiler_invocation_arguments); - - compiler_invocation_arguments.push_back(ModuleImportBufferName); - - // Add additional search paths with { "-I", path } or { "-F", path } here. - - { - llvm::SmallString<128> DefaultModuleCache; - const bool erased_on_reboot = false; - llvm::sys::path::system_temp_directory(erased_on_reboot, DefaultModuleCache); - llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang"); - llvm::sys::path::append(DefaultModuleCache, "ModuleCache"); - std::string module_cache_argument("-fmodules-cache-path="); - module_cache_argument.append(DefaultModuleCache.str().str()); - compiler_invocation_arguments.push_back(module_cache_argument); - } - - FileSpecList &module_search_paths = target.GetClangModuleSearchPaths(); - - for (size_t spi = 0, spe = module_search_paths.GetSize(); spi < spe; ++spi) - { - const FileSpec &search_path = module_search_paths.GetFileSpecAtIndex(spi); - - std::string search_path_argument = "-I"; - search_path_argument.append(search_path.GetPath()); - - compiler_invocation_arguments.push_back(search_path_argument); - } - - { - FileSpec clang_resource_dir = GetResourceDir(); - - if (clang_resource_dir.IsDirectory()) - { - compiler_invocation_arguments.push_back("-resource-dir"); - compiler_invocation_arguments.push_back(clang_resource_dir.GetPath()); - } - } - - llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine = clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions, - new StoringDiagnosticConsumer); - - std::vector<const char *> compiler_invocation_argument_cstrs; - - for (const std::string &arg : compiler_invocation_arguments) { - compiler_invocation_argument_cstrs.push_back(arg.c_str()); - } - - llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> invocation(clang::createInvocationFromCommandLine(compiler_invocation_argument_cstrs, diagnostics_engine)); - - if (!invocation) - return nullptr; - - std::unique_ptr<llvm::MemoryBuffer> source_buffer = llvm::MemoryBuffer::getMemBuffer("extern int __lldb __attribute__((unavailable));", - ModuleImportBufferName); - - invocation->getPreprocessorOpts().addRemappedFile(ModuleImportBufferName, source_buffer.release()); - - std::unique_ptr<clang::CompilerInstance> instance(new clang::CompilerInstance); - - instance->setDiagnostics(diagnostics_engine.get()); - instance->setInvocation(invocation.get()); - - std::unique_ptr<clang::FrontendAction> action(new clang::SyntaxOnlyAction); - - instance->setTarget(clang::TargetInfo::CreateTargetInfo(*diagnostics_engine, instance->getInvocation().TargetOpts)); - - if (!instance->hasTarget()) - return nullptr; - - instance->getTarget().adjust(instance->getLangOpts()); - - if (!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) - return nullptr; - - instance->getPreprocessor().enableIncrementalProcessing(); - - instance->createModuleManager(); - - instance->createSema(action->getTranslationUnitKind(), nullptr); - - const bool skipFunctionBodies = false; - std::unique_ptr<clang::Parser> parser(new clang::Parser(instance->getPreprocessor(), instance->getSema(), skipFunctionBodies)); - - instance->getPreprocessor().EnterMainSourceFile(); - parser->Initialize(); - - clang::Parser::DeclGroupPtrTy parsed; - - while (!parser->ParseTopLevelDecl(parsed)); - - return new ClangModulesDeclVendorImpl (diagnostics_engine, invocation, std::move(instance), std::move(parser)); -} diff --git a/source/Expression/ClangPersistentVariables.cpp b/source/Expression/ClangPersistentVariables.cpp deleted file mode 100644 index db062d2..0000000 --- a/source/Expression/ClangPersistentVariables.cpp +++ /dev/null @@ -1,89 +0,0 @@ -//===-- 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/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp deleted file mode 100644 index 0da70e2..0000000 --- a/source/Expression/ClangUserExpression.cpp +++ /dev/null @@ -1,1172 +0,0 @@ -//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <stdio.h> -#if HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif - -#include <cstdlib> -#include <string> -#include <map> - -#include "lldb/Core/ConstString.h" -#include "lldb/Core/Log.h" -#include "lldb/Core/Module.h" -#include "lldb/Core/StreamFile.h" -#include "lldb/Core/StreamString.h" -#include "lldb/Core/ValueObjectConstResult.h" -#include "lldb/Expression/ASTResultSynthesizer.h" -#include "lldb/Expression/ClangExpressionDeclMap.h" -#include "lldb/Expression/ClangExpressionParser.h" -#include "lldb/Expression/ClangFunction.h" -#include "lldb/Expression/ClangModulesDeclVendor.h" -#include "lldb/Expression/ClangPersistentVariables.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/HostInfo.h" -#include "lldb/Symbol/Block.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/Function.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/SymbolVendor.h" -#include "lldb/Symbol/Type.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" -#include "lldb/Symbol/VariableList.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/StackFrame.h" -#include "lldb/Target/Target.h" -#include "lldb/Target/ThreadPlan.h" -#include "lldb/Target/ThreadPlanCallUserExpression.h" - -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" - -using namespace lldb_private; - -ClangUserExpression::ClangUserExpression (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_expr_decl_map(), - m_execution_unit_sp(), - m_materializer_ap(), - m_result_synthesizer(), - m_jit_module_wp(), - m_enforce_valid_object (true), - m_in_cplusplus_method (false), - m_in_objectivec_method (false), - m_in_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 () -{ - if (m_target) - { - lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); - if (jit_module_sp) - m_target->GetImages().Remove(jit_module_sp); - } -} - -clang::ASTConsumer * -ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough) -{ - 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_in_cplusplus_method = 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_in_objectivec_method = true; - m_needs_object_ptr = true; - - if (!method_decl->isInstanceMethod()) - m_in_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 is by pretending - // that this is a method of a class in whatever runtime the debug info says the object pointer - // belongs to. Do that here. - - ClangASTMetadata *metadata = ClangASTContext::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_in_cplusplus_method = true; - m_needs_object_ptr = true; - } - else if (language == lldb::eLanguageTypeObjC) - { - if (m_enforce_valid_object) - { - lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true)); - - const char *selfErrorString = "Stopped in a context claiming to capture an Objective-C object pointer, but 'self' isn't available; pretending we are in a generic context"; - - if (!variable_list_sp) - { - err.SetErrorString(selfErrorString); - return; - } - - lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self")); - - if (!self_variable_sp || - !self_variable_sp->IsInScope(frame) || - !self_variable_sp->LocationIsValidForFrame (frame)) - { - err.SetErrorString(selfErrorString); - return; - } - - Type *self_type = self_variable_sp->GetType(); - - if (!self_type) - { - err.SetErrorString(selfErrorString); - return; - } - - 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_in_objectivec_method = true; - m_needs_object_ptr = true; - } - else - { - err.SetErrorString(selfErrorString); - return; - } - } - else - { - m_in_objectivec_method = true; - m_needs_object_ptr = true; - } - } - } - } -} - -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, - bool generate_debug_info) -{ - 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::string prefix = m_expr_prefix; - - if (ClangModulesDeclVendor *decl_vendor = m_target->GetClangModulesDeclVendor()) - { - const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = m_target->GetPersistentVariables().GetHandLoadedClangModules(); - ClangModulesDeclVendor::ModuleVector modules_for_macros; - - for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) - { - modules_for_macros.push_back(module); - } - - if (m_target->GetEnableAutoImportClangModules()) - { - if (StackFrame *frame = exe_ctx.GetFramePtr()) - { - if (Block *block = frame->GetFrameBlock()) - { - SymbolContext sc; - - block->CalculateSymbolContext(&sc); - - if (sc.comp_unit) - { - StreamString error_stream; - - decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros, error_stream); - } - } - } - } - } - - std::unique_ptr<ExpressionSourceCode> source_code (ExpressionSourceCode::CreateWrapped(prefix.c_str(), m_expr_text.c_str())); - - lldb::LanguageType lang_type; - - if (m_in_cplusplus_method) - lang_type = lldb::eLanguageTypeC_plus_plus; - else if (m_in_objectivec_method) - lang_type = lldb::eLanguageTypeObjC; - else - lang_type = lldb::eLanguageTypeC; - - if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_in_static_method, exe_ctx)) - { - error_stream.PutCString ("error: couldn't construct expression body"); - return false; - } - - if (log) - log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str()); - - //////////////////////////////////// - // Set up the target and compiler - // - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - { - error_stream.PutCString ("error: invalid target\n"); - return false; - } - - ////////////////////////// - // Parse the expression - // - - m_materializer_ap.reset(new Materializer()); - - 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"); - - m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions. - - return false; - } - - Process *process = exe_ctx.GetProcessPtr(); - ExecutionContextScope *exe_scope = process; - - if (!exe_scope) - exe_scope = exe_ctx.GetTargetPtr(); - - ClangExpressionParser parser(exe_scope, *this, generate_debug_info); - - unsigned num_errors = parser.Parse (error_stream); - - if (num_errors) - { - error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - - m_expr_decl_map.reset(); // We are being careful here in the case of breakpoint conditions. - - return false; - } - - ////////////////////////////////////////////////////////////////////////////////////////// - // Prepare the output of the parser for execution, evaluating it statically if possible - // - - Error jit_error = parser.PrepareForExecution (m_jit_start_addr, - m_jit_end_addr, - m_execution_unit_sp, - exe_ctx, - m_can_interpret, - execution_policy); - - if (generate_debug_info) - { - lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule()); - - if (jit_module_sp) - { - ConstString const_func_name(FunctionName()); - FileSpec jit_file; - jit_file.GetFilename() = const_func_name; - jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString()); - m_jit_module_wp = jit_module_sp; - target->GetImages().Append(jit_module_sp); - } -// lldb_private::ObjectFile *jit_obj_file = jit_module_sp->GetObjectFile(); -// StreamFile strm (stdout, false); -// if (jit_obj_file) -// { -// jit_obj_file->GetSectionList(); -// jit_obj_file->GetSymtab(); -// jit_obj_file->Dump(&strm); -// } -// lldb_private::SymbolVendor *jit_sym_vendor = jit_module_sp->GetSymbolVendor(); -// if (jit_sym_vendor) -// { -// lldb_private::SymbolContextList sc_list; -// jit_sym_vendor->FindFunctions(const_func_name, NULL, lldb::eFunctionNameTypeFull, true, false, sc_list); -// sc_list.Dump(&strm, target); -// jit_sym_vendor->Dump(&strm); -// } - } - - m_expr_decl_map.reset(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions. - - if (jit_error.Success()) - { - if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) - m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); - return true; - } - else - { - const char *error_cstr = jit_error.AsCString(); - if (error_cstr && error_cstr[0]) - error_stream.Printf ("error: %s\n", error_cstr); - else - error_stream.Printf ("error: expression can't be interpreted or run\n"); - return false; - } -} - -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::eExpressionPathOptionsNoFragileObjcIvar | - StackFrame::eExpressionPathOptionsNoSyntheticChildren | - StackFrame::eExpressionPathOptionsNoSyntheticArrayRange, - var_sp, - err); - - if (!err.Success() || !valobj_sp.get()) - return LLDB_INVALID_ADDRESS; - - lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - - if (ret == LLDB_INVALID_ADDRESS) - { - err.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_in_cplusplus_method) - { - object_name.SetCString("this"); - } - else if (m_in_objectivec_method) - { - object_name.SetCString("self"); - } - else - { - error_stream.Printf("Need object pointer but don't know the language\n"); - return false; - } - - Error object_ptr_error; - - object_ptr = GetObjectPointer(frame, object_name, object_ptr_error); - - if (!object_ptr_error.Success()) - { - error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); - object_ptr = 0; - } - - if (m_in_objectivec_method) - { - ConstString cmd_name("_cmd"); - - cmd_ptr = GetObjectPointer(frame, 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_sp->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_sp->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_sp, struct_address, materialize_error); - - if (!materialize_error.Success()) - { - error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString()); - return false; - } - } - return true; -} - -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; -} - -lldb::ExpressionResults -ClangUserExpression::Execute (Stream &error_stream, - ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - lldb::ClangUserExpressionSP &shared_ptr_to_me, - lldb::ClangExpressionVariableSP &result) -{ - // 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 lldb::eExpressionSetupError; - } - - 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_sp->GetModule(); - llvm::Function *function = m_execution_unit_sp->GetFunction(); - - if (!module || !function) - { - error_stream.Printf("Supposed to interpret, but nothing is there"); - return lldb::eExpressionSetupError; - } - - Error interpreter_error; - - llvm::SmallVector <lldb::addr_t, 3> args; - - if (m_needs_object_ptr) - { - args.push_back(object_ptr); - - if (m_in_objectivec_method) - 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_sp.get(), - interpreter_error, - function_stack_bottom, - function_stack_top, - exe_ctx); - - if (!interpreter_error.Success()) - { - error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); - return lldb::eExpressionDiscarded; - } - } - else - { - if (!exe_ctx.HasThreadScope()) - { - error_stream.Printf("ClangUserExpression::Execute called with no thread selected."); - return lldb::eExpressionSetupError; - } - - Address wrapper_address (m_jit_start_addr); - - llvm::SmallVector <lldb::addr_t, 3> args; - - if (m_needs_object_ptr) { - args.push_back(object_ptr); - if (m_in_objectivec_method) - args.push_back(cmd_ptr); - } - - args.push_back(struct_address); - - lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), - wrapper_address, - args, - options, - shared_ptr_to_me)); - - if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) - return lldb::eExpressionSetupError; - - ThreadPlanCallUserExpression *user_expression_plan = static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get()); - - lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); - - function_stack_bottom = function_stack_pointer - HostInfo::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); - - lldb::ExpressionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, - call_plan_sp, - options, - error_stream); - - if (exe_ctx.GetProcessPtr()) - exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); - - if (log) - log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --"); - - if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint) - { - 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.PutCString ("Execution was interrupted."); - - if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) - || (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints())) - error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation."); - else - { - if (execution_result == lldb::eExpressionHitBreakpoint) - user_expression_plan->TransferExpressionOwnership(); - error_stream.PutCString ("\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 == lldb::eExpressionStoppedForDebug) - { - error_stream.PutCString ("Execution was halted at the first instruction of the expression " - "function because \"debug\" was requested.\n" - "Use \"thread return -x\" to return to the state before expression evaluation."); - return execution_result; - } - else if (execution_result != lldb::eExpressionCompleted) - { - 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 lldb::eExpressionCompleted; - } - else - { - return lldb::eExpressionResultUnavailable; - } - } - else - { - error_stream.Printf("Expression can't be run, because there is no JIT compiled function"); - return lldb::eExpressionSetupError; - } -} - -lldb::ExpressionResults -ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, - const EvaluateExpressionOptions& options, - const char *expr_cstr, - const char *expr_prefix, - lldb::ValueObjectSP &result_valobj_sp, - Error &error) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); - - lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); - const lldb::LanguageType language = options.GetLanguage(); - const ResultType desired_type = options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny; - lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; - - 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; - - const char *full_prefix = NULL; - const char *option_prefix = options.GetPrefix(); - std::string full_prefix_storage; - if (expr_prefix && option_prefix) - { - full_prefix_storage.assign(expr_prefix); - full_prefix_storage.append(option_prefix); - if (!full_prefix_storage.empty()) - full_prefix = full_prefix_storage.c_str(); - } - else if (expr_prefix) - full_prefix = expr_prefix; - else - full_prefix = option_prefix; - - lldb::ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, full_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; - const bool generate_debug_info = options.GetGenerateDebugInfo(); - - if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) - { - error.SetErrorString ("expression interrupted by callback before parse"); - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - return lldb::eExpressionInterrupted; - } - - if (!user_expression_sp->Parse (error_stream, - exe_ctx, - execution_policy, - keep_expression_in_memory, - generate_debug_info)) - { - execution_results = lldb::eExpressionParseError; - if (error_stream.GetString().empty()) - error.SetExpressionError (execution_results, "expression failed to parse, unknown error"); - else - error.SetExpressionError (execution_results, 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.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't"); - } - else - { - if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) - { - error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - return lldb::eExpressionInterrupted; - } - - error_stream.GetString().clear(); - - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Executing expression =="); - - execution_results = user_expression_sp->Execute (error_stream, - exe_ctx, - options, - user_expression_sp, - expr_result); - - if (options.GetResultIsInternal() && expr_result && process) - { - process->GetTarget().GetPersistentVariables().RemovePersistentVariable (expr_result); - } - - if (execution_results != lldb::eExpressionCompleted) - { - if (log) - log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally =="); - - if (error_stream.GetString().empty()) - error.SetExpressionError (execution_results, "expression failed to execute, unknown error"); - else - error.SetExpressionError (execution_results, 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 (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) - { - error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); - return lldb::eExpressionInterrupted; - } - - if (result_valobj_sp.get() == NULL) - { - result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); - } - - return execution_results; -} diff --git a/source/Expression/ClangUtilityFunction.cpp b/source/Expression/ClangUtilityFunction.cpp deleted file mode 100644 index de5b0c1..0000000 --- a/source/Expression/ClangUtilityFunction.cpp +++ /dev/null @@ -1,198 +0,0 @@ -//===-- 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/Module.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_expr_decl_map (), - m_execution_unit_sp (), - m_jit_module_wp (), - m_function_text (ExpressionSourceCode::g_expression_prefix), - m_function_name (name) -{ - if (text && text[0]) - m_function_text.append (text); -} - -ClangUtilityFunction::~ClangUtilityFunction () -{ - lldb::ProcessSP process_sp (m_jit_process_wp.lock()); - if (process_sp) - { - lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); - if (jit_module_sp) - process_sp->GetTarget().GetImages().Remove(jit_module_sp); - } - -} - -//------------------------------------------------------------------ -/// 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; - } - - const bool generate_debug_info = true; - ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info); - - unsigned num_errors = parser.Parse (error_stream); - - if (num_errors) - { - error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - - 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_sp, - exe_ctx, - can_interpret, - eExecutionPolicyAlways); - - if (m_jit_start_addr != LLDB_INVALID_ADDRESS) - { - m_jit_process_wp = process->shared_from_this(); - if (parser.GetGenerateDebugInfo()) - { - lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule()); - - if (jit_module_sp) - { - ConstString const_func_name(FunctionName()); - FileSpec jit_file; - jit_file.GetFilename() = const_func_name; - jit_module_sp->SetFileSpecAndObjectName (jit_file, ConstString()); - m_jit_module_wp = jit_module_sp; - target->GetImages().Append(jit_module_sp); - } - } - } - -#if 0 - // jingham: look here - StreamFile logfile ("/tmp/exprs.txt", "a"); - logfile.Printf ("0x%16.16" PRIx64 ": func = %s, source =\n%s\n", - m_jit_start_addr, - m_function_name.c_str(), - m_function_text.c_str()); -#endif - - 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/source/Expression/DWARFExpression.cpp b/source/Expression/DWARFExpression.cpp index 9307c84..ebcc284 100644 --- a/source/Expression/DWARFExpression.cpp +++ b/source/Expression/DWARFExpression.cpp @@ -24,8 +24,8 @@ #include "lldb/Core/Value.h" #include "lldb/Core/VMRange.h" -#include "lldb/Expression/ClangExpressionDeclMap.h" -#include "lldb/Expression/ClangExpressionVariable.h" +#include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h" +#include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" @@ -38,190 +38,27 @@ #include "lldb/Target/StackID.h" #include "lldb/Target/Thread.h" +#include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h" + using namespace lldb; using namespace lldb_private; -// TODO- why is this also defined (in a better way) in DWARFDefines.cpp? -const char * -DW_OP_value_to_name (uint32_t val) +static lldb::addr_t +ReadAddressFromDebugAddrSection(const DWARFCompileUnit* dwarf_cu, uint32_t index) { - 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; - } + uint32_t index_size = dwarf_cu->GetAddressByteSize(); + dw_offset_t addr_base = dwarf_cu->GetAddrBase(); + lldb::offset_t offset = addr_base + index * index_size; + return dwarf_cu->GetSymbolFileDWARF()->get_debug_addr_data().GetMaxU64(&offset, index_size); } - //---------------------------------------------------------------------- // DWARFExpression constructor //---------------------------------------------------------------------- -DWARFExpression::DWARFExpression() : +DWARFExpression::DWARFExpression(DWARFCompileUnit* dwarf_cu) : m_module_wp(), m_data(), + m_dwarf_cu(dwarf_cu), m_reg_kind (eRegisterKindDWARF), m_loclist_slide (LLDB_INVALID_ADDRESS) { @@ -230,15 +67,21 @@ DWARFExpression::DWARFExpression() : DWARFExpression::DWARFExpression(const DWARFExpression& rhs) : m_module_wp(rhs.m_module_wp), m_data(rhs.m_data), + m_dwarf_cu(rhs.m_dwarf_cu), m_reg_kind (rhs.m_reg_kind), m_loclist_slide(rhs.m_loclist_slide) { } -DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) : +DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, + const DataExtractor& data, + DWARFCompileUnit* dwarf_cu, + lldb::offset_t data_offset, + lldb::offset_t data_length) : m_module_wp(), m_data(data, data_offset, data_length), + m_dwarf_cu(dwarf_cu), m_reg_kind (eRegisterKindDWARF), m_loclist_slide(LLDB_INVALID_ADDRESS) { @@ -624,6 +467,12 @@ DWARFExpression::DumpLocation (Stream *s, lldb::offset_t offset, lldb::offset_t case DW_OP_form_tls_address: s->PutCString("DW_OP_form_tls_address"); // 0x9b break; + case DW_OP_GNU_addr_index: // 0xfb + s->Printf("DW_OP_GNU_addr_index(0x%" PRIx64 ")", m_data.GetULEB128(&offset)); + break; + case DW_OP_GNU_const_index: // 0xfc + s->Printf("DW_OP_GNU_const_index(0x%" PRIx64 ")", m_data.GetULEB128(&offset)); + break; case DW_OP_GNU_push_tls_address: s->PutCString("DW_OP_GNU_push_tls_address"); // 0xe0 break; @@ -709,8 +558,14 @@ DWARFExpression::GetDescription (Stream *s, lldb::DescriptionLevel level, addr_t 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); + addr_t begin_addr_offset = LLDB_INVALID_ADDRESS; + addr_t end_addr_offset = LLDB_INVALID_ADDRESS; + if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, begin_addr_offset, end_addr_offset)) + break; + + if (begin_addr_offset == 0 && end_addr_offset == 0) + break; + if (begin_addr_offset < end_addr_offset) { if (count > 0) @@ -723,11 +578,6 @@ DWARFExpression::GetDescription (Stream *s, lldb::DescriptionLevel level, addr_t 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)) || @@ -1027,8 +877,10 @@ GetOpcodeDataSize (const DataExtractor &data, const lldb::offset_t data_offset, 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 + case DW_OP_GNU_addr_index: // 0xfb 1 ULEB128 index + case DW_OP_GNU_const_index: // 0xfc 1 ULEB128 index data.Skip_LEB128(&offset); - return offset - data_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 @@ -1070,6 +922,22 @@ DWARFExpression::GetLocation_DW_OP_addr (uint32_t op_addr_idx, bool &error) cons else ++curr_op_addr_idx; } + else if (op == DW_OP_GNU_addr_index) + { + uint64_t index = m_data.GetULEB128(&offset); + if (curr_op_addr_idx == op_addr_idx) + { + if (!m_dwarf_cu) + { + error = true; + break; + } + + return ReadAddressFromDebugAddrSection(m_dwarf_cu, index); + } + else + ++curr_op_addr_idx; + } else { const offset_t op_arg_size = GetOpcodeDataSize (m_data, offset, op); @@ -1104,7 +972,7 @@ DWARFExpression::Update_DW_OP_addr (lldb::addr_t file_addr) // 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())); + m_data.GetByteSize())); // Make en encoder so we can write the address into the buffer using // the correct byte order (endianness) @@ -1150,20 +1018,21 @@ DWARFExpression::LocationListContainsAddress (lldb::addr_t loclist_base_addr, ll 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); + addr_t lo_pc = LLDB_INVALID_ADDRESS; + addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc, hi_pc)) + break; + 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; + lo_pc += loclist_base_addr - m_loclist_slide; + hi_pc += loclist_base_addr - m_loclist_slide; - offset += m_data.GetU16(&offset); - } + if (lo_pc <= addr && addr < hi_pc) + return true; + + offset += m_data.GetU16(&offset); } } return false; @@ -1186,24 +1055,23 @@ DWARFExpression::GetLocation (addr_t base_addr, addr_t pc, lldb::offset_t &offse 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); + addr_t lo_pc = LLDB_INVALID_ADDRESS; + addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc, hi_pc)) + break; + 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; - } + 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; @@ -1295,25 +1163,36 @@ DWARFExpression::Evaluate 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); + addr_t lo_pc = LLDB_INVALID_ADDRESS; + addr_t hi_pc = LLDB_INVALID_ADDRESS; + if (!AddressRangeForLocationListEntry(m_dwarf_cu, m_data, &offset, lo_pc, hi_pc)) + break; + 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); + lo_pc += curr_loclist_base_load_addr - m_loclist_slide; + hi_pc += curr_loclist_base_load_addr - m_loclist_slide; - if (length > 0 && lo_pc <= pc && pc < hi_pc) - { - return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, module_sp, m_data, offset, length, m_reg_kind, initial_value_ptr, result, error_ptr); - } - offset += length; + 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, + module_sp, + m_data, + m_dwarf_cu, + offset, + length, + m_reg_kind, + initial_value_ptr, + result, + error_ptr); } + offset += length; } } if (error_ptr) @@ -1322,7 +1201,19 @@ DWARFExpression::Evaluate } // Not a location list, just a single expression. - return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, module_sp, m_data, 0, m_data.GetByteSize(), m_reg_kind, initial_value_ptr, result, error_ptr); + return DWARFExpression::Evaluate (exe_ctx, + expr_locals, + decl_map, + reg_ctx, + module_sp, + m_data, + m_dwarf_cu, + 0, + m_data.GetByteSize(), + m_reg_kind, + initial_value_ptr, + result, + error_ptr); } @@ -1336,6 +1227,7 @@ DWARFExpression::Evaluate RegisterContext *reg_ctx, lldb::ModuleSP module_sp, const DataExtractor& opcodes, + DWARFCompileUnit* dwarf_cu, const lldb::offset_t opcodes_offset, const lldb::offset_t opcodes_length, const lldb::RegisterKind reg_kind, @@ -2711,7 +2603,7 @@ DWARFExpression::Evaluate return false; } } - else if (!stack.empty()) + else { // If this is the second or later piece there should be a value on the stack if (pieces.GetBuffer().GetByteSize() != op_piece_offset) @@ -2950,6 +2842,69 @@ DWARFExpression::Evaluate } break; + //---------------------------------------------------------------------- + // OPCODE: DW_OP_GNU_addr_index + // OPERANDS: 1 + // ULEB128: index to the .debug_addr section + // DESCRIPTION: Pushes an address to the stack from the .debug_addr + // section with the base address specified by the DW_AT_addr_base + // attribute and the 0 based index is the ULEB128 encoded index. + //---------------------------------------------------------------------- + case DW_OP_GNU_addr_index: + { + if (!dwarf_cu) + { + if (error_ptr) + error_ptr->SetErrorString ("DW_OP_GNU_addr_index found without a compile unit being specified"); + return false; + } + uint64_t index = opcodes.GetULEB128(&offset); + uint32_t index_size = dwarf_cu->GetAddressByteSize(); + dw_offset_t addr_base = dwarf_cu->GetAddrBase(); + lldb::offset_t offset = addr_base + index * index_size; + uint64_t value = dwarf_cu->GetSymbolFileDWARF()->get_debug_addr_data().GetMaxU64(&offset, index_size); + stack.push_back(Scalar(value)); + stack.back().SetValueType(Value::eValueTypeFileAddress); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_GNU_const_index + // OPERANDS: 1 + // ULEB128: index to the .debug_addr section + // DESCRIPTION: Pushes an constant with the size of a machine address to + // the stack from the .debug_addr section with the base address specified + // by the DW_AT_addr_base attribute and the 0 based index is the ULEB128 + // encoded index. + //---------------------------------------------------------------------- + case DW_OP_GNU_const_index: + { + if (!dwarf_cu) + { + if (error_ptr) + error_ptr->SetErrorString ("DW_OP_GNU_const_index found without a compile unit being specified"); + return false; + } + uint64_t index = opcodes.GetULEB128(&offset); + uint32_t index_size = dwarf_cu->GetAddressByteSize(); + dw_offset_t addr_base = dwarf_cu->GetAddrBase(); + lldb::offset_t offset = addr_base + index * index_size; + const DWARFDataExtractor& debug_addr = dwarf_cu->GetSymbolFileDWARF()->get_debug_addr_data(); + switch (index_size) + { + case 4: + stack.push_back(Scalar(debug_addr.GetU32(&offset))); + break; + case 8: + stack.push_back(Scalar(debug_addr.GetU64(&offset))); + break; + default: + assert(false && "Unhandled index size"); + return false; + } + } + break; + default: if (log) log->Printf("Unhandled opcode %s in DWARFExpression.", DW_OP_value_to_name(op)); @@ -2990,3 +2945,255 @@ DWARFExpression::Evaluate return true; // Return true on success } +size_t +DWARFExpression::LocationListSize(const DWARFCompileUnit* dwarf_cu, + const DataExtractor& debug_loc_data, + lldb::offset_t offset) +{ + const lldb::offset_t debug_loc_offset = offset; + while (debug_loc_data.ValidOffset(offset)) + { + lldb::addr_t start_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t end_addr = LLDB_INVALID_ADDRESS; + if (!AddressRangeForLocationListEntry(dwarf_cu, debug_loc_data, &offset, start_addr, end_addr)) + break; + + if (start_addr == 0 && end_addr == 0) + break; + + uint16_t loc_length = debug_loc_data.GetU16(&offset); + offset += loc_length; + } + + if (offset > debug_loc_offset) + return offset - debug_loc_offset; + return 0; +} + +bool +DWARFExpression::AddressRangeForLocationListEntry(const DWARFCompileUnit* dwarf_cu, + const DataExtractor& debug_loc_data, + lldb::offset_t* offset_ptr, + lldb::addr_t& low_pc, + lldb::addr_t& high_pc) +{ + if (!debug_loc_data.ValidOffset(*offset_ptr)) + return false; + + switch (dwarf_cu->GetSymbolFileDWARF()->GetLocationListFormat()) + { + case NonLocationList: + return false; + case RegularLocationList: + low_pc = debug_loc_data.GetAddress(offset_ptr); + high_pc = debug_loc_data.GetAddress(offset_ptr); + return true; + case SplitDwarfLocationList: + switch (debug_loc_data.GetU8(offset_ptr)) + { + case DW_LLE_end_of_list_entry: + return false; + case DW_LLE_start_end_entry: + { + uint64_t index = debug_loc_data.GetULEB128(offset_ptr); + low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); + index = debug_loc_data.GetULEB128(offset_ptr); + high_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); + return true; + } + case DW_LLE_start_length_entry: + { + uint64_t index = debug_loc_data.GetULEB128(offset_ptr); + low_pc = ReadAddressFromDebugAddrSection(dwarf_cu, index); + uint32_t length = debug_loc_data.GetU32(offset_ptr); + high_pc = low_pc + length; + return true; + } + default: + // Not supported entry type + return false; + } + } + assert (false && "Not supported location list type"); + return false; +} + +static bool +print_dwarf_exp_op (Stream &s, + const DataExtractor& data, + lldb::offset_t *offset_ptr, + int address_size, + int dwarf_ref_size) +{ + uint8_t opcode = data.GetU8(offset_ptr); + DRC_class opcode_class; + uint64_t uint; + int64_t sint; + + int size; + + opcode_class = DW_OP_value_to_class (opcode) & (~DRC_DWARFv3); + + s.Printf("%s ", DW_OP_value_to_name (opcode)); + + /* Does this take zero parameters? If so we can shortcut this function. */ + if (opcode_class == DRC_ZEROOPERANDS) + return true; + + if (opcode_class == DRC_TWOOPERANDS && opcode == DW_OP_bregx) + { + uint = data.GetULEB128(offset_ptr); + sint = data.GetSLEB128(offset_ptr); + s.Printf("%" PRIu64 " %" PRIi64, uint, sint); + return true; + } + if (opcode_class != DRC_ONEOPERAND) + { + s.Printf("UNKNOWN OP %u", opcode); + return false; + } + + switch (opcode) + { + case DW_OP_addr: size = address_size; break; + case DW_OP_const1u: size = 1; break; + case DW_OP_const1s: size = -1; break; + case DW_OP_const2u: size = 2; break; + case DW_OP_const2s: size = -2; break; + case DW_OP_const4u: size = 4; break; + case DW_OP_const4s: size = -4; break; + case DW_OP_const8u: size = 8; break; + case DW_OP_const8s: size = -8; break; + case DW_OP_constu: size = 128; break; + case DW_OP_consts: size = -128; break; + case DW_OP_fbreg: size = -128; 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: + size = -128; break; + case DW_OP_pick: + case DW_OP_deref_size: + case DW_OP_xderef_size: + size = 1; break; + case DW_OP_skip: + case DW_OP_bra: + size = -2; break; + case DW_OP_call2: + size = 2; break; + case DW_OP_call4: + size = 4; break; + case DW_OP_call_ref: + size = dwarf_ref_size; break; + case DW_OP_piece: + case DW_OP_plus_uconst: + case DW_OP_regx: + case DW_OP_GNU_addr_index: + case DW_OP_GNU_const_index: + size = 128; break; + default: + s.Printf("UNKNOWN ONE-OPERAND OPCODE, #%u", opcode); + return true; + } + + switch (size) + { + case -1: sint = (int8_t) data.GetU8(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case -2: sint = (int16_t) data.GetU16(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case -4: sint = (int32_t) data.GetU32(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case -8: sint = (int64_t) data.GetU64(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case -128: sint = data.GetSLEB128(offset_ptr); s.Printf("%+" PRIi64, sint); break; + case 1: uint = data.GetU8(offset_ptr); s.Printf("0x%2.2" PRIx64, uint); break; + case 2: uint = data.GetU16(offset_ptr); s.Printf("0x%4.4" PRIx64, uint); break; + case 4: uint = data.GetU32(offset_ptr); s.Printf("0x%8.8" PRIx64, uint); break; + case 8: uint = data.GetU64(offset_ptr); s.Printf("0x%16.16" PRIx64, uint); break; + case 128: uint = data.GetULEB128(offset_ptr); s.Printf("0x%" PRIx64, uint); break; + } + + return false; +} + +bool +DWARFExpression::PrintDWARFExpression(Stream &s, + const DataExtractor& data, + int address_size, + int dwarf_ref_size, + bool location_expression) +{ + int op_count = 0; + lldb::offset_t offset = 0; + while (data.ValidOffset(offset)) + { + if (location_expression && op_count > 0) + return false; + if (op_count > 0) + s.PutCString(", "); + if (!print_dwarf_exp_op (s, data, &offset, address_size, dwarf_ref_size)) + return false; + op_count++; + } + + return true; +} + +void +DWARFExpression::PrintDWARFLocationList(Stream &s, + const DWARFCompileUnit* cu, + const DataExtractor& debug_loc_data, + lldb::offset_t offset) +{ + uint64_t start_addr, end_addr; + uint32_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu); + s.SetAddressByteSize(DWARFCompileUnit::GetAddressByteSize(cu)); + dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0; + while (debug_loc_data.ValidOffset(offset)) + { + start_addr = debug_loc_data.GetMaxU64(&offset,addr_size); + end_addr = debug_loc_data.GetMaxU64(&offset,addr_size); + + if (start_addr == 0 && end_addr == 0) + break; + + s.PutCString("\n "); + s.Indent(); + if (cu) + s.AddressRange (start_addr + base_addr, + end_addr + base_addr, + cu->GetAddressByteSize(), + NULL, + ": "); + uint32_t loc_length = debug_loc_data.GetU16(&offset); + + DataExtractor locationData(debug_loc_data, offset, loc_length); + PrintDWARFExpression (s, locationData, addr_size, 4, false); + offset += loc_length; + } +} diff --git a/source/Expression/Expression.cpp b/source/Expression/Expression.cpp new file mode 100644 index 0000000..e5dd9c0 --- /dev/null +++ b/source/Expression/Expression.cpp @@ -0,0 +1,32 @@ +//===-- Expression.h ---------------------------------------*- 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/Expression.h" +#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; + +Expression::Expression (Target &target) : + m_target_wp (target.shared_from_this()), + m_jit_start_addr (LLDB_INVALID_ADDRESS), + m_jit_end_addr (LLDB_INVALID_ADDRESS) +{ + // Can't make any kind of expression without a target. + assert (m_target_wp.lock()); +} + +Expression::Expression (ExecutionContextScope &exe_scope) : + m_target_wp (exe_scope.CalculateTarget()), + m_jit_start_addr (LLDB_INVALID_ADDRESS), + m_jit_end_addr (LLDB_INVALID_ADDRESS) +{ + assert (m_target_wp.lock()); +} + diff --git a/source/Expression/ExpressionSourceCode.cpp b/source/Expression/ExpressionSourceCode.cpp index 9a42510..c4ab7a9 100644 --- a/source/Expression/ExpressionSourceCode.cpp +++ b/source/Expression/ExpressionSourceCode.cpp @@ -10,9 +10,12 @@ #include "lldb/Expression/ExpressionSourceCode.h" #include "lldb/Core/StreamString.h" -#include "lldb/Expression/ClangModulesDeclVendor.h" -#include "lldb/Expression/ClangPersistentVariables.h" +#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/Block.h" +#include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Platform.h" #include "lldb/Target/StackFrame.h" @@ -56,6 +59,121 @@ extern "C" } )"; +namespace { + +class AddMacroState +{ + enum State + { + CURRENT_FILE_NOT_YET_PUSHED, + CURRENT_FILE_PUSHED, + CURRENT_FILE_POPPED + }; + +public: + AddMacroState(const FileSpec ¤t_file, const uint32_t current_file_line) + : m_state(CURRENT_FILE_NOT_YET_PUSHED), + m_current_file(current_file), + m_current_file_line(current_file_line) + { } + + void + StartFile(const FileSpec &file) + { + m_file_stack.push_back(file); + if (file == m_current_file) + m_state = CURRENT_FILE_PUSHED; + } + + void + EndFile() + { + if (m_file_stack.size() == 0) + return; + + FileSpec old_top = m_file_stack.back(); + m_file_stack.pop_back(); + if (old_top == m_current_file) + m_state = CURRENT_FILE_POPPED; + } + + // An entry is valid if it occurs before the current line in + // the current file. + bool + IsValidEntry(uint32_t line) + { + switch (m_state) + { + case CURRENT_FILE_NOT_YET_PUSHED: + return true; + case CURRENT_FILE_POPPED: + return false; + case CURRENT_FILE_PUSHED: + // If we are in file included in the current file, + // the entry should be added. + if (m_file_stack.back() != m_current_file) + return true; + + if (line >= m_current_file_line) + return false; + else + return true; + } + } + +private: + std::vector<FileSpec> m_file_stack; + State m_state; + FileSpec m_current_file; + uint32_t m_current_file_line; +}; + +} // anonymous namespace + +static void +AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, AddMacroState &state, StreamString &stream) +{ + if (dm == nullptr) + return; + + for (size_t i = 0; i < dm->GetNumMacroEntries(); i++) + { + const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i); + uint32_t line; + + switch (entry.GetType()) + { + case DebugMacroEntry::DEFINE: + if (state.IsValidEntry(entry.GetLineNumber())) + stream.Printf("#define %s\n", entry.GetMacroString().AsCString()); + else + return; + break; + case DebugMacroEntry::UNDEF: + if (state.IsValidEntry(entry.GetLineNumber())) + stream.Printf("#undef %s\n", entry.GetMacroString().AsCString()); + else + return; + break; + case DebugMacroEntry::START_FILE: + line = entry.GetLineNumber(); + if (state.IsValidEntry(line)) + state.StartFile(entry.GetFileSpec(comp_unit)); + else + return; + break; + case DebugMacroEntry::END_FILE: + state.EndFile(); + break; + case DebugMacroEntry::INDIRECT: + AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream); + break; + default: + // This is an unknown/invalid entry. Ignore. + break; + } + } +} bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method, ExecutionContext &exe_ctx) const { @@ -82,7 +200,8 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi if (ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor()) { - const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = target->GetPersistentVariables().GetHandLoadedClangModules(); + ClangPersistentVariables *persistent_vars = llvm::cast<ClangPersistentVariables>(target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); + const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = persistent_vars->GetHandLoadedClangModules(); ClangModulesDeclVendor::ModuleVector modules_for_macros; for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) @@ -118,6 +237,23 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi } } + + StreamString debug_macros_stream; + if (StackFrame *frame = exe_ctx.GetFramePtr()) + { + const SymbolContext &sc = frame->GetSymbolContext( + lldb:: eSymbolContextCompUnit | lldb::eSymbolContextLineEntry); + + if (sc.comp_unit && sc.line_entry.IsValid()) + { + DebugMacros *dm = sc.comp_unit->GetDebugMacros(); + if (dm) + { + AddMacroState state(sc.line_entry.file, sc.line_entry.line); + AddMacros(dm, sc.comp_unit, state, debug_macros_stream); + } + } + } if (m_wrap) { @@ -133,8 +269,9 @@ bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrappi StreamString wrap_stream; - wrap_stream.Printf("%s\n%s\n%s\n%s\n", + wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), + debug_macros_stream.GetData(), g_expression_prefix, target_specific_defines, m_prefix.c_str()); diff --git a/source/Expression/ExpressionVariable.cpp b/source/Expression/ExpressionVariable.cpp new file mode 100644 index 0000000..8bef60f --- /dev/null +++ b/source/Expression/ExpressionVariable.cpp @@ -0,0 +1,36 @@ +//===-- ExpressionVariable.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/ExpressionVariable.h" + +using namespace lldb_private; + +ExpressionVariable::~ExpressionVariable() +{ +} + +uint8_t * +ExpressionVariable::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; +} + +PersistentExpressionState::~PersistentExpressionState () +{ +} diff --git a/source/Expression/ClangFunction.cpp b/source/Expression/FunctionCaller.cpp index b438dac..ddc378d 100644 --- a/source/Expression/ClangFunction.cpp +++ b/source/Expression/FunctionCaller.cpp @@ -1,4 +1,4 @@ -//===-- ClangFunction.cpp ---------------------------------------*- C++ -*-===// +//===-- FunctionCaller.cpp ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,15 +11,6 @@ // C Includes // C++ Includes // Other libraries and framework includes -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecordLayout.h" -#include "clang/CodeGen/CodeGenAction.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Frontend/CompilerInstance.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/IR/Module.h" // Project includes #include "lldb/Core/DataExtractor.h" @@ -28,12 +19,9 @@ #include "lldb/Core/State.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" -#include "lldb/Expression/ASTStructExtractor.h" -#include "lldb/Expression/ClangExpressionParser.h" -#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ExecutionContext.h" @@ -47,16 +35,17 @@ using namespace lldb_private; //---------------------------------------------------------------------- -// ClangFunction constructor +// FunctionCaller constructor //---------------------------------------------------------------------- -ClangFunction::ClangFunction +FunctionCaller::FunctionCaller ( ExecutionContextScope &exe_scope, - const ClangASTType &return_type, + const CompilerType &return_type, const Address& functionAddress, const ValueList &arg_value_list, const char *name ) : + Expression (exe_scope), m_execution_unit_sp(), m_parser(), m_jit_module_wp(), @@ -72,41 +61,14 @@ ClangFunction::ClangFunction m_JITted (false) { m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess()); - // Can't make a ClangFunction without a process. + // Can't make a FunctionCaller without a process. assert (m_jit_process_wp.lock()); } -ClangFunction::ClangFunction -( - ExecutionContextScope &exe_scope, - Function &function, - ClangASTContext *ast_context, - const ValueList &arg_value_list, - const char *name -) : - m_name (name ? name : "<unknown>"), - m_function_ptr (&function), - m_function_addr (), - m_function_return_type (), - 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 = 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() +FunctionCaller::~FunctionCaller() { lldb::ProcessSP process_sp (m_jit_process_wp.lock()); if (process_sp) @@ -117,147 +79,8 @@ 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().AsCString("")); - - // Cons up the function we're going to wrap our call in, then compile it... - // We declare the function "extern "C"" because the compiler might be in C++ - // mode which would mangle the name and then we couldn't find it again... - m_wrapper_function_text.clear(); - m_wrapper_function_text.append ("extern \"C\" void "); - m_wrapper_function_text.append (m_wrapper_function_name); - m_wrapper_function_text.append (" (void *input)\n{\n struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append (" \n {\n"); - m_wrapper_function_text.append (" "); - m_wrapper_function_text.append (return_type_str); - m_wrapper_function_text.append (" (*fn_ptr) ("); - - // Get the number of arguments. If we have a function type and it is prototyped, - // trust that, otherwise use the values we were given. - - // FIXME: This will need to be extended to handle Variadic functions. We'll need - // to pull the defined arguments out of the function, then add the types from the - // arguments list for the variable arguments. - - uint32_t num_args = UINT32_MAX; - bool trust_function = false; - // GetArgumentCount returns -1 for an unprototyped function. - 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().AsCString(""); - } - else - { - ClangASTType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetClangType (); - if (clang_qual_type) - { - type_name = clang_qual_type.GetTypeName().AsCString(""); - } - else - { - errors.Printf("Could not determine type of input value %" PRIu64 ".", (uint64_t)i); - return 1; - } - } - - m_wrapper_function_text.append (type_name); - if (i < num_args - 1) - m_wrapper_function_text.append (", "); - - char arg_buf[32]; - args_buffer.append (" "); - args_buffer.append (type_name); - snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i); - args_buffer.push_back (' '); - args_buffer.append (arg_buf); - args_buffer.append (";\n"); - - args_list_buffer.append ("__lldb_fn_data->"); - args_list_buffer.append (arg_buf); - if (i < num_args - 1) - args_list_buffer.append (", "); - - } - m_wrapper_function_text.append (");\n"); // Close off the function calling prototype. - - m_wrapper_function_text.append (args_buffer); - - m_wrapper_function_text.append (" "); - m_wrapper_function_text.append (return_type_str); - m_wrapper_function_text.append (" return_value;"); - m_wrapper_function_text.append ("\n };\n struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append ("* __lldb_fn_data = (struct "); - m_wrapper_function_text.append (m_wrapper_struct_name); - m_wrapper_function_text.append (" *) input;\n"); - - m_wrapper_function_text.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); - m_wrapper_function_text.append (args_list_buffer); - m_wrapper_function_text.append (");\n}\n"); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - if (log) - log->Printf ("Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); - - // Okay, now compile this expression - - lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); - if (jit_process_sp) - { - const bool generate_debug_info = true; - m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, generate_debug_info)); - - num_errors = m_parser->Parse (errors); - } - else - { - errors.Printf("no process - unable to inject function"); - num_errors = 1; - } - - m_compiled = (num_errors == 0); - - if (!m_compiled) - return num_errors; - - return num_errors; -} - bool -ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) +FunctionCaller::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) { Process *process = exe_ctx.GetProcessPtr(); @@ -310,18 +133,17 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) } bool -ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) +FunctionCaller::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); + return WriteFunctionArguments(exe_ctx, args_addr_ref, 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, +FunctionCaller::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, - Address function_address, - ValueList &arg_values, + ValueList &arg_values, Stream &errors) { // All the information to reconstruct the struct is provided by the @@ -333,7 +155,6 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, } Error error; - using namespace clang; lldb::ExpressionResults return_value = lldb::eExpressionSetupError; Process *process = exe_ctx.GetProcessPtr(); @@ -363,7 +184,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, } // TODO: verify fun_addr needs to be a callable address - Scalar fun_addr (function_address.GetCallableLoadAddress(exe_ctx.GetTargetPtr())); + Scalar fun_addr (m_function_addr.GetCallableLoadAddress(exe_ctx.GetTargetPtr())); uint64_t first_offset = m_member_offsets[0]; process->WriteScalarToMemory(args_addr_ref + first_offset, fun_addr, process->GetAddressByteSize(), error); @@ -391,7 +212,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, if (arg_value->GetValueType() == Value::eValueTypeHostAddress && arg_value->GetContextType() == Value::eContextTypeInvalid && - arg_value->GetClangType().IsPointerType()) + arg_value->GetCompilerType().IsPointerType()) continue; const Scalar &arg_scalar = arg_value->ResolveValue(&exe_ctx); @@ -404,10 +225,8 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, } bool -ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors) +FunctionCaller::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)) @@ -423,7 +242,7 @@ ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_add } lldb::ThreadPlanSP -ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, +FunctionCaller::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, lldb::addr_t args_addr, const EvaluateExpressionOptions &options, Stream &errors) @@ -431,7 +250,7 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) - log->Printf("-- [ClangFunction::GetThreadPlanToCallFunction] Creating thread plan to call function \"%s\" --", m_name.c_str()); + log->Printf("-- [FunctionCaller::GetThreadPlanToCallFunction] Creating thread plan to call function \"%s\" --", m_name.c_str()); // FIXME: Use the errors Stream for better error reporting. Thread *thread = exe_ctx.GetThreadPtr(); @@ -449,7 +268,7 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, lldb::ThreadPlanSP new_plan_sp (new ThreadPlanCallFunction (*thread, wrapper_address, - ClangASTType(), + CompilerType(), args, options)); new_plan_sp->SetIsMasterPlan(true); @@ -458,17 +277,17 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, } bool -ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr, Value &ret_value) +FunctionCaller::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 + // FIXME: Create our ThreadPlanCallFunction with the return CompilerType, 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 for \"%s\"--", m_name.c_str()); + log->Printf("-- [FunctionCaller::FetchFunctionResults] Fetching function results for \"%s\"--", m_name.c_str()); Process *process = exe_ctx.GetProcessPtr(); @@ -486,13 +305,13 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg if (error.Fail()) return false; - ret_value.SetClangType(m_function_return_type); + ret_value.SetCompilerType(m_function_return_type); ret_value.SetValueType(Value::eValueTypeScalar); return true; } void -ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr) +FunctionCaller::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); @@ -503,17 +322,16 @@ ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_ } lldb::ExpressionResults -ClangFunction::ExecuteFunction( +FunctionCaller::ExecuteFunction( ExecutionContext &exe_ctx, lldb::addr_t *args_addr_ptr, const EvaluateExpressionOptions &options, Stream &errors, Value &results) { - using namespace clang; lldb::ExpressionResults return_value = lldb::eExpressionSetupError; - // ClangFunction::ExecuteFunction execution is always just to get the result. Do make sure we ignore + // FunctionCaller::ExecuteFunction execution is always just to get the result. Do make sure we ignore // breakpoints, unwind on error, and don't try to debug it. EvaluateExpressionOptions real_options = options; real_options.SetDebug(false); @@ -539,7 +357,7 @@ ClangFunction::ExecuteFunction( Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) - log->Printf("== [ClangFunction::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str()); lldb::ThreadPlanSP call_plan_sp = GetThreadPlanToCallFunction (exe_ctx, args_addr, @@ -562,11 +380,11 @@ ClangFunction::ExecuteFunction( { if (return_value != lldb::eExpressionCompleted) { - log->Printf("== [ClangFunction::ExecuteFunction] Execution of \"%s\" completed abnormally ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Execution of \"%s\" completed abnormally ==", m_name.c_str()); } else { - log->Printf("== [ClangFunction::ExecuteFunction] Execution of \"%s\" completed normally ==", m_name.c_str()); + log->Printf("== [FunctionCaller::ExecuteFunction] Execution of \"%s\" completed normally ==", m_name.c_str()); } } @@ -586,11 +404,3 @@ ClangFunction::ExecuteFunction( return lldb::eExpressionCompleted; } - -clang::ASTConsumer * -ClangFunction::ASTTransformer (clang::ASTConsumer *passthrough) -{ - m_struct_extractor.reset(new ASTStructExtractor(passthrough, m_wrapper_struct_name.c_str(), *this)); - - return m_struct_extractor.get(); -} diff --git a/source/Expression/IRDynamicChecks.cpp b/source/Expression/IRDynamicChecks.cpp index aa5d28b..30d7f63 100644 --- a/source/Expression/IRDynamicChecks.cpp +++ b/source/Expression/IRDynamicChecks.cpp @@ -1,4 +1,4 @@ -//===-- IRDynamicChecks.cpp -------------------------------------------*- C++ -*-===// +//===-- IRDynamicChecks.cpp -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,23 +7,28 @@ // //===----------------------------------------------------------------------===// +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/Support/raw_ostream.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/IR/Value.h" + +// Project includes #include "lldb/Expression/IRDynamicChecks.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Log.h" -#include "lldb/Expression/ClangUtilityFunction.h" +#include "lldb/Expression/UtilityFunction.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/DataLayout.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Value.h" +#include "lldb/Target/Target.h" using namespace llvm; using namespace lldb_private; @@ -40,20 +45,22 @@ static const char g_valid_pointer_check_text[] = " unsigned char $__lldb_local_val = *$__lldb_arg_ptr;\n" "}"; -DynamicCheckerFunctions::DynamicCheckerFunctions () -{ -} +DynamicCheckerFunctions::DynamicCheckerFunctions() = default; -DynamicCheckerFunctions::~DynamicCheckerFunctions () -{ -} +DynamicCheckerFunctions::~DynamicCheckerFunctions() = default; 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)); + Error error; + m_valid_pointer_check.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(g_valid_pointer_check_text, + lldb::eLanguageTypeC, + VALID_POINTER_CHECK_NAME, + error)); + if (error.Fail()) + return false; + if (!m_valid_pointer_check->Install(error_stream, exe_ctx)) return false; @@ -80,12 +87,12 @@ DynamicCheckerFunctions::DoCheckersExplainStop (lldb::addr_t addr, Stream &messa { // 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)) + if (m_valid_pointer_check && m_valid_pointer_check->ContainsAddress(addr)) { message.Printf ("Attempted to dereference an invalid pointer."); return true; } - else if (m_objc_object_check.get() != NULL && m_objc_object_check->ContainsAddress(addr)) + else if (m_objc_object_check && m_objc_object_check->ContainsAddress(addr)) { message.Printf ("Attempted to dereference an invalid ObjC Object or send it an unrecognized selector"); return true; @@ -93,7 +100,6 @@ DynamicCheckerFunctions::DoCheckersExplainStop (lldb::addr_t addr, Stream &messa return false; } - static std::string PrintValue(llvm::Value *V, bool truncate = false) { @@ -146,14 +152,12 @@ public: DynamicCheckerFunctions &checker_functions) : m_module(module), m_checker_functions(checker_functions), - m_i8ptr_ty(NULL), - m_intptr_ty(NULL) + m_i8ptr_ty(nullptr), + m_intptr_ty(nullptr) { } - virtual~Instrumenter () - { - } + virtual ~Instrumenter() = default; //------------------------------------------------------------------ /// Inspect a function to find instructions to instrument @@ -187,6 +191,7 @@ public: return true; } + protected: //------------------------------------------------------------------ /// Add instrumentation to a single instruction @@ -344,6 +349,7 @@ protected: 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; IntegerType *m_intptr_ty; @@ -355,15 +361,14 @@ public: ValidPointerChecker (llvm::Module &module, DynamicCheckerFunctions &checker_functions) : Instrumenter(module, checker_functions), - m_valid_pointer_check_func(NULL) + m_valid_pointer_check_func(nullptr) { } - virtual ~ValidPointerChecker () - { - } -private: - bool InstrumentInstruction(llvm::Instruction *inst) + ~ValidPointerChecker() override = default; + +protected: + bool InstrumentInstruction(llvm::Instruction *inst) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -374,7 +379,7 @@ private: 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; + llvm::Value *dereferenced_ptr = nullptr; if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst> (inst)) dereferenced_ptr = li->getPointerOperand(); @@ -406,7 +411,7 @@ private: return true; } - bool InspectInstruction(llvm::Instruction &i) + bool InspectInstruction(llvm::Instruction &i) override { if (dyn_cast<llvm::LoadInst> (&i) || dyn_cast<llvm::StoreInst> (&i)) @@ -415,6 +420,7 @@ private: return true; } +private: llvm::Value *m_valid_pointer_check_func; }; @@ -424,14 +430,11 @@ public: ObjcObjectChecker(llvm::Module &module, DynamicCheckerFunctions &checker_functions) : Instrumenter(module, checker_functions), - m_objc_object_check_func(NULL) + m_objc_object_check_func(nullptr) { } - virtual - ~ObjcObjectChecker () - { - } + ~ObjcObjectChecker() override = default; enum msgSend_type { @@ -444,13 +447,13 @@ public: std::map <llvm::Instruction *, msgSend_type> msgSend_types; -private: - bool InstrumentInstruction(llvm::Instruction *inst) +protected: + bool InstrumentInstruction(llvm::Instruction *inst) override { CallInst *call_inst = dyn_cast<CallInst>(inst); if (!call_inst) - return false; // call_inst really shouldn't be NULL, because otherwise InspectInstruction wouldn't have registered it + return false; // call_inst really shouldn't be nullptr, because otherwise InspectInstruction wouldn't have registered it if (!m_objc_object_check_func) m_objc_object_check_func = BuildObjectCheckerFunc(m_checker_functions.m_objc_object_check->StartAddress()); @@ -504,7 +507,7 @@ private: return true; } - bool InspectInstruction(llvm::Instruction &i) + bool InspectInstruction(llvm::Instruction &i) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -593,6 +596,7 @@ private: return true; } +private: llvm::Value *m_objc_object_check_func; }; @@ -604,9 +608,7 @@ IRDynamicChecks::IRDynamicChecks(DynamicCheckerFunctions &checker_functions, { } -IRDynamicChecks::~IRDynamicChecks() -{ -} +IRDynamicChecks::~IRDynamicChecks() = default; bool IRDynamicChecks::runOnModule(llvm::Module &M) @@ -623,7 +625,7 @@ IRDynamicChecks::runOnModule(llvm::Module &M) return false; } - if (m_checker_functions.m_valid_pointer_check.get()) + if (m_checker_functions.m_valid_pointer_check) { ValidPointerChecker vpc(M, m_checker_functions); @@ -634,7 +636,7 @@ IRDynamicChecks::runOnModule(llvm::Module &M) return false; } - if (m_checker_functions.m_objc_object_check.get()) + if (m_checker_functions.m_objc_object_check) { ObjcObjectChecker ooc(M, m_checker_functions); @@ -650,7 +652,7 @@ IRDynamicChecks::runOnModule(llvm::Module &M) std::string s; raw_string_ostream oss(s); - M.print(oss, NULL); + M.print(oss, nullptr); oss.flush(); diff --git a/source/Expression/IRExecutionUnit.cpp b/source/Expression/IRExecutionUnit.cpp index 59c7fb6..3f19c50 100644 --- a/source/Expression/IRExecutionUnit.cpp +++ b/source/Expression/IRExecutionUnit.cpp @@ -50,10 +50,12 @@ IRExecutionUnit::WriteNow (const uint8_t *bytes, size_t size, Error &error) { + const bool zero_memory = false; lldb::addr_t allocation_process_addr = Malloc (size, 8, lldb::ePermissionsWritable | lldb::ePermissionsReadable, eAllocationPolicyMirror, + zero_memory, error); if (!error.Success()) @@ -432,6 +434,13 @@ IRExecutionUnit::GetRunnableInfo(Error &error, my_extractor.PutToLog(log, 0, my_buffer.GetByteSize(), record.m_process_address, 16, DataExtractor::TypeUInt8); } } + else + { + record.dump(log); + + DataExtractor my_extractor ((const void*)record.m_host_address, record.m_size, lldb::eByteOrderBig, 8); + my_extractor.PutToLog(log, 0, record.m_size, record.m_host_address, 16, DataExtractor::TypeUInt8); + } } } @@ -488,6 +497,8 @@ IRExecutionUnit::GetSectionTypeFromSectionName (const llvm::StringRef &name, IRE sect_type = lldb::eSectionTypeDWARFDebugAbbrev; else if (dwarf_name.equals("aranges")) sect_type = lldb::eSectionTypeDWARFDebugAranges; + else if (dwarf_name.equals("addr")) + sect_type = lldb::eSectionTypeDWARFDebugAddr; break; case 'f': @@ -522,6 +533,8 @@ IRExecutionUnit::GetSectionTypeFromSectionName (const llvm::StringRef &name, IRE case 's': if (dwarf_name.equals("str")) sect_type = lldb::eSectionTypeDWARFDebugStr; + else if (dwarf_name.equals("str_offsets")) + sect_type = lldb::eSectionTypeDWARFDebugStrOffsets; break; case 'r': @@ -789,6 +802,7 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp) { case lldb::eSectionTypeInvalid: case lldb::eSectionTypeDWARFDebugAbbrev: + case lldb::eSectionTypeDWARFDebugAddr: case lldb::eSectionTypeDWARFDebugAranges: case lldb::eSectionTypeDWARFDebugFrame: case lldb::eSectionTypeDWARFDebugInfo: @@ -799,6 +813,7 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp) case lldb::eSectionTypeDWARFDebugPubTypes: case lldb::eSectionTypeDWARFDebugRanges: case lldb::eSectionTypeDWARFDebugStr: + case lldb::eSectionTypeDWARFDebugStrOffsets: case lldb::eSectionTypeDWARFAppleNames: case lldb::eSectionTypeDWARFAppleTypes: case lldb::eSectionTypeDWARFAppleNamespaces: @@ -806,10 +821,12 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp) err.Clear(); break; default: + const bool zero_memory = false; record.m_process_address = Malloc (record.m_size, record.m_alignment, record.m_permissions, eAllocationPolicyProcessOnly, + zero_memory, err); break; } @@ -877,12 +894,13 @@ IRExecutionUnit::AllocationRecord::dump (Log *log) if (!log) return; - log->Printf("[0x%llx+0x%llx]->0x%llx (alignment %d, section ID %d)", + log->Printf("[0x%llx+0x%llx]->0x%llx (alignment %d, section ID %d, name %s)", (unsigned long long)m_host_address, (unsigned long long)m_size, (unsigned long long)m_process_address, (unsigned)m_alignment, - (unsigned)m_section_id); + (unsigned)m_section_id, + m_name.c_str()); } diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp deleted file mode 100644 index cf2a93b..0000000 --- a/source/Expression/IRForTarget.cpp +++ /dev/null @@ -1,2819 +0,0 @@ -//===-- 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/IR/LegacyPassManager.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/IR/Metadata.h" -#include "llvm/IR/ValueSymbolTable.h" - -#include "clang/AST/ASTContext.h" - -#include "lldb/Core/dwarf.h" -#include "lldb/Core/ConstString.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Log.h" -#include "lldb/Core/Scalar.h" -#include "lldb/Core/StreamString.h" -#include "lldb/Expression/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 "lldb/Target/CPPLanguageRuntime.h" - -#include <map> - -using namespace llvm; - -static char ID; - -IRForTarget::StaticDataAllocator::StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit) : - m_execution_unit(execution_unit), - m_stream_string(lldb_private::Stream::eBinary, execution_unit.GetAddressByteSize(), execution_unit.GetByteOrder()), - m_allocation(LLDB_INVALID_ADDRESS) -{ -} - -IRForTarget::FunctionValueCache::FunctionValueCache(Maker const &maker) : - m_maker(maker), - m_values() -{ -} - -IRForTarget::FunctionValueCache::~FunctionValueCache() -{ -} - -llvm::Value * -IRForTarget::FunctionValueCache::GetValue(llvm::Function *function) -{ - if (!m_values.count(function)) - { - llvm::Value *ret = m_maker(function); - m_values[function] = ret; - return ret; - } - return m_values[function]; -} - -lldb::addr_t -IRForTarget::StaticDataAllocator::Allocate() -{ - lldb_private::Error err; - - if (m_allocation != LLDB_INVALID_ADDRESS) - { - m_execution_unit.FreeNow(m_allocation); - m_allocation = LLDB_INVALID_ADDRESS; - } - - m_allocation = m_execution_unit.WriteNow((const uint8_t*)m_stream_string.GetData(), m_stream_string.GetSize(), err); - - return m_allocation; -} - -lldb::TargetSP -IRForTarget::StaticDataAllocator::GetTarget() -{ - return m_execution_unit.GetTarget(); -} - -static llvm::Value * -FindEntryInstruction (llvm::Function *function) -{ - if (function->empty()) - return NULL; - - return function->getEntryBlock().getFirstNonPHIOrDbg(); -} - -IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map, - bool resolve_vars, - lldb_private::IRExecutionUnit &execution_unit, - lldb_private::Stream *error_stream, - const char *func_name) : - ModulePass(ID), - m_resolve_vars(resolve_vars), - m_func_name(func_name), - m_module(NULL), - m_decl_map(decl_map), - m_data_allocator(execution_unit), - m_CFStringCreateWithBytes(NULL), - m_sel_registerName(NULL), - m_intptr_ty(NULL), - m_error_stream(error_stream), - m_result_store(NULL), - m_result_is_pointer(false), - m_reloc_placeholder(NULL), - m_entry_instruction_finder (FindEntryInstruction) -{ -} - -/* Handy utility functions used at several places in the code */ - -static std::string -PrintValue(const Value *value, bool truncate = false) -{ - std::string s; - if (value) - { - raw_string_ostream rso(s); - value->print(rso); - rso.flush(); - if (truncate) - s.resize(s.length() - 1); - } - return s; -} - -static std::string -PrintType(const llvm::Type *type, bool truncate = false) -{ - std::string s; - raw_string_ostream rso(s); - type->print(rso); - rso.flush(); - if (truncate) - s.resize(s.length() - 1); - return s; -} - -IRForTarget::~IRForTarget() -{ -} - -bool -IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function) -{ - llvm_function.setLinkage(GlobalValue::ExternalLinkage); - - std::string name = llvm_function.getName().str(); - - return true; -} - -IRForTarget::LookupResult -IRForTarget::GetFunctionAddress (llvm::Function *fun, - uint64_t &fun_addr, - lldb_private::ConstString &name, - Constant **&value_ptr) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - fun_addr = LLDB_INVALID_ADDRESS; - name.Clear(); - value_ptr = NULL; - - if (fun->isIntrinsic()) - { - Intrinsic::ID intrinsic_id = (Intrinsic::ID)fun->getIntrinsicID(); - - switch (intrinsic_id) - { - default: - if (log) - log->Printf("Unresolved intrinsic \"%s\"", Intrinsic::getName(intrinsic_id).c_str()); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Call to unhandled compiler intrinsic '%s'\n", Intrinsic::getName(intrinsic_id).c_str()); - - return LookupResult::Fail; - case Intrinsic::memcpy: - { - static lldb_private::ConstString g_memcpy_str ("memcpy"); - name = g_memcpy_str; - } - break; - case Intrinsic::memset: - { - static lldb_private::ConstString g_memset_str ("memset"); - name = g_memset_str; - } - break; - case Intrinsic::dbg_declare: - case Intrinsic::dbg_value: - return LookupResult::Ignore; - } - - if (log && name) - log->Printf("Resolved intrinsic name \"%s\"", name.GetCString()); - } - else - { - name.SetCStringWithLength (fun->getName().data(), fun->getName().size()); - } - - // Find the address of the function. - - clang::NamedDecl *fun_decl = DeclForGlobal (fun); - - if (fun_decl) - { - if (!m_decl_map->GetFunctionInfo (fun_decl, fun_addr)) - { - std::vector<lldb_private::ConstString> alternates; - bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr); - if (!found_it) - { - if (log) - log->Printf("Address of function \"%s\" not found.\n", name.GetCString()); - // Check for an alternate mangling for names from the standard library. - // For example, "std::basic_string<...>" has an alternate mangling scheme per - // the Itanium C++ ABI. - lldb::ProcessSP process_sp = m_data_allocator.GetTarget()->GetProcessSP(); - if (process_sp) - { - lldb_private::CPPLanguageRuntime *cpp_runtime = process_sp->GetCPPLanguageRuntime(); - if (cpp_runtime && cpp_runtime->GetAlternateManglings(name, alternates)) - { - for (size_t i = 0; i < alternates.size(); ++i) - { - const lldb_private::ConstString &alternate_name = alternates[i]; - if (log) - log->Printf("Looking up address of function \"%s\" with alternate name \"%s\"", - name.GetCString(), alternate_name.GetCString()); - if ((found_it = m_decl_map->GetFunctionAddress (alternate_name, fun_addr))) - { - if (log) - log->Printf("Found address of function \"%s\" with alternate name \"%s\"", - name.GetCString(), alternate_name.GetCString()); - break; - } - } - } - } - } - - if (!found_it) - { - lldb_private::Mangled mangled_name(name); - if (m_error_stream) - { - if (mangled_name.GetMangledName()) - m_error_stream->Printf("error: call to a function '%s' ('%s') that is not present in the target\n", - mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString(), - mangled_name.GetMangledName().GetCString()); - else - m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n", - mangled_name.GetName(lldb::eLanguageTypeObjC_plus_plus).GetCString()); - } - return LookupResult::Fail; - } - } - } - else - { - if (!m_decl_map->GetFunctionAddress (name, fun_addr)) - { - if (log) - log->Printf ("Metadataless function \"%s\" had no address", name.GetCString()); - - if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Call to a symbol-only function '%s' that is not present in the target\n", name.GetCString()); - - return LookupResult::Fail; - } - } - - if (log) - log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), fun_addr); - - return LookupResult::Success; -} - -llvm::Constant * -IRForTarget::BuildFunctionPointer (llvm::Type *type, - uint64_t ptr) -{ - PointerType *fun_ptr_ty = PointerType::getUnqual(type); - Constant *fun_addr_int = ConstantInt::get(m_intptr_ty, ptr, false); - return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty); -} - -void -IRForTarget::RegisterFunctionMetadata(LLVMContext &context, - llvm::Value *function_ptr, - const char *name) -{ - for (llvm::User *user : function_ptr->users()) - { - if (Instruction *user_inst = dyn_cast<Instruction>(user)) - { - MDString* md_name = MDString::get(context, StringRef(name)); - - MDNode *metadata = MDNode::get(context, md_name); - - user_inst->setMetadata("lldb.call.realName", metadata); - } - else - { - RegisterFunctionMetadata (context, user, name); - } - } -} - -bool -IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - for (llvm::Module::iterator fi = llvm_module.begin(); - fi != llvm_module.end(); - ++fi) - { - Function *fun = fi; - - bool is_decl = fun->isDeclaration(); - - if (log) - log->Printf("Examining %s function %s", (is_decl ? "declaration" : "non-declaration"), fun->getName().str().c_str()); - - if (!is_decl) - continue; - - if (fun->use_empty()) - continue; // ignore - - uint64_t addr = LLDB_INVALID_ADDRESS; - lldb_private::ConstString name; - Constant **value_ptr = NULL; - - LookupResult result = GetFunctionAddress(fun, - addr, - name, - value_ptr); - - switch (result) - { - case LookupResult::Fail: - return false; // GetFunctionAddress reports its own errors - - case LookupResult::Ignore: - break; // Nothing to do - - case LookupResult::Success: - { - Constant *value = BuildFunctionPointer(fun->getFunctionType(), addr); - - RegisterFunctionMetadata (llvm_module.getContext(), fun, name.AsCString()); - - if (value_ptr) - *value_ptr = value; - - // If we are replacing a function with the nobuiltin attribute, it may - // be called with the builtin attribute on call sites. Remove any such - // attributes since it's illegal to have a builtin call to something - // other than a nobuiltin function. - if (fun->hasFnAttribute(llvm::Attribute::NoBuiltin)) { - llvm::Attribute builtin = llvm::Attribute::get(fun->getContext(), llvm::Attribute::Builtin); - - for (auto u : fun->users()) { - if (auto call = dyn_cast<CallInst>(u)) { - call->removeAttribute(AttributeSet::FunctionIndex, builtin); - } - } - } - - fun->replaceAllUsesWith(value); - } - break; - } - } - - return true; -} - - -clang::NamedDecl * -IRForTarget::DeclForGlobal (const GlobalValue *global_val, Module *module) -{ - NamedMDNode *named_metadata = module->getNamedMetadata("clang.global.decl.ptrs"); - - if (!named_metadata) - return NULL; - - unsigned num_nodes = named_metadata->getNumOperands(); - unsigned node_index; - - for (node_index = 0; - node_index < num_nodes; - ++node_index) - { - llvm::MDNode *metadata_node = dyn_cast<llvm::MDNode>(named_metadata->getOperand(node_index)); - if (!metadata_node) - return NULL; - - if (metadata_node->getNumOperands() != 2) - continue; - - if (mdconst::dyn_extract_or_null<GlobalValue>(metadata_node->getOperand(0)) != global_val) - continue; - - ConstantInt *constant_int = mdconst::dyn_extract<ConstantInt>(metadata_node->getOperand(1)); - - if (!constant_int) - return NULL; - - uintptr_t ptr = constant_int->getZExtValue(); - - return reinterpret_cast<clang::NamedDecl *>(ptr); - } - - return NULL; -} - -clang::NamedDecl * -IRForTarget::DeclForGlobal (GlobalValue *global_val) -{ - return DeclForGlobal(global_val, m_module); -} - -bool -IRForTarget::CreateResultVariable (llvm::Function &llvm_function) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (!m_resolve_vars) - return true; - - // Find the result variable. If it doesn't exist, we can give up right here. - - ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable(); - - std::string result_name_str; - const char *result_name = NULL; - - for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end(); - vi != ve; - ++vi) - { - result_name_str = vi->first().str(); - const char *value_name = result_name_str.c_str(); - - if (strstr(value_name, "$__lldb_expr_result_ptr") && - strncmp(value_name, "_ZGV", 4)) - { - result_name = value_name; - m_result_is_pointer = true; - break; - } - - if (strstr(value_name, "$__lldb_expr_result") && - strncmp(value_name, "_ZGV", 4)) - { - result_name = value_name; - m_result_is_pointer = false; - break; - } - } - - if (!result_name) - { - if (log) - log->PutCString("Couldn't find result variable"); - - return true; - } - - if (log) - log->Printf("Result name: \"%s\"", result_name); - - Value *result_value = m_module->getNamedValue(result_name); - - if (!result_value) - { - if (log) - log->PutCString("Result variable had no data"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Result variable's name (%s) exists, but not its definition\n", result_name); - - return false; - } - - if (log) - log->Printf("Found result in the IR: \"%s\"", PrintValue(result_value, false).c_str()); - - GlobalVariable *result_global = dyn_cast<GlobalVariable>(result_value); - - if (!result_global) - { - if (log) - log->PutCString("Result variable isn't a GlobalVariable"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) is defined, but is not a global variable\n", result_name); - - return false; - } - - clang::NamedDecl *result_decl = DeclForGlobal (result_global); - if (!result_decl) - { - if (log) - log->PutCString("Result variable doesn't have a corresponding Decl"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) does not have a corresponding Clang entity\n", result_name); - - return false; - } - - if (log) - { - std::string decl_desc_str; - raw_string_ostream decl_desc_stream(decl_desc_str); - result_decl->print(decl_desc_stream); - decl_desc_stream.flush(); - - log->Printf("Found result decl: \"%s\"", decl_desc_str.c_str()); - } - - clang::VarDecl *result_var = dyn_cast<clang::VarDecl>(result_decl); - if (!result_var) - { - if (log) - log->PutCString("Result variable Decl isn't a VarDecl"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s)'s corresponding Clang entity isn't a variable\n", result_name); - - return false; - } - - // Get the next available result name from m_decl_map and create the persistent - // variable for it - - // If the result is an Lvalue, it is emitted as a pointer; see - // ASTResultSynthesizer::SynthesizeBodyResult. - if (m_result_is_pointer) - { - clang::QualType pointer_qual_type = result_var->getType(); - const clang::Type *pointer_type = pointer_qual_type.getTypePtr(); - - const clang::PointerType *pointer_pointertype = pointer_type->getAs<clang::PointerType>(); - const clang::ObjCObjectPointerType *pointer_objcobjpointertype = pointer_type->getAs<clang::ObjCObjectPointerType>(); - - if (pointer_pointertype) - { - clang::QualType element_qual_type = pointer_pointertype->getPointeeType(); - - m_result_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(), - &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()); - } - - - lldb::TargetSP target_sp (m_data_allocator.GetTarget()); - lldb_private::ExecutionContext exe_ctx (target_sp, true); - if (m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()) == 0) - { - lldb_private::StreamString type_desc_stream; - m_result_type.DumpTypeDescription(&type_desc_stream); - - if (log) - log->Printf("Result type has size 0"); - - if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Size of result type '%s' couldn't be determined\n", - type_desc_stream.GetData()); - return false; - } - - if (log) - { - lldb_private::StreamString type_desc_stream; - m_result_type.DumpTypeDescription(&type_desc_stream); - - log->Printf("Result decl type: \"%s\"", type_desc_stream.GetData()); - } - - m_result_name = lldb_private::ConstString("$RESULT_NAME"); - - if (log) - log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64, - m_result_name.GetCString(), - m_result_type.GetByteSize(nullptr)); - - // Construct a new result global and set up its metadata - - GlobalVariable *new_result_global = new GlobalVariable((*m_module), - result_global->getType()->getElementType(), - false, /* not constant */ - GlobalValue::ExternalLinkage, - NULL, /* no initializer */ - m_result_name.GetCString ()); - - // It's too late in compilation to create a new VarDecl for this, but we don't - // need to. We point the metadata at the old VarDecl. This creates an odd - // anomaly: a variable with a Value whose name is something like $0 and a - // Decl whose name is $__lldb_expr_result. This condition is handled in - // ClangExpressionDeclMap::DoMaterialize, and the name of the variable is - // fixed up. - - ConstantInt *new_constant_int = ConstantInt::get(llvm::Type::getInt64Ty(m_module->getContext()), - reinterpret_cast<uint64_t>(result_decl), - false); - - llvm::Metadata *values[2]; - values[0] = ConstantAsMetadata::get(new_result_global); - values[1] = ConstantAsMetadata::get(new_constant_int); - - ArrayRef<Metadata *> value_ref(values, 2); - - MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref); - NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs"); - named_metadata->addOperand(persistent_global_md); - - if (log) - log->Printf("Replacing \"%s\" with \"%s\"", - PrintValue(result_global).c_str(), - PrintValue(new_result_global).c_str()); - - if (result_global->use_empty()) - { - // We need to synthesize a store for this variable, because otherwise - // there's nothing to put into its equivalent persistent variable. - - BasicBlock &entry_block(llvm_function.getEntryBlock()); - Instruction *first_entry_instruction(entry_block.getFirstNonPHIOrDbg()); - - if (!first_entry_instruction) - return false; - - if (!result_global->hasInitializer()) - { - if (log) - log->Printf("Couldn't find initializer for unused variable"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) has no writes and no initializer\n", result_name); - - return false; - } - - Constant *initializer = result_global->getInitializer(); - - StoreInst *synthesized_store = new StoreInst(initializer, - new_result_global, - first_entry_instruction); - - if (log) - log->Printf("Synthesized result store \"%s\"\n", PrintValue(synthesized_store).c_str()); - } - else - { - result_global->replaceAllUsesWith(new_result_global); - } - - if (!m_decl_map->AddPersistentVariable(result_decl, - m_result_name, - m_result_type, - true, - m_result_is_pointer)) - return false; - - result_global->eraseFromParent(); - - return true; -} - -bool -IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str, - llvm::GlobalVariable *cstr) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - Type *ns_str_ty = ns_str->getType(); - - Type *i8_ptr_ty = Type::getInt8PtrTy(m_module->getContext()); - Type *i32_ty = Type::getInt32Ty(m_module->getContext()); - Type *i8_ty = Type::getInt8Ty(m_module->getContext()); - - if (!m_CFStringCreateWithBytes) - { - lldb::addr_t CFStringCreateWithBytes_addr; - - static lldb_private::ConstString g_CFStringCreateWithBytes_str ("CFStringCreateWithBytes"); - - if (!m_decl_map->GetFunctionAddress (g_CFStringCreateWithBytes_str, CFStringCreateWithBytes_addr)) - { - if (log) - log->PutCString("Couldn't find CFStringCreateWithBytes in the target"); - - if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Rewriting an Objective-C constant string requires CFStringCreateWithBytes\n"); - - return false; - } - - if (log) - log->Printf("Found CFStringCreateWithBytes at 0x%" PRIx64, CFStringCreateWithBytes_addr); - - // Build the function type: - // - // CFStringRef CFStringCreateWithBytes ( - // CFAllocatorRef alloc, - // const UInt8 *bytes, - // CFIndex numBytes, - // CFStringEncoding encoding, - // Boolean isExternalRepresentation - // ); - // - // We make the following substitutions: - // - // CFStringRef -> i8* - // CFAllocatorRef -> i8* - // UInt8 * -> i8* - // CFIndex -> long (i32 or i64, as appropriate; we ask the module for its pointer size for now) - // CFStringEncoding -> i32 - // Boolean -> i8 - - Type *arg_type_array[5]; - - arg_type_array[0] = i8_ptr_ty; - arg_type_array[1] = i8_ptr_ty; - arg_type_array[2] = m_intptr_ty; - arg_type_array[3] = i32_ty; - arg_type_array[4] = i8_ty; - - ArrayRef<Type *> CFSCWB_arg_types(arg_type_array, 5); - - llvm::Type *CFSCWB_ty = FunctionType::get(ns_str_ty, CFSCWB_arg_types, false); - - // Build the constant containing the pointer to the function - PointerType *CFSCWB_ptr_ty = PointerType::getUnqual(CFSCWB_ty); - Constant *CFSCWB_addr_int = ConstantInt::get(m_intptr_ty, CFStringCreateWithBytes_addr, false); - m_CFStringCreateWithBytes = ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty); - } - - ConstantDataSequential *string_array = NULL; - - if (cstr) - string_array = dyn_cast<ConstantDataSequential>(cstr->getInitializer()); - - Constant *alloc_arg = Constant::getNullValue(i8_ptr_ty); - Constant *bytes_arg = cstr ? ConstantExpr::getBitCast(cstr, i8_ptr_ty) : Constant::getNullValue(i8_ptr_ty); - Constant *numBytes_arg = ConstantInt::get(m_intptr_ty, cstr ? string_array->getNumElements() - 1 : 0, false); - Constant *encoding_arg = ConstantInt::get(i32_ty, 0x0600, false); /* 0x0600 is kCFStringEncodingASCII */ - Constant *isExternal_arg = ConstantInt::get(i8_ty, 0x0, false); /* 0x0 is false */ - - Value *argument_array[5]; - - argument_array[0] = alloc_arg; - argument_array[1] = bytes_arg; - argument_array[2] = numBytes_arg; - argument_array[3] = encoding_arg; - argument_array[4] = isExternal_arg; - - ArrayRef <Value *> CFSCWB_arguments(argument_array, 5); - - FunctionValueCache CFSCWB_Caller ([this, &CFSCWB_arguments] (llvm::Function *function)->llvm::Value * { - return CallInst::Create(m_CFStringCreateWithBytes, - CFSCWB_arguments, - "CFStringCreateWithBytes", - llvm::cast<Instruction>(m_entry_instruction_finder.GetValue(function))); - }); - - if (!UnfoldConstant(ns_str, CFSCWB_Caller, m_entry_instruction_finder)) - { - if (log) - log->PutCString("Couldn't replace the NSString with the result of the call"); - - if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Couldn't replace an Objective-C constant string with a dynamic string\n"); - - return false; - } - - ns_str->eraseFromParent(); - - return true; -} - -bool -IRForTarget::RewriteObjCConstStrings() -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable(); - - for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end(); - vi != ve; - ++vi) - { - std::string value_name = vi->first().str(); - const char *value_name_cstr = value_name.c_str(); - - if (strstr(value_name_cstr, "_unnamed_cfstring_")) - { - Value *nsstring_value = vi->second; - - GlobalVariable *nsstring_global = dyn_cast<GlobalVariable>(nsstring_value); - - if (!nsstring_global) - { - if (log) - log->PutCString("NSString variable is not a GlobalVariable"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string is not a global variable\n"); - - return false; - } - - if (!nsstring_global->hasInitializer()) - { - if (log) - log->PutCString("NSString variable does not have an initializer"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string does not have an initializer\n"); - - return false; - } - - ConstantStruct *nsstring_struct = dyn_cast<ConstantStruct>(nsstring_global->getInitializer()); - - if (!nsstring_struct) - { - if (log) - log->PutCString("NSString variable's initializer is not a ConstantStruct"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string is not a structure constant\n"); - - return false; - } - - // We expect the following structure: - // - // struct { - // int *isa; - // int flags; - // char *str; - // long length; - // }; - - if (nsstring_struct->getNumOperands() != 4) - { - if (log) - log->Printf("NSString variable's initializer structure has an unexpected number of members. Should be 4, is %d", nsstring_struct->getNumOperands()); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: The struct for an Objective-C constant string is not as expected\n"); - - return false; - } - - Constant *nsstring_member = nsstring_struct->getOperand(2); - - if (!nsstring_member) - { - if (log) - log->PutCString("NSString initializer's str element was empty"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string does not have a string initializer\n"); - - return false; - } - - ConstantExpr *nsstring_expr = dyn_cast<ConstantExpr>(nsstring_member); - - if (!nsstring_expr) - { - if (log) - log->PutCString("NSString initializer's str element is not a ConstantExpr"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer is not constant\n"); - - return false; - } - - if (nsstring_expr->getOpcode() != Instruction::GetElementPtr) - { - if (log) - log->Printf("NSString initializer's str element is not a GetElementPtr expression, it's a %s", nsstring_expr->getOpcodeName()); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer is not an array\n"); - - return false; - } - - Constant *nsstring_cstr = nsstring_expr->getOperand(0); - - GlobalVariable *cstr_global = dyn_cast<GlobalVariable>(nsstring_cstr); - - if (!cstr_global) - { - if (log) - log->PutCString("NSString initializer's str element is not a GlobalVariable"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to a global\n"); - - return false; - } - - if (!cstr_global->hasInitializer()) - { - if (log) - log->PutCString("NSString initializer's str element does not have an initializer"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to initialized data\n"); - - return false; - } - - /* - if (!cstr_array) - { - if (log) - log->PutCString("NSString initializer's str element is not a ConstantArray"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to an array\n"); - - return false; - } - - if (!cstr_array->isCString()) - { - if (log) - log->PutCString("NSString initializer's str element is not a C string array"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to a C string\n"); - - return false; - } - */ - - ConstantDataArray *cstr_array = dyn_cast<ConstantDataArray>(cstr_global->getInitializer()); - - if (log) - { - if (cstr_array) - log->Printf("Found NSString constant %s, which contains \"%s\"", value_name_cstr, cstr_array->getAsString().str().c_str()); - else - log->Printf("Found NSString constant %s, which contains \"\"", value_name_cstr); - } - - if (!cstr_array) - cstr_global = NULL; - - if (!RewriteObjCConstString(nsstring_global, cstr_global)) - { - if (log) - log->PutCString("Error rewriting the constant string"); - - // We don't print an error message here because RewriteObjCConstString has done so for us. - - return false; - } - } - } - - for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end(); - vi != ve; - ++vi) - { - std::string value_name = vi->first().str(); - const char *value_name_cstr = value_name.c_str(); - - if (!strcmp(value_name_cstr, "__CFConstantStringClassReference")) - { - GlobalVariable *gv = dyn_cast<GlobalVariable>(vi->second); - - if (!gv) - { - if (log) - log->PutCString("__CFConstantStringClassReference is not a global variable"); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Found a CFConstantStringClassReference, but it is not a global object\n"); - - return false; - } - - gv->eraseFromParent(); - - break; - } - } - - return true; -} - -static bool IsObjCSelectorRef (Value *value) -{ - GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value); - - if (!global_variable || !global_variable->hasName() || !global_variable->getName().startswith("OBJC_SELECTOR_REFERENCES_")) - return false; - - return true; -} - -// This function does not report errors; its callers are responsible. -bool -IRForTarget::RewriteObjCSelector (Instruction* selector_load) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - LoadInst *load = dyn_cast<LoadInst>(selector_load); - - if (!load) - return false; - - // Unpack the message name from the selector. In LLVM IR, an objc_msgSend gets represented as - // - // %tmp = load i8** @"OBJC_SELECTOR_REFERENCES_" ; <i8*> - // %call = call i8* (i8*, i8*, ...)* @objc_msgSend(i8* %obj, i8* %tmp, ...) ; <i8*> - // - // where %obj is the object pointer and %tmp is the selector. - // - // @"OBJC_SELECTOR_REFERENCES_" is a pointer to a character array called @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_". - // @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_" contains the string. - - // Find the pointer's initializer (a ConstantExpr with opcode GetElementPtr) and get the string from its target - - GlobalVariable *_objc_selector_references_ = dyn_cast<GlobalVariable>(load->getPointerOperand()); - - if (!_objc_selector_references_ || !_objc_selector_references_->hasInitializer()) - return false; - - Constant *osr_initializer = _objc_selector_references_->getInitializer(); - - ConstantExpr *osr_initializer_expr = dyn_cast<ConstantExpr>(osr_initializer); - - if (!osr_initializer_expr || osr_initializer_expr->getOpcode() != Instruction::GetElementPtr) - return false; - - Value *osr_initializer_base = osr_initializer_expr->getOperand(0); - - if (!osr_initializer_base) - return false; - - // Find the string's initializer (a ConstantArray) and get the string from it - - GlobalVariable *_objc_meth_var_name_ = dyn_cast<GlobalVariable>(osr_initializer_base); - - if (!_objc_meth_var_name_ || !_objc_meth_var_name_->hasInitializer()) - return false; - - Constant *omvn_initializer = _objc_meth_var_name_->getInitializer(); - - ConstantDataArray *omvn_initializer_array = dyn_cast<ConstantDataArray>(omvn_initializer); - - if (!omvn_initializer_array->isString()) - return false; - - std::string omvn_initializer_string = omvn_initializer_array->getAsString(); - - if (log) - log->Printf("Found Objective-C selector reference \"%s\"", omvn_initializer_string.c_str()); - - // Construct a call to sel_registerName - - if (!m_sel_registerName) - { - lldb::addr_t sel_registerName_addr; - - static lldb_private::ConstString g_sel_registerName_str ("sel_registerName"); - if (!m_decl_map->GetFunctionAddress (g_sel_registerName_str, sel_registerName_addr)) - return false; - - if (log) - log->Printf("Found sel_registerName at 0x%" PRIx64, sel_registerName_addr); - - // Build the function type: struct objc_selector *sel_registerName(uint8_t*) - - // The below code would be "more correct," but in actuality what's required is uint8_t* - //Type *sel_type = StructType::get(m_module->getContext()); - //Type *sel_ptr_type = PointerType::getUnqual(sel_type); - Type *sel_ptr_type = Type::getInt8PtrTy(m_module->getContext()); - - Type *type_array[1]; - - type_array[0] = llvm::Type::getInt8PtrTy(m_module->getContext()); - - ArrayRef<Type *> srN_arg_types(type_array, 1); - - llvm::Type *srN_type = FunctionType::get(sel_ptr_type, srN_arg_types, false); - - // Build the constant containing the pointer to the function - PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type); - Constant *srN_addr_int = ConstantInt::get(m_intptr_ty, sel_registerName_addr, false); - m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty); - } - - Value *argument_array[1]; - - Constant *omvn_pointer = ConstantExpr::getBitCast(_objc_meth_var_name_, Type::getInt8PtrTy(m_module->getContext())); - - argument_array[0] = omvn_pointer; - - ArrayRef<Value *> srN_arguments(argument_array, 1); - - CallInst *srN_call = CallInst::Create(m_sel_registerName, - srN_arguments, - "sel_registerName", - selector_load); - - // Replace the load with the call in all users - - selector_load->replaceAllUsesWith(srN_call); - - selector_load->eraseFromParent(); - - return true; -} - -bool -IRForTarget::RewriteObjCSelectors (BasicBlock &basic_block) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - BasicBlock::iterator ii; - - typedef SmallVector <Instruction*, 2> InstrList; - typedef InstrList::iterator InstrIterator; - - InstrList selector_loads; - - for (ii = basic_block.begin(); - ii != basic_block.end(); - ++ii) - { - Instruction &inst = *ii; - - if (LoadInst *load = dyn_cast<LoadInst>(&inst)) - if (IsObjCSelectorRef(load->getPointerOperand())) - selector_loads.push_back(&inst); - } - - InstrIterator iter; - - for (iter = selector_loads.begin(); - iter != selector_loads.end(); - ++iter) - { - if (!RewriteObjCSelector(*iter)) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't change a static reference to an Objective-C selector to a dynamic reference\n"); - - if (log) - log->PutCString("Couldn't rewrite a reference to an Objective-C selector"); - - return false; - } - } - - return true; -} - -// This function does not report errors; its callers are responsible. -bool -IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - AllocaInst *alloc = dyn_cast<AllocaInst>(persistent_alloc); - - MDNode *alloc_md = alloc->getMetadata("clang.decl.ptr"); - - if (!alloc_md || !alloc_md->getNumOperands()) - return false; - - ConstantInt *constant_int = mdconst::dyn_extract<ConstantInt>(alloc_md->getOperand(0)); - - if (!constant_int) - return false; - - // We attempt to register this as a new persistent variable with the DeclMap. - - uintptr_t ptr = constant_int->getZExtValue(); - - clang::VarDecl *decl = reinterpret_cast<clang::VarDecl *>(ptr); - - lldb_private::TypeFromParser result_decl_type (decl->getType().getAsOpaquePtr(), - &decl->getASTContext()); - - StringRef decl_name (decl->getName()); - lldb_private::ConstString persistent_variable_name (decl_name.data(), decl_name.size()); - if (!m_decl_map->AddPersistentVariable(decl, persistent_variable_name, result_decl_type, false, false)) - return false; - - GlobalVariable *persistent_global = new GlobalVariable((*m_module), - alloc->getType(), - false, /* not constant */ - GlobalValue::ExternalLinkage, - NULL, /* no initializer */ - alloc->getName().str().c_str()); - - // What we're going to do here is make believe this was a regular old external - // variable. That means we need to make the metadata valid. - - NamedMDNode *named_metadata = m_module->getOrInsertNamedMetadata("clang.global.decl.ptrs"); - - llvm::Metadata *values[2]; - values[0] = ConstantAsMetadata::get(persistent_global); - values[1] = ConstantAsMetadata::get(constant_int); - - ArrayRef<llvm::Metadata *> value_ref(values, 2); - - MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref); - named_metadata->addOperand(persistent_global_md); - - // Now, since the variable is a pointer variable, we will drop in a load of that - // pointer variable. - - LoadInst *persistent_load = new LoadInst (persistent_global, "", alloc); - - if (log) - log->Printf("Replacing \"%s\" with \"%s\"", - PrintValue(alloc).c_str(), - PrintValue(persistent_load).c_str()); - - alloc->replaceAllUsesWith(persistent_load); - alloc->eraseFromParent(); - - return true; -} - -bool -IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block) -{ - if (!m_resolve_vars) - return true; - - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - BasicBlock::iterator ii; - - typedef SmallVector <Instruction*, 2> InstrList; - typedef InstrList::iterator InstrIterator; - - InstrList pvar_allocs; - - for (ii = basic_block.begin(); - ii != basic_block.end(); - ++ii) - { - Instruction &inst = *ii; - - if (AllocaInst *alloc = dyn_cast<AllocaInst>(&inst)) - { - llvm::StringRef alloc_name = alloc->getName(); - - if (alloc_name.startswith("$") && - !alloc_name.startswith("$__lldb")) - { - if (alloc_name.find_first_of("0123456789") == 1) - { - if (log) - log->Printf("Rejecting a numeric persistent variable."); - - if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Names starting with $0, $1, ... are reserved for use as result names\n"); - - return false; - } - - pvar_allocs.push_back(alloc); - } - } - } - - InstrIterator iter; - - for (iter = pvar_allocs.begin(); - iter != pvar_allocs.end(); - ++iter) - { - if (!RewritePersistentAlloc(*iter)) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite the creation of a persistent variable\n"); - - if (log) - log->PutCString("Couldn't rewrite the creation of a persistent variable"); - - return false; - } - } - - return true; -} - -bool -IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer) -{ - if (!initializer) - return true; - - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log && log->GetVerbose()) - log->Printf(" MaterializeInitializer(%p, %s)", (void *)data, PrintValue(initializer).c_str()); - - Type *initializer_type = initializer->getType(); - - if (ConstantInt *int_initializer = dyn_cast<ConstantInt>(initializer)) - { - memcpy (data, int_initializer->getValue().getRawData(), m_target_data->getTypeStoreSize(initializer_type)); - return true; - } - else if (ConstantDataArray *array_initializer = dyn_cast<ConstantDataArray>(initializer)) - { - if (array_initializer->isString()) - { - std::string array_initializer_string = array_initializer->getAsString(); - memcpy (data, array_initializer_string.c_str(), m_target_data->getTypeStoreSize(initializer_type)); - } - else - { - ArrayType *array_initializer_type = array_initializer->getType(); - Type *array_element_type = array_initializer_type->getElementType(); - - size_t element_size = m_target_data->getTypeAllocSize(array_element_type); - - for (unsigned i = 0; i < array_initializer->getNumOperands(); ++i) - { - Value *operand_value = array_initializer->getOperand(i); - Constant *operand_constant = dyn_cast<Constant>(operand_value); - - if (!operand_constant) - return false; - - if (!MaterializeInitializer(data + (i * element_size), operand_constant)) - return false; - } - } - return true; - } - else if (ConstantStruct *struct_initializer = dyn_cast<ConstantStruct>(initializer)) - { - StructType *struct_initializer_type = struct_initializer->getType(); - const StructLayout *struct_layout = m_target_data->getStructLayout(struct_initializer_type); - - for (unsigned i = 0; - i < struct_initializer->getNumOperands(); - ++i) - { - if (!MaterializeInitializer(data + struct_layout->getElementOffset(i), struct_initializer->getOperand(i))) - return false; - } - return true; - } - else if (isa<ConstantAggregateZero>(initializer)) - { - memset(data, 0, m_target_data->getTypeStoreSize(initializer_type)); - return true; - } - return false; -} - -bool -IRForTarget::MaterializeInternalVariable (GlobalVariable *global_variable) -{ - if (GlobalVariable::isExternalLinkage(global_variable->getLinkage())) - return false; - - if (global_variable == m_reloc_placeholder) - return true; - - uint64_t offset = m_data_allocator.GetStream().GetSize(); - - llvm::Type *variable_type = global_variable->getType(); - - Constant *initializer = global_variable->getInitializer(); - - llvm::Type *initializer_type = initializer->getType(); - - size_t size = m_target_data->getTypeAllocSize(initializer_type); - size_t align = m_target_data->getPrefTypeAlignment(initializer_type); - - const size_t mask = (align - 1); - uint64_t aligned_offset = (offset + mask) & ~mask; - m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0); - offset = aligned_offset; - - lldb_private::DataBufferHeap data(size, '\0'); - - if (initializer) - if (!MaterializeInitializer(data.GetBytes(), initializer)) - return false; - - m_data_allocator.GetStream().Write(data.GetBytes(), data.GetByteSize()); - - Constant *new_pointer = BuildRelocation(variable_type, offset); - - global_variable->replaceAllUsesWith(new_pointer); - - global_variable->eraseFromParent(); - - return true; -} - -// This function does not report errors; its callers are responsible. -bool -IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - log->Printf("MaybeHandleVariable (%s)", PrintValue(llvm_value_ptr).c_str()); - - if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(llvm_value_ptr)) - { - switch (constant_expr->getOpcode()) - { - default: - break; - case Instruction::GetElementPtr: - case Instruction::BitCast: - Value *s = constant_expr->getOperand(0); - if (!MaybeHandleVariable(s)) - return false; - } - } - else if (GlobalVariable *global_variable = dyn_cast<GlobalVariable>(llvm_value_ptr)) - { - if (!GlobalValue::isExternalLinkage(global_variable->getLinkage())) - return MaterializeInternalVariable(global_variable); - - clang::NamedDecl *named_decl = DeclForGlobal(global_variable); - - if (!named_decl) - { - if (IsObjCSelectorRef(llvm_value_ptr)) - return true; - - if (!global_variable->hasExternalLinkage()) - return true; - - if (log) - log->Printf("Found global variable \"%s\" without metadata", global_variable->getName().str().c_str()); - - return false; - } - - std::string name (named_decl->getName().str()); - - clang::ValueDecl *value_decl = dyn_cast<clang::ValueDecl>(named_decl); - if (value_decl == NULL) - return false; - - lldb_private::ClangASTType clang_type(&value_decl->getASTContext(), value_decl->getType()); - - const Type *value_type = NULL; - - if (name[0] == '$') - { - // The $__lldb_expr_result name indicates the return value has allocated as - // a static variable. Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, - // accesses to this static variable need to be redirected to the result of dereferencing - // a pointer that is passed in as one of the arguments. - // - // Consequently, when reporting the size of the type, we report a pointer type pointing - // to the type of $__lldb_expr_result, not the type itself. - // - // We also do this for any user-declared persistent variables. - 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(nullptr); - lldb::offset_t value_alignment = (clang_type.GetTypeBitAlign() + 7ull) / 8ull; - - if (log) - { - log->Printf("Type of \"%s\" is [clang \"%s\", llvm \"%s\"] [size %" PRIu64 ", align %" PRIu64 "]", - 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(); - - Constant *symbol_addr_int = ConstantInt::get(m_intptr_ty, symbol_addr, false); - - Value *symbol_addr_ptr = ConstantExpr::getIntToPtr(symbol_addr_int, symbol_type); - - if (log) - log->Printf("Replacing %s with %s", PrintValue(symbol).c_str(), PrintValue(symbol_addr_ptr).c_str()); - - symbol->replaceAllUsesWith(symbol_addr_ptr); - - return true; -} - -bool -IRForTarget::MaybeHandleCallArguments (CallInst *Old) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - log->Printf("MaybeHandleCallArguments(%s)", PrintValue(Old).c_str()); - - for (unsigned op_index = 0, num_ops = Old->getNumArgOperands(); - op_index < num_ops; - ++op_index) - if (!MaybeHandleVariable(Old->getArgOperand(op_index))) // conservatively believe that this is a store - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite one of the arguments of a function call.\n"); - - return false; - } - - return true; -} - -bool -IRForTarget::HandleObjCClass(Value *classlist_reference) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - GlobalVariable *global_variable = dyn_cast<GlobalVariable>(classlist_reference); - - if (!global_variable) - return false; - - Constant *initializer = global_variable->getInitializer(); - - if (!initializer) - return false; - - if (!initializer->hasName()) - return false; - - StringRef name(initializer->getName()); - lldb_private::ConstString name_cstr(name.str().c_str()); - lldb::addr_t class_ptr = m_decl_map->GetSymbolAddress(name_cstr, lldb::eSymbolTypeObjCClass); - - if (log) - log->Printf("Found reference to Objective-C class %s (0x%llx)", name_cstr.AsCString(), (unsigned long long)class_ptr); - - if (class_ptr == LLDB_INVALID_ADDRESS) - return false; - - if (global_variable->use_empty()) - return false; - - SmallVector<LoadInst *, 2> load_instructions; - - for (llvm::User *u : global_variable->users()) - { - if (LoadInst *load_instruction = dyn_cast<LoadInst>(u)) - load_instructions.push_back(load_instruction); - } - - if (load_instructions.empty()) - return false; - - Constant *class_addr = ConstantInt::get(m_intptr_ty, (uint64_t)class_ptr); - - for (LoadInst *load_instruction : load_instructions) - { - Constant *class_bitcast = ConstantExpr::getIntToPtr(class_addr, load_instruction->getType()); - - load_instruction->replaceAllUsesWith(class_bitcast); - - load_instruction->eraseFromParent(); - } - - return true; -} - -bool -IRForTarget::RemoveCXAAtExit (BasicBlock &basic_block) -{ - BasicBlock::iterator ii; - - std::vector<CallInst *> calls_to_remove; - - for (ii = basic_block.begin(); - ii != basic_block.end(); - ++ii) - { - Instruction &inst = *ii; - - CallInst *call = dyn_cast<CallInst>(&inst); - - // MaybeHandleCallArguments handles error reporting; we are silent here - if (!call) - continue; - - bool remove = false; - - llvm::Function *func = call->getCalledFunction(); - - if (func && func->getName() == "__cxa_atexit") - remove = true; - - llvm::Value *val = call->getCalledValue(); - - if (val && val->getName() == "__cxa_atexit") - remove = true; - - if (remove) - calls_to_remove.push_back(call); - } - - for (std::vector<CallInst *>::iterator ci = calls_to_remove.begin(), ce = calls_to_remove.end(); - ci != ce; - ++ci) - { - (*ci)->eraseFromParent(); - } - - return true; -} - -bool -IRForTarget::ResolveCalls(BasicBlock &basic_block) -{ - ///////////////////////////////////////////////////////////////////////// - // Prepare the current basic block for execution in the remote process - // - - BasicBlock::iterator ii; - - for (ii = basic_block.begin(); - ii != basic_block.end(); - ++ii) - { - Instruction &inst = *ii; - - CallInst *call = dyn_cast<CallInst>(&inst); - - // MaybeHandleCallArguments handles error reporting; we are silent here - if (call && !MaybeHandleCallArguments(call)) - return false; - } - - return true; -} - -bool -IRForTarget::ResolveExternals (Function &llvm_function) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - for (GlobalVariable &global_var : m_module->globals()) - { - std::string global_name = global_var.getName().str(); - - if (log) - log->Printf("Examining %s, DeclForGlobalValue returns %p", - global_name.c_str(), - static_cast<void*>(DeclForGlobal(&global_var))); - - if (global_name.find("OBJC_IVAR") == 0) - { - if (!HandleSymbol(&global_var)) - { - if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Couldn't find Objective-C indirect ivar symbol %s\n", global_name.c_str()); - - return false; - } - } - else if (global_name.find("OBJC_CLASSLIST_REFERENCES_$") != global_name.npos) - { - if (!HandleObjCClass(&global_var)) - { - if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Couldn't resolve the class for an Objective-C static method call\n"); - - return false; - } - } - else if (global_name.find("OBJC_CLASSLIST_SUP_REFS_$") != global_name.npos) - { - if (!HandleObjCClass(&global_var)) - { - if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Couldn't resolve the class for an Objective-C static method call\n"); - - return false; - } - } - else if (DeclForGlobal(&global_var)) - { - if (!MaybeHandleVariable (&global_var)) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite external variable %s\n", global_name.c_str()); - - return false; - } - } - } - - return true; -} - -bool -IRForTarget::ReplaceStrings () -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - typedef std::map <GlobalVariable *, size_t> OffsetsTy; - - OffsetsTy offsets; - - for (GlobalVariable &gv : m_module->globals()) - { - if (!gv.hasInitializer()) - continue; - - Constant *gc = gv.getInitializer(); - - std::string str; - - if (gc->isNullValue()) - { - Type *gc_type = gc->getType(); - - ArrayType *gc_array_type = dyn_cast<ArrayType>(gc_type); - - if (!gc_array_type) - continue; - - Type *gc_element_type = gc_array_type->getElementType(); - - IntegerType *gc_integer_type = dyn_cast<IntegerType>(gc_element_type); - - if (gc_integer_type->getBitWidth() != 8) - continue; - - str = ""; - } - else - { - ConstantDataArray *gc_array = dyn_cast<ConstantDataArray>(gc); - - if (!gc_array) - continue; - - if (!gc_array->isCString()) - continue; - - if (log) - log->Printf("Found a GlobalVariable with string initializer %s", PrintValue(gc).c_str()); - - str = gc_array->getAsString(); - } - - offsets[&gv] = m_data_allocator.GetStream().GetSize(); - - m_data_allocator.GetStream().Write(str.c_str(), str.length() + 1); - } - - Type *char_ptr_ty = Type::getInt8PtrTy(m_module->getContext()); - - for (OffsetsTy::iterator oi = offsets.begin(), oe = offsets.end(); - oi != oe; - ++oi) - { - GlobalVariable *gv = oi->first; - size_t offset = oi->second; - - Constant *new_initializer = BuildRelocation(char_ptr_ty, offset); - - if (log) - log->Printf("Replacing GV %s with %s", PrintValue(gv).c_str(), PrintValue(new_initializer).c_str()); - - for (llvm::User *u : gv->users()) - { - if (log) - log->Printf("Found use %s", PrintValue(u).c_str()); - - ConstantExpr *const_expr = dyn_cast<ConstantExpr>(u); - StoreInst *store_inst = dyn_cast<StoreInst>(u); - - if (const_expr) - { - if (const_expr->getOpcode() != Instruction::GetElementPtr) - { - if (log) - log->Printf("Use (%s) of string variable is not a GetElementPtr constant", PrintValue(const_expr).c_str()); - - return false; - } - - Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, const_expr->getOperand(0)->getType()); - Constant *new_gep = const_expr->getWithOperandReplaced(0, bit_cast); - - const_expr->replaceAllUsesWith(new_gep); - } - else if (store_inst) - { - Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, store_inst->getValueOperand()->getType()); - - store_inst->setOperand(0, bit_cast); - } - else - { - if (log) - log->Printf("Use (%s) of string variable is neither a constant nor a store", PrintValue(const_expr).c_str()); - - return false; - } - } - - gv->eraseFromParent(); - } - - return true; -} - -bool -IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - typedef SmallVector <Value*, 2> ConstantList; - typedef SmallVector <llvm::Instruction*, 2> UserList; - typedef ConstantList::iterator ConstantIterator; - typedef UserList::iterator UserIterator; - - ConstantList static_constants; - UserList static_users; - - for (BasicBlock::iterator ii = basic_block.begin(), ie = basic_block.end(); - ii != ie; - ++ii) - { - llvm::Instruction &inst = *ii; - - for (Value *operand_val : inst.operand_values()) - { - ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val); - - if (operand_constant_fp/* && operand_constant_fp->getType()->isX86_FP80Ty()*/) - { - static_constants.push_back(operand_val); - static_users.push_back(ii); - } - } - } - - ConstantIterator constant_iter; - UserIterator user_iter; - - for (constant_iter = static_constants.begin(), user_iter = static_users.begin(); - constant_iter != static_constants.end(); - ++constant_iter, ++user_iter) - { - Value *operand_val = *constant_iter; - llvm::Instruction *inst = *user_iter; - - ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val); - - if (operand_constant_fp) - { - Type *operand_type = operand_constant_fp->getType(); - - APFloat operand_apfloat = operand_constant_fp->getValueAPF(); - APInt operand_apint = operand_apfloat.bitcastToAPInt(); - - const uint8_t* operand_raw_data = (const uint8_t*)operand_apint.getRawData(); - size_t operand_data_size = operand_apint.getBitWidth() / 8; - - if (log) - { - std::string s; - raw_string_ostream ss(s); - for (size_t index = 0; - index < operand_data_size; - ++index) - { - ss << (uint32_t)operand_raw_data[index]; - ss << " "; - } - ss.flush(); - - log->Printf("Found ConstantFP with size %" PRIu64 " and raw data %s", (uint64_t)operand_data_size, s.c_str()); - } - - lldb_private::DataBufferHeap data(operand_data_size, 0); - - if (lldb::endian::InlHostByteOrder() != m_data_allocator.GetStream().GetByteOrder()) - { - uint8_t *data_bytes = data.GetBytes(); - - for (size_t index = 0; - index < operand_data_size; - ++index) - { - data_bytes[index] = operand_raw_data[operand_data_size - (1 + index)]; - } - } - else - { - memcpy(data.GetBytes(), operand_raw_data, operand_data_size); - } - - uint64_t offset = m_data_allocator.GetStream().GetSize(); - - size_t align = m_target_data->getPrefTypeAlignment(operand_type); - - const size_t mask = (align - 1); - uint64_t aligned_offset = (offset + mask) & ~mask; - m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0); - - m_data_allocator.GetStream().Write(data.GetBytes(), operand_data_size); - - llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo(); - - Constant *new_pointer = BuildRelocation(fp_ptr_ty, aligned_offset); - - llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst); - - operand_constant_fp->replaceAllUsesWith(fp_load); - } - } - - return true; -} - -static bool isGuardVariableRef(Value *V) -{ - Constant *Old = NULL; - - if (!(Old = dyn_cast<Constant>(V))) - return false; - - ConstantExpr *CE = NULL; - - if ((CE = dyn_cast<ConstantExpr>(V))) - { - if (CE->getOpcode() != Instruction::BitCast) - return false; - - Old = CE->getOperand(0); - } - - GlobalVariable *GV = dyn_cast<GlobalVariable>(Old); - - if (!GV || !GV->hasName() || - (!GV->getName().startswith("_ZGV") && // Itanium ABI guard variable - !GV->getName().endswith("@4IA"))) // Microsoft ABI guard variable - { - return false; - } - - return true; -} - -void -IRForTarget::TurnGuardLoadIntoZero(llvm::Instruction* guard_load) -{ - Constant *zero(Constant::getNullValue(guard_load->getType())); - guard_load->replaceAllUsesWith(zero); - guard_load->eraseFromParent(); -} - -static void ExciseGuardStore(Instruction* guard_store) -{ - guard_store->eraseFromParent(); -} - -bool -IRForTarget::RemoveGuards(BasicBlock &basic_block) -{ - /////////////////////////////////////////////////////// - // Eliminate any reference to guard variables found. - // - - BasicBlock::iterator ii; - - typedef SmallVector <Instruction*, 2> InstrList; - typedef InstrList::iterator InstrIterator; - - InstrList guard_loads; - InstrList guard_stores; - - for (ii = basic_block.begin(); - ii != basic_block.end(); - ++ii) - { - Instruction &inst = *ii; - - if (LoadInst *load = dyn_cast<LoadInst>(&inst)) - if (isGuardVariableRef(load->getPointerOperand())) - guard_loads.push_back(&inst); - - if (StoreInst *store = dyn_cast<StoreInst>(&inst)) - if (isGuardVariableRef(store->getPointerOperand())) - guard_stores.push_back(&inst); - } - - InstrIterator iter; - - for (iter = guard_loads.begin(); - iter != guard_loads.end(); - ++iter) - TurnGuardLoadIntoZero(*iter); - - for (iter = guard_stores.begin(); - iter != guard_stores.end(); - ++iter) - ExciseGuardStore(*iter); - - return true; -} - -// This function does not report errors; its callers are responsible. -bool -IRForTarget::UnfoldConstant(Constant *old_constant, - FunctionValueCache &value_maker, - FunctionValueCache &entry_instruction_finder) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - SmallVector<User*, 16> users; - - // We do this because the use list might change, invalidating our iterator. - // Much better to keep a work list ourselves. - for (llvm::User *u : old_constant->users()) - users.push_back(u); - - for (size_t i = 0; - i < users.size(); - ++i) - { - User *user = users[i]; - - if (Constant *constant = dyn_cast<Constant>(user)) - { - // synthesize a new non-constant equivalent of the constant - - if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant)) - { - switch (constant_expr->getOpcode()) - { - default: - if (log) - log->Printf("Unhandled constant expression type: \"%s\"", PrintValue(constant_expr).c_str()); - return false; - case Instruction::BitCast: - { - FunctionValueCache bit_cast_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* { - // UnaryExpr - // OperandList[0] is value - - if (constant_expr->getOperand(0) != old_constant) - return constant_expr; - - return new BitCastInst(value_maker.GetValue(function), - constant_expr->getType(), - "", - llvm::cast<Instruction>(entry_instruction_finder.GetValue(function))); - }); - - if (!UnfoldConstant(constant_expr, bit_cast_maker, entry_instruction_finder)) - return false; - } - break; - case Instruction::GetElementPtr: - { - // GetElementPtrConstantExpr - // OperandList[0] is base - // OperandList[1]... are indices - - FunctionValueCache get_element_pointer_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* { - Value *ptr = constant_expr->getOperand(0); - - if (ptr == old_constant) - ptr = value_maker.GetValue(function); - - std::vector<Value*> index_vector; - - unsigned operand_index; - unsigned num_operands = constant_expr->getNumOperands(); - - for (operand_index = 1; - operand_index < num_operands; - ++operand_index) - { - Value *operand = constant_expr->getOperand(operand_index); - - if (operand == old_constant) - operand = value_maker.GetValue(function); - - index_vector.push_back(operand); - } - - ArrayRef <Value*> indices(index_vector); - - return GetElementPtrInst::Create(nullptr, ptr, indices, "", llvm::cast<Instruction>(entry_instruction_finder.GetValue(function))); - }); - - if (!UnfoldConstant(constant_expr, get_element_pointer_maker, entry_instruction_finder)) - return false; - } - break; - } - } - else - { - if (log) - log->Printf("Unhandled constant type: \"%s\"", PrintValue(constant).c_str()); - return false; - } - } - else - { - if (Instruction *inst = llvm::dyn_cast<Instruction>(user)) - { - inst->replaceUsesOfWith(old_constant, value_maker.GetValue(inst->getParent()->getParent())); - } - else - { - if (log) - log->Printf("Unhandled non-constant type: \"%s\"", PrintValue(user).c_str()); - return false; - } - } - } - - if (!isa<GlobalValue>(old_constant)) - { - old_constant->destroyConstant(); - } - - return true; -} - -bool -IRForTarget::ReplaceVariables (Function &llvm_function) -{ - if (!m_resolve_vars) - return true; - - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - m_decl_map->DoStructLayout(); - - if (log) - log->Printf("Element arrangement:"); - - uint32_t num_elements; - uint32_t element_index; - - size_t size; - lldb::offset_t alignment; - - if (!m_decl_map->GetStructInfo (num_elements, size, alignment)) - return false; - - Function::arg_iterator iter(llvm_function.getArgumentList().begin()); - - if (iter == llvm_function.getArgumentList().end()) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes no arguments (should take at least a struct pointer)"); - - return false; - } - - Argument *argument = iter; - - if (argument->getName().equals("this")) - { - ++iter; - - if (iter == llvm_function.getArgumentList().end()) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'this' argument (should take a struct pointer too)"); - - return false; - } - - argument = iter; - } - else if (argument->getName().equals("self")) - { - ++iter; - - if (iter == llvm_function.getArgumentList().end()) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'self' argument (should take '_cmd' and a struct pointer too)"); - - return false; - } - - if (!iter->getName().equals("_cmd")) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes '%s' after 'self' argument (should take '_cmd')", iter->getName().str().c_str()); - - return false; - } - - ++iter; - - if (iter == llvm_function.getArgumentList().end()) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'self' and '_cmd' arguments (should take a struct pointer too)"); - - return false; - } - - argument = iter; - } - - if (!argument->getName().equals("$__lldb_arg")) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes an argument named '%s' instead of the struct pointer", argument->getName().str().c_str()); - - return false; - } - - if (log) - log->Printf("Arg: \"%s\"", PrintValue(argument).c_str()); - - BasicBlock &entry_block(llvm_function.getEntryBlock()); - Instruction *FirstEntryInstruction(entry_block.getFirstNonPHIOrDbg()); - - if (!FirstEntryInstruction) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find the first instruction in the wrapper for use in rewriting"); - - return false; - } - - LLVMContext &context(m_module->getContext()); - IntegerType *offset_type(Type::getInt32Ty(context)); - - if (!offset_type) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't produce an offset type"); - - return false; - } - - for (element_index = 0; element_index < num_elements; ++element_index) - { - const clang::NamedDecl *decl = NULL; - Value *value = NULL; - lldb::offset_t offset; - lldb_private::ConstString name; - - if (!m_decl_map->GetStructElement (decl, value, offset, name, element_index)) - { - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Structure information is incomplete"); - - return false; - } - - if (log) - log->Printf(" \"%s\" (\"%s\") placed at %" PRIu64, - name.GetCString(), - decl->getNameAsString().c_str(), - offset); - - if (value) - { - if (log) - log->Printf(" Replacing [%s]", PrintValue(value).c_str()); - - FunctionValueCache body_result_maker ([this, name, offset_type, offset, argument, value] (llvm::Function *function)->llvm::Value * { - // Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, in cases where the result - // variable is an rvalue, we have to synthesize a dereference of the appropriate structure - // entry in order to produce the static variable that the AST thinks it is accessing. - - llvm::Instruction *entry_instruction = llvm::cast<Instruction>(m_entry_instruction_finder.GetValue(function)); - - ConstantInt *offset_int(ConstantInt::get(offset_type, offset, true)); - GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(nullptr, - argument, - offset_int, - "", - entry_instruction); - - if (name == m_result_name && !m_result_is_pointer) - { - BitCastInst *bit_cast = new BitCastInst(get_element_ptr, - value->getType()->getPointerTo(), - "", - entry_instruction); - - LoadInst *load = new LoadInst(bit_cast, "", entry_instruction); - - return load; - } - else - { - BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", entry_instruction); - - return bit_cast; - } - }); - - if (Constant *constant = dyn_cast<Constant>(value)) - { - UnfoldConstant(constant, body_result_maker, m_entry_instruction_finder); - } - else if (Instruction *instruction = dyn_cast<Instruction>(value)) - { - value->replaceAllUsesWith(body_result_maker.GetValue(instruction->getParent()->getParent())); - } - else - { - if (log) - log->Printf("Unhandled non-constant type: \"%s\"", PrintValue(value).c_str()); - return false; - } - - if (GlobalVariable *var = dyn_cast<GlobalVariable>(value)) - var->eraseFromParent(); - } - } - - if (log) - log->Printf("Total structure [align %" PRId64 ", size %" PRIu64 "]", (int64_t)alignment, (uint64_t)size); - - return true; -} - -llvm::Constant * -IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset) -{ - llvm::Constant *offset_int = ConstantInt::get(m_intptr_ty, offset); - - llvm::Constant *offset_array[1]; - - offset_array[0] = offset_int; - - llvm::ArrayRef<llvm::Constant *> offsets(offset_array, 1); - llvm::Type *char_type = llvm::Type::getInt8Ty(m_module->getContext()); - llvm::Type *char_pointer_type = char_type->getPointerTo(); - - llvm::Constant *reloc_placeholder_bitcast = ConstantExpr::getBitCast(m_reloc_placeholder, char_pointer_type); - llvm::Constant *reloc_getelementptr = ConstantExpr::getGetElementPtr(char_type, reloc_placeholder_bitcast, offsets); - llvm::Constant *reloc_bitcast = ConstantExpr::getBitCast(reloc_getelementptr, type); - - return reloc_bitcast; -} - -bool -IRForTarget::CompleteDataAllocation () -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - if (!m_data_allocator.GetStream().GetSize()) - return true; - - lldb::addr_t allocation = m_data_allocator.Allocate(); - - if (log) - { - if (allocation) - log->Printf("Allocated static data at 0x%llx", (unsigned long long)allocation); - else - log->Printf("Failed to allocate static data"); - } - - if (!allocation || allocation == LLDB_INVALID_ADDRESS) - return false; - - Constant *relocated_addr = ConstantInt::get(m_intptr_ty, (uint64_t)allocation); - Constant *relocated_bitcast = ConstantExpr::getIntToPtr(relocated_addr, llvm::Type::getInt8PtrTy(m_module->getContext())); - - m_reloc_placeholder->replaceAllUsesWith(relocated_bitcast); - - m_reloc_placeholder->eraseFromParent(); - - return true; -} - -bool -IRForTarget::StripAllGVs (Module &llvm_module) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - std::vector<GlobalVariable *> global_vars; - std::set<GlobalVariable *>erased_vars; - - bool erased = true; - - while (erased) - { - erased = false; - - for (GlobalVariable &global_var : llvm_module.globals()) - { - global_var.removeDeadConstantUsers(); - - if (global_var.use_empty()) - { - if (log) - log->Printf("Did remove %s", - PrintValue(&global_var).c_str()); - global_var.eraseFromParent(); - erased = true; - break; - } - } - } - - for (GlobalVariable &global_var : llvm_module.globals()) - { - GlobalValue::user_iterator ui = global_var.user_begin(); - - if (log) - log->Printf("Couldn't remove %s because of %s", - PrintValue(&global_var).c_str(), - PrintValue(*ui).c_str()); - } - - return true; -} - -bool -IRForTarget::runOnModule (Module &llvm_module) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - m_module = &llvm_module; - m_target_data.reset(new DataLayout(m_module)); - m_intptr_ty = llvm::Type::getIntNTy(m_module->getContext(), m_target_data->getPointerSizeInBits()); - - if (log) - { - std::string s; - raw_string_ostream oss(s); - - m_module->print(oss, NULL); - - oss.flush(); - - log->Printf("Module as passed in to IRForTarget: \n\"%s\"", s.c_str()); - } - - Function* main_function = m_module->getFunction(StringRef(m_func_name.c_str())); - - if (!main_function) - { - if (log) - log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str()); - - if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str()); - - return false; - } - - if (!FixFunctionLinkage (*main_function)) - { - if (log) - log->Printf("Couldn't fix the linkage for the function"); - - return false; - } - - llvm::Type *int8_ty = Type::getInt8Ty(m_module->getContext()); - - m_reloc_placeholder = new llvm::GlobalVariable((*m_module), - int8_ty, - false /* IsConstant */, - GlobalVariable::InternalLinkage, - Constant::getNullValue(int8_ty), - "reloc_placeholder", - NULL /* InsertBefore */, - GlobalVariable::NotThreadLocal /* ThreadLocal */, - 0 /* AddressSpace */); - - //////////////////////////////////////////////////////////// - // Replace $__lldb_expr_result with a persistent variable - // - - if (!CreateResultVariable(*main_function)) - { - if (log) - log->Printf("CreateResultVariable() failed"); - - // CreateResultVariable() reports its own errors, so we don't do so here - - return false; - } - - if (log && log->GetVerbose()) - { - std::string s; - raw_string_ostream oss(s); - - m_module->print(oss, NULL); - - oss.flush(); - - log->Printf("Module after creating the result variable: \n\"%s\"", s.c_str()); - } - - for (Module::iterator fi = m_module->begin(), fe = m_module->end(); - fi != fe; - ++fi) - { - llvm::Function *function = fi; - - if (function->begin() == function->end()) - continue; - - Function::iterator bbi; - - for (bbi = function->begin(); - bbi != function->end(); - ++bbi) - { - if (!RemoveGuards(*bbi)) - { - if (log) - log->Printf("RemoveGuards() failed"); - - // RemoveGuards() reports its own errors, so we don't do so here - - return false; - } - - if (!RewritePersistentAllocs(*bbi)) - { - if (log) - log->Printf("RewritePersistentAllocs() failed"); - - // RewritePersistentAllocs() reports its own errors, so we don't do so here - - return false; - } - - if (!RemoveCXAAtExit(*bbi)) - { - if (log) - log->Printf("RemoveCXAAtExit() failed"); - - // RemoveCXAAtExit() reports its own errors, so we don't do so here - - return false; - } - } - } - - /////////////////////////////////////////////////////////////////////////////// - // Fix all Objective-C constant strings to use NSStringWithCString:encoding: - // - - if (!RewriteObjCConstStrings()) - { - if (log) - log->Printf("RewriteObjCConstStrings() failed"); - - // RewriteObjCConstStrings() reports its own errors, so we don't do so here - - return false; - } - - /////////////////////////////// - // Resolve function pointers - // - - if (!ResolveFunctionPointers(llvm_module)) - { - if (log) - log->Printf("ResolveFunctionPointers() failed"); - - // ResolveFunctionPointers() reports its own errors, so we don't do so here - - return false; - } - - for (Module::iterator fi = m_module->begin(), fe = m_module->end(); - fi != fe; - ++fi) - { - llvm::Function *function = fi; - - for (llvm::Function::iterator bbi = function->begin(), bbe = function->end(); - bbi != bbe; - ++bbi) - { - if (!RewriteObjCSelectors(*bbi)) - { - if (log) - log->Printf("RewriteObjCSelectors() failed"); - - // RewriteObjCSelectors() reports its own errors, so we don't do so here - - return false; - } - } - } - - for (Module::iterator fi = m_module->begin(), fe = m_module->end(); - fi != fe; - ++fi) - { - llvm::Function *function = fi; - - for (llvm::Function::iterator bbi = function->begin(), bbe = function->end(); - bbi != bbe; - ++bbi) - { - if (!ResolveCalls(*bbi)) - { - if (log) - log->Printf("ResolveCalls() failed"); - - // ResolveCalls() reports its own errors, so we don't do so here - - return false; - } - - if (!ReplaceStaticLiterals(*bbi)) - { - if (log) - log->Printf("ReplaceStaticLiterals() failed"); - - return false; - } - } - } - - //////////////////////////////////////////////////////////////////////// - // Run function-level passes that only make sense on the main function - // - - if (!ResolveExternals(*main_function)) - { - if (log) - log->Printf("ResolveExternals() failed"); - - // ResolveExternals() reports its own errors, so we don't do so here - - return false; - } - - if (!ReplaceVariables(*main_function)) - { - if (log) - log->Printf("ReplaceVariables() failed"); - - // ReplaceVariables() reports its own errors, so we don't do so here - - return false; - } - - if (!ReplaceStrings()) - { - if (log) - log->Printf("ReplaceStrings() failed"); - - return false; - } - - if (!CompleteDataAllocation()) - { - if (log) - log->Printf("CompleteDataAllocation() failed"); - - return false; - } - - if (!StripAllGVs(llvm_module)) - { - if (log) - log->Printf("StripAllGVs() failed"); - } - - if (log && log->GetVerbose()) - { - std::string s; - raw_string_ostream oss(s); - - m_module->print(oss, NULL); - - oss.flush(); - - log->Printf("Module after preparing for execution: \n\"%s\"", s.c_str()); - } - - return true; -} - -void -IRForTarget::assignPassManager (PMStack &pass_mgr_stack, PassManagerType pass_mgr_type) -{ -} - -PassManagerType -IRForTarget::getPotentialPassManagerType() const -{ - return PMT_ModulePassManager; -} diff --git a/source/Expression/IRInterpreter.cpp b/source/Expression/IRInterpreter.cpp index 926d1f2..a2b0c5b 100644 --- a/source/Expression/IRInterpreter.cpp +++ b/source/Expression/IRInterpreter.cpp @@ -365,7 +365,7 @@ public: const uint64_t *raw_data = resolved_value.getRawData(); - buffer.PutRawBytes(raw_data, constant_size, lldb::endian::InlHostByteOrder()); + buffer.PutRawBytes(raw_data, constant_size, lldb_private::endian::InlHostByteOrder()); lldb_private::Error write_error; @@ -498,7 +498,7 @@ IRInterpreter::CanInterpret (llvm::Module &module, default: { if (log) - log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str()); + log->Printf("Unsupported instruction: %s", PrintValue(&*ii).c_str()); error.SetErrorToGenericError(); error.SetErrorString(unsupported_opcode_error); return false; @@ -522,7 +522,7 @@ IRInterpreter::CanInterpret (llvm::Module &module, if (!CanIgnoreCall(call_inst) && !support_function_calls) { if (log) - log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str()); + log->Printf("Unsupported instruction: %s", PrintValue(&*ii).c_str()); error.SetErrorToGenericError(); error.SetErrorString(unsupported_opcode_error); return false; @@ -547,7 +547,7 @@ IRInterpreter::CanInterpret (llvm::Module &module, default: { if (log) - log->Printf("Unsupported ICmp predicate: %s", PrintValue(ii).c_str()); + log->Printf("Unsupported ICmp predicate: %s", PrintValue(&*ii).c_str()); error.SetErrorToGenericError(); error.SetErrorString(unsupported_opcode_error); @@ -655,7 +655,7 @@ IRInterpreter::Interpret (llvm::Module &module, ai != ae; ++ai, ++arg_index) { - if (args.size() < static_cast<size_t>(arg_index)) + if (args.size() <= static_cast<size_t>(arg_index)) { error.SetErrorString ("Not enough arguments passed in to function"); return false; @@ -663,16 +663,16 @@ IRInterpreter::Interpret (llvm::Module &module, lldb::addr_t ptr = args[arg_index]; - frame.MakeArgument(ai, ptr); + frame.MakeArgument(&*ai, ptr); } uint32_t num_insts = 0; - frame.Jump(function.begin()); + frame.Jump(&function.front()); while (frame.m_ii != frame.m_ie && (++num_insts < 4096)) { - const Instruction *inst = frame.m_ii; + const Instruction *inst = &*frame.m_ii; if (log) log->Printf("Interpreting %s", PrintValue(inst).c_str()); diff --git a/source/Expression/IRMemoryMap.cpp b/source/Expression/IRMemoryMap.cpp index 4733b16..e96bddd 100644 --- a/source/Expression/IRMemoryMap.cpp +++ b/source/Expression/IRMemoryMap.cpp @@ -47,7 +47,7 @@ IRMemoryMap::~IRMemoryMap () } lldb::addr_t -IRMemoryMap::FindSpace (size_t size) +IRMemoryMap::FindSpace (size_t size, bool zero_memory) { lldb::TargetSP target_sp = m_target_wp.lock(); lldb::ProcessSP process_sp = m_process_wp.lock(); @@ -60,7 +60,10 @@ IRMemoryMap::FindSpace (size_t size) { Error alloc_error; - ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error); + if (!zero_memory) + ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error); + else + ret = process_sp->CallocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error); if (!alloc_error.Success()) return LLDB_INVALID_ADDRESS; @@ -225,7 +228,7 @@ IRMemoryMap::Allocation::Allocation (lldb::addr_t process_alloc, } lldb::addr_t -IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error) +IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, bool zero_memory, Error &error) { lldb_private::Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); error.Clear(); @@ -263,7 +266,11 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc log->Printf ("IRMemoryMap::%s process_sp=0x%" PRIx64 ", process_sp->CanJIT()=%s, process_sp->IsAlive()=%s", __FUNCTION__, (lldb::addr_t) process_sp.get (), process_sp && process_sp->CanJIT () ? "true" : "false", process_sp && process_sp->IsAlive () ? "true" : "false"); if (process_sp && process_sp->CanJIT() && process_sp->IsAlive()) { - allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error); + if (!zero_memory) + allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error); + else + allocation_address = process_sp->CallocateMemory(allocation_size, permissions, error); + if (!error.Success()) return LLDB_INVALID_ADDRESS; } @@ -287,7 +294,11 @@ IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, Alloc { if (process_sp->CanJIT() && process_sp->IsAlive()) { - allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error); + if (!zero_memory) + allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error); + else + allocation_address = process_sp->CallocateMemory(allocation_size, permissions, error); + if (!error.Success()) return LLDB_INVALID_ADDRESS; } diff --git a/source/Expression/LLVMUserExpression.cpp b/source/Expression/LLVMUserExpression.cpp new file mode 100644 index 0000000..eff0a2d --- /dev/null +++ b/source/Expression/LLVMUserExpression.cpp @@ -0,0 +1,363 @@ +//===-- LLVMUserExpression.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 + +// Project includes +#include "lldb/Expression/LLVMUserExpression.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Expression/IRInterpreter.h" +#include "lldb/Expression/Materializer.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallUserExpression.h" + +using namespace lldb_private; + +LLVMUserExpression::LLVMUserExpression(ExecutionContextScope &exe_scope, + const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + ResultType desired_type, + const EvaluateExpressionOptions &options) + : UserExpression(exe_scope, expr, expr_prefix, language, desired_type, options), + m_stack_frame_bottom(LLDB_INVALID_ADDRESS), + m_stack_frame_top(LLDB_INVALID_ADDRESS), + m_transformed_text(), + m_execution_unit_sp(), + m_materializer_ap(), + m_jit_module_wp(), + m_enforce_valid_object(true), + m_in_cplusplus_method(false), + m_in_objectivec_method(false), + m_in_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) +{ +} + +LLVMUserExpression::~LLVMUserExpression() +{ + if (m_target) + { + lldb::ModuleSP jit_module_sp(m_jit_module_wp.lock()); + if (jit_module_sp) + m_target->GetImages().Remove(jit_module_sp); + } +} + +lldb::ExpressionResults +LLVMUserExpression::Execute(Stream &error_stream, ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, lldb::ExpressionVariableSP &result) +{ + // 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; + + if (!PrepareToExecuteJITExpression(error_stream, exe_ctx, struct_address)) + { + error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + 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_sp->GetModule(); + llvm::Function *function = m_execution_unit_sp->GetFunction(); + + if (!module || !function) + { + error_stream.Printf("Supposed to interpret, but nothing is there"); + return lldb::eExpressionSetupError; + } + + Error interpreter_error; + + std::vector<lldb::addr_t> args; + + if (!AddArguments(exe_ctx, args, struct_address, error_stream)) + { + error_stream.Printf("Errored out in %s, couldn't AddArguments", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + function_stack_bottom = m_stack_frame_bottom; + function_stack_top = m_stack_frame_top; + + IRInterpreter::Interpret(*module, *function, args, *m_execution_unit_sp.get(), interpreter_error, + function_stack_bottom, function_stack_top, exe_ctx); + + if (!interpreter_error.Success()) + { + error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString()); + return lldb::eExpressionDiscarded; + } + } + else + { + if (!exe_ctx.HasThreadScope()) + { + error_stream.Printf("UserExpression::Execute called with no thread selected."); + return lldb::eExpressionSetupError; + } + + Address wrapper_address(m_jit_start_addr); + + std::vector<lldb::addr_t> args; + + if (!AddArguments(exe_ctx, args, struct_address, error_stream)) + { + error_stream.Printf("Errored out in %s, couldn't AddArguments", __FUNCTION__); + return lldb::eExpressionSetupError; + } + + lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression(exe_ctx.GetThreadRef(), wrapper_address, + args, options, shared_ptr_to_me)); + + if (!call_plan_sp || !call_plan_sp->ValidatePlan(&error_stream)) + return lldb::eExpressionSetupError; + + ThreadPlanCallUserExpression *user_expression_plan = + static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get()); + + lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); + + function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); + function_stack_top = function_stack_pointer; + + if (log) + log->Printf("-- [UserExpression::Execute] Execution of expression begins --"); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); + + lldb::ExpressionResults execution_result = + exe_ctx.GetProcessRef().RunThreadPlan(exe_ctx, call_plan_sp, options, error_stream); + + if (exe_ctx.GetProcessPtr()) + exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); + + if (log) + log->Printf("-- [UserExpression::Execute] Execution of expression completed --"); + + if (execution_result == lldb::eExpressionInterrupted || execution_result == lldb::eExpressionHitBreakpoint) + { + 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.PutCString("Execution was interrupted."); + + if ((execution_result == lldb::eExpressionInterrupted && options.DoesUnwindOnError()) || + (execution_result == lldb::eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints())) + error_stream.PutCString( + "\nThe process has been returned to the state before expression evaluation."); + else + { + if (execution_result == lldb::eExpressionHitBreakpoint) + user_expression_plan->TransferExpressionOwnership(); + error_stream.PutCString( + "\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 == lldb::eExpressionStoppedForDebug) + { + error_stream.PutCString( + "Execution was halted at the first instruction of the expression " + "function because \"debug\" was requested.\n" + "Use \"thread return -x\" to return to the state before expression evaluation."); + return execution_result; + } + else if (execution_result != lldb::eExpressionCompleted) + { + 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 lldb::eExpressionCompleted; + } + else + { + return lldb::eExpressionResultUnavailable; + } + } + else + { + error_stream.Printf("Expression can't be run, because there is no JIT compiled function"); + return lldb::eExpressionSetupError; + } +} + +bool +LLVMUserExpression::FinalizeJITExecution(Stream &error_stream, ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &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("-- [UserExpression::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, 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; + } + + result = GetResultAfterDematerialization(exe_ctx.GetBestExecutionContextScope()); + + if (result) + result->TransferAddress(); + + m_dematerializer_sp.reset(); + + return true; +} + +bool +LLVMUserExpression::PrepareToExecuteJITExpression(Stream &error_stream, ExecutionContext &exe_ctx, + lldb::addr_t &struct_address) +{ + 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_materialized_address == LLDB_INVALID_ADDRESS) + { + Error alloc_error; + + IRMemoryMap::AllocationPolicy policy = + m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror; + + const bool zero_memory = false; + + m_materialized_address = m_execution_unit_sp->Malloc(m_materializer_ap->GetStructByteSize(), + m_materializer_ap->GetStructAlignment(), + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + policy, + zero_memory, + 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; + + const bool zero_memory = false; + + m_stack_frame_bottom = m_execution_unit_sp->Malloc(stack_frame_size, + 8, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + IRMemoryMap::eAllocationPolicyHostOnly, + zero_memory, + 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_sp, struct_address, materialize_error); + + if (!materialize_error.Success()) + { + error_stream.Printf("Couldn't materialize: %s\n", materialize_error.AsCString()); + return false; + } + } + return true; +} + +lldb::ModuleSP +LLVMUserExpression::GetJITModule() +{ + if (m_execution_unit_sp) + return m_execution_unit_sp->GetJITModule(); + return lldb::ModuleSP(); +} diff --git a/source/Expression/Materializer.cpp b/source/Expression/Materializer.cpp index ef01fee..8d68b4f 100644 --- a/source/Expression/Materializer.cpp +++ b/source/Expression/Materializer.cpp @@ -7,12 +7,15 @@ // //===----------------------------------------------------------------------===// +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes #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/ClangPersistentVariables.h" +#include "lldb/Expression/ExpressionVariable.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Symbol.h" @@ -48,7 +51,7 @@ Materializer::AddStructMember (Entity &entity) } void -Materializer::Entity::SetSizeAndAlignmentFromType (ClangASTType &type) +Materializer::Entity::SetSizeAndAlignmentFromType (CompilerType &type) { m_size = type.GetByteSize(nullptr); @@ -66,9 +69,11 @@ Materializer::Entity::SetSizeAndAlignmentFromType (ClangASTType &type) class EntityPersistentVariable : public Materializer::Entity { public: - EntityPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp) : + EntityPersistentVariable (lldb::ExpressionVariableSP &persistent_variable_sp, + Materializer::PersistentVariableDelegate *delegate) : Entity(), - m_persistent_variable_sp(persistent_variable_sp) + m_persistent_variable_sp(persistent_variable_sp), + m_delegate(delegate) { // Hard-coding to maximum size of a pointer since persistent variables are materialized by reference m_size = 8; @@ -82,11 +87,13 @@ public: // Allocate a spare memory area to store the persistent variable's contents. Error allocate_error; + const bool zero_memory = false; lldb::addr_t mem = map.Malloc(m_persistent_variable_sp->GetByteSize(), 8, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, + zero_memory, allocate_error); if (!allocate_error.Success()) @@ -99,21 +106,21 @@ public: log->Printf("Allocated %s (0x%" PRIx64 ") successfully", 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->GetCompilerType(), m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad, - m_persistent_variable_sp->GetByteSize()); + map.GetAddressByteSize()); // Clear the flag if the variable will never be deallocated. - if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVKeepInTarget) + if (m_persistent_variable_sp->m_flags & ExpressionVariable::EVKeepInTarget) { Error leak_error; map.Leak(mem, leak_error); - m_persistent_variable_sp->m_flags &= ~ClangExpressionVariable::EVNeedsAllocation; + m_persistent_variable_sp->m_flags &= ~ExpressionVariable::EVNeedsAllocation; } // Write the contents of the variable to the area. @@ -147,7 +154,10 @@ public: } } - void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err) + void Materialize(lldb::StackFrameSP &frame_sp, + IRMemoryMap &map, + lldb::addr_t process_address, + Error &err) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -161,17 +171,17 @@ public: m_persistent_variable_sp->m_flags); } - if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVNeedsAllocation) + if (m_persistent_variable_sp->m_flags & ExpressionVariable::EVNeedsAllocation) { MakeAllocation(map, err); - m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated; + m_persistent_variable_sp->m_flags |= ExpressionVariable::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) + if ((m_persistent_variable_sp->m_flags & ExpressionVariable::EVIsProgramReference && m_persistent_variable_sp->m_live_sp) || + m_persistent_variable_sp->m_flags & ExpressionVariable::EVIsLLDBAllocated) { Error write_error; @@ -192,12 +202,12 @@ public: } } - 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) + 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) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -211,10 +221,15 @@ public: 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_delegate) + { + m_delegate->DidDematerialize(m_persistent_variable_sp); + } + + if ((m_persistent_variable_sp->m_flags & ExpressionVariable::EVIsLLDBAllocated) || + (m_persistent_variable_sp->m_flags & ExpressionVariable::EVIsProgramReference)) { - if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsProgramReference && + if (m_persistent_variable_sp->m_flags & ExpressionVariable::EVIsProgramReference && !m_persistent_variable_sp->m_live_sp) { // If the reference comes from the program, then the ClangExpressionVariable's @@ -230,9 +245,9 @@ public: 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.get()->GetCompilerType(), m_persistent_variable_sp->GetName(), location, eAddressTypeLoad, @@ -246,10 +261,10 @@ public: // 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; + m_persistent_variable_sp->m_flags |= ExpressionVariable::EVIsLLDBAllocated; + m_persistent_variable_sp->m_flags |= ExpressionVariable::EVNeedsAllocation; + m_persistent_variable_sp->m_flags |= ExpressionVariable::EVNeedsFreezeDry; + m_persistent_variable_sp->m_flags &= ~ExpressionVariable::EVIsProgramReference; } } @@ -267,8 +282,8 @@ public: return; } - if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVNeedsFreezeDry || - m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVKeepInTarget) + if (m_persistent_variable_sp->m_flags & ExpressionVariable::EVNeedsFreezeDry || + m_persistent_variable_sp->m_flags & ExpressionVariable::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()); @@ -290,7 +305,7 @@ public: return; } - m_persistent_variable_sp->m_flags &= ~ClangExpressionVariable::EVNeedsFreezeDry; + m_persistent_variable_sp->m_flags &= ~ExpressionVariable::EVNeedsFreezeDry; } } else @@ -305,14 +320,14 @@ public: { // Allocations are not persistent so persistent variables cannot stay materialized. - m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation; + m_persistent_variable_sp->m_flags |= ExpressionVariable::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)) + else if (m_persistent_variable_sp->m_flags & ExpressionVariable::EVNeedsAllocation && + !(m_persistent_variable_sp->m_flags & ExpressionVariable::EVKeepInTarget)) { DestroyAllocation(map, err); if (!err.Success()) @@ -320,7 +335,7 @@ public: } } - void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log) + void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override { StreamString dump_stream; @@ -386,18 +401,22 @@ public: log->PutCString(dump_stream.GetData()); } - void Wipe (IRMemoryMap &map, lldb::addr_t process_address) + void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { } + private: - lldb::ClangExpressionVariableSP m_persistent_variable_sp; + lldb::ExpressionVariableSP m_persistent_variable_sp; + Materializer::PersistentVariableDelegate *m_delegate; }; uint32_t -Materializer::AddPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp, Error &err) +Materializer::AddPersistentVariable (lldb::ExpressionVariableSP &persistent_variable_sp, + PersistentVariableDelegate *delegate, + Error &err) { EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); - iter->reset (new EntityPersistentVariable (persistent_variable_sp)); + iter->reset (new EntityPersistentVariable (persistent_variable_sp, delegate)); uint32_t ret = AddStructMember(**iter); (*iter)->SetOffset(ret); return ret; @@ -416,10 +435,13 @@ public: // 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(); + m_is_reference = m_variable_sp->GetType()->GetForwardCompilerType ().IsReferenceType(); } - void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err) + void Materialize(lldb::StackFrameSP &frame_sp, + IRMemoryMap &map, + lldb::addr_t process_address, + Error &err) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -525,15 +547,22 @@ public: return; } - size_t bit_align = m_variable_sp->GetType()->GetClangLayoutType().GetTypeBitAlign(); + size_t bit_align = m_variable_sp->GetType()->GetLayoutCompilerType ().GetTypeBitAlign(); size_t byte_align = (bit_align + 7) / 8; if (!byte_align) byte_align = 1; Error alloc_error; + const bool zero_memory = false; + + m_temporary_allocation = map.Malloc(data.GetByteSize(), + byte_align, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + IRMemoryMap::eAllocationPolicyMirror, + zero_memory, + 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(); m_original_data.reset(new DataBufferHeap(data.GetDataStart(), data.GetByteSize())); @@ -566,12 +595,12 @@ public: } } - 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) + 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) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -650,7 +679,7 @@ public: } } - void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log) + void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override { StreamString dump_stream; @@ -722,7 +751,7 @@ public: log->PutCString(dump_stream.GetData()); } - void Wipe (IRMemoryMap &map, lldb::addr_t process_address) + void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { @@ -735,6 +764,7 @@ public: } } + private: lldb::VariableSP m_variable_sp; bool m_is_reference; @@ -756,20 +786,27 @@ Materializer::AddVariable (lldb::VariableSP &variable_sp, Error &err) class EntityResultVariable : public Materializer::Entity { public: - EntityResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory) : + EntityResultVariable (const CompilerType &type, + bool is_program_reference, + bool keep_in_memory, + Materializer::PersistentVariableDelegate *delegate) : 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) + m_temporary_allocation_size(0), + m_delegate(delegate) { // 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) + void Materialize(lldb::StackFrameSP &frame_sp, + IRMemoryMap &map, + lldb::addr_t process_address, + Error &err) override { if (!m_is_program_reference) { @@ -789,8 +826,14 @@ public: byte_align = 1; Error alloc_error; - - m_temporary_allocation = map.Malloc(byte_size, byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error); + const bool zero_memory = true; + + m_temporary_allocation = map.Malloc(byte_size, + byte_align, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + IRMemoryMap::eAllocationPolicyMirror, + zero_memory, + alloc_error); m_temporary_allocation_size = byte_size; if (!alloc_error.Success()) @@ -810,23 +853,12 @@ public: } } - 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) + 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) override { err.Clear(); @@ -858,15 +890,30 @@ public: return; } - ConstString name = target_sp->GetPersistentVariables().GetNextPersistentVariableName(); + Error type_system_error; + TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(&type_system_error, m_type.GetMinimumLanguage()); + + if (!type_system) + { + err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: couldn't get the corresponding type system: %s", type_system_error.AsCString()); + return; + } + + PersistentExpressionState *persistent_state = type_system->GetPersistentExpressionState(); + + if (!persistent_state) + { + err.SetErrorString("Couldn't dematerialize a result variable: corresponding type system doesn't handle persistent variables"); + return; + } - lldb::ClangExpressionVariableSP ret; + ConstString name = m_delegate ? m_delegate->GetName() : persistent_state->GetNextPersistentVariableName(); - ret = target_sp->GetPersistentVariables().CreateVariable(exe_scope, - name, - m_type, - map.GetByteOrder(), - map.GetAddressByteSize()); + lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(exe_scope, + name, + m_type, + map.GetByteOrder(), + map.GetAddressByteSize()); if (!ret) { @@ -876,6 +923,11 @@ public: lldb::ProcessSP process_sp = map.GetBestExecutionContextScope()->CalculateProcess(); + if (m_delegate) + { + m_delegate->DidDematerialize(ret); + } + 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) @@ -900,12 +952,10 @@ public: 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; + ret->m_flags |= ExpressionVariable::EVNeedsAllocation; if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { @@ -915,14 +965,14 @@ public: } else { - ret->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated; + ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated; } m_temporary_allocation = LLDB_INVALID_ADDRESS; m_temporary_allocation_size = 0; } - void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log) + void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override { StreamString dump_stream; @@ -995,7 +1045,7 @@ public: log->PutCString(dump_stream.GetData()); } - void Wipe (IRMemoryMap &map, lldb::addr_t process_address) + void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) { @@ -1007,23 +1057,28 @@ public: m_temporary_allocation = LLDB_INVALID_ADDRESS; m_temporary_allocation_size = 0; } + private: - TypeFromUser m_type; + CompilerType m_type; bool m_is_program_reference; bool m_keep_in_memory; lldb::addr_t m_temporary_allocation; size_t m_temporary_allocation_size; + Materializer::PersistentVariableDelegate *m_delegate; }; uint32_t -Materializer::AddResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory, Error &err) +Materializer::AddResultVariable (const CompilerType &type, + bool is_program_reference, + bool keep_in_memory, + PersistentVariableDelegate *delegate, + Error &err) { EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); - iter->reset (new EntityResultVariable (type, is_program_reference, keep_in_memory)); + iter->reset (new EntityResultVariable (type, is_program_reference, keep_in_memory, delegate)); uint32_t ret = AddStructMember(**iter); (*iter)->SetOffset(ret); - m_result_entity = iter->get(); return ret; } @@ -1039,7 +1094,10 @@ public: m_alignment = 8; } - void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err) + void Materialize(lldb::StackFrameSP &frame_sp, + IRMemoryMap &map, + lldb::addr_t process_address, + Error &err) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -1083,12 +1141,12 @@ public: } } - 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) + 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) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -1104,7 +1162,7 @@ public: // no work needs to be done } - void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log) + void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override { StreamString dump_stream; @@ -1138,9 +1196,10 @@ public: log->PutCString(dump_stream.GetData()); } - void Wipe (IRMemoryMap &map, lldb::addr_t process_address) + void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { } + private: Symbol m_symbol; }; @@ -1167,7 +1226,10 @@ public: m_alignment = m_register_info.byte_size; } - void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err) + void Materialize(lldb::StackFrameSP &frame_sp, + IRMemoryMap &map, + lldb::addr_t process_address, + Error &err) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -1223,12 +1285,12 @@ public: } } - 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) + 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) override { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -1280,7 +1342,7 @@ public: } } - void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log) + void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override { StreamString dump_stream; @@ -1315,9 +1377,10 @@ public: log->PutCString(dump_stream.GetData()); } - void Wipe (IRMemoryMap &map, lldb::addr_t process_address) + void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { } + private: RegisterInfo m_register_info; lldb::DataBufferSP m_register_contents; @@ -1335,7 +1398,6 @@ Materializer::AddRegister (const RegisterInfo ®ister_info, Error &err) Materializer::Materializer () : m_dematerializer_wp(), - m_result_entity(NULL), m_current_offset(0), m_struct_alignment(8) { @@ -1395,7 +1457,9 @@ Materializer::Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb: } void -Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpressionVariableSP &result_sp, lldb::addr_t frame_bottom, lldb::addr_t frame_top) +Materializer::Dematerializer::Dematerialize (Error &error, + lldb::addr_t frame_bottom, + lldb::addr_t frame_top) { lldb::StackFrameSP frame_sp; @@ -1428,14 +1492,7 @@ Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpression 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); - } + entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error); if (!error.Success()) break; @@ -1456,7 +1513,9 @@ Materializer::Dematerializer::Wipe () entity_up->Wipe (*m_map, m_process_address); } - m_materializer = NULL; - m_map = NULL; + m_materializer = nullptr; + m_map = nullptr; m_process_address = LLDB_INVALID_ADDRESS; } + +Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() = default; diff --git a/source/Expression/REPL.cpp b/source/Expression/REPL.cpp new file mode 100644 index 0000000..1727a13 --- /dev/null +++ b/source/Expression/REPL.cpp @@ -0,0 +1,649 @@ +//===-- REPL.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 +// Project includes +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Expression/REPL.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/AnsiTerminal.h" + +using namespace lldb_private; + +REPL::REPL(LLVMCastKind kind, Target &target) : + m_target(target), + m_kind(kind) +{ + // Make sure all option values have sane defaults + Debugger &debugger = m_target.GetDebugger(); + CommandInterpreter &ci = debugger.GetCommandInterpreter(); + m_format_options.OptionParsingStarting(ci); + m_varobj_options.OptionParsingStarting(ci); + m_command_options.OptionParsingStarting(ci); + + // Default certain settings for REPL regardless of the global settings. + m_command_options.unwind_on_error = false; + m_command_options.ignore_breakpoints = false; + m_command_options.debug = false; +} + +REPL::~REPL() = default; + +lldb::REPLSP +REPL::Create(Error &err, lldb::LanguageType language, Debugger *debugger, Target *target, const char *repl_options) +{ + uint32_t idx = 0; + lldb::REPLSP ret; + + while (REPLCreateInstance create_instance = PluginManager::GetREPLCreateCallbackAtIndex(idx++)) + { + ret = (*create_instance)(err, language, debugger, target, repl_options); + if (ret) + { + break; + } + } + + return ret; +} + +std::string +REPL::GetSourcePath() +{ + ConstString file_basename = GetSourceFileBasename(); + + FileSpec tmpdir_file_spec; + if (HostInfo::GetLLDBPath (lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + { + tmpdir_file_spec.GetFilename().SetCString(file_basename.AsCString()); + m_repl_source_path = tmpdir_file_spec.GetPath(); + } + else + { + tmpdir_file_spec = FileSpec("/tmp", false); + tmpdir_file_spec.AppendPathComponent(file_basename.AsCString()); + } + + return tmpdir_file_spec.GetPath(); +} + +lldb::IOHandlerSP +REPL::GetIOHandler() +{ + if (!m_io_handler_sp) + { + Debugger &debugger = m_target.GetDebugger(); + m_io_handler_sp.reset (new IOHandlerEditline (debugger, + IOHandler::Type::REPL, + "lldb-repl", // Name of input reader for history + "> ", // prompt + ". ", // Continuation prompt + true, // Multi-line + true, // The REPL prompt is always colored + 1, // Line number + *this)); + + // Don't exit if CTRL+C is pressed + static_cast<IOHandlerEditline *>(m_io_handler_sp.get())->SetInterruptExits(false); + + if (m_io_handler_sp->GetIsInteractive() && m_io_handler_sp->GetIsRealTerminal()) + { + m_indent_str.assign (debugger.GetTabSize(), ' '); + m_enable_auto_indent = debugger.GetAutoIndent(); + } + else + { + m_indent_str.clear(); + m_enable_auto_indent = false; + } + + } + return m_io_handler_sp; +} + +void +REPL::IOHandlerActivated (IOHandler &io_handler) +{ + lldb::ProcessSP process_sp = m_target.GetProcessSP(); + if (process_sp && process_sp->IsAlive()) + return; + lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile()); + error_sp->Printf("REPL requires a running target process.\n"); + io_handler.SetIsDone(true); +} + +bool +REPL::IOHandlerInterrupt (IOHandler &io_handler) +{ + return false; +} + +void +REPL::IOHandlerInputInterrupted (IOHandler &io_handler, + std::string &line) +{ +} + +const char * +REPL::IOHandlerGetFixIndentationCharacters() +{ + return (m_enable_auto_indent ? GetAutoIndentCharacters() : nullptr); +} + +ConstString +REPL::IOHandlerGetControlSequence (char ch) +{ + if (ch == 'd') + return ConstString(":quit\n"); + return ConstString(); +} + +const char * +REPL::IOHandlerGetCommandPrefix () +{ + return ":"; +} + +const char * +REPL::IOHandlerGetHelpPrologue () +{ + return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter. " + "Valid statements, expressions, and declarations are immediately compiled and executed.\n\n" + "The complete set of LLDB debugging commands are also available as described below. Commands " + "must be prefixed with a colon at the REPL prompt (:quit for example.) Typing just a colon " + "followed by return will switch to the LLDB prompt.\n\n"; +} + +bool +REPL::IOHandlerIsInputComplete (IOHandler &io_handler, + StringList &lines) +{ + // Check for meta command + const size_t num_lines = lines.GetSize(); + if (num_lines == 1) + { + const char *first_line = lines.GetStringAtIndex(0); + if (first_line[0] == ':') + return true; // Meta command is a single line where that starts with ':' + } + + // Check if REPL input is done + std::string source_string (lines.CopyList()); + return SourceIsComplete(source_string); +} + +int +REPL::CalculateActualIndentation (const StringList &lines) +{ + std::string last_line = lines[lines.GetSize() - 1]; + + int actual_indent = 0; + for (char &ch : last_line) + { + if (ch != ' ') break; + ++actual_indent; + } + + return actual_indent; +} + +int +REPL::IOHandlerFixIndentation (IOHandler &io_handler, + const StringList &lines, + int cursor_position) +{ + if (!m_enable_auto_indent) return 0; + + if (!lines.GetSize()) + { + return 0; + } + + int tab_size = io_handler.GetDebugger().GetTabSize(); + + lldb::offset_t desired_indent = GetDesiredIndentation(lines, + cursor_position, + tab_size); + + int actual_indent = REPL::CalculateActualIndentation(lines); + + if (desired_indent == LLDB_INVALID_OFFSET) + return 0; + + return (int)desired_indent - actual_indent; +} + +void +REPL::IOHandlerInputComplete (IOHandler &io_handler, std::string &code) +{ + lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile()); + bool extra_line = false; + bool did_quit = false; + + if (code.empty()) + { + m_code.AppendString(""); + static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1); + } + else + { + Debugger &debugger = m_target.GetDebugger(); + CommandInterpreter &ci = debugger.GetCommandInterpreter(); + extra_line = ci.GetSpaceReplPrompts(); + + ExecutionContext exe_ctx (m_target.GetProcessSP()->GetThreadList().GetSelectedThread()->GetSelectedFrame().get()); + + lldb::ProcessSP process_sp(exe_ctx.GetProcessSP()); + + if (code[0] == ':') + { + // Meta command + // Strip the ':' + code.erase(0, 1); + if (Args::StripSpaces (code)) + { + // "lldb" was followed by arguments, so just execute the command dump the results + + // Turn off prompt on quit in case the user types ":quit" + const bool saved_prompt_on_quit = ci.GetPromptOnQuit(); + if (saved_prompt_on_quit) + ci.SetPromptOnQuit(false); + + // Execute the command + CommandReturnObject result; + result.SetImmediateOutputStream(output_sp); + result.SetImmediateErrorStream(error_sp); + ci.HandleCommand(code.c_str(), eLazyBoolNo, result); + + if (saved_prompt_on_quit) + ci.SetPromptOnQuit(true); + + if (result.GetStatus() == lldb::eReturnStatusQuit) + { + did_quit = true; + io_handler.SetIsDone(true); + if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) + { + // We typed "quit" or an alias to quit so we need to check if the + // command interpreter is above us and tell it that it is done as well + // so we don't drop back into the command interpreter if we have already + // quit + lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler()); + if (io_handler_sp) + io_handler_sp->SetIsDone(true); + } + } + } + else + { + // ":" was followed by no arguments, so push the LLDB command prompt + if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) + { + // If the user wants to get back to the command interpreter and the + // command interpreter is what launched the REPL, then just let the + // REPL exit and fall back to the command interpreter. + io_handler.SetIsDone(true); + } + else + { + // The REPL wasn't launched the by the command interpreter, it is the + // base IOHandler, so we need to get the command interpreter and + lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler()); + if (io_handler_sp) + { + io_handler_sp->SetIsDone(false); + debugger.PushIOHandler(ci.GetIOHandler()); + } + } + } + } + else + { + // Unwind any expression we might have been running in case our REPL + // expression crashed and the user was looking around + if (m_dedicated_repl_mode) + { + Thread *thread = exe_ctx.GetThreadPtr(); + if (thread && thread->UnwindInnermostExpression().Success()) + { + thread->SetSelectedFrameByIndex(0, false); + exe_ctx.SetFrameSP(thread->GetSelectedFrame()); + } + } + + const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors(); + + EvaluateExpressionOptions expr_options; + expr_options.SetCoerceToId(m_varobj_options.use_objc); + expr_options.SetUnwindOnError(m_command_options.unwind_on_error); + expr_options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints); + expr_options.SetKeepInMemory(true); + expr_options.SetUseDynamic(m_varobj_options.use_dynamic); + expr_options.SetTryAllThreads(m_command_options.try_all_threads); + expr_options.SetGenerateDebugInfo(true); + expr_options.SetREPLEnabled (true); + expr_options.SetColorizeErrors(colorize_err); + expr_options.SetPoundLine(m_repl_source_path.c_str(), m_code.GetSize() + 1); + if (m_command_options.timeout > 0) + expr_options.SetTimeoutUsec(m_command_options.timeout); + else + expr_options.SetTimeoutUsec(0); + + expr_options.SetLanguage(GetLanguage()); + + PersistentExpressionState *persistent_state = m_target.GetPersistentExpressionStateForLanguage(GetLanguage()); + + const size_t var_count_before = persistent_state->GetSize(); + + const char *expr_prefix = nullptr; + lldb::ValueObjectSP result_valobj_sp; + Error error; + lldb::ModuleSP jit_module_sp; + lldb::ExpressionResults execution_results = UserExpression::Evaluate (exe_ctx, + expr_options, + code.c_str(), + expr_prefix, + result_valobj_sp, + error, + 0, // Line offset + &jit_module_sp); + + //CommandInterpreter &ci = debugger.GetCommandInterpreter(); + + if (process_sp && process_sp->IsAlive()) + { + bool add_to_code = true; + bool handled = false; + if (result_valobj_sp) + { + lldb::Format format = m_format_options.GetFormat(); + + if (result_valobj_sp->GetError().Success()) + { + handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp); + } + else if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult) + { + if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) + { + error_sp->PutCString("(void)\n"); + handled = true; + } + } + } + + if (debugger.GetPrintDecls()) + { + for (size_t vi = var_count_before, ve = persistent_state->GetSize(); + vi != ve; + ++vi) + { + lldb::ExpressionVariableSP persistent_var_sp = persistent_state->GetVariableAtIndex(vi); + lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject(); + + PrintOneVariable(debugger, output_sp, valobj_sp, persistent_var_sp.get()); + } + } + + if (!handled) + { + bool useColors = error_sp->GetFile().GetIsTerminalWithColors(); + switch (execution_results) + { + case lldb::eExpressionSetupError: + case lldb::eExpressionParseError: + add_to_code = false; + // Fall through + case lldb::eExpressionDiscarded: + error_sp->Printf("%s\n", error.AsCString()); + break; + + case lldb::eExpressionCompleted: + break; + case lldb::eExpressionInterrupted: + if (useColors) { + error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED)); + error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD)); + } + error_sp->Printf("Execution interrupted. "); + if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL)); + error_sp->Printf("Enter code to recover and continue.\nEnter LLDB commands to investigate (type :help for assistance.)\n"); + break; + + case lldb::eExpressionHitBreakpoint: + // Breakpoint was hit, drop into LLDB command interpreter + if (useColors) { + error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED)); + error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD)); + } + output_sp->Printf("Execution stopped at breakpoint. "); + if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL)); + output_sp->Printf("Enter LLDB commands to investigate (type help for assistance.)\n"); + { + lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler()); + if (io_handler_sp) + { + io_handler_sp->SetIsDone(false); + debugger.PushIOHandler(ci.GetIOHandler()); + } + } + break; + + case lldb::eExpressionTimedOut: + error_sp->Printf("error: timeout\n"); + if (error.AsCString()) + error_sp->Printf("error: %s\n", error.AsCString()); + break; + case lldb::eExpressionResultUnavailable: + // Shoulnd't happen??? + error_sp->Printf("error: could not fetch result -- %s\n", error.AsCString()); + break; + case lldb::eExpressionStoppedForDebug: + // Shoulnd't happen??? + error_sp->Printf("error: stopped for debug -- %s\n", error.AsCString()); + break; + } + } + + if (add_to_code) + { + const uint32_t new_default_line = m_code.GetSize() + 1; + + m_code.SplitIntoLines(code); + + // Update our code on disk + if (!m_repl_source_path.empty()) + { + lldb_private::File file (m_repl_source_path.c_str(), + File::eOpenOptionWrite | File::eOpenOptionTruncate | File::eOpenOptionCanCreate, + lldb::eFilePermissionsFileDefault); + std::string code (m_code.CopyList()); + code.append(1, '\n'); + size_t bytes_written = code.size(); + file.Write(code.c_str(), bytes_written); + file.Close(); + + // Now set the default file and line to the REPL source file + m_target.GetSourceManager().SetDefaultFileAndLine(FileSpec(m_repl_source_path.c_str(), false), new_default_line); + } + static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1); + } + if (extra_line) + { + fprintf(output_sp->GetFile().GetStream(), "\n"); + } + } + } + + // Don't complain about the REPL process going away if we are in the process of quitting. + if (!did_quit && (!process_sp || !process_sp->IsAlive())) + { + error_sp->Printf("error: REPL process is no longer alive, exiting REPL\n"); + io_handler.SetIsDone(true); + } + } +} + +int +REPL::IOHandlerComplete (IOHandler &io_handler, + const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches) +{ + matches.Clear(); + + llvm::StringRef line (current_line, cursor - current_line); + + // Complete an LLDB command if the first character is a colon... + if (!line.empty() && line[0] == ':') + { + Debugger &debugger = m_target.GetDebugger(); + + // auto complete LLDB commands + const char *lldb_current_line = line.substr(1).data(); + return debugger.GetCommandInterpreter().HandleCompletion (lldb_current_line, + cursor, + last_char, + skip_first_n_matches, + max_matches, + matches); + } + + // Strip spaces from the line and see if we had only spaces + line = line.ltrim(); + if (line.empty()) + { + // Only spaces on this line, so just indent + matches.AppendString(m_indent_str); + return 1; + } + + std::string current_code; + current_code.append(m_code.CopyList()); + + IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler); + const StringList *current_lines = editline.GetCurrentLines(); + if (current_lines) + { + const uint32_t current_line_idx = editline.GetCurrentLineIndex(); + + if (current_line_idx < current_lines->GetSize()) + { + for (uint32_t i=0; i<current_line_idx; ++i) + { + const char *line_cstr = current_lines->GetStringAtIndex(i); + if (line_cstr) + { + current_code.append("\n"); + current_code.append (line_cstr); + } + } + } + } + + if (cursor > current_line) + { + current_code.append("\n"); + current_code.append(current_line, cursor - current_line); + } + + return CompleteCode(current_code, matches); +} + +bool +QuitCommandOverrideCallback(void *baton, const char **argv) +{ + Target *target = (Target *)baton; + lldb::ProcessSP process_sp (target->GetProcessSP()); + if (process_sp) + { + process_sp->Destroy(false); + process_sp->GetTarget().GetDebugger().ClearIOHandlers(); + } + return false; +} + +Error +REPL::RunLoop () +{ + Error error; + + error = DoInitialization(); + m_repl_source_path = GetSourcePath(); + + if (!error.Success()) + return error; + + Debugger &debugger = m_target.GetDebugger(); + + lldb::IOHandlerSP io_handler_sp (GetIOHandler()); + + FileSpec save_default_file; + uint32_t save_default_line = 0; + + if (!m_repl_source_path.empty()) + { + // Save the current default file and line + m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file, save_default_line); + } + + debugger.PushIOHandler(io_handler_sp); + + // Check if we are in dedicated REPL mode where LLDB was start with the "--repl" option + // from the command line. Currently we know this by checking if the debugger already + // has a IOHandler thread. + if (!debugger.HasIOHandlerThread()) + { + // The debugger doesn't have an existing IOHandler thread, so this must be + // dedicated REPL mode... + m_dedicated_repl_mode = true; + debugger.StartIOHandlerThread(); + std::string command_name_str ("quit"); + CommandObject *cmd_obj = debugger.GetCommandInterpreter().GetCommandObjectForCommand(command_name_str); + if (cmd_obj) + { + assert(command_name_str.empty()); + cmd_obj->SetOverrideCallback (QuitCommandOverrideCallback, &m_target); + } + } + + // Wait for the REPL command interpreter to get popped + io_handler_sp->WaitForPop(); + + if (m_dedicated_repl_mode) + { + // If we were in dedicated REPL mode we would have started the + // IOHandler thread, and we should kill our process + lldb::ProcessSP process_sp = m_target.GetProcessSP(); + if (process_sp && process_sp->IsAlive()) + process_sp->Destroy(false); + + // Wait for the IO handler thread to exit (TODO: don't do this if the IO handler thread already exists...) + debugger.JoinIOHandlerThread(); + } + + // Restore the default file and line + if (save_default_file && save_default_line != 0) + m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file, save_default_line); + return error; +} diff --git a/source/Expression/UserExpression.cpp b/source/Expression/UserExpression.cpp new file mode 100644 index 0000000..70f004b --- /dev/null +++ b/source/Expression/UserExpression.cpp @@ -0,0 +1,348 @@ +//===-- UserExpression.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <cstdlib> +#include <string> +#include <map> + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Expression/IRInterpreter.h" +#include "lldb/Expression/Materializer.h" +#include "lldb/Expression/UserExpression.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/TypeSystem.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" + +using namespace lldb_private; + +UserExpression::UserExpression (ExecutionContextScope &exe_scope, + const char *expr, + const char *expr_prefix, + lldb::LanguageType language, + ResultType desired_type, + const EvaluateExpressionOptions &options) : + Expression(exe_scope), + m_expr_text(expr), + m_expr_prefix(expr_prefix ? expr_prefix : ""), + m_language(language), + m_desired_type(desired_type), + m_options (options) +{ +} + +UserExpression::~UserExpression () +{ +} + +void +UserExpression::InstallContext (ExecutionContext &exe_ctx) +{ + m_jit_process_wp = exe_ctx.GetProcessSP(); + + lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP(); + + if (frame_sp) + m_address = frame_sp->GetFrameCodeAddress(); +} + +bool +UserExpression::LockAndCheckContext (ExecutionContext &exe_ctx, + lldb::TargetSP &target_sp, + lldb::ProcessSP &process_sp, + lldb::StackFrameSP &frame_sp) +{ + lldb::ProcessSP expected_process_sp = m_jit_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 +UserExpression::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); +} + +lldb::addr_t +UserExpression::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::eExpressionPathOptionsNoFragileObjcIvar | + StackFrame::eExpressionPathOptionsNoSyntheticChildren | + StackFrame::eExpressionPathOptionsNoSyntheticArrayRange, + var_sp, + err); + + if (!err.Success() || !valobj_sp.get()) + return LLDB_INVALID_ADDRESS; + + lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); + + if (ret == LLDB_INVALID_ADDRESS) + { + err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString()); + return LLDB_INVALID_ADDRESS; + } + + return ret; +} + +lldb::ExpressionResults +UserExpression::Evaluate (ExecutionContext &exe_ctx, + const EvaluateExpressionOptions& options, + const char *expr_cstr, + const char *expr_prefix, + lldb::ValueObjectSP &result_valobj_sp, + Error &error, + uint32_t line_offset, + lldb::ModuleSP *jit_module_sp_ptr) +{ + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); + + lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); + lldb::LanguageType language = options.GetLanguage(); + const ResultType desired_type = options.DoesCoerceToId() ? UserExpression::eResultTypeId : UserExpression::eResultTypeAny; + lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; + + Target *target = exe_ctx.GetTargetPtr(); + if (!target) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Passed a NULL target, can't run expressions."); + return lldb::eExpressionSetupError; + } + + Process *process = exe_ctx.GetProcessPtr(); + + if (process == NULL || process->GetState() != lldb::eStateStopped) + { + if (execution_policy == eExecutionPolicyAlways) + { + if (log) + log->Printf("== [UserExpression::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; + + const char *full_prefix = NULL; + const char *option_prefix = options.GetPrefix(); + std::string full_prefix_storage; + if (expr_prefix && option_prefix) + { + full_prefix_storage.assign(expr_prefix); + full_prefix_storage.append(option_prefix); + if (!full_prefix_storage.empty()) + full_prefix = full_prefix_storage.c_str(); + } + else if (expr_prefix) + full_prefix = expr_prefix; + else + full_prefix = option_prefix; + + // If the language was not specified in the expression command, + // set it to the language in the target's properties if + // specified, else default to the langage for the frame. + if (language == lldb::eLanguageTypeUnknown) + { + if (target->GetLanguage() != lldb::eLanguageTypeUnknown) + language = target->GetLanguage(); + else if (StackFrame *frame = exe_ctx.GetFramePtr()) + language = frame->GetLanguage(); + } + + lldb::UserExpressionSP user_expression_sp(target->GetUserExpressionForLanguage (expr_cstr, + full_prefix, + language, + desired_type, + options, + error)); + if (error.Fail()) + { + if (log) + log->Printf ("== [UserExpression::Evaluate] Getting expression: %s ==", error.AsCString()); + return lldb::eExpressionSetupError; + } + + StreamString error_stream; + + if (log) + log->Printf("== [UserExpression::Evaluate] Parsing expression %s ==", expr_cstr); + + const bool keep_expression_in_memory = true; + const bool generate_debug_info = options.GetGenerateDebugInfo(); + + if (options.InvokeCancelCallback (lldb::eExpressionEvaluationParse)) + { + error.SetErrorString ("expression interrupted by callback before parse"); + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + return lldb::eExpressionInterrupted; + } + + if (!user_expression_sp->Parse (error_stream, + exe_ctx, + execution_policy, + keep_expression_in_memory, + generate_debug_info)) + { + execution_results = lldb::eExpressionParseError; + if (error_stream.GetString().empty()) + error.SetExpressionError (execution_results, "expression failed to parse, unknown error"); + else + error.SetExpressionError (execution_results, error_stream.GetString().c_str()); + } + else + { + // If a pointer to a lldb::ModuleSP was passed in, return the JIT'ed module if one was created + if (jit_module_sp_ptr) + *jit_module_sp_ptr = user_expression_sp->GetJITModule(); + + lldb::ExpressionVariableSP expr_result; + + if (execution_policy == eExecutionPolicyNever && + !user_expression_sp->CanInterpret()) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Expression may not run, but is not constant =="); + + if (error_stream.GetString().empty()) + error.SetExpressionError (lldb::eExpressionSetupError, "expression needed to run but couldn't"); + } + else + { + if (options.InvokeCancelCallback (lldb::eExpressionEvaluationExecution)) + { + error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback before execution"); + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + return lldb::eExpressionInterrupted; + } + + error_stream.GetString().clear(); + + if (log) + log->Printf("== [UserExpression::Evaluate] Executing expression =="); + + execution_results = user_expression_sp->Execute (error_stream, + exe_ctx, + options, + user_expression_sp, + expr_result); + + if (options.GetResultIsInternal() && expr_result && process) + { + process->GetTarget().GetPersistentExpressionStateForLanguage(language)->RemovePersistentVariable (expr_result); + } + + if (execution_results != lldb::eExpressionCompleted) + { + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed abnormally =="); + + if (error_stream.GetString().empty()) + error.SetExpressionError (execution_results, "expression failed to execute, unknown error"); + else + error.SetExpressionError (execution_results, error_stream.GetString().c_str()); + } + else + { + if (expr_result) + { + result_valobj_sp = expr_result->GetValueObject(); + + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed normally with result %s ==", + result_valobj_sp->GetValueAsCString()); + } + else + { + if (log) + log->Printf("== [UserExpression::Evaluate] Execution completed normally with no result =="); + + error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric); + } + } + } + } + + if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) + { + error.SetExpressionError (lldb::eExpressionInterrupted, "expression interrupted by callback after complete"); + return lldb::eExpressionInterrupted; + } + + if (result_valobj_sp.get() == NULL) + { + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + } + + return execution_results; +} diff --git a/source/Expression/UtilityFunction.cpp b/source/Expression/UtilityFunction.cpp new file mode 100644 index 0000000..f93e358 --- /dev/null +++ b/source/Expression/UtilityFunction.cpp @@ -0,0 +1,124 @@ +//===-- 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/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Expression/FunctionCaller.h" +#include "lldb/Expression/UtilityFunction.h" +#include "lldb/Expression/ExpressionSourceCode.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Host/Host.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; +using namespace lldb; + +//------------------------------------------------------------------ +/// 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. +//------------------------------------------------------------------ +UtilityFunction::UtilityFunction (ExecutionContextScope &exe_scope, + const char *text, + const char *name) : + Expression (exe_scope), + m_execution_unit_sp (), + m_jit_module_wp (), + m_function_text (ExpressionSourceCode::g_expression_prefix), + m_function_name (name) +{ + if (text && text[0]) + m_function_text.append (text); +} + +UtilityFunction::~UtilityFunction () +{ + lldb::ProcessSP process_sp (m_jit_process_wp.lock()); + if (process_sp) + { + lldb::ModuleSP jit_module_sp (m_jit_module_wp.lock()); + if (jit_module_sp) + process_sp->GetTarget().GetImages().Remove(jit_module_sp); + } + +} + +// FIXME: We should check that every time this is called it is called with the same return type & arguments... + +FunctionCaller * +UtilityFunction::MakeFunctionCaller (const CompilerType &return_type, const ValueList &arg_value_list, Error &error) +{ + if (m_caller_up) + return m_caller_up.get(); + + ProcessSP process_sp = m_jit_process_wp.lock(); + if (!process_sp) + return nullptr; + + Address impl_code_address; + impl_code_address.SetOffset(StartAddress()); + std::string name(m_function_name); + name.append("-caller"); + + m_caller_up.reset (process_sp->GetTarget().GetFunctionCallerForLanguage (Language(), + return_type, + impl_code_address, + arg_value_list, + name.c_str(), + error)); + if (error.Fail()) + { + + return nullptr; + } + if (m_caller_up) + { + StreamString errors; + errors.Clear(); + unsigned num_errors = m_caller_up->CompileFunction(errors); + if (num_errors) + { + error.SetErrorStringWithFormat ("Error compiling %s caller function: \"%s\".", + m_function_name.c_str(), + errors.GetData()); + m_caller_up.reset(); + return nullptr; + } + + errors.Clear(); + ExecutionContext exe_ctx(process_sp); + + if (!m_caller_up->WriteFunctionWrapper(exe_ctx, errors)) + { + error.SetErrorStringWithFormat ("Error inserting caller function for %s: \"%s\".", + m_function_name.c_str(), + errors.GetData()); + m_caller_up.reset(); + return nullptr; + } + } + return m_caller_up.get(); +} |