diff options
Diffstat (limited to 'source/Plugins/ExpressionParser/Clang')
23 files changed, 1316 insertions, 1498 deletions
diff --git a/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp b/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp index 976310610f51..0b8199481158 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp +++ b/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp @@ -11,6 +11,7 @@ #include "lldb/Core/Log.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "llvm/Support/raw_ostream.h" @@ -83,7 +84,7 @@ ASTDumper::ASTDumper (lldb::opaque_compiler_type_t type) ASTDumper::ASTDumper (const CompilerType &compiler_type) { - m_dump = ClangASTContext::GetQualType(compiler_type).getAsString(); + m_dump = ClangUtil::GetQualType(compiler_type).getAsString(); } diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 02505bde240c..f1231572e263 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -11,6 +11,11 @@ #include "ClangPersistentVariables.h" +#include "lldb/Core/Log.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangASTImporter.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBAssert.h" #include "stdlib.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -23,22 +28,18 @@ #include "clang/Sema/SemaDiagnostic.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" -#include "lldb/Core/Log.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Target/Target.h" using namespace llvm; using namespace clang; using namespace lldb_private; -ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough, - Target &target) : - m_ast_context (NULL), - m_passthrough (passthrough), - m_passthrough_sema (NULL), - m_target (target), - m_sema (NULL) +ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough, bool top_level, Target &target) + : m_ast_context(NULL), + m_passthrough(passthrough), + m_passthrough_sema(NULL), + m_target(target), + m_sema(NULL), + m_top_level(top_level) { if (!m_passthrough) return; @@ -76,6 +77,10 @@ ASTResultSynthesizer::TransformTopLevelDecl(Decl* D) log->Printf("TransformTopLevelDecl(<complex>)"); } + if (m_top_level) + { + RecordPersistentDecl(named_decl); + } } if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D)) @@ -89,22 +94,23 @@ ASTResultSynthesizer::TransformTopLevelDecl(Decl* D) TransformTopLevelDecl(*decl_iterator); } } - else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D)) + else if (!m_top_level) { - if (m_ast_context && - !method_decl->getSelector().getAsString().compare("$__lldb_expr:")) + if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D)) { - RecordPersistentTypes(method_decl); - SynthesizeObjCMethodResult(method_decl); + 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")) + else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D)) { - RecordPersistentTypes(function_decl); - SynthesizeFunctionResult(function_decl); + if (m_ast_context && !function_decl->getNameInfo().getAsString().compare("$__lldb_expr")) + { + RecordPersistentTypes(function_decl); + SynthesizeFunctionResult(function_decl); + } } } } @@ -365,8 +371,10 @@ ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body, 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); + if (address_of_expr.get()) + m_sema->AddInitializerToDecl(result_decl, address_of_expr.get(), true, false); + else + return false; } else { @@ -457,14 +465,66 @@ ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D) ConstString name_cs(name.str().c_str()); if (log) - log->Printf ("Recording persistent type %s\n", name_cs.GetCString()); + 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); + m_decls.push_back(D); +} - if (TypeDecl *TypeDecl_scratch = dyn_cast<TypeDecl>(D_scratch)) - llvm::cast<ClangPersistentVariables>(m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC))->RegisterPersistentType(name_cs, TypeDecl_scratch); +void +ASTResultSynthesizer::RecordPersistentDecl(NamedDecl *D) +{ + lldbassert(m_top_level); + + if (!D->getIdentifier()) + return; + + StringRef name = D->getName(); + + if (name.size() == 0) + return; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + ConstString name_cs(name.str().c_str()); + + if (log) + log->Printf("Recording persistent decl %s\n", name_cs.GetCString()); + + m_decls.push_back(D); +} + +void +ASTResultSynthesizer::CommitPersistentDecls() +{ + for (clang::NamedDecl *decl : m_decls) + { + StringRef name = decl->getName(); + ConstString name_cs(name.str().c_str()); + + Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl( + m_target.GetScratchClangASTContext()->getASTContext(), m_ast_context, decl); + + if (!D_scratch) + { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (log) + { + std::string s; + llvm::raw_string_ostream ss(s); + decl->dump(ss); + ss.flush(); + + log->Printf("Couldn't commit persistent decl: %s\n", s.c_str()); + } + + continue; + } + + if (NamedDecl *NamedDecl_scratch = dyn_cast<NamedDecl>(D_scratch)) + llvm::cast<ClangPersistentVariables>(m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)) + ->RegisterPersistentDecl(name_cs, NamedDecl_scratch); + } } void diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h index 9f7bbe05b082..4556713e9933 100644 --- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h +++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h @@ -41,13 +41,16 @@ public: /// pass to the next step in the chain after processing. Passthrough is /// the next ASTConsumer, or NULL if none is required. /// + /// @param[in] top_level + /// If true, register all top-level Decls and don't try to handle the + /// main function. + /// /// @param[in] target /// The target, which contains the persistent variable store and the /// AST importer. //---------------------------------------------------------------------- - ASTResultSynthesizer(clang::ASTConsumer *passthrough, - Target &target); - + ASTResultSynthesizer(clang::ASTConsumer *passthrough, bool top_level, Target &target); + //---------------------------------------------------------------------- /// Destructor //---------------------------------------------------------------------- @@ -106,11 +109,18 @@ public: /// casts it to an Action for actual use. //---------------------------------------------------------------------- void InitializeSema(clang::Sema &S) override; - + //---------------------------------------------------------------------- /// Reset the Sema to NULL now that transformations are done //---------------------------------------------------------------------- - void ForgetSema() override; + void + ForgetSema() override; + + //---------------------------------------------------------------------- + /// The parse has succeeded, so record its persistent decls + //---------------------------------------------------------------------- + void + CommitPersistentDecls(); private: //---------------------------------------------------------------------- @@ -171,13 +181,30 @@ private: /// @param[in] Body /// The body of the function. //---------------------------------------------------------------------- - void MaybeRecordPersistentType(clang::TypeDecl *D); - - clang::ASTContext *m_ast_context; ///< The AST context to use for identifiers and types. - clang::ASTConsumer *m_passthrough; ///< The ASTConsumer down the chain, for passthrough. NULL if it's a SemaConsumer. - clang::SemaConsumer *m_passthrough_sema; ///< The SemaConsumer down the chain, for passthrough. NULL if it's an ASTConsumer. - Target &m_target; ///< The target, which contains the persistent variable store and the - clang::Sema *m_sema; ///< The Sema to use. + void + MaybeRecordPersistentType(clang::TypeDecl *D); + + //---------------------------------------------------------------------- + /// Given a NamedDecl, register it as a pointer type in the target's scratch + /// AST context. + /// + /// @param[in] Body + /// The body of the function. + //---------------------------------------------------------------------- + void + RecordPersistentDecl(clang::NamedDecl *D); + + clang::ASTContext *m_ast_context; ///< The AST context to use for identifiers and types. + clang::ASTConsumer + *m_passthrough; ///< The ASTConsumer down the chain, for passthrough. NULL if it's a SemaConsumer. + clang::SemaConsumer + *m_passthrough_sema; ///< The SemaConsumer down the chain, for passthrough. NULL if it's an ASTConsumer. + + std::vector<clang::NamedDecl *> m_decls; ///< Persistent declarations to register assuming the expression succeeds. + + Target &m_target; ///< The target, which contains the persistent variable store and the + clang::Sema *m_sema; ///< The Sema to use. + bool m_top_level; }; } // namespace lldb_private diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index d2ea4390560a..def0d42d32dd 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -12,18 +12,20 @@ #include "ASTDumper.h" #include "ClangModulesDeclVendor.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecordLayout.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TaggedASTType.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Target.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include <vector> @@ -273,10 +275,10 @@ ClangASTSource::CompleteType (TagDecl *tag_decl) CompilerType clang_type (type->GetFullCompilerType ()); - if (!clang_type) + if (!ClangUtil::IsClangType(clang_type)) continue; - const TagType *tag_type = ClangASTContext::GetQualType(clang_type)->getAs<TagType>(); + const TagType *tag_type = ClangUtil::GetQualType(clang_type)->getAs<TagType>(); if (!tag_type) continue; @@ -299,7 +301,8 @@ ClangASTSource::CompleteType (TagDecl *tag_decl) const ModuleList &module_list = m_target->GetImages(); bool exact_match = false; - module_list.FindTypes (null_sc, name, exact_match, UINT32_MAX, types); + llvm::DenseSet<SymbolFile *> searched_symbol_files; + module_list.FindTypes (null_sc, name, exact_match, UINT32_MAX, searched_symbol_files, types); for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; @@ -312,10 +315,10 @@ ClangASTSource::CompleteType (TagDecl *tag_decl) CompilerType clang_type (type->GetFullCompilerType ()); - if (!clang_type) + if (!ClangUtil::IsClangType(clang_type)) continue; - const TagType *tag_type = ClangASTContext::GetQualType(clang_type)->getAs<TagType>(); + const TagType *tag_type = ClangUtil::GetQualType(clang_type)->getAs<TagType>(); if (!tag_type) continue; @@ -705,7 +708,7 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context, else { const ModuleList &target_images = m_target->GetImages(); - Mutex::Locker modules_locker (target_images.GetMutex()); + std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { @@ -740,16 +743,17 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context, do { + if (context.m_found.type) + break; + TypeList types; SymbolContext null_sc; const bool exact_match = false; - + llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; 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; + m_target->GetImages().FindTypes(null_sc, name, exact_match, 1, searched_symbol_files, types); if (size_t num_types = types.GetSize()) { @@ -782,12 +786,12 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context, context.AddTypeDecl(copied_clang_type); - found_a_type = true; + context.m_found.type = true; break; } } - if (!found_a_type) + if (!context.m_found.type) { // Try the modules next. @@ -832,13 +836,13 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context, context.AddNamedDecl(copied_named_decl); - found_a_type = true; + context.m_found.type = true; } } } while (0); } - if (!found_a_type) + if (!context.m_found.type) { do { @@ -1378,7 +1382,7 @@ FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id, 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)); + DeclFromUser<ObjCPropertyDecl> origin_property_decl(origin_iface_decl->FindPropertyDeclaration(&name_identifier, ObjCPropertyQueryKind::OBJC_PR_query_instance)); bool found = false; @@ -1823,7 +1827,7 @@ ClangASTSource::CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespac else { const ModuleList &target_images = m_target->GetImages(); - Mutex::Locker modules_locker(target_images.GetMutex()); + std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); CompilerDeclContext null_namespace_decl; @@ -1903,7 +1907,8 @@ ClangASTSource::GuardedCopyType (const CompilerType &src_type) SetImportInProgress(true); - QualType copied_qual_type = m_ast_importer_sp->CopyType (m_ast_context, src_ast->getASTContext(), ClangASTContext::GetQualType(src_type)); + QualType copied_qual_type = + m_ast_importer_sp->CopyType(m_ast_context, src_ast->getASTContext(), ClangUtil::GetQualType(src_type)); SetImportInProgress(false); @@ -1931,14 +1936,8 @@ NameSearchContext::AddVarDecl(const CompilerType &type) clang::ASTContext *ast = lldb_ast->getASTContext(); - clang::NamedDecl *Decl = VarDecl::Create(*ast, - const_cast<DeclContext*>(m_decl_context), - SourceLocation(), - SourceLocation(), - ii, - ClangASTContext::GetQualType(type), - 0, - SC_Static); + clang::NamedDecl *Decl = VarDecl::Create(*ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), + SourceLocation(), ii, ClangUtil::GetQualType(type), 0, SC_Static); m_decls.push_back(Decl); return Decl; @@ -1961,7 +1960,7 @@ NameSearchContext::AddFunDecl (const CompilerType &type, bool extern_c) m_function_types.insert(type); - QualType qual_type (ClangASTContext::GetQualType(type)); + QualType qual_type(ClangUtil::GetQualType(type)); clang::ASTContext *ast = lldb_ast->getASTContext(); @@ -2055,9 +2054,9 @@ NameSearchContext::AddGenericFunDecl() clang::NamedDecl * NameSearchContext::AddTypeDecl(const CompilerType &clang_type) { - if (clang_type) + if (ClangUtil::IsClangType(clang_type)) { - QualType qual_type = ClangASTContext::GetQualType(clang_type); + QualType qual_type = ClangUtil::GetQualType(clang_type); if (const TypedefType *typedef_type = llvm::dyn_cast<TypedefType>(qual_type)) { diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index bb6384721f51..13791d7e627f 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -430,6 +430,8 @@ struct NameSearchContext { bool variable : 1; bool function_with_type_info : 1; bool function : 1; + bool local_vars_nsp : 1; + bool type : 1; } m_found; //------------------------------------------------------------------ diff --git a/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h b/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h new file mode 100644 index 000000000000..8273bca105cc --- /dev/null +++ b/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h @@ -0,0 +1,60 @@ +//===-- ClangDiagnostic.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_ClangDiagnostic_h +#define lldb_ClangDiagnostic_h + +#include <vector> + +#include "clang/Basic/Diagnostic.h" + +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" + +#include "lldb/Expression/DiagnosticManager.h" + +namespace lldb_private +{ + + +class ClangDiagnostic : public Diagnostic +{ +public: + typedef std::vector<clang::FixItHint> FixItList; + + static inline bool classof(const ClangDiagnostic *) { return true; } + static inline bool classof(const Diagnostic *diag) { + return diag->getKind() == eDiagnosticOriginClang; + } + + ClangDiagnostic(const char *message, DiagnosticSeverity severity, uint32_t compiler_id) : + Diagnostic(message, severity, eDiagnosticOriginClang, compiler_id) + { + } + + virtual ~ClangDiagnostic() = default; + + bool HasFixIts () const override { return !m_fixit_vec.empty(); } + + void + AddFixitHint (const clang::FixItHint &fixit) + { + m_fixit_vec.push_back(fixit); + } + + const FixItList & + FixIts() const + { + return m_fixit_vec; + } + FixItList m_fixit_vec; +}; + +} // namespace lldb_private +#endif /* lldb_ClangDiagnostic_h */ diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index f4d6b195c7f0..7aeff6e964fe 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -57,6 +57,11 @@ using namespace lldb; using namespace lldb_private; using namespace clang; +namespace +{ + const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars"; +} // anonymous namespace + ClangExpressionDeclMap::ClangExpressionDeclMap (bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, ExecutionContext &exe_ctx) : @@ -510,248 +515,6 @@ ClangExpressionDeclMap::GetFunctionInfo return true; } -static void -FindCodeSymbolInContext -( - const ConstString &name, - SymbolContext &sym_ctx, - uint32_t name_type_mask, - SymbolContextList &sc_list -) -{ - sc_list.Clear(); - SymbolContextList temp_sc_list; - if (sym_ctx.module_sp) - sym_ctx.module_sp->FindFunctions(name, - NULL, - name_type_mask, - true, // include_symbols - false, // include_inlines - true, // append - temp_sc_list); - if (temp_sc_list.GetSize() == 0) - { - if (sym_ctx.target_sp) - sym_ctx.target_sp->GetImages().FindFunctions(name, - name_type_mask, - true, // include_symbols - false, // include_inlines - true, // append - temp_sc_list); - } - - SymbolContextList internal_symbol_sc_list; - unsigned temp_sc_list_size = temp_sc_list.GetSize(); - for (unsigned i = 0; i < temp_sc_list_size; i++) - { - SymbolContext sc; - temp_sc_list.GetContextAtIndex(i, sc); - if (sc.function) - { - sc_list.Append(sc); - } - else if (sc.symbol) - { - if (sc.symbol->IsExternal()) - { - sc_list.Append(sc); - } - else - { - internal_symbol_sc_list.Append(sc); - } - } - } - - // If we had internal symbols and we didn't find any external symbols or - // functions in debug info, then fallback to the internal symbols - if (sc_list.GetSize() == 0 && internal_symbol_sc_list.GetSize()) - { - sc_list = internal_symbol_sc_list; - } -} - -ConstString -FindBestAlternateMangledName -( - const ConstString &demangled, - const LanguageType &lang_type, - SymbolContext &sym_ctx -) -{ - CPlusPlusLanguage::MethodName cpp_name(demangled); - std::string scope_qualified_name = cpp_name.GetScopeQualifiedName(); - - if (!scope_qualified_name.size()) - return ConstString(); - - if (!sym_ctx.module_sp) - return ConstString(); - - SymbolVendor *sym_vendor = sym_ctx.module_sp->GetSymbolVendor(); - if (!sym_vendor) - return ConstString(); - - lldb_private::SymbolFile *sym_file = sym_vendor->GetSymbolFile(); - if (!sym_file) - return ConstString(); - - std::vector<ConstString> alternates; - sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates); - - std::vector<ConstString> param_and_qual_matches; - std::vector<ConstString> param_matches; - for (size_t i = 0; i < alternates.size(); i++) - { - ConstString alternate_mangled_name = alternates[i]; - Mangled mangled(alternate_mangled_name, true); - ConstString demangled = mangled.GetDemangledName(lang_type); - - CPlusPlusLanguage::MethodName alternate_cpp_name(demangled); - if (!cpp_name.IsValid()) - continue; - - if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments()) - { - if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers()) - param_and_qual_matches.push_back(alternate_mangled_name); - else - param_matches.push_back(alternate_mangled_name); - } - } - - if (param_and_qual_matches.size()) - return param_and_qual_matches[0]; // It is assumed that there will be only one! - else if (param_matches.size()) - return param_matches[0]; // Return one of them as a best match - else - return ConstString(); -} - -bool -ClangExpressionDeclMap::GetFunctionAddress -( - const ConstString &name, - uint64_t &func_addr -) -{ - assert (m_parser_vars.get()); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx; - Target *target = exe_ctx.GetTargetPtr(); - // Back out in all cases where we're not fully initialized - if (target == NULL) - return false; - if (!m_parser_vars->m_sym_ctx.target_sp) - return false; - - SymbolContextList sc_list; - - FindCodeSymbolInContext(name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list); - - uint32_t sc_list_size = sc_list.GetSize(); - - if (sc_list_size == 0) - { - SymbolContext &sc = m_parser_vars->m_sym_ctx; - if (sc.comp_unit) - { - LanguageType lang_type = sc.comp_unit->GetLanguage(); - if (Language::LanguageIsCPlusPlus(lang_type) && - CPlusPlusLanguage::IsCPPMangledName(name.AsCString())) - { - Mangled mangled(name, true); - ConstString demangled = mangled.GetDemangledName(lang_type); - - if (demangled) - { - ConstString best_alternate_mangled_name = FindBestAlternateMangledName(demangled, lang_type, sc); - if (best_alternate_mangled_name) - { - FindCodeSymbolInContext( - best_alternate_mangled_name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list); - sc_list_size = sc_list.GetSize(); - } - - if (sc_list_size == 0) - { - FindCodeSymbolInContext( - demangled, m_parser_vars->m_sym_ctx, eFunctionNameTypeFull, sc_list); - sc_list_size = sc_list.GetSize(); - } - } - } - } - } - - if (sc_list_size == 0) - { - // We occasionally get debug information in which a const function is reported - // as non-const, so the mangled name is wrong. This is a hack to compensate. - - if (!strncmp(name.GetCString(), "_ZN", 3) && - strncmp(name.GetCString(), "_ZNK", 4)) - { - std::string fixed_scratch("_ZNK"); - fixed_scratch.append(name.GetCString() + 3); - ConstString fixed_name(fixed_scratch.c_str()); - - if (log) - log->Printf("Failed to find symbols given non-const name %s; trying %s", name.GetCString(), fixed_name.GetCString()); - - FindCodeSymbolInContext( - fixed_name, m_parser_vars->m_sym_ctx, eFunctionNameTypeAuto, sc_list); - sc_list_size = sc_list.GetSize(); - } - } - - lldb::addr_t intern_callable_load_addr = LLDB_INVALID_ADDRESS; - - for (uint32_t i=0; i<sc_list_size; ++i) - { - SymbolContext sym_ctx; - sc_list.GetContextAtIndex(i, sym_ctx); - - - lldb::addr_t callable_load_addr = LLDB_INVALID_ADDRESS; - - if (sym_ctx.function) - { - const Address func_so_addr = sym_ctx.function->GetAddressRange().GetBaseAddress(); - if (func_so_addr.IsValid()) - { - callable_load_addr = func_so_addr.GetCallableLoadAddress(target, false); - } - } - else if (sym_ctx.symbol) - { - if (sym_ctx.symbol->IsExternal()) - callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target); - else - { - if (intern_callable_load_addr == LLDB_INVALID_ADDRESS) - intern_callable_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target); - } - } - - if (callable_load_addr != LLDB_INVALID_ADDRESS) - { - func_addr = callable_load_addr; - return true; - } - } - - // See if we found an internal symbol - if (intern_callable_load_addr != LLDB_INVALID_ADDRESS) - { - func_addr = intern_callable_load_addr; - return true; - } - - return false; -} - addr_t ClangExpressionDeclMap::GetSymbolAddress (Target &target, Process *process, @@ -1004,6 +767,24 @@ ClangExpressionDeclMap::FindGlobalVariable return VariableSP(); } +ClangASTContext * +ClangExpressionDeclMap::GetClangASTContext () +{ + StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); + if (frame == nullptr) + return nullptr; + + SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction|lldb::eSymbolContextBlock); + if (sym_ctx.block == nullptr) + return nullptr; + + CompilerDeclContext frame_decl_context = sym_ctx.block->GetDeclContext(); + if (!frame_decl_context) + return nullptr; + + return llvm::dyn_cast_or_null<ClangASTContext>(frame_decl_context.GetTypeSystem()); +} + // Interface for ClangASTSource void @@ -1039,6 +820,13 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context) if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context)) { + if (namespace_context->getName().str() == std::string(g_lldb_local_vars_namespace_cstr)) + { + CompilerDeclContext compiler_decl_ctx(GetClangASTContext(), const_cast<void *>(static_cast<const void *>(context.m_decl_context))); + FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx, current_id); + return; + } + ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp->GetNamespaceMap(namespace_context); if (log && log->GetVerbose()) @@ -1078,7 +866,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context) current_id); } - if (!context.m_found.variable) + if (!context.m_found.variable && !context.m_found.local_vars_nsp) ClangASTSource::FindExternalVisibleDecls(context); } @@ -1089,6 +877,17 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, unsigned int current_id) { assert (m_ast_context); + + std::function<void (clang::FunctionDecl *)> MaybeRegisterFunctionBody = + [this](clang::FunctionDecl *copied_function_decl) + { + 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); + } + }; + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -1114,6 +913,52 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, SymbolContext sym_ctx; if (frame != nullptr) sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction|lldb::eSymbolContextBlock); + + // Try the persistent decls, which take precedence over all else. + if (!namespace_decl) + { + 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; + + NamedDecl *persistent_decl = m_parser_vars->m_persistent_vars->GetPersistentDecl(name); + + if (!persistent_decl) + break; + + Decl *parser_persistent_decl = m_ast_importer_sp->CopyDecl(m_ast_context, scratch_ast_context, persistent_decl); + + if (!parser_persistent_decl) + break; + + NamedDecl *parser_named_decl = dyn_cast<NamedDecl>(parser_persistent_decl); + + if (!parser_named_decl) + break; + + if (clang::FunctionDecl *parser_function_decl = llvm::dyn_cast<clang::FunctionDecl>(parser_named_decl)) + { + MaybeRegisterFunctionBody(parser_function_decl); + } + + if (log) + log->Printf(" CEDM::FEVD[%u] Found persistent decl %s", current_id, name.GetCString()); + + context.AddNamedDecl(parser_named_decl); + } while (0); + } + if (name_unique_cstr[0] == '$' && !namespace_decl) { static ConstString g_lldb_class_name ("$__lldb_class"); @@ -1335,45 +1180,36 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, return; } - // any other $__lldb names should be weeded out now - if (!::strncmp(name_unique_cstr, "$__lldb", sizeof("$__lldb") - 1)) - return; - - do + if (name == ConstString(g_lldb_local_vars_namespace_cstr)) { - if (!target) - break; - - ClangASTContext *scratch_clang_ast_context = target->GetScratchClangASTContext(); - - if (!scratch_clang_ast_context) - break; - - ASTContext *scratch_ast_context = scratch_clang_ast_context->getASTContext(); - - if (!scratch_ast_context) - break; - - TypeDecl *ptype_type_decl = m_parser_vars->m_persistent_vars->GetPersistentType(name); - - if (!ptype_type_decl) - break; - - Decl *parser_ptype_decl = m_ast_importer_sp->CopyDecl(m_ast_context, scratch_ast_context, ptype_type_decl); + CompilerDeclContext frame_decl_context = sym_ctx.block != nullptr ? + sym_ctx.block->GetDeclContext() : + CompilerDeclContext(); - if (!parser_ptype_decl) - break; - - TypeDecl *parser_ptype_type_decl = dyn_cast<TypeDecl>(parser_ptype_decl); + if (frame_decl_context) + { + ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(frame_decl_context.GetTypeSystem()); - if (!parser_ptype_type_decl) - break; + if (ast) + { + clang::NamespaceDecl *namespace_decl = ClangASTContext::GetUniqueNamespaceDeclaration( + m_ast_context, name_unique_cstr, nullptr); + if (namespace_decl) + { + context.AddNamedDecl(namespace_decl); + clang::DeclContext *clang_decl_ctx = clang::Decl::castToDeclContext(namespace_decl); + clang_decl_ctx->setHasExternalVisibleStorage(true); + context.m_found.local_vars_nsp = true; + } + } + } - if (log) - log->Printf(" CEDM::FEVD[%u] Found persistent type %s", current_id, name.GetCString()); + return; + } - context.AddNamedDecl(parser_ptype_type_decl); - } while (0); + // any other $__lldb names should be weeded out now + if (!::strncmp(name_unique_cstr, "$__lldb", sizeof("$__lldb") - 1)) + return; ExpressionVariableSP pvar_sp(m_parser_vars->m_persistent_vars->GetVariable(name)); @@ -1403,24 +1239,37 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, ValueObjectSP valobj; VariableSP var; - if (frame && !namespace_decl) + bool local_var_lookup = !namespace_decl || + (namespace_decl.GetName() == ConstString(g_lldb_local_vars_namespace_cstr)); + if (frame && local_var_lookup) { CompilerDeclContext compiler_decl_context = sym_ctx.block != nullptr ? sym_ctx.block->GetDeclContext() : CompilerDeclContext(); if (compiler_decl_context) { - // Make sure that the variables are parsed so that we have the declarations + // Make sure that the variables are parsed so that we have the declarations. VariableListSP vars = frame->GetInScopeVariableList(true); for (size_t i = 0; i < vars->GetSize(); i++) vars->GetVariableAtIndex(i)->GetDecl(); - // Search for declarations matching the name - std::vector<CompilerDecl> found_decls = compiler_decl_context.FindDeclByName(name); + // Search for declarations matching the name. Do not include imported decls + // in the search if we are looking for decls in the artificial namespace + // $__lldb_local_vars. + std::vector<CompilerDecl> found_decls = compiler_decl_context.FindDeclByName(name, namespace_decl.IsValid()); bool variable_found = false; for (CompilerDecl decl : found_decls) { - var = decl.GetAsVariable(); + for (size_t vi = 0, ve = vars->GetSize(); vi != ve; ++vi) + { + VariableSP candidate_var = vars->GetVariableAtIndex(vi); + if (candidate_var->GetDecl() == decl) + { + var = candidate_var; + break; + } + } + if (var) { variable_found = true; @@ -1663,9 +1512,12 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, { if (llvm::isa<clang::FunctionDecl>(decl)) { - clang::NamedDecl *copied_decl = llvm::cast<FunctionDecl>(m_ast_importer_sp->CopyDecl(m_ast_context, &decl->getASTContext(), decl)); - context.AddNamedDecl(copied_decl); - context.m_found.function_with_type_info = true; + clang::NamedDecl *copied_decl = llvm::cast_or_null<FunctionDecl>(m_ast_importer_sp->CopyDecl(m_ast_context, &decl->getASTContext(), decl)); + if (copied_decl) + { + context.AddNamedDecl(copied_decl); + context.m_found.function_with_type_info = true; + } } } } @@ -1726,11 +1578,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, 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); - } + MaybeRegisterFunctionBody(copied_function_decl); context.AddNamedDecl(copied_function_decl); @@ -2208,6 +2056,54 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context, if (function) { Type *function_type = function->GetType(); + + const lldb::LanguageType comp_unit_language = function->GetCompileUnit()->GetLanguage(); + const bool extern_c = Language::LanguageIsC(comp_unit_language) || + (Language::LanguageIsObjC(comp_unit_language) && + !Language::LanguageIsCPlusPlus(comp_unit_language)); + + if (!extern_c) + { + TypeSystem *type_system = function->GetDeclContext().GetTypeSystem(); + if (ClangASTContext *src_ast = llvm::dyn_cast<ClangASTContext>(type_system)) + { + clang::DeclContext *src_decl_context = (clang::DeclContext*)function->GetDeclContext().GetOpaqueDeclContext(); + clang::FunctionDecl *src_function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>(src_decl_context); + + if (src_function_decl) + { + if (clang::FunctionDecl *copied_function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>(m_ast_importer_sp->CopyDecl(m_ast_context, src_ast->getASTContext(), src_function_decl))) + { + if (log) + { + ASTDumper ast_dumper((clang::Decl*)copied_function_decl); + + StreamString ss; + + function->DumpSymbolContext(&ss); + + log->Printf(" CEDM::FEVD[%u] Imported decl for function %s (description %s), returned %s", + current_id, + copied_function_decl->getName().str().c_str(), + ss.GetData(), + ast_dumper.GetCString()); + + } + + context.AddNamedDecl(copied_function_decl); + return; + } + else + { + if (log) + { + log->Printf (" Failed to import the function decl for '%s'", + src_function_decl->getName().str().c_str()); + } + } + } + } + } if (!function_type) { @@ -2230,7 +2126,7 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context, CompilerType copied_function_type = GuardedCopyType(function_clang_type); if (copied_function_type) { - function_decl = context.AddFunDecl(copied_function_type); + function_decl = context.AddFunDecl(copied_function_type, extern_c); if (!function_decl) { @@ -2329,10 +2225,10 @@ ClangExpressionDeclMap::AddThisType(NameSearchContext &context, { CompilerType copied_clang_type = GuardedCopyType(ut); + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + if (!copied_clang_type) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - if (log) log->Printf("ClangExpressionDeclMap::AddThisType - Couldn't import the type"); @@ -2349,7 +2245,7 @@ ClangExpressionDeclMap::AddThisType(NameSearchContext &context, &void_ptr_clang_type, 1, false, - copied_clang_type.GetTypeQualifiers()); + 0); const bool is_virtual = false; const bool is_static = false; @@ -2358,7 +2254,7 @@ ClangExpressionDeclMap::AddThisType(NameSearchContext &context, const bool is_attr_used = true; const bool is_artificial = false; - ClangASTContext::GetASTContext(m_ast_context)-> + CXXMethodDecl *method_decl = ClangASTContext::GetASTContext(m_ast_context)-> AddMethodToCXXRecordType (copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", method_type, @@ -2369,6 +2265,16 @@ ClangExpressionDeclMap::AddThisType(NameSearchContext &context, is_explicit, is_attr_used, is_artificial); + + if (log) + { + ASTDumper method_ast_dumper((clang::Decl*)method_decl); + ASTDumper type_ast_dumper(copied_clang_type); + + log->Printf(" CEDM::AddThisType Added function $__lldb_expr (description %s) for this type %s", + method_ast_dumper.GetCString(), + type_ast_dumper.GetCString()); + } } if (!copied_clang_type.IsValid()) diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index b3f890c7acc7..537db71cfeb4 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -265,25 +265,6 @@ public: uint64_t &ptr); //------------------------------------------------------------------ - /// [Used by IRForTarget] Get the address of a function given nothing - /// but its name. Some functions are needed but didn't get Decls made - /// during parsing -- specifically, sel_registerName is never called - /// in the generated IR but we need to call it nonetheless. - /// - /// @param[in] name - /// The name of the function. - /// - /// @param[out] ptr - /// The absolute address of the function in the target. - /// - /// @return - /// True if the address could be retrieved; false otherwise. - //------------------------------------------------------------------ - bool - GetFunctionAddress (const ConstString &name, - uint64_t &ptr); - - //------------------------------------------------------------------ /// [Used by IRForTarget] Get the address of a symbol given nothing /// but its name. /// @@ -707,6 +688,9 @@ private: AddThisType(NameSearchContext &context, TypeFromUser &type, unsigned int current_id); + + ClangASTContext * + GetClangASTContext(); }; } // namespace lldb_private diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h index bb620def691f..bcd30ec4af2e 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h @@ -67,11 +67,14 @@ public: /// the ASTs to after transformation. //------------------------------------------------------------------ virtual clang::ASTConsumer * - ASTTransformer (clang::ASTConsumer *passthrough) = 0; - + ASTTransformer(clang::ASTConsumer *passthrough) = 0; -protected: + virtual void + CommitPersistentDecls() + { + } +protected: }; } // namespace lldb_private diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 72c33fec8105..d1a3c0dea825 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -11,13 +11,18 @@ // C++ Includes // Other libraries and framework includes #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" +#include "clang/Basic/Version.h" #include "clang/CodeGen/CodeGenAction.h" #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Edit/Commit.h" +#include "clang/Edit/EditsReceiver.h" +#include "clang/Edit/EditedSource.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" @@ -28,6 +33,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseAST.h" #include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Sema/SemaConsumer.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" @@ -37,7 +43,11 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/TargetSelect.h" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors" #include "llvm/ExecutionEngine/MCJIT.h" +#pragma clang diagnostic pop + #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/ErrorHandling.h" @@ -48,6 +58,7 @@ // Project includes #include "ClangExpressionParser.h" +#include "ClangDiagnostic.h" #include "ClangASTSource.h" #include "ClangExpressionHelper.h" @@ -65,17 +76,21 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" -#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Core/StringList.h" #include "lldb/Expression/IRDynamicChecks.h" +#include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/File.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Language.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Utility/LLDBAssert.h" using namespace clang; using namespace llvm; @@ -85,21 +100,6 @@ 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 { @@ -154,6 +154,100 @@ public: } }; +class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer +{ +public: + ClangDiagnosticManagerAdapter() : m_passthrough(new clang::TextDiagnosticBuffer) {} + + ClangDiagnosticManagerAdapter(const std::shared_ptr<clang::TextDiagnosticBuffer> &passthrough) + : m_passthrough(passthrough) + { + } + + void + ResetManager(DiagnosticManager *manager = nullptr) + { + m_manager = manager; + } + + void + HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) + { + if (m_manager) + { + llvm::SmallVector<char, 32> diag_str; + Info.FormatDiagnostic(diag_str); + diag_str.push_back('\0'); + const char *data = diag_str.data(); + + lldb_private::DiagnosticSeverity severity; + bool make_new_diagnostic = true; + + switch (DiagLevel) + { + case DiagnosticsEngine::Level::Fatal: + case DiagnosticsEngine::Level::Error: + severity = eDiagnosticSeverityError; + break; + case DiagnosticsEngine::Level::Warning: + severity = eDiagnosticSeverityWarning; + break; + case DiagnosticsEngine::Level::Remark: + case DiagnosticsEngine::Level::Ignored: + severity = eDiagnosticSeverityRemark; + break; + case DiagnosticsEngine::Level::Note: + m_manager->AppendMessageToDiagnostic(data); + make_new_diagnostic = false; + } + if (make_new_diagnostic) + { + ClangDiagnostic *new_diagnostic = new ClangDiagnostic(data, severity, Info.getID()); + m_manager->AddDiagnostic(new_diagnostic); + + // Don't store away warning fixits, since the compiler doesn't have enough + // context in an expression for the warning to be useful. + // FIXME: Should we try to filter out FixIts that apply to our generated + // code, and not the user's expression? + if (severity == eDiagnosticSeverityError) + { + size_t num_fixit_hints = Info.getNumFixItHints(); + for (size_t i = 0; i < num_fixit_hints; i++) + { + const clang::FixItHint &fixit = Info.getFixItHint(i); + if (!fixit.isNull()) + new_diagnostic->AddFixitHint(fixit); + } + } + } + } + + m_passthrough->HandleDiagnostic(DiagLevel, Info); + } + + void + FlushDiagnostics(DiagnosticsEngine &Diags) + { + m_passthrough->FlushDiagnostics(Diags); + } + + DiagnosticConsumer * + clone(DiagnosticsEngine &Diags) const + { + return new ClangDiagnosticManagerAdapter(m_passthrough); + } + + clang::TextDiagnosticBuffer * + GetPassthrough() + { + return m_passthrough.get(); + } + +private: + DiagnosticManager *m_manager = nullptr; + std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough; +}; + //===----------------------------------------------------------------------===// // Implementation of ClangExpressionParser //===----------------------------------------------------------------------===// @@ -166,37 +260,78 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, m_code_generator (), m_pp_callbacks(nullptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + // We can't compile expressions without a target. So if the exe_scope is null or doesn't have a target, + // then we just need to get out of here. I'll lldb_assert and not make any of the compiler objects since + // I can't return errors directly from the constructor. Further calls will check if the compiler was made and + // bag out if it wasn't. + + if (!exe_scope) + { + lldb_assert(exe_scope, "Can't make an expression parser with a null scope.", __FUNCTION__, __FILE__, __LINE__); + return; + } + + lldb::TargetSP target_sp; + target_sp = exe_scope->CalculateTarget(); + if (!target_sp) + { + lldb_assert(exe_scope, "Can't make an expression parser with a null target.", __FUNCTION__, __FILE__, __LINE__); + return; + } + // 1. Create a new compiler instance. m_compiler.reset(new CompilerInstance()); + lldb::LanguageType frame_lang = expr.Language(); // defaults to lldb::eLanguageTypeUnknown + bool overridden_target_opts = false; + lldb_private::LanguageRuntime *lang_rt = nullptr; - // 2. Install the target. + std::string abi; + ArchSpec target_arch; + target_arch = target_sp->GetArchitecture(); - lldb::TargetSP target_sp; - if (exe_scope) - target_sp = exe_scope->CalculateTarget(); + const auto target_machine = target_arch.GetMachine(); + + // If the expression is being evaluated in the context of an existing + // stack frame, we introspect to see if the language runtime is available. + + lldb::StackFrameSP frame_sp = exe_scope->CalculateStackFrame(); + lldb::ProcessSP process_sp = exe_scope->CalculateProcess(); + + // Make sure the user hasn't provided a preferred execution language + // with `expression --language X -- ...` + if (frame_sp && frame_lang == lldb::eLanguageTypeUnknown) + frame_lang = frame_sp->GetLanguage(); + + if (process_sp && frame_lang != lldb::eLanguageTypeUnknown) + { + lang_rt = process_sp->GetLanguageRuntime(frame_lang); + if (log) + log->Printf("Frame has language of type %s", Language::GetNameForLanguageType(frame_lang)); + } - // 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()) + // 2. Configure the compiler with a set of default options that are appropriate + // for most situations. + if (target_arch.IsValid()) { - std::string triple = target_sp->GetArchitecture().GetTriple().str(); + std::string triple = target_arch.GetTriple().str(); m_compiler->getTargetOpts().Triple = triple; + if (log) + log->Printf("Using %s as the target triple", m_compiler->getTargetOpts().Triple.c_str()); } else { + // If we get here we don't have a valid target and just have to guess. + // Sometimes this will be ok to just use the host target triple (when we evaluate say "2+3", but other + // expressions like breakpoint conditions and other things that _are_ target specific really shouldn't just be + // using the host triple. In such a case the language runtime should expose an overridden options set (3), + // below. m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); + if (log) + log->Printf("Using default target triple of %s", m_compiler->getTargetOpts().Triple.c_str()); } - - 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"); - } - + // Now add some special fixes for known architectures: // Any arm32 iOS environment, but not on arm64 if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos && m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos && @@ -204,17 +339,60 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, { m_compiler->getTargetOpts().ABI = "apcs-gnu"; } + // Supported subsets of x86 + if (target_machine == llvm::Triple::x86 || + target_machine == llvm::Triple::x86_64) + { + m_compiler->getTargetOpts().Features.push_back("+sse"); + m_compiler->getTargetOpts().Features.push_back("+sse2"); + } - m_compiler->createDiagnostics(); + // Set the target CPU to generate code for. + // This will be empty for any CPU that doesn't really need to make a special CPU string. + m_compiler->getTargetOpts().CPU = target_arch.GetClangTargetCPU(); - // Create the target instance. - m_compiler->setTarget(TargetInfo::CreateTargetInfo( - m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts)); + // Set the target ABI + abi = GetClangTargetABI(target_arch); + if (!abi.empty()) + m_compiler->getTargetOpts().ABI = abi; - assert (m_compiler->hasTarget()); + // 3. Now allow the runtime to provide custom configuration options for the target. + // In this case, a specialized language runtime is available and we can query it for extra options. + // For 99% of use cases, this will not be needed and should be provided when basic platform detection is not enough. + if (lang_rt) + overridden_target_opts = lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); + + if (overridden_target_opts) + if (log) + { + log->Debug("Using overridden target options for the expression evaluation"); + + auto opts = m_compiler->getTargetOpts(); + log->Debug("Triple: '%s'", opts.Triple.c_str()); + log->Debug("CPU: '%s'", opts.CPU.c_str()); + log->Debug("FPMath: '%s'", opts.FPMath.c_str()); + log->Debug("ABI: '%s'", opts.ABI.c_str()); + log->Debug("LinkerVersion: '%s'", opts.LinkerVersion.c_str()); + StringList::LogDump(log, opts.FeaturesAsWritten, "FeaturesAsWritten"); + StringList::LogDump(log, opts.Features, "Features"); + StringList::LogDump(log, opts.Reciprocals, "Reciprocals"); + } + + // 4. Create and install the target on the compiler. + m_compiler->createDiagnostics(); + auto target_info = TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts); + if (log) + { + log->Printf("Using SIMD alignment: %d", target_info->getSimdDefaultAlign()); + log->Printf("Target datalayout string: '%s'", target_info->getDataLayout().getStringRepresentation().c_str()); + log->Printf("Target ABI: '%s'", target_info->getABI().str().c_str()); + log->Printf("Target vector alignment: %d", target_info->getMaxVectorAlign()); + } + m_compiler->setTarget(target_info); - // 3. Set options. + assert (m_compiler->hasTarget()); + // 5. Set language options. lldb::LanguageType language = expr.Language(); switch (language) @@ -242,7 +420,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, case lldb::eLanguageTypeC_plus_plus_14: m_compiler->getLangOpts().CPlusPlus11 = true; m_compiler->getHeaderSearchOpts().UseLibcxx = true; - // fall thru ... + LLVM_FALLTHROUGH; case lldb::eLanguageTypeC_plus_plus_03: m_compiler->getLangOpts().CPlusPlus = true; // FIXME: the following language option is a temporary workaround, @@ -277,10 +455,6 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, // 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()) @@ -305,9 +479,9 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, m_compiler->getCodeGenOpts().DisableFPElim = true; m_compiler->getCodeGenOpts().OmitLeafFramePointer = false; if (generate_debug_info) - m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::FullDebugInfo); + m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo); else - m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::NoDebugInfo); + m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo); // Disable some warnings. m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError, @@ -321,11 +495,11 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, // created. This complexity should be lifted elsewhere. m_compiler->getTarget().adjust(m_compiler->getLangOpts()); - // 4. Set up the diagnostic buffer for reporting errors + // 6. Set up the diagnostic buffer for reporting errors - m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer); + m_compiler->getDiagnostics().setClient(new ClangDiagnosticManagerAdapter); - // 5. Set up the source management objects inside the compiler + // 7. Set up the source management objects inside the compiler clang::FileSystemOptions file_system_options; m_file_manager.reset(new clang::FileManager(file_system_options)); @@ -344,7 +518,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); } - // 6. Most of this we get from the CompilerInstance, but we + // 8. 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()); @@ -387,37 +561,38 @@ ClangExpressionParser::~ClangExpressionParser() } unsigned -ClangExpressionParser::Parse (Stream &stream) +ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager) { - TextDiagnosticBuffer *diag_buf = static_cast<TextDiagnosticBuffer*>(m_compiler->getDiagnostics().getClient()); + ClangDiagnosticManagerAdapter *adapter = + static_cast<ClangDiagnosticManagerAdapter *>(m_compiler->getDiagnostics().getClient()); + clang::TextDiagnosticBuffer *diag_buf = adapter->GetPassthrough(); + diag_buf->FlushDiagnostics(m_compiler->getDiagnostics()); - diag_buf->FlushDiagnostics (m_compiler->getDiagnostics()); + adapter->ResetManager(&diagnostic_manager); const char *expr_text = m_expr.Text(); - clang::SourceManager &SourceMgr = m_compiler->getSourceManager(); + clang::SourceManager &source_mgr = m_compiler->getSourceManager(); bool created_main_file = false; - if (m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo) + if (m_compiler->getCodeGenOpts().getDebugInfo() == codegenoptions::FullDebugInfo) { - std::string temp_source_path; - int temp_fd = -1; llvm::SmallString<PATH_MAX> result_path; FileSpec tmpdir_file_spec; if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr"); - temp_source_path = tmpdir_file_spec.GetPath(); + std::string temp_source_path = tmpdir_file_spec.GetPath(); llvm::sys::fs::createUniqueFile(temp_source_path, temp_fd, result_path); } else { llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path); } - + if (temp_fd != -1) { - lldb_private::File file (temp_fd, true); + 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()) @@ -425,9 +600,8 @@ ClangExpressionParser::Parse (Stream &stream) if (bytes_written == expr_text_len) { file.Close(); - SourceMgr.setMainFileID(SourceMgr.createFileID( - m_file_manager->getFile(result_path), - SourceLocation(), SrcMgr::C_User)); + source_mgr.setMainFileID(source_mgr.createFileID(m_file_manager->getFile(result_path), + SourceLocation(), SrcMgr::C_User)); created_main_file = true; } } @@ -437,7 +611,7 @@ ClangExpressionParser::Parse (Stream &stream) if (!created_main_file) { std::unique_ptr<MemoryBuffer> memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__); - SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(memory_buffer))); + source_mgr.setMainFileID(source_mgr.createFileID(std::move(memory_buffer))); } diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor()); @@ -462,58 +636,147 @@ ClangExpressionParser::Parse (Stream &stream) diag_buf->EndSourceFile(); - TextDiagnosticBuffer::const_iterator diag_iterator; + unsigned num_errors = diag_buf->getNumErrors(); - int num_errors = 0; - if (m_pp_callbacks && m_pp_callbacks->hasErrors()) { num_errors++; - - stream.PutCString(m_pp_callbacks->getErrorString().c_str()); + diagnostic_manager.PutCString(eDiagnosticSeverityError, "while importing modules:"); + diagnostic_manager.AppendMessageToDiagnostic(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()); + if (!num_errors) + { + if (type_system_helper->DeclMap() && !type_system_helper->DeclMap()->ResolveUnknownTypes()) + { + diagnostic_manager.Printf(eDiagnosticSeverityError, "Couldn't infer the type of a variable"); + num_errors++; + } + } - for (diag_iterator = diag_buf->err_begin(); - diag_iterator != diag_buf->err_end(); - ++diag_iterator) + if (!num_errors) { - num_errors++; - stream.Printf("error: %s\n", (*diag_iterator).second.c_str()); + type_system_helper->CommitPersistentDecls(); } - 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()); + adapter->ResetManager(); - if (!num_errors) + return num_errors; +} + +std::string +ClangExpressionParser::GetClangTargetABI (const ArchSpec &target_arch) +{ + std::string abi; + + if(target_arch.IsMIPS()) { - if (type_system_helper->DeclMap() && !type_system_helper->DeclMap()->ResolveUnknownTypes()) + switch (target_arch.GetFlags () & ArchSpec::eMIPSABI_mask) + { + case ArchSpec::eMIPSABI_N64: + abi = "n64"; break; + case ArchSpec::eMIPSABI_N32: + abi = "n32"; break; + case ArchSpec::eMIPSABI_O32: + abi = "o32"; break; + default: + break; + } + } + return abi; +} + +bool +ClangExpressionParser::RewriteExpression(DiagnosticManager &diagnostic_manager) +{ + clang::SourceManager &source_manager = m_compiler->getSourceManager(); + clang::edit::EditedSource editor(source_manager, m_compiler->getLangOpts(), nullptr); + clang::edit::Commit commit(editor); + clang::Rewriter rewriter(source_manager, m_compiler->getLangOpts()); + + class RewritesReceiver : public edit::EditsReceiver { + Rewriter &rewrite; + + public: + RewritesReceiver(Rewriter &in_rewrite) : rewrite(in_rewrite) { } + + void insert(SourceLocation loc, StringRef text) override { + rewrite.InsertText(loc, text); + } + void replace(CharSourceRange range, StringRef text) override { + rewrite.ReplaceText(range.getBegin(), rewrite.getRangeSize(range), text); + } + }; + + RewritesReceiver rewrites_receiver(rewriter); + + const DiagnosticList &diagnostics = diagnostic_manager.Diagnostics(); + size_t num_diags = diagnostics.size(); + if (num_diags == 0) + return false; + + for (const Diagnostic *diag : diagnostic_manager.Diagnostics()) + { + const ClangDiagnostic *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag); + if (diagnostic && diagnostic->HasFixIts()) { - stream.Printf("error: Couldn't infer the type of a variable\n"); - num_errors++; + for (const FixItHint &fixit : diagnostic->FixIts()) + { + // This is cobbed from clang::Rewrite::FixItRewriter. + if (fixit.CodeToInsert.empty()) + { + if (fixit.InsertFromRange.isValid()) + { + commit.insertFromRange(fixit.RemoveRange.getBegin(), + fixit.InsertFromRange, /*afterToken=*/false, + fixit.BeforePreviousInsertions); + } + else + commit.remove(fixit.RemoveRange); + } + else + { + if (fixit.RemoveRange.isTokenRange() || + fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd()) + commit.replace(fixit.RemoveRange, fixit.CodeToInsert); + else + commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert, + /*afterToken=*/false, fixit.BeforePreviousInsertions); + } + } } } + + // FIXME - do we want to try to propagate specific errors here? + if (!commit.isCommitable()) + return false; + else if (!editor.commit(commit)) + return false; + + // Now play all the edits, and stash the result in the diagnostic manager. + editor.applyRewrites(rewrites_receiver); + RewriteBuffer &main_file_buffer = rewriter.getEditBuffer(source_manager.getMainFileID()); - return num_errors; + std::string fixed_expression; + llvm::raw_string_ostream out_stream(fixed_expression); + + main_file_buffer.write(out_stream); + out_stream.flush(); + diagnostic_manager.SetFixedExpression(fixed_expression); + + return true; } static bool FindFunctionInModule (ConstString &mangled_name, llvm::Module *module, const char *orig_name) { - for (llvm::Module::iterator fi = module->getFunctionList().begin(), fe = module->getFunctionList().end(); - fi != fe; - ++fi) + for (const auto &func : module->getFunctionList()) { - if (fi->getName().str().find(orig_name) != std::string::npos) + const StringRef &name = func.getName(); + if (name.find(orig_name) != StringRef::npos) { - mangled_name.SetCString(fi->getName().str().c_str()); + mangled_name.SetString(name); return true; } } @@ -521,7 +784,7 @@ static bool FindFunctionInModule (ConstString &mangled_name, return false; } -Error +lldb_private::Error ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, lldb::addr_t &func_end, lldb::IRExecutionUnitSP &execution_unit_sp, @@ -533,7 +796,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, func_end = LLDB_INVALID_ADDRESS; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - Error err; + lldb_private::Error err; std::unique_ptr<llvm::Module> llvm_module_ap (m_code_generator->ReleaseModule()); @@ -544,26 +807,65 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, 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())) + if (execution_policy != eExecutionPolicyTopLevel) { - err.SetErrorToGenericError(); - err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName()); - return err; + // Find the actual name of the function (it's often mangled somehow) + + 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()); + } } - else + + SymbolContext sc; + + if (lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP()) + { + sc = frame_sp->GetSymbolContext(lldb::eSymbolContextEverything); + } + else if (lldb::TargetSP target_sp = exe_ctx.GetTargetSP()) + { + sc.target_sp = target_sp; + } + + LLVMUserExpression::IRPasses custom_passes; { + auto lang = m_expr.Language(); if (log) - log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName()); + log->Printf("%s - Currrent expression language is %s\n", __FUNCTION__, + Language::GetNameForLanguageType(lang)); + + if (lang != lldb::eLanguageTypeUnknown) + { + auto runtime = exe_ctx.GetProcessSP()->GetLanguageRuntime(lang); + if (runtime) + runtime->GetIRPasses(custom_passes); + } + } + + if (custom_passes.EarlyPasses) + { + if (log) + log->Printf("%s - Running Early IR Passes from LanguageRuntime on expression module '%s'", __FUNCTION__, + m_expr.FunctionName()); + + custom_passes.EarlyPasses->run(*llvm_module_ap); } execution_unit_sp.reset(new IRExecutionUnit (m_llvm_context, // handed off here llvm_module_ap, // handed off here function_name, exe_ctx.GetTargetSP(), + sc, m_compiler->getTargetOpts().Features)); ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); @@ -576,20 +878,28 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, if (target) error_stream = target->GetDebugger().GetErrorFile().get(); - IRForTarget ir_for_target(decl_map, - m_expr.NeedsVariableResolution(), - *execution_unit_sp, - error_stream, + 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 (execution_policy != eExecutionPolicyAlways && execution_policy != eExecutionPolicyTopLevel) + { + lldb_private::Error interpret_error; + + bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls(); + can_interpret = + IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), + interpret_error, interpret_function_calls); + if (!can_interpret && execution_policy == eExecutionPolicyNever) + { + err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString()); + return err; + } + } if (!ir_can_run) { @@ -597,19 +907,21 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, return err; } - if (!can_interpret && execution_policy == eExecutionPolicyNever) + if (!process && execution_policy == eExecutionPolicyAlways) { - err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString()); + err.SetErrorString("Expression needed to run in the target, but the target can't be run"); return err; } - if (!process && execution_policy == eExecutionPolicyAlways) + if (!process && execution_policy == eExecutionPolicyTopLevel) { - err.SetErrorString("Expression needed to run in the target, but the target can't be run"); + err.SetErrorString( + "Top-level code needs to be inserted into a runnable target, but the target can't be run"); return err; } - if (execution_policy == eExecutionPolicyAlways || !can_interpret) + if (execution_policy == eExecutionPolicyAlways || + (execution_policy != eExecutionPolicyTopLevel && !can_interpret)) { if (m_expr.NeedsValidation() && process) { @@ -617,14 +929,14 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, { DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); - StreamString install_errors; + DiagnosticManager install_diagnostics; - if (!dynamic_checkers->Install(install_errors, exe_ctx)) + if (!dynamic_checkers->Install(install_diagnostics, exe_ctx)) { - if (install_errors.GetString().empty()) - err.SetErrorString ("couldn't install checkers, unknown error"); + if (install_diagnostics.Diagnostics().size()) + err.SetErrorString("couldn't install checkers, unknown error"); else - err.SetErrorString (install_errors.GetString().c_str()); + err.SetErrorString(install_diagnostics.GetString().c_str()); return err; } @@ -637,14 +949,28 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString()); - if (!ir_dynamic_checks.runOnModule(*execution_unit_sp->GetModule())) + llvm::Module *module = execution_unit_sp->GetModule(); + if (!module || !ir_dynamic_checks.runOnModule(*module)) { err.SetErrorToGenericError(); err.SetErrorString("Couldn't add dynamic checks to the expression"); return err; } + + if (custom_passes.LatePasses) + { + if (log) + log->Printf("%s - Running Late IR Passes from LanguageRuntime on expression module '%s'", + __FUNCTION__, m_expr.FunctionName()); + + custom_passes.LatePasses->run(*module); + } } + } + if (execution_policy == eExecutionPolicyAlways || execution_policy == eExecutionPolicyTopLevel || + !can_interpret) + { execution_unit_sp->GetRunnableInfo(err, func_addr, func_end); } } @@ -655,3 +981,51 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, return err; } + +lldb_private::Error +ClangExpressionParser::RunStaticInitializers (lldb::IRExecutionUnitSP &execution_unit_sp, + ExecutionContext &exe_ctx) +{ + lldb_private::Error err; + + lldbassert(execution_unit_sp.get()); + lldbassert(exe_ctx.HasThreadScope()); + + if (!execution_unit_sp.get()) + { + err.SetErrorString ("can't run static initializers for a NULL execution unit"); + return err; + } + + if (!exe_ctx.HasThreadScope()) + { + err.SetErrorString ("can't run static initializers without a thread"); + return err; + } + + std::vector<lldb::addr_t> static_initializers; + + execution_unit_sp->GetStaticInitializers(static_initializers); + + for (lldb::addr_t static_initializer : static_initializers) + { + EvaluateExpressionOptions options; + + lldb::ThreadPlanSP call_static_initializer(new ThreadPlanCallFunction(exe_ctx.GetThreadRef(), + Address(static_initializer), + CompilerType(), + llvm::ArrayRef<lldb::addr_t>(), + options)); + + DiagnosticManager execution_errors; + lldb::ExpressionResults results = exe_ctx.GetThreadRef().GetProcess()->RunThreadPlan(exe_ctx, call_static_initializer, options, execution_errors); + + if (results != lldb::eExpressionCompleted) + { + err.SetErrorStringWithFormat ("couldn't run static initializer: %s", execution_errors.GetString().c_str()); + return err; + } + } + + return err; +} diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 3c055380b839..34c0212b73a4 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -10,11 +10,12 @@ #ifndef liblldb_ClangExpressionParser_h_ #define liblldb_ClangExpressionParser_h_ -#include "lldb/lldb-public.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/Error.h" +#include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/ExpressionParser.h" +#include "lldb/lldb-public.h" #include <string> #include <vector> @@ -63,16 +64,19 @@ public: /// Parse a single expression and convert it to IR using Clang. Don't /// wrap the expression in anything at all. /// - /// @param[in] stream - /// The stream to print errors to. + /// @param[in] diagnostic_manager + /// The diagnostic manager to report errors to. /// /// @return /// The number of errors encountered during parsing. 0 means /// success. //------------------------------------------------------------------ unsigned - Parse (Stream &stream) override; + Parse(DiagnosticManager &diagnostic_manager) override; + bool + RewriteExpression(DiagnosticManager &diagnostic_manager) override; + //------------------------------------------------------------------ /// Ready an already-parsed expression for execution, possibly /// evaluating it statically. @@ -98,7 +102,7 @@ public: /// /// @param[out] const_result /// If the result of the expression is constant, and the - /// expression has no side effects, this is set to the result of the + /// expression has no side effects, this is set to the result of the /// expression. /// /// @param[in] execution_policy @@ -117,7 +121,35 @@ public: ExecutionContext &exe_ctx, bool &can_interpret, lldb_private::ExecutionPolicy execution_policy) override; - + + //------------------------------------------------------------------ + /// Run all static initializers for an execution unit. + /// + /// @param[in] execution_unit_sp + /// The execution unit. + /// + /// @param[in] exe_ctx + /// The execution context to use when running them. Thread can't be null. + /// + /// @return + /// The error code indicating the + //------------------------------------------------------------------ + Error + RunStaticInitializers (lldb::IRExecutionUnitSP &execution_unit_sp, + ExecutionContext &exe_ctx); + + //------------------------------------------------------------------ + /// Returns a string representing current ABI. + /// + /// @param[in] target_arch + /// The target architecture. + /// + /// @return + /// A string representing target ABI for the current architecture. + //------------------------------------------------------------------- + std::string + GetClangTargetABI (const ArchSpec &target_arch); + private: std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into std::unique_ptr<clang::FileManager> m_file_manager; ///< The Clang file manager object used by the compiler diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 0d0d7475a00e..02c0ad5013ec 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -74,10 +74,15 @@ ClangFunctionCaller::~ClangFunctionCaller() } unsigned -ClangFunctionCaller::CompileFunction (Stream &errors) + +ClangFunctionCaller::CompileFunction (lldb::ThreadSP thread_to_use_sp, + DiagnosticManager &diagnostic_manager) { if (m_compiled) return 0; + + // Compilation might call code, make sure to keep on the thread the caller indicated. + ThreadList::ExpressionExecutionThreadPusher execution_thread_pusher(thread_to_use_sp); // FIXME: How does clang tell us there's no return value? We need to handle that case. unsigned num_errors = 0; @@ -143,8 +148,9 @@ ClangFunctionCaller::CompileFunction (Stream &errors) type_name = clang_qual_type.GetTypeName().AsCString(""); } else - { - errors.Printf("Could not determine type of input value %" PRIu64 ".", (uint64_t)i); + { + diagnostic_manager.Printf(eDiagnosticSeverityError, + "Could not determine type of input value %" PRIu64 ".", (uint64_t)i); return 1; } } @@ -195,15 +201,15 @@ ClangFunctionCaller::CompileFunction (Stream &errors) { 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); + + num_errors = m_parser->Parse(diagnostic_manager); } else { - errors.Printf("no process - unable to inject function"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, "no process - unable to inject function"); num_errors = 1; } - + m_compiled = (num_errors == 0); if (!m_compiled) diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h index 3e30f818a932..468b9c1c76dc 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h +++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h @@ -137,17 +137,23 @@ public: //------------------------------------------------------------------ /// Compile the wrapper function /// - /// @param[in] errors - /// The stream to print parser errors to. + /// @param[in] thread_to_use_sp + /// Compilation might end up calling functions. Pass in the thread you + /// want the compilation to use. If you pass in an empty ThreadSP it will + /// use the currently selected thread. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager to report parser errors to. /// /// @return /// The number of errors. //------------------------------------------------------------------ unsigned - CompileFunction (Stream &errors) override; - + CompileFunction (lldb::ThreadSP thread_to_use_sp, + DiagnosticManager &diagnostic_manager) override; + ExpressionTypeSystemHelper * - GetTypeSystemHelper () override + GetTypeSystemHelper() override { return &m_type_system_helper; } diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 05d8a320a5a4..63a3a85bacb4 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -585,6 +585,7 @@ ClangModulesDeclVendorImpl::ForEachMacro(const ClangModulesDeclVendor::ModuleVec break; case clang::tok::TokenKind::raw_identifier: macro_expansion.append(ti->getRawIdentifier().str()); + break; default: macro_expansion.append(ti->getName()); break; @@ -627,7 +628,9 @@ ClangModulesDeclVendor::Create(Target &target) std::vector<std::string> compiler_invocation_arguments = { + "clang", "-fmodules", + "-fimplicit-module-maps", "-fcxx-modules", "-fsyntax-only", "-femit-all-decls", diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 9bf9d435d7ea..d1478e49bff5 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -14,6 +14,8 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/Value.h" +#include "clang/AST/Decl.h" + #include "llvm/ADT/StringMap.h" using namespace lldb; @@ -66,18 +68,26 @@ ClangPersistentVariables::GetNextPersistentVariableName () } void -ClangPersistentVariables::RegisterPersistentType (const ConstString &name, - clang::TypeDecl *type_decl) +ClangPersistentVariables::RegisterPersistentDecl (const ConstString &name, + clang::NamedDecl *decl) { - m_persistent_types.insert(std::pair<const char*, clang::TypeDecl*>(name.GetCString(), type_decl)); + m_persistent_decls.insert(std::pair<const char*, clang::NamedDecl*>(name.GetCString(), decl)); + + if (clang::EnumDecl *enum_decl = llvm::dyn_cast<clang::EnumDecl>(decl)) + { + for (clang::EnumConstantDecl *enumerator_decl : enum_decl->enumerators()) + { + m_persistent_decls.insert(std::pair<const char*, clang::NamedDecl*>(ConstString(enumerator_decl->getNameAsString()).GetCString(), enumerator_decl)); + } + } } -clang::TypeDecl * -ClangPersistentVariables::GetPersistentType (const ConstString &name) +clang::NamedDecl * +ClangPersistentVariables::GetPersistentDecl (const ConstString &name) { - PersistentTypeMap::const_iterator i = m_persistent_types.find(name.GetCString()); + PersistentDeclMap::const_iterator i = m_persistent_decls.find(name.GetCString()); - if (i == m_persistent_types.end()) + if (i == m_persistent_decls.end()) return NULL; else return i->second; diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 0e03d013d049..2928976592d8 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -70,15 +70,12 @@ public: void RemovePersistentVariable (lldb::ExpressionVariableSP variable) override; - lldb::addr_t - LookupSymbol (const ConstString &name) override { return LLDB_INVALID_ADDRESS; } - void - RegisterPersistentType (const ConstString &name, - clang::TypeDecl *tag_decl); + RegisterPersistentDecl (const ConstString &name, + clang::NamedDecl *decl); - clang::TypeDecl * - GetPersistentType (const ConstString &name); + clang::NamedDecl * + GetPersistentDecl (const ConstString &name); void AddHandLoadedClangModule(ClangModulesDeclVendor::ModuleID module) @@ -94,8 +91,8 @@ public: private: uint32_t m_next_persistent_variable_id; ///< The counter used by GetNextResultName(). - typedef llvm::DenseMap<const char *, clang::TypeDecl *> PersistentTypeMap; - PersistentTypeMap m_persistent_types; ///< The persistent types declared by the user. + typedef llvm::DenseMap<const char *, clang::NamedDecl *> PersistentDeclMap; + PersistentDeclMap m_persistent_decls; ///< Persistent entities declared by the user. ClangModulesDeclVendor::ModuleVector m_hand_loaded_clang_modules; ///< These are Clang modules we hand-loaded; these are the highest- ///< priority source for macros. diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 11f7f84ff5f1..52d49aecec9a 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -23,8 +23,10 @@ #include "ClangExpressionParser.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" +#include "ClangDiagnostic.h" #include "lldb/Core/ConstString.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" @@ -55,28 +57,25 @@ using namespace lldb_private; -ClangUserExpression::ClangUserExpression (ExecutionContextScope &exe_scope, - const char *expr, - const char *expr_prefix, - lldb::LanguageType language, - ResultType desired_type, - const EvaluateExpressionOptions &options) : - LLVMUserExpression (exe_scope, expr, expr_prefix, language, desired_type, options), - m_type_system_helper(*m_target_wp.lock().get()) +ClangUserExpression::ClangUserExpression(ExecutionContextScope &exe_scope, const char *expr, const char *expr_prefix, + lldb::LanguageType language, ResultType desired_type, + const EvaluateExpressionOptions &options) + : LLVMUserExpression(exe_scope, expr, expr_prefix, language, desired_type, options), + m_type_system_helper(*m_target_wp.lock().get(), options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { 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; + 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; } } @@ -326,11 +325,9 @@ ApplyObjcCastHack(std::string &expr) } bool -ClangUserExpression::Parse (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, - bool generate_debug_info) +ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, 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)); @@ -346,13 +343,13 @@ ClangUserExpression::Parse (Stream &error_stream, } else { - error_stream.PutCString ("error: couldn't start parsing (no persistent data)"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, "couldn't start parsing (no persistent data)"); return false; } } else { - error_stream.PutCString ("error: couldn't start parsing (no target)"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, "error: couldn't start parsing (no target)"); return false; } @@ -360,11 +357,9 @@ ClangUserExpression::Parse (Stream &error_stream, if (!err.Success()) { - error_stream.Printf("warning: %s\n", err.AsCString()); + diagnostic_manager.PutCString(eDiagnosticSeverityWarning, err.AsCString()); } - StreamString m_transformed_stream; - //////////////////////////////////// // Generate the expression // @@ -404,22 +399,30 @@ ClangUserExpression::Parse (Stream &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; + lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown; - if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_in_static_method, exe_ctx)) + if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { - error_stream.PutCString ("error: couldn't construct expression body"); - return false; + m_transformed_text = m_expr_text; + } + else + { + std::unique_ptr<ExpressionSourceCode> source_code( + ExpressionSourceCode::CreateWrapped(prefix.c_str(), m_expr_text.c_str())); + + 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_in_static_method, exe_ctx)) + { + diagnostic_manager.PutCString(eDiagnosticSeverityError, "couldn't construct expression body"); + return false; + } } if (log) @@ -433,7 +436,7 @@ ClangUserExpression::Parse (Stream &error_stream, if (!target) { - error_stream.PutCString ("error: invalid target\n"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, "invalid target"); return false; } @@ -467,26 +470,47 @@ ClangUserExpression::Parse (Stream &error_stream, if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) { - error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, + "current process state is unsuitable for expression parsing"); ResetDeclMap(); // We are being careful here in the case of breakpoint conditions. return false; } + if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) + { + DeclMap()->SetLookupsEnabled(true); + } + Process *process = exe_ctx.GetProcessPtr(); ExecutionContextScope *exe_scope = process; if (!exe_scope) exe_scope = exe_ctx.GetTargetPtr(); + // We use a shared pointer here so we can use the original parser - if it succeeds + // or the rewrite parser we might make if it fails. But the parser_sp will never be empty. + ClangExpressionParser parser(exe_scope, *this, generate_debug_info); - unsigned num_errors = parser.Parse (error_stream); + unsigned num_errors = parser.Parse(diagnostic_manager); + // Check here for FixItHints. If there are any try to apply the fixits and set the fixed text in m_fixed_text + // before returning an error. if (num_errors) { - error_stream.Printf ("error: %d errors parsing expression\n", num_errors); + if (diagnostic_manager.HasFixIts()) + { + if (parser.RewriteExpression(diagnostic_manager)) + { + size_t fixed_start; + size_t fixed_end; + const std::string &fixed_expression = diagnostic_manager.GetFixedExpression(); + if (ExpressionSourceCode::GetOriginalBodyBounds(fixed_expression, lang_type, fixed_start, fixed_end)) + m_fixed_text = fixed_expression.substr(fixed_start, fixed_end - fixed_start); + } + } ResetDeclMap(); // We are being careful here in the case of breakpoint conditions. @@ -497,16 +521,70 @@ ClangUserExpression::Parse (Stream &error_stream, // 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); + { + 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 (!jit_error.Success()) + { + const char *error_cstr = jit_error.AsCString(); + if (error_cstr && error_cstr[0]) + diagnostic_manager.PutCString(eDiagnosticSeverityError, error_cstr); + else + diagnostic_manager.PutCString(eDiagnosticSeverityError, "expression can't be interpreted or run"); + return false; + } + } + + if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) + { + Error static_init_error = parser.RunStaticInitializers(m_execution_unit_sp, exe_ctx); + + if (!static_init_error.Success()) + { + const char *error_cstr = static_init_error.AsCString(); + if (error_cstr && error_cstr[0]) + diagnostic_manager.Printf(eDiagnosticSeverityError, "couldn't run static initializers: %s\n", + error_cstr); + else + diagnostic_manager.PutCString(eDiagnosticSeverityError, "couldn't run static initializers\n"); + return false; + } + } + + if (m_execution_unit_sp) + { + bool register_execution_unit = false; + + if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) + { + register_execution_unit = true; + } + + // If there is more than one external function in the execution + // unit, it needs to keep living even if it's not top level, because + // the result could refer to that function. + + if (m_execution_unit_sp->GetJittedFunctions().size() > 1) + { + register_execution_unit = true; + } + + if (register_execution_unit) + { + llvm::cast<PersistentExpressionState>( + exe_ctx.GetTargetPtr()->GetPersistentExpressionStateForLanguage(m_language)) + ->RegisterExecutionUnit(m_execution_unit_sp); + } + } if (generate_debug_info) { - lldb::ModuleSP jit_module_sp ( m_execution_unit_sp->GetJITModule()); + lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule()); if (jit_module_sp) { @@ -517,52 +595,23 @@ ClangUserExpression::Parse (Stream &error_stream, m_jit_module_wp = jit_module_sp; target->GetImages().Append(jit_module_sp); } -// lldb_private::ObjectFile *jit_obj_file = jit_module_sp->GetObjectFile(); -// StreamFile strm (stdout, false); -// if (jit_obj_file) -// { -// jit_obj_file->GetSectionList(); -// jit_obj_file->GetSymtab(); -// jit_obj_file->Dump(&strm); -// } -// lldb_private::SymbolVendor *jit_sym_vendor = jit_module_sp->GetSymbolVendor(); -// if (jit_sym_vendor) -// { -// lldb_private::SymbolContextList sc_list; -// jit_sym_vendor->FindFunctions(const_func_name, NULL, lldb::eFunctionNameTypeFull, true, false, sc_list); -// sc_list.Dump(&strm, target); -// jit_sym_vendor->Dump(&strm); -// } } - ResetDeclMap(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any ClangASTImporter::Minions. + ResetDeclMap(); // Make this go away since we don't need any of its state after parsing. This also gets rid of any + // ClangASTImporter::Minions. - if (jit_error.Success()) - { - if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) - m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); - return true; - } - else - { - const char *error_cstr = jit_error.AsCString(); - if (error_cstr && error_cstr[0]) - error_stream.Printf ("error: %s\n", error_cstr); - else - error_stream.Printf ("error: expression can't be interpreted or run\n"); - return false; - } + if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) + m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); + return true; } bool -ClangUserExpression::AddArguments (ExecutionContext &exe_ctx, - std::vector<lldb::addr_t> &args, - lldb::addr_t struct_address, - Stream &error_stream) +ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, std::vector<lldb::addr_t> &args, + lldb::addr_t struct_address, DiagnosticManager &diagnostic_manager) { lldb::addr_t object_ptr = LLDB_INVALID_ADDRESS; - lldb::addr_t cmd_ptr = LLDB_INVALID_ADDRESS; - + lldb::addr_t cmd_ptr = LLDB_INVALID_ADDRESS; + if (m_needs_object_ptr) { lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP(); @@ -581,7 +630,7 @@ ClangUserExpression::AddArguments (ExecutionContext &exe_ctx, } else { - error_stream.Printf("Need object pointer but don't know the language\n"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, "need object pointer but don't know the language"); return false; } @@ -591,7 +640,7 @@ ClangUserExpression::AddArguments (ExecutionContext &exe_ctx, if (!object_ptr_error.Success()) { - error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); + exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf("warning: `%s' is not accessible (subsituting 0)\n", object_name.AsCString()); object_ptr = 0; } @@ -603,12 +652,14 @@ ClangUserExpression::AddArguments (ExecutionContext &exe_ctx, if (!object_ptr_error.Success()) { - error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString()); + diagnostic_manager.Printf(eDiagnosticSeverityWarning, + "couldn't get cmd pointer (substituting NULL): %s", + object_ptr_error.AsCString()); cmd_ptr = 0; } } - if (object_ptr) - args.push_back(object_ptr); + + args.push_back(object_ptr); if (m_in_objectivec_method) args.push_back(cmd_ptr); @@ -635,14 +686,22 @@ ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(ExecutionContext &e } clang::ASTConsumer * -ClangUserExpression::ClangUserExpressionHelper::ASTTransformer (clang::ASTConsumer *passthrough) +ClangUserExpression::ClangUserExpressionHelper::ASTTransformer(clang::ASTConsumer *passthrough) { - m_result_synthesizer_up.reset(new ASTResultSynthesizer(passthrough, - m_target)); + m_result_synthesizer_up.reset(new ASTResultSynthesizer(passthrough, m_top_level, m_target)); return m_result_synthesizer_up.get(); } +void +ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() +{ + if (m_result_synthesizer_up.get()) + { + m_result_synthesizer_up->CommitPersistentDecls(); + } +} + ClangUserExpression::ResultDelegate::ResultDelegate() { } diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index f2bfe31dce09..6077588b0244 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -51,13 +51,10 @@ public: class ClangUserExpressionHelper : public ClangExpressionHelper { public: - ClangUserExpressionHelper (Target &target) : - m_target(target) - { - } - + ClangUserExpressionHelper(Target &target, bool top_level) : m_target(target), m_top_level(top_level) {} + ~ClangUserExpressionHelper() override = default; - + //------------------------------------------------------------------ /// Return the object that the parser should use when resolving external /// values. May be NULL if everything should be self-contained. @@ -88,11 +85,16 @@ public: clang::ASTConsumer * ASTTransformer(clang::ASTConsumer *passthrough) override; + void + CommitPersistentDecls() override; + private: - Target &m_target; + Target &m_target; std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up; - std::unique_ptr<ASTStructExtractor> m_struct_extractor_up; ///< The class that generates the argument struct layout. + std::unique_ptr<ASTStructExtractor> + m_struct_extractor_up; ///< The class that generates the argument struct layout. std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer_up; + bool m_top_level; }; //------------------------------------------------------------------ @@ -126,8 +128,8 @@ public: //------------------------------------------------------------------ /// Parse the expression /// - /// @param[in] error_stream - /// A stream to print parse errors and warnings to. + /// @param[in] diagnostic_manager + /// A diagnostic manager to report parse errors and warnings to. /// /// @param[in] exe_ctx /// The execution context to use when looking up entities that @@ -145,11 +147,9 @@ public: /// True on success (no errors); false otherwise. //------------------------------------------------------------------ bool - Parse (Stream &error_stream, - ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, - bool generate_debug_info) override; + Parse(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, + bool generate_debug_info) override; ExpressionTypeSystemHelper * GetTypeSystemHelper () override @@ -188,13 +188,11 @@ private: lldb_private::Error &err) override; bool - AddArguments (ExecutionContext &exe_ctx, - std::vector<lldb::addr_t> &args, - lldb::addr_t struct_address, - Stream &error_stream) override; - - ClangUserExpressionHelper m_type_system_helper; - + AddArguments(ExecutionContext &exe_ctx, std::vector<lldb::addr_t> &args, lldb::addr_t struct_address, + DiagnosticManager &diagnostic_manager) override; + + ClangUserExpressionHelper m_type_system_helper; + class ResultDelegate : public Materializer::PersistentVariableDelegate { public: diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index fe044c17ac78..727e4b3329b3 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -55,8 +55,8 @@ ClangUtilityFunction::~ClangUtilityFunction () //------------------------------------------------------------------ /// Install the utility function into a process /// -/// @param[in] error_stream -/// A stream to print parse errors and warnings to. +/// @param[in] diagnostic_manager +/// A diagnostic manager to report errors and warnings to. /// /// @param[in] exe_ctx /// The execution context to install the utility function to. @@ -65,35 +65,34 @@ ClangUtilityFunction::~ClangUtilityFunction () /// True on success (no errors); false otherwise. //------------------------------------------------------------------ bool -ClangUtilityFunction::Install (Stream &error_stream, - ExecutionContext &exe_ctx) +ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { if (m_jit_start_addr != LLDB_INVALID_ADDRESS) { - error_stream.PutCString("error: already installed\n"); + diagnostic_manager.PutCString(eDiagnosticSeverityWarning, "already installed"); return false; } - + //////////////////////////////////// // Set up the target and compiler // Target *target = exe_ctx.GetTargetPtr(); - + if (!target) { - error_stream.PutCString ("error: invalid target\n"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, "invalid target"); return false; } - + Process *process = exe_ctx.GetProcessPtr(); - + if (!process) { - error_stream.PutCString ("error: invalid process\n"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, "invalid process"); return false; } - + ////////////////////////// // Parse the expression // @@ -101,24 +100,23 @@ ClangUtilityFunction::Install (Stream &error_stream, bool keep_result_in_memory = false; ResetDeclMap(exe_ctx, keep_result_in_memory); - + if (!DeclMap()->WillParse(exe_ctx, NULL)) { - error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n"); + diagnostic_manager.PutCString(eDiagnosticSeverityError, + "current process state is unsuitable for expression parsing"); return false; } - + const bool generate_debug_info = true; ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info); - - unsigned num_errors = parser.Parse (error_stream); - + + unsigned num_errors = parser.Parse(diagnostic_manager); + if (num_errors) { - error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - ResetDeclMap(); - + return false; } @@ -175,9 +173,13 @@ ClangUtilityFunction::Install (Stream &error_stream, { const char *error_cstr = jit_error.AsCString(); if (error_cstr && error_cstr[0]) - error_stream.Printf ("error: %s\n", error_cstr); + { + diagnostic_manager.Printf(eDiagnosticSeverityError, "%s", error_cstr); + } else - error_stream.Printf ("error: expression can't be interpreted or run\n"); + { + diagnostic_manager.PutCString(eDiagnosticSeverityError, "expression can't be interpreted or run"); + } return false; } } diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index 74839717946b..d4ed37eee049 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -124,12 +124,12 @@ public: { m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); } - + bool - Install (Stream &error_stream, ExecutionContext &exe_ctx) override; - + Install(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) override; + private: - ClangUtilityFunctionHelper m_type_system_helper; ///< The map to use when parsing and materializing the expression. + ClangUtilityFunctionHelper m_type_system_helper; ///< The map to use when parsing and materializing the expression. }; } // namespace lldb_private diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 509c594280a0..12ba7e3c2ac0 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -25,16 +25,17 @@ #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/Core/dwarf.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include <map> @@ -43,13 +44,6 @@ 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() @@ -72,28 +66,6 @@ IRForTarget::FunctionValueCache::GetValue(llvm::Function *function) 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) { @@ -113,11 +85,11 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map, 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_execution_unit(execution_unit), m_result_store(NULL), m_result_is_pointer(false), m_reloc_placeholder(NULL), @@ -163,213 +135,9 @@ 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) - { - 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) { @@ -572,7 +340,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function) } - lldb::TargetSP target_sp (m_data_allocator.GetTarget()); + lldb::TargetSP target_sp (m_execution_unit.GetTarget()); lldb_private::ExecutionContext exe_ctx (target_sp, true); if (m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()) == 0) { @@ -704,7 +472,8 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str, static lldb_private::ConstString g_CFStringCreateWithBytes_str ("CFStringCreateWithBytes"); - if (!m_decl_map->GetFunctionAddress (g_CFStringCreateWithBytes_str, CFStringCreateWithBytes_addr)) + CFStringCreateWithBytes_addr = m_execution_unit.FindSymbol (g_CFStringCreateWithBytes_str); + if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS) { if (log) log->PutCString("Couldn't find CFStringCreateWithBytes in the target"); @@ -1093,7 +862,8 @@ IRForTarget::RewriteObjCSelector (Instruction* selector_load) 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)) + sel_registerName_addr = m_execution_unit.FindSymbol (g_sel_registerName_str); + if (sel_registerName_addr == LLDB_INVALID_ADDRESS) return false; if (log) @@ -1335,7 +1105,13 @@ IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer) if (ConstantInt *int_initializer = dyn_cast<ConstantInt>(initializer)) { - memcpy (data, int_initializer->getValue().getRawData(), m_target_data->getTypeStoreSize(initializer_type)); + size_t constant_size = m_target_data->getTypeStoreSize(initializer_type); + lldb_private::Scalar scalar = int_initializer->getValue().zextOrTrunc(llvm::NextPowerOf2(constant_size) * 8); + + lldb_private::Error get_data_error; + if (!scalar.GetAsMemoryData(data, constant_size, lldb_private::endian::InlHostByteOrder(), get_data_error)) + return false; + return true; } else if (ConstantDataArray *array_initializer = dyn_cast<ConstantDataArray>(initializer)) @@ -1388,48 +1164,6 @@ IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer) 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) @@ -1455,7 +1189,7 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr) else if (GlobalVariable *global_variable = dyn_cast<GlobalVariable>(llvm_value_ptr)) { if (!GlobalValue::isExternalLinkage(global_variable->getLinkage())) - return MaterializeInternalVariable(global_variable); + return true; clang::NamedDecl *named_decl = DeclForGlobal(global_variable); @@ -1508,11 +1242,8 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr) if (log) { log->Printf("Type of \"%s\" is [clang \"%s\", llvm \"%s\"] [size %" PRIu64 ", align %" PRIu64 "]", - name.c_str(), - lldb_private::ClangASTContext::GetQualType(compiler_type).getAsString().c_str(), - PrintType(value_type).c_str(), - value_size, - value_alignment); + name.c_str(), lldb_private::ClangUtil::GetQualType(compiler_type).getAsString().c_str(), + PrintType(value_type).c_str(), value_size, value_alignment); } @@ -1524,10 +1255,8 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr) { if (!global_variable->hasExternalLinkage()) return true; - else if (HandleSymbol (global_variable)) - return true; else - return false; + return true; } } else if (dyn_cast<llvm::Function>(llvm_value_ptr)) @@ -1783,231 +1512,6 @@ IRForTarget::ResolveExternals (Function &llvm_function) return true; } -bool -IRForTarget::ReplaceStrings () -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - typedef std::map <GlobalVariable *, size_t> OffsetsTy; - - OffsetsTy offsets; - - for (GlobalVariable &gv : m_module->globals()) - { - if (!gv.hasInitializer()) - continue; - - Constant *gc = gv.getInitializer(); - - std::string str; - - if (gc->isNullValue()) - { - Type *gc_type = gc->getType(); - - ArrayType *gc_array_type = dyn_cast<ArrayType>(gc_type); - - if (!gc_array_type) - continue; - - Type *gc_element_type = gc_array_type->getElementType(); - - IntegerType *gc_integer_type = dyn_cast<IntegerType>(gc_element_type); - - if (gc_integer_type->getBitWidth() != 8) - continue; - - str = ""; - } - else - { - ConstantDataArray *gc_array = dyn_cast<ConstantDataArray>(gc); - - if (!gc_array) - continue; - - if (!gc_array->isCString()) - continue; - - if (log) - log->Printf("Found a GlobalVariable with string initializer %s", PrintValue(gc).c_str()); - - str = gc_array->getAsString(); - } - - offsets[&gv] = m_data_allocator.GetStream().GetSize(); - - m_data_allocator.GetStream().Write(str.c_str(), str.length() + 1); - } - - Type *char_ptr_ty = Type::getInt8PtrTy(m_module->getContext()); - - for (OffsetsTy::iterator oi = offsets.begin(), oe = offsets.end(); - oi != oe; - ++oi) - { - GlobalVariable *gv = oi->first; - size_t offset = oi->second; - - Constant *new_initializer = BuildRelocation(char_ptr_ty, offset); - - if (log) - log->Printf("Replacing GV %s with %s", PrintValue(gv).c_str(), PrintValue(new_initializer).c_str()); - - for (llvm::User *u : gv->users()) - { - if (log) - log->Printf("Found use %s", PrintValue(u).c_str()); - - ConstantExpr *const_expr = dyn_cast<ConstantExpr>(u); - StoreInst *store_inst = dyn_cast<StoreInst>(u); - - if (const_expr) - { - if (const_expr->getOpcode() != Instruction::GetElementPtr) - { - if (log) - log->Printf("Use (%s) of string variable is not a GetElementPtr constant", PrintValue(const_expr).c_str()); - - return false; - } - - Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, const_expr->getOperand(0)->getType()); - Constant *new_gep = const_expr->getWithOperandReplaced(0, bit_cast); - - const_expr->replaceAllUsesWith(new_gep); - } - else if (store_inst) - { - Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, store_inst->getValueOperand()->getType()); - - store_inst->setOperand(0, bit_cast); - } - else - { - if (log) - log->Printf("Use (%s) of string variable is neither a constant nor a store", PrintValue(const_expr).c_str()); - - return false; - } - } - - gv->eraseFromParent(); - } - - return true; -} - -bool -IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block) -{ - lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - - typedef SmallVector <Value*, 2> ConstantList; - typedef SmallVector <llvm::Instruction*, 2> UserList; - typedef ConstantList::iterator ConstantIterator; - typedef UserList::iterator UserIterator; - - ConstantList static_constants; - UserList static_users; - - for (BasicBlock::iterator ii = basic_block.begin(), ie = basic_block.end(); - ii != ie; - ++ii) - { - llvm::Instruction &inst = *ii; - - for (Value *operand_val : inst.operand_values()) - { - ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val); - - if (operand_constant_fp/* && operand_constant_fp->getType()->isX86_FP80Ty()*/) - { - static_constants.push_back(operand_val); - static_users.push_back(&*ii); - } - } - } - - ConstantIterator constant_iter; - UserIterator user_iter; - - for (constant_iter = static_constants.begin(), user_iter = static_users.begin(); - constant_iter != static_constants.end(); - ++constant_iter, ++user_iter) - { - Value *operand_val = *constant_iter; - llvm::Instruction *inst = *user_iter; - - ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val); - - if (operand_constant_fp) - { - Type *operand_type = operand_constant_fp->getType(); - - APFloat operand_apfloat = operand_constant_fp->getValueAPF(); - APInt operand_apint = operand_apfloat.bitcastToAPInt(); - - const uint8_t* operand_raw_data = (const uint8_t*)operand_apint.getRawData(); - size_t operand_data_size = operand_apint.getBitWidth() / 8; - - if (log) - { - std::string s; - raw_string_ostream ss(s); - for (size_t index = 0; - index < operand_data_size; - ++index) - { - ss << (uint32_t)operand_raw_data[index]; - ss << " "; - } - ss.flush(); - - log->Printf("Found ConstantFP with size %" PRIu64 " and raw data %s", (uint64_t)operand_data_size, s.c_str()); - } - - lldb_private::DataBufferHeap data(operand_data_size, 0); - - if (lldb_private::endian::InlHostByteOrder() != m_data_allocator.GetStream().GetByteOrder()) - { - uint8_t *data_bytes = data.GetBytes(); - - for (size_t index = 0; - index < operand_data_size; - ++index) - { - data_bytes[index] = operand_raw_data[operand_data_size - (1 + index)]; - } - } - else - { - memcpy(data.GetBytes(), operand_raw_data, operand_data_size); - } - - uint64_t offset = m_data_allocator.GetStream().GetSize(); - - size_t align = m_target_data->getPrefTypeAlignment(operand_type); - - const size_t mask = (align - 1); - uint64_t aligned_offset = (offset + mask) & ~mask; - m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0); - - m_data_allocator.GetStream().Write(data.GetBytes(), operand_data_size); - - llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo(); - - Constant *new_pointer = BuildRelocation(fp_ptr_ty, aligned_offset); - - llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst); - - operand_constant_fp->replaceAllUsesWith(fp_load); - } - } - - return true; -} - static bool isGuardVariableRef(Value *V) { Constant *Old = NULL; @@ -2437,79 +1941,6 @@ IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset) } 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)); @@ -2530,25 +1961,29 @@ IRForTarget::runOnModule (Module &llvm_module) 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())); + Function *const main_function = m_func_name.IsEmpty() ? nullptr : m_module->getFunction(m_func_name.GetStringRef()); - if (!main_function) + if (!m_func_name.IsEmpty() && !main_function) { if (log) - log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str()); + log->Printf("Couldn't find \"%s()\" in the module", m_func_name.AsCString()); if (m_error_stream) - m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str()); + m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", + m_func_name.AsCString()); return false; } - if (!FixFunctionLinkage (*main_function)) + if (main_function) { - if (log) - log->Printf("Couldn't fix the linkage for the function"); + if (!FixFunctionLinkage(*main_function)) + { + if (log) + log->Printf("Couldn't fix the linkage for the function"); - return false; + return false; + } } llvm::Type *int8_ty = Type::getInt8Ty(m_module->getContext()); @@ -2567,14 +2002,17 @@ IRForTarget::runOnModule (Module &llvm_module) // Replace $__lldb_expr_result with a persistent variable // - if (!CreateResultVariable(*main_function)) + if (main_function) { - if (log) - log->Printf("CreateResultVariable() failed"); + if (!CreateResultVariable(*main_function)) + { + if (log) + log->Printf("CreateResultVariable() failed"); - // CreateResultVariable() reports its own errors, so we don't do so here + // CreateResultVariable() reports its own errors, so we don't do so here - return false; + return false; + } } if (log && log->GetVerbose()) @@ -2650,20 +2088,6 @@ IRForTarget::runOnModule (Module &llvm_module) 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) @@ -2705,14 +2129,6 @@ IRForTarget::runOnModule (Module &llvm_module) return false; } - - if (!ReplaceStaticLiterals(*bbi)) - { - if (log) - log->Printf("ReplaceStaticLiterals() failed"); - - return false; - } } } @@ -2720,46 +2136,27 @@ IRForTarget::runOnModule (Module &llvm_module) // 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 (main_function) { - if (log) - log->Printf("ReplaceVariables() failed"); - - // ReplaceVariables() reports its own errors, so we don't do so here - - return false; - } + if (!ResolveExternals(*main_function)) + { + if (log) + log->Printf("ResolveExternals() failed"); - if (!ReplaceStrings()) - { - if (log) - log->Printf("ReplaceStrings() failed"); + // ResolveExternals() reports its own errors, so we don't do so here - return false; - } + return false; + } - if (!CompleteDataAllocation()) - { - if (log) - log->Printf("CompleteDataAllocation() failed"); + if (!ReplaceVariables(*main_function)) + { + if (log) + log->Printf("ReplaceVariables() failed"); - return false; - } + // ReplaceVariables() reports its own errors, so we don't do so here - if (!StripAllGVs(llvm_module)) - { - if (log) - log->Printf("StripAllGVs() failed"); + return false; + } } if (log && log->GetVerbose()) diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/source/Plugins/ExpressionParser/Clang/IRForTarget.h index fb4abcc103de..0f95f67babfd 100644 --- a/source/Plugins/ExpressionParser/Clang/IRForTarget.h +++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.h @@ -214,40 +214,6 @@ private: llvm::Constant **&value_ptr); //------------------------------------------------------------------ - /// Build a function pointer given a type and a raw pointer. - /// - /// @param[in] type - /// The type of the function pointer to be built. - /// - /// @param[in] ptr - /// The value of the pointer. - /// - /// @return - /// The pointer. - //------------------------------------------------------------------ - llvm::Constant * - BuildFunctionPointer (llvm::Type *type, - uint64_t ptr); - - void - RegisterFunctionMetadata (llvm::LLVMContext &context, - llvm::Value *function_ptr, - const char *name); - - //------------------------------------------------------------------ - /// The top-level pass implementation - /// - /// @param[in] llvm_function - /// The function currently being processed. - /// - /// @return - /// True if the function has side effects (or if this cannot - /// be determined); false otherwise. - //------------------------------------------------------------------ - bool - ResolveFunctionPointers (llvm::Module &llvm_module); - - //------------------------------------------------------------------ /// A function-level pass to take the generated global value /// $__lldb_expr_result and make it into a persistent variable. /// Also see ASTResultSynthesizer. @@ -565,38 +531,6 @@ private: RemoveGuards (llvm::BasicBlock &basic_block); //------------------------------------------------------------------ - /// A module-level pass to allocate all string literals in a separate - /// allocation and redirect references to them. - //------------------------------------------------------------------ - - //------------------------------------------------------------------ - /// The top-level pass implementation - /// - /// @return - /// True on success; false otherwise - //------------------------------------------------------------------ - bool - ReplaceStrings (); - - //------------------------------------------------------------------ - /// A basic block-level pass to find all literals that will be - /// allocated as statics by the JIT (in contrast to the Strings, - /// which already are statics) and synthesize loads for them. - //------------------------------------------------------------------ - - //------------------------------------------------------------------ - /// The top-level pass implementation - /// - /// @param[in] basic_block - /// The basic block currently being processed. - /// - /// @return - /// True on success; false otherwise - //------------------------------------------------------------------ - bool - ReplaceStaticLiterals (llvm::BasicBlock &basic_block); - - //------------------------------------------------------------------ /// A function-level pass to make all external variable references /// point at the correct offsets from the void* passed into the /// function. ClangExpressionDeclMap::DoStructLayout() must be called @@ -612,73 +546,45 @@ private: /// @return /// True on success; false otherwise //------------------------------------------------------------------ - bool - ReplaceVariables (llvm::Function &llvm_function); - - //------------------------------------------------------------------ - /// A module-level pass to remove all global variables from the - /// module since it no longer should export or import any symbols. - //------------------------------------------------------------------ - - //------------------------------------------------------------------ - /// The top-level pass implementation - /// - /// @param[in] llvm_module - /// The module currently being processed. - /// - /// @return - /// True on success; false otherwise - //------------------------------------------------------------------ bool - StripAllGVs (llvm::Module &llvm_module); - - class StaticDataAllocator { - public: - StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit); - lldb_private::StreamString &GetStream() - { - return m_stream_string; - } - lldb::addr_t Allocate(); + ReplaceVariables(llvm::Function &llvm_function); - lldb::TargetSP - GetTarget(); - private: - lldb_private::IRExecutionUnit &m_execution_unit; - lldb_private::StreamString m_stream_string; - lldb::addr_t m_allocation; - }; - /// Flags - bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved - std::string m_func_name; ///< The name of the function to translate - lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...) - lldb_private::TypeFromParser m_result_type; ///< The type of the result variable. - llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet. - std::unique_ptr<llvm::DataLayout> m_target_data; ///< The target data for the module being processed, or NULL if there is no module. - lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls - StaticDataAllocator m_data_allocator; ///< The allocator to use for constant strings - llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type - llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type - llvm::IntegerType *m_intptr_ty; ///< The type of an integer large enough to hold a pointer. - lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed - - llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL. - bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in ASTResultSynthesizer::SynthesizeBodyResult) - - llvm::GlobalVariable *m_reloc_placeholder; ///< A placeholder that will be replaced by a pointer to the final location of the static allocation. - - //------------------------------------------------------------------ - /// UnfoldConstant operates on a constant [Old] which has just been - /// replaced with a value [New]. We assume that new_value has - /// been properly placed early in the function, in front of the - /// first instruction in the entry basic block - /// [FirstEntryInstruction]. - /// - /// UnfoldConstant reads through the uses of Old and replaces Old - /// in those uses with New. Where those uses are constants, the - /// function generates new instructions to compute the result of the - /// new, non-constant expression and places them before + bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved + lldb_private::ConstString m_func_name; ///< The name of the function to translate + lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...) + lldb_private::TypeFromParser m_result_type; ///< The type of the result variable. + llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet. + std::unique_ptr<llvm::DataLayout> + m_target_data; ///< The target data for the module being processed, or NULL if there is no module. + lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls + llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the + ///appropriate function pointer type + llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate + ///function pointer type + llvm::IntegerType *m_intptr_ty; ///< The type of an integer large enough to hold a pointer. + lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed + lldb_private::IRExecutionUnit &m_execution_unit; ///< The execution unit containing the IR being created. + + llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If + ///m_has_side_effects is true, this is NULL. + bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in + ///ASTResultSynthesizer::SynthesizeBodyResult) + + llvm::GlobalVariable *m_reloc_placeholder; ///< A placeholder that will be replaced by a pointer to the final + ///location of the static allocation. + + //------------------------------------------------------------------ + /// UnfoldConstant operates on a constant [Old] which has just been + /// replaced with a value [New]. We assume that new_value has + /// been properly placed early in the function, in front of the + /// first instruction in the entry basic block + /// [FirstEntryInstruction]. + /// + /// UnfoldConstant reads through the uses of Old and replaces Old + /// in those uses with New. Where those uses are constants, the + /// function generates new instructions to compute the result of the + /// new, non-constant expression and places them before /// FirstEntryInstruction. These instructions replace the constant /// uses, so UnfoldConstant calls itself recursively for those. /// @@ -688,7 +594,7 @@ private: /// @return /// True on success; false otherwise //------------------------------------------------------------------ - + class FunctionValueCache { public: typedef std::function <llvm::Value *(llvm::Function *)> Maker; diff --git a/source/Plugins/ExpressionParser/Clang/Makefile b/source/Plugins/ExpressionParser/Clang/Makefile deleted file mode 100644 index eb592daabb48..000000000000 --- a/source/Plugins/ExpressionParser/Clang/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- source/Plugins/ExpressionParser/Clang ---------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LLDB_LEVEL := ../../../.. -LIBRARYNAME := lldbPluginExpressionParserClang -BUILD_ARCHIVE = 1 - -include $(LLDB_LEVEL)/Makefile |