diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /lldb/source/Plugins | |
parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) | |
download | src-706b4fc47bbc608932d3b491ae19a3b9cde9497b.tar.gz src-706b4fc47bbc608932d3b491ae19a3b9cde9497b.zip |
Vendor import of llvm-project master e26a78e70, the last commit beforevendor/llvm-project/llvmorg-10-init-17466-ge26a78e7085
the llvmorg-11-init tag, from which release/10.x was branched.
Notes
Notes:
svn path=/vendor/llvm-project/master/; revision=356843
svn path=/vendor/llvm-project/llvmorg-10-init-17466-ge26a78e7085/; revision=356844; tag=vendor/llvm-project/llvmorg-10-init-17466-ge26a78e7085
Diffstat (limited to 'lldb/source/Plugins')
157 files changed, 5513 insertions, 4959 deletions
diff --git a/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp b/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp index 6473ccf9a19a..ec7588dfb50c 100644 --- a/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp +++ b/lldb/source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp @@ -2020,6 +2020,8 @@ bool ABIMacOSX_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { // registers x19 through x28 and sp are callee preserved. v8-v15 are non- // volatile (and specifically only the lower 8 bytes of these regs), the rest // of the fp/SIMD registers are volatile. +// +// v. https://github.com/ARM-software/software-standards/blob/master/abi/aapcs64/ // We treat x29 as callee preserved also, else the unwinder won't try to // retrieve fp saves. diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index 28c9de2c1e96..dbdb3520087e 100644 --- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -20,6 +20,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetRegistry.h" @@ -949,8 +950,9 @@ DisassemblerLLVMC::MCDisasmInstance::Create(const char *triple, const char *cpu, if (!subtarget_info_up) return Instance(); + llvm::MCTargetOptions MCOptions; std::unique_ptr<llvm::MCAsmInfo> asm_info_up( - curr_target->createMCAsmInfo(*reg_info_up, triple)); + curr_target->createMCAsmInfo(*reg_info_up, triple, MCOptions)); if (!asm_info_up) return Instance(); @@ -1018,7 +1020,7 @@ uint64_t DisassemblerLLVMC::MCDisasmInstance::GetMCInst( uint64_t new_inst_size; status = m_disasm_up->getInstruction(mc_inst, new_inst_size, data, pc, - llvm::nulls(), llvm::nulls()); + llvm::nulls()); if (status == llvm::MCDisassembler::Success) return new_inst_size; else @@ -1032,8 +1034,8 @@ void DisassemblerLLVMC::MCDisasmInstance::PrintMCInst( llvm::raw_string_ostream comments_stream(comments_string); m_instr_printer_up->setCommentStream(comments_stream); - m_instr_printer_up->printInst(&mc_inst, inst_stream, llvm::StringRef(), - *m_subtarget_info_up); + m_instr_printer_up->printInst(&mc_inst, 0, llvm::StringRef(), + *m_subtarget_info_up, inst_stream); m_instr_printer_up->setCommentStream(llvm::nulls()); comments_stream.flush(); @@ -1212,7 +1214,7 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, if (llvm_arch == llvm::Triple::arm) { std::string thumb_triple(thumb_arch.GetTriple().getTriple()); m_alternate_disasm_up = - MCDisasmInstance::Create(thumb_triple.c_str(), "", features_str.c_str(), + MCDisasmInstance::Create(thumb_triple.c_str(), "", features_str.c_str(), flavor, *this); if (!m_alternate_disasm_up) m_disasm_up.reset(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp deleted file mode 100644 index f33a713cc0b2..000000000000 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp +++ /dev/null @@ -1,104 +0,0 @@ -//===-- ASTDumper.cpp -------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "ASTDumper.h" - -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" -#include "lldb/Symbol/CompilerType.h" -#include "lldb/Utility/Log.h" - -#include "llvm/Support/raw_ostream.h" - -using namespace lldb_private; - -ASTDumper::ASTDumper(clang::Decl *decl) { - clang::DeclContext *decl_ctx = llvm::dyn_cast<clang::DeclContext>(decl); - - bool has_external_lexical_storage; - bool has_external_visible_storage; - - if (decl_ctx) { - has_external_lexical_storage = decl_ctx->hasExternalLexicalStorage(); - has_external_visible_storage = decl_ctx->hasExternalVisibleStorage(); - decl_ctx->setHasExternalLexicalStorage(false); - decl_ctx->setHasExternalVisibleStorage(false); - } - - llvm::raw_string_ostream os(m_dump); - decl->print(os); - os.flush(); - - if (decl_ctx) { - decl_ctx->setHasExternalLexicalStorage(has_external_lexical_storage); - decl_ctx->setHasExternalVisibleStorage(has_external_visible_storage); - } -} - -ASTDumper::ASTDumper(clang::DeclContext *decl_ctx) { - bool has_external_lexical_storage = decl_ctx->hasExternalLexicalStorage(); - bool has_external_visible_storage = decl_ctx->hasExternalVisibleStorage(); - - decl_ctx->setHasExternalLexicalStorage(false); - decl_ctx->setHasExternalVisibleStorage(false); - - if (clang::Decl *decl = llvm::dyn_cast<clang::Decl>(decl_ctx)) { - llvm::raw_string_ostream os(m_dump); - decl->print(os); - os.flush(); - } else { - m_dump.assign("<DeclContext is not a Decl>"); - } - - decl_ctx->setHasExternalLexicalStorage(has_external_lexical_storage); - decl_ctx->setHasExternalVisibleStorage(has_external_visible_storage); -} - -ASTDumper::ASTDumper(const clang::Type *type) { - m_dump = clang::QualType(type, 0).getAsString(); -} - -ASTDumper::ASTDumper(clang::QualType type) { m_dump = type.getAsString(); } - -ASTDumper::ASTDumper(lldb::opaque_compiler_type_t type) { - m_dump = clang::QualType::getFromOpaquePtr(type).getAsString(); -} - -ASTDumper::ASTDumper(const CompilerType &compiler_type) { - m_dump = ClangUtil::GetQualType(compiler_type).getAsString(); -} - -const char *ASTDumper::GetCString() { return m_dump.c_str(); } - -void ASTDumper::ToLog(Log *log, const char *prefix) { - size_t len = m_dump.length() + 1; - - char *alloc = (char *)malloc(len); - char *str = alloc; - - memcpy(str, m_dump.c_str(), len); - - char *end = nullptr; - - end = strchr(str, '\n'); - - while (end) { - *end = '\0'; - - LLDB_LOGF(log, "%s%s", prefix, str); - - *end = '\n'; - - str = end + 1; - end = strchr(str, '\n'); - } - - LLDB_LOGF(log, "%s%s", prefix, str); - - free(alloc); -} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.h deleted file mode 100644 index ddf055d9c0c3..000000000000 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTDumper.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- ASTDumper.h ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_ASTDumper_h_ -#define liblldb_ASTDumper_h_ - -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/TypeVisitor.h" - -#include "lldb/Utility/Stream.h" -#include "llvm/ADT/DenseSet.h" - -namespace lldb_private { - -class ASTDumper { -public: - ASTDumper(clang::Decl *decl); - ASTDumper(clang::DeclContext *decl_ctx); - ASTDumper(const clang::Type *type); - ASTDumper(clang::QualType type); - ASTDumper(lldb::opaque_compiler_type_t type); - ASTDumper(const CompilerType &compiler_type); - - const char *GetCString(); - void ToSTDERR(); - void ToLog(Log *log, const char *prefix); - void ToStream(lldb::StreamSP &stream); - -private: - std::string m_dump; -}; - -} // namespace lldb_private - -#endif diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 68eaad33f51c..77bb9544ea40 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -388,8 +388,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, // replace the old statement with the new one // - *last_stmt_ptr = - reinterpret_cast<Stmt *>(result_initialization_stmt_result.get()); + *last_stmt_ptr = static_cast<Stmt *>(result_initialization_stmt_result.get()); return true; } @@ -448,13 +447,20 @@ void ASTResultSynthesizer::RecordPersistentDecl(NamedDecl *D) { } void ASTResultSynthesizer::CommitPersistentDecls() { + auto *state = + m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC); + if (!state) + return; + + auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); + ClangASTContext *scratch_ctx = ClangASTContext::GetScratch(m_target); + 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); + &scratch_ctx->getASTContext(), decl); if (!D_scratch) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -472,10 +478,8 @@ void ASTResultSynthesizer::CommitPersistentDecls() { } if (NamedDecl *NamedDecl_scratch = dyn_cast<NamedDecl>(D_scratch)) - llvm::cast<ClangPersistentVariables>( - m_target.GetPersistentExpressionStateForLanguage( - lldb::eLanguageTypeC)) - ->RegisterPersistentDecl(name_cs, NamedDecl_scratch); + persistent_vars->RegisterPersistentDecl(name_cs, NamedDecl_scratch, + scratch_ctx); } } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h index 670ba6dce72e..0b0f3b97705d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h @@ -135,18 +135,11 @@ private: void RecordPersistentTypes(clang::DeclContext *FunDeclCtx); /// Given a TypeDecl, if it declares a type whose name starts with a dollar - /// sign, register it as a pointer type in the target's scratch - /// AST context. - /// - /// \param[in] Body - /// The body of the function. + /// sign, register it as a pointer type in the target's scratch AST context. void MaybeRecordPersistentType(clang::TypeDecl *D); /// Given a NamedDecl, register it as a pointer type in the target's scratch /// AST context. - /// - /// \param[in] Body - /// The body of the function. void RecordPersistentDecl(clang::NamedDecl *D); clang::ASTContext diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp index 190eacaa2b62..a164d48ae3e0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp @@ -30,8 +30,8 @@ ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough, const char *struct_name, ClangFunctionCaller &function) : m_ast_context(nullptr), m_passthrough(passthrough), - m_passthrough_sema(nullptr), m_sema(nullptr), m_action(nullptr), - m_function(function), m_struct_name(struct_name) { + m_passthrough_sema(nullptr), m_sema(nullptr), m_function(function), + m_struct_name(struct_name) { if (!m_passthrough) return; @@ -170,7 +170,6 @@ void ASTStructExtractor::PrintStats() { void ASTStructExtractor::InitializeSema(Sema &S) { m_sema = &S; - m_action = reinterpret_cast<Action *>(m_sema); if (m_passthrough_sema) m_passthrough_sema->InitializeSema(S); @@ -178,7 +177,6 @@ void ASTStructExtractor::InitializeSema(Sema &S) { void ASTStructExtractor::ForgetSema() { m_sema = nullptr; - m_action = nullptr; if (m_passthrough_sema) m_passthrough_sema->ForgetSema(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h index 7aef2e254e1f..078cf095975f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h @@ -121,8 +121,6 @@ private: ///for passthrough. NULL if it's an ///ASTConsumer. clang::Sema *m_sema; ///< The Sema to use. - clang::Action - *m_action; ///< The Sema to use, cast to an Action so it's usable. ClangFunctionCaller &m_function; ///< The function to populate with ///information about the argument structure. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 372c2439ebf0..42927ab6cc8a 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -8,7 +8,6 @@ #include "ClangASTSource.h" -#include "ASTDumper.h" #include "ClangDeclVendor.h" #include "ClangModulesDeclVendor.h" @@ -50,114 +49,42 @@ private: }; } -ClangASTSource::ClangASTSource(const lldb::TargetSP &target) +ClangASTSource::ClangASTSource(const lldb::TargetSP &target, + const lldb::ClangASTImporterSP &importer) : m_import_in_progress(false), m_lookups_enabled(false), m_target(target), m_ast_context(nullptr), m_active_lexical_decls(), m_active_lookups() { - if (!target->GetUseModernTypeLookup()) { - m_ast_importer_sp = m_target->GetClangASTImporter(); - } + m_ast_importer_sp = importer; } -void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context, - clang::FileManager &file_manager, - bool is_shared_context) { - m_ast_context = &ast_context; - m_file_manager = &file_manager; - if (m_target->GetUseModernTypeLookup()) { - // Configure the ExternalASTMerger. The merger needs to be able to import - // types from any source that we would do lookups in, which includes the - // persistent AST context as well as the modules and Objective-C runtime - // AST contexts. - - lldbassert(!m_merger_up); - clang::ExternalASTMerger::ImporterTarget target = {ast_context, - file_manager}; - std::vector<clang::ExternalASTMerger::ImporterSource> sources; - for (lldb::ModuleSP module_sp : m_target->GetImages().Modules()) { - auto type_system_or_err = - module_sp->GetTypeSystemForLanguage(lldb::eLanguageTypeC); - if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR( - lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS), - std::move(err), "Failed to get ClangASTContext"); - } else if (auto *module_ast_ctx = llvm::cast_or_null<ClangASTContext>( - &type_system_or_err.get())) { - lldbassert(module_ast_ctx->getASTContext()); - lldbassert(module_ast_ctx->getFileManager()); - sources.emplace_back(*module_ast_ctx->getASTContext(), - *module_ast_ctx->getFileManager(), - module_ast_ctx->GetOriginMap()); - } - } - - do { - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - break; - - ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); - - if (!language_runtime) - break; - - if (auto *runtime_decl_vendor = llvm::dyn_cast_or_null<ClangDeclVendor>( - language_runtime->GetDeclVendor())) { - sources.push_back(runtime_decl_vendor->GetImporterSource()); - } - } while (false); - - do { - auto *modules_decl_vendor = m_target->GetClangModulesDeclVendor(); - - if (!modules_decl_vendor) - break; - - sources.push_back(modules_decl_vendor->GetImporterSource()); - } while (false); - - if (!is_shared_context) { - // Update the scratch AST context's merger to reflect any new sources we - // might have come across since the last time an expression was parsed. - - auto scratch_ast_context = static_cast<ClangASTContextForExpressions*>( - m_target->GetScratchClangASTContext()); - - scratch_ast_context->GetMergerUnchecked().AddSources(sources); - - sources.push_back({*scratch_ast_context->getASTContext(), - *scratch_ast_context->getFileManager(), - scratch_ast_context->GetOriginMap()}); - } - - m_merger_up = - std::make_unique<clang::ExternalASTMerger>(target, sources); - } else { - m_ast_importer_sp->InstallMapCompleter(&ast_context, *this); - } +void ClangASTSource::InstallASTContext(ClangASTContext &clang_ast_context) { + m_ast_context = &clang_ast_context.getASTContext(); + m_clang_ast_context = &clang_ast_context; + m_file_manager = &m_ast_context->getSourceManager().getFileManager(); + m_ast_importer_sp->InstallMapCompleter(m_ast_context, *this); } ClangASTSource::~ClangASTSource() { - if (m_ast_importer_sp) - m_ast_importer_sp->ForgetDestination(m_ast_context); + if (!m_ast_importer_sp) + return; + + m_ast_importer_sp->ForgetDestination(m_ast_context); + if (!m_target) + return; // We are in the process of destruction, don't create clang ast context on // demand by passing false to // Target::GetScratchClangASTContext(create_on_demand). ClangASTContext *scratch_clang_ast_context = - m_target->GetScratchClangASTContext(false); + ClangASTContext::GetScratch(*m_target, false); if (!scratch_clang_ast_context) return; - clang::ASTContext *scratch_ast_context = + clang::ASTContext &scratch_ast_context = scratch_clang_ast_context->getASTContext(); - if (!scratch_ast_context) - return; - - if (m_ast_context != scratch_ast_context && m_ast_importer_sp) - m_ast_importer_sp->ForgetSource(scratch_ast_context, m_ast_context); + if (m_ast_context != &scratch_ast_context && m_ast_importer_sp) + m_ast_importer_sp->ForgetSource(&scratch_ast_context, m_ast_context); } void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) { @@ -279,9 +206,8 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { current_id, static_cast<void *>(m_ast_context), static_cast<void *>(tag_decl), tag_decl->getName().str().c_str()); - LLDB_LOGF(log, " CTD[%u] Before:", current_id); - ASTDumper dumper((Decl *)tag_decl); - dumper.ToLog(log, " [CTD] "); + LLDB_LOG(log, " CTD[%u] Before:\n{0}", current_id, + ClangUtil::DumpDecl(tag_decl)); } auto iter = m_active_lexical_decls.find(tag_decl); @@ -291,9 +217,6 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl); if (!m_ast_importer_sp) { - if (HasMerger()) { - GetMergerUnchecked().CompleteType(tag_decl); - } return; } @@ -365,7 +288,6 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { TypeList types; ConstString name(tag_decl->getName().str().c_str()); - CompilerDeclContext namespace_decl; const ModuleList &module_list = m_target->GetImages(); @@ -407,50 +329,30 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { } } - if (log) { - LLDB_LOGF(log, " [CTD] After:"); - ASTDumper dumper((Decl *)tag_decl); - dumper.ToLog(log, " [CTD] "); - } + LLDB_LOG(log, " [CTD] After:\n{0}", ClangUtil::DumpDecl(tag_decl)); } void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (log) { - LLDB_LOGF(log, - " [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing " - "an ObjCInterfaceDecl named %s", - static_cast<void *>(m_ast_context), - interface_decl->getName().str().c_str()); - LLDB_LOGF(log, " [COID] Before:"); - ASTDumper dumper((Decl *)interface_decl); - dumper.ToLog(log, " [COID] "); - } + LLDB_LOGF(log, + " [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing " + "an ObjCInterfaceDecl named %s", + static_cast<void *>(m_ast_context), + interface_decl->getName().str().c_str()); + LLDB_LOG(log, " [COID] Before:\n{0}", + ClangUtil::DumpDecl(interface_decl)); if (!m_ast_importer_sp) { - if (HasMerger()) { - ObjCInterfaceDecl *complete_iface_decl = - GetCompleteObjCInterface(interface_decl); - - if (complete_iface_decl && (complete_iface_decl != interface_decl)) { - m_merger_up->ForceRecordOrigin(interface_decl, {complete_iface_decl, &complete_iface_decl->getASTContext()}); - } - - GetMergerUnchecked().CompleteType(interface_decl); - } else { - lldbassert(0 && "No mechanism for completing a type!"); - } + lldbassert(0 && "No mechanism for completing a type!"); return; } - Decl *original_decl = nullptr; - ASTContext *original_ctx = nullptr; + ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(interface_decl); - if (m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl, - &original_ctx)) { + if (original.Valid()) { if (ObjCInterfaceDecl *original_iface_decl = - dyn_cast<ObjCInterfaceDecl>(original_decl)) { + dyn_cast<ObjCInterfaceDecl>(original.decl)) { ObjCInterfaceDecl *complete_iface_decl = GetCompleteObjCInterface(original_iface_decl); @@ -468,8 +370,7 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { if (log) { LLDB_LOGF(log, " [COID] After:"); - ASTDumper dumper((Decl *)interface_decl); - dumper.ToLog(log, " [COID] "); + LLDB_LOG(log, " [COID] {0}", ClangUtil::DumpDecl(interface_decl)); } } @@ -519,23 +420,9 @@ void ClangASTSource::FindExternalLexicalDecls( llvm::function_ref<bool(Decl::Kind)> predicate, llvm::SmallVectorImpl<Decl *> &decls) { - if (HasMerger()) { - if (auto *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl_context)) { - ObjCInterfaceDecl *complete_iface_decl = - GetCompleteObjCInterface(interface_decl); - - if (complete_iface_decl && (complete_iface_decl != interface_decl)) { - m_merger_up->ForceRecordOrigin(interface_decl, {complete_iface_decl, &complete_iface_decl->getASTContext()}); - } - } - return GetMergerUnchecked().FindExternalLexicalDecls(decl_context, - predicate, - decls); - } else if (!m_ast_importer_sp) + if (!m_ast_importer_sp) return; - ClangASTMetrics::RegisterLexicalQuery(); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); const Decl *context_decl = dyn_cast<Decl>(decl_context); @@ -574,42 +461,38 @@ void ClangASTSource::FindExternalLexicalDecls( current_id, static_cast<const void *>(m_ast_context)); } - Decl *original_decl = nullptr; - ASTContext *original_ctx = nullptr; + ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(context_decl); - if (!m_ast_importer_sp->ResolveDeclOrigin(context_decl, &original_decl, - &original_ctx)) + if (!original.Valid()) return; - if (log) { - LLDB_LOGF( - log, " FELD[%u] Original decl (ASTContext*)%p (Decl*)%p:", current_id, - static_cast<void *>(original_ctx), static_cast<void *>(original_decl)); - ASTDumper(original_decl).ToLog(log, " "); - } + LLDB_LOG( + log, " FELD[{0}] Original decl (ASTContext*){1:x} (Decl*){2:x}:\n{3}", + current_id, static_cast<void *>(original.ctx), + static_cast<void *>(original.decl), ClangUtil::DumpDecl(original.decl)); if (ObjCInterfaceDecl *original_iface_decl = - dyn_cast<ObjCInterfaceDecl>(original_decl)) { + dyn_cast<ObjCInterfaceDecl>(original.decl)) { ObjCInterfaceDecl *complete_iface_decl = GetCompleteObjCInterface(original_iface_decl); if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) { - original_decl = complete_iface_decl; - original_ctx = &complete_iface_decl->getASTContext(); + original.decl = complete_iface_decl; + original.ctx = &complete_iface_decl->getASTContext(); m_ast_importer_sp->SetDeclOrigin(context_decl, complete_iface_decl); } } - if (TagDecl *original_tag_decl = dyn_cast<TagDecl>(original_decl)) { - ExternalASTSource *external_source = original_ctx->getExternalSource(); + if (TagDecl *original_tag_decl = dyn_cast<TagDecl>(original.decl)) { + ExternalASTSource *external_source = original.ctx->getExternalSource(); if (external_source) external_source->CompleteType(original_tag_decl); } const DeclContext *original_decl_context = - dyn_cast<DeclContext>(original_decl); + dyn_cast<DeclContext>(original.decl); if (!original_decl_context) return; @@ -625,16 +508,16 @@ void ClangASTSource::FindExternalLexicalDecls( // See clang::ExternalASTSource::FindExternalLexicalDecls() if (predicate(decl->getKind())) { if (log) { - ASTDumper ast_dumper(decl); + std::string ast_dump = ClangUtil::DumpDecl(decl); if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl)) LLDB_LOGF(log, " FELD[%d] Adding [to %sDecl %s] lexical %sDecl %s", current_id, context_named_decl->getDeclKindName(), context_named_decl->getNameAsString().c_str(), - decl->getDeclKindName(), ast_dumper.GetCString()); + decl->getDeclKindName(), ast_dump.c_str()); else LLDB_LOGF(log, " FELD[%d] Adding lexical %sDecl %s", current_id, - decl->getDeclKindName(), ast_dumper.GetCString()); + decl->getDeclKindName(), ast_dump.c_str()); } Decl *copied_decl = CopyDecl(decl); @@ -647,20 +530,6 @@ void ClangASTSource::FindExternalLexicalDecls( m_ast_importer_sp->RequireCompleteType(copied_field_type); } - auto decl_context_non_const = const_cast<DeclContext *>(decl_context); - - // The decl ended up in the wrong DeclContext. Let's fix that so - // the decl we copied will actually be found. - // FIXME: This is a horrible hack that shouldn't be necessary. However - // it seems our current setup sometimes fails to copy decls to the right - // place. See rdar://55129537. - if (copied_decl->getDeclContext() != decl_context) { - assert(copied_decl->getDeclContext()->containsDecl(copied_decl)); - copied_decl->getDeclContext()->removeDecl(copied_decl); - copied_decl->setDeclContext(decl_context_non_const); - assert(!decl_context_non_const->containsDecl(copied_decl)); - decl_context_non_const->addDeclInternal(copied_decl); - } } else { SkippedDecls = true; } @@ -683,8 +552,6 @@ void ClangASTSource::FindExternalLexicalDecls( void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { assert(m_ast_context); - ClangASTMetrics::RegisterVisibleQuery(); - const ConstString name(context.m_decl_name.getAsString().c_str()); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -715,25 +582,6 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { name.GetCString(), context.m_decl_context->getDeclKindName()); } - if (HasMerger() && !isa<TranslationUnitDecl>(context.m_decl_context) - /* possibly handle NamespaceDecls here? */) { - if (auto *interface_decl = - dyn_cast<ObjCInterfaceDecl>(context.m_decl_context)) { - ObjCInterfaceDecl *complete_iface_decl = - GetCompleteObjCInterface(interface_decl); - - if (complete_iface_decl && (complete_iface_decl != interface_decl)) { - GetMergerUnchecked().ForceRecordOrigin( - interface_decl, - {complete_iface_decl, &complete_iface_decl->getASTContext()}); - } - } - - GetMergerUnchecked().FindExternalVisibleDeclsByName(context.m_decl_context, - context.m_decl_name); - return; // otherwise we may need to fall back - } - context.m_namespace_map = std::make_shared<ClangASTImporter::NamespaceMap>(); if (const NamespaceDecl *namespace_context = @@ -758,7 +606,7 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { FindExternalVisibleDecls(context, i->first, i->second, current_id); } - } else if (isa<ObjCInterfaceDecl>(context.m_decl_context) && !HasMerger()) { + } else if (isa<ObjCInterfaceDecl>(context.m_decl_context)) { FindObjCPropertyAndIvarDecls(context); } else if (!isa<TranslationUnitDecl>(context.m_decl_context)) { // we shouldn't be getting FindExternalVisibleDecls calls for these @@ -788,7 +636,7 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { } clang::Sema *ClangASTSource::getSema() { - return ClangASTContext::GetASTContext(m_ast_context)->getSema(); + return m_clang_ast_context->getSema(); } bool ClangASTSource::IgnoreName(const ConstString name, @@ -821,6 +669,9 @@ void ClangASTSource::FindExternalVisibleDecls( if (IgnoreName(name, true)) return; + if (!m_target) + return; + if (module_sp && namespace_decl) { CompilerDeclContext found_namespace_decl; @@ -837,7 +688,7 @@ void ClangASTSource::FindExternalVisibleDecls( module_sp->GetFileSpec().GetFilename().GetCString()); } } - } else if (!HasMerger()) { + } else { const ModuleList &target_images = m_target->GetImages(); std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); @@ -1049,11 +900,10 @@ public: template <class D> DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTSource &source) { - DeclFromUser<> origin_decl; - source.ResolveDeclOrigin(this->decl, &origin_decl.decl, nullptr); - if (origin_decl.IsInvalid()) + ClangASTImporter::DeclOrigin origin = source.GetDeclOrigin(this->decl); + if (!origin.Valid()) return DeclFromUser<D>(); - return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl)); + return DeclFromUser<D>(dyn_cast<D>(origin.decl)); } template <class D> @@ -1137,11 +987,8 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (log) { - ASTDumper dumper((Decl *)copied_method_decl); - LLDB_LOGF(log, " CAS::FOMD[%d] found (%s) %s", current_id, log_info, - dumper.GetCString()); - } + LLDB_LOG(log, " CAS::FOMD[{0}] found ({1}) {2}", current_id, log_info, + ClangUtil::DumpDecl(copied_method_decl)); context.AddNamedDecl(copied_method_decl); } @@ -1152,21 +999,6 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (HasMerger()) { - if (auto *interface_decl = dyn_cast<ObjCInterfaceDecl>(context.m_decl_context)) { - ObjCInterfaceDecl *complete_iface_decl = - GetCompleteObjCInterface(interface_decl); - - if (complete_iface_decl && (complete_iface_decl != context.m_decl_context)) { - m_merger_up->ForceRecordOrigin(interface_decl, {complete_iface_decl, &complete_iface_decl->getASTContext()}); - } - } - - GetMergerUnchecked().FindExternalVisibleDeclsByName(context.m_decl_context, - context.m_decl_name); - return; - } - static unsigned int invocation_id = 0; unsigned int current_id = invocation_id++; @@ -1180,17 +1012,13 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { return; do { - Decl *original_decl = nullptr; - ASTContext *original_ctx = nullptr; - - m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl, - &original_ctx); + ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(interface_decl); - if (!original_decl) + if (!original.Valid()) break; ObjCInterfaceDecl *original_interface_decl = - dyn_cast<ObjCInterfaceDecl>(original_decl); + dyn_cast<ObjCInterfaceDecl>(original.decl); if (FindObjCMethodDeclsWithOrigin(current_id, context, original_interface_decl, "at origin")) @@ -1343,11 +1171,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (!copied_method_decl) continue; - if (log) { - ASTDumper dumper((Decl *)copied_method_decl); - LLDB_LOGF(log, " CAS::FOMD[%d] found (in symbols) %s", current_id, - dumper.GetCString()); - } + LLDB_LOG(log, " CAS::FOMD[{0}] found (in symbols)\n{1}", current_id, + ClangUtil::DumpDecl(copied_method_decl)); context.AddNamedDecl(copied_method_decl); } @@ -1476,11 +1301,8 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( DeclFromParser<ObjCPropertyDecl> parser_property_decl( origin_property_decl.Import(source)); if (parser_property_decl.IsValid()) { - if (log) { - ASTDumper dumper((Decl *)parser_property_decl.decl); - LLDB_LOGF(log, " CAS::FOPD[%d] found %s", current_id, - dumper.GetCString()); - } + LLDB_LOG(log, " CAS::FOPD[{0}] found\n{1}", current_id, + ClangUtil::DumpDecl(parser_property_decl.decl)); context.AddNamedDecl(parser_property_decl.decl); found = true; @@ -1495,9 +1317,8 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( origin_ivar_decl.Import(source)); if (parser_ivar_decl.IsValid()) { if (log) { - ASTDumper dumper((Decl *)parser_ivar_decl.decl); - LLDB_LOGF(log, " CAS::FOPD[%d] found %s", current_id, - dumper.GetCString()); + LLDB_LOG(log, " CAS::FOPD[{0}] found\n{1}", current_id, + ClangUtil::DumpDecl(parser_ivar_decl.decl)); } context.AddNamedDecl(parser_ivar_decl.decl); @@ -1736,8 +1557,6 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, FieldOffsetMap &field_offsets, BaseOffsetMap &base_offsets, BaseOffsetMap &virtual_base_offsets) { - ClangASTMetrics::RegisterRecordLayout(); - static unsigned int invocation_id = 0; unsigned int current_id = invocation_id++; @@ -1984,90 +1803,37 @@ NamespaceDecl *ClangASTSource::AddNamespace( return dyn_cast<NamespaceDecl>(copied_decl); } -clang::QualType ClangASTSource::CopyTypeWithMerger( - clang::ASTContext &from_context, - clang::ExternalASTMerger &merger, - clang::QualType type) { - if (!merger.HasImporterForOrigin(from_context)) { - lldbassert(0 && "Couldn't find the importer for a source context!"); - return QualType(); - } - - if (llvm::Expected<QualType> type_or_error = - merger.ImporterForOrigin(from_context).Import(type)) { - return *type_or_error; - } else { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); - LLDB_LOG_ERROR(log, type_or_error.takeError(), "Couldn't import type: {0}"); - return QualType(); - } -} - clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) { - clang::ASTContext &from_context = src_decl->getASTContext(); if (m_ast_importer_sp) { - return m_ast_importer_sp->CopyDecl(m_ast_context, &from_context, src_decl); - } else if (m_merger_up) { - if (!m_merger_up->HasImporterForOrigin(from_context)) { - lldbassert(0 && "Couldn't find the importer for a source context!"); - return nullptr; - } - - if (llvm::Expected<Decl *> decl_or_error = - m_merger_up->ImporterForOrigin(from_context).Import(src_decl)) { - return *decl_or_error; - } else { - Log *log = - lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); - LLDB_LOG_ERROR(log, decl_or_error.takeError(), - "Couldn't import decl: {0}"); - return nullptr; - } + return m_ast_importer_sp->CopyDecl(m_ast_context, src_decl); } else { lldbassert(0 && "No mechanism for copying a decl!"); return nullptr; } } -bool ClangASTSource::ResolveDeclOrigin(const clang::Decl *decl, - clang::Decl **original_decl, - clang::ASTContext **original_ctx) { +ClangASTImporter::DeclOrigin ClangASTSource::GetDeclOrigin(const clang::Decl *decl) { if (m_ast_importer_sp) { - return m_ast_importer_sp->ResolveDeclOrigin(decl, original_decl, - original_ctx); - } else if (m_merger_up) { - return false; // Implement this correctly in ExternalASTMerger + return m_ast_importer_sp->GetDeclOrigin(decl); } else { // this can happen early enough that no ExternalASTSource is installed. - return false; + return ClangASTImporter::DeclOrigin(); } } -clang::ExternalASTMerger &ClangASTSource::GetMergerUnchecked() { - lldbassert(m_merger_up != nullptr); - return *m_merger_up; -} - CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { ClangASTContext *src_ast = llvm::dyn_cast_or_null<ClangASTContext>(src_type.GetTypeSystem()); if (src_ast == nullptr) return CompilerType(); - ClangASTMetrics::RegisterLLDBImport(); - SetImportInProgress(true); QualType copied_qual_type; if (m_ast_importer_sp) { - copied_qual_type = - m_ast_importer_sp->CopyType(m_ast_context, src_ast->getASTContext(), - ClangUtil::GetQualType(src_type)); - } else if (m_merger_up) { - copied_qual_type = - CopyTypeWithMerger(*src_ast->getASTContext(), *m_merger_up, - ClangUtil::GetQualType(src_type)); + copied_qual_type = ClangUtil::GetQualType( + m_ast_importer_sp->CopyType(*m_clang_ast_context, src_type)); } else { lldbassert(0 && "No mechanism for copying a type!"); return CompilerType(); @@ -2081,8 +1847,7 @@ CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { // seems to be generating bad types on occasion. return CompilerType(); - return CompilerType(ClangASTContext::GetASTContext(m_ast_context), - copied_qual_type.getAsOpaquePtr()); + return m_clang_ast_context->GetType(copied_qual_type); } clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { @@ -2098,10 +1863,10 @@ clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo(); - clang::ASTContext *ast = lldb_ast->getASTContext(); + clang::ASTContext &ast = lldb_ast->getASTContext(); clang::NamedDecl *Decl = VarDecl::Create( - *ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), + ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static); m_decls.push_back(Decl); @@ -2127,7 +1892,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, QualType qual_type(ClangUtil::GetQualType(type)); - clang::ASTContext *ast = lldb_ast->getASTContext(); + clang::ASTContext &ast = lldb_ast->getASTContext(); const bool isInlineSpecified = false; const bool hasWrittenPrototype = true; @@ -2137,7 +1902,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, if (extern_c) { context = LinkageSpecDecl::Create( - *ast, context, SourceLocation(), SourceLocation(), + ast, context, SourceLocation(), SourceLocation(), clang::LinkageSpecDecl::LanguageIDs::lang_c, false); } @@ -2149,7 +1914,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, : m_decl_name; clang::FunctionDecl *func_decl = FunctionDecl::Create( - *ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, + ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, isConstexprSpecified ? CSK_constexpr : CSK_unspecified); @@ -2170,7 +1935,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, QualType arg_qual_type(func_proto_type->getParamType(ArgIndex)); parm_var_decls.push_back( - ParmVarDecl::Create(*ast, const_cast<DeclContext *>(context), + ParmVarDecl::Create(ast, const_cast<DeclContext *>(context), SourceLocation(), SourceLocation(), nullptr, arg_qual_type, nullptr, SC_Static, nullptr)); } @@ -2210,9 +1975,7 @@ clang::NamedDecl *NameSearchContext::AddGenericFunDecl() { proto_info)); return AddFunDecl( - CompilerType(ClangASTContext::GetASTContext(m_ast_source.m_ast_context), - generic_function_type.getAsOpaquePtr()), - true); + m_ast_source.m_clang_ast_context->GetType(generic_function_type), true); } clang::NamedDecl * diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index 7a8bacf48a8f..3149b4266b2f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -12,10 +12,9 @@ #include <set> #include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" -#include "clang/AST/ExternalASTMerger.h" +#include "clang/AST/ExternalASTSource.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/SmallSet.h" @@ -30,7 +29,7 @@ namespace lldb_private { /// knows the name it is looking for, but nothing else. The ExternalSemaSource /// class provides Decls (VarDecl, FunDecl, TypeDecl) to Clang for these /// names, consulting the ClangExpressionDeclMap to do the actual lookups. -class ClangASTSource : public ClangExternalASTSourceCommon, +class ClangASTSource : public clang::ExternalASTSource, public ClangASTImporter::MapCompleter { public: /// Constructor @@ -39,7 +38,11 @@ public: /// /// \param[in] target /// A reference to the target containing debug information to use. - ClangASTSource(const lldb::TargetSP &target); + /// + /// \param[in] importer + /// The ClangASTImporter to use. + ClangASTSource(const lldb::TargetSP &target, + const lldb::ClangASTImporterSP &importer); /// Destructor ~ClangASTSource() override; @@ -57,9 +60,7 @@ public: } void MaterializeVisibleDecls(const clang::DeclContext *DC) { return; } - void InstallASTContext(clang::ASTContext &ast_context, - clang::FileManager &file_manager, - bool is_shared_context = false); + void InstallASTContext(ClangASTContext &ast_context); // // APIs for ExternalASTSource @@ -89,7 +90,7 @@ public: /// \param[in] DC /// The DeclContext being searched. /// - /// \param[in] isKindWeWant + /// \param[in] IsKindWeWant /// A callback function that returns true given the /// DeclKinds of desired Decls, and false otherwise. /// @@ -155,7 +156,7 @@ public: /// setHasExternalVisibleStorage() and setHasExternalLexicalStorage() that /// this object has something to say about undefined names. /// - /// \param[in] ASTConsumer + /// \param[in] Consumer /// Unused. void StartTranslationUnit(clang::ASTConsumer *Consumer) override; @@ -210,7 +211,7 @@ public: /// /// Clang AST contexts like to own their AST sources, so this is a state- /// free proxy object. - class ClangASTSourceProxy : public ClangExternalASTSourceCommon { + class ClangASTSourceProxy : public clang::ExternalASTSource { public: ClangASTSourceProxy(ClangASTSource &original) : m_original(original) {} @@ -249,18 +250,6 @@ public: return m_original.StartTranslationUnit(Consumer); } - ClangASTMetadata *GetMetadata(const void *object) { - return m_original.GetMetadata(object); - } - - void SetMetadata(const void *object, ClangASTMetadata &metadata) { - return m_original.SetMetadata(object, metadata); - } - - bool HasMetadata(const void *object) { - return m_original.HasMetadata(object); - } - private: ClangASTSource &m_original; }; @@ -321,13 +310,6 @@ protected: /// A wrapper for ClangASTContext::CopyType that sets a flag that /// indicates that we should not respond to queries during import. /// - /// \param[in] dest_context - /// The target AST context, typically the parser's AST context. - /// - /// \param[in] source_context - /// The source AST context, typically the AST context of whatever - /// symbol file the type was found in. - /// /// \param[in] src_type /// The source type. /// @@ -341,7 +323,7 @@ public: /// \param[in] name /// The name to be considered. /// - /// \param[in] ignore_all_dollar_nmmes + /// \param[in] ignore_all_dollar_names /// True if $-names of all sorts should be ignored. /// /// \return @@ -358,24 +340,6 @@ public: /// \return /// A copy of the Decl in m_ast_context, or NULL if the copy failed. clang::Decl *CopyDecl(clang::Decl *src_decl); - - /// Copies a single Type to the target of the given ExternalASTMerger. - /// - /// \param[in] src_context - /// The ASTContext containing the type. - /// - /// \param[in] merger - /// The merger to use. This isn't just *m_merger_up because it might be - /// the persistent AST context's merger. - /// - /// \param[in] type - /// The type to copy. - /// - /// \return - /// A copy of the Type in the merger's target context. - clang::QualType CopyTypeWithMerger(clang::ASTContext &src_context, - clang::ExternalASTMerger &merger, - clang::QualType type); /// Determined the origin of a single Decl, if it can be found. /// @@ -390,16 +354,7 @@ public: /// /// \return /// True if lookup succeeded; false otherwise. - bool ResolveDeclOrigin(const clang::Decl *decl, clang::Decl **original_decl, - clang::ASTContext **original_ctx); - - /// Returns m_merger_up. Only call this if the target is configured to use - /// modern lookup, - clang::ExternalASTMerger &GetMergerUnchecked(); - - /// Returns true if there is a merger. This only occurs if the target is - /// using modern lookup. - bool HasMerger() { return (bool)m_merger_up; } + ClangASTImporter::DeclOrigin GetDeclOrigin(const clang::Decl *decl); protected: bool FindObjCMethodDeclsWithOrigin( @@ -411,15 +366,16 @@ protected: bool m_import_in_progress; bool m_lookups_enabled; - const lldb::TargetSP - m_target; ///< The target to use in finding variables and types. - clang::ASTContext - *m_ast_context; ///< The AST context requests are coming in for. - clang::FileManager - *m_file_manager; ///< The file manager paired with the AST context. - lldb::ClangASTImporterSP m_ast_importer_sp; ///< The target's AST importer. - std::unique_ptr<clang::ExternalASTMerger> m_merger_up; - ///< The ExternalASTMerger for this parse. + /// The target to use in finding variables and types. + const lldb::TargetSP m_target; + /// The AST context requests are coming in for. + clang::ASTContext *m_ast_context; + /// The ClangASTContext for m_ast_context. + ClangASTContext *m_clang_ast_context; + /// The file manager paired with the AST context. + clang::FileManager *m_file_manager; + /// The target's AST importer. + lldb::ClangASTImporterSP m_ast_importer_sp; std::set<const clang::Decl *> m_active_lexical_decls; std::set<const char *> m_active_lookups; }; @@ -432,20 +388,20 @@ protected: /// what name is being searched for and provides helper functions to construct /// Decls given appropriate type information. struct NameSearchContext { - ClangASTSource &m_ast_source; ///< The AST source making the request - llvm::SmallVectorImpl<clang::NamedDecl *> - &m_decls; ///< The list of declarations already constructed - ClangASTImporter::NamespaceMapSP m_namespace_map; ///< The mapping of all - ///namespaces found for this - ///request back to their - ///modules - const clang::DeclarationName &m_decl_name; ///< The name being looked for - const clang::DeclContext - *m_decl_context; ///< The DeclContext to put declarations into - llvm::SmallSet<CompilerType, 5> m_function_types; ///< All the types of - ///functions that have been - ///reported, so we don't - ///report conflicts + /// The AST source making the request. + ClangASTSource &m_ast_source; + /// The list of declarations already constructed. + llvm::SmallVectorImpl<clang::NamedDecl *> &m_decls; + /// The mapping of all namespaces found for this request back to their + /// modules. + ClangASTImporter::NamespaceMapSP m_namespace_map; + /// The name being looked for. + const clang::DeclarationName &m_decl_name; + /// The DeclContext to put declarations into. + const clang::DeclContext *m_decl_context; + /// All the types of functions that have been reported, so we don't + /// report conflicts. + llvm::SmallSet<CompilerType, 5> m_function_types; struct { bool variable : 1; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp index c59722b7b4f8..c87507a25855 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp @@ -15,16 +15,16 @@ using namespace lldb_private; uint32_t ClangDeclVendor::FindDecls(ConstString name, bool append, uint32_t max_matches, - std::vector<CompilerDecl> &decls) { + std::vector<clang::NamedDecl *> &decls) { if (!append) decls.clear(); - std::vector<clang::NamedDecl *> named_decls; - uint32_t ret = FindDecls(name, /*append*/ false, max_matches, named_decls); - for (auto *named_decl : named_decls) { - decls.push_back(CompilerDecl( - ClangASTContext::GetASTContext(&named_decl->getASTContext()), - named_decl)); + std::vector<CompilerDecl> compiler_decls; + uint32_t ret = FindDecls(name, /*append*/ false, max_matches, compiler_decls); + for (CompilerDecl compiler_decl : compiler_decls) { + clang::Decl *d = static_cast<clang::Decl *>(compiler_decl.GetOpaqueDecl()); + clang::NamedDecl *nd = llvm::cast<clang::NamedDecl>(d); + decls.push_back(nd); } return ret; } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h index 90b715f37cba..0c888de08841 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h @@ -12,8 +12,6 @@ #include "lldb/Core/ClangForward.h" #include "lldb/Symbol/DeclVendor.h" -#include "clang/AST/ExternalASTMerger.h" - namespace lldb_private { // A clang specialized extension to DeclVendor. @@ -23,19 +21,10 @@ public: virtual ~ClangDeclVendor() {} - /// Interface for ExternalASTMerger. Returns an ImporterSource allowing type - /// completion. - /// - /// \return - /// An ImporterSource for this ClangDeclVendor. - virtual clang::ExternalASTMerger::ImporterSource GetImporterSource() = 0; + using DeclVendor::FindDecls; uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, - std::vector<CompilerDecl> &decls) override; - - virtual uint32_t FindDecls(ConstString name, bool append, - uint32_t max_matches, - std::vector<clang::NamedDecl *> &decls) = 0; + std::vector<clang::NamedDecl *> &decls); static bool classof(const DeclVendor *vendor) { return vendor->GetKind() >= eClangDeclVendor && diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index f4457fc1b740..bf3023be5f60 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -8,7 +8,6 @@ #include "ClangExpressionDeclMap.h" -#include "ASTDumper.h" #include "ClangASTSource.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" @@ -20,6 +19,7 @@ #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" @@ -65,9 +65,10 @@ const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars"; ClangExpressionDeclMap::ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, - ExecutionContext &exe_ctx, ValueObject *ctx_obj) - : ClangASTSource(exe_ctx.GetTargetSP()), m_found_entities(), - m_struct_members(), m_keep_result_in_memory(keep_result_in_memory), + const lldb::TargetSP &target, const lldb::ClangASTImporterSP &importer, + ValueObject *ctx_obj) + : ClangASTSource(target, importer), m_found_entities(), m_struct_members(), + m_keep_result_in_memory(keep_result_in_memory), m_result_delegate(result_delegate), m_ctx_obj(ctx_obj), m_parser_vars(), m_struct_vars() { EnableStructVars(); @@ -84,8 +85,6 @@ ClangExpressionDeclMap::~ClangExpressionDeclMap() { bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx, Materializer *materializer) { - ClangASTMetrics::ClearLocalCounters(); - EnableParserVars(); m_parser_vars->m_exe_ctx = exe_ctx; @@ -110,7 +109,7 @@ bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx, m_parser_vars->m_persistent_vars = llvm::cast<ClangPersistentVariables>( target->GetPersistentExpressionStateForLanguage(eLanguageTypeC)); - if (!target->GetScratchClangASTContext()) + if (!ClangASTContext::GetScratch(*target)) return false; } @@ -127,12 +126,7 @@ void ClangExpressionDeclMap::InstallCodeGenerator( } void ClangExpressionDeclMap::DidParse() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - if (log) - ClangASTMetrics::DumpCounters(log); - - if (m_parser_vars) { + if (m_parser_vars && m_parser_vars->m_persistent_vars) { for (size_t entity_index = 0, num_entities = m_found_entities.GetSize(); entity_index < num_entities; ++entity_index) { ExpressionVariableSP var_sp( @@ -180,55 +174,15 @@ ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() { return ret; } -static clang::QualType ExportAllDeclaredTypes( - clang::ExternalASTMerger &parent_merger, clang::ExternalASTMerger &merger, - clang::ASTContext &source, clang::FileManager &source_file_manager, - const clang::ExternalASTMerger::OriginMap &source_origin_map, - clang::FileID file, clang::QualType root) { - // Mark the source as temporary to make sure all declarations from the - // AST are exported. Also add the parent_merger as the merger into the - // source AST so that the merger can track back any declarations from - // the persistent ASTs we used as sources. - clang::ExternalASTMerger::ImporterSource importer_source( - source, source_file_manager, source_origin_map, /*Temporary*/ true, - &parent_merger); - merger.AddSources(importer_source); - clang::ASTImporter &exporter = merger.ImporterForOrigin(source); - llvm::Expected<clang::QualType> ret_or_error = exporter.Import(root); - merger.RemoveSources(importer_source); - if (ret_or_error) { - return *ret_or_error; - } else { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); - LLDB_LOG_ERROR(log, ret_or_error.takeError(), "Couldn't import type: {0}"); - return clang::QualType(); - } -} - TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target, ClangASTContext &source, TypeFromParser parser_type) { - assert(&target == m_target->GetScratchClangASTContext()); + assert(&target == ClangASTContext::GetScratch(*m_target)); assert((TypeSystem *)&source == parser_type.GetTypeSystem()); - assert(source.getASTContext() == m_ast_context); + assert(&source.getASTContext() == m_ast_context); if (m_ast_importer_sp) { - return TypeFromUser(m_ast_importer_sp->DeportType( - target.getASTContext(), source.getASTContext(), - parser_type.GetOpaqueQualType()), - &target); - } else if (m_merger_up) { - clang::FileID source_file = - source.getASTContext()->getSourceManager().getFileID( - source.getASTContext()->getTranslationUnitDecl()->getLocation()); - auto scratch_ast_context = static_cast<ClangASTContextForExpressions *>( - m_target->GetScratchClangASTContext()); - clang::QualType exported_type = ExportAllDeclaredTypes( - *m_merger_up.get(), scratch_ast_context->GetMergerUnchecked(), - *source.getASTContext(), *source.getFileManager(), - m_merger_up->GetOrigins(), source_file, - clang::QualType::getFromOpaquePtr(parser_type.GetOpaqueQualType())); - return TypeFromUser(exported_type.getAsOpaquePtr(), &target); + return TypeFromUser(m_ast_importer_sp->DeportType(target, parser_type)); } else { lldbassert(0 && "No mechanism for deporting a type!"); return TypeFromUser(); @@ -255,8 +209,11 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - TypeFromUser user_type = - DeportType(*target->GetScratchClangASTContext(), *ast, parser_type); + auto *clang_ast_context = ClangASTContext::GetScratch(*target); + if (!clang_ast_context) + return false; + + TypeFromUser user_type = DeportType(*clang_ast_context, *ast, parser_type); uint32_t offset = m_parser_vars->m_materializer->AddResultVariable( user_type, is_lvalue, m_keep_result_in_memory, m_result_delegate, err); @@ -291,7 +248,9 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - ClangASTContext *context(target->GetScratchClangASTContext()); + ClangASTContext *context = ClangASTContext::GetScratch(*target); + if (!context) + return false; TypeFromUser user_type = DeportType(*context, *ast, parser_type); @@ -303,6 +262,9 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (!m_parser_vars->m_target_info.IsValid()) return false; + if (!m_parser_vars->m_persistent_vars) + return false; + ClangExpressionVariable *var = llvm::cast<ClangExpressionVariable>( m_parser_vars->m_persistent_vars ->CreatePersistentVariable( @@ -368,7 +330,7 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, ClangExpressionVariable *var(ClangExpressionVariable::FindVariableInList( m_found_entities, decl, GetParserID())); - if (!var) { + if (!var && m_parser_vars->m_persistent_vars) { var = ClangExpressionVariable::FindVariableInList( *m_parser_vars->m_persistent_vars, decl, GetParserID()); is_persistent_variable = true; @@ -638,7 +600,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(ConstString name, lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( Target &target, ModuleSP &module, ConstString name, - CompilerDeclContext *namespace_decl, TypeFromUser *type) { + CompilerDeclContext *namespace_decl) { VariableList vars; if (module && namespace_decl) @@ -646,21 +608,9 @@ lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( else target.GetImages().FindGlobalVariables(name, -1, vars); - if (vars.GetSize()) { - if (type) { - for (size_t i = 0; i < vars.GetSize(); ++i) { - VariableSP var_sp = vars.GetVariableAtIndex(i); - - if (ClangASTContext::AreTypesSame( - *type, var_sp->GetType()->GetFullCompilerType())) - return var_sp; - } - } else { - return vars.GetVariableAtIndex(0); - } - } - - return VariableSP(); + if (vars.GetSize() == 0) + return VariableSP(); + return vars.GetVariableAtIndex(0); } ClangASTContext *ClangExpressionDeclMap::GetClangASTContext() { @@ -687,8 +637,6 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( NameSearchContext &context) { assert(m_ast_context); - ClangASTMetrics::RegisterVisibleQuery(); - const ConstString name(context.m_decl_name.getAsString().c_str()); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -727,9 +675,9 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( 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))); + CompilerDeclContext compiler_decl_ctx = + m_clang_ast_context->CreateDeclContext( + const_cast<clang::DeclContext *>(context.m_decl_context)); FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx, current_id); return; @@ -771,743 +719,760 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( ClangASTSource::FindExternalVisibleDecls(context); } -void ClangExpressionDeclMap::FindExternalVisibleDecls( - NameSearchContext &context, lldb::ModuleSP module_sp, - CompilerDeclContext &namespace_decl, unsigned int current_id) { - assert(m_ast_context); +void ClangExpressionDeclMap::MaybeRegisterFunctionBody( + FunctionDecl *copied_function_decl) { + if (copied_function_decl->getBody() && m_parser_vars->m_code_gen) { + clang::DeclGroupRef decl_group_ref(copied_function_decl); + m_parser_vars->m_code_gen->HandleTopLevelDecl(decl_group_ref); + } +} - 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); - } - }; +clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) { + if (!m_parser_vars) + return nullptr; + Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); + if (!target) + return nullptr; + + ClangASTContext::GetScratch(*target); + + if (!m_parser_vars->m_persistent_vars) + return nullptr; + return m_parser_vars->m_persistent_vars->GetPersistentDecl(name); +} +void ClangExpressionDeclMap::SearchPersistenDecls(NameSearchContext &context, + const ConstString name, + unsigned int current_id) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - SymbolContextList sc_list; + NamedDecl *persistent_decl = GetPersistentDecl(name); - const ConstString name(context.m_decl_name.getAsString().c_str()); - if (IgnoreName(name, false)) + if (!persistent_decl) return; - // Only look for functions by name out in our symbols if the function doesn't - // start with our phony prefix of '$' - Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); + Decl *parser_persistent_decl = CopyDecl(persistent_decl); + + if (!parser_persistent_decl) + return; + + NamedDecl *parser_named_decl = dyn_cast<NamedDecl>(parser_persistent_decl); + + if (!parser_named_decl) + return; + + if (clang::FunctionDecl *parser_function_decl = + llvm::dyn_cast<clang::FunctionDecl>(parser_named_decl)) { + MaybeRegisterFunctionBody(parser_function_decl); + } + + LLDB_LOGF(log, " CEDM::FEVD[%u] Found persistent decl %s", current_id, + name.GetCString()); + + context.AddNamedDecl(parser_named_decl); +} + +void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, + unsigned int current_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); 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; + if (m_ctx_obj) { + Status status; + lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status); + if (!ctx_obj_ptr || status.Fail()) + return; - ClangASTContext *scratch_clang_ast_context = - target->GetScratchClangASTContext(); + AddThisType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), + current_id); - if (!scratch_clang_ast_context) - break; + m_struct_vars->m_object_pointer_type = + TypeFromUser(ctx_obj_ptr->GetCompilerType()); - ASTContext *scratch_ast_context = - scratch_clang_ast_context->getASTContext(); + return; + } - if (!scratch_ast_context) - break; + // Clang is looking for the type of "this" - NamedDecl *persistent_decl = - m_parser_vars->m_persistent_vars->GetPersistentDecl(name); + if (frame == nullptr) + return; - if (!persistent_decl) - break; + // Find the block that defines the function represented by "sym_ctx" + Block *function_block = sym_ctx.GetFunctionBlock(); - Decl *parser_persistent_decl = CopyDecl(persistent_decl); + if (!function_block) + return; - if (!parser_persistent_decl) - break; + CompilerDeclContext function_decl_ctx = function_block->GetDeclContext(); - NamedDecl *parser_named_decl = - dyn_cast<NamedDecl>(parser_persistent_decl); + if (!function_decl_ctx) + return; - if (!parser_named_decl) - break; + clang::CXXMethodDecl *method_decl = + ClangASTContext::DeclContextGetAsCXXMethodDecl(function_decl_ctx); - if (clang::FunctionDecl *parser_function_decl = - llvm::dyn_cast<clang::FunctionDecl>(parser_named_decl)) { - MaybeRegisterFunctionBody(parser_function_decl); - } + if (method_decl) { + clang::CXXRecordDecl *class_decl = method_decl->getParent(); - LLDB_LOGF(log, " CEDM::FEVD[%u] Found persistent decl %s", current_id, - name.GetCString()); + QualType class_qual_type(class_decl->getTypeForDecl(), 0); - context.AddNamedDecl(parser_named_decl); - } while (false); - } + TypeFromUser class_user_type(class_qual_type.getAsOpaquePtr(), + function_decl_ctx.GetTypeSystem()); - if (name.GetCString()[0] == '$' && !namespace_decl) { - static ConstString g_lldb_class_name("$__lldb_class"); + LLDB_LOG(log, " CEDM::FEVD[{0}] Adding type for $__lldb_class: {1}", + current_id, class_qual_type.getAsString()); - if (name == g_lldb_class_name) { - if (m_ctx_obj) { - Status status; - lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status); - if (!ctx_obj_ptr || status.Fail()) - return; + AddThisType(context, class_user_type, current_id); - AddThisType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), - current_id); + if (method_decl->isInstance()) { + // self is a pointer to the object - m_struct_vars->m_object_pointer_type = - TypeFromUser(ctx_obj_ptr->GetCompilerType()); + QualType class_pointer_type = + method_decl->getASTContext().getPointerType(class_qual_type); - return; - } + TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(), + function_decl_ctx.GetTypeSystem()); - // Clang is looking for the type of "this" + m_struct_vars->m_object_pointer_type = self_user_type; + } + return; + } - if (frame == nullptr) - return; + // This branch will get hit if we are executing code in the context of + // a function that claims to have an object pointer (through + // DW_AT_object_pointer?) but is not formally a method of the class. + // In that case, just look up the "this" variable in the current scope + // and use its type. + // FIXME: This code is formally correct, but clang doesn't currently + // emit DW_AT_object_pointer + // for C++ so it hasn't actually been tested. - // Find the block that defines the function represented by "sym_ctx" - Block *function_block = sym_ctx.GetFunctionBlock(); + VariableList *vars = frame->GetVariableList(false); - if (!function_block) - return; + lldb::VariableSP this_var = vars->FindVariable(ConstString("this")); - CompilerDeclContext function_decl_ctx = function_block->GetDeclContext(); + if (this_var && this_var->IsInScope(frame) && + this_var->LocationIsValidForFrame(frame)) { + Type *this_type = this_var->GetType(); - if (!function_decl_ctx) - return; + if (!this_type) + return; - clang::CXXMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsCXXMethodDecl(function_decl_ctx); + TypeFromUser pointee_type = + this_type->GetForwardCompilerType().GetPointeeType(); - if (method_decl) { - clang::CXXRecordDecl *class_decl = method_decl->getParent(); + LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_class: {1}", current_id, + ClangUtil::GetQualType(pointee_type).getAsString()); - QualType class_qual_type(class_decl->getTypeForDecl(), 0); + AddThisType(context, pointee_type, current_id); + TypeFromUser this_user_type(this_type->GetFullCompilerType()); + m_struct_vars->m_object_pointer_type = this_user_type; + } +} - TypeFromUser class_user_type( - class_qual_type.getAsOpaquePtr(), - ClangASTContext::GetASTContext(&class_decl->getASTContext())); +void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, + unsigned int current_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (log) { - ASTDumper ast_dumper(class_qual_type); - LLDB_LOGF(log, " CEDM::FEVD[%u] Adding type for $__lldb_class: %s", - current_id, ast_dumper.GetCString()); - } + StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); - AddThisType(context, class_user_type, current_id); + if (m_ctx_obj) { + Status status; + lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status); + if (!ctx_obj_ptr || status.Fail()) + return; - if (method_decl->isInstance()) { - // self is a pointer to the object + AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), current_id); - QualType class_pointer_type = - method_decl->getASTContext().getPointerType(class_qual_type); + m_struct_vars->m_object_pointer_type = + TypeFromUser(ctx_obj_ptr->GetCompilerType()); - TypeFromUser self_user_type( - class_pointer_type.getAsOpaquePtr(), - ClangASTContext::GetASTContext(&method_decl->getASTContext())); + return; + } - m_struct_vars->m_object_pointer_type = self_user_type; - } - } else { - // This branch will get hit if we are executing code in the context of - // a function that claims to have an object pointer (through - // DW_AT_object_pointer?) but is not formally a method of the class. - // In that case, just look up the "this" variable in the current scope - // and use its type. - // FIXME: This code is formally correct, but clang doesn't currently - // emit DW_AT_object_pointer - // for C++ so it hasn't actually been tested. + // Clang is looking for the type of "*self" + + if (!frame) + return; - VariableList *vars = frame->GetVariableList(false); + SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | + lldb::eSymbolContextBlock); - lldb::VariableSP this_var = vars->FindVariable(ConstString("this")); + // Find the block that defines the function represented by "sym_ctx" + Block *function_block = sym_ctx.GetFunctionBlock(); - if (this_var && this_var->IsInScope(frame) && - this_var->LocationIsValidForFrame(frame)) { - Type *this_type = this_var->GetType(); + if (!function_block) + return; - if (!this_type) - return; + CompilerDeclContext function_decl_ctx = function_block->GetDeclContext(); - TypeFromUser pointee_type = - this_type->GetForwardCompilerType().GetPointeeType(); + if (!function_decl_ctx) + return; - if (pointee_type.IsValid()) { - if (log) { - ASTDumper ast_dumper(pointee_type); - LLDB_LOGF(log, " FEVD[%u] Adding type for $__lldb_class: %s", - current_id, ast_dumper.GetCString()); - } + clang::ObjCMethodDecl *method_decl = + ClangASTContext::DeclContextGetAsObjCMethodDecl(function_decl_ctx); - AddThisType(context, pointee_type, current_id); - TypeFromUser this_user_type(this_type->GetFullCompilerType()); - m_struct_vars->m_object_pointer_type = this_user_type; - return; - } - } - } + if (method_decl) { + ObjCInterfaceDecl *self_interface = method_decl->getClassInterface(); + if (!self_interface) return; - } - static ConstString g_lldb_objc_class_name("$__lldb_objc_class"); - if (name == g_lldb_objc_class_name) { - if (m_ctx_obj) { - Status status; - lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status); - if (!ctx_obj_ptr || status.Fail()) - return; + const clang::Type *interface_type = self_interface->getTypeForDecl(); - AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), - current_id); + if (!interface_type) + return; // This is unlikely, but we have seen crashes where this + // occurred - m_struct_vars->m_object_pointer_type = - TypeFromUser(ctx_obj_ptr->GetCompilerType()); + TypeFromUser class_user_type(QualType(interface_type, 0).getAsOpaquePtr(), + function_decl_ctx.GetTypeSystem()); - return; - } + LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_objc_class: {1}", + current_id, ClangUtil::ToString(interface_type)); - // Clang is looking for the type of "*self" + AddOneType(context, class_user_type, current_id); - if (!frame) - return; + if (method_decl->isInstanceMethod()) { + // self is a pointer to the object - SymbolContext sym_ctx = frame->GetSymbolContext( - lldb::eSymbolContextFunction | lldb::eSymbolContextBlock); + QualType class_pointer_type = + method_decl->getASTContext().getObjCObjectPointerType( + QualType(interface_type, 0)); - // Find the block that defines the function represented by "sym_ctx" - Block *function_block = sym_ctx.GetFunctionBlock(); + TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(), + function_decl_ctx.GetTypeSystem()); - if (!function_block) - return; + m_struct_vars->m_object_pointer_type = self_user_type; + } else { + // self is a Class pointer + QualType class_type = method_decl->getASTContext().getObjCClassType(); - CompilerDeclContext function_decl_ctx = function_block->GetDeclContext(); + TypeFromUser self_user_type(class_type.getAsOpaquePtr(), + function_decl_ctx.GetTypeSystem()); - if (!function_decl_ctx) - return; + m_struct_vars->m_object_pointer_type = self_user_type; + } - clang::ObjCMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsObjCMethodDecl(function_decl_ctx); + return; + } + // This branch will get hit if we are executing code in the context of + // a function that claims to have an object pointer (through + // DW_AT_object_pointer?) but is not formally a method of the class. + // In that case, just look up the "self" variable in the current scope + // and use its type. - if (method_decl) { - ObjCInterfaceDecl *self_interface = method_decl->getClassInterface(); + VariableList *vars = frame->GetVariableList(false); - if (!self_interface) - return; + lldb::VariableSP self_var = vars->FindVariable(ConstString("self")); - const clang::Type *interface_type = self_interface->getTypeForDecl(); + if (!self_var) + return; + if (!self_var->IsInScope(frame)) + return; + if (!self_var->LocationIsValidForFrame(frame)) + return; - if (!interface_type) - return; // This is unlikely, but we have seen crashes where this - // occurred + Type *self_type = self_var->GetType(); - TypeFromUser class_user_type( - QualType(interface_type, 0).getAsOpaquePtr(), - ClangASTContext::GetASTContext(&method_decl->getASTContext())); + if (!self_type) + return; - if (log) { - ASTDumper ast_dumper(interface_type); - LLDB_LOGF(log, " FEVD[%u] Adding type for $__lldb_objc_class: %s", - current_id, ast_dumper.GetCString()); - } + CompilerType self_clang_type = self_type->GetFullCompilerType(); - AddOneType(context, class_user_type, current_id); + if (ClangASTContext::IsObjCClassType(self_clang_type)) { + return; + } + if (!ClangASTContext::IsObjCObjectPointerType(self_clang_type)) + return; + self_clang_type = self_clang_type.GetPointeeType(); - if (method_decl->isInstanceMethod()) { - // self is a pointer to the object + if (!self_clang_type) + return; - QualType class_pointer_type = - method_decl->getASTContext().getObjCObjectPointerType( - QualType(interface_type, 0)); + LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_objc_class: {1}", + current_id, ClangUtil::ToString(self_type->GetFullCompilerType())); - TypeFromUser self_user_type( - class_pointer_type.getAsOpaquePtr(), - ClangASTContext::GetASTContext(&method_decl->getASTContext())); + TypeFromUser class_user_type(self_clang_type); - m_struct_vars->m_object_pointer_type = self_user_type; - } else { - // self is a Class pointer - QualType class_type = method_decl->getASTContext().getObjCClassType(); + AddOneType(context, class_user_type, current_id); - TypeFromUser self_user_type( - class_type.getAsOpaquePtr(), - ClangASTContext::GetASTContext(&method_decl->getASTContext())); + TypeFromUser self_user_type(self_type->GetFullCompilerType()); - m_struct_vars->m_object_pointer_type = self_user_type; - } + m_struct_vars->m_object_pointer_type = self_user_type; +} - return; - } else { - // This branch will get hit if we are executing code in the context of - // a function that claims to have an object pointer (through - // DW_AT_object_pointer?) but is not formally a method of the class. - // In that case, just look up the "self" variable in the current scope - // and use its type. +void ClangExpressionDeclMap::LookupLocalVarNamespace( + SymbolContext &sym_ctx, NameSearchContext &name_context) { + if (sym_ctx.block == nullptr) + return; - VariableList *vars = frame->GetVariableList(false); + CompilerDeclContext frame_decl_context = sym_ctx.block->GetDeclContext(); + if (!frame_decl_context) + return; - lldb::VariableSP self_var = vars->FindVariable(ConstString("self")); + ClangASTContext *frame_ast = llvm::dyn_cast_or_null<ClangASTContext>( + frame_decl_context.GetTypeSystem()); + if (!frame_ast) + return; - if (self_var && self_var->IsInScope(frame) && - self_var->LocationIsValidForFrame(frame)) { - Type *self_type = self_var->GetType(); + clang::NamespaceDecl *namespace_decl = + m_clang_ast_context->GetUniqueNamespaceDeclaration( + g_lldb_local_vars_namespace_cstr, nullptr); + if (!namespace_decl) + return; - if (!self_type) - return; + name_context.AddNamedDecl(namespace_decl); + clang::DeclContext *ctxt = clang::Decl::castToDeclContext(namespace_decl); + ctxt->setHasExternalVisibleStorage(true); + name_context.m_found.local_vars_nsp = true; +} - CompilerType self_clang_type = self_type->GetFullCompilerType(); +void ClangExpressionDeclMap::LookupInModulesDeclVendor( + NameSearchContext &context, ConstString name, unsigned current_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (ClangASTContext::IsObjCClassType(self_clang_type)) { - return; - } else if (ClangASTContext::IsObjCObjectPointerType( - self_clang_type)) { - self_clang_type = self_clang_type.GetPointeeType(); + if (!m_target) + return; - if (!self_clang_type) - return; + auto *modules_decl_vendor = m_target->GetClangModulesDeclVendor(); + if (!modules_decl_vendor) + return; - if (log) { - ASTDumper ast_dumper(self_type->GetFullCompilerType()); - LLDB_LOGF(log, - " FEVD[%u] Adding type for $__lldb_objc_class: %s", - current_id, ast_dumper.GetCString()); - } + bool append = false; + uint32_t max_matches = 1; + std::vector<clang::NamedDecl *> decls; - TypeFromUser class_user_type(self_clang_type); + if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls)) + return; - AddOneType(context, class_user_type, current_id); + assert(!decls.empty() && "FindDecls returned true but no decls?"); + clang::NamedDecl *const decl_from_modules = decls[0]; - TypeFromUser self_user_type(self_type->GetFullCompilerType()); + LLDB_LOG(log, + " CAS::FEVD[{0}] Matching decl found for " + "\"{1}\" in the modules", + current_id, name); - m_struct_vars->m_object_pointer_type = self_user_type; - return; - } - } - } + clang::Decl *copied_decl = CopyDecl(decl_from_modules); + if (!copied_decl) { + LLDB_LOG(log, + " CAS::FEVD[{0}] - Couldn't export a " + "declaration from the modules", + current_id); + return; + } - return; - } + if (auto copied_function = dyn_cast<clang::FunctionDecl>(copied_decl)) { + MaybeRegisterFunctionBody(copied_function); - if (name == ConstString(g_lldb_local_vars_namespace_cstr)) { - CompilerDeclContext frame_decl_context = - sym_ctx.block != nullptr ? sym_ctx.block->GetDeclContext() - : CompilerDeclContext(); - - if (frame_decl_context) { - ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>( - frame_decl_context.GetTypeSystem()); - - if (ast) { - clang::NamespaceDecl *namespace_decl = - ClangASTContext::GetUniqueNamespaceDeclaration( - m_ast_context, name.GetCString(), 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; - } - } - } + context.AddNamedDecl(copied_function); - return; - } + context.m_found.function_with_type_info = true; + context.m_found.function = true; + } else if (auto copied_var = dyn_cast<clang::VarDecl>(copied_decl)) { + context.AddNamedDecl(copied_var); + context.m_found.variable = true; + } +} - // any other $__lldb names should be weeded out now - if (name.GetStringRef().startswith("$__lldb")) - return; +bool ClangExpressionDeclMap::LookupLocalVariable( + NameSearchContext &context, ConstString name, unsigned current_id, + SymbolContext &sym_ctx, CompilerDeclContext &namespace_decl) { + if (sym_ctx.block == nullptr) + return false; - ExpressionVariableSP pvar_sp( - m_parser_vars->m_persistent_vars->GetVariable(name)); + CompilerDeclContext decl_context = sym_ctx.block->GetDeclContext(); + if (!decl_context) + return false; - if (pvar_sp) { - AddOneVariable(context, pvar_sp, current_id); - return; + // Make sure that the variables are parsed so that we have the + // declarations. + StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); + VariableListSP vars = frame->GetInScopeVariableList(true); + for (size_t i = 0; i < vars->GetSize(); i++) + vars->GetVariableAtIndex(i)->GetDecl(); + + // Search for declarations matching the name. Do not include imported + // decls in the search if we are looking for decls in the artificial + // namespace $__lldb_local_vars. + std::vector<CompilerDecl> found_decls = + decl_context.FindDeclByName(name, namespace_decl.IsValid()); + + VariableSP var; + bool variable_found = false; + for (CompilerDecl decl : found_decls) { + for (size_t vi = 0, ve = vars->GetSize(); vi != ve; ++vi) { + VariableSP candidate_var = vars->GetVariableAtIndex(vi); + if (candidate_var->GetDecl() == decl) { + var = candidate_var; + break; + } } - const char *reg_name(&name.GetCString()[1]); + if (var && !variable_found) { + variable_found = true; + ValueObjectSP valobj = ValueObjectVariable::Create(frame, var); + AddOneVariable(context, var, valobj, current_id); + context.m_found.variable = true; + } + } + return variable_found; +} - if (m_parser_vars->m_exe_ctx.GetRegisterContext()) { - const RegisterInfo *reg_info( - m_parser_vars->m_exe_ctx.GetRegisterContext()->GetRegisterInfoByName( - reg_name)); +/// Structure to hold the info needed when comparing function +/// declarations. +namespace { +struct FuncDeclInfo { + ConstString m_name; + CompilerType m_copied_type; + uint32_t m_decl_lvl; + SymbolContext m_sym_ctx; +}; +} // namespace + +SymbolContextList ClangExpressionDeclMap::SearchFunctionsInSymbolContexts( + const SymbolContextList &sc_list, + const CompilerDeclContext &frame_decl_context) { + // First, symplify things by looping through the symbol contexts to + // remove unwanted functions and separate out the functions we want to + // compare and prune into a separate list. Cache the info needed about + // the function declarations in a vector for efficiency. + uint32_t num_indices = sc_list.GetSize(); + SymbolContextList sc_sym_list; + std::vector<FuncDeclInfo> decl_infos; + decl_infos.reserve(num_indices); + clang::DeclContext *frame_decl_ctx = + (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext(); + ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>( + frame_decl_context.GetTypeSystem()); - if (reg_info) { - LLDB_LOGF(log, " CEDM::FEVD[%u] Found register %s", current_id, - reg_info->name); + for (uint32_t index = 0; index < num_indices; ++index) { + FuncDeclInfo fdi; + SymbolContext sym_ctx; + sc_list.GetContextAtIndex(index, sym_ctx); - AddOneRegister(context, reg_info, current_id); - } + // We don't know enough about symbols to compare them, but we should + // keep them in the list. + Function *function = sym_ctx.function; + if (!function) { + sc_sym_list.Append(sym_ctx); + continue; + } + // Filter out functions without declaration contexts, as well as + // class/instance methods, since they'll be skipped in the code that + // follows anyway. + CompilerDeclContext func_decl_context = function->GetDeclContext(); + if (!func_decl_context || + func_decl_context.IsClassMethod(nullptr, nullptr, nullptr)) + continue; + // We can only prune functions for which we can copy the type. + CompilerType func_clang_type = function->GetType()->GetFullCompilerType(); + CompilerType copied_func_type = GuardedCopyType(func_clang_type); + if (!copied_func_type) { + sc_sym_list.Append(sym_ctx); + continue; } - } else { - ValueObjectSP valobj; - VariableSP var; - - 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. - VariableListSP vars = frame->GetInScopeVariableList(true); - for (size_t i = 0; i < vars->GetSize(); i++) - vars->GetVariableAtIndex(i)->GetDecl(); - - // Search for declarations matching the name. Do not include imported - // decls in the search if we are looking for decls in the artificial - // namespace $__lldb_local_vars. - std::vector<CompilerDecl> found_decls = - compiler_decl_context.FindDeclByName(name, - namespace_decl.IsValid()); - - bool variable_found = false; - for (CompilerDecl decl : found_decls) { - for (size_t vi = 0, ve = vars->GetSize(); vi != ve; ++vi) { - VariableSP candidate_var = vars->GetVariableAtIndex(vi); - if (candidate_var->GetDecl() == decl) { - var = candidate_var; - break; - } - } - if (var && !variable_found) { - variable_found = true; - valobj = ValueObjectVariable::Create(frame, var); - AddOneVariable(context, var, valobj, current_id); - context.m_found.variable = true; - } - } - if (variable_found) - return; - } + fdi.m_sym_ctx = sym_ctx; + fdi.m_name = function->GetName(); + fdi.m_copied_type = copied_func_type; + fdi.m_decl_lvl = LLDB_INVALID_DECL_LEVEL; + if (fdi.m_copied_type && func_decl_context) { + // Call CountDeclLevels to get the number of parent scopes we have + // to look through before we find the function declaration. When + // comparing functions of the same type, the one with a lower count + // will be closer to us in the lookup scope and shadows the other. + clang::DeclContext *func_decl_ctx = + (clang::DeclContext *)func_decl_context.GetOpaqueDeclContext(); + fdi.m_decl_lvl = ast->CountDeclLevels(frame_decl_ctx, func_decl_ctx, + &fdi.m_name, &fdi.m_copied_type); } - if (target) { - var = FindGlobalVariable(*target, module_sp, name, &namespace_decl, - nullptr); + decl_infos.emplace_back(fdi); + } - if (var) { - valobj = ValueObjectVariable::Create(target, var); - AddOneVariable(context, var, valobj, current_id); - context.m_found.variable = true; - return; - } + // Loop through the functions in our cache looking for matching types, + // then compare their scope levels to see which is closer. + std::multimap<CompilerType, const FuncDeclInfo *> matches; + for (const FuncDeclInfo &fdi : decl_infos) { + const CompilerType t = fdi.m_copied_type; + auto q = matches.find(t); + if (q != matches.end()) { + if (q->second->m_decl_lvl > fdi.m_decl_lvl) + // This function is closer; remove the old set. + matches.erase(t); + else if (q->second->m_decl_lvl < fdi.m_decl_lvl) + // The functions in our set are closer - skip this one. + continue; } + matches.insert(std::make_pair(t, &fdi)); + } - std::vector<clang::NamedDecl *> decls_from_modules; + // Loop through our matches and add their symbol contexts to our list. + SymbolContextList sc_func_list; + for (const auto &q : matches) + sc_func_list.Append(q.second->m_sym_ctx); - if (target) { - if (ClangModulesDeclVendor *decl_vendor = - target->GetClangModulesDeclVendor()) { - decl_vendor->FindDecls(name, false, UINT32_MAX, decls_from_modules); - } - } + // Rejoin the lists with the functions in front. + sc_func_list.Append(sc_sym_list); + return sc_func_list; +} - const bool include_inlines = false; - sc_list.Clear(); - if (namespace_decl && module_sp) { - const bool include_symbols = false; +void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, + lldb::ModuleSP module_sp, + ConstString name, + CompilerDeclContext &namespace_decl, + unsigned current_id) { + if (!m_parser_vars) + return; - module_sp->FindFunctions(name, &namespace_decl, eFunctionNameTypeBase, - include_symbols, include_inlines, sc_list); - } else if (target && !namespace_decl) { - const bool include_symbols = true; + Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); - // TODO Fix FindFunctions so that it doesn't return - // instance methods for eFunctionNameTypeBase. + std::vector<clang::NamedDecl *> decls_from_modules; - target->GetImages().FindFunctions(name, eFunctionNameTypeFull, - include_symbols, include_inlines, - sc_list); + if (target) { + if (ClangModulesDeclVendor *decl_vendor = + target->GetClangModulesDeclVendor()) { + decl_vendor->FindDecls(name, false, UINT32_MAX, decls_from_modules); } + } - // If we found more than one function, see if we can use the frame's decl - // context to remove functions that are shadowed by other functions which - // match in type but are nearer in scope. - // - // AddOneFunction will not add a function whose type has already been - // added, so if there's another function in the list with a matching type, - // check to see if their decl context is a parent of the current frame's or - // was imported via a and using statement, and pick the best match - // according to lookup rules. - if (sc_list.GetSize() > 1) { - // Collect some info about our frame's context. - StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); - SymbolContext frame_sym_ctx; - if (frame != nullptr) - frame_sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | - lldb::eSymbolContextBlock); - CompilerDeclContext frame_decl_context = - frame_sym_ctx.block != nullptr ? frame_sym_ctx.block->GetDeclContext() - : CompilerDeclContext(); - - // We can't do this without a compiler decl context for our frame. - if (frame_decl_context) { - clang::DeclContext *frame_decl_ctx = - (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext(); - ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>( - frame_decl_context.GetTypeSystem()); - - // Structure to hold the info needed when comparing function - // declarations. - struct FuncDeclInfo { - ConstString m_name; - CompilerType m_copied_type; - uint32_t m_decl_lvl; - SymbolContext m_sym_ctx; - }; - - // First, symplify things by looping through the symbol contexts to - // remove unwanted functions and separate out the functions we want to - // compare and prune into a separate list. Cache the info needed about - // the function declarations in a vector for efficiency. - SymbolContextList sc_sym_list; - uint32_t num_indices = sc_list.GetSize(); - std::vector<FuncDeclInfo> fdi_cache; - fdi_cache.reserve(num_indices); - for (uint32_t index = 0; index < num_indices; ++index) { - FuncDeclInfo fdi; - SymbolContext sym_ctx; - sc_list.GetContextAtIndex(index, sym_ctx); - - // We don't know enough about symbols to compare them, but we should - // keep them in the list. - Function *function = sym_ctx.function; - if (!function) { - sc_sym_list.Append(sym_ctx); - continue; - } - // Filter out functions without declaration contexts, as well as - // class/instance methods, since they'll be skipped in the code that - // follows anyway. - CompilerDeclContext func_decl_context = function->GetDeclContext(); - if (!func_decl_context || - func_decl_context.IsClassMethod(nullptr, nullptr, nullptr)) - continue; - // We can only prune functions for which we can copy the type. - CompilerType func_clang_type = - function->GetType()->GetFullCompilerType(); - CompilerType copied_func_type = GuardedCopyType(func_clang_type); - if (!copied_func_type) { - sc_sym_list.Append(sym_ctx); - continue; - } + const bool include_inlines = false; + SymbolContextList sc_list; + if (namespace_decl && module_sp) { + const bool include_symbols = false; - fdi.m_sym_ctx = sym_ctx; - fdi.m_name = function->GetName(); - fdi.m_copied_type = copied_func_type; - fdi.m_decl_lvl = LLDB_INVALID_DECL_LEVEL; - if (fdi.m_copied_type && func_decl_context) { - // Call CountDeclLevels to get the number of parent scopes we have - // to look through before we find the function declaration. When - // comparing functions of the same type, the one with a lower count - // will be closer to us in the lookup scope and shadows the other. - clang::DeclContext *func_decl_ctx = - (clang::DeclContext *)func_decl_context.GetOpaqueDeclContext(); - fdi.m_decl_lvl = ast->CountDeclLevels( - frame_decl_ctx, func_decl_ctx, &fdi.m_name, &fdi.m_copied_type); - } - fdi_cache.emplace_back(fdi); - } + module_sp->FindFunctions(name, &namespace_decl, eFunctionNameTypeBase, + include_symbols, include_inlines, sc_list); + } else if (target && !namespace_decl) { + const bool include_symbols = true; - // Loop through the functions in our cache looking for matching types, - // then compare their scope levels to see which is closer. - std::multimap<CompilerType, const FuncDeclInfo *> matches; - for (const FuncDeclInfo &fdi : fdi_cache) { - const CompilerType t = fdi.m_copied_type; - auto q = matches.find(t); - if (q != matches.end()) { - if (q->second->m_decl_lvl > fdi.m_decl_lvl) - // This function is closer; remove the old set. - matches.erase(t); - else if (q->second->m_decl_lvl < fdi.m_decl_lvl) - // The functions in our set are closer - skip this one. - continue; - } - matches.insert(std::make_pair(t, &fdi)); - } + // TODO Fix FindFunctions so that it doesn't return + // instance methods for eFunctionNameTypeBase. - // Loop through our matches and add their symbol contexts to our list. - SymbolContextList sc_func_list; - for (const auto &q : matches) - sc_func_list.Append(q.second->m_sym_ctx); + target->GetImages().FindFunctions( + name, eFunctionNameTypeFull | eFunctionNameTypeBase, include_symbols, + include_inlines, sc_list); + } - // Rejoin the lists with the functions in front. - sc_list = sc_func_list; - sc_list.Append(sc_sym_list); - } + // If we found more than one function, see if we can use the frame's decl + // context to remove functions that are shadowed by other functions which + // match in type but are nearer in scope. + // + // AddOneFunction will not add a function whose type has already been + // added, so if there's another function in the list with a matching type, + // check to see if their decl context is a parent of the current frame's or + // was imported via a and using statement, and pick the best match + // according to lookup rules. + if (sc_list.GetSize() > 1) { + // Collect some info about our frame's context. + StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); + SymbolContext frame_sym_ctx; + if (frame != nullptr) + frame_sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | + lldb::eSymbolContextBlock); + CompilerDeclContext frame_decl_context = + frame_sym_ctx.block != nullptr ? frame_sym_ctx.block->GetDeclContext() + : CompilerDeclContext(); + + // We can't do this without a compiler decl context for our frame. + if (frame_decl_context) { + sc_list = SearchFunctionsInSymbolContexts(sc_list, frame_decl_context); } + } - if (sc_list.GetSize()) { - Symbol *extern_symbol = nullptr; - Symbol *non_extern_symbol = nullptr; - - for (uint32_t index = 0, num_indices = sc_list.GetSize(); - index < num_indices; ++index) { - SymbolContext sym_ctx; - sc_list.GetContextAtIndex(index, sym_ctx); + if (sc_list.GetSize()) { + Symbol *extern_symbol = nullptr; + Symbol *non_extern_symbol = nullptr; - if (sym_ctx.function) { - CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext(); + for (uint32_t index = 0, num_indices = sc_list.GetSize(); + index < num_indices; ++index) { + SymbolContext sym_ctx; + sc_list.GetContextAtIndex(index, sym_ctx); - if (!decl_ctx) - continue; + if (sym_ctx.function) { + CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext(); - // Filter out class/instance methods. - if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr)) - continue; + if (!decl_ctx) + continue; - AddOneFunction(context, sym_ctx.function, nullptr, current_id); - context.m_found.function_with_type_info = true; - context.m_found.function = true; - } else if (sym_ctx.symbol) { - if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target) { - sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target); - if (sym_ctx.symbol == nullptr) - continue; - } + // Filter out class/instance methods. + if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr)) + continue; - if (sym_ctx.symbol->IsExternal()) - extern_symbol = sym_ctx.symbol; - else - non_extern_symbol = sym_ctx.symbol; + AddOneFunction(context, sym_ctx.function, nullptr, current_id); + context.m_found.function_with_type_info = true; + context.m_found.function = true; + } else if (sym_ctx.symbol) { + if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target) { + sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target); + if (sym_ctx.symbol == nullptr) + continue; } + + if (sym_ctx.symbol->IsExternal()) + extern_symbol = sym_ctx.symbol; + else + non_extern_symbol = sym_ctx.symbol; } + } - if (!context.m_found.function_with_type_info) { - for (clang::NamedDecl *decl : decls_from_modules) { - if (llvm::isa<clang::FunctionDecl>(decl)) { - clang::NamedDecl *copied_decl = - llvm::cast_or_null<FunctionDecl>(CopyDecl(decl)); - if (copied_decl) { - context.AddNamedDecl(copied_decl); - context.m_found.function_with_type_info = true; - } + if (!context.m_found.function_with_type_info) { + for (clang::NamedDecl *decl : decls_from_modules) { + if (llvm::isa<clang::FunctionDecl>(decl)) { + clang::NamedDecl *copied_decl = + llvm::cast_or_null<FunctionDecl>(CopyDecl(decl)); + if (copied_decl) { + context.AddNamedDecl(copied_decl); + context.m_found.function_with_type_info = true; } } } + } - if (!context.m_found.function_with_type_info) { - if (extern_symbol) { - AddOneFunction(context, nullptr, extern_symbol, current_id); - context.m_found.function = true; - } else if (non_extern_symbol) { - AddOneFunction(context, nullptr, non_extern_symbol, current_id); - context.m_found.function = true; - } + if (!context.m_found.function_with_type_info) { + if (extern_symbol) { + AddOneFunction(context, nullptr, extern_symbol, current_id); + context.m_found.function = true; + } else if (non_extern_symbol) { + AddOneFunction(context, nullptr, non_extern_symbol, current_id); + context.m_found.function = true; } } + } +} - if (!context.m_found.function_with_type_info) { - // Try the modules next. +void ClangExpressionDeclMap::FindExternalVisibleDecls( + NameSearchContext &context, lldb::ModuleSP module_sp, + CompilerDeclContext &namespace_decl, unsigned int current_id) { + assert(m_ast_context); - do { - if (ClangModulesDeclVendor *modules_decl_vendor = - m_target->GetClangModulesDeclVendor()) { - bool append = false; - uint32_t max_matches = 1; - std::vector<clang::NamedDecl *> decls; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls)) - break; + const ConstString name(context.m_decl_name.getAsString().c_str()); + if (IgnoreName(name, false)) + return; - clang::NamedDecl *const decl_from_modules = decls[0]; + // Only look for functions by name out in our symbols if the function doesn't + // start with our phony prefix of '$' - if (llvm::isa<clang::FunctionDecl>(decl_from_modules)) { - if (log) { - LLDB_LOGF(log, - " CAS::FEVD[%u] Matching function found for " - "\"%s\" in the modules", - current_id, name.GetCString()); - } + Target *target = nullptr; + StackFrame *frame = nullptr; + SymbolContext sym_ctx; + if (m_parser_vars) { + target = m_parser_vars->m_exe_ctx.GetTargetPtr(); + frame = m_parser_vars->m_exe_ctx.GetFramePtr(); + } + if (frame != nullptr) + sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | + lldb::eSymbolContextBlock); - clang::Decl *copied_decl = CopyDecl(decl_from_modules); - clang::FunctionDecl *copied_function_decl = - copied_decl ? dyn_cast<clang::FunctionDecl>(copied_decl) - : nullptr; + // Try the persistent decls, which take precedence over all else. + if (!namespace_decl) + SearchPersistenDecls(context, name, current_id); - if (!copied_function_decl) { - LLDB_LOGF(log, - " CAS::FEVD[%u] - Couldn't export a function " - "declaration from the modules", - current_id); + if (name.GetStringRef().startswith("$") && !namespace_decl) { + if (name == "$__lldb_class") { + LookUpLldbClass(context, current_id); + return; + } - break; - } + if (name == "$__lldb_objc_class") { + LookUpLldbObjCClass(context, current_id); + return; + } + if (name == g_lldb_local_vars_namespace_cstr) { + LookupLocalVarNamespace(sym_ctx, context); + return; + } + + // any other $__lldb names should be weeded out now + if (name.GetStringRef().startswith("$__lldb")) + return; - MaybeRegisterFunctionBody(copied_function_decl); + // No ParserVars means we can't do register or variable lookup. + if (!m_parser_vars || !m_parser_vars->m_persistent_vars) + return; - context.AddNamedDecl(copied_function_decl); + ExpressionVariableSP pvar_sp( + m_parser_vars->m_persistent_vars->GetVariable(name)); - context.m_found.function_with_type_info = true; - context.m_found.function = true; - } else if (llvm::isa<clang::VarDecl>(decl_from_modules)) { - if (log) { - LLDB_LOGF(log, - " CAS::FEVD[%u] Matching variable found for " - "\"%s\" in the modules", - current_id, name.GetCString()); - } + if (pvar_sp) { + AddOneVariable(context, pvar_sp, current_id); + return; + } - clang::Decl *copied_decl = CopyDecl(decl_from_modules); - clang::VarDecl *copied_var_decl = - copied_decl ? dyn_cast_or_null<clang::VarDecl>(copied_decl) - : nullptr; + assert(name.GetStringRef().startswith("$")); + llvm::StringRef reg_name = name.GetStringRef().substr(1); - if (!copied_var_decl) { - LLDB_LOGF(log, - " CAS::FEVD[%u] - Couldn't export a variable " - "declaration from the modules", - current_id); + if (m_parser_vars->m_exe_ctx.GetRegisterContext()) { + const RegisterInfo *reg_info( + m_parser_vars->m_exe_ctx.GetRegisterContext()->GetRegisterInfoByName( + reg_name)); - break; - } + if (reg_info) { + LLDB_LOGF(log, " CEDM::FEVD[%u] Found register %s", current_id, + reg_info->name); - context.AddNamedDecl(copied_var_decl); + AddOneRegister(context, reg_info, current_id); + } + } + return; + } - context.m_found.variable = true; - } - } - } while (false); + bool local_var_lookup = !namespace_decl || (namespace_decl.GetName() == + g_lldb_local_vars_namespace_cstr); + if (frame && local_var_lookup) + if (LookupLocalVariable(context, name, current_id, sym_ctx, namespace_decl)) + return; + + if (target) { + ValueObjectSP valobj; + VariableSP var; + var = FindGlobalVariable(*target, module_sp, name, &namespace_decl); + + if (var) { + valobj = ValueObjectVariable::Create(target, var); + AddOneVariable(context, var, valobj, current_id); + context.m_found.variable = true; + return; } + } - if (target && !context.m_found.variable && !namespace_decl) { - // We couldn't find a non-symbol variable for this. Now we'll hunt for a - // generic data symbol, and -- if it is found -- treat it as a variable. - Status error; + LookupFunction(context, module_sp, name, namespace_decl, current_id); - const Symbol *data_symbol = - m_parser_vars->m_sym_ctx.FindBestGlobalDataSymbol(name, error); + // Try the modules next. + if (!context.m_found.function_with_type_info) + LookupInModulesDeclVendor(context, name, current_id); - if (!error.Success()) { - const unsigned diag_id = - m_ast_context->getDiagnostics().getCustomDiagID( - clang::DiagnosticsEngine::Level::Error, "%0"); - m_ast_context->getDiagnostics().Report(diag_id) << error.AsCString(); - } + if (target && !context.m_found.variable && !namespace_decl) { + // We couldn't find a non-symbol variable for this. Now we'll hunt for a + // generic data symbol, and -- if it is found -- treat it as a variable. + Status error; - if (data_symbol) { - std::string warning("got name from symbols: "); - warning.append(name.AsCString()); - const unsigned diag_id = - m_ast_context->getDiagnostics().getCustomDiagID( - clang::DiagnosticsEngine::Level::Warning, "%0"); - m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str(); - AddOneGenericVariable(context, *data_symbol, current_id); - context.m_found.variable = true; - } + const Symbol *data_symbol = + m_parser_vars->m_sym_ctx.FindBestGlobalDataSymbol(name, error); + + if (!error.Success()) { + const unsigned diag_id = + m_ast_context->getDiagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Level::Error, "%0"); + m_ast_context->getDiagnostics().Report(diag_id) << error.AsCString(); + } + + if (data_symbol) { + std::string warning("got name from symbols: "); + warning.append(name.AsCString()); + const unsigned diag_id = + m_ast_context->getDiagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Level::Warning, "%0"); + m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str(); + AddOneGenericVariable(context, *data_symbol, current_id); + context.m_found.variable = true; } } } @@ -1543,15 +1508,6 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, return false; } - ASTContext *ast = clang_ast->getASTContext(); - - if (!ast) { - if (log) - log->PutCString( - "There is no AST context for the current execution context"); - return false; - } - DWARFExpression &var_location_expr = var->LocationExpression(); Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); @@ -1664,14 +1620,10 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, if (is_reference) entity->m_flags |= ClangExpressionVariable::EVTypeIsReference; - if (log) { - ASTDumper orig_dumper(ut.GetOpaqueQualType()); - ASTDumper ast_dumper(var_decl); - LLDB_LOGF(log, - " CEDM::FEVD[%u] Found variable %s, returned %s (original %s)", - current_id, decl_name.c_str(), ast_dumper.GetCString(), - orig_dumper.GetCString()); - } + LLDB_LOG(log, + " CEDM::FEVD[{0}] Found variable {1}, returned\n{2} (original {3})", + current_id, decl_name, ClangUtil::DumpDecl(var_decl), + ClangUtil::ToString(ut)); } void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, @@ -1703,11 +1655,8 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value.Clear(); - if (log) { - ASTDumper ast_dumper(var_decl); - LLDB_LOGF(log, " CEDM::FEVD[%u] Added pvar %s, returned %s", current_id, - pvar_sp->GetName().GetCString(), ast_dumper.GetCString()); - } + LLDB_LOG(log, " CEDM::FEVD[{0}] Added pvar {1}, returned\n{2}", current_id, + pvar_sp->GetName(), ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, @@ -1722,17 +1671,16 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, if (target == nullptr) return; - ASTContext *scratch_ast_context = - target->GetScratchClangASTContext()->getASTContext(); + ClangASTContext *scratch_ast_context = ClangASTContext::GetScratch(*target); + if (!scratch_ast_context) + return; - TypeFromUser user_type( - ClangASTContext::GetBasicType(scratch_ast_context, eBasicTypeVoid) - .GetPointerType() - .GetLValueReferenceType()); - TypeFromParser parser_type( - ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid) - .GetPointerType() - .GetLValueReferenceType()); + TypeFromUser user_type(scratch_ast_context->GetBasicType(eBasicTypeVoid) + .GetPointerType() + .GetLValueReferenceType()); + TypeFromParser parser_type(m_clang_ast_context->GetBasicType(eBasicTypeVoid) + .GetPointerType() + .GetLValueReferenceType()); NamedDecl *var_decl = context.AddVarDecl(parser_type); std::string decl_name(context.m_decl_name.getAsString()); @@ -1761,86 +1709,8 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_sym = &symbol; - if (log) { - ASTDumper ast_dumper(var_decl); - - LLDB_LOGF(log, " CEDM::FEVD[%u] Found variable %s, returned %s", - current_id, decl_name.c_str(), ast_dumper.GetCString()); - } -} - -bool ClangExpressionDeclMap::ResolveUnknownTypes() { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr(); - - ClangASTContextForExpressions *scratch_ast_context = - static_cast<ClangASTContextForExpressions *>( - target->GetScratchClangASTContext()); - - for (size_t index = 0, num_entities = m_found_entities.GetSize(); - index < num_entities; ++index) { - ExpressionVariableSP entity = m_found_entities.GetVariableAtIndex(index); - - ClangExpressionVariable::ParserVars *parser_vars = - llvm::cast<ClangExpressionVariable>(entity.get()) - ->GetParserVars(GetParserID()); - - if (entity->m_flags & ClangExpressionVariable::EVUnknownType) { - const NamedDecl *named_decl = parser_vars->m_named_decl; - const VarDecl *var_decl = dyn_cast<VarDecl>(named_decl); - - if (!var_decl) { - LLDB_LOGF(log, "Entity of unknown type does not have a VarDecl"); - return false; - } - - if (log) { - ASTDumper ast_dumper(const_cast<VarDecl *>(var_decl)); - LLDB_LOGF(log, "Variable of unknown type now has Decl %s", - ast_dumper.GetCString()); - } - - QualType var_type = var_decl->getType(); - TypeFromParser parser_type( - var_type.getAsOpaquePtr(), - ClangASTContext::GetASTContext(&var_decl->getASTContext())); - - lldb::opaque_compiler_type_t copied_type = nullptr; - if (m_ast_importer_sp) { - copied_type = m_ast_importer_sp->CopyType( - scratch_ast_context->getASTContext(), &var_decl->getASTContext(), - var_type.getAsOpaquePtr()); - } else if (HasMerger()) { - copied_type = CopyTypeWithMerger( - var_decl->getASTContext(), - scratch_ast_context->GetMergerUnchecked(), var_type) - .getAsOpaquePtr(); - } else { - lldbassert(0 && "No mechanism to copy a resolved unknown type!"); - return false; - } - - if (!copied_type) { - LLDB_LOGF(log, "ClangExpressionDeclMap::ResolveUnknownType - Couldn't " - "import the type for a variable"); - - return (bool)lldb::ExpressionVariableSP(); - } - - TypeFromUser user_type(copied_type, scratch_ast_context); - - // parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, - // user_type.GetOpaqueQualType()); - parser_vars->m_lldb_value.SetCompilerType(user_type); - parser_vars->m_parser_type = parser_type; - - entity->SetCompilerType(user_type); - - entity->m_flags &= ~(ClangExpressionVariable::EVUnknownType); - } - } - - return true; + LLDB_LOG(log, " CEDM::FEVD[{0}] Found variable {1}, returned\n{2}", + current_id, decl_name, ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, @@ -1849,8 +1719,8 @@ void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); CompilerType clang_type = - ClangASTContext::GetBuiltinTypeForEncodingAndBitSize( - m_ast_context, reg_info->encoding, reg_info->byte_size * 8); + m_clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( + reg_info->encoding, reg_info->byte_size * 8); if (!clang_type) { LLDB_LOGF(log, " Tried to add a type for %s, but couldn't get one", @@ -1880,12 +1750,9 @@ void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, parser_vars->m_lldb_value.Clear(); entity->m_flags |= ClangExpressionVariable::EVBareRegister; - if (log) { - ASTDumper ast_dumper(var_decl); - LLDB_LOGF(log, " CEDM::FEVD[%d] Added register %s, returned %s", - current_id, context.m_decl_name.getAsString().c_str(), - ast_dumper.GetCString()); - } + LLDB_LOG(log, " CEDM::FEVD[{0}] Added register {1}, returned\n{2}", + current_id, context.m_decl_name.getAsString(), + ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, @@ -1928,17 +1795,16 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, CopyDecl(function_template)); if (copied_function_template) { if (log) { - ASTDumper ast_dumper((clang::Decl *)copied_function_template); - StreamString ss; function->DumpSymbolContext(&ss); - log->Printf(" CEDM::FEVD[%u] Imported decl for function template" - " %s (description %s), returned %s", - current_id, - copied_function_template->getNameAsString().c_str(), - ss.GetData(), ast_dumper.GetCString()); + LLDB_LOG(log, + " CEDM::FEVD[{0}] Imported decl for function template" + " {1} (description {2}), returned\n{3}", + current_id, copied_function_template->getNameAsString(), + ss.GetData(), + ClangUtil::DumpDecl(copied_function_template)); } context.AddNamedDecl(copied_function_template); @@ -1948,18 +1814,15 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, llvm::dyn_cast_or_null<clang::FunctionDecl>( CopyDecl(src_function_decl))) { if (log) { - ASTDumper ast_dumper((clang::Decl *)copied_function_decl); - StreamString ss; function->DumpSymbolContext(&ss); - LLDB_LOGF(log, - " CEDM::FEVD[%u] Imported decl for function %s " - "(description %s), returned %s", - current_id, - copied_function_decl->getNameAsString().c_str(), - ss.GetData(), ast_dumper.GetCString()); + LLDB_LOG(log, + " CEDM::FEVD[{0}]] Imported decl for function {1} " + "(description {2}), returned\n{3}", + current_id, copied_function_decl->getNameAsString(), + ss.GetData(), ClangUtil::DumpDecl(copied_function_decl)); } context.AddNamedDecl(copied_function_decl); @@ -2061,20 +1924,17 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, parser_vars->m_llvm_value = nullptr; if (log) { - std::string function_str = - function_decl ? ASTDumper(function_decl).GetCString() : "nullptr"; - StreamString ss; fun_address.Dump(&ss, m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription); - LLDB_LOGF( - log, - " CEDM::FEVD[%u] Found %s function %s (description %s), returned %s", - current_id, (function ? "specific" : "generic"), decl_name.c_str(), - ss.GetData(), function_str.c_str()); + LLDB_LOG(log, + " CEDM::FEVD[{0}] Found {1} function {2} (description {3}), " + "returned\n{4}", + current_id, (function ? "specific" : "generic"), decl_name, + ss.GetData(), ClangUtil::DumpDecl(function_decl)); } } @@ -2097,11 +1957,11 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, if (copied_clang_type.IsAggregateType() && copied_clang_type.GetCompleteType()) { CompilerType void_clang_type = - ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid); + m_clang_ast_context->GetBasicType(eBasicTypeVoid); CompilerType void_ptr_clang_type = void_clang_type.GetPointerType(); - CompilerType method_type = ClangASTContext::CreateFunctionType( - m_ast_context, void_clang_type, &void_ptr_clang_type, 1, false, 0); + CompilerType method_type = m_clang_ast_context->CreateFunctionType( + void_clang_type, &void_ptr_clang_type, 1, false, 0); const bool is_virtual = false; const bool is_static = false; @@ -2110,22 +1970,16 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, const bool is_attr_used = true; const bool is_artificial = false; - CXXMethodDecl *method_decl = - ClangASTContext::GetASTContext(m_ast_context) - ->AddMethodToCXXRecordType( - copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr, - method_type, lldb::eAccessPublic, is_virtual, is_static, - is_inline, is_explicit, is_attr_used, is_artificial); - - if (log) { - ASTDumper method_ast_dumper((clang::Decl *)method_decl); - ASTDumper type_ast_dumper(copied_clang_type); + CXXMethodDecl *method_decl = m_clang_ast_context->AddMethodToCXXRecordType( + copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr, + method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline, + is_explicit, is_attr_used, is_artificial); - LLDB_LOGF(log, - " CEDM::AddThisType Added function $__lldb_expr " - "(description %s) for this type %s", - method_ast_dumper.GetCString(), type_ast_dumper.GetCString()); - } + LLDB_LOG(log, + " CEDM::AddThisType Added function $__lldb_expr " + "(description {0}) for this type\n{1}", + ClangUtil::ToString(copied_clang_type), + ClangUtil::DumpDecl(method_decl)); } if (!copied_clang_type.IsValid()) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index 2711e90726e7..722f5e15a2aa 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -63,12 +63,15 @@ public: /// the result persistent variable, and instead marks the variable /// as persisting. /// - /// \param[in] delegate + /// \param[in] result_delegate /// If non-NULL, use this delegate to report result values. This /// allows the client ClangUserExpression to report a result. /// - /// \param[in] exe_ctx - /// The execution context to use when parsing. + /// \param[in] target + /// The target to use when parsing. + /// + /// \param[in] importer + /// The ClangASTImporter to use when parsing. /// /// \param[in] ctx_obj /// If not empty, then expression is evaluated in context of this object. @@ -76,7 +79,7 @@ public: ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, - ExecutionContext &exe_ctx, + const lldb::TargetSP &target, const lldb::ClangASTImporterSP &importer, ValueObject *ctx_obj); /// Destructor @@ -98,13 +101,6 @@ public: void InstallCodeGenerator(clang::ASTConsumer *code_gen); - /// [Used by ClangExpressionParser] For each variable that had an unknown - /// type at the beginning of parsing, determine its final type now. - /// - /// \return - /// True on success; false otherwise. - bool ResolveUnknownTypes(); - /// Disable the state needed for parsing and IR transformation. void DidParse(); @@ -248,17 +244,6 @@ public: lldb::addr_t GetSymbolAddress(ConstString name, lldb::SymbolType symbol_type); - /// [Used by IRInterpreter] Get basic target information. - /// - /// \param[out] byte_order - /// The byte order of the target. - /// - /// \param[out] address_byte_size - /// The size of a pointer in bytes. - /// - /// \return - /// True if the information could be determined; false - /// otherwise. struct TargetInfo { lldb::ByteOrder byte_order; size_t address_byte_size; @@ -276,9 +261,6 @@ public: /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. - /// - /// \return - /// True on success; false otherwise. void FindExternalVisibleDecls(NameSearchContext &context) override; /// Find all entities matching a given name in a given module/namespace, @@ -296,14 +278,19 @@ public: /// \param[in] current_id /// The ID for the current FindExternalVisibleDecls invocation, /// for logging purposes. - /// - /// \return - /// True on success; false otherwise. void FindExternalVisibleDecls(NameSearchContext &context, lldb::ModuleSP module, CompilerDeclContext &namespace_decl, unsigned int current_id); +protected: + /// Retrieves the declaration with the given name from the storage of + /// persistent declarations. + /// + /// \return + /// A persistent decl with the given name or a nullptr. + virtual clang::NamedDecl *GetPersistentDecl(ConstString name); + private: ExpressionVariableList m_found_entities; ///< All entities that were looked up for the parser. @@ -329,7 +316,7 @@ private: if (m_exe_ctx.GetTargetPtr()) return m_exe_ctx.GetTargetPtr(); else if (m_sym_ctx.target_sp) - m_sym_ctx.target_sp.get(); + return m_sym_ctx.target_sp.get(); return nullptr; } @@ -396,6 +383,130 @@ private: /// from persistent variables. uint64_t GetParserID() { return (uint64_t) this; } + /// Should be called on all copied functions. + void MaybeRegisterFunctionBody(clang::FunctionDecl *copied_function_decl); + + /// Searches the persistent decls of the target for entities with the + /// given name. + /// + /// \param[in] context + /// The NameSearchContext that can construct Decls for this name. + /// + /// \param[in] name + /// The name of the entities that need to be found. + /// + /// \param[in] current_id + /// The ID for the current FindExternalVisibleDecls invocation, + /// for logging purposes. + void SearchPersistenDecls(NameSearchContext &context, const ConstString name, + unsigned int current_id); + + /// Handles looking up $__lldb_class which requires special treatment. + /// + /// \param[in] context + /// The NameSearchContext that can construct Decls for this name. + /// + /// \param[in] current_id + /// The ID for the current FindExternalVisibleDecls invocation, + /// for logging purposes. + void LookUpLldbClass(NameSearchContext &context, unsigned int current_id); + + /// Handles looking up $__lldb_objc_class which requires special treatment. + /// + /// \param[in] context + /// The NameSearchContext that can construct Decls for this name. + /// + /// \param[in] current_id + /// The ID for the current FindExternalVisibleDecls invocation, + /// for logging purposes. + void LookUpLldbObjCClass(NameSearchContext &context, unsigned int current_id); + + /// Handles looking up the synthetic namespace that contains our local + /// variables for the current frame. + /// + /// \param[in] sym_ctx + /// The current SymbolContext of this frame. + /// + /// \param[in] name_context + /// The NameSearchContext that can construct Decls for this name. + void LookupLocalVarNamespace(SymbolContext &sym_ctx, + NameSearchContext &name_context); + + /// Lookup entities in the ClangModulesDeclVendor. + /// \param[in] context + /// The NameSearchContext that can construct Decls for this name. + /// + /// \param[in] name + /// The name of the entities that need to be found. + /// + /// \param[in] current_id + /// The ID for the current FindExternalVisibleDecls invocation, + /// for logging purposes. + void LookupInModulesDeclVendor(NameSearchContext &context, ConstString name, + unsigned current_id); + + /// Looks up a local variable. + /// + /// \param[in] context + /// The NameSearchContext that can construct Decls for this name. + /// + /// \param[in] name + /// The name of the entities that need to be found. + /// + /// \param[in] current_id + /// The ID for the current FindExternalVisibleDecls invocation, + /// for logging purposes. + /// + /// \param[in] sym_ctx + /// The current SymbolContext of this frame. + /// + /// \param[in] namespace_decl + /// The parent namespace if there is one. + /// + /// \return + /// True iff a local variable was found. + bool LookupLocalVariable(NameSearchContext &context, ConstString name, + unsigned current_id, SymbolContext &sym_ctx, + CompilerDeclContext &namespace_decl); + + /// Searches for functions in the given SymbolContextList. + /// + /// \param[in] sc_list + /// The SymbolContextList to search. + /// + /// \param[in] frame_decl_context + /// The current DeclContext of the current frame. + /// + /// \return + /// A SymbolContextList with any found functions in the front and + /// any unknown SymbolContexts which are not functions in the back. + /// The SymbolContexts for the functions are ordered by how close they are + /// to the DeclContext for the given frame DeclContext. + SymbolContextList SearchFunctionsInSymbolContexts( + const SymbolContextList &sc_list, + const CompilerDeclContext &frame_decl_context); + + /// Looks up a function. + /// + /// \param[in] context + /// The NameSearchContext that can construct Decls for this name. + /// + /// \param[in] module_sp + /// If non-NULL, the module to query. + /// + /// \param[in] name + /// The name of the function that should be find. + /// + /// \param[in] namespace_decl + /// If valid and module is non-NULL, the parent namespace. + /// + /// \param[in] current_id + /// The ID for the current FindExternalVisibleDecls invocation, + /// for logging purposes. + void LookupFunction(NameSearchContext &context, lldb::ModuleSP module_sp, + ConstString name, CompilerDeclContext &namespace_decl, + unsigned current_id); + /// Given a target, find a variable that matches the given name and type. /// /// \param[in] target @@ -410,17 +521,11 @@ private: /// \param[in] namespace_decl /// If non-NULL and module is non-NULL, the parent namespace. /// - /// \param[in] type - /// The required type for the variable. This function may be called - /// during parsing, in which case we don't know its type; hence the - /// default. - /// /// \return /// The LLDB Variable found, or NULL if none was found. lldb::VariableSP FindGlobalVariable(Target &target, lldb::ModuleSP &module, ConstString name, - CompilerDeclContext *namespace_decl, - TypeFromUser *type = nullptr); + CompilerDeclContext *namespace_decl); /// Get the value of a variable in a given execution context and return the /// associated Types if needed. @@ -441,9 +546,6 @@ private: /// AST context. This is only useful when the variable is being /// inspected on behalf of the parser, hence the default. /// - /// \param[in] decl - /// The Decl to be looked up. - /// /// \return /// Return true if the value was successfully filled in. bool GetVariableValue(lldb::VariableSP &var, @@ -471,7 +573,7 @@ private: /// \param[in] context /// The NameSearchContext to use when constructing the Decl. /// - /// \param[in] pvar + /// \param[in] pvar_sp /// The persistent variable that needs a Decl. /// /// \param[in] current_id @@ -483,12 +585,6 @@ private: /// Use the NameSearchContext to generate a Decl for the given LLDB symbol /// (treated as a variable), and put it in the list of found entities. - /// - /// \param[in] context - /// The NameSearchContext to use when constructing the Decl. - /// - /// \param[in] var - /// The LLDB Variable that needs a Decl. void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol, unsigned int current_id); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 1422911d6546..8abd14942885 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -10,6 +10,7 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" @@ -582,15 +583,16 @@ ClangExpressionParser::ClangExpressionParser( if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor()) { - ClangPersistentVariables *clang_persistent_vars = - llvm::cast<ClangPersistentVariables>( + if (auto *clang_persistent_vars = llvm::cast<ClangPersistentVariables>( target_sp->GetPersistentExpressionStateForLanguage( - lldb::eLanguageTypeC)); - std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks( - *decl_vendor, *clang_persistent_vars, m_compiler->getSourceManager())); - m_pp_callbacks = - static_cast<LLDBPreprocessorCallbacks *>(pp_callbacks.get()); - m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); + lldb::eLanguageTypeC))) { + std::unique_ptr<PPCallbacks> pp_callbacks( + new LLDBPreprocessorCallbacks(*decl_vendor, *clang_persistent_vars, + m_compiler->getSourceManager())); + m_pp_callbacks = + static_cast<LLDBPreprocessorCallbacks *>(pp_callbacks.get()); + m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); + } } // 8. Most of this we get from the CompilerInstance, but we also want to give @@ -696,10 +698,7 @@ class CodeComplete : public CodeCompleteConsumer { public: /// Constructs a CodeComplete consumer that can be attached to a Sema. - /// \param[out] matches - /// The list of matches that the lldb completion API expects as a result. - /// This may already contain matches, so it's only allowed to append - /// to this variable. + /// /// \param[out] expr /// The whole expression string that we are currently parsing. This /// string needs to be equal to the input the user typed, and NOT the @@ -976,7 +975,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, m_compiler->setASTConsumer(std::move(Consumer)); if (ast_context.getLangOpts().Modules) { - m_compiler->createModuleManager(); + m_compiler->createASTReader(); m_ast_context->setSema(&m_compiler->getSema()); } @@ -999,7 +998,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, } else { ast_context.setExternalSource(ast_source); } - decl_map->InstallASTContext(ast_context, m_compiler->getFileManager()); + decl_map->InstallASTContext(*m_ast_context); } // Check that the ASTReader is properly attached to ASTContext and Sema. @@ -1036,15 +1035,6 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, } 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++; - } - } - - if (!num_errors) { type_system_helper->CommitPersistentDecls(); } @@ -1268,8 +1258,9 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( interpret_error, interpret_function_calls); if (!can_interpret && execution_policy == eExecutionPolicyNever) { - err.SetErrorStringWithFormat("Can't run the expression locally: %s", - interpret_error.AsCString()); + err.SetErrorStringWithFormat( + "Can't evaluate the expression without a running target due to: %s", + interpret_error.AsCString()); return err; } } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 79ad5728bf74..4a410cecb94a 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -42,7 +42,7 @@ public: /// /// Initializes class variables. /// - /// \param[in] exe_scope, + /// \param[in] exe_scope /// If non-NULL, an execution context scope that can help to /// correctly create an expression with a valid process for /// optional tuning Objective-C runtime support. Can be NULL. @@ -77,7 +77,7 @@ public: /// \return /// The number of errors encountered during parsing. 0 means /// success. - unsigned Parse(DiagnosticManager &diagnostic_manager) override; + unsigned Parse(DiagnosticManager &diagnostic_manager); bool RewriteExpression(DiagnosticManager &diagnostic_manager) override; @@ -99,15 +99,6 @@ public: /// \param[in] exe_ctx /// The execution context to write the function into. /// - /// \param[out] evaluated_statically - /// Set to true if the expression could be interpreted statically; - /// untouched otherwise. - /// - /// \param[out] const_result - /// If the result of the expression is constant, and the - /// expression has no side effects, this is set to the result of the - /// expression. - /// /// \param[in] execution_policy /// Determines whether the expression must be JIT-compiled, must be /// evaluated statically, or whether this decision may be made diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index 21cb33402e7f..7ebb5fee1ec6 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -315,12 +315,10 @@ bool ClangExpressionSourceCode::GetText( } } - if (ClangModulesDeclVendor *decl_vendor = - target->GetClangModulesDeclVendor()) { - ClangPersistentVariables *persistent_vars = - llvm::cast<ClangPersistentVariables>( - target->GetPersistentExpressionStateForLanguage( - lldb::eLanguageTypeC)); + ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor(); + auto *persistent_vars = llvm::cast<ClangPersistentVariables>( + target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); + if (decl_vendor && persistent_vars) { const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = persistent_vars->GetHandLoadedClangModules(); ClangModulesDeclVendor::ModuleVector modules_for_macros; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index eb7f74f20a20..0e6de28ee4df 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -74,9 +74,6 @@ public: /// Finds a variable by NamedDecl in the list. /// - /// \param[in] name - /// The name of the requested variable. - /// /// \return /// The variable requested, or NULL if that variable is not in the list. static ClangExpressionVariable * diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 8fbfa6e47578..7f7c0a97f538 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -42,6 +42,8 @@ using namespace lldb_private; +char ClangFunctionCaller::ID; + // ClangFunctionCaller constructor ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope, const CompilerType &return_type, @@ -186,10 +188,10 @@ ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp, lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); if (jit_process_sp) { const bool generate_debug_info = true; - m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this, - generate_debug_info)); - - num_errors = m_parser->Parse(diagnostic_manager); + auto *clang_parser = new ClangExpressionParser(jit_process_sp.get(), *this, + generate_debug_info); + num_errors = clang_parser->Parse(diagnostic_manager); + m_parser.reset(clang_parser); } else { diagnostic_manager.PutString(eDiagnosticSeverityError, "no process - unable to inject function"); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h index 24f6f2eb91b3..150a913152d0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h @@ -59,11 +59,6 @@ class ClangExpressionParser; class ClangFunctionCaller : public FunctionCaller { friend class ASTStructExtractor; - /// LLVM-style RTTI support. - static bool classof(const Expression *E) { - return E->getKind() == eKindClangFunctionCaller; - } - class ClangFunctionCallerHelper : public ClangExpressionHelper { public: ClangFunctionCallerHelper(ClangFunctionCaller &owner) : m_owner(owner) {} @@ -91,18 +86,23 @@ class ClangFunctionCaller : public FunctionCaller { ///layout. }; + // LLVM RTTI support + static char ID; + public: + bool isA(const void *ClassID) const override { + return ClassID == &ID || FunctionCaller::isA(ClassID); + } + static bool classof(const Expression *obj) { return obj->isA(&ID); } + /// Constructor /// /// \param[in] exe_scope /// An execution context scope that gets us at least a target and /// process. /// - /// \param[in] ast_context - /// The AST context to evaluate argument types in. - /// - /// \param[in] return_qualtype - /// An opaque Clang QualType for the function result. Should be + /// \param[in] return_type + /// A compiler type for the function result. Should be /// defined in ast_context. /// /// \param[in] function_address diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index f3df589d7311..0696c669f2e2 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -80,12 +80,10 @@ public: Stream &error_stream) override; uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, - std::vector<clang::NamedDecl *> &decls) override; + std::vector<CompilerDecl> &decls) override; void ForEachMacro(const ModuleVector &modules, std::function<bool(const std::string &)> handler) override; - - clang::ExternalASTMerger::ImporterSource GetImporterSource() override; private: void ReportModuleExportsHelper(std::set<ClangModulesDeclVendor::ModuleID> &exports, @@ -110,7 +108,6 @@ private: typedef std::set<ModuleID> ImportedModuleSet; ImportedModuleMap m_imported_modules; ImportedModuleSet m_user_imported_modules; - const clang::ExternalASTMerger::OriginMap m_origin_map; // We assume that every ASTContext has an ClangASTContext, so we also store // a custom ClangASTContext for our internal ASTContext. std::unique_ptr<ClangASTContext> m_ast_context; @@ -160,7 +157,7 @@ ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl( : m_diagnostics_engine(std::move(diagnostics_engine)), m_compiler_invocation(std::move(compiler_invocation)), m_compiler_instance(std::move(compiler_instance)), - m_parser(std::move(parser)), m_origin_map() { + m_parser(std::move(parser)) { // Initialize our ClangASTContext. m_ast_context.reset(new ClangASTContext(m_compiler_instance->getASTContext())); @@ -359,7 +356,7 @@ bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit( uint32_t ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, uint32_t max_matches, - std::vector<clang::NamedDecl *> &decls) { + std::vector<CompilerDecl> &decls) { if (!m_enabled) { return 0; } @@ -385,7 +382,7 @@ ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, if (num_matches >= max_matches) return num_matches; - decls.push_back(named_decl); + decls.push_back(CompilerDecl(m_ast_context.get(), named_decl)); ++num_matches; } @@ -569,13 +566,6 @@ ClangModulesDeclVendorImpl::DoGetModule(clang::ModuleIdPath path, is_inclusion_directive); } -clang::ExternalASTMerger::ImporterSource -ClangModulesDeclVendorImpl::GetImporterSource() { - return clang::ExternalASTMerger::ImporterSource( - m_compiler_instance->getASTContext(), - m_compiler_instance->getFileManager(), m_origin_map); -} - static const char *ModuleImportBufferName = "LLDBModulesMemoryBuffer"; lldb_private::ClangModulesDeclVendor * @@ -704,7 +694,7 @@ ClangModulesDeclVendor::Create(Target &target) { instance->getPreprocessor().enableIncrementalProcessing(); - instance->createModuleManager(); + instance->createASTReader(); instance->createSema(action->getTranslationUnitKind(), nullptr); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 24dd705e37b1..41d62a462ab4 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -67,39 +67,35 @@ void ClangPersistentVariables::RemovePersistentVariable( llvm::Optional<CompilerType> ClangPersistentVariables::GetCompilerTypeFromPersistentDecl( ConstString type_name) { - CompilerType compiler_type; - if (clang::TypeDecl *tdecl = llvm::dyn_cast_or_null<clang::TypeDecl>( - GetPersistentDecl(type_name))) { - compiler_type.SetCompilerType( - ClangASTContext::GetASTContext(&tdecl->getASTContext()), - reinterpret_cast<lldb::opaque_compiler_type_t>( - const_cast<clang::Type *>(tdecl->getTypeForDecl()))); - return compiler_type; + PersistentDecl p = m_persistent_decls.lookup(type_name.GetCString()); + + if (p.m_decl == nullptr) + return llvm::None; + + if (clang::TypeDecl *tdecl = llvm::dyn_cast<clang::TypeDecl>(p.m_decl)) { + opaque_compiler_type_t t = static_cast<opaque_compiler_type_t>( + const_cast<clang::Type *>(tdecl->getTypeForDecl())); + return CompilerType(p.m_context, t); } return llvm::None; } void ClangPersistentVariables::RegisterPersistentDecl(ConstString name, - clang::NamedDecl *decl) { - m_persistent_decls.insert( - std::pair<const char *, clang::NamedDecl *>(name.GetCString(), decl)); + clang::NamedDecl *decl, + ClangASTContext *ctx) { + PersistentDecl p = {decl, ctx}; + m_persistent_decls.insert(std::make_pair(name.GetCString(), p)); if (clang::EnumDecl *enum_decl = llvm::dyn_cast<clang::EnumDecl>(decl)) { for (clang::EnumConstantDecl *enumerator_decl : enum_decl->enumerators()) { - m_persistent_decls.insert(std::pair<const char *, clang::NamedDecl *>( - ConstString(enumerator_decl->getNameAsString()).GetCString(), - enumerator_decl)); + p = {enumerator_decl, ctx}; + m_persistent_decls.insert(std::make_pair( + ConstString(enumerator_decl->getNameAsString()).GetCString(), p)); } } } clang::NamedDecl * ClangPersistentVariables::GetPersistentDecl(ConstString name) { - PersistentDeclMap::const_iterator i = - m_persistent_decls.find(name.GetCString()); - - if (i == m_persistent_decls.end()) - return nullptr; - else - return i->second; + return m_persistent_decls.lookup(name.GetCString()).m_decl; } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 95e6c3ac963d..434196b35fd5 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -62,7 +62,8 @@ public: llvm::Optional<CompilerType> GetCompilerTypeFromPersistentDecl(ConstString type_name) override; - void RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl); + void RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl, + ClangASTContext *ctx); clang::NamedDecl *GetPersistentDecl(ConstString name); @@ -80,7 +81,14 @@ private: // The counter used by GetNextPersistentVariableName uint32_t m_next_persistent_variable_id = 0; - typedef llvm::DenseMap<const char *, clang::NamedDecl *> PersistentDeclMap; + struct PersistentDecl { + /// The persistent decl. + clang::NamedDecl *m_decl = nullptr; + /// The ClangASTContext for the ASTContext of m_decl. + ClangASTContext *m_context = nullptr; + }; + + typedef llvm::DenseMap<const char *, PersistentDecl> PersistentDeclMap; PersistentDeclMap m_persistent_decls; ///< Persistent entities declared by the user. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index da1ca785635c..6698797617a3 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -38,10 +38,11 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/VariableList.h" @@ -62,13 +63,15 @@ using namespace lldb_private; +char ClangUserExpression::ID; + ClangUserExpression::ClangUserExpression( ExecutionContextScope &exe_scope, llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, ResultType desired_type, const EvaluateExpressionOptions &options, ValueObject *ctx_obj) : LLVMUserExpression(exe_scope, expr, prefix, language, desired_type, - options, eKindClangUserExpression), + options), m_type_system_helper(*m_target_wp.lock(), options.GetExecutionPolicy() == eExecutionPolicyTopLevel), m_result_delegate(exe_scope.CalculateTarget()), m_ctx_obj(ctx_obj) { @@ -347,11 +350,12 @@ bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_man static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) { if (ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor()) { + auto *persistent_state = llvm::cast<ClangPersistentVariables>( + target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); + if (!persistent_state) + return; const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = - llvm::cast<ClangPersistentVariables>( - target->GetPersistentExpressionStateForLanguage( - lldb::eLanguageTypeC)) - ->GetHandLoadedClangModules(); + persistent_state->GetHandLoadedClangModules(); ClangModulesDeclVendor::ModuleVector modules_for_macros; for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) { @@ -476,15 +480,18 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language, files.AppendIfUnique(f); // We also need to look at external modules in the case of -gmodules as they // contain the support files for libc++ and the C library. - sc.comp_unit->ForEachExternalModule([&files](lldb::ModuleSP module) { - for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) { - const FileSpecList &support_files = - module->GetCompileUnitAtIndex(i)->GetSupportFiles(); - for (const FileSpec &f : support_files) { - files.AppendIfUnique(f); - } - } - }); + llvm::DenseSet<SymbolFile *> visited_symbol_files; + sc.comp_unit->ForEachExternalModule( + visited_symbol_files, [&files](Module &module) { + for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) { + const FileSpecList &support_files = + module.GetCompileUnitAtIndex(i)->GetSupportFiles(); + for (const FileSpec &f : support_files) { + files.AppendIfUnique(f); + } + } + return false; + }); LLDB_LOG(log, "[C++ module config] Found {0} support files to analyze", files.GetSize()); @@ -576,7 +583,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); }); - if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) { + if (!DeclMap()->WillParse(exe_ctx, GetMaterializer())) { diagnostic_manager.PutString( eDiagnosticSeverityError, "current process state is unsuitable for expression parsing"); @@ -676,10 +683,12 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, register_execution_unit = true; } - if (register_execution_unit) - exe_ctx.GetTargetPtr() - ->GetPersistentExpressionStateForLanguage(m_language) - ->RegisterExecutionUnit(m_execution_unit_sp); + if (register_execution_unit) { + if (auto *persistent_state = + exe_ctx.GetTargetPtr()->GetPersistentExpressionStateForLanguage( + m_language)) + persistent_state->RegisterExecutionUnit(m_execution_unit_sp); + } } if (generate_debug_info) { @@ -764,7 +773,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); }); - if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) { + if (!DeclMap()->WillParse(exe_ctx, GetMaterializer())) { diagnostic_manager.PutString( eDiagnosticSeverityError, "current process state is unsuitable for expression parsing"); @@ -887,9 +896,9 @@ void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap( Materializer::PersistentVariableDelegate &delegate, bool keep_result_in_memory, ValueObject *ctx_obj) { - m_expr_decl_map_up.reset( - new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx, - ctx_obj)); + m_expr_decl_map_up.reset(new ClangExpressionDeclMap( + keep_result_in_memory, &delegate, exe_ctx.GetTargetSP(), + exe_ctx.GetTargetRef().GetClangASTImporter(), ctx_obj)); } clang::ASTConsumer * diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index d94f9cc5e066..00cbffa7fd6f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -38,11 +38,14 @@ namespace lldb_private { /// the objects needed to parse and interpret or JIT an expression. It uses /// the Clang parser to produce LLVM IR from the expression. class ClangUserExpression : public LLVMUserExpression { + // LLVM RTTI support + static char ID; + public: - /// LLVM-style RTTI support. - static bool classof(const Expression *E) { - return E->getKind() == eKindClangUserExpression; + bool isA(const void *ClassID) const override { + return ClassID == &ID || LLVMUserExpression::isA(ClassID); } + static bool classof(const Expression *obj) { return obj->isA(&ID); } enum { kDefaultTimeout = 500000u }; @@ -93,7 +96,7 @@ public: /// \param[in] expr /// The expression to parse. /// - /// \param[in] expr_prefix + /// \param[in] prefix /// If non-NULL, a C string containing translation-unit level /// definitions to be included when the expression is parsed. /// diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 564c62c6a2c6..199e4898e118 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -31,6 +31,8 @@ using namespace lldb_private; +char ClangUtilityFunction::ID; + /// Constructor /// /// \param[in] text @@ -40,7 +42,7 @@ using namespace lldb_private; /// The name of the function, as used in the text. ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope, const char *text, const char *name) - : UtilityFunction(exe_scope, text, name, eKindClangUtilityFunction) { + : UtilityFunction(exe_scope, text, name) { m_function_text.assign(ClangExpressionSourceCode::g_expression_prefix); if (text && text[0]) m_function_text.append(text); @@ -157,7 +159,7 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap( ExecutionContext &exe_ctx, bool keep_result_in_memory) { - m_expr_decl_map_up.reset( - new ClangExpressionDeclMap(keep_result_in_memory, nullptr, exe_ctx, - nullptr)); + m_expr_decl_map_up.reset(new ClangExpressionDeclMap( + keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), + exe_ctx.GetTargetRef().GetClangASTImporter(), nullptr)); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index 70ebb2f3ad8a..9efaa0254c3e 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -33,11 +33,14 @@ namespace lldb_private { /// simply provide a way to push a function into the target for the debugger /// to call later on. class ClangUtilityFunction : public UtilityFunction { + // LLVM RTTI support + static char ID; + public: - /// LLVM-style RTTI support. - static bool classof(const Expression *E) { - return E->getKind() == eKindClangUtilityFunction; + bool isA(const void *ClassID) const override { + return ClassID == &ID || UtilityFunction::isA(ClassID); } + static bool classof(const Expression *obj) { return obj->isA(&ID); } class ClangUtilityFunctionHelper : public ClangExpressionHelper { public: diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h index 60c0691b21c1..5b9c8007ab76 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h @@ -76,10 +76,6 @@ public: /// /// \param[in] func_name /// The name of the function to prepare for execution in the target. - /// - /// \param[in] decl_map - /// The mapping used to look up entities in the target process. In - /// this case, used to find objc_msgSend IRDynamicChecks(ClangDynamicCheckerFunctions &checker_functions, const char *func_name = "$__lldb_expr"); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 4e871f7d6a44..103a7ee46f35 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -355,7 +355,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { ConstantInt *new_constant_int = ConstantInt::get(llvm::Type::getInt64Ty(m_module->getContext()), - reinterpret_cast<uint64_t>(result_decl), false); + reinterpret_cast<uintptr_t>(result_decl), false); llvm::Metadata *values[2]; values[0] = ConstantAsMetadata::get(new_result_global); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h index 893620f7f8e0..262e8ee0c06c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h @@ -71,15 +71,6 @@ public: /// variables) should be resolved. If not, only external functions /// are resolved. /// - /// \param[in] execution_policy - /// Determines whether an IR interpreter can be used to statically - /// evaluate the expression. - /// - /// \param[in] const_result - /// This variable is populated with the statically-computed result - /// of the function, if it has no side-effects and the result can - /// be computed statically. - /// /// \param[in] execution_unit /// The holder for raw data associated with the expression. /// @@ -105,10 +96,6 @@ public: /// $__lldb_expr, and that function is passed to the passes one by /// one. /// - /// \param[in] interpreter_error - /// An error. If the expression fails to be interpreted, this error - /// is set to a reason why. - /// /// \return /// True on success; false otherwise bool runOnModule(llvm::Module &llvm_module) override; @@ -142,9 +129,6 @@ private: /// The top-level pass implementation /// - /// \param[in] llvm_module - /// The module currently being processed. - /// /// \param[in] llvm_function /// The function currently being processed. /// @@ -184,12 +168,12 @@ private: /// Find the NamedDecl corresponding to a Value. This interface is exposed /// for the IR interpreter. /// + /// \param[in] global_val + /// The global entity to search for + /// /// \param[in] module /// The module containing metadata to search /// - /// \param[in] global - /// The global entity to search for - /// /// \return /// The corresponding variable declaration public: @@ -287,7 +271,7 @@ private: /// Replace a single old-style class reference /// - /// \param[in] selector_load + /// \param[in] class_load /// The load of the statically-allocated selector. /// /// \return @@ -362,7 +346,7 @@ private: /// Handle all the arguments to a function call /// - /// \param[in] C + /// \param[in] call_inst /// The call instruction. /// /// \return @@ -381,8 +365,8 @@ private: /// Remove calls to __cxa_atexit, which should never be generated by /// expressions. /// - /// \param[in] call_inst - /// The call instruction. + /// \param[in] basic_block + /// The basic block currently being processed. /// /// \return /// True if the scan was successful; false if some operation @@ -391,7 +375,7 @@ private: /// The top-level pass implementation /// - /// \param[in] basic_block + /// \param[in] llvm_function /// The function currently being processed. /// /// \return @@ -474,28 +458,9 @@ private: ///pointer (see comments in /// ASTResultSynthesizer::SynthesizeBodyResult) - llvm::GlobalVariable *m_reloc_placeholder; ///< A placeholder that will be - ///replaced by a pointer to the - ///final - /// location of the static allocation. - - /// UnfoldConstant operates on a constant [Old] which has just been replaced - /// with a value [New]. We assume that new_value has been properly placed - /// early in the function, in front of the first instruction in the entry - /// basic block [FirstEntryInstruction]. - /// - /// UnfoldConstant reads through the uses of Old and replaces Old in those - /// uses with New. Where those uses are constants, the function generates - /// new instructions to compute the result of the new, non-constant - /// expression and places them before FirstEntryInstruction. These - /// instructions replace the constant uses, so UnfoldConstant calls itself - /// recursively for those. - /// - /// \param[in] llvm_function - /// The function currently being processed. - /// - /// \return - /// True on success; false otherwise + /// A placeholder that will be replaced by a pointer to the final location of + /// the static allocation. + llvm::GlobalVariable *m_reloc_placeholder; class FunctionValueCache { public: @@ -513,6 +478,20 @@ private: FunctionValueCache m_entry_instruction_finder; + /// UnfoldConstant operates on a constant [Old] which has just been replaced + /// with a value [New]. We assume that new_value has been properly placed + /// early in the function, in front of the first instruction in the entry + /// basic block [FirstEntryInstruction]. + /// + /// UnfoldConstant reads through the uses of Old and replaces Old in those + /// uses with New. Where those uses are constants, the function generates + /// new instructions to compute the result of the new, non-constant + /// expression and places them before FirstEntryInstruction. These + /// instructions replace the constant uses, so UnfoldConstant calls itself + /// recursively for those. + /// + /// \return + /// True on success; false otherwise static bool UnfoldConstant(llvm::Constant *old_constant, llvm::Function *llvm_function, FunctionValueCache &value_maker, @@ -522,9 +501,6 @@ private: /// Commit the allocation in m_data_allocator and use its final location to /// replace m_reloc_placeholder. /// - /// \param[in] module - /// The module that m_data_allocator resides in - /// /// \return /// True on success; false otherwise bool CompleteDataAllocation(); diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index 19a987b0f004..ff142e6f35ff 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -850,6 +850,7 @@ uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber() const { /* On Apple iOS et al, the frame pointer register is always r7. * Typically on other ARM systems, thumb code uses r7; arm code uses r11. + * Windows on ARM, which is in thumb mode, uses r11 though. */ uint32_t fp_regnum = 11; @@ -857,7 +858,7 @@ uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber() const { if (is_apple) fp_regnum = 7; - if (m_opcode_mode == eModeThumb) + if (m_opcode_mode == eModeThumb && !m_arch.GetTriple().isOSWindows()) fp_regnum = 7; return fp_regnum; @@ -879,6 +880,7 @@ uint32_t EmulateInstructionARM::GetFramePointerDWARFRegisterNumber() const { /* On Apple iOS et al, the frame pointer register is always r7. * Typically on other ARM systems, thumb code uses r7; arm code uses r11. + * Windows on ARM, which is in thumb mode, uses r11 though. */ uint32_t fp_regnum = dwarf_r11; @@ -886,7 +888,7 @@ uint32_t EmulateInstructionARM::GetFramePointerDWARFRegisterNumber() const { if (is_apple) fp_regnum = dwarf_r7; - if (m_opcode_mode == eModeThumb) + if (m_opcode_mode == eModeThumb && !m_arch.GetTriple().isOSWindows()) fp_regnum = dwarf_r7; return fp_regnum; @@ -1343,6 +1345,8 @@ bool EmulateInstructionARM::EmulateMOVRdRm(const uint32_t opcode, EmulateInstruction::Context context; if (Rd == 13) context.type = EmulateInstruction::eContextAdjustStackPointer; + else if (Rd == GetFramePointerRegisterNumber() && Rm == 13) + context.type = EmulateInstruction::eContextSetFramePointer; else context.type = EmulateInstruction::eContextRegisterPlusOffset; RegisterInfo dwarf_reg; diff --git a/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp index 21b6296745bd..b55eeb0eaf46 100644 --- a/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp +++ b/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp @@ -28,6 +28,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" @@ -149,7 +150,9 @@ EmulateInstructionMIPS::EmulateInstructionMIPS( m_insn_info.reset(target->createMCInstrInfo()); assert(m_insn_info.get()); - m_asm_info.reset(target->createMCAsmInfo(*m_reg_info, triple.getTriple())); + llvm::MCTargetOptions MCOptions; + m_asm_info.reset( + target->createMCAsmInfo(*m_reg_info, triple.getTriple(), MCOptions)); m_subtype_info.reset( target->createMCSubtargetInfo(triple.getTriple(), cpu, features)); assert(m_asm_info.get() && m_subtype_info.get()); @@ -978,13 +981,11 @@ EmulateInstructionMIPS::GetSizeOfInstruction(lldb_private::DataExtractor &data, llvm::ArrayRef<uint8_t> raw_insn(data.GetDataStart(), data.GetByteSize()); if (m_use_alt_disaasm) - decode_status = - m_alt_disasm->getInstruction(mc_insn, next_inst_size, raw_insn, - inst_addr, llvm::nulls(), llvm::nulls()); + decode_status = m_alt_disasm->getInstruction( + mc_insn, next_inst_size, raw_insn, inst_addr, llvm::nulls()); else - decode_status = - m_disasm->getInstruction(mc_insn, next_inst_size, raw_insn, inst_addr, - llvm::nulls(), llvm::nulls()); + decode_status = m_disasm->getInstruction(mc_insn, next_inst_size, raw_insn, + inst_addr, llvm::nulls()); if (decode_status != llvm::MCDisassembler::Success) return false; @@ -1067,11 +1068,11 @@ bool EmulateInstructionMIPS::EvaluateInstruction(uint32_t evaluate_options) { llvm::MCDisassembler::DecodeStatus decode_status; llvm::ArrayRef<uint8_t> raw_insn(data.GetDataStart(), data.GetByteSize()); if (m_use_alt_disaasm) - decode_status = m_alt_disasm->getInstruction( - mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls()); + decode_status = m_alt_disasm->getInstruction(mc_insn, insn_size, raw_insn, + m_addr, llvm::nulls()); else - decode_status = m_disasm->getInstruction( - mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls()); + decode_status = m_disasm->getInstruction(mc_insn, insn_size, raw_insn, + m_addr, llvm::nulls()); if (decode_status != llvm::MCDisassembler::Success) return false; diff --git a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp index 5fabbeb756cc..3baf942bc17f 100644 --- a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp +++ b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp @@ -28,6 +28,7 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" @@ -153,7 +154,9 @@ EmulateInstructionMIPS64::EmulateInstructionMIPS64( m_insn_info.reset(target->createMCInstrInfo()); assert(m_insn_info.get()); - m_asm_info.reset(target->createMCAsmInfo(*m_reg_info, triple.getTriple())); + llvm::MCTargetOptions MCOptions; + m_asm_info.reset( + target->createMCAsmInfo(*m_reg_info, triple.getTriple(), MCOptions)); m_subtype_info.reset( target->createMCSubtargetInfo(triple.getTriple(), cpu, features)); assert(m_asm_info.get() && m_subtype_info.get()); @@ -962,8 +965,8 @@ bool EmulateInstructionMIPS64::EvaluateInstruction(uint32_t evaluate_options) { if (m_opcode.GetData(data)) { llvm::MCDisassembler::DecodeStatus decode_status; llvm::ArrayRef<uint8_t> raw_insn(data.GetDataStart(), data.GetByteSize()); - decode_status = m_disasm->getInstruction( - mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls()); + decode_status = m_disasm->getInstruction(mc_insn, insn_size, raw_insn, + m_addr, llvm::nulls()); if (decode_status != llvm::MCDisassembler::Success) return false; } @@ -1360,7 +1363,7 @@ bool EmulateInstructionMIPS64::Emulate_BXX_3ops(llvm::MCInst &insn) { if (!success) return false; - if (!strcasecmp(op_name, "BEQ") || !strcasecmp(op_name, "BEQL") + if (!strcasecmp(op_name, "BEQ") || !strcasecmp(op_name, "BEQL") || !strcasecmp(op_name, "BEQ64") ) { if (rs_val == rt_val) target = pc + offset; @@ -1602,7 +1605,7 @@ bool EmulateInstructionMIPS64::Emulate_BXX_2ops(llvm::MCInst &insn) { target = pc + offset; else target = pc + 8; - } else if (!strcasecmp(op_name, "BLEZL") || !strcasecmp(op_name, "BLEZ") + } else if (!strcasecmp(op_name, "BLEZL") || !strcasecmp(op_name, "BLEZ") || !strcasecmp(op_name, "BLEZ64")) { if (rs_val <= 0) target = pc + offset; diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp index dfe61316b042..b73b6c095368 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp @@ -153,7 +153,7 @@ bool MainThreadCheckerRuntime::NotifyBreakpointHit( user_id_t break_loc_id) { assert(baton && "null baton"); if (!baton) - return false; //< false => resume execution. + return false; ///< false => resume execution. MainThreadCheckerRuntime *const instance = static_cast<MainThreadCheckerRuntime *>(baton); @@ -241,30 +241,30 @@ MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP info) { ThreadCollectionSP threads; threads = std::make_shared<ThreadCollection>(); - + ProcessSP process_sp = GetProcessSP(); - + if (info->GetObjectForDotSeparatedPath("instrumentation_class") ->GetStringValue() != "MainThreadChecker") return threads; - + std::vector<lldb::addr_t> PCs; auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray(); trace->ForEach([&PCs](StructuredData::Object *PC) -> bool { PCs.push_back(PC->GetAsInteger()->GetValue()); return true; }); - + if (PCs.empty()) return threads; - + StructuredData::ObjectSP thread_id_obj = info->GetObjectForDotSeparatedPath("tid"); tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0; HistoryThread *history_thread = new HistoryThread(*process_sp, tid, PCs); ThreadSP new_thread_sp(history_thread); - + // Save this in the Process' ExtendedThreadList so a strong pointer retains // the object process_sp->GetExtendedThreadList().AddThread(new_thread_sp); diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp index 50f1d48d03e0..137ecab224bc 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp @@ -207,7 +207,7 @@ bool UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit( user_id_t break_loc_id) { assert(baton && "null baton"); if (!baton) - return false; //< false => resume execution. + return false; ///< false => resume execution. UndefinedBehaviorSanitizerRuntime *const instance = static_cast<UndefinedBehaviorSanitizerRuntime *>(baton); diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 489fa7d0ad91..4385a60f5862 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Demangle/ItaniumDemangle.h" +#include "lldb/Core/Mangled.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/UniqueCStringMap.h" #include "lldb/DataFormatters/CXXFunctionPointer.h" @@ -238,18 +239,16 @@ std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() { return res; } -bool CPlusPlusLanguage::IsCPPMangledName(const char *name) { +bool CPlusPlusLanguage::IsCPPMangledName(llvm::StringRef name) { // FIXME!! we should really run through all the known C++ Language plugins // and ask each one if this is a C++ mangled name - if (name == nullptr) - return false; + Mangled::ManglingScheme scheme = Mangled::GetManglingScheme(name); - // MSVC style mangling - if (name[0] == '?') - return true; + if (scheme == Mangled::eManglingSchemeNone) + return false; - return (name[0] != '\0' && name[0] == '_' && name[1] == 'Z'); + return true; } bool CPlusPlusLanguage::ExtractContextAndIdentifier( @@ -285,46 +284,34 @@ public: } }; -/// Given a mangled function `Mangled`, replace all the primitive function type -/// arguments of `Search` with type `Replace`. -class TypeSubstitutor - : public llvm::itanium_demangle::AbstractManglingParser<TypeSubstitutor, +template <typename Derived> +class ManglingSubstitutor + : public llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator> { - /// Input character until which we have constructed the respective output - /// already - const char *Written; + using Base = + llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>; - llvm::StringRef Search; - llvm::StringRef Replace; - llvm::SmallString<128> Result; +public: + ManglingSubstitutor() : Base(nullptr, nullptr) {} - /// Whether we have performed any substitutions. - bool Substituted; + template<typename... Ts> + ConstString substitute(llvm::StringRef Mangled, Ts &&... Vals) { + this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...); + return substituteImpl(Mangled); + } - void reset(llvm::StringRef Mangled, llvm::StringRef Search, - llvm::StringRef Replace) { - AbstractManglingParser::reset(Mangled.begin(), Mangled.end()); + +protected: + void reset(llvm::StringRef Mangled) { + Base::reset(Mangled.begin(), Mangled.end()); Written = Mangled.begin(); - this->Search = Search; - this->Replace = Replace; Result.clear(); Substituted = false; } - void appendUnchangedInput() { - Result += llvm::StringRef(Written, First - Written); - Written = First; - } - -public: - TypeSubstitutor() : AbstractManglingParser(nullptr, nullptr) {} - - ConstString substitute(llvm::StringRef Mangled, llvm::StringRef From, - llvm::StringRef To) { + ConstString substituteImpl(llvm::StringRef Mangled) { Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - - reset(Mangled, From, To); - if (parse() == nullptr) { + if (this->parse() == nullptr) { LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled); return ConstString(); } @@ -337,20 +324,69 @@ public: return ConstString(Result); } + void trySubstitute(llvm::StringRef From, llvm::StringRef To) { + if (!llvm::StringRef(currentParserPos(), this->numLeft()).startswith(From)) + return; + + // We found a match. Append unmodified input up to this point. + appendUnchangedInput(); + + // And then perform the replacement. + Result += To; + Written += From.size(); + Substituted = true; + } + +private: + /// Input character until which we have constructed the respective output + /// already. + const char *Written; + + llvm::SmallString<128> Result; + + /// Whether we have performed any substitutions. + bool Substituted; + + const char *currentParserPos() const { return this->First; } + + void appendUnchangedInput() { + Result += + llvm::StringRef(Written, std::distance(Written, currentParserPos())); + Written = currentParserPos(); + } + +}; + +/// Given a mangled function `Mangled`, replace all the primitive function type +/// arguments of `Search` with type `Replace`. +class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> { + llvm::StringRef Search; + llvm::StringRef Replace; + +public: + void reset(llvm::StringRef Mangled, llvm::StringRef Search, + llvm::StringRef Replace) { + ManglingSubstitutor::reset(Mangled); + this->Search = Search; + this->Replace = Replace; + } + llvm::itanium_demangle::Node *parseType() { - if (llvm::StringRef(First, numLeft()).startswith(Search)) { - // We found a match. Append unmodified input up to this point. - appendUnchangedInput(); - - // And then perform the replacement. - Result += Replace; - Written += Search.size(); - Substituted = true; - } - return AbstractManglingParser::parseType(); + trySubstitute(Search, Replace); + return ManglingSubstitutor::parseType(); } }; -} + +class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> { +public: + llvm::itanium_demangle::Node * + parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) { + trySubstitute("C1", "C2"); + trySubstitute("D1", "D2"); + return ManglingSubstitutor::parseCtorDtorName(SoFar, State); + } +}; +} // namespace uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings( const ConstString mangled_name, std::set<ConstString> &alternates) { @@ -398,6 +434,10 @@ uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings( TS.substitute(mangled_name.GetStringRef(), "y", "m")) alternates.insert(ulong_fixup); + if (ConstString ctor_fixup = + CtorDtorSubstitutor().substitute(mangled_name.GetStringRef())) + alternates.insert(ctor_fixup); + return alternates.size() - start_size; } @@ -426,6 +466,13 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "std::__[[:alnum:]]+::char_traits<char>, " "std::__[[:alnum:]]+::allocator<char> >$"), stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxStringSummaryProviderASCII, + "std::string summary provider", + ConstString("^std::__[[:alnum:]]+::basic_string<unsigned char, " + "std::__[[:alnum:]]+::char_traits<unsigned char>, " + "std::__[[:alnum:]]+::allocator<unsigned char> >$"), + stl_summary_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxStringSummaryProviderUTF16, @@ -568,6 +615,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "weak_ptr synthetic children", ConstString("^(std::__[[:alnum:]]+::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxFunctionSummaryProvider, + "libc++ std::function summary provider", + ConstString("^std::__[[:alnum:]]+::function<.+>$"), + stl_summary_flags, true); stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); @@ -719,6 +771,10 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, " "std::allocator<char> >"), cxx11_string_summary_sp); + cpp_category_sp->GetTypeSummariesContainer()->Add( + ConstString("std::__cxx11::basic_string<unsigned char, std::char_traits<unsigned char>, " + "std::allocator<unsigned char> >"), + cxx11_string_summary_sp); // making sure we force-pick the summary for printing wstring (_M_p is a // wchar_t*) diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index d30e56080732..4ed45bc904ce 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -101,7 +101,7 @@ public: static lldb_private::ConstString GetPluginNameStatic(); - static bool IsCPPMangledName(const char *name); + static bool IsCPPMangledName(llvm::StringRef name); // Extract C++ context and identifier from a string using heuristic matching // (as opposed to diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index abe89035c532..ecadaef7a87e 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -572,10 +572,13 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( location_sp->GetPointeeData(extractor, 0, size); // std::wstring::size() is measured in 'characters', not bytes - auto wchar_t_size = valobj.GetTargetSP() - ->GetScratchClangASTContext() - ->GetBasicType(lldb::eBasicTypeWChar) - .GetByteSize(nullptr); + ClangASTContext *ast_context = + ClangASTContext::GetScratch(*valobj.GetTargetSP()); + if (!ast_context) + return false; + + auto wchar_t_size = + ast_context->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr); if (!wchar_t_size) return false; diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 619c718a1c1b..f6d8d4d9a7eb 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -94,6 +94,8 @@ public: MapIterator(ValueObject *entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {} + MapIterator &operator=(const MapIterator &) = default; + ValueObjectSP value() { return m_entry.GetEntry(); } ValueObjectSP advance(size_t count) { diff --git a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp index a9a1b44731f2..3e77b1646739 100644 --- a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp +++ b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp @@ -139,6 +139,22 @@ void ClangHighlighter::Highlight(const HighlightStyle &options, FileManager file_mgr(file_opts, FileSystem::Instance().GetVirtualFileSystem()); + // The line might end in a backslash which would cause Clang to drop the + // backslash and the terminating new line. This makes sense when parsing C++, + // but when highlighting we care about preserving the backslash/newline. To + // not lose this information we remove the new line here so that Clang knows + // this is just a single line we are highlighting. We add back the newline + // after tokenizing. + llvm::StringRef line_ending = ""; + // There are a few legal line endings Clang recognizes and we need to + // temporarily remove from the string. + if (line.consume_back("\r\n")) + line_ending = "\r\n"; + else if (line.consume_back("\n")) + line_ending = "\n"; + else if (line.consume_back("\r")) + line_ending = "\r"; + unsigned line_number = previous_lines.count('\n') + 1U; // Let's build the actual source code Clang needs and setup some utility @@ -227,6 +243,9 @@ void ClangHighlighter::Highlight(const HighlightStyle &options, color.Apply(result, to_print); } + // Add the line ending we trimmed before tokenizing. + result << line_ending; + // If we went over the whole file but couldn't find our own file, then // somehow our setup was wrong. When we're in release mode we just give the // user the normal line and pretend we don't know how to highlight it. In diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index ddf3953bb512..8a81abbaedbe 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -694,32 +694,44 @@ bool lldb_private::formatters::NSURLSummaryProvider( CompilerType type(valobj.GetCompilerType()); ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true)); ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true)); - if (!text) - return false; - if (text->GetValueAsUnsigned(0) == 0) + if (!text || text->GetValueAsUnsigned(0) == 0) return false; + + StreamString base_summary; + if (base && base->GetValueAsUnsigned(0)) { + if (!NSURLSummaryProvider(*base, base_summary, options)) + base_summary.Clear(); + } + if (base_summary.Empty()) + return NSStringSummaryProvider(*text, stream, options); + StreamString summary; - if (!NSStringSummaryProvider(*text, summary, options)) + if (!NSStringSummaryProvider(*text, summary, options) || summary.Empty()) return false; - if (base && base->GetValueAsUnsigned(0)) { - std::string summary_str = summary.GetString(); - - if (!summary_str.empty()) - summary_str.pop_back(); - summary_str += " -- "; - StreamString base_summary; - if (NSURLSummaryProvider(*base, base_summary, options) && - !base_summary.Empty()) { - llvm::StringRef base_str = base_summary.GetString(); - if (base_str.size() > 2) - base_str = base_str.drop_front(2); - summary_str += base_str; + + const char quote_char = '"'; + std::string prefix, suffix; + if (Language *language = Language::FindPlugin(options.GetLanguage())) { + if (!language->GetFormatterPrefixSuffix(*text, ConstString("NSString"), + prefix, suffix)) { + prefix.clear(); + suffix.clear(); } - summary.Clear(); - summary.PutCString(summary_str); } - if (!summary.Empty()) { - stream.PutCString(summary.GetString()); + // @"A" -> @"A + llvm::StringRef summary_str = summary.GetString(); + bool back_consumed = summary_str.consume_back(quote_char + suffix); + assert(back_consumed); + UNUSED_IF_ASSERT_DISABLED(back_consumed); + // @"B" -> B" + llvm::StringRef base_summary_str = base_summary.GetString(); + bool front_consumed = base_summary_str.consume_front(prefix + quote_char); + assert(front_consumed); + UNUSED_IF_ASSERT_DISABLED(front_consumed); + // @"A -- B" + if (!summary_str.empty() && !base_summary_str.empty()) { + stream.Printf("%s -- %s", summary_str.str().c_str(), + base_summary_str.str().c_str()); return true; } diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp index 7219c016dfd1..73335aff2fd7 100644 --- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -96,31 +96,6 @@ private: D64 *m_data_64; }; -namespace Foundation109 { - struct DataDescriptor_32 { - uint32_t _used; - uint32_t _priv1 : 2; - uint32_t _size : 30; - uint32_t _priv2 : 2; - uint32_t _offset : 30; - uint32_t _priv3; - uint32_t _data; - }; - - struct DataDescriptor_64 { - uint64_t _used; - uint64_t _priv1 : 2; - uint64_t _size : 62; - uint64_t _priv2 : 2; - uint64_t _offset : 62; - uint32_t _priv3; - uint64_t _data; - }; - - using NSArrayMSyntheticFrontEnd = - GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>; -} - namespace Foundation1010 { struct DataDescriptor_32 { uint32_t _used; @@ -461,13 +436,12 @@ lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontE : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), m_id_type() { if (valobj_sp) { - auto *clang_ast_context = valobj_sp->GetExecutionContextRef() - .GetTargetSP() - ->GetScratchClangASTContext(); + auto *clang_ast_context = ClangASTContext::GetScratch( + *valobj_sp->GetExecutionContextRef().GetTargetSP()); if (clang_ast_context) m_id_type = CompilerType( clang_ast_context, - clang_ast_context->getASTContext()->ObjCBuiltinIdTy.getAsOpaquePtr()); + clang_ast_context->getASTContext().ObjCBuiltinIdTy.getAsOpaquePtr()); if (valobj_sp->GetProcessSP()) m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize(); } @@ -610,13 +584,11 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: if (valobj_sp) { CompilerType type = valobj_sp->GetCompilerType(); if (type) { - auto *clang_ast_context = valobj_sp->GetExecutionContextRef() - .GetTargetSP() - ->GetScratchClangASTContext(); + auto *clang_ast_context = ClangASTContext::GetScratch( + *valobj_sp->GetExecutionContextRef().GetTargetSP()); if (clang_ast_context) - m_id_type = CompilerType(clang_ast_context, - clang_ast_context->getASTContext() - ->ObjCBuiltinIdTy.getAsOpaquePtr()); + m_id_type = clang_ast_context->GetType( + clang_ast_context->getASTContext().ObjCBuiltinIdTy); } } } @@ -780,11 +752,15 @@ lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex( static const ConstString g_zero("[0]"); if (idx == 0) { - CompilerType id_type( - m_backend.GetTargetSP()->GetScratchClangASTContext()->GetBasicType( - lldb::eBasicTypeObjCID)); - return m_backend.GetSyntheticChildAtOffset( - m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true, g_zero); + auto *clang_ast_context = + ClangASTContext::GetScratch(*m_backend.GetTargetSP()); + if (clang_ast_context) { + CompilerType id_type( + clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID)); + return m_backend.GetSyntheticChildAtOffset( + m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true, + g_zero); + } } return lldb::ValueObjectSP(); } @@ -857,8 +833,6 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator( return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp)); if (runtime->GetFoundationVersion() >= 1100) return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp)); - else - return (new Foundation109::NSArrayMSyntheticFrontEnd(valobj_sp)); } else if (class_name == g_NSCallStackArray) { return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp)); } else { diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 10f66c4a37f8..ae00674c49f3 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -65,7 +65,7 @@ NSDictionary_Additionals::GetAdditionalSynthetics() { static CompilerType GetLLDBNSPairType(TargetSP target_sp) { CompilerType compiler_type; - ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext(); + ClangASTContext *target_ast_context = ClangASTContext::GetScratch(*target_sp); if (target_ast_context) { ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair"); diff --git a/lldb/source/Plugins/Language/ObjC/NSError.cpp b/lldb/source/Plugins/Language/ObjC/NSError.cpp index 97df3be72c84..94a97c8ad039 100644 --- a/lldb/source/Plugins/Language/ObjC/NSError.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSError.cpp @@ -86,10 +86,10 @@ bool lldb_private::formatters::NSError_SummaryProvider( ValueObjectSP domain_str_sp = ValueObject::CreateValueObjectFromData( "domain_str", isw.GetAsData(process_sp->GetByteOrder()), - valobj.GetExecutionContextRef(), process_sp->GetTarget() - .GetScratchClangASTContext() - ->GetBasicType(lldb::eBasicTypeVoid) - .GetPointerType()); + valobj.GetExecutionContextRef(), + ClangASTContext::GetScratch(process_sp->GetTarget()) + ->GetBasicType(lldb::eBasicTypeVoid) + .GetPointerType()); if (!domain_str_sp) return false; @@ -156,8 +156,8 @@ public: m_child_sp = CreateValueObjectFromData( "_userInfo", isw.GetAsData(process_sp->GetByteOrder()), m_backend.GetExecutionContextRef(), - process_sp->GetTarget().GetScratchClangASTContext()->GetBasicType( - lldb::eBasicTypeObjCID)); + ClangASTContext::GetScratch(process_sp->GetTarget()) + ->GetBasicType(lldb::eBasicTypeObjCID)); return false; } diff --git a/lldb/source/Plugins/Language/ObjC/NSException.cpp b/lldb/source/Plugins/Language/ObjC/NSException.cpp index 931794a12ab1..9150787361c5 100644 --- a/lldb/source/Plugins/Language/ObjC/NSException.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSException.cpp @@ -69,10 +69,12 @@ static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp, InferiorSizedWord userinfo_isw(userinfo, *process_sp); InferiorSizedWord reserved_isw(reserved, *process_sp); - CompilerType voidstar = process_sp->GetTarget() - .GetScratchClangASTContext() - ->GetBasicType(lldb::eBasicTypeVoid) - .GetPointerType(); + auto *clang_ast_context = ClangASTContext::GetScratch(process_sp->GetTarget()); + if (!clang_ast_context) + return false; + + CompilerType voidstar = + clang_ast_context->GetBasicType(lldb::eBasicTypeVoid).GetPointerType(); if (name_sp) *name_sp = ValueObject::CreateValueObjectFromData( @@ -96,21 +98,19 @@ static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp, bool lldb_private::formatters::NSException_SummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { - lldb::ValueObjectSP name_sp; lldb::ValueObjectSP reason_sp; - if (!ExtractFields(valobj, &name_sp, &reason_sp, nullptr, nullptr)) + if (!ExtractFields(valobj, nullptr, &reason_sp, nullptr, nullptr)) return false; - if (!name_sp || !reason_sp) + if (!reason_sp) { + stream.Printf("No reason"); return false; + } - StreamString name_str_summary; StreamString reason_str_summary; - if (NSStringSummaryProvider(*name_sp, name_str_summary, options) && - NSStringSummaryProvider(*reason_sp, reason_str_summary, options) && - !name_str_summary.Empty() && !reason_str_summary.Empty()) { - stream.Printf("name: %s - reason: %s", name_str_summary.GetData(), - reason_str_summary.GetData()); + if (NSStringSummaryProvider(*reason_sp, reason_str_summary, options) && + !reason_str_summary.Empty()) { + stream.Printf("%s", reason_str_summary.GetData()); return true; } else return false; diff --git a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp index 9ee6021ae56b..587dd13870a0 100644 --- a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp @@ -53,9 +53,8 @@ public: if (!type_system) return false; - ClangASTContext *ast = m_backend.GetExecutionContextRef() - .GetTargetSP() - ->GetScratchClangASTContext(); + ClangASTContext *ast = ClangASTContext::GetScratch( + *m_backend.GetExecutionContextRef().GetTargetSP()); if (!ast) return false; diff --git a/lldb/source/Plugins/Language/ObjC/NSString.cpp b/lldb/source/Plugins/Language/ObjC/NSString.cpp index 55e129b098dc..ce54d657374b 100644 --- a/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -35,7 +35,7 @@ NSString_Additionals::GetAdditionalSummaries() { static CompilerType GetNSPathStore2Type(Target &target) { static ConstString g_type_name("__lldb_autogen_nspathstore2"); - ClangASTContext *ast_ctx = target.GetScratchClangASTContext(); + ClangASTContext *ast_ctx = ClangASTContext::GetScratch(target); if (!ast_ctx) return CompilerType(); diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp index c5bfb5747c13..3be548ad4144 100644 --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -15,6 +15,7 @@ #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" @@ -887,7 +888,7 @@ ObjCLanguage::GetPossibleFormattersMatches(ValueObject &valobj, bool canBeObjCDynamic = compiler_type.IsPossibleDynamicType(nullptr, check_cpp, check_objc); - if (canBeObjCDynamic) { + if (canBeObjCDynamic && ClangUtil::IsClangType(compiler_type)) { do { lldb::ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index f38014505a8b..d556aae1c458 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/UniqueCStringMap.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/RegisterContext.h" @@ -28,6 +29,7 @@ #include "lldb/Target/StackFrame.h" #include "lldb/Target/ThreadPlanRunToAddress.h" #include "lldb/Target/ThreadPlanStepInRange.h" +#include "lldb/Utility/Timer.h" using namespace lldb; using namespace lldb_private; @@ -58,9 +60,53 @@ bool CPPLanguageRuntime::GetObjectDescription( return false; } +bool contains_lambda_identifier(llvm::StringRef &str_ref) { + return str_ref.contains("$_") || str_ref.contains("'lambda'"); +} + +CPPLanguageRuntime::LibCppStdFunctionCallableInfo +line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol, + llvm::StringRef first_template_param_sref, + bool has___invoke) { + + CPPLanguageRuntime::LibCppStdFunctionCallableInfo optional_info; + + AddressRange range; + sc.GetAddressRange(eSymbolContextEverything, 0, false, range); + + Address address = range.GetBaseAddress(); + + Address addr; + if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), + addr)) { + LineEntry line_entry; + addr.CalculateSymbolContextLineEntry(line_entry); + + if (contains_lambda_identifier(first_template_param_sref) || has___invoke) { + // Case 1 and 2 + optional_info.callable_case = lldb_private::CPPLanguageRuntime:: + LibCppStdFunctionCallableCase::Lambda; + } else { + // Case 3 + optional_info.callable_case = lldb_private::CPPLanguageRuntime:: + LibCppStdFunctionCallableCase::CallableObject; + } + + optional_info.callable_symbol = *symbol; + optional_info.callable_line_entry = line_entry; + optional_info.callable_address = addr; + } + + return optional_info; +} + CPPLanguageRuntime::LibCppStdFunctionCallableInfo CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( lldb::ValueObjectSP &valobj_sp) { + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer(func_cat, + "CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo"); + LibCppStdFunctionCallableInfo optional_info; if (!valobj_sp) @@ -93,7 +139,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( // this entry and lookup operator()() and obtain the line table entry. // 3) a callable object via operator()(). We will obtain the name of the // object from the first template parameter from __func's vtable. We will - // look up the objectc operator()() and obtain the line table entry. + // look up the objects operator()() and obtain the line table entry. // 4) a member function. A pointer to the function will stored after the // we will obtain the name from this pointer. // 5) a free function. A pointer to the function will stored after the vtable @@ -113,6 +159,9 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( optional_info.member__f_pointer_value = member__f_pointer_value; + if (!member__f_pointer_value) + return optional_info; + ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); @@ -130,8 +179,14 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( if (status.Fail()) return optional_info; + lldb::addr_t vtable_address_first_entry = + process->ReadPointerFromMemory(vtable_address + address_size, status); + + if (status.Fail()) + return optional_info; + lldb::addr_t address_after_vtable = member__f_pointer_value + address_size; - // As commened above we may not have a function pointer but if we do we will + // As commented above we may not have a function pointer but if we do we will // need it. lldb::addr_t possible_function_address = process->ReadPointerFromMemory(address_after_vtable, status); @@ -144,9 +199,15 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( if (target.GetSectionLoadList().IsEmpty()) return optional_info; + Address vtable_first_entry_resolved; + + if (!target.GetSectionLoadList().ResolveLoadAddress( + vtable_address_first_entry, vtable_first_entry_resolved)) + return optional_info; + Address vtable_addr_resolved; SymbolContext sc; - Symbol *symbol; + Symbol *symbol = nullptr; if (!target.GetSectionLoadList().ResolveLoadAddress(vtable_address, vtable_addr_resolved)) @@ -159,7 +220,7 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( if (symbol == nullptr) return optional_info; - llvm::StringRef vtable_name(symbol->GetName().GetCString()); + llvm::StringRef vtable_name(symbol->GetName().GetStringRef()); bool found_expected_start_string = vtable_name.startswith("vtable for std::__1::__function::__func<"); @@ -172,6 +233,11 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( // ... __func<main::$_0, std::__1::allocator<main::$_0> ... // ^^^^^^^^^ // + // We could see names such as: + // main::$_0 + // Bar::add_num2(int)::'lambda'(int) + // Bar + // // We do this by find the first < and , and extracting in between. // // This covers the case of the lambda known at compile time. @@ -193,81 +259,28 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( symbol = sc.symbol; } - auto get_name = [&first_template_parameter, &symbol]() { - // Given case 1: - // - // main::$_0 - // - // we want to append ::operator()() - if (first_template_parameter.contains("$_")) - return llvm::Regex::escape(first_template_parameter.str()) + - R"(::operator\(\)\(.*\))"; - - if (symbol != nullptr && - symbol->GetName().GetStringRef().contains("__invoke")) { - - llvm::StringRef symbol_name = symbol->GetName().GetStringRef(); - size_t pos2 = symbol_name.find_last_of(':'); - - // Given case 2: - // - // main::$_1::__invoke(...) - // - // We want to slice off __invoke(...) and append operator()() - std::string lambda_operator = - llvm::Regex::escape(symbol_name.slice(0, pos2 + 1).str()) + - R"(operator\(\)\(.*\))"; - - return lambda_operator; - } - - // Case 3 - return first_template_parameter.str() + R"(::operator\(\)\(.*\))"; - ; + // These conditions are used several times to simplify statements later on. + bool has___invoke = + (symbol ? symbol->GetName().GetStringRef().contains("__invoke") : false); + auto calculate_symbol_context_helper = [](auto &t, + SymbolContextList &sc_list) { + SymbolContext sc; + t->CalculateSymbolContext(&sc); + sc_list.Append(sc); }; - std::string func_to_match = get_name(); - - SymbolContextList scl; - - target.GetImages().FindSymbolsMatchingRegExAndType( - RegularExpression{R"(^)" + func_to_match}, eSymbolTypeAny, scl); + // Case 2 + if (has___invoke) { + SymbolContextList scl; + calculate_symbol_context_helper(symbol, scl); - // Case 1,2 or 3 - if (scl.GetSize() >= 1) { - SymbolContext sc2 = scl[0]; - - AddressRange range; - sc2.GetAddressRange(eSymbolContextEverything, 0, false, range); - - Address address = range.GetBaseAddress(); - - Address addr; - if (target.ResolveLoadAddress(address.GetCallableLoadAddress(&target), - addr)) { - LineEntry line_entry; - addr.CalculateSymbolContextLineEntry(line_entry); - - if (first_template_parameter.contains("$_") || - (symbol != nullptr && - symbol->GetName().GetStringRef().contains("__invoke"))) { - // Case 1 and 2 - optional_info.callable_case = LibCppStdFunctionCallableCase::Lambda; - } else { - // Case 3 - optional_info.callable_case = - LibCppStdFunctionCallableCase::CallableObject; - } - - optional_info.callable_symbol = *symbol; - optional_info.callable_line_entry = line_entry; - optional_info.callable_address = addr; - return optional_info; - } + return line_entry_helper(target, scl[0], symbol, first_template_parameter, + has___invoke); } // Case 4 or 5 - if (symbol && !symbol->GetName().GetStringRef().startswith("vtable for")) { + if (symbol && !symbol->GetName().GetStringRef().startswith("vtable for") && + !contains_lambda_identifier(first_template_parameter) && !has___invoke) { optional_info.callable_case = LibCppStdFunctionCallableCase::FreeOrMemberFunction; optional_info.callable_address = function_address_resolved; @@ -276,6 +289,50 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( return optional_info; } + std::string func_to_match = first_template_parameter.str(); + + auto it = CallableLookupCache.find(func_to_match); + if (it != CallableLookupCache.end()) + return it->second; + + SymbolContextList scl; + + CompileUnit *vtable_cu = + vtable_first_entry_resolved.CalculateSymbolContextCompileUnit(); + llvm::StringRef name_to_use = func_to_match; + + // Case 3, we have a callable object instead of a lambda + // + // TODO + // We currently don't support this case a callable object may have multiple + // operator()() varying on const/non-const and number of arguments and we + // don't have a way to currently distinguish them so we will bail out now. + if (!contains_lambda_identifier(name_to_use)) + return optional_info; + + if (vtable_cu && !has___invoke) { + lldb::FunctionSP func_sp = + vtable_cu->FindFunction([name_to_use](const FunctionSP &f) { + auto name = f->GetName().GetStringRef(); + if (name.startswith(name_to_use) && name.contains("operator")) + return true; + + return false; + }); + + if (func_sp) { + calculate_symbol_context_helper(func_sp, scl); + } + } + + // Case 1 or 3 + if (scl.GetSize() >= 1) { + optional_info = line_entry_helper(target, scl[0], symbol, + first_template_parameter, has___invoke); + } + + CallableLookupCache[func_to_match] = optional_info; + return optional_info; } diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h index 28526361efc4..abdd79fcd7b9 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h @@ -10,6 +10,9 @@ #define liblldb_CPPLanguageRuntime_h_ #include <vector> + +#include "llvm/ADT/StringMap.h" + #include "lldb/Core/PluginInterface.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/lldb-private.h" @@ -82,6 +85,11 @@ protected: CPPLanguageRuntime(Process *process); private: + using OperatorStringToCallableInfoMap = + llvm::StringMap<CPPLanguageRuntime::LibCppStdFunctionCallableInfo>; + + OperatorStringToCallableInfoMap CallableLookupCache; + DISALLOW_COPY_AND_ASSIGN(CPPLanguageRuntime); }; diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 02e62a263286..9efb021caa83 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -537,7 +537,10 @@ ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( return {}; ClangASTContext *clang_ast_context = - m_process->GetTarget().GetScratchClangASTContext(); + ClangASTContext::GetScratch(m_process->GetTarget()); + if (!clang_ast_context) + return {}; + CompilerType voidstar = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); @@ -559,6 +562,9 @@ ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( modules.FindSymbolsWithNameAndType( ConstString("__cxa_current_exception_type"), eSymbolTypeCode, contexts); contexts.GetContextAtIndex(0, context); + if (!context.symbol) { + return {}; + } Address addr = context.symbol->GetAddress(); Status error; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp index 93aa07f89165..859b693477a9 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -111,6 +111,18 @@ bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) { m_firstSubclass = extractor.GetAddress_unchecked(&cursor); m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor); + if (m_ro_ptr & 1) { + DataBufferHeap buffer(ptr_size, '\0'); + process->ReadMemory(m_ro_ptr ^ 1, buffer.GetBytes(), ptr_size, error); + if (error.Fail()) + return false; + cursor = 0; + DataExtractor extractor(buffer.GetBytes(), ptr_size, + process->GetByteOrder(), + process->GetAddressByteSize()); + m_ro_ptr = extractor.GetAddress_unchecked(&cursor); + } + return true; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index 1f27a4f0b3ed..73843063606c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -8,10 +8,9 @@ #include "AppleObjCDeclVendor.h" -#include "Plugins/ExpressionParser/Clang/ASTDumper.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -19,12 +18,12 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" - +#include "clang/AST/ExternalASTSource.h" using namespace lldb_private; class lldb_private::AppleObjCExternalASTSource - : public ClangExternalASTSourceCommon { + : public clang::ExternalASTSource { public: AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor) : m_decl_vendor(decl_vendor) {} @@ -77,24 +76,18 @@ public: Log *log(GetLogIfAllCategoriesSet( LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? - if (log) { - LLDB_LOGF(log, - "AppleObjCExternalASTSource::CompleteType[%u] on " - "(ASTContext*)%p Completing (TagDecl*)%p named %s", - current_id, static_cast<void *>(&tag_decl->getASTContext()), - static_cast<void *>(tag_decl), - tag_decl->getName().str().c_str()); + LLDB_LOGF(log, + "AppleObjCExternalASTSource::CompleteType[%u] on " + "(ASTContext*)%p Completing (TagDecl*)%p named %s", + current_id, static_cast<void *>(&tag_decl->getASTContext()), + static_cast<void *>(tag_decl), tag_decl->getName().str().c_str()); - LLDB_LOGF(log, " AOEAS::CT[%u] Before:", current_id); - ASTDumper dumper((clang::Decl *)tag_decl); - dumper.ToLog(log, " [CT] "); - } + LLDB_LOG(log, " AOEAS::CT[{0}] Before:\n{1}", current_id, + ClangUtil::DumpDecl(tag_decl)); + + LLDB_LOG(log, " AOEAS::CT[{1}] After:{1}", current_id, + ClangUtil::DumpDecl(tag_decl)); - if (log) { - LLDB_LOGF(log, " AOEAS::CT[%u] After:", current_id); - ASTDumper dumper((clang::Decl *)tag_decl); - dumper.ToLog(log, " [CT] "); - } return; } @@ -115,16 +108,14 @@ public: interface_decl->getName().str().c_str()); LLDB_LOGF(log, " AOEAS::CT[%u] Before:", current_id); - ASTDumper dumper((clang::Decl *)interface_decl); - dumper.ToLog(log, " [CT] "); + LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl)); } m_decl_vendor.FinishDecl(interface_decl); if (log) { LLDB_LOGF(log, " [CT] After:"); - ASTDumper dumper((clang::Decl *)interface_decl); - dumper.ToLog(log, " [CT] "); + LLDB_LOG(log, " [CT] {0}", ClangUtil::DumpDecl(interface_decl)); } return; } @@ -141,7 +132,7 @@ public: void StartTranslationUnit(clang::ASTConsumer *Consumer) override { clang::TranslationUnitDecl *translation_unit_decl = - m_decl_vendor.m_ast_ctx.getASTContext()->getTranslationUnitDecl(); + m_decl_vendor.m_ast_ctx.getASTContext().getTranslationUnitDecl(); translation_unit_decl->setHasExternalVisibleStorage(); translation_unit_decl->setHasExternalLexicalStorage(); } @@ -155,14 +146,12 @@ AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime) m_ast_ctx(runtime.GetProcess() ->GetTarget() .GetArchitecture() - .GetTriple() - .getTriple() - .c_str()), + .GetTriple()), m_type_realizer_sp(m_runtime.GetEncodingToType()) { m_external_source = new AppleObjCExternalASTSource(*this); llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr( m_external_source); - m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr); + m_ast_ctx.getASTContext().setExternalSource(external_source_owning_ptr); } clang::ObjCInterfaceDecl * @@ -172,7 +161,7 @@ AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) { if (iter != m_isa_to_interface.end()) return iter->second; - clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); + clang::ASTContext &ast_ctx = m_ast_ctx.getASTContext(); ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(isa); @@ -183,20 +172,20 @@ AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) { ConstString name(descriptor->GetClassName()); clang::IdentifierInfo &identifier_info = - ast_ctx->Idents.get(name.GetStringRef()); + ast_ctx.Idents.get(name.GetStringRef()); clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create( - *ast_ctx, ast_ctx->getTranslationUnitDecl(), clang::SourceLocation(), + ast_ctx, ast_ctx.getTranslationUnitDecl(), clang::SourceLocation(), &identifier_info, nullptr, nullptr); ClangASTMetadata meta_data; meta_data.SetISAPtr(isa); - m_external_source->SetMetadata(new_iface_decl, meta_data); + m_ast_ctx.SetMetadata(new_iface_decl, meta_data); new_iface_decl->setHasExternalVisibleStorage(); new_iface_decl->setHasExternalLexicalStorage(); - ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl); + ast_ctx.getTranslationUnitDecl()->addDecl(new_iface_decl); m_isa_to_interface[isa] = new_iface_decl; @@ -320,7 +309,8 @@ public: } clang::ObjCMethodDecl * - BuildMethod(clang::ObjCInterfaceDecl *interface_decl, const char *name, + BuildMethod(ClangASTContext &clang_ast_ctxt, + clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance, ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) { if (!m_is_valid || m_type_vector.size() < 3) @@ -330,7 +320,8 @@ public: const bool isInstance = instance; const bool isVariadic = false; - const bool isSynthesized = false; + const bool isPropertyAccessor = false; + const bool isSynthesizedAccessorStub = false; const bool isImplicitlyDeclared = true; const bool isDefined = false; const clang::ObjCMethodDecl::ImplementationControl impControl = @@ -368,8 +359,7 @@ public: clang::QualType ret_type = ClangUtil::GetQualType(type_realizer_sp->RealizeType( - interface_decl->getASTContext(), m_type_vector[0].c_str(), - for_expression)); + clang_ast_ctxt, m_type_vector[0].c_str(), for_expression)); if (ret_type.isNull()) return nullptr; @@ -377,8 +367,8 @@ public: clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create( ast_ctx, clang::SourceLocation(), clang::SourceLocation(), sel, ret_type, nullptr, interface_decl, isInstance, isVariadic, - isSynthesized, isImplicitlyDeclared, isDefined, impControl, - HasRelatedResultType); + isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared, + isDefined, impControl, HasRelatedResultType); std::vector<clang::ParmVarDecl *> parm_vars; @@ -386,7 +376,7 @@ public: const bool for_expression = true; clang::QualType arg_type = ClangUtil::GetQualType(type_realizer_sp->RealizeType( - ast_ctx, m_type_vector[ai].c_str(), for_expression)); + clang_ast_ctxt, m_type_vector[ai].c_str(), for_expression)); if (arg_type.isNull()) return nullptr; // well, we just wasted a bunch of time. Wish we could @@ -421,7 +411,7 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { Log *log(GetLogIfAllCategoriesSet( LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? - ClangASTMetadata *metadata = m_external_source->GetMetadata(interface_decl); + ClangASTMetadata *metadata = m_ast_ctx.GetMetadata(interface_decl); ObjCLanguageRuntime::ObjCISA objc_isa = 0; if (metadata) objc_isa = metadata->GetISAPtr(); @@ -451,9 +441,9 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { return; FinishDecl(superclass_decl); - clang::ASTContext *context = m_ast_ctx.getASTContext(); - interface_decl->setSuperClass(context->getTrivialTypeSourceInfo( - context->getObjCInterfaceType(superclass_decl))); + clang::ASTContext &context = m_ast_ctx.getASTContext(); + interface_decl->setSuperClass(context.getTrivialTypeSourceInfo( + context.getObjCInterfaceType(superclass_decl))); }; auto instance_method_func = @@ -463,8 +453,8 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { ObjCRuntimeMethodType method_type(types); - clang::ObjCMethodDecl *method_decl = - method_type.BuildMethod(interface_decl, name, true, m_type_realizer_sp); + clang::ObjCMethodDecl *method_decl = method_type.BuildMethod( + m_ast_ctx, interface_decl, name, true, m_type_realizer_sp); LLDB_LOGF(log, "[ AOTV::FD] Instance method [%s] [%s]", name, types); @@ -482,7 +472,7 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { ObjCRuntimeMethodType method_type(types); clang::ObjCMethodDecl *method_decl = method_type.BuildMethod( - interface_decl, name, false, m_type_realizer_sp); + m_ast_ctx, interface_decl, name, false, m_type_realizer_sp); LLDB_LOGF(log, "[ AOTV::FD] Class method [%s] [%s]", name, types); @@ -511,8 +501,8 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { clang::TypeSourceInfo *const type_source_info = nullptr; const bool is_synthesized = false; clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create( - *m_ast_ctx.getASTContext(), interface_decl, clang::SourceLocation(), - clang::SourceLocation(), &m_ast_ctx.getASTContext()->Idents.get(name), + m_ast_ctx.getASTContext(), interface_decl, clang::SourceLocation(), + clang::SourceLocation(), &m_ast_ctx.getASTContext().Idents.get(name), ClangUtil::GetQualType(ivar_type), type_source_info, // TypeSourceInfo * clang::ObjCIvarDecl::Public, nullptr, is_synthesized); @@ -525,36 +515,29 @@ bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { return false; }; - if (log) { - ASTDumper method_dumper((clang::Decl *)interface_decl); - - LLDB_LOGF(log, - "[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C " - "interface for %s", - descriptor->GetClassName().AsCString()); - } + LLDB_LOG(log, + "[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C " + "interface for %s", + descriptor->GetClassName().AsCString()); if (!descriptor->Describe(superclass_func, instance_method_func, class_method_func, ivar_func)) return false; if (log) { - ASTDumper method_dumper((clang::Decl *)interface_decl); - LLDB_LOGF( log, "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface"); - method_dumper.ToLog(log, " [AOTV::FD] "); + LLDB_LOG(log, " [AOTV::FD] {0}", ClangUtil::DumpDecl(interface_decl)); } return true; } -uint32_t -AppleObjCDeclVendor::FindDecls(ConstString name, bool append, - uint32_t max_matches, - std::vector<clang::NamedDecl *> &decls) { +uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append, + uint32_t max_matches, + std::vector<CompilerDecl> &decls) { static unsigned int invocation_id = 0; unsigned int current_id = invocation_id++; @@ -573,37 +556,35 @@ AppleObjCDeclVendor::FindDecls(ConstString name, bool append, do { // See if the type is already in our ASTContext. - clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); + clang::ASTContext &ast_ctx = m_ast_ctx.getASTContext(); clang::IdentifierInfo &identifier_info = - ast_ctx->Idents.get(name.GetStringRef()); + ast_ctx.Idents.get(name.GetStringRef()); clang::DeclarationName decl_name = - ast_ctx->DeclarationNames.getIdentifier(&identifier_info); + ast_ctx.DeclarationNames.getIdentifier(&identifier_info); clang::DeclContext::lookup_result lookup_result = - ast_ctx->getTranslationUnitDecl()->lookup(decl_name); + ast_ctx.getTranslationUnitDecl()->lookup(decl_name); if (!lookup_result.empty()) { if (clang::ObjCInterfaceDecl *result_iface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) { if (log) { clang::QualType result_iface_type = - ast_ctx->getObjCInterfaceType(result_iface_decl); - ASTDumper dumper(result_iface_type); + ast_ctx.getObjCInterfaceType(result_iface_decl); uint64_t isa_value = LLDB_INVALID_ADDRESS; - ClangASTMetadata *metadata = - m_external_source->GetMetadata(result_iface_decl); + ClangASTMetadata *metadata = m_ast_ctx.GetMetadata(result_iface_decl); if (metadata) isa_value = metadata->GetISAPtr(); - LLDB_LOGF(log, - "AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 - ") in the ASTContext", - current_id, dumper.GetCString(), isa_value); + LLDB_LOG(log, + "AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 + ") in the ASTContext", + current_id, result_iface_type.getAsString(), isa_value); } - decls.push_back(result_iface_decl); + decls.push_back(CompilerDecl(&m_ast_ctx, result_iface_decl)); ret++; break; } else { @@ -640,24 +621,16 @@ AppleObjCDeclVendor::FindDecls(ConstString name, bool append, } if (log) { - clang::QualType new_iface_type = - ast_ctx->getObjCInterfaceType(iface_decl); - ASTDumper dumper(new_iface_type); - LLDB_LOGF(log, "AOCTV::FT [%u] Created %s (isa 0x%" PRIx64 ")", - current_id, dumper.GetCString(), (uint64_t)isa); + clang::QualType new_iface_type = ast_ctx.getObjCInterfaceType(iface_decl); + + LLDB_LOG(log, "AOCTV::FT [{0}] Created {1} (isa 0x{2:x})", current_id, + new_iface_type.getAsString(), (uint64_t)isa); } - decls.push_back(iface_decl); + decls.push_back(CompilerDecl(&m_ast_ctx, iface_decl)); ret++; break; } while (false); return ret; } - -clang::ExternalASTMerger::ImporterSource -AppleObjCDeclVendor::GetImporterSource() { - return clang::ExternalASTMerger::ImporterSource(*m_ast_ctx.getASTContext(), - *m_ast_ctx.getFileManager(), - m_ast_ctx.GetOriginMap()); -} diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h index 99ca4b748709..f49ca3540c2c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h @@ -28,9 +28,7 @@ public: } uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, - std::vector<clang::NamedDecl *> &decls) override; - - clang::ExternalASTMerger::ImporterSource GetImporterSource() override; + std::vector<CompilerDecl> &decls) override; friend class AppleObjCExternalASTSource; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 8ca9ad7b843a..7076959bee97 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -111,7 +111,10 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, } } else { // If it is not a pointer, see if we can make it into a pointer. - ClangASTContext *ast_context = target->GetScratchClangASTContext(); + ClangASTContext *ast_context = ClangASTContext::GetScratch(*target); + if (!ast_context) + return false; + CompilerType opaque_type = ast_context->GetBasicType(eBasicTypeObjCID); if (!opaque_type) opaque_type = ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); @@ -123,7 +126,9 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, arg_value_list.PushValue(value); // This is the return value: - ClangASTContext *ast_context = target->GetScratchClangASTContext(); + ClangASTContext *ast_context = ClangASTContext::GetScratch(*target); + if (!ast_context) + return false; CompilerType return_compiler_type = ast_context->GetCStringType(true); Value ret; @@ -494,9 +499,12 @@ ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( reserved_dict = reserved_dict->GetSyntheticValue(); if (!reserved_dict) return ThreadSP(); + ClangASTContext *clang_ast_context = + ClangASTContext::GetScratch(*exception_sp->GetTargetSP()); + if (!clang_ast_context) + return ThreadSP(); CompilerType objc_id = - exception_sp->GetTargetSP()->GetScratchClangASTContext()->GetBasicType( - lldb::eBasicTypeObjCID); + clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID); ValueObjectSP return_addresses; auto objc_object_from_address = [&exception_sp, &objc_id](uint64_t addr, diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 9bdbef393e39..4015f10c4966 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -1301,7 +1301,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( return DescriptorMapUpdateResult::Fail(); thread_sp->CalculateExecutionContext(exe_ctx); - ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); + ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); if (!ast) return DescriptorMapUpdateResult::Fail(); @@ -1563,7 +1563,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { return DescriptorMapUpdateResult::Fail(); thread_sp->CalculateExecutionContext(exe_ctx); - ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); + ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); if (!ast) return DescriptorMapUpdateResult::Fail(); @@ -1625,19 +1625,13 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { // Substitute in the correct class_getName / class_getNameRaw function name, // concatenate the two parts of our expression text. The format string // has two %s's, so provide the name twice. - int prefix_string_size = snprintf (nullptr, 0, + std::string shared_class_expression; + llvm::raw_string_ostream(shared_class_expression) << llvm::format( g_shared_cache_class_name_funcptr, class_name_getter_function_name.AsCString(), class_name_getter_function_name.AsCString()); - char *class_name_func_ptr_expr = (char*) malloc (prefix_string_size + 1); - snprintf (class_name_func_ptr_expr, prefix_string_size + 1, - g_shared_cache_class_name_funcptr, - class_name_getter_function_name.AsCString(), - class_name_getter_function_name.AsCString()); - std::string shared_class_expression = class_name_func_ptr_expr; shared_class_expression += g_get_shared_cache_class_info_body; - free (class_name_func_ptr_expr); m_get_shared_cache_class_info_code.reset( GetTargetRef().GetUtilityFunctionForLanguage( @@ -1984,36 +1978,6 @@ void AppleObjCRuntimeV2::WarnIfNoClassesCached( } } -ConstString -AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) { - if (isa == g_objc_Tagged_ISA) { - static const ConstString g_objc_tagged_isa_name("_lldb_Tagged_ObjC_ISA"); - return g_objc_tagged_isa_name; - } - if (isa == g_objc_Tagged_ISA_NSAtom) { - static const ConstString g_objc_tagged_isa_nsatom_name("NSAtom"); - return g_objc_tagged_isa_nsatom_name; - } - if (isa == g_objc_Tagged_ISA_NSNumber) { - static const ConstString g_objc_tagged_isa_nsnumber_name("NSNumber"); - return g_objc_tagged_isa_nsnumber_name; - } - if (isa == g_objc_Tagged_ISA_NSDateTS) { - static const ConstString g_objc_tagged_isa_nsdatets_name("NSDateTS"); - return g_objc_tagged_isa_nsdatets_name; - } - if (isa == g_objc_Tagged_ISA_NSManagedObject) { - static const ConstString g_objc_tagged_isa_nsmanagedobject_name( - "NSManagedObject"); - return g_objc_tagged_isa_nsmanagedobject_name; - } - if (isa == g_objc_Tagged_ISA_NSDate) { - static const ConstString g_objc_tagged_isa_nsdate_name("NSDate"); - return g_objc_tagged_isa_nsdate_name; - } - return ObjCLanguageRuntime::GetActualTypeName(isa); -} - DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() { if (!m_decl_vendor_up) m_decl_vendor_up.reset(new AppleObjCDeclVendor(*this)); @@ -2678,10 +2642,12 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { const lldb::ABISP &abi = process_sp->GetABI(); if (!abi) return; - CompilerType voidstar = process_sp->GetTarget() - .GetScratchClangASTContext() - ->GetBasicType(lldb::eBasicTypeVoid) - .GetPointerType(); + ClangASTContext *clang_ast_context = + ClangASTContext::GetScratch(process_sp->GetTarget()); + if (!clang_ast_context) + return; + CompilerType voidstar = + clang_ast_context->GetBasicType(lldb::eBasicTypeVoid).GetPointerType(); ValueList args; Value input_value; @@ -2699,7 +2665,7 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { exception = ValueObjectRecognizerSynthesizedValue::Create( *exception, eValueTypeVariableArgument); exception = exception->GetDynamicValue(eDynamicDontRunTarget); - + m_arguments = ValueObjectListSP(new ValueObjectList()); m_arguments->Append(exception); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index a0fd39dc03b2..785bb3938d2c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -69,8 +69,6 @@ public: void UpdateISAToDescriptorMapIfNeeded() override; - ConstString GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) override; - ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override; ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index 379ef3dca86c..36f95c063b81 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -522,7 +522,10 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines( const ABI *abi = process->GetABI().get(); ClangASTContext *clang_ast_context = - process->GetTarget().GetScratchClangASTContext(); + ClangASTContext::GetScratch(process->GetTarget()); + if (!clang_ast_context) + return false; + ValueList argument_values; Value input_value; CompilerType clang_void_ptr_type = @@ -802,7 +805,10 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, // Next make the runner function for our implementation utility function. ClangASTContext *clang_ast_context = - thread.GetProcess()->GetTarget().GetScratchClangASTContext(); + ClangASTContext::GetScratch(thread.GetProcess()->GetTarget()); + if (!clang_ast_context) + return LLDB_INVALID_ADDRESS; + CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); Status error; @@ -895,7 +901,10 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, TargetSP target_sp(thread.CalculateTarget()); - ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext(); + ClangASTContext *clang_ast_context = ClangASTContext::GetScratch(*target_sp); + if (!clang_ast_context) + return ret_plan_sp; + ValueList argument_values; Value void_ptr_value; CompilerType clang_void_ptr_type = diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index 6402e80d6f98..66f04bef6cbd 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -26,9 +26,7 @@ AppleObjCTypeEncodingParser::AppleObjCTypeEncodingParser( m_scratch_ast_ctx_up.reset(new ClangASTContext(runtime.GetProcess() ->GetTarget() .GetArchitecture() - .GetTriple() - .str() - .c_str())); + .GetTriple())); } std::string AppleObjCTypeEncodingParser::ReadStructName(StringLexer &type) { @@ -63,7 +61,7 @@ AppleObjCTypeEncodingParser::StructElement::StructElement() : name(""), type(clang::QualType()), bitfield(0) {} AppleObjCTypeEncodingParser::StructElement -AppleObjCTypeEncodingParser::ReadStructElement(clang::ASTContext &ast_ctx, +AppleObjCTypeEncodingParser::ReadStructElement(ClangASTContext &ast_ctx, StringLexer &type, bool for_expression) { StructElement retval; @@ -78,19 +76,19 @@ AppleObjCTypeEncodingParser::ReadStructElement(clang::ASTContext &ast_ctx, } clang::QualType AppleObjCTypeEncodingParser::BuildStruct( - clang::ASTContext &ast_ctx, StringLexer &type, bool for_expression) { + ClangASTContext &ast_ctx, StringLexer &type, bool for_expression) { return BuildAggregate(ast_ctx, type, for_expression, '{', '}', clang::TTK_Struct); } clang::QualType AppleObjCTypeEncodingParser::BuildUnion( - clang::ASTContext &ast_ctx, StringLexer &type, bool for_expression) { + ClangASTContext &ast_ctx, StringLexer &type, bool for_expression) { return BuildAggregate(ast_ctx, type, for_expression, '(', ')', clang::TTK_Union); } clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( - clang::ASTContext &ast_ctx, StringLexer &type, bool for_expression, + ClangASTContext &ast_ctx, StringLexer &type, bool for_expression, char opener, char closer, uint32_t kind) { if (!type.NextIf(opener)) return clang::QualType(); @@ -124,11 +122,8 @@ clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( if (is_templated) return clang::QualType(); // This is where we bail out. Sorry! - ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); - if (!lldb_ctx) - return clang::QualType(); - CompilerType union_type(lldb_ctx->CreateRecordType( - nullptr, lldb::eAccessPublic, name.c_str(), kind, lldb::eLanguageTypeC)); + CompilerType union_type(ast_ctx.CreateRecordType( + nullptr, lldb::eAccessPublic, name, kind, lldb::eLanguageTypeC)); if (union_type) { ClangASTContext::StartTagDeclarationDefinition(union_type); @@ -140,9 +135,7 @@ clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( element.name = elem_name.GetString(); } ClangASTContext::AddFieldToRecordType( - union_type, element.name.c_str(), - CompilerType(ClangASTContext::GetASTContext(&ast_ctx), - element.type.getAsOpaquePtr()), + union_type, element.name.c_str(), ast_ctx.GetType(element.type), lldb::eAccessPublic, element.bitfield); ++count; } @@ -152,20 +145,15 @@ clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( } clang::QualType AppleObjCTypeEncodingParser::BuildArray( - clang::ASTContext &ast_ctx, StringLexer &type, bool for_expression) { + ClangASTContext &ast_ctx, StringLexer &type, bool for_expression) { if (!type.NextIf('[')) return clang::QualType(); uint32_t size = ReadNumber(type); clang::QualType element_type(BuildType(ast_ctx, type, for_expression)); if (!type.NextIf(']')) return clang::QualType(); - ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); - if (!lldb_ctx) - return clang::QualType(); - CompilerType array_type(lldb_ctx->CreateArrayType( - CompilerType(ClangASTContext::GetASTContext(&ast_ctx), - element_type.getAsOpaquePtr()), - size, false)); + CompilerType array_type(ast_ctx.CreateArrayType( + CompilerType(&ast_ctx, element_type.getAsOpaquePtr()), size, false)); return ClangUtil::GetQualType(array_type); } @@ -175,10 +163,12 @@ clang::QualType AppleObjCTypeEncodingParser::BuildArray( // consume but ignore the type info and always return an 'id'; if anything, // dynamic typing will resolve things for us anyway clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( - clang::ASTContext &ast_ctx, StringLexer &type, bool for_expression) { + ClangASTContext &clang_ast_ctx, StringLexer &type, bool for_expression) { if (!type.NextIf('@')) return clang::QualType(); + clang::ASTContext &ast_ctx = clang_ast_ctx.getASTContext(); + std::string name; if (type.NextIf('"')) { @@ -257,23 +247,25 @@ clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( } clang::QualType -AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx, +AppleObjCTypeEncodingParser::BuildType(ClangASTContext &clang_ast_ctx, StringLexer &type, bool for_expression, uint32_t *bitfield_bit_size) { if (!type.HasAtLeast(1)) return clang::QualType(); + clang::ASTContext &ast_ctx = clang_ast_ctx.getASTContext(); + switch (type.Peek()) { default: break; case '{': - return BuildStruct(ast_ctx, type, for_expression); + return BuildStruct(clang_ast_ctx, type, for_expression); case '[': - return BuildArray(ast_ctx, type, for_expression); + return BuildArray(clang_ast_ctx, type, for_expression); case '(': - return BuildUnion(ast_ctx, type, for_expression); + return BuildUnion(clang_ast_ctx, type, for_expression); case '@': - return BuildObjCObjectPointerType(ast_ctx, type, for_expression); + return BuildObjCObjectPointerType(clang_ast_ctx, type, for_expression); } switch (type.Next()) { @@ -289,10 +281,7 @@ AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx, case 'l': return ast_ctx.getIntTypeForBitwidth(32, true); // this used to be done like this: - // ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); - // if (!lldb_ctx) - // return clang::QualType(); - // return lldb_ctx->GetIntTypeFromBitSize(32, true).GetQualType(); + // return clang_ast_ctx->GetIntTypeFromBitSize(32, true).GetQualType(); // which uses one of the constants if one is available, but we don't think // all this work is necessary. case 'q': @@ -331,7 +320,8 @@ AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx, return clang::QualType(); } case 'r': { - clang::QualType target_type = BuildType(ast_ctx, type, for_expression); + clang::QualType target_type = + BuildType(clang_ast_ctx, type, for_expression); if (target_type.isNull()) return clang::QualType(); else if (target_type == ast_ctx.UnknownAnyTy) @@ -348,7 +338,8 @@ AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx, // practical cases return ast_ctx.VoidPtrTy; } else { - clang::QualType target_type = BuildType(ast_ctx, type, for_expression); + clang::QualType target_type = + BuildType(clang_ast_ctx, type, for_expression); if (target_type.isNull()) return clang::QualType(); else if (target_type == ast_ctx.UnknownAnyTy) @@ -362,13 +353,13 @@ AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx, } } -CompilerType AppleObjCTypeEncodingParser::RealizeType( - clang::ASTContext &ast_ctx, const char *name, bool for_expression) { +CompilerType AppleObjCTypeEncodingParser::RealizeType(ClangASTContext &ast_ctx, + const char *name, + bool for_expression) { if (name && name[0]) { StringLexer lexer(name); clang::QualType qual_type = BuildType(ast_ctx, lexer, for_expression); - return CompilerType(ClangASTContext::GetASTContext(&ast_ctx), - qual_type.getAsOpaquePtr()); + return ast_ctx.GetType(qual_type); } return CompilerType(); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h index 590bc4ba9eae..e43711bf4ee4 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h @@ -22,7 +22,7 @@ public: AppleObjCTypeEncodingParser(ObjCLanguageRuntime &runtime); ~AppleObjCTypeEncodingParser() override = default; - CompilerType RealizeType(clang::ASTContext &ast_ctx, const char *name, + CompilerType RealizeType(ClangASTContext &ast_ctx, const char *name, bool for_expression) override; private: @@ -35,29 +35,29 @@ private: ~StructElement() = default; }; - clang::QualType BuildType(clang::ASTContext &ast_ctx, StringLexer &type, + clang::QualType BuildType(ClangASTContext &clang_ast_ctx, StringLexer &type, bool for_expression, uint32_t *bitfield_bit_size = nullptr); - clang::QualType BuildStruct(clang::ASTContext &ast_ctx, StringLexer &type, + clang::QualType BuildStruct(ClangASTContext &ast_ctx, StringLexer &type, bool for_expression); - clang::QualType BuildAggregate(clang::ASTContext &ast_ctx, StringLexer &type, - bool for_expression, char opener, char closer, - uint32_t kind); + clang::QualType BuildAggregate(ClangASTContext &clang_ast_ctx, + StringLexer &type, bool for_expression, + char opener, char closer, uint32_t kind); - clang::QualType BuildUnion(clang::ASTContext &ast_ctx, StringLexer &type, + clang::QualType BuildUnion(ClangASTContext &ast_ctx, StringLexer &type, bool for_expression); - clang::QualType BuildArray(clang::ASTContext &ast_ctx, StringLexer &type, + clang::QualType BuildArray(ClangASTContext &ast_ctx, StringLexer &type, bool for_expression); std::string ReadStructName(StringLexer &type); - StructElement ReadStructElement(clang::ASTContext &ast_ctx, StringLexer &type, + StructElement ReadStructElement(ClangASTContext &ast_ctx, StringLexer &type, bool for_expression); - clang::QualType BuildObjCObjectPointerType(clang::ASTContext &ast_ctx, + clang::QualType BuildObjCObjectPointerType(ClangASTContext &clang_ast_ctx, StringLexer &type, bool for_expression); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index 87ae4c2c6c48..9eb493f83c84 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -222,14 +222,6 @@ ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) { return 0; } -ConstString -ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) { - ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(isa)); - if (objc_class_sp) - return objc_class_sp->GetClassName(); - return ConstString(); -} - ObjCLanguageRuntime::ClassDescriptorSP ObjCLanguageRuntime::GetClassDescriptorFromClassName( ConstString class_name) { @@ -313,14 +305,6 @@ ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name, return CompilerType(); } -CompilerType ObjCLanguageRuntime::EncodingToType::RealizeType( - ClangASTContext &ast_ctx, const char *name, bool for_expression) { - clang::ASTContext *clang_ast = ast_ctx.getASTContext(); - if (!clang_ast) - return CompilerType(); - return RealizeType(*clang_ast, name, for_expression); -} - ObjCLanguageRuntime::EncodingToType::~EncodingToType() {} ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() { diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h index 39acd6e9f268..b9a4d5dae08a 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h @@ -145,12 +145,9 @@ public: virtual ~EncodingToType(); virtual CompilerType RealizeType(ClangASTContext &ast_ctx, const char *name, - bool for_expression); + bool for_expression) = 0; virtual CompilerType RealizeType(const char *name, bool for_expression); - virtual CompilerType RealizeType(clang::ASTContext &ast_ctx, - const char *name, bool for_expression) = 0; - protected: std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_up; }; @@ -274,8 +271,6 @@ public: virtual ObjCISA GetISA(ConstString name); - virtual ConstString GetActualTypeName(ObjCISA isa); - virtual ObjCISA GetParentClass(ObjCISA isa); // Finds the byte offset of the child_type ivar in parent_type. If it can't diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index 5200749d759f..4edb8dec6082 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -2240,8 +2240,7 @@ void RenderScriptRuntime::FindStructTypeName(Element &elem, // Iterate over all the global variables looking for one with a matching type // to the Element. We make the assumption a match exists since there needs to // be a global variable to reflect the struct type back into java host code. - for (uint32_t i = 0; i < var_list.GetSize(); ++i) { - const VariableSP var_sp(var_list.GetVariableAtIndex(i)); + for (const VariableSP &var_sp : var_list) { if (!var_sp) continue; @@ -3892,7 +3891,7 @@ void RSModuleDescriptor::Dump(Stream &strm) const { int indent = strm.GetIndentLevel(); strm.Indent(); - m_module->GetFileSpec().Dump(&strm); + m_module->GetFileSpec().Dump(strm.AsRawOstream()); strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded." : "Debug info does not exist."); strm.EOL(); diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp index a6d225d2fbd8..4ddff3ad9c4c 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp @@ -72,7 +72,7 @@ bool isRSAllocationTyCallSite(llvm::Module &module, llvm::CallInst *call_inst) { (void)module; if (!call_inst->hasByValArgument()) return false; - for (const auto ¶m : call_inst->operand_values()) + for (const auto *param : call_inst->operand_values()) if (isRSAllocationPtrTy(param->getType())) return true; return false; diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp index de17d986a860..b83b2efb492f 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp +++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp @@ -72,7 +72,7 @@ llvm::Triple::ArchType stringTo<llvm::Triple::ArchType>(llvm::StringRef Str) { .Case("sparc", Triple::sparc) .Case("sparcv9", Triple::sparcv9) .Case("x86", Triple::x86) - .Case("x86_64", Triple::x86_64) + .Cases("x86_64", "x86_64h", Triple::x86_64) .Default(Triple::UnknownArch); } diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 3f8502548fc2..8b62afa18cd6 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1572,8 +1572,10 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) { .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo) .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine) .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr) - .Cases("loc", "loc.dwo", eSectionTypeDWARFDebugLoc) - .Cases("loclists", "loclists.dwo", eSectionTypeDWARFDebugLocLists) + .Case("loc", eSectionTypeDWARFDebugLoc) + .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo) + .Case("loclists", eSectionTypeDWARFDebugLocLists) + .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo) .Case("macinfo", eSectionTypeDWARFDebugMacInfo) .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro) .Case("names", eSectionTypeDWARFDebugNames) @@ -1581,6 +1583,7 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) { .Case("pubtypes", eSectionTypeDWARFDebugPubTypes) .Case("ranges", eSectionTypeDWARFDebugRanges) .Case("rnglists", eSectionTypeDWARFDebugRngLists) + .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo) .Case("str", eSectionTypeDWARFDebugStr) .Case("str.dwo", eSectionTypeDWARFDebugStrDwo) .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets) @@ -2257,6 +2260,8 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, symbol_size_valid, // Symbol size is valid has_suffix, // Contains linker annotations? flags); // Symbol flags. + if (symbol.getBinding() == STB_WEAK) + dc_symbol.SetIsWeak(true); symtab->AddSymbol(dc_symbol); } return i; diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index b777a5319104..b04ac61c99a1 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -6,7 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_DISABLE_PYTHON +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON #include "OperatingSystemPython.h" @@ -88,13 +90,12 @@ OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process, python_module_path.GetFilename().AsCString("")); if (!os_plugin_class_name.empty()) { const bool init_session = false; - const bool allow_reload = true; char python_module_path_cstr[PATH_MAX]; python_module_path.GetPath(python_module_path_cstr, sizeof(python_module_path_cstr)); Status error; - if (m_interpreter->LoadScriptingModule( - python_module_path_cstr, allow_reload, init_session, error)) { + if (m_interpreter->LoadScriptingModule(python_module_path_cstr, + init_session, error)) { // Strip the ".py" extension if there is one size_t py_extension_pos = os_plugin_class_name.rfind(".py"); if (py_extension_pos != std::string::npos) @@ -166,7 +167,7 @@ bool OperatingSystemPython::UpdateThreadList(ThreadList &old_thread_list, Target &target = m_process->GetTarget(); std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), std::defer_lock); - api_lock.try_lock(); + (void)api_lock.try_lock(); // See above. auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); LLDB_LOGF(log, @@ -308,7 +309,7 @@ OperatingSystemPython::CreateRegisterContextForThread(Thread *thread, Target &target = m_process->GetTarget(); std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), std::defer_lock); - api_lock.try_lock(); + (void)api_lock.try_lock(); // See above. auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); @@ -395,7 +396,7 @@ lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid, Target &target = m_process->GetTarget(); std::unique_lock<std::recursive_mutex> api_lock(target.GetAPIMutex(), std::defer_lock); - api_lock.try_lock(); + (void)api_lock.try_lock(); // See above. auto interpreter_lock = m_interpreter->AcquireInterpreterLock(); StructuredData::DictionarySP thread_info_dict = @@ -416,4 +417,4 @@ lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid, return ThreadSP(); } -#endif // #ifndef LLDB_DISABLE_PYTHON +#endif // #if LLDB_ENABLE_PYTHON diff --git a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h index e76227ddb981..4a594cf29a08 100644 --- a/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h +++ b/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h @@ -9,7 +9,9 @@ #ifndef liblldb_OperatingSystemPython_h_ #define liblldb_OperatingSystemPython_h_ -#ifndef LLDB_DISABLE_PYTHON +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON #include "lldb/Target/OperatingSystem.h" #include "lldb/Utility/StructuredData.h" @@ -80,6 +82,6 @@ protected: lldb_private::StructuredData::ObjectSP m_python_object_sp; }; -#endif // LLDB_DISABLE_PYTHON +#endif #endif // liblldb_OperatingSystemPython_h_ diff --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index 946f0ea3a5cf..261f44c230f9 100644 --- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/Config.h" #include <stdio.h> -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX #include <sys/utsname.h> #endif @@ -194,7 +194,7 @@ bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx, void PlatformFreeBSD::GetStatus(Stream &strm) { Platform::GetStatus(strm); -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX // Display local kernel information only when we are running in host mode. // Otherwise, we would end up printing non-FreeBSD information (when running // on Mac OS for example). diff --git a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp index 63245d18fc5c..53f819e6a272 100644 --- a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/Config.h" #include <stdio.h> -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX #include <sys/utsname.h> #endif @@ -168,7 +168,7 @@ bool PlatformNetBSD::GetSupportedArchitectureAtIndex(uint32_t idx, void PlatformNetBSD::GetStatus(Stream &strm) { Platform::GetStatus(strm); -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX // Display local kernel information only when we are running in host mode. // Otherwise, we would end up printing non-NetBSD information (when running // on Mac OS for example). diff --git a/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp b/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp index 9dfb8844c574..1b63e2da0a4f 100644 --- a/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp +++ b/lldb/source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/Config.h" #include <stdio.h> -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX #include <sys/utsname.h> #endif @@ -173,7 +173,7 @@ bool PlatformOpenBSD::GetSupportedArchitectureAtIndex(uint32_t idx, void PlatformOpenBSD::GetStatus(Stream &strm) { Platform::GetStatus(strm); -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX // Display local kernel information only when we are running in host mode. // Otherwise, we would end up printing non-OpenBSD information (when running // on Mac OS for example). diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index b12e21deb459..2b64be63a623 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -223,7 +223,7 @@ static uint32_t chown_file(Platform *platform, const char *path, command.Printf(":%d", gid); command.Printf("%s", path); int status; - platform->RunShellCommand(command.GetData(), nullptr, &status, nullptr, + platform->RunShellCommand(command.GetData(), FileSpec(), &status, nullptr, nullptr, std::chrono::seconds(10)); return status; } @@ -235,7 +235,7 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (IsHost()) { - if (FileSpec::Equal(source, destination, true)) + if (source == destination) return Status(); // cp src dst // chown uid:gid dst @@ -248,7 +248,7 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, StreamString command; command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); int status; - RunShellCommand(command.GetData(), nullptr, &status, nullptr, nullptr, + RunShellCommand(command.GetData(), FileSpec(), &status, nullptr, nullptr, std::chrono::seconds(10)); if (status != 0) return Status("unable to perform copy"); @@ -278,7 +278,7 @@ PlatformPOSIX::PutFile(const lldb_private::FileSpec &source, GetHostname(), dst_path.c_str()); LLDB_LOGF(log, "[PutFile] Running command: %s\n", command.GetData()); int retcode; - Host::RunShellCommand(command.GetData(), nullptr, &retcode, nullptr, + Host::RunShellCommand(command.GetData(), FileSpec(), &retcode, nullptr, nullptr, std::chrono::minutes(1)); if (retcode == 0) { // Don't chown a local file for a remote system @@ -307,14 +307,14 @@ lldb_private::Status PlatformPOSIX::GetFile( if (dst_path.empty()) return Status("unable to get file path for destination"); if (IsHost()) { - if (FileSpec::Equal(source, destination, true)) + if (source == destination) return Status("local scenario->source and destination are the same file " "path: no operation performed"); // cp src dst StreamString cp_command; cp_command.Printf("cp %s %s", src_path.c_str(), dst_path.c_str()); int status; - RunShellCommand(cp_command.GetData(), nullptr, &status, nullptr, nullptr, + RunShellCommand(cp_command.GetData(), FileSpec(), &status, nullptr, nullptr, std::chrono::seconds(10)); if (status != 0) return Status("unable to perform copy"); @@ -335,7 +335,7 @@ lldb_private::Status PlatformPOSIX::GetFile( dst_path.c_str()); LLDB_LOGF(log, "[GetFile] Running command: %s\n", command.GetData()); int retcode; - Host::RunShellCommand(command.GetData(), nullptr, &retcode, nullptr, + Host::RunShellCommand(command.GetData(), FileSpec(), &retcode, nullptr, nullptr, std::chrono::minutes(1)); if (retcode == 0) return Status(); @@ -706,7 +706,9 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, FunctionCaller *do_dlopen_function = nullptr; // Fetch the clang types we will need: - ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); + ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); + if (!ast) + return nullptr; CompilerType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); @@ -948,7 +950,11 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, Value return_value; // Fetch the clang types we will need: - ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); + ClangASTContext *ast = ClangASTContext::GetScratch(process->GetTarget()); + if (!ast) { + error.SetErrorString("dlopen error: Unable to get ClangASTContext"); + return LLDB_INVALID_IMAGE_TOKEN; + } CompilerType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index 8b6f9fbc33c3..4313d27e11e9 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -8,8 +8,7 @@ #include "NativeProcessNetBSD.h" - - +#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #include "lldb/Host/HostProcess.h" #include "lldb/Host/common/NativeRegisterContext.h" @@ -99,6 +98,17 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, pid, launch_info.GetPTY().ReleaseMasterFileDescriptor(), native_delegate, Info.GetArchitecture(), mainloop)); + // Enable event reporting + ptrace_event_t events; + status = PtraceWrapper(PT_GET_EVENT_MASK, pid, &events, sizeof(events)); + if (status.Fail()) + return status.ToError(); + // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN? + events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT; + status = PtraceWrapper(PT_SET_EVENT_MASK, pid, &events, sizeof(events)); + if (status.Fail()) + return status.ToError(); + status = process_up->ReinitializeThreads(); if (status.Fail()) return status.ToError(); @@ -211,17 +221,32 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { return; } + NativeThreadNetBSD* thread = nullptr; + if (info.psi_lwpid > 0) { + for (const auto &t : m_threads) { + if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) { + thread = static_cast<NativeThreadNetBSD *>(t.get()); + break; + } + static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason(); + } + if (!thread) + LLDB_LOG(log, + "thread not found in m_threads, pid = {0}, LWP = {1}", pid, + info.psi_lwpid); + } + switch (info.psi_siginfo.si_code) { case TRAP_BRKPT: - for (const auto &thread : m_threads) { - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByBreakpoint(); - FixupBreakpointPCAsNeeded(static_cast<NativeThreadNetBSD &>(*thread)); + if (thread) { + thread->SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(*thread); } SetState(StateType::eStateStopped, true); break; case TRAP_TRACE: - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByTrace(); + if (thread) + thread->SetStoppedByTrace(); SetState(StateType::eStateStopped, true); break; case TRAP_EXEC: { @@ -238,54 +263,66 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec(); SetState(StateType::eStateStopped, true); } break; - case TRAP_DBREG: { - // Find the thread. - NativeThreadNetBSD* thread = nullptr; - for (const auto &t : m_threads) { - if (t->GetID() == info.psi_lwpid) { - thread = static_cast<NativeThreadNetBSD *>(t.get()); + case TRAP_LWP: { + ptrace_state_t pst; + Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst)); + if (error.Fail()) { + SetState(StateType::eStateInvalid); + return; + } + + switch (pst.pe_report_event) { + case PTRACE_LWP_CREATE: { + LLDB_LOG(log, + "monitoring new thread, pid = {0}, LWP = {1}", pid, + pst.pe_lwp); + NativeThreadNetBSD& t = AddThread(pst.pe_lwp); + error = t.CopyWatchpointsFrom( + static_cast<NativeThreadNetBSD &>(*GetCurrentThread())); + if (error.Fail()) { + LLDB_LOG(log, + "failed to copy watchpoints to new thread {0}: {1}", + pst.pe_lwp, error); + SetState(StateType::eStateInvalid); + return; + } + } break; + case PTRACE_LWP_EXIT: + LLDB_LOG(log, + "removing exited thread, pid = {0}, LWP = {1}", pid, + pst.pe_lwp); + RemoveThread(pst.pe_lwp); break; - } } - if (!thread) { - LLDB_LOG(log, - "thread not found in m_threads, pid = {0}, LWP = {1}", - GetID(), info.psi_lwpid); - break; + + error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void*>(1), 0); + if (error.Fail()) { + SetState(StateType::eStateInvalid); + return; } + } break; + case TRAP_DBREG: { + if (!thread) + break; - // If a watchpoint was hit, report it + auto ®ctx = static_cast<NativeRegisterContextNetBSD &>( + thread->GetRegisterContext()); uint32_t wp_index = LLDB_INVALID_INDEX32; - Status error = thread->GetRegisterContext().GetWatchpointHitIndex( - wp_index, (uintptr_t)info.psi_siginfo.si_addr); + Status error = regctx.GetWatchpointHitIndex(wp_index, + (uintptr_t)info.psi_siginfo.si_addr); if (error.Fail()) LLDB_LOG(log, "received error while checking for watchpoint hits, pid = " - "{0}, LWP = {1}, error = {2}", - GetID(), info.psi_lwpid, error); + "{0}, LWP = {1}, error = {2}", pid, info.psi_lwpid, error); if (wp_index != LLDB_INVALID_INDEX32) { - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByWatchpoint( - wp_index); + thread->SetStoppedByWatchpoint(wp_index); + regctx.ClearWatchpointHit(wp_index); SetState(StateType::eStateStopped, true); break; } - // If a breakpoint was hit, report it - uint32_t bp_index = LLDB_INVALID_INDEX32; - error = thread->GetRegisterContext().GetHardwareBreakHitIndex( - bp_index, (uintptr_t)info.psi_siginfo.si_addr); - if (error.Fail()) - LLDB_LOG(log, - "received error while checking for hardware " - "breakpoint hits, pid = {0}, LWP = {1}, error = {2}", - GetID(), info.psi_lwpid, error); - if (bp_index != LLDB_INVALID_INDEX32) { - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByBreakpoint(); - SetState(StateType::eStateStopped, true); - break; - } + thread->SetStoppedByTrace(); + SetState(StateType::eStateStopped, true); } break; } } @@ -295,9 +332,14 @@ void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) { const auto siginfo_err = PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info)); - for (const auto &thread : m_threads) { - static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal( - info.psi_siginfo.si_signo, &info.psi_siginfo); + for (const auto &abs_thread : m_threads) { + NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread); + assert(info.psi_lwpid >= 0); + if (info.psi_lwpid == 0 || + static_cast<lldb::tid_t>(info.psi_lwpid) == thread.GetID()) + thread.SetStoppedBySignal(info.psi_siginfo.si_signo, &info.psi_siginfo); + else + thread.SetStoppedWithNoReason(); } SetState(StateType::eStateStopped, true); } @@ -325,68 +367,137 @@ Status NativeProcessNetBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, return error; } +static llvm::Expected<ptrace_siginfo_t> ComputeSignalInfo( + const std::vector<std::unique_ptr<NativeThreadProtocol>> &threads, + const ResumeActionList &resume_actions) { + // We need to account for three possible scenarios: + // 1. no signal being sent. + // 2. a signal being sent to one thread. + // 3. a signal being sent to the whole process. + + // Count signaled threads. While at it, determine which signal is being sent + // and ensure there's only one. + size_t signaled_threads = 0; + int signal = LLDB_INVALID_SIGNAL_NUMBER; + lldb::tid_t signaled_lwp; + for (const auto &thread : threads) { + assert(thread && "thread list should not contain NULL threads"); + const ResumeAction *action = + resume_actions.GetActionForThread(thread->GetID(), true); + if (action) { + if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) { + signaled_threads++; + if (action->signal != signal) { + if (signal != LLDB_INVALID_SIGNAL_NUMBER) + return Status("NetBSD does not support passing multiple signals " + "simultaneously") + .ToError(); + signal = action->signal; + signaled_lwp = thread->GetID(); + } + } + } + } + + if (signaled_threads == 0) { + ptrace_siginfo_t siginfo; + siginfo.psi_siginfo.si_signo = LLDB_INVALID_SIGNAL_NUMBER; + return siginfo; + } + + if (signaled_threads > 1 && signaled_threads < threads.size()) + return Status("NetBSD does not support passing signal to 1<i<all threads") + .ToError(); + + ptrace_siginfo_t siginfo; + siginfo.psi_siginfo.si_signo = signal; + siginfo.psi_siginfo.si_code = SI_USER; + siginfo.psi_siginfo.si_pid = getpid(); + siginfo.psi_siginfo.si_uid = getuid(); + if (signaled_threads == 1) + siginfo.psi_lwpid = signaled_lwp; + else // signal for the whole process + siginfo.psi_lwpid = 0; + return siginfo; +} + Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "pid {0}", GetID()); - const auto &thread = m_threads[0]; - const ResumeAction *const action = - resume_actions.GetActionForThread(thread->GetID(), true); + Status ret; - if (action == nullptr) { - LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), - thread->GetID()); - return Status(); - } + Expected<ptrace_siginfo_t> siginfo = + ComputeSignalInfo(m_threads, resume_actions); + if (!siginfo) + return Status(siginfo.takeError()); - Status error; - int signal = - action->signal != LLDB_INVALID_SIGNAL_NUMBER ? action->signal : 0; - - switch (action->state) { - case eStateRunning: { - // Run the thread, possibly feeding it the signal. - error = NativeProcessNetBSD::PtraceWrapper(PT_CONTINUE, GetID(), (void *)1, - signal); - if (!error.Success()) - return error; - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetRunning(); - SetState(eStateRunning, true); - break; - } - case eStateStepping: - // Run the thread, possibly feeding it the signal. - error = NativeProcessNetBSD::PtraceWrapper(PT_STEP, GetID(), (void *)1, - signal); - if (!error.Success()) - return error; - for (const auto &thread : m_threads) - static_cast<NativeThreadNetBSD &>(*thread).SetStepping(); - SetState(eStateStepping, true); - break; + for (const auto &abs_thread : m_threads) { + assert(abs_thread && "thread list should not contain NULL threads"); + NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread); - case eStateSuspended: - case eStateStopped: - llvm_unreachable("Unexpected state"); + const ResumeAction *action = + resume_actions.GetActionForThread(thread.GetID(), true); + // we need to explicit issue suspend requests, so it is simpler to map it + // into proper action + ResumeAction suspend_action{thread.GetID(), eStateSuspended, + LLDB_INVALID_SIGNAL_NUMBER}; - default: - return Status("NativeProcessNetBSD::%s (): unexpected state %s specified " - "for pid %" PRIu64 ", tid %" PRIu64, - __FUNCTION__, StateAsCString(action->state), GetID(), - thread->GetID()); + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread.GetID()); + action = &suspend_action; + } + + LLDB_LOG( + log, + "processing resume action state {0} signal {1} for pid {2} tid {3}", + action->state, action->signal, GetID(), thread.GetID()); + + switch (action->state) { + case eStateRunning: + ret = thread.Resume(); + break; + case eStateStepping: + ret = thread.SingleStep(); + break; + case eStateSuspended: + case eStateStopped: + if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) + return Status("Passing signal to suspended thread unsupported"); + + ret = thread.Suspend(); + break; + + default: + return Status("NativeProcessNetBSD::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), + thread.GetID()); + } + + if (!ret.Success()) + return ret; } - return Status(); + int signal = 0; + if (siginfo->psi_siginfo.si_signo != LLDB_INVALID_SIGNAL_NUMBER) { + ret = PtraceWrapper(PT_SET_SIGINFO, GetID(), &siginfo.get(), + sizeof(*siginfo)); + if (!ret.Success()) + return ret; + signal = siginfo->psi_siginfo.si_signo; + } + + ret = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), + signal); + if (ret.Success()) + SetState(eStateRunning, true); + return ret; } Status NativeProcessNetBSD::Halt() { - Status error; - - if (kill(GetID(), SIGSTOP) != 0) - error.SetErrorToErrno(); - - return error; + return PtraceWrapper(PT_STOP, GetID()); } Status NativeProcessNetBSD::Detach() { @@ -411,6 +522,10 @@ Status NativeProcessNetBSD::Signal(int signo) { return error; } +Status NativeProcessNetBSD::Interrupt() { + return PtraceWrapper(PT_STOP, GetID()); +} + Status NativeProcessNetBSD::Kill() { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "pid {0}", GetID()); @@ -650,10 +765,10 @@ bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) { } NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + assert(thread_id > 0); assert(!HasThreadNoLock(thread_id) && "attempted to add a thread by id that already exists"); @@ -665,6 +780,22 @@ NativeThreadNetBSD &NativeProcessNetBSD::AddThread(lldb::tid_t thread_id) { return static_cast<NativeThreadNetBSD &>(*m_threads.back()); } +void NativeProcessNetBSD::RemoveThread(lldb::tid_t thread_id) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id); + + assert(thread_id > 0); + assert(HasThreadNoLock(thread_id) && + "attempted to remove a thread that does not exist"); + + for (auto it = m_threads.begin(); it != m_threads.end(); ++it) { + if ((*it)->GetID() == thread_id) { + m_threads.erase(it); + break; + } + } +} + Status NativeProcessNetBSD::Attach() { // Attach to the requested process. // An attach will cause the thread to stop with a SIGSTOP. @@ -783,15 +914,23 @@ Status NativeProcessNetBSD::ReinitializeThreads() { m_threads.clear(); // Initialize new thread +#ifdef PT_LWPSTATUS + struct ptrace_lwpstatus info = {}; + int op = PT_LWPNEXT; +#else struct ptrace_lwpinfo info = {}; - Status error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info)); + int op = PT_LWPINFO; +#endif + + Status error = PtraceWrapper(op, GetID(), &info, sizeof(info)); + if (error.Fail()) { return error; } // Reinitialize from scratch threads and register them in process while (info.pl_lwpid != 0) { AddThread(info.pl_lwpid); - error = PtraceWrapper(PT_LWPINFO, GetID(), &info, sizeof(info)); + error = PtraceWrapper(op, GetID(), &info, sizeof(info)); if (error.Fail()) { return error; } diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 4e7f0a1c13ab..6a06773f40a8 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -47,6 +47,8 @@ public: Status Signal(int signo) override; + Status Interrupt() override; + Status Kill() override; Status GetMemoryRegionInfo(lldb::addr_t load_addr, @@ -98,6 +100,7 @@ private: bool HasThreadNoLock(lldb::tid_t thread_id); NativeThreadNetBSD &AddThread(lldb::tid_t thread_id); + void RemoveThread(lldb::tid_t thread_id); void MonitorCallback(lldb::pid_t pid, int signal); void MonitorExited(lldb::pid_t pid, WaitStatus status); diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp index 3a9caaad74c8..a8afa0b20305 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp @@ -8,6 +8,8 @@ #include "NativeRegisterContextNetBSD.h" +#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" + #include "lldb/Host/common/NativeProcessProtocol.h" using namespace lldb_private; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h index f5dd0c33b677..13e023d856d2 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h @@ -11,12 +11,13 @@ #include "lldb/Host/common/NativeThreadProtocol.h" -#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h" #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" namespace lldb_private { namespace process_netbsd { +class NativeProcessNetBSD; + class NativeRegisterContextNetBSD : public NativeRegisterContextRegisterInfo { public: NativeRegisterContextNetBSD(NativeThreadProtocol &native_thread, @@ -30,6 +31,10 @@ public: static NativeRegisterContextNetBSD * CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); + virtual Status + CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) = 0; + + virtual Status ClearWatchpointHit(uint32_t wp_index) = 0; protected: Status DoRegisterSet(int req, void *buf); diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp index 6cc2810fa235..05a35401da46 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp @@ -84,13 +84,71 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - k_num_gpr_registers_x86_64, "g_gpr_regnums_x86_64 has wrong number of register infos"); +// x86 64-bit floating point registers. +static const uint32_t g_fpu_regnums_x86_64[] = { + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64, + lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64, + lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64, + lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64, + lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64, + lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64, + lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64, + lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, + lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, + lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64, + lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64, + lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - + 1 == + k_num_fpr_registers_x86_64, + "g_fpu_regnums_x86_64 has wrong number of register infos"); + +// x86 64-bit registers available via XState. +static const uint32_t g_xstate_regnums_x86_64[] = { + lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64, + lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64, + lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64, + lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64, + // Note: we currently do not provide them but this is needed to avoid + // unnamed groups in SBFrame::GetRegisterContext(). + lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, + lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_xstate_regnums_x86_64) / sizeof(g_xstate_regnums_x86_64[0])) - + 1 == + k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, + "g_xstate_regnums_x86_64 has wrong number of register infos"); + +// x86 debug registers. +static const uint32_t g_dbr_regnums_x86_64[] = { + lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, + lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - + 1 == + k_num_dbr_registers_x86_64, + "g_dbr_regnums_x86_64 has wrong number of register infos"); + // Number of register sets provided by this context. -enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 }; +enum { k_num_register_sets = 4 }; // Register sets for x86 64-bit. static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, + g_fpu_regnums_x86_64}, + {"Extended State Registers", "xstate", + k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, + g_xstate_regnums_x86_64}, + {"Debug Registers", "dbr", k_num_dbr_registers_x86_64, + g_dbr_regnums_x86_64}, }; #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize()) @@ -667,11 +725,6 @@ Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues( ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize()); dst += GetRegisterInfoInterface().GetGPRSize(); - RegisterValue value((uint64_t)-1); - const RegisterInfo *reg_info = - GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_eax"); - if (reg_info == nullptr) - reg_info = GetRegisterInfoInterface().GetDynamicRegisterInfo("orig_rax"); return error; } @@ -795,10 +848,10 @@ Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( if (!is_vacant) return Status("Watchpoint index not vacant"); - RegisterValue reg_value; const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(lldb_dr7_x86_64); - error = ReadRegister(reg_info_dr7, reg_value); + RegisterValue dr7_value; + error = ReadRegister(reg_info_dr7, dr7_value); if (error.Fail()) return error; @@ -816,16 +869,28 @@ Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; + uint64_t control_bits = dr7_value.GetAsUInt64() & ~bit_mask; control_bits |= enable_bit | rw_bits | size_bits; const RegisterInfo *const reg_info_drN = GetRegisterInfoAtIndex(lldb_dr0_x86_64 + wp_index); - error = WriteRegister(reg_info_drN, RegisterValue(addr)); + RegisterValue drN_value; + error = ReadRegister(reg_info_drN, drN_value); if (error.Fail()) return error; + // clear dr6 if address or bits changed (i.e. we're not reenabling the same + // watchpoint) + if (drN_value.GetAsUInt64() != addr || + (dr7_value.GetAsUInt64() & bit_mask) != (rw_bits | size_bits)) { + ClearWatchpointHit(wp_index); + + error = WriteRegister(reg_info_drN, RegisterValue(addr)); + if (error.Fail()) + return error; + } + error = WriteRegister(reg_info_dr7, RegisterValue(control_bits)); if (error.Fail()) return error; @@ -839,32 +904,36 @@ bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( if (wp_index >= NumSupportedHardwareWatchpoints()) return false; + // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0-1, 2-3, 4-5 + // or 6-7 of the debug control register (DR7) + const RegisterInfo *const reg_info_dr7 = + GetRegisterInfoAtIndex(lldb_dr7_x86_64); RegisterValue reg_value; + Status error = ReadRegister(reg_info_dr7, reg_value); + if (error.Fail()) + return false; + uint64_t bit_mask = 0x3 << (2 * wp_index); + uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of + return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success(); +} + +Status NativeRegisterContextNetBSD_x86_64::ClearWatchpointHit(uint32_t wp_index) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + // for watchpoints 0, 1, 2, or 3, respectively, check bits 0, 1, 2, or 3 of // the debug status register (DR6) const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(lldb_dr6_x86_64); + RegisterValue reg_value; Status error = ReadRegister(reg_info_dr6, reg_value); if (error.Fail()) - return false; + return error; + uint64_t bit_mask = 1 << wp_index; uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - error = WriteRegister(reg_info_dr6, RegisterValue(status_bits)); - if (error.Fail()) - return false; - - // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, - // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register - // (DR7) - const RegisterInfo *const reg_info_dr7 = - GetRegisterInfoAtIndex(lldb_dr7_x86_64); - error = ReadRegister(reg_info_dr7, reg_value); - if (error.Fail()) - return false; - bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success(); + return WriteRegister(reg_info_dr6, RegisterValue(status_bits)); } Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() { @@ -930,4 +999,19 @@ uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() { return 4; } +Status NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom( + NativeRegisterContextNetBSD &source) { + auto &r_source = static_cast<NativeRegisterContextNetBSD_x86_64&>(source); + Status res = r_source.ReadRegisterSet(DBRegSet); + if (!res.Fail()) { + // copy dbregs only if any watchpoints were set + if ((r_source.m_dbr_x86_64.dr[7] & 0xFF) == 0) + return res; + + m_dbr_x86_64 = r_source.m_dbr_x86_64; + res = WriteRegisterSet(DBRegSet); + } + return res; +} + #endif // defined(__x86_64__) diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h index 0fed16542a95..54b8a806267f 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h @@ -58,6 +58,8 @@ public: bool ClearHardwareWatchpoint(uint32_t wp_index) override; + Status ClearWatchpointHit(uint32_t wp_index) override; + Status ClearAllHardwareWatchpoints() override; Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, @@ -71,9 +73,12 @@ public: uint32_t NumSupportedHardwareWatchpoints() override; + Status + CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) override; + private: // Private member types. - enum { GPRegSet, FPRegSet, DBRegSet, XStateRegSet }; + enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet }; // Private member variables. struct reg m_gpr_x86_64; diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index e25975c93446..dd2745d9330e 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -16,9 +16,20 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/State.h" +#include "llvm/Support/Errno.h" + +// clang-format off +#include <sys/types.h> +#include <sys/ptrace.h> +// clang-format on #include <sstream> +// clang-format off +#include <sys/types.h> +#include <sys/sysctl.h> +// clang-format on + using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_netbsd; @@ -30,6 +41,38 @@ NativeThreadNetBSD::NativeThreadNetBSD(NativeProcessNetBSD &process, NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(process.GetArchitecture(), *this) ), m_stop_description() {} +Status NativeThreadNetBSD::Resume() { + Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), + nullptr, GetID()); + if (!ret.Success()) + return ret; + ret = NativeProcessNetBSD::PtraceWrapper(PT_CLEARSTEP, m_process.GetID(), + nullptr, GetID()); + if (ret.Success()) + SetRunning(); + return ret; +} + +Status NativeThreadNetBSD::SingleStep() { + Status ret = NativeProcessNetBSD::PtraceWrapper(PT_RESUME, m_process.GetID(), + nullptr, GetID()); + if (!ret.Success()) + return ret; + ret = NativeProcessNetBSD::PtraceWrapper(PT_SETSTEP, m_process.GetID(), + nullptr, GetID()); + if (ret.Success()) + SetStepping(); + return ret; +} + +Status NativeThreadNetBSD::Suspend() { + Status ret = NativeProcessNetBSD::PtraceWrapper(PT_SUSPEND, m_process.GetID(), + nullptr, GetID()); + if (ret.Success()) + SetStopped(); + return ret; +} + void NativeThreadNetBSD::SetStoppedBySignal(uint32_t signo, const siginfo_t *info) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); @@ -89,6 +132,13 @@ void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { m_stop_info.details.signal.signo = SIGTRAP; } +void NativeThreadNetBSD::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.details.signal.signo = 0; +} + void NativeThreadNetBSD::SetStopped() { const StateType new_state = StateType::eStateStopped; m_state = new_state; @@ -105,7 +155,49 @@ void NativeThreadNetBSD::SetStepping() { m_stop_info.reason = StopReason::eStopReasonNone; } -std::string NativeThreadNetBSD::GetName() { return std::string(""); } +std::string NativeThreadNetBSD::GetName() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + +#ifdef PT_LWPSTATUS + struct ptrace_lwpstatus info = {}; + info.pl_lwpid = m_tid; + Status error = NativeProcessNetBSD::PtraceWrapper( + PT_LWPSTATUS, static_cast<int>(m_process.GetID()), &info, sizeof(info)); + if (error.Fail()) { + return ""; + } + return info.pl_name; +#else + std::vector<struct kinfo_lwp> infos; + int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), + sizeof(struct kinfo_lwp), 0}; + size_t size; + + if (::sysctl(mib, 5, nullptr, &size, nullptr, 0) == -1 || size == 0) { + LLDB_LOG(log, "sysctl() for LWP info size failed: {0}", + llvm::sys::StrError()); + return ""; + } + + mib[4] = size / sizeof(size_t); + infos.resize(size / sizeof(struct kinfo_lwp)); + + if (sysctl(mib, 5, infos.data(), &size, NULL, 0) == -1 || size == 0) { + LLDB_LOG(log, "sysctl() for LWP info failed: {0}", llvm::sys::StrError()); + return ""; + } + + size_t nlwps = size / sizeof(struct kinfo_lwp); + for (size_t i = 0; i < nlwps; i++) { + if (static_cast<lldb::tid_t>(infos[i].l_lid) == m_tid) { + return infos[i].l_name; + } + } + + LLDB_LOG(log, "unable to find lwp {0} in LWP infos", m_tid); + return ""; +#endif +} lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } @@ -140,9 +232,9 @@ bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, llvm_unreachable("unhandled StateType!"); } -NativeRegisterContext& NativeThreadNetBSD::GetRegisterContext() { +NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { assert(m_reg_context_up); -return *m_reg_context_up; + return *m_reg_context_up; } Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, @@ -203,3 +295,13 @@ Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { return Status("Clearing hardware breakpoint failed."); } + +Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { + Status s = GetRegisterContext().CopyHardwareWatchpointsFrom( + source.GetRegisterContext()); + if (!s.Fail()) { + m_watchpoint_index_map = source.m_watchpoint_index_map; + m_hw_break_index_map = source.m_hw_break_index_map; + } + return s; +} diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h index 015d8995db34..89b61ef86722 100644 --- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h +++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h @@ -11,6 +11,8 @@ #include "lldb/Host/common/NativeThreadProtocol.h" +#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h" + #include <csignal> #include <map> #include <string> @@ -34,7 +36,7 @@ public: bool GetStopReason(ThreadStopInfo &stop_info, std::string &description) override; - NativeRegisterContext& GetRegisterContext() override; + NativeRegisterContextNetBSD &GetRegisterContext() override; Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) override; @@ -48,19 +50,26 @@ public: private: // Interface for friend classes + Status Resume(); + Status SingleStep(); + Status Suspend(); + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); void SetStoppedByBreakpoint(); void SetStoppedByTrace(); void SetStoppedByExec(); void SetStoppedByWatchpoint(uint32_t wp_index); + void SetStoppedWithNoReason(); void SetStopped(); void SetRunning(); void SetStepping(); + Status CopyWatchpointsFrom(NativeThreadNetBSD& source); + // Member Variables lldb::StateType m_state; ThreadStopInfo m_stop_info; - std::unique_ptr<NativeRegisterContext> m_reg_context_up; + std::unique_ptr<NativeRegisterContextNetBSD> m_reg_context_up; std::string m_stop_description; using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>; WatchpointIndexMap m_watchpoint_index_map; diff --git a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp index 9678e48436e7..b872269fdfe1 100644 --- a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp +++ b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp @@ -136,15 +136,15 @@ std::string GetCrashReasonString(CrashReason reason, const siginfo_t &info) { #if defined(si_lower) && defined(si_upper) if (reason == CrashReason::eBoundViolation) { str = "signal SIGSEGV"; - AppendBounds(str, reinterpret_cast<lldb::addr_t>(info.si_lower), - reinterpret_cast<lldb::addr_t>(info.si_upper), - reinterpret_cast<lldb::addr_t>(info.si_addr)); + AppendBounds(str, reinterpret_cast<uintptr_t>(info.si_lower), + reinterpret_cast<uintptr_t>(info.si_upper), + reinterpret_cast<uintptr_t>(info.si_addr)); return str; } #endif return GetCrashReasonString(reason, - reinterpret_cast<lldb::addr_t>(info.si_addr)); + reinterpret_cast<uintptr_t>(info.si_addr)); } std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) { diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 2ccbeacc4960..ee939b01d350 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -20,7 +20,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlanCallFunction.h" -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX #include <sys/mman.h> #else // define them diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp index 4ca33c248c6f..173e66904151 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp @@ -21,12 +21,6 @@ #include <memory> -// Support building against older versions of LLVM, this macro was added -// recently. -#ifndef LLVM_EXTENSION -#define LLVM_EXTENSION -#endif - #include "Utility/ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" @@ -1146,10 +1140,11 @@ bool RegisterContextDarwin_arm::ReadRegister(const RegisterInfo *reg_info, case gpr_sp: case gpr_lr: case gpr_pc: - case gpr_cpsr: value.SetUInt32(gpr.r[reg - gpr_r0]); break; - + case gpr_cpsr: + value.SetUInt32(gpr.cpsr); + break; case fpu_s0: case fpu_s1: case fpu_s2: diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp index b3ec24d8905d..fa5197cd6bf4 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -30,12 +30,6 @@ #include <sys/sysctl.h> #endif -// Support building against older versions of LLVM, this macro was added -// recently. -#ifndef LLVM_EXTENSION -#define LLVM_EXTENSION -#endif - #include "Utility/ARM64_DWARF_Registers.h" using namespace lldb; diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp index 873713fd8373..959b04700b17 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp @@ -19,12 +19,6 @@ #include <memory> -// Support building against older versions of LLVM, this macro was added -// recently. -#ifndef LLVM_EXTENSION -#define LLVM_EXTENSION -#endif - #include "RegisterContextDarwin_i386.h" using namespace lldb; diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp index 47758ce85eb2..22088a7d6448 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp @@ -21,12 +21,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" -// Support building against older versions of LLVM, this macro was added -// recently. -#ifndef LLVM_EXTENSION -#define LLVM_EXTENSION -#endif - #include "RegisterContextDarwin_x86_64.h" using namespace lldb; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h index 4a3b3c73fd6b..af3027afa73c 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -25,15 +25,18 @@ LLVM_EXTENSION offsetof(FPR, xsave) + \ LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + (32 * reg_index)) +// Guarantees BNDR/BNDC offsets do not overlap with YMM offsets. +#define GDB_REMOTE_OFFSET 128 + #define BNDR_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR, xsave) + \ - LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index])) + LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index]) + GDB_REMOTE_OFFSET) #define BNDC_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR, xsave) + \ - LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index])) + LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index]) + GDB_REMOTE_OFFSET) #ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT diff --git a/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h index 0d2149c83573..bfdd586d9ded 100644 --- a/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h +++ b/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h @@ -294,7 +294,8 @@ enum { lldb_bndstatus_x86_64, k_last_mpxc_x86_64 = lldb_bndstatus_x86_64, - lldb_dr0_x86_64, + k_first_dbr_x86_64, + lldb_dr0_x86_64 = k_first_dbr_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, @@ -302,6 +303,7 @@ enum { lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, + k_last_dbr_x86_64 = lldb_dr7_x86_64, k_num_registers_x86_64, k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1, @@ -312,6 +314,7 @@ enum { k_num_fpr_registers_x86_64 + k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, + k_num_dbr_registers_x86_64 = k_last_dbr_x86_64 - k_first_dbr_x86_64 + 1, }; } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 144ae103faa4..7cea013eea7f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -31,6 +31,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ScopedPrinter.h" @@ -49,7 +50,7 @@ #include <compression.h> #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB #include <zlib.h> #endif @@ -581,7 +582,7 @@ bool GDBRemoteCommunication::DecompressPacket() { } #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr && m_compression_type == CompressionType::ZlibDeflate) { @@ -1243,8 +1244,9 @@ Status GDBRemoteCommunication::StartDebugserverProcess( void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); } -void GDBRemoteCommunication::SetHistoryStream(llvm::raw_ostream *strm) { - m_history.SetStream(strm); +void GDBRemoteCommunication::SetPacketRecorder( + repro::PacketRecorder *recorder) { + m_history.SetRecorder(recorder); } llvm::Error diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index bb777a5c26a7..0b670018bd69 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -27,6 +27,9 @@ #include "lldb/lldb-public.h" namespace lldb_private { +namespace repro { +class PacketRecorder; +} namespace process_gdb_remote { enum GDBStoppointType { @@ -133,7 +136,8 @@ public: // fork/exec to avoid having to connect/accept void DumpHistory(Stream &strm); - void SetHistoryStream(llvm::raw_ostream *strm); + + void SetPacketRecorder(repro::PacketRecorder *recorder); static llvm::Error ConnectLocally(GDBRemoteCommunication &client, GDBRemoteCommunication &server); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index feb9f0589cee..b2f1ee527e8b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -543,21 +543,24 @@ GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse( // // Takes a valid thread ID because p needs to apply to a thread. bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) { - if (m_supports_p == eLazyBoolCalculate) { - m_supports_p = eLazyBoolNo; - StreamString payload; - payload.PutCString("p0"); - StringExtractorGDBRemote response; - if (SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), - response, false) == - PacketResult::Success && - response.IsNormalResponse()) { - m_supports_p = eLazyBoolYes; - } - } + if (m_supports_p == eLazyBoolCalculate) + m_supports_p = GetThreadPacketSupported(tid, "p0"); return m_supports_p; } +LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported( + lldb::tid_t tid, llvm::StringRef packetStr) { + StreamString payload; + payload.PutCString(packetStr); + StringExtractorGDBRemote response; + if (SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response, false) == PacketResult::Success && + response.IsNormalResponse()) { + return eLazyBoolYes; + } + return eLazyBoolNo; +} + StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { // Get information on all threads at one using the "jThreadsInfo" packet StructuredData::ObjectSP object_sp; @@ -1042,7 +1045,7 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression( } #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { @@ -3737,7 +3740,7 @@ bool GDBRemoteCommunicationClient::ReadExtFeature( case ('m'): if (str.length() > 1) output << &str[1]; - offset += size; + offset += str.length() - 1; break; // unknown chunk diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 574cd0fd70c5..11fd40bce44f 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -89,7 +89,7 @@ public: /// Sends a GDB remote protocol 'A' packet that delivers program /// arguments to the remote server. /// - /// \param[in] argv + /// \param[in] launch_info /// A NULL terminated array of const C strings to use as the /// arguments. /// @@ -155,7 +155,7 @@ public: /// Sets the path to use for stdin/out/err for a process /// that will be launched with the 'A' packet. /// - /// \param[in] path + /// \param[in] file_spec /// The path to use for stdin/out/err /// /// \return @@ -596,6 +596,8 @@ protected: Status GetQXferMemoryMapRegionInfo(lldb::addr_t addr, MemoryRegionInfo ®ion); + LazyBool GetThreadPacketSupported(lldb::tid_t tid, llvm::StringRef packetStr); + private: DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationClient); }; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp index d2cc32f63f20..9e5646985f87 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp @@ -40,8 +40,8 @@ void GDBRemoteCommunicationHistory::AddPacket(char packet_char, m_packets[idx].bytes_transmitted = bytes_transmitted; m_packets[idx].packet_idx = m_total_packet_count; m_packets[idx].tid = llvm::get_threadid(); - if (m_stream) - m_packets[idx].Serialize(*m_stream); + if (m_recorder) + m_recorder->Record(m_packets[idx]); } void GDBRemoteCommunicationHistory::AddPacket(const std::string &src, @@ -58,8 +58,8 @@ void GDBRemoteCommunicationHistory::AddPacket(const std::string &src, m_packets[idx].bytes_transmitted = bytes_transmitted; m_packets[idx].packet_idx = m_total_packet_count; m_packets[idx].tid = llvm::get_threadid(); - if (m_stream) - m_packets[idx].Serialize(*m_stream); + if (m_recorder) + m_recorder->Record(m_packets[idx]); } void GDBRemoteCommunicationHistory::Dump(Stream &strm) const { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h index c006fbd34a4b..ee265ef86dff 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h @@ -13,11 +13,15 @@ #include <vector> #include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/lldb-public.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" namespace lldb_private { +namespace repro { +class PacketRecorder; +} namespace process_gdb_remote { /// The history keeps a circular buffer of GDB remote packets. The history is @@ -41,7 +45,7 @@ public: void Dump(Log *log) const; bool DidDumpToLog() const { return m_dumped_to_log; } - void SetStream(llvm::raw_ostream *strm) { m_stream = strm; } + void SetRecorder(repro::PacketRecorder *recorder) { m_recorder = recorder; } private: uint32_t GetFirstSavedPacketIndex() const { @@ -73,7 +77,7 @@ private: uint32_t m_curr_idx; uint32_t m_total_packet_count; mutable bool m_dumped_to_log; - llvm::raw_ostream *m_stream = nullptr; + repro::PacketRecorder *m_recorder = nullptr; }; } // namespace process_gdb_remote diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp index 2d26c550dc76..15c73e78bd44 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp @@ -143,7 +143,14 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( entry.packet.data); LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'", packet.GetStringRef()); - assert(false && "Encountered unexpected packet during replay"); +#ifndef NDEBUG + // This behaves like a regular assert, but prints the expected and + // received packet before aborting. + printf("Reproducer expected packet: '%s'\n", entry.packet.data.c_str()); + printf("Reproducer received packet: '%s'\n", + packet.GetStringRef().data()); + llvm::report_fatal_error("Encountered unexpected packet during replay"); +#endif return PacketResult::ErrorSendFailed; } @@ -204,9 +211,9 @@ bool GDBRemoteCommunicationReplayServer::StartAsyncThread() { "<lldb.gdb-replay.async>", GDBRemoteCommunicationReplayServer::AsyncThread, this); if (!async_thread) { - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), - "failed to launch host thread: {}", - llvm::toString(async_thread.takeError())); + LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), + async_thread.takeError(), + "failed to launch host thread: {}"); return false; } m_async_thread = *async_thread; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 37980d914dc2..4b5fc0774a6d 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -429,7 +429,7 @@ GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qUserName( StringExtractorGDBRemote &packet) { -#if !defined(LLDB_DISABLE_POSIX) +#if LLDB_ENABLE_POSIX Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOGF(log, "GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__); @@ -452,7 +452,7 @@ GDBRemoteCommunicationServerCommon::Handle_qUserName( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qGroupName( StringExtractorGDBRemote &packet) { -#if !defined(LLDB_DISABLE_POSIX) +#if LLDB_ENABLE_POSIX // Packet format: "qGroupName:%i" where %i is the gid packet.SetFilePos(::strlen("qGroupName:")); uint32_t gid = packet.GetU32(UINT32_MAX); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index ad1a39b57969..f33f0ee66304 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -669,9 +669,9 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( response.PutStringAsRawHex8(unescaped_response.GetData()); response.PutChar(';'); } else { - LLDB_LOG(log, "failed to prepare a jstopinfo field for pid {0}:", - m_debugged_process_up->GetID(), - llvm::toString(threads_info.takeError())); + LLDB_LOG_ERROR(log, threads_info.takeError(), + "failed to prepare a jstopinfo field for pid {1}: {0}", + m_debugged_process_up->GetID()); } } @@ -2013,7 +2013,7 @@ GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) { } const uint8_t *const data = - reinterpret_cast<const uint8_t *>(reg_value.GetBytes()); + static_cast<const uint8_t *>(reg_value.GetBytes()); if (!data) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to get data " @@ -3087,9 +3087,9 @@ GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo( llvm::Expected<json::Value> threads_info = GetJSONThreadsInfo( *m_debugged_process_up, threads_with_valid_stop_info_only); if (!threads_info) { - LLDB_LOG(log, "failed to prepare a packet for pid {0}: {1}", - m_debugged_process_up->GetID(), - llvm::toString(threads_info.takeError())); + LLDB_LOG_ERROR(log, threads_info.takeError(), + "failed to prepare a packet for pid {1}: {0}", + m_debugged_process_up->GetID()); return SendErrorResponse(52); } diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index c06c9527708e..ec1a54afd727 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -31,9 +31,11 @@ using namespace lldb_private::process_gdb_remote; // GDBRemoteRegisterContext constructor GDBRemoteRegisterContext::GDBRemoteRegisterContext( ThreadGDBRemote &thread, uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once) + GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once, + bool write_all_at_once) : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info), - m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once) { + m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once), + m_write_all_at_once(write_all_at_once) { // Resize our vector of bools to contain one bool for every register. We will // use these boolean values to know when a register value is valid in // m_reg_data. @@ -87,6 +89,9 @@ bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { // Read the register if (ReadRegisterBytes(reg_info, m_reg_data)) { + const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; + if (m_reg_valid[reg] == false) + return false; const bool partial_data_ok = false; Status error(value.SetValueFromData( reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok)); @@ -203,6 +208,18 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, if (buffer_sp->GetByteSize() >= m_reg_data.GetByteSize()) { SetAllRegisterValid(true); return true; + } else if (buffer_sp->GetByteSize() > 0) { + const int regcount = m_reg_info.GetNumRegisters(); + for (int i = 0; i < regcount; i++) { + struct RegisterInfo *reginfo = m_reg_info.GetRegisterInfoAtIndex(i); + if (reginfo->byte_offset + reginfo->byte_size + <= buffer_sp->GetByteSize()) { + m_reg_valid[i] = true; + } else { + m_reg_valid[i] = false; + } + } + return true; } else { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); @@ -333,7 +350,7 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, { GDBRemoteClientBase::Lock lock(gdb_comm, false); if (lock) { - if (m_read_all_at_once) { + if (m_write_all_at_once) { // Invalidate all register values InvalidateIfNeeded(true); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 25e9b716f8cb..b42c87b5991b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -41,7 +41,7 @@ class GDBRemoteRegisterContext : public RegisterContext { public: GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx, GDBRemoteDynamicRegisterInfo ®_info, - bool read_all_at_once); + bool read_all_at_once, bool write_all_at_once); ~GDBRemoteRegisterContext() override; @@ -114,6 +114,7 @@ protected: std::vector<bool> m_reg_valid; DataExtractor m_reg_data; bool m_read_all_at_once; + bool m_write_all_at_once; private: // Helper function for ReadRegisterBytes(). diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index f1762abc55f8..a49db5d9a934 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -10,7 +10,7 @@ #include <errno.h> #include <stdlib.h> -#ifndef LLDB_DISABLE_POSIX +#if LLDB_ENABLE_POSIX #include <netinet/in.h> #include <sys/mman.h> #include <sys/socket.h> @@ -154,6 +154,11 @@ public: nullptr, idx, g_processgdbremote_properties[idx].default_uint_value != 0); } + + bool GetUseGPacketForReading() const { + const uint32_t idx = ePropertyUseGPacketForReading; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); + } }; typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; @@ -274,12 +279,9 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, "async thread did exit"); if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { - repro::ProcessGDBRemoteProvider &provider = - g->GetOrCreate<repro::ProcessGDBRemoteProvider>(); - // Set the history stream to the stream owned by the provider. - m_gdb_comm.SetHistoryStream(provider.GetHistoryStream()); - // Make sure to clear the stream again when we're finished. - provider.SetCallback([&]() { m_gdb_comm.SetHistoryStream(nullptr); }); + repro::GDBRemoteProvider &provider = + g->GetOrCreate<repro::GDBRemoteProvider>(); + m_gdb_comm.SetPacketRecorder(provider.GetNewPacketRecorder()); } Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); @@ -309,6 +311,9 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, GetGlobalPluginProperties()->GetPacketTimeout(); if (timeout_seconds > 0) m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds)); + + m_use_g_packet_for_reading = + GetGlobalPluginProperties()->GetUseGPacketForReading(); } // Destructor @@ -380,36 +385,6 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition( return false; } -// If the remote stub didn't give us eh_frame or DWARF register numbers for a -// register, see if the ABI can provide them. -// DWARF and eh_frame register numbers are defined as a part of the ABI. -static void AugmentRegisterInfoViaABI(RegisterInfo ®_info, - ConstString reg_name, ABISP abi_sp) { - if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM || - reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) { - if (abi_sp) { - RegisterInfo abi_reg_info; - if (abi_sp->GetRegisterInfoByName(reg_name, abi_reg_info)) { - if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) { - reg_info.kinds[eRegisterKindEHFrame] = - abi_reg_info.kinds[eRegisterKindEHFrame]; - } - if (reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) { - reg_info.kinds[eRegisterKindDWARF] = - abi_reg_info.kinds[eRegisterKindDWARF]; - } - if (reg_info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM && - abi_reg_info.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) { - reg_info.kinds[eRegisterKindGeneric] = - abi_reg_info.kinds[eRegisterKindGeneric]; - } - } - } - } -} - static size_t SplitCommaSeparatedRegisterNumberString( const llvm::StringRef &comma_separated_regiter_numbers, std::vector<uint32_t> ®nums, int base) { @@ -607,12 +582,12 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { reg_info.invalidate_regs = invalidate_regs.data(); } + reg_info.name = reg_name.AsCString(); // We have to make a temporary ABI here, and not use the GetABI because // this code gets called in DidAttach, when the target architecture // (and consequently the ABI we'll get from the process) may be wrong. - ABISP abi_to_use = ABI::FindPlugin(shared_from_this(), arch_to_use); - - AugmentRegisterInfoViaABI(reg_info, reg_name, abi_to_use); + if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use)) + abi_sp->AugmentRegisterInfo(reg_info); m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); } else { @@ -2374,21 +2349,22 @@ void ProcessGDBRemote::RefreshStateAfterStop() { m_thread_ids.clear(); m_thread_pcs.clear(); + // Set the thread stop info. It might have a "threads" key whose value is a // list of all thread IDs in the current process, so m_thread_ids might get // set. + // Check to see if SetThreadStopInfo() filled in m_thread_ids? + if (m_thread_ids.empty()) { + // No, we need to fetch the thread list manually + UpdateThreadIDList(); + } + + // We might set some stop info's so make sure the thread list is up to + // date before we do that or we might overwrite what was computed here. + UpdateThreadListIfNeeded(); // Scope for the lock { - // Check to see if SetThreadStopInfo() filled in m_thread_ids? - if (m_thread_ids.empty()) { - // No, we need to fetch the thread list manually - UpdateThreadIDList(); - } - // We might set some stop info's so make sure the thread list is up to - // date before we do that or we might overwrite what was computed here. - UpdateThreadListIfNeeded(); - // Lock the thread stack while we access it std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); // Get the number of stop packets on the stack @@ -3384,17 +3360,20 @@ Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { if (!loader) return Status("No loader provided."); - // Construct replay history path. - FileSpec history_file = - loader->GetFile<repro::ProcessGDBRemoteProvider::Info>(); - if (!history_file) - return Status("No provider for gdb-remote."); + static std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>> + multi_loader = repro::MultiLoader<repro::GDBRemoteProvider>::Create( + repro::Reproducer::Instance().GetLoader()); - // Enable replay mode. - m_replay_mode = true; + if (!multi_loader) + return Status("No gdb remote provider found."); + + llvm::Optional<std::string> history_file = multi_loader->GetNextFile(); + if (!history_file) + return Status("No gdb remote packet log found."); // Load replay history. - if (auto error = m_gdb_replay_server.LoadReplayHistory(history_file)) + if (auto error = + m_gdb_replay_server.LoadReplayHistory(FileSpec(*history_file))) return Status("Unable to load replay history"); // Make a local connection. @@ -3402,6 +3381,9 @@ Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { m_gdb_replay_server)) return Status("Unable to connect to replay server"); + // Enable replay mode. + m_replay_mode = true; + // Start server thread. m_gdb_replay_server.StartAsyncThread(); @@ -3627,9 +3609,9 @@ bool ProcessGDBRemote::StartAsyncThread() { llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread( "<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this); if (!async_thread) { - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), - "failed to launch host thread: {}", - llvm::toString(async_thread.takeError())); + LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), + async_thread.takeError(), + "failed to launch host thread: {}"); return false; } m_async_thread = *async_thread; @@ -4475,7 +4457,9 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, } ++cur_reg_num; - AugmentRegisterInfoViaABI(reg_info, reg_name, abi_sp); + reg_info.name = reg_name.AsCString(); + if (abi_sp) + abi_sp->AugmentRegisterInfo(reg_info); dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name); return true; // Keep iterating through all "reg" elements diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 0e3e3b39d9c8..9ea3940103b6 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -284,6 +284,7 @@ protected: lldb::CommandObjectSP m_command_sp; int64_t m_breakpoint_pc_offset; lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach + bool m_use_g_packet_for_reading; bool m_replay_mode; bool m_allow_flash_writes; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td index 16e7723e3061..9cbe3d40ca2c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteProperties.td @@ -13,4 +13,8 @@ let Definition = "processgdbremote" in { Global, DefaultFalse, Desc<"If true, the libraries-svr4 feature will be used to get a hold of the process's loaded modules.">; + def UseGPacketForReading: Property<"use-g-packet-for-reading", "Boolean">, + Global, + DefaultFalse, + Desc<"Specify if the server should use 'g' packets to read registers.">; } diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 8a6a58c55450..9da481979f73 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -301,13 +301,14 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { if (process_sp) { ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get()); - // read_all_registers_at_once will be true if 'p' packet is not - // supported. + bool pSupported = + gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); bool read_all_registers_at_once = - !gdb_process->GetGDBRemote().GetpPacketSupported(GetID()); + !pSupported || gdb_process->m_use_g_packet_for_reading; + bool write_all_registers_at_once = !pSupported; reg_ctx_sp = std::make_shared<GDBRemoteRegisterContext>( *this, concrete_frame_idx, gdb_process->m_register_info, - read_all_registers_at_once); + read_all_registers_at_once, write_all_registers_at_once); } } else { Unwind *unwinder = GetUnwinder(); diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index 70933f91fe51..3c0e1cb49d1d 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -174,6 +174,7 @@ ArchSpec MinidumpParser::GetArchitecture() { triple.setArch(llvm::Triple::ArchType::arm); break; case ProcessorArchitecture::ARM64: + case ProcessorArchitecture::BP_ARM64: triple.setArch(llvm::Triple::ArchType::aarch64); break; default: @@ -518,58 +519,26 @@ CreateRegionsCacheFromMemory64List(MinidumpParser &parser, return !regions.empty(); } -MemoryRegionInfo -MinidumpParser::FindMemoryRegion(lldb::addr_t load_addr) const { - auto begin = m_regions.begin(); - auto end = m_regions.end(); - auto pos = std::lower_bound(begin, end, load_addr); - if (pos != end && pos->GetRange().Contains(load_addr)) - return *pos; - - MemoryRegionInfo region; - if (pos == begin) - region.GetRange().SetRangeBase(0); - else { - auto prev = pos - 1; - if (prev->GetRange().Contains(load_addr)) - return *prev; - region.GetRange().SetRangeBase(prev->GetRange().GetRangeEnd()); - } - if (pos == end) - region.GetRange().SetRangeEnd(UINT64_MAX); - else - region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); - region.SetReadable(MemoryRegionInfo::eNo); - region.SetWritable(MemoryRegionInfo::eNo); - region.SetExecutable(MemoryRegionInfo::eNo); - region.SetMapped(MemoryRegionInfo::eNo); - return region; -} - -MemoryRegionInfo -MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) { - if (!m_parsed_regions) - GetMemoryRegions(); - return FindMemoryRegion(load_addr); -} - -const MemoryRegionInfos &MinidumpParser::GetMemoryRegions() { - if (!m_parsed_regions) { - m_parsed_regions = true; - // We haven't cached our memory regions yet we will create the region cache - // once. We create the region cache using the best source. We start with - // the linux maps since they are the most complete and have names for the - // regions. Next we try the MemoryInfoList since it has - // read/write/execute/map data, and then fall back to the MemoryList and - // Memory64List to just get a list of the memory that is mapped in this - // core file - if (!CreateRegionsCacheFromLinuxMaps(*this, m_regions)) - if (!CreateRegionsCacheFromMemoryInfoList(*this, m_regions)) - if (!CreateRegionsCacheFromMemoryList(*this, m_regions)) - CreateRegionsCacheFromMemory64List(*this, m_regions); - llvm::sort(m_regions.begin(), m_regions.end()); - } - return m_regions; +std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() { + // We create the region cache using the best source. We start with + // the linux maps since they are the most complete and have names for the + // regions. Next we try the MemoryInfoList since it has + // read/write/execute/map data, and then fall back to the MemoryList and + // Memory64List to just get a list of the memory that is mapped in this + // core file + MemoryRegionInfos result; + const auto &return_sorted = [&](bool is_complete) { + llvm::sort(result); + return std::make_pair(std::move(result), is_complete); + }; + if (CreateRegionsCacheFromLinuxMaps(*this, result)) + return return_sorted(true); + if (CreateRegionsCacheFromMemoryInfoList(*this, result)) + return return_sorted(true); + if (CreateRegionsCacheFromMemoryList(*this, result)) + return return_sorted(false); + CreateRegionsCacheFromMemory64List(*this, result); + return return_sorted(false); } #define ENUM_TO_CSTR(ST) \ diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h index d206fe6c9a00..4bcb2b47d45a 100644 --- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h +++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h @@ -88,9 +88,9 @@ public: llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size); - MemoryRegionInfo GetMemoryRegionInfo(lldb::addr_t load_addr); - - const MemoryRegionInfos &GetMemoryRegions(); + /// Returns a list of memory regions and a flag indicating whether the list is + /// complete (includes all regions mapped into the process memory). + std::pair<MemoryRegionInfos, bool> BuildMemoryRegions(); static llvm::StringRef GetStreamTypeAsString(StreamType stream_type); @@ -100,14 +100,10 @@ private: MinidumpParser(lldb::DataBufferSP data_sp, std::unique_ptr<llvm::object::MinidumpFile> file); - MemoryRegionInfo FindMemoryRegion(lldb::addr_t load_addr) const; - private: lldb::DataBufferSP m_data_sp; std::unique_ptr<llvm::object::MinidumpFile> m_file; ArchSpec m_arch; - MemoryRegionInfos m_regions; - bool m_parsed_regions = false; }; } // end namespace minidump diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index e30a3c82a887..5c090dc6e12f 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -334,15 +334,84 @@ ArchSpec ProcessMinidump::GetArchitecture() { return ArchSpec(triple); } +static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos ®ions, + lldb::addr_t load_addr) { + MemoryRegionInfo region; + auto pos = llvm::upper_bound(regions, load_addr); + if (pos != regions.begin() && + std::prev(pos)->GetRange().Contains(load_addr)) { + return *std::prev(pos); + } + + if (pos == regions.begin()) + region.GetRange().SetRangeBase(0); + else + region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd()); + + if (pos == regions.end()) + region.GetRange().SetRangeEnd(UINT64_MAX); + else + region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); + + region.SetReadable(MemoryRegionInfo::eNo); + region.SetWritable(MemoryRegionInfo::eNo); + region.SetExecutable(MemoryRegionInfo::eNo); + region.SetMapped(MemoryRegionInfo::eNo); + return region; +} + +void ProcessMinidump::BuildMemoryRegions() { + if (m_memory_regions) + return; + m_memory_regions.emplace(); + bool is_complete; + std::tie(*m_memory_regions, is_complete) = + m_minidump_parser->BuildMemoryRegions(); + + if (is_complete) + return; + + MemoryRegionInfos to_add; + ModuleList &modules = GetTarget().GetImages(); + SectionLoadList &load_list = GetTarget().GetSectionLoadList(); + modules.ForEach([&](const ModuleSP &module_sp) { + SectionList *sections = module_sp->GetSectionList(); + for (size_t i = 0; i < sections->GetSize(); ++i) { + SectionSP section_sp = sections->GetSectionAtIndex(i); + addr_t load_addr = load_list.GetSectionLoadAddress(section_sp); + if (load_addr == LLDB_INVALID_ADDRESS) + continue; + MemoryRegionInfo::RangeType section_range(load_addr, + section_sp->GetByteSize()); + MemoryRegionInfo region = + ::GetMemoryRegionInfo(*m_memory_regions, load_addr); + if (region.GetMapped() != MemoryRegionInfo::eYes && + region.GetRange().GetRangeBase() <= section_range.GetRangeBase() && + section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) { + to_add.emplace_back(); + to_add.back().GetRange() = section_range; + to_add.back().SetLLDBPermissions(section_sp->GetPermissions()); + to_add.back().SetMapped(MemoryRegionInfo::eYes); + to_add.back().SetName(module_sp->GetFileSpec().GetPath().c_str()); + } + } + return true; + }); + m_memory_regions->insert(m_memory_regions->end(), to_add.begin(), + to_add.end()); + llvm::sort(*m_memory_regions); +} + Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo &range_info) { - range_info = m_minidump_parser->GetMemoryRegionInfo(load_addr); + MemoryRegionInfo ®ion) { + BuildMemoryRegions(); + region = ::GetMemoryRegionInfo(*m_memory_regions, load_addr); return Status(); } -Status ProcessMinidump::GetMemoryRegions( - lldb_private::MemoryRegionInfos ®ion_list) { - region_list = m_minidump_parser->GetMemoryRegions(); +Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos ®ion_list) { + BuildMemoryRegions(); + region_list = *m_memory_regions; return Status(); } diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index 22dc24af7c0e..750164cf8aaf 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -111,6 +111,9 @@ private: const minidump::ExceptionStream *m_active_exception; lldb::CommandObjectSP m_command_sp; bool m_is_wow64; + llvm::Optional<MemoryRegionInfos> m_memory_regions; + + void BuildMemoryRegions(); }; } // namespace minidump diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp new file mode 100644 index 000000000000..ecee8cc674f8 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp @@ -0,0 +1,59 @@ +//===-- Lua.cpp -----------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Lua.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Utility/FileSpec.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace lldb_private; +using namespace lldb; + +llvm::Error Lua::Run(llvm::StringRef buffer) { + int error = + luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") || + lua_pcall(m_lua_state, 0, 0, 0); + if (!error) + return llvm::Error::success(); + + llvm::Error e = llvm::make_error<llvm::StringError>( + llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(m_lua_state, 1); + return e; +} + +llvm::Error Lua::LoadModule(llvm::StringRef filename) { + FileSpec file(filename); + if (!FileSystem::Instance().Exists(file)) { + return llvm::make_error<llvm::StringError>("invalid path", + llvm::inconvertibleErrorCode()); + } + + ConstString module_extension = file.GetFileNameExtension(); + if (module_extension != ".lua") { + return llvm::make_error<llvm::StringError>("invalid extension", + llvm::inconvertibleErrorCode()); + } + + int error = luaL_loadfile(m_lua_state, filename.data()) || + lua_pcall(m_lua_state, 0, 1, 0); + if (error) { + llvm::Error e = llvm::make_error<llvm::StringError>( + llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(m_lua_state, 1); + return e; + } + + ConstString module_name = file.GetFileNameStrippingExtension(); + lua_setglobal(m_lua_state, module_name.GetCString()); + return llvm::Error::success(); +} diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h new file mode 100644 index 000000000000..f2984a925dfe --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h @@ -0,0 +1,48 @@ +//===-- ScriptInterpreterLua.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Lua_h_ +#define liblldb_Lua_h_ + +#include "lldb/lldb-types.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +#include "lua.hpp" + +#include <mutex> + +namespace lldb_private { + +extern "C" { +int luaopen_lldb(lua_State *L); +} + +class Lua { +public: + Lua() : m_lua_state(luaL_newstate()) { + assert(m_lua_state); + luaL_openlibs(m_lua_state); + luaopen_lldb(m_lua_state); + } + + ~Lua() { + assert(m_lua_state); + luaL_openlibs(m_lua_state); + } + + llvm::Error Run(llvm::StringRef buffer); + llvm::Error LoadModule(llvm::StringRef filename); + +private: + lua_State *m_lua_state; +}; + +} // namespace lldb_private + +#endif // liblldb_Lua_h_ diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp new file mode 100644 index 000000000000..701d68d1ec08 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp @@ -0,0 +1,157 @@ +//===-- ScriptInterpreterLua.cpp --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ScriptInterpreterLua.h" +#include "Lua.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StringList.h" +#include "lldb/Utility/Timer.h" + +using namespace lldb; +using namespace lldb_private; + +class IOHandlerLuaInterpreter : public IOHandlerDelegate, + public IOHandlerEditline { +public: + IOHandlerLuaInterpreter(Debugger &debugger, + ScriptInterpreterLua &script_interpreter) + : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua", + ">>> ", "..> ", true, debugger.GetUseColor(), 0, + *this, nullptr), + m_script_interpreter(script_interpreter) { + llvm::cantFail(m_script_interpreter.EnterSession(debugger.GetID())); + } + + ~IOHandlerLuaInterpreter() { + llvm::cantFail(m_script_interpreter.LeaveSession()); + } + + void IOHandlerInputComplete(IOHandler &io_handler, + std::string &data) override { + if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) { + *GetOutputStreamFileSP() << llvm::toString(std::move(error)); + } + } + +private: + ScriptInterpreterLua &m_script_interpreter; +}; + +ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger) + : ScriptInterpreter(debugger, eScriptLanguageLua), + m_lua(std::make_unique<Lua>()) {} + +ScriptInterpreterLua::~ScriptInterpreterLua() {} + +bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, + CommandReturnObject *result, + const ExecuteScriptOptions &options) { + if (llvm::Error e = m_lua->Run(command)) { + result->AppendErrorWithFormatv( + "lua failed attempting to evaluate '{0}': {1}\n", command, + llvm::toString(std::move(e))); + return false; + } + return true; +} + +void ScriptInterpreterLua::ExecuteInterpreterLoop() { + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + + Debugger &debugger = m_debugger; + + // At the moment, the only time the debugger does not have an input file + // handle is when this is called directly from lua, in which case it is + // both dangerous and unnecessary (not to mention confusing) to try to embed + // a running interpreter loop inside the already running lua interpreter + // loop, so we won't do it. + + if (!debugger.GetInputFile().IsValid()) + return; + + IOHandlerSP io_handler_sp(new IOHandlerLuaInterpreter(debugger, *this)); + debugger.PushIOHandler(io_handler_sp); +} + +bool ScriptInterpreterLua::LoadScriptingModule( + const char *filename, bool init_session, lldb_private::Status &error, + StructuredData::ObjectSP *module_sp) { + + if (llvm::Error e = m_lua->LoadModule(filename)) { + error.SetErrorStringWithFormatv("lua failed to import '{0}': {1}\n", + filename, llvm::toString(std::move(e))); + return false; + } + return true; +} + +void ScriptInterpreterLua::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + lldb::eScriptLanguageLua, CreateInstance); + }); +} + +void ScriptInterpreterLua::Terminate() {} + +llvm::Error ScriptInterpreterLua::EnterSession(user_id_t debugger_id) { + if (m_session_is_active) + return llvm::Error::success(); + + const char *fmt_str = + "lldb.debugger = lldb.SBDebugger.FindDebuggerWithID({0}); " + "lldb.target = lldb.debugger:GetSelectedTarget(); " + "lldb.process = lldb.target:GetProcess(); " + "lldb.thread = lldb.process:GetSelectedThread(); " + "lldb.frame = lldb.thread:GetSelectedFrame()"; + return m_lua->Run(llvm::formatv(fmt_str, debugger_id).str()); +} + +llvm::Error ScriptInterpreterLua::LeaveSession() { + if (!m_session_is_active) + return llvm::Error::success(); + + m_session_is_active = false; + + llvm::StringRef str = "lldb.debugger = nil; " + "lldb.target = nil; " + "lldb.process = nil; " + "lldb.thread = nil; " + "lldb.frame = nil"; + return m_lua->Run(str); +} + +lldb::ScriptInterpreterSP +ScriptInterpreterLua::CreateInstance(Debugger &debugger) { + return std::make_shared<ScriptInterpreterLua>(debugger); +} + +lldb_private::ConstString ScriptInterpreterLua::GetPluginNameStatic() { + static ConstString g_name("script-lua"); + return g_name; +} + +const char *ScriptInterpreterLua::GetPluginDescriptionStatic() { + return "Lua script interpreter"; +} + +lldb_private::ConstString ScriptInterpreterLua::GetPluginName() { + return GetPluginNameStatic(); +} + +uint32_t ScriptInterpreterLua::GetPluginVersion() { return 1; } + +Lua &ScriptInterpreterLua::GetLua() { return *m_lua; } diff --git a/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h new file mode 100644 index 000000000000..4e922151385b --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h @@ -0,0 +1,61 @@ +//===-- ScriptInterpreterLua.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ScriptInterpreterLua_h_ +#define liblldb_ScriptInterpreterLua_h_ + +#include "lldb/Interpreter/ScriptInterpreter.h" + +namespace lldb_private { +class Lua; +class ScriptInterpreterLua : public ScriptInterpreter { +public: + ScriptInterpreterLua(Debugger &debugger); + + ~ScriptInterpreterLua() override; + + bool ExecuteOneLine( + llvm::StringRef command, CommandReturnObject *result, + const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; + + void ExecuteInterpreterLoop() override; + + virtual bool + LoadScriptingModule(const char *filename, bool init_session, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp = nullptr) override; + + // Static Functions + static void Initialize(); + + static void Terminate(); + + static lldb::ScriptInterpreterSP CreateInstance(Debugger &debugger); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + // PluginInterface protocol + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + Lua &GetLua(); + + llvm::Error EnterSession(lldb::user_id_t debugger_id); + llvm::Error LeaveSession(); + +private: + std::unique_ptr<Lua> m_lua; + bool m_session_is_active = false; +}; + +} // namespace lldb_private + +#endif // liblldb_ScriptInterpreterLua_h_ diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 70d93424fdec..e5a67653e334 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -6,11 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifdef LLDB_DISABLE_PYTHON +#include "lldb/Host/Config.h" -// Python is disabled in this build - -#else +#if LLDB_ENABLE_PYTHON #include "PythonDataObjects.h" #include "ScriptInterpreterPython.h" @@ -802,29 +800,11 @@ bool PythonCallable::Check(PyObject *py_obj) { return PyCallable_Check(py_obj); } -PythonCallable::ArgInfo PythonCallable::GetNumInitArguments() const { - auto arginfo = GetInitArgInfo(); - if (!arginfo) { - llvm::consumeError(arginfo.takeError()); - return ArgInfo{}; - } - return arginfo.get(); -} - -Expected<PythonCallable::ArgInfo> PythonCallable::GetInitArgInfo() const { - if (!IsValid()) - return nullDeref(); - auto init = As<PythonCallable>(GetAttribute("__init__")); - if (!init) - return init.takeError(); - return init.get().GetArgInfo(); -} - #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 static const char get_arg_info_script[] = R"( from inspect import signature, Parameter, ismethod from collections import namedtuple -ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs', 'is_bound_method']) +ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs']) def main(f): count = 0 varargs = False @@ -840,7 +820,7 @@ def main(f): pass else: raise Exception(f'unknown parameter kind: {kind}') - return ArgInfo(count, varargs, ismethod(f)) + return ArgInfo(count, varargs) )"; #endif @@ -856,21 +836,27 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const { Expected<PythonObject> pyarginfo = get_arg_info(*this); if (!pyarginfo) return pyarginfo.takeError(); - result.count = cantFail(As<long long>(pyarginfo.get().GetAttribute("count"))); - result.has_varargs = + long long count = + cantFail(As<long long>(pyarginfo.get().GetAttribute("count"))); + bool has_varargs = cantFail(As<bool>(pyarginfo.get().GetAttribute("has_varargs"))); - bool is_method = - cantFail(As<bool>(pyarginfo.get().GetAttribute("is_bound_method"))); - result.max_positional_args = - result.has_varargs ? ArgInfo::UNBOUNDED : result.count; - - // FIXME emulate old broken behavior - if (is_method) - result.count++; + result.max_positional_args = has_varargs ? ArgInfo::UNBOUNDED : count; #else + PyObject *py_func_obj; bool is_bound_method = false; - PyObject *py_func_obj = m_py_obj; + bool is_class = false; + + if (PyType_Check(m_py_obj) || PyClass_Check(m_py_obj)) { + auto init = GetAttribute("__init__"); + if (!init) + return init.takeError(); + py_func_obj = init.get().get(); + is_class = true; + } else { + py_func_obj = m_py_obj; + } + if (PyMethod_Check(py_func_obj)) { py_func_obj = PyMethod_GET_FUNCTION(py_func_obj); PythonObject im_self = GetAttributeValue("im_self"); @@ -899,11 +885,11 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const { if (!code) return result; - result.count = code->co_argcount; - result.has_varargs = !!(code->co_flags & CO_VARARGS); - result.max_positional_args = result.has_varargs - ? ArgInfo::UNBOUNDED - : (result.count - (int)is_bound_method); + auto count = code->co_argcount; + bool has_varargs = !!(code->co_flags & CO_VARARGS); + result.max_positional_args = + has_varargs ? ArgInfo::UNBOUNDED + : (count - (int)is_bound_method) - (int)is_class; #endif @@ -913,15 +899,6 @@ Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const { constexpr unsigned PythonCallable::ArgInfo::UNBOUNDED; // FIXME delete after c++17 -PythonCallable::ArgInfo PythonCallable::GetNumArguments() const { - auto arginfo = GetArgInfo(); - if (!arginfo) { - llvm::consumeError(arginfo.takeError()); - return ArgInfo{}; - } - return arginfo.get(); -} - PythonObject PythonCallable::operator()() { return PythonObject(PyRefType::Owned, PyObject_CallObject(m_py_obj, nullptr)); } @@ -1385,11 +1362,13 @@ llvm::Expected<FileSP> PythonFile::ConvertToFile(bool borrowed) { if (!options) return options.takeError(); - // LLDB and python will not share I/O buffers. We should probably - // flush the python buffers now. - auto r = CallMethod("flush"); - if (!r) - return r.takeError(); + if (options.get() & File::eOpenOptionWrite) { + // LLDB and python will not share I/O buffers. We should probably + // flush the python buffers now. + auto r = CallMethod("flush"); + if (!r) + return r.takeError(); + } FileSP file_sp; if (borrowed) { @@ -1498,14 +1477,23 @@ Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) { PyObject *file_obj; #if PY_MAJOR_VERSION >= 3 file_obj = PyFile_FromFd(file.GetDescriptor(), nullptr, mode, -1, nullptr, - "ignore", nullptr, 0); + "ignore", nullptr, /*closefd=*/0); #else - // Read through the Python source, doesn't seem to modify these strings - char *cmode = const_cast<char *>(mode); - // We pass ::flush instead of ::fclose here so we borrow the FILE* -- - // the lldb_private::File still owns it. - file_obj = - PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, ::fflush); + // I'd like to pass ::fflush here if the file is writable, so that + // when the python side destructs the file object it will be flushed. + // However, this would be dangerous. It can cause fflush to be called + // after fclose if the python program keeps a reference to the file after + // the original lldb_private::File has been destructed. + // + // It's all well and good to ask a python program not to use a closed file + // but asking a python program to make sure objects get released in a + // particular order is not safe. + // + // The tradeoff here is that if a python 2 program wants to make sure this + // file gets flushed, they'll have to do it explicitly or wait untill the + // original lldb File itself gets flushed. + file_obj = PyFile_FromFile(file.GetStream(), py2_const_cast(""), + py2_const_cast(mode), [](FILE *) { return 0; }); #endif if (!file_obj) diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 373d3212697d..b75045b239a8 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -48,7 +48,9 @@ #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONDATAOBJECTS_H -#ifndef LLDB_DISABLE_PYTHON +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON // LLDB Python header must be included first #include "lldb-python.h" @@ -130,7 +132,7 @@ template <typename T> T Take(PyObject *obj) { assert(!PyErr_Occurred()); T thing(PyRefType::Owned, obj); assert(thing.IsValid()); - return std::move(thing); + return thing; } // Retain a reference you have borrowed, and turn it into @@ -148,7 +150,7 @@ template <typename T> T Retain(PyObject *obj) { assert(!PyErr_Occurred()); T thing(PyRefType::Borrowed, obj); assert(thing.IsValid()); - return std::move(thing); + return thing; } // This class can be used like a utility function to convert from @@ -189,6 +191,14 @@ inline llvm::Error keyError() { "key not in dict"); } +#if PY_MAJOR_VERSION < 3 +// The python 2 API declares some arguments as char* that should +// be const char *, but it doesn't actually modify them. +inline char *py2_const_cast(const char *s) { return const_cast<char *>(s); } +#else +inline const char *py2_const_cast(const char *s) { return s; } +#endif + enum class PyInitialValue { Invalid, Empty }; template <typename T, typename Enable = void> struct PythonFormat; @@ -309,16 +319,6 @@ public: StructuredData::ObjectSP CreateStructuredObject() const; -protected: - -#if PY_MAJOR_VERSION < 3 - // The python 2 API declares some arguments as char* that should - // be const char *, but it doesn't actually modify them. - static char *py2_const_cast(const char *s) { return const_cast<char *>(s); } -#else - static const char *py2_const_cast(const char *s) { return s; } -#endif - public: template <typename... T> llvm::Expected<PythonObject> CallMethod(const char *name, @@ -621,30 +621,12 @@ public: * function and can accept an arbitrary number */ unsigned max_positional_args; static constexpr unsigned UNBOUNDED = UINT_MAX; // FIXME c++17 inline - /* the number of positional arguments, including optional ones, - * and excluding varargs. If this is a bound method, then the - * count will still include a +1 for self. - * - * FIXME. That's crazy. This should be replaced with - * an accurate min and max for positional args. - */ - int count; - /* does the callable have positional varargs? */ - bool has_varargs : 1; // FIXME delete this }; static bool Check(PyObject *py_obj); llvm::Expected<ArgInfo> GetArgInfo() const; - llvm::Expected<ArgInfo> GetInitArgInfo() const; - - ArgInfo GetNumArguments() const; // DEPRECATED - - // If the callable is a Py_Class, then find the number of arguments - // of the __init__ method. - ArgInfo GetNumInitArguments() const; // DEPRECATED - PythonObject operator()(); PythonObject operator()(std::initializer_list<PyObject *> args); diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp new file mode 100644 index 000000000000..5f6429f5cd0e --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp @@ -0,0 +1,88 @@ +#include "PythonReadline.h" + +#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE + +#include <stdio.h> + +#include <editline/readline.h> + +// Simple implementation of the Python readline module using libedit. +// In the event that libedit is excluded from the build, this turns +// back into a null implementation that blocks the module from pulling +// in the GNU readline shared lib, which causes linkage confusion when +// both readline and libedit's readline compatibility symbols collide. +// +// Currently it only installs a PyOS_ReadlineFunctionPointer, without +// implementing any of the readline module methods. This is meant to +// work around LLVM pr18841 to avoid seg faults in the stock Python +// readline.so linked against GNU readline. +// +// Bug on the cpython side: https://bugs.python.org/issue38634 + +PyDoc_STRVAR(moduleDocumentation, + "Simple readline module implementation based on libedit."); + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef readline_module = { + PyModuleDef_HEAD_INIT, // m_base + "lldb_editline", // m_name + moduleDocumentation, // m_doc + -1, // m_size + nullptr, // m_methods + nullptr, // m_reload + nullptr, // m_traverse + nullptr, // m_clear + nullptr, // m_free +}; +#else +static struct PyMethodDef moduleMethods[] = {{nullptr, nullptr, 0, nullptr}}; +#endif + +static char * +#if PY_MAJOR_VERSION >= 3 +simple_readline(FILE *stdin, FILE *stdout, const char *prompt) +#else +simple_readline(FILE *stdin, FILE *stdout, char *prompt) +#endif +{ + rl_instream = stdin; + rl_outstream = stdout; + char *line = readline(prompt); + if (!line) { +#if PY_MAJOR_VERSION >= 3 + char *ret = (char *)PyMem_RawMalloc(1); +#else + char *ret = (char *)PyMem_Malloc(1); +#endif + if (ret != NULL) + *ret = '\0'; + return ret; + } + if (*line) + add_history(line); + int n = strlen(line); +#if PY_MAJOR_VERSION >= 3 + char *ret = (char *)PyMem_RawMalloc(n + 2); +#else + char *ret = (char *)PyMem_Malloc(n + 2); +#endif + if (ret) { + memcpy(ret, line, n); + free(line); + ret[n] = '\n'; + ret[n + 1] = '\0'; + } + return ret; +} + +PyMODINIT_FUNC initlldb_readline(void) { + PyOS_ReadlineFunctionPointer = simple_readline; + +#if PY_MAJOR_VERSION >= 3 + return PyModule_Create(&readline_module); +#else + Py_InitModule4("readline", moduleMethods, moduleDocumentation, + static_cast<PyObject *>(NULL), PYTHON_API_VERSION); +#endif +} +#endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h new file mode 100644 index 000000000000..c75219eb1a4f --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h @@ -0,0 +1,28 @@ +//===-- PythonReadline.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_LIBEDIT && defined(__linux__) +// NOTE: Since Python may define some pre-processor definitions which affect the +// standard headers on some systems, you must include Python.h before any +// standard headers are included. +#include "Python.h" + +// no need to hack into Python's readline module if libedit isn't used. +// +#define LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE 1 + +PyMODINIT_FUNC initlldb_readline(void); + +#endif + +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 3eee52184142..06e0d5bfa63f 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -6,16 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifdef LLDB_DISABLE_PYTHON +#include "lldb/Host/Config.h" -// Python is disabled in this build - -#else +#if LLDB_ENABLE_PYTHON // LLDB Python header must be included first #include "lldb-python.h" #include "PythonDataObjects.h" +#include "PythonReadline.h" #include "ScriptInterpreterPythonImpl.h" #include "lldb/API/SBFrame.h" @@ -72,10 +71,28 @@ extern "C" void init_lldb(void); // These prototypes are the Pythonic implementations of the required callbacks. // Although these are scripting-language specific, their definition depends on // the public API. -extern "C" bool LLDBSwigPythonBreakpointCallbackFunction( + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" + +// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has +// C-linkage specified, but returns UDT 'llvm::Expected<bool>' which is +// incompatible with C +#if _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4190) +#endif + +extern "C" llvm::Expected<bool> LLDBSwigPythonBreakpointCallbackFunction( const char *python_function_name, const char *session_dictionary_name, const lldb::StackFrameSP &sb_frame, - const lldb::BreakpointLocationSP &sb_bp_loc); + const lldb::BreakpointLocationSP &sb_bp_loc, StructuredDataImpl *args_impl); + +#if _MSC_VER +#pragma warning (pop) +#endif + +#pragma clang diagnostic pop extern "C" bool LLDBSwigPythonWatchpointCallbackFunction( const char *python_function_name, const char *session_dictionary_name, @@ -211,6 +228,22 @@ public: InitializePythonHome(); +#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE + // Python's readline is incompatible with libedit being linked into lldb. + // Provide a patched version local to the embedded interpreter. + bool ReadlinePatched = false; + for (auto *p = PyImport_Inittab; p->name != NULL; p++) { + if (strcmp(p->name, "readline") == 0) { + p->initfunc = initlldb_readline; + break; + } + } + if (!ReadlinePatched) { + PyImport_AppendInittab("readline", initlldb_readline); + ReadlinePatched = true; + } +#endif + // Register _lldb as a built-in module. PyImport_AppendInittab("_lldb", LLDBSwigPyInit); @@ -552,8 +585,10 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, break; data_up->user_source.SplitIntoLines(data); + StructuredData::ObjectSP empty_args_sp; if (GenerateBreakpointCommandCallbackData(data_up->user_source, - data_up->script_source) + data_up->script_source, + false) .Success()) { auto baton_sp = std::make_shared<BreakpointOptions::CommandBaton>( std::move(data_up)); @@ -779,6 +814,32 @@ PythonDictionary &ScriptInterpreterPythonImpl::GetSysModuleDictionary() { return m_sys_module_dict; } +llvm::Expected<unsigned> +ScriptInterpreterPythonImpl::GetMaxPositionalArgumentsForCallable( + const llvm::StringRef &callable_name) { + if (callable_name.empty()) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "called with empty callable name."); + } + Locker py_lock(this, Locker::AcquireLock | + Locker::InitSession | + Locker::NoSTDIN); + auto dict = PythonModule::MainModule() + .ResolveName<PythonDictionary>(m_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( + callable_name, dict); + if (!pfunc.IsAllocated()) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "can't find callable: %s", callable_name.str().c_str()); + } + llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo(); + if (!arg_info) + return arg_info.takeError(); + return arg_info.get().max_positional_args; +} + static std::string GenerateUniqueName(const char *base_name_wanted, uint32_t &functions_counter, const void *name_token = nullptr) { @@ -1139,6 +1200,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn( return true; } } + llvm_unreachable("Fully covered switch!"); } Status ScriptInterpreterPythonImpl::ExecuteMultipleLines( @@ -1186,24 +1248,56 @@ void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback( CommandReturnObject &result) { m_active_io_handler = eIOHandlerBreakpoint; m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler( - " ", *this, true, &bp_options_vec); + " ", *this, &bp_options_vec); } void ScriptInterpreterPythonImpl::CollectDataForWatchpointCommandCallback( WatchpointOptions *wp_options, CommandReturnObject &result) { m_active_io_handler = eIOHandlerWatchpoint; m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler( - " ", *this, true, wp_options); + " ", *this, wp_options); } -void ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction( - BreakpointOptions *bp_options, const char *function_name) { +Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction( + BreakpointOptions *bp_options, const char *function_name, + StructuredData::ObjectSP extra_args_sp) { + Status error; // For now just cons up a oneliner that calls the provided function. std::string oneliner("return "); oneliner += function_name; - oneliner += "(frame, bp_loc, internal_dict)"; - m_debugger.GetScriptInterpreter()->SetBreakpointCommandCallback( - bp_options, oneliner.c_str()); + + llvm::Expected<unsigned> maybe_args = + GetMaxPositionalArgumentsForCallable(function_name); + if (!maybe_args) { + error.SetErrorStringWithFormat( + "could not get num args: %s", + llvm::toString(maybe_args.takeError()).c_str()); + return error; + } + size_t max_args = *maybe_args; + + bool uses_extra_args = false; + if (max_args >= 4) { + uses_extra_args = true; + oneliner += "(frame, bp_loc, extra_args, internal_dict)"; + } else if (max_args >= 3) { + if (extra_args_sp) { + error.SetErrorString("cannot pass extra_args to a three argument callback" + ); + return error; + } + uses_extra_args = false; + oneliner += "(frame, bp_loc, internal_dict)"; + } else { + error.SetErrorStringWithFormat("expected 3 or 4 argument " + "function, %s can only take %zu", + function_name, max_args); + return error; + } + + SetBreakpointCommandCallback(bp_options, oneliner.c_str(), extra_args_sp, + uses_extra_args); + return error; } Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( @@ -1211,7 +1305,8 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( std::unique_ptr<BreakpointOptions::CommandData> &cmd_data_up) { Status error; error = GenerateBreakpointCommandCallbackData(cmd_data_up->user_source, - cmd_data_up->script_source); + cmd_data_up->script_source, + false); if (error.Fail()) { return error; } @@ -1222,11 +1317,17 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( return error; } -// Set a Python one-liner as the callback for the breakpoint. Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( BreakpointOptions *bp_options, const char *command_body_text) { - auto data_up = std::make_unique<CommandDataPython>(); + return SetBreakpointCommandCallback(bp_options, command_body_text, {},false); +} +// Set a Python one-liner as the callback for the breakpoint. +Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( + BreakpointOptions *bp_options, const char *command_body_text, + StructuredData::ObjectSP extra_args_sp, + bool uses_extra_args) { + auto data_up = std::make_unique<CommandDataPython>(extra_args_sp); // Split the command_body_text into lines, and pass that to // GenerateBreakpointCommandCallbackData. That will wrap the body in an // auto-generated function, and return the function name in script_source. @@ -1234,7 +1335,8 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( data_up->user_source.SplitIntoLines(command_body_text); Status error = GenerateBreakpointCommandCallbackData(data_up->user_source, - data_up->script_source); + data_up->script_source, + uses_extra_args); if (error.Success()) { auto baton_sp = std::make_shared<BreakpointOptions::CommandBaton>(std::move(data_up)); @@ -1771,8 +1873,7 @@ StructuredData::DictionarySP ScriptInterpreterPythonImpl::OSPlugin_CreateThread( StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan( const char *class_name, StructuredDataImpl *args_data, - std::string &error_str, - lldb::ThreadPlanSP thread_plan_sp) { + std::string &error_str, lldb::ThreadPlanSP thread_plan_sp) { if (class_name == nullptr || class_name[0] == '\0') return StructuredData::ObjectSP(); @@ -1956,8 +2057,7 @@ ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, StructuredData::ObjectSP module_sp; - if (LoadScriptingModule(file_spec.GetPath().c_str(), true, true, error, - &module_sp)) + if (LoadScriptingModule(file_spec.GetPath().c_str(), true, error, &module_sp)) return module_sp; return StructuredData::ObjectSP(); @@ -2063,7 +2163,8 @@ bool ScriptInterpreterPythonImpl::GenerateTypeSynthClass( } Status ScriptInterpreterPythonImpl::GenerateBreakpointCommandCallbackData( - StringList &user_input, std::string &output) { + StringList &user_input, std::string &output, + bool has_extra_args) { static uint32_t num_created_functions = 0; user_input.RemoveBlankLines(); StreamString sstr; @@ -2075,8 +2176,12 @@ Status ScriptInterpreterPythonImpl::GenerateBreakpointCommandCallbackData( std::string auto_generated_function_name(GenerateUniqueName( "lldb_autogen_python_bp_callback_func_", num_created_functions)); - sstr.Printf("def %s (frame, bp_loc, internal_dict):", - auto_generated_function_name.c_str()); + if (has_extra_args) + sstr.Printf("def %s (frame, bp_loc, extra_args, internal_dict):", + auto_generated_function_name.c_str()); + else + sstr.Printf("def %s (frame, bp_loc, internal_dict):", + auto_generated_function_name.c_str()); error = GenerateFunction(sstr.GetData(), user_input); if (!error.Success()) @@ -2193,10 +2298,26 @@ bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction( Locker py_lock(python_interpreter, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - ret_val = LLDBSwigPythonBreakpointCallbackFunction( - python_function_name, - python_interpreter->m_dictionary_name.c_str(), stop_frame_sp, - bp_loc_sp); + Expected<bool> maybe_ret_val = + LLDBSwigPythonBreakpointCallbackFunction( + python_function_name, + python_interpreter->m_dictionary_name.c_str(), stop_frame_sp, + bp_loc_sp, bp_option_data->m_extra_args_up.get()); + + if (!maybe_ret_val) { + + llvm::handleAllErrors( + maybe_ret_val.takeError(), + [&](PythonException &E) { + debugger.GetErrorStream() << E.ReadBacktrace(); + }, + [&](const llvm::ErrorInfoBase &E) { + debugger.GetErrorStream() << E.message(); + }); + + } else { + ret_val = maybe_ret_val.get(); + } } return ret_val; } @@ -2615,8 +2736,8 @@ uint64_t replace_all(std::string &str, const std::string &oldStr, } bool ScriptInterpreterPythonImpl::LoadScriptingModule( - const char *pathname, bool can_reload, bool init_session, - lldb_private::Status &error, StructuredData::ObjectSP *module_sp) { + const char *pathname, bool init_session, lldb_private::Status &error, + StructuredData::ObjectSP *module_sp) { if (!pathname || !pathname[0]) { error.SetErrorString("invalid pathname"); return false; @@ -2716,11 +2837,6 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( bool was_imported = (was_imported_globally || was_imported_locally); - if (was_imported && !can_reload) { - error.SetErrorString("module already imported"); - return false; - } - // now actually do the import command_stream.Clear(); @@ -3171,4 +3287,4 @@ void ScriptInterpreterPythonImpl::AddToSysPath(AddLocation location, // // void ScriptInterpreterPythonImpl::Terminate() { Py_Finalize (); } -#endif // LLDB_DISABLE_PYTHON +#endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h index 33ae308041b2..e59fedbd0971 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -9,14 +9,13 @@ #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H -#ifdef LLDB_DISABLE_PYTHON +#include "lldb/Host/Config.h" -// Python is disabled in this build - -#else +#if LLDB_ENABLE_PYTHON #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/IOHandler.h" +#include "lldb/Core/StructuredDataImpl.h" #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/lldb-private.h" @@ -34,6 +33,13 @@ public: CommandDataPython() : BreakpointOptions::CommandData() { interpreter = lldb::eScriptLanguagePython; } + CommandDataPython(StructuredData::ObjectSP extra_args_sp) : + BreakpointOptions::CommandData(), + m_extra_args_up(new StructuredDataImpl()) { + interpreter = lldb::eScriptLanguagePython; + m_extra_args_up->SetObjectSP(extra_args_sp); + } + lldb::StructuredDataImplUP m_extra_args_up; }; ScriptInterpreterPython(Debugger &debugger) @@ -52,5 +58,5 @@ protected: }; } // namespace lldb_private -#endif // LLDB_DISABLE_PYTHON +#endif // LLDB_ENABLE_PYTHON #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHON_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 929567e579d8..1fa198b07e54 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -6,11 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifdef LLDB_DISABLE_PYTHON +#include "lldb/Host/Config.h" -// Python is disabled in this build - -#else +#if LLDB_ENABLE_PYTHON #include "lldb-python.h" @@ -179,8 +177,10 @@ public: Status GenerateFunction(const char *signature, const StringList &input) override; - Status GenerateBreakpointCommandCallbackData(StringList &input, - std::string &output) override; + Status GenerateBreakpointCommandCallbackData( + StringList &input, + std::string &output, + bool has_extra_args) override; bool GenerateWatchpointCommandCallbackData(StringList &input, std::string &output) override; @@ -224,7 +224,7 @@ public: std::string &output, Status &error) override; bool - LoadScriptingModule(const char *filename, bool can_reload, bool init_session, + LoadScriptingModule(const char *filename, bool init_session, lldb_private::Status &error, StructuredData::ObjectSP *module_sp = nullptr) override; @@ -244,14 +244,21 @@ public: Status SetBreakpointCommandCallback(BreakpointOptions *bp_options, const char *callback_body) override; - void SetBreakpointCommandCallbackFunction(BreakpointOptions *bp_options, - const char *function_name) override; + Status SetBreakpointCommandCallbackFunction( + BreakpointOptions *bp_options, + const char *function_name, + StructuredData::ObjectSP extra_args_sp) override; /// This one is for deserialization: Status SetBreakpointCommandCallback( BreakpointOptions *bp_options, std::unique_ptr<BreakpointOptions::CommandData> &data_up) override; + Status SetBreakpointCommandCallback(BreakpointOptions *bp_options, + const char *command_body_text, + StructuredData::ObjectSP extra_args_sp, + bool uses_extra_args); + /// Set a one-liner as the callback for the watchpoint. void SetWatchpointCommandCallback(WatchpointOptions *wp_options, const char *oneliner) override; @@ -369,6 +376,9 @@ public: python::PythonDictionary &GetSysModuleDictionary(); + llvm::Expected<unsigned> GetMaxPositionalArgumentsForCallable( + const llvm::StringRef &callable_name) override; + bool GetEmbeddedInterpreterModuleObjects(); bool SetStdHandle(lldb::FileSP file, const char *py_name, diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h b/lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h index 884514da9924..48f27b09b95c 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/lldb-python.h @@ -9,12 +9,12 @@ #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H +#include "lldb/Host/Config.h" + // Python.h needs to be included before any system headers in order to avoid // redefinition of macros -#ifdef LLDB_DISABLE_PYTHON -// Python is disabled in this build -#else +#if LLDB_ENABLE_PYTHON #include "llvm/Support/Compiler.h" #if defined(_WIN32) // If anyone #includes Host/PosixApi.h later, it will try to typedef pid_t. We @@ -40,6 +40,6 @@ // Include python for non windows machines #include <Python.h> -#endif // LLDB_DISABLE_PYTHON +#endif #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_LLDB_PYTHON_H diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp index f84cf0c5368d..b2c4d0883341 100644 --- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -25,6 +25,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::breakpad; +char SymbolFileBreakpad::ID; + class SymbolFileBreakpad::LineIterator { public: // begin iterator for sections of given type @@ -307,8 +309,9 @@ void SymbolFileBreakpad::FindTypes( uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {} -void SymbolFileBreakpad::FindTypes(llvm::ArrayRef<CompilerContext> pattern, - LanguageSet languages, TypeMap &types) {} +void SymbolFileBreakpad::FindTypes( + llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {} void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS); @@ -728,7 +731,7 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, } if (next_addr) finish_sequence(); - data.support_files = map.translate(cu, *m_files); + data.support_files = map.translate(cu.GetPrimaryFile(), *m_files); } void SymbolFileBreakpad::ParseUnwindData() { diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h index a10138cdf92f..de271224a65d 100644 --- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -21,7 +21,18 @@ namespace lldb_private { namespace breakpad { class SymbolFileBreakpad : public SymbolFile { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + // Static Functions static void Initialize(); static void Terminate(); @@ -112,6 +123,7 @@ public: TypeMap &types) override; void FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) override; llvm::Expected<TypeSystem &> diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 636e6032b877..232063a6f339 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -22,7 +22,7 @@ #include "lldb/Core/Value.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" @@ -135,61 +135,111 @@ static bool IsClangModuleFwdDecl(const DWARFDIE &Die) { return false; } -TypeSP DWARFASTParserClang::ParseTypeFromDWO(const DWARFDIE &die, Log *log) { - ModuleSP dwo_module_sp = die.GetContainingDWOModule(); - if (!dwo_module_sp) +static DWARFDIE GetContainingClangModuleDIE(const DWARFDIE &die) { + if (die.IsValid()) { + DWARFDIE top_module_die; + // Now make sure this DIE is scoped in a DW_TAG_module tag and return true + // if so + for (DWARFDIE parent = die.GetParent(); parent.IsValid(); + parent = parent.GetParent()) { + const dw_tag_t tag = parent.Tag(); + if (tag == DW_TAG_module) + top_module_die = parent; + else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) + break; + } + + return top_module_die; + } + return DWARFDIE(); +} + +static lldb::ModuleSP GetContainingClangModule(const DWARFDIE &die) { + if (die.IsValid()) { + DWARFDIE clang_module_die = GetContainingClangModuleDIE(die); + + if (clang_module_die) { + const char *module_name = clang_module_die.GetName(); + if (module_name) + return die.GetDWARF()->GetExternalModule( + lldb_private::ConstString(module_name)); + } + } + return lldb::ModuleSP(); +} + +TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, + const DWARFDIE &die, + Log *log) { + ModuleSP clang_module_sp = GetContainingClangModule(die); + if (!clang_module_sp) return TypeSP(); - // If this type comes from a Clang module, look in the DWARF section - // of the pcm file in the module cache. Clang generates DWO skeleton - // units as breadcrumbs to find them. + // If this type comes from a Clang module, recursively look in the + // DWARF section of the .pcm file in the module cache. Clang + // generates DWO skeleton units as breadcrumbs to find them. llvm::SmallVector<CompilerContext, 4> decl_context; die.GetDeclContext(decl_context); - TypeMap dwo_types; + TypeMap pcm_types; // The type in the Clang module must have the same language as the current CU. LanguageSet languages; languages.Insert(die.GetCU()->GetLanguageType()); - dwo_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, dwo_types); - if (dwo_types.Empty()) { - if (!IsClangModuleFwdDecl(die)) - return TypeSP(); - + llvm::DenseSet<SymbolFile *> searched_symbol_files; + clang_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, + searched_symbol_files, pcm_types); + if (pcm_types.Empty()) { // Since this type is defined in one of the Clang modules imported - // by this symbol file, search all of them. + // by this symbol file, search all of them. Instead of calling + // sym_file->FindTypes(), which would return this again, go straight + // to the imported modules. auto &sym_file = die.GetCU()->GetSymbolFileDWARF(); - for (const auto &name_module : sym_file.getExternalTypeModules()) { - if (!name_module.second) - continue; - name_module.second->GetSymbolFile()->FindTypes(decl_context, - languages, dwo_types); - if (dwo_types.GetSize()) - break; - } + + // Well-formed clang modules never form cycles; guard against corrupted + // ones by inserting the current file. + searched_symbol_files.insert(&sym_file); + sym_file.ForEachExternalModule( + *sc.comp_unit, searched_symbol_files, [&](Module &module) { + module.GetSymbolFile()->FindTypes(decl_context, languages, + searched_symbol_files, pcm_types); + return pcm_types.GetSize(); + }); } - if (dwo_types.GetSize() != 1) + if (!pcm_types.GetSize()) return TypeSP(); // We found a real definition for this type in the Clang module, so lets use // it and cache the fact that we found a complete type for this die. - TypeSP dwo_type_sp = dwo_types.GetTypeAtIndex(0); - if (!dwo_type_sp) + TypeSP pcm_type_sp = pcm_types.GetTypeAtIndex(0); + if (!pcm_type_sp) return TypeSP(); - lldb_private::CompilerType dwo_type = dwo_type_sp->GetForwardCompilerType(); - + lldb_private::CompilerType pcm_type = pcm_type_sp->GetForwardCompilerType(); lldb_private::CompilerType type = - GetClangASTImporter().CopyType(m_ast, dwo_type); + GetClangASTImporter().CopyType(m_ast, pcm_type); if (!type) return TypeSP(); + // Under normal operation pcm_type is a shallow forward declaration + // that gets completed later. This is necessary to support cyclic + // data structures. If, however, pcm_type is already complete (for + // example, because it was loaded for a different target before), + // the definition needs to be imported right away, too. + // Type::ResolveClangType() effectively ignores the ResolveState + // inside type_sp and only looks at IsDefined(), so it never calls + // ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(), + // which does extra work for Objective-C classes. This would result + // in only the forward declaration to be visible. + if (pcm_type.IsDefined()) + GetClangASTImporter().RequireCompleteType(ClangUtil::GetQualType(type)); + SymbolFileDWARF *dwarf = die.GetDWARF(); TypeSP type_sp(new Type( - die.GetID(), dwarf, dwo_type_sp->GetName(), dwo_type_sp->GetByteSize(), + die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, - &dwo_type_sp->GetDeclaration(), type, Type::eResolveStateForward)); + &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward)); dwarf->GetTypeList().Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); @@ -205,7 +255,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWO(const DWARFDIE &die, Log *log) { return type_sp; } -static void CompleteExternalTagDeclType(ClangASTImporter &ast_importer, +static void CompleteExternalTagDeclType(ClangASTContext &ast, + ClangASTImporter &ast_importer, clang::DeclContext *decl_ctx, DWARFDIE die, const char *type_name_cstr) { @@ -214,7 +265,7 @@ static void CompleteExternalTagDeclType(ClangASTImporter &ast_importer, return; // If this type was not imported from an external AST, there's nothing to do. - CompilerType type = ClangASTContext::GetTypeForDecl(tag_decl_ctx); + CompilerType type = ast.GetTypeForDecl(tag_decl_ctx); if (!type || !ast_importer.CanImport(type)) return; @@ -340,6 +391,10 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { is_complete_objc_class = form_value.Signed(); break; + case DW_AT_APPLE_objc_direct: + is_objc_direct_call = true; + break; + case DW_AT_APPLE_runtime_class: class_language = (LanguageType)form_value.Signed(); break; @@ -347,6 +402,9 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { case DW_AT_GNU_vector: is_vector = form_value.Boolean(); break; + case DW_AT_export_symbols: + exports_symbols = form_value.Boolean(); + break; } } } @@ -377,13 +435,12 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x, decl_ctx = %p (die " - "0x%8.8x)) %s name = '%s')", + "DWARFASTParserClang::ParseTypeFromDWARF " + "(die = 0x%8.8x, decl_ctx = %p (die 0x%8.8x)) %s name = '%s')", die.GetOffset(), static_cast<void *>(context), context_die.GetOffset(), die.GetTagAsCString(), die.GetName()); } - Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); if (type_ptr == DIE_IS_BEING_PARSED) return nullptr; @@ -411,13 +468,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, const dw_tag_t tag = die.Tag(); - Type::ResolveState resolve_state = Type::eResolveStateUnresolved; - - Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; - CompilerType clang_type; - TypeSP type_sp; - LanguageType cu_language = die.GetLanguage(); + switch (tag) { case DW_TAG_typedef: case DW_TAG_base_type: @@ -427,848 +479,895 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, case DW_TAG_const_type: case DW_TAG_restrict_type: case DW_TAG_volatile_type: + case DW_TAG_atomic_type: case DW_TAG_unspecified_type: { - if (tag == DW_TAG_typedef && attrs.type.IsValid()) { - // Try to parse a typedef from the DWO file first as modules can - // contain typedef'ed structures that have no names like: - // - // typedef struct { int a; } Foo; - // - // In this case we will have a structure with no name and a typedef - // named "Foo" that points to this unnamed structure. The name in the - // typedef is the only identifier for the struct, so always try to - // get typedefs from DWO files if possible. - // - // The type_sp returned will be empty if the typedef doesn't exist in - // a DWO file, so it is cheap to call this function just to check. - // - // If we don't do this we end up creating a TypeSP that says this is - // a typedef to type 0x123 (the DW_AT_type value would be 0x123 in - // the DW_TAG_typedef), and this is the unnamed structure type. We - // will have a hard time tracking down an unnammed structure type in - // the module DWO file, so we make sure we don't get into this - // situation by always resolving typedefs from the DWO file. - const DWARFDIE encoding_die = attrs.type.Reference(); - - // First make sure that the die that this is typedef'ed to _is_ just - // a declaration (DW_AT_declaration == 1), not a full definition - // since template types can't be represented in modules since only - // concrete instances of templates are ever emitted and modules won't - // contain those - if (encoding_die && - encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { - type_sp = ParseTypeFromDWO(die, log); - if (type_sp) - return type_sp; - } - } + type_sp = ParseTypeModifier(sc, die, attrs); + break; + } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", - die.GetID(), DW_TAG_value_to_name(tag), type_name_cstr, - encoding_uid.Reference()); + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: { + type_sp = ParseStructureLikeDIE(sc, die, attrs); + break; + } - switch (tag) { - default: - break; + case DW_TAG_enumeration_type: { + type_sp = ParseEnum(sc, die, attrs); + break; + } - case DW_TAG_unspecified_type: - if (attrs.name == "nullptr_t" || attrs.name == "decltype(nullptr)") { - resolve_state = Type::eResolveStateFull; - clang_type = m_ast.GetBasicType(eBasicTypeNullPtr); - break; - } - // Fall through to base type below in case we can handle the type - // there... - LLVM_FALLTHROUGH; - - case DW_TAG_base_type: - resolve_state = Type::eResolveStateFull; - clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( - attrs.name.GetCString(), attrs.encoding, - attrs.byte_size.getValueOr(0) * 8); - break; + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: { + type_sp = ParseSubroutine(die, attrs); + break; + } + case DW_TAG_array_type: { + type_sp = ParseArrayType(die, attrs); + break; + } + case DW_TAG_ptr_to_member_type: { + type_sp = ParsePointerToMemberType(die, attrs); + break; + } + default: + dwarf->GetObjectFile()->GetModule()->ReportError( + "{0x%8.8x}: unhandled type tag 0x%4.4x (%s), please file a bug and " + "attach the file at the start of this error message", + die.GetOffset(), tag, DW_TAG_value_to_name(tag)); + break; + } - case DW_TAG_pointer_type: - encoding_data_type = Type::eEncodingIsPointerUID; - break; - case DW_TAG_reference_type: - encoding_data_type = Type::eEncodingIsLValueReferenceUID; - break; - case DW_TAG_rvalue_reference_type: - encoding_data_type = Type::eEncodingIsRValueReferenceUID; - break; - case DW_TAG_typedef: - encoding_data_type = Type::eEncodingIsTypedefUID; - break; - case DW_TAG_const_type: - encoding_data_type = Type::eEncodingIsConstUID; - break; - case DW_TAG_restrict_type: - encoding_data_type = Type::eEncodingIsRestrictUID; - break; - case DW_TAG_volatile_type: - encoding_data_type = Type::eEncodingIsVolatileUID; + // TODO: We should consider making the switch above exhaustive to simplify + // control flow in ParseTypeFromDWARF. Then, we could simply replace this + // return statement with a call to llvm_unreachable. + return UpdateSymbolContextScopeForType(sc, die, type_sp); +} + +lldb::TypeSP +DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, + const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS)); + SymbolFileDWARF *dwarf = die.GetDWARF(); + const dw_tag_t tag = die.Tag(); + LanguageType cu_language = die.GetLanguage(); + Type::ResolveState resolve_state = Type::ResolveState::Unresolved; + Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; + TypeSP type_sp; + CompilerType clang_type; + + if (tag == DW_TAG_typedef && attrs.type.IsValid()) { + // Try to parse a typedef from the (DWARF embedded in the) Clang + // module file first as modules can contain typedef'ed + // structures that have no names like: + // + // typedef struct { int a; } Foo; + // + // In this case we will have a structure with no name and a + // typedef named "Foo" that points to this unnamed + // structure. The name in the typedef is the only identifier for + // the struct, so always try to get typedefs from Clang modules + // if possible. + // + // The type_sp returned will be empty if the typedef doesn't + // exist in a module file, so it is cheap to call this function + // just to check. + // + // If we don't do this we end up creating a TypeSP that says + // this is a typedef to type 0x123 (the DW_AT_type value would + // be 0x123 in the DW_TAG_typedef), and this is the unnamed + // structure type. We will have a hard time tracking down an + // unnammed structure type in the module debug info, so we make + // sure we don't get into this situation by always resolving + // typedefs from the module. + const DWARFDIE encoding_die = attrs.type.Reference(); + + // First make sure that the die that this is typedef'ed to _is_ + // just a declaration (DW_AT_declaration == 1), not a full + // definition since template types can't be represented in + // modules since only concrete instances of templates are ever + // emitted and modules won't contain those + if (encoding_die && + encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { + type_sp = ParseTypeFromClangModule(sc, die, log); + if (type_sp) + return type_sp; + } + } + + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr, + encoding_uid.Reference()); + + switch (tag) { + default: + break; + + case DW_TAG_unspecified_type: + if (attrs.name == "nullptr_t" || attrs.name == "decltype(nullptr)") { + resolve_state = Type::ResolveState::Full; + clang_type = m_ast.GetBasicType(eBasicTypeNullPtr); break; } + // Fall through to base type below in case we can handle the type + // there... + LLVM_FALLTHROUGH; - if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || - encoding_data_type == Type::eEncodingIsTypedefUID)) { - if (tag == DW_TAG_pointer_type) { - DWARFDIE target_die = die.GetReferencedDIE(DW_AT_type); - - if (target_die.GetAttributeValueAsUnsigned(DW_AT_APPLE_block, 0)) { - // Blocks have a __FuncPtr inside them which is a pointer to a - // function of the proper type. - - for (DWARFDIE child_die = target_die.GetFirstChild(); - child_die.IsValid(); child_die = child_die.GetSibling()) { - if (!strcmp(child_die.GetAttributeValueAsString(DW_AT_name, ""), - "__FuncPtr")) { - DWARFDIE function_pointer_type = - child_die.GetReferencedDIE(DW_AT_type); - - if (function_pointer_type) { - DWARFDIE function_type = - function_pointer_type.GetReferencedDIE(DW_AT_type); - - bool function_type_is_new_pointer; - TypeSP lldb_function_type_sp = ParseTypeFromDWARF( - sc, function_type, &function_type_is_new_pointer); - - if (lldb_function_type_sp) { - clang_type = m_ast.CreateBlockPointerType( - lldb_function_type_sp->GetForwardCompilerType()); - encoding_data_type = Type::eEncodingIsUID; - attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; - } - } + case DW_TAG_base_type: + resolve_state = Type::ResolveState::Full; + clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( + attrs.name.GetStringRef(), attrs.encoding, + attrs.byte_size.getValueOr(0) * 8); + break; - break; + case DW_TAG_pointer_type: + encoding_data_type = Type::eEncodingIsPointerUID; + break; + case DW_TAG_reference_type: + encoding_data_type = Type::eEncodingIsLValueReferenceUID; + break; + case DW_TAG_rvalue_reference_type: + encoding_data_type = Type::eEncodingIsRValueReferenceUID; + break; + case DW_TAG_typedef: + encoding_data_type = Type::eEncodingIsTypedefUID; + break; + case DW_TAG_const_type: + encoding_data_type = Type::eEncodingIsConstUID; + break; + case DW_TAG_restrict_type: + encoding_data_type = Type::eEncodingIsRestrictUID; + break; + case DW_TAG_volatile_type: + encoding_data_type = Type::eEncodingIsVolatileUID; + break; + case DW_TAG_atomic_type: + encoding_data_type = Type::eEncodingIsAtomicUID; + break; + } + + if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || + encoding_data_type == Type::eEncodingIsTypedefUID)) { + if (tag == DW_TAG_pointer_type) { + DWARFDIE target_die = die.GetReferencedDIE(DW_AT_type); + + if (target_die.GetAttributeValueAsUnsigned(DW_AT_APPLE_block, 0)) { + // Blocks have a __FuncPtr inside them which is a pointer to a + // function of the proper type. + + for (DWARFDIE child_die = target_die.GetFirstChild(); + child_die.IsValid(); child_die = child_die.GetSibling()) { + if (!strcmp(child_die.GetAttributeValueAsString(DW_AT_name, ""), + "__FuncPtr")) { + DWARFDIE function_pointer_type = + child_die.GetReferencedDIE(DW_AT_type); + + if (function_pointer_type) { + DWARFDIE function_type = + function_pointer_type.GetReferencedDIE(DW_AT_type); + + bool function_type_is_new_pointer; + TypeSP lldb_function_type_sp = ParseTypeFromDWARF( + sc, function_type, &function_type_is_new_pointer); + + if (lldb_function_type_sp) { + clang_type = m_ast.CreateBlockPointerType( + lldb_function_type_sp->GetForwardCompilerType()); + encoding_data_type = Type::eEncodingIsUID; + attrs.type.Clear(); + resolve_state = Type::ResolveState::Full; + } } + + break; } } } + } - if (cu_language == eLanguageTypeObjC || - cu_language == eLanguageTypeObjC_plus_plus) { - if (attrs.name) { - static ConstString g_objc_type_name_id("id"); - static ConstString g_objc_type_name_Class("Class"); - static ConstString g_objc_type_name_selector("SEL"); + if (cu_language == eLanguageTypeObjC || + cu_language == eLanguageTypeObjC_plus_plus) { + if (attrs.name) { + if (attrs.name == "id") { + if (log) + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " + "is Objective-C 'id' built-in type.", + die.GetOffset(), die.GetTagAsCString(), die.GetName()); + clang_type = m_ast.GetBasicType(eBasicTypeObjCID); + encoding_data_type = Type::eEncodingIsUID; + attrs.type.Clear(); + resolve_state = Type::ResolveState::Full; + } else if (attrs.name == "Class") { + if (log) + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " + "is Objective-C 'Class' built-in type.", + die.GetOffset(), die.GetTagAsCString(), die.GetName()); + clang_type = m_ast.GetBasicType(eBasicTypeObjCClass); + encoding_data_type = Type::eEncodingIsUID; + attrs.type.Clear(); + resolve_state = Type::ResolveState::Full; + } else if (attrs.name == "SEL") { + if (log) + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " + "is Objective-C 'selector' built-in type.", + die.GetOffset(), die.GetTagAsCString(), die.GetName()); + clang_type = m_ast.GetBasicType(eBasicTypeObjCSel); + encoding_data_type = Type::eEncodingIsUID; + attrs.type.Clear(); + resolve_state = Type::ResolveState::Full; + } + } else if (encoding_data_type == Type::eEncodingIsPointerUID && + attrs.type.IsValid()) { + // Clang sometimes erroneously emits id as objc_object*. In that + // case we fix up the type to "id". - if (attrs.name == g_objc_type_name_id) { - if (log) - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective-C 'id' built-in type.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); - clang_type = m_ast.GetBasicType(eBasicTypeObjCID); - encoding_data_type = Type::eEncodingIsUID; - attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; + const DWARFDIE encoding_die = attrs.type.Reference(); - } else if (attrs.name == g_objc_type_name_Class) { + if (encoding_die && encoding_die.Tag() == DW_TAG_structure_type) { + llvm::StringRef struct_name = encoding_die.GetName(); + if (struct_name == "objc_object") { if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective-C 'Class' built-in type.", + "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s " + "'%s' is 'objc_object*', which we overrode to " + "'id'.", die.GetOffset(), die.GetTagAsCString(), die.GetName()); - clang_type = m_ast.GetBasicType(eBasicTypeObjCClass); - encoding_data_type = Type::eEncodingIsUID; - attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; - } else if (attrs.name == g_objc_type_name_selector) { - if (log) - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective-C 'selector' built-in type.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); - clang_type = m_ast.GetBasicType(eBasicTypeObjCSel); + clang_type = m_ast.GetBasicType(eBasicTypeObjCID); encoding_data_type = Type::eEncodingIsUID; attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; - } - } else if (encoding_data_type == Type::eEncodingIsPointerUID && - attrs.type.IsValid()) { - // Clang sometimes erroneously emits id as objc_object*. In that - // case we fix up the type to "id". - - const DWARFDIE encoding_die = attrs.type.Reference(); - - if (encoding_die && encoding_die.Tag() == DW_TAG_structure_type) { - if (const char *struct_name = encoding_die.GetName()) { - if (!strcmp(struct_name, "objc_object")) { - if (log) - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s " - "'%s' is 'objc_object*', which we overrode to " - "'id'.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); - clang_type = m_ast.GetBasicType(eBasicTypeObjCID); - encoding_data_type = Type::eEncodingIsUID; - attrs.type.Clear(); - resolve_state = Type::eResolveStateFull; - } - } + resolve_state = Type::ResolveState::Full; } } } } - - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, - dwarf->GetUID(attrs.type.Reference()), encoding_data_type, &attrs.decl, - clang_type, resolve_state); - - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - } break; - - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_class_type: { - assert((!type_sp && !clang_type) && - "Did not expect partially computed structure-like type"); - TypeSP struct_like_type_sp = ParseStructureLikeDIE(die, attrs); - return UpdateSymbolContextScopeForType(sc, die, struct_like_type_sp); } - case DW_TAG_enumeration_type: { - if (attrs.is_forward_declaration) { - type_sp = ParseTypeFromDWO(die, log); - if (type_sp) - return type_sp; + type_sp = std::make_shared<Type>( + die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, + dwarf->GetUID(attrs.type.Reference()), encoding_data_type, &attrs.decl, + clang_type, resolve_state); - DWARFDeclContext die_decl_ctx; - die.GetDWARFDeclContext(die_decl_ctx); + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + return type_sp; +} - type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx); +TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, + const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS)); + SymbolFileDWARF *dwarf = die.GetDWARF(); + const dw_tag_t tag = die.Tag(); + TypeSP type_sp; - if (!type_sp) { - SymbolFileDWARFDebugMap *debug_map_symfile = - dwarf->GetDebugMapSymfile(); - if (debug_map_symfile) { - // We weren't able to find a full declaration in this DWARF, - // see if we have a declaration anywhere else... - type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext( - die_decl_ctx); - } - } + if (attrs.is_forward_declaration) { + type_sp = ParseTypeFromClangModule(sc, die, log); + if (type_sp) + return type_sp; - if (type_sp) { - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a " - "forward declaration, complete type is 0x%8.8" PRIx64, - static_cast<void *>(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString(), - type_sp->GetID()); - } + DWARFDeclContext die_decl_ctx; + die.GetDWARFDeclContext(die_decl_ctx); - // We found a real definition for this type elsewhere so lets use - // it and cache the fact that we found a complete type for this - // die - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - clang::DeclContext *defn_decl_ctx = - GetCachedClangDeclContextForDIE(dwarf->GetDIE(type_sp->GetID())); - if (defn_decl_ctx) - LinkDeclContextToDIE(defn_decl_ctx, die); - return type_sp; + type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die_decl_ctx); + + if (!type_sp) { + SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); + if (debug_map_symfile) { + // We weren't able to find a full declaration in this DWARF, + // see if we have a declaration anywhere else... + type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext( + die_decl_ctx); } } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); - - CompilerType enumerator_clang_type; - clang_type.SetCompilerType( - &m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); - if (!clang_type) { - if (attrs.type.IsValid()) { - Type *enumerator_type = - dwarf->ResolveTypeUID(attrs.type.Reference(), true); - if (enumerator_type) - enumerator_clang_type = enumerator_type->GetFullCompilerType(); - } - if (!enumerator_clang_type) { - if (attrs.byte_size) { - enumerator_clang_type = - m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( - NULL, DW_ATE_signed, *attrs.byte_size * 8); - } else { - enumerator_clang_type = m_ast.GetBasicType(eBasicTypeInt); - } + if (type_sp) { + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a " + "forward declaration, complete type is 0x%8.8" PRIx64, + static_cast<void *>(this), die.GetOffset(), + DW_TAG_value_to_name(tag), attrs.name.GetCString(), + type_sp->GetID()); } - clang_type = m_ast.CreateEnumerationType( - attrs.name.GetCString(), - GetClangDeclContextContainingDIE(die, nullptr), attrs.decl, - enumerator_clang_type, attrs.is_scoped_enum); - } else { - enumerator_clang_type = - m_ast.GetEnumerationIntegerType(clang_type.GetOpaqueQualType()); + // We found a real definition for this type elsewhere so lets use + // it and cache the fact that we found a complete type for this + // die + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + clang::DeclContext *defn_decl_ctx = + GetCachedClangDeclContextForDIE(dwarf->GetDIE(type_sp->GetID())); + if (defn_decl_ctx) + LinkDeclContextToDIE(defn_decl_ctx, die); + return type_sp; } + } + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); - LinkDeclContextToDIE(ClangASTContext::GetDeclContextForType(clang_type), - die); - - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, - dwarf->GetUID(attrs.type.Reference()), Type::eEncodingIsUID, - &attrs.decl, clang_type, Type::eResolveStateForward); + CompilerType enumerator_clang_type; + CompilerType clang_type; + clang_type.SetCompilerType( + &m_ast, dwarf->GetForwardDeclDieToClangType().lookup(die.GetDIE())); + if (!clang_type) { + if (attrs.type.IsValid()) { + Type *enumerator_type = + dwarf->ResolveTypeUID(attrs.type.Reference(), true); + if (enumerator_type) + enumerator_clang_type = enumerator_type->GetFullCompilerType(); + } - if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { - if (die.HasChildren()) { - bool is_signed = false; - enumerator_clang_type.IsIntegerType(is_signed); - ParseChildEnumerators(clang_type, is_signed, - type_sp->GetByteSize().getValueOr(0), die); + if (!enumerator_clang_type) { + if (attrs.byte_size) { + enumerator_clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( + "", DW_ATE_signed, *attrs.byte_size * 8); + } else { + enumerator_clang_type = m_ast.GetBasicType(eBasicTypeInt); } - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); - } else { - dwarf->GetObjectFile()->GetModule()->ReportError( - "DWARF DIE at 0x%8.8x named \"%s\" was not able to start its " - "definition.\nPlease file a bug and attach the file at the " - "start of this error message", - die.GetOffset(), attrs.name.GetCString()); } - } break; - case DW_TAG_inlined_subroutine: - case DW_TAG_subprogram: - case DW_TAG_subroutine_type: { - bool is_variadic = false; - bool is_static = false; - bool has_template_params = false; + clang_type = m_ast.CreateEnumerationType( + attrs.name.GetCString(), GetClangDeclContextContainingDIE(die, nullptr), + attrs.decl, enumerator_clang_type, attrs.is_scoped_enum); + } else { + enumerator_clang_type = + m_ast.GetEnumerationIntegerType(clang_type.GetOpaqueQualType()); + } - unsigned type_quals = 0; + LinkDeclContextToDIE(ClangASTContext::GetDeclContextForType(clang_type), die); - std::string object_pointer_name; - if (attrs.object_pointer) { - const char *object_pointer_name_cstr = attrs.object_pointer.GetName(); - if (object_pointer_name_cstr) - object_pointer_name = object_pointer_name_cstr; - } + type_sp = std::make_shared<Type>( + die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, + dwarf->GetUID(attrs.type.Reference()), Type::eEncodingIsUID, &attrs.decl, + clang_type, Type::ResolveState::Forward); - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); + if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { + if (die.HasChildren()) { + bool is_signed = false; + enumerator_clang_type.IsIntegerType(is_signed); + ParseChildEnumerators(clang_type, is_signed, + type_sp->GetByteSize().getValueOr(0), die); + } + ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + } else { + dwarf->GetObjectFile()->GetModule()->ReportError( + "DWARF DIE at 0x%8.8x named \"%s\" was not able to start its " + "definition.\nPlease file a bug and attach the file at the " + "start of this error message", + die.GetOffset(), attrs.name.GetCString()); + } + return type_sp; +} - CompilerType return_clang_type; - Type *func_type = NULL; +TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS)); - if (attrs.type.IsValid()) - func_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); + SymbolFileDWARF *dwarf = die.GetDWARF(); + const dw_tag_t tag = die.Tag(); - if (func_type) - return_clang_type = func_type->GetForwardCompilerType(); - else - return_clang_type = m_ast.GetBasicType(eBasicTypeVoid); + bool is_variadic = false; + bool is_static = false; + bool has_template_params = false; - std::vector<CompilerType> function_param_types; - std::vector<clang::ParmVarDecl *> function_param_decls; + unsigned type_quals = 0; - // Parse the function children for the parameters + std::string object_pointer_name; + if (attrs.object_pointer) { + const char *object_pointer_name_cstr = attrs.object_pointer.GetName(); + if (object_pointer_name_cstr) + object_pointer_name = object_pointer_name_cstr; + } - DWARFDIE decl_ctx_die; - clang::DeclContext *containing_decl_ctx = - GetClangDeclContextContainingDIE(die, &decl_ctx_die); - const clang::Decl::Kind containing_decl_kind = - containing_decl_ctx->getDeclKind(); + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); - bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind); - // Start off static. This will be set to false in - // ParseChildParameters(...) if we find a "this" parameters as the - // first parameter - if (is_cxx_method) { - is_static = true; - } + CompilerType return_clang_type; + Type *func_type = NULL; + + if (attrs.type.IsValid()) + func_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); + + if (func_type) + return_clang_type = func_type->GetForwardCompilerType(); + else + return_clang_type = m_ast.GetBasicType(eBasicTypeVoid); + + std::vector<CompilerType> function_param_types; + std::vector<clang::ParmVarDecl *> function_param_decls; + + // Parse the function children for the parameters + + DWARFDIE decl_ctx_die; + clang::DeclContext *containing_decl_ctx = + GetClangDeclContextContainingDIE(die, &decl_ctx_die); + const clang::Decl::Kind containing_decl_kind = + containing_decl_ctx->getDeclKind(); + + bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind); + // Start off static. This will be set to false in + // ParseChildParameters(...) if we find a "this" parameters as the + // first parameter + if (is_cxx_method) { + is_static = true; + } + + if (die.HasChildren()) { + bool skip_artificial = true; + ParseChildParameters(containing_decl_ctx, die, skip_artificial, is_static, + is_variadic, has_template_params, + function_param_types, function_param_decls, + type_quals); + } + + bool ignore_containing_context = false; + // Check for templatized class member functions. If we had any + // DW_TAG_template_type_parameter or DW_TAG_template_value_parameter + // the DW_TAG_subprogram DIE, then we can't let this become a method in + // a class. Why? Because templatized functions are only emitted if one + // of the templatized methods is used in the current compile unit and + // we will end up with classes that may or may not include these member + // functions and this means one class won't match another class + // definition and it affects our ability to use a class in the clang + // expression parser. So for the greater good, we currently must not + // allow any template member functions in a class definition. + if (is_cxx_method && has_template_params) { + ignore_containing_context = true; + is_cxx_method = false; + } + + // clang_type will get the function prototype clang type after this + // call + CompilerType clang_type = m_ast.CreateFunctionType( + return_clang_type, function_param_types.data(), + function_param_types.size(), is_variadic, type_quals); - if (die.HasChildren()) { - bool skip_artificial = true; - ParseChildParameters(containing_decl_ctx, die, skip_artificial, is_static, - is_variadic, has_template_params, - function_param_types, function_param_decls, - type_quals); - } - - bool ignore_containing_context = false; - // Check for templatized class member functions. If we had any - // DW_TAG_template_type_parameter or DW_TAG_template_value_parameter - // the DW_TAG_subprogram DIE, then we can't let this become a method in - // a class. Why? Because templatized functions are only emitted if one - // of the templatized methods is used in the current compile unit and - // we will end up with classes that may or may not include these member - // functions and this means one class won't match another class - // definition and it affects our ability to use a class in the clang - // expression parser. So for the greater good, we currently must not - // allow any template member functions in a class definition. - if (is_cxx_method && has_template_params) { - ignore_containing_context = true; - is_cxx_method = false; - } - - // clang_type will get the function prototype clang type after this - // call - clang_type = m_ast.CreateFunctionType( - return_clang_type, function_param_types.data(), - function_param_types.size(), is_variadic, type_quals); - - if (attrs.name) { - bool type_handled = false; - if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { - ObjCLanguage::MethodName objc_method(attrs.name.GetStringRef(), true); - if (objc_method.IsValid(true)) { - CompilerType class_opaque_type; - ConstString class_name(objc_method.GetClassName()); - if (class_name) { - TypeSP complete_objc_class_type_sp( - dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(), - class_name, false)); - - if (complete_objc_class_type_sp) { - CompilerType type_clang_forward_type = - complete_objc_class_type_sp->GetForwardCompilerType(); - if (ClangASTContext::IsObjCObjectOrInterfaceType( - type_clang_forward_type)) - class_opaque_type = type_clang_forward_type; - } + if (attrs.name) { + bool type_handled = false; + if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { + ObjCLanguage::MethodName objc_method(attrs.name.GetStringRef(), true); + if (objc_method.IsValid(true)) { + CompilerType class_opaque_type; + ConstString class_name(objc_method.GetClassName()); + if (class_name) { + TypeSP complete_objc_class_type_sp( + dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(), + class_name, false)); + + if (complete_objc_class_type_sp) { + CompilerType type_clang_forward_type = + complete_objc_class_type_sp->GetForwardCompilerType(); + if (ClangASTContext::IsObjCObjectOrInterfaceType( + type_clang_forward_type)) + class_opaque_type = type_clang_forward_type; } + } - if (class_opaque_type) { - // If accessibility isn't set to anything valid, assume public - // for now... - if (attrs.accessibility == eAccessNone) - attrs.accessibility = eAccessPublic; - - clang::ObjCMethodDecl *objc_method_decl = - m_ast.AddMethodToObjCObjectType( - class_opaque_type, attrs.name.GetCString(), clang_type, - attrs.accessibility, attrs.is_artificial, is_variadic); - type_handled = objc_method_decl != NULL; - if (type_handled) { - LinkDeclContextToDIE( - ClangASTContext::GetAsDeclContext(objc_method_decl), die); - m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID()); - } else { - dwarf->GetObjectFile()->GetModule()->ReportError( - "{0x%8.8x}: invalid Objective-C method 0x%4.4x (%s), " - "please file a bug and attach the file at the start of " - "this error message", - die.GetOffset(), tag, DW_TAG_value_to_name(tag)); - } + if (class_opaque_type) { + // If accessibility isn't set to anything valid, assume public + // for now... + if (attrs.accessibility == eAccessNone) + attrs.accessibility = eAccessPublic; + + clang::ObjCMethodDecl *objc_method_decl = + m_ast.AddMethodToObjCObjectType( + class_opaque_type, attrs.name.GetCString(), clang_type, + attrs.accessibility, attrs.is_artificial, is_variadic, + attrs.is_objc_direct_call); + type_handled = objc_method_decl != NULL; + if (type_handled) { + LinkDeclContextToDIE(objc_method_decl, die); + m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID()); + } else { + dwarf->GetObjectFile()->GetModule()->ReportError( + "{0x%8.8x}: invalid Objective-C method 0x%4.4x (%s), " + "please file a bug and attach the file at the start of " + "this error message", + die.GetOffset(), tag, DW_TAG_value_to_name(tag)); } - } else if (is_cxx_method) { - // Look at the parent of this DIE and see if is is a class or - // struct and see if this is actually a C++ method - Type *class_type = dwarf->ResolveType(decl_ctx_die); - if (class_type) { - bool alternate_defn = false; - if (class_type->GetID() != decl_ctx_die.GetID() || - decl_ctx_die.GetContainingDWOModuleDIE()) { - alternate_defn = true; - - // We uniqued the parent class of this function to another - // class so we now need to associate all dies under - // "decl_ctx_die" to DIEs in the DIE for "class_type"... - DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID()); - - if (class_type_die) { - std::vector<DWARFDIE> failures; - - CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die, - class_type, failures); - - // FIXME do something with these failures that's smarter - // than - // just dropping them on the ground. Unfortunately classes - // don't like having stuff added to them after their - // definitions are complete... - - type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; - if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { - type_sp = type_ptr->shared_from_this(); - break; - } + } + } else if (is_cxx_method) { + // Look at the parent of this DIE and see if is is a class or + // struct and see if this is actually a C++ method + Type *class_type = dwarf->ResolveType(decl_ctx_die); + if (class_type) { + bool alternate_defn = false; + if (class_type->GetID() != decl_ctx_die.GetID() || + IsClangModuleFwdDecl(decl_ctx_die)) { + alternate_defn = true; + + // We uniqued the parent class of this function to another + // class so we now need to associate all dies under + // "decl_ctx_die" to DIEs in the DIE for "class_type"... + DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID()); + + if (class_type_die) { + std::vector<DWARFDIE> failures; + + CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die, + class_type, failures); + + // FIXME do something with these failures that's + // smarter than just dropping them on the ground. + // Unfortunately classes don't like having stuff added + // to them after their definitions are complete... + + Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; + if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { + return type_ptr->shared_from_this(); } } + } - if (attrs.specification.IsValid()) { - // We have a specification which we are going to base our - // function prototype off of, so we need this type to be - // completed so that the m_die_to_decl_ctx for the method in - // the specification has a valid clang decl context. - class_type->GetForwardCompilerType(); - // If we have a specification, then the function type should - // have been made with the specification and not with this - // die. - DWARFDIE spec_die = attrs.specification.Reference(); - clang::DeclContext *spec_clang_decl_ctx = - GetClangDeclContextForDIE(spec_die); - if (spec_clang_decl_ctx) { - LinkDeclContextToDIE(spec_clang_decl_ctx, die); - } else { - dwarf->GetObjectFile()->GetModule()->ReportWarning( - "0x%8.8" PRIx64 ": DW_AT_specification(0x%8.8x" - ") has no decl\n", - die.GetID(), spec_die.GetOffset()); - } - type_handled = true; - } else if (attrs.abstract_origin.IsValid()) { - // We have a specification which we are going to base our - // function prototype off of, so we need this type to be - // completed so that the m_die_to_decl_ctx for the method in - // the abstract origin has a valid clang decl context. - class_type->GetForwardCompilerType(); - - DWARFDIE abs_die = attrs.abstract_origin.Reference(); - clang::DeclContext *abs_clang_decl_ctx = - GetClangDeclContextForDIE(abs_die); - if (abs_clang_decl_ctx) { - LinkDeclContextToDIE(abs_clang_decl_ctx, die); - } else { - dwarf->GetObjectFile()->GetModule()->ReportWarning( - "0x%8.8" PRIx64 ": DW_AT_abstract_origin(0x%8.8x" - ") has no decl\n", - die.GetID(), abs_die.GetOffset()); - } - type_handled = true; + if (attrs.specification.IsValid()) { + // We have a specification which we are going to base our + // function prototype off of, so we need this type to be + // completed so that the m_die_to_decl_ctx for the method in + // the specification has a valid clang decl context. + class_type->GetForwardCompilerType(); + // If we have a specification, then the function type should + // have been made with the specification and not with this + // die. + DWARFDIE spec_die = attrs.specification.Reference(); + clang::DeclContext *spec_clang_decl_ctx = + GetClangDeclContextForDIE(spec_die); + if (spec_clang_decl_ctx) { + LinkDeclContextToDIE(spec_clang_decl_ctx, die); + } else { + dwarf->GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8" PRIx64 ": DW_AT_specification(0x%8.8x" + ") has no decl\n", + die.GetID(), spec_die.GetOffset()); + } + type_handled = true; + } else if (attrs.abstract_origin.IsValid()) { + // We have a specification which we are going to base our + // function prototype off of, so we need this type to be + // completed so that the m_die_to_decl_ctx for the method in + // the abstract origin has a valid clang decl context. + class_type->GetForwardCompilerType(); + + DWARFDIE abs_die = attrs.abstract_origin.Reference(); + clang::DeclContext *abs_clang_decl_ctx = + GetClangDeclContextForDIE(abs_die); + if (abs_clang_decl_ctx) { + LinkDeclContextToDIE(abs_clang_decl_ctx, die); } else { - CompilerType class_opaque_type = - class_type->GetForwardCompilerType(); - if (ClangASTContext::IsCXXClassType(class_opaque_type)) { - if (class_opaque_type.IsBeingDefined() || alternate_defn) { - if (!is_static && !die.HasChildren()) { - // We have a C++ member function with no children (this - // pointer!) and clang will get mad if we try and make - // a function that isn't well formed in the DWARF, so - // we will just skip it... - type_handled = true; - } else { - bool add_method = true; - if (alternate_defn) { - // If an alternate definition for the class exists, - // then add the method only if an equivalent is not - // already present. - clang::CXXRecordDecl *record_decl = - m_ast.GetAsCXXRecordDecl( - class_opaque_type.GetOpaqueQualType()); - if (record_decl) { - for (auto method_iter = record_decl->method_begin(); - method_iter != record_decl->method_end(); - method_iter++) { - clang::CXXMethodDecl *method_decl = *method_iter; - if (method_decl->getNameInfo().getAsString() == - attrs.name.GetStringRef()) { - if (method_decl->getType() == - ClangUtil::GetQualType(clang_type)) { - add_method = false; - LinkDeclContextToDIE( - ClangASTContext::GetAsDeclContext( - method_decl), - die); - type_handled = true; - - break; - } + dwarf->GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8" PRIx64 ": DW_AT_abstract_origin(0x%8.8x" + ") has no decl\n", + die.GetID(), abs_die.GetOffset()); + } + type_handled = true; + } else { + CompilerType class_opaque_type = + class_type->GetForwardCompilerType(); + if (ClangASTContext::IsCXXClassType(class_opaque_type)) { + if (class_opaque_type.IsBeingDefined() || alternate_defn) { + if (!is_static && !die.HasChildren()) { + // We have a C++ member function with no children (this + // pointer!) and clang will get mad if we try and make + // a function that isn't well formed in the DWARF, so + // we will just skip it... + type_handled = true; + } else { + bool add_method = true; + if (alternate_defn) { + // If an alternate definition for the class exists, + // then add the method only if an equivalent is not + // already present. + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl( + class_opaque_type.GetOpaqueQualType()); + if (record_decl) { + for (auto method_iter = record_decl->method_begin(); + method_iter != record_decl->method_end(); + method_iter++) { + clang::CXXMethodDecl *method_decl = *method_iter; + if (method_decl->getNameInfo().getAsString() == + attrs.name.GetStringRef()) { + if (method_decl->getType() == + ClangUtil::GetQualType(clang_type)) { + add_method = false; + LinkDeclContextToDIE(method_decl, die); + type_handled = true; + + break; } } } } + } - if (add_method) { - llvm::PrettyStackTraceFormat stack_trace( - "SymbolFileDWARF::ParseType() is adding a method " - "%s to class %s in DIE 0x%8.8" PRIx64 " from %s", - attrs.name.GetCString(), - class_type->GetName().GetCString(), die.GetID(), - dwarf->GetObjectFile() - ->GetFileSpec() - .GetPath() - .c_str()); - - const bool is_attr_used = false; - // Neither GCC 4.2 nor clang++ currently set a valid - // accessibility in the DWARF for C++ methods... - // Default to public for now... - if (attrs.accessibility == eAccessNone) - attrs.accessibility = eAccessPublic; - - clang::CXXMethodDecl *cxx_method_decl = - m_ast.AddMethodToCXXRecordType( - class_opaque_type.GetOpaqueQualType(), - attrs.name.GetCString(), attrs.mangled_name, - clang_type, attrs.accessibility, attrs.is_virtual, - is_static, attrs.is_inline, attrs.is_explicit, - is_attr_used, attrs.is_artificial); - - type_handled = cxx_method_decl != NULL; - // Artificial methods are always handled even when we - // don't create a new declaration for them. - type_handled |= attrs.is_artificial; - - if (cxx_method_decl) { - LinkDeclContextToDIE( - ClangASTContext::GetAsDeclContext(cxx_method_decl), - die); - - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - - if (!object_pointer_name.empty()) { - metadata.SetObjectPtrName( - object_pointer_name.c_str()); - LLDB_LOGF(log, - "Setting object pointer name: %s on method " - "object %p.\n", - object_pointer_name.c_str(), - static_cast<void *>(cxx_method_decl)); - } - m_ast.SetMetadata(cxx_method_decl, metadata); - } else { - ignore_containing_context = true; + if (add_method) { + llvm::PrettyStackTraceFormat stack_trace( + "SymbolFileDWARF::ParseType() is adding a method " + "%s to class %s in DIE 0x%8.8" PRIx64 " from %s", + attrs.name.GetCString(), + class_type->GetName().GetCString(), die.GetID(), + dwarf->GetObjectFile() + ->GetFileSpec() + .GetPath() + .c_str()); + + const bool is_attr_used = false; + // Neither GCC 4.2 nor clang++ currently set a valid + // accessibility in the DWARF for C++ methods... + // Default to public for now... + if (attrs.accessibility == eAccessNone) + attrs.accessibility = eAccessPublic; + + clang::CXXMethodDecl *cxx_method_decl = + m_ast.AddMethodToCXXRecordType( + class_opaque_type.GetOpaqueQualType(), + attrs.name.GetCString(), attrs.mangled_name, + clang_type, attrs.accessibility, attrs.is_virtual, + is_static, attrs.is_inline, attrs.is_explicit, + is_attr_used, attrs.is_artificial); + + type_handled = cxx_method_decl != NULL; + // Artificial methods are always handled even when we + // don't create a new declaration for them. + type_handled |= attrs.is_artificial; + + if (cxx_method_decl) { + LinkDeclContextToDIE(cxx_method_decl, die); + + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + + if (!object_pointer_name.empty()) { + metadata.SetObjectPtrName( + object_pointer_name.c_str()); + LLDB_LOGF(log, + "Setting object pointer name: %s on method " + "object %p.\n", + object_pointer_name.c_str(), + static_cast<void *>(cxx_method_decl)); } + m_ast.SetMetadata(cxx_method_decl, metadata); + } else { + ignore_containing_context = true; } } - } else { - // We were asked to parse the type for a method in a - // class, yet the class hasn't been asked to complete - // itself through the clang::ExternalASTSource protocol, - // so we need to just have the class complete itself and - // do things the right way, then our - // DIE should then have an entry in the - // dwarf->GetDIEToType() map. First - // we need to modify the dwarf->GetDIEToType() so it - // doesn't think we are trying to parse this DIE - // anymore... - dwarf->GetDIEToType()[die.GetDIE()] = NULL; - - // Now we get the full type to force our class type to - // complete itself using the clang::ExternalASTSource - // protocol which will parse all base classes and all - // methods (including the method for this DIE). - class_type->GetFullCompilerType(); - - // The type for this DIE should have been filled in the - // function call above - type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; - if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { - type_sp = type_ptr->shared_from_this(); - break; - } - - // FIXME This is fixing some even uglier behavior but we - // really need to - // uniq the methods of each class as well as the class - // itself. <rdar://problem/11240464> - type_handled = true; } + } else { + // We were asked to parse the type for a method in a + // class, yet the class hasn't been asked to complete + // itself through the clang::ExternalASTSource protocol, + // so we need to just have the class complete itself and + // do things the right way, then our + // DIE should then have an entry in the + // dwarf->GetDIEToType() map. First + // we need to modify the dwarf->GetDIEToType() so it + // doesn't think we are trying to parse this DIE + // anymore... + dwarf->GetDIEToType()[die.GetDIE()] = NULL; + + // Now we get the full type to force our class type to + // complete itself using the clang::ExternalASTSource + // protocol which will parse all base classes and all + // methods (including the method for this DIE). + class_type->GetFullCompilerType(); + + // The type for this DIE should have been filled in the + // function call above + Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; + if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { + return type_ptr->shared_from_this(); + } + + // FIXME This is fixing some even uglier behavior but we + // really need to + // uniq the methods of each class as well as the class + // itself. <rdar://problem/11240464> + type_handled = true; } } } } } + } - if (!type_handled) { - clang::FunctionDecl *function_decl = nullptr; - clang::FunctionDecl *template_function_decl = nullptr; + if (!type_handled) { + clang::FunctionDecl *function_decl = nullptr; + clang::FunctionDecl *template_function_decl = nullptr; - if (attrs.abstract_origin.IsValid()) { - DWARFDIE abs_die = attrs.abstract_origin.Reference(); + if (attrs.abstract_origin.IsValid()) { + DWARFDIE abs_die = attrs.abstract_origin.Reference(); - if (dwarf->ResolveType(abs_die)) { - function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>( - GetCachedClangDeclContextForDIE(abs_die)); + if (dwarf->ResolveType(abs_die)) { + function_decl = llvm::dyn_cast_or_null<clang::FunctionDecl>( + GetCachedClangDeclContextForDIE(abs_die)); - if (function_decl) { - LinkDeclContextToDIE(function_decl, die); - } + if (function_decl) { + LinkDeclContextToDIE(function_decl, die); } } + } - if (!function_decl) { - // We just have a function that isn't part of a class - function_decl = m_ast.CreateFunctionDeclaration( + if (!function_decl) { + // We just have a function that isn't part of a class + function_decl = m_ast.CreateFunctionDeclaration( + ignore_containing_context ? m_ast.GetTranslationUnitDecl() + : containing_decl_ctx, + attrs.name.GetCString(), clang_type, attrs.storage, + attrs.is_inline); + + if (has_template_params) { + ClangASTContext::TemplateParameterInfos template_param_infos; + ParseTemplateParameterInfos(die, template_param_infos); + template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, attrs.name.GetCString(), clang_type, attrs.storage, attrs.is_inline); + clang::FunctionTemplateDecl *func_template_decl = + m_ast.CreateFunctionTemplateDecl( + containing_decl_ctx, template_function_decl, + attrs.name.GetCString(), template_param_infos); + m_ast.CreateFunctionTemplateSpecializationInfo( + function_decl, func_template_decl, template_param_infos); + } - if (has_template_params) { - ClangASTContext::TemplateParameterInfos template_param_infos; - ParseTemplateParameterInfos(die, template_param_infos); - template_function_decl = m_ast.CreateFunctionDeclaration( - ignore_containing_context ? m_ast.GetTranslationUnitDecl() - : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, - attrs.is_inline); - clang::FunctionTemplateDecl *func_template_decl = - m_ast.CreateFunctionTemplateDecl( - containing_decl_ctx, template_function_decl, - attrs.name.GetCString(), template_param_infos); - m_ast.CreateFunctionTemplateSpecializationInfo( - function_decl, func_template_decl, template_param_infos); - } - - lldbassert(function_decl); + lldbassert(function_decl); - if (function_decl) { - LinkDeclContextToDIE(function_decl, die); + if (function_decl) { + LinkDeclContextToDIE(function_decl, die); - if (!function_param_decls.empty()) { - m_ast.SetFunctionParameters(function_decl, + if (!function_param_decls.empty()) { + m_ast.SetFunctionParameters(function_decl, + &function_param_decls.front(), + function_param_decls.size()); + if (template_function_decl) + m_ast.SetFunctionParameters(template_function_decl, &function_param_decls.front(), function_param_decls.size()); - if (template_function_decl) - m_ast.SetFunctionParameters(template_function_decl, - &function_param_decls.front(), - function_param_decls.size()); - } + } - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); - if (!object_pointer_name.empty()) { - metadata.SetObjectPtrName(object_pointer_name.c_str()); - LLDB_LOGF(log, - "Setting object pointer name: %s on function " - "object %p.", - object_pointer_name.c_str(), - static_cast<void *>(function_decl)); - } - m_ast.SetMetadata(function_decl, metadata); + if (!object_pointer_name.empty()) { + metadata.SetObjectPtrName(object_pointer_name.c_str()); + LLDB_LOGF(log, + "Setting object pointer name: %s on function " + "object %p.", + object_pointer_name.c_str(), + static_cast<void *>(function_decl)); } + m_ast.SetMetadata(function_decl, metadata); } } } - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, attrs.name, llvm::None, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, &attrs.decl, clang_type, Type::eResolveStateFull); - assert(type_sp.get()); - } break; + } + return std::make_shared<Type>( + die.GetID(), dwarf, attrs.name, llvm::None, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Full); +} - case DW_TAG_array_type: { - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); +TypeSP DWARFASTParserClang::ParseArrayType(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs) { + SymbolFileDWARF *dwarf = die.GetDWARF(); - DWARFDIE type_die = attrs.type.Reference(); - Type *element_type = dwarf->ResolveTypeUID(type_die, true); + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); - if (element_type) { - auto array_info = ParseChildArrayInfo(die); - if (array_info) { - attrs.byte_stride = array_info->byte_stride; - attrs.bit_stride = array_info->bit_stride; - } - if (attrs.byte_stride == 0 && attrs.bit_stride == 0) - attrs.byte_stride = element_type->GetByteSize().getValueOr(0); - CompilerType array_element_type = element_type->GetForwardCompilerType(); - - if (ClangASTContext::IsCXXClassType(array_element_type) && - !array_element_type.GetCompleteType()) { - ModuleSP module_sp = die.GetModule(); - if (module_sp) { - if (die.GetCU()->GetProducer() == eProducerClang) - module_sp->ReportError( - "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " - "class/union/struct element type DIE 0x%8.8x that is a " - "forward declaration, not a complete definition.\nTry " - "compiling the source file with -fstandalone-debug or " - "disable -gmodules", - die.GetOffset(), type_die.GetOffset()); - else - module_sp->ReportError( - "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " - "class/union/struct element type DIE 0x%8.8x that is a " - "forward declaration, not a complete definition.\nPlease " - "file a bug against the compiler and include the " - "preprocessed output for %s", - die.GetOffset(), type_die.GetOffset(), - GetUnitName(die).c_str()); - } + DWARFDIE type_die = attrs.type.Reference(); + Type *element_type = dwarf->ResolveTypeUID(type_die, true); - // We have no choice other than to pretend that the element class - // type is complete. If we don't do this, clang will crash when - // trying to layout the class. Since we provide layout - // assistance, all ivars in this class and other classes will be - // fine, this is the best we can do short of crashing. - if (ClangASTContext::StartTagDeclarationDefinition( - array_element_type)) { - ClangASTContext::CompleteTagDeclarationDefinition(array_element_type); - } else { - module_sp->ReportError("DWARF DIE at 0x%8.8x was not able to " - "start its definition.\nPlease file a " - "bug and attach the file at the start " - "of this error message", - type_die.GetOffset()); - } - } + if (!element_type) + return nullptr; - uint64_t array_element_bit_stride = - attrs.byte_stride * 8 + attrs.bit_stride; - if (array_info && array_info->element_orders.size() > 0) { - uint64_t num_elements = 0; - auto end = array_info->element_orders.rend(); - for (auto pos = array_info->element_orders.rbegin(); pos != end; - ++pos) { - num_elements = *pos; - clang_type = m_ast.CreateArrayType(array_element_type, num_elements, - attrs.is_vector); - array_element_type = clang_type; - array_element_bit_stride = - num_elements ? array_element_bit_stride * num_elements - : array_element_bit_stride; - } - } else { - clang_type = m_ast.CreateArrayType(array_element_type, 0, attrs.is_vector); - } - ConstString empty_name; - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, empty_name, array_element_bit_stride / 8, nullptr, - dwarf->GetUID(type_die), Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::eResolveStateFull); - type_sp->SetEncodingType(element_type); - m_ast.SetMetadataAsUserID(clang_type.GetOpaqueQualType(), die.GetID()); + llvm::Optional<SymbolFile::ArrayInfo> array_info = ParseChildArrayInfo(die); + if (array_info) { + attrs.byte_stride = array_info->byte_stride; + attrs.bit_stride = array_info->bit_stride; + } + if (attrs.byte_stride == 0 && attrs.bit_stride == 0) + attrs.byte_stride = element_type->GetByteSize().getValueOr(0); + CompilerType array_element_type = element_type->GetForwardCompilerType(); + + if (ClangASTContext::IsCXXClassType(array_element_type) && + !array_element_type.GetCompleteType()) { + ModuleSP module_sp = die.GetModule(); + if (module_sp) { + if (die.GetCU()->GetProducer() == eProducerClang) + module_sp->ReportError( + "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " + "class/union/struct element type DIE 0x%8.8x that is a " + "forward declaration, not a complete definition.\nTry " + "compiling the source file with -fstandalone-debug or " + "disable -gmodules", + die.GetOffset(), type_die.GetOffset()); + else + module_sp->ReportError( + "DWARF DW_TAG_array_type DIE at 0x%8.8x has a " + "class/union/struct element type DIE 0x%8.8x that is a " + "forward declaration, not a complete definition.\nPlease " + "file a bug against the compiler and include the " + "preprocessed output for %s", + die.GetOffset(), type_die.GetOffset(), GetUnitName(die).c_str()); + } + + // We have no choice other than to pretend that the element class + // type is complete. If we don't do this, clang will crash when + // trying to layout the class. Since we provide layout + // assistance, all ivars in this class and other classes will be + // fine, this is the best we can do short of crashing. + if (ClangASTContext::StartTagDeclarationDefinition(array_element_type)) { + ClangASTContext::CompleteTagDeclarationDefinition(array_element_type); + } else { + module_sp->ReportError("DWARF DIE at 0x%8.8x was not able to " + "start its definition.\nPlease file a " + "bug and attach the file at the start " + "of this error message", + type_die.GetOffset()); } - } break; + } - case DW_TAG_ptr_to_member_type: { - Type *pointee_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); - Type *class_type = - dwarf->ResolveTypeUID(attrs.containing_type.Reference(), true); + uint64_t array_element_bit_stride = + attrs.byte_stride * 8 + attrs.bit_stride; + CompilerType clang_type; + if (array_info && array_info->element_orders.size() > 0) { + uint64_t num_elements = 0; + auto end = array_info->element_orders.rend(); + for (auto pos = array_info->element_orders.rbegin(); pos != end; ++pos) { + num_elements = *pos; + clang_type = m_ast.CreateArrayType(array_element_type, num_elements, + attrs.is_vector); + array_element_type = clang_type; + array_element_bit_stride = num_elements + ? array_element_bit_stride * num_elements + : array_element_bit_stride; + } + } else { + clang_type = + m_ast.CreateArrayType(array_element_type, 0, attrs.is_vector); + } + ConstString empty_name; + TypeSP type_sp = std::make_shared<Type>( + die.GetID(), dwarf, empty_name, array_element_bit_stride / 8, nullptr, + dwarf->GetUID(type_die), Type::eEncodingIsUID, &attrs.decl, clang_type, + Type::ResolveState::Full); + type_sp->SetEncodingType(element_type); + const clang::Type *type = ClangUtil::GetQualType(clang_type).getTypePtr(); + m_ast.SetMetadataAsUserID(type, die.GetID()); + return type_sp; +} - CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType(); - CompilerType class_clang_type = class_type->GetLayoutCompilerType(); +TypeSP DWARFASTParserClang::ParsePointerToMemberType( + const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs) { + SymbolFileDWARF *dwarf = die.GetDWARF(); + Type *pointee_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); + Type *class_type = + dwarf->ResolveTypeUID(attrs.containing_type.Reference(), true); - clang_type = ClangASTContext::CreateMemberPointerType(class_clang_type, - pointee_clang_type); + CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType(); + CompilerType class_clang_type = class_type->GetLayoutCompilerType(); - if (llvm::Optional<uint64_t> clang_type_size = - clang_type.GetByteSize(nullptr)) { - type_sp = std::make_shared<Type>( - die.GetID(), dwarf, attrs.name, *clang_type_size, nullptr, - LLDB_INVALID_UID, Type::eEncodingIsUID, nullptr, clang_type, - Type::eResolveStateForward); - } + CompilerType clang_type = ClangASTContext::CreateMemberPointerType( + class_clang_type, pointee_clang_type); - break; - } - default: - dwarf->GetObjectFile()->GetModule()->ReportError( - "{0x%8.8x}: unhandled type tag 0x%4.4x (%s), please file a bug and " - "attach the file at the start of this error message", - die.GetOffset(), tag, DW_TAG_value_to_name(tag)); - break; + if (llvm::Optional<uint64_t> clang_type_size = + clang_type.GetByteSize(nullptr)) { + return std::make_shared<Type>(die.GetID(), dwarf, attrs.name, + *clang_type_size, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, nullptr, clang_type, + Type::ResolveState::Forward); } - - // TODO: We should consider making the switch above exhaustive to simplify - // control flow in ParseTypeFromDWARF. Then, we could simply replace this - // return statement with a call to llvm_unreachable. - return UpdateSymbolContextScopeForType(sc, die, type_sp); + return nullptr; } TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( @@ -1281,20 +1380,20 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); dw_tag_t sc_parent_tag = sc_parent_die.Tag(); - SymbolContextScope *symbol_context_scope = NULL; + SymbolContextScope *symbol_context_scope = nullptr; if (sc_parent_tag == DW_TAG_compile_unit || sc_parent_tag == DW_TAG_partial_unit) { symbol_context_scope = sc.comp_unit; - } else if (sc.function != NULL && sc_parent_die) { + } else if (sc.function != nullptr && sc_parent_die) { symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); - if (symbol_context_scope == NULL) + if (symbol_context_scope == nullptr) symbol_context_scope = sc.function; } else { symbol_context_scope = sc.module_sp.get(); } - if (symbol_context_scope != NULL) + if (symbol_context_scope != nullptr) type_sp->SetSymbolContextScope(symbol_context_scope); // We are ready to put this type into the uniqued list up at the module @@ -1306,7 +1405,8 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( } TypeSP -DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, +DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, + const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs) { TypeSP type_sp; CompilerType clang_type; @@ -1438,9 +1538,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, attrs.name.GetCString()); } - // See if the type comes from a DWO module and if so, track down that - // type. - type_sp = ParseTypeFromDWO(die, log); + // See if the type comes from a Clang module and if so, track down + // that type. + type_sp = ParseTypeFromClangModule(sc, die, log); if (type_sp) return type_sp; @@ -1495,7 +1595,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, // backing the Decl is complete before adding children to it. This is // not an issue in the non-gmodules case because the debug info will // always contain a full definition of parent types in that case. - CompleteExternalTagDeclType(GetClangASTImporter(), decl_ctx, die, + CompleteExternalTagDeclType(m_ast, GetClangASTImporter(), decl_ctx, die, attrs.name.GetCString()); if (attrs.accessibility == eAccessNone && decl_ctx) { @@ -1546,7 +1646,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, clang_type_was_created = true; clang_type = m_ast.CreateRecordType( decl_ctx, attrs.accessibility, attrs.name.GetCString(), tag_decl_kind, - attrs.class_language, &metadata); + attrs.class_language, &metadata, attrs.exports_symbols); } } @@ -1557,7 +1657,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, type_sp = std::make_shared<Type>(die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::eResolveStateForward); + clang_type, Type::ResolveState::Forward); type_sp->SetIsCompleteObjCClass(attrs.is_complete_objc_class); @@ -1621,7 +1721,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die, ClangASTContext::GetAsRecordDecl(clang_type); if (record_decl) { - GetClangASTImporter().InsertRecordDecl( + GetClangASTImporter().SetRecordLayout( record_decl, ClangASTImporter::LayoutInfo()); } } @@ -1810,7 +1910,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( } } - clang::ASTContext *ast = m_ast.getASTContext(); + clang::ASTContext &ast = m_ast.getASTContext(); if (!clang_type) clang_type = m_ast.GetBasicType(eBasicTypeVoid); @@ -1830,7 +1930,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( return false; llvm::APInt apint(*size, uval64, is_signed); template_param_infos.args.push_back( - clang::TemplateArgument(*ast, llvm::APSInt(apint, !is_signed), + clang::TemplateArgument(ast, llvm::APSInt(apint, !is_signed), ClangUtil::GetQualType(clang_type))); } else { template_param_infos.args.push_back( @@ -1880,6 +1980,182 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( return template_param_infos.args.size() == template_param_infos.names.size(); } +bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, + lldb_private::Type *type, + CompilerType &clang_type) { + const dw_tag_t tag = die.Tag(); + SymbolFileDWARF *dwarf = die.GetDWARF(); + + ClangASTImporter::LayoutInfo layout_info; + + { + if (die.HasChildren()) { + LanguageType class_language = eLanguageTypeUnknown; + if (ClangASTContext::IsObjCObjectOrInterfaceType(clang_type)) { + class_language = eLanguageTypeObjC; + // For objective C we don't start the definition when the class is + // created. + ClangASTContext::StartTagDeclarationDefinition(clang_type); + } + + int tag_decl_kind = -1; + AccessType default_accessibility = eAccessNone; + if (tag == DW_TAG_structure_type) { + tag_decl_kind = clang::TTK_Struct; + default_accessibility = eAccessPublic; + } else if (tag == DW_TAG_union_type) { + tag_decl_kind = clang::TTK_Union; + default_accessibility = eAccessPublic; + } else if (tag == DW_TAG_class_type) { + tag_decl_kind = clang::TTK_Class; + default_accessibility = eAccessPrivate; + } + + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; + std::vector<int> member_accessibilities; + bool is_a_class = false; + // Parse members and base classes first + std::vector<DWARFDIE> member_function_dies; + + DelayedPropertyList delayed_properties; + ParseChildMembers(die, clang_type, class_language, bases, + member_accessibilities, member_function_dies, + delayed_properties, default_accessibility, is_a_class, + layout_info); + + // Now parse any methods if there were any... + for (const DWARFDIE &die : member_function_dies) + dwarf->ResolveType(die); + + if (class_language == eLanguageTypeObjC) { + ConstString class_name(clang_type.GetTypeName()); + if (class_name) { + DIEArray method_die_offsets; + dwarf->GetObjCMethodDIEOffsets(class_name, method_die_offsets); + + if (!method_die_offsets.empty()) { + DWARFDebugInfo *debug_info = dwarf->DebugInfo(); + + const size_t num_matches = method_die_offsets.size(); + for (size_t i = 0; i < num_matches; ++i) { + const DIERef &die_ref = method_die_offsets[i]; + DWARFDIE method_die = debug_info->GetDIE(die_ref); + + if (method_die) + method_die.ResolveType(); + } + } + + for (DelayedPropertyList::iterator pi = delayed_properties.begin(), + pe = delayed_properties.end(); + pi != pe; ++pi) + pi->Finalize(); + } + } + + // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we + // need to tell the clang type it is actually a class. + if (class_language != eLanguageTypeObjC) { + if (is_a_class && tag_decl_kind != clang::TTK_Class) + m_ast.SetTagTypeKind(ClangUtil::GetQualType(clang_type), + clang::TTK_Class); + } + + // Since DW_TAG_structure_type gets used for both classes and + // structures, we may need to set any DW_TAG_member fields to have a + // "private" access if none was specified. When we parsed the child + // members we tracked that actual accessibility value for each + // DW_TAG_member in the "member_accessibilities" array. If the value + // for the member is zero, then it was set to the + // "default_accessibility" which for structs was "public". Below we + // correct this by setting any fields to "private" that weren't + // correctly set. + if (is_a_class && !member_accessibilities.empty()) { + // This is a class and all members that didn't have their access + // specified are private. + m_ast.SetDefaultAccessForRecordFields( + m_ast.GetAsRecordDecl(clang_type), eAccessPrivate, + &member_accessibilities.front(), member_accessibilities.size()); + } + + if (!bases.empty()) { + // Make sure all base classes refer to complete types and not forward + // declarations. If we don't do this, clang will crash with an + // assertion in the call to clang_type.TransferBaseClasses() + for (const auto &base_class : bases) { + clang::TypeSourceInfo *type_source_info = + base_class->getTypeSourceInfo(); + if (type_source_info) { + CompilerType base_class_type = + m_ast.GetType(type_source_info->getType()); + if (!base_class_type.GetCompleteType()) { + auto module = dwarf->GetObjectFile()->GetModule(); + module->ReportError(":: Class '%s' has a base class '%s' which " + "does not have a complete definition.", + die.GetName(), + base_class_type.GetTypeName().GetCString()); + if (die.GetCU()->GetProducer() == eProducerClang) + module->ReportError(":: Try compiling the source file with " + "-fstandalone-debug."); + + // We have no choice other than to pretend that the base class + // is complete. If we don't do this, clang will crash when we + // call setBases() inside of + // "clang_type.TransferBaseClasses()" below. Since we + // provide layout assistance, all ivars in this class and other + // classes will be fine, this is the best we can do short of + // crashing. + if (ClangASTContext::StartTagDeclarationDefinition( + base_class_type)) { + ClangASTContext::CompleteTagDeclarationDefinition( + base_class_type); + } + } + } + } + + m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), + std::move(bases)); + } + } + } + + m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType()); + ClangASTContext::BuildIndirectFields(clang_type); + ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + + if (!layout_info.field_offsets.empty() || !layout_info.base_offsets.empty() || + !layout_info.vbase_offsets.empty()) { + if (type) + layout_info.bit_size = type->GetByteSize().getValueOr(0) * 8; + if (layout_info.bit_size == 0) + layout_info.bit_size = + die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; + + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + if (record_decl) + GetClangASTImporter().SetRecordLayout(record_decl, layout_info); + } + + return (bool)clang_type; +} + +bool DWARFASTParserClang::CompleteEnumType(const DWARFDIE &die, + lldb_private::Type *type, + CompilerType &clang_type) { + if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { + if (die.HasChildren()) { + bool is_signed = false; + clang_type.IsIntegerType(is_signed); + ParseChildEnumerators(clang_type, is_signed, + type->GetByteSize().getValueOr(0), die); + } + ClangASTContext::CompleteTagDeclarationDefinition(clang_type); + } + return (bool)clang_type; +} + bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &clang_type) { @@ -1895,39 +2171,6 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, if (!die) return false; -#if defined LLDB_CONFIGURATION_DEBUG - // For debugging purposes, the LLDB_DWARF_DONT_COMPLETE_TYPENAMES environment - // variable can be set with one or more typenames separated by ';' - // characters. This will cause this function to not complete any types whose - // names match. - // - // Examples of setting this environment variable: - // - // LLDB_DWARF_DONT_COMPLETE_TYPENAMES=Foo - // LLDB_DWARF_DONT_COMPLETE_TYPENAMES=Foo;Bar;Baz - const char *dont_complete_typenames_cstr = - getenv("LLDB_DWARF_DONT_COMPLETE_TYPENAMES"); - if (dont_complete_typenames_cstr && dont_complete_typenames_cstr[0]) { - const char *die_name = die.GetName(); - if (die_name && die_name[0]) { - const char *match = strstr(dont_complete_typenames_cstr, die_name); - if (match) { - size_t die_name_length = strlen(die_name); - while (match) { - const char separator_char = ';'; - const char next_char = match[die_name_length]; - if (next_char == '\0' || next_char == separator_char) { - if (match == dont_complete_typenames_cstr || - match[-1] == separator_char) - return false; - } - match = strstr(match + 1, die_name); - } - } - } - } -#endif - const dw_tag_t tag = die.Tag(); Log *log = @@ -1941,239 +2184,10 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, switch (tag) { case DW_TAG_structure_type: case DW_TAG_union_type: - case DW_TAG_class_type: { - ClangASTImporter::LayoutInfo layout_info; - - { - if (die.HasChildren()) { - LanguageType class_language = eLanguageTypeUnknown; - if (ClangASTContext::IsObjCObjectOrInterfaceType(clang_type)) { - class_language = eLanguageTypeObjC; - // For objective C we don't start the definition when the class is - // created. - ClangASTContext::StartTagDeclarationDefinition(clang_type); - } - - int tag_decl_kind = -1; - AccessType default_accessibility = eAccessNone; - if (tag == DW_TAG_structure_type) { - tag_decl_kind = clang::TTK_Struct; - default_accessibility = eAccessPublic; - } else if (tag == DW_TAG_union_type) { - tag_decl_kind = clang::TTK_Union; - default_accessibility = eAccessPublic; - } else if (tag == DW_TAG_class_type) { - tag_decl_kind = clang::TTK_Class; - default_accessibility = eAccessPrivate; - } - - std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; - std::vector<int> member_accessibilities; - bool is_a_class = false; - // Parse members and base classes first - std::vector<DWARFDIE> member_function_dies; - - DelayedPropertyList delayed_properties; - ParseChildMembers(die, clang_type, class_language, bases, - member_accessibilities, member_function_dies, - delayed_properties, default_accessibility, is_a_class, - layout_info); - - // Now parse any methods if there were any... - for (const DWARFDIE &die : member_function_dies) - dwarf->ResolveType(die); - - if (class_language == eLanguageTypeObjC) { - ConstString class_name(clang_type.GetTypeName()); - if (class_name) { - DIEArray method_die_offsets; - dwarf->GetObjCMethodDIEOffsets(class_name, method_die_offsets); - - if (!method_die_offsets.empty()) { - DWARFDebugInfo *debug_info = dwarf->DebugInfo(); - - const size_t num_matches = method_die_offsets.size(); - for (size_t i = 0; i < num_matches; ++i) { - const DIERef &die_ref = method_die_offsets[i]; - DWARFDIE method_die = debug_info->GetDIE(die_ref); - - if (method_die) - method_die.ResolveType(); - } - } - - for (DelayedPropertyList::iterator pi = delayed_properties.begin(), - pe = delayed_properties.end(); - pi != pe; ++pi) - pi->Finalize(); - } - } - - // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we - // need to tell the clang type it is actually a class. - if (class_language != eLanguageTypeObjC) { - if (is_a_class && tag_decl_kind != clang::TTK_Class) - m_ast.SetTagTypeKind(ClangUtil::GetQualType(clang_type), - clang::TTK_Class); - } - - // Since DW_TAG_structure_type gets used for both classes and - // structures, we may need to set any DW_TAG_member fields to have a - // "private" access if none was specified. When we parsed the child - // members we tracked that actual accessibility value for each - // DW_TAG_member in the "member_accessibilities" array. If the value - // for the member is zero, then it was set to the - // "default_accessibility" which for structs was "public". Below we - // correct this by setting any fields to "private" that weren't - // correctly set. - if (is_a_class && !member_accessibilities.empty()) { - // This is a class and all members that didn't have their access - // specified are private. - m_ast.SetDefaultAccessForRecordFields( - m_ast.GetAsRecordDecl(clang_type), eAccessPrivate, - &member_accessibilities.front(), member_accessibilities.size()); - } - - if (!bases.empty()) { - // Make sure all base classes refer to complete types and not forward - // declarations. If we don't do this, clang will crash with an - // assertion in the call to clang_type.TransferBaseClasses() - for (const auto &base_class : bases) { - clang::TypeSourceInfo *type_source_info = - base_class->getTypeSourceInfo(); - if (type_source_info) { - CompilerType base_class_type( - &m_ast, type_source_info->getType().getAsOpaquePtr()); - if (!base_class_type.GetCompleteType()) { - auto module = dwarf->GetObjectFile()->GetModule(); - module->ReportError(":: Class '%s' has a base class '%s' which " - "does not have a complete definition.", - die.GetName(), - base_class_type.GetTypeName().GetCString()); - if (die.GetCU()->GetProducer() == eProducerClang) - module->ReportError(":: Try compiling the source file with " - "-fstandalone-debug."); - - // We have no choice other than to pretend that the base class - // is complete. If we don't do this, clang will crash when we - // call setBases() inside of - // "clang_type.TransferBaseClasses()" below. Since we - // provide layout assistance, all ivars in this class and other - // classes will be fine, this is the best we can do short of - // crashing. - if (ClangASTContext::StartTagDeclarationDefinition( - base_class_type)) { - ClangASTContext::CompleteTagDeclarationDefinition( - base_class_type); - } - } - } - } - - m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), - std::move(bases)); - } - } - } - - m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType()); - ClangASTContext::BuildIndirectFields(clang_type); - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); - - if (!layout_info.field_offsets.empty() || - !layout_info.base_offsets.empty() || - !layout_info.vbase_offsets.empty()) { - if (type) - layout_info.bit_size = type->GetByteSize().getValueOr(0) * 8; - if (layout_info.bit_size == 0) - layout_info.bit_size = - die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; - - clang::CXXRecordDecl *record_decl = - m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); - if (record_decl) { - if (log) { - ModuleSP module_sp = dwarf->GetObjectFile()->GetModule(); - - if (module_sp) { - module_sp->LogMessage( - log, - "ClangASTContext::CompleteTypeFromDWARF (clang_type = %p) " - "caching layout info for record_decl = %p, bit_size = %" PRIu64 - ", alignment = %" PRIu64 - ", field_offsets[%u], base_offsets[%u], vbase_offsets[%u])", - static_cast<void *>(clang_type.GetOpaqueQualType()), - static_cast<void *>(record_decl), layout_info.bit_size, - layout_info.alignment, - static_cast<uint32_t>(layout_info.field_offsets.size()), - static_cast<uint32_t>(layout_info.base_offsets.size()), - static_cast<uint32_t>(layout_info.vbase_offsets.size())); - - uint32_t idx; - { - llvm::DenseMap<const clang::FieldDecl *, uint64_t>::const_iterator - pos, - end = layout_info.field_offsets.end(); - for (idx = 0, pos = layout_info.field_offsets.begin(); pos != end; - ++pos, ++idx) { - module_sp->LogMessage( - log, "ClangASTContext::CompleteTypeFromDWARF (clang_type = " - "%p) field[%u] = { bit_offset=%u, name='%s' }", - static_cast<void *>(clang_type.GetOpaqueQualType()), idx, - static_cast<uint32_t>(pos->second), - pos->first->getNameAsString().c_str()); - } - } - - { - llvm::DenseMap<const clang::CXXRecordDecl *, - clang::CharUnits>::const_iterator base_pos, - base_end = layout_info.base_offsets.end(); - for (idx = 0, base_pos = layout_info.base_offsets.begin(); - base_pos != base_end; ++base_pos, ++idx) { - module_sp->LogMessage( - log, "ClangASTContext::CompleteTypeFromDWARF (clang_type = " - "%p) base[%u] = { byte_offset=%u, name='%s' }", - clang_type.GetOpaqueQualType(), idx, - (uint32_t)base_pos->second.getQuantity(), - base_pos->first->getNameAsString().c_str()); - } - } - { - llvm::DenseMap<const clang::CXXRecordDecl *, - clang::CharUnits>::const_iterator vbase_pos, - vbase_end = layout_info.vbase_offsets.end(); - for (idx = 0, vbase_pos = layout_info.vbase_offsets.begin(); - vbase_pos != vbase_end; ++vbase_pos, ++idx) { - module_sp->LogMessage( - log, "ClangASTContext::CompleteTypeFromDWARF (clang_type = " - "%p) vbase[%u] = { byte_offset=%u, name='%s' }", - static_cast<void *>(clang_type.GetOpaqueQualType()), idx, - static_cast<uint32_t>(vbase_pos->second.getQuantity()), - vbase_pos->first->getNameAsString().c_str()); - } - } - } - } - GetClangASTImporter().InsertRecordDecl(record_decl, layout_info); - } - } - } - - return (bool)clang_type; - + case DW_TAG_class_type: + return CompleteRecordType(die, type, clang_type); case DW_TAG_enumeration_type: - if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { - if (die.HasChildren()) { - bool is_signed = false; - clang_type.IsIntegerType(is_signed); - ParseChildEnumerators(clang_type, is_signed, - type->GetByteSize().getValueOr(0), die); - } - ClangASTContext::CompleteTagDeclarationDefinition(clang_type); - } - return (bool)clang_type; - + return CompleteEnumType(die, type, clang_type); default: assert(false && "not a forward clang type decl!"); break; @@ -2205,7 +2219,7 @@ CompilerDeclContext DWARFASTParserClang::GetDeclContextForUIDFromDWARF(const DWARFDIE &die) { clang::DeclContext *clang_decl_ctx = GetClangDeclContextForDIE(die); if (clang_decl_ctx) - return CompilerDeclContext(&m_ast, clang_decl_ctx); + return m_ast.CreateDeclContext(clang_decl_ctx); return CompilerDeclContext(); } @@ -2214,7 +2228,7 @@ DWARFASTParserClang::GetDeclContextContainingUIDFromDWARF(const DWARFDIE &die) { clang::DeclContext *clang_decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); if (clang_decl_ctx) - return CompilerDeclContext(&m_ast, clang_decl_ctx); + return m_ast.CreateDeclContext(clang_decl_ctx); return CompilerDeclContext(); } @@ -2284,54 +2298,6 @@ size_t DWARFASTParserClang::ParseChildEnumerators( return enumerators_added; } -#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) - -class DIEStack { -public: - void Push(const DWARFDIE &die) { m_dies.push_back(die); } - - void LogDIEs(Log *log) { - StreamString log_strm; - const size_t n = m_dies.size(); - log_strm.Printf("DIEStack[%" PRIu64 "]:\n", (uint64_t)n); - for (size_t i = 0; i < n; i++) { - std::string qualified_name; - const DWARFDIE &die = m_dies[i]; - die.GetQualifiedName(qualified_name); - log_strm.Printf("[%" PRIu64 "] 0x%8.8x: %s name='%s'\n", (uint64_t)i, - die.GetOffset(), die.GetTagAsCString(), - qualified_name.c_str()); - } - log->PutCString(log_strm.GetData()); - } - void Pop() { m_dies.pop_back(); } - - class ScopedPopper { - public: - ScopedPopper(DIEStack &die_stack) - : m_die_stack(die_stack), m_valid(false) {} - - void Push(const DWARFDIE &die) { - m_valid = true; - m_die_stack.Push(die); - } - - ~ScopedPopper() { - if (m_valid) - m_die_stack.Pop(); - } - - protected: - DIEStack &m_die_stack; - bool m_valid; - }; - -protected: - typedef std::vector<DWARFDIE> Stack; - Stack m_dies; -}; -#endif - Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, const DWARFDIE &die) { DWARFRangeList func_ranges; @@ -2445,495 +2411,499 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, return nullptr; } -bool DWARFASTParserClang::ParseChildMembers( - const DWARFDIE &parent_die, CompilerType &class_clang_type, - const LanguageType class_language, - std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, +void DWARFASTParserClang::ParseSingleMember( + const DWARFDIE &die, const DWARFDIE &parent_die, + lldb_private::CompilerType &class_clang_type, + const lldb::LanguageType class_language, std::vector<int> &member_accessibilities, - std::vector<DWARFDIE> &member_function_dies, - DelayedPropertyList &delayed_properties, AccessType &default_accessibility, - bool &is_a_class, ClangASTImporter::LayoutInfo &layout_info) { - if (!parent_die) - return false; - + lldb::AccessType &default_accessibility, + DelayedPropertyList &delayed_properties, + lldb_private::ClangASTImporter::LayoutInfo &layout_info, + BitfieldInfo &last_field_info) { + ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); + const dw_tag_t tag = die.Tag(); // Get the parent byte size so we can verify any members will fit const uint64_t parent_byte_size = parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX); const uint64_t parent_bit_size = parent_byte_size == UINT64_MAX ? UINT64_MAX : parent_byte_size * 8; - uint32_t member_idx = 0; - BitfieldInfo last_field_info; - - ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); - ClangASTContext *ast = - llvm::dyn_cast_or_null<ClangASTContext>(class_clang_type.GetTypeSystem()); - if (ast == nullptr) - return false; - - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { - dw_tag_t tag = die.Tag(); - - switch (tag) { - case DW_TAG_member: - case DW_TAG_APPLE_property: { - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - if (num_attributes > 0) { - const char *name = nullptr; - const char *prop_name = nullptr; - const char *prop_getter_name = nullptr; - const char *prop_setter_name = nullptr; - uint32_t prop_attributes = 0; - - bool is_artificial = false; - DWARFFormValue encoding_form; - AccessType accessibility = eAccessNone; - uint32_t member_byte_offset = - (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX; - llvm::Optional<uint64_t> byte_size; - int64_t bit_offset = 0; - uint64_t data_bit_offset = UINT64_MAX; - size_t bit_size = 0; - bool is_external = - false; // On DW_TAG_members, this means the member is static - uint32_t i; - for (i = 0; i < num_attributes && !is_artificial; ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - name = form_value.AsCString(); - break; - case DW_AT_type: - encoding_form = form_value; - break; - case DW_AT_bit_offset: - bit_offset = form_value.Signed(); - break; - case DW_AT_bit_size: - bit_size = form_value.Unsigned(); - break; - case DW_AT_byte_size: - byte_size = form_value.Unsigned(); - break; - case DW_AT_data_bit_offset: - data_bit_offset = form_value.Unsigned(); - break; - case DW_AT_data_member_location: - if (form_value.BlockData()) { - Value initialValue(0); - Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = die.GetData(); - uint32_t block_length = form_value.Unsigned(); - uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); - if (DWARFExpression::Evaluate( - nullptr, // ExecutionContext * - nullptr, // RegisterContext * - module_sp, - DataExtractor(debug_info_data, block_offset, - block_length), - die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr, - memberOffset, nullptr)) { - member_byte_offset = - memberOffset.ResolveValue(nullptr).UInt(); - } - } else { - // With DWARF 3 and later, if the value is an integer constant, - // this form value is the offset in bytes from the beginning of - // the containing entity. - member_byte_offset = form_value.Unsigned(); - } - break; - - case DW_AT_accessibility: - accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); - break; - case DW_AT_artificial: - is_artificial = form_value.Boolean(); - break; - case DW_AT_APPLE_property_name: - prop_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_getter: - prop_getter_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_setter: - prop_setter_name = form_value.AsCString(); - break; - case DW_AT_APPLE_property_attribute: - prop_attributes = form_value.Unsigned(); - break; - case DW_AT_external: - is_external = form_value.Boolean(); - break; - - default: - case DW_AT_declaration: - case DW_AT_description: - case DW_AT_mutable: - case DW_AT_visibility: - case DW_AT_sibling: - break; + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + if (num_attributes > 0) { + const char *name = nullptr; + const char *prop_name = nullptr; + const char *prop_getter_name = nullptr; + const char *prop_setter_name = nullptr; + uint32_t prop_attributes = 0; + + bool is_artificial = false; + DWARFFormValue encoding_form; + AccessType accessibility = eAccessNone; + uint32_t member_byte_offset = + (parent_die.Tag() == DW_TAG_union_type) ? 0 : UINT32_MAX; + llvm::Optional<uint64_t> byte_size; + int64_t bit_offset = 0; + uint64_t data_bit_offset = UINT64_MAX; + size_t bit_size = 0; + bool is_external = + false; // On DW_TAG_members, this means the member is static + uint32_t i; + for (i = 0; i < num_attributes && !is_artificial; ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + case DW_AT_name: + name = form_value.AsCString(); + break; + case DW_AT_type: + encoding_form = form_value; + break; + case DW_AT_bit_offset: + bit_offset = form_value.Signed(); + break; + case DW_AT_bit_size: + bit_size = form_value.Unsigned(); + break; + case DW_AT_byte_size: + byte_size = form_value.Unsigned(); + break; + case DW_AT_data_bit_offset: + data_bit_offset = form_value.Unsigned(); + break; + case DW_AT_data_member_location: + if (form_value.BlockData()) { + Value initialValue(0); + Value memberOffset(0); + const DWARFDataExtractor &debug_info_data = die.GetData(); + uint32_t block_length = form_value.Unsigned(); + uint32_t block_offset = + form_value.BlockData() - debug_info_data.GetDataStart(); + if (DWARFExpression::Evaluate( + nullptr, // ExecutionContext * + nullptr, // RegisterContext * + module_sp, + DataExtractor(debug_info_data, block_offset, block_length), + die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr, + memberOffset, nullptr)) { + member_byte_offset = memberOffset.ResolveValue(nullptr).UInt(); } + } else { + // With DWARF 3 and later, if the value is an integer constant, + // this form value is the offset in bytes from the beginning of + // the containing entity. + member_byte_offset = form_value.Unsigned(); } - } - - if (prop_name) { - ConstString fixed_getter; - ConstString fixed_setter; - - // Check if the property getter/setter were provided as full names. - // We want basenames, so we extract them. - - if (prop_getter_name && prop_getter_name[0] == '-') { - ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true); - prop_getter_name = prop_getter_method.GetSelector().GetCString(); - } + break; - if (prop_setter_name && prop_setter_name[0] == '-') { - ObjCLanguage::MethodName prop_setter_method(prop_setter_name, true); - prop_setter_name = prop_setter_method.GetSelector().GetCString(); - } + case DW_AT_accessibility: + accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); + break; + case DW_AT_artificial: + is_artificial = form_value.Boolean(); + break; + case DW_AT_APPLE_property_name: + prop_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_getter: + prop_getter_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_setter: + prop_setter_name = form_value.AsCString(); + break; + case DW_AT_APPLE_property_attribute: + prop_attributes = form_value.Unsigned(); + break; + case DW_AT_external: + is_external = form_value.Boolean(); + break; - // If the names haven't been provided, they need to be filled in. + default: + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_mutable: + case DW_AT_visibility: + case DW_AT_sibling: + break; + } + } + } - if (!prop_getter_name) { - prop_getter_name = prop_name; - } - if (!prop_setter_name && prop_name[0] && - !(prop_attributes & DW_APPLE_PROPERTY_readonly)) { - StreamString ss; + if (prop_name) { + ConstString fixed_setter; - ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]); + // Check if the property getter/setter were provided as full names. + // We want basenames, so we extract them. - fixed_setter.SetString(ss.GetString()); - prop_setter_name = fixed_setter.GetCString(); - } - } + if (prop_getter_name && prop_getter_name[0] == '-') { + ObjCLanguage::MethodName prop_getter_method(prop_getter_name, true); + prop_getter_name = prop_getter_method.GetSelector().GetCString(); + } - // Clang has a DWARF generation bug where sometimes it represents - // fields that are references with bad byte size and bit size/offset - // information such as: - // - // DW_AT_byte_size( 0x00 ) - // DW_AT_bit_size( 0x40 ) - // DW_AT_bit_offset( 0xffffffffffffffc0 ) - // - // So check the bit offset to make sure it is sane, and if the values - // are not sane, remove them. If we don't do this then we will end up - // with a crash if we try to use this type in an expression when clang - // becomes unhappy with its recycled debug info. - - if (byte_size.getValueOr(0) == 0 && bit_offset < 0) { - bit_size = 0; - bit_offset = 0; - } + if (prop_setter_name && prop_setter_name[0] == '-') { + ObjCLanguage::MethodName prop_setter_method(prop_setter_name, true); + prop_setter_name = prop_setter_method.GetSelector().GetCString(); + } - // FIXME: Make Clang ignore Objective-C accessibility for expressions - if (class_language == eLanguageTypeObjC || - class_language == eLanguageTypeObjC_plus_plus) - accessibility = eAccessNone; - - // Handle static members - if (is_external && member_byte_offset == UINT32_MAX) { - Type *var_type = die.ResolveTypeUID(encoding_form.Reference()); - - if (var_type) { - if (accessibility == eAccessNone) - accessibility = eAccessPublic; - ClangASTContext::AddVariableToRecordType( - class_clang_type, name, var_type->GetLayoutCompilerType(), - accessibility); - } - break; - } + // If the names haven't been provided, they need to be filled in. - if (!is_artificial) { - Type *member_type = die.ResolveTypeUID(encoding_form.Reference()); - - clang::FieldDecl *field_decl = nullptr; - if (tag == DW_TAG_member) { - if (member_type) { - if (accessibility == eAccessNone) - accessibility = default_accessibility; - member_accessibilities.push_back(accessibility); - - uint64_t field_bit_offset = - (member_byte_offset == UINT32_MAX ? 0 - : (member_byte_offset * 8)); - if (bit_size > 0) { - - BitfieldInfo this_field_info; - this_field_info.bit_offset = field_bit_offset; - this_field_info.bit_size = bit_size; - - ///////////////////////////////////////////////////////////// - // How to locate a field given the DWARF debug information - // - // AT_byte_size indicates the size of the word in which the bit - // offset must be interpreted. - // - // AT_data_member_location indicates the byte offset of the - // word from the base address of the structure. - // - // AT_bit_offset indicates how many bits into the word - // (according to the host endianness) the low-order bit of the - // field starts. AT_bit_offset can be negative. - // - // AT_bit_size indicates the size of the field in bits. - ///////////////////////////////////////////////////////////// - - if (data_bit_offset != UINT64_MAX) { - this_field_info.bit_offset = data_bit_offset; - } else { - if (!byte_size) - byte_size = member_type->GetByteSize(); - - ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); - if (objfile->GetByteOrder() == eByteOrderLittle) { - this_field_info.bit_offset += byte_size.getValueOr(0) * 8; - this_field_info.bit_offset -= (bit_offset + bit_size); - } else { - this_field_info.bit_offset += bit_offset; - } - } + if (!prop_getter_name) { + prop_getter_name = prop_name; + } + if (!prop_setter_name && prop_name[0] && + !(prop_attributes & DW_APPLE_PROPERTY_readonly)) { + StreamString ss; - if ((this_field_info.bit_offset >= parent_bit_size) || - !last_field_info.NextBitfieldOffsetIsValid( - this_field_info.bit_offset)) { - ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); - objfile->GetModule()->ReportWarning( - "0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid " - "bit offset (0x%8.8" PRIx64 - ") member will be ignored. Please file a bug against the " - "compiler and include the preprocessed output for %s\n", - die.GetID(), DW_TAG_value_to_name(tag), name, - this_field_info.bit_offset, - GetUnitName(parent_die).c_str()); - this_field_info.Clear(); - continue; - } + ss.Printf("set%c%s:", toupper(prop_name[0]), &prop_name[1]); - // Update the field bit offset we will report for layout - field_bit_offset = this_field_info.bit_offset; - - // If the member to be emitted did not start on a character - // boundary and there is empty space between the last field and - // this one, then we need to emit an anonymous member filling - // up the space up to its start. There are three cases here: - // - // 1 If the previous member ended on a character boundary, then - // we can emit an - // anonymous member starting at the most recent character - // boundary. - // - // 2 If the previous member did not end on a character boundary - // and the distance - // from the end of the previous member to the current member - // is less than a - // word width, then we can emit an anonymous member starting - // right after the - // previous member and right before this member. - // - // 3 If the previous member did not end on a character boundary - // and the distance - // from the end of the previous member to the current member - // is greater than - // or equal a word width, then we act as in Case 1. - - const uint64_t character_width = 8; - const uint64_t word_width = 32; - - // Objective-C has invalid DW_AT_bit_offset values in older - // versions of clang, so we have to be careful and only insert - // unnamed bitfields if we have a new enough clang. - bool detect_unnamed_bitfields = true; - - if (class_language == eLanguageTypeObjC || - class_language == eLanguageTypeObjC_plus_plus) - detect_unnamed_bitfields = - die.GetCU()->Supports_unnamed_objc_bitfields(); - - if (detect_unnamed_bitfields) { - BitfieldInfo anon_field_info; - - if ((this_field_info.bit_offset % character_width) != - 0) // not char aligned - { - uint64_t last_field_end = 0; - - if (last_field_info.IsValid()) - last_field_end = - last_field_info.bit_offset + last_field_info.bit_size; - - if (this_field_info.bit_offset != last_field_end) { - if (((last_field_end % character_width) == 0) || // case 1 - (this_field_info.bit_offset - last_field_end >= - word_width)) // case 3 - { - anon_field_info.bit_size = - this_field_info.bit_offset % character_width; - anon_field_info.bit_offset = - this_field_info.bit_offset - - anon_field_info.bit_size; - } else // case 2 - { - anon_field_info.bit_size = - this_field_info.bit_offset - last_field_end; - anon_field_info.bit_offset = last_field_end; - } - } - } + fixed_setter.SetString(ss.GetString()); + prop_setter_name = fixed_setter.GetCString(); + } + } - if (anon_field_info.IsValid()) { - clang::FieldDecl *unnamed_bitfield_decl = - ClangASTContext::AddFieldToRecordType( - class_clang_type, llvm::StringRef(), - m_ast.GetBuiltinTypeForEncodingAndBitSize( - eEncodingSint, word_width), - accessibility, anon_field_info.bit_size); + // Clang has a DWARF generation bug where sometimes it represents + // fields that are references with bad byte size and bit size/offset + // information such as: + // + // DW_AT_byte_size( 0x00 ) + // DW_AT_bit_size( 0x40 ) + // DW_AT_bit_offset( 0xffffffffffffffc0 ) + // + // So check the bit offset to make sure it is sane, and if the values + // are not sane, remove them. If we don't do this then we will end up + // with a crash if we try to use this type in an expression when clang + // becomes unhappy with its recycled debug info. + + if (byte_size.getValueOr(0) == 0 && bit_offset < 0) { + bit_size = 0; + bit_offset = 0; + } + + // FIXME: Make Clang ignore Objective-C accessibility for expressions + if (class_language == eLanguageTypeObjC || + class_language == eLanguageTypeObjC_plus_plus) + accessibility = eAccessNone; + + // Handle static members + if (is_external && member_byte_offset == UINT32_MAX) { + Type *var_type = die.ResolveTypeUID(encoding_form.Reference()); + + if (var_type) { + if (accessibility == eAccessNone) + accessibility = eAccessPublic; + ClangASTContext::AddVariableToRecordType( + class_clang_type, name, var_type->GetLayoutCompilerType(), + accessibility); + } + return; + } + + if (!is_artificial) { + Type *member_type = die.ResolveTypeUID(encoding_form.Reference()); + + clang::FieldDecl *field_decl = nullptr; + if (tag == DW_TAG_member) { + if (member_type) { + if (accessibility == eAccessNone) + accessibility = default_accessibility; + member_accessibilities.push_back(accessibility); + + uint64_t field_bit_offset = + (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); + if (bit_size > 0) { + + BitfieldInfo this_field_info; + this_field_info.bit_offset = field_bit_offset; + this_field_info.bit_size = bit_size; + + ///////////////////////////////////////////////////////////// + // How to locate a field given the DWARF debug information + // + // AT_byte_size indicates the size of the word in which the bit + // offset must be interpreted. + // + // AT_data_member_location indicates the byte offset of the + // word from the base address of the structure. + // + // AT_bit_offset indicates how many bits into the word + // (according to the host endianness) the low-order bit of the + // field starts. AT_bit_offset can be negative. + // + // AT_bit_size indicates the size of the field in bits. + ///////////////////////////////////////////////////////////// + + if (data_bit_offset != UINT64_MAX) { + this_field_info.bit_offset = data_bit_offset; + } else { + if (!byte_size) + byte_size = member_type->GetByteSize(); - layout_info.field_offsets.insert(std::make_pair( - unnamed_bitfield_decl, anon_field_info.bit_offset)); - } - } - last_field_info = this_field_info; + ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); + if (objfile->GetByteOrder() == eByteOrderLittle) { + this_field_info.bit_offset += byte_size.getValueOr(0) * 8; + this_field_info.bit_offset -= (bit_offset + bit_size); } else { - last_field_info.Clear(); + this_field_info.bit_offset += bit_offset; } + } - CompilerType member_clang_type = - member_type->GetLayoutCompilerType(); - if (!member_clang_type.IsCompleteType()) - member_clang_type.GetCompleteType(); + if ((this_field_info.bit_offset >= parent_bit_size) || + !last_field_info.NextBitfieldOffsetIsValid( + this_field_info.bit_offset)) { + ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); + objfile->GetModule()->ReportWarning( + "0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid " + "bit offset (0x%8.8" PRIx64 + ") member will be ignored. Please file a bug against the " + "compiler and include the preprocessed output for %s\n", + die.GetID(), DW_TAG_value_to_name(tag), name, + this_field_info.bit_offset, GetUnitName(parent_die).c_str()); + this_field_info.Clear(); + return; + } + // Update the field bit offset we will report for layout + field_bit_offset = this_field_info.bit_offset; + + // If the member to be emitted did not start on a character + // boundary and there is empty space between the last field and + // this one, then we need to emit an anonymous member filling + // up the space up to its start. There are three cases here: + // + // 1 If the previous member ended on a character boundary, then + // we can emit an + // anonymous member starting at the most recent character + // boundary. + // + // 2 If the previous member did not end on a character boundary + // and the distance + // from the end of the previous member to the current member + // is less than a + // word width, then we can emit an anonymous member starting + // right after the + // previous member and right before this member. + // + // 3 If the previous member did not end on a character boundary + // and the distance + // from the end of the previous member to the current member + // is greater than + // or equal a word width, then we act as in Case 1. + + const uint64_t character_width = 8; + const uint64_t word_width = 32; + + // Objective-C has invalid DW_AT_bit_offset values in older + // versions of clang, so we have to be careful and only insert + // unnamed bitfields if we have a new enough clang. + bool detect_unnamed_bitfields = true; + + if (class_language == eLanguageTypeObjC || + class_language == eLanguageTypeObjC_plus_plus) + detect_unnamed_bitfields = + die.GetCU()->Supports_unnamed_objc_bitfields(); + + if (detect_unnamed_bitfields) { + BitfieldInfo anon_field_info; + + if ((this_field_info.bit_offset % character_width) != + 0) // not char aligned { - // Older versions of clang emit array[0] and array[1] in the - // same way (<rdar://problem/12566646>). If the current field - // is at the end of the structure, then there is definitely no - // room for extra elements and we override the type to - // array[0]. - - CompilerType member_array_element_type; - uint64_t member_array_size; - bool member_array_is_incomplete; - - if (member_clang_type.IsArrayType( - &member_array_element_type, &member_array_size, - &member_array_is_incomplete) && - !member_array_is_incomplete) { - uint64_t parent_byte_size = - parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, - UINT64_MAX); - - if (member_byte_offset >= parent_byte_size) { - if (member_array_size != 1 && - (member_array_size != 0 || - member_byte_offset > parent_byte_size)) { - module_sp->ReportError( - "0x%8.8" PRIx64 - ": DW_TAG_member '%s' refers to type 0x%8.8x" - " which extends beyond the bounds of 0x%8.8" PRIx64, - die.GetID(), name, - encoding_form.Reference().GetOffset(), - parent_die.GetID()); - } + uint64_t last_field_end = 0; + + if (last_field_info.IsValid()) + last_field_end = + last_field_info.bit_offset + last_field_info.bit_size; - member_clang_type = m_ast.CreateArrayType( - member_array_element_type, 0, false); + if (this_field_info.bit_offset != last_field_end) { + if (((last_field_end % character_width) == 0) || // case 1 + (this_field_info.bit_offset - last_field_end >= + word_width)) // case 3 + { + anon_field_info.bit_size = + this_field_info.bit_offset % character_width; + anon_field_info.bit_offset = + this_field_info.bit_offset - anon_field_info.bit_size; + } else // case 2 + { + anon_field_info.bit_size = + this_field_info.bit_offset - last_field_end; + anon_field_info.bit_offset = last_field_end; } } } - if (ClangASTContext::IsCXXClassType(member_clang_type) && - !member_clang_type.GetCompleteType()) { - if (die.GetCU()->GetProducer() == eProducerClang) - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type is a forward declaration, not a " - "complete definition.\nTry compiling the source file " - "with -fstandalone-debug", - parent_die.GetOffset(), parent_die.GetName(), - die.GetOffset(), name); - else - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type is a forward declaration, not a " - "complete definition.\nPlease file a bug against the " - "compiler and include the preprocessed output for %s", - parent_die.GetOffset(), parent_die.GetName(), - die.GetOffset(), name, GetUnitName(parent_die).c_str()); - // We have no choice other than to pretend that the member - // class is complete. If we don't do this, clang will crash - // when trying to layout the class. Since we provide layout - // assistance, all ivars in this class and other classes will - // be fine, this is the best we can do short of crashing. - if (ClangASTContext::StartTagDeclarationDefinition( - member_clang_type)) { - ClangASTContext::CompleteTagDeclarationDefinition( - member_clang_type); - } else { - module_sp->ReportError( - "DWARF DIE at 0x%8.8x (class %s) has a member variable " - "0x%8.8x (%s) whose type claims to be a C++ class but we " - "were not able to start its definition.\nPlease file a " - "bug and attach the file at the start of this error " - "message", - parent_die.GetOffset(), parent_die.GetName(), - die.GetOffset(), name); - } + if (anon_field_info.IsValid()) { + clang::FieldDecl *unnamed_bitfield_decl = + ClangASTContext::AddFieldToRecordType( + class_clang_type, llvm::StringRef(), + m_ast.GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, + word_width), + accessibility, anon_field_info.bit_size); + + layout_info.field_offsets.insert(std::make_pair( + unnamed_bitfield_decl, anon_field_info.bit_offset)); } + } + last_field_info = this_field_info; + } else { + last_field_info.Clear(); + } - field_decl = ClangASTContext::AddFieldToRecordType( - class_clang_type, name, member_clang_type, accessibility, - bit_size); + CompilerType member_clang_type = member_type->GetLayoutCompilerType(); + if (!member_clang_type.IsCompleteType()) + member_clang_type.GetCompleteType(); + + { + // Older versions of clang emit array[0] and array[1] in the + // same way (<rdar://problem/12566646>). If the current field + // is at the end of the structure, then there is definitely no + // room for extra elements and we override the type to + // array[0]. + + CompilerType member_array_element_type; + uint64_t member_array_size; + bool member_array_is_incomplete; + + if (member_clang_type.IsArrayType(&member_array_element_type, + &member_array_size, + &member_array_is_incomplete) && + !member_array_is_incomplete) { + uint64_t parent_byte_size = + parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, + UINT64_MAX); + + if (member_byte_offset >= parent_byte_size) { + if (member_array_size != 1 && + (member_array_size != 0 || + member_byte_offset > parent_byte_size)) { + module_sp->ReportError( + "0x%8.8" PRIx64 + ": DW_TAG_member '%s' refers to type 0x%8.8x" + " which extends beyond the bounds of 0x%8.8" PRIx64, + die.GetID(), name, encoding_form.Reference().GetOffset(), + parent_die.GetID()); + } - m_ast.SetMetadataAsUserID(field_decl, die.GetID()); + member_clang_type = + m_ast.CreateArrayType(member_array_element_type, 0, false); + } + } + } - layout_info.field_offsets.insert( - std::make_pair(field_decl, field_bit_offset)); + if (ClangASTContext::IsCXXClassType(member_clang_type) && + !member_clang_type.GetCompleteType()) { + if (die.GetCU()->GetProducer() == eProducerClang) + module_sp->ReportError( + "DWARF DIE at 0x%8.8x (class %s) has a member variable " + "0x%8.8x (%s) whose type is a forward declaration, not a " + "complete definition.\nTry compiling the source file " + "with -fstandalone-debug", + parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), + name); + else + module_sp->ReportError( + "DWARF DIE at 0x%8.8x (class %s) has a member variable " + "0x%8.8x (%s) whose type is a forward declaration, not a " + "complete definition.\nPlease file a bug against the " + "compiler and include the preprocessed output for %s", + parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), + name, GetUnitName(parent_die).c_str()); + // We have no choice other than to pretend that the member + // class is complete. If we don't do this, clang will crash + // when trying to layout the class. Since we provide layout + // assistance, all ivars in this class and other classes will + // be fine, this is the best we can do short of crashing. + if (ClangASTContext::StartTagDeclarationDefinition( + member_clang_type)) { + ClangASTContext::CompleteTagDeclarationDefinition( + member_clang_type); } else { - if (name) - module_sp->ReportError( - "0x%8.8" PRIx64 - ": DW_TAG_member '%s' refers to type 0x%8.8x" - " which was unable to be parsed", - die.GetID(), name, encoding_form.Reference().GetOffset()); - else - module_sp->ReportError( - "0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8x" - " which was unable to be parsed", - die.GetID(), encoding_form.Reference().GetOffset()); + module_sp->ReportError( + "DWARF DIE at 0x%8.8x (class %s) has a member variable " + "0x%8.8x (%s) whose type claims to be a C++ class but we " + "were not able to start its definition.\nPlease file a " + "bug and attach the file at the start of this error " + "message", + parent_die.GetOffset(), parent_die.GetName(), die.GetOffset(), + name); } } - if (prop_name != nullptr && member_type) { - clang::ObjCIvarDecl *ivar_decl = nullptr; + field_decl = ClangASTContext::AddFieldToRecordType( + class_clang_type, name, member_clang_type, accessibility, + bit_size); - if (field_decl) { - ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl); - assert(ivar_decl != nullptr); - } + m_ast.SetMetadataAsUserID(field_decl, die.GetID()); - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - delayed_properties.push_back(DelayedAddObjCClassProperty( - class_clang_type, prop_name, - member_type->GetLayoutCompilerType(), ivar_decl, - prop_setter_name, prop_getter_name, prop_attributes, - &metadata)); + layout_info.field_offsets.insert( + std::make_pair(field_decl, field_bit_offset)); + } else { + if (name) + module_sp->ReportError( + "0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8x" + " which was unable to be parsed", + die.GetID(), name, encoding_form.Reference().GetOffset()); + else + module_sp->ReportError( + "0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8x" + " which was unable to be parsed", + die.GetID(), encoding_form.Reference().GetOffset()); + } + } - if (ivar_decl) - m_ast.SetMetadataAsUserID(ivar_decl, die.GetID()); - } + if (prop_name != nullptr && member_type) { + clang::ObjCIvarDecl *ivar_decl = nullptr; + + if (field_decl) { + ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl); + assert(ivar_decl != nullptr); } + + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + delayed_properties.push_back(DelayedAddObjCClassProperty( + class_clang_type, prop_name, member_type->GetLayoutCompilerType(), + ivar_decl, prop_setter_name, prop_getter_name, prop_attributes, + &metadata)); + + if (ivar_decl) + m_ast.SetMetadataAsUserID(ivar_decl, die.GetID()); } - ++member_idx; - } break; + } + } +} + +bool DWARFASTParserClang::ParseChildMembers( + const DWARFDIE &parent_die, CompilerType &class_clang_type, + const LanguageType class_language, + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes, + std::vector<int> &member_accessibilities, + std::vector<DWARFDIE> &member_function_dies, + DelayedPropertyList &delayed_properties, AccessType &default_accessibility, + bool &is_a_class, ClangASTImporter::LayoutInfo &layout_info) { + if (!parent_die) + return false; + + BitfieldInfo last_field_info; + + ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule(); + ClangASTContext *ast = + llvm::dyn_cast_or_null<ClangASTContext>(class_clang_type.GetTypeSystem()); + if (ast == nullptr) + return false; + + for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); + die = die.GetSibling()) { + dw_tag_t tag = die.Tag(); + + switch (tag) { + case DW_TAG_member: + case DW_TAG_APPLE_property: + ParseSingleMember(die, parent_die, class_clang_type, class_language, + member_accessibilities, default_accessibility, + delayed_properties, layout_info, last_field_info); + break; case DW_TAG_subprogram: // Let the type parsing code handle this one for us. @@ -3552,18 +3522,20 @@ DWARFASTParserClang::ResolveNamespaceDIE(const DWARFDIE &die) { SymbolFileDWARF *dwarf = die.GetDWARF(); if (namespace_name) { dwarf->GetObjectFile()->GetModule()->LogMessage( - log, "ASTContext => %p: 0x%8.8" PRIx64 - ": DW_TAG_namespace with DW_AT_name(\"%s\") => " - "clang::NamespaceDecl *%p (original = %p)", - static_cast<void *>(m_ast.getASTContext()), die.GetID(), + log, + "ASTContext => %p: 0x%8.8" PRIx64 + ": DW_TAG_namespace with DW_AT_name(\"%s\") => " + "clang::NamespaceDecl *%p (original = %p)", + static_cast<void *>(&m_ast.getASTContext()), die.GetID(), namespace_name, static_cast<void *>(namespace_decl), static_cast<void *>(namespace_decl->getOriginalNamespace())); } else { dwarf->GetObjectFile()->GetModule()->LogMessage( - log, "ASTContext => %p: 0x%8.8" PRIx64 - ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p " - "(original = %p)", - static_cast<void *>(m_ast.getASTContext()), die.GetID(), + log, + "ASTContext => %p: 0x%8.8" PRIx64 + ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p " + "(original = %p)", + static_cast<void *>(&m_ast.getASTContext()), die.GetID(), static_cast<void *>(namespace_decl), static_cast<void *>(namespace_decl->getOriginalNamespace())); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 106f9254a449..4ad757247c3e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -128,7 +128,8 @@ protected: const DWARFDIE &parent_die); /// Parse a structure, class, or union type DIE. - lldb::TypeSP ParseStructureLikeDIE(const DWARFDIE &die, + lldb::TypeSP ParseStructureLikeDIE(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs); lldb_private::Type *GetTypeForDIE(const DWARFDIE &die); @@ -159,11 +160,73 @@ protected: UpdateSymbolContextScopeForType(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb::TypeSP type_sp); - lldb::TypeSP ParseTypeFromDWO(const DWARFDIE &die, lldb_private::Log *log); + /// Follow Clang Module Skeleton CU references to find a type definition. + lldb::TypeSP ParseTypeFromClangModule(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, + lldb_private::Log *log); // Return true if this type is a declaration to a type in an external // module. lldb::ModuleSP GetModuleForType(const DWARFDIE &die); + +private: + struct BitfieldInfo { + uint64_t bit_size; + uint64_t bit_offset; + + BitfieldInfo() + : bit_size(LLDB_INVALID_ADDRESS), bit_offset(LLDB_INVALID_ADDRESS) {} + + void Clear() { + bit_size = LLDB_INVALID_ADDRESS; + bit_offset = LLDB_INVALID_ADDRESS; + } + + bool IsValid() const { + return (bit_size != LLDB_INVALID_ADDRESS) && + (bit_offset != LLDB_INVALID_ADDRESS); + } + + bool NextBitfieldOffsetIsValid(const uint64_t next_bit_offset) const { + if (IsValid()) { + // This bitfield info is valid, so any subsequent bitfields must not + // overlap and must be at a higher bit offset than any previous bitfield + // + size. + return (bit_size + bit_offset) <= next_bit_offset; + } else { + // If the this BitfieldInfo is not valid, then any offset isOK + return true; + } + } + }; + + void + ParseSingleMember(const DWARFDIE &die, const DWARFDIE &parent_die, + lldb_private::CompilerType &class_clang_type, + const lldb::LanguageType class_language, + std::vector<int> &member_accessibilities, + lldb::AccessType &default_accessibility, + DelayedPropertyList &delayed_properties, + lldb_private::ClangASTImporter::LayoutInfo &layout_info, + BitfieldInfo &last_field_info); + + bool CompleteRecordType(const DWARFDIE &die, lldb_private::Type *type, + lldb_private::CompilerType &clang_type); + bool CompleteEnumType(const DWARFDIE &die, lldb_private::Type *type, + lldb_private::CompilerType &clang_type); + + lldb::TypeSP ParseTypeModifier(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP ParseEnum(const lldb_private::SymbolContext &sc, + const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP ParseSubroutine(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); + // FIXME: attrs should be passed as a const reference. + lldb::TypeSP ParseArrayType(const DWARFDIE &die, + ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP ParsePointerToMemberType(const DWARFDIE &die, + const ParsedDWARFTypeAttributes &attrs); }; /// Parsed form of all attributes that are relevant for type reconstruction. @@ -181,6 +244,8 @@ struct ParsedDWARFTypeAttributes { bool is_scoped_enum = false; bool is_vector = false; bool is_virtual = false; + bool is_objc_direct_call = false; + bool exports_symbols = false; clang::StorageClass storage = clang::SC_None; const char *mangled_name = nullptr; lldb_private::ConstString name; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 75647dbb082f..454637ef981c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -24,8 +24,8 @@ private: DWARFCompileUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, - DIERef::Section section) - : DWARFUnit(dwarf, uid, header, abbrevs, section) {} + DIERef::Section section, bool is_dwo) + : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp index eb307ce1cce1..5052b825fea6 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.cpp @@ -70,6 +70,17 @@ const DWARFDataExtractor &DWARFContext::getOrLoadLineStrData() { m_data_debug_line_str); } +const DWARFDataExtractor &DWARFContext::getOrLoadLocData() { + return LoadOrGetSection(eSectionTypeDWARFDebugLoc, + eSectionTypeDWARFDebugLocDwo, m_data_debug_loc); +} + +const DWARFDataExtractor &DWARFContext::getOrLoadLocListsData() { + return LoadOrGetSection(eSectionTypeDWARFDebugLocLists, + eSectionTypeDWARFDebugLocListsDwo, + m_data_debug_loclists); +} + const DWARFDataExtractor &DWARFContext::getOrLoadMacroData() { return LoadOrGetSection(eSectionTypeDWARFDebugMacro, llvm::None, m_data_debug_macro); @@ -81,7 +92,8 @@ const DWARFDataExtractor &DWARFContext::getOrLoadRangesData() { } const DWARFDataExtractor &DWARFContext::getOrLoadRngListsData() { - return LoadOrGetSection(eSectionTypeDWARFDebugRngLists, llvm::None, + return LoadOrGetSection(eSectionTypeDWARFDebugRngLists, + eSectionTypeDWARFDebugRngListsDwo, m_data_debug_rnglists); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h index add042384039..8691001b1b76 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFContext.h @@ -34,6 +34,8 @@ private: SectionData m_data_debug_info; SectionData m_data_debug_line; SectionData m_data_debug_line_str; + SectionData m_data_debug_loc; + SectionData m_data_debug_loclists; SectionData m_data_debug_macro; SectionData m_data_debug_ranges; SectionData m_data_debug_rnglists; @@ -41,8 +43,6 @@ private: SectionData m_data_debug_str_offsets; SectionData m_data_debug_types; - bool isDwo() { return m_dwo_section_list != nullptr; } - const DWARFDataExtractor & LoadOrGetSection(lldb::SectionType main_section_type, llvm::Optional<lldb::SectionType> dwo_section_type, @@ -60,6 +60,8 @@ public: const DWARFDataExtractor &getOrLoadDebugInfoData(); const DWARFDataExtractor &getOrLoadLineData(); const DWARFDataExtractor &getOrLoadLineStrData(); + const DWARFDataExtractor &getOrLoadLocData(); + const DWARFDataExtractor &getOrLoadLocListsData(); const DWARFDataExtractor &getOrLoadMacroData(); const DWARFDataExtractor &getOrLoadRangesData(); const DWARFDataExtractor &getOrLoadRngListsData(); @@ -67,6 +69,8 @@ public: const DWARFDataExtractor &getOrLoadStrOffsetsData(); const DWARFDataExtractor &getOrLoadDebugTypesData(); + bool isDwo() { return m_dwo_section_list != nullptr; } + llvm::DWARFContext &GetAsLLVM(); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 5ee0687995a1..c5411a17f274 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -406,39 +406,6 @@ bool DWARFDIE::IsMethod() const { return false; } -DWARFDIE -DWARFDIE::GetContainingDWOModuleDIE() const { - if (IsValid()) { - DWARFDIE top_module_die; - // Now make sure this DIE is scoped in a DW_TAG_module tag and return true - // if so - for (DWARFDIE parent = GetParent(); parent.IsValid(); - parent = parent.GetParent()) { - const dw_tag_t tag = parent.Tag(); - if (tag == DW_TAG_module) - top_module_die = parent; - else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) - break; - } - - return top_module_die; - } - return DWARFDIE(); -} - -lldb::ModuleSP DWARFDIE::GetContainingDWOModule() const { - if (IsValid()) { - DWARFDIE dwo_module_die = GetContainingDWOModuleDIE(); - - if (dwo_module_die) { - const char *module_name = dwo_module_die.GetName(); - if (module_name) - return GetDWARF()->GetDWOModule(lldb_private::ConstString(module_name)); - } - } - return lldb::ModuleSP(); -} - bool DWARFDIE::GetDIENamesAndRanges( const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index a779c589611a..87d52eee9dd9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -22,10 +22,6 @@ public: bool IsMethod() const; // Accessors - lldb::ModuleSP GetContainingDWOModule() const; - - DWARFDIE - GetContainingDWOModuleDIE() const; // Accessing information about a DIE const char *GetMangledName() const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index d1b066ffe80c..056cf33a202f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -16,7 +16,6 @@ #include "DWARFTypeUnit.h" #include "DWARFUnit.h" #include "SymbolFileDWARF.h" -#include "lldb/Core/STLUtils.h" #include "lldb/lldb-private.h" #include "llvm/Support/Error.h" @@ -24,11 +23,6 @@ namespace lldb_private { class DWARFContext; } -typedef std::multimap<const char *, dw_offset_t, CStringCompareFunctionObject> - CStringToDIEMap; -typedef CStringToDIEMap::iterator CStringToDIEMapIter; -typedef CStringToDIEMap::const_iterator CStringToDIEMapConstIter; - class DWARFDebugInfo { public: typedef dw_offset_t (*Callback)(SymbolFileDWARF *dwarf2Data, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 8c0fbeb4b717..320500fe608d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -156,6 +156,7 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, // signed or unsigned LEB 128 values case DW_FORM_addrx: + case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_sdata: case DW_FORM_udata: @@ -200,7 +201,7 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, return false; } -static DWARFRangeList GetRangesOrReportError(const DWARFUnit &unit, +static DWARFRangeList GetRangesOrReportError(DWARFUnit &unit, const DWARFDebugInfoEntry &die, const DWARFFormValue &value) { llvm::Expected<DWARFRangeList> expected_ranges = @@ -223,7 +224,7 @@ static DWARFRangeList GetRangesOrReportError(const DWARFUnit &unit, // Gets the valid address ranges for a given DIE by looking for a // DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges attributes. bool DWARFDebugInfoEntry::GetDIENamesAndRanges( - const DWARFUnit *cu, const char *&name, const char *&mangled, + DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, DWARFExpression *frame_base) const { @@ -343,15 +344,15 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( *frame_base = DWARFExpression( module, DataExtractor(data, block_offset, block_length), cu); } else { - DataExtractor data = dwarf.DebugLocData(); + DataExtractor data = cu->GetLocationData(); const dw_offset_t offset = form_value.Unsigned(); if (data.ValidOffset(offset)) { data = DataExtractor(data, offset, data.GetByteSize() - offset); *frame_base = DWARFExpression(module, data, cu); if (lo_pc != LLDB_INVALID_ADDRESS) { assert(lo_pc >= cu->GetBaseAddress()); - frame_base->SetLocationListSlide(lo_pc - - cu->GetBaseAddress()); + frame_base->SetLocationListAddresses(cu->GetBaseAddress(), + lo_pc); } else { set_frame_base_loclist_addr = true; } @@ -379,7 +380,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( if (set_frame_base_loclist_addr) { dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0); assert(lowest_range_pc >= cu->GetBaseAddress()); - frame_base->SetLocationListSlide(lowest_range_pc - cu->GetBaseAddress()); + frame_base->SetLocationListAddresses(cu->GetBaseAddress(), lowest_range_pc); } if (ranges.IsEmpty() || name == nullptr || mangled == nullptr) { @@ -477,8 +478,6 @@ void DWARFDebugInfoEntry::DumpAttribute( s.PutCString("( "); - SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); - // Check to see if we have any special attribute formatters switch (attr) { case DW_AT_stmt_list: @@ -508,7 +507,7 @@ void DWARFDebugInfoEntry::DumpAttribute( // We have a location list offset as the value that is the offset into // the .debug_loc section that describes the value over it's lifetime uint64_t debug_loc_offset = form_value.Unsigned(); - DWARFExpression::PrintDWARFLocationList(s, cu, dwarf.DebugLocData(), + DWARFExpression::PrintDWARFLocationList(s, cu, cu->GetLocationData(), debug_loc_offset); } } break; @@ -646,25 +645,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( } } } - - // If we're a unit DIE, also check the attributes of the dwo unit (if any). - if (GetParent()) - return 0; - SymbolFileDWARFDwo *dwo_symbol_file = cu->GetDwoSymbolFile(); - if (!dwo_symbol_file) - return 0; - - DWARFCompileUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); - if (!dwo_cu) - return 0; - - DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); - if (!dwo_cu_die.IsValid()) - return 0; - - return dwo_cu_die.GetDIE()->GetAttributeValue( - dwo_cu, attr, form_value, end_attr_offset_ptr, - check_specification_or_abstract_origin); + return 0; } // GetAttributeValueAsString @@ -766,7 +747,7 @@ bool DWARFDebugInfoEntry::GetAttributeAddressRange( } size_t DWARFDebugInfoEntry::GetAttributeAddressRanges( - const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, + DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin) const { ranges.Clear(); @@ -1012,8 +993,7 @@ DWARFDebugInfoEntry::GetQualifiedName(DWARFUnit *cu, return storage.c_str(); } -bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, - const DWARFUnit *cu, +bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die) { bool found_address = false; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 25c885608d85..f35af6e7d498 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -23,6 +23,10 @@ class DWARFDeclContext; #define DIE_SIBLING_IDX_BITSIZE 31 +/// DWARFDebugInfoEntry objects assume that they are living in one big +/// vector and do pointer arithmetic on their this pointers. Don't +/// pass them by value. Due to the way they are constructed in a +/// std::vector, we cannot delete the copy constructor. class DWARFDebugInfoEntry { public: typedef std::vector<DWARFDebugInfoEntry> collection; @@ -46,7 +50,7 @@ public: bool Extract(const lldb_private::DWARFDataExtractor &data, const DWARFUnit *cu, lldb::offset_t *offset_ptr); - bool LookupAddress(const dw_addr_t address, const DWARFUnit *cu, + bool LookupAddress(const dw_addr_t address, DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die); @@ -87,7 +91,7 @@ public: bool check_specification_or_abstract_origin = false) const; size_t GetAttributeAddressRanges( - const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, + DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin = false) const; const char *GetName(const DWARFUnit *cu) const; @@ -112,7 +116,7 @@ public: dw_attr_t attr, DWARFFormValue &form_value); bool GetDIENamesAndRanges( - const DWARFUnit *cu, const char *&name, const char *&mangled, + DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &rangeList, int &decl_file, int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, lldb_private::DWARFExpression *frame_base = nullptr) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index 0b08fa09f906..6c074002cb20 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -95,13 +95,15 @@ void DWARFDebugRanges::Dump(Stream &s, } else if (begin == LLDB_INVALID_ADDRESS) { // A base address selection entry base_addr = end; - s.Address(base_addr, sizeof(dw_addr_t), " Base address = "); + DumpAddress(s.AsRawOstream(), base_addr, sizeof(dw_addr_t), + " Base address = "); } else { // Convert from offset to an address dw_addr_t begin_addr = begin + base_addr; dw_addr_t end_addr = end + base_addr; - s.AddressRange(begin_addr, end_addr, sizeof(dw_addr_t), nullptr); + DumpAddressRange(s.AsRawOstream(), begin_addr, end_addr, + sizeof(dw_addr_t), nullptr); } } } @@ -122,164 +124,3 @@ bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu, } return false; } - -bool DWARFDebugRngLists::ExtractRangeList( - const DWARFDataExtractor &data, uint8_t addrSize, - lldb::offset_t *offset_ptr, std::vector<RngListEntry> &rangeList) { - rangeList.clear(); - - bool error = false; - while (!error) { - switch (data.GetU8(offset_ptr)) { - case DW_RLE_end_of_list: - return true; - - case DW_RLE_start_length: { - dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); - dw_addr_t len = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_start_length, begin, len}); - break; - } - - case DW_RLE_start_end: { - dw_addr_t begin = data.GetMaxU64(offset_ptr, addrSize); - dw_addr_t end = data.GetMaxU64(offset_ptr, addrSize); - rangeList.push_back({DW_RLE_start_end, begin, end}); - break; - } - - case DW_RLE_base_address: { - dw_addr_t base = data.GetMaxU64(offset_ptr, addrSize); - rangeList.push_back({DW_RLE_base_address, base, 0}); - break; - } - - case DW_RLE_offset_pair: { - dw_addr_t begin = data.GetULEB128(offset_ptr); - dw_addr_t end = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_offset_pair, begin, end}); - break; - } - - case DW_RLE_base_addressx: { - dw_addr_t base = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_base_addressx, base, 0}); - break; - } - - case DW_RLE_startx_endx: { - dw_addr_t start = data.GetULEB128(offset_ptr); - dw_addr_t end = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_startx_endx, start, end}); - break; - } - - case DW_RLE_startx_length: { - dw_addr_t start = data.GetULEB128(offset_ptr); - dw_addr_t length = data.GetULEB128(offset_ptr); - rangeList.push_back({DW_RLE_startx_length, start, length}); - break; - } - - default: - lldbassert(0 && "unknown range list entry encoding"); - error = true; - } - } - - return false; -} - -static uint64_t ReadAddressFromDebugAddrSection(const DWARFUnit *cu, - uint32_t index) { - uint32_t index_size = cu->GetAddressByteSize(); - dw_offset_t addr_base = cu->GetAddrBase(); - lldb::offset_t offset = addr_base + index * index_size; - return cu->GetSymbolFileDWARF() - .GetDWARFContext() - .getOrLoadAddrData() - .GetMaxU64(&offset, index_size); -} - -bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu, - dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const { - range_list.Clear(); - dw_addr_t debug_ranges_address = cu->GetRangesBase() + debug_ranges_offset; - auto pos = m_range_map.find(debug_ranges_address); - if (pos != m_range_map.end()) { - dw_addr_t BaseAddr = cu->GetBaseAddress(); - for (const RngListEntry &E : pos->second) { - switch (E.encoding) { - case DW_RLE_start_length: - range_list.Append(DWARFRangeList::Entry(E.value0, E.value1)); - break; - case DW_RLE_base_address: - BaseAddr = E.value0; - break; - case DW_RLE_start_end: - range_list.Append(DWARFRangeList::Entry(E.value0, E.value1 - E.value0)); - break; - case DW_RLE_offset_pair: - range_list.Append( - DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0)); - break; - case DW_RLE_base_addressx: { - BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0); - break; - } - case DW_RLE_startx_endx: { - dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); - dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1); - range_list.Append(DWARFRangeList::Entry(start, end - start)); - break; - } - case DW_RLE_startx_length: { - dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0); - range_list.Append(DWARFRangeList::Entry(start, E.value1)); - break; - } - default: - llvm_unreachable("unexpected encoding"); - } - } - return true; - } - return false; -} - -void DWARFDebugRngLists::Extract(DWARFContext &context) { - const DWARFDataExtractor &data = context.getOrLoadRngListsData(); - lldb::offset_t offset = 0; - - uint64_t length = data.GetU32(&offset); - // FIXME: Handle DWARF64. - lldb::offset_t end = offset + length; - - // Check version. - if (data.GetU16(&offset) < 5) - return; - - uint8_t addrSize = data.GetU8(&offset); - - // We do not support non-zero segment selector size. - if (data.GetU8(&offset) != 0) { - lldbassert(0 && "not implemented"); - return; - } - - uint32_t offsetsAmount = data.GetU32(&offset); - for (uint32_t i = 0; i < offsetsAmount; ++i) - Offsets.push_back(data.GetMaxU64(&offset, 4)); - - lldb::offset_t listOffset = offset; - std::vector<RngListEntry> rangeList; - while (offset < end && ExtractRangeList(data, addrSize, &offset, rangeList)) { - m_range_map[listOffset] = rangeList; - listOffset = offset; - } -} - -uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const { - return Offsets[Index]; -} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h index c398259056b3..1888a7760f27 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h @@ -17,22 +17,13 @@ namespace lldb_private { class DWARFContext; } -class DWARFDebugRangesBase { -public: - virtual ~DWARFDebugRangesBase(){}; - - virtual void Extract(lldb_private::DWARFContext &context) = 0; - virtual bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const = 0; -}; - -class DWARFDebugRanges final : public DWARFDebugRangesBase { +class DWARFDebugRanges { public: DWARFDebugRanges(); - void Extract(lldb_private::DWARFContext &context) override; + void Extract(lldb_private::DWARFContext &context); bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const override; + DWARFRangeList &range_list) const; static void Dump(lldb_private::Stream &s, const lldb_private::DWARFDataExtractor &debug_ranges_data, @@ -48,27 +39,4 @@ protected: range_map m_range_map; }; -// DWARF v5 .debug_rnglists section. -class DWARFDebugRngLists final : public DWARFDebugRangesBase { - struct RngListEntry { - uint8_t encoding; - uint64_t value0; - uint64_t value1; - }; - -public: - void Extract(lldb_private::DWARFContext &context) override; - bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset, - DWARFRangeList &range_list) const override; - uint64_t GetOffset(size_t Index) const; - -protected: - bool ExtractRangeList(const lldb_private::DWARFDataExtractor &data, - uint8_t addrSize, lldb::offset_t *offset_ptr, - std::vector<RngListEntry> &list); - - std::vector<uint64_t> Offsets; - std::map<dw_offset_t, std::vector<RngListEntry>> m_range_map; -}; - #endif // SymbolFileDWARF_DWARFDebugRanges_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h index 6501ac27f27d..348b33464a54 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -63,7 +63,7 @@ public: const char *GetQualifiedName() const; - // Same as GetQaulifiedName, but the life time of the returned string will + // Same as GetQualifiedName, but the life time of the returned string will // be that of the LLDB session. lldb_private::ConstString GetQualifiedNameAsConstString() const { return lldb_private::ConstString(GetQualifiedName()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index 046ae67446af..f660cc32b3f8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -107,6 +107,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, m_value.value.uval = data.GetU64(offset_ptr); break; case DW_FORM_addrx: + case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_strx: case DW_FORM_udata: @@ -305,6 +306,7 @@ bool DWARFFormValue::SkipValue(dw_form_t form, // signed or unsigned LEB 128 values case DW_FORM_addrx: + case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_sdata: case DW_FORM_udata: @@ -333,7 +335,7 @@ void DWARFFormValue::Dump(Stream &s) const { switch (m_form) { case DW_FORM_addr: - s.Address(uvalue, sizeof(uint64_t)); + DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t)); break; case DW_FORM_flag: case DW_FORM_data1: @@ -409,10 +411,11 @@ void DWARFFormValue::Dump(Stream &s) const { assert(m_unit); // Unit must be valid for DW_FORM_ref_addr objects or we // will get this wrong if (m_unit->GetVersion() <= 2) - s.Address(uvalue, sizeof(uint64_t) * 2); + DumpAddress(s.AsRawOstream(), uvalue, sizeof(uint64_t) * 2); else - s.Address(uvalue, 4 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't - // support DWARF64 yet + DumpAddress(s.AsRawOstream(), uvalue, + 4 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't + // support DWARF64 yet break; } case DW_FORM_ref1: @@ -599,105 +602,11 @@ bool DWARFFormValue::IsDataForm(const dw_form_t form) { return false; } -int DWARFFormValue::Compare(const DWARFFormValue &a_value, - const DWARFFormValue &b_value) { - dw_form_t a_form = a_value.Form(); - dw_form_t b_form = b_value.Form(); - if (a_form < b_form) - return -1; - if (a_form > b_form) - return 1; - switch (a_form) { - case DW_FORM_addr: - case DW_FORM_addrx: - case DW_FORM_flag: - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: - case DW_FORM_udata: - case DW_FORM_ref_addr: - case DW_FORM_sec_offset: - case DW_FORM_flag_present: - case DW_FORM_ref_sig8: - case DW_FORM_GNU_addr_index: { - uint64_t a = a_value.Unsigned(); - uint64_t b = b_value.Unsigned(); - if (a < b) - return -1; - if (a > b) - return 1; - return 0; - } - - case DW_FORM_sdata: { - int64_t a = a_value.Signed(); - int64_t b = b_value.Signed(); - if (a < b) - return -1; - if (a > b) - return 1; - return 0; - } - - case DW_FORM_string: - case DW_FORM_strp: - case DW_FORM_GNU_str_index: { - const char *a_string = a_value.AsCString(); - const char *b_string = b_value.AsCString(); - if (a_string == b_string) - return 0; - else if (a_string && b_string) - return strcmp(a_string, b_string); - else if (a_string == nullptr) - return -1; // A string is NULL, and B is valid - else - return 1; // A string valid, and B is NULL - } - - case DW_FORM_block: - case DW_FORM_block1: - case DW_FORM_block2: - case DW_FORM_block4: - case DW_FORM_exprloc: { - uint64_t a_len = a_value.Unsigned(); - uint64_t b_len = b_value.Unsigned(); - if (a_len < b_len) - return -1; - if (a_len > b_len) - return 1; - // The block lengths are the same - return memcmp(a_value.BlockData(), b_value.BlockData(), a_value.Unsigned()); - } break; - - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_udata: { - uint64_t a = a_value.m_value.value.uval; - uint64_t b = b_value.m_value.value.uval; - if (a < b) - return -1; - if (a > b) - return 1; - return 0; - } - - case DW_FORM_indirect: - llvm_unreachable( - "This shouldn't happen after the form has been extracted..."); - - default: - llvm_unreachable("Unhandled DW_FORM"); - } - return -1; -} - bool DWARFFormValue::FormIsSupported(dw_form_t form) { switch (form) { case DW_FORM_addr: case DW_FORM_addrx: + case DW_FORM_loclistx: case DW_FORM_rnglistx: case DW_FORM_block2: case DW_FORM_block4: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h index 6ff73ecd8efa..8967509c081a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -28,8 +28,8 @@ private: DWARFTypeUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, - DIERef::Section section) - : DWARFUnit(dwarf, uid, header, abbrevs, section) {} + DIERef::Section section, bool is_dwo) + : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} friend class DWARFUnit; }; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 9964cf4b893c..22e3e40dac93 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -32,9 +32,9 @@ extern int g_verbose; DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, - DIERef::Section section) + DIERef::Section section, bool is_dwo) : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs), - m_cancel_scopes(false), m_section(section) {} + m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo) {} DWARFUnit::~DWARFUnit() = default; @@ -287,15 +287,27 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { DWARFAttributes attributes; size_t num_attributes = cu_die.GetAttributes(this, attributes); + + // Extract DW_AT_addr_base first, as other attributes may need it. + for (size_t i = 0; i < num_attributes; ++i) { + if (attributes.AttributeAtIndex(i) != DW_AT_addr_base) + continue; + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + addr_base = form_value.Unsigned(); + SetAddrBase(*addr_base); + break; + } + } + for (size_t i = 0; i < num_attributes; ++i) { dw_attr_t attr = attributes.AttributeAtIndex(i); DWARFFormValue form_value; if (!attributes.ExtractFormValueAtIndex(i, form_value)) continue; switch (attr) { - case DW_AT_addr_base: - addr_base = form_value.Unsigned(); - SetAddrBase(*addr_base); + case DW_AT_loclists_base: + SetLoclistsBase(form_value.Unsigned()); break; case DW_AT_rnglists_base: ranges_base = form_value.Unsigned(); @@ -324,6 +336,9 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { } } + if (m_is_dwo) + return; + std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = m_dwarf.GetDwoSymbolFileForCompileUnit(*this, cu_die); if (!dwo_symbol_file) @@ -358,10 +373,18 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { else if (gnu_addr_base) dwo_cu->SetAddrBase(*gnu_addr_base); - if (ranges_base) - dwo_cu->SetRangesBase(*ranges_base); - else if (gnu_ranges_base) + if (GetVersion() <= 4 && gnu_ranges_base) dwo_cu->SetRangesBase(*gnu_ranges_base); + else if (m_dwo_symbol_file->GetDWARFContext() + .getOrLoadRngListsData() + .GetByteSize() > 0) + dwo_cu->SetRangesBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); + + if (GetVersion() >= 5 && m_dwo_symbol_file->GetDWARFContext() + .getOrLoadLocListsData() + .GetByteSize() > 0) + dwo_cu->SetLoclistsBase(llvm::DWARFListTableHeader::getHeaderSize(DWARF32)); + dwo_cu->SetBaseAddress(GetBaseAddress()); for (size_t i = 0; i < m_dwo_symbol_file->DebugInfo()->GetNumUnits(); ++i) { DWARFUnit *unit = m_dwo_symbol_file->DebugInfo()->GetUnitAtIndex(i); @@ -380,24 +403,6 @@ DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { return DWARFDIE(); } -size_t DWARFUnit::AppendDIEsWithTag(const dw_tag_t tag, - std::vector<DWARFDIE> &dies, - uint32_t depth) const { - size_t old_size = dies.size(); - { - llvm::sys::ScopedReader lock(m_die_array_mutex); - DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator end = m_die_array.end(); - for (pos = m_die_array.begin(); pos != end; ++pos) { - if (pos->Tag() == tag) - dies.emplace_back(this, &(*pos)); - } - } - - // Return the number of DIEs added to the collection - return dies.size() - old_size; -} - size_t DWARFUnit::GetDebugInfoSize() const { return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); } @@ -417,8 +422,79 @@ dw_offset_t DWARFUnit::GetLineTableOffset() { void DWARFUnit::SetAddrBase(dw_addr_t addr_base) { m_addr_base = addr_base; } +// Parse the rangelist table header, including the optional array of offsets +// following it (DWARF v5 and later). +template <typename ListTableType> +static llvm::Expected<ListTableType> +ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset, + DwarfFormat format) { + // We are expected to be called with Offset 0 or pointing just past the table + // header. Correct Offset in the latter case so that it points to the start + // of the header. + if (offset > 0) { + uint64_t HeaderSize = llvm::DWARFListTableHeader::getHeaderSize(format); + if (offset < HeaderSize) + return llvm::createStringError(errc::invalid_argument, + "did not detect a valid" + " list table with base = 0x%" PRIx64 "\n", + offset); + offset -= HeaderSize; + } + ListTableType Table; + if (llvm::Error E = Table.extractHeaderAndOffsets(data, &offset)) + return std::move(E); + return Table; +} + +void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) { + m_loclists_base = loclists_base; + + uint64_t header_size = llvm::DWARFListTableHeader::getHeaderSize(DWARF32); + if (loclists_base < header_size) + return; + + m_loclist_table_header.emplace(".debug_loclists", "locations"); + uint64_t offset = loclists_base - header_size; + if (llvm::Error E = m_loclist_table_header->extract( + m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVM(), + &offset)) { + GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "Failed to extract location list table at offset 0x%" PRIx64 ": %s", + loclists_base, toString(std::move(E)).c_str()); + } +} + +std::unique_ptr<llvm::DWARFLocationTable> +DWARFUnit::GetLocationTable(const DataExtractor &data) const { + llvm::DWARFDataExtractor llvm_data( + toStringRef(data.GetData()), + data.GetByteOrder() == lldb::eByteOrderLittle, data.GetAddressByteSize()); + + if (m_is_dwo || GetVersion() >= 5) + return std::make_unique<llvm::DWARFDebugLoclists>(llvm_data, GetVersion()); + return std::make_unique<llvm::DWARFDebugLoc>(llvm_data); +} + +const DWARFDataExtractor &DWARFUnit::GetLocationData() const { + DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext(); + return GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() + : Ctx.getOrLoadLocData(); +} + void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) { m_ranges_base = ranges_base; + + if (GetVersion() < 5) + return; + + if (auto table_or_error = ParseListTableHeader<llvm::DWARFDebugRnglistTable>( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), + ranges_base, DWARF32)) + m_rnglist_table = std::move(table_or_error.get()); + else + GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "Failed to extract range list table at offset 0x%" PRIx64 ": %s", + ranges_base, toString(table_or_error.takeError()).c_str()); } void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) { @@ -646,6 +722,8 @@ FileSpec DWARFUnit::GetFile(size_t file_idx) { // Remove the host part if present. static llvm::StringRef removeHostnameFromPathname(llvm::StringRef path_from_dwarf) { + if (!path_from_dwarf.contains(':')) + return path_from_dwarf; llvm::StringRef host, path; std::tie(host, path) = path_from_dwarf.split(':'); @@ -715,7 +793,8 @@ void DWARFUnit::ComputeAbsolutePath() { m_file_spec->MakeAbsolute(GetCompilationDirectory()); } -SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() const { +SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() { + ExtractUnitDIEIfNeeded(); return m_dwo_symbol_file.get(); } @@ -816,11 +895,12 @@ DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, return llvm::make_error<llvm::object::GenericBinaryError>( "No abbrev exists at the specified offset."); + bool is_dwo = dwarf.GetDWARFContext().isDwo(); if (expected_header->IsTypeUnit()) - return DWARFUnitSP( - new DWARFTypeUnit(dwarf, uid, *expected_header, *abbrevs, section)); - return DWARFUnitSP( - new DWARFCompileUnit(dwarf, uid, *expected_header, *abbrevs, section)); + return DWARFUnitSP(new DWARFTypeUnit(dwarf, uid, *expected_header, *abbrevs, + section, is_dwo)); + return DWARFUnitSP(new DWARFCompileUnit(dwarf, uid, *expected_header, + *abbrevs, section, is_dwo)); } const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { @@ -845,30 +925,56 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { } llvm::Expected<DWARFRangeList> -DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) const { - const DWARFDebugRangesBase *debug_ranges; - llvm::StringRef section; +DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { if (GetVersion() <= 4) { - debug_ranges = m_dwarf.GetDebugRanges(); - section = "debug_ranges"; - } else { - debug_ranges = m_dwarf.GetDebugRngLists(); - section = "debug_rnglists"; + const DWARFDebugRanges *debug_ranges = m_dwarf.GetDebugRanges(); + if (!debug_ranges) + return llvm::make_error<llvm::object::GenericBinaryError>( + "No debug_ranges section"); + DWARFRangeList ranges; + debug_ranges->FindRanges(this, offset, ranges); + return ranges; } - if (!debug_ranges) - return llvm::make_error<llvm::object::GenericBinaryError>("No " + section + - " section"); + + if (!m_rnglist_table) + return llvm::createStringError(errc::invalid_argument, + "missing or invalid range list table"); + + auto range_list_or_error = m_rnglist_table->findList( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), offset); + if (!range_list_or_error) + return range_list_or_error.takeError(); + + llvm::Expected<llvm::DWARFAddressRangesVector> llvm_ranges = + range_list_or_error->getAbsoluteRanges( + llvm::object::SectionedAddress{GetBaseAddress()}, + [&](uint32_t index) { + uint32_t index_size = GetAddressByteSize(); + dw_offset_t addr_base = GetAddrBase(); + lldb::offset_t offset = addr_base + index * index_size; + return llvm::object::SectionedAddress{ + m_dwarf.GetDWARFContext().getOrLoadAddrData().GetMaxU64( + &offset, index_size)}; + }); + if (!llvm_ranges) + return llvm_ranges.takeError(); DWARFRangeList ranges; - debug_ranges->FindRanges(this, offset, ranges); + for (const llvm::DWARFAddressRange &llvm_range : *llvm_ranges) { + ranges.Append(DWARFRangeList::Entry(llvm_range.LowPC, + llvm_range.HighPC - llvm_range.LowPC)); + } return ranges; } llvm::Expected<DWARFRangeList> -DWARFUnit::FindRnglistFromIndex(uint32_t index) const { - const DWARFDebugRngLists *debug_rnglists = m_dwarf.GetDebugRngLists(); - if (!debug_rnglists) - return llvm::make_error<llvm::object::GenericBinaryError>( - "No debug_rnglists section"); - return FindRnglistFromOffset(debug_rnglists->GetOffset(index)); +DWARFUnit::FindRnglistFromIndex(uint32_t index) { + if (llvm::Optional<uint64_t> offset = GetRnglistOffset(index)) + return FindRnglistFromOffset(*offset); + if (m_rnglist_table) + return llvm::createStringError(errc::invalid_argument, + "invalid range list table index %d", index); + + return llvm::createStringError(errc::invalid_argument, + "missing or invalid range list table"); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 87e0de283de4..217f9bb89ace 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -95,8 +95,6 @@ public: ScopedExtractDIEs ExtractDIEsScoped(); DWARFDIE LookupAddress(const dw_addr_t address); - size_t AppendDIEsWithTag(const dw_tag_t tag, std::vector<DWARFDIE> &dies, - uint32_t depth = UINT32_MAX) const; bool Verify(lldb_private::Stream *s) const; virtual void Dump(lldb_private::Stream *s) const = 0; /// Get the data that contains the DIE information for this unit. @@ -147,6 +145,7 @@ public: dw_addr_t GetRangesBase() const { return m_ranges_base; } dw_addr_t GetStrOffsetsBase() const { return m_str_offsets_base; } void SetAddrBase(dw_addr_t addr_base); + void SetLoclistsBase(dw_addr_t loclists_base); void SetRangesBase(dw_addr_t ranges_base); void SetStrOffsetsBase(dw_offset_t str_offsets_base); virtual void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) = 0; @@ -202,7 +201,7 @@ public: lldb_private::FileSpec GetFile(size_t file_idx); lldb_private::FileSpec::Style GetPathStyle(); - SymbolFileDWARFDwo *GetDwoSymbolFile() const; + SymbolFileDWARFDwo *GetDwoSymbolFile(); die_iterator_range dies() { ExtractDIEsIfNeeded(); @@ -216,18 +215,46 @@ public: /// Return a list of address ranges resulting from a (possibly encoded) /// range list starting at a given offset in the appropriate ranges section. - llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset) const; + llvm::Expected<DWARFRangeList> FindRnglistFromOffset(dw_offset_t offset); /// Return a list of address ranges retrieved from an encoded range /// list whose offset is found via a table lookup given an index (DWARF v5 /// and later). - llvm::Expected<DWARFRangeList> FindRnglistFromIndex(uint32_t index) const; + llvm::Expected<DWARFRangeList> FindRnglistFromIndex(uint32_t index); + + /// Return a rangelist's offset based on an index. The index designates + /// an entry in the rangelist table's offset array and is supplied by + /// DW_FORM_rnglistx. + llvm::Optional<uint64_t> GetRnglistOffset(uint32_t Index) const { + if (!m_rnglist_table) + return llvm::None; + if (llvm::Optional<uint64_t> off = m_rnglist_table->getOffsetEntry(Index)) + return *off + m_ranges_base; + return llvm::None; + } + + llvm::Optional<uint64_t> GetLoclistOffset(uint32_t Index) { + if (!m_loclist_table_header) + return llvm::None; + + llvm::Optional<uint64_t> Offset = m_loclist_table_header->getOffsetEntry(Index); + if (!Offset) + return llvm::None; + return *Offset + m_loclists_base; + } + + /// Return the location table for parsing the given location list data. The + /// format is chosen according to the unit type. Never returns null. + std::unique_ptr<llvm::DWARFLocationTable> + GetLocationTable(const lldb_private::DataExtractor &data) const; + + const lldb_private::DWARFDataExtractor &GetLocationData() const; protected: DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, const DWARFAbbreviationDeclarationSet &abbrevs, - DIERef::Section section); + DIERef::Section section, bool is_dwo); llvm::Error ExtractHeader(SymbolFileDWARF &dwarf, const lldb_private::DWARFDataExtractor &data, @@ -281,14 +308,20 @@ protected: lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; llvm::Optional<lldb_private::FileSpec> m_comp_dir; llvm::Optional<lldb_private::FileSpec> m_file_spec; - dw_addr_t m_addr_base = 0; // Value of DW_AT_addr_base - dw_addr_t m_ranges_base = 0; // Value of DW_AT_ranges_base + dw_addr_t m_addr_base = 0; ///< Value of DW_AT_addr_base. + dw_addr_t m_loclists_base = 0; ///< Value of DW_AT_loclists_base. + dw_addr_t m_ranges_base = 0; ///< Value of DW_AT_rnglists_base. /// Value of DW_AT_stmt_list. dw_offset_t m_line_table_offset = DW_INVALID_OFFSET; dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base. + + llvm::Optional<llvm::DWARFDebugRnglistTable> m_rnglist_table; + llvm::Optional<llvm::DWARFListTableHeader> m_loclist_table_header; + const DIERef::Section m_section; + bool m_is_dwo; private: void ParseProducerInfo(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index aff8b5d8c15f..1e5927bd14f0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -401,8 +401,6 @@ void ManualDWARFIndex::GetFunctions(ConstString name, SymbolFileDWARF &dwarf, if (name_type_mask & eFunctionNameTypeFull) { DIEArray offsets; - m_set.function_basenames.Find(name, offsets); - m_set.function_methods.Find(name, offsets); m_set.function_fullnames.Find(name, offsets); for (const DIERef &die_ref: offsets) { DWARFDIE die = dwarf.GetDIE(die_ref); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index c982d59c2830..d45a8b56efe4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -94,6 +94,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARF::ID; + // static inline bool // child_requires_parent_class_union_or_struct_to_be_completed (dw_tag_t tag) //{ @@ -179,36 +181,46 @@ ParseLLVMLineTable(lldb_private::DWARFContext &context, return *line_table; } -static FileSpecList ParseSupportFilesFromPrologue( - const lldb::ModuleSP &module, - const llvm::DWARFDebugLine::Prologue &prologue, FileSpec::Style style, - llvm::StringRef compile_dir = {}, FileSpec first_file = {}) { +static llvm::Optional<std::string> +GetFileByIndex(const llvm::DWARFDebugLine::Prologue &prologue, size_t idx, + llvm::StringRef compile_dir, FileSpec::Style style) { + // Try to get an absolute path first. + std::string abs_path; + auto absolute = llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath; + if (prologue.getFileNameByIndex(idx, compile_dir, absolute, abs_path, style)) + return std::move(abs_path); + + // Otherwise ask for a relative path. + std::string rel_path; + auto relative = llvm::DILineInfoSpecifier::FileLineInfoKind::Default; + if (!prologue.getFileNameByIndex(idx, compile_dir, relative, rel_path, style)) + return {}; + return std::move(rel_path); +} + +static FileSpecList +ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, + const llvm::DWARFDebugLine::Prologue &prologue, + FileSpec::Style style, + llvm::StringRef compile_dir = {}) { FileSpecList support_files; - support_files.Append(first_file); + size_t first_file = 0; + if (prologue.getVersion() <= 4) { + // File index 0 is not valid before DWARF v5. Add a dummy entry to ensure + // support file list indices match those we get from the debug info and line + // tables. + support_files.Append(FileSpec()); + first_file = 1; + } const size_t number_of_files = prologue.FileNames.size(); - for (size_t idx = 1; idx <= number_of_files; ++idx) { - std::string original_file; - if (!prologue.getFileNameByIndex( - idx, compile_dir, - llvm::DILineInfoSpecifier::FileLineInfoKind::Default, original_file, - style)) { - // Always add an entry so the indexes remain correct. - support_files.EmplaceBack(); - continue; - } - + for (size_t idx = first_file; idx <= number_of_files; ++idx) { std::string remapped_file; - if (!prologue.getFileNameByIndex( - idx, compile_dir, - llvm::DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, - remapped_file, style)) { - // Always add an entry so the indexes remain correct. - support_files.EmplaceBack(original_file, style); - continue; - } + if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) + if (!module->RemapSourceFile(llvm::StringRef(*file_path), remapped_file)) + remapped_file = std::move(*file_path); - module->RemapSourceFile(llvm::StringRef(original_file), remapped_file); + // Unconditionally add an entry, so the indices match up. support_files.EmplaceBack(remapped_file, style); } @@ -585,22 +597,6 @@ void SymbolFileDWARF::LoadSectionData(lldb::SectionType sect_type, m_objfile_sp->ReadSectionData(section_sp.get(), data); } -const DWARFDataExtractor &SymbolFileDWARF::DebugLocData() { - const DWARFDataExtractor &debugLocData = get_debug_loc_data(); - if (debugLocData.GetByteSize() > 0) - return debugLocData; - return get_debug_loclists_data(); -} - -const DWARFDataExtractor &SymbolFileDWARF::get_debug_loc_data() { - return GetCachedSectionData(eSectionTypeDWARFDebugLoc, m_data_debug_loc); -} - -const DWARFDataExtractor &SymbolFileDWARF::get_debug_loclists_data() { - return GetCachedSectionData(eSectionTypeDWARFDebugLocLists, - m_data_debug_loclists); -} - DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (m_abbr) return m_abbr.get(); @@ -672,21 +668,6 @@ DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { return m_ranges.get(); } -DWARFDebugRngLists *SymbolFileDWARF::GetDebugRngLists() { - if (!m_rnglists) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, - static_cast<void *>(this)); - - if (m_context.getOrLoadRngListsData().GetByteSize() > 0) - m_rnglists.reset(new DWARFDebugRngLists()); - - if (m_rnglists) - m_rnglists->Extract(m_context); - } - return m_rnglists.get(); -} - lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { CompUnitSP cu_sp; CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); @@ -703,7 +684,8 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { } else { ModuleSP module_sp(m_objfile_sp->GetModule()); if (module_sp) { - const DWARFDIE cu_die = dwarf_cu.DIE(); + const DWARFBaseDIE cu_die = + dwarf_cu.GetNonSkeletonUnit().GetUnitDIEOnly(); if (cu_die) { FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); if (cu_file_spec) { @@ -721,7 +703,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); - bool is_optimized = dwarf_cu.GetIsOptimized(); + bool is_optimized = dwarf_cu.GetNonSkeletonUnit().GetIsOptimized(); BuildCuTranslationTable(); cu_sp = std::make_shared<CompileUnit>( module_sp, &dwarf_cu, cu_file_spec, @@ -828,15 +810,20 @@ lldb::LanguageType SymbolFileDWARF::ParseLanguage(CompileUnit &comp_unit) { } size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer(func_cat, "SymbolFileDWARF::ParseFunctions"); std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (!dwarf_cu) return 0; size_t functions_added = 0; - std::vector<DWARFDIE> function_dies; - dwarf_cu->AppendDIEsWithTag(DW_TAG_subprogram, function_dies); - for (const DWARFDIE &die : function_dies) { + dwarf_cu = &dwarf_cu->GetNonSkeletonUnit(); + for (DWARFDebugInfoEntry &entry : dwarf_cu->dies()) { + if (entry.Tag() != DW_TAG_subprogram) + continue; + + DWARFDIE die(dwarf_cu, &entry); if (comp_unit.FindFunctionByUID(die.GetID())) continue; if (ParseFunction(comp_unit, die)) @@ -846,16 +833,32 @@ size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { return functions_added; } -void SymbolFileDWARF::ForEachExternalModule( - CompileUnit &comp_unit, llvm::function_ref<void(ModuleSP)> f) { - UpdateExternalModuleListIfNeeded(); +bool SymbolFileDWARF::ForEachExternalModule( + CompileUnit &comp_unit, + llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files, + llvm::function_ref<bool(Module &)> lambda) { + // Only visit each symbol file once. + if (!visited_symbol_files.insert(this).second) + return false; + UpdateExternalModuleListIfNeeded(); for (auto &p : m_external_type_modules) { ModuleSP module = p.second; - f(module); - for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) - module->GetCompileUnitAtIndex(i)->ForEachExternalModule(f); + if (!module) + continue; + + // Invoke the action and potentially early-exit. + if (lambda(*module)) + return true; + + for (std::size_t i = 0; i < module->GetNumCompileUnits(); ++i) { + auto cu = module->GetCompileUnitAtIndex(i); + bool early_exit = cu->ForEachExternalModule(visited_symbol_files, lambda); + if (early_exit) + return true; + } } + return false; } bool SymbolFileDWARF::ParseSupportFiles(CompileUnit &comp_unit, @@ -961,7 +964,7 @@ bool SymbolFileDWARF::ParseImportedModules( DW_AT_LLVM_include_path, nullptr)) module.search_path = ConstString(include_path); if (const char *sysroot = module_die.GetAttributeValueAsString( - DW_AT_LLVM_isysroot, nullptr)) + DW_AT_LLVM_sysroot, nullptr)) module.sysroot = ConstString(sysroot); imported_modules.push_back(module); } @@ -1023,7 +1026,7 @@ bool SymbolFileDWARF::ParseLineTable(CompileUnit &comp_unit) { comp_unit.SetSupportFiles(ParseSupportFilesFromPrologue( comp_unit.GetModule(), line_table->Prologue, dwarf_cu->GetPathStyle(), - dwarf_cu->GetCompilationDirectory().GetCString(), FileSpec(comp_unit))); + dwarf_cu->GetCompilationDirectory().GetCString())); return true; } @@ -1507,7 +1510,7 @@ bool SymbolFileDWARF::GetFunction(const DWARFDIE &die, SymbolContext &sc) { return false; } -lldb::ModuleSP SymbolFileDWARF::GetDWOModule(ConstString name) { +lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) { UpdateExternalModuleListIfNeeded(); const auto &pos = m_external_type_modules.find(name); if (pos != m_external_type_modules.end()) @@ -1532,12 +1535,48 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { return DWARFDIE(); } +/// Return the DW_AT_(GNU_)dwo_name. +static const char *GetDWOName(DWARFCompileUnit &dwarf_cu, + const DWARFDebugInfoEntry &cu_die) { + const char *dwo_name = + cu_die.GetAttributeValueAsString(&dwarf_cu, DW_AT_GNU_dwo_name, nullptr); + if (!dwo_name) + dwo_name = + cu_die.GetAttributeValueAsString(&dwarf_cu, DW_AT_dwo_name, nullptr); + return dwo_name; +} + +/// Return the DW_AT_(GNU_)dwo_id. +/// FIXME: Technically 0 is a valid hash. +static uint64_t GetDWOId(DWARFCompileUnit &dwarf_cu, + const DWARFDebugInfoEntry &cu_die) { + uint64_t dwo_id = + cu_die.GetAttributeValueAsUnsigned(&dwarf_cu, DW_AT_GNU_dwo_id, 0); + if (!dwo_id) + dwo_id = cu_die.GetAttributeValueAsUnsigned(&dwarf_cu, DW_AT_dwo_id, 0); + return dwo_id; +} + +llvm::Optional<uint64_t> SymbolFileDWARF::GetDWOId() { + if (GetNumCompileUnits() == 1) { + if (auto comp_unit = GetCompileUnitAtIndex(0)) + if (DWARFCompileUnit *cu = llvm::dyn_cast_or_null<DWARFCompileUnit>( + GetDWARFCompileUnit(comp_unit.get()))) + if (DWARFDebugInfoEntry *cu_die = cu->DIE().GetDIE()) + if (uint64_t dwo_id = ::GetDWOId(*cu, *cu_die)) + return dwo_id; + } + return {}; +} + std::unique_ptr<SymbolFileDWARFDwo> SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( DWARFUnit &unit, const DWARFDebugInfoEntry &cu_die) { - // If we are using a dSYM file, we never want the standard DWO files since - // the -gmodules support uses the same DWO machanism to specify full debug - // info files for modules. + // If this is a Darwin-style debug map (non-.dSYM) symbol file, + // never attempt to load ELF-style DWO files since the -gmodules + // support uses the same DWO machanism to specify full debug info + // files for modules. This is handled in + // UpdateExternalModuleListIfNeeded(). if (GetDebugMapSymfile()) return nullptr; @@ -1546,15 +1585,13 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( if (!dwarf_cu) return nullptr; - const char *dwo_name = - cu_die.GetAttributeValueAsString(dwarf_cu, DW_AT_GNU_dwo_name, nullptr); + const char *dwo_name = GetDWOName(*dwarf_cu, cu_die); if (!dwo_name) return nullptr; SymbolFileDWARFDwp *dwp_symfile = GetDwpSymbolFile(); if (dwp_symfile) { - uint64_t dwo_id = - cu_die.GetAttributeValueAsUnsigned(dwarf_cu, DW_AT_GNU_dwo_id, 0); + uint64_t dwo_id = ::GetDWOId(*dwarf_cu, cu_die); std::unique_ptr<SymbolFileDWARFDwo> dwo_symfile = dwp_symfile->GetSymbolFileForDwoId(*dwarf_cu, dwo_id); if (dwo_symfile) @@ -1594,76 +1631,101 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { if (m_fetched_external_modules) return; m_fetched_external_modules = true; - DWARFDebugInfo *debug_info = DebugInfo(); + // Follow DWO skeleton unit breadcrumbs. const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFUnit *dwarf_cu = debug_info->GetUnitAtIndex(cu_idx); + auto *dwarf_cu = + llvm::dyn_cast<DWARFCompileUnit>(debug_info->GetUnitAtIndex(cu_idx)); + if (!dwarf_cu) + continue; const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); - if (die && !die.HasChildren()) { - const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); - - if (name) { - ConstString const_name(name); - if (m_external_type_modules.find(const_name) == - m_external_type_modules.end()) { - ModuleSP module_sp; - const char *dwo_path = - die.GetAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); - if (dwo_path) { - ModuleSpec dwo_module_spec; - dwo_module_spec.GetFileSpec().SetFile(dwo_path, - FileSpec::Style::native); - if (dwo_module_spec.GetFileSpec().IsRelative()) { - const char *comp_dir = - die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr); - if (comp_dir) { - dwo_module_spec.GetFileSpec().SetFile(comp_dir, - FileSpec::Style::native); - FileSystem::Instance().Resolve(dwo_module_spec.GetFileSpec()); - dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); - } - } - dwo_module_spec.GetArchitecture() = - m_objfile_sp->GetModule()->GetArchitecture(); - - // When LLDB loads "external" modules it looks at the presence of - // DW_AT_GNU_dwo_name. However, when the already created module - // (corresponding to .dwo itself) is being processed, it will see - // the presence of DW_AT_GNU_dwo_name (which contains the name of - // dwo file) and will try to call ModuleList::GetSharedModule - // again. In some cases (i.e. for empty files) Clang 4.0 generates - // a *.dwo file which has DW_AT_GNU_dwo_name, but no - // DW_AT_comp_dir. In this case the method - // ModuleList::GetSharedModule will fail and the warning will be - // printed. However, as one can notice in this case we don't - // actually need to try to load the already loaded module - // (corresponding to .dwo) so we simply skip it. - if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" && - llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath()) - .endswith(dwo_module_spec.GetFileSpec().GetPath())) { - continue; - } + if (!die || die.HasChildren() || !die.GetDIE()) + continue; - Status error = ModuleList::GetSharedModule( - dwo_module_spec, module_sp, nullptr, nullptr, nullptr); - if (!module_sp) { - GetObjectFile()->GetModule()->ReportWarning( - "0x%8.8x: unable to locate module needed for external types: " - "%s\nerror: %s\nDebugging will be degraded due to missing " - "types. Rebuilding your project will regenerate the needed " - "module files.", - die.GetOffset(), - dwo_module_spec.GetFileSpec().GetPath().c_str(), - error.AsCString("unknown error")); - } - } - m_external_type_modules[const_name] = module_sp; - } + const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); + if (!name) + continue; + + ConstString const_name(name); + ModuleSP &module_sp = m_external_type_modules[const_name]; + if (module_sp) + continue; + + const char *dwo_path = GetDWOName(*dwarf_cu, *die.GetDIE()); + if (!dwo_path) + continue; + + ModuleSpec dwo_module_spec; + dwo_module_spec.GetFileSpec().SetFile(dwo_path, FileSpec::Style::native); + if (dwo_module_spec.GetFileSpec().IsRelative()) { + const char *comp_dir = + die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr); + if (comp_dir) { + dwo_module_spec.GetFileSpec().SetFile(comp_dir, + FileSpec::Style::native); + FileSystem::Instance().Resolve(dwo_module_spec.GetFileSpec()); + dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); } } + dwo_module_spec.GetArchitecture() = + m_objfile_sp->GetModule()->GetArchitecture(); + + // When LLDB loads "external" modules it looks at the presence of + // DW_AT_dwo_name. However, when the already created module + // (corresponding to .dwo itself) is being processed, it will see + // the presence of DW_AT_dwo_name (which contains the name of dwo + // file) and will try to call ModuleList::GetSharedModule + // again. In some cases (i.e., for empty files) Clang 4.0 + // generates a *.dwo file which has DW_AT_dwo_name, but no + // DW_AT_comp_dir. In this case the method + // ModuleList::GetSharedModule will fail and the warning will be + // printed. However, as one can notice in this case we don't + // actually need to try to load the already loaded module + // (corresponding to .dwo) so we simply skip it. + if (m_objfile_sp->GetFileSpec().GetFileNameExtension() == ".dwo" && + llvm::StringRef(m_objfile_sp->GetFileSpec().GetPath()) + .endswith(dwo_module_spec.GetFileSpec().GetPath())) { + continue; + } + + Status error = ModuleList::GetSharedModule(dwo_module_spec, module_sp, + nullptr, nullptr, nullptr); + if (!module_sp) { + GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8x: unable to locate module needed for external types: " + "%s\nerror: %s\nDebugging will be degraded due to missing " + "types. Rebuilding the project will regenerate the needed " + "module files.", + die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str(), + error.AsCString("unknown error")); + continue; + } + + // Verify the DWO hash. + // FIXME: Technically "0" is a valid hash. + uint64_t dwo_id = ::GetDWOId(*dwarf_cu, *die.GetDIE()); + if (!dwo_id) + continue; + + auto *dwo_symfile = + llvm::dyn_cast_or_null<SymbolFileDWARF>(module_sp->GetSymbolFile()); + if (!dwo_symfile) + continue; + llvm::Optional<uint64_t> dwo_dwo_id = dwo_symfile->GetDWOId(); + if (!dwo_dwo_id) + continue; + + if (dwo_id != dwo_dwo_id) { + GetObjectFile()->GetModule()->ReportWarning( + "0x%8.8x: Module %s is out-of-date (hash mismatch). Type information " + "from this module may be incomplete or inconsistent with the rest of " + "the program. Rebuilding the project will regenerate the needed " + "module files.", + die.GetOffset(), dwo_module_spec.GetFileSpec().GetPath().c_str()); + } } } @@ -1867,9 +1929,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, if (!dc_cu) continue; - const bool full_match = (bool)file_spec.GetDirectory(); bool file_spec_matches_cu_file_spec = - FileSpec::Equal(file_spec, *dc_cu, full_match); + FileSpec::Match(file_spec, dc_cu->GetPrimaryFile()); if (check_inlines || file_spec_matches_cu_file_spec) { SymbolContext sc(m_objfile_sp->GetModule()); sc.comp_unit = dc_cu; @@ -2208,9 +2269,12 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, addr = sc.function->GetAddressRange().GetBaseAddress(); } - if (addr.IsValid()) { - sc_list.Append(sc); - return true; + + if (auto section_sp = addr.GetSection()) { + if (section_sp->GetPermissions() & ePermissionsExecutable) { + sc_list.Append(sc); + return true; + } } } @@ -2364,12 +2428,10 @@ void SymbolFileDWARF::FindTypes( llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - // Make sure we haven't already searched this SymbolFile before... - if (searched_symbol_files.count(this)) + // Make sure we haven't already searched this SymbolFile before. + if (!searched_symbol_files.insert(this).second) return; - searched_symbol_files.insert(this); - DWARFDebugInfo *info = DebugInfo(); if (!info) return; @@ -2451,8 +2513,13 @@ void SymbolFileDWARF::FindTypes( } } -void SymbolFileDWARF::FindTypes(llvm::ArrayRef<CompilerContext> pattern, - LanguageSet languages, TypeMap &types) { +void SymbolFileDWARF::FindTypes( + llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) { + // Make sure we haven't already searched this SymbolFile before. + if (!searched_symbol_files.insert(this).second) + return; + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); if (pattern.empty()) return; @@ -2482,11 +2549,22 @@ void SymbolFileDWARF::FindTypes(llvm::ArrayRef<CompilerContext> pattern, if (!contextMatches(die_context, pattern)) continue; - if (Type *matching_type = ResolveType(die, true, true)) + if (Type *matching_type = ResolveType(die, true, true)) { // We found a type pointer, now find the shared pointer form our type // list. types.InsertUnique(matching_type->shared_from_this()); + } } + + // Next search through the reachable Clang modules. This only applies for + // DWARF objects compiled with -gmodules that haven't been processed by + // dsymutil. + UpdateExternalModuleListIfNeeded(); + + for (const auto &pair : m_external_type_modules) + if (ModuleSP external_module_sp = pair.second) + external_module_sp->FindTypes(pattern, languages, searched_symbol_files, + types); } CompilerDeclContext @@ -3268,15 +3346,17 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, module, DataExtractor(data, block_offset, block_length), die.GetCU()); } else { - DataExtractor data = DebugLocData(); - const dw_offset_t offset = form_value.Unsigned(); + DataExtractor data = die.GetCU()->GetLocationData(); + dw_offset_t offset = form_value.Unsigned(); + if (form_value.Form() == DW_FORM_loclistx) + offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); if (data.ValidOffset(offset)) { data = DataExtractor(data, offset, data.GetByteSize() - offset); location = DWARFExpression(module, data, die.GetCU()); assert(func_low_pc != LLDB_INVALID_ADDRESS); - location.SetLocationListSlide( - func_low_pc - - attributes.CompileUnitAtIndex(i)->GetBaseAddress()); + location.SetLocationListAddresses( + attributes.CompileUnitAtIndex(i)->GetBaseAddress(), + func_low_pc); } } } break; @@ -3685,8 +3765,8 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { if (child.Tag() != DW_TAG_call_site_parameter) continue; - llvm::Optional<DWARFExpression> LocationInCallee = {}; - llvm::Optional<DWARFExpression> LocationInCaller = {}; + llvm::Optional<DWARFExpression> LocationInCallee; + llvm::Optional<DWARFExpression> LocationInCaller; DWARFAttributes attributes; const size_t num_attributes = child.GetAttributes(attributes); @@ -3725,7 +3805,7 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { } /// Collect call graph edges present in a function DIE. -static std::vector<lldb_private::CallEdge> +static std::vector<std::unique_ptr<lldb_private::CallEdge>> CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // Check if the function has a supported call site-related attribute. // TODO: In the future it may be worthwhile to support call_all_source_calls. @@ -3743,32 +3823,87 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // to be DWARF5-compliant. This may need to be done lazily to be performant. // For now, assume that all entries are nested directly under the subprogram // (this is the kind of DWARF LLVM produces) and parse them eagerly. - std::vector<CallEdge> call_edges; + std::vector<std::unique_ptr<CallEdge>> call_edges; for (DWARFDIE child = function_die.GetFirstChild(); child.IsValid(); child = child.GetSibling()) { if (child.Tag() != DW_TAG_call_site) continue; - // Extract DW_AT_call_origin (the call target's DIE). - DWARFDIE call_origin = child.GetReferencedDIE(DW_AT_call_origin); - if (!call_origin.IsValid()) { - LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", - function_die.GetPubname()); + llvm::Optional<DWARFDIE> call_origin; + llvm::Optional<DWARFExpression> call_target; + addr_t return_pc = LLDB_INVALID_ADDRESS; + + DWARFAttributes attributes; + const size_t num_attributes = child.GetAttributes(attributes); + for (size_t i = 0; i < num_attributes; ++i) { + DWARFFormValue form_value; + if (!attributes.ExtractFormValueAtIndex(i, form_value)) { + LLDB_LOG(log, "CollectCallEdges: Could not extract TAG_call_site form"); + break; + } + + dw_attr_t attr = attributes.AttributeAtIndex(i); + + // Extract DW_AT_call_origin (the call target's DIE). + if (attr == DW_AT_call_origin) { + call_origin = form_value.Reference(); + if (!call_origin->IsValid()) { + LLDB_LOG(log, "CollectCallEdges: Invalid call origin in {0}", + function_die.GetPubname()); + break; + } + } + + // Extract DW_AT_call_return_pc (the PC the call returns to) if it's + // available. It should only ever be unavailable for tail call edges, in + // which case use LLDB_INVALID_ADDRESS. + if (attr == DW_AT_call_return_pc) + return_pc = form_value.Address(); + + // Extract DW_AT_call_target (the location of the address of the indirect + // call). + if (attr == DW_AT_call_target) { + if (!DWARFFormValue::IsBlockForm(form_value.Form())) { + LLDB_LOG(log, + "CollectCallEdges: AT_call_target does not have block form"); + break; + } + + auto data = child.GetData(); + uint32_t block_offset = form_value.BlockData() - data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + call_target = DWARFExpression( + module, DataExtractor(data, block_offset, block_length), + child.GetCU()); + } + } + if (!call_origin && !call_target) { + LLDB_LOG(log, "CollectCallEdges: call site without any call target"); continue; } - // Extract DW_AT_call_return_pc (the PC the call returns to) if it's - // available. It should only ever be unavailable for tail call edges, in - // which case use LLDB_INVALID_ADDRESS. - addr_t return_pc = child.GetAttributeValueAsAddress(DW_AT_call_return_pc, - LLDB_INVALID_ADDRESS); - // Extract call site parameters. CallSiteParameterArray parameters = CollectCallSiteParameters(module, child); - LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", - call_origin.GetPubname(), return_pc); + std::unique_ptr<CallEdge> edge; + if (call_origin) { + LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", + call_origin->GetPubname(), return_pc); + edge = std::make_unique<DirectCallEdge>(call_origin->GetMangledName(), + return_pc, std::move(parameters)); + } else { + if (log) { + StreamString call_target_desc; + call_target->GetDescription(&call_target_desc, eDescriptionLevelBrief, + LLDB_INVALID_ADDRESS, nullptr); + LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}", + call_target_desc.GetString()); + } + edge = std::make_unique<IndirectCallEdge>(*call_target, return_pc, + std::move(parameters)); + } + if (log && parameters.size()) { for (const CallSiteParameter ¶m : parameters) { StreamString callee_loc_desc, caller_loc_desc; @@ -3783,13 +3918,12 @@ CollectCallEdges(ModuleSP module, DWARFDIE function_die) { } } - call_edges.emplace_back(call_origin.GetMangledName(), return_pc, - std::move(parameters)); + call_edges.push_back(std::move(edge)); } return call_edges; } -std::vector<lldb_private::CallEdge> +std::vector<std::unique_ptr<lldb_private::CallEdge>> SymbolFileDWARF::ParseCallEdgesInFunction(UserID func_id) { DWARFDIE func_die = GetDIE(func_id.GetID()); if (func_die.IsValid()) @@ -3829,13 +3963,6 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { return m_debug_map_symfile; } -DWARFExpression::LocationListFormat -SymbolFileDWARF::GetLocationListFormat() const { - if (m_data_debug_loclists.m_data.GetByteSize() > 0) - return DWARFExpression::LocLists; - return DWARFExpression::RegularLocationList; -} - SymbolFileDWARFDwp *SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { ModuleSpec module_spec; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 04cb11d426be..23e26732453f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -21,7 +21,6 @@ #include "lldb/Core/UniqueCStringMap.h" #include "lldb/Core/dwarf.h" -#include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" @@ -47,7 +46,6 @@ class DWARFDebugInfo; class DWARFDebugInfoEntry; class DWARFDebugLine; class DWARFDebugRanges; -class DWARFDebugRngLists; class DWARFDeclContext; class DWARFFormValue; class DWARFTypeUnit; @@ -59,7 +57,18 @@ class SymbolFileDWARFDwp; class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::UserID { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + friend class SymbolFileDWARFDebugMap; friend class SymbolFileDWARFDwo; friend class DebugMapModule; @@ -105,9 +114,9 @@ public: bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; - void - ForEachExternalModule(lldb_private::CompileUnit &comp_unit, - llvm::function_ref<void(lldb::ModuleSP)> f) override; + bool ForEachExternalModule( + lldb_private::CompileUnit &, llvm::DenseSet<lldb_private::SymbolFile *> &, + llvm::function_ref<bool(lldb_private::Module &)>) override; bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, lldb_private::FileSpecList &support_files) override; @@ -190,6 +199,7 @@ public: void FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> pattern, lldb_private::LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; void GetTypes(lldb_private::SymbolContextScope *sc_scope, @@ -212,9 +222,6 @@ public: uint32_t GetPluginVersion() override; - const lldb_private::DWARFDataExtractor &get_debug_loc_data(); - const lldb_private::DWARFDataExtractor &get_debug_loclists_data(); - DWARFDebugAbbrev *DebugAbbrev(); const DWARFDebugAbbrev *DebugAbbrev() const; @@ -224,9 +231,6 @@ public: const DWARFDebugInfo *DebugInfo() const; DWARFDebugRanges *GetDebugRanges(); - DWARFDebugRngLists *GetDebugRngLists(); - - const lldb_private::DWARFDataExtractor &DebugLocData(); static bool SupportedVersion(uint16_t version); @@ -250,10 +254,7 @@ public: virtual lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu); - virtual lldb_private::DWARFExpression::LocationListFormat - GetLocationListFormat() const; - - lldb::ModuleSP GetDWOModule(lldb_private::ConstString name); + lldb::ModuleSP GetExternalModule(lldb_private::ConstString name); typedef std::map<lldb_private::ConstString, lldb::ModuleSP> ExternalTypeModuleMap; @@ -277,7 +278,7 @@ public: lldb::user_id_t GetUID(DIERef ref); - virtual std::unique_ptr<SymbolFileDWARFDwo> + std::unique_ptr<SymbolFileDWARFDwo> GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die); @@ -288,11 +289,14 @@ public: virtual llvm::Optional<uint32_t> GetDwoNum() { return llvm::None; } + /// If this is a DWARF object with a single CU, return its DW_AT_dwo_id. + llvm::Optional<uint64_t> GetDWOId(); + static bool DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, const DWARFDIE &die); - std::vector<lldb_private::CallEdge> + std::vector<std::unique_ptr<lldb_private::CallEdge>> ParseCallEdgesInFunction(UserID func_id) override; void Dump(lldb_private::Stream &s) override; @@ -484,7 +488,6 @@ protected: typedef llvm::StringMap<DIERefSet> NameToOffsetMap; NameToOffsetMap m_function_scope_qualified_name_map; std::unique_ptr<DWARFDebugRanges> m_ranges; - std::unique_ptr<DWARFDebugRngLists> m_rnglists; UniqueDWARFASTTypeMap m_unique_ast_type_map; DIEToTypePtr m_die_to_type; DIEToVariableSP m_die_to_variable_sp; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index a50d4e460bae..cce666a222d0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -39,6 +39,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARFDebugMap::ID; + // Subclass lldb_private::Module so we can intercept the // "Module::GetObjectFile()" (so we can fixup the object file sections) and // also for "Module::GetSymbolFile()" (so we can fixup the symbol file id. @@ -602,7 +604,7 @@ SymbolFileDWARFDebugMap::CompileUnitInfo * SymbolFileDWARFDebugMap::GetCompUnitInfo(const CompileUnit &comp_unit) { const uint32_t cu_count = GetNumCompileUnits(); for (uint32_t i = 0; i < cu_count; ++i) { - if (comp_unit == m_compile_unit_infos[i].compile_unit_sp.get()) + if (&comp_unit == m_compile_unit_infos[i].compile_unit_sp.get()) return &m_compile_unit_infos[i]; } return nullptr; @@ -652,12 +654,15 @@ bool SymbolFileDWARFDebugMap::ParseDebugMacros(CompileUnit &comp_unit) { return false; } -void SymbolFileDWARFDebugMap::ForEachExternalModule( - CompileUnit &comp_unit, llvm::function_ref<void(ModuleSP)> f) { +bool SymbolFileDWARFDebugMap::ForEachExternalModule( + CompileUnit &comp_unit, + llvm::DenseSet<lldb_private::SymbolFile *> &visited_symbol_files, + llvm::function_ref<bool(Module &)> f) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); SymbolFileDWARF *oso_dwarf = GetSymbolFile(comp_unit); if (oso_dwarf) - oso_dwarf->ForEachExternalModule(comp_unit, f); + return oso_dwarf->ForEachExternalModule(comp_unit, visited_symbol_files, f); + return false; } bool SymbolFileDWARFDebugMap::ParseSupportFiles(CompileUnit &comp_unit, @@ -807,12 +812,8 @@ uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( if (!resolve) { FileSpec so_file_spec; - if (GetFileSpecForSO(i, so_file_spec)) { - // Match the full path if the incoming file_spec has a directory (not - // just a basename) - const bool full_match = (bool)file_spec.GetDirectory(); - resolve = FileSpec::Equal(file_spec, so_file_spec, full_match); - } + if (GetFileSpecForSO(i, so_file_spec)) + resolve = FileSpec::Match(file_spec, so_file_spec); } if (resolve) { SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(i); @@ -1071,7 +1072,7 @@ void SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, } } -std::vector<lldb_private::CallEdge> +std::vector<std::unique_ptr<lldb_private::CallEdge>> SymbolFileDWARFDebugMap::ParseCallEdgesInFunction(UserID func_id) { uint32_t oso_idx = GetOSOIndexFromUserID(func_id.GetID()); SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); @@ -1183,6 +1184,16 @@ void SymbolFileDWARFDebugMap::FindTypes( }); } +void SymbolFileDWARFDebugMap::FindTypes( + llvm::ArrayRef<CompilerContext> context, LanguageSet languages, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, + TypeMap &types) { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + oso_dwarf->FindTypes(context, languages, searched_symbol_files, types); + return false; + }); +} + // // uint32_t // SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 7adee1b356ce..035a902498be 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -23,7 +23,18 @@ class DWARFDebugAranges; class DWARFDeclContext; class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + // Static Functions static void Initialize(); @@ -53,9 +64,9 @@ public: bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override; - void - ForEachExternalModule(lldb_private::CompileUnit &comp_unit, - llvm::function_ref<void(lldb::ModuleSP)> f) override; + bool ForEachExternalModule( + lldb_private::CompileUnit &, llvm::DenseSet<lldb_private::SymbolFile *> &, + llvm::function_ref<bool(lldb_private::Module &)>) override; bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit, lldb_private::FileSpecList &support_files) override; @@ -114,13 +125,18 @@ public: uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; + void + FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> context, + lldb_private::LanguageSet languages, + llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, + lldb_private::TypeMap &types) override; lldb_private::CompilerDeclContext FindNamespace( lldb_private::ConstString name, const lldb_private::CompilerDeclContext *parent_decl_ctx) override; void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, lldb_private::TypeList &type_list) override; - std::vector<lldb_private::CallEdge> + std::vector<std::unique_ptr<lldb_private::CallEdge>> ParseCallEdgesInFunction(lldb_private::UserID func_id) override; void DumpClangAST(lldb_private::Stream &s) override; @@ -348,8 +364,8 @@ protected: /// \param[in] oso_symfile /// The DWARF symbol file that produced the \a line_table /// - /// \param[in] addr - /// A section offset address from a .o file + /// \param[in] line_table + /// A pointer to the line table. /// /// \return /// Returns a valid line table full of linked addresses, or NULL diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index b0f7e813d4f8..f75f06f31e2d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -21,6 +21,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARFDwo::ID; + SymbolFileDWARFDwo::SymbolFileDWARFDwo(ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu) : SymbolFileDWARF(objfile, objfile->GetSectionList( @@ -135,11 +137,6 @@ SymbolFileDWARF &SymbolFileDWARFDwo::GetBaseSymbolFile() { return m_base_dwarf_cu.GetSymbolFileDWARF(); } -DWARFExpression::LocationListFormat -SymbolFileDWARFDwo::GetLocationListFormat() const { - return DWARFExpression::SplitDwarfLocationList; -} - llvm::Expected<TypeSystem &> SymbolFileDWARFDwo::GetTypeSystemForLanguage(LanguageType language) { return GetBaseSymbolFile().GetTypeSystemForLanguage(language); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index ad290cdcf65e..0855dba044e4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -12,7 +12,18 @@ #include "SymbolFileDWARF.h" class SymbolFileDWARFDwo : public SymbolFileDWARF { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFileDWARF::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + SymbolFileDWARFDwo(lldb::ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu); ~SymbolFileDWARFDwo() override = default; @@ -24,9 +35,6 @@ public: DWARFUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) override; - lldb_private::DWARFExpression::LocationListFormat - GetLocationListFormat() const override; - size_t GetObjCMethodDIEOffsets(lldb_private::ConstString class_name, DIEArray &method_die_offsets) override; @@ -36,12 +44,6 @@ public: DWARFDIE GetDIE(const DIERef &die_ref) override; - std::unique_ptr<SymbolFileDWARFDwo> - GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, - const DWARFDebugInfoEntry &cu_die) override { - return nullptr; - } - DWARFCompileUnit *GetBaseCompileUnit() override { return &m_base_dwarf_cu; } llvm::Optional<uint32_t> GetDwoNum() override { return GetID() >> 32; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp index efea192b17ce..4288dcb5c9bd 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp @@ -19,6 +19,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileDWARFDwoDwp::ID; + SymbolFileDWARFDwoDwp::SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h index 2105e1a8f6cb..a55795ba5950 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h @@ -13,7 +13,17 @@ #include "SymbolFileDWARFDwp.h" class SymbolFileDWARFDwoDwp : public SymbolFileDWARFDwo { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFileDWARFDwo::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, lldb::ObjectFileSP objfile, DWARFCompileUnit &dwarf_cu, uint64_t dwo_id); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 986b0b785d87..4588c80aa1b1 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -17,7 +17,7 @@ #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" @@ -655,7 +655,7 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { lldbassert(IsTagRecord(type_id, m_index.tpi())); - clang::QualType tag_qt = m_clang.getASTContext()->getTypeDeclType(&tag); + clang::QualType tag_qt = m_clang.getASTContext().getTypeDeclType(&tag); ClangASTContext::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false); TypeIndex tag_ti = type_id.index; @@ -700,7 +700,7 @@ clang::QualType PdbAstBuilder::CreateSimpleType(TypeIndex ti) { if (ti.getSimpleMode() != SimpleTypeMode::Direct) { clang::QualType direct_type = GetOrCreateType(ti.makeDirect()); - return m_clang.getASTContext()->getPointerType(direct_type); + return m_clang.getASTContext().getPointerType(direct_type); } if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated) @@ -725,19 +725,17 @@ clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) { MemberPointerInfo mpi = pointer.getMemberInfo(); clang::QualType class_type = GetOrCreateType(mpi.ContainingType); - return m_clang.getASTContext()->getMemberPointerType( + return m_clang.getASTContext().getMemberPointerType( pointee_type, class_type.getTypePtr()); } clang::QualType pointer_type; if (pointer.getMode() == PointerMode::LValueReference) - pointer_type = - m_clang.getASTContext()->getLValueReferenceType(pointee_type); + pointer_type = m_clang.getASTContext().getLValueReferenceType(pointee_type); else if (pointer.getMode() == PointerMode::RValueReference) - pointer_type = - m_clang.getASTContext()->getRValueReferenceType(pointee_type); + pointer_type = m_clang.getASTContext().getRValueReferenceType(pointee_type); else - pointer_type = m_clang.getASTContext()->getPointerType(pointee_type); + pointer_type = m_clang.getASTContext().getPointerType(pointee_type); if ((pointer.getOptions() & PointerOptions::Const) != PointerOptions::None) pointer_type.addConst(); @@ -778,9 +776,8 @@ clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, metadata.SetUserID(toOpaqueUid(id)); metadata.SetIsDynamicCXXType(false); - CompilerType ct = - m_clang.CreateRecordType(context, access, uname.c_str(), ttk, - lldb::eLanguageTypeC_plus_plus, &metadata); + CompilerType ct = m_clang.CreateRecordType( + context, access, uname, ttk, lldb::eLanguageTypeC_plus_plus, &metadata); lldbassert(ct.IsValid()); @@ -1081,7 +1078,7 @@ void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, PdbCompilandSymId param_uid(func_id.modi, record_offset); clang::QualType qt = GetOrCreateType(param_type); - CompilerType param_type_ct(&m_clang, qt.getAsOpaquePtr()); + CompilerType param_type_ct = m_clang.GetType(qt); clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( &function_decl, param_name.str().c_str(), param_type_ct, clang::SC_None, true); @@ -1346,7 +1343,7 @@ CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) { CompilerDeclContext PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) { - return {&m_clang, &context}; + return m_clang.CreateDeclContext(&context); } clang::Decl * PdbAstBuilder::FromCompilerDecl(CompilerDecl decl) { diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index 33b8da3b543b..370c339fb74b 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -20,7 +20,6 @@ #include "lldb/Core/StreamBuffer.h" #include "lldb/Core/StreamFile.h" #include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" @@ -67,6 +66,8 @@ using namespace npdb; using namespace llvm::codeview; using namespace llvm::pdb; +char SymbolFileNativePDB::ID; + static lldb::LanguageType TranslateLanguage(PDB_Lang lang) { switch (lang) { case PDB_Lang::Cpp: @@ -460,7 +461,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id, return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(name), modified_type->GetByteSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, - ct, Type::eResolveStateFull); + ct, Type::ResolveState::Full); } lldb::TypeSP @@ -480,7 +481,7 @@ SymbolFileNativePDB::CreatePointerType(PdbTypeSymId type_id, return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(), pr.getSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, - Type::eResolveStateFull); + Type::ResolveState::Full); } lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti, @@ -490,7 +491,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti, Declaration decl; return std::make_shared<Type>( uid, this, ConstString("std::nullptr_t"), 0, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull); + Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full); } if (ti.getSimpleMode() != SimpleTypeMode::Direct) { @@ -511,7 +512,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti, Declaration decl; return std::make_shared<Type>( uid, this, ConstString(), pointer_size, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull); + Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full); } if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated) @@ -523,7 +524,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti, Declaration decl; return std::make_shared<Type>(uid, this, ConstString(type_name), size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, - decl, ct, Type::eResolveStateFull); + decl, ct, Type::ResolveState::Full); } static std::string GetUnqualifiedTypeName(const TagRecord &record) { @@ -557,7 +558,7 @@ SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id, return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(uname), size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, - Type::eResolveStateForward); + Type::ResolveState::Forward); } lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, @@ -584,7 +585,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, toOpaqueUid(type_id), this, ConstString(uname), underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct, - lldb_private::Type::eResolveStateForward); + lldb_private::Type::ResolveState::Forward); } TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id, @@ -596,7 +597,7 @@ TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id, TypeSP array_sp = std::make_shared<lldb_private::Type>( toOpaqueUid(type_id), this, ConstString(), ar.Size, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct, - lldb_private::Type::eResolveStateFull); + lldb_private::Type::ResolveState::Full); array_sp->SetEncodingType(element_type.get()); return array_sp; } @@ -609,7 +610,7 @@ TypeSP SymbolFileNativePDB::CreateFunctionType(PdbTypeSymId type_id, return std::make_shared<lldb_private::Type>( toOpaqueUid(type_id), this, ConstString(), 0, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct, - lldb_private::Type::eResolveStateFull); + lldb_private::Type::ResolveState::Full); } TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id, @@ -619,7 +620,7 @@ TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id, return std::make_shared<lldb_private::Type>( toOpaqueUid(type_id), this, ConstString(), 0, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct, - lldb_private::Type::eResolveStateFull); + lldb_private::Type::ResolveState::Full); } TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) { @@ -1108,9 +1109,7 @@ bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) { // LLDB wants the index of the file in the list of support files. auto fn_iter = llvm::find(cci->m_file_list, *efn); lldbassert(fn_iter != cci->m_file_list.end()); - // LLDB support file indices are 1-based. - uint32_t file_index = - 1 + std::distance(cci->m_file_list.begin(), fn_iter); + uint32_t file_index = std::distance(cci->m_file_list.begin(), fn_iter); std::unique_ptr<LineSequence> sequence( line_table->CreateLineSequenceContainer()); @@ -1153,14 +1152,6 @@ bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit, FileSpec spec(f, style); support_files.Append(spec); } - - llvm::SmallString<64> main_source_file = - m_index->compilands().GetMainSourceFile(*cci); - FileSpec::Style style = main_source_file.startswith("/") - ? FileSpec::Style::posix - : FileSpec::Style::windows; - FileSpec spec(main_source_file, style); - support_files.Insert(0, spec); return true; } @@ -1259,8 +1250,9 @@ void SymbolFileNativePDB::FindTypes( FindTypesByName(name.GetStringRef(), max_matches, types); } -void SymbolFileNativePDB::FindTypes(llvm::ArrayRef<CompilerContext> pattern, - LanguageSet languages, TypeMap &types) {} +void SymbolFileNativePDB::FindTypes( + llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) {} void SymbolFileNativePDB::FindTypesByName(llvm::StringRef name, uint32_t max_matches, @@ -1386,7 +1378,7 @@ TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) { toOpaqueUid(id), this, ConstString(udt.Name), target_type->GetByteSize(), nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, decl, target_type->GetForwardCompilerType(), - lldb_private::Type::eResolveStateForward); + lldb_private::Type::ResolveState::Forward); } TypeSP SymbolFileNativePDB::GetOrCreateTypedef(PdbGlobalSymId id) { diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h index ca7de0e7d1ed..a37de0f58ef3 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -41,7 +41,18 @@ class PdbAstBuilder; class SymbolFileNativePDB : public SymbolFile { friend class UdtRecordCompleter; + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + // Static Functions static void Initialize(); @@ -131,6 +142,7 @@ public: TypeMap &types) override; void FindTypes(llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, TypeMap &types) override; llvm::Expected<TypeSystem &> diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index 3c494dc83986..7221144407c1 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -231,6 +231,6 @@ void UdtRecordCompleter::complete() { ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct); if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) { - m_ast_builder.importer().InsertRecordDecl(record_decl, m_layout); + m_ast_builder.importer().SetRecordLayout(record_decl, m_layout); } } diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 47c4ad088494..6b2dbd9e1e5a 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -16,7 +16,7 @@ #include "lldb/Core/Module.h" #include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolFile.h" @@ -103,9 +103,7 @@ static CompilerType GetBuiltinTypeForPDBEncodingAndBitSize(ClangASTContext &clang_ast, const PDBSymbolTypeBuiltin &pdb_type, Encoding encoding, uint32_t width) { - auto *ast = clang_ast.getASTContext(); - if (!ast) - return CompilerType(); + clang::ASTContext &ast = clang_ast.getASTContext(); switch (pdb_type.getBuiltinType()) { default: @@ -119,32 +117,25 @@ GetBuiltinTypeForPDBEncodingAndBitSize(ClangASTContext &clang_ast, case PDB_BuiltinType::Bool: return clang_ast.GetBasicType(eBasicTypeBool); case PDB_BuiltinType::Long: - if (width == ast->getTypeSize(ast->LongTy)) - return CompilerType(ClangASTContext::GetASTContext(ast), - ast->LongTy.getAsOpaquePtr()); - if (width == ast->getTypeSize(ast->LongLongTy)) - return CompilerType(ClangASTContext::GetASTContext(ast), - ast->LongLongTy.getAsOpaquePtr()); + if (width == ast.getTypeSize(ast.LongTy)) + return CompilerType(&clang_ast, ast.LongTy.getAsOpaquePtr()); + if (width == ast.getTypeSize(ast.LongLongTy)) + return CompilerType(&clang_ast, ast.LongLongTy.getAsOpaquePtr()); break; case PDB_BuiltinType::ULong: - if (width == ast->getTypeSize(ast->UnsignedLongTy)) - return CompilerType(ClangASTContext::GetASTContext(ast), - ast->UnsignedLongTy.getAsOpaquePtr()); - if (width == ast->getTypeSize(ast->UnsignedLongLongTy)) - return CompilerType(ClangASTContext::GetASTContext(ast), - ast->UnsignedLongLongTy.getAsOpaquePtr()); + if (width == ast.getTypeSize(ast.UnsignedLongTy)) + return CompilerType(&clang_ast, ast.UnsignedLongTy.getAsOpaquePtr()); + if (width == ast.getTypeSize(ast.UnsignedLongLongTy)) + return CompilerType(&clang_ast, ast.UnsignedLongLongTy.getAsOpaquePtr()); break; case PDB_BuiltinType::WCharT: - if (width == ast->getTypeSize(ast->WCharTy)) - return CompilerType(ClangASTContext::GetASTContext(ast), - ast->WCharTy.getAsOpaquePtr()); + if (width == ast.getTypeSize(ast.WCharTy)) + return CompilerType(&clang_ast, ast.WCharTy.getAsOpaquePtr()); break; case PDB_BuiltinType::Char16: - return CompilerType(ClangASTContext::GetASTContext(ast), - ast->Char16Ty.getAsOpaquePtr()); + return CompilerType(&clang_ast, ast.Char16Ty.getAsOpaquePtr()); case PDB_BuiltinType::Char32: - return CompilerType(ClangASTContext::GetASTContext(ast), - ast->Char32Ty.getAsOpaquePtr()); + return CompilerType(&clang_ast, ast.Char32Ty.getAsOpaquePtr()); case PDB_BuiltinType::Float: // Note: types `long double` and `double` have same bit size in MSVC and // there is no information in the PDB to distinguish them. So when falling @@ -405,7 +396,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { // This may occur with const or volatile types. There are separate type // symbols in PDB for types with const or volatile modifiers, but we need // to create only one declaration for them all. - Type::ResolveStateTag type_resolve_state_tag; + Type::ResolveState type_resolve_state; CompilerType clang_type = m_ast.GetTypeForIdentifier<clang::CXXRecordDecl>( ConstString(name), decl_context); if (!clang_type.IsValid()) { @@ -417,9 +408,9 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { metadata.SetUserID(type.getSymIndexId()); metadata.SetIsDynamicCXXType(false); - clang_type = m_ast.CreateRecordType( - decl_context, access, name.c_str(), tag_type_kind, - lldb::eLanguageTypeC_plus_plus, &metadata); + clang_type = + m_ast.CreateRecordType(decl_context, access, name, tag_type_kind, + lldb::eLanguageTypeC_plus_plus, &metadata); assert(clang_type.IsValid()); auto record_decl = @@ -428,7 +419,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { m_uid_to_decl[type.getSymIndexId()] = record_decl; auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit( - *m_ast.getASTContext(), GetMSInheritance(*udt)); + m_ast.getASTContext(), GetMSInheritance(*udt)); record_decl->addAttr(inheritance_attr); ClangASTContext::StartTagDeclarationDefinition(clang_type); @@ -442,7 +433,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(), false); - type_resolve_state_tag = Type::eResolveStateFull; + type_resolve_state = Type::ResolveState::Full; } else { // Add the type to the forward declarations. It will help us to avoid // an endless recursion in CompleteTypeFromUdt function. @@ -451,10 +442,10 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { ClangASTContext::SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); - type_resolve_state_tag = Type::eResolveStateForward; + type_resolve_state = Type::ResolveState::Forward; } } else - type_resolve_state_tag = Type::eResolveStateForward; + type_resolve_state = Type::ResolveState::Forward; if (udt->isConstType()) clang_type = clang_type.AddConstModifier(); @@ -467,7 +458,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), udt->getLength(), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type, - type_resolve_state_tag); + type_resolve_state); } break; case PDB_SymType::Enum: { auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type); @@ -535,7 +526,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { return std::make_shared<lldb_private::Type>( type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, - ast_enum, lldb_private::Type::eResolveStateFull); + ast_enum, lldb_private::Type::ResolveState::Full); } break; case PDB_SymType::Typedef: { auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type); @@ -558,7 +549,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { CompilerType target_ast_type = target_type->GetFullCompilerType(); ast_typedef = m_ast.CreateTypedefType( - target_ast_type, name.c_str(), CompilerDeclContext(&m_ast, decl_ctx)); + target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx)); if (!ast_typedef) return nullptr; @@ -581,7 +572,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), size, nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, decl, ast_typedef, - lldb_private::Type::eResolveStateFull); + lldb_private::Type::ResolveState::Full); } break; case PDB_SymType::Function: case PDB_SymType::FunctionSig: { @@ -649,7 +640,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), llvm::None, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, func_sig_ast_type, - lldb_private::Type::eResolveStateFull); + lldb_private::Type::ResolveState::Full); } break; case PDB_SymType::ArrayType: { auto array_type = llvm::dyn_cast<PDBSymbolTypeArray>(&type); @@ -683,7 +674,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { TypeSP type_sp = std::make_shared<lldb_private::Type>( array_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), bytes, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, - decl, array_ast_type, lldb_private::Type::eResolveStateFull); + decl, array_ast_type, lldb_private::Type::ResolveState::Full); type_sp->SetEncodingType(element_type); return type_sp; } break; @@ -712,7 +703,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { return std::make_shared<lldb_private::Type>( builtin_type->getSymIndexId(), m_ast.GetSymbolFile(), type_name, bytes, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, - builtin_ast_type, lldb_private::Type::eResolveStateFull); + builtin_ast_type, lldb_private::Type::ResolveState::Full); } break; case PDB_SymType::PointerType: { auto *pointer_type = llvm::dyn_cast<PDBSymbolTypePointer>(&type); @@ -739,7 +730,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { pointer_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), pointer_type->getLength(), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, pointer_ast_type, - lldb_private::Type::eResolveStateForward); + lldb_private::Type::ResolveState::Forward); } CompilerType pointer_ast_type; @@ -764,7 +755,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { pointer_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), pointer_type->getLength(), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, pointer_ast_type, - lldb_private::Type::eResolveStateFull); + lldb_private::Type::ResolveState::Full); } break; default: break; @@ -900,7 +891,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { // Check if the current context already contains the symbol with the name. clang::Decl *decl = - GetDeclFromContextByName(*m_ast.getASTContext(), *decl_context, name); + GetDeclFromContextByName(m_ast.getASTContext(), *decl_context, name); if (!decl) { auto type = symbol_file->ResolveTypeUID(data->getTypeId()); if (!type) @@ -1160,7 +1151,7 @@ bool PDBASTParser::AddEnumValue(CompilerType enum_type, } CompilerType underlying_type = m_ast.GetEnumerationIntegerType(enum_type.GetOpaqueQualType()); - uint32_t byte_size = m_ast.getASTContext()->getTypeSize( + uint32_t byte_size = m_ast.getASTContext().getTypeSize( ClangUtil::GetQualType(underlying_type)); auto enum_constant_decl = m_ast.AddEnumerationValueToEnumerationType( enum_type, decl, name.c_str(), raw_value, byte_size * 8); @@ -1207,7 +1198,7 @@ bool PDBASTParser::CompleteTypeFromUDT( if (!record_decl) return static_cast<bool>(compiler_type); - GetClangASTImporter().InsertRecordDecl(record_decl, layout_info); + GetClangASTImporter().SetRecordLayout(record_decl, layout_info); return static_cast<bool>(compiler_type); } diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index 854e735b5f83..917ab68af418 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -58,6 +58,8 @@ using namespace lldb; using namespace lldb_private; using namespace llvm::pdb; +char SymbolFilePDB::ID; + namespace { lldb::LanguageType TranslateLanguage(PDB_Lang lang) { switch (lang) { @@ -369,10 +371,6 @@ bool SymbolFilePDB::ParseSupportFiles( support_files.AppendIfUnique(spec); } - // LLDB uses the DWARF-like file numeration (one based), - // the zeroth file is the compile unit itself - support_files.Insert(0, comp_unit); - return true; } @@ -668,7 +666,7 @@ SymbolFilePDB::GetDeclContextForUID(lldb::user_id_t uid) { if (!decl_context) return GetDeclContextContainingUID(uid); - return CompilerDeclContext(clang_ast_ctx, decl_context); + return clang_ast_ctx->CreateDeclContext(decl_context); } lldb_private::CompilerDeclContext @@ -697,7 +695,7 @@ SymbolFilePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { auto decl_context = pdb->GetDeclContextContainingSymbol(*symbol); assert(decl_context); - return CompilerDeclContext(clang_ast_ctx, decl_context); + return clang_ast_ctx->CreateDeclContext(decl_context); } void SymbolFilePDB::ParseDeclsForContext( @@ -1562,9 +1560,10 @@ void SymbolFilePDB::FindTypesByName( } } -void SymbolFilePDB::FindTypes(llvm::ArrayRef<CompilerContext> pattern, - LanguageSet languages, - lldb_private::TypeMap &types) {} +void SymbolFilePDB::FindTypes( + llvm::ArrayRef<CompilerContext> pattern, LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, + lldb_private::TypeMap &types) {} void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol, uint32_t type_mask, @@ -1704,8 +1703,7 @@ lldb_private::CompilerDeclContext SymbolFilePDB::FindNamespace( if (!namespace_decl) return CompilerDeclContext(); - return CompilerDeclContext(clang_type_system, - static_cast<clang::DeclContext *>(namespace_decl)); + return clang_type_system->CreateDeclContext(namespace_decl); } lldb_private::ConstString SymbolFilePDB::GetPluginName() { @@ -1777,7 +1775,6 @@ bool SymbolFilePDB::ParseCompileUnitLineTable(CompileUnit &comp_unit, auto line_table = std::make_unique<LineTable>(&comp_unit); // Find contributions to `compiland` from all source and header files. - std::string path = comp_unit.GetPath(); auto files = m_session_up->getSourceFilesForCompiland(*compiland_up); if (!files) return false; @@ -1879,9 +1876,7 @@ void SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap( if (!source_files) return; - // LLDB uses the DWARF-like file numeration (one based) - int index = 1; - + int index = 0; while (auto file = source_files->getNext()) { uint32_t source_id = file->getUniqueId(); index_map[source_id] = index++; diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h index df717bbbbdb0..7a4eee48771a 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -22,7 +22,18 @@ class PDBASTParser; class SymbolFilePDB : public lldb_private::SymbolFile { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + // Static Functions static void Initialize(); @@ -134,6 +145,7 @@ public: void FindTypes(llvm::ArrayRef<lldb_private::CompilerContext> pattern, lldb_private::LanguageSet languages, + llvm::DenseSet<SymbolFile *> &searched_symbol_files, lldb_private::TypeMap &types) override; void FindTypesByRegex(const lldb_private::RegularExpression ®ex, diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index 62da76581c3e..305efea1afab 100644 --- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -25,6 +25,8 @@ using namespace lldb; using namespace lldb_private; +char SymbolFileSymtab::ID; + void SymbolFileSymtab::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h index 2ac4660f0125..1fff8188433e 100644 --- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -16,7 +16,18 @@ #include "lldb/Symbol/Symtab.h" class SymbolFileSymtab : public lldb_private::SymbolFile { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + /// \{ + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + /// \} + // Constructors and Destructors SymbolFileSymtab(lldb::ObjectFileSP objfile_sp); diff --git a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index e61e5763fabb..d4d7a8937c12 100644 --- a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -119,14 +119,17 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList(); static const SectionType g_sections[] = { - eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAddr, - eSectionTypeDWARFDebugAranges, eSectionTypeDWARFDebugCuIndex, - eSectionTypeDWARFDebugFrame, eSectionTypeDWARFDebugInfo, - eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLoc, - eSectionTypeDWARFDebugMacInfo, eSectionTypeDWARFDebugPubNames, - eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, - eSectionTypeDWARFDebugStr, eSectionTypeDWARFDebugStrOffsets, - eSectionTypeELFSymbolTable, eSectionTypeDWARFGNUDebugAltLink, + eSectionTypeDWARFDebugAbbrev, eSectionTypeDWARFDebugAddr, + eSectionTypeDWARFDebugAranges, eSectionTypeDWARFDebugCuIndex, + eSectionTypeDWARFDebugFrame, eSectionTypeDWARFDebugInfo, + eSectionTypeDWARFDebugLine, eSectionTypeDWARFDebugLineStr, + eSectionTypeDWARFDebugLoc, eSectionTypeDWARFDebugLocLists, + eSectionTypeDWARFDebugMacInfo, eSectionTypeDWARFDebugMacro, + eSectionTypeDWARFDebugNames, eSectionTypeDWARFDebugPubNames, + eSectionTypeDWARFDebugPubTypes, eSectionTypeDWARFDebugRanges, + eSectionTypeDWARFDebugRngLists, eSectionTypeDWARFDebugStr, + eSectionTypeDWARFDebugStrOffsets, eSectionTypeDWARFDebugTypes, + eSectionTypeELFSymbolTable, eSectionTypeDWARFGNUDebugAltLink, }; for (SectionType section_type : g_sections) { if (SectionSP section_sp = |