diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:09:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:09:23 +0000 |
| commit | f73363f1dd94996356cefbf24388f561891acf0b (patch) | |
| tree | e3c31248bdb36eaec5fd833490d4278162dba2a0 /source/Plugins/SymbolFile | |
| parent | 160ee69dd7ae18978f4068116777639ea98dc951 (diff) | |
Notes
Diffstat (limited to 'source/Plugins/SymbolFile')
71 files changed, 6490 insertions, 4642 deletions
diff --git a/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp new file mode 100644 index 000000000000..db75cf9c3bb3 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -0,0 +1,177 @@ +//===-- AppleDWARFIndex.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" +#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" +#include "Plugins/SymbolFile/DWARF/DWARFUnit.h" +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" + +#include "lldb/Core/Module.h" +#include "lldb/Symbol/Function.h" + +using namespace lldb_private; +using namespace lldb; + +std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create( + Module &module, DWARFDataExtractor apple_names, + DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types, + DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) { + auto apple_names_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( + apple_names, debug_str, ".apple_names"); + if (!apple_names_table_up->IsValid()) + apple_names_table_up.reset(); + + auto apple_namespaces_table_up = + llvm::make_unique<DWARFMappedHash::MemoryTable>( + apple_namespaces, debug_str, ".apple_namespaces"); + if (!apple_namespaces_table_up->IsValid()) + apple_namespaces_table_up.reset(); + + auto apple_types_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( + apple_types, debug_str, ".apple_types"); + if (!apple_types_table_up->IsValid()) + apple_types_table_up.reset(); + + auto apple_objc_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>( + apple_objc, debug_str, ".apple_objc"); + if (!apple_objc_table_up->IsValid()) + apple_objc_table_up.reset(); + + if (apple_names_table_up || apple_names_table_up || apple_types_table_up || + apple_objc_table_up) + return llvm::make_unique<AppleDWARFIndex>( + module, std::move(apple_names_table_up), + std::move(apple_namespaces_table_up), std::move(apple_types_table_up), + std::move(apple_objc_table_up)); + + return nullptr; +} + +void AppleDWARFIndex::GetGlobalVariables(ConstString basename, DIEArray &offsets) { + if (m_apple_names_up) + m_apple_names_up->FindByName(basename.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) { + if (!m_apple_names_up) + return; + + DWARFMappedHash::DIEInfoArray hash_data; + if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); +} + +void AppleDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, + DIEArray &offsets) { + if (!m_apple_names_up) + return; + + DWARFMappedHash::DIEInfoArray hash_data; + if (m_apple_names_up->AppendAllDIEsInRange( + cu.GetOffset(), cu.GetNextCompileUnitOffset(), hash_data)) + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); +} + +void AppleDWARFIndex::GetObjCMethods(ConstString class_name, + DIEArray &offsets) { + if (m_apple_objc_up) + m_apple_objc_up->FindByName(class_name.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetCompleteObjCClass(ConstString class_name, + bool must_be_implementation, + DIEArray &offsets) { + if (m_apple_types_up) { + m_apple_types_up->FindCompleteObjCClassByName( + class_name.GetStringRef(), offsets, must_be_implementation); + } +} + +void AppleDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { + if (m_apple_types_up) + m_apple_types_up->FindByName(name.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context, + DIEArray &offsets) { + if (!m_apple_types_up) + return; + + Log *log = LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION | + DWARF_LOG_LOOKUPS); + const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom( + DWARFMappedHash::eAtomTypeTag); + const bool has_qualified_name_hash = + m_apple_types_up->GetHeader().header_data.ContainsAtom( + DWARFMappedHash::eAtomTypeQualNameHash); + const ConstString type_name(context[0].name); + const dw_tag_t tag = context[0].tag; + if (has_tag && has_qualified_name_hash) { + const char *qualified_name = context.GetQualifiedName(); + const uint32_t qualified_name_hash = llvm::djbHash(qualified_name); + if (log) + m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()"); + m_apple_types_up->FindByNameAndTagAndQualifiedNameHash( + type_name.GetStringRef(), tag, qualified_name_hash, offsets); + } else if (has_tag) { + if (log) + m_module.LogMessage(log, "FindByNameAndTag()"); + m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets); + } else + m_apple_types_up->FindByName(type_name.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { + if (m_apple_namespaces_up) + m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets); +} + +void AppleDWARFIndex::GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) { + DIEArray offsets; + m_apple_names_up->FindByName(name.GetStringRef(), offsets); + for (const DIERef &die_ref : offsets) { + ProcessFunctionDIE(name.GetStringRef(), die_ref, info, parent_decl_ctx, + name_type_mask, dies); + } +} + +void AppleDWARFIndex::GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) { + if (!m_apple_names_up) + return; + + DWARFMappedHash::DIEInfoArray hash_data; + if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) + DWARFMappedHash::ExtractDIEArray(hash_data, offsets); +} + +void AppleDWARFIndex::ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) { + m_module.ReportErrorIfModifyDetected( + "the DWARF debug information has been modified (accelerator table had " + "bad die 0x%8.8x for '%s')\n", + offset, name.str().c_str()); +} + +void AppleDWARFIndex::Dump(Stream &s) { + if (m_apple_names_up) + s.PutCString(".apple_names index present\n"); + if (m_apple_namespaces_up) + s.PutCString(".apple_namespaces index present\n"); + if (m_apple_types_up) + s.PutCString(".apple_types index present\n"); + if (m_apple_objc_up) + s.PutCString(".apple_objc index present\n"); + // TODO: Dump index contents +} diff --git a/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h b/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h new file mode 100644 index 000000000000..ea133d0e73cf --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.h @@ -0,0 +1,64 @@ +//===-- AppleDWARFIndex.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_APPLEDWARFINDEX_H +#define LLDB_APPLEDWARFINDEX_H + +#include "Plugins/SymbolFile/DWARF/DWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/HashedNameToDIE.h" + +namespace lldb_private { +class AppleDWARFIndex : public DWARFIndex { +public: + static std::unique_ptr<AppleDWARFIndex> + Create(Module &module, DWARFDataExtractor apple_names, + DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types, + DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str); + + AppleDWARFIndex( + Module &module, std::unique_ptr<DWARFMappedHash::MemoryTable> apple_names, + std::unique_ptr<DWARFMappedHash::MemoryTable> apple_namespaces, + std::unique_ptr<DWARFMappedHash::MemoryTable> apple_types, + std::unique_ptr<DWARFMappedHash::MemoryTable> apple_objc) + : DWARFIndex(module), m_apple_names_up(std::move(apple_names)), + m_apple_namespaces_up(std::move(apple_namespaces)), + m_apple_types_up(std::move(apple_types)), + m_apple_objc_up(std::move(apple_objc)) {} + + void Preload() override {} + + void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; + void GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) override; + void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; + void GetObjCMethods(ConstString class_name, DIEArray &offsets) override; + void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, + DIEArray &offsets) override; + void GetTypes(ConstString name, DIEArray &offsets) override; + void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; + void GetNamespaces(ConstString name, DIEArray &offsets) override; + void GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) override; + void GetFunctions(const RegularExpression ®ex, DIEArray &offsets) override; + + void ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) override; + void Dump(Stream &s) override; + +private: + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_names_up; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_up; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_types_up; + std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_up; +}; +} // namespace lldb_private + +#endif // LLDB_APPLEDWARFINDEX_H diff --git a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt index 05d9e6642868..f62a496f808a 100644 --- a/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -1,4 +1,6 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN + AppleDWARFIndex.cpp + DebugNamesDWARFIndex.cpp DIERef.cpp DWARFAbbreviationDeclaration.cpp DWARFASTParserClang.cpp @@ -6,6 +8,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN DWARFASTParserJava.cpp DWARFASTParserOCaml.cpp DWARFAttribute.cpp + DWARFBaseDIE.cpp DWARFCompileUnit.cpp DWARFDataExtractor.cpp DWARFDebugAbbrev.cpp @@ -17,16 +20,17 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN DWARFDebugMacro.cpp DWARFDebugMacinfo.cpp DWARFDebugMacinfoEntry.cpp - DWARFDebugPubnames.cpp - DWARFDebugPubnamesSet.cpp DWARFDebugRanges.cpp DWARFDeclContext.cpp DWARFDefines.cpp DWARFDIE.cpp DWARFDIECollection.cpp DWARFFormValue.cpp + DWARFIndex.cpp + DWARFUnit.cpp HashedNameToDIE.cpp LogChannelDWARF.cpp + ManualDWARFIndex.cpp NameToDIE.cpp SymbolFileDWARF.cpp SymbolFileDWARFDwo.cpp diff --git a/source/Plugins/SymbolFile/DWARF/DIERef.cpp b/source/Plugins/SymbolFile/DWARF/DIERef.cpp index c05444c031e6..0cd0f0c0272a 100644 --- a/source/Plugins/SymbolFile/DWARF/DIERef.cpp +++ b/source/Plugins/SymbolFile/DWARF/DIERef.cpp @@ -8,17 +8,12 @@ //===----------------------------------------------------------------------===// #include "DIERef.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" #include "DWARFFormValue.h" #include "SymbolFileDWARF.h" #include "SymbolFileDWARFDebugMap.h" -DIERef::DIERef() - : cu_offset(DW_INVALID_OFFSET), die_offset(DW_INVALID_OFFSET) {} - -DIERef::DIERef(dw_offset_t c, dw_offset_t d) : cu_offset(c), die_offset(d) {} - DIERef::DIERef(lldb::user_id_t uid, SymbolFileDWARF *dwarf) : cu_offset(DW_INVALID_OFFSET), die_offset(uid & 0xffffffff) { SymbolFileDWARFDebugMap *debug_map = dwarf->GetDebugMapSymfile(); @@ -28,7 +23,7 @@ DIERef::DIERef(lldb::user_id_t uid, SymbolFileDWARF *dwarf) if (actual_dwarf) { DWARFDebugInfo *debug_info = actual_dwarf->DebugInfo(); if (debug_info) { - DWARFCompileUnit *dwarf_cu = + DWARFUnit *dwarf_cu = debug_info->GetCompileUnitContainingDIEOffset(die_offset); if (dwarf_cu) { cu_offset = dwarf_cu->GetOffset(); @@ -45,7 +40,7 @@ DIERef::DIERef(lldb::user_id_t uid, SymbolFileDWARF *dwarf) DIERef::DIERef(const DWARFFormValue &form_value) : cu_offset(DW_INVALID_OFFSET), die_offset(DW_INVALID_OFFSET) { if (form_value.IsValid()) { - const DWARFCompileUnit *dwarf_cu = form_value.GetCompileUnit(); + const DWARFUnit *dwarf_cu = form_value.GetCompileUnit(); if (dwarf_cu) { if (dwarf_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) cu_offset = dwarf_cu->GetBaseObjOffset(); diff --git a/source/Plugins/SymbolFile/DWARF/DIERef.h b/source/Plugins/SymbolFile/DWARF/DIERef.h index d0048d0f6d6b..cb28c890c25a 100644 --- a/source/Plugins/SymbolFile/DWARF/DIERef.h +++ b/source/Plugins/SymbolFile/DWARF/DIERef.h @@ -17,9 +17,9 @@ class DWARFFormValue; class SymbolFileDWARF; struct DIERef { - DIERef(); + DIERef() = default; - DIERef(dw_offset_t c, dw_offset_t d); + DIERef(dw_offset_t c, dw_offset_t d) : cu_offset(c), die_offset(d) {} //---------------------------------------------------------------------- // In order to properly decode a lldb::user_id_t back into a DIERef we @@ -45,8 +45,12 @@ struct DIERef { bool operator<(const DIERef &ref) { return die_offset < ref.die_offset; } - dw_offset_t cu_offset; - dw_offset_t die_offset; + explicit operator bool() const { + return cu_offset != DW_INVALID_OFFSET || die_offset != DW_INVALID_OFFSET; + } + + dw_offset_t cu_offset = DW_INVALID_OFFSET; + dw_offset_t die_offset = DW_INVALID_OFFSET; }; typedef std::vector<DIERef> DIEArray; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 54b12cfb3b8c..fe6f1be3ca48 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -10,13 +10,13 @@ #include <stdlib.h> #include "DWARFASTParserClang.h" -#include "DWARFCompileUnit.h" #include "DWARFDIE.h" #include "DWARFDIECollection.h" #include "DWARFDebugInfo.h" #include "DWARFDeclContext.h" #include "DWARFDefines.h" #include "SymbolFileDWARF.h" +#include "SymbolFileDWARFDwo.h" #include "SymbolFileDWARFDebugMap.h" #include "UniqueDWARFASTType.h" @@ -24,7 +24,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Host/Host.h" -#include "lldb/Interpreter/Args.h" #include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/ClangUtil.h" @@ -39,8 +38,10 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include <map> #include <vector> @@ -105,9 +106,9 @@ struct BitfieldInfo { 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. + // 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 @@ -123,57 +124,108 @@ ClangASTImporter &DWARFASTParserClang::GetClangASTImporter() { return *m_clang_ast_importer_ap; } +/// Detect a forward declaration that is nested in a DW_TAG_module. +static bool isClangModuleFwdDecl(const DWARFDIE &Die) { + if (!Die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0)) + return false; + auto Parent = Die.GetParent(); + while (Parent.IsValid()) { + if (Parent.Tag() == DW_TAG_module) + return true; + Parent = Parent.GetParent(); + } + return false; +} + TypeSP DWARFASTParserClang::ParseTypeFromDWO(const DWARFDIE &die, Log *log) { ModuleSP dwo_module_sp = die.GetContainingDWOModule(); - if (dwo_module_sp) { - // This type comes from an external DWO module - std::vector<CompilerContext> dwo_context; - die.GetDWOContext(dwo_context); - TypeMap dwo_types; - if (dwo_module_sp->GetSymbolVendor()->FindTypes(dwo_context, true, - dwo_types)) { - const size_t num_dwo_types = dwo_types.GetSize(); - if (num_dwo_types == 1) { - // 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 - TypeSP dwo_type_sp = dwo_types.GetTypeAtIndex(0); - if (dwo_type_sp) { - lldb_private::CompilerType dwo_type = - dwo_type_sp->GetForwardCompilerType(); + if (!dwo_module_sp) + return TypeSP(); - lldb_private::CompilerType type = - GetClangASTImporter().CopyType(m_ast, dwo_type); + // This type comes from an external DWO module. + std::vector<CompilerContext> dwo_context; + die.GetDWOContext(dwo_context); + TypeMap dwo_types; - // printf ("copied_qual_type: ast = %p, clang_type = %p, name = - // '%s'\n", m_ast, copied_qual_type.getAsOpaquePtr(), - // external_type->GetName().GetCString()); - if (type) { - SymbolFileDWARF *dwarf = die.GetDWARF(); - TypeSP type_sp(new Type(die.GetID(), dwarf, dwo_type_sp->GetName(), - dwo_type_sp->GetByteSize(), NULL, - LLDB_INVALID_UID, Type::eEncodingInvalid, - &dwo_type_sp->GetDeclaration(), type, - Type::eResolveStateForward)); + if (!dwo_module_sp->GetSymbolVendor()->FindTypes(dwo_context, true, + dwo_types)) { + if (!isClangModuleFwdDecl(die)) + return TypeSP(); - dwarf->GetTypeList()->Insert(type_sp); - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - clang::TagDecl *tag_decl = ClangASTContext::GetAsTagDecl(type); - if (tag_decl) - LinkDeclContextToDIE(tag_decl, die); - else { - clang::DeclContext *defn_decl_ctx = - GetCachedClangDeclContextForDIE(die); - if (defn_decl_ctx) - LinkDeclContextToDIE(defn_decl_ctx, die); - } - return type_sp; - } - } - } + // Since this this type is defined in one of the Clang modules imported by + // this symbol file, search all of them. + auto *SymFile = die.GetCU()->GetSymbolFileDWARF(); + for (const auto &NameModule : SymFile->getExternalTypeModules()) { + if (!NameModule.second) + continue; + SymbolVendor *SymVendor = NameModule.second->GetSymbolVendor(); + if (SymVendor->FindTypes(dwo_context, true, dwo_types)) + break; } } - return TypeSP(); + + const size_t num_dwo_types = dwo_types.GetSize(); + if (num_dwo_types != 1) + 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) + return TypeSP(); + + lldb_private::CompilerType dwo_type = dwo_type_sp->GetForwardCompilerType(); + + lldb_private::CompilerType type = + GetClangASTImporter().CopyType(m_ast, dwo_type); + + if (!type) + return TypeSP(); + + SymbolFileDWARF *dwarf = die.GetDWARF(); + TypeSP type_sp(new Type( + die.GetID(), dwarf, dwo_type_sp->GetName(), dwo_type_sp->GetByteSize(), + NULL, LLDB_INVALID_UID, Type::eEncodingInvalid, + &dwo_type_sp->GetDeclaration(), type, Type::eResolveStateForward)); + + dwarf->GetTypeList()->Insert(type_sp); + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + clang::TagDecl *tag_decl = ClangASTContext::GetAsTagDecl(type); + if (tag_decl) + LinkDeclContextToDIE(tag_decl, die); + else { + clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(die); + if (defn_decl_ctx) + LinkDeclContextToDIE(defn_decl_ctx, die); + } + + return type_sp; +} + +static void CompleteExternalTagDeclType(ClangASTImporter &ast_importer, + clang::DeclContext *decl_ctx, + DWARFDIE die, + const char *type_name_cstr) { + auto *tag_decl_ctx = clang::dyn_cast<clang::TagDecl>(decl_ctx); + if (!tag_decl_ctx) + return; + + // If this type was not imported from an external AST, there's nothing to do. + CompilerType type = ClangASTContext::GetTypeForDecl(tag_decl_ctx); + if (!type || !ast_importer.CanImport(type)) + return; + + auto qual_type = ClangUtil::GetQualType(type); + if (!ast_importer.RequireCompleteType(qual_type)) { + die.GetDWARF()->GetObjectFile()->GetModule()->ReportError( + "Unable to complete the Decl context for DIE '%s' at offset " + "0x%8.8x.\nPlease file a bug report.", + type_name_cstr ? type_name_cstr : "", die.GetOffset()); + // We need to make the type look complete otherwise, we might crash in + // Clang when adding children. + if (ClangASTContext::StartTagDeclarationDefinition(type)) + ClangASTContext::CompleteTagDeclarationDefinition(type); + } } TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, @@ -198,17 +250,6 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, die.GetOffset(), static_cast<void *>(context), context_die.GetOffset(), die.GetTagAsCString(), die.GetName()); } - // - // Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); - // if (log && dwarf_cu) - // { - // StreamString s; - // die->DumpLocation (this, dwarf_cu, s); - // dwarf->GetObjectFile()->GetModule()->LogMessage (log, - // "SymbolFileDwarf::%s %s", __FUNCTION__, s.GetData()); - // - // } - Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); TypeList *type_list = dwarf->GetTypeList(); if (type_ptr == NULL) { @@ -220,6 +261,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, bool is_forward_declaration = false; DWARFAttributes attributes; const char *type_name_cstr = NULL; + const char *mangled_name_cstr = NULL; ConstString type_name_const_str; Type::ResolveState resolve_state = Type::eResolveStateUnresolved; uint64_t byte_size = 0; @@ -268,8 +310,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_name_cstr = form_value.AsCString(); // Work around a bug in llvm-gcc where they give a name to a - // reference type which doesn't - // include the "&"... + // reference type which doesn't include the "&"... if (tag == DW_TAG_reference_type) { if (strchr(type_name_cstr, '&') == NULL) type_name_cstr = NULL; @@ -295,32 +336,32 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } if (tag == DW_TAG_typedef && encoding_uid.IsValid()) { - // Try to parse a typedef from the DWO file first as modules - // can contain typedef'ed structures that have no names like: + // 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. + // 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. + // 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. + // 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 = dwarf->GetDIE(DIERef(encoding_uid)); - // First make sure that the die that this is typedef'ed to _is_ - // just a declaration (DW_AT_declaration == 1), not a full definition + // 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 + // concrete instances of templates are ever emitted and modules won't + // contain those if (encoding_die && encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { @@ -433,7 +474,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective C 'id' built-in type.", + "is Objective-C 'id' built-in type.", die.GetOffset(), die.GetTagAsCString(), die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCID); encoding_data_type = Type::eEncodingIsUID; @@ -444,7 +485,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective C 'Class' built-in type.", + "is Objective-C 'Class' built-in type.", die.GetOffset(), die.GetTagAsCString(), die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCClass); encoding_data_type = Type::eEncodingIsUID; @@ -454,7 +495,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' " - "is Objective C 'selector' built-in type.", + "is Objective-C 'selector' built-in type.", die.GetOffset(), die.GetTagAsCString(), die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCSel); encoding_data_type = Type::eEncodingIsUID; @@ -495,17 +536,6 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, &decl, clang_type, resolve_state)); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - - // Type* encoding_type = - // GetUniquedTypeForDIEOffset(encoding_uid, type_sp, - // NULL, 0, 0, false); - // if (encoding_type != NULL) - // { - // if (encoding_type != DIE_IS_BEING_PARSED) - // type_sp->SetEncodingType(encoding_type); - // else - // m_indirect_fixups.push_back(type_sp.get()); - // } } break; case DW_TAG_structure_type: @@ -517,7 +547,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, LanguageType class_language = eLanguageTypeUnknown; bool is_complete_objc_class = false; - // bool struct_is_class = false; + size_t calling_convention + = llvm::dwarf::CallingConvention::DW_CC_normal; + const size_t num_attributes = die.GetAttributes(attributes); if (num_attributes > 0) { uint32_t i; @@ -528,10 +560,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, case DW_AT_decl_file: if (die.GetCU()->DW_AT_decl_file_attributes_are_invalid()) { // llvm-gcc outputs invalid DW_AT_decl_file attributes that - // always - // point to the compile unit file, so we clear this invalid - // value - // so that we can still unique types efficiently. + // always point to the compile unit file, so we clear this + // invalid value so that we can still unique types + // efficiently. decl.SetFile(FileSpec("<invalid>", false)); } else decl.SetFile( @@ -572,7 +603,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, case DW_AT_APPLE_objc_complete_type: is_complete_objc_class = form_value.Signed(); break; - + case DW_AT_calling_convention: + calling_convention = form_value.Unsigned(); + break; + case DW_AT_allocated: case DW_AT_associated: case DW_AT_data_location: @@ -587,10 +621,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } } - // UniqueDWARFASTType is large, so don't create a local variables on the - // stack, put it on the heap. This function is often called recursively - // and clang isn't good and sharing the stack space for variables in - // different blocks. + // UniqueDWARFASTType is large, so don't create a local variables on + // the stack, put it on the heap. This function is often called + // recursively and clang isn't good and sharing the stack space for + // variables in different blocks. std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap( new UniqueDWARFASTType()); @@ -601,10 +635,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, LanguageType die_language = die.GetLanguage(); if (Language::LanguageIsCPlusPlus(die_language)) { // For C++, we rely solely upon the one definition rule that says - // only - // one thing can exist at a given decl context. We ignore the file - // and - // line that things are declared on. + // only one thing can exist at a given decl context. We ignore the + // file and line that things are declared on. std::string qualified_name; if (die.GetQualifiedName(qualified_name)) unique_typename = ConstString(qualified_name); @@ -641,17 +673,16 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (byte_size_valid && byte_size == 0 && type_name_cstr && die.HasChildren() == false && sc.comp_unit->GetLanguage() == eLanguageTypeObjC) { - // Work around an issue with clang at the moment where - // forward declarations for objective C classes are emitted - // as: + // Work around an issue with clang at the moment where forward + // declarations for objective C classes are emitted as: // DW_TAG_structure_type [2] // DW_AT_name( "ForwardObjcClass" ) // DW_AT_byte_size( 0x00 ) // DW_AT_decl_file( "..." ) // DW_AT_decl_line( 1 ) // - // Note that there is no DW_AT_declaration and there are - // no children, and the byte size is zero. + // Note that there is no DW_AT_declaration and there are no children, + // and the byte size is zero. is_forward_declaration = true; } @@ -659,11 +690,11 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, class_language == eLanguageTypeObjC_plus_plus) { if (!is_complete_objc_class && die.Supports_DW_AT_APPLE_objc_complete_type()) { - // We have a valid eSymbolTypeObjCClass class symbol whose - // name matches the current objective C class that we - // are trying to find and this DIE isn't the complete - // definition (we checked is_complete_objc_class above and - // know it is false), so the real definition is in here somewhere + // We have a valid eSymbolTypeObjCClass class symbol whose name + // matches the current objective C class that we are trying to find + // and this DIE isn't the complete definition (we checked + // is_complete_objc_class above and know it is false), so the real + // definition is in here somewhere type_sp = dwarf->FindCompleteObjCDefinitionTypeForDIE( die, type_name_const_str, true); @@ -671,9 +702,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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... + // 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->FindCompleteObjCDefinitionTypeForDIE( die, type_name_const_str, true); @@ -690,9 +720,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_sp->GetID()); } - // 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 + // 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(); return type_sp; } @@ -700,11 +730,11 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } if (is_forward_declaration) { - // We have a forward declaration to a type and we need - // to try and find a full declaration. We look in the - // current type index just in case we have a forward - // declaration followed by an actual declarations in the - // DWARF. If this fails, we need to look elsewhere... + // We have a forward declaration to a type and we need to try and + // find a full declaration. We look in the current type index just in + // case we have a forward declaration followed by an actual + // declarations in the DWARF. If this fails, we need to look + // elsewhere... if (log) { dwarf->GetObjectFile()->GetModule()->LogMessage( log, "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a " @@ -730,9 +760,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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... + // 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); @@ -748,9 +777,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, DW_TAG_value_to_name(tag), type_name_cstr, type_sp->GetID()); } - // 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 + // 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->DebugInfo()->GetDIE(DIERef(type_sp->GetID(), dwarf))); @@ -766,9 +794,18 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (!clang_type) { clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); + + // If your decl context is a record that was imported from another + // AST context (in the gmodules case), we need to make sure the type + // 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, + type_name_cstr); + if (accessibility == eAccessNone && decl_ctx) { - // Check the decl context that contains this class/struct/union. - // If it is a class we must give it an accessibility. + // Check the decl context that contains this class/struct/union. If + // it is a class we must give it an accessibility. const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind(); if (DeclKindIsCXXClass(containing_decl_kind)) @@ -818,10 +855,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, class_language, &metadata); } } - + // Store a forward declaration to this class type in case any - // parameters in any class methods need it for the clang - // types for function prototypes. + // parameters in any class methods need it for the clang types for + // function prototypes. LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, byte_size, NULL, LLDB_INVALID_UID, @@ -830,9 +867,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_sp->SetIsCompleteObjCClass(is_complete_objc_class); - // Add our type to the unique type map so we don't - // end up creating many copies of the same type over - // and over in the ASTContext for our module + // Add our type to the unique type map so we don't end up creating many + // copies of the same type over and over in the ASTContext for our + // module unique_ast_entry_ap->m_type_sp = type_sp; unique_ast_entry_ap->m_die = die; unique_ast_entry_ap->m_declaration = unique_decl; @@ -844,8 +881,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, // Check to see if the DIE actually has a definition, some version of // GCC will // emit DIEs with DW_AT_declaration set to true, but yet still have - // subprogram, - // members, or inheritance, so we can't trust it + // subprogram, members, or inheritance, so we can't trust it DWARFDIE child_die = die.GetFirstChild(); while (child_die) { switch (child_die.Tag()) { @@ -869,10 +905,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } if (!is_forward_declaration) { - // Always start the definition for a class type so that - // if the class has child classes or types that require - // the class to be created for use as their decl contexts - // the class will be ready to accept these child definitions. + // Always start the definition for a class type so that if the class + // has child classes or types that require the class to be created + // for use as their decl contexts the class will be ready to accept + // these child definitions. if (die.HasChildren() == false) { // No children for this struct/union/class, lets finish it if (ClangASTContext::StartTagDeclarationDefinition(clang_type)) { @@ -896,33 +932,30 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } } } else if (clang_type_was_created) { - // Start the definition if the class is not objective C since - // the underlying decls respond to isCompleteDefinition(). Objective + // Start the definition if the class is not objective C since the + // underlying decls respond to isCompleteDefinition(). Objective // C decls don't respond to isCompleteDefinition() so we can't // start the declaration definition right away. For C++ - // class/union/structs - // we want to start the definition in case the class is needed as - // the - // declaration context for a contained class or type without the - // need - // to complete that type.. + // class/union/structs we want to start the definition in case the + // class is needed as the declaration context for a contained class + // or type without the need to complete that type.. if (class_language != eLanguageTypeObjC && class_language != eLanguageTypeObjC_plus_plus) ClangASTContext::StartTagDeclarationDefinition(clang_type); - // Leave this as a forward declaration until we need - // to know the details of the type. lldb_private::Type - // will automatically call the SymbolFile virtual function - // "SymbolFileDWARF::CompleteType(Type *)" - // When the definition needs to be defined. + // Leave this as a forward declaration until we need to know the + // details of the type. lldb_private::Type will automatically call + // the SymbolFile virtual function + // "SymbolFileDWARF::CompleteType(Type *)" When the definition + // needs to be defined. assert(!dwarf->GetForwardDeclClangTypeToDie().count( ClangUtil::RemoveFastQualifiers(clang_type) .GetOpaqueQualType()) && "Type already in the forward declaration map!"); - // Can't assume m_ast.GetSymbolFile() is actually a SymbolFileDWARF, - // it can be a - // SymbolFileDWARFDebugMap for Apple binaries. + // Can't assume m_ast.GetSymbolFile() is actually a + // SymbolFileDWARF, it can be a SymbolFileDWARFDebugMap for Apple + // binaries. dwarf->GetForwardDeclDieToClangType()[die.GetDIE()] = clang_type.GetOpaqueQualType(); dwarf->GetForwardDeclClangTypeToDie() @@ -931,6 +964,19 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); } } + + // If we made a clang type, set the trivial abi if applicable: We only + // do this for pass by value - which implies the Trivial ABI. There + // isn't a way to assert that something that would normally be pass by + // value is pass by reference, so we ignore that attribute if set. + if (calling_convention == llvm::dwarf::DW_CC_pass_by_value) { + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + if (record_decl) { + record_decl->setHasTrivialSpecialMemberForCall(); + } + } + } break; case DW_TAG_enumeration_type: { @@ -1008,9 +1054,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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... + // 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); @@ -1027,9 +1072,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_sp->GetID()); } - // 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 + // 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->DebugInfo()->GetDIE( @@ -1145,9 +1190,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: - break; // mangled = - // form_value.AsCString(&dwarf->get_debug_str_data()); - // break; + mangled_name_cstr = form_value.AsCString(); + break; case DW_AT_type: type_die_form = form_value; break; @@ -1256,8 +1300,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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 + // ParseChildParameters(...) if we find a "this" parameters as the + // first parameter if (is_cxx_method) { is_static = true; } @@ -1272,25 +1316,22 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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. + // 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 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); @@ -1318,8 +1359,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (class_opaque_type) { // If accessibility isn't set to anything valid, assume public - // for - // now... + // for now... if (accessibility == eAccessNone) accessibility = eAccessPublic; @@ -1341,9 +1381,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } } } 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 + // 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; @@ -1352,10 +1391,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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"... + // class so we now need to associate all dies under + // "decl_ctx_die" to DIEs in the DIE for "class_type"... SymbolFileDWARF *class_symfile = NULL; DWARFDIE class_type_die; @@ -1381,10 +1418,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, // 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... + // 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) { @@ -1396,16 +1431,13 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, if (specification_die_form.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. + // 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. + // have been made with the specification and not with this + // die. DWARFDIE spec_die = dwarf->DebugInfo()->GetDIE( DIERef(specification_die_form)); clang::DeclContext *spec_clang_decl_ctx = @@ -1421,12 +1453,9 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_handled = true; } else if (abstract_origin_die_form.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. + // 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 = dwarf->DebugInfo()->GetDIE( @@ -1449,17 +1478,16 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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... + // 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. + // then add the method only if an equivalent is not + // already present. clang::CXXRecordDecl *record_decl = m_ast.GetAsCXXRecordDecl( class_opaque_type.GetOpaqueQualType()); @@ -1499,18 +1527,18 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, 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... + // accessibility in the DWARF for C++ methods... + // Default to public for now... if (accessibility == eAccessNone) accessibility = eAccessPublic; clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType( class_opaque_type.GetOpaqueQualType(), - type_name_cstr, clang_type, accessibility, - is_virtual, is_static, is_inline, is_explicit, - is_attr_used, is_artificial); + type_name_cstr, mangled_name_cstr, clang_type, + accessibility, is_virtual, is_static, + is_inline, is_explicit, is_attr_used, + is_artificial); type_handled = cxx_method_decl != NULL; @@ -1541,25 +1569,21 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } } 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 + // 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... + // 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). + // 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 @@ -1573,8 +1597,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, // 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> + // itself. <rdar://problem/11240464> type_handled = true; } } @@ -1737,8 +1760,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, array_element_type.GetCompleteType() == false) { ModuleSP module_sp = die.GetModule(); if (module_sp) { - if (die.GetCU()->GetProducer() == - DWARFCompileUnit::eProducerClang) + 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 " @@ -1760,11 +1782,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, } // 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. + // 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( @@ -1864,7 +1885,8 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, dw_tag_t sc_parent_tag = sc_parent_die.Tag(); SymbolContextScope *symbol_context_scope = NULL; - if (sc_parent_tag == DW_TAG_compile_unit) { + 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) { symbol_context_scope = @@ -1956,6 +1978,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( const DWARFDIE &die, ClangASTContext::TemplateParameterInfos &template_param_infos) { const dw_tag_t tag = die.Tag(); + bool is_template_template_argument = false; switch (tag) { case DW_TAG_GNU_template_parameter_pack: { @@ -1971,11 +1994,15 @@ bool DWARFASTParserClang::ParseTemplateDIE( } return true; } + case DW_TAG_GNU_template_template_param: + is_template_template_argument = true; + LLVM_FALLTHROUGH; case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: { DWARFAttributes attributes; const size_t num_attributes = die.GetAttributes(attributes); const char *name = nullptr; + const char *template_name = nullptr; CompilerType clang_type; uint64_t uval64 = 0; bool uval64_valid = false; @@ -1990,6 +2017,11 @@ bool DWARFASTParserClang::ParseTemplateDIE( name = form_value.AsCString(); break; + case DW_AT_GNU_template_name: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + template_name = form_value.AsCString(); + break; + case DW_AT_type: if (attributes.ExtractFormValueAtIndex(i, form_value)) { Type *lldb_type = die.ResolveTypeUID(DIERef(form_value)); @@ -2013,7 +2045,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( if (!clang_type) clang_type = m_ast.GetBasicType(eBasicTypeVoid); - if (clang_type) { + if (!is_template_template_argument) { bool is_signed = false; if (name && name[0]) template_param_infos.names.push_back(name); @@ -2033,7 +2065,10 @@ bool DWARFASTParserClang::ParseTemplateDIE( clang::TemplateArgument(ClangUtil::GetQualType(clang_type))); } } else { - return false; + auto *tplt_type = m_ast.CreateTemplateTemplateParmDecl(template_name); + template_param_infos.names.push_back(name); + template_param_infos.args.push_back( + clang::TemplateArgument(clang::TemplateName(tplt_type))); } } } @@ -2052,7 +2087,6 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( if (!parent_die) return false; - Args template_parameter_names; for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) { const dw_tag_t tag = die.Tag(); @@ -2061,6 +2095,7 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: case DW_TAG_GNU_template_parameter_pack: + case DW_TAG_GNU_template_template_param: ParseTemplateDIE(die, template_param_infos); break; @@ -2073,6 +2108,95 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( return template_param_infos.args.size() == template_param_infos.names.size(); } +// Checks whether m1 is an overload of m2 (as opposed to an override). This is +// called by addOverridesForMethod to distinguish overrides (which share a +// vtable entry) from overloads (which require distinct entries). +static bool isOverload(clang::CXXMethodDecl *m1, clang::CXXMethodDecl *m2) { + // FIXME: This should detect covariant return types, but currently doesn't. + lldbassert(&m1->getASTContext() == &m2->getASTContext() && + "Methods should have the same AST context"); + clang::ASTContext &context = m1->getASTContext(); + + const auto *m1Type = + llvm::cast<clang::FunctionProtoType>( + context.getCanonicalType(m1->getType())); + + const auto *m2Type = + llvm::cast<clang::FunctionProtoType>( + context.getCanonicalType(m2->getType())); + + auto compareArgTypes = + [&context](const clang::QualType &m1p, const clang::QualType &m2p) { + return context.hasSameType(m1p.getUnqualifiedType(), + m2p.getUnqualifiedType()); + }; + + // FIXME: In C++14 and later, we can just pass m2Type->param_type_end() + // as a fourth parameter to std::equal(). + return (m1->getNumParams() != m2->getNumParams()) || + !std::equal(m1Type->param_type_begin(), m1Type->param_type_end(), + m2Type->param_type_begin(), compareArgTypes); +} + +// If decl is a virtual method, walk the base classes looking for methods that +// decl overrides. This table of overridden methods is used by IRGen to +// determine the vtable layout for decl's parent class. +static void addOverridesForMethod(clang::CXXMethodDecl *decl) { + if (!decl->isVirtual()) + return; + + clang::CXXBasePaths paths; + + auto find_overridden_methods = + [decl](const clang::CXXBaseSpecifier *specifier, clang::CXXBasePath &path) { + if (auto *base_record = + llvm::dyn_cast<clang::CXXRecordDecl>( + specifier->getType()->getAs<clang::RecordType>()->getDecl())) { + + clang::DeclarationName name = decl->getDeclName(); + + // If this is a destructor, check whether the base class destructor is + // virtual. + if (name.getNameKind() == clang::DeclarationName::CXXDestructorName) + if (auto *baseDtorDecl = base_record->getDestructor()) { + if (baseDtorDecl->isVirtual()) { + path.Decls = baseDtorDecl; + return true; + } else + return false; + } + + // Otherwise, search for name in the base class. + for (path.Decls = base_record->lookup(name); !path.Decls.empty(); + path.Decls = path.Decls.slice(1)) { + if (auto *method_decl = + llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front())) + if (method_decl->isVirtual() && !isOverload(decl, method_decl)) { + path.Decls = method_decl; + return true; + } + } + } + + return false; + }; + + if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) { + for (auto *overridden_decl : paths.found_decls()) + decl->addOverriddenMethod( + llvm::cast<clang::CXXMethodDecl>(overridden_decl)); + } +} + +// If clang_type is a CXXRecordDecl, builds the method override list for each +// of its virtual methods. +static void addMethodOverrides(ClangASTContext &ast, CompilerType &clang_type) { + if (auto *record = + ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType())) + for (auto *method : record->methods()) + addOverridesForMethod(method); +} + bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &clang_type) { @@ -2090,10 +2214,10 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, #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. + // 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: // @@ -2144,8 +2268,8 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, 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. + // For objective C we don't start the definition when the class is + // created. ClangASTContext::StartTagDeclarationDefinition(clang_type); } @@ -2217,29 +2341,27 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, 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. + // 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. + // 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 (!base_classes.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.SetBaseClassesForClassType() + // 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.SetBaseClassesForClassType() for (auto &base_class : base_classes) { clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); @@ -2252,19 +2374,17 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, "does not have a complete definition.", die.GetName(), base_class_type.GetTypeName().GetCString()); - if (die.GetCU()->GetProducer() == - DWARFCompileUnit::eProducerClang) + 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.SetBaseClassesForClassType()" - // 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. + // "clang_type.SetBaseClassesForClassType()" 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( @@ -2277,14 +2397,15 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, &base_classes.front(), base_classes.size()); - // Clang will copy each CXXBaseSpecifier in "base_classes" - // so we have to free them all. + // Clang will copy each CXXBaseSpecifier in "base_classes" so we have + // to free them all. ClangASTContext::DeleteBaseClassSpecifiers(&base_classes.front(), base_classes.size()); } } } + addMethodOverrides(m_ast, clang_type); ClangASTContext::BuildIndirectFields(clang_type); ClangASTContext::CompleteTagDeclarationDefinition(clang_type); @@ -2582,14 +2703,13 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(const SymbolContext &sc, Mangled func_name; if (mangled) func_name.SetValue(ConstString(mangled), true); - else if (die.GetParent().Tag() == DW_TAG_compile_unit && + else if ((die.GetParent().Tag() == DW_TAG_compile_unit || + die.GetParent().Tag() == DW_TAG_partial_unit) && Language::LanguageIsCPlusPlus(die.GetLanguage()) && name && strcmp(name, "main") != 0) { // If the mangled name is not present in the DWARF, generate the - // demangled name - // using the decl context. We skip if the function is "main" as its name - // is - // never mangled. + // demangled name using the decl context. We skip if the function is + // "main" as its name is never mangled. bool is_static = false; bool is_variadic = false; bool has_template_params = false; @@ -2748,8 +2868,7 @@ bool DWARFASTParserClang::ParseChildMembers( if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + 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(); @@ -2763,8 +2882,8 @@ bool DWARFASTParserClang::ParseChildMembers( } } 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. + // this form value is the offset in bytes from the beginning of + // the containing entity. member_byte_offset = form_value.Unsigned(); } break; @@ -2806,8 +2925,8 @@ bool DWARFASTParserClang::ParseChildMembers( ConstString fixed_getter; ConstString fixed_setter; - // Check if the property getter/setter were provided as full - // names. We want basenames, so we extract them. + // 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); @@ -2819,8 +2938,7 @@ bool DWARFASTParserClang::ParseChildMembers( prop_setter_name = prop_setter_method.GetSelector().GetCString(); } - // If the names haven't been provided, they need to be - // filled in. + // If the names haven't been provided, they need to be filled in. if (!prop_getter_name) { prop_getter_name = prop_name; @@ -2836,19 +2954,18 @@ bool DWARFASTParserClang::ParseChildMembers( } } - // 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: + // 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. + // 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 == 0 && bit_offset < 0) { bit_size = 0; @@ -2862,12 +2979,10 @@ bool DWARFASTParserClang::ParseChildMembers( if (member_idx == 0 && !is_artificial && name && (strstr(name, "_vptr$") == name)) { - // Not all compilers will mark the vtable pointer - // member as artificial (llvm-gcc). We can't have - // the virtual members in our classes otherwise it - // throws off all child offsets since we end up - // having and extra pointer sized member in our - // class layouts. + // Not all compilers will mark the vtable pointer member as + // artificial (llvm-gcc). We can't have the virtual members in our + // classes otherwise it throws off all child offsets since we end up + // having and extra pointer sized member in our class layouts. is_artificial = true; } @@ -2907,15 +3022,15 @@ bool DWARFASTParserClang::ParseChildMembers( ///////////////////////////////////////////////////////////// // 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_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. + // (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. ///////////////////////////////////////////////////////////// @@ -2956,12 +3071,9 @@ bool DWARFASTParserClang::ParseChildMembers( 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: + // 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 @@ -2986,10 +3098,8 @@ bool DWARFASTParserClang::ParseChildMembers( 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. + // 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 || @@ -3052,10 +3162,10 @@ bool DWARFASTParserClang::ParseChildMembers( { // 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]. + // 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; @@ -3089,8 +3199,7 @@ bool DWARFASTParserClang::ParseChildMembers( if (ClangASTContext::IsCXXClassType(member_clang_type) && member_clang_type.GetCompleteType() == false) { - if (die.GetCU()->GetProducer() == - DWARFCompileUnit::eProducerClang) + 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 " @@ -3108,12 +3217,11 @@ bool DWARFASTParserClang::ParseChildMembers( die.GetOffset(), name, sc.comp_unit ? sc.comp_unit->GetPath().c_str() : "the source file"); - // 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. + // 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( @@ -3221,8 +3329,7 @@ bool DWARFASTParserClang::ParseChildMembers( if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + 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(); @@ -3235,8 +3342,8 @@ bool DWARFASTParserClang::ParseChildMembers( } } 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. + // this form value is the offset in bytes from the beginning of + // the containing entity. member_byte_offset = form_value.Unsigned(); } break; @@ -3282,18 +3389,16 @@ bool DWARFASTParserClang::ParseChildMembers( if (is_virtual) { // Do not specify any offset for virtual inheritance. The DWARF - // produced by clang doesn't - // give us a constant offset, but gives us a DWARF expressions that - // requires an actual object - // in memory. the DW_AT_data_member_location for a virtual base - // class looks like: + // produced by clang doesn't give us a constant offset, but gives + // us a DWARF expressions that requires an actual object in memory. + // the DW_AT_data_member_location for a virtual base class looks + // like: // DW_AT_data_member_location( DW_OP_dup, DW_OP_deref, // DW_OP_constu(0x00000018), DW_OP_minus, DW_OP_deref, // DW_OP_plus ) // Given this, there is really no valid response we can give to - // clang for virtual base - // class offsets, and this should eventually be removed from - // LayoutRecordType() in the external + // clang for virtual base class offsets, and this should eventually + // be removed from LayoutRecordType() in the external // AST source in clang. } else { layout_info.base_offsets.insert(std::make_pair( @@ -3365,22 +3470,6 @@ size_t DWARFASTParserClang::ParseChildParameters( is_artificial = form_value.Boolean(); break; case DW_AT_location: - // if (form_value.BlockData()) - // { - // const DWARFDataExtractor& - // debug_info_data = debug_info(); - // uint32_t block_length = - // form_value.Unsigned(); - // DWARFDataExtractor - // location(debug_info_data, - // form_value.BlockData() - - // debug_info_data.GetDataStart(), - // block_length); - // } - // else - // { - // } - // break; case DW_AT_const_value: case DW_AT_default_value: case DW_AT_description: @@ -3397,52 +3486,29 @@ size_t DWARFASTParserClang::ParseChildParameters( } bool skip = false; - if (skip_artificial) { - if (is_artificial) { - // In order to determine if a C++ member function is - // "const" we have to look at the const-ness of "this"... - // Ugly, but that - if (arg_idx == 0) { - if (DeclKindIsCXXClass(containing_decl_ctx->getDeclKind())) { - // Often times compilers omit the "this" name for the - // specification DIEs, so we can't rely upon the name - // being in the formal parameter DIE... - if (name == NULL || ::strcmp(name, "this") == 0) { - Type *this_type = - die.ResolveTypeUID(DIERef(param_type_die_form)); - if (this_type) { - uint32_t encoding_mask = this_type->GetEncodingMask(); - if (encoding_mask & Type::eEncodingIsPointerUID) { - is_static = false; + if (skip_artificial && is_artificial) { + // In order to determine if a C++ member function is "const" we + // have to look at the const-ness of "this"... + if (arg_idx == 0 && + DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()) && + // Often times compilers omit the "this" name for the + // specification DIEs, so we can't rely upon the name being in + // the formal parameter DIE... + (name == NULL || ::strcmp(name, "this") == 0)) { + Type *this_type = die.ResolveTypeUID(DIERef(param_type_die_form)); + if (this_type) { + uint32_t encoding_mask = this_type->GetEncodingMask(); + if (encoding_mask & Type::eEncodingIsPointerUID) { + is_static = false; - if (encoding_mask & (1u << Type::eEncodingIsConstUID)) - type_quals |= clang::Qualifiers::Const; - if (encoding_mask & (1u << Type::eEncodingIsVolatileUID)) - type_quals |= clang::Qualifiers::Volatile; - } - } - } - } - } - skip = true; - } else { - - // HACK: Objective C formal parameters "self" and "_cmd" - // are not marked as artificial in the DWARF... - CompileUnit *comp_unit = die.GetLLDBCompileUnit(); - if (comp_unit) { - switch (comp_unit->GetLanguage()) { - case eLanguageTypeObjC: - case eLanguageTypeObjC_plus_plus: - if (name && name[0] && - (strcmp(name, "self") == 0 || strcmp(name, "_cmd") == 0)) - skip = true; - break; - default: - break; + if (encoding_mask & (1u << Type::eEncodingIsConstUID)) + type_quals |= clang::Qualifiers::Const; + if (encoding_mask & (1u << Type::eEncodingIsVolatileUID)) + type_quals |= clang::Qualifiers::Volatile; } } } + skip = true; } if (!skip) { @@ -3470,10 +3536,10 @@ size_t DWARFASTParserClang::ParseChildParameters( case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: case DW_TAG_GNU_template_parameter_pack: - // The one caller of this was never using the template_param_infos, - // and the local variable was taking up a large amount of stack space - // in SymbolFileDWARF::ParseType() so this was removed. If we ever need - // the template params back, we can add them back. + // The one caller of this was never using the template_param_infos, and + // the local variable was taking up a large amount of stack space in + // SymbolFileDWARF::ParseType() so this was removed. If we ever need the + // template params back, we can add them back. // ParseTemplateDIE (dwarf_cu, die, template_param_infos); has_template_params = true; break; @@ -3692,6 +3758,7 @@ DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) { bool try_parsing_type = true; switch (die.Tag()) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: decl_ctx = m_ast.GetTranslationUnitDecl(); try_parsing_type = false; break; @@ -4008,8 +4075,8 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( // Now do the work of linking the DeclContexts and Types. if (fast_path) { - // We can do this quickly. Just run across the tables index-for-index since - // we know each node has matching names and tags. + // We can do this quickly. Just run across the tables index-for-index + // since we know each node has matching names and tags. for (idx = 0; idx < src_size; ++idx) { src_die = src_name_to_die.GetValueAtIndexUnchecked(idx); dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx); @@ -4046,9 +4113,9 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( } } } else { - // We must do this slowly. For each member of the destination, look - // up a member in the source with the same name, check its tag, and - // unique them if everything matches up. Report failures. + // We must do this slowly. For each member of the destination, look up a + // member in the source with the same name, check its tag, and unique them + // if everything matches up. Report failures. if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty()) { src_name_to_die.Sort(); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp index e04dc76d1dbe..328212e4b684 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp @@ -10,7 +10,6 @@ #include "DWARFASTParserGo.h" #include "DWARFASTParserGo.h" -#include "DWARFCompileUnit.h" #include "DWARFDIE.h" #include "DWARFDIECollection.h" #include "DWARFDebugInfo.h" @@ -158,7 +157,8 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( Type *type = dwarf->ResolveTypeUID(encoding_uid); if (type) { if (go_kind == 0 && type->GetName() == type_name_const_str) { - // Go emits extra typedefs as a forward declaration. Ignore these. + // Go emits extra typedefs as a forward declaration. Ignore + // these. dwarf->m_die_to_type[die.GetDIE()] = type; return type->shared_from_this(); } @@ -213,10 +213,10 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( // TODO(ribrdb): Do we need this? - // UniqueDWARFASTType is large, so don't create a local variables on the - // stack, put it on the heap. This function is often called recursively - // and clang isn't good and sharing the stack space for variables in - // different blocks. + // UniqueDWARFASTType is large, so don't create a local variables on + // the stack, put it on the heap. This function is often called + // recursively and clang isn't good and sharing the stack space for + // variables in different blocks. std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap( new UniqueDWARFASTType()); @@ -225,11 +225,10 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( dwarf->GetUniqueDWARFASTTypeMap().Find( type_name_const_str, die, decl, byte_size_valid ? byte_size : -1, *unique_ast_entry_ap)) { - // We have already parsed this type or from another - // compile unit. GCC loves to use the "one definition - // rule" which can result in multiple definitions - // of the same class over and over in each compile - // unit. + // We have already parsed this type or from another compile unit. GCC + // loves to use the "one definition rule" which can result in + // multiple definitions of the same class over and over in each + // compile unit. type_sp = unique_ast_entry_ap->m_type_sp; if (type_sp) { dwarf->m_die_to_type[die.GetDIE()] = type_sp.get(); @@ -255,9 +254,9 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( Type::eEncodingIsUID, &decl, compiler_type, Type::eResolveStateForward)); - // Add our type to the unique type map so we don't - // end up creating many copies of the same type over - // and over in the ASTContext for our module + // Add our type to the unique type map so we don't end up creating many + // copies of the same type over and over in the ASTContext for our + // module unique_ast_entry_ap->m_type_sp = type_sp; unique_ast_entry_ap->m_die = die; unique_ast_entry_ap->m_declaration = decl; @@ -266,19 +265,19 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( *unique_ast_entry_ap); if (!is_forward_declaration) { - // Always start the definition for a class type so that - // if the class has child classes or types that require - // the class to be created for use as their decl contexts - // the class will be ready to accept these child definitions. + // Always start the definition for a class type so that if the class + // has child classes or types that require the class to be created + // for use as their decl contexts the class will be ready to accept + // these child definitions. if (die.HasChildren() == false) { // No children for this struct/union/class, lets finish it m_ast.CompleteStructType(compiler_type); } else if (compiler_type_was_created) { - // Leave this as a forward declaration until we need - // to know the details of the type. lldb_private::Type - // will automatically call the SymbolFile virtual function - // "SymbolFileDWARF::CompleteType(Type *)" - // When the definition needs to be defined. + // Leave this as a forward declaration until we need to know the + // details of the type. lldb_private::Type will automatically call + // the SymbolFile virtual function + // "SymbolFileDWARF::CompleteType(Type *)" When the definition + // needs to be defined. dwarf->m_forward_decl_die_to_clang_type[die.GetDIE()] = compiler_type.GetOpaqueQualType(); dwarf->m_forward_decl_clang_type_to_die[compiler_type @@ -432,7 +431,8 @@ TypeSP DWARFASTParserGo::ParseTypeFromDWARF( dw_tag_t sc_parent_tag = sc_parent_die.Tag(); SymbolContextScope *symbol_context_scope = NULL; - if (sc_parent_tag == DW_TAG_compile_unit) { + 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) { symbol_context_scope = @@ -655,8 +655,7 @@ size_t DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, if (form_value.BlockData()) { Value initialValue(0); Value memberOffset(0); - const DWARFDataExtractor &debug_info_data = - die.GetDWARF()->get_debug_info_data(); + 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(); @@ -670,8 +669,8 @@ size_t DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, } } 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. + // this form value is the offset in bytes from the beginning of + // the containing entity. member_byte_offset = form_value.Unsigned(); } break; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp index 8b5202ba265f..476394487985 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp @@ -9,7 +9,7 @@ #include "DWARFASTParserJava.h" #include "DWARFAttribute.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfoEntry.h" #include "DWARFDebugInfoEntry.h" #include "DWARFDeclContext.h" @@ -324,7 +324,8 @@ lldb::TypeSP DWARFASTParserJava::ParseTypeFromDWARF( dw_tag_t sc_parent_tag = sc_parent_die.Tag(); SymbolContextScope *symbol_context_scope = nullptr; - if (sc_parent_tag == DW_TAG_compile_unit) { + 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 != nullptr && sc_parent_die) { symbol_context_scope = @@ -418,7 +419,7 @@ bool DWARFASTParserJava::CompleteTypeFromDWARF( void DWARFASTParserJava::ParseChildMembers(const DWARFDIE &parent_die, CompilerType &compiler_type) { - DWARFCompileUnit *dwarf_cu = parent_die.GetCU(); + DWARFUnit *dwarf_cu = parent_die.GetCU(); for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling()) { switch (die.Tag()) { diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp index 3b1466df21b0..3ef5c2eb8626 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp @@ -98,7 +98,8 @@ lldb::TypeSP DWARFASTParserOCaml::ParseTypeFromDWARF(const SymbolContext &sc, dw_tag_t sc_parent_tag = sc_parent_die.Tag(); SymbolContextScope *symbol_context_scope = nullptr; - if (sc_parent_tag == DW_TAG_compile_unit) { + 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 != nullptr && sc_parent_die) { symbol_context_scope = diff --git a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h index e3b2279ca8fc..09cb5e14934f 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h @@ -4,7 +4,6 @@ #define SymbolFileDWARF_DWARFASTParserOCaml_h_ #include "DWARFASTParser.h" -#include "DWARFCompileUnit.h" #include "DWARFDIE.h" #include "DWARFDebugInfo.h" #include "DWARFDefines.h" diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp index bc49fc5de2cd..a765be0b46d0 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -10,6 +10,7 @@ #include "DWARFAbbreviationDeclaration.h" #include "lldb/Core/dwarf.h" +#include "lldb/Utility/Stream.h" #include "DWARFFormValue.h" diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h index 28e713f9beb1..b2296c455d6a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -13,8 +13,6 @@ #include "DWARFAttribute.h" #include "SymbolFileDWARF.h" -class DWARFCompileUnit; - class DWARFAbbreviationDeclaration { public: enum { InvalidCode = 0 }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp index d2573f3742ba..2586d1f18530 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "DWARFAttribute.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" DWARFAttributes::DWARFAttributes() : m_infos() {} @@ -26,7 +26,7 @@ uint32_t DWARFAttributes::FindAttributeIndex(dw_attr_t attr) const { return UINT32_MAX; } -void DWARFAttributes::Append(const DWARFCompileUnit *cu, +void DWARFAttributes::Append(const DWARFUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form) { AttributeValue attr_value = {cu, attr_die_offset, {attr, form}}; @@ -48,12 +48,11 @@ bool DWARFAttributes::RemoveAttribute(dw_attr_t attr) { bool DWARFAttributes::ExtractFormValueAtIndex( uint32_t i, DWARFFormValue &form_value) const { - const DWARFCompileUnit *cu = CompileUnitAtIndex(i); + const DWARFUnit *cu = CompileUnitAtIndex(i); form_value.SetCompileUnit(cu); form_value.SetForm(FormAtIndex(i)); lldb::offset_t offset = DIEOffsetAtIndex(i); - return form_value.ExtractValue( - cu->GetSymbolFileDWARF()->get_debug_info_data(), &offset); + return form_value.ExtractValue(cu->GetData(), &offset); } uint64_t DWARFAttributes::FormValueAsUnsigned(dw_attr_t attr, diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h index 317e710e6d94..db4324cf7725 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h @@ -14,7 +14,7 @@ #include "llvm/ADT/SmallVector.h" #include <vector> -class DWARFCompileUnit; +class DWARFUnit; class DWARFFormValue; class DWARFAttribute { @@ -50,9 +50,9 @@ public: DWARFAttributes(); ~DWARFAttributes(); - void Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, + void Append(const DWARFUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form); - const DWARFCompileUnit *CompileUnitAtIndex(uint32_t i) const { + const DWARFUnit *CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; } dw_offset_t DIEOffsetAtIndex(uint32_t i) const { @@ -73,7 +73,7 @@ public: protected: struct AttributeValue { - const DWARFCompileUnit *cu; // Keep the compile unit with each attribute in + const DWARFUnit *cu; // Keep the compile unit with each attribute in // case we have DW_FORM_ref_addr values dw_offset_t die_offset; DWARFAttribute attr; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp b/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp new file mode 100644 index 000000000000..077de9604f1d --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp @@ -0,0 +1,193 @@ +//===-- DWARFBaseDIE.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFBaseDIE.h" + +#include "DWARFUnit.h" +#include "DWARFDebugInfoEntry.h" +#include "SymbolFileDWARF.h" + +#include "lldb/Core/Module.h" +#include "lldb/Symbol/ObjectFile.h" + +using namespace lldb_private; + +DIERef DWARFBaseDIE::GetDIERef() const { + if (!IsValid()) + return DIERef(); + + dw_offset_t cu_offset = m_cu->GetOffset(); + if (m_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) + cu_offset = m_cu->GetBaseObjOffset(); + return DIERef(cu_offset, m_die->GetOffset()); +} + +dw_tag_t DWARFBaseDIE::Tag() const { + if (m_die) + return m_die->Tag(); + else + return 0; +} + +const char *DWARFBaseDIE::GetTagAsCString() const { + return lldb_private::DW_TAG_value_to_name(Tag()); +} + +const char *DWARFBaseDIE::GetAttributeValueAsString(const dw_attr_t attr, + const char *fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsString(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +uint64_t DWARFBaseDIE::GetAttributeValueAsUnsigned(const dw_attr_t attr, + uint64_t fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsUnsigned(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +int64_t DWARFBaseDIE::GetAttributeValueAsSigned(const dw_attr_t attr, + int64_t fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsSigned(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +uint64_t DWARFBaseDIE::GetAttributeValueAsReference(const dw_attr_t attr, + uint64_t fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsReference(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +uint64_t DWARFBaseDIE::GetAttributeValueAsAddress(const dw_attr_t attr, + uint64_t fail_value) const { + if (IsValid()) + return m_die->GetAttributeValueAsAddress(GetDWARF(), GetCU(), attr, + fail_value); + else + return fail_value; +} + +lldb::user_id_t DWARFBaseDIE::GetID() const { + return GetDIERef().GetUID(GetDWARF()); +} + +const char *DWARFBaseDIE::GetName() const { + if (IsValid()) + return m_die->GetName(GetDWARF(), m_cu); + else + return nullptr; +} + +lldb::LanguageType DWARFBaseDIE::GetLanguage() const { + if (IsValid()) + return m_cu->GetLanguageType(); + else + return lldb::eLanguageTypeUnknown; +} + +lldb::ModuleSP DWARFBaseDIE::GetModule() const { + SymbolFileDWARF *dwarf = GetDWARF(); + if (dwarf) + return dwarf->GetObjectFile()->GetModule(); + else + return lldb::ModuleSP(); +} + +lldb_private::CompileUnit *DWARFBaseDIE::GetLLDBCompileUnit() const { + if (IsValid()) + return GetDWARF()->GetCompUnitForDWARFCompUnit(GetCU()); + else + return nullptr; +} + +dw_offset_t DWARFBaseDIE::GetOffset() const { + if (IsValid()) + return m_die->GetOffset(); + else + return DW_INVALID_OFFSET; +} + +dw_offset_t DWARFBaseDIE::GetCompileUnitRelativeOffset() const { + if (IsValid()) + return m_die->GetOffset() - m_cu->GetOffset(); + else + return DW_INVALID_OFFSET; +} + +SymbolFileDWARF *DWARFBaseDIE::GetDWARF() const { + if (m_cu) + return m_cu->GetSymbolFileDWARF(); + else + return nullptr; +} + +lldb_private::TypeSystem *DWARFBaseDIE::GetTypeSystem() const { + if (m_cu) + return m_cu->GetTypeSystem(); + else + return nullptr; +} + +DWARFASTParser *DWARFBaseDIE::GetDWARFParser() const { + lldb_private::TypeSystem *type_system = GetTypeSystem(); + if (type_system) + return type_system->GetDWARFParser(); + else + return nullptr; +} + +bool DWARFBaseDIE::HasChildren() const { + return m_die && m_die->HasChildren(); +} + +bool DWARFBaseDIE::Supports_DW_AT_APPLE_objc_complete_type() const { + return IsValid() && GetDWARF()->Supports_DW_AT_APPLE_objc_complete_type(m_cu); +} + +size_t DWARFBaseDIE::GetAttributes(DWARFAttributes &attributes, + uint32_t depth) const { + if (IsValid()) { + return m_die->GetAttributes(m_cu, m_cu->GetFixedFormSizes(), attributes, + depth); + } + if (depth == 0) + attributes.Clear(); + return 0; +} + +void DWARFBaseDIE::Dump(lldb_private::Stream *s, + const uint32_t recurse_depth) const { + if (s && IsValid()) + m_die->Dump(GetDWARF(), GetCU(), *s, recurse_depth); +} + +bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) { + return lhs.GetDIE() == rhs.GetDIE() && lhs.GetCU() == rhs.GetCU(); +} + +bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs) { + return !(lhs == rhs); +} + +const DWARFDataExtractor &DWARFBaseDIE::GetData() const { + // Clients must check if this DIE is valid before calling this function. + assert(IsValid()); + return m_cu->GetData(); +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h new file mode 100644 index 000000000000..2163a027ffbc --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h @@ -0,0 +1,157 @@ +//===-- DWARFBaseDIE.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_DWARFBaseDIE_h_ +#define SymbolFileDWARF_DWARFBaseDIE_h_ + +#include "lldb/Core/dwarf.h" +#include "lldb/lldb-types.h" + +struct DIERef; +class DWARFASTParser; +class DWARFAttributes; +class DWARFUnit; +class DWARFDebugInfoEntry; +class DWARFDeclContext; +class DWARFDIECollection; +class SymbolFileDWARF; + +class DWARFBaseDIE { +public: + DWARFBaseDIE() : m_cu(nullptr), m_die(nullptr) {} + + DWARFBaseDIE(DWARFUnit *cu, DWARFDebugInfoEntry *die) + : m_cu(cu), m_die(die) {} + + DWARFBaseDIE(const DWARFUnit *cu, DWARFDebugInfoEntry *die) + : m_cu(const_cast<DWARFUnit *>(cu)), m_die(die) {} + + DWARFBaseDIE(DWARFUnit *cu, const DWARFDebugInfoEntry *die) + : m_cu(cu), m_die(const_cast<DWARFDebugInfoEntry *>(die)) {} + + DWARFBaseDIE(const DWARFUnit *cu, const DWARFDebugInfoEntry *die) + : m_cu(const_cast<DWARFUnit *>(cu)), + m_die(const_cast<DWARFDebugInfoEntry *>(die)) {} + + //---------------------------------------------------------------------- + // Tests + //---------------------------------------------------------------------- + explicit operator bool() const { return IsValid(); } + + bool IsValid() const { return m_cu && m_die; } + + bool HasChildren() const; + + bool Supports_DW_AT_APPLE_objc_complete_type() const; + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + SymbolFileDWARF *GetDWARF() const; + + DWARFUnit *GetCU() const { return m_cu; } + + DWARFDebugInfoEntry *GetDIE() const { return m_die; } + + DIERef GetDIERef() const; + + lldb_private::TypeSystem *GetTypeSystem() const; + + DWARFASTParser *GetDWARFParser() const; + + void Set(DWARFUnit *cu, DWARFDebugInfoEntry *die) { + if (cu && die) { + m_cu = cu; + m_die = die; + } else { + Clear(); + } + } + + void Clear() { + m_cu = nullptr; + m_die = nullptr; + } + + //---------------------------------------------------------------------- + // Get the data that contains the attribute values for this DIE. Support + // for .debug_types means that any DIE can have its data either in the + // .debug_info or the .debug_types section; this method will return the + // correct section data. + // + // Clients must validate that this object is valid before calling this. + //---------------------------------------------------------------------- + const lldb_private::DWARFDataExtractor &GetData() const; + + //---------------------------------------------------------------------- + // Accessing information about a DIE + //---------------------------------------------------------------------- + dw_tag_t Tag() const; + + const char *GetTagAsCString() const; + + dw_offset_t GetOffset() const; + + dw_offset_t GetCompileUnitRelativeOffset() const; + + //---------------------------------------------------------------------- + // Get the LLDB user ID for this DIE. This is often just the DIE offset, + // but it might have a SymbolFileDWARF::GetID() in the high 32 bits if + // we are doing Darwin DWARF in .o file, or DWARF stand alone debug + // info. + //---------------------------------------------------------------------- + lldb::user_id_t GetID() const; + + const char *GetName() const; + + lldb::LanguageType GetLanguage() const; + + lldb::ModuleSP GetModule() const; + + lldb_private::CompileUnit *GetLLDBCompileUnit() const; + + //---------------------------------------------------------------------- + // Getting attribute values from the DIE. + // + // GetAttributeValueAsXXX() functions should only be used if you are + // looking for one or two attributes on a DIE. If you are trying to + // parse all attributes, use GetAttributes (...) instead + //---------------------------------------------------------------------- + const char *GetAttributeValueAsString(const dw_attr_t attr, + const char *fail_value) const; + + uint64_t GetAttributeValueAsUnsigned(const dw_attr_t attr, + uint64_t fail_value) const; + + int64_t GetAttributeValueAsSigned(const dw_attr_t attr, + int64_t fail_value) const; + + uint64_t GetAttributeValueAsReference(const dw_attr_t attr, + uint64_t fail_value) const; + + uint64_t GetAttributeValueAsAddress(const dw_attr_t attr, + uint64_t fail_value) const; + + size_t GetAttributes(DWARFAttributes &attributes, uint32_t depth = 0) const; + + //---------------------------------------------------------------------- + // Pretty printing + //---------------------------------------------------------------------- + + void Dump(lldb_private::Stream *s, const uint32_t recurse_depth) const; + +protected: + DWARFUnit *m_cu; + DWARFDebugInfoEntry *m_die; +}; + +bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); +bool operator!=(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); + +#endif // SymbolFileDWARF_DWARFBaseDIE_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index 5d7b12067263..8541f1cfe1f6 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -9,48 +9,22 @@ #include "DWARFCompileUnit.h" -#include "Plugins/Language/ObjC/ObjCLanguage.h" -#include "lldb/Core/DumpDataExtractor.h" -#include "lldb/Core/Mangled.h" -#include "lldb/Core/Module.h" -#include "lldb/Host/StringConvert.h" -#include "lldb/Symbol/CompileUnit.h" -#include "lldb/Symbol/LineTable.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Utility/Stream.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/Utility/Timer.h" - -#include "DWARFDIECollection.h" -#include "DWARFDebugAbbrev.h" -#include "DWARFDebugAranges.h" -#include "DWARFDebugInfo.h" -#include "DWARFFormValue.h" -#include "LogChannelDWARF.h" -#include "NameToDIE.h" #include "SymbolFileDWARF.h" -#include "SymbolFileDWARFDebugMap.h" -#include "SymbolFileDWARFDwo.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; -using namespace std; extern int g_verbose; DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data) - : m_dwarf2Data(dwarf2Data) {} + : DWARFUnit(dwarf2Data) {} -DWARFCompileUnit::~DWARFCompileUnit() {} - -DWARFCompileUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, - lldb::offset_t *offset_ptr) { - DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(dwarf2Data)); - // Out of memory? - if (cu_sp.get() == NULL) - return nullptr; - - const DWARFDataExtractor &debug_info = dwarf2Data->get_debug_info_data(); +DWARFUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, + const DWARFDataExtractor &debug_info, + lldb::offset_t *offset_ptr) { + // std::make_shared would require the ctor to be public. + std::shared_ptr<DWARFCompileUnit> cu_sp(new DWARFCompileUnit(dwarf2Data)); cu_sp->m_offset = *offset_ptr; @@ -83,259 +57,6 @@ DWARFCompileUnitSP DWARFCompileUnit::Extract(SymbolFileDWARF *dwarf2Data, return nullptr; } -void DWARFCompileUnit::ClearDIEs(bool keep_compile_unit_die) { - if (m_die_array.size() > 1) { - // std::vectors never get any smaller when resized to a smaller size, - // or when clear() or erase() are called, the size will report that it - // is smaller, but the memory allocated remains intact (call capacity() - // to see this). So we need to create a temporary vector and swap the - // contents which will cause just the internal pointers to be swapped - // so that when "tmp_array" goes out of scope, it will destroy the - // contents. - - // Save at least the compile unit DIE - DWARFDebugInfoEntry::collection tmp_array; - m_die_array.swap(tmp_array); - if (keep_compile_unit_die) - m_die_array.push_back(tmp_array.front()); - } - - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->ClearDIEs(keep_compile_unit_die); -} - -//---------------------------------------------------------------------- -// ParseCompileUnitDIEsIfNeeded -// -// Parses a compile unit and indexes its DIEs if it hasn't already been -// done. -//---------------------------------------------------------------------- -size_t DWARFCompileUnit::ExtractDIEsIfNeeded(bool cu_die_only) { - const size_t initial_die_array_size = m_die_array.size(); - if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1) - return 0; // Already parsed - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, - "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )", - m_offset, cu_die_only); - - // Set the offset to that of the first DIE and calculate the start of the - // next compilation unit header. - lldb::offset_t offset = GetFirstDIEOffset(); - lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); - - DWARFDebugInfoEntry die; - // Keep a flat array of the DIE for binary lookup by DIE offset - if (!cu_die_only) { - Log *log( - LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); - if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( - log, "DWARFCompileUnit::ExtractDIEsIfNeeded () for compile unit at " - ".debug_info[0x%8.8x]", - GetOffset()); - } - } - - uint32_t depth = 0; - // We are in our compile unit, parse starting at the offset - // we were told to parse - const DWARFDataExtractor &debug_info_data = - m_dwarf2Data->get_debug_info_data(); - std::vector<uint32_t> die_index_stack; - die_index_stack.reserve(32); - die_index_stack.push_back(0); - bool prev_die_had_children = false; - DWARFFormValue::FixedFormSizes fixed_form_sizes = - DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - m_is_dwarf64); - while (offset < next_cu_offset && - die.FastExtract(debug_info_data, this, fixed_form_sizes, &offset)) { - // if (log) - // log->Printf("0x%8.8x: %*.*s%s%s", - // die.GetOffset(), - // depth * 2, depth * 2, "", - // DW_TAG_value_to_name (die.Tag()), - // die.HasChildren() ? " *" : ""); - - const bool null_die = die.IsNULL(); - if (depth == 0) { - if (initial_die_array_size == 0) - AddCompileUnitDIE(die); - uint64_t base_addr = die.GetAttributeValueAsAddress( - m_dwarf2Data, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); - if (base_addr == LLDB_INVALID_ADDRESS) - base_addr = die.GetAttributeValueAsAddress(m_dwarf2Data, this, - DW_AT_entry_pc, 0); - SetBaseAddress(base_addr); - if (cu_die_only) - return 1; - } else { - if (null_die) { - if (prev_die_had_children) { - // This will only happen if a DIE says is has children - // but all it contains is a NULL tag. Since we are removing - // the NULL DIEs from the list (saves up to 25% in C++ code), - // we need a way to let the DIE know that it actually doesn't - // have children. - if (!m_die_array.empty()) - m_die_array.back().SetEmptyChildren(true); - } - } else { - die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); - - if (die_index_stack.back()) - m_die_array[die_index_stack.back()].SetSiblingIndex( - m_die_array.size() - die_index_stack.back()); - - // Only push the DIE if it isn't a NULL DIE - m_die_array.push_back(die); - } - } - - if (null_die) { - // NULL DIE. - if (!die_index_stack.empty()) - die_index_stack.pop_back(); - - if (depth > 0) - --depth; - if (depth == 0) - break; // We are done with this compile unit! - - prev_die_had_children = false; - } else { - die_index_stack.back() = m_die_array.size() - 1; - // Normal DIE - const bool die_has_children = die.HasChildren(); - if (die_has_children) { - die_index_stack.push_back(0); - ++depth; - } - prev_die_had_children = die_has_children; - } - } - - // Give a little bit of info if we encounter corrupt DWARF (our offset - // should always terminate at or before the start of the next compilation - // unit header). - if (offset > next_cu_offset) { - m_dwarf2Data->GetObjectFile()->GetModule()->ReportWarning( - "DWARF compile unit extends beyond its bounds cu 0x%8.8x at " - "0x%8.8" PRIx64 "\n", - GetOffset(), offset); - } - - // Since std::vector objects will double their size, we really need to - // make a new array with the perfect size so we don't end up wasting - // space. So here we copy and swap to make sure we don't have any extra - // memory taken up. - - if (m_die_array.size() < m_die_array.capacity()) { - DWARFDebugInfoEntry::collection exact_size_die_array(m_die_array.begin(), - m_die_array.end()); - exact_size_die_array.swap(m_die_array); - } - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); - if (log && log->GetVerbose()) { - StreamString strm; - Dump(&strm); - if (m_die_array.empty()) - strm.Printf("error: no DIE for compile unit"); - else - m_die_array[0].Dump(m_dwarf2Data, this, strm, UINT32_MAX); - log->PutString(strm.GetString()); - } - - if (!m_dwo_symbol_file) - return m_die_array.size(); - - DWARFCompileUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - size_t dwo_die_count = dwo_cu->ExtractDIEsIfNeeded(cu_die_only); - return m_die_array.size() + dwo_die_count - - 1; // We have 2 CU die, but we want to count it only as one -} - -void DWARFCompileUnit::AddCompileUnitDIE(DWARFDebugInfoEntry &die) { - assert(m_die_array.empty() && "Compile unit DIE already added"); - AddDIE(die); - - const DWARFDebugInfoEntry &cu_die = m_die_array.front(); - std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = - m_dwarf2Data->GetDwoSymbolFileForCompileUnit(*this, cu_die); - if (!dwo_symbol_file) - return; - - DWARFCompileUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); - if (!dwo_cu) - return; // Can't fetch the compile unit from the dwo file. - - DWARFDIE dwo_cu_die = dwo_cu->GetCompileUnitDIEOnly(); - if (!dwo_cu_die.IsValid()) - return; // Can't fetch the compile unit DIE from the dwo file. - - uint64_t main_dwo_id = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_dwo_id, 0); - uint64_t sub_dwo_id = - dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); - if (main_dwo_id != sub_dwo_id) - return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to - // a differectn compilation. - - m_dwo_symbol_file = std::move(dwo_symbol_file); - - dw_addr_t addr_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_addr_base, 0); - dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_GNU_ranges_base, 0); - dwo_cu->SetAddrBase(addr_base, ranges_base, m_offset); -} - -dw_offset_t DWARFCompileUnit::GetAbbrevOffset() const { - return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; -} - -bool DWARFCompileUnit::Verify(Stream *s) const { - const DWARFDataExtractor &debug_info = m_dwarf2Data->get_debug_info_data(); - bool valid_offset = debug_info.ValidOffset(m_offset); - bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(m_version); - bool abbr_offset_OK = - m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset()); - bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8)); - if (valid_offset && length_OK && version_OK && addr_size_OK && - abbr_offset_OK) { - return true; - } else { - s->Printf(" 0x%8.8x: ", m_offset); - DumpDataExtractor(m_dwarf2Data->get_debug_info_data(), s, m_offset, - lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0, - 0); - s->EOL(); - if (valid_offset) { - if (!length_OK) - s->Printf(" The length (0x%8.8x) for this compile unit is too " - "large for the .debug_info provided.\n", - m_length); - if (!version_OK) - s->Printf(" The 16 bit compile unit header version is not " - "supported.\n"); - if (!abbr_offset_OK) - s->Printf(" The offset into the .debug_abbrev section (0x%8.8x) " - "is not valid.\n", - GetAbbrevOffset()); - if (!addr_size_OK) - s->Printf(" The address size is unsupported: 0x%2.2x\n", - m_addr_size); - } else - s->Printf(" The start offset of the compile unit header in the " - ".debug_info is invalid.\n"); - } - return false; -} - void DWARFCompileUnit::Dump(Stream *s) const { s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, " "abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at " @@ -344,768 +65,7 @@ void DWARFCompileUnit::Dump(Stream *s) const { GetNextCompileUnitOffset()); } -static uint8_t g_default_addr_size = 4; - -uint8_t DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit *cu) { - if (cu) - return cu->GetAddressByteSize(); - return DWARFCompileUnit::GetDefaultAddressSize(); -} - -bool DWARFCompileUnit::IsDWARF64(const DWARFCompileUnit *cu) { - if (cu) - return cu->IsDWARF64(); - return false; -} - -uint8_t DWARFCompileUnit::GetDefaultAddressSize() { - return g_default_addr_size; -} - -void DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size) { - g_default_addr_size = addr_size; -} - -lldb::user_id_t DWARFCompileUnit::GetID() const { - dw_offset_t local_id = - m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; - if (m_dwarf2Data) - return DIERef(local_id, local_id).GetUID(m_dwarf2Data); - else - return local_id; -} - -void DWARFCompileUnit::BuildAddressRangeTable( - SymbolFileDWARF *dwarf2Data, DWARFDebugAranges *debug_aranges) { - // This function is usually called if there in no .debug_aranges section - // in order to produce a compile unit level set of address ranges that - // is accurate. - - size_t num_debug_aranges = debug_aranges->GetNumRanges(); - - // First get the compile unit DIE only and check if it has a DW_AT_ranges - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - - const dw_offset_t cu_offset = GetOffset(); - if (die) { - DWARFRangeList ranges; - const size_t num_ranges = - die->GetAttributeAddressRanges(dwarf2Data, this, ranges, false); - if (num_ranges > 0) { - // This compile unit has DW_AT_ranges, assume this is correct if it - // is present since clang no longer makes .debug_aranges by default - // and it emits DW_AT_ranges for DW_TAG_compile_units. GCC also does - // this with recent GCC builds. - for (size_t i = 0; i < num_ranges; ++i) { - const DWARFRangeList::Entry &range = ranges.GetEntryRef(i); - debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), - range.GetRangeEnd()); - } - - return; // We got all of our ranges from the DW_AT_ranges attribute - } - } - // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF - - // If the DIEs weren't parsed, then we don't want all dies for all compile - // units - // to stay loaded when they weren't needed. So we can end up parsing the DWARF - // and then throwing them all away to keep memory usage down. - const bool clear_dies = ExtractDIEsIfNeeded(false) > 1; - - die = DIEPtr(); - if (die) - die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges); - - if (debug_aranges->GetNumRanges() == num_debug_aranges) { - // We got nothing from the functions, maybe we have a line tables only - // situation. Check the line tables and build the arange table from this. - SymbolContext sc; - sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); - if (sc.comp_unit) { - SymbolFileDWARFDebugMap *debug_map_sym_file = - m_dwarf2Data->GetDebugMapSymfile(); - if (debug_map_sym_file == NULL) { - LineTable *line_table = sc.comp_unit->GetLineTable(); - - if (line_table) { - LineTable::FileAddressRanges file_ranges; - const bool append = true; - const size_t num_ranges = - line_table->GetContiguousFileAddressRanges(file_ranges, append); - for (uint32_t idx = 0; idx < num_ranges; ++idx) { - const LineTable::FileAddressRanges::Entry &range = - file_ranges.GetEntryRef(idx); - debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), - range.GetRangeEnd()); - } - } - } else - debug_map_sym_file->AddOSOARanges(dwarf2Data, debug_aranges); - } - } - - if (debug_aranges->GetNumRanges() == num_debug_aranges) { - // We got nothing from the functions, maybe we have a line tables only - // situation. Check the line tables and build the arange table from this. - SymbolContext sc; - sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this); - if (sc.comp_unit) { - LineTable *line_table = sc.comp_unit->GetLineTable(); - - if (line_table) { - LineTable::FileAddressRanges file_ranges; - const bool append = true; - const size_t num_ranges = - line_table->GetContiguousFileAddressRanges(file_ranges, append); - for (uint32_t idx = 0; idx < num_ranges; ++idx) { - const LineTable::FileAddressRanges::Entry &range = - file_ranges.GetEntryRef(idx); - debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), - range.GetRangeEnd()); - } - } - } - } - - // Keep memory down by clearing DIEs if this generate function - // caused them to be parsed - if (clear_dies) - ClearDIEs(true); -} - -const DWARFDebugAranges &DWARFCompileUnit::GetFunctionAranges() { - if (m_func_aranges_ap.get() == NULL) { - m_func_aranges_ap.reset(new DWARFDebugAranges()); - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); - - if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( - log, "DWARFCompileUnit::GetFunctionAranges() for compile unit at " - ".debug_info[0x%8.8x]", - GetOffset()); - } - const DWARFDebugInfoEntry *die = DIEPtr(); - if (die) - die->BuildFunctionAddressRangeTable(m_dwarf2Data, this, - m_func_aranges_ap.get()); - - if (m_dwo_symbol_file) { - DWARFCompileUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); - const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); - if (dwo_die) - dwo_die->BuildFunctionAddressRangeTable(m_dwo_symbol_file.get(), dwo_cu, - m_func_aranges_ap.get()); - } - - const bool minimize = false; - m_func_aranges_ap->Sort(minimize); - } - return *m_func_aranges_ap.get(); -} - -DWARFDIE -DWARFCompileUnit::LookupAddress(const dw_addr_t address) { - if (DIE()) { - const DWARFDebugAranges &func_aranges = GetFunctionAranges(); - - // Re-check the aranges auto pointer contents in case it was created above - if (!func_aranges.IsEmpty()) - return GetDIE(func_aranges.FindAddress(address)); - } - return DWARFDIE(); -} - -//---------------------------------------------------------------------- -// Compare function DWARFDebugAranges::Range structures -//---------------------------------------------------------------------- -static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, - const dw_offset_t die_offset) { - return die.GetOffset() < die_offset; -} - -//---------------------------------------------------------------------- -// GetDIE() -// -// Get the DIE (Debug Information Entry) with the specified offset by -// first checking if the DIE is contained within this compile unit and -// grabbing the DIE from this compile unit. Otherwise we grab the DIE -// from the DWARF file. -//---------------------------------------------------------------------- -DWARFDIE -DWARFCompileUnit::GetDIE(dw_offset_t die_offset) { - if (die_offset != DW_INVALID_OFFSET) { - if (m_dwo_symbol_file) - return m_dwo_symbol_file->GetCompileUnit()->GetDIE(die_offset); - - if (ContainsDIEOffset(die_offset)) { - ExtractDIEsIfNeeded(false); - DWARFDebugInfoEntry::iterator end = m_die_array.end(); - DWARFDebugInfoEntry::iterator pos = - lower_bound(m_die_array.begin(), end, die_offset, CompareDIEOffset); - if (pos != end) { - if (die_offset == (*pos).GetOffset()) - return DWARFDIE(this, &(*pos)); - } - } else { - // Don't specify the compile unit offset as we don't know it because the - // DIE belongs to - // a different compile unit in the same symbol file. - return m_dwarf2Data->DebugInfo()->GetDIEForDIEOffset(die_offset); - } - } - return DWARFDIE(); // Not found -} - -size_t DWARFCompileUnit::AppendDIEsWithTag(const dw_tag_t tag, - DWARFDIECollection &dies, - uint32_t depth) const { - size_t old_size = dies.Size(); - 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.Append(DWARFDIE(this, &(*pos))); - } - - // Return the number of DIEs added to the collection - return dies.Size() - old_size; -} - -// void -// DWARFCompileUnit::AddGlobalDIEByIndex (uint32_t die_idx) -//{ -// m_global_die_indexes.push_back (die_idx); -//} -// -// -// void -// DWARFCompileUnit::AddGlobal (const DWARFDebugInfoEntry* die) -//{ -// // Indexes to all file level global and static variables -// m_global_die_indexes; -// -// if (m_die_array.empty()) -// return; -// -// const DWARFDebugInfoEntry* first_die = &m_die_array[0]; -// const DWARFDebugInfoEntry* end = first_die + m_die_array.size(); -// if (first_die <= die && die < end) -// m_global_die_indexes.push_back (die - first_die); -//} - -void DWARFCompileUnit::Index(NameToDIE &func_basenames, - NameToDIE &func_fullnames, NameToDIE &func_methods, - NameToDIE &func_selectors, - NameToDIE &objc_class_selectors, - NameToDIE &globals, NameToDIE &types, - NameToDIE &namespaces) { - assert(!m_dwarf2Data->GetBaseCompileUnit() && - "DWARFCompileUnit associated with .dwo or .dwp " - "should not be indexed directly"); - - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); - - if (log) { - m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage( - log, - "DWARFCompileUnit::Index() for compile unit at .debug_info[0x%8.8x]", - GetOffset()); - } - - const LanguageType cu_language = GetLanguageType(); - DWARFFormValue::FixedFormSizes fixed_form_sizes = - DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - m_is_dwarf64); - - IndexPrivate(this, cu_language, fixed_form_sizes, GetOffset(), func_basenames, - func_fullnames, func_methods, func_selectors, - objc_class_selectors, globals, types, namespaces); - - SymbolFileDWARFDwo *dwo_symbol_file = GetDwoSymbolFile(); - if (dwo_symbol_file) { - IndexPrivate(dwo_symbol_file->GetCompileUnit(), cu_language, - fixed_form_sizes, GetOffset(), func_basenames, func_fullnames, - func_methods, func_selectors, objc_class_selectors, globals, - types, namespaces); - } -} - -void DWARFCompileUnit::IndexPrivate( - DWARFCompileUnit *dwarf_cu, const LanguageType cu_language, - const DWARFFormValue::FixedFormSizes &fixed_form_sizes, - const dw_offset_t cu_offset, NameToDIE &func_basenames, - NameToDIE &func_fullnames, NameToDIE &func_methods, - NameToDIE &func_selectors, NameToDIE &objc_class_selectors, - NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces) { - DWARFDebugInfoEntry::const_iterator pos; - DWARFDebugInfoEntry::const_iterator begin = dwarf_cu->m_die_array.begin(); - DWARFDebugInfoEntry::const_iterator end = dwarf_cu->m_die_array.end(); - for (pos = begin; pos != end; ++pos) { - const DWARFDebugInfoEntry &die = *pos; - - const dw_tag_t tag = die.Tag(); - - switch (tag) { - case DW_TAG_array_type: - case DW_TAG_base_type: - case DW_TAG_class_type: - case DW_TAG_constant: - case DW_TAG_enumeration_type: - case DW_TAG_inlined_subroutine: - case DW_TAG_namespace: - case DW_TAG_string_type: - case DW_TAG_structure_type: - case DW_TAG_subprogram: - case DW_TAG_subroutine_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - case DW_TAG_unspecified_type: - case DW_TAG_variable: - break; - - default: - continue; - } - - DWARFAttributes attributes; - const char *name = NULL; - const char *mangled_cstr = NULL; - bool is_declaration = false; - // bool is_artificial = false; - bool has_address = false; - bool has_location_or_const_value = false; - bool is_global_or_static_variable = false; - - DWARFFormValue specification_die_form; - const size_t num_attributes = - die.GetAttributes(dwarf_cu, fixed_form_sizes, attributes); - if (num_attributes > 0) { - for (uint32_t i = 0; i < num_attributes; ++i) { - dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - switch (attr) { - case DW_AT_name: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - name = form_value.AsCString(); - break; - - case DW_AT_declaration: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - is_declaration = form_value.Unsigned() != 0; - break; - - // case DW_AT_artificial: - // if (attributes.ExtractFormValueAtIndex(i, - // form_value)) - // is_artificial = form_value.Unsigned() != 0; - // break; - - case DW_AT_MIPS_linkage_name: - case DW_AT_linkage_name: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - mangled_cstr = form_value.AsCString(); - break; - - case DW_AT_low_pc: - case DW_AT_high_pc: - case DW_AT_ranges: - has_address = true; - break; - - case DW_AT_entry_pc: - has_address = true; - break; - - case DW_AT_location: - case DW_AT_const_value: - has_location_or_const_value = true; - if (tag == DW_TAG_variable) { - const DWARFDebugInfoEntry *parent_die = die.GetParent(); - while (parent_die != NULL) { - switch (parent_die->Tag()) { - case DW_TAG_subprogram: - case DW_TAG_lexical_block: - case DW_TAG_inlined_subroutine: - // Even if this is a function level static, we don't add it. We - // could theoretically - // add these if we wanted to by introspecting into the - // DW_AT_location and seeing - // if the location describes a hard coded address, but we dont - // want the performance - // penalty of that right now. - is_global_or_static_variable = false; - // if - // (attributes.ExtractFormValueAtIndex(dwarf2Data, - // i, form_value)) - // { - // // If we have valid block - // data, then we have location - // expression bytes - // // that are fixed (not a - // location list). - // const uint8_t *block_data = - // form_value.BlockData(); - // if (block_data) - // { - // uint32_t block_length = - // form_value.Unsigned(); - // if (block_length == 1 + - // attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) - // { - // if (block_data[0] == - // DW_OP_addr) - // add_die = true; - // } - // } - // } - parent_die = NULL; // Terminate the while loop. - break; - - case DW_TAG_compile_unit: - is_global_or_static_variable = true; - parent_die = NULL; // Terminate the while loop. - break; - - default: - parent_die = - parent_die->GetParent(); // Keep going in the while loop. - break; - } - } - } - break; - - case DW_AT_specification: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - specification_die_form = form_value; - break; - } - } - } - - switch (tag) { - case DW_TAG_subprogram: - if (has_address) { - if (name) { - ObjCLanguage::MethodName objc_method(name, true); - if (objc_method.IsValid(true)) { - ConstString objc_class_name_with_category( - objc_method.GetClassNameWithCategory()); - ConstString objc_selector_name(objc_method.GetSelector()); - ConstString objc_fullname_no_category_name( - objc_method.GetFullNameWithoutCategory(true)); - ConstString objc_class_name_no_category(objc_method.GetClassName()); - func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - if (objc_class_name_with_category) - objc_class_selectors.Insert(objc_class_name_with_category, - DIERef(cu_offset, die.GetOffset())); - if (objc_class_name_no_category && - objc_class_name_no_category != objc_class_name_with_category) - objc_class_selectors.Insert(objc_class_name_no_category, - DIERef(cu_offset, die.GetOffset())); - if (objc_selector_name) - func_selectors.Insert(objc_selector_name, - DIERef(cu_offset, die.GetOffset())); - if (objc_fullname_no_category_name) - func_fullnames.Insert(objc_fullname_no_category_name, - DIERef(cu_offset, die.GetOffset())); - } - // If we have a mangled name, then the DW_AT_name attribute - // is usually the method name without the class or any parameters - const DWARFDebugInfoEntry *parent = die.GetParent(); - bool is_method = false; - if (parent) { - dw_tag_t parent_tag = parent->Tag(); - if (parent_tag == DW_TAG_class_type || - parent_tag == DW_TAG_structure_type) { - is_method = true; - } else { - if (specification_die_form.IsValid()) { - DWARFDIE specification_die = - dwarf_cu->GetSymbolFileDWARF()->DebugInfo()->GetDIE( - DIERef(specification_die_form)); - if (specification_die.GetParent().IsStructOrClass()) - is_method = true; - } - } - } - - if (is_method) - func_methods.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - else - func_basenames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - - if (!is_method && !mangled_cstr && !objc_method.IsValid(true)) - func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - } - if (mangled_cstr) { - // Make sure our mangled name isn't the same string table entry - // as our name. If it starts with '_', then it is ok, else compare - // the string to make sure it isn't the same and we don't end up - // with duplicate entries - if (name && name != mangled_cstr && - ((mangled_cstr[0] == '_') || - (::strcmp(name, mangled_cstr) != 0))) { - Mangled mangled(ConstString(mangled_cstr), true); - func_fullnames.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); - ConstString demangled = mangled.GetDemangledName(cu_language); - if (demangled) - func_fullnames.Insert(demangled, - DIERef(cu_offset, die.GetOffset())); - } - } - } - break; - - case DW_TAG_inlined_subroutine: - if (has_address) { - if (name) - func_basenames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - if (mangled_cstr) { - // Make sure our mangled name isn't the same string table entry - // as our name. If it starts with '_', then it is ok, else compare - // the string to make sure it isn't the same and we don't end up - // with duplicate entries - if (name && name != mangled_cstr && - ((mangled_cstr[0] == '_') || - (::strcmp(name, mangled_cstr) != 0))) { - Mangled mangled(ConstString(mangled_cstr), true); - func_fullnames.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); - ConstString demangled = mangled.GetDemangledName(cu_language); - if (demangled) - func_fullnames.Insert(demangled, - DIERef(cu_offset, die.GetOffset())); - } - } else - func_fullnames.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - } - break; - - case DW_TAG_array_type: - case DW_TAG_base_type: - case DW_TAG_class_type: - case DW_TAG_constant: - case DW_TAG_enumeration_type: - case DW_TAG_string_type: - case DW_TAG_structure_type: - case DW_TAG_subroutine_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - case DW_TAG_unspecified_type: - if (name && !is_declaration) - types.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset())); - if (mangled_cstr && !is_declaration) - types.Insert(ConstString(mangled_cstr), - DIERef(cu_offset, die.GetOffset())); - break; - - case DW_TAG_namespace: - if (name) - namespaces.Insert(ConstString(name), - DIERef(cu_offset, die.GetOffset())); - break; - - case DW_TAG_variable: - if (name && has_location_or_const_value && is_global_or_static_variable) { - globals.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset())); - // Be sure to include variables by their mangled and demangled - // names if they have any since a variable can have a basename - // "i", a mangled named "_ZN12_GLOBAL__N_11iE" and a demangled - // mangled name "(anonymous namespace)::i"... - - // Make sure our mangled name isn't the same string table entry - // as our name. If it starts with '_', then it is ok, else compare - // the string to make sure it isn't the same and we don't end up - // with duplicate entries - if (mangled_cstr && name != mangled_cstr && - ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { - Mangled mangled(ConstString(mangled_cstr), true); - globals.Insert(mangled.GetMangledName(), - DIERef(cu_offset, die.GetOffset())); - ConstString demangled = mangled.GetDemangledName(cu_language); - if (demangled) - globals.Insert(demangled, DIERef(cu_offset, die.GetOffset())); - } - } - break; - - default: - continue; - } - } -} - -bool DWARFCompileUnit::Supports_unnamed_objc_bitfields() { - if (GetProducer() == eProducerClang) { - const uint32_t major_version = GetProducerVersionMajor(); - if (major_version > 425 || - (major_version == 425 && GetProducerVersionUpdate() >= 13)) - return true; - else - return false; - } - return true; // Assume all other compilers didn't have incorrect ObjC bitfield - // info -} - -bool DWARFCompileUnit::Supports_DW_AT_APPLE_objc_complete_type() { - if (GetProducer() == eProducerLLVMGCC) - return false; - return true; -} - -bool DWARFCompileUnit::DW_AT_decl_file_attributes_are_invalid() { - // llvm-gcc makes completely invalid decl file attributes and won't ever - // be fixed, so we need to know to ignore these. - return GetProducer() == eProducerLLVMGCC; -} - -void DWARFCompileUnit::ParseProducerInfo() { - m_producer_version_major = UINT32_MAX; - m_producer_version_minor = UINT32_MAX; - m_producer_version_update = UINT32_MAX; - - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) { - - const char *producer_cstr = die->GetAttributeValueAsString( - m_dwarf2Data, this, DW_AT_producer, NULL); - if (producer_cstr) { - RegularExpression llvm_gcc_regex( - llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " - "Inc\\. build [0-9]+\\) \\(LLVM build " - "[\\.0-9]+\\)$")); - if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { - m_producer = eProducerLLVMGCC; - } else if (strstr(producer_cstr, "clang")) { - static RegularExpression g_clang_version_regex( - llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); - RegularExpression::Match regex_match(3); - if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr), - ®ex_match)) { - std::string str; - if (regex_match.GetMatchAtIndex(producer_cstr, 1, str)) - m_producer_version_major = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - if (regex_match.GetMatchAtIndex(producer_cstr, 2, str)) - m_producer_version_minor = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - if (regex_match.GetMatchAtIndex(producer_cstr, 3, str)) - m_producer_version_update = - StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); - } - m_producer = eProducerClang; - } else if (strstr(producer_cstr, "GNU")) - m_producer = eProducerGCC; - } - } - if (m_producer == eProducerInvalid) - m_producer = eProcucerOther; -} - -DWARFCompileUnit::Producer DWARFCompileUnit::GetProducer() { - if (m_producer == eProducerInvalid) - ParseProducerInfo(); - return m_producer; -} - -uint32_t DWARFCompileUnit::GetProducerVersionMajor() { - if (m_producer_version_major == 0) - ParseProducerInfo(); - return m_producer_version_major; -} - -uint32_t DWARFCompileUnit::GetProducerVersionMinor() { - if (m_producer_version_minor == 0) - ParseProducerInfo(); - return m_producer_version_minor; -} - -uint32_t DWARFCompileUnit::GetProducerVersionUpdate() { - if (m_producer_version_update == 0) - ParseProducerInfo(); - return m_producer_version_update; -} - -LanguageType DWARFCompileUnit::LanguageTypeFromDWARF(uint64_t val) { - // Note: user languages between lo_user and hi_user - // must be handled explicitly here. - switch (val) { - case DW_LANG_Mips_Assembler: - return eLanguageTypeMipsAssembler; - case DW_LANG_GOOGLE_RenderScript: - return eLanguageTypeExtRenderScript; - default: - return static_cast<LanguageType>(val); - } -} - -LanguageType DWARFCompileUnit::GetLanguageType() { - if (m_language_type != eLanguageTypeUnknown) - return m_language_type; - - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) - m_language_type = LanguageTypeFromDWARF(die->GetAttributeValueAsUnsigned( - m_dwarf2Data, this, DW_AT_language, 0)); - return m_language_type; -} - -bool DWARFCompileUnit::IsDWARF64() const { return m_is_dwarf64; } - -bool DWARFCompileUnit::GetIsOptimized() { - if (m_is_optimized == eLazyBoolCalculate) { - const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly(); - if (die) { - m_is_optimized = eLazyBoolNo; - if (die->GetAttributeValueAsUnsigned(m_dwarf2Data, this, - DW_AT_APPLE_optimized, 0) == 1) { - m_is_optimized = eLazyBoolYes; - } - } - } - if (m_is_optimized == eLazyBoolYes) { - return true; - } else { - return false; - } -} - -DWARFFormValue::FixedFormSizes DWARFCompileUnit::GetFixedFormSizes() { - return DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), - IsDWARF64()); -} - -TypeSystem *DWARFCompileUnit::GetTypeSystem() { - if (m_dwarf2Data) - return m_dwarf2Data->GetTypeSystemForLanguage(GetLanguageType()); - else - return nullptr; -} - -void DWARFCompileUnit::SetUserData(void *d) { - m_user_data = d; - if (m_dwo_symbol_file) - m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); -} - -void DWARFCompileUnit::SetAddrBase(dw_addr_t addr_base, - dw_addr_t ranges_base, - dw_offset_t base_obj_offset) { - m_addr_base = addr_base; - m_ranges_base = ranges_base; - m_base_obj_offset = base_obj_offset; -} -lldb::ByteOrder DWARFCompileUnit::GetByteOrder() const { - return m_dwarf2Data->GetObjectFile()->GetByteOrder(); +const lldb_private::DWARFDataExtractor &DWARFCompileUnit::GetData() const { + return m_dwarf->get_debug_info_data(); } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 8ea0d6465adf..9c1fc82f58b7 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -10,214 +10,39 @@ #ifndef SymbolFileDWARF_DWARFCompileUnit_h_ #define SymbolFileDWARF_DWARFCompileUnit_h_ -#include "DWARFDIE.h" -#include "DWARFDebugInfoEntry.h" -#include "lldb/lldb-enumerations.h" +#include "DWARFUnit.h" -class NameToDIE; -class SymbolFileDWARF; -class SymbolFileDWARFDwo; +class DWARFCompileUnit : public DWARFUnit { + friend class DWARFUnit; -typedef std::shared_ptr<DWARFCompileUnit> DWARFCompileUnitSP; - -class DWARFCompileUnit { public: - enum Producer { - eProducerInvalid = 0, - eProducerClang, - eProducerGCC, - eProducerLLVMGCC, - eProcucerOther - }; - - static DWARFCompileUnitSP Extract(SymbolFileDWARF *dwarf2Data, - lldb::offset_t *offset_ptr); - ~DWARFCompileUnit(); - - size_t ExtractDIEsIfNeeded(bool cu_die_only); - DWARFDIE LookupAddress(const dw_addr_t address); - size_t AppendDIEsWithTag(const dw_tag_t tag, - DWARFDIECollection &matching_dies, - uint32_t depth = UINT32_MAX) const; - bool Verify(lldb_private::Stream *s) const; - void Dump(lldb_private::Stream *s) const; - // Offset of the initial length field. - dw_offset_t GetOffset() const { return m_offset; } - lldb::user_id_t GetID() const; - // Size in bytes of the initial length + compile unit header. - uint32_t Size() const { return m_is_dwarf64 ? 23 : 11; } - bool ContainsDIEOffset(dw_offset_t die_offset) const { - return die_offset >= GetFirstDIEOffset() && - die_offset < GetNextCompileUnitOffset(); - } - dw_offset_t GetFirstDIEOffset() const { return m_offset + Size(); } - dw_offset_t GetNextCompileUnitOffset() const { - return m_offset + (m_is_dwarf64 ? 12 : 4) + m_length; - } - // Size of the CU data (without initial length and without header). - size_t GetDebugInfoSize() const { - return (m_is_dwarf64 ? 12 : 4) + m_length - Size(); - } - // Size of the CU data incl. header but without initial length. - uint32_t GetLength() const { return m_length; } - uint16_t GetVersion() const { return m_version; } - const DWARFAbbreviationDeclarationSet *GetAbbreviations() const { - return m_abbrevs; - } - dw_offset_t GetAbbrevOffset() const; - uint8_t GetAddressByteSize() const { return m_addr_size; } - dw_addr_t GetBaseAddress() const { return m_base_addr; } - dw_addr_t GetAddrBase() const { return m_addr_base; } - dw_addr_t GetRangesBase() const { return m_ranges_base; } - void SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, dw_offset_t base_obj_offset); - void ClearDIEs(bool keep_compile_unit_die); - void BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data, - DWARFDebugAranges *debug_aranges); - - lldb::ByteOrder GetByteOrder() const; - - lldb_private::TypeSystem *GetTypeSystem(); - - DWARFFormValue::FixedFormSizes GetFixedFormSizes(); - - void SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } - - DWARFDIE - GetCompileUnitDIEOnly() { return DWARFDIE(this, GetCompileUnitDIEPtrOnly()); } + static DWARFUnitSP Extract(SymbolFileDWARF *dwarf2Data, + const lldb_private::DWARFDataExtractor &debug_info, + lldb::offset_t *offset_ptr); + void Dump(lldb_private::Stream *s) const override; - DWARFDIE - DIE() { return DWARFDIE(this, DIEPtr()); } + //------------------------------------------------------------------ + /// Get the data that contains the DIE information for this unit. + /// + /// @return + /// The correct data (.debug_types for DWARF 4 and earlier, and + /// .debug_info for DWARF 5 and later) for the DIE information in + /// this unit. + //------------------------------------------------------------------ + const lldb_private::DWARFDataExtractor &GetData() const override; - void AddDIE(DWARFDebugInfoEntry &die) { - // The average bytes per DIE entry has been seen to be - // around 14-20 so lets pre-reserve half of that since - // we are now stripping the NULL tags. - - // Only reserve the memory if we are adding children of - // the main compile unit DIE. The compile unit DIE is always - // the first entry, so if our size is 1, then we are adding - // the first compile unit child DIE and should reserve - // the memory. - if (m_die_array.empty()) - m_die_array.reserve(GetDebugInfoSize() / 24); - m_die_array.push_back(die); + //------------------------------------------------------------------ + /// Get the size in bytes of the header. + /// + /// @return + /// Byte size of the compile unit header + //------------------------------------------------------------------ + uint32_t GetHeaderByteSize() const override { + return m_is_dwarf64 ? 23 : 11; } - void AddCompileUnitDIE(DWARFDebugInfoEntry &die); - - bool HasDIEsParsed() const { return m_die_array.size() > 1; } - - DWARFDIE - GetDIE(dw_offset_t die_offset); - - static uint8_t GetAddressByteSize(const DWARFCompileUnit *cu); - - static bool IsDWARF64(const DWARFCompileUnit *cu); - - static uint8_t GetDefaultAddressSize(); - - static void SetDefaultAddressSize(uint8_t addr_size); - - void *GetUserData() const { return m_user_data; } - - void SetUserData(void *d); - - bool Supports_DW_AT_APPLE_objc_complete_type(); - - bool DW_AT_decl_file_attributes_are_invalid(); - - bool Supports_unnamed_objc_bitfields(); - - void Index(NameToDIE &func_basenames, NameToDIE &func_fullnames, - NameToDIE &func_methods, NameToDIE &func_selectors, - NameToDIE &objc_class_selectors, NameToDIE &globals, - NameToDIE &types, NameToDIE &namespaces); - - const DWARFDebugAranges &GetFunctionAranges(); - - SymbolFileDWARF *GetSymbolFileDWARF() const { return m_dwarf2Data; } - - Producer GetProducer(); - - uint32_t GetProducerVersionMajor(); - - uint32_t GetProducerVersionMinor(); - - uint32_t GetProducerVersionUpdate(); - - static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); - - lldb::LanguageType GetLanguageType(); - - bool IsDWARF64() const; - - bool GetIsOptimized(); - - SymbolFileDWARFDwo *GetDwoSymbolFile() const { - return m_dwo_symbol_file.get(); - } - - dw_offset_t GetBaseObjOffset() const { return m_base_obj_offset; } - -protected: - SymbolFileDWARF *m_dwarf2Data; - std::unique_ptr<SymbolFileDWARFDwo> m_dwo_symbol_file; - const DWARFAbbreviationDeclarationSet *m_abbrevs; - void *m_user_data = nullptr; - DWARFDebugInfoEntry::collection - m_die_array; // The compile unit debug information entry item - std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap; // A table similar to - // the .debug_aranges - // table, but this one - // points to the exact - // DW_TAG_subprogram - // DIEs - dw_addr_t m_base_addr = 0; - // Offset of the initial length field. - dw_offset_t m_offset; - dw_offset_t m_length; - uint16_t m_version; - uint8_t m_addr_size; - Producer m_producer = eProducerInvalid; - uint32_t m_producer_version_major = 0; - uint32_t m_producer_version_minor = 0; - uint32_t m_producer_version_update = 0; - lldb::LanguageType m_language_type = lldb::eLanguageTypeUnknown; - bool m_is_dwarf64; - lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; - 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 - // If this is a dwo compile unit this is the offset of the base compile unit - // in the main object file - dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET; - - void ParseProducerInfo(); - - static void - IndexPrivate(DWARFCompileUnit *dwarf_cu, const lldb::LanguageType cu_language, - const DWARFFormValue::FixedFormSizes &fixed_form_sizes, - const dw_offset_t cu_offset, NameToDIE &func_basenames, - NameToDIE &func_fullnames, NameToDIE &func_methods, - NameToDIE &func_selectors, NameToDIE &objc_class_selectors, - NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces); - private: DWARFCompileUnit(SymbolFileDWARF *dwarf2Data); - - const DWARFDebugInfoEntry *GetCompileUnitDIEPtrOnly() { - ExtractDIEsIfNeeded(true); - if (m_die_array.empty()) - return NULL; - return &m_die_array[0]; - } - - const DWARFDebugInfoEntry *DIEPtr() { - ExtractDIEsIfNeeded(false); - if (m_die_array.empty()) - return NULL; - return &m_die_array[0]; - } - DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit); }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 4ef2e772ea5d..d9754e911017 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -10,43 +10,27 @@ #include "DWARFDIE.h" #include "DWARFASTParser.h" -#include "DWARFCompileUnit.h" #include "DWARFDIECollection.h" -#include "DWARFDebugAbbrev.h" -#include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "DWARFDebugInfoEntry.h" -#include "DWARFDebugRanges.h" #include "DWARFDeclContext.h" -#include "DWARFFormValue.h" -#include "SymbolFileDWARF.h" - -#include "lldb/Core/Module.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/Type.h" -#include "lldb/Symbol/TypeSystem.h" +#include "DWARFUnit.h" using namespace lldb_private; -DIERef DWARFDIE::GetDIERef() const { - if (!IsValid()) - return DIERef(); - - dw_offset_t cu_offset = m_cu->GetOffset(); - if (m_cu->GetBaseObjOffset() != DW_INVALID_OFFSET) - cu_offset = m_cu->GetBaseObjOffset(); - return DIERef(cu_offset, m_die->GetOffset()); -} +void DWARFDIE::ElaboratingDIEIterator::Next() { + assert(!m_worklist.empty() && "Incrementing end iterator?"); -dw_tag_t DWARFDIE::Tag() const { - if (m_die) - return m_die->Tag(); - else - return 0; -} + // Pop the current item from the list. + DWARFDIE die = m_worklist.back(); + m_worklist.pop_back(); -const char *DWARFDIE::GetTagAsCString() const { - return lldb_private::DW_TAG_value_to_name(Tag()); + // And add back any items that elaborate it. + for (dw_attr_t attr : {DW_AT_specification, DW_AT_abstract_origin}) { + if (DWARFDIE d = die.GetReferencedDIE(attr)) + if (m_seen.insert(die.GetID()).second) + m_worklist.push_back(d); + } } DWARFDIE @@ -91,37 +75,10 @@ DWARFDIE::GetDIE(dw_offset_t die_offset) const { return DWARFDIE(); } -const char *DWARFDIE::GetAttributeValueAsString(const dw_attr_t attr, - const char *fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsString(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - -uint64_t DWARFDIE::GetAttributeValueAsUnsigned(const dw_attr_t attr, - uint64_t fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsUnsigned(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - -int64_t DWARFDIE::GetAttributeValueAsSigned(const dw_attr_t attr, - int64_t fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsSigned(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - DWARFDIE DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { if (IsValid()) { - DWARFCompileUnit *cu = GetCU(); + DWARFUnit *cu = GetCU(); SymbolFileDWARF *dwarf = cu->GetSymbolFileDWARF(); const bool check_specification_or_abstract_origin = true; DWARFFormValue form_value; @@ -132,29 +89,11 @@ DWARFDIE::GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const { return DWARFDIE(); } -uint64_t DWARFDIE::GetAttributeValueAsReference(const dw_attr_t attr, - uint64_t fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsReference(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - -uint64_t DWARFDIE::GetAttributeValueAsAddress(const dw_attr_t attr, - uint64_t fail_value) const { - if (IsValid()) - return m_die->GetAttributeValueAsAddress(GetDWARF(), GetCU(), attr, - fail_value); - else - return fail_value; -} - DWARFDIE DWARFDIE::LookupDeepestBlock(lldb::addr_t file_addr) const { if (IsValid()) { SymbolFileDWARF *dwarf = GetDWARF(); - DWARFCompileUnit *cu = GetCU(); + DWARFUnit *cu = GetCU(); DWARFDebugInfoEntry *function_die = nullptr; DWARFDebugInfoEntry *block_die = nullptr; if (m_die->LookupAddress(file_addr, dwarf, cu, &function_die, &block_die)) { @@ -171,17 +110,6 @@ DWARFDIE::LookupDeepestBlock(lldb::addr_t file_addr) const { return DWARFDIE(); } -lldb::user_id_t DWARFDIE::GetID() const { - return GetDIERef().GetUID(GetDWARF()); -} - -const char *DWARFDIE::GetName() const { - if (IsValid()) - return m_die->GetName(GetDWARF(), m_cu); - else - return nullptr; -} - const char *DWARFDIE::GetMangledName() const { if (IsValid()) return m_die->GetMangledName(GetDWARF(), m_cu); @@ -203,28 +131,6 @@ const char *DWARFDIE::GetQualifiedName(std::string &storage) const { return nullptr; } -lldb::LanguageType DWARFDIE::GetLanguage() const { - if (IsValid()) - return m_cu->GetLanguageType(); - else - return lldb::eLanguageTypeUnknown; -} - -lldb::ModuleSP DWARFDIE::GetModule() const { - SymbolFileDWARF *dwarf = GetDWARF(); - if (dwarf) - return dwarf->GetObjectFile()->GetModule(); - else - return lldb::ModuleSP(); -} - -lldb_private::CompileUnit *DWARFDIE::GetLLDBCompileUnit() const { - if (IsValid()) - return GetDWARF()->GetCompUnitForDWARFCompUnit(GetCU()); - else - return nullptr; -} - lldb_private::Type *DWARFDIE::ResolveType() const { if (IsValid()) return GetDWARF()->ResolveType(*this, true); @@ -262,7 +168,7 @@ void DWARFDIE::GetDWARFDeclContext(DWARFDeclContext &dwarf_decl_ctx) const { void DWARFDIE::GetDWOContext(std::vector<CompilerContext> &context) const { const dw_tag_t tag = Tag(); - if (tag == DW_TAG_compile_unit) + if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) return; DWARFDIE parent = GetParent(); if (parent) @@ -317,45 +223,17 @@ DWARFDIE::GetParentDeclContextDIE() const { return DWARFDIE(); } -dw_offset_t DWARFDIE::GetOffset() const { - if (IsValid()) - return m_die->GetOffset(); - else - return DW_INVALID_OFFSET; -} - -dw_offset_t DWARFDIE::GetCompileUnitRelativeOffset() const { - if (IsValid()) - return m_die->GetOffset() - m_cu->GetOffset(); - else - return DW_INVALID_OFFSET; -} - -SymbolFileDWARF *DWARFDIE::GetDWARF() const { - if (m_cu) - return m_cu->GetSymbolFileDWARF(); - else - return nullptr; -} - -lldb_private::TypeSystem *DWARFDIE::GetTypeSystem() const { - if (m_cu) - return m_cu->GetTypeSystem(); - else - return nullptr; -} - -DWARFASTParser *DWARFDIE::GetDWARFParser() const { - lldb_private::TypeSystem *type_system = GetTypeSystem(); - if (type_system) - return type_system->GetDWARFParser(); - else - return nullptr; +bool DWARFDIE::IsStructUnionOrClass() const { + const dw_tag_t tag = Tag(); + return tag == DW_TAG_class_type || tag == DW_TAG_structure_type || + tag == DW_TAG_union_type; } -bool DWARFDIE::IsStructOrClass() const { - const dw_tag_t tag = Tag(); - return tag == DW_TAG_class_type || tag == DW_TAG_structure_type; +bool DWARFDIE::IsMethod() const { + for (DWARFDIE d: elaborating_dies()) + if (d.GetParent().IsStructUnionOrClass()) + return true; + return false; } DWARFDIE @@ -369,7 +247,7 @@ DWARFDIE::GetContainingDWOModuleDIE() const { const dw_tag_t tag = parent.Tag(); if (tag == DW_TAG_module) top_module_die = parent; - else if (tag == DW_TAG_compile_unit) + else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) break; } @@ -391,25 +269,6 @@ lldb::ModuleSP DWARFDIE::GetContainingDWOModule() const { return lldb::ModuleSP(); } -bool DWARFDIE::HasChildren() const { - return m_die && m_die->HasChildren(); -} - -bool DWARFDIE::Supports_DW_AT_APPLE_objc_complete_type() const { - return IsValid() && GetDWARF()->Supports_DW_AT_APPLE_objc_complete_type(m_cu); -} - -size_t DWARFDIE::GetAttributes(DWARFAttributes &attributes, - uint32_t depth) const { - if (IsValid()) { - return m_die->GetAttributes(m_cu, m_cu->GetFixedFormSizes(), attributes, - depth); - } - if (depth == 0) - attributes.Clear(); - return 0; -} - bool DWARFDIE::GetDIENamesAndRanges( const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, @@ -423,12 +282,6 @@ bool DWARFDIE::GetDIENamesAndRanges( return false; } -void DWARFDIE::Dump(lldb_private::Stream *s, - const uint32_t recurse_depth) const { - if (s && IsValid()) - m_die->Dump(GetDWARF(), GetCU(), *s, recurse_depth); -} - CompilerDecl DWARFDIE::GetDecl() const { DWARFASTParser *dwarf_ast = GetDWARFParser(); if (dwarf_ast) @@ -452,11 +305,3 @@ CompilerDeclContext DWARFDIE::GetContainingDeclContext() const { else return CompilerDeclContext(); } - -bool operator==(const DWARFDIE &lhs, const DWARFDIE &rhs) { - return lhs.GetDIE() == rhs.GetDIE() && lhs.GetCU() == rhs.GetCU(); -} - -bool operator!=(const DWARFDIE &lhs, const DWARFDIE &rhs) { - return !(lhs == rhs); -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 8af3015b9d76..ecbf4912634e 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -10,115 +10,41 @@ #ifndef SymbolFileDWARF_DWARFDIE_h_ #define SymbolFileDWARF_DWARFDIE_h_ -#include "lldb/Core/dwarf.h" -#include "lldb/lldb-types.h" +#include "DWARFBaseDIE.h" +#include "llvm/ADT/SmallSet.h" -struct DIERef; -class DWARFASTParser; -class DWARFAttributes; -class DWARFCompileUnit; -class DWARFDebugInfoEntry; -class DWARFDeclContext; -class DWARFDIECollection; -class SymbolFileDWARF; - -class DWARFDIE { +class DWARFDIE : public DWARFBaseDIE { public: - DWARFDIE() : m_cu(nullptr), m_die(nullptr) {} - - DWARFDIE(DWARFCompileUnit *cu, DWARFDebugInfoEntry *die) - : m_cu(cu), m_die(die) {} - - DWARFDIE(const DWARFCompileUnit *cu, DWARFDebugInfoEntry *die) - : m_cu(const_cast<DWARFCompileUnit *>(cu)), m_die(die) {} + class ElaboratingDIEIterator; - DWARFDIE(DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) - : m_cu(cu), m_die(const_cast<DWARFDebugInfoEntry *>(die)) {} - - DWARFDIE(const DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die) - : m_cu(const_cast<DWARFCompileUnit *>(cu)), - m_die(const_cast<DWARFDebugInfoEntry *>(die)) {} + using DWARFBaseDIE::DWARFBaseDIE; //---------------------------------------------------------------------- // Tests //---------------------------------------------------------------------- - explicit operator bool() const { return IsValid(); } - - bool IsValid() const { return m_cu && m_die; } - - bool IsStructOrClass() const; + bool IsStructUnionOrClass() const; - bool HasChildren() const; - - bool Supports_DW_AT_APPLE_objc_complete_type() const; + bool IsMethod() const; //---------------------------------------------------------------------- // Accessors //---------------------------------------------------------------------- - SymbolFileDWARF *GetDWARF() const; - - DWARFCompileUnit *GetCU() const { return m_cu; } - - DWARFDebugInfoEntry *GetDIE() const { return m_die; } - - DIERef GetDIERef() const; - - lldb_private::TypeSystem *GetTypeSystem() const; - - DWARFASTParser *GetDWARFParser() const; - - void Set(DWARFCompileUnit *cu, DWARFDebugInfoEntry *die) { - if (cu && die) { - m_cu = cu; - m_die = die; - } else { - Clear(); - } - } - - void Clear() { - m_cu = nullptr; - m_die = nullptr; - } - lldb::ModuleSP GetContainingDWOModule() const; DWARFDIE GetContainingDWOModuleDIE() const; - //---------------------------------------------------------------------- - // Accessing information about a DIE - //---------------------------------------------------------------------- - dw_tag_t Tag() const; - - const char *GetTagAsCString() const; - - dw_offset_t GetOffset() const; - - dw_offset_t GetCompileUnitRelativeOffset() const; + inline llvm::iterator_range<ElaboratingDIEIterator> elaborating_dies() const; //---------------------------------------------------------------------- - // Get the LLDB user ID for this DIE. This is often just the DIE offset, - // but it might have a SymbolFileDWARF::GetID() in the high 32 bits if - // we are doing Darwin DWARF in .o file, or DWARF stand alone debug - // info. + // Accessing information about a DIE //---------------------------------------------------------------------- - lldb::user_id_t GetID() const; - - const char *GetName() const; - const char *GetMangledName() const; const char *GetPubname() const; const char *GetQualifiedName(std::string &storage) const; - lldb::LanguageType GetLanguage() const; - - lldb::ModuleSP GetModule() const; - - lldb_private::CompileUnit *GetLLDBCompileUnit() const; - lldb_private::Type *ResolveType() const; //---------------------------------------------------------------------- @@ -149,6 +75,7 @@ public: //---------------------------------------------------------------------- DWARFDIE GetDIE(dw_offset_t die_offset) const; + using DWARFBaseDIE::GetDIE; DWARFDIE LookupDeepestBlock(lldb::addr_t file_addr) const; @@ -172,26 +99,9 @@ public: // looking for one or two attributes on a DIE. If you are trying to // parse all attributes, use GetAttributes (...) instead //---------------------------------------------------------------------- - const char *GetAttributeValueAsString(const dw_attr_t attr, - const char *fail_value) const; - - uint64_t GetAttributeValueAsUnsigned(const dw_attr_t attr, - uint64_t fail_value) const; - - int64_t GetAttributeValueAsSigned(const dw_attr_t attr, - int64_t fail_value) const; - - uint64_t GetAttributeValueAsReference(const dw_attr_t attr, - uint64_t fail_value) const; - DWARFDIE GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const; - uint64_t GetAttributeValueAsAddress(const dw_attr_t attr, - uint64_t fail_value) const; - - size_t GetAttributes(DWARFAttributes &attributes, uint32_t depth = 0) const; - bool GetDIENamesAndRanges(const char *&name, const char *&mangled, DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column, int &call_file, @@ -199,23 +109,68 @@ public: lldb_private::DWARFExpression *frame_base) const; //---------------------------------------------------------------------- - // Pretty printing + // CompilerDecl related functions //---------------------------------------------------------------------- - void Dump(lldb_private::Stream *s, const uint32_t recurse_depth) const; - lldb_private::CompilerDecl GetDecl() const; lldb_private::CompilerDeclContext GetDeclContext() const; lldb_private::CompilerDeclContext GetContainingDeclContext() const; +}; + +/// Iterate through all DIEs elaborating (i.e. reachable by a chain of +/// DW_AT_specification and DW_AT_abstract_origin attributes) a given DIE. For +/// convenience, the starting die is included in the sequence as the first +/// item. +class DWARFDIE::ElaboratingDIEIterator + : public std::iterator<std::input_iterator_tag, DWARFDIE> { + + // The operating invariant is: top of m_worklist contains the "current" item + // and the rest of the list are items yet to be visited. An empty worklist + // means we've reached the end. + // Infinite recursion is prevented by maintaining a list of seen DIEs. + // Container sizes are optimized for the case of following DW_AT_specification + // and DW_AT_abstract_origin just once. + llvm::SmallVector<DWARFDIE, 2> m_worklist; + llvm::SmallSet<lldb::user_id_t, 3> m_seen; + + void Next(); + +public: + /// An iterator starting at die d. + explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {} -protected: - DWARFCompileUnit *m_cu; - DWARFDebugInfoEntry *m_die; + /// End marker + ElaboratingDIEIterator() {} + + const DWARFDIE &operator*() const { return m_worklist.back(); } + ElaboratingDIEIterator &operator++() { + Next(); + return *this; + } + ElaboratingDIEIterator operator++(int) { + ElaboratingDIEIterator I = *this; + Next(); + return I; + } + + friend bool operator==(const ElaboratingDIEIterator &a, + const ElaboratingDIEIterator &b) { + if (a.m_worklist.empty() || b.m_worklist.empty()) + return a.m_worklist.empty() == b.m_worklist.empty(); + return a.m_worklist.back() == b.m_worklist.back(); + } + friend bool operator!=(const ElaboratingDIEIterator &a, + const ElaboratingDIEIterator &b) { + return !(a == b); + } }; -bool operator==(const DWARFDIE &lhs, const DWARFDIE &rhs); -bool operator!=(const DWARFDIE &lhs, const DWARFDIE &rhs); +llvm::iterator_range<DWARFDIE::ElaboratingDIEIterator> +DWARFDIE::elaborating_dies() const { + return llvm::make_range(ElaboratingDIEIterator(*this), + ElaboratingDIEIterator()); +} #endif // SymbolFileDWARF_DWARFDIE_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp index 0c807d7d604b..2fcdd34d532f 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp @@ -22,6 +22,6 @@ DWARFDataExtractor::GetDWARFInitialLength(lldb::offset_t *offset_ptr) const { dw_offset_t DWARFDataExtractor::GetDWARFOffset(lldb::offset_t *offset_ptr) const { - return GetMaxU64(offset_ptr, m_is_dwarf64 ? 8 : 4); + return GetMaxU64(offset_ptr, GetDWARFSizeOfOffset()); } } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h index 46d09f1ca237..ce0bfb3931d5 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h @@ -29,7 +29,7 @@ public: dw_offset_t GetDWARFOffset(lldb::offset_t *offset_ptr) const; size_t GetDWARFSizeofInitialLength() const { return m_is_dwarf64 ? 12 : 4; } - + size_t GetDWARFSizeOfOffset() const { return m_is_dwarf64 ? 8 : 4; } bool IsDWARF64() const { return m_is_dwarf64; } protected: diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp index 1cf0e7eeeb60..affe4b85bdab 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp @@ -80,8 +80,8 @@ DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration( //---------------------------------------------------------------------- // DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential() // -// Append an abbreviation declaration with a sequential code for O(n) -// lookups. Handy when creating an DWARFAbbreviationDeclarationSet. +// Append an abbreviation declaration with a sequential code for O(n) lookups. +// Handy when creating an DWARFAbbreviationDeclarationSet. //---------------------------------------------------------------------- dw_uleb128_t DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential( const DWARFAbbreviationDeclaration &abbrevDecl) { @@ -115,9 +115,9 @@ void DWARFAbbreviationDeclarationSet::GetUnsupportedForms( //---------------------------------------------------------------------- // Encode // -// Encode the abbreviation table onto the end of the buffer provided -// into a byte representation as would be found in a ".debug_abbrev" -// debug information section. +// Encode the abbreviation table onto the end of the buffer provided into a +// byte representation as would be found in a ".debug_abbrev" debug information +// section. //---------------------------------------------------------------------- // void // DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf) diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp index cecb69c8fb46..00265361f865 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp @@ -46,19 +46,17 @@ void DWARFDebugArangeSet::Compact() { if (m_arange_descriptors.empty()) return; - // Iterate through all arange descriptors and combine any ranges that - // overlap or have matching boundaries. The m_arange_descriptors are assumed - // to be in ascending order after being built by adding descriptors - // using the AddDescriptor method. + // Iterate through all arange descriptors and combine any ranges that overlap + // or have matching boundaries. The m_arange_descriptors are assumed to be in + // ascending order after being built by adding descriptors using the + // AddDescriptor method. uint32_t i = 0; while (i + 1 < m_arange_descriptors.size()) { if (m_arange_descriptors[i].end_address() >= m_arange_descriptors[i + 1].address) { // The current range ends at or exceeds the start of the next address - // range. - // Compute the max end address between the two and use that to make the - // new - // length. + // range. Compute the max end address between the two and use that to + // make the new length. const dw_addr_t max_end_addr = std::max(m_arange_descriptors[i].end_address(), m_arange_descriptors[i + 1].end_address()); @@ -82,8 +80,8 @@ static bool DescriptorLessThan(const DWARFDebugArangeSet::Descriptor &range1, } //---------------------------------------------------------------------- -// Add a range descriptor and keep things sorted so we can easily -// compact the ranges before being saved or used. +// Add a range descriptor and keep things sorted so we can easily compact the +// ranges before being saved or used. //---------------------------------------------------------------------- void DWARFDebugArangeSet::AddDescriptor( const DWARFDebugArangeSet::Descriptor &range) { @@ -103,15 +101,14 @@ void DWARFDebugArangeSet::AddDescriptor( // Non-contiguous entries, add this one before the found entry m_arange_descriptors.insert(pos, range); } else if (range_end_addr == pos->address) { - // The top end of 'range' is the lower end of the entry - // pointed to by 'pos'. We can combine range with the - // entry we found by setting the starting address and - // increasing the length since they don't overlap. + // The top end of 'range' is the lower end of the entry pointed to by + // 'pos'. We can combine range with the entry we found by setting the + // starting address and increasing the length since they don't overlap. pos->address = range.address; pos->length += range.length; } else { - // We can combine these two and make sure the largest end - // address is used to make end address. + // We can combine these two and make sure the largest end address is + // used to make end address. pos->address = range.address; pos->length = std::max(found_end_addr, range_end_addr) - pos->address; } @@ -142,18 +139,18 @@ bool DWARFDebugArangeSet::Extract(const DWARFDataExtractor &data, // 7.20 Address Range Table // - // Each set of entries in the table of address ranges contained in - // the .debug_aranges section begins with a header consisting of: a - // 4-byte length containing the length of the set of entries for this - // compilation unit, not including the length field itself; a 2-byte - // version identifier containing the value 2 for DWARF Version 2; a - // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer - // containing the size in bytes of an address (or the offset portion of - // an address for segmented addressing) on the target system; and a - // 1-byte unsigned integer containing the size in bytes of a segment - // descriptor on the target system. This header is followed by a series - // of tuples. Each tuple consists of an address and a length, each in - // the size appropriate for an address on the target architecture. + // Each set of entries in the table of address ranges contained in the + // .debug_aranges section begins with a header consisting of: a 4-byte + // length containing the length of the set of entries for this compilation + // unit, not including the length field itself; a 2-byte version identifier + // containing the value 2 for DWARF Version 2; a 4-byte offset into + // the.debug_infosection; a 1-byte unsigned integer containing the size in + // bytes of an address (or the offset portion of an address for segmented + // addressing) on the target system; and a 1-byte unsigned integer + // containing the size in bytes of a segment descriptor on the target + // system. This header is followed by a series of tuples. Each tuple + // consists of an address and a length, each in the size appropriate for an + // address on the target architecture. m_header.length = data.GetDWARFInitialLength(offset_ptr); m_header.version = data.GetU16(offset_ptr); m_header.cu_offset = data.GetDWARFOffset(offset_ptr); @@ -195,8 +192,8 @@ bool DWARFDebugArangeSet::Extract(const DWARFDataExtractor &data, arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size); - // Each set of tuples is terminated by a 0 for the address and 0 - // for the length. + // Each set of tuples is terminated by a 0 for the address and 0 for + // the length. if (arangeDescriptor.address || arangeDescriptor.length) m_arange_descriptors.push_back(arangeDescriptor); else diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index 13c2d8726821..02f528d571b0 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -18,7 +18,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" #include "LogChannelDWARF.h" #include "SymbolFileDWARF.h" @@ -82,7 +82,7 @@ bool DWARFDebugAranges::Generate(SymbolFileDWARF *dwarf2Data) { uint32_t cu_idx = 0; const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFCompileUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); + DWARFUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (cu) cu->BuildAddressRangeTable(dwarf2Data, this); } diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 9c0f1d3c8905..dadc30dc918a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -72,7 +72,7 @@ DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() { bool printed = false; const size_t num_compile_units = GetNumCompileUnits(); for (size_t idx = 0; idx < num_compile_units; ++idx) { - DWARFCompileUnit *cu = GetCompileUnitAtIndex(idx); + DWARFUnit *cu = GetCompileUnitAtIndex(idx); dw_offset_t offset = cu->GetOffset(); if (cus_with_data.find(offset) == cus_with_data.end()) { @@ -97,8 +97,10 @@ void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() { if (m_compile_units.empty()) { if (m_dwarf2Data != NULL) { lldb::offset_t offset = 0; - DWARFCompileUnitSP cu_sp; - while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, &offset))) { + DWARFUnitSP cu_sp; + const auto &debug_info_data = m_dwarf2Data->get_debug_info_data(); + while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, debug_info_data, + &offset))) { m_compile_units.push_back(cu_sp); offset = cu_sp->GetNextCompileUnitOffset(); @@ -112,16 +114,16 @@ size_t DWARFDebugInfo::GetNumCompileUnits() { return m_compile_units.size(); } -DWARFCompileUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { - DWARFCompileUnit *cu = NULL; +DWARFUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) { + DWARFUnit *cu = NULL; if (idx < GetNumCompileUnits()) cu = m_compile_units[idx].get(); return cu; } -bool DWARFDebugInfo::ContainsCompileUnit(const DWARFCompileUnit *cu) const { - // Not a verify efficient function, but it is handy for use in assertions - // to make sure that a compile unit comes from a debug information file. +bool DWARFDebugInfo::ContainsCompileUnit(const DWARFUnit *cu) const { + // Not a verify efficient function, but it is handy for use in assertions to + // make sure that a compile unit comes from a debug information file. CompileUnitColl::const_iterator end_pos = m_compile_units.end(); CompileUnitColl::const_iterator pos; @@ -133,13 +135,13 @@ bool DWARFDebugInfo::ContainsCompileUnit(const DWARFCompileUnit *cu) const { } bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset( - dw_offset_t offset, const DWARFCompileUnitSP &cu_sp) { + dw_offset_t offset, const DWARFUnitSP &cu_sp) { return offset < cu_sp->GetOffset(); } -DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, +DWARFUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t *idx_ptr) { - DWARFCompileUnitSP cu_sp; + DWARFUnitSP cu_sp; uint32_t cu_idx = DW_INVALID_INDEX; if (cu_offset != DW_INVALID_OFFSET) { ParseCompileUnitHeadersIfNeeded(); @@ -170,18 +172,18 @@ DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, return cu_sp.get(); } -DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { +DWARFUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) { if (die_ref.cu_offset == DW_INVALID_OFFSET) return GetCompileUnitContainingDIEOffset(die_ref.die_offset); else return GetCompileUnit(die_ref.cu_offset); } -DWARFCompileUnit * +DWARFUnit * DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { ParseCompileUnitHeadersIfNeeded(); - DWARFCompileUnitSP cu_sp; + DWARFUnitSP cu_sp; // Watch out for single compile unit executable as they are pretty common const size_t num_cus = m_compile_units.size(); @@ -205,7 +207,7 @@ DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) { DWARFDIE DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { - DWARFCompileUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); + DWARFUnit *cu = GetCompileUnitContainingDIEOffset(die_offset); if (cu) return cu->GetDIE(die_offset); return DWARFDIE(); @@ -218,275 +220,9 @@ DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) { //---------------------------------------------------------------------- DWARFDIE DWARFDebugInfo::GetDIE(const DIERef &die_ref) { - DWARFCompileUnit *cu = GetCompileUnit(die_ref); + DWARFUnit *cu = GetCompileUnit(die_ref); if (cu) return cu->GetDIE(die_ref.die_offset); return DWARFDIE(); // Not found } -//---------------------------------------------------------------------- -// Parse -// -// Parses the .debug_info section and uses the .debug_abbrev section -// and various other sections in the SymbolFileDWARF class and calls the -// supplied callback function each time a compile unit header, or debug -// information entry is successfully parsed. This function can be used -// for different tasks such as parsing the file contents into a -// structured data, dumping, verifying and much more. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback, - void *userData) { - if (dwarf2Data) { - lldb::offset_t offset = 0; - uint32_t depth = 0; - DWARFDebugInfoEntry die; - - DWARFCompileUnitSP cu; - while ((cu = DWARFCompileUnit::Extract(dwarf2Data, &offset))) { - const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset(); - - depth = 0; - // Call the callback function with no DIE pointer for the compile unit - // and get the offset that we are to continue to parse from - offset = callback(dwarf2Data, cu.get(), NULL, offset, depth, userData); - - // Make sure we are within our compile unit - if (offset < next_cu_offset) { - // We are in our compile unit, parse starting at the offset - // we were told to parse - bool done = false; - while (!done && die.Extract(dwarf2Data, cu.get(), &offset)) { - // Call the callback function with DIE pointer that falls within the - // compile unit - offset = - callback(dwarf2Data, cu.get(), &die, offset, depth, userData); - - if (die.IsNULL()) { - if (depth) - --depth; - else - done = true; // We are done with this compile unit! - } else if (die.HasChildren()) - ++depth; - } - } - - // Make sure the offset returned is valid, and if not stop parsing. - // Returning DW_INVALID_OFFSET from this callback is a good way to end - // all parsing - if (!dwarf2Data->get_debug_info_data().ValidOffset(offset)) - break; - - // Make sure we start on a proper - offset = next_cu_offset; - } - } -} - -typedef struct DumpInfo { - DumpInfo(Stream *init_strm, uint32_t off, uint32_t depth) - : strm(init_strm), die_offset(off), recurse_depth(depth), - found_depth(UINT32_MAX), found_die(false), ancestors() {} - Stream *strm; - const uint32_t die_offset; - const uint32_t recurse_depth; - uint32_t found_depth; - bool found_die; - std::vector<DWARFDebugInfoEntry> ancestors; - - DISALLOW_COPY_AND_ASSIGN(DumpInfo); -} DumpInfo; - -//---------------------------------------------------------------------- -// DumpCallback -// -// A callback function for the static DWARFDebugInfo::Parse() function -// that gets called each time a compile unit header or debug information -// entry is successfully parsed. -// -// This function dump DWARF information and obey recurse depth and -// whether a single DIE is to be dumped (or all of the data). -//---------------------------------------------------------------------- -static dw_offset_t DumpCallback(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, DWARFDebugInfoEntry *die, - const dw_offset_t next_offset, - const uint32_t curr_depth, void *userData) { - DumpInfo *dumpInfo = (DumpInfo *)userData; - Stream *s = dumpInfo->strm; - bool show_parents = - s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors); - - if (die) { - // Are we dumping everything? - if (dumpInfo->die_offset == DW_INVALID_OFFSET) { - // Yes we are dumping everything. Obey our recurse level though - if (curr_depth < dumpInfo->recurse_depth) - die->Dump(dwarf2Data, cu, *s, 0); - } else { - // We are dumping a specific DIE entry by offset - if (dumpInfo->die_offset == die->GetOffset()) { - // We found the DIE we were looking for, dump it! - if (show_parents) { - s->SetIndentLevel(0); - const uint32_t num_ancestors = dumpInfo->ancestors.size(); - if (num_ancestors > 0) { - for (uint32_t i = 0; i < num_ancestors - 1; ++i) { - dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0); - s->IndentMore(); - } - } - } - - dumpInfo->found_depth = curr_depth; - - die->Dump(dwarf2Data, cu, *s, 0); - - // Note that we found the DIE we were looking for - dumpInfo->found_die = true; - - // Since we are dumping a single DIE, if there are no children we are - // done! - if (!die->HasChildren() || dumpInfo->recurse_depth == 0) - return DW_INVALID_OFFSET; // Return an invalid address to end parsing - } else if (dumpInfo->found_die) { - // Are we done with all the children? - if (curr_depth <= dumpInfo->found_depth) - return DW_INVALID_OFFSET; - - // We have already found our DIE and are printing it's children. Obey - // our recurse depth and return an invalid offset if we get done - // dumping all of the children - if (dumpInfo->recurse_depth == UINT32_MAX || - curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth) - die->Dump(dwarf2Data, cu, *s, 0); - } else if (dumpInfo->die_offset > die->GetOffset()) { - if (show_parents) - dumpInfo->ancestors.back() = *die; - } - } - - // Keep up with our indent level - if (die->IsNULL()) { - if (show_parents) - dumpInfo->ancestors.pop_back(); - - if (curr_depth <= 1) - return cu->GetNextCompileUnitOffset(); - else - s->IndentLess(); - } else if (die->HasChildren()) { - if (show_parents) { - DWARFDebugInfoEntry null_die; - dumpInfo->ancestors.push_back(null_die); - } - s->IndentMore(); - } - } else { - if (cu == NULL) - s->PutCString("NULL - cu"); - // We have a compile unit, reset our indent level to zero just in case - s->SetIndentLevel(0); - - // See if we are dumping everything? - if (dumpInfo->die_offset == DW_INVALID_OFFSET) { - // We are dumping everything - if (cu) { - cu->Dump(s); - return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this - // Compile Unit - } else { - return DW_INVALID_OFFSET; - } - } else { - if (show_parents) { - dumpInfo->ancestors.clear(); - dumpInfo->ancestors.resize(1); - } - - // We are dumping only a single DIE possibly with it's children and - // we must find it's compile unit before we can dump it properly - if (cu && dumpInfo->die_offset < cu->GetFirstDIEOffset()) { - // Not found, maybe the DIE offset provided wasn't correct? - // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " - // was not found." << endl; - return DW_INVALID_OFFSET; - } else { - // See if the DIE is in this compile unit? - if (cu && dumpInfo->die_offset < cu->GetNextCompileUnitOffset()) { - return next_offset; - // // We found our compile unit that contains our DIE, just skip to - // dumping the requested DIE... - // return dumpInfo->die_offset; - } else { - // Skip to the next compile unit as the DIE isn't in the current one! - if (cu) { - return cu->GetNextCompileUnitOffset(); - } else { - return DW_INVALID_OFFSET; - } - } - } - } - } - - // Just return the current offset to parse the next CU or DIE entry - return next_offset; -} - -//---------------------------------------------------------------------- -// Dump -// -// Dump the information in the .debug_info section to the specified -// ostream. If die_offset is valid, a single DIE will be dumped. If the -// die_offset is invalid, all the DWARF information will be dumped. Both -// cases will obey a "recurse_depth" or how deep to traverse into the -// children of each DIE entry. A recurse_depth of zero will dump all -// compile unit headers. A recurse_depth of 1 will dump all compile unit -// headers and the DW_TAG_compile unit tags. A depth of 2 will also -// dump all types and functions. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Dump(Stream *s, SymbolFileDWARF *dwarf2Data, - const uint32_t die_offset, - const uint32_t recurse_depth) { - DumpInfo dumpInfo(s, die_offset, recurse_depth); - s->PutCString(".debug_info contents"); - if (dwarf2Data->get_debug_info_data().GetByteSize() > 0) { - if (die_offset == DW_INVALID_OFFSET) - s->PutCString(":\n"); - else { - s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset); - if (recurse_depth != UINT32_MAX) - s->Printf(" recursing %u levels deep.", recurse_depth); - s->EOL(); - } - } else { - s->PutCString(": < EMPTY >\n"); - return; - } - DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo); -} - -//---------------------------------------------------------------------- -// Dump -// -// Dump the contents of this DWARFDebugInfo object as has been parsed -// and/or modified after it has been parsed. -//---------------------------------------------------------------------- -void DWARFDebugInfo::Dump(Stream *s, const uint32_t die_offset, - const uint32_t recurse_depth) { - DumpInfo dumpInfo(s, die_offset, recurse_depth); - - s->PutCString("Dumping .debug_info section from internal representation\n"); - - CompileUnitColl::const_iterator pos; - uint32_t curr_depth = 0; - ParseCompileUnitHeadersIfNeeded(); - for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos) { - DWARFCompileUnit *cu = pos->get(); - DumpCallback(m_dwarf2Data, cu, NULL, 0, curr_depth, &dumpInfo); - - const DWARFDIE die = cu->DIE(); - if (die) - die.Dump(s, recurse_depth); - } -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index 14c7d767d05b..fc6085f99a21 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -13,6 +13,7 @@ #include <map> #include <vector> +#include "DWARFUnit.h" #include "DWARFDIE.h" #include "SymbolFileDWARF.h" #include "lldb/Core/STLUtils.h" @@ -26,7 +27,7 @@ typedef CStringToDIEMap::const_iterator CStringToDIEMapConstIter; class DWARFDebugInfo { public: typedef dw_offset_t (*Callback)(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, DWARFDebugInfoEntry *die, const dw_offset_t next_offset, const uint32_t depth, void *userData); @@ -35,22 +36,14 @@ public: void SetDwarfData(SymbolFileDWARF *dwarf2Data); size_t GetNumCompileUnits(); - bool ContainsCompileUnit(const DWARFCompileUnit *cu) const; - DWARFCompileUnit *GetCompileUnitAtIndex(uint32_t idx); - DWARFCompileUnit *GetCompileUnit(dw_offset_t cu_offset, - uint32_t *idx_ptr = NULL); - DWARFCompileUnit *GetCompileUnitContainingDIEOffset(dw_offset_t die_offset); - DWARFCompileUnit *GetCompileUnit(const DIERef &die_ref); + bool ContainsCompileUnit(const DWARFUnit *cu) const; + DWARFUnit *GetCompileUnitAtIndex(uint32_t idx); + DWARFUnit *GetCompileUnit(dw_offset_t cu_offset, uint32_t *idx_ptr = NULL); + DWARFUnit *GetCompileUnitContainingDIEOffset(dw_offset_t die_offset); + DWARFUnit *GetCompileUnit(const DIERef &die_ref); DWARFDIE GetDIEForDIEOffset(dw_offset_t die_offset); DWARFDIE GetDIE(const DIERef &die_ref); - void Dump(lldb_private::Stream *s, const uint32_t die_offset, - const uint32_t recurse_depth); - static void Parse(SymbolFileDWARF *parser, Callback callback, void *userData); - static void Verify(lldb_private::Stream *s, SymbolFileDWARF *dwarf2Data); - static void Dump(lldb_private::Stream *s, SymbolFileDWARF *dwarf2Data, - const uint32_t die_offset, const uint32_t recurse_depth); - enum { eDumpFlag_Verbose = (1 << 0), // Verbose dumping eDumpFlag_ShowForm = (1 << 1), // Show the DW_form type @@ -62,9 +55,9 @@ public: protected: static bool OffsetLessThanCompileUnitOffset(dw_offset_t offset, - const DWARFCompileUnitSP &cu_sp); + const DWARFUnitSP &cu_sp); - typedef std::vector<DWARFCompileUnitSP> CompileUnitColl; + typedef std::vector<DWARFUnitSP> CompileUnitColl; //---------------------------------------------------------------------- // Member variables diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index f595bd83d846..d32aef6e162c 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -18,7 +18,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/Stream.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDIECollection.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" @@ -34,7 +34,7 @@ using namespace std; extern int g_verbose; bool DWARFDebugInfoEntry::FastExtract( - const DWARFDataExtractor &debug_info_data, const DWARFCompileUnit *cu, + const DWARFDataExtractor &debug_info_data, const DWARFUnit *cu, const DWARFFormValue::FixedFormSizes &fixed_form_sizes, lldb::offset_t *offset_ptr) { m_offset = *offset_ptr; @@ -189,14 +189,14 @@ bool DWARFDebugInfoEntry::FastExtract( //---------------------------------------------------------------------- // Extract // -// Extract a debug info entry for a given compile unit from the -// .debug_info and .debug_abbrev data within the SymbolFileDWARF class -// starting at the given offset +// Extract a debug info entry for a given compile unit from the .debug_info and +// .debug_abbrev data within the SymbolFileDWARF class starting at the given +// offset //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, lldb::offset_t *offset_ptr) { - const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); // const DWARFDataExtractor& debug_str_data = // dwarf2Data->get_debug_str_data(); const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset(); @@ -218,9 +218,10 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, m_tag = abbrevDecl->Tag(); m_has_children = abbrevDecl->HasChildren(); - bool isCompileUnitTag = m_tag == DW_TAG_compile_unit; + bool isCompileUnitTag = (m_tag == DW_TAG_compile_unit || + m_tag == DW_TAG_partial_unit); if (cu && isCompileUnitTag) - const_cast<DWARFCompileUnit *>(cu)->SetBaseAddress(0); + const_cast<DWARFUnit *>(cu)->SetBaseAddress(0); // Skip all data in the .debug_info for the attributes const uint32_t numAttributes = abbrevDecl->NumAttributes(); @@ -235,7 +236,7 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, DWARFFormValue form_value(cu, form); if (form_value.ExtractValue(debug_info_data, &offset)) { if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc) - const_cast<DWARFCompileUnit *>(cu)->SetBaseAddress( + const_cast<DWARFUnit *>(cu)->SetBaseAddress( form_value.Address()); } } else { @@ -245,8 +246,7 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, uint32_t form_size = 0; switch (form) { // Blocks if inlined data that have a length field and the data - // bytes - // inlined in the .debug_info + // bytes inlined in the .debug_info case DW_FORM_exprloc: case DW_FORM_block: form_size = debug_info_data.GetULEB128(&offset); @@ -356,11 +356,11 @@ bool DWARFDebugInfoEntry::Extract(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // DumpAncestry // -// Dumps all of a debug information entries parents up until oldest and -// all of it's attributes to the specified stream. +// Dumps all of a debug information entries parents up until oldest and all of +// it's attributes to the specified stream. //---------------------------------------------------------------------- void DWARFDebugInfoEntry::DumpAncestry(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const DWARFDebugInfoEntry *oldest, Stream &s, uint32_t recurse_depth) const { @@ -374,11 +374,10 @@ void DWARFDebugInfoEntry::DumpAncestry(SymbolFileDWARF *dwarf2Data, // GetDIENamesAndRanges // // 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. +// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges attributes. //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::GetDIENamesAndRanges( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, const char *&name, + SymbolFileDWARF *dwarf2Data, const 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 { @@ -404,8 +403,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( lldb::ModuleSP module = dwarf2Data->GetObjectFile()->GetModule(); if (abbrevDecl) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); if (!debug_info_data.ValidOffset(offset)) return false; @@ -451,9 +449,9 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( const DWARFDebugRanges *debug_ranges = dwarf2Data->DebugRanges(); if (debug_ranges) { debug_ranges->FindRanges(cu->GetRangesBase(), form_value.Unsigned(), ranges); - // All DW_AT_ranges are relative to the base address of the - // compile unit. We add the compile unit base address to make - // sure all the addresses are properly fixed up. + // All DW_AT_ranges are relative to the base address of the compile + // unit. We add the compile unit base address to make sure all the + // addresses are properly fixed up. ranges.Slide(cu->GetBaseAddress()); } else { cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError( @@ -582,13 +580,13 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( //---------------------------------------------------------------------- // Dump // -// Dumps a debug information entry and all of it's attributes to the -// specified stream. +// Dumps a debug information entry and all of it's attributes to the specified +// stream. //---------------------------------------------------------------------- void DWARFDebugInfoEntry::Dump(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, Stream &s, + const DWARFUnit *cu, Stream &s, uint32_t recurse_depth) const { - const DWARFDataExtractor &debug_info_data = dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); lldb::offset_t offset = m_offset; if (debug_info_data.ValidOffset(offset)) { @@ -639,8 +637,8 @@ void DWARFDebugInfoEntry::Dump(SymbolFileDWARF *dwarf2Data, } void DWARFDebugInfoEntry::DumpLocation(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, Stream &s) const { - const DWARFDIE cu_die = cu->GetCompileUnitDIEOnly(); + DWARFUnit *cu, Stream &s) const { + const DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); const char *cu_name = NULL; if (cu_die) cu_name = cu_die.GetName(); @@ -658,12 +656,12 @@ void DWARFDebugInfoEntry::DumpLocation(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // DumpAttribute // -// Dumps a debug information entry attribute along with it's form. Any -// special display of attributes is done (disassemble location lists, -// show enumeration values for attributes, etc). +// Dumps a debug information entry attribute along with it's form. Any special +// display of attributes is done (disassemble location lists, show enumeration +// values for attributes, etc). //---------------------------------------------------------------------- void DWARFDebugInfoEntry::DumpAttribute( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr, Stream &s, dw_attr_t attr, dw_form_t form) { bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm); @@ -714,11 +712,10 @@ void DWARFDebugInfoEntry::DumpAttribute( (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned()); DWARFExpression::PrintDWARFExpression( - s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false); + s, locationData, DWARFUnit::GetAddressByteSize(cu), 4, false); } else { - // 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 + // 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(); if (dwarf2Data) { DWARFExpression::PrintDWARFLocationList( @@ -759,18 +756,18 @@ void DWARFDebugInfoEntry::DumpAttribute( //---------------------------------------------------------------------- // Get all attribute values for a given DIE, including following any -// specification or abstract origin attributes and including those in -// the results. Any duplicate attributes will have the first instance -// take precedence (this can happen for declaration attributes). +// specification or abstract origin attributes and including those in the +// results. Any duplicate attributes will have the first instance take +// precedence (this can happen for declaration attributes). //---------------------------------------------------------------------- size_t DWARFDebugInfoEntry::GetAttributes( - const DWARFCompileUnit *cu, DWARFFormValue::FixedFormSizes fixed_form_sizes, + const DWARFUnit *cu, DWARFFormValue::FixedFormSizes fixed_form_sizes, DWARFAttributes &attributes, uint32_t curr_depth) const { SymbolFileDWARF *dwarf2Data = nullptr; const DWARFAbbreviationDeclaration *abbrevDecl = nullptr; lldb::offset_t offset = 0; if (cu) { - if (m_tag != DW_TAG_compile_unit) { + if (m_tag != DW_TAG_compile_unit && m_tag != DW_TAG_partial_unit) { SymbolFileDWARFDwo *dwo_symbol_file = cu->GetDwoSymbolFile(); if (dwo_symbol_file) return GetAttributes(dwo_symbol_file->GetCompileUnit(), @@ -782,8 +779,7 @@ size_t DWARFDebugInfoEntry::GetAttributes( } if (abbrevDecl) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); if (fixed_form_sizes.Empty()) fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize( @@ -803,9 +799,9 @@ size_t DWARFDebugInfoEntry::GetAttributes( case DW_AT_sibling: case DW_AT_declaration: if (curr_depth > 0) { - // This attribute doesn't make sense when combined with - // the DIE that references this DIE. We know a DIE is - // referencing this DIE because curr_depth is not zero + // This attribute doesn't make sense when combined with the DIE that + // references this DIE. We know a DIE is referencing this DIE because + // curr_depth is not zero break; } LLVM_FALLTHROUGH; @@ -819,7 +815,7 @@ size_t DWARFDebugInfoEntry::GetAttributes( if (form_value.ExtractValue(debug_info_data, &offset)) { dw_offset_t die_offset = form_value.Reference(); DWARFDIE spec_die = - const_cast<DWARFCompileUnit *>(cu)->GetDIE(die_offset); + const_cast<DWARFUnit *>(cu)->GetDIE(die_offset); if (spec_die) spec_die.GetAttributes(attributes, curr_depth + 1); } @@ -841,17 +837,18 @@ size_t DWARFDebugInfoEntry::GetAttributes( // GetAttributeValue // // Get the value of an attribute and return the .debug_info offset of the -// attribute if it was properly extracted into form_value, or zero -// if we fail since an offset of zero is invalid for an attribute (it -// would be a compile unit header). +// attribute if it was properly extracted into form_value, or zero if we fail +// since an offset of zero is invalid for an attribute (it would be a compile +// unit header). //---------------------------------------------------------------------- dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, DWARFFormValue &form_value, dw_offset_t *end_attr_offset_ptr, bool check_specification_or_abstract_origin) const { SymbolFileDWARFDwo *dwo_symbol_file = cu->GetDwoSymbolFile(); - if (dwo_symbol_file && m_tag != DW_TAG_compile_unit) + if (dwo_symbol_file && m_tag != DW_TAG_compile_unit && + m_tag != DW_TAG_partial_unit) return GetAttributeValue(dwo_symbol_file, dwo_symbol_file->GetCompileUnit(), attr, form_value, end_attr_offset_ptr, check_specification_or_abstract_origin); @@ -864,8 +861,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( uint32_t attr_idx = abbrevDecl->FindAttributeIndex(attr); if (attr_idx != DW_INVALID_INDEX) { - const DWARFDataExtractor &debug_info_data = - dwarf2Data->get_debug_info_data(); + const DWARFDataExtractor &debug_info_data = cu->GetData(); uint32_t idx = 0; while (idx < attr_idx) @@ -886,7 +882,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( if (check_specification_or_abstract_origin) { if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value)) { DWARFDIE die = - const_cast<DWARFCompileUnit *>(cu)->GetDIE(form_value.Reference()); + const_cast<DWARFUnit *>(cu)->GetDIE(form_value.Reference()); if (die) { dw_offset_t die_offset = die.GetDIE()->GetAttributeValue( die.GetDWARF(), die.GetCU(), attr, form_value, end_attr_offset_ptr, @@ -898,7 +894,7 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( if (GetAttributeValue(dwarf2Data, cu, DW_AT_abstract_origin, form_value)) { DWARFDIE die = - const_cast<DWARFCompileUnit *>(cu)->GetDIE(form_value.Reference()); + const_cast<DWARFUnit *>(cu)->GetDIE(form_value.Reference()); if (die) { dw_offset_t die_offset = die.GetDIE()->GetAttributeValue( die.GetDWARF(), die.GetCU(), attr, form_value, end_attr_offset_ptr, @@ -912,11 +908,11 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( if (!dwo_symbol_file) return 0; - DWARFCompileUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); + DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); if (!dwo_cu) return 0; - DWARFDIE dwo_cu_die = dwo_cu->GetCompileUnitDIEOnly(); + DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); if (!dwo_cu_die.IsValid()) return 0; @@ -928,13 +924,13 @@ dw_offset_t DWARFDebugInfoEntry::GetAttributeValue( //---------------------------------------------------------------------- // GetAttributeValueAsString // -// Get the value of an attribute as a string return it. The resulting -// pointer to the string data exists within the supplied SymbolFileDWARF -// and will only be available as long as the SymbolFileDWARF is still around -// and it's content doesn't change. +// Get the value of an attribute as a string return it. The resulting pointer +// to the string data exists within the supplied SymbolFileDWARF and will only +// be available as long as the SymbolFileDWARF is still around and it's content +// doesn't change. //---------------------------------------------------------------------- const char *DWARFDebugInfoEntry::GetAttributeValueAsString( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -950,7 +946,7 @@ const char *DWARFDebugInfoEntry::GetAttributeValueAsString( // Get the value of an attribute as unsigned and return it. //---------------------------------------------------------------------- uint64_t DWARFDebugInfoEntry::GetAttributeValueAsUnsigned( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -966,7 +962,7 @@ uint64_t DWARFDebugInfoEntry::GetAttributeValueAsUnsigned( // Get the value of an attribute a signed value and return it. //---------------------------------------------------------------------- int64_t DWARFDebugInfoEntry::GetAttributeValueAsSigned( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, int64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -979,11 +975,11 @@ int64_t DWARFDebugInfoEntry::GetAttributeValueAsSigned( //---------------------------------------------------------------------- // GetAttributeValueAsReference // -// Get the value of an attribute as reference and fix up and compile -// unit relative offsets as needed. +// Get the value of an attribute as reference and fix up and compile unit +// relative offsets as needed. //---------------------------------------------------------------------- uint64_t DWARFDebugInfoEntry::GetAttributeValueAsReference( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -994,7 +990,7 @@ uint64_t DWARFDebugInfoEntry::GetAttributeValueAsReference( } uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; @@ -1007,13 +1003,13 @@ uint64_t DWARFDebugInfoEntry::GetAttributeValueAsAddress( //---------------------------------------------------------------------- // GetAttributeHighPC // -// Get the hi_pc, adding hi_pc to lo_pc when specified -// as an <offset-from-low-pc>. +// Get the hi_pc, adding hi_pc to lo_pc when specified as an <offset-from-low- +// pc>. // // Returns the hi_pc or fail_value. //---------------------------------------------------------------------- dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, dw_addr_t lo_pc, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value, bool check_specification_or_abstract_origin) const { DWARFFormValue form_value; if (GetAttributeValue(dwarf2Data, cu, DW_AT_high_pc, form_value, nullptr, @@ -1031,13 +1027,13 @@ dw_addr_t DWARFDebugInfoEntry::GetAttributeHighPC( //---------------------------------------------------------------------- // GetAttributeAddressRange // -// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified -// as an <offset-from-low-pc>. +// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified as an <offset- +// from-low-pc>. // // Returns true or sets lo_pc and hi_pc to fail_value. //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::GetAttributeAddressRange( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, dw_addr_t &lo_pc, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc, uint64_t fail_value, bool check_specification_or_abstract_origin) const { lo_pc = GetAttributeValueAsAddress(dwarf2Data, cu, DW_AT_low_pc, fail_value, @@ -1054,7 +1050,7 @@ bool DWARFDebugInfoEntry::GetAttributeAddressRange( } size_t DWARFDebugInfoEntry::GetAttributeAddressRanges( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin) const { ranges.Clear(); @@ -1083,23 +1079,23 @@ size_t DWARFDebugInfoEntry::GetAttributeAddressRanges( //---------------------------------------------------------------------- // GetName // -// Get value of the DW_AT_name attribute and return it if one exists, -// else return NULL. +// Get value of the DW_AT_name attribute and return it if one exists, else +// return NULL. //---------------------------------------------------------------------- const char *DWARFDebugInfoEntry::GetName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu) const { + const DWARFUnit *cu) const { return GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, nullptr, true); } //---------------------------------------------------------------------- // GetMangledName // -// Get value of the DW_AT_MIPS_linkage_name attribute and return it if -// one exists, else return the value of the DW_AT_name attribute +// Get value of the DW_AT_MIPS_linkage_name attribute and return it if one +// exists, else return the value of the DW_AT_name attribute //---------------------------------------------------------------------- const char * DWARFDebugInfoEntry::GetMangledName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, bool substitute_name_allowed) const { const char *name = nullptr; @@ -1123,11 +1119,11 @@ DWARFDebugInfoEntry::GetMangledName(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // GetPubname // -// Get value the name for a DIE as it should appear for a -// .debug_pubnames or .debug_pubtypes section. +// Get value the name for a DIE as it should appear for a .debug_pubnames or +// .debug_pubtypes section. //---------------------------------------------------------------------- const char *DWARFDebugInfoEntry::GetPubname(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu) const { + const DWARFUnit *cu) const { const char *name = nullptr; if (!dwarf2Data) return name; @@ -1149,14 +1145,13 @@ const char *DWARFDebugInfoEntry::GetPubname(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // GetName // -// Get value of the DW_AT_name attribute for a debug information entry -// that exists at offset "die_offset" and place that value into the -// supplied stream object. If the DIE is a NULL object "NULL" is placed -// into the stream, and if no DW_AT_name attribute exists for the DIE -// then nothing is printed. +// Get value of the DW_AT_name attribute for a debug information entry that +// exists at offset "die_offset" and place that value into the supplied stream +// object. If the DIE is a NULL object "NULL" is placed into the stream, and if +// no DW_AT_name attribute exists for the DIE then nothing is printed. //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::GetName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const dw_offset_t die_offset, Stream &s) { if (dwarf2Data == NULL) { s.PutCString("NULL"); @@ -1184,13 +1179,12 @@ bool DWARFDebugInfoEntry::GetName(SymbolFileDWARF *dwarf2Data, //---------------------------------------------------------------------- // AppendTypeName // -// Follows the type name definition down through all needed tags to -// end up with a fully qualified type name and dump the results to -// the supplied stream. This is used to show the name of types given -// a type identifier. +// Follows the type name definition down through all needed tags to end up with +// a fully qualified type name and dump the results to the supplied stream. +// This is used to show the name of types given a type identifier. //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::AppendTypeName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const dw_offset_t die_offset, Stream &s) { if (dwarf2Data == NULL) { @@ -1318,7 +1312,7 @@ bool DWARFDebugInfoEntry::AppendTypeName(SymbolFileDWARF *dwarf2Data, // BuildAddressRangeTable //---------------------------------------------------------------------- void DWARFDebugInfoEntry::BuildAddressRangeTable( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { if (m_tag) { if (m_tag == DW_TAG_subprogram) { @@ -1343,13 +1337,13 @@ void DWARFDebugInfoEntry::BuildAddressRangeTable( //---------------------------------------------------------------------- // BuildFunctionAddressRangeTable // -// This function is very similar to the BuildAddressRangeTable function -// except that the actual DIE offset for the function is placed in the -// table instead of the compile unit offset (which is the way the -// standard .debug_aranges section does it). +// This function is very similar to the BuildAddressRangeTable function except +// that the actual DIE offset for the function is placed in the table instead +// of the compile unit offset (which is the way the standard .debug_aranges +// section does it). //---------------------------------------------------------------------- void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { if (m_tag) { if (m_tag == DW_TAG_subprogram) { @@ -1372,21 +1366,22 @@ void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( } void DWARFDebugInfoEntry::GetDeclContextDIEs( - DWARFCompileUnit *cu, DWARFDIECollection &decl_context_dies) const { + DWARFUnit *cu, DWARFDIECollection &decl_context_dies) const { DWARFDIE die(cu, const_cast<DWARFDebugInfoEntry *>(this)); die.GetDeclContextDIEs(decl_context_dies); } void DWARFDebugInfoEntry::GetDWARFDeclContext( - SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, DWARFDeclContext &dwarf_decl_ctx) const { const dw_tag_t tag = Tag(); - if (tag != DW_TAG_compile_unit) { + if (tag != DW_TAG_compile_unit && tag != DW_TAG_partial_unit) { dwarf_decl_ctx.AppendDeclContext(tag, GetName(dwarf2Data, cu)); DWARFDIE parent_decl_ctx_die = GetParentDeclContextDIE(dwarf2Data, cu); if (parent_decl_ctx_die && parent_decl_ctx_die.GetDIE() != this) { - if (parent_decl_ctx_die.Tag() != DW_TAG_compile_unit) + if (parent_decl_ctx_die.Tag() != DW_TAG_compile_unit && + parent_decl_ctx_die.Tag() != DW_TAG_partial_unit) parent_decl_ctx_die.GetDIE()->GetDWARFDeclContext( parent_decl_ctx_die.GetDWARF(), parent_decl_ctx_die.GetCU(), dwarf_decl_ctx); @@ -1395,7 +1390,7 @@ void DWARFDebugInfoEntry::GetDWARFDeclContext( } bool DWARFDebugInfoEntry::MatchesDWARFDeclContext( - SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, const DWARFDeclContext &dwarf_decl_ctx) const { DWARFDeclContext this_dwarf_decl_ctx; @@ -1405,7 +1400,7 @@ bool DWARFDebugInfoEntry::MatchesDWARFDeclContext( DWARFDIE DWARFDebugInfoEntry::GetParentDeclContextDIE(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu) const { + DWARFUnit *cu) const { DWARFAttributes attributes; GetAttributes(cu, DWARFFormValue::FixedFormSizes(), attributes); return GetParentDeclContextDIE(dwarf2Data, cu, attributes); @@ -1413,17 +1408,18 @@ DWARFDebugInfoEntry::GetParentDeclContextDIE(SymbolFileDWARF *dwarf2Data, DWARFDIE DWARFDebugInfoEntry::GetParentDeclContextDIE( - SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, const DWARFAttributes &attributes) const { DWARFDIE die(cu, const_cast<DWARFDebugInfoEntry *>(this)); while (die) { - // If this is the original DIE that we are searching for a declaration - // for, then don't look in the cache as we don't want our own decl - // context to be our decl context... + // If this is the original DIE that we are searching for a declaration for, + // then don't look in the cache as we don't want our own decl context to be + // our decl context... if (die.GetDIE() != this) { switch (die.Tag()) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: case DW_TAG_namespace: case DW_TAG_structure_type: case DW_TAG_union_type: @@ -1465,7 +1461,7 @@ DWARFDebugInfoEntry::GetParentDeclContextDIE( } const char *DWARFDebugInfoEntry::GetQualifiedName(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, std::string &storage) const { DWARFAttributes attributes; GetAttributes(cu, DWARFFormValue::FixedFormSizes(), attributes); @@ -1473,7 +1469,7 @@ const char *DWARFDebugInfoEntry::GetQualifiedName(SymbolFileDWARF *dwarf2Data, } const char *DWARFDebugInfoEntry::GetQualifiedName( - SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, const DWARFAttributes &attributes, std::string &storage) const { const char *name = GetName(dwarf2Data, cu); @@ -1529,7 +1525,7 @@ const char *DWARFDebugInfoEntry::GetQualifiedName( //---------------------------------------------------------------------- bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die) { bool found_address = false; @@ -1661,6 +1657,7 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, case DW_TAG_unspecified_type: break; case DW_TAG_partial_unit: + match_addr_range = true; break; case DW_TAG_imported_unit: break; @@ -1684,6 +1681,7 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, // puts("***MATCH***"); switch (m_tag) { case DW_TAG_compile_unit: // File + case DW_TAG_partial_unit: // File check_children = ((function_die != NULL) || (block_die != NULL)); break; @@ -1706,10 +1704,12 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, break; } } - } else { // compile units may not have a valid high/low pc when there + } else { + // Compile units may not have a valid high/low pc when there // are address gaps in subroutines so we must always search - // if there is no valid high and low PC - check_children = (m_tag == DW_TAG_compile_unit) && + // if there is no valid high and low PC. + check_children = (m_tag == DW_TAG_compile_unit || + m_tag == DW_TAG_partial_unit) && ((function_die != NULL) || (block_die != NULL)); } } else { @@ -1719,15 +1719,16 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, DWARFRangeList ranges; DWARFDebugRanges *debug_ranges = dwarf2Data->DebugRanges(); debug_ranges->FindRanges(cu->GetRangesBase(), debug_ranges_offset, ranges); - // All DW_AT_ranges are relative to the base address of the - // compile unit. We add the compile unit base address to make - // sure all the addresses are properly fixed up. + // All DW_AT_ranges are relative to the base address of the compile + // unit. We add the compile unit base address to make sure all the + // addresses are properly fixed up. ranges.Slide(cu->GetBaseAddress()); if (ranges.FindEntryThatContains(address)) { found_address = true; // puts("***MATCH***"); switch (m_tag) { case DW_TAG_compile_unit: // File + case DW_TAG_partial_unit: // File check_children = ((function_die != NULL) || (block_die != NULL)); break; @@ -1772,7 +1773,7 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address, const DWARFAbbreviationDeclaration * DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, lldb::offset_t &offset) const { if (dwarf2Data) { offset = GetOffset(); @@ -1782,11 +1783,10 @@ DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr( const DWARFAbbreviationDeclaration *abbrev_decl = abbrev_set->GetAbbreviationDeclaration(m_abbr_idx); if (abbrev_decl) { - // Make sure the abbreviation code still matches. If it doesn't and - // the DWARF data was mmap'ed, the backing file might have been modified + // Make sure the abbreviation code still matches. If it doesn't and the + // DWARF data was mmap'ed, the backing file might have been modified // which is bad news. - const uint64_t abbrev_code = - dwarf2Data->get_debug_info_data().GetULEB128(&offset); + const uint64_t abbrev_code = cu->GetData().GetULEB128(&offset); if (abbrev_decl->Code() == abbrev_code) return abbrev_decl; @@ -1825,3 +1825,15 @@ void DWARFDebugInfoEntry::DumpDIECollection( die_ref.HasChildren() ? " *" : ""); } } + +bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const { + return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx && + m_sibling_idx == rhs.m_sibling_idx && + m_empty_children == rhs.m_empty_children && + m_abbr_idx == rhs.m_abbr_idx && m_has_children == rhs.m_has_children && + m_tag == rhs.m_tag; +} + +bool DWARFDebugInfoEntry::operator!=(const DWARFDebugInfoEntry &rhs) const { + return !(*this == rhs); +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 89450d327adf..97cb3046eb3e 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -60,128 +60,132 @@ public: m_empty_children(false), m_abbr_idx(0), m_has_children(false), m_tag(0) {} + explicit operator bool() const { return m_offset != DW_INVALID_OFFSET; } + bool operator==(const DWARFDebugInfoEntry &rhs) const; + bool operator!=(const DWARFDebugInfoEntry &rhs) const; + void BuildAddressRangeTable(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; void BuildFunctionAddressRangeTable(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; bool FastExtract(const lldb_private::DWARFDataExtractor &debug_info_data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const DWARFFormValue::FixedFormSizes &fixed_form_sizes, lldb::offset_t *offset_ptr); - bool Extract(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + bool Extract(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, lldb::offset_t *offset_ptr); bool LookupAddress(const dw_addr_t address, SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, DWARFDebugInfoEntry **function_die, DWARFDebugInfoEntry **block_die); - size_t GetAttributes(const DWARFCompileUnit *cu, + size_t GetAttributes(const DWARFUnit *cu, DWARFFormValue::FixedFormSizes fixed_form_sizes, DWARFAttributes &attrs, uint32_t curr_depth = 0) const; // "curr_depth" for internal use only, don't set this yourself!!! dw_offset_t - GetAttributeValue(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + GetAttributeValue(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, DWARFFormValue &formValue, dw_offset_t *end_attr_offset_ptr = nullptr, bool check_specification_or_abstract_origin = false) const; const char *GetAttributeValueAsString( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, const char *fail_value, bool check_specification_or_abstract_origin = false) const; uint64_t GetAttributeValueAsUnsigned( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; uint64_t GetAttributeValueAsReference( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; int64_t GetAttributeValueAsSigned( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, int64_t fail_value, bool check_specification_or_abstract_origin = false) const; uint64_t GetAttributeValueAsAddress( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_attr_t attr, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; dw_addr_t - GetAttributeHighPC(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + GetAttributeHighPC(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, dw_addr_t lo_pc, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; bool GetAttributeAddressRange( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, dw_addr_t &lo_pc, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, dw_addr_t &lo_pc, dw_addr_t &hi_pc, uint64_t fail_value, bool check_specification_or_abstract_origin = false) const; size_t GetAttributeAddressRanges( - SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, DWARFRangeList &ranges, bool check_hi_lo_pc, bool check_specification_or_abstract_origin = false) const; const char *GetName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu) const; + const DWARFUnit *cu) const; const char *GetMangledName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, bool substitute_name_allowed = true) const; const char *GetPubname(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu) const; + const DWARFUnit *cu) const; - static bool GetName(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + static bool GetName(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const dw_offset_t die_offset, lldb_private::Stream &s); static bool AppendTypeName(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, const dw_offset_t die_offset, lldb_private::Stream &s); const char *GetQualifiedName(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, std::string &storage) const; const char *GetQualifiedName(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, const DWARFAttributes &attributes, std::string &storage) const; static bool OffsetLessThan(const DWARFDebugInfoEntry &a, const DWARFDebugInfoEntry &b); - void Dump(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + void Dump(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, lldb_private::Stream &s, uint32_t recurse_depth) const; - void DumpAncestry(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + void DumpAncestry(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const DWARFDebugInfoEntry *oldest, lldb_private::Stream &s, uint32_t recurse_depth) const; static void - DumpAttribute(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + DumpAttribute(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const lldb_private::DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr, lldb_private::Stream &s, dw_attr_t attr, dw_form_t form); // This one dumps the comp unit name, objfile name and die offset for this die // so the stream S. - void DumpLocation(SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + void DumpLocation(SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, lldb_private::Stream &s) const; bool - GetDIENamesAndRanges(SymbolFileDWARF *dwarf2Data, const DWARFCompileUnit *cu, + GetDIENamesAndRanges(SymbolFileDWARF *dwarf2Data, const DWARFUnit *cu, const char *&name, const char *&mangled, DWARFRangeList &rangeList, int &decl_file, int &decl_line, int &decl_column, int &call_file, @@ -190,7 +194,7 @@ public: const DWARFAbbreviationDeclaration * GetAbbreviationDeclarationPtr(SymbolFileDWARF *dwarf2Data, - const DWARFCompileUnit *cu, + const DWARFUnit *cu, lldb::offset_t &offset) const; dw_tag_t Tag() const { return m_tag; } @@ -229,20 +233,20 @@ public: return (HasChildren() && !m_empty_children) ? this + 1 : NULL; } - void GetDeclContextDIEs(DWARFCompileUnit *cu, + void GetDeclContextDIEs(DWARFUnit *cu, DWARFDIECollection &decl_context_dies) const; - void GetDWARFDeclContext(SymbolFileDWARF *dwarf2Data, DWARFCompileUnit *cu, + void GetDWARFDeclContext(SymbolFileDWARF *dwarf2Data, DWARFUnit *cu, DWARFDeclContext &dwarf_decl_ctx) const; bool MatchesDWARFDeclContext(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, const DWARFDeclContext &dwarf_decl_ctx) const; DWARFDIE GetParentDeclContextDIE(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu) const; + DWARFUnit *cu) const; DWARFDIE GetParentDeclContextDIE(SymbolFileDWARF *dwarf2Data, - DWARFCompileUnit *cu, + DWARFUnit *cu, const DWARFAttributes &attributes) const; void SetParent(DWARFDebugInfoEntry *parent) { diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp index 694d34fc211c..317ea4c22c66 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp @@ -242,8 +242,8 @@ dw_offset_t DWARFDebugLine::DumpStatementOpcodes( log->Printf("0x%8.8x: DW_LNE_??? (%2.2x) - Skipping unknown upcode", op_offset, opcode); // Length doesn't include the zero opcode byte or the length itself, - // but - // it does include the sub_opcode, so we have to adjust for that below + // but it does include the sub_opcode, so we have to adjust for that + // below offset += arg_size; break; } @@ -324,9 +324,9 @@ dw_offset_t DWARFDebugLine::DumpStatementOpcodes( // Special Opcodes default: if (opcode < prologue.opcode_base) { - // We have an opcode that this parser doesn't know about, skip - // the number of ULEB128 numbers that is says to skip in the - // prologue's standard_opcode_lengths array + // We have an opcode that this parser doesn't know about, skip the + // number of ULEB128 numbers that is says to skip in the prologue's + // standard_opcode_lengths array uint8_t n = prologue.standard_opcode_lengths[opcode - 1]; log->Printf("0x%8.8x: Special : Unknown skipping %u ULEB128 values.", op_offset, n); @@ -357,9 +357,9 @@ dw_offset_t DWARFDebugLine::DumpStatementOpcodes( //---------------------------------------------------------------------- // Parse // -// Parse the entire line table contents calling callback each time a -// new prologue is parsed and every time a new row is to be added to -// the line table. +// Parse the entire line table contents calling callback each time a new +// prologue is parsed and every time a new row is to be added to the line +// table. //---------------------------------------------------------------------- void DWARFDebugLine::Parse(const DWARFDataExtractor &debug_line_data, DWARFDebugLine::State::Callback callback, @@ -444,7 +444,7 @@ bool DWARFDebugLine::ParsePrologue(const DWARFDataExtractor &debug_line_data, bool DWARFDebugLine::ParseSupportFiles( const lldb::ModuleSP &module_sp, const DWARFDataExtractor &debug_line_data, - const char *cu_comp_dir, dw_offset_t stmt_list, + const lldb_private::FileSpec &cu_comp_dir, dw_offset_t stmt_list, FileSpecList &support_files) { lldb::offset_t offset = stmt_list; @@ -463,7 +463,7 @@ bool DWARFDebugLine::ParseSupportFiles( for (uint32_t file_idx = 1; prologue.GetFile(file_idx, cu_comp_dir, file_spec); ++file_idx) { if (module_sp->RemapSourceFile(file_spec.GetPath(), remapped_file)) - file_spec.SetFile(remapped_file, false); + file_spec.SetFile(remapped_file, false, FileSpec::Style::native); support_files.Append(file_spec); } return true; @@ -472,9 +472,9 @@ bool DWARFDebugLine::ParseSupportFiles( //---------------------------------------------------------------------- // ParseStatementTable // -// Parse a single line table (prologue and all rows) and call the -// callback function once for the prologue (row in state will be zero) -// and each time a row is to be added to the line table. +// Parse a single line table (prologue and all rows) and call the callback +// function once for the prologue (row in state will be zero) and each time a +// row is to be added to the line table. //---------------------------------------------------------------------- bool DWARFDebugLine::ParseStatementTable( const DWARFDataExtractor &debug_line_data, lldb::offset_t *offset_ptr, @@ -511,8 +511,8 @@ bool DWARFDebugLine::ParseStatementTable( uint8_t opcode = debug_line_data.GetU8(offset_ptr); if (opcode == 0) { - // Extended Opcodes always start with a zero opcode followed by - // a uleb128 length so you can skip ones you don't know about + // Extended Opcodes always start with a zero opcode followed by a uleb128 + // length so you can skip ones you don't know about lldb::offset_t ext_offset = *offset_ptr; dw_uleb128_t len = debug_line_data.GetULEB128(offset_ptr); dw_offset_t arg_size = len - (*offset_ptr - ext_offset); @@ -522,12 +522,12 @@ bool DWARFDebugLine::ParseStatementTable( switch (sub_opcode) { case DW_LNE_end_sequence: // Set the end_sequence register of the state machine to true and - // append a row to the matrix using the current values of the - // state-machine registers. Then reset the registers to the initial - // values specified above. Every statement program sequence must end - // with a DW_LNE_end_sequence instruction which creates a row whose - // address is that of the byte after the last target machine instruction - // of the sequence. + // append a row to the matrix using the current values of the state- + // machine registers. Then reset the registers to the initial values + // specified above. Every statement program sequence must end with a + // DW_LNE_end_sequence instruction which creates a row whose address is + // that of the byte after the last target machine instruction of the + // sequence. state.end_sequence = true; state.AppendRowToMatrix(*offset_ptr); state.Reset(); @@ -537,8 +537,8 @@ bool DWARFDebugLine::ParseStatementTable( // Takes a single relocatable address as an operand. The size of the // operand is the size appropriate to hold an address on the target // machine. Set the address register to the value given by the - // relocatable address. All of the other statement program opcodes - // that affect the address register add a delta to it. This instruction + // relocatable address. All of the other statement program opcodes that + // affect the address register add a delta to it. This instruction // stores a relocatable value into it instead. if (arg_size == 4) state.address = debug_line_data.GetU32(offset_ptr); @@ -549,24 +549,24 @@ bool DWARFDebugLine::ParseStatementTable( case DW_LNE_define_file: // Takes 4 arguments. The first is a null terminated string containing // a source file name. The second is an unsigned LEB128 number - // representing - // the directory index of the directory in which the file was found. The - // third is an unsigned LEB128 number representing the time of last - // modification of the file. The fourth is an unsigned LEB128 number - // representing the length in bytes of the file. The time and length - // fields may contain LEB128(0) if the information is not available. + // representing the directory index of the directory in which the file + // was found. The third is an unsigned LEB128 number representing the + // time of last modification of the file. The fourth is an unsigned + // LEB128 number representing the length in bytes of the file. The time + // and length fields may contain LEB128(0) if the information is not + // available. // // The directory index represents an entry in the include_directories - // section of the statement program prologue. The index is LEB128(0) - // if the file was found in the current directory of the compilation, + // section of the statement program prologue. The index is LEB128(0) if + // the file was found in the current directory of the compilation, // LEB128(1) if it was found in the first directory in the // include_directories section, and so on. The directory index is // ignored for file names that represent full path names. // // The files are numbered, starting at 1, in the order in which they - // appear; the names in the prologue come before names defined by - // the DW_LNE_define_file instruction. These numbers are used in the - // file register of the state machine. + // appear; the names in the prologue come before names defined by the + // DW_LNE_define_file instruction. These numbers are used in the file + // register of the state machine. { FileNameEntry fileEntry; fileEntry.name = debug_line_data.GetCStr(offset_ptr); @@ -578,8 +578,9 @@ bool DWARFDebugLine::ParseStatementTable( break; default: - // Length doesn't include the zero opcode byte or the length itself, but - // it does include the sub_opcode, so we have to adjust for that below + // Length doesn't include the zero opcode byte or the length itself, + // but it does include the sub_opcode, so we have to adjust for that + // below (*offset_ptr) += arg_size; break; } @@ -587,23 +588,23 @@ bool DWARFDebugLine::ParseStatementTable( switch (opcode) { // Standard Opcodes case DW_LNS_copy: - // Takes no arguments. Append a row to the matrix using the - // current values of the state-machine registers. Then set - // the basic_block register to false. + // Takes no arguments. Append a row to the matrix using the current + // values of the state-machine registers. Then set the basic_block + // register to false. state.AppendRowToMatrix(*offset_ptr); break; case DW_LNS_advance_pc: // Takes a single unsigned LEB128 operand, multiplies it by the - // min_inst_length field of the prologue, and adds the - // result to the address register of the state machine. + // min_inst_length field of the prologue, and adds the result to the + // address register of the state machine. state.address += debug_line_data.GetULEB128(offset_ptr) * prologue->min_inst_length; break; case DW_LNS_advance_line: - // Takes a single signed LEB128 operand and adds that value to - // the line register of the state machine. + // Takes a single signed LEB128 operand and adds that value to the line + // register of the state machine. state.line += debug_line_data.GetSLEB128(offset_ptr); break; @@ -614,35 +615,35 @@ bool DWARFDebugLine::ParseStatementTable( break; case DW_LNS_set_column: - // Takes a single unsigned LEB128 operand and stores it in the - // column register of the state machine. + // Takes a single unsigned LEB128 operand and stores it in the column + // register of the state machine. state.column = debug_line_data.GetULEB128(offset_ptr); break; case DW_LNS_negate_stmt: - // Takes no arguments. Set the is_stmt register of the state - // machine to the logical negation of its current value. + // Takes no arguments. Set the is_stmt register of the state machine to + // the logical negation of its current value. state.is_stmt = !state.is_stmt; break; case DW_LNS_set_basic_block: - // Takes no arguments. Set the basic_block register of the - // state machine to true + // Takes no arguments. Set the basic_block register of the state + // machine to true state.basic_block = true; break; case DW_LNS_const_add_pc: - // Takes no arguments. Add to the address register of the state - // machine the address increment value corresponding to special - // opcode 255. The motivation for DW_LNS_const_add_pc is this: - // when the statement program needs to advance the address by a - // small amount, it can use a single special opcode, which occupies - // a single byte. When it needs to advance the address by up to - // twice the range of the last special opcode, it can use - // DW_LNS_const_add_pc followed by a special opcode, for a total - // of two bytes. Only if it needs to advance the address by more - // than twice that range will it need to use both DW_LNS_advance_pc - // and a special opcode, requiring three or more bytes. + // Takes no arguments. Add to the address register of the state machine + // the address increment value corresponding to special opcode 255. The + // motivation for DW_LNS_const_add_pc is this: when the statement + // program needs to advance the address by a small amount, it can use a + // single special opcode, which occupies a single byte. When it needs + // to advance the address by up to twice the range of the last special + // opcode, it can use DW_LNS_const_add_pc followed by a special opcode, + // for a total of two bytes. Only if it needs to advance the address by + // more than twice that range will it need to use both + // DW_LNS_advance_pc and a special opcode, requiring three or more + // bytes. { uint8_t adjust_opcode = 255 - prologue->opcode_base; dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * @@ -652,40 +653,40 @@ bool DWARFDebugLine::ParseStatementTable( break; case DW_LNS_fixed_advance_pc: - // Takes a single uhalf operand. Add to the address register of - // the state machine the value of the (unencoded) operand. This - // is the only extended opcode that takes an argument that is not - // a variable length number. The motivation for DW_LNS_fixed_advance_pc - // is this: existing assemblers cannot emit DW_LNS_advance_pc or - // special opcodes because they cannot encode LEB128 numbers or - // judge when the computation of a special opcode overflows and - // requires the use of DW_LNS_advance_pc. Such assemblers, however, - // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. + // Takes a single uhalf operand. Add to the address register of the + // state machine the value of the (unencoded) operand. This is the only + // extended opcode that takes an argument that is not a variable length + // number. The motivation for DW_LNS_fixed_advance_pc is this: existing + // assemblers cannot emit DW_LNS_advance_pc or special opcodes because + // they cannot encode LEB128 numbers or judge when the computation of a + // special opcode overflows and requires the use of DW_LNS_advance_pc. + // Such assemblers, however, can use DW_LNS_fixed_advance_pc instead, + // sacrificing compression. state.address += debug_line_data.GetU16(offset_ptr); break; case DW_LNS_set_prologue_end: - // Takes no arguments. Set the prologue_end register of the - // state machine to true + // Takes no arguments. Set the prologue_end register of the state + // machine to true state.prologue_end = true; break; case DW_LNS_set_epilogue_begin: - // Takes no arguments. Set the basic_block register of the - // state machine to true + // Takes no arguments. Set the basic_block register of the state + // machine to true state.epilogue_begin = true; break; case DW_LNS_set_isa: - // Takes a single unsigned LEB128 operand and stores it in the - // column register of the state machine. + // Takes a single unsigned LEB128 operand and stores it in the column + // register of the state machine. state.isa = debug_line_data.GetULEB128(offset_ptr); break; default: - // Handle any unknown standard opcodes here. We know the lengths - // of such opcodes because they are specified in the prologue - // as a multiple of LEB128 operands for each opcode. + // Handle any unknown standard opcodes here. We know the lengths of + // such opcodes because they are specified in the prologue as a + // multiple of LEB128 operands for each opcode. { uint8_t i; assert(static_cast<size_t>(opcode - 1) < @@ -702,32 +703,32 @@ bool DWARFDebugLine::ParseStatementTable( // A special opcode value is chosen based on the amount that needs // to be added to the line and address registers. The maximum line - // increment for a special opcode is the value of the line_base - // field in the header, plus the value of the line_range field, - // minus 1 (line base + line range - 1). If the desired line - // increment is greater than the maximum line increment, a standard - // opcode must be used instead of a special opcode. The "address - // advance" is calculated by dividing the desired address increment - // by the minimum_instruction_length field from the header. The - // special opcode is then calculated using the following formula: + // increment for a special opcode is the value of the line_base field in + // the header, plus the value of the line_range field, minus 1 (line base + // + line range - 1). If the desired line increment is greater than the + // maximum line increment, a standard opcode must be used instead of a + // special opcode. The "address advance" is calculated by dividing the + // desired address increment by the minimum_instruction_length field from + // the header. The special opcode is then calculated using the following + // formula: // // opcode = (desired line increment - line_base) + (line_range * address // advance) + opcode_base // - // If the resulting opcode is greater than 255, a standard opcode - // must be used instead. + // If the resulting opcode is greater than 255, a standard opcode must be + // used instead. // - // To decode a special opcode, subtract the opcode_base from the - // opcode itself to give the adjusted opcode. The amount to - // increment the address register is the result of the adjusted - // opcode divided by the line_range multiplied by the - // minimum_instruction_length field from the header. That is: + // To decode a special opcode, subtract the opcode_base from the opcode + // itself to give the adjusted opcode. The amount to increment the + // address register is the result of the adjusted opcode divided by the + // line_range multiplied by the minimum_instruction_length field from the + // header. That is: // // address increment = (adjusted opcode / line_range) * // minimum_instruction_length // - // The amount to increment the line register is the line_base plus - // the result of the adjusted opcode modulo the line_range. That is: + // The amount to increment the line register is the line_base plus the + // result of the adjusted opcode modulo the line_range. That is: // // line increment = line_base + (adjusted opcode % line_range) @@ -755,8 +756,8 @@ static void ParseStatementTableCallback(dw_offset_t offset, void *userData) { DWARFDebugLine::LineTable *line_table = (DWARFDebugLine::LineTable *)userData; if (state.row == DWARFDebugLine::State::StartParsingLineTable) { - // Just started parsing the line table, so lets keep a reference to - // the prologue using the supplied shared pointer + // Just started parsing the line table, so lets keep a reference to the + // prologue using the supplied shared pointer line_table->prologue = state.prologue; } else if (state.row == DWARFDebugLine::State::DoneParsingLineTable) { // Done parsing line table, nothing to do for the cleanup @@ -769,8 +770,8 @@ static void ParseStatementTableCallback(dw_offset_t offset, //---------------------------------------------------------------------- // ParseStatementTable // -// Parse a line table at offset and populate the LineTable class with -// the prologue and all rows. +// Parse a line table at offset and populate the LineTable class with the +// prologue and all rows. //---------------------------------------------------------------------- bool DWARFDebugLine::ParseStatementTable( const DWARFDataExtractor &debug_line_data, lldb::offset_t *offset_ptr, @@ -861,11 +862,11 @@ void DWARFDebugLine::Prologue::Dump(Log *log) { // buff.Append8(0); // Terminate the file names section with empty string //} -bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, const char *comp_dir, - FileSpec &file) const { +bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, + const lldb_private::FileSpec &comp_dir, FileSpec &file) const { uint32_t idx = file_idx - 1; // File indexes are 1 based... if (idx < file_names.size()) { - file.SetFile(file_names[idx].name, false); + file.SetFile(file_names[idx].name, false, FileSpec::Style::native); if (file.IsRelative()) { if (file_names[idx].dir_idx > 0) { const uint32_t dir_idx = file_names[idx].dir_idx - 1; @@ -876,7 +877,7 @@ bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, const char *comp_dir, } } - if (comp_dir && comp_dir[0]) + if (comp_dir) file.PrependPathComponent(comp_dir); } return true; @@ -936,11 +937,10 @@ uint32_t DWARFDebugLine::LineTable::LookupAddress(dw_addr_t address, if (address < cu_high_pc) return rows.size() - 1; } else { - // Rely on fact that we are using a std::vector and we can do - // pointer arithmetic to find the row index (which will be one less - // that what we found since it will find the first position after - // the current address) since std::vector iterators are just - // pointers to the container type. + // Rely on fact that we are using a std::vector and we can do pointer + // arithmetic to find the row index (which will be one less that what we + // found since it will find the first position after the current address) + // since std::vector iterators are just pointers to the container type. index = pos - begin_pos; if (pos->address > address) { if (index > 0) @@ -1005,9 +1005,9 @@ static bool AddressLessThan(const DWARFDebugLine::Row &a, return a.address < b.address; } -// Insert a row at the correct address if the addresses can be out of -// order which can only happen when we are linking a line table that -// may have had it's contents rearranged. +// Insert a row at the correct address if the addresses can be out of order +// which can only happen when we are linking a line table that may have had +// it's contents rearranged. void DWARFDebugLine::Row::Insert(Row::collection &state_coll, const Row &state) { // If we don't have anything yet, or if the address of the last state in our @@ -1020,12 +1020,12 @@ void DWARFDebugLine::Row::Insert(Row::collection &state_coll, state_coll.begin(), state_coll.end(), state, AddressLessThan)); // If the addresses are equal, we can safely replace the previous entry - // with the current one if the one it is replacing is an end_sequence entry. - // We currently always place an extra end sequence when ever we exit a valid - // address range for a function in case the functions get rearranged by - // optimizations or by order specifications. These extra end sequences will - // disappear by getting replaced with valid consecutive entries within a - // compile unit if there are no gaps. + // with the current one if the one it is replacing is an end_sequence + // entry. We currently always place an extra end sequence when ever we exit + // a valid address range for a function in case the functions get + // rearranged by optimizations or by order specifications. These extra end + // sequences will disappear by getting replaced with valid consecutive + // entries within a compile unit if there are no gaps. if (range.first == range.second) { state_coll.insert(range.first, state); } else { @@ -1065,10 +1065,9 @@ void DWARFDebugLine::State::Reset() { Row::Reset(prologue->default_is_stmt); } // DWARFDebugLine::State::AppendRowToMatrix //---------------------------------------------------------------------- void DWARFDebugLine::State::AppendRowToMatrix(dw_offset_t offset) { - // Each time we are to add an entry into the line table matrix - // call the callback function so that someone can do something with - // the current state of the state machine (like build a line table - // or dump the line table!) + // Each time we are to add an entry into the line table matrix call the + // callback function so that someone can do something with the current state + // of the state machine (like build a line table or dump the line table!) if (log) { if (row == 0) { log->PutCString("Address Line Column File ISA Flags"); @@ -1088,8 +1087,8 @@ void DWARFDebugLine::State::AppendRowToMatrix(dw_offset_t offset) { // DWARFDebugLine::State::Finalize //---------------------------------------------------------------------- void DWARFDebugLine::State::Finalize(dw_offset_t offset) { - // Call the callback with a special row state when we are done parsing a - // line table + // Call the callback with a special row state when we are done parsing a line + // table row = DoneParsingLineTable; if (callback) callback(offset, *this, callbackUserData); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h index ea02cfed6e01..3ab15ac59028 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h @@ -90,7 +90,7 @@ public: include_directories.clear(); file_names.clear(); } - bool GetFile(uint32_t file_idx, const char *comp_dir, + bool GetFile(uint32_t file_idx, const lldb_private::FileSpec &cu_comp_dir, lldb_private::FileSpec &file) const; }; @@ -199,7 +199,8 @@ public: static bool ParseSupportFiles(const lldb::ModuleSP &module_sp, const lldb_private::DWARFDataExtractor &debug_line_data, - const char *cu_comp_dir, dw_offset_t stmt_list, + const lldb_private::FileSpec &cu_comp_dir, + dw_offset_t stmt_list, lldb_private::FileSpecList &support_files); static bool ParsePrologue(const lldb_private::DWARFDataExtractor &debug_line_data, diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp deleted file mode 100644 index 766899c497b0..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp +++ /dev/null @@ -1,255 +0,0 @@ -//===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DWARFDebugPubnames.h" - -#include "lldb/Utility/Stream.h" -#include "lldb/Utility/Timer.h" - -#include "DWARFCompileUnit.h" -#include "DWARFDIECollection.h" -#include "DWARFDebugInfo.h" -#include "DWARFFormValue.h" -#include "LogChannelDWARF.h" -#include "SymbolFileDWARF.h" - -using namespace lldb; -using namespace lldb_private; - -DWARFDebugPubnames::DWARFDebugPubnames() : m_sets() {} - -bool DWARFDebugPubnames::Extract(const DWARFDataExtractor &data) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", - (uint64_t)data.GetByteSize()); - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); - if (log) - log->Printf("DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", - (uint64_t)data.GetByteSize()); - - if (data.ValidOffset(0)) { - lldb::offset_t offset = 0; - - DWARFDebugPubnamesSet set; - while (data.ValidOffset(offset)) { - if (set.Extract(data, &offset)) { - m_sets.push_back(set); - offset = set.GetOffsetOfNextEntry(); - } else - break; - } - if (log) - Dump(log); - return true; - } - return false; -} - -bool DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF *dwarf2Data) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "DWARFDebugPubnames::GeneratePubnames (data = %p)", - static_cast<void *>(dwarf2Data)); - - Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES)); - if (log) - log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", - static_cast<void *>(dwarf2Data)); - - m_sets.clear(); - DWARFDebugInfo *debug_info = dwarf2Data->DebugInfo(); - if (debug_info) { - uint32_t cu_idx = 0; - const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); - for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - - DWARFCompileUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); - - DWARFFormValue::FixedFormSizes fixed_form_sizes = - DWARFFormValue::GetFixedFormSizesForAddressSize( - cu->GetAddressByteSize(), cu->IsDWARF64()); - - bool clear_dies = cu->ExtractDIEsIfNeeded(false) > 1; - - DWARFDIECollection dies; - const size_t die_count = cu->AppendDIEsWithTag(DW_TAG_subprogram, dies) + - cu->AppendDIEsWithTag(DW_TAG_variable, dies); - - dw_offset_t cu_offset = cu->GetOffset(); - DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, - cu->GetNextCompileUnitOffset() - - cu_offset); - - size_t die_idx; - for (die_idx = 0; die_idx < die_count; ++die_idx) { - DWARFDIE die = dies.GetDIEAtIndex(die_idx); - DWARFAttributes attributes; - const char *name = NULL; - const char *mangled = NULL; - bool add_die = false; - const size_t num_attributes = die.GetDIE()->GetAttributes( - die.GetCU(), fixed_form_sizes, attributes); - if (num_attributes > 0) { - uint32_t i; - - dw_tag_t tag = die.Tag(); - - for (i = 0; i < num_attributes; ++i) { - dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - switch (attr) { - case DW_AT_name: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - name = form_value.AsCString(); - break; - - case DW_AT_MIPS_linkage_name: - case DW_AT_linkage_name: - if (attributes.ExtractFormValueAtIndex(i, form_value)) - mangled = form_value.AsCString(); - break; - - case DW_AT_low_pc: - case DW_AT_ranges: - case DW_AT_entry_pc: - if (tag == DW_TAG_subprogram) - add_die = true; - break; - - case DW_AT_location: - if (tag == DW_TAG_variable) { - DWARFDIE parent_die = die.GetParent(); - while (parent_die) { - switch (parent_die.Tag()) { - case DW_TAG_subprogram: - case DW_TAG_lexical_block: - case DW_TAG_inlined_subroutine: - // Even if this is a function level static, we don't add it. - // We could theoretically - // add these if we wanted to by introspecting into the - // DW_AT_location and seeing - // if the location describes a hard coded address, but we - // don't want the performance - // penalty of that right now. - add_die = false; - parent_die.Clear(); // Terminate the while loop. - break; - - case DW_TAG_compile_unit: - add_die = true; - parent_die.Clear(); // Terminate the while loop. - break; - - default: - parent_die = - parent_die.GetParent(); // Keep going in the while loop. - break; - } - } - } - break; - } - } - } - - if (add_die && (name || mangled)) { - pubnames_set.AddDescriptor(die.GetCompileUnitRelativeOffset(), - mangled ? mangled : name); - } - } - - if (pubnames_set.NumDescriptors() > 0) { - m_sets.push_back(pubnames_set); - } - - // Keep memory down by clearing DIEs if this generate function - // caused them to be parsed - if (clear_dies) - cu->ClearDIEs(true); - } - } - if (m_sets.empty()) - return false; - if (log) - Dump(log); - return true; -} - -bool DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF *dwarf2Data) { - m_sets.clear(); - DWARFDebugInfo *debug_info = dwarf2Data->DebugInfo(); - if (debug_info) { - uint32_t cu_idx = 0; - const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); - for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFCompileUnit *cu = debug_info->GetCompileUnitAtIndex(cu_idx); - DWARFDIECollection dies; - const size_t die_count = cu->AppendDIEsWithTag(DW_TAG_base_type, dies); - dw_offset_t cu_offset = cu->GetOffset(); - DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, - cu->GetNextCompileUnitOffset() - - cu_offset); - - size_t die_idx; - for (die_idx = 0; die_idx < die_count; ++die_idx) { - DWARFDIE die = dies.GetDIEAtIndex(die_idx); - const char *name = die.GetName(); - - if (name) - pubnames_set.AddDescriptor(die.GetCompileUnitRelativeOffset(), name); - } - - if (pubnames_set.NumDescriptors() > 0) { - m_sets.push_back(pubnames_set); - } - } - } - return !m_sets.empty(); -} - -void DWARFDebugPubnames::Dump(Log *s) const { - if (m_sets.empty()) - s->PutCString("< EMPTY >\n"); - else { - const_iterator pos; - const_iterator end = m_sets.end(); - - for (pos = m_sets.begin(); pos != end; ++pos) - (*pos).Dump(s); - } -} - -bool DWARFDebugPubnames::Find(const char *name, bool ignore_case, - std::vector<dw_offset_t> &die_offsets) const { - const_iterator pos; - const_iterator end = m_sets.end(); - - die_offsets.clear(); - - for (pos = m_sets.begin(); pos != end; ++pos) { - (*pos).Find(name, ignore_case, die_offsets); - } - - return !die_offsets.empty(); -} - -bool DWARFDebugPubnames::Find(const RegularExpression ®ex, - std::vector<dw_offset_t> &die_offsets) const { - const_iterator pos; - const_iterator end = m_sets.end(); - - die_offsets.clear(); - - for (pos = m_sets.begin(); pos != end; ++pos) { - (*pos).Find(regex, die_offsets); - } - - return !die_offsets.empty(); -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h deleted file mode 100644 index 57dabade012c..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- DWARFDebugPubnames.h ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef SymbolFileDWARF_DWARFDebugPubnames_h_ -#define SymbolFileDWARF_DWARFDebugPubnames_h_ - -#include "SymbolFileDWARF.h" - -#include <list> - -#include "DWARFDebugPubnamesSet.h" - -class DWARFDebugPubnames { -public: - DWARFDebugPubnames(); - bool Extract(const lldb_private::DWARFDataExtractor &data); - bool GeneratePubnames(SymbolFileDWARF *dwarf2Data); - bool GeneratePubBaseTypes(SymbolFileDWARF *dwarf2Data); - - void Dump(lldb_private::Log *s) const; - bool Find(const char *name, bool ignore_case, - std::vector<dw_offset_t> &die_offset_coll) const; - bool Find(const lldb_private::RegularExpression ®ex, - std::vector<dw_offset_t> &die_offsets) const; - -protected: - typedef std::list<DWARFDebugPubnamesSet> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - - collection m_sets; -}; - -#endif // SymbolFileDWARF_DWARFDebugPubnames_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp deleted file mode 100644 index 21e2482783a1..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp +++ /dev/null @@ -1,146 +0,0 @@ -//===-- DWARFDebugPubnamesSet.cpp -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "DWARFDebugPubnamesSet.h" - -#include "lldb/Utility/Log.h" -#include "lldb/Utility/RegularExpression.h" - -#include "SymbolFileDWARF.h" - -using namespace lldb_private; - -DWARFDebugPubnamesSet::DWARFDebugPubnamesSet() - : m_offset(DW_INVALID_OFFSET), m_header(), m_descriptors(), - m_name_to_descriptor_index() {} - -DWARFDebugPubnamesSet::DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, - dw_offset_t cu_die_offset, - dw_offset_t cu_die_length) - : m_offset(debug_aranges_offset), m_header(), m_descriptors(), - m_name_to_descriptor_index() { - m_header.length = - 10; // set the length to only include the header right for now - m_header.version = 2; // The DWARF version number - m_header.die_offset = cu_die_offset; // compile unit .debug_info offset - m_header.die_length = cu_die_length; // compile unit .debug_info length -} - -void DWARFDebugPubnamesSet::AddDescriptor(dw_offset_t cu_rel_offset, - const char *name) { - if (name && name[0]) { - // Adjust our header length - m_header.length += strlen(name) + 1 + sizeof(dw_offset_t); - Descriptor pubnameDesc(cu_rel_offset, name); - m_descriptors.push_back(pubnameDesc); - } -} - -void DWARFDebugPubnamesSet::Clear() { - m_offset = DW_INVALID_OFFSET; - m_header.length = 10; - m_header.version = 2; - m_header.die_offset = DW_INVALID_OFFSET; - m_header.die_length = 0; - m_descriptors.clear(); -} - -//---------------------------------------------------------------------- -// InitNameIndexes -//---------------------------------------------------------------------- -void DWARFDebugPubnamesSet::InitNameIndexes() const { - // Create the name index vector to be able to quickly search by name - const size_t count = m_descriptors.size(); - for (uint32_t idx = 0; idx < count; ++idx) { - const char *name = m_descriptors[idx].name.c_str(); - if (name && name[0]) - m_name_to_descriptor_index.insert( - cstr_to_index_mmap::value_type(name, idx)); - } -} - -bool DWARFDebugPubnamesSet::Extract(const DWARFDataExtractor &data, - lldb::offset_t *offset_ptr) { - if (data.ValidOffset(*offset_ptr)) { - m_descriptors.clear(); - m_offset = *offset_ptr; - m_header.length = data.GetDWARFInitialLength(offset_ptr); - m_header.version = data.GetU16(offset_ptr); - m_header.die_offset = data.GetDWARFOffset(offset_ptr); - m_header.die_length = data.GetDWARFOffset(offset_ptr); - - Descriptor pubnameDesc; - while (data.ValidOffset(*offset_ptr)) { - pubnameDesc.offset = data.GetDWARFOffset(offset_ptr); - - if (pubnameDesc.offset) { - const char *name = data.GetCStr(offset_ptr); - if (name && name[0]) { - pubnameDesc.name = name; - m_descriptors.push_back(pubnameDesc); - } - } else - break; // We are done if we get a zero 4 byte offset - } - - return !m_descriptors.empty(); - } - return false; -} - -dw_offset_t DWARFDebugPubnamesSet::GetOffsetOfNextEntry() const { - return m_offset + m_header.length + 4; -} - -void DWARFDebugPubnamesSet::Dump(Log *log) const { - log->Printf("Pubnames Header: length = 0x%8.8x, version = 0x%4.4x, " - "die_offset = 0x%8.8x, die_length = 0x%8.8x", - m_header.length, m_header.version, m_header.die_offset, - m_header.die_length); - - bool verbose = log->GetVerbose(); - - DescriptorConstIter pos; - DescriptorConstIter end = m_descriptors.end(); - for (pos = m_descriptors.begin(); pos != end; ++pos) { - if (verbose) - log->Printf("0x%8.8x + 0x%8.8x = 0x%8.8x: %s", pos->offset, - m_header.die_offset, pos->offset + m_header.die_offset, - pos->name.c_str()); - else - log->Printf("0x%8.8x: %s", pos->offset + m_header.die_offset, - pos->name.c_str()); - } -} - -void DWARFDebugPubnamesSet::Find( - const char *name, bool ignore_case, - std::vector<dw_offset_t> &die_offset_coll) const { - if (!m_descriptors.empty() && m_name_to_descriptor_index.empty()) - InitNameIndexes(); - - std::pair<cstr_to_index_mmap::const_iterator, - cstr_to_index_mmap::const_iterator> - range(m_name_to_descriptor_index.equal_range(name)); - for (cstr_to_index_mmap::const_iterator pos = range.first; - pos != range.second; ++pos) - die_offset_coll.push_back(m_header.die_offset + - m_descriptors[(*pos).second].offset); -} - -void DWARFDebugPubnamesSet::Find( - const RegularExpression ®ex, - std::vector<dw_offset_t> &die_offset_coll) const { - DescriptorConstIter pos; - DescriptorConstIter end = m_descriptors.end(); - for (pos = m_descriptors.begin(); pos != end; ++pos) { - if (regex.Execute(pos->name)) - die_offset_coll.push_back(m_header.die_offset + pos->offset); - } -} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h deleted file mode 100644 index 6e7d3f38aa85..000000000000 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h +++ /dev/null @@ -1,95 +0,0 @@ -//===-- DWARFDebugPubnamesSet.h ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef SymbolFileDWARF_DWARFDebugPubnamesSet_h_ -#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_ - -#include "SymbolFileDWARF.h" -#include <map> -#include <string> -#include <vector> -#if __cplusplus >= 201103L || defined(_MSC_VER) -#include <unordered_map> -#else -#include <ext/hash_map> -#endif - -#include "lldb/Core/STLUtils.h" - -class DWARFDebugPubnamesSet { -public: - struct Header { - uint32_t length; // length of the set of entries for this compilation unit, - // not including the length field itself - uint16_t version; // The DWARF version number - uint32_t die_offset; // compile unit .debug_info offset - uint32_t die_length; // compile unit .debug_info length - Header() - : length(10), version(2), die_offset(DW_INVALID_OFFSET), die_length(0) { - } - }; - - struct Descriptor { - Descriptor() : offset(), name() {} - - Descriptor(dw_offset_t the_offset, const char *the_name) - : offset(the_offset), name(the_name ? the_name : "") {} - - dw_offset_t offset; - std::string name; - }; - - DWARFDebugPubnamesSet(); - DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, - dw_offset_t cu_die_offset, dw_offset_t die_length); - dw_offset_t GetOffset() const { return m_offset; } - void SetOffset(dw_offset_t offset) { m_offset = offset; } - DWARFDebugPubnamesSet::Header &GetHeader() { return m_header; } - const DWARFDebugPubnamesSet::Header &GetHeader() const { return m_header; } - const DWARFDebugPubnamesSet::Descriptor *GetDescriptor(uint32_t i) const { - if (i < m_descriptors.size()) - return &m_descriptors[i]; - return NULL; - } - uint32_t NumDescriptors() const { return m_descriptors.size(); } - void AddDescriptor(dw_offset_t cu_rel_offset, const char *name); - void Clear(); - bool Extract(const lldb_private::DWARFDataExtractor &debug_pubnames_data, - lldb::offset_t *offset_ptr); - void Dump(lldb_private::Log *s) const; - void InitNameIndexes() const; - void Find(const char *name, bool ignore_case, - std::vector<dw_offset_t> &die_offset_coll) const; - void Find(const lldb_private::RegularExpression ®ex, - std::vector<dw_offset_t> &die_offsets) const; - dw_offset_t GetOffsetOfNextEntry() const; - -protected: - typedef std::vector<Descriptor> DescriptorColl; - typedef DescriptorColl::iterator DescriptorIter; - typedef DescriptorColl::const_iterator DescriptorConstIter; - - dw_offset_t m_offset; - Header m_header; -#if __cplusplus >= 201103L || defined(_MSC_VER) - typedef std::unordered_multimap<const char *, uint32_t, - std::hash<const char *>, - CStringEqualBinaryPredicate> - cstr_to_index_mmap; -#else - typedef __gnu_cxx::hash_multimap<const char *, uint32_t, - __gnu_cxx::hash<const char *>, - CStringEqualBinaryPredicate> - cstr_to_index_mmap; -#endif - DescriptorColl m_descriptors; - mutable cstr_to_index_mmap m_name_to_descriptor_index; -}; - -#endif // SymbolFileDWARF_DWARFDebugPubnamesSet_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index a8c48b7f2f84..89e27efb3cc2 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -89,8 +89,8 @@ void DWARFDebugRanges::Dump(Stream &s, debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size)) { dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size); - // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits - // of ones + // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits of + // ones if (begin == 0xFFFFFFFFull && addr_size == 4) begin = LLDB_INVALID_ADDRESS; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp index 79f2f221696b..dbaf0b0ed127 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp @@ -67,8 +67,8 @@ bool DWARFDeclContext::operator==(const DWARFDeclContext &rhs) const { // First compare the tags before we do expensive name compares for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos) { if (pos->tag != rhs_pos->tag) { - // Check for DW_TAG_structure_type and DW_TAG_class_type as they are often - // used interchangeably in GCC + // Check for DW_TAG_structure_type and DW_TAG_class_type as they are + // often used interchangeably in GCC if (pos->tag == DW_TAG_structure_type && rhs_pos->tag == DW_TAG_class_type) continue; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp index 2ff0fe3aac41..1d927ba3bca3 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp @@ -473,16 +473,6 @@ const char *DW_ORD_value_to_name(uint32_t val) { return llvmstr.data(); } -const char *DW_DSC_value_to_name(uint32_t val) { - static char invalid[100]; - llvm::StringRef llvmstr = llvm::dwarf::DiscriminantString(val); - if (llvmstr.empty()) { - snprintf(invalid, sizeof(invalid), "Unknown DW_DSC constant: 0x%x", val); - return invalid; - } - return llvmstr.data(); -} - const char *DW_LNS_value_to_name(uint32_t val) { static char invalid[100]; llvm::StringRef llvmstr = llvm::dwarf::LNStandardString(val); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h index 038f5706c060..926f83b3564a 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -58,8 +58,6 @@ const char *DW_INL_value_to_name(uint32_t val); const char *DW_ORD_value_to_name(uint32_t val); -const char *DW_DSC_value_to_name(uint32_t val); - const char *DW_LNS_value_to_name(uint32_t val); const char *DW_LNE_value_to_name(uint32_t val); diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index a21e313c2f81..4fde5748d3f3 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -12,10 +12,10 @@ #include "lldb/Core/dwarf.h" #include "lldb/Utility/Stream.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFFormValue.h" -class DWARFCompileUnit; +class DWARFUnit; using namespace lldb_private; @@ -154,7 +154,7 @@ DWARFFormValue::GetFixedFormSizesForAddressSize(uint8_t addr_size, DWARFFormValue::DWARFFormValue() : m_cu(NULL), m_form(0), m_value() {} -DWARFFormValue::DWARFFormValue(const DWARFCompileUnit *cu, dw_form_t form) +DWARFFormValue::DWARFFormValue(const DWARFUnit *cu, dw_form_t form) : m_cu(cu), m_form(form), m_value() {} void DWARFFormValue::Clear() { @@ -177,7 +177,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, case DW_FORM_addr: assert(m_cu); m_value.value.uval = data.GetMaxU64( - offset_ptr, DWARFCompileUnit::GetAddressByteSize(m_cu)); + offset_ptr, DWARFUnit::GetAddressByteSize(m_cu)); break; case DW_FORM_block2: m_value.value.uval = data.GetU16(offset_ptr); @@ -220,7 +220,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, case DW_FORM_strp: assert(m_cu); m_value.value.uval = - data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); + data.GetMaxU64(offset_ptr, DWARFUnit::IsDWARF64(m_cu) ? 8 : 4); break; // case DW_FORM_APPLE_db_str: case DW_FORM_udata: @@ -258,7 +258,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data, case DW_FORM_sec_offset: assert(m_cu); m_value.value.uval = - data.GetMaxU64(offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4); + data.GetMaxU64(offset_ptr, DWARFUnit::IsDWARF64(m_cu) ? 8 : 4); break; case DW_FORM_flag_present: m_value.value.uval = 1; @@ -296,11 +296,11 @@ bool DWARFFormValue::SkipValue(const DWARFDataExtractor &debug_info_data, bool DWARFFormValue::SkipValue(dw_form_t form, const DWARFDataExtractor &debug_info_data, lldb::offset_t *offset_ptr, - const DWARFCompileUnit *cu) { + const DWARFUnit *cu) { uint8_t ref_addr_size; switch (form) { - // Blocks if inlined data that have a length field and the data bytes - // inlined in the .debug_info + // Blocks if inlined data that have a length field and the data bytes inlined + // in the .debug_info case DW_FORM_exprloc: case DW_FORM_block: { dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr); @@ -330,7 +330,7 @@ bool DWARFFormValue::SkipValue(dw_form_t form, // Compile unit address sized values case DW_FORM_addr: - *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu); + *offset_ptr += DWARFUnit::GetAddressByteSize(cu); return true; case DW_FORM_ref_addr: diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index 2aa7460c4910..ef1a693b37c9 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -13,7 +13,7 @@ #include "DWARFDataExtractor.h" #include <stddef.h> // for NULL -class DWARFCompileUnit; +class DWARFUnit; class DWARFFormValue { public: @@ -55,9 +55,9 @@ public: }; DWARFFormValue(); - DWARFFormValue(const DWARFCompileUnit *cu, dw_form_t form); - const DWARFCompileUnit *GetCompileUnit() const { return m_cu; } - void SetCompileUnit(const DWARFCompileUnit *cu) { m_cu = cu; } + DWARFFormValue(const DWARFUnit *cu, dw_form_t form); + const DWARFUnit *GetCompileUnit() const { return m_cu; } + void SetCompileUnit(const DWARFUnit *cu) { m_cu = cu; } dw_form_t Form() const { return m_form; } void SetForm(dw_form_t form) { m_form = form; } const ValueType &Value() const { return m_value; } @@ -79,7 +79,7 @@ public: lldb::offset_t *offset_ptr) const; static bool SkipValue(const dw_form_t form, const lldb_private::DWARFDataExtractor &debug_info_data, - lldb::offset_t *offset_ptr, const DWARFCompileUnit *cu); + lldb::offset_t *offset_ptr, const DWARFUnit *cu); static bool IsBlockForm(const dw_form_t form); static bool IsDataForm(const dw_form_t form); static FixedFormSizes GetFixedFormSizesForAddressSize(uint8_t addr_size, @@ -89,7 +89,7 @@ public: static bool FormIsSupported(dw_form_t form); protected: - const DWARFCompileUnit *m_cu; // Compile unit for this form + const DWARFUnit *m_cu; // Compile unit for this form dw_form_t m_form; // Form for this value ValueType m_value; // Contains all data for the form }; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp new file mode 100644 index 000000000000..4577f0557a1d --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp @@ -0,0 +1,68 @@ +//===-- DWARFIndex.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/SymbolFile/DWARF/DWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/DWARFDIE.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" + +#include "Plugins/Language/ObjC/ObjCLanguage.h" + +using namespace lldb_private; +using namespace lldb; + +DWARFIndex::~DWARFIndex() = default; + +void DWARFIndex::ProcessFunctionDIE(llvm::StringRef name, DIERef ref, + DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) { + DWARFDIE die = info.GetDIE(ref); + if (!die) { + ReportInvalidDIEOffset(ref.die_offset, name); + return; + } + + // Exit early if we're searching exclusively for methods or selectors and + // we have a context specified (no methods in namespaces). + uint32_t looking_for_nonmethods = + name_type_mask & ~(eFunctionNameTypeMethod | eFunctionNameTypeSelector); + if (!looking_for_nonmethods && parent_decl_ctx.IsValid()) + return; + + // Otherwise, we need to also check that the context matches. If it does not + // match, we do nothing. + if (!SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) + return; + + // In case of a full match, we just insert everything we find. + if (name_type_mask & eFunctionNameTypeFull) { + dies.push_back(die); + return; + } + + // If looking for ObjC selectors, we need to also check if the name is a + // possible selector. + if (name_type_mask & eFunctionNameTypeSelector && + ObjCLanguage::IsPossibleObjCMethodName(die.GetName())) { + dies.push_back(die); + return; + } + + bool looking_for_methods = name_type_mask & lldb::eFunctionNameTypeMethod; + bool looking_for_functions = name_type_mask & lldb::eFunctionNameTypeBase; + if (looking_for_methods || looking_for_functions) { + // If we're looking for either methods or functions, we definitely want this + // die. Otherwise, only keep it if the die type matches what we are + // searching for. + if ((looking_for_methods && looking_for_functions) || + looking_for_methods == die.IsMethod()) + dies.push_back(die); + } +} diff --git a/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/source/Plugins/SymbolFile/DWARF/DWARFIndex.h new file mode 100644 index 000000000000..77af67b8e60f --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFIndex.h @@ -0,0 +1,69 @@ +//===-- DWARFIndex.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_DWARFINDEX_H +#define LLDB_DWARFINDEX_H + +#include "Plugins/SymbolFile/DWARF/DIERef.h" +#include "Plugins/SymbolFile/DWARF/DWARFDIE.h" +#include "Plugins/SymbolFile/DWARF/DWARFFormValue.h" + +class DWARFDebugInfo; +class DWARFDeclContext; +class DWARFDIE; + +namespace lldb_private { +class DWARFIndex { +public: + DWARFIndex(Module &module) : m_module(module) {} + virtual ~DWARFIndex(); + + virtual void Preload() = 0; + + /// Finds global variables with the given base name. Any additional filtering + /// (e.g., to only retrieve variables from a given context) should be done by + /// the consumer. + virtual void GetGlobalVariables(ConstString basename, DIEArray &offsets) = 0; + + virtual void GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) = 0; + virtual void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) = 0; + virtual void GetObjCMethods(ConstString class_name, DIEArray &offsets) = 0; + virtual void GetCompleteObjCClass(ConstString class_name, + bool must_be_implementation, + DIEArray &offsets) = 0; + virtual void GetTypes(ConstString name, DIEArray &offsets) = 0; + virtual void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) = 0; + virtual void GetNamespaces(ConstString name, DIEArray &offsets) = 0; + virtual void GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) = 0; + virtual void GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) = 0; + + virtual void ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) = 0; + virtual void Dump(Stream &s) = 0; + +protected: + Module &m_module; + + /// Helper function implementing common logic for processing function dies. If + /// the function given by "ref" matches search criteria given by + /// "parent_decl_ctx" and "name_type_mask", it is inserted into the "dies" + /// vector. + void ProcessFunctionDIE(llvm::StringRef name, DIERef ref, + DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, std::vector<DWARFDIE> &dies); +}; +} // namespace lldb_private + +#endif // LLDB_DWARFINDEX_H diff --git a/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp new file mode 100644 index 000000000000..f44b2bb97b2b --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -0,0 +1,755 @@ +//===-- DWARFUnit.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFUnit.h" + +#include "lldb/Core/Module.h" +#include "lldb/Host/StringConvert.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/Timer.h" + +#include "DWARFDIECollection.h" +#include "DWARFDebugAranges.h" +#include "DWARFDebugInfo.h" +#include "LogChannelDWARF.h" +#include "SymbolFileDWARFDebugMap.h" +#include "SymbolFileDWARFDwo.h" + +using namespace lldb; +using namespace lldb_private; +using namespace std; + +extern int g_verbose; + +DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf) + : m_dwarf(dwarf), m_cancel_scopes(false) {} + +DWARFUnit::~DWARFUnit() {} + +//---------------------------------------------------------------------- +// Parses first DIE of a compile unit. +//---------------------------------------------------------------------- +void DWARFUnit::ExtractUnitDIEIfNeeded() { + { + llvm::sys::ScopedReader lock(m_first_die_mutex); + if (m_first_die) + return; // Already parsed + } + llvm::sys::ScopedWriter lock(m_first_die_mutex); + if (m_first_die) + return; // Already parsed + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer( + func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", m_offset); + + // Set the offset to that of the first DIE and calculate the start of the + // next compilation unit header. + lldb::offset_t offset = GetFirstDIEOffset(); + + // We are in our compile unit, parse starting at the offset we were told to + // parse + const DWARFDataExtractor &data = GetData(); + DWARFFormValue::FixedFormSizes fixed_form_sizes = + DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), + IsDWARF64()); + if (offset < GetNextCompileUnitOffset() && + m_first_die.FastExtract(data, this, fixed_form_sizes, &offset)) { + AddUnitDIE(m_first_die); + return; + } + + ExtractDIEsEndCheck(offset); +} + +//---------------------------------------------------------------------- +// Parses a compile unit and indexes its DIEs if it hasn't already been done. +// It will leave this compile unit extracted forever. +//---------------------------------------------------------------------- +void DWARFUnit::ExtractDIEsIfNeeded() { + m_cancel_scopes = true; + + { + llvm::sys::ScopedReader lock(m_die_array_mutex); + if (!m_die_array.empty()) + return; // Already parsed + } + llvm::sys::ScopedWriter lock(m_die_array_mutex); + if (!m_die_array.empty()) + return; // Already parsed + + ExtractDIEsRWLocked(); +} + +//---------------------------------------------------------------------- +// Parses a compile unit and indexes its DIEs if it hasn't already been done. +// It will clear this compile unit after returned instance gets out of scope, +// no other ScopedExtractDIEs instance is running for this compile unit +// and no ExtractDIEsIfNeeded() has been executed during this ScopedExtractDIEs +// lifetime. +//---------------------------------------------------------------------- +DWARFUnit::ScopedExtractDIEs DWARFUnit::ExtractDIEsScoped() { + ScopedExtractDIEs scoped(this); + + { + llvm::sys::ScopedReader lock(m_die_array_mutex); + if (!m_die_array.empty()) + return scoped; // Already parsed + } + llvm::sys::ScopedWriter lock(m_die_array_mutex); + if (!m_die_array.empty()) + return scoped; // Already parsed + + // Otherwise m_die_array would be already populated. + lldbassert(!m_cancel_scopes); + + ExtractDIEsRWLocked(); + scoped.m_clear_dies = true; + return scoped; +} + +DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(DWARFUnit *cu) : m_cu(cu) { + lldbassert(m_cu); + m_cu->m_die_array_scoped_mutex.lock_shared(); +} + +DWARFUnit::ScopedExtractDIEs::~ScopedExtractDIEs() { + if (!m_cu) + return; + m_cu->m_die_array_scoped_mutex.unlock_shared(); + if (!m_clear_dies || m_cu->m_cancel_scopes) + return; + // Be sure no other ScopedExtractDIEs is running anymore. + llvm::sys::ScopedWriter lock_scoped(m_cu->m_die_array_scoped_mutex); + llvm::sys::ScopedWriter lock(m_cu->m_die_array_mutex); + if (m_cu->m_cancel_scopes) + return; + m_cu->ClearDIEsRWLocked(); +} + +DWARFUnit::ScopedExtractDIEs::ScopedExtractDIEs(ScopedExtractDIEs &&rhs) + : m_cu(rhs.m_cu), m_clear_dies(rhs.m_clear_dies) { + rhs.m_cu = nullptr; +} + +DWARFUnit::ScopedExtractDIEs &DWARFUnit::ScopedExtractDIEs::operator=( + DWARFUnit::ScopedExtractDIEs &&rhs) { + m_cu = rhs.m_cu; + rhs.m_cu = nullptr; + m_clear_dies = rhs.m_clear_dies; + return *this; +} + +//---------------------------------------------------------------------- +// Parses a compile unit and indexes its DIEs, m_die_array_mutex must be +// held R/W and m_die_array must be empty. +//---------------------------------------------------------------------- +void DWARFUnit::ExtractDIEsRWLocked() { + llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex); + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer( + func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", m_offset); + + // Set the offset to that of the first DIE and calculate the start of the + // next compilation unit header. + lldb::offset_t offset = GetFirstDIEOffset(); + lldb::offset_t next_cu_offset = GetNextCompileUnitOffset(); + + DWARFDebugInfoEntry die; + // Keep a flat array of the DIE for binary lookup by DIE offset + Log *log( + LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS)); + if (log) { + m_dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( + log, + "DWARFUnit::ExtractDIEsIfNeeded () for compile unit at " + ".debug_info[0x%8.8x]", + GetOffset()); + } + + uint32_t depth = 0; + // We are in our compile unit, parse starting at the offset we were told to + // parse + const DWARFDataExtractor &data = GetData(); + std::vector<uint32_t> die_index_stack; + die_index_stack.reserve(32); + die_index_stack.push_back(0); + bool prev_die_had_children = false; + DWARFFormValue::FixedFormSizes fixed_form_sizes = + DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), + IsDWARF64()); + while (offset < next_cu_offset && + die.FastExtract(data, this, fixed_form_sizes, &offset)) { + // if (log) + // log->Printf("0x%8.8x: %*.*s%s%s", + // die.GetOffset(), + // depth * 2, depth * 2, "", + // DW_TAG_value_to_name (die.Tag()), + // die.HasChildren() ? " *" : ""); + + const bool null_die = die.IsNULL(); + if (depth == 0) { + assert(m_die_array.empty() && "Compile unit DIE already added"); + + // The average bytes per DIE entry has been seen to be around 14-20 so + // lets pre-reserve half of that since we are now stripping the NULL + // tags. + + // Only reserve the memory if we are adding children of the main + // compile unit DIE. The compile unit DIE is always the first entry, so + // if our size is 1, then we are adding the first compile unit child + // DIE and should reserve the memory. + m_die_array.reserve(GetDebugInfoSize() / 24); + m_die_array.push_back(die); + + if (!m_first_die) + AddUnitDIE(m_die_array.front()); + } else { + if (null_die) { + if (prev_die_had_children) { + // This will only happen if a DIE says is has children but all it + // contains is a NULL tag. Since we are removing the NULL DIEs from + // the list (saves up to 25% in C++ code), we need a way to let the + // DIE know that it actually doesn't have children. + if (!m_die_array.empty()) + m_die_array.back().SetEmptyChildren(true); + } + } else { + die.SetParentIndex(m_die_array.size() - die_index_stack[depth - 1]); + + if (die_index_stack.back()) + m_die_array[die_index_stack.back()].SetSiblingIndex( + m_die_array.size() - die_index_stack.back()); + + // Only push the DIE if it isn't a NULL DIE + m_die_array.push_back(die); + } + } + + if (null_die) { + // NULL DIE. + if (!die_index_stack.empty()) + die_index_stack.pop_back(); + + if (depth > 0) + --depth; + if (depth == 0) + break; // We are done with this compile unit! + + prev_die_had_children = false; + } else { + die_index_stack.back() = m_die_array.size() - 1; + // Normal DIE + const bool die_has_children = die.HasChildren(); + if (die_has_children) { + die_index_stack.push_back(0); + ++depth; + } + prev_die_had_children = die_has_children; + } + } + + if (!m_die_array.empty()) { + lldbassert(!m_first_die || m_first_die == m_die_array.front()); + m_first_die = m_die_array.front(); + } + + m_die_array.shrink_to_fit(); + + ExtractDIEsEndCheck(offset); + + if (m_dwo_symbol_file) { + DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); + dwo_cu->ExtractDIEsIfNeeded(); + } +} + +//-------------------------------------------------------------------------- +// Final checks for both ExtractUnitDIEIfNeeded() and ExtractDIEsIfNeeded(). +//-------------------------------------------------------------------------- +void DWARFUnit::ExtractDIEsEndCheck(lldb::offset_t offset) const { + // Give a little bit of info if we encounter corrupt DWARF (our offset should + // always terminate at or before the start of the next compilation unit + // header). + if (offset > GetNextCompileUnitOffset()) { + m_dwarf->GetObjectFile()->GetModule()->ReportWarning( + "DWARF compile unit extends beyond its bounds cu 0x%8.8x at " + "0x%8.8" PRIx64 "\n", + GetOffset(), offset); + } + + Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); + if (log && log->GetVerbose()) { + StreamString strm; + Dump(&strm); + if (m_die_array.empty()) + strm.Printf("error: no DIE for compile unit"); + else + m_die_array[0].Dump(m_dwarf, this, strm, UINT32_MAX); + log->PutString(strm.GetString()); + } +} + +// m_die_array_mutex must be already held as read/write. +void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { + uint64_t base_addr = cu_die.GetAttributeValueAsAddress( + m_dwarf, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS); + if (base_addr == LLDB_INVALID_ADDRESS) + base_addr = cu_die.GetAttributeValueAsAddress( + m_dwarf, this, DW_AT_entry_pc, 0); + SetBaseAddress(base_addr); + + std::unique_ptr<SymbolFileDWARFDwo> dwo_symbol_file = + m_dwarf->GetDwoSymbolFileForCompileUnit(*this, cu_die); + if (!dwo_symbol_file) + return; + + DWARFUnit *dwo_cu = dwo_symbol_file->GetCompileUnit(); + if (!dwo_cu) + return; // Can't fetch the compile unit from the dwo file. + + DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); + if (!dwo_cu_die.IsValid()) + return; // Can't fetch the compile unit DIE from the dwo file. + + uint64_t main_dwo_id = + cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_dwo_id, 0); + uint64_t sub_dwo_id = + dwo_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0); + if (main_dwo_id != sub_dwo_id) + return; // The 2 dwo ID isn't match. Don't use the dwo file as it belongs to + // a differectn compilation. + + m_dwo_symbol_file = std::move(dwo_symbol_file); + + dw_addr_t addr_base = + cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_GNU_addr_base, 0); + dw_addr_t ranges_base = cu_die.GetAttributeValueAsUnsigned( + m_dwarf, this, DW_AT_GNU_ranges_base, 0); + dwo_cu->SetAddrBase(addr_base, ranges_base, m_offset); +} + +DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { + if (DIE()) { + const DWARFDebugAranges &func_aranges = GetFunctionAranges(); + + // Re-check the aranges auto pointer contents in case it was created above + if (!func_aranges.IsEmpty()) + return GetDIE(func_aranges.FindAddress(address)); + } + return DWARFDIE(); +} + +size_t DWARFUnit::AppendDIEsWithTag(const dw_tag_t tag, + DWARFDIECollection &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.Append(DWARFDIE(this, &(*pos))); + } + } + + // Return the number of DIEs added to the collection + return dies.Size() - old_size; +} + + +lldb::user_id_t DWARFUnit::GetID() const { + dw_offset_t local_id = + m_base_obj_offset != DW_INVALID_OFFSET ? m_base_obj_offset : m_offset; + if (m_dwarf) + return DIERef(local_id, local_id).GetUID(m_dwarf); + else + return local_id; +} + +dw_offset_t DWARFUnit::GetNextCompileUnitOffset() const { + return m_offset + GetLengthByteSize() + GetLength(); +} + +size_t DWARFUnit::GetDebugInfoSize() const { + return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); +} + +const DWARFAbbreviationDeclarationSet *DWARFUnit::GetAbbreviations() const { + return m_abbrevs; +} + +dw_offset_t DWARFUnit::GetAbbrevOffset() const { + return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET; +} + +void DWARFUnit::SetAddrBase(dw_addr_t addr_base, + dw_addr_t ranges_base, + dw_offset_t base_obj_offset) { + m_addr_base = addr_base; + m_ranges_base = ranges_base; + m_base_obj_offset = base_obj_offset; +} + +// It may be called only with m_die_array_mutex held R/W. +void DWARFUnit::ClearDIEsRWLocked() { + m_die_array.clear(); + m_die_array.shrink_to_fit(); + + if (m_dwo_symbol_file) + m_dwo_symbol_file->GetCompileUnit()->ClearDIEsRWLocked(); +} + +void DWARFUnit::BuildAddressRangeTable(SymbolFileDWARF *dwarf, + DWARFDebugAranges *debug_aranges) { + // This function is usually called if there in no .debug_aranges section in + // order to produce a compile unit level set of address ranges that is + // accurate. + + size_t num_debug_aranges = debug_aranges->GetNumRanges(); + + // First get the compile unit DIE only and check if it has a DW_AT_ranges + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + + const dw_offset_t cu_offset = GetOffset(); + if (die) { + DWARFRangeList ranges; + const size_t num_ranges = + die->GetAttributeAddressRanges(dwarf, this, ranges, false); + if (num_ranges > 0) { + // This compile unit has DW_AT_ranges, assume this is correct if it is + // present since clang no longer makes .debug_aranges by default and it + // emits DW_AT_ranges for DW_TAG_compile_units. GCC also does this with + // recent GCC builds. + for (size_t i = 0; i < num_ranges; ++i) { + const DWARFRangeList::Entry &range = ranges.GetEntryRef(i); + debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), + range.GetRangeEnd()); + } + + return; // We got all of our ranges from the DW_AT_ranges attribute + } + } + // We don't have a DW_AT_ranges attribute, so we need to parse the DWARF + + // If the DIEs weren't parsed, then we don't want all dies for all compile + // units to stay loaded when they weren't needed. So we can end up parsing + // the DWARF and then throwing them all away to keep memory usage down. + ScopedExtractDIEs clear_dies(ExtractDIEsScoped()); + + die = DIEPtr(); + if (die) + die->BuildAddressRangeTable(dwarf, this, debug_aranges); + + if (debug_aranges->GetNumRanges() == num_debug_aranges) { + // We got nothing from the functions, maybe we have a line tables only + // situation. Check the line tables and build the arange table from this. + SymbolContext sc; + sc.comp_unit = dwarf->GetCompUnitForDWARFCompUnit(this); + if (sc.comp_unit) { + SymbolFileDWARFDebugMap *debug_map_sym_file = + m_dwarf->GetDebugMapSymfile(); + if (debug_map_sym_file == NULL) { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table) { + LineTable::FileAddressRanges file_ranges; + const bool append = true; + const size_t num_ranges = + line_table->GetContiguousFileAddressRanges(file_ranges, append); + for (uint32_t idx = 0; idx < num_ranges; ++idx) { + const LineTable::FileAddressRanges::Entry &range = + file_ranges.GetEntryRef(idx); + debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), + range.GetRangeEnd()); + } + } + } else + debug_map_sym_file->AddOSOARanges(dwarf, debug_aranges); + } + } + + if (debug_aranges->GetNumRanges() == num_debug_aranges) { + // We got nothing from the functions, maybe we have a line tables only + // situation. Check the line tables and build the arange table from this. + SymbolContext sc; + sc.comp_unit = dwarf->GetCompUnitForDWARFCompUnit(this); + if (sc.comp_unit) { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table) { + LineTable::FileAddressRanges file_ranges; + const bool append = true; + const size_t num_ranges = + line_table->GetContiguousFileAddressRanges(file_ranges, append); + for (uint32_t idx = 0; idx < num_ranges; ++idx) { + const LineTable::FileAddressRanges::Entry &range = + file_ranges.GetEntryRef(idx); + debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), + range.GetRangeEnd()); + } + } + } + } +} + +lldb::ByteOrder DWARFUnit::GetByteOrder() const { + return m_dwarf->GetObjectFile()->GetByteOrder(); +} + +TypeSystem *DWARFUnit::GetTypeSystem() { + if (m_dwarf) + return m_dwarf->GetTypeSystemForLanguage(GetLanguageType()); + else + return nullptr; +} + +DWARFFormValue::FixedFormSizes DWARFUnit::GetFixedFormSizes() { + return DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(), + IsDWARF64()); +} + +void DWARFUnit::SetBaseAddress(dw_addr_t base_addr) { m_base_addr = base_addr; } + +//---------------------------------------------------------------------- +// Compare function DWARFDebugAranges::Range structures +//---------------------------------------------------------------------- +static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, + const dw_offset_t die_offset) { + return die.GetOffset() < die_offset; +} + +//---------------------------------------------------------------------- +// GetDIE() +// +// Get the DIE (Debug Information Entry) with the specified offset by first +// checking if the DIE is contained within this compile unit and grabbing the +// DIE from this compile unit. Otherwise we grab the DIE from the DWARF file. +//---------------------------------------------------------------------- +DWARFDIE +DWARFUnit::GetDIE(dw_offset_t die_offset) { + if (die_offset != DW_INVALID_OFFSET) { + if (GetDwoSymbolFile()) + return GetDwoSymbolFile()->GetCompileUnit()->GetDIE(die_offset); + + if (ContainsDIEOffset(die_offset)) { + ExtractDIEsIfNeeded(); + DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); + DWARFDebugInfoEntry::const_iterator pos = + lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset); + if (pos != end) { + if (die_offset == (*pos).GetOffset()) + return DWARFDIE(this, &(*pos)); + } + } else { + // Don't specify the compile unit offset as we don't know it because the + // DIE belongs to + // a different compile unit in the same symbol file. + return m_dwarf->DebugInfo()->GetDIEForDIEOffset(die_offset); + } + } + return DWARFDIE(); // Not found +} + +uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) { + if (cu) + return cu->GetAddressByteSize(); + return DWARFUnit::GetDefaultAddressSize(); +} + +bool DWARFUnit::IsDWARF64(const DWARFUnit *cu) { + if (cu) + return cu->IsDWARF64(); + return false; +} + +uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; } + +void *DWARFUnit::GetUserData() const { return m_user_data; } + +void DWARFUnit::SetUserData(void *d) { + m_user_data = d; + if (m_dwo_symbol_file) + m_dwo_symbol_file->GetCompileUnit()->SetUserData(d); +} + +bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() { + if (GetProducer() == eProducerLLVMGCC) + return false; + return true; +} + +bool DWARFUnit::DW_AT_decl_file_attributes_are_invalid() { + // llvm-gcc makes completely invalid decl file attributes and won't ever be + // fixed, so we need to know to ignore these. + return GetProducer() == eProducerLLVMGCC; +} + +bool DWARFUnit::Supports_unnamed_objc_bitfields() { + if (GetProducer() == eProducerClang) { + const uint32_t major_version = GetProducerVersionMajor(); + if (major_version > 425 || + (major_version == 425 && GetProducerVersionUpdate() >= 13)) + return true; + else + return false; + } + return true; // Assume all other compilers didn't have incorrect ObjC bitfield + // info +} + +SymbolFileDWARF *DWARFUnit::GetSymbolFileDWARF() const { return m_dwarf; } + +void DWARFUnit::ParseProducerInfo() { + m_producer_version_major = UINT32_MAX; + m_producer_version_minor = UINT32_MAX; + m_producer_version_update = UINT32_MAX; + + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) { + + const char *producer_cstr = + die->GetAttributeValueAsString(m_dwarf, this, DW_AT_producer, NULL); + if (producer_cstr) { + RegularExpression llvm_gcc_regex( + llvm::StringRef("^4\\.[012]\\.[01] \\(Based on Apple " + "Inc\\. build [0-9]+\\) \\(LLVM build " + "[\\.0-9]+\\)$")); + if (llvm_gcc_regex.Execute(llvm::StringRef(producer_cstr))) { + m_producer = eProducerLLVMGCC; + } else if (strstr(producer_cstr, "clang")) { + static RegularExpression g_clang_version_regex( + llvm::StringRef("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)")); + RegularExpression::Match regex_match(3); + if (g_clang_version_regex.Execute(llvm::StringRef(producer_cstr), + ®ex_match)) { + std::string str; + if (regex_match.GetMatchAtIndex(producer_cstr, 1, str)) + m_producer_version_major = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + if (regex_match.GetMatchAtIndex(producer_cstr, 2, str)) + m_producer_version_minor = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + if (regex_match.GetMatchAtIndex(producer_cstr, 3, str)) + m_producer_version_update = + StringConvert::ToUInt32(str.c_str(), UINT32_MAX, 10); + } + m_producer = eProducerClang; + } else if (strstr(producer_cstr, "GNU")) + m_producer = eProducerGCC; + } + } + if (m_producer == eProducerInvalid) + m_producer = eProcucerOther; +} + +DWARFProducer DWARFUnit::GetProducer() { + if (m_producer == eProducerInvalid) + ParseProducerInfo(); + return m_producer; +} + +uint32_t DWARFUnit::GetProducerVersionMajor() { + if (m_producer_version_major == 0) + ParseProducerInfo(); + return m_producer_version_major; +} + +uint32_t DWARFUnit::GetProducerVersionMinor() { + if (m_producer_version_minor == 0) + ParseProducerInfo(); + return m_producer_version_minor; +} + +uint32_t DWARFUnit::GetProducerVersionUpdate() { + if (m_producer_version_update == 0) + ParseProducerInfo(); + return m_producer_version_update; +} +LanguageType DWARFUnit::LanguageTypeFromDWARF(uint64_t val) { + // Note: user languages between lo_user and hi_user must be handled + // explicitly here. + switch (val) { + case DW_LANG_Mips_Assembler: + return eLanguageTypeMipsAssembler; + case DW_LANG_GOOGLE_RenderScript: + return eLanguageTypeExtRenderScript; + default: + return static_cast<LanguageType>(val); + } +} + +LanguageType DWARFUnit::GetLanguageType() { + if (m_language_type != eLanguageTypeUnknown) + return m_language_type; + + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) + m_language_type = LanguageTypeFromDWARF( + die->GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_language, 0)); + return m_language_type; +} + +bool DWARFUnit::GetIsOptimized() { + if (m_is_optimized == eLazyBoolCalculate) { + const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly(); + if (die) { + m_is_optimized = eLazyBoolNo; + if (die->GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_APPLE_optimized, + 0) == 1) { + m_is_optimized = eLazyBoolYes; + } + } + } + return m_is_optimized == eLazyBoolYes; +} + +SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() const { + return m_dwo_symbol_file.get(); +} + +dw_offset_t DWARFUnit::GetBaseObjOffset() const { return m_base_obj_offset; } + +const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { + if (m_func_aranges_ap.get() == NULL) { + m_func_aranges_ap.reset(new DWARFDebugAranges()); + Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES)); + + if (log) { + m_dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "DWARFUnit::GetFunctionAranges() for compile unit at " + ".debug_info[0x%8.8x]", + GetOffset()); + } + const DWARFDebugInfoEntry *die = DIEPtr(); + if (die) + die->BuildFunctionAddressRangeTable(m_dwarf, this, + m_func_aranges_ap.get()); + + if (m_dwo_symbol_file) { + DWARFUnit *dwo_cu = m_dwo_symbol_file->GetCompileUnit(); + const DWARFDebugInfoEntry *dwo_die = dwo_cu->DIEPtr(); + if (dwo_die) + dwo_die->BuildFunctionAddressRangeTable(m_dwo_symbol_file.get(), dwo_cu, + m_func_aranges_ap.get()); + } + + const bool minimize = false; + m_func_aranges_ap->Sort(minimize); + } + return *m_func_aranges_ap.get(); +} + diff --git a/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFUnit.h new file mode 100644 index 000000000000..c9e48c538bc1 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -0,0 +1,252 @@ +//===-- DWARFUnit.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_DWARFUnit_h_ +#define SymbolFileDWARF_DWARFUnit_h_ + +#include "DWARFDIE.h" +#include "DWARFDebugInfoEntry.h" +#include "lldb/lldb-enumerations.h" +#include "llvm/Support/RWMutex.h" +#include <atomic> + +class DWARFUnit; +class DWARFCompileUnit; +class NameToDIE; +class SymbolFileDWARF; +class SymbolFileDWARFDwo; + +typedef std::shared_ptr<DWARFUnit> DWARFUnitSP; + +enum DWARFProducer { + eProducerInvalid = 0, + eProducerClang, + eProducerGCC, + eProducerLLVMGCC, + eProcucerOther +}; + +class DWARFUnit { + friend class DWARFCompileUnit; + + using die_iterator_range = + llvm::iterator_range<DWARFDebugInfoEntry::collection::iterator>; + +public: + virtual ~DWARFUnit(); + + void ExtractUnitDIEIfNeeded(); + void ExtractDIEsIfNeeded(); + + class ScopedExtractDIEs { + DWARFUnit *m_cu; + public: + bool m_clear_dies = false; + ScopedExtractDIEs(DWARFUnit *cu); + ~ScopedExtractDIEs(); + DISALLOW_COPY_AND_ASSIGN(ScopedExtractDIEs); + ScopedExtractDIEs(ScopedExtractDIEs &&rhs); + ScopedExtractDIEs &operator=(ScopedExtractDIEs &&rhs); + }; + ScopedExtractDIEs ExtractDIEsScoped(); + + DWARFDIE LookupAddress(const dw_addr_t address); + size_t AppendDIEsWithTag(const dw_tag_t tag, + DWARFDIECollection &matching_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. + /// + /// This will return the correct bytes that contain the data for + /// this DWARFUnit. It could be .debug_info or .debug_types + /// depending on where the data for this unit originates. + /// + /// @return + /// The correct data for the DIE information in this unit. + //------------------------------------------------------------------ + virtual const lldb_private::DWARFDataExtractor &GetData() const = 0; + //------------------------------------------------------------------ + /// Get the size in bytes of the compile unit header. + /// + /// @return + /// Byte size of the compile unit header + //------------------------------------------------------------------ + virtual uint32_t GetHeaderByteSize() const = 0; + // Offset of the initial length field. + dw_offset_t GetOffset() const { return m_offset; } + lldb::user_id_t GetID() const; + //------------------------------------------------------------------ + /// Get the size in bytes of the length field in the header. + /// + /// In DWARF32 this is just 4 bytes, and DWARF64 it is 12 where 4 + /// are 0xFFFFFFFF followed by the actual 64 bit length. + /// + /// @return + /// Byte size of the compile unit header length field + //------------------------------------------------------------------ + size_t GetLengthByteSize() const { return IsDWARF64() ? 12 : 4; } + + bool ContainsDIEOffset(dw_offset_t die_offset) const { + return die_offset >= GetFirstDIEOffset() && + die_offset < GetNextCompileUnitOffset(); + } + dw_offset_t GetFirstDIEOffset() const { + return m_offset + GetHeaderByteSize(); + } + dw_offset_t GetNextCompileUnitOffset() const; + // Size of the CU data (without initial length and without header). + size_t GetDebugInfoSize() const; + // Size of the CU data incl. header but without initial length. + uint32_t GetLength() const { return m_length; } + uint16_t GetVersion() const { return m_version; } + const DWARFAbbreviationDeclarationSet *GetAbbreviations() const; + dw_offset_t GetAbbrevOffset() const; + uint8_t GetAddressByteSize() const { return m_addr_size; } + dw_addr_t GetBaseAddress() const { return m_base_addr; } + dw_addr_t GetAddrBase() const { return m_addr_base; } + dw_addr_t GetRangesBase() const { return m_ranges_base; } + void SetAddrBase(dw_addr_t addr_base, dw_addr_t ranges_base, + dw_offset_t base_obj_offset); + void BuildAddressRangeTable(SymbolFileDWARF *dwarf, + DWARFDebugAranges *debug_aranges); + + lldb::ByteOrder GetByteOrder() const; + + lldb_private::TypeSystem *GetTypeSystem(); + + const DWARFDebugAranges &GetFunctionAranges(); + + DWARFFormValue::FixedFormSizes GetFixedFormSizes(); + + void SetBaseAddress(dw_addr_t base_addr); + + DWARFBaseDIE GetUnitDIEOnly() { return DWARFDIE(this, GetUnitDIEPtrOnly()); } + + DWARFDIE DIE() { return DWARFDIE(this, DIEPtr()); } + + DWARFDIE GetDIE(dw_offset_t die_offset); + + static uint8_t GetAddressByteSize(const DWARFUnit *cu); + + static bool IsDWARF64(const DWARFUnit *cu); + + static uint8_t GetDefaultAddressSize(); + + void *GetUserData() const; + + void SetUserData(void *d); + + bool Supports_DW_AT_APPLE_objc_complete_type(); + + bool DW_AT_decl_file_attributes_are_invalid(); + + bool Supports_unnamed_objc_bitfields(); + + SymbolFileDWARF *GetSymbolFileDWARF() const; + + DWARFProducer GetProducer(); + + uint32_t GetProducerVersionMajor(); + + uint32_t GetProducerVersionMinor(); + + uint32_t GetProducerVersionUpdate(); + + static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); + + lldb::LanguageType GetLanguageType(); + + bool IsDWARF64() const { return m_is_dwarf64; } + + bool GetIsOptimized(); + + SymbolFileDWARFDwo *GetDwoSymbolFile() const; + + dw_offset_t GetBaseObjOffset() const; + + die_iterator_range dies() { + ExtractDIEsIfNeeded(); + return die_iterator_range(m_die_array.begin(), m_die_array.end()); + } + +protected: + DWARFUnit(SymbolFileDWARF *dwarf); + + SymbolFileDWARF *m_dwarf = nullptr; + std::unique_ptr<SymbolFileDWARFDwo> m_dwo_symbol_file; + const DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; + void *m_user_data = nullptr; + // The compile unit debug information entry item + DWARFDebugInfoEntry::collection m_die_array; + mutable llvm::sys::RWMutex m_die_array_mutex; + // It is used for tracking of ScopedExtractDIEs instances. + mutable llvm::sys::RWMutex m_die_array_scoped_mutex; + // ScopedExtractDIEs instances should not call ClearDIEsRWLocked() + // as someone called ExtractDIEsIfNeeded(). + std::atomic<bool> m_cancel_scopes; + // GetUnitDIEPtrOnly() needs to return pointer to the first DIE. + // But the first element of m_die_array after ExtractUnitDIEIfNeeded() + // would possibly move in memory after later ExtractDIEsIfNeeded(). + DWARFDebugInfoEntry m_first_die; + llvm::sys::RWMutex m_first_die_mutex; + // A table similar to the .debug_aranges table, but this one points to the + // exact DW_TAG_subprogram DIEs + std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap; + dw_addr_t m_base_addr = 0; + dw_offset_t m_length = 0; + uint16_t m_version = 0; + uint8_t m_addr_size = 0; + DWARFProducer m_producer = eProducerInvalid; + uint32_t m_producer_version_major = 0; + uint32_t m_producer_version_minor = 0; + uint32_t m_producer_version_update = 0; + lldb::LanguageType m_language_type = lldb::eLanguageTypeUnknown; + bool m_is_dwarf64 = false; + lldb_private::LazyBool m_is_optimized = lldb_private::eLazyBoolCalculate; + 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 + // If this is a dwo compile unit this is the offset of the base compile unit + // in the main object file + dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET; + + // Offset of the initial length field. + dw_offset_t m_offset; + +private: + void ParseProducerInfo(); + void ExtractDIEsRWLocked(); + void ClearDIEsRWLocked(); + + // Get the DWARF unit DWARF debug informration entry. Parse the single DIE + // if needed. + const DWARFDebugInfoEntry *GetUnitDIEPtrOnly() { + ExtractUnitDIEIfNeeded(); + // m_first_die_mutex is not required as m_first_die is never cleared. + if (!m_first_die) + return NULL; + return &m_first_die; + } + + // Get all DWARF debug informration entries. Parse all DIEs if needed. + const DWARFDebugInfoEntry *DIEPtr() { + ExtractDIEsIfNeeded(); + if (m_die_array.empty()) + return NULL; + return &m_die_array[0]; + } + + void AddUnitDIE(const DWARFDebugInfoEntry &cu_die); + void ExtractDIEsEndCheck(lldb::offset_t offset) const; + + DISALLOW_COPY_AND_ASSIGN(DWARFUnit); +}; + +#endif // SymbolFileDWARF_DWARFUnit_h_ diff --git a/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp new file mode 100644 index 000000000000..614ff470d161 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -0,0 +1,272 @@ +//===-- DebugNamesDWARFIndex.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" +#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" +#include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb_private; +using namespace lldb; + +static llvm::DWARFDataExtractor ToLLVM(const DWARFDataExtractor &data) { + return llvm::DWARFDataExtractor( + llvm::StringRef(reinterpret_cast<const char *>(data.GetDataStart()), + data.GetByteSize()), + data.GetByteOrder() == eByteOrderLittle, data.GetAddressByteSize()); +} + +llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> +DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, + DWARFDataExtractor debug_str, + DWARFDebugInfo *debug_info) { + if (!debug_info) { + return llvm::make_error<llvm::StringError>("debug info null", + llvm::inconvertibleErrorCode()); + } + auto index_up = + llvm::make_unique<DebugNames>(ToLLVM(debug_names), ToLLVM(debug_str)); + if (llvm::Error E = index_up->extract()) + return std::move(E); + + return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex( + module, std::move(index_up), debug_names, debug_str, *debug_info)); +} + +llvm::DenseSet<dw_offset_t> +DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { + llvm::DenseSet<dw_offset_t> result; + for (const DebugNames::NameIndex &ni : debug_names) { + for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu) + result.insert(ni.getCUOffset(cu)); + } + return result; +} + +DIERef DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) { + llvm::Optional<uint64_t> cu_offset = entry.getCUOffset(); + if (!cu_offset) + return DIERef(); + + DWARFUnit *cu = m_debug_info.GetCompileUnit(*cu_offset); + if (!cu) + return DIERef(); + + // This initializes the DWO symbol file. It's not possible for + // GetDwoSymbolFile to call this automatically because of mutual recursion + // between this and DWARFDebugInfoEntry::GetAttributeValue. + cu->ExtractUnitDIEIfNeeded(); + uint64_t die_bias = cu->GetDwoSymbolFile() ? 0 : *cu_offset; + + if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset()) + return DIERef(*cu_offset, die_bias + *die_offset); + + return DIERef(); +} + +void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry, + DIEArray &offsets) { + if (DIERef ref = ToDIERef(entry)) + offsets.push_back(ref); +} + +void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error, + const DebugNames::NameIndex &ni, + llvm::StringRef name) { + // Ignore SentinelErrors, log everything else. + LLDB_LOG_ERROR( + LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS), + handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}), + "Failed to parse index entries for index at {1:x}, name {2}: {0}", + ni.getUnitOffset(), name); +} + +void DebugNamesDWARFIndex::GetGlobalVariables(ConstString basename, + DIEArray &offsets) { + m_fallback.GetGlobalVariables(basename, offsets); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(basename.GetStringRef())) { + if (entry.tag() != DW_TAG_variable) + continue; + + Append(entry, offsets); + } +} + +void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) { + m_fallback.GetGlobalVariables(regex, offsets); + + for (const DebugNames::NameIndex &ni: *m_debug_names_up) { + for (DebugNames::NameTableEntry nte: ni) { + if (!regex.Execute(nte.getString())) + continue; + + uint32_t entry_offset = nte.getEntryOffset(); + llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); + for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { + if (entry_or->tag() != DW_TAG_variable) + continue; + + Append(*entry_or, offsets); + } + MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); + } + } +} + +void DebugNamesDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, + DIEArray &offsets) { + m_fallback.GetGlobalVariables(cu, offsets); + + uint64_t cu_offset = cu.GetOffset(); + for (const DebugNames::NameIndex &ni: *m_debug_names_up) { + for (DebugNames::NameTableEntry nte: ni) { + uint32_t entry_offset = nte.getEntryOffset(); + llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); + for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { + if (entry_or->tag() != DW_TAG_variable) + continue; + if (entry_or->getCUOffset() != cu_offset) + continue; + + Append(*entry_or, offsets); + } + MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); + } + } +} + +void DebugNamesDWARFIndex::GetCompleteObjCClass(ConstString class_name, + bool must_be_implementation, + DIEArray &offsets) { + m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, offsets); + + // Keep a list of incomplete types as fallback for when we don't find the + // complete type. + DIEArray incomplete_types; + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(class_name.GetStringRef())) { + if (entry.tag() != DW_TAG_structure_type && + entry.tag() != DW_TAG_class_type) + continue; + + DIERef ref = ToDIERef(entry); + if (!ref) + continue; + + DWARFUnit *cu = m_debug_info.GetCompileUnit(ref.cu_offset); + if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) { + incomplete_types.push_back(ref); + continue; + } + + // FIXME: We should return DWARFDIEs so we don't have to resolve it twice. + DWARFDIE die = m_debug_info.GetDIE(ref); + if (!die) + continue; + + if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) { + // If we find the complete version we're done. + offsets.push_back(ref); + return; + } else { + incomplete_types.push_back(ref); + } + } + + offsets.insert(offsets.end(), incomplete_types.begin(), + incomplete_types.end()); +} + +void DebugNamesDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { + m_fallback.GetTypes(name, offsets); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(name.GetStringRef())) { + if (isType(entry.tag())) + Append(entry, offsets); + } +} + +void DebugNamesDWARFIndex::GetTypes(const DWARFDeclContext &context, + DIEArray &offsets) { + m_fallback.GetTypes(context, offsets); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(context[0].name)) { + if (entry.tag() == context[0].tag) + Append(entry, offsets); + } +} + +void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { + m_fallback.GetNamespaces(name, offsets); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(name.GetStringRef())) { + if (entry.tag() == DW_TAG_namespace) + Append(entry, offsets); + } +} + +void DebugNamesDWARFIndex::GetFunctions( + ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) { + + m_fallback.GetFunctions(name, info, parent_decl_ctx, name_type_mask, dies); + + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(name.GetStringRef())) { + Tag tag = entry.tag(); + if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) + continue; + + if (DIERef ref = ToDIERef(entry)) + ProcessFunctionDIE(name.GetStringRef(), ref, info, parent_decl_ctx, + name_type_mask, dies); + } +} + +void DebugNamesDWARFIndex::GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) { + m_fallback.GetFunctions(regex, offsets); + + for (const DebugNames::NameIndex &ni: *m_debug_names_up) { + for (DebugNames::NameTableEntry nte: ni) { + if (!regex.Execute(nte.getString())) + continue; + + uint32_t entry_offset = nte.getEntryOffset(); + llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset); + for (; entry_or; entry_or = ni.getEntry(&entry_offset)) { + Tag tag = entry_or->tag(); + if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) + continue; + + Append(*entry_or, offsets); + } + MaybeLogLookupError(entry_or.takeError(), ni, nte.getString()); + } + } +} + +void DebugNamesDWARFIndex::Dump(Stream &s) { + m_fallback.Dump(s); + + std::string data; + llvm::raw_string_ostream os(data); + m_debug_names_up->dump(os); + s.PutCString(os.str()); +} diff --git a/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h new file mode 100644 index 000000000000..30423c7ca2a2 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -0,0 +1,83 @@ +//===-- DebugNamesDWARFIndex.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_DEBUGNAMESDWARFINDEX_H +#define LLDB_DEBUGNAMESDWARFINDEX_H + +#include "Plugins/SymbolFile/DWARF/DWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" +#include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h" +#include "lldb/Utility/ConstString.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" + +namespace lldb_private { +class DebugNamesDWARFIndex : public DWARFIndex { +public: + static llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> + Create(Module &module, DWARFDataExtractor debug_names, + DWARFDataExtractor debug_str, DWARFDebugInfo *debug_info); + + void Preload() override { m_fallback.Preload(); } + + void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; + void GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) override; + void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; + void GetObjCMethods(ConstString class_name, DIEArray &offsets) override {} + void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, + DIEArray &offsets) override; + void GetTypes(ConstString name, DIEArray &offsets) override; + void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; + void GetNamespaces(ConstString name, DIEArray &offsets) override; + void GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) override; + void GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) override; + + void ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) override {} + void Dump(Stream &s) override; + +private: + DebugNamesDWARFIndex(Module &module, + std::unique_ptr<llvm::DWARFDebugNames> debug_names_up, + DWARFDataExtractor debug_names_data, + DWARFDataExtractor debug_str_data, + DWARFDebugInfo &debug_info) + : DWARFIndex(module), m_debug_info(debug_info), + m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data), + m_debug_names_up(std::move(debug_names_up)), + m_fallback(module, &debug_info, GetUnits(*m_debug_names_up)) {} + + DWARFDebugInfo &m_debug_info; + + // LLVM DWARFDebugNames will hold a non-owning reference to this data, so keep + // track of the ownership here. + DWARFDataExtractor m_debug_names_data; + DWARFDataExtractor m_debug_str_data; + + using DebugNames = llvm::DWARFDebugNames; + std::unique_ptr<DebugNames> m_debug_names_up; + ManualDWARFIndex m_fallback; + + DIERef ToDIERef(const DebugNames::Entry &entry); + void Append(const DebugNames::Entry &entry, DIEArray &offsets); + + static void MaybeLogLookupError(llvm::Error error, + const DebugNames::NameIndex &ni, + llvm::StringRef name); + + static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names); +}; + +} // namespace lldb_private + +#endif // LLDB_DEBUGNAMESDWARFINDEX_H diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp index cb1e5c185613..36211a08557e 100644 --- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp @@ -75,15 +75,14 @@ void DWARFMappedHash::ExtractClassOrStructDIEArray( die_tag == DW_TAG_structure_type) { if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation) { if (return_implementation_only_if_available) { - // We found the one true definition for this class, so - // only return that + // We found the one true definition for this class, so only return + // that die_offsets.clear(); die_offsets.emplace_back(die_info_array[i].cu_offset, die_info_array[i].offset); return; } else { - // Put the one true definition as the first entry so it - // matches first + // Put the one true definition as the first entry so it matches first die_offsets.emplace(die_offsets.begin(), die_info_array[i].cu_offset, die_info_array[i].offset); } @@ -137,9 +136,8 @@ DWARFMappedHash::DIEInfo::DIEInfo(dw_offset_t c, dw_offset_t o, dw_tag_t t, DWARFMappedHash::Prologue::Prologue(dw_offset_t _die_base_offset) : die_base_offset(_die_base_offset), atoms(), atom_mask(0), min_hash_data_byte_size(0), hash_data_has_fixed_byte_size(true) { - // Define an array of DIE offsets by first defining an array, - // and then define the atom type for the array, in this case - // we have an array of DIE offsets + // Define an array of DIE offsets by first defining an array, and then define + // the atom type for the array, in this case we have an array of DIE offsets AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4); } @@ -239,8 +237,7 @@ DWARFMappedHash::Prologue::Read(const lldb_private::DataExtractor &data, size_t DWARFMappedHash::Prologue::GetByteSize() const { // Add an extra count to the atoms size for the zero termination Atom that - // gets - // written to disk + // gets written to disk return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom); } @@ -379,17 +376,18 @@ bool DWARFMappedHash::MemoryTable::ReadHashData(uint32_t hash_data_offset, DWARFMappedHash::MemoryTable::Result DWARFMappedHash::MemoryTable::GetHashDataForName( - const char *name, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const { + llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr, + Pair &pair) const { pair.key = m_data.GetU32(hash_data_offset_ptr); pair.value.clear(); - // If the key is zero, this terminates our chain of HashData objects - // for this hash value. + // If the key is zero, this terminates our chain of HashData objects for this + // hash value. if (pair.key == 0) return eResultEndOfHashData; - // There definitely should be a string for this string offset, if - // there isn't, there is something wrong, return and error + // There definitely should be a string for this string offset, if there + // isn't, there is something wrong, return and error const char *strp_cstr = m_string_table.PeekCStr(pair.key); if (strp_cstr == NULL) { *hash_data_offset_ptr = UINT32_MAX; @@ -402,22 +400,21 @@ DWARFMappedHash::MemoryTable::GetHashDataForName( if (count > 0 && m_data.ValidOffsetForDataOfSize(*hash_data_offset_ptr, min_total_hash_data_size)) { - // We have at least one HashData entry, and we have enough - // data to parse at least "count" HashData entries. + // We have at least one HashData entry, and we have enough data to parse at + // least "count" HashData entries. // First make sure the entire C string matches... - const bool match = strcmp(name, strp_cstr) == 0; + const bool match = name == strp_cstr; if (!match && m_header.header_data.HashDataHasFixedByteSize()) { - // If the string doesn't match and we have fixed size data, - // we can just add the total byte size of all HashData objects - // to the hash data offset and be done... + // If the string doesn't match and we have fixed size data, we can just + // add the total byte size of all HashData objects to the hash data + // offset and be done... *hash_data_offset_ptr += min_total_hash_data_size; } else { - // If the string does match, or we don't have fixed size data - // then we need to read the hash data as a stream. If the - // string matches we also append all HashData objects to the - // value array. + // If the string does match, or we don't have fixed size data then we + // need to read the hash data as a stream. If the string matches we also + // append all HashData objects to the value array. for (uint32_t i = 0; i < count; ++i) { DIEInfo die_info; if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) { @@ -431,16 +428,15 @@ DWARFMappedHash::MemoryTable::GetHashDataForName( } } } - // Return the correct response depending on if the string matched - // or not... + // Return the correct response depending on if the string matched or not... if (match) return eResultKeyMatch; // The key (cstring) matches and we have lookup // results! else return eResultKeyMismatch; // The key doesn't match, this function will // get called - // again for the next key/value or the key terminator - // which in our case is a zero .debug_str offset. + // again for the next key/value or the key terminator which in our case is + // a zero .debug_str offset. } else { *hash_data_offset_ptr = UINT32_MAX; return eResultError; @@ -452,13 +448,13 @@ DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression( const lldb_private::RegularExpression ®ex, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const { pair.key = m_data.GetU32(hash_data_offset_ptr); - // If the key is zero, this terminates our chain of HashData objects - // for this hash value. + // If the key is zero, this terminates our chain of HashData objects for this + // hash value. if (pair.key == 0) return eResultEndOfHashData; - // There definitely should be a string for this string offset, if - // there isn't, there is something wrong, return and error + // There definitely should be a string for this string offset, if there + // isn't, there is something wrong, return and error const char *strp_cstr = m_string_table.PeekCStr(pair.key); if (strp_cstr == NULL) return eResultError; @@ -472,15 +468,14 @@ DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression( const bool match = regex.Execute(llvm::StringRef(strp_cstr)); if (!match && m_header.header_data.HashDataHasFixedByteSize()) { - // If the regex doesn't match and we have fixed size data, - // we can just add the total byte size of all HashData objects - // to the hash data offset and be done... + // If the regex doesn't match and we have fixed size data, we can just + // add the total byte size of all HashData objects to the hash data + // offset and be done... *hash_data_offset_ptr += min_total_hash_data_size; } else { - // If the string does match, or we don't have fixed size data - // then we need to read the hash data as a stream. If the - // string matches we also append all HashData objects to the - // value array. + // If the string does match, or we don't have fixed size data then we + // need to read the hash data as a stream. If the string matches we also + // append all HashData objects to the value array. for (uint32_t i = 0; i < count; ++i) { DIEInfo die_info; if (m_header.Read(m_data, hash_data_offset_ptr, die_info)) { @@ -494,16 +489,15 @@ DWARFMappedHash::MemoryTable::AppendHashDataForRegularExpression( } } } - // Return the correct response depending on if the string matched - // or not... + // Return the correct response depending on if the string matched or not... if (match) return eResultKeyMatch; // The key (cstring) matches and we have lookup // results! else return eResultKeyMismatch; // The key doesn't match, this function will // get called - // again for the next key/value or the key terminator - // which in our case is a zero .debug_str offset. + // again for the next key/value or the key terminator which in our case is + // a zero .debug_str offset. } else { *hash_data_offset_ptr = UINT32_MAX; return eResultError; @@ -528,8 +522,7 @@ size_t DWARFMappedHash::MemoryTable::AppendAllDIEsThatMatchingRegex( switch (hash_result) { case eResultKeyMatch: case eResultKeyMismatch: - // Whether we matches or not, it doesn't matter, we - // keep looking. + // Whether we matches or not, it doesn't matter, we keep looking. break; case eResultEndOfHashData: @@ -552,8 +545,8 @@ size_t DWARFMappedHash::MemoryTable::AppendAllDIEsInRange( lldb::offset_t hash_data_offset = GetHashDataOffset(offset_idx); while (!done && hash_data_offset != UINT32_MAX) { KeyType key = m_data.GetU32(&hash_data_offset); - // If the key is zero, this terminates our chain of HashData objects - // for this hash value. + // If the key is zero, this terminates our chain of HashData objects for + // this hash value. if (key == 0) break; @@ -573,9 +566,9 @@ size_t DWARFMappedHash::MemoryTable::AppendAllDIEsInRange( return die_info_array.size(); } -size_t DWARFMappedHash::MemoryTable::FindByName(const char *name, +size_t DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name, DIEArray &die_offsets) { - if (!name || !name[0]) + if (name.empty()) return 0; DIEInfoArray die_info_array; @@ -584,7 +577,7 @@ size_t DWARFMappedHash::MemoryTable::FindByName(const char *name, return die_info_array.size(); } -size_t DWARFMappedHash::MemoryTable::FindByNameAndTag(const char *name, +size_t DWARFMappedHash::MemoryTable::FindByNameAndTag(llvm::StringRef name, const dw_tag_t tag, DIEArray &die_offsets) { DIEInfoArray die_info_array; @@ -594,8 +587,8 @@ size_t DWARFMappedHash::MemoryTable::FindByNameAndTag(const char *name, } size_t DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash( - const char *name, const dw_tag_t tag, const uint32_t qualified_name_hash, - DIEArray &die_offsets) { + llvm::StringRef name, const dw_tag_t tag, + const uint32_t qualified_name_hash, DIEArray &die_offsets) { DIEInfoArray die_info_array; if (FindByName(name, die_info_array)) DWARFMappedHash::ExtractDIEArray(die_info_array, tag, qualified_name_hash, @@ -604,22 +597,21 @@ size_t DWARFMappedHash::MemoryTable::FindByNameAndTagAndQualifiedNameHash( } size_t DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName( - const char *name, DIEArray &die_offsets, bool must_be_implementation) { + llvm::StringRef name, DIEArray &die_offsets, bool must_be_implementation) { DIEInfoArray die_info_array; if (FindByName(name, die_info_array)) { if (must_be_implementation && GetHeader().header_data.ContainsAtom(eAtomTypeTypeFlags)) { - // If we have two atoms, then we have the DIE offset and - // the type flags so we can find the objective C class - // efficiently. + // If we have two atoms, then we have the DIE offset and the type flags + // so we can find the objective C class efficiently. DWARFMappedHash::ExtractTypesFromDIEArray(die_info_array, UINT32_MAX, eTypeFlagClassIsImplementation, die_offsets); } else { - // We don't only want the one true definition, so try and see - // what we can find, and only return class or struct DIEs. - // If we do have the full implementation, then return it alone, - // else return all possible matches. + // We don't only want the one true definition, so try and see what we can + // find, and only return class or struct DIEs. If we do have the full + // implementation, then return it alone, else return all possible + // matches. const bool return_implementation_only_if_available = true; DWARFMappedHash::ExtractClassOrStructDIEArray( die_info_array, return_implementation_only_if_available, die_offsets); @@ -628,9 +620,9 @@ size_t DWARFMappedHash::MemoryTable::FindCompleteObjCClassByName( return die_offsets.size(); } -size_t DWARFMappedHash::MemoryTable::FindByName(const char *name, +size_t DWARFMappedHash::MemoryTable::FindByName(llvm::StringRef name, DIEInfoArray &die_info_array) { - if (!name || !name[0]) + if (name.empty()) return 0; Pair kv_pair; diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h index 959517529e52..17600df2edd4 100644 --- a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h +++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -21,10 +21,6 @@ #include "DWARFFormValue.h" #include "NameToDIE.h" -class SymbolFileDWARF; -class DWARFCompileUnit; -class DWARFDebugInfoEntry; - class DWARFMappedHash { public: enum AtomType : uint16_t { @@ -136,17 +132,17 @@ public: const uint32_t die_offset_end, DIEInfoArray &die_info_array) const; - size_t FindByName(const char *name, DIEArray &die_offsets); + size_t FindByName(llvm::StringRef name, DIEArray &die_offsets); - size_t FindByNameAndTag(const char *name, const dw_tag_t tag, + size_t FindByNameAndTag(llvm::StringRef name, const dw_tag_t tag, DIEArray &die_offsets); - size_t - FindByNameAndTagAndQualifiedNameHash(const char *name, const dw_tag_t tag, - const uint32_t qualified_name_hash, - DIEArray &die_offsets); + size_t FindByNameAndTagAndQualifiedNameHash( + llvm::StringRef name, const dw_tag_t tag, + const uint32_t qualified_name_hash, DIEArray &die_offsets); - size_t FindCompleteObjCClassByName(const char *name, DIEArray &die_offsets, + size_t FindCompleteObjCClassByName(llvm::StringRef name, + DIEArray &die_offsets, bool must_be_implementation); protected: @@ -154,14 +150,14 @@ public: const lldb_private::RegularExpression ®ex, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const; - size_t FindByName(const char *name, DIEInfoArray &die_info_array); + size_t FindByName(llvm::StringRef name, DIEInfoArray &die_info_array); - Result GetHashDataForName(const char *name, + Result GetHashDataForName(llvm::StringRef name, lldb::offset_t *hash_data_offset_ptr, Pair &pair) const override; - const lldb_private::DWARFDataExtractor &m_data; - const lldb_private::DWARFDataExtractor &m_string_table; + lldb_private::DWARFDataExtractor m_data; + lldb_private::DWARFDataExtractor m_string_table; std::string m_name; }; diff --git a/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp new file mode 100644 index 000000000000..6438f02fe8ec --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -0,0 +1,488 @@ +//===-- ManualDWARFIndex.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h" +#include "Plugins/Language/ObjC/ObjCLanguage.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" +#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" +#include "lldb/Core/Module.h" +#include "lldb/Host/TaskPool.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/Timer.h" + +using namespace lldb_private; +using namespace lldb; + +void ManualDWARFIndex::Index() { + if (!m_debug_info) + return; + + DWARFDebugInfo &debug_info = *m_debug_info; + m_debug_info = nullptr; + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer(func_cat, "%p", static_cast<void *>(&debug_info)); + + std::vector<DWARFUnit *> units_to_index; + units_to_index.reserve(debug_info.GetNumCompileUnits()); + for (size_t U = 0; U < debug_info.GetNumCompileUnits(); ++U) { + DWARFUnit *unit = debug_info.GetCompileUnitAtIndex(U); + if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0) + units_to_index.push_back(unit); + } + if (units_to_index.empty()) + return; + + std::vector<IndexSet> sets(units_to_index.size()); + + //---------------------------------------------------------------------- + // Keep memory down by clearing DIEs for any compile units if indexing + // caused us to load the compile unit's DIEs. + //---------------------------------------------------------------------- + std::vector<llvm::Optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies( + units_to_index.size()); + auto parser_fn = [&](size_t cu_idx) { + IndexUnit(*units_to_index[cu_idx], sets[cu_idx]); + }; + + auto extract_fn = [&units_to_index, &clear_cu_dies](size_t cu_idx) { + clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped(); + }; + + // Create a task runner that extracts dies for each DWARF compile unit in a + // separate thread + //---------------------------------------------------------------------- + // First figure out which compile units didn't have their DIEs already + // parsed and remember this. If no DIEs were parsed prior to this index + // function call, we are going to want to clear the CU dies after we are + // done indexing to make sure we don't pull in all DWARF dies, but we need + // to wait until all compile units have been indexed in case a DIE in one + // compile unit refers to another and the indexes accesses those DIEs. + //---------------------------------------------------------------------- + TaskMapOverInt(0, units_to_index.size(), extract_fn); + + // Now create a task runner that can index each DWARF compile unit in a + // separate thread so we can index quickly. + + TaskMapOverInt(0, units_to_index.size(), parser_fn); + + auto finalize_fn = [this, &sets](NameToDIE(IndexSet::*index)) { + NameToDIE &result = m_set.*index; + for (auto &set : sets) + result.Append(set.*index); + result.Finalize(); + }; + + TaskPool::RunTasks([&]() { finalize_fn(&IndexSet::function_basenames); }, + [&]() { finalize_fn(&IndexSet::function_fullnames); }, + [&]() { finalize_fn(&IndexSet::function_methods); }, + [&]() { finalize_fn(&IndexSet::function_selectors); }, + [&]() { finalize_fn(&IndexSet::objc_class_selectors); }, + [&]() { finalize_fn(&IndexSet::globals); }, + [&]() { finalize_fn(&IndexSet::types); }, + [&]() { finalize_fn(&IndexSet::namespaces); }); +} + +void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, IndexSet &set) { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS); + + if (log) { + m_module.LogMessage( + log, "ManualDWARFIndex::IndexUnit for compile unit at .debug_info[0x%8.8x]", + unit.GetOffset()); + } + + const LanguageType cu_language = unit.GetLanguageType(); + DWARFFormValue::FixedFormSizes fixed_form_sizes = unit.GetFixedFormSizes(); + + IndexUnitImpl(unit, cu_language, fixed_form_sizes, unit.GetOffset(), set); + + SymbolFileDWARFDwo *dwo_symbol_file = unit.GetDwoSymbolFile(); + if (dwo_symbol_file && dwo_symbol_file->GetCompileUnit()) { + IndexUnitImpl(*dwo_symbol_file->GetCompileUnit(), cu_language, + fixed_form_sizes, unit.GetOffset(), set); + } +} + +void ManualDWARFIndex::IndexUnitImpl( + DWARFUnit &unit, const LanguageType cu_language, + const DWARFFormValue::FixedFormSizes &fixed_form_sizes, + const dw_offset_t cu_offset, IndexSet &set) { + for (const DWARFDebugInfoEntry &die : unit.dies()) { + const dw_tag_t tag = die.Tag(); + + switch (tag) { + case DW_TAG_array_type: + case DW_TAG_base_type: + case DW_TAG_class_type: + case DW_TAG_constant: + case DW_TAG_enumeration_type: + case DW_TAG_inlined_subroutine: + case DW_TAG_namespace: + case DW_TAG_string_type: + case DW_TAG_structure_type: + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: + case DW_TAG_typedef: + case DW_TAG_union_type: + case DW_TAG_unspecified_type: + case DW_TAG_variable: + break; + + default: + continue; + } + + DWARFAttributes attributes; + const char *name = NULL; + const char *mangled_cstr = NULL; + bool is_declaration = false; + // bool is_artificial = false; + bool has_address = false; + bool has_location_or_const_value = false; + bool is_global_or_static_variable = false; + + DWARFFormValue specification_die_form; + const size_t num_attributes = + die.GetAttributes(&unit, fixed_form_sizes, attributes); + if (num_attributes > 0) { + for (uint32_t i = 0; i < num_attributes; ++i) { + dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + switch (attr) { + case DW_AT_name: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + name = form_value.AsCString(); + break; + + case DW_AT_declaration: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + is_declaration = form_value.Unsigned() != 0; + break; + + // case DW_AT_artificial: + // if (attributes.ExtractFormValueAtIndex(i, + // form_value)) + // is_artificial = form_value.Unsigned() != 0; + // break; + + case DW_AT_MIPS_linkage_name: + case DW_AT_linkage_name: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + mangled_cstr = form_value.AsCString(); + break; + + case DW_AT_low_pc: + case DW_AT_high_pc: + case DW_AT_ranges: + has_address = true; + break; + + case DW_AT_entry_pc: + has_address = true; + break; + + case DW_AT_location: + case DW_AT_const_value: + has_location_or_const_value = true; + if (tag == DW_TAG_variable) { + const DWARFDebugInfoEntry *parent_die = die.GetParent(); + while (parent_die != NULL) { + switch (parent_die->Tag()) { + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + // Even if this is a function level static, we don't add it. We + // could theoretically add these if we wanted to by + // introspecting into the DW_AT_location and seeing if the + // location describes a hard coded address, but we don't want + // the performance penalty of that right now. + is_global_or_static_variable = false; + // if (attributes.ExtractFormValueAtIndex(dwarf, i, + // form_value)) { + // // If we have valid block data, then we have location + // // expression bytesthat are fixed (not a location list). + // const uint8_t *block_data = form_value.BlockData(); + // if (block_data) { + // uint32_t block_length = form_value.Unsigned(); + // if (block_length == 1 + + // attributes.CompileUnitAtIndex(i)->GetAddressByteSize()) { + // if (block_data[0] == DW_OP_addr) + // add_die = true; + // } + // } + // } + parent_die = NULL; // Terminate the while loop. + break; + + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + is_global_or_static_variable = true; + parent_die = NULL; // Terminate the while loop. + break; + + default: + parent_die = + parent_die->GetParent(); // Keep going in the while loop. + break; + } + } + } + break; + + case DW_AT_specification: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + specification_die_form = form_value; + break; + } + } + } + + switch (tag) { + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + if (has_address) { + if (name) { + ObjCLanguage::MethodName objc_method(name, true); + if (objc_method.IsValid(true)) { + ConstString objc_class_name_with_category( + objc_method.GetClassNameWithCategory()); + ConstString objc_selector_name(objc_method.GetSelector()); + ConstString objc_fullname_no_category_name( + objc_method.GetFullNameWithoutCategory(true)); + ConstString objc_class_name_no_category(objc_method.GetClassName()); + set.function_fullnames.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + if (objc_class_name_with_category) + set.objc_class_selectors.Insert( + objc_class_name_with_category, + DIERef(cu_offset, die.GetOffset())); + if (objc_class_name_no_category && + objc_class_name_no_category != objc_class_name_with_category) + set.objc_class_selectors.Insert( + objc_class_name_no_category, + DIERef(cu_offset, die.GetOffset())); + if (objc_selector_name) + set.function_selectors.Insert(objc_selector_name, + DIERef(cu_offset, die.GetOffset())); + if (objc_fullname_no_category_name) + set.function_fullnames.Insert(objc_fullname_no_category_name, + DIERef(cu_offset, die.GetOffset())); + } + // If we have a mangled name, then the DW_AT_name attribute is + // usually the method name without the class or any parameters + bool is_method = DWARFDIE(&unit, &die).IsMethod(); + + if (is_method) + set.function_methods.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + else + set.function_basenames.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + + if (!is_method && !mangled_cstr && !objc_method.IsValid(true)) + set.function_fullnames.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + } + if (mangled_cstr) { + // Make sure our mangled name isn't the same string table entry as + // our name. If it starts with '_', then it is ok, else compare the + // string to make sure it isn't the same and we don't end up with + // duplicate entries + if (name && name != mangled_cstr && + ((mangled_cstr[0] == '_') || + (::strcmp(name, mangled_cstr) != 0))) { + set.function_fullnames.Insert(ConstString(mangled_cstr), + DIERef(cu_offset, die.GetOffset())); + } + } + } + break; + + case DW_TAG_array_type: + case DW_TAG_base_type: + case DW_TAG_class_type: + case DW_TAG_constant: + case DW_TAG_enumeration_type: + case DW_TAG_string_type: + case DW_TAG_structure_type: + case DW_TAG_subroutine_type: + case DW_TAG_typedef: + case DW_TAG_union_type: + case DW_TAG_unspecified_type: + if (name && !is_declaration) + set.types.Insert(ConstString(name), DIERef(cu_offset, die.GetOffset())); + if (mangled_cstr && !is_declaration) + set.types.Insert(ConstString(mangled_cstr), + DIERef(cu_offset, die.GetOffset())); + break; + + case DW_TAG_namespace: + if (name) + set.namespaces.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + break; + + case DW_TAG_variable: + if (name && has_location_or_const_value && is_global_or_static_variable) { + set.globals.Insert(ConstString(name), + DIERef(cu_offset, die.GetOffset())); + // Be sure to include variables by their mangled and demangled names if + // they have any since a variable can have a basename "i", a mangled + // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name + // "(anonymous namespace)::i"... + + // Make sure our mangled name isn't the same string table entry as our + // name. If it starts with '_', then it is ok, else compare the string + // to make sure it isn't the same and we don't end up with duplicate + // entries + if (mangled_cstr && name != mangled_cstr && + ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0))) { + set.globals.Insert(ConstString(mangled_cstr), + DIERef(cu_offset, die.GetOffset())); + } + } + break; + + default: + continue; + } + } +} + +void ManualDWARFIndex::GetGlobalVariables(ConstString basename, DIEArray &offsets) { + Index(); + m_set.globals.Find(basename, offsets); +} + +void ManualDWARFIndex::GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) { + Index(); + m_set.globals.Find(regex, offsets); +} + +void ManualDWARFIndex::GetGlobalVariables(const DWARFUnit &cu, + DIEArray &offsets) { + Index(); + m_set.globals.FindAllEntriesForCompileUnit(cu.GetOffset(), offsets); +} + +void ManualDWARFIndex::GetObjCMethods(ConstString class_name, + DIEArray &offsets) { + Index(); + m_set.objc_class_selectors.Find(class_name, offsets); +} + +void ManualDWARFIndex::GetCompleteObjCClass(ConstString class_name, + bool must_be_implementation, + DIEArray &offsets) { + Index(); + m_set.types.Find(class_name, offsets); +} + +void ManualDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) { + Index(); + m_set.types.Find(name, offsets); +} + +void ManualDWARFIndex::GetTypes(const DWARFDeclContext &context, + DIEArray &offsets) { + Index(); + m_set.types.Find(ConstString(context[0].name), offsets); +} + +void ManualDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) { + Index(); + m_set.namespaces.Find(name, offsets); +} + +void ManualDWARFIndex::GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) { + Index(); + + 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 = info.GetDIE(die_ref); + if (!die) + continue; + if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) + dies.push_back(die); + } + } + if (name_type_mask & eFunctionNameTypeBase) { + DIEArray offsets; + m_set.function_basenames.Find(name, offsets); + for (const DIERef &die_ref: offsets) { + DWARFDIE die = info.GetDIE(die_ref); + if (!die) + continue; + if (SymbolFileDWARF::DIEInDeclContext(&parent_decl_ctx, die)) + dies.push_back(die); + } + offsets.clear(); + } + + if (name_type_mask & eFunctionNameTypeMethod && !parent_decl_ctx.IsValid()) { + DIEArray offsets; + m_set.function_methods.Find(name, offsets); + for (const DIERef &die_ref: offsets) { + if (DWARFDIE die = info.GetDIE(die_ref)) + dies.push_back(die); + } + } + + if (name_type_mask & eFunctionNameTypeSelector && + !parent_decl_ctx.IsValid()) { + DIEArray offsets; + m_set.function_selectors.Find(name, offsets); + for (const DIERef &die_ref: offsets) { + if (DWARFDIE die = info.GetDIE(die_ref)) + dies.push_back(die); + } + } +} + +void ManualDWARFIndex::GetFunctions(const RegularExpression ®ex, + DIEArray &offsets) { + Index(); + + m_set.function_basenames.Find(regex, offsets); + m_set.function_fullnames.Find(regex, offsets); +} + +void ManualDWARFIndex::Dump(Stream &s) { + s.Format("Manual DWARF index for ({0}) '{1:F}':", + m_module.GetArchitecture().GetArchitectureName(), + m_module.GetObjectFile()->GetFileSpec()); + s.Printf("\nFunction basenames:\n"); + m_set.function_basenames.Dump(&s); + s.Printf("\nFunction fullnames:\n"); + m_set.function_fullnames.Dump(&s); + s.Printf("\nFunction methods:\n"); + m_set.function_methods.Dump(&s); + s.Printf("\nFunction selectors:\n"); + m_set.function_selectors.Dump(&s); + s.Printf("\nObjective-C class selectors:\n"); + m_set.objc_class_selectors.Dump(&s); + s.Printf("\nGlobals and statics:\n"); + m_set.globals.Dump(&s); + s.Printf("\nTypes:\n"); + m_set.types.Dump(&s); + s.Printf("\nNamespaces:\n"); + m_set.namespaces.Dump(&s); +} diff --git a/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h new file mode 100644 index 000000000000..79ab1d95b380 --- /dev/null +++ b/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -0,0 +1,75 @@ +//===-- ManulaDWARFIndex.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_MANUALDWARFINDEX_H +#define LLDB_MANUALDWARFINDEX_H + +#include "Plugins/SymbolFile/DWARF/DWARFIndex.h" +#include "Plugins/SymbolFile/DWARF/NameToDIE.h" +#include "llvm/ADT/DenseSet.h" + +namespace lldb_private { +class ManualDWARFIndex : public DWARFIndex { +public: + ManualDWARFIndex(Module &module, DWARFDebugInfo *debug_info, + llvm::DenseSet<dw_offset_t> units_to_avoid = {}) + : DWARFIndex(module), m_debug_info(debug_info), + m_units_to_avoid(std::move(units_to_avoid)) {} + + void Preload() override { Index(); } + + void GetGlobalVariables(ConstString basename, DIEArray &offsets) override; + void GetGlobalVariables(const RegularExpression ®ex, + DIEArray &offsets) override; + void GetGlobalVariables(const DWARFUnit &cu, DIEArray &offsets) override; + void GetObjCMethods(ConstString class_name, DIEArray &offsets) override; + void GetCompleteObjCClass(ConstString class_name, bool must_be_implementation, + DIEArray &offsets) override; + void GetTypes(ConstString name, DIEArray &offsets) override; + void GetTypes(const DWARFDeclContext &context, DIEArray &offsets) override; + void GetNamespaces(ConstString name, DIEArray &offsets) override; + void GetFunctions(ConstString name, DWARFDebugInfo &info, + const CompilerDeclContext &parent_decl_ctx, + uint32_t name_type_mask, + std::vector<DWARFDIE> &dies) override; + void GetFunctions(const RegularExpression ®ex, DIEArray &offsets) override; + + void ReportInvalidDIEOffset(dw_offset_t offset, + llvm::StringRef name) override {} + void Dump(Stream &s) override; + +private: + struct IndexSet { + NameToDIE function_basenames; + NameToDIE function_fullnames; + NameToDIE function_methods; + NameToDIE function_selectors; + NameToDIE objc_class_selectors; + NameToDIE globals; + NameToDIE types; + NameToDIE namespaces; + }; + void Index(); + void IndexUnit(DWARFUnit &unit, IndexSet &set); + + static void + IndexUnitImpl(DWARFUnit &unit, const lldb::LanguageType cu_language, + const DWARFFormValue::FixedFormSizes &fixed_form_sizes, + const dw_offset_t cu_offset, IndexSet &set); + + /// Non-null value means we haven't built the index yet. + DWARFDebugInfo *m_debug_info; + /// Which dwarf units should we skip while building the index. + llvm::DenseSet<dw_offset_t> m_units_to_avoid; + + IndexSet m_set; +}; +} // namespace lldb_private + +#endif // LLDB_MANUALDWARFINDEX_H diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp index c97680eda0fe..c8d6bba16976 100644 --- a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp +++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp @@ -14,7 +14,6 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" -#include "DWARFCompileUnit.h" #include "DWARFDebugInfo.h" #include "DWARFDebugInfoEntry.h" #include "SymbolFileDWARF.h" diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index f149ec354f08..ac320ac52b08 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -27,6 +27,7 @@ #include "lldb/Utility/Timer.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" @@ -49,27 +50,24 @@ #include "lldb/Symbol/TypeSystem.h" #include "lldb/Symbol/VariableList.h" -#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" -#include "Plugins/Language/ObjC/ObjCLanguage.h" - #include "lldb/Target/Language.h" -#include "lldb/Host/TaskPool.h" - +#include "AppleDWARFIndex.h" #include "DWARFASTParser.h" #include "DWARFASTParserClang.h" -#include "DWARFCompileUnit.h" #include "DWARFDIECollection.h" #include "DWARFDebugAbbrev.h" #include "DWARFDebugAranges.h" #include "DWARFDebugInfo.h" #include "DWARFDebugLine.h" #include "DWARFDebugMacro.h" -#include "DWARFDebugPubnames.h" #include "DWARFDebugRanges.h" #include "DWARFDeclContext.h" #include "DWARFFormValue.h" +#include "DWARFUnit.h" +#include "DebugNamesDWARFIndex.h" #include "LogChannelDWARF.h" +#include "ManualDWARFIndex.h" #include "SymbolFileDWARFDebugMap.h" #include "SymbolFileDWARFDwo.h" #include "SymbolFileDWARFDwp.h" @@ -115,11 +113,20 @@ namespace { PropertyDefinition g_properties[] = { {"comp-dir-symlink-paths", OptionValue::eTypeFileSpecList, true, 0, nullptr, - nullptr, "If the DW_AT_comp_dir matches any of these paths the symbolic " - "links will be resolved at DWARF parse time."}, - {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; + nullptr, + "If the DW_AT_comp_dir matches any of these paths the symbolic " + "links will be resolved at DWARF parse time."}, + {"ignore-file-indexes", OptionValue::eTypeBoolean, true, 0, nullptr, + nullptr, + "Ignore indexes present in the object files and always index DWARF " + "manually."}, + {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}, +}; -enum { ePropertySymLinkPaths }; +enum { + ePropertySymLinkPaths, + ePropertyIgnoreIndexes, +}; class PluginProperties : public Properties { public: @@ -139,6 +146,11 @@ public: assert(option_value); return option_value->GetCurrentValue(); } + + bool IgnoreFileIndexes() const { + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, ePropertyIgnoreIndexes, false); + } }; typedef std::shared_ptr<PluginProperties> SymbolFileDWARFPropertiesSP; @@ -165,8 +177,8 @@ static const char *removeHostnameFromPathname(const char *path_from_dwarf) { return path_from_dwarf; } - // check whether we have a windows path, and so the first character - // is a drive-letter not a hostname. + // check whether we have a windows path, and so the first character is a + // drive-letter not a hostname. if (colon_pos == path_from_dwarf + 1 && isalpha(*path_from_dwarf) && strlen(path_from_dwarf) > 2 && '\\' == path_from_dwarf[2]) { return path_from_dwarf; @@ -175,41 +187,42 @@ static const char *removeHostnameFromPathname(const char *path_from_dwarf) { return colon_pos + 1; } -static const char *resolveCompDir(const char *path_from_dwarf) { +static FileSpec resolveCompDir(const char *path_from_dwarf) { if (!path_from_dwarf) - return nullptr; + return FileSpec(); // DWARF2/3 suggests the form hostname:pathname for compilation directory. // Remove the host part if present. const char *local_path = removeHostnameFromPathname(path_from_dwarf); if (!local_path) - return nullptr; + return FileSpec(); bool is_symlink = false; - FileSpec local_path_spec(local_path, false); + // Always normalize our compile unit directory to get rid of redundant + // slashes and other path anomalies before we use it for path prepending + FileSpec local_spec(local_path, false); const auto &file_specs = GetGlobalPluginProperties()->GetSymLinkPaths(); for (size_t i = 0; i < file_specs.GetSize() && !is_symlink; ++i) is_symlink = FileSpec::Equal(file_specs.GetFileSpecAtIndex(i), - local_path_spec, true); + local_spec, true); if (!is_symlink) - return local_path; + return local_spec; namespace fs = llvm::sys::fs; - if (fs::get_file_type(local_path_spec.GetPath(), false) != + if (fs::get_file_type(local_spec.GetPath(), false) != fs::file_type::symlink_file) - return local_path; + return local_spec; - FileSpec resolved_local_path_spec; - const auto error = - FileSystem::Readlink(local_path_spec, resolved_local_path_spec); + FileSpec resolved_symlink; + const auto error = FileSystem::Readlink(local_spec, resolved_symlink); if (error.Success()) - return resolved_local_path_spec.GetCString(); + return resolved_symlink; - return nullptr; + return local_spec; } -DWARFCompileUnit *SymbolFileDWARF::GetBaseCompileUnit() { +DWARFUnit *SymbolFileDWARF::GetBaseCompileUnit() { return nullptr; } @@ -334,7 +347,7 @@ size_t SymbolFileDWARF::GetTypes(SymbolContextScope *sc_scope, TypeSet type_set; CompileUnit *comp_unit = NULL; - DWARFCompileUnit *dwarf_cu = NULL; + DWARFUnit *dwarf_cu = NULL; if (sc_scope) comp_unit = sc_scope->CalculateSymbolContextCompileUnit(); @@ -382,6 +395,7 @@ SymbolFileDWARF::GetParentSymbolContextDIE(const DWARFDIE &child_die) { switch (tag) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: case DW_TAG_subprogram: case DW_TAG_inlined_subroutine: case DW_TAG_lexical_block: @@ -392,20 +406,16 @@ SymbolFileDWARF::GetParentSymbolContextDIE(const DWARFDIE &child_die) { } SymbolFileDWARF::SymbolFileDWARF(ObjectFile *objfile) - : SymbolFile(objfile), UserID(0), // Used by SymbolFileDWARFDebugMap to when - // this class parses .o files to contain - // the .o file index/ID + : SymbolFile(objfile), UserID(uint64_t(DW_INVALID_OFFSET) + << 32), // Used by SymbolFileDWARFDebugMap to + // when this class parses .o files to + // contain the .o file index/ID m_debug_map_module_wp(), m_debug_map_symfile(NULL), m_data_debug_abbrev(), m_data_debug_aranges(), m_data_debug_frame(), m_data_debug_info(), m_data_debug_line(), m_data_debug_macro(), m_data_debug_loc(), m_data_debug_ranges(), m_data_debug_str(), m_data_apple_names(), m_data_apple_types(), m_data_apple_namespaces(), m_abbr(), m_info(), - m_line(), m_apple_names_ap(), m_apple_types_ap(), m_apple_namespaces_ap(), - m_apple_objc_ap(), m_function_basename_index(), - m_function_fullname_index(), m_function_method_index(), - m_function_selector_index(), m_objc_class_selectors_index(), - m_global_index(), m_type_index(), m_namespace_index(), m_indexed(false), - m_using_apple_tables(false), m_fetched_external_modules(false), + m_line(), m_fetched_external_modules(false), m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate), m_ranges(), m_unique_ast_type_map() {} @@ -438,6 +448,7 @@ TypeSystem *SymbolFileDWARF::GetTypeSystemForLanguage(LanguageType language) { } void SymbolFileDWARF::InitializeObject() { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); ModuleSP module_sp(m_obj_file->GetModule()); if (module_sp) { const SectionList *section_list = module_sp->GetSectionList(); @@ -448,45 +459,38 @@ void SymbolFileDWARF::InitializeObject() { m_obj_file->ReadSectionData(section, m_dwarf_data); } - get_apple_names_data(); - if (m_data_apple_names.m_data.GetByteSize() > 0) { - m_apple_names_ap.reset(new DWARFMappedHash::MemoryTable( - m_data_apple_names.m_data, get_debug_str_data(), ".apple_names")); - if (m_apple_names_ap->IsValid()) - m_using_apple_tables = true; - else - m_apple_names_ap.reset(); - } - get_apple_types_data(); - if (m_data_apple_types.m_data.GetByteSize() > 0) { - m_apple_types_ap.reset(new DWARFMappedHash::MemoryTable( - m_data_apple_types.m_data, get_debug_str_data(), ".apple_types")); - if (m_apple_types_ap->IsValid()) - m_using_apple_tables = true; - else - m_apple_types_ap.reset(); - } + if (!GetGlobalPluginProperties()->IgnoreFileIndexes()) { + DWARFDataExtractor apple_names, apple_namespaces, apple_types, apple_objc; + LoadSectionData(eSectionTypeDWARFAppleNames, apple_names); + LoadSectionData(eSectionTypeDWARFAppleNamespaces, apple_namespaces); + LoadSectionData(eSectionTypeDWARFAppleTypes, apple_types); + LoadSectionData(eSectionTypeDWARFAppleObjC, apple_objc); - get_apple_namespaces_data(); - if (m_data_apple_namespaces.m_data.GetByteSize() > 0) { - m_apple_namespaces_ap.reset(new DWARFMappedHash::MemoryTable( - m_data_apple_namespaces.m_data, get_debug_str_data(), - ".apple_namespaces")); - if (m_apple_namespaces_ap->IsValid()) - m_using_apple_tables = true; - else - m_apple_namespaces_ap.reset(); - } + m_index = AppleDWARFIndex::Create( + *GetObjectFile()->GetModule(), apple_names, apple_namespaces, + apple_types, apple_objc, get_debug_str_data()); - get_apple_objc_data(); - if (m_data_apple_objc.m_data.GetByteSize() > 0) { - m_apple_objc_ap.reset(new DWARFMappedHash::MemoryTable( - m_data_apple_objc.m_data, get_debug_str_data(), ".apple_objc")); - if (m_apple_objc_ap->IsValid()) - m_using_apple_tables = true; - else - m_apple_objc_ap.reset(); + if (m_index) + return; + + DWARFDataExtractor debug_names; + LoadSectionData(eSectionTypeDWARFDebugNames, debug_names); + if (debug_names.GetByteSize() > 0) { + llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> index_or = + DebugNamesDWARFIndex::Create(*GetObjectFile()->GetModule(), + debug_names, get_debug_str_data(), + DebugInfo()); + if (index_or) { + m_index = std::move(*index_or); + return; + } + LLDB_LOG_ERROR(log, index_or.takeError(), + "Unable to read .debug_names data: {0}"); + } } + + m_index = llvm::make_unique<ManualDWARFIndex>(*GetObjectFile()->GetModule(), + DebugInfo()); } bool SymbolFileDWARF::SupportedVersion(uint16_t version) { @@ -501,15 +505,14 @@ uint32_t SymbolFileDWARF::CalculateAbilities() { if (section_list == NULL) return 0; - // On non Apple platforms we might have .debug_types debug info that - // is created by using "-fdebug-types-section". LLDB currently will try - // to load this debug info, but it causes crashes during debugging when - // types are missing since it doesn't know how to parse the info in - // the .debug_types type units. This causes all complex debug info - // types to be unresolved. Because this causes LLDB to crash and since - // it really doesn't provide a solid debuggiung experience, we should - // disable trying to debug this kind of DWARF until support gets - // added or deprecated. + // On non Apple platforms we might have .debug_types debug info that is + // created by using "-fdebug-types-section". LLDB currently will try to + // load this debug info, but it causes crashes during debugging when types + // are missing since it doesn't know how to parse the info in the + // .debug_types type units. This causes all complex debug info types to be + // unresolved. Because this causes LLDB to crash and since it really + // doesn't provide a solid debuggiung experience, we should disable trying + // to debug this kind of DWARF until support gets added or deprecated. if (section_list->FindSectionByName(ConstString(".debug_types"))) { m_obj_file->GetModule()->ReportWarning( "lldb doesn’t support .debug_types debug info"); @@ -561,10 +564,10 @@ uint32_t SymbolFileDWARF::CalculateAbilities() { if (symfile_dir_cstr) { if (strcasestr(symfile_dir_cstr, ".dsym")) { if (m_obj_file->GetType() == ObjectFile::eTypeDebugInfo) { - // We have a dSYM file that didn't have a any debug info. - // If the string table has a size of 1, then it was made from - // an executable with no debug info, or from an executable that - // was stripped. + // We have a dSYM file that didn't have a any debug info. If the + // string table has a size of 1, then it was made from an + // executable with no debug info, or from an executable that was + // stripped. section = section_list->FindSectionByType(eSectionTypeDWARFDebugStr, true) .get(); @@ -664,6 +667,10 @@ const DWARFDataExtractor &SymbolFileDWARF::get_debug_str_offsets_data() { m_data_debug_str_offsets); } +const DWARFDataExtractor &SymbolFileDWARF::get_debug_types_data() { + return GetCachedSectionData(eSectionTypeDWARFDebugTypes, m_data_debug_types); +} + const DWARFDataExtractor &SymbolFileDWARF::get_apple_names_data() { return GetCachedSectionData(eSectionTypeDWARFAppleNames, m_data_apple_names); } @@ -681,6 +688,11 @@ const DWARFDataExtractor &SymbolFileDWARF::get_apple_objc_data() { return GetCachedSectionData(eSectionTypeDWARFAppleObjC, m_data_apple_objc); } +const DWARFDataExtractor &SymbolFileDWARF::get_gnu_debugaltlink() { + return GetCachedSectionData(eSectionTypeDWARFGNUDebugAltLink, + m_data_gnu_debugaltlink); +} + DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (m_abbr.get() == NULL) { const DWARFDataExtractor &debug_abbrev_data = get_debug_abbrev_data(); @@ -716,17 +728,17 @@ const DWARFDebugInfo *SymbolFileDWARF::DebugInfo() const { return m_info.get(); } -DWARFCompileUnit * +DWARFUnit * SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { if (!comp_unit) return nullptr; DWARFDebugInfo *info = DebugInfo(); if (info) { - // Just a normal DWARF file whose user ID for the compile unit is - // the DWARF offset itself + // Just a normal DWARF file whose user ID for the compile unit is the DWARF + // offset itself - DWARFCompileUnit *dwarf_cu = + DWARFUnit *dwarf_cu = info->GetCompileUnit((dw_offset_t)comp_unit->GetID()); if (dwarf_cu && dwarf_cu->GetUserData() == NULL) dwarf_cu->SetUserData(comp_unit); @@ -753,7 +765,7 @@ const DWARFDebugRanges *SymbolFileDWARF::DebugRanges() const { return m_ranges.get(); } -lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, +lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx) { CompUnitSP cu_sp; if (dwarf_cu) { @@ -772,13 +784,13 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, } else { ModuleSP module_sp(m_obj_file->GetModule()); if (module_sp) { - const DWARFDIE cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE cu_die = dwarf_cu->DIE(); if (cu_die) { FileSpec cu_file_spec{cu_die.GetName(), false}; if (cu_file_spec) { // If we have a full path to the compile unit, we don't need to - // resolve - // the file. This can be expensive e.g. when the source files are + // resolve the file. This can be expensive e.g. when the source + // files are // NFS mounted. if (cu_file_spec.IsRelative()) { const char *cu_comp_dir{ @@ -789,10 +801,11 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, std::string remapped_file; if (module_sp->RemapSourceFile(cu_file_spec.GetPath(), remapped_file)) - cu_file_spec.SetFile(remapped_file, false); + cu_file_spec.SetFile(remapped_file, false, + FileSpec::Style::native); } - LanguageType cu_language = DWARFCompileUnit::LanguageTypeFromDWARF( + LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); bool is_optimized = dwarf_cu->GetIsOptimized(); @@ -801,10 +814,8 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, cu_language, is_optimized ? eLazyBoolYes : eLazyBoolNo)); if (cu_sp) { // If we just created a compile unit with an invalid file spec, - // try and get the - // first entry in the supports files from the line table as that - // should be the - // compile unit. + // try and get the first entry in the supports files from the + // line table as that should be the compile unit. if (!cu_file_spec) { cu_file_spec = cu_sp->GetSupportFiles().GetFileSpecAtIndex(1); if (cu_file_spec) { @@ -843,7 +854,7 @@ CompUnitSP SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) { CompUnitSP cu_sp; DWARFDebugInfo *info = DebugInfo(); if (info) { - DWARFCompileUnit *dwarf_cu = info->GetCompileUnitAtIndex(cu_idx); + DWARFUnit *dwarf_cu = info->GetCompileUnitAtIndex(cu_idx); if (dwarf_cu) cu_sp = ParseCompileUnit(dwarf_cu, cu_idx); } @@ -876,7 +887,7 @@ bool SymbolFileDWARF::FixupAddress(Address &addr) { lldb::LanguageType SymbolFileDWARF::ParseCompileUnitLanguage(const SymbolContext &sc) { assert(sc.comp_unit); - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) return dwarf_cu->GetLanguageType(); else @@ -886,7 +897,7 @@ SymbolFileDWARF::ParseCompileUnitLanguage(const SymbolContext &sc) { size_t SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) { assert(sc.comp_unit); size_t functions_added = 0; - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { DWARFDIECollection function_dies; const size_t num_functions = @@ -907,12 +918,12 @@ size_t SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) { bool SymbolFileDWARF::ParseCompileUnitSupportFiles( const SymbolContext &sc, FileSpecList &support_files) { assert(sc.comp_unit); - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { - const DWARFDIE cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFBaseDIE cu_die = dwarf_cu->GetUnitDIEOnly(); if (cu_die) { - const char *cu_comp_dir = resolveCompDir( + FileSpec cu_comp_dir = resolveCompDir( cu_die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr)); const dw_offset_t stmt_list = cu_die.GetAttributeValueAsUnsigned( DW_AT_stmt_list, DW_INVALID_OFFSET); @@ -931,7 +942,7 @@ bool SymbolFileDWARF::ParseCompileUnitSupportFiles( bool SymbolFileDWARF::ParseCompileUnitIsOptimized( const lldb_private::SymbolContext &sc) { - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) return dwarf_cu->GetIsOptimized(); return false; @@ -941,14 +952,14 @@ bool SymbolFileDWARF::ParseImportedModules( const lldb_private::SymbolContext &sc, std::vector<lldb_private::ConstString> &imported_modules) { assert(sc.comp_unit); - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { if (ClangModulesDeclVendor::LanguageSupportsClangModules( sc.comp_unit->GetLanguage())) { UpdateExternalModuleListIfNeeded(); if (sc.comp_unit) { - const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFDIE die = dwarf_cu->DIE(); if (die) { for (DWARFDIE child_die = die.GetFirstChild(); child_die; @@ -998,8 +1009,7 @@ static void ParseDWARFLineTableCallback(dw_offset_t offset, (ParseDWARFLineTableCallbackInfo *)userData; LineTable *line_table = info->line_table; - // If this is our first time here, we need to create a - // sequence container. + // If this is our first time here, we need to create a sequence container. if (!info->sequence_ap.get()) { info->sequence_ap.reset(line_table->CreateLineSequenceContainer()); assert(info->sequence_ap.get()); @@ -1022,9 +1032,9 @@ bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { if (sc.comp_unit->GetLineTable() != NULL) return true; - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { - const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly(); if (dwarf_cu_die) { const dw_offset_t cu_line_offset = dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_stmt_list, @@ -1063,10 +1073,10 @@ bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) { &info); SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); if (debug_map_symfile) { - // We have an object file that has a line table with addresses - // that are not linked. We need to link the line table and convert - // the addresses that are relative to the .o file into addresses - // for the main executable. + // We have an object file that has a line table with addresses that + // are not linked. We need to link the line table and convert the + // addresses that are relative to the .o file into addresses for + // the main executable. sc.comp_unit->SetLineTable( debug_map_symfile->LinkOSOLineTable(this, line_table_ap.get())); } else { @@ -1105,11 +1115,11 @@ SymbolFileDWARF::ParseDebugMacros(lldb::offset_t *offset) { bool SymbolFileDWARF::ParseCompileUnitDebugMacros(const SymbolContext &sc) { assert(sc.comp_unit); - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu == nullptr) return false; - const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly(); if (!dwarf_cu_die) return false; @@ -1142,9 +1152,9 @@ size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, case DW_TAG_lexical_block: { Block *block = NULL; if (tag == DW_TAG_subprogram) { - // Skip any DW_TAG_subprogram DIEs that are inside - // of a normal or inlined functions. These will be - // parsed on their own as separate entities. + // Skip any DW_TAG_subprogram DIEs that are inside of a normal or + // inlined functions. These will be parsed on their own as separate + // entities. if (depth > 0) break; @@ -1172,18 +1182,14 @@ size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, assert(subprogram_low_pc == LLDB_INVALID_ADDRESS); subprogram_low_pc = ranges.GetMinRangeBase(0); } else if (tag == DW_TAG_inlined_subroutine) { - // We get called here for inlined subroutines in two ways. - // The first time is when we are making the Function object - // for this inlined concrete instance. Since we're creating a top - // level block at + // We get called here for inlined subroutines in two ways. The first + // time is when we are making the Function object for this inlined + // concrete instance. Since we're creating a top level block at // here, the subprogram_low_pc will be LLDB_INVALID_ADDRESS. So we - // need to - // adjust the containing address. - // The second time is when we are parsing the blocks inside the - // function that contains - // the inlined concrete instance. Since these will be blocks inside - // the containing "real" - // function the offset will be for that function. + // need to adjust the containing address. The second time is when we + // are parsing the blocks inside the function that contains the + // inlined concrete instance. Since these will be blocks inside the + // containing "real" function the offset will be for that function. if (subprogram_low_pc == LLDB_INVALID_ADDRESS) { subprogram_low_pc = ranges.GetMinRangeBase(0); } @@ -1238,9 +1244,9 @@ size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc, break; } - // Only parse siblings of the block if we are not at depth zero. A depth - // of zero indicates we are currently parsing the top level - // DW_TAG_subprogram DIE + // Only parse siblings of the block if we are not at depth zero. A depth of + // zero indicates we are currently parsing the top level DW_TAG_subprogram + // DIE if (depth == 0) die.Clear(); @@ -1286,12 +1292,12 @@ void SymbolFileDWARF::ParseDeclsForContext(CompilerDeclContext decl_ctx) { } SymbolFileDWARF *SymbolFileDWARF::GetDWARFForUID(lldb::user_id_t uid) { - // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API - // we must make sure we use the correct DWARF file when resolving things. - // On MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple - // SymbolFileDWARF classes, one for each .o file. We can often end up - // with references to other DWARF objects and we must be ready to receive - // a "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF + // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we + // must make sure we use the correct DWARF file when resolving things. On + // MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple + // SymbolFileDWARF classes, one for each .o file. We can often end up with + // references to other DWARF objects and we must be ready to receive a + // "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF // instance. SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile(); if (debug_map) @@ -1302,12 +1308,12 @@ SymbolFileDWARF *SymbolFileDWARF::GetDWARFForUID(lldb::user_id_t uid) { DWARFDIE SymbolFileDWARF::GetDIEFromUID(lldb::user_id_t uid) { - // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API - // we must make sure we use the correct DWARF file when resolving things. - // On MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple - // SymbolFileDWARF classes, one for each .o file. We can often end up - // with references to other DWARF objects and we must be ready to receive - // a "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF + // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we + // must make sure we use the correct DWARF file when resolving things. On + // MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple + // SymbolFileDWARF classes, one for each .o file. We can often end up with + // references to other DWARF objects and we must be ready to receive a + // "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF // instance. SymbolFileDWARF *dwarf = GetDWARFForUID(uid); if (dwarf) @@ -1316,9 +1322,9 @@ SymbolFileDWARF::GetDIEFromUID(lldb::user_id_t uid) { } CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) { - // Anytime we have a lldb::user_id_t, we must get the DIE by - // calling SymbolFileDWARF::GetDIEFromUID(). See comments inside - // the SymbolFileDWARF::GetDIEFromUID() for details. + // Anytime we have a lldb::user_id_t, we must get the DIE by calling + // SymbolFileDWARF::GetDIEFromUID(). See comments inside the + // SymbolFileDWARF::GetDIEFromUID() for details. DWARFDIE die = GetDIEFromUID(type_uid); if (die) return die.GetDecl(); @@ -1327,9 +1333,9 @@ CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) { CompilerDeclContext SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) { - // Anytime we have a lldb::user_id_t, we must get the DIE by - // calling SymbolFileDWARF::GetDIEFromUID(). See comments inside - // the SymbolFileDWARF::GetDIEFromUID() for details. + // Anytime we have a lldb::user_id_t, we must get the DIE by calling + // SymbolFileDWARF::GetDIEFromUID(). See comments inside the + // SymbolFileDWARF::GetDIEFromUID() for details. DWARFDIE die = GetDIEFromUID(type_uid); if (die) return die.GetDeclContext(); @@ -1338,9 +1344,9 @@ SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) { CompilerDeclContext SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) { - // Anytime we have a lldb::user_id_t, we must get the DIE by - // calling SymbolFileDWARF::GetDIEFromUID(). See comments inside - // the SymbolFileDWARF::GetDIEFromUID() for details. + // Anytime we have a lldb::user_id_t, we must get the DIE by calling + // SymbolFileDWARF::GetDIEFromUID(). See comments inside the + // SymbolFileDWARF::GetDIEFromUID() for details. DWARFDIE die = GetDIEFromUID(type_uid); if (die) return die.GetContainingDeclContext(); @@ -1348,9 +1354,9 @@ SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) { } Type *SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) { - // Anytime we have a lldb::user_id_t, we must get the DIE by - // calling SymbolFileDWARF::GetDIEFromUID(). See comments inside - // the SymbolFileDWARF::GetDIEFromUID() for details. + // Anytime we have a lldb::user_id_t, we must get the DIE by calling + // SymbolFileDWARF::GetDIEFromUID(). See comments inside the + // SymbolFileDWARF::GetDIEFromUID() for details. DWARFDIE type_die = GetDIEFromUID(type_uid); if (type_die) return type_die.ResolveType(); @@ -1371,9 +1377,9 @@ Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die, log, "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s'", die.GetOffset(), die.GetTagAsCString(), die.GetName()); - // We might be coming in in the middle of a type tree (a class - // within a class, an enum within a class), so parse any needed - // parent DIEs before we get to this one... + // We might be coming in in the middle of a type tree (a class within a + // class, an enum within a class), so parse any needed parent DIEs before + // we get to this one... DWARFDIE decl_ctx_die = GetDeclContextDIEContainingDIE(die); if (decl_ctx_die) { if (log) { @@ -1401,8 +1407,8 @@ Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die, } // This function is used when SymbolFileDWARFDebugMap owns a bunch of -// SymbolFileDWARF objects to detect if this DWARF file is the one that -// can resolve a compiler_type. +// SymbolFileDWARF objects to detect if this DWARF file is the one that can +// resolve a compiler_type. bool SymbolFileDWARF::HasForwardDeclForClangType( const CompilerType &compiler_type) { CompilerType compiler_type_no_qualifiers = @@ -1448,12 +1454,10 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { DWARFDIE dwarf_die = GetDIE(die_it->getSecond()); if (dwarf_die) { - // Once we start resolving this type, remove it from the forward declaration - // map in case anyone child members or other types require this type to get - // resolved. - // The type will get resolved when all of the calls to - // SymbolFileDWARF::ResolveClangOpaqueTypeDefinition - // are done. + // Once we start resolving this type, remove it from the forward + // declaration map in case anyone child members or other types require this + // type to get resolved. The type will get resolved when all of the calls + // to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition are done. GetForwardDeclClangTypeToDie().erase(die_it); Type *type = GetDIEToType().lookup(dwarf_die.GetDIE()); @@ -1494,12 +1498,12 @@ Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die, } CompileUnit * -SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit *dwarf_cu, +SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx) { // Check if the symbol vendor already knows about this compile unit? if (dwarf_cu->GetUserData() == NULL) { - // The symbol vendor doesn't know about this compile unit, we - // need to parse and add it to the symbol vendor object. + // The symbol vendor doesn't know about this compile unit, we need to parse + // and add it to the symbol vendor object. return ParseCompileUnit(dwarf_cu, cu_idx).get(); } return (CompileUnit *)dwarf_cu->GetUserData(); @@ -1508,15 +1512,7 @@ SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit *dwarf_cu, size_t SymbolFileDWARF::GetObjCMethodDIEOffsets(ConstString class_name, DIEArray &method_die_offsets) { method_die_offsets.clear(); - if (m_using_apple_tables) { - if (m_apple_objc_ap.get()) - m_apple_objc_ap->FindByName(class_name.GetCString(), method_die_offsets); - } else { - if (!m_indexed) - Index(); - - m_objc_class_selectors_index.Find(class_name, method_die_offsets); - } + m_index->GetObjCMethods(class_name, method_die_offsets); return method_die_offsets.size(); } @@ -1560,9 +1556,9 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { std::unique_ptr<SymbolFileDWARFDwo> SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( - DWARFCompileUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) { + DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) { // If we are using a dSYM file, we never want the standard DWO files since - // the -gmodule support uses the same DWO machanism to specify full debug + // the -gmodules support uses the same DWO machanism to specify full debug // info files for modules. if (GetDebugMapSymfile()) return nullptr; @@ -1589,7 +1585,7 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( if (!comp_dir) return nullptr; - dwo_file.SetFile(comp_dir, true); + dwo_file.SetFile(comp_dir, true, FileSpec::Style::native); dwo_file.AppendPathComponent(dwo_name); } @@ -1617,9 +1613,9 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); + DWARFUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly(); + const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); if (die && die.HasChildren() == false) { const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr); @@ -1632,35 +1628,35 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() { die.GetAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); if (dwo_path) { ModuleSpec dwo_module_spec; - dwo_module_spec.GetFileSpec().SetFile(dwo_path, false); + dwo_module_spec.GetFileSpec().SetFile(dwo_path, false, + 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, true); + dwo_module_spec.GetFileSpec().SetFile(comp_dir, true, + FileSpec::Style::native); dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path); } } dwo_module_spec.GetArchitecture() = m_obj_file->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. + // 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_obj_file->GetFileSpec() .GetFileNameExtension() - .GetStringRef() == "dwo" && + .GetStringRef() == ".dwo" && llvm::StringRef(m_obj_file->GetFileSpec().GetPath()) .endswith(dwo_module_spec.GetFileSpec().GetPath())) { continue; @@ -1751,13 +1747,11 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, const dw_offset_t cu_offset = debug_info->GetCompileUnitAranges().FindAddress(file_vm_addr); if (cu_offset == DW_INVALID_OFFSET) { - // Global variables are not in the compile unit address ranges. The only - // way to - // currently find global variables is to iterate over the - // .debug_pubnames or the - // __apple_names table and find all items in there that point to - // DW_TAG_variable - // DIEs and then find the address that matches. + // Global variables are not in the compile unit address ranges. The + // only way to currently find global variables is to iterate over the + // .debug_pubnames or the __apple_names table and find all items in + // there that point to DW_TAG_variable DIEs and then find the address + // that matches. if (resolve_scope & eSymbolContextVariable) { GlobalVariableMap &map = GetGlobalAranges(); const GlobalVariableMap::Entry *entry = @@ -1774,7 +1768,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, } } else { uint32_t cu_idx = DW_INVALID_INDEX; - DWARFCompileUnit *dwarf_cu = + DWARFUnit *dwarf_cu = debug_info->GetCompileUnit(cu_offset, &cu_idx); if (dwarf_cu) { sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx); @@ -1825,13 +1819,10 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, LineTable *line_table = sc.comp_unit->GetLineTable(); if (line_table != NULL) { // And address that makes it into this function should be in - // terms - // of this debug file if there is no debug map, or it will be an - // address in the .o file which needs to be fixed up to be in - // terms - // of the debug map executable. Either way, calling - // FixupAddress() - // will work for us. + // terms of this debug file if there is no debug map, or it + // will be an address in the .o file which needs to be fixed up + // to be in terms of the debug map executable. Either way, + // calling FixupAddress() will work for us. Address exe_so_addr(so_addr); if (FixupAddress(exe_so_addr)) { if (line_table->FindLineEntryByAddress(exe_so_addr, @@ -1845,11 +1836,11 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, if (force_check_line_table && !(resolved & eSymbolContextLineEntry)) { // We might have had a compile unit that had discontiguous - // address ranges where the gaps are symbols that don't have - // any debug info. Discontiguous compile unit address ranges - // should only happen when there aren't other functions from - // other compile units in these gaps. This helps keep the size - // of the aranges down. + // address ranges where the gaps are symbols that don't have any + // debug info. Discontiguous compile unit address ranges should + // only happen when there aren't other functions from other + // compile units in these gaps. This helps keep the size of the + // aranges down. sc.comp_unit = NULL; resolved &= ~eSymbolContextCompUnit; } @@ -1876,7 +1867,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, DWARFDebugInfo *debug_info = DebugInfo(); if (debug_info) { uint32_t cu_idx; - DWARFCompileUnit *dwarf_cu = NULL; + DWARFUnit *dwarf_cu = NULL; for (cu_idx = 0; (dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; @@ -1891,8 +1882,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, if (sc.comp_unit) { uint32_t file_idx = UINT32_MAX; - // If we are looking for inline functions only and we don't - // find it in the support files, we are done. + // If we are looking for inline functions only and we don't find it + // in the support files, we are done. if (check_inlines) { file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex( 1, file_spec, true); @@ -1904,8 +1895,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, LineTable *line_table = sc.comp_unit->GetLineTable(); if (line_table != NULL && line != 0) { - // We will have already looked up the file index if - // we are searching for inline entries. + // We will have already looked up the file index if we are + // searching for inline entries. if (!check_inlines) file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex( 1, file_spec, true); @@ -1962,16 +1953,14 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, } } else if (file_spec_matches_cu_file_spec && !check_inlines) { // only append the context if we aren't looking for inline call - // sites - // by file and line and if the file spec matches that of the - // compile unit + // sites by file and line and if the file spec matches that of + // the compile unit sc_list.Append(sc); } } else if (file_spec_matches_cu_file_spec && !check_inlines) { // only append the context if we aren't looking for inline call - // sites - // by file and line and if the file spec matches that of the - // compile unit + // sites by file and line and if the file spec matches that of + // the compile unit sc_list.Append(sc); } @@ -1988,143 +1977,15 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, void SymbolFileDWARF::PreloadSymbols() { std::lock_guard<std::recursive_mutex> guard( GetObjectFile()->GetModule()->GetMutex()); - Index(); -} - -void SymbolFileDWARF::Index() { - if (m_indexed) - return; - m_indexed = true; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "SymbolFileDWARF::Index (%s)", - GetObjectFile()->GetFileSpec().GetFilename().AsCString("<Unknown>")); - - DWARFDebugInfo *debug_info = DebugInfo(); - if (debug_info) { - const uint32_t num_compile_units = GetNumCompileUnits(); - if (num_compile_units == 0) - return; - - std::vector<NameToDIE> function_basename_index(num_compile_units); - std::vector<NameToDIE> function_fullname_index(num_compile_units); - std::vector<NameToDIE> function_method_index(num_compile_units); - std::vector<NameToDIE> function_selector_index(num_compile_units); - std::vector<NameToDIE> objc_class_selectors_index(num_compile_units); - std::vector<NameToDIE> global_index(num_compile_units); - std::vector<NameToDIE> type_index(num_compile_units); - std::vector<NameToDIE> namespace_index(num_compile_units); - - // std::vector<bool> might be implemented using bit test-and-set, so use - // uint8_t instead. - std::vector<uint8_t> clear_cu_dies(num_compile_units, false); - auto parser_fn = [debug_info, &function_basename_index, - &function_fullname_index, &function_method_index, - &function_selector_index, &objc_class_selectors_index, - &global_index, &type_index, - &namespace_index](size_t cu_idx) { - DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - if (dwarf_cu) { - dwarf_cu->Index( - function_basename_index[cu_idx], function_fullname_index[cu_idx], - function_method_index[cu_idx], function_selector_index[cu_idx], - objc_class_selectors_index[cu_idx], global_index[cu_idx], - type_index[cu_idx], namespace_index[cu_idx]); - } - }; - - auto extract_fn = [debug_info, &clear_cu_dies](size_t cu_idx) { - DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); - if (dwarf_cu) { - // dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the - // DIEs for a compile unit have already been parsed. - if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1) - clear_cu_dies[cu_idx] = true; - } - }; - - // Create a task runner that extracts dies for each DWARF compile unit in a - // separate thread - //---------------------------------------------------------------------- - // First figure out which compile units didn't have their DIEs already - // parsed and remember this. If no DIEs were parsed prior to this index - // function call, we are going to want to clear the CU dies after we - // are done indexing to make sure we don't pull in all DWARF dies, but - // we need to wait until all compile units have been indexed in case - // a DIE in one compile unit refers to another and the indexes accesses - // those DIEs. - //---------------------------------------------------------------------- - TaskMapOverInt(0, num_compile_units, extract_fn); - - // Now create a task runner that can index each DWARF compile unit in a - // separate - // thread so we can index quickly. - - TaskMapOverInt(0, num_compile_units, parser_fn); - - auto finalize_fn = [](NameToDIE &index, std::vector<NameToDIE> &srcs) { - for (auto &src : srcs) - index.Append(src); - index.Finalize(); - }; - - TaskPool::RunTasks( - [&]() { - finalize_fn(m_function_basename_index, function_basename_index); - }, - [&]() { - finalize_fn(m_function_fullname_index, function_fullname_index); - }, - [&]() { finalize_fn(m_function_method_index, function_method_index); }, - [&]() { - finalize_fn(m_function_selector_index, function_selector_index); - }, - [&]() { - finalize_fn(m_objc_class_selectors_index, objc_class_selectors_index); - }, - [&]() { finalize_fn(m_global_index, global_index); }, - [&]() { finalize_fn(m_type_index, type_index); }, - [&]() { finalize_fn(m_namespace_index, namespace_index); }); - - //---------------------------------------------------------------------- - // Keep memory down by clearing DIEs for any compile units if indexing - // caused us to load the compile unit's DIEs. - //---------------------------------------------------------------------- - for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - if (clear_cu_dies[cu_idx]) - debug_info->GetCompileUnitAtIndex(cu_idx)->ClearDIEs(true); - } - -#if defined(ENABLE_DEBUG_PRINTF) - StreamFile s(stdout, false); - s.Printf("DWARF index for '%s':", - GetObjectFile()->GetFileSpec().GetPath().c_str()); - s.Printf("\nFunction basenames:\n"); - m_function_basename_index.Dump(&s); - s.Printf("\nFunction fullnames:\n"); - m_function_fullname_index.Dump(&s); - s.Printf("\nFunction methods:\n"); - m_function_method_index.Dump(&s); - s.Printf("\nFunction selectors:\n"); - m_function_selector_index.Dump(&s); - s.Printf("\nObjective C class selectors:\n"); - m_objc_class_selectors_index.Dump(&s); - s.Printf("\nGlobals and statics:\n"); - m_global_index.Dump(&s); - s.Printf("\nTypes:\n"); - m_type_index.Dump(&s); - s.Printf("\nNamespaces:\n"); - m_namespace_index.Dump(&s); -#endif - } + m_index->Preload(); } bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile( const lldb_private::CompilerDeclContext *decl_ctx) { if (decl_ctx == nullptr || !decl_ctx->IsValid()) { - // Invalid namespace decl which means we aren't matching only things - // in this symbol file, so return true to indicate it matches this - // symbol file. + // Invalid namespace decl which means we aren't matching only things in + // this symbol file, so return true to indicate it matches this symbol + // file. return true; } @@ -2146,14 +2007,15 @@ bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile( uint32_t SymbolFileDWARF::FindGlobalVariables( const ConstString &name, const CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, VariableList &variables) { + uint32_t max_matches, VariableList &variables) { Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) GetObjectFile()->GetModule()->LogMessage( - log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " - "parent_decl_ctx=%p, append=%u, max_matches=%u, variables)", - name.GetCString(), static_cast<const void *>(parent_decl_ctx), append, + log, + "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " + "parent_decl_ctx=%p, max_matches=%u, variables)", + name.GetCString(), static_cast<const void *>(parent_decl_ctx), max_matches); if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) @@ -2163,42 +2025,28 @@ uint32_t SymbolFileDWARF::FindGlobalVariables( if (info == NULL) return 0; - // If we aren't appending the results to this list, then clear the list - if (!append) - variables.Clear(); - - // Remember how many variables are in the list before we search in case - // we are appending the results to a variable list. + // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); - DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) { - const char *name_cstr = name.GetCString(); - llvm::StringRef basename; - llvm::StringRef context; - - if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context, - basename)) - basename = name_cstr; - - m_apple_names_ap->FindByName(basename.data(), die_offsets); - } - } else { - // Index the DWARF if we haven't already - if (!m_indexed) - Index(); + llvm::StringRef basename; + llvm::StringRef context; - m_global_index.Find(name, die_offsets); - } + if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name.GetCString(), + context, basename)) + basename = name.GetStringRef(); + DIEArray die_offsets; + m_index->GetGlobalVariables(ConstString(basename), die_offsets); const size_t num_die_matches = die_offsets.size(); if (num_die_matches) { SymbolContext sc; sc.module_sp = m_obj_file->GetModule(); assert(sc.module_sp); + // Loop invariant: Variables up to this index have been checked for context + // matches. + uint32_t pruned_idx = original_size; + bool done = false; for (size_t i = 0; i < num_die_matches && !done; ++i) { const DIERef &die_ref = die_offsets[i]; @@ -2229,18 +2077,21 @@ uint32_t SymbolFileDWARF::FindGlobalVariables( ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables); + while (pruned_idx < variables.GetSize()) { + VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx); + if (var_sp->GetName().GetStringRef().contains(name.GetStringRef())) + ++pruned_idx; + else + variables.RemoveVariableAtIndex(pruned_idx); + } if (variables.GetSize() - original_size >= max_matches) done = true; } break; } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + name.GetStringRef()); } } } @@ -2249,54 +2100,37 @@ uint32_t SymbolFileDWARF::FindGlobalVariables( const uint32_t num_matches = variables.GetSize() - original_size; if (log && num_matches > 0) { GetObjectFile()->GetModule()->LogMessage( - log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " - "parent_decl_ctx=%p, append=%u, max_matches=%u, variables) => %u", - name.GetCString(), static_cast<const void *>(parent_decl_ctx), append, + log, + "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", " + "parent_decl_ctx=%p, max_matches=%u, variables) => %u", + name.GetCString(), static_cast<const void *>(parent_decl_ctx), max_matches, num_matches); } return num_matches; } uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, VariableList &variables) { Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); if (log) { GetObjectFile()->GetModule()->LogMessage( - log, "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, " - "max_matches=%u, variables)", - regex.GetText().str().c_str(), append, max_matches); + log, + "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", " + "max_matches=%u, variables)", + regex.GetText().str().c_str(), max_matches); } DWARFDebugInfo *info = DebugInfo(); if (info == NULL) return 0; - // If we aren't appending the results to this list, then clear the list - if (!append) - variables.Clear(); - - // Remember how many variables are in the list before we search in case - // we are appending the results to a variable list. + // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) { - DWARFMappedHash::DIEInfoArray hash_data_array; - if (m_apple_names_ap->AppendAllDIEsThatMatchingRegex(regex, - hash_data_array)) - DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets); - } - } else { - // Index the DWARF if we haven't already - if (!m_indexed) - Index(); - - m_global_index.Find(regex, die_offsets); - } + m_index->GetGlobalVariables(regex, die_offsets); SymbolContext sc; sc.module_sp = m_obj_file->GetModule(); @@ -2315,14 +2149,8 @@ uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression ®ex, if (variables.GetSize() - original_size >= max_matches) break; - } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for regex '%s')\n", - die_ref.die_offset, regex.GetText().str().c_str()); - } - } + } else + m_index->ReportInvalidDIEOffset(die_ref.die_offset, regex.GetText()); } } @@ -2330,13 +2158,6 @@ uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression ®ex, return variables.GetSize() - original_size; } -bool SymbolFileDWARF::ResolveFunction(const DIERef &die_ref, - bool include_inlines, - SymbolContextList &sc_list) { - DWARFDIE die = DebugInfo()->GetDIE(die_ref); - return ResolveFunction(die, include_inlines, sc_list); -} - bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, bool include_inlines, SymbolContextList &sc_list) { @@ -2390,54 +2211,11 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die, return false; } -void SymbolFileDWARF::FindFunctions(const ConstString &name, - const NameToDIE &name_to_die, - bool include_inlines, - SymbolContextList &sc_list) { - DIEArray die_offsets; - if (name_to_die.Find(name, die_offsets)) { - ParseFunctions(die_offsets, include_inlines, sc_list); - } -} - -void SymbolFileDWARF::FindFunctions(const RegularExpression ®ex, - const NameToDIE &name_to_die, - bool include_inlines, - SymbolContextList &sc_list) { - DIEArray die_offsets; - if (name_to_die.Find(regex, die_offsets)) { - ParseFunctions(die_offsets, include_inlines, sc_list); - } -} - -void SymbolFileDWARF::FindFunctions( - const RegularExpression ®ex, - const DWARFMappedHash::MemoryTable &memory_table, bool include_inlines, - SymbolContextList &sc_list) { - DIEArray die_offsets; - DWARFMappedHash::DIEInfoArray hash_data_array; - if (memory_table.AppendAllDIEsThatMatchingRegex(regex, hash_data_array)) { - DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets); - ParseFunctions(die_offsets, include_inlines, sc_list); - } -} - -void SymbolFileDWARF::ParseFunctions(const DIEArray &die_offsets, - bool include_inlines, - SymbolContextList &sc_list) { - const size_t num_matches = die_offsets.size(); - if (num_matches) { - for (size_t i = 0; i < num_matches; ++i) - ResolveFunction(die_offsets[i], include_inlines, sc_list); - } -} - bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext *decl_ctx, const DWARFDIE &die) { // If we have no parent decl context to match this DIE matches, and if the - // parent - // decl context isn't valid, we aren't trying to look for any particular decl - // context so any die matches. + // parent decl context isn't valid, we aren't trying to look for any + // particular decl context so any die matches. if (decl_ctx == nullptr || !decl_ctx->IsValid()) return true; @@ -2486,10 +2264,8 @@ SymbolFileDWARF::FindFunctions(const ConstString &name, if (name.IsEmpty()) return 0; - // Remember how many sc_list are in the list before we search in case - // we are appending the results to a variable list. - - const char *name_cstr = name.GetCString(); + // Remember how many sc_list are in the list before we search in case we are + // appending the results to a variable list. const uint32_t original_size = sc_list.GetSize(); @@ -2497,228 +2273,17 @@ SymbolFileDWARF::FindFunctions(const ConstString &name, if (info == NULL) return 0; - std::set<const DWARFDebugInfoEntry *> resolved_dies; - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) { - - DIEArray die_offsets; - - uint32_t num_matches = 0; - - if (name_type_mask & eFunctionNameTypeFull) { - // If they asked for the full name, match what they typed. At some - // point we may - // want to canonicalize this (strip double spaces, etc. For now, we - // just add all the - // dies that we find by exact match. - num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets); - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = info->GetDIE(die_ref); - if (die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (ResolveFunction(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } else { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for '%s')", - die_ref.die_offset, name_cstr); - } - } - } - - if (name_type_mask & eFunctionNameTypeSelector) { - if (parent_decl_ctx && parent_decl_ctx->IsValid()) - return 0; // no selectors in namespaces - - num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets); - // Now make sure these are actually ObjC methods. In this case we can - // simply look up the name, - // and if it is an ObjC method name, we're good. - - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = info->GetDIE(die_ref); - if (die) { - const char *die_name = die.GetName(); - if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) { - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (ResolveFunction(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } else { - GetObjectFile()->GetModule()->ReportError( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for '%s')", - die_ref.die_offset, name_cstr); - } - } - die_offsets.clear(); - } - - if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) || - name_type_mask & eFunctionNameTypeBase) { - // The apple_names table stores just the "base name" of C++ methods in - // the table. So we have to - // extract the base name, look that up, and if there is any other - // information in the name we were - // passed in we have to post-filter based on that. - - // FIXME: Arrange the logic above so that we don't calculate the base - // name twice: - num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets); - - for (uint32_t i = 0; i < num_matches; i++) { - const DIERef &die_ref = die_offsets[i]; - DWARFDIE die = info->GetDIE(die_ref); - if (die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end() && - ResolveFunction(die, include_inlines, sc_list)) { - bool keep_die = true; - if ((name_type_mask & - (eFunctionNameTypeBase | eFunctionNameTypeMethod)) != - (eFunctionNameTypeBase | eFunctionNameTypeMethod)) { - // We are looking for either basenames or methods, so we need to - // trim out the ones we won't want by looking at the type - SymbolContext sc; - if (sc_list.GetLastContext(sc)) { - if (sc.block) { - // We have an inlined function - } else if (sc.function) { - Type *type = sc.function->GetType(); - - if (type) { - CompilerDeclContext decl_ctx = - GetDeclContextContainingUID(type->GetID()); - if (decl_ctx.IsStructUnionOrClass()) { - if (name_type_mask & eFunctionNameTypeBase) { - sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); - keep_die = false; - } - } else { - if (name_type_mask & eFunctionNameTypeMethod) { - sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1); - keep_die = false; - } - } - } else { - GetObjectFile()->GetModule()->ReportWarning( - "function at die offset 0x%8.8x had no function type", - die_ref.die_offset); - } - } - } - } - if (keep_die) - resolved_dies.insert(die.GetDIE()); - } - } else { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_names " - "accelerator table had bad die 0x%8.8x for '%s')", - die_ref.die_offset, name_cstr); - } - } - die_offsets.clear(); - } - } - } else { - - // Index the DWARF if we haven't already - if (!m_indexed) - Index(); - - if (name_type_mask & eFunctionNameTypeFull) { - FindFunctions(name, m_function_fullname_index, include_inlines, sc_list); - - // FIXME Temporary workaround for global/anonymous namespace - // functions debugging FreeBSD and Linux binaries. - // If we didn't find any functions in the global namespace try - // looking in the basename index but ignore any returned - // functions that have a namespace but keep functions which - // have an anonymous namespace - // TODO: The arch in the object file isn't correct for MSVC - // binaries on windows, we should find a way to make it - // correct and handle those symbols as well. - if (sc_list.GetSize() == original_size) { - ArchSpec arch; - if (!parent_decl_ctx && GetObjectFile()->GetArchitecture(arch) && - arch.GetTriple().isOSBinFormatELF()) { - SymbolContextList temp_sc_list; - FindFunctions(name, m_function_basename_index, include_inlines, - temp_sc_list); - SymbolContext sc; - for (uint32_t i = 0; i < temp_sc_list.GetSize(); i++) { - if (temp_sc_list.GetContextAtIndex(i, sc)) { - ConstString mangled_name = - sc.GetFunctionName(Mangled::ePreferMangled); - ConstString demangled_name = - sc.GetFunctionName(Mangled::ePreferDemangled); - // Mangled names on Linux and FreeBSD are of the form: - // _ZN18function_namespace13function_nameEv. - if (strncmp(mangled_name.GetCString(), "_ZN", 3) || - !strncmp(demangled_name.GetCString(), "(anonymous namespace)", - 21)) { - sc_list.Append(sc); - } - } - } - } - } - } - DIEArray die_offsets; - if (name_type_mask & eFunctionNameTypeBase) { - uint32_t num_base = m_function_basename_index.Find(name, die_offsets); - for (uint32_t i = 0; i < num_base; i++) { - DWARFDIE die = info->GetDIE(die_offsets[i]); - if (die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - continue; // The containing decl contexts don't match - - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (ResolveFunction(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } - die_offsets.clear(); - } - - if (name_type_mask & eFunctionNameTypeMethod) { - if (parent_decl_ctx && parent_decl_ctx->IsValid()) - return 0; // no methods in namespaces - - uint32_t num_base = m_function_method_index.Find(name, die_offsets); - { - for (uint32_t i = 0; i < num_base; i++) { - DWARFDIE die = info->GetDIE(die_offsets[i]); - if (die) { - // If we get to here, the die is good, and we should add it: - if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) { - if (ResolveFunction(die, include_inlines, sc_list)) - resolved_dies.insert(die.GetDIE()); - } - } - } - } - die_offsets.clear(); - } + llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies; + DIEArray offsets; + CompilerDeclContext empty_decl_ctx; + if (!parent_decl_ctx) + parent_decl_ctx = &empty_decl_ctx; - if ((name_type_mask & eFunctionNameTypeSelector) && - (!parent_decl_ctx || !parent_decl_ctx->IsValid())) { - FindFunctions(name, m_function_selector_index, include_inlines, sc_list); - } + std::vector<DWARFDIE> dies; + m_index->GetFunctions(name, *info, *parent_decl_ctx, name_type_mask, dies); + for (const DWARFDIE &die: dies) { + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); } // Return the number of variable that were appended to the list @@ -2755,21 +2320,26 @@ uint32_t SymbolFileDWARF::FindFunctions(const RegularExpression ®ex, if (!append) sc_list.Clear(); - // Remember how many sc_list are in the list before we search in case - // we are appending the results to a variable list. - uint32_t original_size = sc_list.GetSize(); + DWARFDebugInfo *info = DebugInfo(); + if (!info) + return 0; - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) - FindFunctions(regex, *m_apple_names_ap, include_inlines, sc_list); - } else { - // Index the DWARF if we haven't already - if (!m_indexed) - Index(); + // Remember how many sc_list are in the list before we search in case we are + // appending the results to a variable list. + uint32_t original_size = sc_list.GetSize(); - FindFunctions(regex, m_function_basename_index, include_inlines, sc_list); + DIEArray offsets; + m_index->GetFunctions(regex, offsets); - FindFunctions(regex, m_function_fullname_index, include_inlines, sc_list); + llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies; + for (DIERef ref : offsets) { + DWARFDIE die = info->GetDIE(ref); + if (!die) { + m_index->ReportInvalidDIEOffset(ref.die_offset, regex.GetText()); + continue; + } + if (resolved_dies.insert(die.GetDIE()).second) + ResolveFunction(die, include_inlines, sc_list); } // Return the number of variable that were appended to the list @@ -2785,7 +2355,7 @@ void SymbolFileDWARF::GetMangledNamesForFunction( num_comp_units = info->GetNumCompileUnits(); for (uint32_t i = 0; i < num_comp_units; i++) { - DWARFCompileUnit *cu = info->GetCompileUnitAtIndex(i); + DWARFUnit *cu = info->GetCompileUnitAtIndex(i); if (cu == nullptr) continue; @@ -2847,19 +2417,7 @@ uint32_t SymbolFileDWARF::FindTypes( return 0; DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_types_ap.get()) { - const char *name_cstr = name.GetCString(); - m_apple_types_ap->FindByName(name_cstr, die_offsets); - } - } else { - if (!m_indexed) - Index(); - - m_type_index.Find(name, die_offsets); - } - + m_index->GetTypes(name, die_offsets); const size_t num_die_matches = die_offsets.size(); if (num_die_matches) { @@ -2881,12 +2439,8 @@ uint32_t SymbolFileDWARF::FindTypes( break; } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_types " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + name.GetStringRef()); } } const uint32_t num_matches = types.GetSize() - initial_types_size; @@ -2935,25 +2489,13 @@ size_t SymbolFileDWARF::FindTypes(const std::vector<CompilerContext> &context, if (context.empty()) return 0; - DIEArray die_offsets; - ConstString name = context.back().name; if (!name) return 0; - if (m_using_apple_tables) { - if (m_apple_types_ap.get()) { - const char *name_cstr = name.GetCString(); - m_apple_types_ap->FindByName(name_cstr, die_offsets); - } - } else { - if (!m_indexed) - Index(); - - m_type_index.Find(name, die_offsets); - } - + DIEArray die_offsets; + m_index->GetTypes(name, die_offsets); const size_t num_die_matches = die_offsets.size(); if (num_die_matches) { @@ -2976,12 +2518,8 @@ size_t SymbolFileDWARF::FindTypes(const std::vector<CompilerContext> &context, ++num_matches; } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_types " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + name.GetStringRef()); } } return num_matches; @@ -3008,21 +2546,7 @@ SymbolFileDWARF::FindNamespace(const SymbolContext &sc, const ConstString &name, DWARFDebugInfo *info = DebugInfo(); if (info) { DIEArray die_offsets; - - // Index if we already haven't to make sure the compile units - // get indexed and make their global DIE index list - if (m_using_apple_tables) { - if (m_apple_namespaces_ap.get()) { - const char *name_cstr = name.GetCString(); - m_apple_namespaces_ap->FindByName(name_cstr, die_offsets); - } - } else { - if (!m_indexed) - Index(); - - m_namespace_index.Find(name, die_offsets); - } - + m_index->GetNamespaces(name, die_offsets); const size_t num_matches = die_offsets.size(); if (num_matches) { for (size_t i = 0; i < num_matches; ++i) { @@ -3040,13 +2564,8 @@ SymbolFileDWARF::FindNamespace(const SymbolContext &sc, const ConstString &name, break; } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified " - "(.apple_namespaces accelerator table had bad die 0x%8.8x for " - "'%s')\n", - die_ref.die_offset, name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + name.GetStringRef()); } } } @@ -3105,6 +2624,7 @@ SymbolFileDWARF::GetDeclContextDIEContainingDIE(const DWARFDIE &orig_die) { if (orig_die != die) { switch (die.Tag()) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: case DW_TAG_namespace: case DW_TAG_structure_type: case DW_TAG_union_type: @@ -3159,16 +2679,14 @@ SymbolFileDWARF::GetObjCClassSymbol(const ConstString &objc_class_name) { } // Some compilers don't emit the DW_AT_APPLE_objc_complete_type attribute. If -// they don't -// then we can end up looking through all class types for a complete type and -// never find -// the full definition. We need to know if this attribute is supported, so we -// determine -// this here and cache th result. We also need to worry about the debug map +// they don't then we can end up looking through all class types for a complete +// type and never find the full definition. We need to know if this attribute +// is supported, so we determine this here and cache th result. We also need to +// worry about the debug map // DWARF file // if we are doing darwin DWARF in .o file debugging. bool SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type( - DWARFCompileUnit *cu) { + DWARFUnit *cu) { if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) { m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo; if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type()) @@ -3177,7 +2695,7 @@ bool SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type( DWARFDebugInfo *debug_info = DebugInfo(); const uint32_t num_compile_units = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); + DWARFUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (dwarf_cu != cu && dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type()) { m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; @@ -3204,19 +2722,7 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( return type_sp; DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_types_ap.get()) { - const char *name_cstr = type_name.GetCString(); - m_apple_types_ap->FindCompleteObjCClassByName(name_cstr, die_offsets, - must_be_implementation); - } - } else { - if (!m_indexed) - Index(); - - m_type_index.Find(type_name, die_offsets); - } + m_index->GetCompleteObjCClass(type_name, must_be_implementation, die_offsets); const size_t num_matches = die_offsets.size(); @@ -3228,7 +2734,8 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( if (type_die) { bool try_resolving_type = false; - // Don't try and resolve the DIE we are looking for with the DIE itself! + // Don't try and resolve the DIE we are looking for with the DIE + // itself! if (type_die != die) { switch (type_die.Tag()) { case DW_TAG_class_type: @@ -3264,12 +2771,8 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( } } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_types " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, type_name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + type_name.GetStringRef()); } } } @@ -3277,16 +2780,15 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( } //---------------------------------------------------------------------- -// This function helps to ensure that the declaration contexts match for -// two different DIEs. Often times debug information will refer to a -// forward declaration of a type (the equivalent of "struct my_struct;". -// There will often be a declaration of that type elsewhere that has the -// full definition. When we go looking for the full type "my_struct", we -// will find one or more matches in the accelerator tables and we will -// then need to make sure the type was in the same declaration context -// as the original DIE. This function can efficiently compare two DIEs -// and will return true when the declaration context matches, and false -// when they don't. +// This function helps to ensure that the declaration contexts match for two +// different DIEs. Often times debug information will refer to a forward +// declaration of a type (the equivalent of "struct my_struct;". There will +// often be a declaration of that type elsewhere that has the full definition. +// When we go looking for the full type "my_struct", we will find one or more +// matches in the accelerator tables and we will then need to make sure the +// type was in the same declaration context as the original DIE. This function +// can efficiently compare two DIEs and will return true when the declaration +// context matches, and false when they don't. //---------------------------------------------------------------------- bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, const DWARFDIE &die2) { @@ -3295,32 +2797,31 @@ bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, DWARFDIECollection decl_ctx_1; DWARFDIECollection decl_ctx_2; - // The declaration DIE stack is a stack of the declaration context - // DIEs all the way back to the compile unit. If a type "T" is - // declared inside a class "B", and class "B" is declared inside - // a class "A" and class "A" is in a namespace "lldb", and the - // namespace is in a compile unit, there will be a stack of DIEs: + // The declaration DIE stack is a stack of the declaration context DIEs all + // the way back to the compile unit. If a type "T" is declared inside a class + // "B", and class "B" is declared inside a class "A" and class "A" is in a + // namespace "lldb", and the namespace is in a compile unit, there will be a + // stack of DIEs: // // [0] DW_TAG_class_type for "B" // [1] DW_TAG_class_type for "A" // [2] DW_TAG_namespace for "lldb" - // [3] DW_TAG_compile_unit for the source file. + // [3] DW_TAG_compile_unit or DW_TAG_partial_unit for the source file. // - // We grab both contexts and make sure that everything matches - // all the way back to the compiler unit. + // We grab both contexts and make sure that everything matches all the way + // back to the compiler unit. // First lets grab the decl contexts for both DIEs die1.GetDeclContextDIEs(decl_ctx_1); die2.GetDeclContextDIEs(decl_ctx_2); - // Make sure the context arrays have the same size, otherwise - // we are done + // Make sure the context arrays have the same size, otherwise we are done const size_t count1 = decl_ctx_1.Size(); const size_t count2 = decl_ctx_2.Size(); if (count1 != count2) return false; - // Make sure the DW_TAG values match all the way back up the - // compile unit. If they don't, then we are done. + // Make sure the DW_TAG values match all the way back up the compile unit. If + // they don't, then we are done. DWARFDIE decl_ctx_die1; DWARFDIE decl_ctx_die2; size_t i; @@ -3333,25 +2834,28 @@ bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, #if defined LLDB_CONFIGURATION_DEBUG // Make sure the top item in the decl context die array is always - // DW_TAG_compile_unit. If it isn't then something went wrong in - // the DWARFDIE::GetDeclContextDIEs() function... - assert(decl_ctx_1.GetDIEAtIndex(count1 - 1).Tag() == DW_TAG_compile_unit); + // DW_TAG_compile_unit or DW_TAG_partial_unit. If it isn't then + // something went wrong in the DWARFDIE::GetDeclContextDIEs() + // function. + dw_tag_t cu_tag = decl_ctx_1.GetDIEAtIndex(count1 - 1).Tag(); + UNUSED_IF_ASSERT_DISABLED(cu_tag); + assert(cu_tag == DW_TAG_compile_unit || cu_tag == DW_TAG_partial_unit); #endif - // Always skip the compile unit when comparing by only iterating up to - // "count - 1". Here we compare the names as we go. + // Always skip the compile unit when comparing by only iterating up to "count + // - 1". Here we compare the names as we go. for (i = 0; i < count1 - 1; i++) { decl_ctx_die1 = decl_ctx_1.GetDIEAtIndex(i); decl_ctx_die2 = decl_ctx_2.GetDIEAtIndex(i); const char *name1 = decl_ctx_die1.GetName(); const char *name2 = decl_ctx_die2.GetName(); - // If the string was from a DW_FORM_strp, then the pointer will often - // be the same! + // If the string was from a DW_FORM_strp, then the pointer will often be + // the same! if (name1 == name2) continue; - // Name pointers are not equal, so only compare the strings - // if both are not NULL. + // Name pointers are not equal, so only compare the strings if both are not + // NULL. if (name1 && name2) { // If the strings don't compare, we are done... if (strcmp(name1, name2) != 0) @@ -3361,8 +2865,8 @@ bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, return false; } } - // We made it through all of the checks and the declaration contexts - // are equal. + // We made it through all of the checks and the declaration contexts are + // equal. return true; } @@ -3387,47 +2891,12 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( } DIEArray die_offsets; - - if (m_using_apple_tables) { - if (m_apple_types_ap.get()) { - const bool has_tag = - m_apple_types_ap->GetHeader().header_data.ContainsAtom( - DWARFMappedHash::eAtomTypeTag); - const bool has_qualified_name_hash = - m_apple_types_ap->GetHeader().header_data.ContainsAtom( - DWARFMappedHash::eAtomTypeQualNameHash); - if (has_tag && has_qualified_name_hash) { - const char *qualified_name = dwarf_decl_ctx.GetQualifiedName(); - const uint32_t qualified_name_hash = - MappedHash::HashStringUsingDJB(qualified_name); - if (log) - GetObjectFile()->GetModule()->LogMessage( - log, "FindByNameAndTagAndQualifiedNameHash()"); - m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash( - type_name.GetCString(), tag, qualified_name_hash, die_offsets); - } else if (has_tag) { - if (log) - GetObjectFile()->GetModule()->LogMessage(log, - "FindByNameAndTag()"); - m_apple_types_ap->FindByNameAndTag(type_name.GetCString(), tag, - die_offsets); - } else { - m_apple_types_ap->FindByName(type_name.GetCString(), die_offsets); - } - } - } else { - if (!m_indexed) - Index(); - - m_type_index.Find(type_name, die_offsets); - } - + m_index->GetTypes(dwarf_decl_ctx, die_offsets); const size_t num_matches = die_offsets.size(); - // Get the type system that we are looking to find a type for. We will use - // this - // to ensure any matches we find are in a language that this type system - // supports + // Get the type system that we are looking to find a type for. We will + // use this to ensure any matches we find are in a language that this + // type system supports const LanguageType language = dwarf_decl_ctx.GetLanguage(); TypeSystem *type_system = (language == eLanguageTypeUnknown) ? nullptr @@ -3440,10 +2909,8 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( if (type_die) { // Make sure type_die's langauge matches the type system we are - // looking for. - // We don't want to find a "Foo" type from Java if we are looking - // for a "Foo" - // type for C, C++, ObjC, or ObjC++. + // looking for. We don't want to find a "Foo" type from Java if we + // are looking for a "Foo" type for C, C++, ObjC, or ObjC++. if (type_system && !type_system->SupportsLanguage(type_die.GetLanguage())) continue; @@ -3457,24 +2924,23 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( // The tags match, lets try resolving this type try_resolving_type = true; } else { - // The tags don't match, but we need to watch our for a - // forward declaration for a struct and ("struct foo") - // ends up being a class ("class foo { ... };") or - // vice versa. + // The tags don't match, but we need to watch our for a forward + // declaration for a struct and ("struct foo") ends up being a + // class ("class foo { ... };") or vice versa. switch (type_tag) { case DW_TAG_class_type: - // We had a "class foo", see if we ended up with a "struct foo { - // ... };" + // We had a "class foo", see if we ended up with a "struct foo + // { ... };" try_resolving_type = (tag == DW_TAG_structure_type); break; case DW_TAG_structure_type: - // We had a "struct foo", see if we ended up with a "class foo { - // ... };" + // We had a "struct foo", see if we ended up with a "class foo + // { ... };" try_resolving_type = (tag == DW_TAG_class_type); break; default: - // Tags don't match, don't event try to resolve - // using this type whose name matches.... + // Tags don't match, don't event try to resolve using this type + // whose name matches.... break; } } @@ -3515,12 +2981,8 @@ TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext( } } } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified (.apple_types " - "accelerator table had bad die 0x%8.8x for '%s')\n", - die_ref.die_offset, type_name.GetCString()); - } + m_index->ReportInvalidDIEOffset(die_ref.die_offset, + type_name.GetStringRef()); } } } @@ -3606,7 +3068,7 @@ size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc, size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc) { assert(sc.comp_unit && sc.function); size_t functions_added = 0; - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { const dw_offset_t function_die_offset = sc.function->GetID(); DWARFDIE function_die = dwarf_cu->GetDIE(function_die_offset); @@ -3623,7 +3085,7 @@ size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc) { // At least a compile unit must be valid assert(sc.comp_unit); size_t types_added = 0; - DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); + DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit); if (dwarf_cu) { if (sc.function) { dw_offset_t function_die_offset = sc.function->GetID(); @@ -3662,7 +3124,7 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { return num_variables; } } else if (sc.comp_unit) { - DWARFCompileUnit *dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID()); + DWARFUnit *dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID()); if (dwarf_cu == NULL) return 0; @@ -3675,25 +3137,7 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { sc.comp_unit->SetVariableList(variables); DIEArray die_offsets; - if (m_using_apple_tables) { - if (m_apple_names_ap.get()) { - DWARFMappedHash::DIEInfoArray hash_data_array; - if (m_apple_names_ap->AppendAllDIEsInRange( - dwarf_cu->GetOffset(), dwarf_cu->GetNextCompileUnitOffset(), - hash_data_array)) { - DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets); - } - } - } else { - // Index if we already haven't to make sure the compile units - // get indexed and make their global DIE index list - if (!m_indexed) - Index(); - - m_global_index.FindAllEntriesForCompileUnit(dwarf_cu->GetOffset(), - die_offsets); - } - + m_index->GetGlobalVariables(*dwarf_cu, die_offsets); const size_t num_matches = die_offsets.size(); if (num_matches) { for (size_t i = 0; i < num_matches; ++i) { @@ -3706,14 +3150,8 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { variables->AddVariableIfUnique(var_sp); ++vars_added; } - } else { - if (m_using_apple_tables) { - GetObjectFile()->GetModule()->ReportErrorIfModifyDetected( - "the DWARF debug information has been modified " - "(.apple_names accelerator table had bad die 0x%8.8x)\n", - die_ref.die_offset); - } - } + } else + m_index->ReportInvalidDIEOffset(die_ref.die_offset, ""); } } } @@ -3796,7 +3234,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, location_is_const_value_data = true; // The constant value will be either a block, a data value or a // string. - const DWARFDataExtractor &debug_info_data = get_debug_info_data(); + auto debug_info_data = die.GetData(); if (DWARFFormValue::IsBlockForm(form_value.Form())) { // Retrieve the value as a block expression. uint32_t block_offset = @@ -3853,13 +3291,12 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, location_is_const_value_data = false; has_explicit_location = true; if (DWARFFormValue::IsBlockForm(form_value.Form())) { - const DWARFDataExtractor &debug_info_data = get_debug_info_data(); + auto data = die.GetData(); uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); + form_value.BlockData() - data.GetDataStart(); uint32_t block_length = form_value.Unsigned(); - location.CopyOpcodeData(module, get_debug_info_data(), - block_offset, block_length); + location.CopyOpcodeData(module, data, block_offset, block_length); } else { const DWARFDataExtractor &debug_loc_data = get_debug_loc_data(); const dw_offset_t debug_loc_offset = form_value.Unsigned(); @@ -3902,10 +3339,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, // TODO: Handle the case when DW_AT_start_scope have form // constant. The // dwarf spec is a bit ambiguous about what is the expected - // behavior in - // case the enclosing block have a non coninious address range and - // the - // DW_AT_start_scope entry have a form constant. + // behavior in case the enclosing block have a non coninious + // address range and the DW_AT_start_scope entry have a form + // constant. GetObjectFile()->GetModule()->ReportWarning( "0x%8.8" PRIx64 ": DW_AT_start_scope has unsupported form type (0x%x)\n", @@ -3937,7 +3373,8 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); const dw_tag_t parent_tag = die.GetParent().Tag(); bool is_static_member = - parent_tag == DW_TAG_compile_unit && + (parent_tag == DW_TAG_compile_unit || + parent_tag == DW_TAG_partial_unit) && (parent_context_die.Tag() == DW_TAG_class_type || parent_context_die.Tag() == DW_TAG_structure_type); @@ -3949,17 +3386,17 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, bool has_explicit_mangled = mangled != nullptr; if (!mangled) { // LLDB relies on the mangled name (DW_TAG_linkage_name or - // DW_AT_MIPS_linkage_name) to - // generate fully qualified names of global variables with commands like - // "frame var j". - // For example, if j were an int variable holding a value 4 and declared - // in a namespace - // B which in turn is contained in a namespace A, the command "frame var - // j" returns - // "(int) A::B::j = 4". If the compiler does not emit a linkage name, we - // should be able - // to generate a fully qualified name from the declaration context. - if (parent_tag == DW_TAG_compile_unit && + // DW_AT_MIPS_linkage_name) to generate fully qualified names + // of global variables with commands like "frame var j". For + // example, if j were an int variable holding a value 4 and + // declared in a namespace B which in turn is contained in a + // namespace A, the command "frame var j" returns + // "(int) A::B::j = 4". + // If the compiler does not emit a linkage name, we should be + // able to generate a fully qualified name from the + // declaration context. + if ((parent_tag == DW_TAG_compile_unit || + parent_tag == DW_TAG_partial_unit) && Language::LanguageIsCPlusPlus(die.GetLanguage())) { DWARFDeclContext decl_ctx; @@ -4007,24 +3444,21 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, scope = eValueTypeVariableStatic; if (debug_map_symfile) { - // When leaving the DWARF in the .o files on darwin, - // when we have a global variable that wasn't initialized, - // the .o file might not have allocated a virtual - // address for the global variable. In this case it will - // have created a symbol for the global variable - // that is undefined/data and external and the value will - // be the byte size of the variable. When we do the - // address map in SymbolFileDWARFDebugMap we rely on - // having an address, we need to do some magic here - // so we can get the correct address for our global - // variable. The address for all of these entries - // will be zero, and there will be an undefined symbol - // in this object file, and the executable will have - // a matching symbol with a good address. So here we - // dig up the correct address and replace it in the - // location for the variable, and set the variable's - // symbol context scope to be that of the main executable - // so the file address will resolve correctly. + // When leaving the DWARF in the .o files on darwin, when we have a + // global variable that wasn't initialized, the .o file might not + // have allocated a virtual address for the global variable. In + // this case it will have created a symbol for the global variable + // that is undefined/data and external and the value will be the + // byte size of the variable. When we do the address map in + // SymbolFileDWARFDebugMap we rely on having an address, we need to + // do some magic here so we can get the correct address for our + // global variable. The address for all of these entries will be + // zero, and there will be an undefined symbol in this object file, + // and the executable will have a matching symbol with a good + // address. So here we dig up the correct address and replace it in + // the location for the variable, and set the variable's symbol + // context scope to be that of the main executable so the file + // address will resolve correctly. bool linked_oso_file_addr = false; if (is_external && location_DW_OP_addr == 0) { // we have a possible uninitialized extern global @@ -4056,8 +3490,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, if (!linked_oso_file_addr) { // The DW_OP_addr is not zero, but it contains a .o file address - // which - // needs to be linked up correctly. + // which needs to be linked up correctly. const lldb::addr_t exe_file_addr = debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr); @@ -4127,16 +3560,16 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, var_sp->SetLocationIsConstantValueData(location_is_const_value_data); } else { - // Not ready to parse this variable yet. It might be a global - // or static variable that is in a function scope and the function - // in the symbol context wasn't filled in yet + // Not ready to parse this variable yet. It might be a global or static + // variable that is in a function scope and the function in the symbol + // context wasn't filled in yet return var_sp; } } - // Cache var_sp even if NULL (the variable was just a specification or - // was missing vital information to be able to be displayed in the debugger - // (missing location due to optimization, etc)) so we don't re-parse - // this DIE over and over later... + // Cache var_sp even if NULL (the variable was just a specification or was + // missing vital information to be able to be displayed in the debugger + // (missing location due to optimization, etc)) so we don't re-parse this + // DIE over and over later... GetDIEToVariable()[die.GetDIE()] = var_sp; if (spec_die) GetDIEToVariable()[spec_die.GetDIE()] = var_sp; @@ -4217,11 +3650,11 @@ size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc, dw_tag_t parent_tag = sc_parent_die.Tag(); switch (parent_tag) { case DW_TAG_compile_unit: + case DW_TAG_partial_unit: if (sc.comp_unit != NULL) { variable_list_sp = sc.comp_unit->GetVariableList(false); if (variable_list_sp.get() == NULL) { variable_list_sp.reset(new VariableList()); - sc.comp_unit->SetVariableList(variable_list_sp); } } else { GetObjectFile()->GetModule()->ReportError( @@ -4243,8 +3676,8 @@ size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc, Block *block = sc.function->GetBlock(true).FindBlockByID( sc_parent_die.GetID()); if (block == NULL) { - // This must be a specification or abstract origin with - // a concrete block counterpart in the current function. We need + // This must be a specification or abstract origin with a + // concrete block counterpart in the current function. We need // to find the concrete block so we can correctly add the // variable to it const DWARFDIE concrete_block_die = @@ -4310,30 +3743,7 @@ ConstString SymbolFileDWARF::GetPluginName() { return GetPluginNameStatic(); } uint32_t SymbolFileDWARF::GetPluginVersion() { return 1; } -void SymbolFileDWARF::DumpIndexes() { - StreamFile s(stdout, false); - - s.Printf( - "DWARF index for (%s) '%s':", - GetObjectFile()->GetModule()->GetArchitecture().GetArchitectureName(), - GetObjectFile()->GetFileSpec().GetPath().c_str()); - s.Printf("\nFunction basenames:\n"); - m_function_basename_index.Dump(&s); - s.Printf("\nFunction fullnames:\n"); - m_function_fullname_index.Dump(&s); - s.Printf("\nFunction methods:\n"); - m_function_method_index.Dump(&s); - s.Printf("\nFunction selectors:\n"); - m_function_selector_index.Dump(&s); - s.Printf("\nObjective C class selectors:\n"); - m_objc_class_selectors_index.Dump(&s); - s.Printf("\nGlobals and statics:\n"); - m_global_index.Dump(&s); - s.Printf("\nTypes:\n"); - m_type_index.Dump(&s); - s.Printf("\nNamespaces:\n"); - m_namespace_index.Dump(&s); -} +void SymbolFileDWARF::Dump(lldb_private::Stream &s) { m_index->Dump(s); } SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired()) { diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 6902dc0333d2..a5f2ac8f3e7d 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -38,8 +38,7 @@ // Project includes #include "DWARFDataExtractor.h" #include "DWARFDefines.h" -#include "HashedNameToDIE.h" -#include "NameToDIE.h" +#include "DWARFIndex.h" #include "UniqueDWARFASTType.h" //---------------------------------------------------------------------- @@ -54,7 +53,6 @@ class DWARFDebugAranges; class DWARFDebugInfo; class DWARFDebugInfoEntry; class DWARFDebugLine; -class DWARFDebugPubnames; class DWARFDebugRanges; class DWARFDeclContext; class DWARFDIECollection; @@ -72,7 +70,7 @@ public: friend class SymbolFileDWARFDwo; friend class DebugMapModule; friend struct DIERef; - friend class DWARFCompileUnit; + friend class DWARFUnit; friend class DWARFDIE; friend class DWARFASTParserClang; friend class DWARFASTParserGo; @@ -181,11 +179,11 @@ public: uint32_t FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t FindGlobalVariables(const lldb_private::RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t @@ -247,10 +245,12 @@ public: const lldb_private::DWARFDataExtractor &get_debug_ranges_data(); const lldb_private::DWARFDataExtractor &get_debug_str_data(); const lldb_private::DWARFDataExtractor &get_debug_str_offsets_data(); + const lldb_private::DWARFDataExtractor &get_debug_types_data(); const lldb_private::DWARFDataExtractor &get_apple_names_data(); const lldb_private::DWARFDataExtractor &get_apple_types_data(); const lldb_private::DWARFDataExtractor &get_apple_namespaces_data(); const lldb_private::DWARFDataExtractor &get_apple_objc_data(); + const lldb_private::DWARFDataExtractor &get_gnu_debugaltlink(); DWARFDebugAbbrev *DebugAbbrev(); @@ -273,19 +273,19 @@ public: HasForwardDeclForClangType(const lldb_private::CompilerType &compiler_type); lldb_private::CompileUnit * - GetCompUnitForDWARFCompUnit(DWARFCompileUnit *dwarf_cu, + GetCompUnitForDWARFCompUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx = UINT32_MAX); virtual size_t GetObjCMethodDIEOffsets(lldb_private::ConstString class_name, DIEArray &method_die_offsets); - bool Supports_DW_AT_APPLE_objc_complete_type(DWARFCompileUnit *cu); + bool Supports_DW_AT_APPLE_objc_complete_type(DWARFUnit *cu); lldb_private::DebugMacrosSP ParseDebugMacros(lldb::offset_t *offset); static DWARFDIE GetParentSymbolContextDIE(const DWARFDIE &die); - virtual lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit *dwarf_cu, + virtual lldb::CompUnitSP ParseCompileUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx); virtual lldb_private::DWARFExpression::LocationListFormat @@ -293,16 +293,30 @@ public: lldb::ModuleSP GetDWOModule(lldb_private::ConstString name); + typedef std::map<lldb_private::ConstString, lldb::ModuleSP> + ExternalTypeModuleMap; + + /// Return the list of Clang modules imported by this SymbolFile. + const ExternalTypeModuleMap& getExternalTypeModules() const { + return m_external_type_modules; + } + virtual DWARFDIE GetDIE(const DIERef &die_ref); virtual std::unique_ptr<SymbolFileDWARFDwo> - GetDwoSymbolFileForCompileUnit(DWARFCompileUnit &dwarf_cu, + GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die); // For regular SymbolFileDWARF instances the method returns nullptr, // for the instances of the subclass SymbolFileDWARFDwo // the method returns a pointer to the base compile unit. - virtual DWARFCompileUnit *GetBaseCompileUnit(); + virtual DWARFUnit *GetBaseCompileUnit(); + + static bool + DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, + const DWARFDIE &die); + + void Dump(lldb_private::Stream &s) override; protected: typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> @@ -331,14 +345,10 @@ protected: bool DeclContextMatchesThisSymbolFile( const lldb_private::CompilerDeclContext *decl_ctx); - bool - DIEInDeclContext(const lldb_private::CompilerDeclContext *parent_decl_ctx, - const DWARFDIE &die); - - virtual DWARFCompileUnit * + virtual DWARFUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit); - DWARFCompileUnit *GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit *prev_cu); + DWARFUnit *GetNextUnparsedDWARFCompileUnit(DWARFUnit *prev_cu); bool GetFunction(const DWARFDIE &die, lldb_private::SymbolContext &sc); @@ -375,25 +385,9 @@ protected: bool ClassOrStructIsVirtual(const DWARFDIE &die); // Given a die_offset, figure out the symbol context representing that die. - bool ResolveFunction(const DIERef &die_ref, bool include_inlines, - lldb_private::SymbolContextList &sc_list); - bool ResolveFunction(const DWARFDIE &die, bool include_inlines, lldb_private::SymbolContextList &sc_list); - void FindFunctions(const lldb_private::ConstString &name, - const NameToDIE &name_to_die, bool include_inlines, - lldb_private::SymbolContextList &sc_list); - - void FindFunctions(const lldb_private::RegularExpression ®ex, - const NameToDIE &name_to_die, bool include_inlines, - lldb_private::SymbolContextList &sc_list); - - void FindFunctions(const lldb_private::RegularExpression ®ex, - const DWARFMappedHash::MemoryTable &memory_table, - bool include_inlines, - lldb_private::SymbolContextList &sc_list); - virtual lldb::TypeSP FindDefinitionTypeForDWARFDeclContext(const DWARFDeclContext &die_decl_ctx); @@ -404,16 +398,9 @@ protected: lldb_private::Symbol * GetObjCClassSymbol(const lldb_private::ConstString &objc_class_name); - void ParseFunctions(const DIEArray &die_offsets, bool include_inlines, - lldb_private::SymbolContextList &sc_list); - lldb::TypeSP GetTypeForDIE(const DWARFDIE &die, bool resolve_function_context = false); - void Index(); - - void DumpIndexes(); - void SetDebugMapModule(const lldb::ModuleSP &module_sp) { m_debug_map_module_wp = module_sp; } @@ -439,9 +426,6 @@ protected: typedef std::set<lldb_private::Type *> TypeSet; - typedef std::map<lldb_private::ConstString, lldb::ModuleSP> - ExternalTypeModuleMap; - void GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset, dw_offset_t max_die_offset, uint32_t type_mask, TypeSet &type_set); @@ -487,10 +471,12 @@ protected: DWARFDataSegment m_data_debug_ranges; DWARFDataSegment m_data_debug_str; DWARFDataSegment m_data_debug_str_offsets; + DWARFDataSegment m_data_debug_types; DWARFDataSegment m_data_apple_names; DWARFDataSegment m_data_apple_types; DWARFDataSegment m_data_apple_namespaces; DWARFDataSegment m_data_apple_objc; + DWARFDataSegment m_data_gnu_debugaltlink; // The unique pointer items below are generated on demand if and when someone // accesses @@ -498,10 +484,6 @@ protected: std::unique_ptr<DWARFDebugAbbrev> m_abbr; std::unique_ptr<DWARFDebugInfo> m_info; std::unique_ptr<DWARFDebugLine> m_line; - std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_names_ap; - std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_types_ap; - std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_ap; - std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_ap; std::unique_ptr<GlobalVariableMap> m_global_aranges_ap; typedef std::unordered_map<lldb::offset_t, lldb_private::DebugMacrosSP> @@ -509,17 +491,8 @@ protected: DebugMacrosMap m_debug_macros_map; ExternalTypeModuleMap m_external_type_modules; - NameToDIE m_function_basename_index; // All concrete functions - NameToDIE m_function_fullname_index; // All concrete functions - NameToDIE m_function_method_index; // All inlined functions - NameToDIE - m_function_selector_index; // All method names for functions of classes - NameToDIE m_objc_class_selectors_index; // Given a class name, find all - // selectors for the class - NameToDIE m_global_index; // Global and static variables - NameToDIE m_type_index; // All type DIE offsets - NameToDIE m_namespace_index; // All type DIE offsets - bool m_indexed : 1, m_using_apple_tables : 1, m_fetched_external_modules : 1; + std::unique_ptr<lldb_private::DWARFIndex> m_index; + bool m_fetched_external_modules : 1; lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; typedef std::shared_ptr<std::set<DIERef>> DIERefSetSP; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index eabff86a5428..39c70d146524 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -44,10 +44,8 @@ using namespace lldb; using namespace lldb_private; // Subclass lldb_private::Module so we can intercept the -// "Module::GetObjectFile()" -// (so we can fixup the object file sections) and also for -// "Module::GetSymbolVendor()" -// (so we can fixup the symbol file id. +// "Module::GetObjectFile()" (so we can fixup the object file sections) and +// also for "Module::GetSymbolVendor()" (so we can fixup the symbol file id. const SymbolFileDWARFDebugMap::FileRangeMap & SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( @@ -84,8 +82,8 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( /// const uint32_t fun_resolve_flags = SymbolContext::Module | /// eSymbolContextCompUnit | eSymbolContextFunction; // SectionList *oso_sections = oso_objfile->Sections(); - // Now we need to make sections that map from zero based object - // file addresses to where things ended up in the main executable. + // Now we need to make sections that map from zero based object file + // addresses to where things ended up in the main executable. assert(comp_unit_info->first_symbol_index != UINT32_MAX); // End index is one past the last valid symbol index @@ -104,9 +102,9 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( break; case eSymbolTypeCode: { - // For each N_FUN, or function that we run into in the debug map - // we make a new section that we add to the sections found in the - // .o file. This new section has the file address set to what the + // For each N_FUN, or function that we run into in the debug map we + // make a new section that we add to the sections found in the .o + // file. This new section has the file address set to what the // addresses are in the .o file, and the load address is adjusted // to match where it ended up in the final executable! We do this // before we parse any dwarf info so that when it goes get parsed @@ -129,21 +127,21 @@ SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap( } break; case eSymbolTypeData: { - // For each N_GSYM we remap the address for the global by making - // a new section that we add to the sections found in the .o file. - // This new section has the file address set to what the - // addresses are in the .o file, and the load address is adjusted - // to match where it ended up in the final executable! We do this - // before we parse any dwarf info so that when it goes get parsed - // all section/offset addresses that get registered will resolve + // For each N_GSYM we remap the address for the global by making a + // new section that we add to the sections found in the .o file. + // This new section has the file address set to what the addresses + // are in the .o file, and the load address is adjusted to match + // where it ended up in the final executable! We do this before we + // parse any dwarf info so that when it goes get parsed all + // section/offset addresses that get registered will resolve // correctly to the new addresses in the main executable. We // initially set the section size to be 1 byte, but will need to // fix up these addresses further after all globals have been // parsed to span the gaps, or we can find the global variable // sizes from the DWARF info as we are parsing. - // Next we find the non-stab entry that corresponds to the N_GSYM in - // the .o file + // Next we find the non-stab entry that corresponds to the N_GSYM + // in the .o file Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType( exe_symbol->GetMangled().GetName(lldb::eLanguageTypeUnknown, @@ -198,9 +196,9 @@ public: SymbolVendor *symbol_vendor = Module::GetSymbolVendor(can_create, feedback_strm); if (symbol_vendor) { - // Set a pointer to this class to set our OSO DWARF file know - // that the DWARF is being used along with a debug map and that - // it will have the remapped sections that we do below. + // Set a pointer to this class to set our OSO DWARF file know that + // the DWARF is being used along with a debug map and that it will + // have the remapped sections that we do below. SymbolFileDWARF *oso_symfile = SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF( symbol_vendor->GetSymbolFile()); @@ -292,8 +290,8 @@ void SymbolFileDWARFDebugMap::InitOSO() { // In order to get the abilities of this plug-in, we look at the list of // N_OSO entries (object files) from the symbol table and make sure that - // these files exist and also contain valid DWARF. If we get any of that - // then we return the abilities of the first N_OSO's DWARF. + // these files exist and also contain valid DWARF. If we get any of that then + // we return the abilities of the first N_OSO's DWARF. Symtab *symtab = m_obj_file->GetSymtab(); if (symtab) { @@ -303,10 +301,10 @@ void SymbolFileDWARFDebugMap::InitOSO() { // When a mach-o symbol is encoded, the n_type field is encoded in bits // 23:16, and the n_desc field is encoded in bits 15:0. // - // To find all N_OSO entries that are part of the DWARF + debug map - // we find only object file symbols with the flags value as follows: - // bits 23:16 == 0x66 (N_OSO) - // bits 15: 0 == 0x0001 (specifies this is a debug map object file) + // To find all N_OSO entries that are part of the DWARF + debug map we find + // only object file symbols with the flags value as follows: bits 23:16 == + // 0x66 (N_OSO) bits 15: 0 == 0x0001 (specifies this is a debug map object + // file) const uint32_t k_oso_symbol_flags_value = 0x660001u; const uint32_t oso_index_count = @@ -353,7 +351,7 @@ void SymbolFileDWARFDebugMap::InitOSO() { so_symbol->GetType() == eSymbolTypeSourceFile && oso_symbol->GetType() == eSymbolTypeObjectFile) { m_compile_unit_infos[i].so_file.SetFile( - so_symbol->GetName().AsCString(), false); + so_symbol->GetName().AsCString(), false, FileSpec::Style::native); m_compile_unit_infos[i].oso_path = oso_symbol->GetName(); m_compile_unit_infos[i].oso_mod_time = llvm::sys::toTimePoint(oso_symbol->GetIntegerValue(0)); @@ -413,13 +411,15 @@ Module *SymbolFileDWARFDebugMap::GetModuleByOSOIndex(uint32_t oso_idx) { Module *SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo( CompileUnitInfo *comp_unit_info) { if (!comp_unit_info->oso_sp) { - auto pos = m_oso_map.find(comp_unit_info->oso_path); + auto pos = m_oso_map.find( + {comp_unit_info->oso_path, comp_unit_info->oso_mod_time}); if (pos != m_oso_map.end()) { comp_unit_info->oso_sp = pos->second; } else { ObjectFile *obj_file = GetObjectFile(); comp_unit_info->oso_sp.reset(new OSOInfo()); - m_oso_map[comp_unit_info->oso_path] = comp_unit_info->oso_sp; + m_oso_map[{comp_unit_info->oso_path, comp_unit_info->oso_mod_time}] = + comp_unit_info->oso_sp; const char *oso_path = comp_unit_info->oso_path.GetCString(); FileSpec oso_file(oso_path, false); ConstString oso_object; @@ -443,16 +443,15 @@ Module *SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo( return NULL; } } - // Always create a new module for .o files. Why? Because we - // use the debug map, to add new sections to each .o file and - // even though a .o file might not have changed, the sections - // that get added to the .o file can change. + // Always create a new module for .o files. Why? Because we use the debug + // map, to add new sections to each .o file and even though a .o file + // might not have changed, the sections that get added to the .o file can + // change. ArchSpec oso_arch; // Only adopt the architecture from the module (not the vendor or OS) - // since .o files for "i386-apple-ios" will historically show up as - // "i386-apple-macosx" - // due to the lack of a LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS - // load command... + // since .o files for "i386-apple-ios" will historically show up as "i386 + // -apple-macosx" due to the lack of a LC_VERSION_MIN_MACOSX or + // LC_VERSION_MIN_IPHONEOS load command... oso_arch.SetTriple(m_obj_file->GetModule() ->GetArchitecture() .GetTriple() @@ -546,8 +545,8 @@ SymbolFileDWARF *SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo( uint32_t SymbolFileDWARFDebugMap::CalculateAbilities() { // In order to get the abilities of this plug-in, we look at the list of // N_OSO entries (object files) from the symbol table and make sure that - // these files exist and also contain valid DWARF. If we get any of that - // then we return the abilities of the first N_OSO's DWARF. + // these files exist and also contain valid DWARF. If we get any of that then + // we return the abilities of the first N_OSO's DWARF. const uint32_t oso_index_count = GetNumCompileUnits(); if (oso_index_count > 0) { @@ -576,9 +575,8 @@ CompUnitSP SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx) { if (oso_module) { FileSpec so_file_spec; if (GetFileSpecForSO(cu_idx, so_file_spec)) { - // User zero as the ID to match the compile unit at offset - // zero in each .o file since each .o file can only have - // one compile unit for now. + // User zero as the ID to match the compile unit at offset zero in each + // .o file since each .o file can only have one compile unit for now. lldb::user_id_t cu_id = 0; m_compile_unit_infos[cu_idx].compile_unit_sp.reset( new CompileUnit(m_obj_file->GetModule(), NULL, so_file_spec, cu_id, @@ -767,8 +765,8 @@ uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( const uint32_t cu_count = GetNumCompileUnits(); for (uint32_t i = 0; i < cu_count; ++i) { - // If we are checking for inlines, then we need to look through all - // compile units no matter if "file_spec" matches. + // If we are checking for inlines, then we need to look through all compile + // units no matter if "file_spec" matches. bool resolve = check_inlines; if (!resolve) { @@ -805,8 +803,8 @@ uint32_t SymbolFileDWARFDebugMap::PrivateFindGlobalVariables( if (comp_unit_info) { SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx); if (oso_dwarf) { - if (oso_dwarf->FindGlobalVariables(name, parent_decl_ctx, true, - max_matches, variables)) + if (oso_dwarf->FindGlobalVariables(name, parent_decl_ctx, max_matches, + variables)) if (variables.GetSize() > max_matches) break; } @@ -817,21 +815,16 @@ uint32_t SymbolFileDWARFDebugMap::PrivateFindGlobalVariables( uint32_t SymbolFileDWARFDebugMap::FindGlobalVariables( const ConstString &name, const CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, VariableList &variables) { + uint32_t max_matches, VariableList &variables) { - // If we aren't appending the results to this list, then clear the list - if (!append) - variables.Clear(); - - // Remember how many variables are in the list before we search in case - // we are appending the results to a variable list. + // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); uint32_t total_matches = 0; ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { const uint32_t oso_matches = oso_dwarf->FindGlobalVariables( - name, parent_decl_ctx, true, max_matches, variables); + name, parent_decl_ctx, max_matches, variables); if (oso_matches > 0) { total_matches += oso_matches; @@ -843,8 +836,8 @@ uint32_t SymbolFileDWARFDebugMap::FindGlobalVariables( if (max_matches >= total_matches) return true; - // Update the max matches for any subsequent calls to find globals - // in any other object files with DWARF + // Update the max matches for any subsequent calls to find globals in any + // other object files with DWARF max_matches -= oso_matches; } @@ -857,20 +850,15 @@ uint32_t SymbolFileDWARFDebugMap::FindGlobalVariables( uint32_t SymbolFileDWARFDebugMap::FindGlobalVariables(const RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, VariableList &variables) { - // If we aren't appending the results to this list, then clear the list - if (!append) - variables.Clear(); - - // Remember how many variables are in the list before we search in case - // we are appending the results to a variable list. + // Remember how many variables are in the list before we search. const uint32_t original_size = variables.GetSize(); uint32_t total_matches = 0; ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { const uint32_t oso_matches = - oso_dwarf->FindGlobalVariables(regex, true, max_matches, variables); + oso_dwarf->FindGlobalVariables(regex, max_matches, variables); if (oso_matches > 0) { total_matches += oso_matches; @@ -882,8 +870,8 @@ SymbolFileDWARFDebugMap::FindGlobalVariables(const RegularExpression ®ex, if (max_matches >= total_matches) return true; - // Update the max matches for any subsequent calls to find globals - // in any other object files with DWARF + // Update the max matches for any subsequent calls to find globals in any + // other object files with DWARF max_matches -= oso_matches; } @@ -965,12 +953,12 @@ SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithID( static void RemoveFunctionsWithModuleNotEqualTo(const ModuleSP &module_sp, SymbolContextList &sc_list, uint32_t start_idx) { - // We found functions in .o files. Not all functions in the .o files - // will have made it into the final output file. The ones that did - // make it into the final output file will have a section whose module - // matches the module from the ObjectFile for this SymbolFile. When - // the modules don't match, then we have something that was in a - // .o file, but doesn't map to anything in the final executable. + // We found functions in .o files. Not all functions in the .o files will + // have made it into the final output file. The ones that did make it into + // the final output file will have a section whose module matches the module + // from the ObjectFile for this SymbolFile. When the modules don't match, + // then we have something that was in a .o file, but doesn't map to anything + // in the final executable. uint32_t i = start_idx; while (i < sc_list.GetSize()) { SymbolContext sc; @@ -1101,12 +1089,12 @@ bool SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type( TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( const DWARFDIE &die, const ConstString &type_name, bool must_be_implementation) { - // If we have a debug map, we will have an Objective C symbol whose name is + // If we have a debug map, we will have an Objective-C symbol whose name is // the type name and whose type is eSymbolTypeObjCClass. If we can find that // symbol and find its containing parent, we can locate the .o file that will // contain the implementation definition since it will be scoped inside the - // N_SO - // and we can then locate the SymbolFileDWARF that corresponds to that N_SO. + // N_SO and we can then locate the SymbolFileDWARF that corresponds to that + // N_SO. SymbolFileDWARF *oso_dwarf = NULL; TypeSP type_sp; ObjectFile *module_objfile = m_obj_file->GetModule()->GetObjectFile(); @@ -1118,8 +1106,7 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( Symtab::eVisibilityAny); if (objc_class_symbol) { // Get the N_SO symbol that contains the objective C class symbol as - // this - // should be the .o file that contains the real definition... + // this should be the .o file that contains the real definition... const Symbol *source_file_symbol = symtab->GetParent(objc_class_symbol); if (source_file_symbol && @@ -1147,10 +1134,8 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( } // Only search all .o files for the definition if we don't need the - // implementation - // because otherwise, with a valid debug map we should have the ObjC class - // symbol and - // the code above should have found it. + // implementation because otherwise, with a valid debug map we should have + // the ObjC class symbol and the code above should have found it. if (must_be_implementation == false) { TypeSP type_sp; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index dcca4268b6eb..550f74a203ea 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -95,10 +95,10 @@ public: uint32_t FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t FindGlobalVariables(const lldb_private::RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t FindFunctions(const lldb_private::ConstString &name, @@ -136,7 +136,7 @@ protected: friend class DebugMapModule; friend struct DIERef; friend class DWARFASTParserClang; - friend class DWARFCompileUnit; + friend class DWARFUnit; friend class SymbolFileDWARF; struct OSOInfo { lldb::ModuleSP module_sp; @@ -300,7 +300,9 @@ protected: std::vector<CompileUnitInfo> m_compile_unit_infos; std::vector<uint32_t> m_func_indexes; // Sorted by address std::vector<uint32_t> m_glob_indexes; - std::map<lldb_private::ConstString, OSOInfoSP> m_oso_map; + std::map<std::pair<lldb_private::ConstString, llvm::sys::TimePoint<>>, + OSOInfoSP> + m_oso_map; UniqueDWARFASTTypeMap m_unique_ast_type_map; lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type; DebugMap m_debug_map; diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 17c188a41a77..15fe362fa117 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -14,14 +14,14 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" using namespace lldb; using namespace lldb_private; SymbolFileDWARFDwo::SymbolFileDWARFDwo(ObjectFileSP objfile, - DWARFCompileUnit *dwarf_cu) + DWARFUnit *dwarf_cu) : SymbolFileDWARF(objfile.get()), m_obj_file_sp(objfile), m_base_dwarf_cu(dwarf_cu) { SetID(((lldb::user_id_t)dwarf_cu->GetOffset()) << 32); @@ -52,7 +52,7 @@ void SymbolFileDWARFDwo::LoadSectionData(lldb::SectionType sect_type, } lldb::CompUnitSP -SymbolFileDWARFDwo::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, +SymbolFileDWARFDwo::ParseCompileUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx) { assert(GetCompileUnit() == dwarf_cu && "SymbolFileDWARFDwo::ParseCompileUnit " "called with incompatible compile " @@ -60,7 +60,7 @@ SymbolFileDWARFDwo::ParseCompileUnit(DWARFCompileUnit *dwarf_cu, return GetBaseSymbolFile()->ParseCompileUnit(m_base_dwarf_cu, UINT32_MAX); } -DWARFCompileUnit *SymbolFileDWARFDwo::GetCompileUnit() { +DWARFUnit *SymbolFileDWARFDwo::GetCompileUnit() { // A clang module is found via a skeleton CU, but is not a proper DWO. // Clang modules have a .debug_info section instead of the *_dwo variant. if (auto *section_list = m_obj_file->GetSectionList(false)) @@ -76,7 +76,7 @@ DWARFCompileUnit *SymbolFileDWARFDwo::GetCompileUnit() { return nullptr; } -DWARFCompileUnit * +DWARFUnit * SymbolFileDWARFDwo::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { return GetCompileUnit(); } @@ -122,7 +122,7 @@ lldb::TypeSP SymbolFileDWARFDwo::FindCompleteObjCDefinitionTypeForDIE( die, type_name, must_be_implementation); } -DWARFCompileUnit *SymbolFileDWARFDwo::GetBaseCompileUnit() { +DWARFUnit *SymbolFileDWARFDwo::GetBaseCompileUnit() { return m_base_dwarf_cu; } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index b67967aafab2..483a19512a36 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -18,16 +18,16 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF { public: - SymbolFileDWARFDwo(lldb::ObjectFileSP objfile, DWARFCompileUnit *dwarf_cu); + SymbolFileDWARFDwo(lldb::ObjectFileSP objfile, DWARFUnit *dwarf_cu); ~SymbolFileDWARFDwo() override = default; - lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit *dwarf_cu, + lldb::CompUnitSP ParseCompileUnit(DWARFUnit *dwarf_cu, uint32_t cu_idx) override; - DWARFCompileUnit *GetCompileUnit(); + DWARFUnit *GetCompileUnit(); - DWARFCompileUnit * + DWARFUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) override; lldb_private::DWARFExpression::LocationListFormat @@ -43,12 +43,12 @@ public: GetDIE(const DIERef &die_ref) override; std::unique_ptr<SymbolFileDWARFDwo> - GetDwoSymbolFileForCompileUnit(DWARFCompileUnit &dwarf_cu, + GetDwoSymbolFileForCompileUnit(DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) override { return nullptr; } - DWARFCompileUnit *GetBaseCompileUnit() override; + DWARFUnit *GetBaseCompileUnit() override; protected: void LoadSectionData(lldb::SectionType sect_type, @@ -74,7 +74,7 @@ protected: SymbolFileDWARF *GetBaseSymbolFile(); lldb::ObjectFileSP m_obj_file_sp; - DWARFCompileUnit *m_base_dwarf_cu; + DWARFUnit *m_base_dwarf_cu; }; #endif // SymbolFileDWARFDwo_SymbolFileDWARFDwo_h_ diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp index f6de1818eae0..403c10fe65ea 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.cpp @@ -14,7 +14,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" -#include "DWARFCompileUnit.h" +#include "DWARFUnit.h" #include "DWARFDebugInfo.h" using namespace lldb; @@ -22,7 +22,7 @@ using namespace lldb_private; SymbolFileDWARFDwoDwp::SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, ObjectFileSP objfile, - DWARFCompileUnit *dwarf_cu, + DWARFUnit *dwarf_cu, uint64_t dwo_id) : SymbolFileDWARFDwo(objfile, dwarf_cu), m_dwp_symfile(dwp_symfile), m_dwo_id(dwo_id) {} diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h index 00ad7aafd96b..b1b505b5899f 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwoDwp.h @@ -20,7 +20,7 @@ class SymbolFileDWARFDwoDwp : public SymbolFileDWARFDwo { public: SymbolFileDWARFDwoDwp(SymbolFileDWARFDwp *dwp_symfile, - lldb::ObjectFileSP objfile, DWARFCompileUnit *dwarf_cu, + lldb::ObjectFileSP objfile, DWARFUnit *dwarf_cu, uint64_t dwo_id); protected: diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp index 1dc1dab34a5c..ae10e7179e33 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.cpp @@ -85,7 +85,7 @@ SymbolFileDWARFDwp::SymbolFileDWARFDwp(lldb::ModuleSP module_sp, {} std::unique_ptr<SymbolFileDWARFDwo> -SymbolFileDWARFDwp::GetSymbolFileForDwoId(DWARFCompileUnit *dwarf_cu, +SymbolFileDWARFDwp::GetSymbolFileForDwoId(DWARFUnit *dwarf_cu, uint64_t dwo_id) { return std::unique_ptr<SymbolFileDWARFDwo>( new SymbolFileDWARFDwoDwp(this, m_obj_file, dwarf_cu, dwo_id)); diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h index a7372b9358b1..470d1c5b1c48 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwp.h @@ -29,7 +29,7 @@ public: Create(lldb::ModuleSP module_sp, const lldb_private::FileSpec &file_spec); std::unique_ptr<SymbolFileDWARFDwo> - GetSymbolFileForDwoId(DWARFCompileUnit *dwarf_cu, uint64_t dwo_id); + GetSymbolFileForDwoId(DWARFUnit *dwarf_cu, uint64_t dwo_id); bool LoadSectionData(uint64_t dwo_id, lldb::SectionType sect_type, lldb_private::DWARFDataExtractor &data); diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp index 8697e08dbf86..8273d975e57d 100644 --- a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp +++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp @@ -27,8 +27,8 @@ bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die, udt.m_byte_size == byte_size) { // Make sure the file and line match if (udt.m_declaration == decl) { - // The type has the same name, and was defined on the same - // file and line. Now verify all of the parent DIEs match. + // The type has the same name, and was defined on the same file and + // line. Now verify all of the parent DIEs match. DWARFDIE parent_arg_die = die.GetParent(); DWARFDIE parent_pos_die = udt.m_die.GetParent(); bool match = true; @@ -57,6 +57,7 @@ bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die, } break; case DW_TAG_compile_unit: + case DW_TAG_partial_unit: done = true; break; } diff --git a/source/Plugins/SymbolFile/PDB/CMakeLists.txt b/source/Plugins/SymbolFile/PDB/CMakeLists.txt index 871f382298d6..1c176c32224d 100644 --- a/source/Plugins/SymbolFile/PDB/CMakeLists.txt +++ b/source/Plugins/SymbolFile/PDB/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginSymbolFilePDB PLUGIN PDBASTParser.cpp + PDBLocationToDWARFExpression.cpp SymbolFilePDB.cpp LINK_LIBS diff --git a/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 7802d6f0d859..8bea994aae5d 100644 --- a/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -19,19 +19,22 @@ #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeSystem.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" using namespace lldb; using namespace lldb_private; -using namespace llvm; using namespace llvm::pdb; namespace { @@ -46,7 +49,7 @@ int TranslateUdtKind(PDB_UdtType pdb_kind) { case PDB_UdtType::Interface: return clang::TTK_Interface; } - return clang::TTK_Class; + return -1; } lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { @@ -58,16 +61,146 @@ lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { case PDB_BuiltinType::Char: return lldb::eEncodingSint; case PDB_BuiltinType::Bool: + case PDB_BuiltinType::Char16: + case PDB_BuiltinType::Char32: case PDB_BuiltinType::UInt: case PDB_BuiltinType::ULong: case PDB_BuiltinType::HResult: + case PDB_BuiltinType::WCharT: return lldb::eEncodingUint; default: return lldb::eEncodingInvalid; } } + +lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) { + switch (type) { + case PDB_VariantType::Int8: + case PDB_VariantType::Int16: + case PDB_VariantType::Int32: + case PDB_VariantType::Int64: + return lldb::eEncodingSint; + + case PDB_VariantType::UInt8: + case PDB_VariantType::UInt16: + case PDB_VariantType::UInt32: + case PDB_VariantType::UInt64: + return lldb::eEncodingUint; + + default: + break; + } + + return lldb::eEncodingSint; } +CompilerType +GetBuiltinTypeForPDBEncodingAndBitSize(ClangASTContext &clang_ast, + const PDBSymbolTypeBuiltin &pdb_type, + Encoding encoding, uint32_t width) { + auto *ast = clang_ast.getASTContext(); + if (!ast) + return CompilerType(); + + switch (pdb_type.getBuiltinType()) { + default: + break; + case PDB_BuiltinType::None: + return CompilerType(); + case PDB_BuiltinType::Void: + return clang_ast.GetBasicType(eBasicTypeVoid); + case PDB_BuiltinType::Bool: + return clang_ast.GetBasicType(eBasicTypeBool); + case PDB_BuiltinType::Long: + if (width == ast->getTypeSize(ast->LongTy)) + return CompilerType(ast, ast->LongTy); + if (width == ast->getTypeSize(ast->LongLongTy)) + return CompilerType(ast, ast->LongLongTy); + break; + case PDB_BuiltinType::ULong: + if (width == ast->getTypeSize(ast->UnsignedLongTy)) + return CompilerType(ast, ast->UnsignedLongTy); + if (width == ast->getTypeSize(ast->UnsignedLongLongTy)) + return CompilerType(ast, ast->UnsignedLongLongTy); + break; + case PDB_BuiltinType::WCharT: + if (width == ast->getTypeSize(ast->WCharTy)) + return CompilerType(ast, ast->WCharTy); + break; + case PDB_BuiltinType::Char16: + return CompilerType(ast, ast->Char16Ty); + case PDB_BuiltinType::Char32: + return CompilerType(ast, ast->Char32Ty); + 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 + // back to default search, the compiler type of `long double` will be + // represented by the one generated for `double`. + break; + } + // If there is no match on PDB_BuiltinType, fall back to default search by + // encoding and width only + return clang_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, width); +} + +ConstString GetPDBBuiltinTypeName(const PDBSymbolTypeBuiltin &pdb_type, + CompilerType &compiler_type) { + PDB_BuiltinType kind = pdb_type.getBuiltinType(); + switch (kind) { + default: + break; + case PDB_BuiltinType::Currency: + return ConstString("CURRENCY"); + case PDB_BuiltinType::Date: + return ConstString("DATE"); + case PDB_BuiltinType::Variant: + return ConstString("VARIANT"); + case PDB_BuiltinType::Complex: + return ConstString("complex"); + case PDB_BuiltinType::Bitfield: + return ConstString("bitfield"); + case PDB_BuiltinType::BSTR: + return ConstString("BSTR"); + case PDB_BuiltinType::HResult: + return ConstString("HRESULT"); + case PDB_BuiltinType::BCD: + return ConstString("BCD"); + case PDB_BuiltinType::Char16: + return ConstString("char16_t"); + case PDB_BuiltinType::Char32: + return ConstString("char32_t"); + case PDB_BuiltinType::None: + return ConstString("..."); + } + return compiler_type.GetTypeName(); +} + +bool GetDeclarationForSymbol(const PDBSymbol &symbol, Declaration &decl) { + auto &raw_sym = symbol.getRawSymbol(); + auto first_line_up = raw_sym.getSrcLineOnTypeDefn(); + + if (!first_line_up) { + auto lines_up = symbol.getSession().findLineNumbersByAddress( + raw_sym.getVirtualAddress(), raw_sym.getLength()); + if (!lines_up) + return false; + first_line_up = lines_up->getNext(); + if (!first_line_up) + return false; + } + uint32_t src_file_id = first_line_up->getSourceFileId(); + auto src_file_up = symbol.getSession().getSourceFileById(src_file_id); + if (!src_file_up) + return false; + + FileSpec spec(src_file_up->getFileName(), /*resolve_path*/ false); + decl.SetFile(spec); + decl.SetColumn(first_line_up->getColumnNumber()); + decl.SetLine(first_line_up->getLineNumber()); + return true; +} +} // namespace + PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {} PDBASTParser::~PDBASTParser() {} @@ -76,21 +209,27 @@ PDBASTParser::~PDBASTParser() {} lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { // PDB doesn't maintain enough information to robustly rebuild the entire - // tree, and this is most problematic when it comes to figure out the - // right DeclContext to put a type in. So for now, everything goes in - // the translation unit decl as a fully qualified type. + // tree, and this is most problematic when it comes to figure out the right + // DeclContext to put a type in. So for now, everything goes in the + // translation unit decl as a fully qualified type. clang::DeclContext *tu_decl_ctx = m_ast.GetTranslationUnitDecl(); Declaration decl; - if (auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type)) { + switch (type.getSymTag()) { + case PDB_SymType::UDT: { + auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type); + assert(udt); AccessType access = lldb::eAccessPublic; PDB_UdtType udt_kind = udt->getUdtKind(); + auto tag_type_kind = TranslateUdtKind(udt_kind); + if (tag_type_kind == -1) + return nullptr; if (udt_kind == PDB_UdtType::Class) access = lldb::eAccessPrivate; CompilerType clang_type = m_ast.CreateRecordType( - tu_decl_ctx, access, udt->getName().c_str(), TranslateUdtKind(udt_kind), + tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind, lldb::eLanguageTypeC_plus_plus, nullptr); m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); @@ -100,51 +239,107 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { ConstString(udt->getName()), udt->getLength(), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type, lldb_private::Type::eResolveStateForward); - } else if (auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type)) { - std::string name = enum_type->getName(); + } break; + case PDB_SymType::Enum: { + auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type); + assert(enum_type); + auto underlying_type_up = enum_type->getUnderlyingType(); + if (!underlying_type_up) + return nullptr; lldb::Encoding encoding = - TranslateBuiltinEncoding(enum_type->getBuiltinType()); + TranslateBuiltinEncoding(underlying_type_up->getBuiltinType()); + // FIXME: Type of underlying builtin is always `Int`. We correct it with + // the very first enumerator's encoding if any. + auto first_child = enum_type->findOneChild<PDBSymbolData>(); + if (first_child) { + encoding = TranslateEnumEncoding(first_child->getValue().Type); + } + std::string name = enum_type->getName(); uint64_t bytes = enum_type->getLength(); - CompilerType builtin_type = - m_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, bytes * 8); + CompilerType builtin_type; + if (bytes > 0) + builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize( + m_ast, *underlying_type_up, encoding, bytes * 8); + else + builtin_type = m_ast.GetBasicType(eBasicTypeInt); + // FIXME: PDB does not have information about scoped enumeration (Enum + // Class). Set it false for now. + bool isScoped = false; CompilerType ast_enum = m_ast.CreateEnumerationType( - name.c_str(), tu_decl_ctx, decl, builtin_type, false); + name.c_str(), tu_decl_ctx, decl, builtin_type, isScoped); auto enum_values = enum_type->findAllChildren<PDBSymbolData>(); - while (auto enum_value = enum_values->getNext()) { - if (enum_value->getDataKind() != PDB_DataKind::Constant) - continue; - AddEnumValue(ast_enum, *enum_value); + if (enum_values) { + while (auto enum_value = enum_values->getNext()) { + if (enum_value->getDataKind() != PDB_DataKind::Constant) + continue; + AddEnumValue(ast_enum, *enum_value); + } } + if (ClangASTContext::StartTagDeclarationDefinition(ast_enum)) + ClangASTContext::CompleteTagDeclarationDefinition(ast_enum); + GetDeclarationForSymbol(type, decl); 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); - } else if (auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type)) { + } break; + case PDB_SymType::Typedef: { + auto type_def = llvm::dyn_cast<PDBSymbolTypeTypedef>(&type); + assert(type_def); lldb_private::Type *target_type = m_ast.GetSymbolFile()->ResolveTypeUID(type_def->getTypeId()); if (!target_type) return nullptr; std::string name = type_def->getName(); uint64_t bytes = type_def->getLength(); - if (!target_type) - return nullptr; CompilerType target_ast_type = target_type->GetFullCompilerType(); CompilerDeclContext target_decl_ctx = m_ast.GetSymbolFile()->GetDeclContextForUID(target_type->GetID()); CompilerType ast_typedef = m_ast.CreateTypedefType(target_ast_type, name.c_str(), target_decl_ctx); + if (!ast_typedef) + return nullptr; + return std::make_shared<lldb_private::Type>( type_def->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, decl, ast_typedef, lldb_private::Type::eResolveStateFull); - } else if (auto func_sig = llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) { + } break; + case PDB_SymType::Function: + case PDB_SymType::FunctionSig: { + std::string name; + PDBSymbolTypeFunctionSig *func_sig = nullptr; + if (auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(&type)) { + if (pdb_func->isCompilerGenerated()) + return nullptr; + + auto sig = pdb_func->getSignature(); + if (!sig) + return nullptr; + func_sig = sig.release(); + // Function type is named. + name = pdb_func->getName(); + } else if (auto pdb_func_sig = + llvm::dyn_cast<PDBSymbolTypeFunctionSig>(&type)) { + func_sig = const_cast<PDBSymbolTypeFunctionSig *>(pdb_func_sig); + } else + llvm_unreachable("Unexpected PDB symbol!"); + auto arg_enum = func_sig->getArguments(); uint32_t num_args = arg_enum->getChildCount(); - std::vector<CompilerType> arg_list(num_args); - while (auto arg = arg_enum->getNext()) { + std::vector<CompilerType> arg_list; + + bool is_variadic = func_sig->isCVarArgs(); + // Drop last variadic argument. + if (is_variadic) + --num_args; + for (uint32_t arg_idx = 0; arg_idx < num_args; arg_idx++) { + auto arg = arg_enum->getChildAtIndex(arg_idx); + if (!arg) + break; lldb_private::Type *arg_type = m_ast.GetSymbolFile()->ResolveTypeUID(arg->getSymIndexId()); // If there's some error looking up one of the dependent types of this @@ -154,6 +349,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { CompilerType arg_ast_type = arg_type->GetFullCompilerType(); arg_list.push_back(arg_ast_type); } + lldbassert(arg_list.size() <= num_args); + auto pdb_return_type = func_sig->getReturnType(); lldb_private::Type *return_type = m_ast.GetSymbolFile()->ResolveTypeUID(pdb_return_type->getSymIndexId()); @@ -167,29 +364,109 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { type_quals |= clang::Qualifiers::Const; if (func_sig->isVolatileType()) type_quals |= clang::Qualifiers::Volatile; - CompilerType func_sig_ast_type = m_ast.CreateFunctionType( - return_ast_type, &arg_list[0], num_args, false, type_quals); + CompilerType func_sig_ast_type = + m_ast.CreateFunctionType(return_ast_type, arg_list.data(), + arg_list.size(), is_variadic, type_quals); + GetDeclarationForSymbol(type, decl); return std::make_shared<lldb_private::Type>( - func_sig->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), 0, + type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), 0, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, func_sig_ast_type, lldb_private::Type::eResolveStateFull); - } else if (auto array_type = llvm::dyn_cast<PDBSymbolTypeArray>(&type)) { + } break; + case PDB_SymType::ArrayType: { + auto array_type = llvm::dyn_cast<PDBSymbolTypeArray>(&type); + assert(array_type); uint32_t num_elements = array_type->getCount(); - uint32_t element_uid = array_type->getElementType()->getSymIndexId(); + uint32_t element_uid = array_type->getElementTypeId(); uint32_t bytes = array_type->getLength(); + // If array rank > 0, PDB gives the element type at N=0. So element type + // will parsed in the order N=0, N=1,..., N=rank sequentially. lldb_private::Type *element_type = m_ast.GetSymbolFile()->ResolveTypeUID(element_uid); if (!element_type) return nullptr; - CompilerType element_ast_type = element_type->GetFullCompilerType(); - CompilerType array_ast_type = - m_ast.CreateArrayType(element_ast_type, num_elements, false); - return std::make_shared<lldb_private::Type>( + + CompilerType element_ast_type = element_type->GetForwardCompilerType(); + // If element type is UDT, it needs to be complete. + if (ClangASTContext::IsCXXClassType(element_ast_type) && + element_ast_type.GetCompleteType() == false) { + if (ClangASTContext::StartTagDeclarationDefinition(element_ast_type)) { + ClangASTContext::CompleteTagDeclarationDefinition(element_ast_type); + } else { + // We are not able to start defintion. + return nullptr; + } + } + CompilerType array_ast_type = m_ast.CreateArrayType( + element_ast_type, num_elements, /*is_gnu_vector*/ false); + 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); + type_sp->SetEncodingType(element_type); + return type_sp; + } break; + case PDB_SymType::BuiltinType: { + auto *builtin_type = llvm::dyn_cast<PDBSymbolTypeBuiltin>(&type); + assert(builtin_type); + PDB_BuiltinType builtin_kind = builtin_type->getBuiltinType(); + if (builtin_kind == PDB_BuiltinType::None) + return nullptr; + + uint64_t bytes = builtin_type->getLength(); + Encoding encoding = TranslateBuiltinEncoding(builtin_kind); + CompilerType builtin_ast_type = GetBuiltinTypeForPDBEncodingAndBitSize( + m_ast, *builtin_type, encoding, bytes * 8); + + if (builtin_type->isConstType()) + builtin_ast_type = builtin_ast_type.AddConstModifier(); + + if (builtin_type->isVolatileType()) + builtin_ast_type = builtin_ast_type.AddVolatileModifier(); + + auto type_name = GetPDBBuiltinTypeName(*builtin_type, builtin_ast_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); + } break; + case PDB_SymType::PointerType: { + auto *pointer_type = llvm::dyn_cast<PDBSymbolTypePointer>(&type); + assert(pointer_type); + Type *pointee_type = m_ast.GetSymbolFile()->ResolveTypeUID( + pointer_type->getPointeeType()->getSymIndexId()); + if (!pointee_type) + return nullptr; + + CompilerType pointer_ast_type; + pointer_ast_type = pointee_type->GetFullCompilerType(); + if (pointer_type->isReference()) + pointer_ast_type = pointer_ast_type.GetLValueReferenceType(); + else if (pointer_type->isRValueReference()) + pointer_ast_type = pointer_ast_type.GetRValueReferenceType(); + else + pointer_ast_type = pointer_ast_type.GetPointerType(); + + if (pointer_type->isConstType()) + pointer_ast_type = pointer_ast_type.AddConstModifier(); + + if (pointer_type->isVolatileType()) + pointer_ast_type = pointer_ast_type.AddVolatileModifier(); + + if (pointer_type->isRestrictedType()) + pointer_ast_type = pointer_ast_type.AddRestrictModifier(); + + return std::make_shared<lldb_private::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); + } break; + default: + break; } return nullptr; } diff --git a/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/source/Plugins/SymbolFile/PDB/PDBASTParser.h index e9ff02c0a77e..d1ac138b8115 100644 --- a/source/Plugins/SymbolFile/PDB/PDBASTParser.h +++ b/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -19,20 +19,20 @@ class CharUnits; class CXXRecordDecl; class FieldDecl; class RecordDecl; -} +} // namespace clang namespace lldb_private { class ClangASTContext; class CompilerType; -} +} // namespace lldb_private namespace llvm { namespace pdb { class PDBSymbol; class PDBSymbolData; class PDBSymbolTypeBuiltin; -} -} +} // namespace pdb +} // namespace llvm class PDBASTParser { public: @@ -49,4 +49,4 @@ private: lldb_private::ClangASTImporter m_ast_importer; }; -#endif // SymbolFileDWARF_DWARFASTParserClang_h_ +#endif // LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H diff --git a/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp new file mode 100644 index 000000000000..69ef70cc508c --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp @@ -0,0 +1,585 @@ +//===-- PDBLocationToDWARFExpression.cpp ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PDBLocationToDWARFExpression.h" + +#include "lldb/Core/Section.h" +#include "lldb/Core/StreamBuffer.h" +#include "lldb/Core/dwarf.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Utility/DataBufferHeap.h" + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm::pdb; + +namespace { +const uint32_t g_code_view_to_lldb_registers_x86[] = { + LLDB_INVALID_REGNUM, // CVRegNONE + lldb_al_i386, // CVRegAL + lldb_cl_i386, // CVRegCL + lldb_dl_i386, // CVRegDL + lldb_bl_i386, // CVRegBL + lldb_ah_i386, // CVRegAH + lldb_ch_i386, // CVRegCH + lldb_dh_i386, // CVRegDH + lldb_bh_i386, // CVRegBH + lldb_ax_i386, // CVRegAX + lldb_cx_i386, // CVRegCX + lldb_dx_i386, // CVRegDX + lldb_bx_i386, // CVRegBX + lldb_sp_i386, // CVRegSP + lldb_bp_i386, // CVRegBP + lldb_si_i386, // CVRegSI + lldb_di_i386, // CVRegDI + lldb_eax_i386, // CVRegEAX + lldb_ecx_i386, // CVRegECX + lldb_edx_i386, // CVRegEDX + lldb_ebx_i386, // CVRegEBX + lldb_esp_i386, // CVRegESP + lldb_ebp_i386, // CVRegEBP + lldb_esi_i386, // CVRegESI + lldb_edi_i386, // CVRegEDI + lldb_es_i386, // CVRegES + lldb_cs_i386, // CVRegCS + lldb_ss_i386, // CVRegSS + lldb_ds_i386, // CVRegDS + lldb_fs_i386, // CVRegFS + lldb_gs_i386, // CVRegGS + LLDB_INVALID_REGNUM, // CVRegIP + LLDB_INVALID_REGNUM, // CVRegFLAGS + lldb_eip_i386, // CVRegEIP + lldb_eflags_i386, // CVRegEFLAGS + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CVRegTEMP + LLDB_INVALID_REGNUM, // CVRegTEMPH + LLDB_INVALID_REGNUM, // CVRegQUOTE + LLDB_INVALID_REGNUM, // CVRegPCDR3 + LLDB_INVALID_REGNUM, // CVRegPCDR4 + LLDB_INVALID_REGNUM, // CVRegPCDR5 + LLDB_INVALID_REGNUM, // CVRegPCDR6 + LLDB_INVALID_REGNUM, // CVRegPCDR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CVRegCR0 + LLDB_INVALID_REGNUM, // CVRegCR1 + LLDB_INVALID_REGNUM, // CVRegCR2 + LLDB_INVALID_REGNUM, // CVRegCR3 + LLDB_INVALID_REGNUM, // CVRegCR4 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_dr0_i386, // CVRegDR0 + lldb_dr1_i386, // CVRegDR1 + lldb_dr2_i386, // CVRegDR2 + lldb_dr3_i386, // CVRegDR3 + lldb_dr4_i386, // CVRegDR4 + lldb_dr5_i386, // CVRegDR5 + lldb_dr6_i386, // CVRegDR6 + lldb_dr7_i386, // CVRegDR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CVRegGDTR + LLDB_INVALID_REGNUM, // CVRegGDTL + LLDB_INVALID_REGNUM, // CVRegIDTR + LLDB_INVALID_REGNUM, // CVRegIDTL + LLDB_INVALID_REGNUM, // CVRegLDTR + LLDB_INVALID_REGNUM, // CVRegTR + LLDB_INVALID_REGNUM, // CVRegPSEUDO1 + LLDB_INVALID_REGNUM, // CVRegPSEUDO2 + LLDB_INVALID_REGNUM, // CVRegPSEUDO3 + LLDB_INVALID_REGNUM, // CVRegPSEUDO4 + LLDB_INVALID_REGNUM, // CVRegPSEUDO5 + LLDB_INVALID_REGNUM, // CVRegPSEUDO6 + LLDB_INVALID_REGNUM, // CVRegPSEUDO7 + LLDB_INVALID_REGNUM, // CVRegPSEUDO8 + LLDB_INVALID_REGNUM, // CVRegPSEUDO9 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_st0_i386, // CVRegST0 + lldb_st1_i386, // CVRegST1 + lldb_st2_i386, // CVRegST2 + lldb_st3_i386, // CVRegST3 + lldb_st4_i386, // CVRegST4 + lldb_st5_i386, // CVRegST5 + lldb_st6_i386, // CVRegST6 + lldb_st7_i386, // CVRegST7 + LLDB_INVALID_REGNUM, // CVRegCTRL + LLDB_INVALID_REGNUM, // CVRegSTAT + LLDB_INVALID_REGNUM, // CVRegTAG + LLDB_INVALID_REGNUM, // CVRegFPIP + LLDB_INVALID_REGNUM, // CVRegFPCS + LLDB_INVALID_REGNUM, // CVRegFPDO + LLDB_INVALID_REGNUM, // CVRegFPDS + LLDB_INVALID_REGNUM, // CVRegISEM + LLDB_INVALID_REGNUM, // CVRegFPEIP + LLDB_INVALID_REGNUM, // CVRegFPEDO + lldb_mm0_i386, // CVRegMM0 + lldb_mm1_i386, // CVRegMM1 + lldb_mm2_i386, // CVRegMM2 + lldb_mm3_i386, // CVRegMM3 + lldb_mm4_i386, // CVRegMM4 + lldb_mm5_i386, // CVRegMM5 + lldb_mm6_i386, // CVRegMM6 + lldb_mm7_i386, // CVRegMM7 + lldb_xmm0_i386, // CVRegXMM0 + lldb_xmm1_i386, // CVRegXMM1 + lldb_xmm2_i386, // CVRegXMM2 + lldb_xmm3_i386, // CVRegXMM3 + lldb_xmm4_i386, // CVRegXMM4 + lldb_xmm5_i386, // CVRegXMM5 + lldb_xmm6_i386, // CVRegXMM6 + lldb_xmm7_i386 // CVRegXMM7 +}; + +const uint32_t g_code_view_to_lldb_registers_x86_64[] = { + LLDB_INVALID_REGNUM, // CVRegNONE + lldb_al_x86_64, // CVRegAL + lldb_cl_x86_64, // CVRegCL + lldb_dl_x86_64, // CVRegDL + lldb_bl_x86_64, // CVRegBL + lldb_ah_x86_64, // CVRegAH + lldb_ch_x86_64, // CVRegCH + lldb_dh_x86_64, // CVRegDH + lldb_bh_x86_64, // CVRegBH + lldb_ax_x86_64, // CVRegAX + lldb_cx_x86_64, // CVRegCX + lldb_dx_x86_64, // CVRegDX + lldb_bx_x86_64, // CVRegBX + lldb_sp_x86_64, // CVRegSP + lldb_bp_x86_64, // CVRegBP + lldb_si_x86_64, // CVRegSI + lldb_di_x86_64, // CVRegDI + lldb_eax_x86_64, // CVRegEAX + lldb_ecx_x86_64, // CVRegECX + lldb_edx_x86_64, // CVRegEDX + lldb_ebx_x86_64, // CVRegEBX + lldb_esp_x86_64, // CVRegESP + lldb_ebp_x86_64, // CVRegEBP + lldb_esi_x86_64, // CVRegESI + lldb_edi_x86_64, // CVRegEDI + lldb_es_x86_64, // CVRegES + lldb_cs_x86_64, // CVRegCS + lldb_ss_x86_64, // CVRegSS + lldb_ds_x86_64, // CVRegDS + lldb_fs_x86_64, // CVRegFS + lldb_gs_x86_64, // CVRegGS + LLDB_INVALID_REGNUM, // CVRegIP + LLDB_INVALID_REGNUM, // CVRegFLAGS + LLDB_INVALID_REGNUM, // CVRegEIP + LLDB_INVALID_REGNUM, // CVRegEFLAGS + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CVRegTEMP + LLDB_INVALID_REGNUM, // CVRegTEMPH + LLDB_INVALID_REGNUM, // CVRegQUOTE + LLDB_INVALID_REGNUM, // CVRegPCDR3 + LLDB_INVALID_REGNUM, // CVRegPCDR4 + LLDB_INVALID_REGNUM, // CVRegPCDR5 + LLDB_INVALID_REGNUM, // CVRegPCDR6 + LLDB_INVALID_REGNUM, // CVRegPCDR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CVRegCR0 + LLDB_INVALID_REGNUM, // CVRegCR1 + LLDB_INVALID_REGNUM, // CVRegCR2 + LLDB_INVALID_REGNUM, // CVRegCR3 + LLDB_INVALID_REGNUM, // CVRegCR4 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_dr0_x86_64, // CVRegDR0 + lldb_dr1_x86_64, // CVRegDR1 + lldb_dr2_x86_64, // CVRegDR2 + lldb_dr3_x86_64, // CVRegDR3 + lldb_dr4_x86_64, // CVRegDR4 + lldb_dr5_x86_64, // CVRegDR5 + lldb_dr6_x86_64, // CVRegDR6 + lldb_dr7_x86_64, // CVRegDR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CVRegGDTR + LLDB_INVALID_REGNUM, // CVRegGDTL + LLDB_INVALID_REGNUM, // CVRegIDTR + LLDB_INVALID_REGNUM, // CVRegIDTL + LLDB_INVALID_REGNUM, // CVRegLDTR + LLDB_INVALID_REGNUM, // CVRegTR + LLDB_INVALID_REGNUM, // CVRegPSEUDO1 + LLDB_INVALID_REGNUM, // CVRegPSEUDO2 + LLDB_INVALID_REGNUM, // CVRegPSEUDO3 + LLDB_INVALID_REGNUM, // CVRegPSEUDO4 + LLDB_INVALID_REGNUM, // CVRegPSEUDO5 + LLDB_INVALID_REGNUM, // CVRegPSEUDO6 + LLDB_INVALID_REGNUM, // CVRegPSEUDO7 + LLDB_INVALID_REGNUM, // CVRegPSEUDO8 + LLDB_INVALID_REGNUM, // CVRegPSEUDO9 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_st0_x86_64, // CVRegST0 + lldb_st1_x86_64, // CVRegST1 + lldb_st2_x86_64, // CVRegST2 + lldb_st3_x86_64, // CVRegST3 + lldb_st4_x86_64, // CVRegST4 + lldb_st5_x86_64, // CVRegST5 + lldb_st6_x86_64, // CVRegST6 + lldb_st7_x86_64, // CVRegST7 + LLDB_INVALID_REGNUM, // CVRegCTRL + LLDB_INVALID_REGNUM, // CVRegSTAT + LLDB_INVALID_REGNUM, // CVRegTAG + LLDB_INVALID_REGNUM, // CVRegFPIP + LLDB_INVALID_REGNUM, // CVRegFPCS + LLDB_INVALID_REGNUM, // CVRegFPDO + LLDB_INVALID_REGNUM, // CVRegFPDS + LLDB_INVALID_REGNUM, // CVRegISEM + LLDB_INVALID_REGNUM, // CVRegFPEIP + LLDB_INVALID_REGNUM, // CVRegFPEDO + lldb_mm0_x86_64, // CVRegMM0 + lldb_mm1_x86_64, // CVRegMM1 + lldb_mm2_x86_64, // CVRegMM2 + lldb_mm3_x86_64, // CVRegMM3 + lldb_mm4_x86_64, // CVRegMM4 + lldb_mm5_x86_64, // CVRegMM5 + lldb_mm6_x86_64, // CVRegMM6 + lldb_mm7_x86_64, // CVRegMM7 + lldb_xmm0_x86_64, // CVRegXMM0 + lldb_xmm1_x86_64, // CVRegXMM1 + lldb_xmm2_x86_64, // CVRegXMM2 + lldb_xmm3_x86_64, // CVRegXMM3 + lldb_xmm4_x86_64, // CVRegXMM4 + lldb_xmm5_x86_64, // CVRegXMM5 + lldb_xmm6_x86_64, // CVRegXMM6 + lldb_xmm7_x86_64, // CVRegXMM7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + lldb_mxcsr_x86_64, // CVRegMXCSR + LLDB_INVALID_REGNUM, // CVRegEDXEAX + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CVRegEMM0L + LLDB_INVALID_REGNUM, // CVRegEMM1L + LLDB_INVALID_REGNUM, // CVRegEMM2L + LLDB_INVALID_REGNUM, // CVRegEMM3L + LLDB_INVALID_REGNUM, // CVRegEMM4L + LLDB_INVALID_REGNUM, // CVRegEMM5L + LLDB_INVALID_REGNUM, // CVRegEMM6L + LLDB_INVALID_REGNUM, // CVRegEMM7L + LLDB_INVALID_REGNUM, // CVRegEMM0H + LLDB_INVALID_REGNUM, // CVRegEMM1H + LLDB_INVALID_REGNUM, // CVRegEMM2H + LLDB_INVALID_REGNUM, // CVRegEMM3H + LLDB_INVALID_REGNUM, // CVRegEMM4H + LLDB_INVALID_REGNUM, // CVRegEMM5H + LLDB_INVALID_REGNUM, // CVRegEMM6H + LLDB_INVALID_REGNUM, // CVRegEMM7H + LLDB_INVALID_REGNUM, // CVRegMM00 + LLDB_INVALID_REGNUM, // CVRegMM01 + LLDB_INVALID_REGNUM, // CVRegMM10 + LLDB_INVALID_REGNUM, // CVRegMM11 + LLDB_INVALID_REGNUM, // CVRegMM20 + LLDB_INVALID_REGNUM, // CVRegMM21 + LLDB_INVALID_REGNUM, // CVRegMM30 + LLDB_INVALID_REGNUM, // CVRegMM31 + LLDB_INVALID_REGNUM, // CVRegMM40 + LLDB_INVALID_REGNUM, // CVRegMM41 + LLDB_INVALID_REGNUM, // CVRegMM50 + LLDB_INVALID_REGNUM, // CVRegMM51 + LLDB_INVALID_REGNUM, // CVRegMM60 + LLDB_INVALID_REGNUM, // CVRegMM61 + LLDB_INVALID_REGNUM, // CVRegMM70 + LLDB_INVALID_REGNUM, // CVRegMM71 + lldb_xmm8_x86_64, // CVRegXMM8 + lldb_xmm9_x86_64, // CVRegXMM9 + lldb_xmm10_x86_64, // CVRegXMM10 + lldb_xmm11_x86_64, // CVRegXMM11 + lldb_xmm12_x86_64, // CVRegXMM12 + lldb_xmm13_x86_64, // CVRegXMM13 + lldb_xmm14_x86_64, // CVRegXMM14 + lldb_xmm15_x86_64, // CVRegXMM15 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + lldb_sil_x86_64, // CVRegSIL + lldb_dil_x86_64, // CVRegDIL + lldb_bpl_x86_64, // CVRegBPL + lldb_spl_x86_64, // CVRegSPL + lldb_rax_x86_64, // CVRegRAX + lldb_rbx_x86_64, // CVRegRBX + lldb_rcx_x86_64, // CVRegRCX + lldb_rdx_x86_64, // CVRegRDX + lldb_rsi_x86_64, // CVRegRSI + lldb_rdi_x86_64, // CVRegRDI + lldb_rbp_x86_64, // CVRegRBP + lldb_rsp_x86_64, // CVRegRSP + lldb_r8_x86_64, // CVRegR8 + lldb_r9_x86_64, // CVRegR9 + lldb_r10_x86_64, // CVRegR10 + lldb_r11_x86_64, // CVRegR11 + lldb_r12_x86_64, // CVRegR12 + lldb_r13_x86_64, // CVRegR13 + lldb_r14_x86_64, // CVRegR14 + lldb_r15_x86_64, // CVRegR15 + lldb_r8l_x86_64, // CVRegR8B + lldb_r9l_x86_64, // CVRegR9B + lldb_r10l_x86_64, // CVRegR10B + lldb_r11l_x86_64, // CVRegR11B + lldb_r12l_x86_64, // CVRegR12B + lldb_r13l_x86_64, // CVRegR13B + lldb_r14l_x86_64, // CVRegR14B + lldb_r15l_x86_64, // CVRegR15B + lldb_r8w_x86_64, // CVRegR8W + lldb_r9w_x86_64, // CVRegR9W + lldb_r10w_x86_64, // CVRegR10W + lldb_r11w_x86_64, // CVRegR11W + lldb_r12w_x86_64, // CVRegR12W + lldb_r13w_x86_64, // CVRegR13W + lldb_r14w_x86_64, // CVRegR14W + lldb_r15w_x86_64, // CVRegR15W + lldb_r8d_x86_64, // CVRegR8D + lldb_r9d_x86_64, // CVRegR9D + lldb_r10d_x86_64, // CVRegR10D + lldb_r11d_x86_64, // CVRegR11D + lldb_r12d_x86_64, // CVRegR12D + lldb_r13d_x86_64, // CVRegR13D + lldb_r14d_x86_64, // CVRegR14D + lldb_r15d_x86_64, // CVRegR15D + lldb_ymm0_x86_64, // CVRegAMD64_YMM0 + lldb_ymm1_x86_64, // CVRegAMD64_YMM1 + lldb_ymm2_x86_64, // CVRegAMD64_YMM2 + lldb_ymm3_x86_64, // CVRegAMD64_YMM3 + lldb_ymm4_x86_64, // CVRegAMD64_YMM4 + lldb_ymm5_x86_64, // CVRegAMD64_YMM5 + lldb_ymm6_x86_64, // CVRegAMD64_YMM6 + lldb_ymm7_x86_64, // CVRegAMD64_YMM7 + lldb_ymm8_x86_64, // CVRegAMD64_YMM8 + lldb_ymm9_x86_64, // CVRegAMD64_YMM9 + lldb_ymm10_x86_64, // CVRegAMD64_YMM10 + lldb_ymm11_x86_64, // CVRegAMD64_YMM11 + lldb_ymm12_x86_64, // CVRegAMD64_YMM12 + lldb_ymm13_x86_64, // CVRegAMD64_YMM13 + lldb_ymm14_x86_64, // CVRegAMD64_YMM14 + lldb_ymm15_x86_64, // CVRegAMD64_YMM15 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_bnd0_x86_64, // CVRegBND0 + lldb_bnd1_x86_64, // CVRegBND1 + lldb_bnd2_x86_64 // CVRegBND2 +}; + +uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type, + llvm::codeview::RegisterId register_id) { + switch (arch_type) { + case llvm::Triple::x86: + if (static_cast<uint16_t>(register_id) < + sizeof(g_code_view_to_lldb_registers_x86) / + sizeof(g_code_view_to_lldb_registers_x86[0])) + return g_code_view_to_lldb_registers_x86[static_cast<uint16_t>( + register_id)]; + + switch (register_id) { + case llvm::codeview::RegisterId::CVRegMXCSR: + return lldb_mxcsr_i386; + case llvm::codeview::RegisterId::CVRegBND0: + return lldb_bnd0_i386; + case llvm::codeview::RegisterId::CVRegBND1: + return lldb_bnd1_i386; + case llvm::codeview::RegisterId::CVRegBND2: + return lldb_bnd2_i386; + default: + return LLDB_INVALID_REGNUM; + } + case llvm::Triple::x86_64: + if (static_cast<uint16_t>(register_id) < + sizeof(g_code_view_to_lldb_registers_x86_64) / + sizeof(g_code_view_to_lldb_registers_x86_64[0])) + return g_code_view_to_lldb_registers_x86_64[static_cast<uint16_t>( + register_id)]; + + return LLDB_INVALID_REGNUM; + default: + return LLDB_INVALID_REGNUM; + } +} + +uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) { + if (register_id == llvm::codeview::RegisterId::CVRegVFRAME) + return LLDB_REGNUM_GENERIC_FP; + + return LLDB_INVALID_REGNUM; +} + +uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type, + llvm::codeview::RegisterId register_id, + RegisterKind ®ister_kind) { + register_kind = eRegisterKindLLDB; + uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id); + if (reg_num != LLDB_INVALID_REGNUM) + return reg_num; + + register_kind = eRegisterKindGeneric; + return GetGenericRegisterNumber(register_id); +} +} // namespace + +DWARFExpression ConvertPDBLocationToDWARFExpression(ModuleSP module, + const PDBSymbolData &symbol, + bool &is_constant) { + is_constant = true; + + if (!module) + return DWARFExpression(nullptr); + + const ArchSpec &architecture = module->GetArchitecture(); + llvm::Triple::ArchType arch_type = architecture.GetMachine(); + ByteOrder byte_order = architecture.GetByteOrder(); + uint32_t address_size = architecture.GetAddressByteSize(); + uint32_t byte_size = architecture.GetDataByteSize(); + if (byte_order == eByteOrderInvalid || address_size == 0) + return DWARFExpression(nullptr); + + RegisterKind register_kind = eRegisterKindDWARF; + StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order); + switch (symbol.getLocationType()) { + case PDB_LocType::Static: + case PDB_LocType::TLS: { + stream.PutHex8(DW_OP_addr); + + SectionList *section_list = module->GetSectionList(); + if (!section_list) + return DWARFExpression(nullptr); + + uint32_t section_idx = symbol.getAddressSection() - 1; + if (section_idx >= section_list->GetSize()) + return DWARFExpression(nullptr); + + auto section = section_list->GetSectionAtIndex(section_idx); + if (!section) + return DWARFExpression(nullptr); + + uint32_t offset = symbol.getAddressOffset(); + stream.PutMaxHex64(section->GetFileAddress() + offset, address_size, + byte_order); + + is_constant = false; + + break; + } + case PDB_LocType::RegRel: { + uint32_t reg_num = + GetRegisterNumber(arch_type, symbol.getRegisterId(), register_kind); + if (reg_num == LLDB_INVALID_REGNUM) + return DWARFExpression(nullptr); + + if (reg_num > 31) { + stream.PutHex8(DW_OP_bregx); + stream.PutULEB128(reg_num); + } else + stream.PutHex8(DW_OP_breg0 + reg_num); + + int32_t offset = symbol.getOffset(); + stream.PutSLEB128(offset); + + is_constant = false; + + break; + } + case PDB_LocType::Enregistered: { + uint32_t reg_num = + GetRegisterNumber(arch_type, symbol.getRegisterId(), register_kind); + if (reg_num == LLDB_INVALID_REGNUM) + return DWARFExpression(nullptr); + + if (reg_num > 31) { + stream.PutHex8(DW_OP_regx); + stream.PutULEB128(reg_num); + } else + stream.PutHex8(DW_OP_reg0 + reg_num); + + is_constant = false; + + break; + } + case PDB_LocType::Constant: { + Variant value = symbol.getValue(); + stream.PutRawBytes(&value.Value, sizeof(value.Value), + endian::InlHostByteOrder()); + break; + } + default: + return DWARFExpression(nullptr); + } + + DataBufferSP buffer = + std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize()); + DataExtractor extractor(buffer, byte_order, address_size, byte_size); + DWARFExpression result(module, extractor, nullptr, 0, buffer->GetByteSize()); + result.SetRegisterKind(register_kind); + + return result; +} diff --git a/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h new file mode 100644 index 000000000000..37b80dfccb84 --- /dev/null +++ b/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h @@ -0,0 +1,45 @@ +//===-- PDBLocationToDWARFExpression.h --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Plugins_SymbolFile_PDB_PDBLocationToDWARFExpression_h_ +#define lldb_Plugins_SymbolFile_PDB_PDBLocationToDWARFExpression_h_ + +#include "lldb/Core/Module.h" + +namespace lldb_private { +class DWARFExpression; +} + +namespace llvm { +namespace pdb { +class PDBSymbolData; +} +} // namespace llvm + +//------------------------------------------------------------------------------ +/// Converts a location information from a PDB symbol to a DWARF expression +/// +/// @param[in] module +/// The module \a symbol belongs to. +/// +/// @param[in] symbol +/// The symbol with a location information to convert. +/// +/// @param[out] is_constant +/// Set to \b true if the result expression is a constant value data, +/// and \b false if it is a DWARF bytecode. +/// +/// @return +/// The DWARF expression corresponding to the location data of \a symbol. +//------------------------------------------------------------------------------ +lldb_private::DWARFExpression +ConvertPDBLocationToDWARFExpression(lldb::ModuleSP module, + const llvm::pdb::PDBSymbolData &symbol, + bool &is_constant); +#endif diff --git a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index de9b9f024fc7..05f3017819fa 100644 --- a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -18,16 +18,21 @@ #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeMap.h" +#include "lldb/Symbol/Variable.h" #include "lldb/Utility/RegularExpression.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBDataStream.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/IPDBTable.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" @@ -35,14 +40,18 @@ #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "Plugins/SymbolFile/PDB/PDBASTParser.h" +#include "Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h" #include <regex> +using namespace lldb; using namespace lldb_private; using namespace llvm::pdb; @@ -63,7 +72,7 @@ bool ShouldAddLine(uint32_t requested_line, uint32_t actual_line, return ((requested_line == 0 || actual_line == requested_line) && addr_length > 0); } -} +} // namespace void SymbolFilePDB::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), @@ -92,7 +101,8 @@ SymbolFilePDB::CreateInstance(lldb_private::ObjectFile *obj_file) { } SymbolFilePDB::SymbolFilePDB(lldb_private::ObjectFile *object_file) - : SymbolFile(object_file), m_cached_compile_unit_count(0) {} + : SymbolFile(object_file), m_session_up(), m_global_scope_up(), + m_cached_compile_unit_count(0), m_tu_decl_ctx_up() {} SymbolFilePDB::~SymbolFilePDB() {} @@ -116,15 +126,14 @@ uint32_t SymbolFilePDB::CalculateAbilities() { if (!symfile) return 0; error = loadDataForPDB(PDB_ReaderType::DIA, - llvm::StringRef(symfile.GetPath()), - m_session_up); + llvm::StringRef(symfile.GetPath()), m_session_up); if (error) { llvm::consumeError(std::move(error)); return 0; } } } - if (!m_session_up.get()) + if (!m_session_up) return 0; auto enum_tables_up = m_session_up->getEnumTables(); @@ -138,13 +147,14 @@ uint32_t SymbolFilePDB::CalculateAbilities() { case PDB_TableType::Symbols: // This table represents a store of symbols with types listed in // PDBSym_Type - abilities |= (CompileUnits | Functions | Blocks | - GlobalVariables | LocalVariables | VariableTypes); + abilities |= (CompileUnits | Functions | Blocks | GlobalVariables | + LocalVariables | VariableTypes); break; case PDB_TableType::LineNumbers: abilities |= LineTables; break; - default: break; + default: + break; } } return abilities; @@ -152,41 +162,88 @@ uint32_t SymbolFilePDB::CalculateAbilities() { void SymbolFilePDB::InitializeObject() { lldb::addr_t obj_load_address = m_obj_file->GetFileOffset(); + lldbassert(obj_load_address && obj_load_address != LLDB_INVALID_ADDRESS); m_session_up->setLoadAddress(obj_load_address); + if (!m_global_scope_up) + m_global_scope_up = m_session_up->getGlobalScope(); + lldbassert(m_global_scope_up.get()); TypeSystem *type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); ClangASTContext *clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system); + lldbassert(clang_type_system); m_tu_decl_ctx_up = llvm::make_unique<CompilerDeclContext>( type_system, clang_type_system->GetTranslationUnitDecl()); } uint32_t SymbolFilePDB::GetNumCompileUnits() { if (m_cached_compile_unit_count == 0) { - auto global = m_session_up->getGlobalScope(); - auto compilands = global->findAllChildren<PDBSymbolCompiland>(); + auto compilands = m_global_scope_up->findAllChildren<PDBSymbolCompiland>(); + if (!compilands) + return 0; + + // The linker could link *.dll (compiland language = LINK), or import + // *.dll. For example, a compiland with name `Import:KERNEL32.dll` could be + // found as a child of the global scope (PDB executable). Usually, such + // compilands contain `thunk` symbols in which we are not interested for + // now. However we still count them in the compiland list. If we perform + // any compiland related activity, like finding symbols through + // llvm::pdb::IPDBSession methods, such compilands will all be searched + // automatically no matter whether we include them or not. m_cached_compile_unit_count = compilands->getChildCount(); // The linker can inject an additional "dummy" compilation unit into the // PDB. Ignore this special compile unit for our purposes, if it is there. // It is always the last one. - auto last_cu = compilands->getChildAtIndex(m_cached_compile_unit_count - 1); - std::string name = last_cu->getName(); + auto last_compiland_up = + compilands->getChildAtIndex(m_cached_compile_unit_count - 1); + lldbassert(last_compiland_up.get()); + std::string name = last_compiland_up->getName(); if (name == "* Linker *") --m_cached_compile_unit_count; } return m_cached_compile_unit_count; } -lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index) { - auto global = m_session_up->getGlobalScope(); - auto compilands = global->findAllChildren<PDBSymbolCompiland>(); - auto cu = compilands->getChildAtIndex(index); +void SymbolFilePDB::GetCompileUnitIndex( + const llvm::pdb::PDBSymbolCompiland &pdb_compiland, uint32_t &index) { + auto results_up = m_global_scope_up->findAllChildren<PDBSymbolCompiland>(); + if (!results_up) + return; + auto uid = pdb_compiland.getSymIndexId(); + for (uint32_t cu_idx = 0; cu_idx < GetNumCompileUnits(); ++cu_idx) { + auto compiland_up = results_up->getChildAtIndex(cu_idx); + if (!compiland_up) + continue; + if (compiland_up->getSymIndexId() == uid) { + index = cu_idx; + return; + } + } + index = UINT32_MAX; + return; +} + +std::unique_ptr<llvm::pdb::PDBSymbolCompiland> +SymbolFilePDB::GetPDBCompilandByUID(uint32_t uid) { + return m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(uid); +} - uint32_t id = cu->getSymIndexId(); +lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitAtIndex(uint32_t index) { + if (index >= GetNumCompileUnits()) + return CompUnitSP(); - return ParseCompileUnitForSymIndex(id); + // Assuming we always retrieve same compilands listed in same order through + // `PDBSymbolExe::findAllChildren` method, otherwise using `index` to get a + // compile unit makes no sense. + auto results = m_global_scope_up->findAllChildren<PDBSymbolCompiland>(); + if (!results) + return CompUnitSP(); + auto compiland_up = results->getChildAtIndex(index); + if (!compiland_up) + return CompUnitSP(); + return ParseCompileUnitForUID(compiland_up->getSymIndexId(), index); } lldb::LanguageType @@ -196,24 +253,71 @@ SymbolFilePDB::ParseCompileUnitLanguage(const lldb_private::SymbolContext &sc) { if (!sc.comp_unit) return lldb::eLanguageTypeUnknown; - auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>( - sc.comp_unit->GetID()); - if (!cu) + auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland_up) return lldb::eLanguageTypeUnknown; - auto details = cu->findOneChild<PDBSymbolCompilandDetails>(); + auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>(); if (!details) return lldb::eLanguageTypeUnknown; return TranslateLanguage(details->getLanguage()); } +lldb_private::Function *SymbolFilePDB::ParseCompileUnitFunctionForPDBFunc( + const PDBSymbolFunc &pdb_func, const lldb_private::SymbolContext &sc) { + lldbassert(sc.comp_unit && sc.module_sp.get()); + + auto file_vm_addr = pdb_func.getVirtualAddress(); + if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0) + return nullptr; + + auto func_length = pdb_func.getLength(); + AddressRange func_range = + AddressRange(file_vm_addr, func_length, sc.module_sp->GetSectionList()); + if (!func_range.GetBaseAddress().IsValid()) + return nullptr; + + lldb_private::Type *func_type = ResolveTypeUID(pdb_func.getSymIndexId()); + if (!func_type) + return nullptr; + + user_id_t func_type_uid = pdb_func.getSignatureId(); + + Mangled mangled = GetMangledForPDBFunc(pdb_func); + + FunctionSP func_sp = + std::make_shared<Function>(sc.comp_unit, pdb_func.getSymIndexId(), + func_type_uid, mangled, func_type, func_range); + + sc.comp_unit->AddFunction(func_sp); + return func_sp.get(); +} + size_t SymbolFilePDB::ParseCompileUnitFunctions( const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + lldbassert(sc.comp_unit); + size_t func_added = 0; + auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland_up) + return 0; + auto results_up = compiland_up->findAllChildren<PDBSymbolFunc>(); + if (!results_up) + return 0; + while (auto pdb_func_up = results_up->getNext()) { + auto func_sp = + sc.comp_unit->FindFunctionByUID(pdb_func_up->getSymIndexId()); + if (!func_sp) { + if (ParseCompileUnitFunctionForPDBFunc(*pdb_func_up, sc)) + ++func_added; + } + } + return func_added; } bool SymbolFilePDB::ParseCompileUnitLineTable( const lldb_private::SymbolContext &sc) { + lldbassert(sc.comp_unit); + if (sc.comp_unit->GetLineTable()) + return true; return ParseCompileUnitLineTable(sc, 0); } @@ -226,26 +330,29 @@ bool SymbolFilePDB::ParseCompileUnitDebugMacros( bool SymbolFilePDB::ParseCompileUnitSupportFiles( const lldb_private::SymbolContext &sc, lldb_private::FileSpecList &support_files) { - if (!sc.comp_unit) - return false; + lldbassert(sc.comp_unit); // In theory this is unnecessary work for us, because all of this information // is easily (and quickly) accessible from DebugInfoPDB, so caching it a // second time seems like a waste. Unfortunately, there's no good way around // this short of a moderate refactor since SymbolVendor depends on being able // to cache this list. - auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>( - sc.comp_unit->GetID()); - if (!cu) + auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland_up) return false; - auto files = m_session_up->getSourceFilesForCompiland(*cu); + auto files = m_session_up->getSourceFilesForCompiland(*compiland_up); if (!files || files->getChildCount() == 0) return false; while (auto file = files->getNext()) { - FileSpec spec(file->getFileName(), false); - support_files.Append(spec); + FileSpec spec(file->getFileName(), false, FileSpec::Style::windows); + 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, *sc.comp_unit); + return true; } @@ -256,21 +363,178 @@ bool SymbolFilePDB::ParseImportedModules( return false; } +static size_t ParseFunctionBlocksForPDBSymbol( + const lldb_private::SymbolContext &sc, uint64_t func_file_vm_addr, + const llvm::pdb::PDBSymbol *pdb_symbol, lldb_private::Block *parent_block, + bool is_top_parent) { + assert(pdb_symbol && parent_block); + + size_t num_added = 0; + switch (pdb_symbol->getSymTag()) { + case PDB_SymType::Block: + case PDB_SymType::Function: { + Block *block = nullptr; + auto &raw_sym = pdb_symbol->getRawSymbol(); + if (auto *pdb_func = llvm::dyn_cast<PDBSymbolFunc>(pdb_symbol)) { + if (pdb_func->hasNoInlineAttribute()) + break; + if (is_top_parent) + block = parent_block; + else + break; + } else if (llvm::dyn_cast<PDBSymbolBlock>(pdb_symbol)) { + auto uid = pdb_symbol->getSymIndexId(); + if (parent_block->FindBlockByID(uid)) + break; + if (raw_sym.getVirtualAddress() < func_file_vm_addr) + break; + + auto block_sp = std::make_shared<Block>(pdb_symbol->getSymIndexId()); + parent_block->AddChild(block_sp); + block = block_sp.get(); + } else + llvm_unreachable("Unexpected PDB symbol!"); + + block->AddRange(Block::Range( + raw_sym.getVirtualAddress() - func_file_vm_addr, raw_sym.getLength())); + block->FinalizeRanges(); + ++num_added; + + auto results_up = pdb_symbol->findAllChildren(); + if (!results_up) + break; + while (auto symbol_up = results_up->getNext()) { + num_added += ParseFunctionBlocksForPDBSymbol( + sc, func_file_vm_addr, symbol_up.get(), block, false); + } + } break; + default: + break; + } + return num_added; +} + size_t SymbolFilePDB::ParseFunctionBlocks(const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + lldbassert(sc.comp_unit && sc.function); + size_t num_added = 0; + auto uid = sc.function->GetID(); + auto pdb_func_up = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(uid); + if (!pdb_func_up) + return 0; + Block &parent_block = sc.function->GetBlock(false); + num_added = + ParseFunctionBlocksForPDBSymbol(sc, pdb_func_up->getVirtualAddress(), + pdb_func_up.get(), &parent_block, true); + return num_added; } size_t SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + lldbassert(sc.module_sp.get()); + if (!sc.comp_unit) + return 0; + + size_t num_added = 0; + auto compiland = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland) + return 0; + + auto ParseTypesByTagFn = [&num_added, this](const PDBSymbol &raw_sym) { + std::unique_ptr<IPDBEnumSymbols> results; + PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef, + PDB_SymType::UDT}; + for (auto tag : tags_to_search) { + results = raw_sym.findAllChildren(tag); + if (!results || results->getChildCount() == 0) + continue; + while (auto symbol = results->getNext()) { + switch (symbol->getSymTag()) { + case PDB_SymType::Enum: + case PDB_SymType::UDT: + case PDB_SymType::Typedef: + break; + default: + continue; + } + + // This should cause the type to get cached and stored in the `m_types` + // lookup. + if (!ResolveTypeUID(symbol->getSymIndexId())) + continue; + + ++num_added; + } + } + }; + + if (sc.function) { + auto pdb_func = m_session_up->getConcreteSymbolById<PDBSymbolFunc>( + sc.function->GetID()); + if (!pdb_func) + return 0; + ParseTypesByTagFn(*pdb_func); + } else { + ParseTypesByTagFn(*compiland); + + // Also parse global types particularly coming from this compiland. + // Unfortunately, PDB has no compiland information for each global type. We + // have to parse them all. But ensure we only do this once. + static bool parse_all_global_types = false; + if (!parse_all_global_types) { + ParseTypesByTagFn(*m_global_scope_up); + parse_all_global_types = true; + } + } + return num_added; } size_t SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + if (!sc.comp_unit) + return 0; + + size_t num_added = 0; + if (sc.function) { + auto pdb_func = m_session_up->getConcreteSymbolById<PDBSymbolFunc>( + sc.function->GetID()); + if (!pdb_func) + return 0; + + num_added += ParseVariables(sc, *pdb_func); + sc.function->GetBlock(false).SetDidParseVariables(true, true); + } else if (sc.comp_unit) { + auto compiland = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland) + return 0; + + if (sc.comp_unit->GetVariableList(false)) + return 0; + + auto results = m_global_scope_up->findAllChildren<PDBSymbolData>(); + if (results && results->getChildCount()) { + while (auto result = results->getNext()) { + auto cu_id = result->getCompilandId(); + // FIXME: We are not able to determine variable's compile unit. + if (cu_id == 0) + continue; + + if (cu_id == sc.comp_unit->GetID()) + num_added += ParseVariables(sc, *result); + } + } + + // FIXME: A `file static` or `global constant` variable appears both in + // compiland's children and global scope's children with unexpectedly + // different symbol's Id making it ambiguous. + + // FIXME: 'local constant', for example, const char var[] = "abc", declared + // in a function scope, can't be found in PDB. + + // Parse variables in this compiland. + num_added += ParseVariables(sc, *compiland); + } + + return num_added; } lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { @@ -294,8 +558,12 @@ lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) { return nullptr; lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type); - if (result.get()) + if (result) { m_types.insert(std::make_pair(type_uid, result)); + auto type_list = GetTypeList(); + if (type_list) + type_list->Insert(result); + } return result.get(); } @@ -328,12 +596,62 @@ uint32_t SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, uint32_t resolve_scope, lldb_private::SymbolContext &sc) { - return uint32_t(); + uint32_t resolved_flags = 0; + if (resolve_scope & eSymbolContextCompUnit || + resolve_scope & eSymbolContextVariable || + resolve_scope & eSymbolContextFunction || + resolve_scope & eSymbolContextBlock || + resolve_scope & eSymbolContextLineEntry) { + auto cu_sp = GetCompileUnitContainsAddress(so_addr); + if (!cu_sp) { + if (resolved_flags | eSymbolContextVariable) { + // TODO: Resolve variables + } + return 0; + } + sc.comp_unit = cu_sp.get(); + resolved_flags |= eSymbolContextCompUnit; + lldbassert(sc.module_sp == cu_sp->GetModule()); + } + + if (resolve_scope & eSymbolContextFunction) { + addr_t file_vm_addr = so_addr.GetFileAddress(); + auto symbol_up = + m_session_up->findSymbolByAddress(file_vm_addr, PDB_SymType::Function); + if (symbol_up) { + auto *pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get()); + assert(pdb_func); + auto func_uid = pdb_func->getSymIndexId(); + sc.function = sc.comp_unit->FindFunctionByUID(func_uid).get(); + if (sc.function == nullptr) + sc.function = ParseCompileUnitFunctionForPDBFunc(*pdb_func, sc); + if (sc.function) { + resolved_flags |= eSymbolContextFunction; + if (resolve_scope & eSymbolContextBlock) { + Block &block = sc.function->GetBlock(true); + sc.block = block.FindBlockByID(sc.function->GetID()); + if (sc.block) + resolved_flags |= eSymbolContextBlock; + } + } + } + } + + if (resolve_scope & eSymbolContextLineEntry) { + if (auto *line_table = sc.comp_unit->GetLineTable()) { + Address addr(so_addr); + if (line_table->FindLineEntryByAddress(addr, sc.line_entry)) + resolved_flags |= eSymbolContextLineEntry; + } + } + + return resolved_flags; } uint32_t SymbolFilePDB::ResolveSymbolContext( const lldb_private::FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList &sc_list) { + const size_t old_size = sc_list.GetSize(); if (resolve_scope & lldb::eSymbolContextCompUnit) { // Locate all compilation units with line numbers referencing the specified // file. For example, if `file_spec` is <vector>, then this should return @@ -342,56 +660,498 @@ uint32_t SymbolFilePDB::ResolveSymbolContext( auto compilands = m_session_up->findCompilandsForSourceFile( file_spec.GetPath(), PDB_NameSearchFlags::NS_CaseInsensitive); + if (!compilands) + return 0; + // For each one, either find its previously parsed data or parse it afresh // and add it to the symbol context list. while (auto compiland = compilands->getNext()) { - // If we're not checking inlines, then don't add line information for this - // file unless the FileSpec matches. + // If we're not checking inlines, then don't add line information for + // this file unless the FileSpec matches. For inline functions, we don't + // have to match the FileSpec since they could be defined in headers + // other than file specified in FileSpec. if (!check_inlines) { - // `getSourceFileName` returns the basename of the original source file - // used to generate this compiland. It does not return the full path. - // Currently the only way to get that is to do a basename lookup to get - // the IPDBSourceFile, but this is ambiguous in the case of two source - // files with the same name contributing to the same compiland. This is - // a moderately extreme edge case, so we consider this OK for now, - // although we need to find a long-term solution. - std::string source_file = compiland->getSourceFileName(); - auto pdb_file = m_session_up->findOneSourceFile( - compiland.get(), source_file, - PDB_NameSearchFlags::NS_CaseInsensitive); - source_file = pdb_file->getFileName(); - FileSpec this_spec(source_file, false, FileSpec::ePathSyntaxWindows); - if (!file_spec.FileEquals(this_spec)) + std::string source_file = compiland->getSourceFileFullPath(); + if (source_file.empty()) + continue; + FileSpec this_spec(source_file, false, FileSpec::Style::windows); + bool need_full_match = !file_spec.GetDirectory().IsEmpty(); + if (FileSpec::Compare(file_spec, this_spec, need_full_match) != 0) continue; } SymbolContext sc; - auto cu = ParseCompileUnitForSymIndex(compiland->getSymIndexId()); + auto cu = ParseCompileUnitForUID(compiland->getSymIndexId()); + if (!cu) + continue; sc.comp_unit = cu.get(); sc.module_sp = cu->GetModule(); - sc_list.Append(sc); // If we were asked to resolve line entries, add all entries to the line // table that match the requested line (or all lines if `line` == 0). - if (resolve_scope & lldb::eSymbolContextLineEntry) - ParseCompileUnitLineTable(sc, line); + if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock | + eSymbolContextLineEntry)) { + bool has_line_table = ParseCompileUnitLineTable(sc, line); + + if ((resolve_scope & eSymbolContextLineEntry) && !has_line_table) { + // The query asks for line entries, but we can't get them for the + // compile unit. This is not normal for `line` = 0. So just assert + // it. + assert(line && "Couldn't get all line entries!\n"); + + // Current compiland does not have the requested line. Search next. + continue; + } + + if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock)) { + if (!has_line_table) + continue; + + auto *line_table = sc.comp_unit->GetLineTable(); + lldbassert(line_table); + + uint32_t num_line_entries = line_table->GetSize(); + // Skip the terminal line entry. + --num_line_entries; + + // If `line `!= 0, see if we can resolve function for each line entry + // in the line table. + for (uint32_t line_idx = 0; line && line_idx < num_line_entries; + ++line_idx) { + if (!line_table->GetLineEntryAtIndex(line_idx, sc.line_entry)) + continue; + + auto file_vm_addr = + sc.line_entry.range.GetBaseAddress().GetFileAddress(); + if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0) + continue; + + auto symbol_up = m_session_up->findSymbolByAddress( + file_vm_addr, PDB_SymType::Function); + if (symbol_up) { + auto func_uid = symbol_up->getSymIndexId(); + sc.function = sc.comp_unit->FindFunctionByUID(func_uid).get(); + if (sc.function == nullptr) { + auto pdb_func = llvm::dyn_cast<PDBSymbolFunc>(symbol_up.get()); + assert(pdb_func); + sc.function = ParseCompileUnitFunctionForPDBFunc(*pdb_func, sc); + } + if (sc.function && (resolve_scope & eSymbolContextBlock)) { + Block &block = sc.function->GetBlock(true); + sc.block = block.FindBlockByID(sc.function->GetID()); + } + } + sc_list.Append(sc); + } + } else if (has_line_table) { + // We can parse line table for the compile unit. But no query to + // resolve function or block. We append `sc` to the list anyway. + sc_list.Append(sc); + } + } else { + // No query for line entry, function or block. But we have a valid + // compile unit, append `sc` to the list. + sc_list.Append(sc); + } + } + } + return sc_list.GetSize() - old_size; +} + +std::string SymbolFilePDB::GetMangledForPDBData(const PDBSymbolData &pdb_data) { + std::string decorated_name; + auto vm_addr = pdb_data.getVirtualAddress(); + if (vm_addr != LLDB_INVALID_ADDRESS && vm_addr) { + auto result_up = + m_global_scope_up->findAllChildren(PDB_SymType::PublicSymbol); + if (result_up) { + while (auto symbol_up = result_up->getNext()) { + if (symbol_up->getRawSymbol().getVirtualAddress() == vm_addr) { + decorated_name = symbol_up->getRawSymbol().getName(); + break; + } + } + } + } + if (!decorated_name.empty()) + return decorated_name; + + return std::string(); +} + +VariableSP SymbolFilePDB::ParseVariableForPDBData( + const lldb_private::SymbolContext &sc, + const llvm::pdb::PDBSymbolData &pdb_data) { + VariableSP var_sp; + uint32_t var_uid = pdb_data.getSymIndexId(); + auto result = m_variables.find(var_uid); + if (result != m_variables.end()) + return result->second; + + ValueType scope = eValueTypeInvalid; + bool is_static_member = false; + bool is_external = false; + bool is_artificial = false; + + switch (pdb_data.getDataKind()) { + case PDB_DataKind::Global: + scope = eValueTypeVariableGlobal; + is_external = true; + break; + case PDB_DataKind::Local: + scope = eValueTypeVariableLocal; + break; + case PDB_DataKind::FileStatic: + scope = eValueTypeVariableStatic; + break; + case PDB_DataKind::StaticMember: + is_static_member = true; + scope = eValueTypeVariableStatic; + break; + case PDB_DataKind::Member: + scope = eValueTypeVariableStatic; + break; + case PDB_DataKind::Param: + scope = eValueTypeVariableArgument; + break; + case PDB_DataKind::Constant: + scope = eValueTypeConstResult; + break; + default: + break; + } + + switch (pdb_data.getLocationType()) { + case PDB_LocType::TLS: + scope = eValueTypeVariableThreadLocal; + break; + case PDB_LocType::RegRel: { + // It is a `this` pointer. + if (pdb_data.getDataKind() == PDB_DataKind::ObjectPtr) { + scope = eValueTypeVariableArgument; + is_artificial = true; + } + } break; + default: + break; + } + + Declaration decl; + if (!is_artificial && !pdb_data.isCompilerGenerated()) { + if (auto lines = pdb_data.getLineNumbers()) { + if (auto first_line = lines->getNext()) { + uint32_t src_file_id = first_line->getSourceFileId(); + auto src_file = m_session_up->getSourceFileById(src_file_id); + if (src_file) { + FileSpec spec(src_file->getFileName(), /*resolve_path*/ false); + decl.SetFile(spec); + decl.SetColumn(first_line->getColumnNumber()); + decl.SetLine(first_line->getLineNumber()); + } + } + } + } + + Variable::RangeList ranges; + SymbolContextScope *context_scope = sc.comp_unit; + if (scope == eValueTypeVariableLocal) { + if (sc.function) { + context_scope = sc.function->GetBlock(true).FindBlockByID( + pdb_data.getClassParentId()); + if (context_scope == nullptr) + context_scope = sc.function; + } + } + + SymbolFileTypeSP type_sp = + std::make_shared<SymbolFileType>(*this, pdb_data.getTypeId()); + + auto var_name = pdb_data.getName(); + auto mangled = GetMangledForPDBData(pdb_data); + auto mangled_cstr = mangled.empty() ? nullptr : mangled.c_str(); + + bool is_constant; + DWARFExpression location = ConvertPDBLocationToDWARFExpression( + GetObjectFile()->GetModule(), pdb_data, is_constant); + + var_sp = std::make_shared<Variable>( + var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope, + ranges, &decl, location, is_external, is_artificial, is_static_member); + var_sp->SetLocationIsConstantValueData(is_constant); + + m_variables.insert(std::make_pair(var_uid, var_sp)); + return var_sp; +} + +size_t +SymbolFilePDB::ParseVariables(const lldb_private::SymbolContext &sc, + const llvm::pdb::PDBSymbol &pdb_symbol, + lldb_private::VariableList *variable_list) { + size_t num_added = 0; + + if (auto pdb_data = llvm::dyn_cast<PDBSymbolData>(&pdb_symbol)) { + VariableListSP local_variable_list_sp; + + auto result = m_variables.find(pdb_data->getSymIndexId()); + if (result != m_variables.end()) { + if (variable_list) + variable_list->AddVariableIfUnique(result->second); + } else { + // Prepare right VariableList for this variable. + if (auto lexical_parent = pdb_data->getLexicalParent()) { + switch (lexical_parent->getSymTag()) { + case PDB_SymType::Exe: + assert(sc.comp_unit); + LLVM_FALLTHROUGH; + case PDB_SymType::Compiland: { + if (sc.comp_unit) { + local_variable_list_sp = sc.comp_unit->GetVariableList(false); + if (!local_variable_list_sp) { + local_variable_list_sp = std::make_shared<VariableList>(); + sc.comp_unit->SetVariableList(local_variable_list_sp); + } + } + } break; + case PDB_SymType::Block: + case PDB_SymType::Function: { + if (sc.function) { + Block *block = sc.function->GetBlock(true).FindBlockByID( + lexical_parent->getSymIndexId()); + if (block) { + local_variable_list_sp = block->GetBlockVariableList(false); + if (!local_variable_list_sp) { + local_variable_list_sp = std::make_shared<VariableList>(); + block->SetVariableList(local_variable_list_sp); + } + } + } + } break; + default: + break; + } + } + + if (local_variable_list_sp) { + if (auto var_sp = ParseVariableForPDBData(sc, *pdb_data)) { + local_variable_list_sp->AddVariableIfUnique(var_sp); + if (variable_list) + variable_list->AddVariableIfUnique(var_sp); + ++num_added; + } + } } } - return sc_list.GetSize(); + + if (auto results = pdb_symbol.findAllChildren()) { + while (auto result = results->getNext()) + num_added += ParseVariables(sc, *result, variable_list); + } + + return num_added; } uint32_t SymbolFilePDB::FindGlobalVariables( const lldb_private::ConstString &name, - const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append, + const lldb_private::CompilerDeclContext *parent_decl_ctx, uint32_t max_matches, lldb_private::VariableList &variables) { - return uint32_t(); + if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) + return 0; + if (name.IsEmpty()) + return 0; + + auto results = + m_global_scope_up->findChildren(PDB_SymType::Data, name.GetStringRef(), + PDB_NameSearchFlags::NS_CaseSensitive); + if (!results) + return 0; + + uint32_t matches = 0; + size_t old_size = variables.GetSize(); + while (auto result = results->getNext()) { + auto pdb_data = llvm::dyn_cast<PDBSymbolData>(result.get()); + if (max_matches > 0 && matches >= max_matches) + break; + + SymbolContext sc; + sc.module_sp = m_obj_file->GetModule(); + lldbassert(sc.module_sp.get()); + + sc.comp_unit = ParseCompileUnitForUID(pdb_data->getCompilandId()).get(); + // FIXME: We are not able to determine the compile unit. + if (sc.comp_unit == nullptr) + continue; + + ParseVariables(sc, *pdb_data, &variables); + matches = variables.GetSize() - old_size; + } + + return matches; } uint32_t SymbolFilePDB::FindGlobalVariables(const lldb_private::RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) { - return uint32_t(); + if (!regex.IsValid()) + return 0; + auto results = m_global_scope_up->findAllChildren<PDBSymbolData>(); + if (!results) + return 0; + + uint32_t matches = 0; + size_t old_size = variables.GetSize(); + while (auto pdb_data = results->getNext()) { + if (max_matches > 0 && matches >= max_matches) + break; + + auto var_name = pdb_data->getName(); + if (var_name.empty()) + continue; + if (!regex.Execute(var_name)) + continue; + SymbolContext sc; + sc.module_sp = m_obj_file->GetModule(); + lldbassert(sc.module_sp.get()); + + sc.comp_unit = ParseCompileUnitForUID(pdb_data->getCompilandId()).get(); + // FIXME: We are not able to determine the compile unit. + if (sc.comp_unit == nullptr) + continue; + + ParseVariables(sc, *pdb_data, &variables); + matches = variables.GetSize() - old_size; + } + + return matches; +} + +bool SymbolFilePDB::ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func, + bool include_inlines, + lldb_private::SymbolContextList &sc_list) { + lldb_private::SymbolContext sc; + sc.comp_unit = ParseCompileUnitForUID(pdb_func.getCompilandId()).get(); + if (!sc.comp_unit) + return false; + sc.module_sp = sc.comp_unit->GetModule(); + sc.function = ParseCompileUnitFunctionForPDBFunc(pdb_func, sc); + if (!sc.function) + return false; + + sc_list.Append(sc); + return true; +} + +bool SymbolFilePDB::ResolveFunction(uint32_t uid, bool include_inlines, + lldb_private::SymbolContextList &sc_list) { + auto pdb_func_up = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(uid); + if (!pdb_func_up && !(include_inlines && pdb_func_up->hasInlineAttribute())) + return false; + return ResolveFunction(*pdb_func_up, include_inlines, sc_list); +} + +void SymbolFilePDB::CacheFunctionNames() { + if (!m_func_full_names.IsEmpty()) + return; + + std::map<uint64_t, uint32_t> addr_ids; + + if (auto results_up = m_global_scope_up->findAllChildren<PDBSymbolFunc>()) { + while (auto pdb_func_up = results_up->getNext()) { + if (pdb_func_up->isCompilerGenerated()) + continue; + + auto name = pdb_func_up->getName(); + auto demangled_name = pdb_func_up->getUndecoratedName(); + if (name.empty() && demangled_name.empty()) + continue; + + auto uid = pdb_func_up->getSymIndexId(); + if (!demangled_name.empty() && pdb_func_up->getVirtualAddress()) + addr_ids.insert(std::make_pair(pdb_func_up->getVirtualAddress(), uid)); + + if (auto parent = pdb_func_up->getClassParent()) { + + // PDB have symbols for class/struct methods or static methods in Enum + // Class. We won't bother to check if the parent is UDT or Enum here. + m_func_method_names.Append(ConstString(name), uid); + + ConstString cstr_name(name); + + // To search a method name, like NS::Class:MemberFunc, LLDB searches + // its base name, i.e. MemberFunc by default. Since PDBSymbolFunc does + // not have inforamtion of this, we extract base names and cache them + // by our own effort. + llvm::StringRef basename; + CPlusPlusLanguage::MethodName cpp_method(cstr_name); + if (cpp_method.IsValid()) { + llvm::StringRef context; + basename = cpp_method.GetBasename(); + if (basename.empty()) + CPlusPlusLanguage::ExtractContextAndIdentifier(name.c_str(), + context, basename); + } + + if (!basename.empty()) + m_func_base_names.Append(ConstString(basename), uid); + else { + m_func_base_names.Append(ConstString(name), uid); + } + + if (!demangled_name.empty()) + m_func_full_names.Append(ConstString(demangled_name), uid); + + } else { + // Handle not-method symbols. + + // The function name might contain namespace, or its lexical scope. It + // is not safe to get its base name by applying same scheme as we deal + // with the method names. + // FIXME: Remove namespace if function is static in a scope. + m_func_base_names.Append(ConstString(name), uid); + + if (name == "main") { + m_func_full_names.Append(ConstString(name), uid); + + if (!demangled_name.empty() && name != demangled_name) { + m_func_full_names.Append(ConstString(demangled_name), uid); + m_func_base_names.Append(ConstString(demangled_name), uid); + } + } else if (!demangled_name.empty()) { + m_func_full_names.Append(ConstString(demangled_name), uid); + } else { + m_func_full_names.Append(ConstString(name), uid); + } + } + } + } + + if (auto results_up = + m_global_scope_up->findAllChildren<PDBSymbolPublicSymbol>()) { + while (auto pub_sym_up = results_up->getNext()) { + if (!pub_sym_up->isFunction()) + continue; + auto name = pub_sym_up->getName(); + if (name.empty()) + continue; + + if (CPlusPlusLanguage::IsCPPMangledName(name.c_str())) { + auto vm_addr = pub_sym_up->getVirtualAddress(); + + // PDB public symbol has mangled name for its associated function. + if (vm_addr && addr_ids.find(vm_addr) != addr_ids.end()) { + // Cache mangled name. + m_func_full_names.Append(ConstString(name), addr_ids[vm_addr]); + } + } + } + } + // Sort them before value searching is working properly + m_func_full_names.Sort(); + m_func_full_names.SizeToFit(); + m_func_method_names.Sort(); + m_func_method_names.SizeToFit(); + m_func_base_names.Sort(); + m_func_base_names.SizeToFit(); } uint32_t SymbolFilePDB::FindFunctions( @@ -399,14 +1159,77 @@ uint32_t SymbolFilePDB::FindFunctions( const lldb_private::CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList &sc_list) { - return uint32_t(); + if (!append) + sc_list.Clear(); + lldbassert((name_type_mask & eFunctionNameTypeAuto) == 0); + + if (name_type_mask == eFunctionNameTypeNone) + return 0; + if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) + return 0; + if (name.IsEmpty()) + return 0; + + auto old_size = sc_list.GetSize(); + if (name_type_mask & eFunctionNameTypeFull || + name_type_mask & eFunctionNameTypeBase || + name_type_mask & eFunctionNameTypeMethod) { + CacheFunctionNames(); + + std::set<uint32_t> resolved_ids; + auto ResolveFn = [include_inlines, &name, &sc_list, &resolved_ids, + this](UniqueCStringMap<uint32_t> &Names) { + std::vector<uint32_t> ids; + if (Names.GetValues(name, ids)) { + for (auto id : ids) { + if (resolved_ids.find(id) == resolved_ids.end()) { + if (ResolveFunction(id, include_inlines, sc_list)) + resolved_ids.insert(id); + } + } + } + }; + if (name_type_mask & eFunctionNameTypeFull) { + ResolveFn(m_func_full_names); + } + if (name_type_mask & eFunctionNameTypeBase) { + ResolveFn(m_func_base_names); + } + if (name_type_mask & eFunctionNameTypeMethod) { + ResolveFn(m_func_method_names); + } + } + return sc_list.GetSize() - old_size; } uint32_t SymbolFilePDB::FindFunctions(const lldb_private::RegularExpression ®ex, bool include_inlines, bool append, lldb_private::SymbolContextList &sc_list) { - return uint32_t(); + if (!append) + sc_list.Clear(); + if (!regex.IsValid()) + return 0; + + auto old_size = sc_list.GetSize(); + CacheFunctionNames(); + + std::set<uint32_t> resolved_ids; + auto ResolveFn = [®ex, include_inlines, &sc_list, &resolved_ids, + this](UniqueCStringMap<uint32_t> &Names) { + std::vector<uint32_t> ids; + if (Names.GetValues(regex, ids)) { + for (auto id : ids) { + if (resolved_ids.find(id) == resolved_ids.end()) + if (ResolveFunction(id, include_inlines, sc_list)) + resolved_ids.insert(id); + } + } + }; + ResolveFn(m_func_full_names); + ResolveFn(m_func_base_names); + + return sc_list.GetSize() - old_size; } void SymbolFilePDB::GetMangledNamesForFunction( @@ -424,6 +1247,8 @@ uint32_t SymbolFilePDB::FindTypes( types.Clear(); if (!name) return 0; + if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) + return 0; searched_symbol_files.clear(); searched_symbol_files.insert(this); @@ -432,14 +1257,13 @@ uint32_t SymbolFilePDB::FindTypes( // There is an assumption 'name' is not a regex FindTypesByName(name_str, max_matches, types); - + return types.GetSize(); } -void -SymbolFilePDB::FindTypesByRegex(const lldb_private::RegularExpression ®ex, - uint32_t max_matches, - lldb_private::TypeMap &types) { +void SymbolFilePDB::FindTypesByRegex( + const lldb_private::RegularExpression ®ex, uint32_t max_matches, + lldb_private::TypeMap &types) { // When searching by regex, we need to go out of our way to limit the search // space as much as possible since this searches EVERYTHING in the PDB, // manually doing regex comparisons. PDB library isn't optimized for regex @@ -448,13 +1272,15 @@ SymbolFilePDB::FindTypesByRegex(const lldb_private::RegularExpression ®ex, // and do a regex comparison against each of them. PDB_SymType tags_to_search[] = {PDB_SymType::Enum, PDB_SymType::Typedef, PDB_SymType::UDT}; - auto global = m_session_up->getGlobalScope(); std::unique_ptr<IPDBEnumSymbols> results; uint32_t matches = 0; for (auto tag : tags_to_search) { - results = global->findAllChildren(tag); + results = m_global_scope_up->findAllChildren(tag); + if (!results) + continue; + while (auto result = results->getNext()) { if (max_matches > 0 && matches >= max_matches) break; @@ -493,10 +1319,13 @@ SymbolFilePDB::FindTypesByRegex(const lldb_private::RegularExpression ®ex, void SymbolFilePDB::FindTypesByName(const std::string &name, uint32_t max_matches, lldb_private::TypeMap &types) { - auto global = m_session_up->getGlobalScope(); std::unique_ptr<IPDBEnumSymbols> results; - results = global->findChildren(PDB_SymType::None, name, - PDB_NameSearchFlags::NS_Default); + if (name.empty()) + return; + results = m_global_scope_up->findChildren(PDB_SymType::None, name, + PDB_NameSearchFlags::NS_Default); + if (!results) + return; uint32_t matches = 0; @@ -509,8 +1338,8 @@ void SymbolFilePDB::FindTypesByName(const std::string &name, case PDB_SymType::Typedef: break; default: - // We're looking only for types that have names. Skip symbols, as well as - // unnamed types such as arrays, pointers, etc. + // We're looking only for types that have names. Skip symbols, as well + // as unnamed types such as arrays, pointers, etc. continue; } @@ -533,12 +1362,87 @@ size_t SymbolFilePDB::FindTypes( return 0; } -lldb_private::TypeList *SymbolFilePDB::GetTypeList() { return nullptr; } +lldb_private::TypeList *SymbolFilePDB::GetTypeList() { + return m_obj_file->GetModule()->GetTypeList(); +} + +void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol, + uint32_t type_mask, + TypeCollection &type_collection) { + bool can_parse = false; + switch (pdb_symbol.getSymTag()) { + case PDB_SymType::ArrayType: + can_parse = ((type_mask & eTypeClassArray) != 0); + break; + case PDB_SymType::BuiltinType: + can_parse = ((type_mask & eTypeClassBuiltin) != 0); + break; + case PDB_SymType::Enum: + can_parse = ((type_mask & eTypeClassEnumeration) != 0); + break; + case PDB_SymType::Function: + case PDB_SymType::FunctionSig: + can_parse = ((type_mask & eTypeClassFunction) != 0); + break; + case PDB_SymType::PointerType: + can_parse = ((type_mask & (eTypeClassPointer | eTypeClassBlockPointer | + eTypeClassMemberPointer)) != 0); + break; + case PDB_SymType::Typedef: + can_parse = ((type_mask & eTypeClassTypedef) != 0); + break; + case PDB_SymType::UDT: { + auto *udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&pdb_symbol); + assert(udt); + can_parse = (udt->getUdtKind() != PDB_UdtType::Interface && + ((type_mask & (eTypeClassClass | eTypeClassStruct | + eTypeClassUnion)) != 0)); + } break; + default: + break; + } + + if (can_parse) { + if (auto *type = ResolveTypeUID(pdb_symbol.getSymIndexId())) { + auto result = + std::find(type_collection.begin(), type_collection.end(), type); + if (result == type_collection.end()) + type_collection.push_back(type); + } + } + + auto results_up = pdb_symbol.findAllChildren(); + while (auto symbol_up = results_up->getNext()) + GetTypesForPDBSymbol(*symbol_up, type_mask, type_collection); +} size_t SymbolFilePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, uint32_t type_mask, lldb_private::TypeList &type_list) { - return size_t(); + TypeCollection type_collection; + uint32_t old_size = type_list.GetSize(); + CompileUnit *cu = + sc_scope ? sc_scope->CalculateSymbolContextCompileUnit() : nullptr; + if (cu) { + auto compiland_up = GetPDBCompilandByUID(cu->GetID()); + if (!compiland_up) + return 0; + GetTypesForPDBSymbol(*compiland_up, type_mask, type_collection); + } else { + for (uint32_t cu_idx = 0; cu_idx < GetNumCompileUnits(); ++cu_idx) { + auto cu_sp = ParseCompileUnitAtIndex(cu_idx); + if (cu_sp) { + if (auto compiland_up = GetPDBCompilandByUID(cu_sp->GetID())) + GetTypesForPDBSymbol(*compiland_up, type_mask, type_collection); + } + } + } + + for (auto type : type_collection) { + type->GetForwardCompilerType(); + type_list.Insert(type->shared_from_this()); + } + return type_list.GetSize() - old_size; } lldb_private::TypeSystem * @@ -570,65 +1474,78 @@ const IPDBSession &SymbolFilePDB::GetPDBSession() const { return *m_session_up; } -lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForSymIndex(uint32_t id) { +lldb::CompUnitSP SymbolFilePDB::ParseCompileUnitForUID(uint32_t id, + uint32_t index) { auto found_cu = m_comp_units.find(id); if (found_cu != m_comp_units.end()) return found_cu->second; - auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>(id); - - // `getSourceFileName` returns the basename of the original source file used - // to generate this compiland. It does not return the full path. Currently - // the only way to get that is to do a basename lookup to get the - // IPDBSourceFile, but this is ambiguous in the case of two source files with - // the same name contributing to the same compiland. This is a moderately - // extreme edge case, so we consider this OK for now, although we need to find - // a long-term solution. - auto file = - m_session_up->findOneSourceFile(cu.get(), cu->getSourceFileName(), - PDB_NameSearchFlags::NS_CaseInsensitive); - std::string path = file->getFileName(); + auto compiland_up = GetPDBCompilandByUID(id); + if (!compiland_up) + return CompUnitSP(); lldb::LanguageType lang; - auto details = cu->findOneChild<PDBSymbolCompilandDetails>(); + auto details = compiland_up->findOneChild<PDBSymbolCompilandDetails>(); if (!details) lang = lldb::eLanguageTypeC_plus_plus; else lang = TranslateLanguage(details->getLanguage()); + if (lang == lldb::LanguageType::eLanguageTypeUnknown) + return CompUnitSP(); + + std::string path = compiland_up->getSourceFileFullPath(); + if (path.empty()) + return CompUnitSP(); + // Don't support optimized code for now, DebugInfoPDB does not return this // information. LazyBool optimized = eLazyBoolNo; - auto result = std::make_shared<CompileUnit>( - m_obj_file->GetModule(), nullptr, path.c_str(), id, lang, optimized); - m_comp_units.insert(std::make_pair(id, result)); - return result; + auto cu_sp = std::make_shared<CompileUnit>(m_obj_file->GetModule(), nullptr, + path.c_str(), id, lang, optimized); + + if (!cu_sp) + return CompUnitSP(); + + m_comp_units.insert(std::make_pair(id, cu_sp)); + if (index == UINT32_MAX) + GetCompileUnitIndex(*compiland_up, index); + lldbassert(index != UINT32_MAX); + m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(index, + cu_sp); + return cu_sp; } bool SymbolFilePDB::ParseCompileUnitLineTable( const lldb_private::SymbolContext &sc, uint32_t match_line) { - auto global = m_session_up->getGlobalScope(); - auto cu = m_session_up->getConcreteSymbolById<PDBSymbolCompiland>( - sc.comp_unit->GetID()); + lldbassert(sc.comp_unit); + + auto compiland_up = GetPDBCompilandByUID(sc.comp_unit->GetID()); + if (!compiland_up) + return false; // LineEntry needs the *index* of the file into the list of support files // returned by ParseCompileUnitSupportFiles. But the underlying SDK gives us - // a globally unique idenfitifier in the namespace of the PDB. So, we have to - // do a mapping so that we can hand out indices. + // a globally unique idenfitifier in the namespace of the PDB. So, we have + // to do a mapping so that we can hand out indices. llvm::DenseMap<uint32_t, uint32_t> index_map; - BuildSupportFileIdToSupportFileIndexMap(*cu, index_map); + BuildSupportFileIdToSupportFileIndexMap(*compiland_up, index_map); auto line_table = llvm::make_unique<LineTable>(sc.comp_unit); - // Find contributions to `cu` from all source and header files. + // Find contributions to `compiland` from all source and header files. std::string path = sc.comp_unit->GetPath(); - auto files = m_session_up->getSourceFilesForCompiland(*cu); + auto files = m_session_up->getSourceFilesForCompiland(*compiland_up); + if (!files) + return false; - // For each source and header file, create a LineSequence for contributions to - // the cu from that file, and add the sequence. + // For each source and header file, create a LineSequence for contributions + // to the compiland from that file, and add the sequence. while (auto file = files->getNext()) { std::unique_ptr<LineSequence> sequence( line_table->CreateLineSequenceContainer()); - auto lines = m_session_up->findLineNumbers(*cu, *file); + auto lines = m_session_up->findLineNumbers(*compiland_up, *file); + if (!lines) + continue; int entry_count = lines->getChildCount(); uint64_t prev_addr; @@ -646,8 +1563,8 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( uint32_t col = line->getColumnNumber(); uint32_t source_idx = index_map[source_id]; - // There was a gap between the current entry and the previous entry if the - // addresses don't perfectly line up. + // There was a gap between the current entry and the previous entry if + // the addresses don't perfectly line up. bool is_gap = (i > 0) && (prev_addr + prev_length < addr); // Before inserting the current entry, insert a terminal entry at the end @@ -657,6 +1574,9 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( line_table->AppendLineEntryToSequence( sequence.get(), prev_addr + prev_length, prev_line, 0, prev_source_idx, false, false, false, false, true); + + line_table->InsertSequence(sequence.release()); + sequence.reset(line_table->CreateLineSequenceContainer()); } if (ShouldAddLine(match_line, lno, length)) { @@ -667,10 +1587,12 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( m_session_up->findSymbolByAddress(addr, PDB_SymType::Function); if (func) { auto prologue = func->findOneChild<PDBSymbolFuncDebugStart>(); - is_prologue = (addr == prologue->getVirtualAddress()); + if (prologue) + is_prologue = (addr == prologue->getVirtualAddress()); auto epilogue = func->findOneChild<PDBSymbolFuncDebugEnd>(); - is_epilogue = (addr == epilogue->getVirtualAddress()); + if (epilogue) + is_epilogue = (addr == epilogue->getVirtualAddress()); } line_table->AppendLineEntryToSequence(sequence.get(), addr, lno, col, @@ -694,23 +1616,134 @@ bool SymbolFilePDB::ParseCompileUnitLineTable( line_table->InsertSequence(sequence.release()); } - sc.comp_unit->SetLineTable(line_table.release()); - return true; + if (line_table->GetSize()) { + sc.comp_unit->SetLineTable(line_table.release()); + return true; + } + return false; } void SymbolFilePDB::BuildSupportFileIdToSupportFileIndexMap( - const PDBSymbolCompiland &cu, + const PDBSymbolCompiland &compiland, llvm::DenseMap<uint32_t, uint32_t> &index_map) const { - // This is a hack, but we need to convert the source id into an index into the - // support files array. We don't want to do path comparisons to avoid + // This is a hack, but we need to convert the source id into an index into + // the support files array. We don't want to do path comparisons to avoid // basename / full path issues that may or may not even be a problem, so we // use the globally unique source file identifiers. Ideally we could use the // global identifiers everywhere, but LineEntry currently assumes indices. - auto source_files = m_session_up->getSourceFilesForCompiland(cu); - int index = 0; + auto source_files = m_session_up->getSourceFilesForCompiland(compiland); + if (!source_files) + return; + + // LLDB uses the DWARF-like file numeration (one based) + int index = 1; while (auto file = source_files->getNext()) { uint32_t source_id = file->getUniqueId(); index_map[source_id] = index++; } } + +lldb::CompUnitSP SymbolFilePDB::GetCompileUnitContainsAddress( + const lldb_private::Address &so_addr) { + lldb::addr_t file_vm_addr = so_addr.GetFileAddress(); + if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0) + return nullptr; + + // If it is a PDB function's vm addr, this is the first sure bet. + if (auto lines = + m_session_up->findLineNumbersByAddress(file_vm_addr, /*Length=*/1)) { + if (auto first_line = lines->getNext()) + return ParseCompileUnitForUID(first_line->getCompilandId()); + } + + // Otherwise we resort to section contributions. + if (auto sec_contribs = m_session_up->getSectionContribs()) { + while (auto section = sec_contribs->getNext()) { + auto va = section->getVirtualAddress(); + if (file_vm_addr >= va && file_vm_addr < va + section->getLength()) + return ParseCompileUnitForUID(section->getCompilandId()); + } + } + return nullptr; +} + +Mangled +SymbolFilePDB::GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func) { + Mangled mangled; + auto func_name = pdb_func.getName(); + auto func_undecorated_name = pdb_func.getUndecoratedName(); + std::string func_decorated_name; + + // Seek from public symbols for non-static function's decorated name if any. + // For static functions, they don't have undecorated names and aren't exposed + // in Public Symbols either. + if (!func_undecorated_name.empty()) { + auto result_up = m_global_scope_up->findChildren( + PDB_SymType::PublicSymbol, func_undecorated_name, + PDB_NameSearchFlags::NS_UndecoratedName); + if (result_up) { + while (auto symbol_up = result_up->getNext()) { + // For a public symbol, it is unique. + lldbassert(result_up->getChildCount() == 1); + if (auto *pdb_public_sym = + llvm::dyn_cast_or_null<PDBSymbolPublicSymbol>( + symbol_up.get())) { + if (pdb_public_sym->isFunction()) { + func_decorated_name = pdb_public_sym->getName(); + break; + } + } + } + } + } + if (!func_decorated_name.empty()) { + mangled.SetMangledName(ConstString(func_decorated_name)); + + // For MSVC, format of C funciton's decorated name depends on calling + // conventon. Unfortunately none of the format is recognized by current + // LLDB. For example, `_purecall` is a __cdecl C function. From PDB, + // `__purecall` is retrieved as both its decorated and undecorated name + // (using PDBSymbolFunc::getUndecoratedName method). However `__purecall` + // string is not treated as mangled in LLDB (neither `?` nor `_Z` prefix). + // Mangled::GetDemangledName method will fail internally and caches an + // empty string as its undecorated name. So we will face a contradition + // here for the same symbol: + // non-empty undecorated name from PDB + // empty undecorated name from LLDB + if (!func_undecorated_name.empty() && + mangled.GetDemangledName(mangled.GuessLanguage()).IsEmpty()) + mangled.SetDemangledName(ConstString(func_undecorated_name)); + + // LLDB uses several flags to control how a C++ decorated name is + // undecorated for MSVC. See `safeUndecorateName` in Class Mangled. So the + // yielded name could be different from what we retrieve from + // PDB source unless we also apply same flags in getting undecorated + // name through PDBSymbolFunc::getUndecoratedNameEx method. + if (!func_undecorated_name.empty() && + mangled.GetDemangledName(mangled.GuessLanguage()) != + ConstString(func_undecorated_name)) + mangled.SetDemangledName(ConstString(func_undecorated_name)); + } else if (!func_undecorated_name.empty()) { + mangled.SetDemangledName(ConstString(func_undecorated_name)); + } else if (!func_name.empty()) + mangled.SetValue(ConstString(func_name), false); + + return mangled; +} + +bool SymbolFilePDB::DeclContextMatchesThisSymbolFile( + const lldb_private::CompilerDeclContext *decl_ctx) { + if (decl_ctx == nullptr || !decl_ctx->IsValid()) + return true; + + TypeSystem *decl_ctx_type_system = decl_ctx->GetTypeSystem(); + if (!decl_ctx_type_system) + return false; + TypeSystem *type_system = GetTypeSystemForLanguage( + decl_ctx_type_system->GetMinimumLanguage(nullptr)); + if (decl_ctx_type_system == type_system) + return true; // The type systems match, return true + + return false; +} diff --git a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h index eef96be8d1fe..96b62d68a6c2 100644 --- a/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -10,12 +10,15 @@ #ifndef lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ #define lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ +#include "lldb/Core/UniqueCStringMap.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/VariableList.h" #include "lldb/Utility/UserID.h" #include "llvm/ADT/DenseMap.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" class SymbolFilePDB : public lldb_private::SymbolFile { public: @@ -108,11 +111,11 @@ public: uint32_t FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::CompilerDeclContext *parent_decl_ctx, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t FindGlobalVariables(const lldb_private::RegularExpression ®ex, - bool append, uint32_t max_matches, + uint32_t max_matches, lldb_private::VariableList &variables) override; uint32_t @@ -141,8 +144,7 @@ public: bool append, lldb_private::TypeMap &types) override; void FindTypesByRegex(const lldb_private::RegularExpression ®ex, - uint32_t max_matches, - lldb_private::TypeMap &types); + uint32_t max_matches, lldb_private::TypeMap &types); lldb_private::TypeList *GetTypeList() override; @@ -167,25 +169,76 @@ public: const llvm::pdb::IPDBSession &GetPDBSession() const; private: - lldb::CompUnitSP ParseCompileUnitForSymIndex(uint32_t id); + lldb::CompUnitSP ParseCompileUnitForUID(uint32_t id, + uint32_t index = UINT32_MAX); bool ParseCompileUnitLineTable(const lldb_private::SymbolContext &sc, uint32_t match_line); void BuildSupportFileIdToSupportFileIndexMap( - const llvm::pdb::PDBSymbolCompiland &cu, + const llvm::pdb::PDBSymbolCompiland &pdb_compiland, llvm::DenseMap<uint32_t, uint32_t> &index_map) const; void FindTypesByName(const std::string &name, uint32_t max_matches, lldb_private::TypeMap &types); + std::string GetMangledForPDBData(const llvm::pdb::PDBSymbolData &pdb_data); + + lldb::VariableSP + ParseVariableForPDBData(const lldb_private::SymbolContext &sc, + const llvm::pdb::PDBSymbolData &pdb_data); + + size_t ParseVariables(const lldb_private::SymbolContext &sc, + const llvm::pdb::PDBSymbol &pdb_data, + lldb_private::VariableList *variable_list = nullptr); + + lldb::CompUnitSP + GetCompileUnitContainsAddress(const lldb_private::Address &so_addr); + + typedef std::vector<lldb_private::Type *> TypeCollection; + + void GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol, + uint32_t type_mask, + TypeCollection &type_collection); + + lldb_private::Function * + ParseCompileUnitFunctionForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func, + const lldb_private::SymbolContext &sc); + + void GetCompileUnitIndex(const llvm::pdb::PDBSymbolCompiland &pdb_compiland, + uint32_t &index); + + std::unique_ptr<llvm::pdb::PDBSymbolCompiland> + GetPDBCompilandByUID(uint32_t uid); + + lldb_private::Mangled + GetMangledForPDBFunc(const llvm::pdb::PDBSymbolFunc &pdb_func); + + bool ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func, + bool include_inlines, + lldb_private::SymbolContextList &sc_list); + + bool ResolveFunction(uint32_t uid, bool include_inlines, + lldb_private::SymbolContextList &sc_list); + + void CacheFunctionNames(); + + bool DeclContextMatchesThisSymbolFile( + const lldb_private::CompilerDeclContext *decl_ctx); + llvm::DenseMap<uint32_t, lldb::CompUnitSP> m_comp_units; llvm::DenseMap<uint32_t, lldb::TypeSP> m_types; + llvm::DenseMap<uint32_t, lldb::VariableSP> m_variables; std::vector<lldb::TypeSP> m_builtin_types; std::unique_ptr<llvm::pdb::IPDBSession> m_session_up; + std::unique_ptr<llvm::pdb::PDBSymbolExe> m_global_scope_up; uint32_t m_cached_compile_unit_count; std::unique_ptr<lldb_private::CompilerDeclContext> m_tu_decl_ctx_up; + + lldb_private::UniqueCStringMap<uint32_t> m_func_full_names; + lldb_private::UniqueCStringMap<uint32_t> m_func_base_names; + lldb_private::UniqueCStringMap<uint32_t> m_func_method_names; }; #endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index dbc1b9ee5470..64e2daf60ee5 100644 --- a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -63,9 +63,9 @@ uint32_t SymbolFileSymtab::CalculateAbilities() { const Symtab *symtab = m_obj_file->GetSymtab(); if (symtab) { //---------------------------------------------------------------------- - // The snippet of code below will get the indexes the module symbol - // table entries that are code, data, or function related (debug info), - // sort them by value (address) and dump the sorted symbols. + // The snippet of code below will get the indexes the module symbol table + // entries that are code, data, or function related (debug info), sort + // them by value (address) and dump the sorted symbols. //---------------------------------------------------------------------- if (symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile, m_source_indexes)) { @@ -105,24 +105,21 @@ uint32_t SymbolFileSymtab::CalculateAbilities() { } uint32_t SymbolFileSymtab::GetNumCompileUnits() { - // If we don't have any source file symbols we will just have one compile unit - // for - // the entire object file + // If we don't have any source file symbols we will just have one compile + // unit for the entire object file if (m_source_indexes.empty()) return 0; // If we have any source file symbols we will logically organize the object - // symbols - // using these. + // symbols using these. return m_source_indexes.size(); } CompUnitSP SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx) { CompUnitSP cu_sp; - // If we don't have any source file symbols we will just have one compile unit - // for - // the entire object file + // If we don't have any source file symbols we will just have one compile + // unit for the entire object file if (idx < m_source_indexes.size()) { const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]); @@ -152,13 +149,12 @@ size_t SymbolFileSymtab::ParseCompileUnitFunctions(const SymbolContext &sc) { // // const uint32_t prefix_len = strlen(prefix); - // If we don't have any source file symbols we will just have one compile unit - // for - // the entire object file + // If we don't have any source file symbols we will just have one compile + // unit for the entire object file if (m_source_indexes.empty()) { - // The only time we will have a user ID of zero is when we don't have - // and source file symbols and we declare one compile unit for the - // entire object file + // The only time we will have a user ID of zero is when we don't have and + // source file symbols and we declare one compile unit for the entire + // object file if (!m_func_indexes.empty()) { } |
