From b61ac4a88f934ab5c02ee2a4957fb1b9943e7a5d Mon Sep 17 00:00:00 2001 From: avl-llvm <55248412+avl-llvm@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:56:34 +0300 Subject: [PATCH] [DWARFLinkerParallel] Add support for -odr mode. (#68721) This patch is extracted from D96035, it adds support for the type deduplication mode. With this patch DWARFLinkerParallel handles --odr option. It also processes clang modules. --- .../AcceleratorRecordsSaver.cpp | 295 ++++++ .../AcceleratorRecordsSaver.h | 70 ++ llvm/lib/DWARFLinkerParallel/ArrayList.h | 26 +- llvm/lib/DWARFLinkerParallel/CMakeLists.txt | 3 + .../DIEAttributeCloner.cpp | 297 +++--- .../DWARFLinkerParallel/DIEAttributeCloner.h | 73 +- llvm/lib/DWARFLinkerParallel/DIEGenerator.h | 21 +- llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp | 1 + .../DWARFLinkerCompileUnit.cpp | 843 +++++++++++------- .../DWARFLinkerCompileUnit.h | 269 ++++-- .../DWARFLinkerGlobalData.h | 1 + .../DWARFLinkerParallel/DWARFLinkerImpl.cpp | 440 ++++++--- .../lib/DWARFLinkerParallel/DWARFLinkerImpl.h | 58 +- .../DWARFLinkerTypeUnit.cpp | 391 ++++++++ .../DWARFLinkerParallel/DWARFLinkerTypeUnit.h | 138 +++ .../DWARFLinkerParallel/DWARFLinkerUnit.cpp | 50 +- .../lib/DWARFLinkerParallel/DWARFLinkerUnit.h | 108 +-- .../DebugLineSectionEmitter.h | 1 + .../DWARFLinkerParallel/DependencyTracker.cpp | 830 +++++++++++++---- .../DWARFLinkerParallel/DependencyTracker.h | 235 ++++- .../DWARFLinkerParallel/OutputSections.cpp | 164 +++- llvm/lib/DWARFLinkerParallel/OutputSections.h | 93 +- .../SyntheticTypeNameBuilder.cpp | 767 ++++++++++++++++ .../SyntheticTypeNameBuilder.h | 155 ++++ llvm/lib/DWARFLinkerParallel/TypePool.h | 177 ++++ llvm/lib/DWARFLinkerParallel/Utils.h | 40 + .../accel-imported-declarations.test | 80 ++ .../ARM/accel-imported-declarations.test | 20 +- .../tools/dsymutil/ARM/dwarf5-addr-base.test | 43 +- .../ARM/dwarf5-dwarf4-combination-macho.test | 28 +- .../test/tools/dsymutil/ARM/dwarf5-macho.test | 20 +- .../ARM/dwarf5-str-offsets-base-strx.test | 65 +- .../X86/DWARFLinkerParallel/dead-stripped.cpp | 67 ++ .../X86/DWARFLinkerParallel/empty-CU.test | 5 + .../inlined-static-variable.cpp | 74 ++ .../X86/DWARFLinkerParallel/keep-func.test | 36 + .../odr-anon-namespace.cpp | 68 ++ .../odr-fwd-declaration.test | 101 +++ .../odr-fwd-declaration2.test | 131 +++ .../odr-fwd-declaration3.test | 381 ++++++++ .../odr-member-functions.cpp | 192 ++++ .../odr-namespace-extension.test | 157 ++++ .../odr-nested-types1.test | 384 ++++++++ .../odr-nested-types2.test | 374 ++++++++ .../X86/DWARFLinkerParallel/odr-parents.test | 238 +++++ .../odr-predictable-output.test | 117 +++ .../odr-predictable-output2.test | 120 +++ .../odr-recursive-dependence.test | 245 +++++ .../X86/DWARFLinkerParallel/odr-string.test | 180 ++++ .../odr-template-parameters.test | 201 +++++ .../odr-two-units-in-single-file.test | 205 +++++ .../odr-types-in-subprogram1.test | 431 +++++++++ .../X86/DWARFLinkerParallel/odr-uniquing.cpp | 475 ++++++++++ .../tools/dsymutil/X86/Inputs/String/foo1.o | Bin 0 -> 47448 bytes .../tools/dsymutil/X86/Inputs/String/foo2.o | Bin 0 -> 56860 bytes .../tools/dsymutil/X86/Inputs/String/foo3.o | Bin 0 -> 61128 bytes .../tools/dsymutil/X86/Inputs/String/main.o | Bin 0 -> 50140 bytes .../test/tools/dsymutil/X86/dead-stripped.cpp | 5 - .../tools/dsymutil/X86/dummy-debug-map.map | 4 +- .../tools/dsymutil/X86/dwarf5-rnglists.test | 4 +- llvm/test/tools/dsymutil/X86/empty-CU.test | 2 - .../dsymutil/X86/inlined-static-variable.cpp | 18 +- llvm/test/tools/dsymutil/X86/keep-func.test | 5 - .../X86/linker-llvm-union-fwd-decl.test | 65 ++ .../dsymutil/X86/location-expression.test | 6 +- llvm/test/tools/dsymutil/X86/modules-empty.m | 6 +- llvm/test/tools/dsymutil/X86/odr-uniquing.cpp | 2 + llvm/test/tools/dsymutil/X86/op-convert.test | 12 +- .../tools/dsymutil/X86/union-fwd-decl.test | 3 - .../ELF/X86/dwarf5-addresses.test | 2 +- .../ELF/X86/dwarf5-rnglists.test | 24 +- .../llvm-dwarfutil/ELF/X86/gc-default.test | 18 +- .../gc-func-overlapping-address-ranges.test | 4 +- .../llvm-dwarfutil/ELF/X86/gc-maxpc.test | 8 +- .../llvm-dwarfutil/ELF/X86/gc-no-garbage.test | 4 +- .../gc-unit-overlapping-address-ranges.test | 4 +- llvm/tools/dsymutil/DwarfLinkerForBinary.cpp | 1 - 77 files changed, 9062 insertions(+), 1119 deletions(-) create mode 100644 llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp create mode 100644 llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h create mode 100644 llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp create mode 100644 llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h create mode 100644 llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp create mode 100644 llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h create mode 100644 llvm/lib/DWARFLinkerParallel/TypePool.h create mode 100644 llvm/lib/DWARFLinkerParallel/Utils.h create mode 100644 llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test create mode 100644 llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/String/main.o create mode 100644 llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test diff --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp new file mode 100644 index 00000000000000..5ec25cfe5fd26e --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp @@ -0,0 +1,295 @@ +//=== AcceleratorRecordsSaver.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AcceleratorRecordsSaver.h" +#include "Utils.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/Support/DJB.h" + +namespace llvm { +namespace dwarflinker_parallel { + +static uint32_t hashFullyQualifiedName(CompileUnit &InputCU, DWARFDie &InputDIE, + int ChildRecurseDepth = 0) { + const char *Name = nullptr; + CompileUnit *CU = &InputCU; + std::optional RefVal; + + if (Error Err = finiteLoop([&]() -> Expected { + if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName)) + Name = CurrentName; + + if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) && + !(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin))) + return false; + + if (!RefVal->isFormClass(DWARFFormValue::FC_Reference)) + return false; + + std::optional RefDie = CU->resolveDIEReference( + *RefVal, ResolveInterCUReferencesMode::Resolve); + if (!RefDie) + return false; + + if (!RefDie->DieEntry) + return false; + + CU = RefDie->CU; + InputDIE = RefDie->CU->getDIE(RefDie->DieEntry); + return true; + })) { + consumeError(std::move(Err)); + } + + if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace) + Name = "(anonymous namespace)"; + + DWARFDie ParentDie = InputDIE.getParent(); + if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit) + return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::")); + + return djbHash( + (Name ? Name : ""), + djbHash((Name ? "::" : ""), + hashFullyQualifiedName(*CU, ParentDie, ++ChildRecurseDepth))); +} + +void AcceleratorRecordsSaver::save(const DWARFDebugInfoEntry *InputDieEntry, + DIE *OutDIE, AttributesInfo &AttrInfo, + TypeEntry *TypeEntry) { + if (GlobalData.getOptions().AccelTables.empty()) + return; + + DWARFDie InputDIE = InUnit.getDIE(InputDieEntry); + + // Look for short name recursively if short name is not known yet. + if (AttrInfo.Name == nullptr) + if (const char *ShortName = InputDIE.getShortName()) + AttrInfo.Name = GlobalData.getStringPool().insert(ShortName).first; + + switch (InputDieEntry->getTag()) { + case dwarf::DW_TAG_array_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_pointer_type: + case dwarf::DW_TAG_reference_type: + case dwarf::DW_TAG_string_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_subroutine_type: + case dwarf::DW_TAG_typedef: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_ptr_to_member_type: + case dwarf::DW_TAG_set_type: + case dwarf::DW_TAG_subrange_type: + case dwarf::DW_TAG_base_type: + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_constant: + case dwarf::DW_TAG_file_type: + case dwarf::DW_TAG_namelist: + case dwarf::DW_TAG_packed_type: + case dwarf::DW_TAG_volatile_type: + case dwarf::DW_TAG_restrict_type: + case dwarf::DW_TAG_atomic_type: + case dwarf::DW_TAG_interface_type: + case dwarf::DW_TAG_unspecified_type: + case dwarf::DW_TAG_shared_type: + case dwarf::DW_TAG_immutable_type: + case dwarf::DW_TAG_rvalue_reference_type: { + if (!AttrInfo.IsDeclaration && AttrInfo.Name != nullptr && + !AttrInfo.Name->getKey().empty()) { + uint32_t Hash = hashFullyQualifiedName(InUnit, InputDIE); + + uint64_t RuntimeLang = + dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class)) + .value_or(0); + + bool ObjCClassIsImplementation = + (RuntimeLang == dwarf::DW_LANG_ObjC || + RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) && + dwarf::toUnsigned( + InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type)) + .value_or(0); + + saveTypeRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), Hash, + ObjCClassIsImplementation, TypeEntry); + } + } break; + case dwarf::DW_TAG_namespace: { + if (AttrInfo.Name == nullptr) + AttrInfo.Name = + GlobalData.getStringPool().insert("(anonymous namespace)").first; + + saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), + TypeEntry); + } break; + case dwarf::DW_TAG_imported_declaration: { + if (AttrInfo.Name != nullptr) + saveNamespaceRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), + TypeEntry); + } break; + case dwarf::DW_TAG_compile_unit: + case dwarf::DW_TAG_lexical_block: { + // Nothing to do. + } break; + default: + if (TypeEntry) + // Do not store this kind of accelerator entries for type entries. + return; + + if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) { + if (AttrInfo.Name) + saveNameRecord(AttrInfo.Name, OutDIE, InputDieEntry->getTag(), + InputDieEntry->getTag() == + dwarf::DW_TAG_inlined_subroutine); + + // Look for mangled name recursively if mangled name is not known yet. + if (!AttrInfo.MangledName) + if (const char *LinkageName = InputDIE.getLinkageName()) + AttrInfo.MangledName = + GlobalData.getStringPool().insert(LinkageName).first; + + if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name) + saveNameRecord(AttrInfo.MangledName, OutDIE, InputDieEntry->getTag(), + InputDieEntry->getTag() == + dwarf::DW_TAG_inlined_subroutine); + + // Strip template parameters from the short name. + if (AttrInfo.Name && AttrInfo.MangledName != AttrInfo.Name && + (InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) { + if (std::optional Name = + StripTemplateParameters(AttrInfo.Name->getKey())) { + StringEntry *NameWithoutTemplateParams = + GlobalData.getStringPool().insert(*Name).first; + + saveNameRecord(NameWithoutTemplateParams, OutDIE, + InputDieEntry->getTag(), true); + } + } + + if (AttrInfo.Name) + saveObjC(InputDieEntry, OutDIE, AttrInfo); + } + break; + } +} + +void AcceleratorRecordsSaver::saveObjC(const DWARFDebugInfoEntry *InputDieEntry, + DIE *OutDIE, AttributesInfo &AttrInfo) { + std::optional Names = + getObjCNamesIfSelector(AttrInfo.Name->getKey()); + if (!Names) + return; + + StringEntry *Selector = + GlobalData.getStringPool().insert(Names->Selector).first; + saveNameRecord(Selector, OutDIE, InputDieEntry->getTag(), true); + StringEntry *ClassName = + GlobalData.getStringPool().insert(Names->ClassName).first; + saveObjCNameRecord(ClassName, OutDIE, InputDieEntry->getTag()); + if (Names->ClassNameNoCategory) { + StringEntry *ClassNameNoCategory = + GlobalData.getStringPool().insert(*Names->ClassNameNoCategory).first; + saveObjCNameRecord(ClassNameNoCategory, OutDIE, InputDieEntry->getTag()); + } + if (Names->MethodNameNoCategory) { + StringEntry *MethodNameNoCategory = + GlobalData.getStringPool().insert(*Names->MethodNameNoCategory).first; + saveNameRecord(MethodNameNoCategory, OutDIE, InputDieEntry->getTag(), true); + } +} + +void AcceleratorRecordsSaver::saveNameRecord(StringEntry *Name, DIE *OutDIE, + dwarf::Tag Tag, + bool AvoidForPubSections) { + DwarfUnit::AccelInfo Info; + + Info.Type = DwarfUnit::AccelType::Name; + Info.String = Name; + Info.OutOffset = OutDIE->getOffset(); + Info.Tag = Tag; + Info.AvoidForPubSections = AvoidForPubSections; + + OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info); +} +void AcceleratorRecordsSaver::saveNamespaceRecord(StringEntry *Name, + DIE *OutDIE, dwarf::Tag Tag, + TypeEntry *TypeEntry) { + if (OutUnit.isCompileUnit()) { + assert(TypeEntry == nullptr); + DwarfUnit::AccelInfo Info; + + Info.Type = DwarfUnit::AccelType::Namespace; + Info.String = Name; + Info.OutOffset = OutDIE->getOffset(); + Info.Tag = Tag; + + OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info); + return; + } + + assert(TypeEntry != nullptr); + TypeUnit::TypeUnitAccelInfo Info; + Info.Type = DwarfUnit::AccelType::Namespace; + Info.String = Name; + Info.OutOffset = 0xbaddef; + Info.Tag = Tag; + Info.OutDIE = OutDIE; + Info.TypeEntryBodyPtr = TypeEntry->getValue().load(); + + OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info); +} + +void AcceleratorRecordsSaver::saveObjCNameRecord(StringEntry *Name, DIE *OutDIE, + dwarf::Tag Tag) { + DwarfUnit::AccelInfo Info; + + Info.Type = DwarfUnit::AccelType::ObjC; + Info.String = Name; + Info.OutOffset = OutDIE->getOffset(); + Info.Tag = Tag; + Info.AvoidForPubSections = true; + + OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info); +} + +void AcceleratorRecordsSaver::saveTypeRecord(StringEntry *Name, DIE *OutDIE, + dwarf::Tag Tag, + uint32_t QualifiedNameHash, + bool ObjcClassImplementation, + TypeEntry *TypeEntry) { + if (OutUnit.isCompileUnit()) { + assert(TypeEntry == nullptr); + DwarfUnit::AccelInfo Info; + + Info.Type = DwarfUnit::AccelType::Type; + Info.String = Name; + Info.OutOffset = OutDIE->getOffset(); + Info.Tag = Tag; + Info.QualifiedNameHash = QualifiedNameHash; + Info.ObjcClassImplementation = ObjcClassImplementation; + + OutUnit.getAsCompileUnit()->saveAcceleratorInfo(Info); + return; + } + + assert(TypeEntry != nullptr); + TypeUnit::TypeUnitAccelInfo Info; + + Info.Type = DwarfUnit::AccelType::Type; + Info.String = Name; + Info.OutOffset = 0xbaddef; + Info.Tag = Tag; + Info.QualifiedNameHash = QualifiedNameHash; + Info.ObjcClassImplementation = ObjcClassImplementation; + Info.OutDIE = OutDIE; + Info.TypeEntryBodyPtr = TypeEntry->getValue().load(); + OutUnit.getAsTypeUnit()->saveAcceleratorInfo(Info); +} + +} // end of namespace dwarflinker_parallel +} // namespace llvm diff --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h new file mode 100644 index 00000000000000..5e7f4d0c3166fd --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.h @@ -0,0 +1,70 @@ +//===- AcceleratorRecordsSaver.h --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H +#define LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H + +#include "DIEAttributeCloner.h" +#include "DWARFLinkerCompileUnit.h" +#include "DWARFLinkerGlobalData.h" +#include "DWARFLinkerTypeUnit.h" + +namespace llvm { +namespace dwarflinker_parallel { + +/// This class helps to store information for accelerator entries. +/// It prepares accelerator info for the certain DIE and store it inside +/// OutUnit. +class AcceleratorRecordsSaver { +public: + AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit, + CompileUnit *OutUnit) + : AcceleratorRecordsSaver(GlobalData, InUnit, + CompileUnit::OutputUnitVariantPtr(OutUnit)) {} + + AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit, + TypeUnit *OutUnit) + : AcceleratorRecordsSaver(GlobalData, InUnit, + CompileUnit::OutputUnitVariantPtr(OutUnit)) {} + + /// Save accelerator info for the specified \p OutDIE inside OutUnit. + /// Side effects: set attributes in \p AttrInfo. + void save(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE, + AttributesInfo &AttrInfo, TypeEntry *TypeEntry); + +protected: + AcceleratorRecordsSaver(LinkingGlobalData &GlobalData, CompileUnit &InUnit, + CompileUnit::OutputUnitVariantPtr OutUnit) + : GlobalData(GlobalData), InUnit(InUnit), OutUnit(OutUnit) {} + + void saveObjC(const DWARFDebugInfoEntry *InputDieEntry, DIE *OutDIE, + AttributesInfo &AttrInfo); + + void saveNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag, + bool AvoidForPubSections); + void saveNamespaceRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag, + TypeEntry *TypeEntry); + void saveObjCNameRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag); + void saveTypeRecord(StringEntry *Name, DIE *OutDIE, dwarf::Tag Tag, + uint32_t QualifiedNameHash, bool ObjcClassImplementation, + TypeEntry *TypeEntry); + + /// Global linking data. + LinkingGlobalData &GlobalData; + + /// Comiple unit corresponding to input DWARF. + CompileUnit &InUnit; + + /// Compile unit or Artificial type unit corresponding to the output DWARF. + CompileUnit::OutputUnitVariantPtr OutUnit; +}; + +} // end of namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_LIB_DWARFLINKERPARALLEL_ACCELERATORRECORDSSAVER_H diff --git a/llvm/lib/DWARFLinkerParallel/ArrayList.h b/llvm/lib/DWARFLinkerParallel/ArrayList.h index 58d550982c8dfc..def83f91bc6f31 100644 --- a/llvm/lib/DWARFLinkerParallel/ArrayList.h +++ b/llvm/lib/DWARFLinkerParallel/ArrayList.h @@ -21,6 +21,9 @@ namespace dwarflinker_parallel { /// Method add() can be called asynchronously. template class ArrayList { public: + ArrayList(parallel::PerThreadBumpPtrAllocator *Allocator) + : Allocator(Allocator) {} + /// Add specified \p Item to the list. T &add(const T &Item) { assert(Allocator); @@ -73,8 +76,27 @@ template class ArrayList { LastGroup = nullptr; } - void setAllocator(parallel::PerThreadBumpPtrAllocator *Allocator) { - this->Allocator = Allocator; + void sort(function_ref Comparator) { + SmallVector SortedItems; + forEach([&](T &Item) { SortedItems.push_back(Item); }); + + if (SortedItems.size()) { + std::sort(SortedItems.begin(), SortedItems.end(), Comparator); + + size_t SortedItemIdx = 0; + forEach([&](T &Item) { Item = SortedItems[SortedItemIdx++]; }); + assert(SortedItemIdx == SortedItems.size()); + } + } + + size_t size() { + size_t Result = 0; + + for (ItemsGroup *CurGroup = GroupsHead; CurGroup != nullptr; + CurGroup = CurGroup->Next) + Result += CurGroup->getItemsCount(); + + return Result; } protected: diff --git a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt index d321ecf8d5ce84..b0f0b3910e586a 100644 --- a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt +++ b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt @@ -1,14 +1,17 @@ add_llvm_component_library(LLVMDWARFLinkerParallel + AcceleratorRecordsSaver.cpp DependencyTracker.cpp DIEAttributeCloner.cpp DWARFEmitterImpl.cpp DWARFFile.cpp DWARFLinker.cpp DWARFLinkerCompileUnit.cpp + DWARFLinkerTypeUnit.cpp DWARFLinkerImpl.cpp DWARFLinkerUnit.cpp OutputSections.cpp StringPool.cpp + SyntheticTypeNameBuilder.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/DWARFLinkerParallel diff --git a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp index d05fd8d61b8574..81fc57f7cabbb7 100644 --- a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp +++ b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.cpp @@ -13,18 +13,16 @@ namespace llvm { namespace dwarflinker_parallel { void DIEAttributeCloner::clone() { - DWARFUnit &U = CU.getOrigUnit(); - // Extract and clone every attribute. - DWARFDataExtractor Data = U.getDebugInfoExtractor(); + DWARFDataExtractor Data = InUnit.getOrigUnit().getDebugInfoExtractor(); uint64_t Offset = InputDieEntry->getOffset(); // Point to the next DIE (generally there is always at least a NULL // entry after the current one). If this is a lone // DW_TAG_compile_unit without any children, point to the next unit. - uint64_t NextOffset = (InputDIEIdx + 1 < U.getNumDIEs()) - ? U.getDIEAtIndex(InputDIEIdx + 1).getOffset() - : U.getNextUnitOffset(); + uint64_t NextOffset = (InputDIEIdx + 1 < InUnit.getOrigUnit().getNumDIEs()) + ? InUnit.getDIEAtIndex(InputDIEIdx + 1).getOffset() + : InUnit.getOrigUnit().getNextUnitOffset(); // We could copy the data only if we need to apply a relocation to it. After // testing, it seems there is no performance downside to doing the copy @@ -34,8 +32,8 @@ void DIEAttributeCloner::clone() { DWARFDataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize()); // Modify the copy with relocated addresses. - CU.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset, - Data.isLittleEndian()); + InUnit.getContaingFile().Addresses->applyValidRelocs(DIECopy, Offset, + Data.isLittleEndian()); // Reset the Offset to 0 as we will be working on the local copy of // the data. @@ -45,17 +43,18 @@ void DIEAttributeCloner::clone() { Offset += getULEB128Size(Abbrev->getCode()); // Set current output offset. - AttrOutOffset = OutDIE->getOffset(); + AttrOutOffset = OutUnit.isCompileUnit() ? OutDIE->getOffset() : 0; for (const auto &AttrSpec : Abbrev->attributes()) { // Check whether current attribute should be skipped. if (shouldSkipAttribute(AttrSpec)) { DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, - U.getFormParams()); + InUnit.getFormParams()); continue; } DWARFFormValue Val = AttrSpec.getFormValue(); - Val.extractValue(Data, &Offset, U.getFormParams(), &U); + Val.extractValue(Data, &Offset, InUnit.getFormParams(), + &InUnit.getOrigUnit()); // Clone current attribute. switch (AttrSpec.Form) { @@ -107,10 +106,10 @@ void DIEAttributeCloner::clone() { AttrOutOffset += cloneAddressAttr(Val, AttrSpec); break; default: - CU.warn("unsupported attribute form " + - dwarf::FormEncodingString(AttrSpec.Form) + - " in DieAttributeCloner::clone(). Dropping.", - InputDieEntry); + InUnit.warn("unsupported attribute form " + + dwarf::FormEncodingString(AttrSpec.Form) + + " in DieAttributeCloner::clone(). Dropping.", + InputDieEntry); } } @@ -118,19 +117,20 @@ void DIEAttributeCloner::clone() { // Check if original compile unit already has DW_AT_str_offsets_base // attribute. if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit && - CU.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) { + InUnit.getVersion() >= 5 && !AttrInfo.HasStringOffsetBaseAttr) { DebugInfoOutputSection.notePatchWithOffsetUpdate( - DebugOffsetPatch{ - AttrOutOffset, - &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets), - true}, + DebugOffsetPatch{AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugStrOffsets), + true}, PatchesOffsets); - AttrOutOffset += Generator - .addScalarAttribute(dwarf::DW_AT_str_offsets_base, - dwarf::DW_FORM_sec_offset, - CU.getDebugStrOffsetsHeaderSize()) - .second; + AttrOutOffset += + Generator + .addScalarAttribute(dwarf::DW_AT_str_offsets_base, + dwarf::DW_FORM_sec_offset, + OutUnit->getDebugStrOffsetsHeaderSize()) + .second; } } @@ -142,28 +142,28 @@ bool DIEAttributeCloner::shouldSkipAttribute( case dwarf::DW_AT_low_pc: case dwarf::DW_AT_high_pc: case dwarf::DW_AT_ranges: - if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly) + if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) return false; // Skip address attribute if we are in function scope and function does not // reference live address. - return CU.getDIEInfo(InputDIEIdx).getIsInFunctionScope() && + return InUnit.getDIEInfo(InputDIEIdx).getIsInFunctionScope() && !FuncAddressAdjustment.has_value(); case dwarf::DW_AT_rnglists_base: // In case !Update the .debug_addr table is not generated/preserved. // Thus instead of DW_FORM_rnglistx the DW_FORM_sec_offset is used. // Since DW_AT_rnglists_base is used for only DW_FORM_rnglistx the // DW_AT_rnglists_base is removed. - return !CU.getGlobalData().getOptions().UpdateIndexTablesOnly; + return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly; case dwarf::DW_AT_loclists_base: // In case !Update the .debug_addr table is not generated/preserved. // Thus instead of DW_FORM_loclistx the DW_FORM_sec_offset is used. // Since DW_AT_loclists_base is used for only DW_FORM_loclistx the // DW_AT_loclists_base is removed. - return !CU.getGlobalData().getOptions().UpdateIndexTablesOnly; + return !InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly; case dwarf::DW_AT_location: case dwarf::DW_AT_frame_base: - if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly) + if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) return false; // When location expression contains an address: skip this attribute @@ -173,7 +173,7 @@ bool DIEAttributeCloner::shouldSkipAttribute( // Skip location attribute if we are in function scope and function does not // reference live address. - return CU.getDIEInfo(InputDIEIdx).getIsInFunctionScope() && + return InUnit.getDIEInfo(InputDIEIdx).getIsInFunctionScope() && !FuncAddressAdjustment.has_value(); } } @@ -183,19 +183,12 @@ size_t DIEAttributeCloner::cloneStringAttr( const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { std::optional String = dwarf::toString(Val); if (!String) { - CU.warn("cann't read string attribute."); + InUnit.warn("cann't read string attribute."); return 0; } StringEntry *StringInPool = - CU.getGlobalData().getStringPool().insert(*String).first; - if (AttrSpec.Form == dwarf::DW_FORM_line_strp) { - DebugInfoOutputSection.notePatchWithOffsetUpdate( - DebugLineStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets); - return Generator - .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_line_strp) - .second; - } + InUnit.getGlobalData().getStringPool().insert(*String).first; // Update attributes info. if (AttrSpec.Attr == dwarf::DW_AT_name) @@ -204,9 +197,29 @@ size_t DIEAttributeCloner::cloneStringAttr( AttrSpec.Attr == dwarf::DW_AT_linkage_name) AttrInfo.MangledName = StringInPool; - if (CU.getVersion() < 5) { - DebugInfoOutputSection.notePatchWithOffsetUpdate( - DebugStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets); + if (AttrSpec.Form == dwarf::DW_FORM_line_strp) { + if (OutUnit.isTypeUnit()) { + DebugInfoOutputSection.notePatch(DebugTypeLineStrPatch{ + AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(InputDIEIdx), + StringInPool}); + } else { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugLineStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets); + } + return Generator + .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_line_strp) + .second; + } + + if (Use_DW_FORM_strp) { + if (OutUnit.isTypeUnit()) { + DebugInfoOutputSection.notePatch( + DebugTypeStrPatch{AttrOutOffset, OutDIE, + InUnit.getDieTypeEntry(InputDIEIdx), StringInPool}); + } else { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugStrPatch{{AttrOutOffset}, StringInPool}, PatchesOffsets); + } return Generator .addStringPlaceholderAttribute(AttrSpec.Attr, dwarf::DW_FORM_strp) @@ -215,7 +228,7 @@ size_t DIEAttributeCloner::cloneStringAttr( return Generator .addIndexedStringAttribute(AttrSpec.Attr, dwarf::DW_FORM_strx, - CU.getDebugStrIndex(StringInPool)) + OutUnit->getDebugStrIndex(StringInPool)) .second; } @@ -225,22 +238,48 @@ size_t DIEAttributeCloner::cloneDieRefAttr( if (AttrSpec.Attr == dwarf::DW_AT_sibling) return 0; - std::optional> RefDiePair = - CU.resolveDIEReference(Val, ResolveInterCUReferencesMode::Resolve); - if (!RefDiePair) { + std::optional RefDiePair = + InUnit.resolveDIEReference(Val, ResolveInterCUReferencesMode::Resolve); + if (!RefDiePair || !RefDiePair->DieEntry) { // If the referenced DIE is not found, drop the attribute. - CU.warn("cann't find referenced DIE.", InputDieEntry); + InUnit.warn("cann't find referenced DIE.", InputDieEntry); return 0; } - assert(RefDiePair->first->getStage() >= CompileUnit::Stage::Loaded); - assert(RefDiePair->second != 0); + + TypeEntry *RefTypeName = nullptr; + const CompileUnit::DIEInfo &RefDIEInfo = + RefDiePair->CU->getDIEInfo(RefDiePair->DieEntry); + if (RefDIEInfo.needToPlaceInTypeTable()) + RefTypeName = RefDiePair->CU->getDieTypeEntry(RefDiePair->DieEntry); + + if (OutUnit.isTypeUnit()) { + assert(RefTypeName && "Type name for referenced DIE is not set"); + assert(InUnit.getDieTypeEntry(InputDIEIdx) && + "Type name for DIE is not set"); + + DebugInfoOutputSection.notePatch(DebugType2TypeDieRefPatch{ + AttrOutOffset, OutDIE, InUnit.getDieTypeEntry(InputDIEIdx), + RefTypeName}); + + return Generator + .addScalarAttribute(AttrSpec.Attr, dwarf::DW_FORM_ref4, 0xBADDEF) + .second; + } + + if (RefTypeName) { + DebugInfoOutputSection.notePatchWithOffsetUpdate( + DebugDieTypeRefPatch{AttrOutOffset, RefTypeName}, PatchesOffsets); + + return Generator + .addScalarAttribute(AttrSpec.Attr, dwarf::DW_FORM_ref_addr, 0xBADDEF) + .second; + } // Get output offset for referenced DIE. - uint64_t OutDieOffset = - RefDiePair->first->getDieOutOffset(RefDiePair->second); + uint64_t OutDieOffset = RefDiePair->CU->getDieOutOffset(RefDiePair->DieEntry); // Examine whether referenced DIE is in current compile unit. - bool IsLocal = CU.getUniqueID() == RefDiePair->first->getUniqueID(); + bool IsLocal = OutUnit->getUniqueID() == RefDiePair->CU->getUniqueID(); // Set attribute form basing on the kind of referenced DIE(local or not?). dwarf::Form NewForm = IsLocal ? dwarf::DW_FORM_ref4 : dwarf::DW_FORM_ref_addr; @@ -254,8 +293,9 @@ size_t DIEAttributeCloner::cloneDieRefAttr( // If offset value is not known at this point then create patch for the // reference value and write dummy value into the attribute. DebugInfoOutputSection.notePatchWithOffsetUpdate( - DebugDieRefPatch{AttrOutOffset, &CU, RefDiePair->first, - RefDiePair->second}, + DebugDieRefPatch{AttrOutOffset, OutUnit.getAsCompileUnit(), + RefDiePair->CU, + RefDiePair->CU->getDIEIndex(RefDiePair->DieEntry)}, PatchesOffsets); return Generator.addScalarAttribute(AttrSpec.Attr, NewForm, 0xBADDEF).second; } @@ -267,41 +307,47 @@ size_t DIEAttributeCloner::cloneScalarAttr( // Create patches for attribute referencing other non invariant section. // Invariant section could not be updated here as this section and // reference to it do not change value in case --update. - if (AttrSpec.Attr == dwarf::DW_AT_macro_info) { + switch (AttrSpec.Attr) { + case dwarf::DW_AT_macro_info: { if (std::optional Offset = Val.getAsSectionOffset()) { const DWARFDebugMacro *Macro = - CU.getContaingFile().Dwarf->getDebugMacinfo(); + InUnit.getContaingFile().Dwarf->getDebugMacinfo(); if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset)) return 0; DebugInfoOutputSection.notePatchWithOffsetUpdate( - DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor( - DebugSectionKind::DebugMacinfo)}, + DebugOffsetPatch{AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugMacinfo)}, PatchesOffsets); } - } else if (AttrSpec.Attr == dwarf::DW_AT_macros) { + } break; + case dwarf::DW_AT_macros: { if (std::optional Offset = Val.getAsSectionOffset()) { const DWARFDebugMacro *Macro = - CU.getContaingFile().Dwarf->getDebugMacro(); + InUnit.getContaingFile().Dwarf->getDebugMacro(); if (Macro == nullptr || !Macro->hasEntryForOffset(*Offset)) return 0; DebugInfoOutputSection.notePatchWithOffsetUpdate( - DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor( - DebugSectionKind::DebugMacro)}, + DebugOffsetPatch{AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugMacro)}, PatchesOffsets); } - } else if (AttrSpec.Attr == dwarf::DW_AT_stmt_list) { + } break; + case dwarf::DW_AT_stmt_list: { DebugInfoOutputSection.notePatchWithOffsetUpdate( - DebugOffsetPatch{AttrOutOffset, &CU.getOrCreateSectionDescriptor( + DebugOffsetPatch{AttrOutOffset, &OutUnit->getOrCreateSectionDescriptor( DebugSectionKind::DebugLine)}, PatchesOffsets); - } else if (AttrSpec.Attr == dwarf::DW_AT_str_offsets_base) { + } break; + case dwarf::DW_AT_str_offsets_base: { DebugInfoOutputSection.notePatchWithOffsetUpdate( - DebugOffsetPatch{ - AttrOutOffset, - &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets), - true}, + DebugOffsetPatch{AttrOutOffset, + &OutUnit->getOrCreateSectionDescriptor( + DebugSectionKind::DebugStrOffsets), + true}, PatchesOffsets); // Use size of .debug_str_offsets header as attribute value. The offset @@ -309,9 +355,36 @@ size_t DIEAttributeCloner::cloneScalarAttr( AttrInfo.HasStringOffsetBaseAttr = true; return Generator .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, - CU.getDebugStrOffsetsHeaderSize()) + OutUnit->getDebugStrOffsetsHeaderSize()) .second; - } + } break; + case dwarf::DW_AT_decl_file: { + // Value of DW_AT_decl_file may exceed original form. Longer + // form can affect offsets to the following attributes. To not + // update offsets of the following attributes we always remove + // original DW_AT_decl_file and attach it to the last position + // later. + if (OutUnit.isTypeUnit()) { + if (std::optional> DirAndFilename = + InUnit.getDirAndFilenameFromLineTable(Val)) + DebugInfoOutputSection.notePatch(DebugTypeDeclFilePatch{ + OutDIE, + InUnit.getDieTypeEntry(InputDIEIdx), + OutUnit->getGlobalData() + .getStringPool() + .insert(DirAndFilename->first) + .first, + OutUnit->getGlobalData() + .getStringPool() + .insert(DirAndFilename->second) + .first, + }); + return 0; + } + } break; + default: { + } break; + }; uint64_t Value; if (AttrSpec.Attr == dwarf::DW_AT_const_value && @@ -319,7 +392,7 @@ size_t DIEAttributeCloner::cloneScalarAttr( InputDieEntry->getTag() == dwarf::DW_TAG_constant)) AttrInfo.HasLiveAddress = true; - if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly) { + if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) { if (auto OptionalValue = Val.getAsUnsignedConstant()) Value = *OptionalValue; else if (auto OptionalValue = Val.getAsSignedConstant()) @@ -327,8 +400,8 @@ size_t DIEAttributeCloner::cloneScalarAttr( else if (auto OptionalValue = Val.getAsSectionOffset()) Value = *OptionalValue; else { - CU.warn("unsupported scalar attribute form. Dropping attribute.", - InputDieEntry); + InUnit.warn("unsupported scalar attribute form. Dropping attribute.", + InputDieEntry); return 0; } @@ -350,12 +423,13 @@ size_t DIEAttributeCloner::cloneScalarAttr( // to DW_FORM_sec_offset here. std::optional Index = Val.getAsSectionOffset(); if (!Index) { - CU.warn("cann't read the attribute. Dropping.", InputDieEntry); + InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry); return 0; } - std::optional Offset = CU.getOrigUnit().getRnglistOffset(*Index); + std::optional Offset = + InUnit.getOrigUnit().getRnglistOffset(*Index); if (!Offset) { - CU.warn("cann't read the attribute. Dropping.", InputDieEntry); + InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry); return 0; } @@ -367,12 +441,13 @@ size_t DIEAttributeCloner::cloneScalarAttr( // to DW_FORM_sec_offset here. std::optional Index = Val.getAsSectionOffset(); if (!Index) { - CU.warn("cann't read the attribute. Dropping.", InputDieEntry); + InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry); return 0; } - std::optional Offset = CU.getOrigUnit().getLoclistOffset(*Index); + std::optional Offset = + InUnit.getOrigUnit().getLoclistOffset(*Index); if (!Offset) { - CU.warn("cann't read the attribute. Dropping.", InputDieEntry); + InUnit.warn("cann't read the attribute. Dropping.", InputDieEntry); return 0; } @@ -380,11 +455,14 @@ size_t DIEAttributeCloner::cloneScalarAttr( ResultingForm = dwarf::DW_FORM_sec_offset; } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc && InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) { - std::optional LowPC = CU.getLowPc(); + if (!OutUnit.isCompileUnit()) + return 0; + + std::optional LowPC = OutUnit.getAsCompileUnit()->getLowPc(); if (!LowPC) return 0; // Dwarf >= 4 high_pc is an size, not an address. - Value = CU.getHighPc() - *LowPC; + Value = OutUnit.getAsCompileUnit()->getHighPc() - *LowPC; } else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset) Value = *Val.getAsSectionOffset(); else if (AttrSpec.Form == dwarf::DW_FORM_sdata) @@ -392,8 +470,8 @@ size_t DIEAttributeCloner::cloneScalarAttr( else if (auto OptionalValue = Val.getAsUnsignedConstant()) Value = *OptionalValue; else { - CU.warn("unsupported scalar attribute form. Dropping attribute.", - InputDieEntry); + InUnit.warn("unsupported scalar attribute form. Dropping attribute.", + InputDieEntry); return 0; } @@ -408,7 +486,7 @@ size_t DIEAttributeCloner::cloneScalarAttr( } else if (DWARFAttribute::mayHaveLocationList(AttrSpec.Attr) && dwarf::doesFormBelongToClass(AttrSpec.Form, DWARFFormValue::FC_SectionOffset, - CU.getOrigUnit().getVersion())) { + InUnit.getOrigUnit().getVersion())) { int64_t AddrAdjustmentValue = 0; if (VarAddressAdjustment) AddrAdjustmentValue = *VarAddressAdjustment; @@ -422,7 +500,7 @@ size_t DIEAttributeCloner::cloneScalarAttr( DebugInfoOutputSection.notePatchWithOffsetUpdate( DebugOffsetPatch{ AttrOutOffset, - &CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr), + &OutUnit->getOrCreateSectionDescriptor(DebugSectionKind::DebugAddr), true}, PatchesOffsets); @@ -430,7 +508,7 @@ size_t DIEAttributeCloner::cloneScalarAttr( // .debug_addr would be added later while patching. return Generator .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, - CU.getDebugAddrHeaderSize()) + OutUnit->getDebugAddrHeaderSize()) .second; } else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) AttrInfo.IsDeclaration = true; @@ -443,6 +521,9 @@ size_t DIEAttributeCloner::cloneBlockAttr( const DWARFFormValue &Val, const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { + if (OutUnit.isTypeUnit()) + return 0; + size_t NumberOfPatchesAtStart = PatchesOffsets.size(); // If the block is a DWARF Expression, clone it into the temporary @@ -452,15 +533,14 @@ size_t DIEAttributeCloner::cloneBlockAttr( if (DWARFAttribute::mayHaveLocationExpr(AttrSpec.Attr) && (Val.isFormClass(DWARFFormValue::FC_Block) || Val.isFormClass(DWARFFormValue::FC_Exprloc))) { - DWARFUnit &OrigUnit = CU.getOrigUnit(); DataExtractor Data(StringRef((const char *)Bytes.data(), Bytes.size()), - OrigUnit.isLittleEndian(), - OrigUnit.getAddressByteSize()); - DWARFExpression Expr(Data, OrigUnit.getAddressByteSize(), - OrigUnit.getFormParams().Format); + InUnit.getOrigUnit().isLittleEndian(), + InUnit.getOrigUnit().getAddressByteSize()); + DWARFExpression Expr(Data, InUnit.getOrigUnit().getAddressByteSize(), + InUnit.getFormParams().Format); - CU.cloneDieAttrExpression(Expr, Buffer, DebugInfoOutputSection, - VarAddressAdjustment, PatchesOffsets); + InUnit.cloneDieAttrExpression(Expr, Buffer, DebugInfoOutputSection, + VarAddressAdjustment, PatchesOffsets); Bytes = Buffer; } @@ -491,7 +571,7 @@ size_t DIEAttributeCloner::cloneBlockAttr( if (HasLocationExpressionAddress) AttrInfo.HasLiveAddress = VarAddressAdjustment.has_value() || - CU.getGlobalData().getOptions().UpdateIndexTablesOnly; + InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly; return FinalAttributeSize; } @@ -502,11 +582,14 @@ size_t DIEAttributeCloner::cloneAddressAttr( if (AttrSpec.Attr == dwarf::DW_AT_low_pc) AttrInfo.HasLiveAddress = true; - if (CU.getGlobalData().getOptions().UpdateIndexTablesOnly) + if (InUnit.getGlobalData().getOptions().UpdateIndexTablesOnly) return Generator .addScalarAttribute(AttrSpec.Attr, AttrSpec.Form, Val.getRawUValue()) .second; + if (OutUnit.isTypeUnit()) + return 0; + // Cloned Die may have address attributes relocated to a // totally unrelated value. This can happen: // - If high_pc is an address (Dwarf version == 2), then it might have been @@ -520,25 +603,25 @@ size_t DIEAttributeCloner::cloneAddressAttr( // Info.PCOffset here. std::optional AddrAttribute = - CU.find(InputDieEntry, AttrSpec.Attr); + InUnit.find(InputDieEntry, AttrSpec.Attr); if (!AddrAttribute) llvm_unreachable("Cann't find attribute"); std::optional Addr = AddrAttribute->getAsAddress(); if (!Addr) { - CU.warn("cann't read address attribute value."); + InUnit.warn("cann't read address attribute value."); return 0; } if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit && AttrSpec.Attr == dwarf::DW_AT_low_pc) { - if (std::optional LowPC = CU.getLowPc()) + if (std::optional LowPC = OutUnit.getAsCompileUnit()->getLowPc()) Addr = *LowPC; else return 0; } else if (InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit && AttrSpec.Attr == dwarf::DW_AT_high_pc) { - if (uint64_t HighPc = CU.getHighPc()) + if (uint64_t HighPc = OutUnit.getAsCompileUnit()->getHighPc()) Addr = HighPc; else return 0; @@ -556,20 +639,14 @@ size_t DIEAttributeCloner::cloneAddressAttr( return Generator .addScalarAttribute(AttrSpec.Attr, dwarf::Form::DW_FORM_addrx, - CU.getDebugAddrIndex(*Addr)) + OutUnit.getAsCompileUnit()->getDebugAddrIndex(*Addr)) .second; } unsigned DIEAttributeCloner::finalizeAbbreviations(bool HasChildrenToClone) { - size_t SizeOfAbbreviationNumber = - Generator.finalizeAbbreviations(HasChildrenToClone); - - // We need to update patches offsets after we know the size of the - // abbreviation number. - updatePatchesWithSizeOfAbbreviationNumber(SizeOfAbbreviationNumber); - // Add the size of the abbreviation number to the output offset. - AttrOutOffset += SizeOfAbbreviationNumber; + AttrOutOffset += + Generator.finalizeAbbreviations(HasChildrenToClone, &PatchesOffsets); return AttrOutOffset; } diff --git a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h index 74d80e13148017..e18c0a15cefc63 100644 --- a/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h +++ b/llvm/lib/DWARFLinkerParallel/DIEAttributeCloner.h @@ -13,6 +13,7 @@ #include "DIEGenerator.h" #include "DWARFLinkerCompileUnit.h" #include "DWARFLinkerGlobalData.h" +#include "DWARFLinkerTypeUnit.h" namespace llvm { namespace dwarflinker_parallel { @@ -44,20 +45,28 @@ struct AttributesInfo { /// attribute, adds cloned attribute to the output DIE. class DIEAttributeCloner { public: - DIEAttributeCloner(DIE *OutDIE, CompileUnit &CU, + DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit, CompileUnit *OutUnit, const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &Generator, std::optional FuncAddressAdjustment, std::optional VarAddressAdjustment, bool HasLocationExpressionAddress) - : OutDIE(OutDIE), CU(CU), - DebugInfoOutputSection( - CU.getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo)), - InputDieEntry(InputDieEntry), Generator(Generator), - FuncAddressAdjustment(FuncAddressAdjustment), - VarAddressAdjustment(VarAddressAdjustment), - HasLocationExpressionAddress(HasLocationExpressionAddress) { - InputDIEIdx = CU.getDIEIndex(InputDieEntry); + : DIEAttributeCloner(OutDIE, InUnit, + CompileUnit::OutputUnitVariantPtr(OutUnit), + InputDieEntry, Generator, FuncAddressAdjustment, + VarAddressAdjustment, HasLocationExpressionAddress) { + } + + DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit, TypeUnit *OutUnit, + const DWARFDebugInfoEntry *InputDieEntry, + DIEGenerator &Generator, + std::optional FuncAddressAdjustment, + std::optional VarAddressAdjustment, + bool HasLocationExpressionAddress) + : DIEAttributeCloner(OutDIE, InUnit, + CompileUnit::OutputUnitVariantPtr(OutUnit), + InputDieEntry, Generator, FuncAddressAdjustment, + VarAddressAdjustment, HasLocationExpressionAddress) { } /// Clone attributes of input DIE. @@ -69,7 +78,36 @@ class DIEAttributeCloner { /// Cannot be used concurrently. AttributesInfo AttrInfo; + unsigned getOutOffset() { return AttrOutOffset; } + protected: + DIEAttributeCloner(DIE *OutDIE, CompileUnit &InUnit, + CompileUnit::OutputUnitVariantPtr OutUnit, + const DWARFDebugInfoEntry *InputDieEntry, + DIEGenerator &Generator, + std::optional FuncAddressAdjustment, + std::optional VarAddressAdjustment, + bool HasLocationExpressionAddress) + : OutDIE(OutDIE), InUnit(InUnit), OutUnit(OutUnit), + DebugInfoOutputSection( + OutUnit->getSectionDescriptor(DebugSectionKind::DebugInfo)), + InputDieEntry(InputDieEntry), Generator(Generator), + FuncAddressAdjustment(FuncAddressAdjustment), + VarAddressAdjustment(VarAddressAdjustment), + HasLocationExpressionAddress(HasLocationExpressionAddress) { + InputDIEIdx = InUnit.getDIEIndex(InputDieEntry); + + // Use DW_FORM_strp form for string attributes for DWARF version less than 5 + // or if output unit is type unit and we need to produce deterministic + // result. (We can not generate deterministic results for debug_str_offsets + // section when attributes are cloned parallelly). + Use_DW_FORM_strp = + (InUnit.getVersion() < 5) || + (OutUnit.isTypeUnit() && + ((InUnit.getGlobalData().getOptions().Threads != 1) && + !InUnit.getGlobalData().getOptions().AllowNonDeterministicOutput)); + } + /// Clone string attribute. size_t cloneStringAttr(const DWARFFormValue &Val, @@ -99,18 +137,14 @@ class DIEAttributeCloner { bool shouldSkipAttribute(DWARFAbbreviationDeclaration::AttributeSpec AttrSpec); - /// Update patches offsets with the size of abbreviation number. - void - updatePatchesWithSizeOfAbbreviationNumber(unsigned SizeOfAbbreviationNumber) { - for (uint64_t *OffsetPtr : PatchesOffsets) - *OffsetPtr += SizeOfAbbreviationNumber; - } - /// Output DIE. DIE *OutDIE = nullptr; - /// Compile unit for the output DIE. - CompileUnit &CU; + /// Input compilation unit. + CompileUnit &InUnit; + + /// Output unit(either "plain" compilation unit, either artificial type unit). + CompileUnit::OutputUnitVariantPtr OutUnit; /// .debug_info section descriptor. SectionDescriptor &DebugInfoOutputSection; @@ -139,6 +173,9 @@ class DIEAttributeCloner { /// Patches for the cloned attributes. OffsetsPtrVector PatchesOffsets; + + /// This flag forces using DW_FORM_strp for string attributes. + bool Use_DW_FORM_strp = false; }; } // end of namespace dwarflinker_parallel diff --git a/llvm/lib/DWARFLinkerParallel/DIEGenerator.h b/llvm/lib/DWARFLinkerParallel/DIEGenerator.h index c0bbce0f520143..42bf00f55ff180 100644 --- a/llvm/lib/DWARFLinkerParallel/DIEGenerator.h +++ b/llvm/lib/DWARFLinkerParallel/DIEGenerator.h @@ -23,6 +23,9 @@ class DIEGenerator { DIEGenerator(BumpPtrAllocator &Allocator, DwarfUnit &CU) : Allocator(Allocator), CU(CU) {} + DIEGenerator(DIE *OutputDIE, BumpPtrAllocator &Allocator, DwarfUnit &CU) + : Allocator(Allocator), CU(CU), OutputDIE(OutputDIE) {} + /// Creates a DIE of specified tag \p DieTag and \p OutOffset. DIE *createDIE(dwarf::Tag DieTag, uint32_t OutOffset) { OutputDIE = DIE::get(Allocator, DieTag); @@ -32,6 +35,8 @@ class DIEGenerator { return OutputDIE; } + DIE *getDIE() { return OutputDIE; } + /// Adds a specified \p Child to the current DIE. void addChild(DIE *Child) { assert(Child != nullptr); @@ -126,8 +131,10 @@ class DIEGenerator { } /// Creates appreviations for the current DIE. Returns value of - /// abbreviation number. - size_t finalizeAbbreviations(bool CHILDREN_yes) { + /// abbreviation number. Updates offsets with the size of abbreviation + /// number. + size_t finalizeAbbreviations(bool CHILDREN_yes, + OffsetsPtrVector *OffsetsList) { // Create abbreviations for output DIE. DIEAbbrev NewAbbrev = OutputDIE->generateAbbrev(); if (CHILDREN_yes) @@ -136,7 +143,15 @@ class DIEGenerator { CU.assignAbbrev(NewAbbrev); OutputDIE->setAbbrevNumber(NewAbbrev.getNumber()); - return getULEB128Size(OutputDIE->getAbbrevNumber()); + size_t AbbrevNumberSize = getULEB128Size(OutputDIE->getAbbrevNumber()); + + // Add size of abbreviation number to the offsets. + if (OffsetsList != nullptr) { + for (uint64_t *OffsetPtr : *OffsetsList) + *OffsetPtr += AbbrevNumberSize; + } + + return AbbrevNumberSize; } protected: diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp index f082fd60361003..269f24b1a13b9a 100644 --- a/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "DWARFLinkerImpl.h" +#include "DependencyTracker.h" std::unique_ptr llvm::dwarflinker_parallel::DWARFLinker::createLinker( diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp index c1181a264f879f..48e7cb1fd7e2f3 100644 --- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.cpp @@ -7,17 +7,65 @@ //===----------------------------------------------------------------------===// #include "DWARFLinkerCompileUnit.h" +#include "AcceleratorRecordsSaver.h" #include "DIEAttributeCloner.h" #include "DIEGenerator.h" -#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "DependencyTracker.h" +#include "SyntheticTypeNameBuilder.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "llvm/Support/DJB.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Path.h" +#include using namespace llvm; using namespace llvm::dwarflinker_parallel; +CompileUnit::CompileUnit(LinkingGlobalData &GlobalData, unsigned ID, + StringRef ClangModuleName, DWARFFile &File, + OffsetToUnitTy UnitFromOffset, + dwarf::FormParams Format, llvm::endianness Endianess) + : DwarfUnit(GlobalData, ID, ClangModuleName), File(File), + getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded), + AcceleratorRecords(&GlobalData.getAllocator()) { + UnitName = File.FileName; + setOutputFormat(Format, Endianess); + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); +} + +CompileUnit::CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit, + unsigned ID, StringRef ClangModuleName, + DWARFFile &File, OffsetToUnitTy UnitFromOffset, + dwarf::FormParams Format, llvm::endianness Endianess) + : DwarfUnit(GlobalData, ID, ClangModuleName), File(File), + OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset), + Stage(Stage::CreatedNotLoaded), + AcceleratorRecords(&GlobalData.getAllocator()) { + setOutputFormat(Format, Endianess); + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + + DWARFDie CUDie = OrigUnit.getUnitDIE(); + if (!CUDie) + return; + + if (std::optional Val = CUDie.find(dwarf::DW_AT_language)) { + uint16_t LangVal = dwarf::toUnsigned(Val, 0); + if (isODRLanguage(LangVal)) + Language = LangVal; + } + + if (!GlobalData.getOptions().NoODR && Language.has_value()) + NoODR = false; + + if (const char *CUName = CUDie.getName(DINameKind::ShortName)) + UnitName = CUName; + else + UnitName = File.FileName; + SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str(); +} + void CompileUnit::loadLineTable() { LineTablePtr = File.Dwarf->getLineTableForUnit(&getOrigUnit()); } @@ -39,6 +87,7 @@ void CompileUnit::maybeResetToLoadedStage() { HighPc = 0; Labels.clear(); Ranges.clear(); + Dependencies.reset(nullptr); if (getStage() < Stage::Cloned) { setStage(Stage::Loaded); @@ -53,6 +102,8 @@ void CompileUnit::maybeResetToLoadedStage() { for (uint64_t &Offset : OutDieOffsetArray) Offset = 0; + for (TypeEntry *&Name : TypeEntries) + Name = nullptr; eraseSections(); setStage(Stage::CreatedNotLoaded); @@ -66,21 +117,30 @@ bool CompileUnit::loadInputDIEs() { // load input dies, resize Info structures array. DieInfoArray.resize(getOrigUnit().getNumDIEs()); OutDieOffsetArray.resize(getOrigUnit().getNumDIEs(), 0); + if (!NoODR) + TypeEntries.resize(getOrigUnit().getNumDIEs()); return true; } void CompileUnit::analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry, - bool IsInModule, bool IsInFunction) { + bool IsODRUnavailableFunctionScope) { + CompileUnit::DIEInfo &DieInfo = getDIEInfo(DieEntry); + for (const DWARFDebugInfoEntry *CurChild = getFirstChildEntry(DieEntry); CurChild && CurChild->getAbbreviationDeclarationPtr(); CurChild = getSiblingEntry(CurChild)) { CompileUnit::DIEInfo &ChildInfo = getDIEInfo(CurChild); + bool ChildIsODRUnavailableFunctionScope = IsODRUnavailableFunctionScope; - if (IsInModule) + if (DieInfo.getIsInMouduleScope()) ChildInfo.setIsInMouduleScope(); - if (IsInFunction) + + if (DieInfo.getIsInFunctionScope()) ChildInfo.setIsInFunctionScope(); + if (DieInfo.getIsInAnonNamespaceScope()) + ChildInfo.setIsInAnonNamespaceScope(); + switch (CurChild->getTag()) { case dwarf::DW_TAG_module: ChildInfo.setIsInMouduleScope(); @@ -91,19 +151,35 @@ void CompileUnit::analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry, break; case dwarf::DW_TAG_subprogram: ChildInfo.setIsInFunctionScope(); + if (!ChildIsODRUnavailableFunctionScope && + !ChildInfo.getIsInMouduleScope()) { + if (find(CurChild, + {dwarf::DW_AT_abstract_origin, dwarf::DW_AT_specification})) + ChildIsODRUnavailableFunctionScope = true; + } break; + case dwarf::DW_TAG_namespace: { + UnitEntryPairTy NamespaceEntry = {this, CurChild}; + + if (find(CurChild, dwarf::DW_AT_extension)) + NamespaceEntry = NamespaceEntry.getNamespaceOrigin(); + + if (!NamespaceEntry.CU->find(NamespaceEntry.DieEntry, dwarf::DW_AT_name)) + ChildInfo.setIsInAnonNamespaceScope(); + } break; default: break; } - if (IsInModule) - ChildInfo.setIsInMouduleScope(); - if (IsInFunction) - ChildInfo.setIsInFunctionScope(); + if (!isClangModule() && !getGlobalData().getOptions().UpdateIndexTablesOnly) + ChildInfo.setTrackLiveness(); + + if ((!ChildInfo.getIsInAnonNamespaceScope() && + !ChildIsODRUnavailableFunctionScope && !NoODR)) + ChildInfo.setODRAvailable(); if (CurChild->hasChildren()) - analyzeDWARFStructureRec(CurChild, ChildInfo.getIsInMouduleScope(), - ChildInfo.getIsInFunctionScope()); + analyzeDWARFStructureRec(CurChild, ChildIsODRUnavailableFunctionScope); } } @@ -162,8 +238,11 @@ void CompileUnit::cleanupDataAfterClonning() { AbbreviationsSet.clear(); ResolvedFullPaths.shrink_and_clear(); ResolvedParentPaths.clear(); + FileNames.shrink_and_clear(); DieInfoArray = SmallVector(); OutDieOffsetArray = SmallVector(); + TypeEntries = SmallVector(); + Dependencies.reset(nullptr); getOrigUnit().clear(); } @@ -184,7 +263,7 @@ static SmallString<128> guessToolchainBaseDir(StringRef SysRoot) { /// Collect references to parseable Swift interfaces in imported /// DW_TAG_module blocks. void CompileUnit::analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry) { - if (getLanguage() != dwarf::DW_LANG_Swift) + if (!Language || Language != dwarf::DW_LANG_Swift) return; if (!GlobalData.getOptions().ParseableSwiftInterfaces) @@ -231,12 +310,43 @@ void CompileUnit::analyzeImportedModule(const DWARFDebugInfoEntry *DieEntry) { } } +Error CompileUnit::assignTypeNames(TypePool &TypePoolRef) { + if (!getUnitDIE().isValid()) + return Error::success(); + + SyntheticTypeNameBuilder NameBuilder(TypePoolRef); + return assignTypeNamesRec(getDebugInfoEntry(0), NameBuilder); +} + +Error CompileUnit::assignTypeNamesRec(const DWARFDebugInfoEntry *DieEntry, + SyntheticTypeNameBuilder &NameBuilder) { + OrderedChildrenIndexAssigner ChildrenIndexAssigner(*this, DieEntry); + for (const DWARFDebugInfoEntry *CurChild = getFirstChildEntry(DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = getSiblingEntry(CurChild)) { + CompileUnit::DIEInfo &ChildInfo = getDIEInfo(CurChild); + if (!ChildInfo.needToPlaceInTypeTable()) + continue; + + assert(ChildInfo.getODRAvailable()); + if (Error Err = NameBuilder.assignName( + {this, CurChild}, + ChildrenIndexAssigner.getChildIndex(*this, CurChild))) + return Err; + + if (Error Err = assignTypeNamesRec(CurChild, NameBuilder)) + return Err; + } + + return Error::success(); +} + void CompileUnit::updateDieRefPatchesWithClonedOffsets() { if (std::optional DebugInfoSection = tryGetSectionDescriptor(DebugSectionKind::DebugInfo)) { (*DebugInfoSection) - ->ListDebugDieRefPatch.forEach([](DebugDieRefPatch &Patch) { + ->ListDebugDieRefPatch.forEach([&](DebugDieRefPatch &Patch) { /// Replace stored DIE indexes with DIE output offsets. Patch.RefDieIdxOrClonedOffset = Patch.RefCU.getPointer()->getDieOutOffset( @@ -245,7 +355,7 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() { (*DebugInfoSection) ->ListDebugULEB128DieRefPatch.forEach( - [](DebugULEB128DieRefPatch &Patch) { + [&](DebugULEB128DieRefPatch &Patch) { /// Replace stored DIE indexes with DIE output offsets. Patch.RefDieIdxOrClonedOffset = Patch.RefCU.getPointer()->getDieOutOffset( @@ -278,45 +388,53 @@ void CompileUnit::updateDieRefPatchesWithClonedOffsets() { } } -std::optional> -CompileUnit::resolveDIEReference( +std::optional CompileUnit::resolveDIEReference( const DWARFFormValue &RefValue, ResolveInterCUReferencesMode CanResolveInterCUReferences) { if (std::optional Ref = *RefValue.getAsRelativeReference()) { - if (Ref->Unit != nullptr) { + if (Ref->Unit == OrigUnit) { // Referenced DIE is in current compile unit. - if (std::optional RefDieIdx = - getDIEIndexForOffset(Ref->Unit->getOffset() + Ref->Offset)) - return std::make_pair(this, *RefDieIdx); + getDIEIndexForOffset(OrigUnit->getOffset() + Ref->Offset)) + return UnitEntryPairTy{this, OrigUnit->getDebugInfoEntry(*RefDieIdx)}; } - - if (CompileUnit *RefCU = getUnitFromOffset(Ref->Offset)) { - if (RefCU->getUniqueID() == getUniqueID()) { + uint64_t RefDIEOffset = + Ref->Unit ? Ref->Unit->getOffset() + Ref->Offset : Ref->Offset; + if (CompileUnit *RefCU = getUnitFromOffset(RefDIEOffset)) { + if (RefCU == this) { // Referenced DIE is in current compile unit. if (std::optional RefDieIdx = - getDIEIndexForOffset(Ref->Offset)) - return std::make_pair(this, *RefDieIdx); + getDIEIndexForOffset(RefDIEOffset)) + return UnitEntryPairTy{this, getDebugInfoEntry(*RefDieIdx)}; } else if (CanResolveInterCUReferences) { // Referenced DIE is in other compile unit. // Check whether DIEs are loaded for that compile unit. enum Stage ReferredCUStage = RefCU->getStage(); if (ReferredCUStage < Stage::Loaded || ReferredCUStage > Stage::Cloned) - return std::make_pair(RefCU, 0); + return UnitEntryPairTy{RefCU, nullptr}; if (std::optional RefDieIdx = - RefCU->getDIEIndexForOffset(Ref->Offset)) - return std::make_pair(RefCU, *RefDieIdx); + RefCU->getDIEIndexForOffset(RefDIEOffset)) + return UnitEntryPairTy{RefCU, RefCU->getDebugInfoEntry(*RefDieIdx)}; } else - return std::make_pair(RefCU, 0); + return UnitEntryPairTy{RefCU, nullptr}; } } return std::nullopt; } +std::optional CompileUnit::resolveDIEReference( + const DWARFDebugInfoEntry *DieEntry, dwarf::Attribute Attr, + ResolveInterCUReferencesMode CanResolveInterCUReferences) { + if (std::optional AttrVal = find(DieEntry, Attr)) + return resolveDIEReference(*AttrVal, CanResolveInterCUReferences); + + return std::nullopt; +} + void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, int64_t PcOffset) { std::lock_guard Guard(RangesMutex); @@ -565,48 +683,6 @@ Error CompileUnit::emitDebugAddrSection() { return Error::success(); } -Error CompileUnit::emitDebugStringOffsetSection() { - if (getVersion() < 5) - return Error::success(); - - if (DebugStringIndexMap.empty()) - return Error::success(); - - SectionDescriptor &OutDebugStrOffsetsSection = - getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets); - - // Emit section header. - - // Emit length. - OutDebugStrOffsetsSection.emitUnitLength(0xBADDEF); - uint64_t OffsetAfterSectionLength = OutDebugStrOffsetsSection.OS.tell(); - - // Emit version. - OutDebugStrOffsetsSection.emitIntVal(5, 2); - - // Emit padding. - OutDebugStrOffsetsSection.emitIntVal(0, 2); - - // Emit index to offset map. - for (const StringEntry *String : DebugStringIndexMap.getValues()) { - // Note patch for string offset value. - OutDebugStrOffsetsSection.notePatch( - DebugStrPatch{{OutDebugStrOffsetsSection.OS.tell()}, String}); - - // Emit placeholder for offset value. - OutDebugStrOffsetsSection.emitOffset(0xBADDEF); - } - - // Patch section length. - OutDebugStrOffsetsSection.apply( - OffsetAfterSectionLength - - OutDebugStrOffsetsSection.getFormParams().getDwarfOffsetByteSize(), - dwarf::DW_FORM_sec_offset, - OutDebugStrOffsetsSection.OS.tell() - OffsetAfterSectionLength); - - return Error::success(); -} - Error CompileUnit::cloneAndEmitRanges() { if (getGlobalData().getOptions().UpdateIndexTablesOnly) return Error::success(); @@ -1165,20 +1241,25 @@ void CompileUnit::cloneDieAttrExpression( } } -Error CompileUnit::cloneAndEmit(std::optional TargetTriple) { +Error CompileUnit::cloneAndEmit(std::optional TargetTriple, + TypeUnit *ArtificialTypeUnit) { BumpPtrAllocator Allocator; DWARFDie OrigUnitDIE = getOrigUnit().getUnitDIE(); if (!OrigUnitDIE.isValid()) return Error::success(); + TypeEntry *RootEntry = nullptr; + if (ArtificialTypeUnit) + RootEntry = ArtificialTypeUnit->getTypePool().getRoot(); + // Clone input DIE entry recursively. - DIE *OutCUDie = - cloneDIE(OrigUnitDIE.getDebugInfoEntry(), getDebugInfoHeaderSize(), - std::nullopt, std::nullopt, Allocator); - setOutUnitDIE(OutCUDie); + std::pair OutCUDie = cloneDIE( + OrigUnitDIE.getDebugInfoEntry(), RootEntry, getDebugInfoHeaderSize(), + std::nullopt, std::nullopt, Allocator, ArtificialTypeUnit); + setOutUnitDIE(OutCUDie.first); - if (getGlobalData().getOptions().NoOutput || (OutCUDie == nullptr)) + if (getGlobalData().getOptions().NoOutput || (OutCUDie.first == nullptr)) return Error::success(); assert(TargetTriple.has_value()); @@ -1188,6 +1269,7 @@ Error CompileUnit::cloneAndEmit(std::optional TargetTriple) { if (Error Err = cloneAndEmitDebugMacro()) return Err; + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); if (Error Err = emitDebugInfo(*TargetTriple)) return Err; @@ -1215,27 +1297,103 @@ Error CompileUnit::cloneAndEmit(std::optional TargetTriple) { return emitAbbreviations(); } -bool needToClone(CompileUnit::DIEInfo &Info) { - return Info.getKeep() || Info.getKeepChildren(); -} - -DIE *CompileUnit::cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, - uint64_t OutOffset, - std::optional FuncAddressAdjustment, - std::optional VarAddressAdjustment, - BumpPtrAllocator &Allocator) { +std::pair CompileUnit::cloneDIE( + const DWARFDebugInfoEntry *InputDieEntry, TypeEntry *ClonedParentTypeDIE, + uint64_t OutOffset, std::optional FuncAddressAdjustment, + std::optional VarAddressAdjustment, BumpPtrAllocator &Allocator, + TypeUnit *ArtificialTypeUnit) { uint32_t InputDieIdx = getDIEIndex(InputDieEntry); CompileUnit::DIEInfo &Info = getDIEInfo(InputDieIdx); - if (!needToClone(Info)) - return nullptr; + bool NeedToClonePlainDIE = Info.needToKeepInPlainDwarf(); + bool NeedToCloneTypeDIE = + (InputDieEntry->getTag() != dwarf::DW_TAG_compile_unit) && + Info.needToPlaceInTypeTable(); + std::pair ClonedDIE; + + DIEGenerator PlainDIEGenerator(Allocator, *this); + + if (NeedToClonePlainDIE) + // Create a cloned DIE which would be placed into the cloned version + // of input compile unit. + ClonedDIE.first = createPlainDIEandCloneAttributes( + InputDieEntry, PlainDIEGenerator, OutOffset, FuncAddressAdjustment, + VarAddressAdjustment); + if (NeedToCloneTypeDIE) { + // Create a cloned DIE which would be placed into the artificial type + // unit. + assert(ArtificialTypeUnit != nullptr); + DIEGenerator TypeDIEGenerator( + ArtificialTypeUnit->getTypePool().getThreadLocalAllocator(), *this); + + ClonedDIE.second = createTypeDIEandCloneAttributes( + InputDieEntry, TypeDIEGenerator, ClonedParentTypeDIE, + ArtificialTypeUnit); + } + TypeEntry *TypeParentForChild = + ClonedDIE.second ? ClonedDIE.second : ClonedParentTypeDIE; + + bool HasPlainChildrenToClone = + (ClonedDIE.first && Info.getKeepPlainChildren()); + + bool HasTypeChildrenToClone = + ((ClonedDIE.second || + InputDieEntry->getTag() == dwarf::DW_TAG_compile_unit) && + Info.getKeepTypeChildren()); + + // Recursively clone children. + if (HasPlainChildrenToClone || HasTypeChildrenToClone) { + for (const DWARFDebugInfoEntry *CurChild = + getFirstChildEntry(InputDieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = getSiblingEntry(CurChild)) { + std::pair ClonedChild = cloneDIE( + CurChild, TypeParentForChild, OutOffset, FuncAddressAdjustment, + VarAddressAdjustment, Allocator, ArtificialTypeUnit); + + if (ClonedChild.first) { + OutOffset = + ClonedChild.first->getOffset() + ClonedChild.first->getSize(); + PlainDIEGenerator.addChild(ClonedChild.first); + } + } + assert(ClonedDIE.first == nullptr || + HasPlainChildrenToClone == ClonedDIE.first->hasChildren()); + + // Account for the end of children marker. + if (HasPlainChildrenToClone) + OutOffset += sizeof(int8_t); + } + + // Update our size. + if (ClonedDIE.first != nullptr) + ClonedDIE.first->setSize(OutOffset - ClonedDIE.first->getOffset()); + return ClonedDIE; +} + +DIE *CompileUnit::createPlainDIEandCloneAttributes( + const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &PlainDIEGenerator, + uint64_t &OutOffset, std::optional &FuncAddressAdjustment, + std::optional &VarAddressAdjustment) { + uint32_t InputDieIdx = getDIEIndex(InputDieEntry); + CompileUnit::DIEInfo &Info = getDIEInfo(InputDieIdx); + DIE *ClonedDIE = nullptr; bool HasLocationExpressionAddress = false; if (InputDieEntry->getTag() == dwarf::DW_TAG_subprogram) { // Get relocation adjustment value for the current function. FuncAddressAdjustment = getContaingFile().Addresses->getSubprogramRelocAdjustment( getDIE(InputDieEntry)); + } else if (InputDieEntry->getTag() == dwarf::DW_TAG_label) { + // Get relocation adjustment value for the current label. + std::optional lowPC = + dwarf::toAddress(find(InputDieEntry, dwarf::DW_AT_low_pc)); + if (lowPC) { + LabelMapTy::iterator It = Labels.find(*lowPC); + if (It != Labels.end()) + FuncAddressAdjustment = It->second; + } } else if (InputDieEntry->getTag() == dwarf::DW_TAG_variable) { // Get relocation adjustment value for the current variable. std::pair> LocExprAddrAndRelocAdjustment = @@ -1248,51 +1406,132 @@ DIE *CompileUnit::cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, VarAddressAdjustment = *LocExprAddrAndRelocAdjustment.second; } - DIEGenerator DIEGenerator(Allocator, *this); - DIE *ClonedDIE = DIEGenerator.createDIE(InputDieEntry->getTag(), OutOffset); + ClonedDIE = PlainDIEGenerator.createDIE(InputDieEntry->getTag(), OutOffset); + + // Offset to the DIE would be used after output DIE tree is deleted. + // Thus we need to remember DIE offset separately. rememberDieOutOffset(InputDieIdx, OutOffset); // Clone Attributes. - DIEAttributeCloner AttributesCloner( - ClonedDIE, *this, InputDieEntry, DIEGenerator, FuncAddressAdjustment, - VarAddressAdjustment, HasLocationExpressionAddress); + DIEAttributeCloner AttributesCloner(ClonedDIE, *this, this, InputDieEntry, + PlainDIEGenerator, FuncAddressAdjustment, + VarAddressAdjustment, + HasLocationExpressionAddress); AttributesCloner.clone(); // Remember accelerator info. - rememberAcceleratorEntries(InputDieEntry, OutOffset, - AttributesCloner.AttrInfo); + AcceleratorRecordsSaver AccelRecordsSaver(getGlobalData(), *this, this); + AccelRecordsSaver.save(InputDieEntry, ClonedDIE, AttributesCloner.AttrInfo, + nullptr); - bool HasChildrenToClone = Info.getKeepChildren(); - OutOffset = AttributesCloner.finalizeAbbreviations(HasChildrenToClone); + OutOffset = + AttributesCloner.finalizeAbbreviations(Info.getKeepPlainChildren()); - if (HasChildrenToClone) { - // Recursively clone children. - for (const DWARFDebugInfoEntry *CurChild = - getFirstChildEntry(InputDieEntry); - CurChild && CurChild->getAbbreviationDeclarationPtr(); - CurChild = getSiblingEntry(CurChild)) { - if (DIE *ClonedChild = - cloneDIE(CurChild, OutOffset, FuncAddressAdjustment, - VarAddressAdjustment, Allocator)) { - OutOffset = ClonedChild->getOffset() + ClonedChild->getSize(); - DIEGenerator.addChild(ClonedChild); - } + return ClonedDIE; +} + +/// Allocates output DIE for the specified \p TypeDescriptor. +DIE *CompileUnit::allocateTypeDie(TypeEntryBody *TypeDescriptor, + DIEGenerator &TypeDIEGenerator, + dwarf::Tag DieTag, bool IsDeclaration, + bool IsParentDeclaration) { + DIE *DefinitionDie = TypeDescriptor->Die; + // Do not allocate any new DIE if definition DIE is already met. + if (DefinitionDie) + return nullptr; + + DIE *DeclarationDie = TypeDescriptor->DeclarationDie; + bool OldParentIsDeclaration = TypeDescriptor->ParentIsDeclaration; + + if (IsDeclaration && !DeclarationDie) { + // Alocate declaration DIE. + DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0); + if (TypeDescriptor->DeclarationDie.compare_exchange_weak(DeclarationDie, + NewDie)) + return NewDie; + } else if (IsDeclaration && !IsParentDeclaration && OldParentIsDeclaration) { + // Overwrite existing declaration DIE if it's parent is also an declaration + // while parent of current declaration DIE is a definition. + if (TypeDescriptor->ParentIsDeclaration.compare_exchange_weak( + OldParentIsDeclaration, false)) { + DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0); + TypeDescriptor->DeclarationDie = NewDie; + return NewDie; + } + } else if (!IsDeclaration && IsParentDeclaration && !DeclarationDie) { + // Alocate declaration DIE since parent of current DIE is marked as + // declaration. + DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0); + if (TypeDescriptor->DeclarationDie.compare_exchange_weak(DeclarationDie, + NewDie)) + return NewDie; + } else if (!IsDeclaration && !IsParentDeclaration) { + // Allocate definition DIE. + DIE *NewDie = TypeDIEGenerator.createDIE(DieTag, 0); + if (TypeDescriptor->Die.compare_exchange_weak(DefinitionDie, NewDie)) { + TypeDescriptor->ParentIsDeclaration = false; + return NewDie; } + } - // Account for the end of children marker. - OutOffset += sizeof(int8_t); + return nullptr; +} + +TypeEntry *CompileUnit::createTypeDIEandCloneAttributes( + const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &TypeDIEGenerator, + TypeEntry *ClonedParentTypeDIE, TypeUnit *ArtificialTypeUnit) { + assert(ArtificialTypeUnit != nullptr); + uint32_t InputDieIdx = getDIEIndex(InputDieEntry); + + TypeEntry *Entry = getDieTypeEntry(InputDieIdx); + assert(Entry != nullptr); + assert(ClonedParentTypeDIE != nullptr); + TypeEntryBody *EntryBody = + ArtificialTypeUnit->getTypePool().getOrCreateTypeEntryBody( + Entry, ClonedParentTypeDIE); + assert(EntryBody); + + bool IsDeclaration = + dwarf::toUnsigned(find(InputDieEntry, dwarf::DW_AT_declaration), 0); + + bool ParentIsDeclaration = false; + if (std::optional ParentIdx = InputDieEntry->getParentIdx()) + ParentIsDeclaration = + dwarf::toUnsigned(find(*ParentIdx, dwarf::DW_AT_declaration), 0); + + DIE *OutDIE = + allocateTypeDie(EntryBody, TypeDIEGenerator, InputDieEntry->getTag(), + IsDeclaration, ParentIsDeclaration); + + if (OutDIE != nullptr) { + assert(ArtificialTypeUnit != nullptr); + ArtificialTypeUnit->getSectionDescriptor(DebugSectionKind::DebugInfo); + + DIEAttributeCloner AttributesCloner(OutDIE, *this, ArtificialTypeUnit, + InputDieEntry, TypeDIEGenerator, + std::nullopt, std::nullopt, false); + AttributesCloner.clone(); + + // Remember accelerator info. + AcceleratorRecordsSaver AccelRecordsSaver(getGlobalData(), *this, + ArtificialTypeUnit); + AccelRecordsSaver.save(InputDieEntry, OutDIE, AttributesCloner.AttrInfo, + Entry); + + // if AttributesCloner.getOutOffset() == 0 then we need to add + // 1 to avoid assertion for zero size. We will subtract it back later. + OutDIE->setSize(AttributesCloner.getOutOffset() + 1); } - // Update our size. - ClonedDIE->setSize(OutOffset - ClonedDIE->getOffset()); - return ClonedDIE; + return Entry; } Error CompileUnit::cloneAndEmitLineTable(Triple &TargetTriple) { const DWARFDebugLine::LineTable *InputLineTable = getContaingFile().Dwarf->getLineTableForUnit(&getOrigUnit()); if (InputLineTable == nullptr) { - warn("cann't load line table."); + if (getOrigUnit().getUnitDIE().find(dwarf::DW_AT_stmt_list)) + warn("cann't load line table."); return Error::success(); } @@ -1413,230 +1652,228 @@ void CompileUnit::insertLineSequence(std::vector &Seq, #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void CompileUnit::DIEInfo::dump() { - llvm::errs() << "{\n"; + llvm::errs() << "{"; llvm::errs() << " Placement: "; switch (getPlacement()) { case NotSet: - llvm::errs() << "NotSet\n"; + llvm::errs() << "NotSet"; break; case TypeTable: - llvm::errs() << "TypeTable\n"; + llvm::errs() << "TypeTable"; break; case PlainDwarf: - llvm::errs() << "PlainDwarf\n"; + llvm::errs() << "PlainDwarf"; break; case Both: - llvm::errs() << "Both\n"; - break; - case Parent: - llvm::errs() << "Parent\n"; + llvm::errs() << "Both"; break; } llvm::errs() << " Keep: " << getKeep(); - llvm::errs() << " KeepChildren: " << getKeepChildren(); - llvm::errs() << " ReferrencedBy: " << getReferrencedBy(); + llvm::errs() << " KeepPlainChildren: " << getKeepPlainChildren(); + llvm::errs() << " KeepTypeChildren: " << getKeepTypeChildren(); llvm::errs() << " IsInMouduleScope: " << getIsInMouduleScope(); llvm::errs() << " IsInFunctionScope: " << getIsInFunctionScope(); + llvm::errs() << " IsInAnonNamespaceScope: " << getIsInAnonNamespaceScope(); + llvm::errs() << " ODRAvailable: " << getODRAvailable(); + llvm::errs() << " TrackLiveness: " << getTrackLiveness(); llvm::errs() << "}\n"; } #endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -static uint32_t hashFullyQualifiedName(CompileUnit *InputCU, DWARFDie &InputDIE, - int ChildRecurseDepth = 0) { - const char *Name = nullptr; - CompileUnit *CU = InputCU; - std::optional RefVal; +std::optional> +CompileUnit::getDirAndFilenameFromLineTable( + const DWARFFormValue &FileIdxValue) { + uint64_t FileIdx; + if (std::optional Val = FileIdxValue.getAsUnsignedConstant()) + FileIdx = *Val; + else if (std::optional Val = FileIdxValue.getAsSignedConstant()) + FileIdx = *Val; + else if (std::optional Val = FileIdxValue.getAsSectionOffset()) + FileIdx = *Val; + else + return std::nullopt; - // Usually name`s depth does not exceed 3. Set maximal depth - // to 1000 here, to avoid infinite loop in case incorrect input - // DWARF. - size_t MaxNameDepth = 1000; - size_t CurNameDepth = 0; + return getDirAndFilenameFromLineTable(FileIdx); +} - while (CurNameDepth++ < MaxNameDepth) { - if (const char *CurrentName = InputDIE.getName(DINameKind::ShortName)) - Name = CurrentName; +static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) { + // Debug info can contain paths from any OS, not necessarily + // an OS we're currently running on. Moreover different compilation units can + // be compiled on different operating systems and linked together later. + return sys::path::is_absolute(Path, sys::path::Style::posix) || + sys::path::is_absolute(Path, sys::path::Style::windows); +} - if (!(RefVal = InputDIE.find(dwarf::DW_AT_specification)) && - !(RefVal = InputDIE.find(dwarf::DW_AT_abstract_origin))) - break; +std::optional> +CompileUnit::getDirAndFilenameFromLineTable(uint64_t FileIdx) { + FileNamesCache::iterator FileData = FileNames.find(FileIdx); + if (FileData != FileNames.end()) + return std::make_pair(StringRef(FileData->second.first), + StringRef(FileData->second.second)); - if (!RefVal->isFormClass(DWARFFormValue::FC_Reference)) - break; + if (const DWARFDebugLine::LineTable *LineTable = + getOrigUnit().getContext().getLineTableForUnit(&getOrigUnit())) { + if (LineTable->hasFileAtIndex(FileIdx)) { - std::optional> RefDie = - CU->resolveDIEReference(*RefVal, ResolveInterCUReferencesMode::Resolve); - if (!RefDie) - break; + const llvm::DWARFDebugLine::FileNameEntry &Entry = + LineTable->Prologue.getFileNameEntry(FileIdx); + + Expected Name = Entry.Name.getAsCString(); + if (!Name) { + warn(Name.takeError()); + return std::nullopt; + } + + std::string FileName = *Name; + if (isPathAbsoluteOnWindowsOrPosix(FileName)) { + FileNamesCache::iterator FileData = + FileNames + .insert(std::make_pair( + FileIdx, + std::make_pair(std::string(""), std::move(FileName)))) + .first; + return std::make_pair(StringRef(FileData->second.first), + StringRef(FileData->second.second)); + } + + SmallString<256> FilePath; + StringRef IncludeDir; + // Be defensive about the contents of Entry. + if (getVersion() >= 5) { + // DirIdx 0 is the compilation directory, so don't include it for + // relative names. + if ((Entry.DirIdx != 0) && + Entry.DirIdx < LineTable->Prologue.IncludeDirectories.size()) { + Expected DirName = + LineTable->Prologue.IncludeDirectories[Entry.DirIdx] + .getAsCString(); + if (DirName) + IncludeDir = *DirName; + else { + warn(DirName.takeError()); + return std::nullopt; + } + } + } else { + if (0 < Entry.DirIdx && + Entry.DirIdx <= LineTable->Prologue.IncludeDirectories.size()) { + Expected DirName = + LineTable->Prologue.IncludeDirectories[Entry.DirIdx - 1] + .getAsCString(); + if (DirName) + IncludeDir = *DirName; + else { + warn(DirName.takeError()); + return std::nullopt; + } + } + } + + StringRef CompDir = getOrigUnit().getCompilationDir(); + + if (!CompDir.empty() && !isPathAbsoluteOnWindowsOrPosix(IncludeDir)) { + sys::path::append(FilePath, sys::path::Style::native, CompDir); + } - assert(RefDie->second != 0); + sys::path::append(FilePath, sys::path::Style::native, IncludeDir); - CU = RefDie->first; - InputDIE = RefDie->first->getDIEAtIndex(RefDie->second); + FileNamesCache::iterator FileData = + FileNames + .insert( + std::make_pair(FileIdx, std::make_pair(std::string(FilePath), + std::move(FileName)))) + .first; + return std::make_pair(StringRef(FileData->second.first), + StringRef(FileData->second.second)); + } } - if (!Name && InputDIE.getTag() == dwarf::DW_TAG_namespace) - Name = "(anonymous namespace)"; + return std::nullopt; +} + +#define MAX_REFERENCIES_DEPTH 1000 +UnitEntryPairTy UnitEntryPairTy::getNamespaceOrigin() { + UnitEntryPairTy CUDiePair(*this); + std::optional RefDiePair; + int refDepth = 0; + do { + RefDiePair = CUDiePair.CU->resolveDIEReference( + CUDiePair.DieEntry, dwarf::DW_AT_extension, + ResolveInterCUReferencesMode::Resolve); + if (!RefDiePair || !RefDiePair->DieEntry) + return CUDiePair; + + CUDiePair = *RefDiePair; + } while (refDepth++ < MAX_REFERENCIES_DEPTH); + + return CUDiePair; +} - DWARFDie ParentDie = InputDIE.getParent(); - if (!ParentDie.isValid() || ParentDie.getTag() == dwarf::DW_TAG_compile_unit) - return djbHash(Name ? Name : "", djbHash(ChildRecurseDepth ? "" : "::")); +std::optional UnitEntryPairTy::getParent() { + if (std::optional ParentIdx = DieEntry->getParentIdx()) + return UnitEntryPairTy{CU, CU->getDebugInfoEntry(*ParentIdx)}; - return djbHash( - (Name ? Name : ""), - djbHash((Name ? "::" : ""), - hashFullyQualifiedName(CU, ParentDie, ++ChildRecurseDepth))); + return std::nullopt; } -void CompileUnit::rememberAcceleratorEntries( - const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset, - AttributesInfo &AttrInfo) { - if (GlobalData.getOptions().AccelTables.empty()) - return; +CompileUnit::OutputUnitVariantPtr::OutputUnitVariantPtr(CompileUnit *U) + : Ptr(U) { + assert(U != nullptr); +} - DWARFDie InputDIE = getDIE(InputDieEntry); - - // Look for short name recursively if short name is not known yet. - if (AttrInfo.Name == nullptr) - if (const char *ShortName = InputDIE.getShortName()) - AttrInfo.Name = getGlobalData().getStringPool().insert(ShortName).first; - - switch (InputDieEntry->getTag()) { - case dwarf::DW_TAG_array_type: - case dwarf::DW_TAG_class_type: - case dwarf::DW_TAG_enumeration_type: - case dwarf::DW_TAG_pointer_type: - case dwarf::DW_TAG_reference_type: - case dwarf::DW_TAG_string_type: - case dwarf::DW_TAG_structure_type: - case dwarf::DW_TAG_subroutine_type: - case dwarf::DW_TAG_typedef: - case dwarf::DW_TAG_union_type: - case dwarf::DW_TAG_ptr_to_member_type: - case dwarf::DW_TAG_set_type: - case dwarf::DW_TAG_subrange_type: - case dwarf::DW_TAG_base_type: - case dwarf::DW_TAG_const_type: - case dwarf::DW_TAG_constant: - case dwarf::DW_TAG_file_type: - case dwarf::DW_TAG_namelist: - case dwarf::DW_TAG_packed_type: - case dwarf::DW_TAG_volatile_type: - case dwarf::DW_TAG_restrict_type: - case dwarf::DW_TAG_atomic_type: - case dwarf::DW_TAG_interface_type: - case dwarf::DW_TAG_unspecified_type: - case dwarf::DW_TAG_shared_type: - case dwarf::DW_TAG_immutable_type: - case dwarf::DW_TAG_rvalue_reference_type: { - if (!AttrInfo.IsDeclaration && AttrInfo.Name != nullptr && - !AttrInfo.Name->getKey().empty()) { - uint32_t Hash = hashFullyQualifiedName(this, InputDIE); - - uint64_t RuntimeLang = - dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class)) - .value_or(0); - - bool ObjCClassIsImplementation = - (RuntimeLang == dwarf::DW_LANG_ObjC || - RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) && - dwarf::toUnsigned( - InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type)) - .value_or(0); - - rememberTypeForAccelerators(AttrInfo.Name, OutOffset, - InputDieEntry->getTag(), Hash, - ObjCClassIsImplementation); - } - } break; - case dwarf::DW_TAG_namespace: { - if (AttrInfo.Name == nullptr) - AttrInfo.Name = - getGlobalData().getStringPool().insert("(anonymous namespace)").first; - - rememberNamespaceForAccelerators(AttrInfo.Name, OutOffset, - InputDieEntry->getTag()); - } break; - case dwarf::DW_TAG_imported_declaration: { - if (AttrInfo.Name != nullptr) - rememberNamespaceForAccelerators(AttrInfo.Name, OutOffset, - InputDieEntry->getTag()); - } break; - case dwarf::DW_TAG_compile_unit: - case dwarf::DW_TAG_lexical_block: { - // Nothing to do. - } break; - default: - if (AttrInfo.HasLiveAddress || AttrInfo.HasRanges) { - if (AttrInfo.Name != nullptr) - rememberNameForAccelerators( - AttrInfo.Name, OutOffset, InputDieEntry->getTag(), - InputDieEntry->getTag() == dwarf::DW_TAG_inlined_subroutine); - - // Look for mangled name recursively if mangled name is not known yet. - if (AttrInfo.MangledName == nullptr) - if (const char *LinkageName = InputDIE.getLinkageName()) - AttrInfo.MangledName = - getGlobalData().getStringPool().insert(LinkageName).first; - - if (AttrInfo.MangledName != nullptr && - AttrInfo.MangledName != AttrInfo.Name) - rememberNameForAccelerators( - AttrInfo.MangledName, OutOffset, InputDieEntry->getTag(), - InputDieEntry->getTag() == dwarf::DW_TAG_inlined_subroutine); - - // Strip template parameters from the short name. - if (AttrInfo.Name != nullptr && AttrInfo.MangledName != AttrInfo.Name && - (InputDieEntry->getTag() != dwarf::DW_TAG_inlined_subroutine)) { - if (std::optional Name = - StripTemplateParameters(AttrInfo.Name->getKey())) { - StringEntry *NameWithoutTemplateParams = - getGlobalData().getStringPool().insert(*Name).first; - - rememberNameForAccelerators(NameWithoutTemplateParams, OutOffset, - InputDieEntry->getTag(), true); - } - } +CompileUnit::OutputUnitVariantPtr::OutputUnitVariantPtr(TypeUnit *U) : Ptr(U) { + assert(U != nullptr); +} - if (AttrInfo.Name) - rememberObjCAccelerator(InputDieEntry, OutOffset, AttrInfo); - } - break; - } +DwarfUnit *CompileUnit::OutputUnitVariantPtr::operator->() { + if (isCompileUnit()) + return getAsCompileUnit(); + else + return getAsTypeUnit(); } -void CompileUnit::rememberObjCAccelerator( - const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset, - AttributesInfo &AttrInfo) { - std::optional Names = - getObjCNamesIfSelector(AttrInfo.Name->getKey()); - if (!Names) - return; +bool CompileUnit::OutputUnitVariantPtr::isCompileUnit() { + return Ptr.is(); +} - StringEntry *Selector = - getGlobalData().getStringPool().insert(Names->Selector).first; - rememberNameForAccelerators(Selector, OutOffset, InputDieEntry->getTag(), - true); - StringEntry *ClassName = - getGlobalData().getStringPool().insert(Names->ClassName).first; - rememberObjCNameForAccelerators(ClassName, OutOffset, - InputDieEntry->getTag()); - if (Names->ClassNameNoCategory) { - StringEntry *ClassNameNoCategory = getGlobalData() - .getStringPool() - .insert(*Names->ClassNameNoCategory) - .first; - rememberObjCNameForAccelerators(ClassNameNoCategory, OutOffset, - InputDieEntry->getTag()); - } - if (Names->MethodNameNoCategory) { - StringEntry *MethodNameNoCategory = - getGlobalData() - .getStringPool() - .insert(*Names->MethodNameNoCategory) - .first; - rememberNameForAccelerators(MethodNameNoCategory, OutOffset, - InputDieEntry->getTag(), true); - } +bool CompileUnit::OutputUnitVariantPtr::isTypeUnit() { + return Ptr.is(); +} + +CompileUnit *CompileUnit::OutputUnitVariantPtr::getAsCompileUnit() { + return Ptr.get(); +} + +TypeUnit *CompileUnit::OutputUnitVariantPtr::getAsTypeUnit() { + return Ptr.get(); +} + +bool CompileUnit::resolveDependenciesAndMarkLiveness( + bool InterCUProcessingStarted, std::atomic &HasNewInterconnectedCUs) { + if (!Dependencies.get()) + Dependencies.reset(new DependencyTracker(*this)); + + return Dependencies->resolveDependenciesAndMarkLiveness( + InterCUProcessingStarted, HasNewInterconnectedCUs); +} + +bool CompileUnit::updateDependenciesCompleteness() { + assert(Dependencies.get()); + + return Dependencies.get()->updateDependenciesCompleteness(); +} + +void CompileUnit::verifyDependencies() { + assert(Dependencies.get()); + + Dependencies.get()->verifyKeepChain(); +} + +ArrayRef llvm::dwarflinker_parallel::getODRAttributes() { + static dwarf::Attribute ODRAttributes[] = { + dwarf::DW_AT_type, dwarf::DW_AT_specification, + dwarf::DW_AT_abstract_origin, dwarf::DW_AT_import}; + + return ODRAttributes; } diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h index 54666f684f3a3b..39e010fd632393 100644 --- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h @@ -10,7 +10,6 @@ #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H #include "DWARFLinkerUnit.h" -#include "IndexedValuesMap.h" #include "llvm/DWARFLinkerParallel/DWARFFile.h" #include @@ -20,6 +19,26 @@ namespace dwarflinker_parallel { using OffsetToUnitTy = function_ref; struct AttributesInfo; +class SyntheticTypeNameBuilder; +class DIEGenerator; +class TypeUnit; +class DependencyTracker; + +class CompileUnit; + +/// This is a helper structure which keeps a debug info entry +/// with it's containing compilation unit. +struct UnitEntryPairTy { + UnitEntryPairTy() = default; + UnitEntryPairTy(CompileUnit *CU, const DWARFDebugInfoEntry *DieEntry) + : CU(CU), DieEntry(DieEntry) {} + + CompileUnit *CU = nullptr; + const DWARFDebugInfoEntry *DieEntry = nullptr; + + UnitEntryPairTy getNamespaceOrigin(); + std::optional getParent(); +}; enum ResolveInterCUReferencesMode : bool { Resolve = true, @@ -42,6 +61,13 @@ class CompileUnit : public DwarfUnit { /// discovered, type names are assigned if ODR is requested). LivenessAnalysisDone, + /// Check if dependencies have incompatible placement. + /// If that is the case modify placement to be compatible. + UpdateDependenciesCompleteness, + + /// Type names assigned to DIEs. + TypeNamesAssigned, + /// Output DWARF is generated. Cloned, @@ -50,38 +76,20 @@ class CompileUnit : public DwarfUnit { /// Resources(Input DWARF, Output DWARF tree) are released. Cleaned, + + /// Compile Unit should be skipped + Skipped }; CompileUnit(LinkingGlobalData &GlobalData, unsigned ID, StringRef ClangModuleName, DWARFFile &File, OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format, - llvm::endianness Endianess) - : DwarfUnit(GlobalData, ID, ClangModuleName), File(File), - getUnitFromOffset(UnitFromOffset), Stage(Stage::CreatedNotLoaded) { - UnitName = File.FileName; - setOutputFormat(Format, Endianess); - } + llvm::endianness Endianess); CompileUnit(LinkingGlobalData &GlobalData, DWARFUnit &OrigUnit, unsigned ID, StringRef ClangModuleName, DWARFFile &File, OffsetToUnitTy UnitFromOffset, dwarf::FormParams Format, - llvm::endianness Endianess) - : DwarfUnit(GlobalData, ID, ClangModuleName), File(File), - OrigUnit(&OrigUnit), getUnitFromOffset(UnitFromOffset), - Stage(Stage::CreatedNotLoaded) { - DWARFDie CUDie = OrigUnit.getUnitDIE(); - if (!CUDie) - return; - - setOutputFormat(Format, Endianess); - - Language = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language), 0); - if (const char *CUName = CUDie.getName(DINameKind::ShortName)) - UnitName = CUName; - else - UnitName = File.FileName; - SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str(); - } + llvm::endianness Endianess); /// Returns stage of overall processing. Stage getStage() const { return Stage; } @@ -114,7 +122,7 @@ class CompileUnit : public DwarfUnit { /// Navigate DWARF tree and set die properties. void analyzeDWARFStructure() { - analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false, false); + analyzeDWARFStructureRec(getUnitDIE().getDebugInfoEntry(), false); } /// Cleanup unneeded resources after compile unit is cloned. @@ -124,25 +132,34 @@ class CompileUnit : public DwarfUnit { /// This method copies output offsets for referenced DIEs into DIEs patches. void updateDieRefPatchesWithClonedOffsets(); + /// Search for subprograms and variables referencing live code and discover + /// dependend DIEs. Mark live DIEs, set placement for DIEs. + bool resolveDependenciesAndMarkLiveness( + bool InterCUProcessingStarted, + std::atomic &HasNewInterconnectedCUs); + + /// Check dependend DIEs for incompatible placement. + /// Make placement to be consistent. + bool updateDependenciesCompleteness(); + + /// Check DIEs to have a consistent marking(keep marking, placement marking). + void verifyDependencies(); + + /// Search for type entries and assign names. + Error assignTypeNames(TypePool &TypePoolRef); + /// Kinds of placement for the output die. enum DieOutputPlacement : uint8_t { NotSet = 0, /// Corresponding DIE goes to the type table only. - /// NOTE: Not used yet. TypeTable = 1, /// Corresponding DIE goes to the plain dwarf only. PlainDwarf = 2, /// Corresponding DIE goes to type table and to plain dwarf. - /// NOTE: Not used yet. Both = 3, - - /// Corresponding DIE needs to examine parent to determine - /// the point of placement. - /// NOTE: Not used yet. - Parent = 4 }; /// Information gathered about source DIEs. @@ -204,10 +221,10 @@ class CompileUnit : public DwarfUnit { SINGLE_FLAG_METHODS_SET(Keep, 0x08) /// DIE has children which are part of the linked output. - SINGLE_FLAG_METHODS_SET(KeepChildren, 0x10) + SINGLE_FLAG_METHODS_SET(KeepPlainChildren, 0x10) - /// DIE is referenced by other DIE. - SINGLE_FLAG_METHODS_SET(ReferrencedBy, 0x20) + /// DIE has children which are part of the type table. + SINGLE_FLAG_METHODS_SET(KeepTypeChildren, 0x20) /// DIE is in module scope. SINGLE_FLAG_METHODS_SET(IsInMouduleScope, 0x40) @@ -215,6 +232,18 @@ class CompileUnit : public DwarfUnit { /// DIE is in function scope. SINGLE_FLAG_METHODS_SET(IsInFunctionScope, 0x80) + /// DIE is in anonymous namespace scope. + SINGLE_FLAG_METHODS_SET(IsInAnonNamespaceScope, 0x100) + + /// DIE is available for ODR type deduplication. + SINGLE_FLAG_METHODS_SET(ODRAvailable, 0x200) + + /// Track liveness for the DIE. + SINGLE_FLAG_METHODS_SET(TrackLiveness, 0x400) + + /// Track liveness for the DIE. + SINGLE_FLAG_METHODS_SET(HasAnAddress, 0x800) + void unsetFlagsWhichSetDuringLiveAnalysis() { auto InputData = Flags.load(); while (!Flags.compare_exchange_weak( @@ -228,6 +257,18 @@ class CompileUnit : public DwarfUnit { #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump(); #endif + + bool needToPlaceInTypeTable() const { + return (getKeep() && (getPlacement() == CompileUnit::TypeTable || + getPlacement() == CompileUnit::Both)) || + getKeepTypeChildren(); + } + + bool needToKeepInPlainDwarf() const { + return (getKeep() && (getPlacement() == CompileUnit::PlainDwarf || + getPlacement() == CompileUnit::Both)) || + getKeepPlainChildren(); + } }; /// \defgroup Group of functions returning DIE info. @@ -273,6 +314,29 @@ class CompileUnit : public DwarfUnit { ->load(); } + /// \p Idx index of the DIE. + /// \returns type entry. + TypeEntry *getDieTypeEntry(uint32_t Idx) { + return reinterpret_cast *>(&TypeEntries[Idx]) + ->load(); + } + + /// \p InputDieEntry debug info entry. + /// \returns DieInfo descriptor. + uint64_t getDieOutOffset(const DWARFDebugInfoEntry *InputDieEntry) { + return reinterpret_cast *>( + &OutDieOffsetArray[getOrigUnit().getDIEIndex(InputDieEntry)]) + ->load(); + } + + /// \p InputDieEntry debug info entry. + /// \returns type entry. + TypeEntry *getDieTypeEntry(const DWARFDebugInfoEntry *InputDieEntry) { + return reinterpret_cast *>( + &TypeEntries[getOrigUnit().getDIEIndex(InputDieEntry)]) + ->load(); + } + /// \p Idx index of the DIE. /// \returns DieInfo descriptor. void rememberDieOutOffset(uint32_t Idx, uint64_t Offset) { @@ -280,6 +344,22 @@ class CompileUnit : public DwarfUnit { ->store(Offset); } + /// \p Idx index of the DIE. + /// \p Type entry. + void setDieTypeEntry(uint32_t Idx, TypeEntry *Entry) { + reinterpret_cast *>(&TypeEntries[Idx]) + ->store(Entry); + } + + /// \p InputDieEntry debug info entry. + /// \p Type entry. + void setDieTypeEntry(const DWARFDebugInfoEntry *InputDieEntry, + TypeEntry *Entry) { + reinterpret_cast *>( + &TypeEntries[getOrigUnit().getDIEIndex(InputDieEntry)]) + ->store(Entry); + } + /// @} /// Returns value of DW_AT_low_pc attribute. @@ -299,9 +379,15 @@ class CompileUnit : public DwarfUnit { /// RefValue. The resulting DIE might be in another CompileUnit. /// \returns referenced die and corresponding compilation unit. /// compilation unit is null if reference could not be resolved. - std::optional> + std::optional resolveDIEReference(const DWARFFormValue &RefValue, ResolveInterCUReferencesMode CanResolveInterCUReferences); + + std::optional + resolveDIEReference(const DWARFDebugInfoEntry *DieEntry, + dwarf::Attribute Attr, + ResolveInterCUReferencesMode CanResolveInterCUReferences); + /// @} /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying @@ -312,7 +398,8 @@ class CompileUnit : public DwarfUnit { const RangesTy &getFunctionRanges() const { return Ranges; } /// Clone and emit this compilation unit. - Error cloneAndEmit(std::optional TargetTriple); + Error cloneAndEmit(std::optional TargetTriple, + TypeUnit *ArtificialTypeUnit); /// Clone and emit debug locations(.debug_loc/.debug_loclists). Error cloneAndEmitDebugLocations(); @@ -324,10 +411,12 @@ class CompileUnit : public DwarfUnit { Error cloneAndEmitDebugMacro(); // Clone input DIE entry. - DIE *cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, uint64_t OutOffset, - std::optional FuncAddressAdjustment, - std::optional VarAddressAdjustment, - BumpPtrAllocator &Allocator); + std::pair + cloneDIE(const DWARFDebugInfoEntry *InputDieEntry, + TypeEntry *ClonedParentTypeDIE, uint64_t OutOffset, + std::optional FuncAddressAdjustment, + std::optional VarAddressAdjustment, + BumpPtrAllocator &Allocator, TypeUnit *ArtificialTypeUnit); // Clone and emit line table. Error cloneAndEmitLineTable(Triple &TargetTriple); @@ -344,10 +433,13 @@ class CompileUnit : public DwarfUnit { return DebugAddrIndexMap.getValueIndex(Addr); } - /// Returns index(inside .debug_str_offsets) of specified string. - uint64_t getDebugStrIndex(const StringEntry *String) { - return DebugStringIndexMap.getValueIndex(String); - } + /// Returns directory and file from the line table by index. + std::optional> + getDirAndFilenameFromLineTable(const DWARFFormValue &FileIdxValue); + + /// Returns directory and file from the line table by index. + std::optional> + getDirAndFilenameFromLineTable(uint64_t FileIdx); /// \defgroup Helper methods to access OrigUnit. /// @@ -469,10 +561,44 @@ class CompileUnit : public DwarfUnit { /// @} + /// Save specified accelerator info \p Info. + void saveAcceleratorInfo(const DwarfUnit::AccelInfo &Info) { + AcceleratorRecords.add(Info); + } + + /// Enumerates all units accelerator records. + void + forEachAcceleratorRecord(function_ref Handler) override { + AcceleratorRecords.forEach(Handler); + } + + /// Output unit selector. + class OutputUnitVariantPtr { + public: + OutputUnitVariantPtr(CompileUnit *U); + OutputUnitVariantPtr(TypeUnit *U); + + /// Accessor for common functionality. + DwarfUnit *operator->(); + + bool isCompileUnit(); + + bool isTypeUnit(); + + /// Returns CompileUnit if applicable. + CompileUnit *getAsCompileUnit(); + + /// Returns TypeUnit if applicable. + TypeUnit *getAsTypeUnit(); + + protected: + PointerUnion Ptr; + }; + private: /// Navigate DWARF tree recursively and set die properties. void analyzeDWARFStructureRec(const DWARFDebugInfoEntry *DieEntry, - bool IsInModule, bool IsInFunction); + bool IsODRUnavailableFunctionScope); struct LinkedLocationExpressionsWithOffsetPatches { DWARFLocationExpression Expression; @@ -495,9 +621,6 @@ class CompileUnit : public DwarfUnit { /// Emit the .debug_addr section fragment for current unit. Error emitDebugAddrSection(); - /// Emit the .debug_str_offsets section for current unit. - Error emitDebugStringOffsetSection(); - /// Emit .debug_aranges. void emitAranges(AddressRanges &LinkedFunctionRanges); @@ -521,13 +644,25 @@ class CompileUnit : public DwarfUnit { void emitMacroTableImpl(const DWARFDebugMacro *MacroTable, uint64_t OffsetToMacroTable, bool hasDWARFv5Header); - /// Store accelerator information for the \p InputDieEntry. - void rememberAcceleratorEntries(const DWARFDebugInfoEntry *InputDieEntry, - uint64_t OutOffset, AttributesInfo &AttrInfo); + /// Creates DIE which would be placed into the "Plain" compile unit. + DIE *createPlainDIEandCloneAttributes( + const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &PlainDIEGenerator, + uint64_t &OutOffset, std::optional &FuncAddressAdjustment, + std::optional &VarAddressAdjustment); + + /// Creates DIE which would be placed into the "Type" compile unit. + TypeEntry *createTypeDIEandCloneAttributes( + const DWARFDebugInfoEntry *InputDieEntry, DIEGenerator &TypeDIEGenerator, + TypeEntry *ClonedParentTypeDIE, TypeUnit *ArtificialTypeUnit); + + /// Create output DIE inside specified \p TypeDescriptor. + DIE *allocateTypeDie(TypeEntryBody *TypeDescriptor, + DIEGenerator &TypeDIEGenerator, dwarf::Tag DieTag, + bool IsDeclaration, bool IsParentDeclaration); - /// Store ObjC accelerator information for the \p InputDieEntry. - void rememberObjCAccelerator(const DWARFDebugInfoEntry *InputDieEntry, - uint64_t OutOffset, AttributesInfo &AttrInfo); + /// Enumerate \p DieEntry children and assign names for them. + Error assignTypeNamesRec(const DWARFDebugInfoEntry *DieEntry, + SyntheticTypeNameBuilder &NameBuilder); /// DWARFFile containing this compile unit. DWARFFile &File; @@ -535,6 +670,9 @@ class CompileUnit : public DwarfUnit { /// Pointer to the paired compile unit from the input DWARF. DWARFUnit *OrigUnit = nullptr; + /// The DW_AT_language of this unit. + std::optional Language; + /// Line table for this unit. const DWARFDebugLine::LineTable *LineTablePtr = nullptr; @@ -547,10 +685,9 @@ class CompileUnit : public DwarfUnit { /// Maps an address into the index inside .debug_addr section. IndexedValuesMap DebugAddrIndexMap; - /// Maps a string into the index inside .debug_str_offsets section. - IndexedValuesMap DebugStringIndexMap; + std::unique_ptr Dependencies; - /// \defgroup Data Members accessed asinchroniously. + /// \defgroup Data Members accessed asinchronously. /// /// @{ OffsetToUnitTy getUnitFromOffset; @@ -558,6 +695,9 @@ class CompileUnit : public DwarfUnit { std::optional LowPc; uint64_t HighPc = 0; + /// Flag indicating whether type de-duplication is forbidden. + bool NoODR = true; + /// The ranges in that map are the PC ranges for functions in this unit, /// associated with the PC offset to apply to the addresses to get /// the linked address. @@ -565,7 +705,8 @@ class CompileUnit : public DwarfUnit { std::mutex RangesMutex; /// The DW_AT_low_pc of each DW_TAG_label. - SmallDenseMap Labels; + using LabelMapTy = SmallDenseMap; + LabelMapTy Labels; std::mutex LabelsMutex; /// This field keeps current stage of overall compile unit processing. @@ -574,9 +715,19 @@ class CompileUnit : public DwarfUnit { /// DIE info indexed by DIE index. SmallVector DieInfoArray; SmallVector OutDieOffsetArray; + SmallVector TypeEntries; + + /// The list of accelerator records for this unit. + ArrayList AcceleratorRecords; /// @} }; +/// \returns list of attributes referencing type DIEs which might be +/// deduplicated. +/// Note: it does not include DW_AT_containing_type attribute to avoid +/// infinite recursion. +ArrayRef getODRAttributes(); + } // end of namespace dwarflinker_parallel } // end namespace llvm diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h index 78d0b5468d0495..220739a1214c69 100644 --- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerGlobalData.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERGLOBALDATA_H +#include "TypePool.h" #include "llvm/DWARFLinkerParallel/DWARFLinker.h" #include "llvm/DWARFLinkerParallel/StringPool.h" #include "llvm/Support/PerThreadBumpPtrAllocator.h" diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp index a755d540aef99e..c49b9ef0cdf989 100644 --- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp @@ -9,6 +9,8 @@ #include "DWARFLinkerImpl.h" #include "DIEGenerator.h" #include "DependencyTracker.h" +#include "Utils.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/ThreadPool.h" @@ -16,6 +18,50 @@ namespace llvm { namespace dwarflinker_parallel { +DWARFLinkerImpl::DWARFLinkerImpl(MessageHandlerTy ErrorHandler, + MessageHandlerTy WarningHandler, + TranslatorFuncTy StringsTranslator) + : UniqueUnitID(0), DebugStrStrings(GlobalData), + DebugLineStrStrings(GlobalData), CommonSections(GlobalData) { + GlobalData.setTranslator(StringsTranslator); + GlobalData.setErrorHandler(ErrorHandler); + GlobalData.setWarningHandler(WarningHandler); +} + +DWARFLinkerImpl::LinkContext::LinkContext(LinkingGlobalData &GlobalData, + DWARFFile &File, + StringMap &ClangModules, + std::atomic &UniqueUnitID, + std::optional TargetTriple) + : OutputSections(GlobalData), InputDWARFFile(File), + ClangModules(ClangModules), TargetTriple(TargetTriple), + UniqueUnitID(UniqueUnitID) { + + if (File.Dwarf) { + if (!File.Dwarf->compile_units().empty()) + CompileUnits.reserve(File.Dwarf->getNumCompileUnits()); + + // Set context format&endianness based on the input file. + Format.Version = File.Dwarf->getMaxVersion(); + Format.AddrSize = File.Dwarf->getCUAddrSize(); + Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little + : llvm::endianness::big; + } +} + +DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit( + DWARFFile &File, std::unique_ptr Unit) + : File(File), Unit(std::move(Unit)) {} + +DWARFLinkerImpl::LinkContext::RefModuleUnit::RefModuleUnit( + LinkContext::RefModuleUnit &&Other) + : File(Other.File), Unit(std::move(Other.Unit)) {} + +void DWARFLinkerImpl::LinkContext::addModulesCompileUnit( + LinkContext::RefModuleUnit &&Unit) { + ModulesCompileUnits.emplace_back(std::move(Unit)); +} + Error DWARFLinkerImpl::createEmitter(const Triple &TheTriple, OutputFileType FileType, raw_pwrite_stream &OutFile) { @@ -55,6 +101,10 @@ void DWARFLinkerImpl::addObjectFile(DWARFFile &File, ObjFileLoaderTy Loader, } } +void DWARFLinkerImpl::setEstimatedObjfilesAmount(unsigned ObjFilesNum) { + ObjectContexts.reserve(ObjFilesNum); +} + Error DWARFLinkerImpl::link() { // reset compile unit unique ID counter. UniqueUnitID = 0; @@ -71,6 +121,7 @@ Error DWARFLinkerImpl::link() { ? llvm::endianness::little : llvm::endianness::big; } + std::optional Language; for (std::unique_ptr &Context : ObjectContexts) { if (Context->InputDWARFFile.Dwarf.get() == nullptr) { @@ -101,6 +152,23 @@ Error DWARFLinkerImpl::link() { std::max(GlobalFormat.AddrSize, Context->getFormParams().AddrSize); Context->setOutputFormat(Context->getFormParams(), GlobalEndianness); + + // FIXME: move creation of CompileUnits into the addObjectFile. + // This would allow to not scan for context Language and Modules state + // twice. And then following handling might be removed. + for (const std::unique_ptr &OrigCU : + Context->InputDWARFFile.Dwarf->compile_units()) { + DWARFDie UnitDie = OrigCU.get()->getUnitDIE(); + + if (!Language) { + if (std::optional Val = + UnitDie.find(dwarf::DW_AT_language)) { + uint16_t LangVal = dwarf::toUnsigned(Val, 0); + if (isODRLanguage(LangVal)) + Language = LangVal; + } + } + } } if (GlobalFormat.AddrSize == 0) { @@ -113,6 +181,14 @@ Error DWARFLinkerImpl::link() { CommonSections.setOutputFormat(GlobalFormat, GlobalEndianness); + if (!GlobalData.Options.NoODR && Language.has_value()) { + parallel::TaskGroup TGroup; + TGroup.spawn([&]() { + ArtificialTypeUnit = std::make_unique( + GlobalData, UniqueUnitID++, Language, GlobalFormat, GlobalEndianness); + }); + } + // Set parallel options. if (GlobalData.getOptions().Threads == 0) parallel::strategy = optimal_concurrency(OverallNumberOfCU); @@ -123,7 +199,7 @@ Error DWARFLinkerImpl::link() { if (GlobalData.getOptions().Threads == 1) { for (std::unique_ptr &Context : ObjectContexts) { // Link object file. - if (Error Err = Context->link()) + if (Error Err = Context->link(ArtificialTypeUnit.get())) GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName); Context->InputDWARFFile.unload(); @@ -133,7 +209,7 @@ Error DWARFLinkerImpl::link() { for (std::unique_ptr &Context : ObjectContexts) Pool.async([&]() { // Link object file. - if (Error Err = Context->link()) + if (Error Err = Context->link(ArtificialTypeUnit.get())) GlobalData.error(std::move(Err), Context->InputDWARFFile.FileName); Context->InputDWARFFile.unload(); @@ -142,6 +218,19 @@ Error DWARFLinkerImpl::link() { Pool.wait(); } + if (ArtificialTypeUnit.get() != nullptr && !ArtificialTypeUnit->getTypePool() + .getRoot() + ->getValue() + .load() + ->Children.empty()) { + std::optional OutTriple = TheDwarfEmitter.get() == nullptr + ? std::optional(std::nullopt) + : TheDwarfEmitter->getTargetTriple(); + + if (Error Err = ArtificialTypeUnit.get()->finishCloningAndEmit(OutTriple)) + return Err; + } + // At this stage each compile units are cloned to their own set of debug // sections. Now, update patches, assign offsets and assemble final file // glueing debug tables from each compile unit. @@ -175,6 +264,11 @@ Error DWARFLinkerImpl::validateAndUpdateOptions() { "set number of threads to 1 to make --verbose to work properly.", ""); } + // Do not do types deduplication in case --update. + if (GlobalData.getOptions().UpdateIndexTablesOnly && + !GlobalData.Options.NoODR) + GlobalData.Options.NoODR = true; + return Error::success(); } @@ -369,7 +463,7 @@ Error DWARFLinkerImpl::LinkContext::loadClangModule( return Error::success(); } -Error DWARFLinkerImpl::LinkContext::link() { +Error DWARFLinkerImpl::LinkContext::link(TypeUnit *ArtificialTypeUnit) { InterCUProcessingStarted = false; if (!InputDWARFFile.Dwarf) return Error::success(); @@ -380,7 +474,7 @@ Error DWARFLinkerImpl::LinkContext::link() { // Link modules compile units first. parallelForEach(ModulesCompileUnits, [&](RefModuleUnit &RefModule) { - linkSingleCompileUnit(*RefModule.Unit); + linkSingleCompileUnit(*RefModule.Unit, ArtificialTypeUnit); }); // Check for live relocations. If there is no any live relocation then we @@ -420,43 +514,78 @@ Error DWARFLinkerImpl::LinkContext::link() { // Link self-sufficient compile units and discover inter-connected compile // units. parallelForEach(CompileUnits, [&](std::unique_ptr &CU) { - linkSingleCompileUnit(*CU); + linkSingleCompileUnit(*CU, ArtificialTypeUnit); }); // Link all inter-connected units. if (HasNewInterconnectedCUs) { InterCUProcessingStarted = true; - do { - HasNewInterconnectedCUs = false; - - // Load inter-connected units. - parallelForEach(CompileUnits, [&](std::unique_ptr &CU) { - if (CU->isInterconnectedCU()) { - CU->maybeResetToLoadedStage(); - linkSingleCompileUnit(*CU, CompileUnit::Stage::Loaded); - } - }); + if (Error Err = finiteLoop([&]() -> Expected { + HasNewInterconnectedCUs = false; + + // Load inter-connected units. + parallelForEach( + CompileUnits, [&](std::unique_ptr &CU) { + if (CU->isInterconnectedCU()) { + CU->maybeResetToLoadedStage(); + linkSingleCompileUnit(*CU, ArtificialTypeUnit, + CompileUnit::Stage::Loaded); + } + }); + + // Do liveness analysis for inter-connected units. + parallelForEach(CompileUnits, + [&](std::unique_ptr &CU) { + linkSingleCompileUnit( + *CU, ArtificialTypeUnit, + CompileUnit::Stage::LivenessAnalysisDone); + }); + + return HasNewInterconnectedCUs.load(); + })) + return Err; + + // Update dependencies. + if (Error Err = finiteLoop([&]() -> Expected { + HasNewGlobalDependency = false; + parallelForEach( + CompileUnits, [&](std::unique_ptr &CU) { + linkSingleCompileUnit( + *CU, ArtificialTypeUnit, + CompileUnit::Stage::UpdateDependenciesCompleteness); + }); + return HasNewGlobalDependency.load(); + })) + return Err; + parallelForEach(CompileUnits, [&](std::unique_ptr &CU) { + if (CU->isInterconnectedCU() && + CU->getStage() == CompileUnit::Stage::LivenessAnalysisDone) + CU->setStage(CompileUnit::Stage::UpdateDependenciesCompleteness); + }); - // Do liveness analysis for inter-connected units. - parallelForEach(CompileUnits, [&](std::unique_ptr &CU) { - linkSingleCompileUnit(*CU, CompileUnit::Stage::LivenessAnalysisDone); - }); - } while (HasNewInterconnectedCUs); + // Assign type names. + parallelForEach(CompileUnits, [&](std::unique_ptr &CU) { + linkSingleCompileUnit(*CU, ArtificialTypeUnit, + CompileUnit::Stage::TypeNamesAssigned); + }); // Clone inter-connected units. parallelForEach(CompileUnits, [&](std::unique_ptr &CU) { - linkSingleCompileUnit(*CU, CompileUnit::Stage::Cloned); + linkSingleCompileUnit(*CU, ArtificialTypeUnit, + CompileUnit::Stage::Cloned); }); // Update patches for inter-connected units. parallelForEach(CompileUnits, [&](std::unique_ptr &CU) { - linkSingleCompileUnit(*CU, CompileUnit::Stage::PatchesUpdated); + linkSingleCompileUnit(*CU, ArtificialTypeUnit, + CompileUnit::Stage::PatchesUpdated); }); // Release data. parallelForEach(CompileUnits, [&](std::unique_ptr &CU) { - linkSingleCompileUnit(*CU, CompileUnit::Stage::Cleaned); + linkSingleCompileUnit(*CU, ArtificialTypeUnit, + CompileUnit::Stage::Cleaned); }); } @@ -483,78 +612,119 @@ Error DWARFLinkerImpl::LinkContext::link() { } void DWARFLinkerImpl::LinkContext::linkSingleCompileUnit( - CompileUnit &CU, enum CompileUnit::Stage DoUntilStage) { - while (CU.getStage() < DoUntilStage) { - if (InterCUProcessingStarted != CU.isInterconnectedCU()) - return; + CompileUnit &CU, TypeUnit *ArtificialTypeUnit, + enum CompileUnit::Stage DoUntilStage) { + if (InterCUProcessingStarted != CU.isInterconnectedCU()) + return; - switch (CU.getStage()) { - case CompileUnit::Stage::CreatedNotLoaded: { - // Load input compilation unit DIEs. - // Analyze properties of DIEs. - if (!CU.loadInputDIEs()) { - // We do not need to do liveness analysis for invalud compilation unit. - CU.setStage(CompileUnit::Stage::LivenessAnalysisDone); - } else { - CU.analyzeDWARFStructure(); - - // The registerModuleReference() condition effectively skips - // over fully resolved skeleton units. This second pass of - // registerModuleReferences doesn't do any new work, but it - // will collect top-level errors, which are suppressed. Module - // warnings were already displayed in the first iteration. - if (registerModuleReference( - CU.getOrigUnit().getUnitDIE(), nullptr, - [](const DWARFUnit &) {}, 0)) - CU.setStage(CompileUnit::Stage::PatchesUpdated); - else - CU.setStage(CompileUnit::Stage::Loaded); - } - } break; + if (Error Err = finiteLoop([&]() -> Expected { + if (CU.getStage() >= DoUntilStage) + return false; + + switch (CU.getStage()) { + case CompileUnit::Stage::CreatedNotLoaded: { + // Load input compilation unit DIEs. + // Analyze properties of DIEs. + if (!CU.loadInputDIEs()) { + // We do not need to do liveness analysis for invalid compilation + // unit. + CU.setStage(CompileUnit::Stage::Skipped); + } else { + CU.analyzeDWARFStructure(); + + // The registerModuleReference() condition effectively skips + // over fully resolved skeleton units. This second pass of + // registerModuleReferences doesn't do any new work, but it + // will collect top-level errors, which are suppressed. Module + // warnings were already displayed in the first iteration. + if (registerModuleReference( + CU.getOrigUnit().getUnitDIE(), nullptr, + [](const DWARFUnit &) {}, 0)) + CU.setStage(CompileUnit::Stage::PatchesUpdated); + else + CU.setStage(CompileUnit::Stage::Loaded); + } + } break; - case CompileUnit::Stage::Loaded: { - // Mark all the DIEs that need to be present in the generated output. - // If ODR requested, build type names. - if (!DependencyTracker(*this).resolveDependenciesAndMarkLiveness(CU)) { - assert(HasNewInterconnectedCUs); - return; - } + case CompileUnit::Stage::Loaded: { + // Mark all the DIEs that need to be present in the generated output. + // If ODR requested, build type names. + if (!CU.resolveDependenciesAndMarkLiveness(InterCUProcessingStarted, + HasNewInterconnectedCUs)) { + assert(HasNewInterconnectedCUs && + "Flag indicating new inter-connections is not set"); + return false; + } - CU.setStage(CompileUnit::Stage::LivenessAnalysisDone); - } break; + CU.setStage(CompileUnit::Stage::LivenessAnalysisDone); + } break; - case CompileUnit::Stage::LivenessAnalysisDone: + case CompileUnit::Stage::LivenessAnalysisDone: { + if (InterCUProcessingStarted) { + if (CU.updateDependenciesCompleteness()) + HasNewGlobalDependency = true; + return false; + } else { + if (Error Err = finiteLoop([&]() -> Expected { + return CU.updateDependenciesCompleteness(); + })) + return std::move(Err); + + CU.setStage(CompileUnit::Stage::UpdateDependenciesCompleteness); + } + } break; + case CompileUnit::Stage::UpdateDependenciesCompleteness: #ifndef NDEBUG - DependencyTracker::verifyKeepChain(CU); + CU.verifyDependencies(); #endif - // Clone input compile unit. - if (CU.isClangModule() || GlobalData.getOptions().UpdateIndexTablesOnly || - CU.getContaingFile().Addresses->hasValidRelocs()) { - if (Error Err = CU.cloneAndEmit(TargetTriple)) - CU.error(std::move(Err)); - } + if (ArtificialTypeUnit) { + if (Error Err = + CU.assignTypeNames(ArtificialTypeUnit->getTypePool())) + return std::move(Err); + } + CU.setStage(CompileUnit::Stage::TypeNamesAssigned); + break; + + case CompileUnit::Stage::TypeNamesAssigned: + // Clone input compile unit. + if (CU.isClangModule() || + GlobalData.getOptions().UpdateIndexTablesOnly || + CU.getContaingFile().Addresses->hasValidRelocs()) { + if (Error Err = CU.cloneAndEmit(TargetTriple, ArtificialTypeUnit)) + return std::move(Err); + } - CU.setStage(CompileUnit::Stage::Cloned); - break; + CU.setStage(CompileUnit::Stage::Cloned); + break; - case CompileUnit::Stage::Cloned: - // Update DIEs referencies. - CU.updateDieRefPatchesWithClonedOffsets(); - CU.setStage(CompileUnit::Stage::PatchesUpdated); - break; + case CompileUnit::Stage::Cloned: + // Update DIEs referencies. + CU.updateDieRefPatchesWithClonedOffsets(); + CU.setStage(CompileUnit::Stage::PatchesUpdated); + break; - case CompileUnit::Stage::PatchesUpdated: - // Cleanup resources. - CU.cleanupDataAfterClonning(); - CU.setStage(CompileUnit::Stage::Cleaned); - break; + case CompileUnit::Stage::PatchesUpdated: + // Cleanup resources. + CU.cleanupDataAfterClonning(); + CU.setStage(CompileUnit::Stage::Cleaned); + break; - case CompileUnit::Stage::Cleaned: - assert(false); - break; - } + case CompileUnit::Stage::Cleaned: + assert(false); + break; + + case CompileUnit::Stage::Skipped: + // Nothing to do. + break; + } + + return true; + })) { + CU.error(std::move(Err)); + CU.cleanupDataAfterClonning(); + CU.setStage(CompileUnit::Stage::Skipped); } } @@ -716,6 +886,9 @@ void DWARFLinkerImpl::glueCompileUnitsAndWriteToTheOutput() { // units into the resulting file. emitCommonSectionsAndWriteCompileUnitsToTheOutput(); + if (ArtificialTypeUnit.get() != nullptr) + ArtificialTypeUnit.reset(); + // Write common debug sections into the resulting file. writeCommonSectionsToTheOutput(); @@ -861,47 +1034,101 @@ void DWARFLinkerImpl::forEachOutputString( }); }); - CU->AcceleratorRecords.forEach([&](DwarfUnit::AccelInfo &Info) { + CU->forEachAcceleratorRecord([&](DwarfUnit::AccelInfo &Info) { StringHandler(DebugStr, Info.String); }); }); + + if (ArtificialTypeUnit.get() != nullptr) { + ArtificialTypeUnit->forEach([&](SectionDescriptor &OutSection) { + OutSection.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) { + StringHandler(StringDestinationKind::DebugStr, Patch.String); + }); + + OutSection.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) { + StringHandler(StringDestinationKind::DebugLineStr, Patch.String); + }); + + OutSection.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) { + if (Patch.Die == nullptr) + return; + + StringHandler(StringDestinationKind::DebugStr, Patch.String); + }); + + OutSection.ListDebugTypeLineStrPatch.forEach( + [&](DebugTypeLineStrPatch &Patch) { + if (Patch.Die == nullptr) + return; + + StringHandler(StringDestinationKind::DebugStr, Patch.String); + }); + }); + } } void DWARFLinkerImpl::forEachObjectSectionsSet( function_ref SectionsSetHandler) { - // Handle all modules first(before regular compilation units). + // Handle artificial type unit first. + if (ArtificialTypeUnit.get() != nullptr) + SectionsSetHandler(*ArtificialTypeUnit); + + // Then all modules(before regular compilation units). for (const std::unique_ptr &Context : ObjectContexts) for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) - SectionsSetHandler(*ModuleUnit.Unit); + if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) + SectionsSetHandler(*ModuleUnit.Unit); + // Finally all compilation units. for (const std::unique_ptr &Context : ObjectContexts) { // Handle object file common sections. SectionsSetHandler(*Context); // Handle compilation units. for (std::unique_ptr &CU : Context->CompileUnits) - SectionsSetHandler(*CU); + if (CU->getStage() != CompileUnit::Stage::Skipped) + SectionsSetHandler(*CU); } } +void DWARFLinkerImpl::forEachCompileAndTypeUnit( + function_ref UnitHandler) { + if (ArtificialTypeUnit.get() != nullptr) + UnitHandler(ArtificialTypeUnit.get()); + + // Enumerate module units. + for (const std::unique_ptr &Context : ObjectContexts) + for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) + if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) + UnitHandler(ModuleUnit.Unit.get()); + + // Enumerate compile units. + for (const std::unique_ptr &Context : ObjectContexts) + for (std::unique_ptr &CU : Context->CompileUnits) + if (CU->getStage() != CompileUnit::Stage::Skipped) + UnitHandler(CU.get()); +} + void DWARFLinkerImpl::forEachCompileUnit( function_ref UnitHandler) { // Enumerate module units. for (const std::unique_ptr &Context : ObjectContexts) for (LinkContext::RefModuleUnit &ModuleUnit : Context->ModulesCompileUnits) - UnitHandler(ModuleUnit.Unit.get()); + if (ModuleUnit.Unit->getStage() != CompileUnit::Stage::Skipped) + UnitHandler(ModuleUnit.Unit.get()); // Enumerate compile units. for (const std::unique_ptr &Context : ObjectContexts) for (std::unique_ptr &CU : Context->CompileUnits) - UnitHandler(CU.get()); + if (CU->getStage() != CompileUnit::Stage::Skipped) + UnitHandler(CU.get()); } void DWARFLinkerImpl::patchOffsetsAndSizes() { forEachObjectSectionsSet([&](OutputSections &SectionsSet) { SectionsSet.forEach([&](SectionDescriptor &OutSection) { - SectionsSet.applyPatches(OutSection, DebugStrStrings, - DebugLineStrStrings); + SectionsSet.applyPatches(OutSection, DebugStrStrings, DebugLineStrStrings, + ArtificialTypeUnit.get()); }); }); } @@ -1005,8 +1232,9 @@ void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) { AccelTable AppleObjC; AccelTable AppleTypes; - forEachCompileUnit([&](CompileUnit *CU) { - CU->AcceleratorRecords.forEach([&](const DwarfUnit::AccelInfo &Info) { + forEachCompileAndTypeUnit([&](DwarfUnit *CU) { + CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) { + uint64_t OutOffset = Info.OutOffset; switch (Info.Type) { case DwarfUnit::AccelType::None: { llvm_unreachable("Unknown accelerator record"); @@ -1015,25 +1243,25 @@ void DWARFLinkerImpl::emitAppleAcceleratorSections(const Triple &TargetTriple) { AppleNamespaces.addName( *DebugStrStrings.getExistingEntry(Info.String), CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset + - Info.OutOffset); + OutOffset); } break; case DwarfUnit::AccelType::Name: { AppleNames.addName( *DebugStrStrings.getExistingEntry(Info.String), CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset + - Info.OutOffset); + OutOffset); } break; case DwarfUnit::AccelType::ObjC: { AppleObjC.addName( *DebugStrStrings.getExistingEntry(Info.String), CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset + - Info.OutOffset); + OutOffset); } break; case DwarfUnit::AccelType::Type: { AppleTypes.addName( *DebugStrStrings.getExistingEntry(Info.String), CU->getSectionDescriptor(DebugSectionKind::DebugInfo).StartOffset + - Info.OutOffset, + OutOffset, Info.Tag, Info.ObjcClassImplementation ? dwarf::DW_FLAG_type_implementation : 0, @@ -1136,16 +1364,13 @@ void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) { unsigned Id = 0; - forEachCompileUnit([&](CompileUnit *CU) { - CompUnits.push_back( - CU->getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo) - .StartOffset); - CUidToIdx[CU->getUniqueID()] = Id++; - - CU->AcceleratorRecords.forEach([&](const DwarfUnit::AccelInfo &Info) { + forEachCompileAndTypeUnit([&](DwarfUnit *CU) { + bool HasRecords = false; + CU->forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) { if (DebugNames.get() == nullptr) DebugNames = std::make_unique(); + HasRecords = true; switch (Info.Type) { case DwarfUnit::AccelType::Name: case DwarfUnit::AccelType::Namespace: @@ -1158,6 +1383,13 @@ void DWARFLinkerImpl::emitDWARFv5DebugNamesSection(const Triple &TargetTriple) { break; // Nothing to do. }; }); + + if (HasRecords) { + CompUnits.push_back( + CU->getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo) + .StartOffset); + CUidToIdx[CU->getUniqueID()] = Id++; + } }); if (DebugNames.get() != nullptr) { diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h index 45dc506b9947ea..60018eea121f20 100644 --- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h @@ -11,6 +11,7 @@ #include "DWARFEmitterImpl.h" #include "DWARFLinkerCompileUnit.h" +#include "DWARFLinkerTypeUnit.h" #include "StringEntryToDwarfStringPoolEntryMap.h" #include "llvm/ADT/AddressRanges.h" #include "llvm/CodeGen/AccelTable.h" @@ -25,13 +26,7 @@ class DWARFLinkerImpl : public DWARFLinker { public: DWARFLinkerImpl(MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler, - TranslatorFuncTy StringsTranslator) - : UniqueUnitID(0), DebugStrStrings(GlobalData), - DebugLineStrStrings(GlobalData), CommonSections(GlobalData) { - GlobalData.setTranslator(StringsTranslator); - GlobalData.setErrorHandler(ErrorHandler); - GlobalData.setWarningHandler(WarningHandler); - } + TranslatorFuncTy StringsTranslator); /// Create debug info emitter. Error createEmitter(const Triple &TheTriple, OutputFileType FileType, @@ -74,11 +69,7 @@ class DWARFLinkerImpl : public DWARFLinker { } /// Do not unique types according to ODR. - void setNoODR(bool) override { - // FIXME: set option when ODR mode will be supported. - // getOptions().NoODR = NoODR; - GlobalData.Options.NoODR = true; - } + void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; } /// Update index tables only(do not modify rest of DWARF). void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override { @@ -114,9 +105,7 @@ class DWARFLinkerImpl : public DWARFLinker { } /// Set estimated objects files amount, for preliminary data allocation. - void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override { - ObjectContexts.reserve(ObjFilesNum); - } + void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override; /// Set verification handler which would be used to report verification /// errors. @@ -173,10 +162,8 @@ class DWARFLinkerImpl : public DWARFLinker { /// Keep information for referenced clang module: already loaded DWARF info /// of the clang module and a CompileUnit of the module. struct RefModuleUnit { - RefModuleUnit(DWARFFile &File, std::unique_ptr Unit) - : File(File), Unit(std::move(Unit)) {} - RefModuleUnit(RefModuleUnit &&Other) - : File(Other.File), Unit(std::move(Other.Unit)) {} + RefModuleUnit(DWARFFile &File, std::unique_ptr Unit); + RefModuleUnit(RefModuleUnit &&Other); RefModuleUnit(const RefModuleUnit &) = delete; DWARFFile &File; @@ -209,28 +196,15 @@ class DWARFLinkerImpl : public DWARFLinker { /// if new inter-connected units were found. std::atomic HasNewInterconnectedCUs = {false}; + std::atomic HasNewGlobalDependency = {false}; + /// Counter for compile units ID. std::atomic &UniqueUnitID; LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File, StringMap &ClangModules, std::atomic &UniqueUnitID, - std::optional TargetTriple) - : OutputSections(GlobalData), InputDWARFFile(File), - ClangModules(ClangModules), TargetTriple(TargetTriple), - UniqueUnitID(UniqueUnitID) { - - if (File.Dwarf) { - if (!File.Dwarf->compile_units().empty()) - CompileUnits.reserve(File.Dwarf->getNumCompileUnits()); - - // Set context format&endianness based on the input file. - Format.Version = File.Dwarf->getMaxVersion(); - Format.AddrSize = File.Dwarf->getCUAddrSize(); - Endianness = File.Dwarf->isLittleEndian() ? llvm::endianness::little - : llvm::endianness::big; - } - } + std::optional TargetTriple); /// Check whether specified \p CUDie is a Clang module reference. /// if \p Quiet is false then display error messages. @@ -259,9 +233,7 @@ class DWARFLinkerImpl : public DWARFLinker { unsigned Indent = 0); /// Add Compile Unit corresponding to the module. - void addModulesCompileUnit(RefModuleUnit &&Unit) { - ModulesCompileUnits.emplace_back(std::move(Unit)); - } + void addModulesCompileUnit(RefModuleUnit &&Unit); /// Computes the total size of the debug info. uint64_t getInputDebugInfoSize() const { @@ -277,11 +249,11 @@ class DWARFLinkerImpl : public DWARFLinker { } /// Link compile units for this context. - Error link(); + Error link(TypeUnit *ArtificialTypeUnit); /// Link specified compile unit until specified stage. void linkSingleCompileUnit( - CompileUnit &CU, + CompileUnit &CU, TypeUnit *ArtificialTypeUnit, enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned); /// Emit invariant sections. @@ -331,6 +303,9 @@ class DWARFLinkerImpl : public DWARFLinker { void forEachObjectSectionsSet( function_ref SectionsSetHandler); + /// Enumerates all compile and type units. + void forEachCompileAndTypeUnit(function_ref UnitHandler); + /// Enumerates all comple units. void forEachCompileUnit(function_ref UnitHandler); @@ -368,6 +343,9 @@ class DWARFLinkerImpl : public DWARFLinker { /// Mapping the PCM filename to the DwoId. StringMap ClangModules; std::mutex ClangModulesMutex; + + /// Type unit. + std::unique_ptr ArtificialTypeUnit; /// @} /// \defgroup Data members accessed sequentially. diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp new file mode 100644 index 00000000000000..9d5c213085c293 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.cpp @@ -0,0 +1,391 @@ +//===- DWARFLinkerTypeUnit.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DWARFLinkerTypeUnit.h" +#include "DIEGenerator.h" +#include "DWARFEmitterImpl.h" +#include "llvm/Support/LEB128.h" + +using namespace llvm; +using namespace llvm::dwarflinker_parallel; + +TypeUnit::TypeUnit(LinkingGlobalData &GlobalData, unsigned ID, + std::optional Language, dwarf::FormParams Format, + endianness Endianess) + : DwarfUnit(GlobalData, ID, ""), Language(Language), + AcceleratorRecords(&GlobalData.getAllocator()) { + + UnitName = "__artificial_type_unit"; + + setOutputFormat(Format, Endianess); + + // Create line table prologue. + LineTable.Prologue.FormParams = getFormParams(); + LineTable.Prologue.MinInstLength = 1; + LineTable.Prologue.MaxOpsPerInst = 1; + LineTable.Prologue.DefaultIsStmt = 1; + LineTable.Prologue.LineBase = -5; + LineTable.Prologue.LineRange = 14; + LineTable.Prologue.OpcodeBase = 13; + LineTable.Prologue.StandardOpcodeLengths = {0, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 0, 1}; + + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); +} + +void TypeUnit::createDIETree(BumpPtrAllocator &Allocator) { + prepareDataForTreeCreation(); + + // TaskGroup is created here as internal code has calls to + // PerThreadBumpPtrAllocator which should be called from the task group task. + parallel::TaskGroup TG; + TG.spawn([&]() { + SectionDescriptor &DebugInfoSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + SectionDescriptor &DebugLineSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugLine); + + DIEGenerator DIETreeGenerator(Allocator, *this); + OffsetsPtrVector PatchesOffsets; + + // Create a Die for artificial compilation unit for types. + DIE *UnitDIE = DIETreeGenerator.createDIE(dwarf::DW_TAG_compile_unit, 0); + uint64_t OutOffset = getDebugInfoHeaderSize(); + UnitDIE->setOffset(OutOffset); + + SmallString<200> ProducerString; + ProducerString += "llvm DWARFLinkerParallel library version "; + DebugInfoSection.notePatchWithOffsetUpdate( + DebugStrPatch{ + {OutOffset}, + GlobalData.getStringPool().insert(ProducerString.str()).first}, + PatchesOffsets); + OutOffset += DIETreeGenerator + .addStringPlaceholderAttribute(dwarf::DW_AT_producer, + dwarf::DW_FORM_strp) + .second; + + if (Language) { + OutOffset += DIETreeGenerator + .addScalarAttribute(dwarf::DW_AT_language, + dwarf::DW_FORM_data2, *Language) + .second; + } + + DebugInfoSection.notePatchWithOffsetUpdate( + DebugStrPatch{{OutOffset}, + GlobalData.getStringPool().insert(getUnitName()).first}, + PatchesOffsets); + OutOffset += DIETreeGenerator + .addStringPlaceholderAttribute(dwarf::DW_AT_name, + dwarf::DW_FORM_strp) + .second; + + if (!LineTable.Prologue.FileNames.empty()) { + DebugInfoSection.notePatchWithOffsetUpdate( + DebugOffsetPatch{OutOffset, &DebugLineSection}, PatchesOffsets); + + OutOffset += DIETreeGenerator + .addScalarAttribute(dwarf::DW_AT_stmt_list, + dwarf::DW_FORM_sec_offset, 0xbaddef) + .second; + } + + DebugInfoSection.notePatchWithOffsetUpdate( + DebugStrPatch{{OutOffset}, GlobalData.getStringPool().insert("").first}, + PatchesOffsets); + OutOffset += DIETreeGenerator + .addStringPlaceholderAttribute(dwarf::DW_AT_comp_dir, + dwarf::DW_FORM_strp) + .second; + + if (!DebugStringIndexMap.empty()) { + // Type unit is assumed to be emitted first. Thus we can use direct value + // for DW_AT_str_offsets_base attribute(No need to fix it up with unit + // offset value). + OutOffset += DIETreeGenerator + .addScalarAttribute(dwarf::DW_AT_str_offsets_base, + dwarf::DW_FORM_sec_offset, + getDebugStrOffsetsHeaderSize()) + .second; + } + + UnitDIE->setSize(OutOffset - UnitDIE->getOffset() + 1); + OutOffset = + finalizeTypeEntryRec(UnitDIE->getOffset(), UnitDIE, Types.getRoot()); + + // Update patch offsets. + for (uint64_t *OffsetPtr : PatchesOffsets) + *OffsetPtr += getULEB128Size(UnitDIE->getAbbrevNumber()); + + setOutUnitDIE(UnitDIE); + }); +} + +void TypeUnit::prepareDataForTreeCreation() { + SectionDescriptor &DebugInfoSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + + // Type unit data created parallelly. So the order of data is not + // deterministic. Order data here if we need deterministic output. + + parallel::TaskGroup TG; + + if (!GlobalData.getOptions().AllowNonDeterministicOutput) { + TG.spawn([&]() { + // Sort types to have a deterministic output. + Types.sortTypes(); + }); + } + + TG.spawn([&]() { + if (!GlobalData.getOptions().AllowNonDeterministicOutput) { + // Sort decl type patches to have a deterministic output. + std::function + PatchesComparator = [&](const DebugTypeDeclFilePatch &LHS, + const DebugTypeDeclFilePatch &RHS) { + return LHS.Directory->first() < RHS.Directory->first() || + (!(RHS.Directory->first() < LHS.Directory->first()) && + LHS.FilePath->first() < RHS.FilePath->first()); + }; + // Sort patches to have a deterministic output. + DebugInfoSection.ListDebugTypeDeclFilePatch.sort(PatchesComparator); + } + + // Update DW_AT_decl_file attribute + dwarf::Form DeclFileForm = + getScalarFormForValue( + DebugInfoSection.ListDebugTypeDeclFilePatch.size()) + .first; + + DebugInfoSection.ListDebugTypeDeclFilePatch.forEach( + [&](DebugTypeDeclFilePatch &Patch) { + TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load(); + assert(TypeEntry && + formatv("No data for type {0}", Patch.TypeName->getKey()) + .str() + .c_str()); + if (&TypeEntry->getFinalDie() != Patch.Die) + return; + + uint32_t FileIdx = + addFileNameIntoLinetable(Patch.Directory, Patch.FilePath); + + unsigned DIESize = Patch.Die->getSize(); + DIEGenerator DIEGen(Patch.Die, Types.getThreadLocalAllocator(), + *this); + + DIESize += DIEGen + .addScalarAttribute(dwarf::DW_AT_decl_file, + DeclFileForm, FileIdx) + .second; + Patch.Die->setSize(DIESize); + }); + }); + + if (!GlobalData.getOptions().AllowNonDeterministicOutput) { + // Sort patches to have a deterministic output. + TG.spawn([&]() { + forEach([&](SectionDescriptor &OutSection) { + std::function + StrPatchesComparator = + [&](const DebugStrPatch &LHS, const DebugStrPatch &RHS) { + return LHS.String->getKey() < RHS.String->getKey(); + }; + OutSection.ListDebugStrPatch.sort(StrPatchesComparator); + + std::function + TypeStrPatchesComparator = [&](const DebugTypeStrPatch &LHS, + const DebugTypeStrPatch &RHS) { + return LHS.String->getKey() < RHS.String->getKey(); + }; + OutSection.ListDebugTypeStrPatch.sort(TypeStrPatchesComparator); + }); + }); + } + + if (!GlobalData.getOptions().AllowNonDeterministicOutput) { + // Sort patches to have a deterministic output. + TG.spawn([&]() { + forEach([&](SectionDescriptor &OutSection) { + std::function + LineStrPatchesComparator = [&](const DebugLineStrPatch &LHS, + const DebugLineStrPatch &RHS) { + return LHS.String->getKey() < RHS.String->getKey(); + }; + OutSection.ListDebugLineStrPatch.sort(LineStrPatchesComparator); + + std::function + TypeLineStrPatchesComparator = + [&](const DebugTypeLineStrPatch &LHS, + const DebugTypeLineStrPatch &RHS) { + return LHS.String->getKey() < RHS.String->getKey(); + }; + OutSection.ListDebugTypeLineStrPatch.sort(TypeLineStrPatchesComparator); + }); + }); + } +} + +uint64_t TypeUnit::finalizeTypeEntryRec(uint64_t OutOffset, DIE *OutDIE, + TypeEntry *Entry) { + bool HasChildren = !Entry->getValue().load()->Children.empty(); + DIEGenerator DIEGen(OutDIE, Types.getThreadLocalAllocator(), *this); + OutOffset += DIEGen.finalizeAbbreviations(HasChildren, nullptr); + OutOffset += OutDIE->getSize() - 1; + + if (HasChildren) { + Entry->getValue().load()->Children.forEach([&](TypeEntry *ChildEntry) { + DIE *ChildDIE = &ChildEntry->getValue().load()->getFinalDie(); + DIEGen.addChild(ChildDIE); + + ChildDIE->setOffset(OutOffset); + + OutOffset = finalizeTypeEntryRec(OutOffset, ChildDIE, ChildEntry); + }); + + // End of children marker. + OutOffset += sizeof(int8_t); + } + + OutDIE->setSize(OutOffset - OutDIE->getOffset()); + return OutOffset; +} + +uint32_t TypeUnit::addFileNameIntoLinetable(StringEntry *Dir, + StringEntry *FileName) { + uint32_t DirIdx = 0; + + if (Dir->first() == "") { + DirIdx = 0; + } else { + DirectoriesMapTy::iterator DirEntry = DirectoriesMap.find(Dir); + if (DirEntry == DirectoriesMap.end()) { + // We currently do not support more than UINT32_MAX directories. + assert(LineTable.Prologue.IncludeDirectories.size() < UINT32_MAX); + DirIdx = LineTable.Prologue.IncludeDirectories.size(); + DirectoriesMap.insert({Dir, DirIdx}); + LineTable.Prologue.IncludeDirectories.push_back( + DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, + Dir->getKeyData())); + } else { + DirIdx = DirEntry->second; + } + + if (getVersion() < 5) + DirIdx++; + } + + uint32_t FileIdx = 0; + FilenamesMapTy::iterator FileEntry = FileNamesMap.find({FileName, DirIdx}); + if (FileEntry == FileNamesMap.end()) { + // We currently do not support more than UINT32_MAX files. + assert(LineTable.Prologue.FileNames.size() < UINT32_MAX); + FileIdx = LineTable.Prologue.FileNames.size(); + FileNamesMap.insert({{FileName, DirIdx}, FileIdx}); + LineTable.Prologue.FileNames.push_back(DWARFDebugLine::FileNameEntry()); + LineTable.Prologue.FileNames.back().Name = DWARFFormValue::createFromPValue( + dwarf::DW_FORM_string, FileName->getKeyData()); + LineTable.Prologue.FileNames.back().DirIdx = DirIdx; + } else { + FileIdx = FileEntry->second; + } + + return getVersion() < 5 ? FileIdx + 1 : FileIdx; +} + +std::pair +TypeUnit::getScalarFormForValue(uint64_t Value) const { + if (Value > 0xFFFFFFFF) + return std::make_pair(dwarf::DW_FORM_data8, 8); + + if (Value > 0xFFFF) + return std::make_pair(dwarf::DW_FORM_data4, 4); + + if (Value > 0xFF) + return std::make_pair(dwarf::DW_FORM_data2, 2); + + return std::make_pair(dwarf::DW_FORM_data1, 1); +} + +uint8_t TypeUnit::getSizeByAttrForm(dwarf::Form Form) const { + if (Form == dwarf::DW_FORM_data1) + return 1; + + if (Form == dwarf::DW_FORM_data2) + return 2; + + if (Form == dwarf::DW_FORM_data4) + return 4; + + if (Form == dwarf::DW_FORM_data8) + return 8; + + if (Form == dwarf::DW_FORM_data16) + return 16; + + llvm_unreachable("Unsupported Attr Form"); +} + +Error TypeUnit::finishCloningAndEmit(std::optional TargetTriple) { + BumpPtrAllocator Allocator; + createDIETree(Allocator); + + if (getGlobalData().getOptions().NoOutput || (getOutUnitDIE() == nullptr)) + return Error::success(); + + // Create sections ahead so that they should not be created asynchronously + // later. + getOrCreateSectionDescriptor(DebugSectionKind::DebugInfo); + getOrCreateSectionDescriptor(DebugSectionKind::DebugLine); + getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets); + getOrCreateSectionDescriptor(DebugSectionKind::DebugAbbrev); + if (llvm::is_contained(GlobalData.getOptions().AccelTables, + DWARFLinker::AccelTableKind::Pub)) { + getOrCreateSectionDescriptor(DebugSectionKind::DebugPubNames); + getOrCreateSectionDescriptor(DebugSectionKind::DebugPubTypes); + } + + SmallVector> Tasks; + + // Add task for emitting .debug_line section. + if (!LineTable.Prologue.FileNames.empty()) { + Tasks.push_back([&]() -> Error { + assert(TargetTriple.has_value()); + return emitDebugLine(*TargetTriple, LineTable); + }); + } + + // Add task for emitting .debug_info section. + Tasks.push_back([&]() -> Error { return emitDebugInfo(*TargetTriple); }); + + // Add task for emitting Pub accelerator sections. + if (llvm::is_contained(GlobalData.getOptions().AccelTables, + DWARFLinker::AccelTableKind::Pub)) { + Tasks.push_back([&]() -> Error { + emitPubAccelerators(); + return Error::success(); + }); + } + + // Add task for emitting .debug_str_offsets section. + Tasks.push_back([&]() -> Error { return emitDebugStringOffsetSection(); }); + + // Add task for emitting .debug_abbr section. + Tasks.push_back([&]() -> Error { return emitAbbreviations(); }); + + if (auto Err = parallelForEachError( + Tasks, [&](std::function F) { return F(); })) + return Err; + + return Error::success(); +} diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h new file mode 100644 index 00000000000000..97e620eee0c424 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerTypeUnit.h @@ -0,0 +1,138 @@ +//===- DWARFLinkerTypeUnit.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H +#define LLVM_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H + +#include "DWARFLinkerUnit.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" + +namespace llvm { +namespace dwarflinker_parallel { + +/// Type Unit is used to represent an artificial compilation unit +/// which keeps all type information. This type information is referenced +/// from other compilation units. +class TypeUnit : public DwarfUnit { +public: + TypeUnit(LinkingGlobalData &GlobalData, unsigned ID, + std::optional Language, dwarf::FormParams Format, + llvm::endianness Endianess); + + /// Generates DIE tree based on information from TypesMap. + void createDIETree(BumpPtrAllocator &Allocator); + + /// Emits resulting dwarf based on information from DIE tree. + Error finishCloningAndEmit(std::optional TargetTriple); + + /// Returns global type pool. + TypePool &getTypePool() { return Types; } + + /// TypeUnitAccelInfo extends AccelInfo structure with type specific fileds. + /// We need these additional fields to decide whether OutDIE should have an + /// accelerator record or not. The TypeEntryBodyPtr can refer to the + /// declaration DIE and definition DIE corresponding to the type entry. + /// Only one of them would be used in final output. So if TypeUnitAccelInfo + /// refers OutDIE which does not match with TypeEntryBodyPtr->getFinalDie() + /// then such record should be skipped. + struct TypeUnitAccelInfo : public AccelInfo { + /// Pointer to the output DIE which owns this accelerator record. + DIE *OutDIE = nullptr; + + /// Pointer to the type entry body. + TypeEntryBody *TypeEntryBodyPtr = nullptr; + }; + + /// Enumerates all accelerator records and call \p Handler for each. + void + forEachAcceleratorRecord(function_ref Handler) override { + AcceleratorRecords.forEach([&](TypeUnitAccelInfo &Info) { + // Check whether current record is for the final DIE. + assert(Info.TypeEntryBodyPtr != nullptr); + + if (&Info.TypeEntryBodyPtr->getFinalDie() != Info.OutDIE) + return; + + Info.OutOffset = Info.OutDIE->getOffset(); + Handler(Info); + }); + } + + /// Returns index for the specified \p String inside .debug_str_offsets. + uint64_t getDebugStrIndex(const StringEntry *String) override { + std::unique_lock LockGuard(DebugStringIndexMapMutex); + return DebugStringIndexMap.getValueIndex(String); + } + + /// Adds \p Info to the unit's accelerator records. + void saveAcceleratorInfo(const TypeUnitAccelInfo &Info) { + AcceleratorRecords.add(Info); + } + +private: + /// Type DIEs are partially created at clonning stage. They are organised + /// as a tree using type entries. This function links DIEs(corresponding + /// to the type entries) into the tree structure. + uint64_t finalizeTypeEntryRec(uint64_t OutOffset, DIE *OutDIE, + TypeEntry *Entry); + + /// Prepares DIEs to be linked into the tree. + void prepareDataForTreeCreation(); + + /// Add specified \p Dir and \p Filename into the line table + /// of this type unit. + uint32_t addFileNameIntoLinetable(StringEntry *Dir, StringEntry *FileName); + + std::pair getScalarFormForValue(uint64_t Value) const; + + uint8_t getSizeByAttrForm(dwarf::Form Form) const; + + struct CmpStringEntryRef { + bool operator()(const StringEntry *LHS, const StringEntry *RHS) const { + return LHS->first() < RHS->first(); + } + }; + struct CmpDirIDStringEntryRef { + bool operator()(const std::pair &LHS, + const std::pair &RHS) const { + return LHS.second < RHS.second || + (!(RHS.second < LHS.second) && + LHS.first->first() < RHS.first->first()); + } + }; + + /// The DW_AT_language of this unit. + std::optional Language; + + /// This unit line table. + DWARFDebugLine::LineTable LineTable; + + /// Data members keeping file names for line table. + using DirectoriesMapTy = std::map; + using FilenamesMapTy = std::map, size_t, + CmpDirIDStringEntryRef>; + + DirectoriesMapTy DirectoriesMap; + FilenamesMapTy FileNamesMap; + + /// Type DIEs tree. + TypePool Types; + + /// List of accelerator entries for this unit. + ArrayList AcceleratorRecords; + + /// Guard for DebugStringIndexMap. + std::mutex DebugStringIndexMapMutex; +}; + +} // end of namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_DWARFLINKERPARALLEL_DWARFLINKERTYPEUNIT_H diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp index 1503015f015575..b1da1900d65ef7 100644 --- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.cpp @@ -88,7 +88,7 @@ void DwarfUnit::emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev, encodeULEB128(0, AbbrevSection.OS); } -Error DwarfUnit::emitDebugInfo(Triple &TargetTriple) { +Error DwarfUnit::emitDebugInfo(const Triple &TargetTriple) { DIE *OutUnitDIE = getOutUnitDIE(); if (OutUnitDIE == nullptr) return Error::success(); @@ -119,18 +119,60 @@ Error DwarfUnit::emitDebugInfo(Triple &TargetTriple) { return Error::success(); } -Error DwarfUnit::emitDebugLine(Triple &TargetTriple, +Error DwarfUnit::emitDebugLine(const Triple &TargetTriple, const DWARFDebugLine::LineTable &OutLineTable) { DebugLineSectionEmitter DebugLineEmitter(TargetTriple, *this); return DebugLineEmitter.emit(OutLineTable); } +Error DwarfUnit::emitDebugStringOffsetSection() { + if (getVersion() < 5) + return Error::success(); + + if (DebugStringIndexMap.empty()) + return Error::success(); + + SectionDescriptor &OutDebugStrOffsetsSection = + getOrCreateSectionDescriptor(DebugSectionKind::DebugStrOffsets); + + // Emit section header. + + // Emit length. + OutDebugStrOffsetsSection.emitUnitLength(0xBADDEF); + uint64_t OffsetAfterSectionLength = OutDebugStrOffsetsSection.OS.tell(); + + // Emit version. + OutDebugStrOffsetsSection.emitIntVal(5, 2); + + // Emit padding. + OutDebugStrOffsetsSection.emitIntVal(0, 2); + + // Emit index to offset map. + for (const StringEntry *String : DebugStringIndexMap.getValues()) { + // Note patch for string offset value. + OutDebugStrOffsetsSection.notePatch( + DebugStrPatch{{OutDebugStrOffsetsSection.OS.tell()}, String}); + + // Emit placeholder for offset value. + OutDebugStrOffsetsSection.emitOffset(0xBADDEF); + } + + // Patch section length. + OutDebugStrOffsetsSection.apply( + OffsetAfterSectionLength - + OutDebugStrOffsetsSection.getFormParams().getDwarfOffsetByteSize(), + dwarf::DW_FORM_sec_offset, + OutDebugStrOffsetsSection.OS.tell() - OffsetAfterSectionLength); + + return Error::success(); +} + /// Emit the pubnames or pubtypes section contribution for \p /// Unit into \p Sec. The data is provided in \p Info. std::optional DwarfUnit::emitPubAcceleratorEntry(SectionDescriptor &OutSection, - DwarfUnit::AccelInfo &Info, + const DwarfUnit::AccelInfo &Info, std::optional LengthOffset) { if (!LengthOffset) { // Emit the header. @@ -160,7 +202,7 @@ void DwarfUnit::emitPubAccelerators() { std::optional NamesLengthOffset; std::optional TypesLengthOffset; - AcceleratorRecords.forEach([&](DwarfUnit::AccelInfo &Info) { + forEachAcceleratorRecord([&](const DwarfUnit::AccelInfo &Info) { if (Info.AvoidForPubSections) return; diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h index 0835fad1e667a3..9640a8ee711eb0 100644 --- a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h @@ -10,6 +10,7 @@ #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H #include "DWARFLinkerGlobalData.h" +#include "IndexedValuesMap.h" #include "OutputSections.h" #include "llvm/CodeGen/DIE.h" #include "llvm/DWARFLinkerParallel/DWARFLinker.h" @@ -30,16 +31,11 @@ class DwarfUnit : public OutputSections { DwarfUnit(LinkingGlobalData &GlobalData, unsigned ID, StringRef ClangModuleName) : OutputSections(GlobalData), ID(ID), ClangModuleName(ClangModuleName), - OutUnitDIE(nullptr) { - AcceleratorRecords.setAllocator(&GlobalData.getAllocator()); - } + OutUnitDIE(nullptr) {} /// Unique id of the unit. unsigned getUniqueID() const { return ID; } - /// Return language of this unit. - uint16_t getLanguage() const { return Language; } - /// Returns size of this(newly generated) compile unit. uint64_t getUnitSize() const { return UnitSize; } @@ -91,11 +87,14 @@ class DwarfUnit : public OutputSections { Error emitAbbreviations(); /// Emit .debug_info section for unit DIEs. - Error emitDebugInfo(Triple &TargetTriple); + Error emitDebugInfo(const Triple &TargetTriple); /// Emit .debug_line section. - Error emitDebugLine(Triple &TargetTriple, + Error emitDebugLine(const Triple &TargetTriple, const DWARFDebugLine::LineTable &OutLineTable); + + /// Emit the .debug_str_offsets section for current unit. + Error emitDebugStringOffsetSection(); /// @} /// \defgroup Methods used for reporting warnings and errors: @@ -124,7 +123,7 @@ class DwarfUnit : public OutputSections { StringEntry *String = nullptr; /// Output offset of the DIE this entry describes. - uint64_t OutOffset = 0; + uint64_t OutOffset; /// Hash of the fully qualified name. uint32_t QualifiedNameHash = 0; @@ -135,71 +134,27 @@ class DwarfUnit : public OutputSections { /// Type of this accelerator record. AccelType Type = AccelType::None; - /// Avoid using this entry for pub sections. + /// Avoid emitting this entry for pub sections. bool AvoidForPubSections : 1; /// Is this an ObjC class implementation? bool ObjcClassImplementation : 1; }; - void rememberNameForAccelerators(StringEntry *Name, uint64_t OutOffset, - dwarf::Tag Tag, bool AvoidForPubSections) { - AccelInfo Info; - - Info.Type = AccelType::Name; - Info.String = Name; - Info.OutOffset = OutOffset; - Info.Tag = Tag; - Info.AvoidForPubSections = AvoidForPubSections; - - AcceleratorRecords.add(Info); - } - void rememberNamespaceForAccelerators(StringEntry *Name, uint64_t OutOffset, - dwarf::Tag Tag) { - AccelInfo Info; - - Info.Type = AccelType::Namespace; - Info.String = Name; - Info.OutOffset = OutOffset; - Info.Tag = Tag; - - AcceleratorRecords.add(Info); - } - void rememberObjCNameForAccelerators(StringEntry *Name, uint64_t OutOffset, - dwarf::Tag Tag) { - AccelInfo Info; - - Info.Type = AccelType::ObjC; - Info.String = Name; - Info.OutOffset = OutOffset; - Info.Tag = Tag; - Info.AvoidForPubSections = true; - - AcceleratorRecords.add(Info); - } - void rememberTypeForAccelerators(StringEntry *Name, uint64_t OutOffset, - dwarf::Tag Tag, uint32_t QualifiedNameHash, - bool ObjcClassImplementation) { - AccelInfo Info; - - Info.Type = AccelType::Type; - Info.String = Name; - Info.OutOffset = OutOffset; - Info.Tag = Tag; - Info.QualifiedNameHash = QualifiedNameHash; - Info.ObjcClassImplementation = ObjcClassImplementation; - - AcceleratorRecords.add(Info); - } - /// Emit .debug_pubnames and .debug_pubtypes for \p Unit. void emitPubAccelerators(); - /// Accelerator tables data. - ArrayList AcceleratorRecords; + /// Enumerates accelerator data. + virtual void + forEachAcceleratorRecord(function_ref Handler) = 0; /// @} + /// Returns index(inside .debug_str_offsets) of specified string. + virtual uint64_t getDebugStrIndex(const StringEntry *String) { + return DebugStringIndexMap.getValueIndex(String); + } + protected: /// Emit single abbreviation entry. void emitDwarfAbbrevEntry(const DIEAbbrev &Abbrev, @@ -207,16 +162,12 @@ class DwarfUnit : public OutputSections { /// Emit single pubnames/pubtypes accelerator entry. std::optional - emitPubAcceleratorEntry(SectionDescriptor &OutSection, - DwarfUnit::AccelInfo &Info, + emitPubAcceleratorEntry(SectionDescriptor &OutSection, const AccelInfo &Info, std::optional LengthOffset); /// Unique ID for the unit. unsigned ID = 0; - /// The DW_AT_language of this unit. - uint16_t Language = 0; - /// The name of this unit. std::string UnitName; @@ -239,8 +190,31 @@ class DwarfUnit : public OutputSections { /// Output unit DIE. DIE *OutUnitDIE = nullptr; + + /// Cache for file names for this unit. + using FileNamesCache = + DenseMap>; + FileNamesCache FileNames; + + /// Maps a string into the index inside .debug_str_offsets section. + IndexedValuesMap DebugStringIndexMap; }; +inline bool isODRLanguage(uint16_t Language) { + switch (Language) { + case dwarf::DW_LANG_C_plus_plus: + case dwarf::DW_LANG_C_plus_plus_03: + case dwarf::DW_LANG_C_plus_plus_11: + case dwarf::DW_LANG_C_plus_plus_14: + case dwarf::DW_LANG_ObjC_plus_plus: + return true; + default: + return false; + }; + + return false; +} + } // end of namespace dwarflinker_parallel } // end namespace llvm diff --git a/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h b/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h index 4aef0d0d67303d..fc7f8cbc4a8e7b 100644 --- a/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h +++ b/llvm/lib/DWARFLinkerParallel/DebugLineSectionEmitter.h @@ -149,6 +149,7 @@ class DebugLineSectionEmitter { // A null-terminated string containing the full or relative path name of a // source file. Section.emitString(File.Name.getForm(), *FileNameStr); + // An unsigned LEB128 number representing the directory index of a // directory in the include_directories section. encodeULEB128(File.DirIdx, Section.OS); diff --git a/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp b/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp index 3a69c3821e8b52..8767cc0fc6e77c 100644 --- a/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp +++ b/llvm/lib/DWARFLinkerParallel/DependencyTracker.cpp @@ -12,18 +12,20 @@ namespace llvm { namespace dwarflinker_parallel { -#ifndef NDEBUG /// A broken link in the keep chain. By recording both the parent and the child /// we can show only broken links for DIEs with multiple children. struct BrokenLink { - BrokenLink(DWARFDie Parent, DWARFDie Child) : Parent(Parent), Child(Child) {} + BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message) + : Parent(Parent), Child(Child), Message(Message) {} DWARFDie Parent; DWARFDie Child; + std::string Message; }; /// Verify the keep chain by looking for DIEs that are kept but who's parent /// isn't. -void DependencyTracker::verifyKeepChain(CompileUnit &CU) { +void DependencyTracker::verifyKeepChain() { +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) SmallVector Worklist; Worklist.push_back(CU.getOrigUnit().getUnitDIE()); @@ -37,176 +39,585 @@ void DependencyTracker::verifyKeepChain(CompileUnit &CU) { if (!Current.isValid()) continue; - const bool CurrentDieIsKept = CU.getDIEInfo(Current).getKeep() || - CU.getDIEInfo(Current).getKeepChildren(); + CompileUnit::DIEInfo &CurrentInfo = + CU.getDIEInfo(Current.getDebugInfoEntry()); + const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf(); + const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable(); for (DWARFDie Child : reverse(Current.children())) { Worklist.push_back(Child); - const bool ChildDieIsKept = CU.getDIEInfo(Child).getKeep() || - CU.getDIEInfo(Child).getKeepChildren(); - if (!CurrentDieIsKept && ChildDieIsKept) - BrokenLinks.emplace_back(Current, Child); + CompileUnit::DIEInfo &ChildInfo = + CU.getDIEInfo(Child.getDebugInfoEntry()); + const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf(); + const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable(); + + if (!ParentPlainDieIsKept && ChildPlainDieIsKept) + BrokenLinks.emplace_back(Current, Child, + "Found invalid link in keep chain"); + + if (Child.getTag() == dwarf::DW_TAG_subprogram) { + if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy( + &CU, Child.getDebugInfoEntry()))) { + BrokenLinks.emplace_back(Current, Child, + "Live subprogram is not marked as kept"); + } + } + + if (!ChildInfo.getODRAvailable()) { + assert(!ChildTypeDieIsKept); + continue; + } + + if (!ParentTypeDieIsKept && ChildTypeDieIsKept) + BrokenLinks.emplace_back(Current, Child, + "Found invalid link in keep chain"); + + if (CurrentInfo.getIsInAnonNamespaceScope() && + ChildInfo.needToPlaceInTypeTable()) { + BrokenLinks.emplace_back(Current, Child, + "Found invalid placement marking for member " + "of anonymous namespace"); + } } } if (!BrokenLinks.empty()) { for (BrokenLink Link : BrokenLinks) { - WithColor::error() << formatv( - "Found invalid link in keep chain between {0:x} and {1:x}\n", - Link.Parent.getOffset(), Link.Child.getOffset()); + errs() << "\n=================================\n"; + WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message, + Link.Parent.getOffset(), + Link.Child.getOffset()); - errs() << "Parent:"; + errs() << "\nParent:"; Link.Parent.dump(errs(), 0, {}); + errs() << "\n"; CU.getDIEInfo(Link.Parent).dump(); - errs() << "Child:"; + errs() << "\nChild:"; Link.Child.dump(errs(), 2, {}); + errs() << "\n"; CU.getDIEInfo(Link.Child).dump(); } report_fatal_error("invalid keep chain"); } -} #endif +} -bool DependencyTracker::resolveDependenciesAndMarkLiveness(CompileUnit &CU) { - // We do not track liveness inside Clang modules. We also do not track - // liveness if UpdateIndexTablesOnly is requested. - TrackLiveness = !(CU.isClangModule() || - CU.getGlobalData().getOptions().UpdateIndexTablesOnly); +bool DependencyTracker::resolveDependenciesAndMarkLiveness( + bool InterCUProcessingStarted, std::atomic &HasNewInterconnectedCUs) { RootEntriesWorkList.clear(); // Search for live root DIEs. - collectRootsToKeep(CU, CU.getDebugInfoEntry(0)); + CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0)); + CUInfo.setPlacement(CompileUnit::PlainDwarf); + collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)}, + std::nullopt, false); // Mark live DIEs as kept. - return markLiveRootsAsKept(); + return markCollectedLiveRootsAsKept(InterCUProcessingStarted, + HasNewInterconnectedCUs); } -void DependencyTracker::collectRootsToKeep(CompileUnit &CU, - const DWARFDebugInfoEntry *Entry) { - if (!TrackLiveness) { - addItemToWorklist(CU, Entry); +void DependencyTracker::addActionToRootEntriesWorkList( + LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry, + std::optional ReferencedBy) { + if (ReferencedBy) { + RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy); return; } - switch (Entry->getTag()) { - case dwarf::DW_TAG_subprogram: - case dwarf::DW_TAG_label: - if (isLiveSubprogramEntry(CU, Entry)) { - addItemToWorklist(CU, Entry); + RootEntriesWorkList.emplace_back(Action, Entry); +} + +void DependencyTracker::collectRootsToKeep( + const UnitEntryPairTy &Entry, std::optional ReferencedBy, + bool IsLiveParent) { + for (const DWARFDebugInfoEntry *CurChild = + Entry.CU->getFirstChildEntry(Entry.DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = Entry.CU->getSiblingEntry(CurChild)) { + UnitEntryPairTy ChildEntry(Entry.CU, CurChild); + CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild); + + bool IsLiveChild = false; + + switch (CurChild->getTag()) { + case dwarf::DW_TAG_label: { + IsLiveChild = isLiveSubprogramEntry(ChildEntry); + + // Keep label referencing live address. + // Keep label which is child of live parent entry. + if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) { + addActionToRootEntriesWorkList( + LiveRootWorklistActionTy::MarkLiveEntryRec, ChildEntry, + ReferencedBy); + } + } break; + case dwarf::DW_TAG_subprogram: { + IsLiveChild = isLiveSubprogramEntry(ChildEntry); + + // Keep subprogram referencing live address. + if (IsLiveChild) { + // If subprogram is in module scope and this module allows ODR + // deduplication set "TypeTable" placement, otherwise set "" placement + LiveRootWorklistActionTy Action = + (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable()) + ? LiveRootWorklistActionTy::MarkTypeEntryRec + : LiveRootWorklistActionTy::MarkLiveEntryRec; + + addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy); + } + } break; + case dwarf::DW_TAG_constant: + case dwarf::DW_TAG_variable: { + IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent); + + // Keep variable referencing live address. + if (IsLiveChild) { + // If variable is in module scope and this module allows ODR + // deduplication set "TypeTable" placement, otherwise set "" placement + + LiveRootWorklistActionTy Action = + (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable()) + ? LiveRootWorklistActionTy::MarkTypeEntryRec + : LiveRootWorklistActionTy::MarkLiveEntryRec; + + addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy); + } + } break; + case dwarf::DW_TAG_base_type: { + // Always keep base types. + addActionToRootEntriesWorkList( + LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry, + ReferencedBy); + } break; + case dwarf::DW_TAG_imported_module: + case dwarf::DW_TAG_imported_declaration: + case dwarf::DW_TAG_imported_unit: { + // Always keep DIEs having DW_AT_import attribute. + if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) { + addActionToRootEntriesWorkList( + LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry, + ReferencedBy); + break; + } + + addActionToRootEntriesWorkList( + LiveRootWorklistActionTy::MarkSingleTypeEntry, ChildEntry, + ReferencedBy); + } break; + case dwarf::DW_TAG_type_unit: + case dwarf::DW_TAG_partial_unit: + case dwarf::DW_TAG_compile_unit: { + llvm_unreachable("Called for incorrect DIE"); + } break; + default: + // Nothing to do. break; } - [[fallthrough]]; - case dwarf::DW_TAG_compile_unit: - case dwarf::DW_TAG_namespace: - case dwarf::DW_TAG_module: - case dwarf::DW_TAG_lexical_block: { - for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(Entry); - CurChild && CurChild->getAbbreviationDeclarationPtr(); - CurChild = CU.getSiblingEntry(CurChild)) - collectRootsToKeep(CU, CurChild); - } break; - case dwarf::DW_TAG_constant: - case dwarf::DW_TAG_variable: { - if (isLiveVariableEntry(CU, Entry)) - addItemToWorklist(CU, Entry); - } break; - case dwarf::DW_TAG_base_type: { - addItemToWorklist(CU, Entry); - } break; - case dwarf::DW_TAG_imported_module: - case dwarf::DW_TAG_imported_declaration: - case dwarf::DW_TAG_imported_unit: { - addItemToWorklist(CU, Entry); - } break; - default: - // Nothing to do. - break; + + collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent); } } -bool DependencyTracker::markLiveRootsAsKept() { +bool DependencyTracker::markCollectedLiveRootsAsKept( + bool InterCUProcessingStarted, std::atomic &HasNewInterconnectedCUs) { bool Res = true; + // Mark roots as kept. while (!RootEntriesWorkList.empty()) { - RootEntryTy CurrentItem = RootEntriesWorkList.pop_back_val(); - - if (!markDIEEntryAsKeptRec(CurrentItem, CurrentItem.CU, - CurrentItem.RootEntry)) + LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val(); + + if (markDIEEntryAsKeptRec(Root.getAction(), Root.getRootEntry(), + Root.getRootEntry(), InterCUProcessingStarted, + HasNewInterconnectedCUs)) { + if (Root.hasReferencedByOtherEntry()) + Dependencies.push_back(Root); + } else Res = false; } return Res; } -bool DependencyTracker::markDIEEntryAsKeptRec( - const RootEntryTy &RootItem, CompileUnit &CU, - const DWARFDebugInfoEntry *Entry) { - if (Entry->getAbbreviationDeclarationPtr() == nullptr) - return true; +bool DependencyTracker::updateDependenciesCompleteness() { + bool HasNewDependency = false; + for (LiveRootWorklistItemTy &Root : Dependencies) { + assert(Root.hasReferencedByOtherEntry() && + "Root entry without dependency inside the dependencies list"); + + UnitEntryPairTy RootEntry = Root.getRootEntry(); + CompileUnit::DIEInfo &RootInfo = + RootEntry.CU->getDIEInfo(RootEntry.DieEntry); + + UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry(); + CompileUnit::DIEInfo &ReferencedByInfo = + ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry); + + if (!RootInfo.needToPlaceInTypeTable() && + ReferencedByInfo.needToPlaceInTypeTable()) { + HasNewDependency = true; + setPlainDwarfPlacementRec(ReferencedByEntry); + + // FIXME: we probably need to update getKeepTypeChildren status for + // parents of *Root.ReferencedBy. + } + } + + return HasNewDependency; +} + +void DependencyTracker::setPlainDwarfPlacementRec( + const UnitEntryPairTy &Entry) { + CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry); + if (Info.getPlacement() == CompileUnit::PlainDwarf && + !Info.getKeepTypeChildren()) + return; - CompileUnit::DIEInfo &Info = CU.getDIEInfo(Entry); + Info.setPlacement(CompileUnit::PlainDwarf); + Info.unsetKeepTypeChildren(); + markParentsAsKeepingChildren(Entry); - if (Info.getKeep()) + for (const DWARFDebugInfoEntry *CurChild = + Entry.CU->getFirstChildEntry(Entry.DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = Entry.CU->getSiblingEntry(CurChild)) + setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild}); +} + +static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) { + switch (Entry->getTag()) { + case dwarf::DW_TAG_compile_unit: + case dwarf::DW_TAG_module: + case dwarf::DW_TAG_namespace: return true; - // Mark parents as 'KeepChildren'. - std::optional ParentIdx = Entry->getParentIdx(); + default: + return false; + } +} + +bool isAlreadyMarked(const CompileUnit::DIEInfo &Info, + CompileUnit::DieOutputPlacement NewPlacement) { + if (!Info.getKeep()) + return false; + + switch (NewPlacement) { + case CompileUnit::TypeTable: + return Info.needToPlaceInTypeTable(); + + case CompileUnit::PlainDwarf: + return Info.needToKeepInPlainDwarf(); + + case CompileUnit::Both: + return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf(); + + case CompileUnit::NotSet: + llvm_unreachable("Unset placement type is specified."); + }; +} + +bool isAlreadyMarked(const UnitEntryPairTy &Entry, + CompileUnit::DieOutputPlacement NewPlacement) { + return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement); +} + +void DependencyTracker::markParentsAsKeepingChildren( + const UnitEntryPairTy &Entry) { + if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr) + return; + + CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry); + bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable(); + bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf(); + + bool AreTypeParentsDone = !NeedKeepTypeChildren; + bool ArePlainParentsDone = !NeedKeepPlainChildren; + + // Mark parents as 'Keep*Children'. + std::optional ParentIdx = Entry.DieEntry->getParentIdx(); while (ParentIdx) { - const DWARFDebugInfoEntry *ParentEntry = CU.getDebugInfoEntry(*ParentIdx); - CompileUnit::DIEInfo &ParentInfo = CU.getDIEInfo(*ParentIdx); - if (ParentInfo.getKeepChildren()) + const DWARFDebugInfoEntry *ParentEntry = + Entry.CU->getDebugInfoEntry(*ParentIdx); + CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx); + + if (!AreTypeParentsDone && NeedKeepTypeChildren) { + if (ParentInfo.getKeepTypeChildren()) + AreTypeParentsDone = true; + else { + bool AddToWorklist = !isAlreadyMarked( + ParentInfo, CompileUnit::DieOutputPlacement::TypeTable); + ParentInfo.setKeepTypeChildren(); + if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) { + addActionToRootEntriesWorkList( + LiveRootWorklistActionTy::MarkTypeChildrenRec, + UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt); + } + } + } + + if (!ArePlainParentsDone && NeedKeepPlainChildren) { + if (ParentInfo.getKeepPlainChildren()) + ArePlainParentsDone = true; + else { + bool AddToWorklist = !isAlreadyMarked( + ParentInfo, CompileUnit::DieOutputPlacement::PlainDwarf); + ParentInfo.setKeepPlainChildren(); + if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) { + addActionToRootEntriesWorkList( + LiveRootWorklistActionTy::MarkLiveChildrenRec, + UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt); + } + } + } + + if (AreTypeParentsDone && ArePlainParentsDone) break; - ParentInfo.setKeepChildren(); + ParentIdx = ParentEntry->getParentIdx(); } +} + +// This function tries to set specified \p Placement for the \p Entry. +// Depending on the concrete entry, the placement could be: +// a) changed to another. +// b) joined with current entry placement. +// c) set as requested. +static CompileUnit::DieOutputPlacement +getFinalPlacementForEntry(const UnitEntryPairTy &Entry, + CompileUnit::DieOutputPlacement Placement) { + assert((Placement != CompileUnit::NotSet) && "Placement is not set"); + CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry); + + if (!EntryInfo.getODRAvailable()) + return CompileUnit::PlainDwarf; + + if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) { + // Do not put variable into the "TypeTable" and "PlainDwarf" at the same + // time. + if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf || + EntryInfo.getPlacement() == CompileUnit::Both) + return CompileUnit::PlainDwarf; + + if (Placement == CompileUnit::PlainDwarf || Placement == CompileUnit::Both) + return CompileUnit::PlainDwarf; + } + + switch (EntryInfo.getPlacement()) { + case CompileUnit::NotSet: + return Placement; + + case CompileUnit::TypeTable: + return Placement == CompileUnit::PlainDwarf ? CompileUnit::Both : Placement; + + case CompileUnit::PlainDwarf: + return Placement == CompileUnit::TypeTable ? CompileUnit::Both : Placement; + + case CompileUnit::Both: + return CompileUnit::Both; + }; + + llvm_unreachable("Unknown placement type."); + return Placement; +} + +bool DependencyTracker::markDIEEntryAsKeptRec( + LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, + const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, + std::atomic &HasNewInterconnectedCUs) { + if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr) + return true; + + CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry); + + // Calculate final placement placement. + CompileUnit::DieOutputPlacement Placement = getFinalPlacementForEntry( + Entry, + isLiveAction(Action) ? CompileUnit::PlainDwarf : CompileUnit::TypeTable); + assert((Info.getODRAvailable() || isLiveAction(Action) || + Placement == CompileUnit::PlainDwarf) && + "Wrong kind of placement for ODR unavailable entry"); + + if (!isChildrenAction(Action)) + if (isAlreadyMarked(Entry, Placement)) + return true; // Mark current DIE as kept. Info.setKeep(); - setDIEPlacementAndTypename(Info); + Info.setPlacement(Placement); - // Set liveness information. - switch (Entry->getTag()) { - case dwarf::DW_TAG_constant: - case dwarf::DW_TAG_variable: { - isLiveVariableEntry(CU, Entry); - } break; - case dwarf::DW_TAG_subprogram: - case dwarf::DW_TAG_label: { - isLiveSubprogramEntry(CU, Entry); - } break; - default: - // Nothing to do. - break; - } + // Set keep children property for parents. + markParentsAsKeepingChildren(Entry); + + UnitEntryPairTy FinalRootEntry = + Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry; // Analyse referenced DIEs. bool Res = true; - if (!maybeAddReferencedRoots(RootItem, CU, Entry)) + if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry, + InterCUProcessingStarted, + HasNewInterconnectedCUs)) Res = false; - // Navigate children. - for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(Entry); + // Return if we do not need to process children. + if (isSingleAction(Action)) + return Res; + + // Process children. + // Check for subprograms special case. + if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram && + Info.getODRAvailable()) { + // Subprograms is a special case. As it can be root for type DIEs + // and itself may be subject to move into the artificial type unit. + // a) Non removable children(like DW_TAG_formal_parameter) should always + // be cloned. They are placed into the "PlainDwarf" and into the + // "TypeTable". + // b) ODR deduplication candidates(type DIEs) children should not be put + // into the "PlainDwarf". + // c) Children keeping addresses and locations(like DW_TAG_call_site) + // should not be put into the "TypeTable". + for (const DWARFDebugInfoEntry *CurChild = + Entry.CU->getFirstChildEntry(Entry.DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = Entry.CU->getSiblingEntry(CurChild)) { + CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild); + + switch (CurChild->getTag()) { + case dwarf::DW_TAG_variable: + case dwarf::DW_TAG_constant: + case dwarf::DW_TAG_subprogram: + case dwarf::DW_TAG_label: { + if (ChildInfo.getHasAnAddress()) + continue; + } break; + + // Entries having following tags could not be removed from the subprogram. + case dwarf::DW_TAG_lexical_block: + case dwarf::DW_TAG_friend: + case dwarf::DW_TAG_inheritance: + case dwarf::DW_TAG_formal_parameter: + case dwarf::DW_TAG_unspecified_parameters: + case dwarf::DW_TAG_template_type_parameter: + case dwarf::DW_TAG_template_value_parameter: + case dwarf::DW_TAG_GNU_template_parameter_pack: + case dwarf::DW_TAG_GNU_formal_parameter_pack: + case dwarf::DW_TAG_GNU_template_template_param: + case dwarf::DW_TAG_thrown_type: { + // Go to the default child handling. + } break; + + default: { + bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild); + + // Skip child marked to be copied into the artificial type unit. + if (isLiveAction(Action) && ChildIsTypeTableCandidate) + continue; + + // Skip child marked to be copied into the plain unit. + if (isTypeAction(Action) && !ChildIsTypeTableCandidate) + continue; + + // Go to the default child handling. + } break; + } + + if (!markDIEEntryAsKeptRec( + Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild}, + InterCUProcessingStarted, HasNewInterconnectedCUs)) + Res = false; + } + + return Res; + } + + // Recursively process children. + for (const DWARFDebugInfoEntry *CurChild = + Entry.CU->getFirstChildEntry(Entry.DieEntry); CurChild && CurChild->getAbbreviationDeclarationPtr(); - CurChild = CU.getSiblingEntry(CurChild)) { - if (!markDIEEntryAsKeptRec(RootItem, CU, CurChild)) + CurChild = Entry.CU->getSiblingEntry(CurChild)) { + CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild); + switch (CurChild->getTag()) { + case dwarf::DW_TAG_variable: + case dwarf::DW_TAG_constant: + case dwarf::DW_TAG_subprogram: + case dwarf::DW_TAG_label: { + if (ChildInfo.getHasAnAddress()) + continue; + } break; + default: + break; // Nothing to do. + }; + + if (!markDIEEntryAsKeptRec( + Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild}, + InterCUProcessingStarted, HasNewInterconnectedCUs)) Res = false; } return Res; } +bool DependencyTracker::isTypeTableCandidate( + const DWARFDebugInfoEntry *DIEEntry) { + switch (DIEEntry->getTag()) { + default: + return false; + + case dwarf::DW_TAG_imported_module: + case dwarf::DW_TAG_imported_declaration: + case dwarf::DW_TAG_imported_unit: + case dwarf::DW_TAG_array_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_pointer_type: + case dwarf::DW_TAG_reference_type: + case dwarf::DW_TAG_string_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_subroutine_type: + case dwarf::DW_TAG_typedef: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_variant: + case dwarf::DW_TAG_module: + case dwarf::DW_TAG_ptr_to_member_type: + case dwarf::DW_TAG_set_type: + case dwarf::DW_TAG_subrange_type: + case dwarf::DW_TAG_base_type: + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_enumerator: + case dwarf::DW_TAG_file_type: + case dwarf::DW_TAG_packed_type: + case dwarf::DW_TAG_thrown_type: + case dwarf::DW_TAG_volatile_type: + case dwarf::DW_TAG_dwarf_procedure: + case dwarf::DW_TAG_restrict_type: + case dwarf::DW_TAG_interface_type: + case dwarf::DW_TAG_namespace: + case dwarf::DW_TAG_unspecified_type: + case dwarf::DW_TAG_shared_type: + case dwarf::DW_TAG_rvalue_reference_type: + case dwarf::DW_TAG_coarray_type: + case dwarf::DW_TAG_dynamic_type: + case dwarf::DW_TAG_atomic_type: + case dwarf::DW_TAG_immutable_type: + case dwarf::DW_TAG_function_template: + case dwarf::DW_TAG_class_template: + return true; + } +} + bool DependencyTracker::maybeAddReferencedRoots( - const RootEntryTy &RootItem, CompileUnit &CU, - const DWARFDebugInfoEntry *Entry) { - const auto *Abbrev = Entry->getAbbreviationDeclarationPtr(); + LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, + const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, + std::atomic &HasNewInterconnectedCUs) { + const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr(); if (Abbrev == nullptr) return true; - DWARFUnit &Unit = CU.getOrigUnit(); + DWARFUnit &Unit = Entry.CU->getOrigUnit(); DWARFDataExtractor Data = Unit.getDebugInfoExtractor(); - uint64_t Offset = Entry->getOffset() + getULEB128Size(Abbrev->getCode()); + uint64_t Offset = + Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode()); // For each DIE attribute... for (const auto &AttrSpec : Abbrev->attributes()) { @@ -220,132 +631,157 @@ bool DependencyTracker::maybeAddReferencedRoots( Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit); // Resolve reference. - std::optional> RefDie = - CU.resolveDIEReference( - Val, Context.InterCUProcessingStarted - ? ResolveInterCUReferencesMode::Resolve - : ResolveInterCUReferencesMode::AvoidResolving); + std::optional RefDie = Entry.CU->resolveDIEReference( + Val, InterCUProcessingStarted + ? ResolveInterCUReferencesMode::Resolve + : ResolveInterCUReferencesMode::AvoidResolving); if (!RefDie) { - CU.warn("cann't find referenced DIE", Entry); + Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry); continue; } - if (RefDie->second == 0) { + if (!RefDie->DieEntry) { // Delay resolving reference. - RefDie->first->setInterconnectedCU(); - CU.setInterconnectedCU(); - Context.HasNewInterconnectedCUs = true; + RefDie->CU->setInterconnectedCU(); + Entry.CU->setInterconnectedCU(); + HasNewInterconnectedCUs = true; return false; } - assert(CU.getUniqueID() == RefDie->first->getUniqueID() || - Context.InterCUProcessingStarted); + assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() || + InterCUProcessingStarted) && + "Inter-CU reference while inter-CU processing is not started"); + + CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry); + if (!RefInfo.getODRAvailable()) + Action = LiveRootWorklistActionTy::MarkLiveEntryRec; + else if (RefInfo.getODRAvailable() && + llvm::is_contained(getODRAttributes(), AttrSpec.Attr)) + // Note: getODRAttributes does not include DW_AT_containing_type. + // It should be OK as we do getRootForSpecifiedEntry(). So any containing + // type would be found as the root for the entry. + Action = LiveRootWorklistActionTy::MarkTypeEntryRec; + else if (isLiveAction(Action)) + Action = LiveRootWorklistActionTy::MarkLiveEntryRec; + else + Action = LiveRootWorklistActionTy::MarkTypeEntryRec; + + if (AttrSpec.Attr == dwarf::DW_AT_import) { + if (isNamespaceLikeEntry(RefDie->DieEntry)) { + addActionToRootEntriesWorkList( + isTypeAction(Action) + ? LiveRootWorklistActionTy::MarkSingleTypeEntry + : LiveRootWorklistActionTy::MarkSingleLiveEntry, + *RefDie, RootEntry); + continue; + } - addItemToWorklist(*RefDie->first, - RefDie->first->getDebugInfoEntry(RefDie->second)); + addActionToRootEntriesWorkList(Action, *RefDie, RootEntry); + continue; + } + + UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie); + addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry); } return true; } -// Returns true if the specified DIE type allows removing children. -static bool childrenCanBeRemoved(uint32_t Tag) { - switch (Tag) { - default: - return true; - case dwarf::DW_TAG_class_type: - case dwarf::DW_TAG_common_block: - case dwarf::DW_TAG_lexical_block: - case dwarf::DW_TAG_structure_type: - case dwarf::DW_TAG_subprogram: - case dwarf::DW_TAG_subroutine_type: - case dwarf::DW_TAG_union_type: - case dwarf::DW_TAG_array_type: - return false; - } - llvm_unreachable("Invalid Tag"); -} - -void DependencyTracker::addItemToWorklist(CompileUnit &CU, - const DWARFDebugInfoEntry *Entry) { - if (Entry->getAbbreviationDeclarationPtr() == nullptr) - return; +UnitEntryPairTy +DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry) { + UnitEntryPairTy Result = Entry; + + do { + switch (Entry.DieEntry->getTag()) { + case dwarf::DW_TAG_subprogram: + case dwarf::DW_TAG_label: + case dwarf::DW_TAG_variable: + case dwarf::DW_TAG_constant: { + return Result; + } break; + + default: { + // Nothing to do. + } + } - const DWARFDebugInfoEntry *EntryToAdd = Entry; + std::optional ParentIdx = Result.DieEntry->getParentIdx(); + if (!ParentIdx) + return Result; - // If parent does not allow children removing then use that parent as a root - // DIE. - std::optional ParentIdx = Entry->getParentIdx(); - while (ParentIdx) { - const DWARFDebugInfoEntry *ParentEntry = CU.getDebugInfoEntry(*ParentIdx); - if (childrenCanBeRemoved(ParentEntry->getTag())) + const DWARFDebugInfoEntry *ParentEntry = + Result.CU->getDebugInfoEntry(*ParentIdx); + if (isNamespaceLikeEntry(ParentEntry)) break; - EntryToAdd = ParentEntry; - ParentIdx = ParentEntry->getParentIdx(); - } + Result.DieEntry = ParentEntry; + } while (true); - // Check if the DIE entry is already kept. - if (CU.getDIEInfo(EntryToAdd).getKeep()) - return; - - RootEntriesWorkList.emplace_back(CU, EntryToAdd); + return Result; } -bool DependencyTracker::isLiveVariableEntry(CompileUnit &CU, - const DWARFDebugInfoEntry *Entry) { - DWARFDie DIE = CU.getDIE(Entry); - CompileUnit::DIEInfo &Info = CU.getDIEInfo(DIE); +bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy &Entry, + bool IsLiveParent) { + DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry); + CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE); - if (TrackLiveness) { + if (Info.getTrackLiveness()) { const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); - // Global variables with constant value can always be kept. if (!Info.getIsInFunctionScope() && - Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) - return true; - - // See if there is a relocation to a valid debug map entry inside this - // variable's location. The order is important here. We want to always check - // if the variable has a location expression address. - // However, we don't want a static variable in a function to force us to - // keep the enclosing function, unless requested explicitly. - std::pair> LocExprAddrAndRelocAdjustment = - CU.getContaingFile().Addresses->getVariableRelocAdjustment(DIE); - - if (!LocExprAddrAndRelocAdjustment.second) - return false; + Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) { + // Global variables with constant value can always be kept. + } else { + // See if there is a relocation to a valid debug map entry inside this + // variable's location. The order is important here. We want to always + // check if the variable has a location expression address. However, we + // don't want a static variable in a function to force us to keep the + // enclosing function, unless requested explicitly. + std::pair> LocExprAddrAndRelocAdjustment = + Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment( + DIE); + + if (LocExprAddrAndRelocAdjustment.first) + Info.setHasAnAddress(); + + if (!LocExprAddrAndRelocAdjustment.second) + return false; - if ((Info.getIsInFunctionScope()) && - !LLVM_UNLIKELY(CU.getGlobalData().getOptions().KeepFunctionForStatic)) - return false; + if (!IsLiveParent && Info.getIsInFunctionScope() && + !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic) + return false; + } } + Info.setHasAnAddress(); - if (CU.getGlobalData().getOptions().Verbose) { + if (Entry.CU->getGlobalData().getOptions().Verbose) { outs() << "Keeping variable DIE:"; DIDumpOptions DumpOpts; DumpOpts.ChildRecurseDepth = 0; - DumpOpts.Verbose = CU.getGlobalData().getOptions().Verbose; + DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose; DIE.dump(outs(), 8 /* Indent */, DumpOpts); } return true; } -bool DependencyTracker::isLiveSubprogramEntry( - CompileUnit &CU, const DWARFDebugInfoEntry *Entry) { - DWARFDie DIE = CU.getDIE(Entry); +bool DependencyTracker::isLiveSubprogramEntry(const UnitEntryPairTy &Entry) { + DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry); + CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry); + std::optional LowPCVal = DIE.find(dwarf::DW_AT_low_pc); std::optional LowPc; std::optional HighPc; std::optional RelocAdjustment; - - if (TrackLiveness) { - LowPc = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc)); + if (Info.getTrackLiveness()) { + LowPc = dwarf::toAddress(LowPCVal); if (!LowPc) return false; + Info.setHasAnAddress(); + RelocAdjustment = - CU.getContaingFile().Addresses->getSubprogramRelocAdjustment(DIE); + Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment( + DIE); if (!RelocAdjustment) return false; @@ -354,16 +790,18 @@ bool DependencyTracker::isLiveSubprogramEntry( HighPc = DIE.getHighPC(*LowPc); if (!HighPc) { - CU.warn("function without high_pc. Range will be discarded.", &DIE); + Entry.CU->warn("function without high_pc. Range will be discarded.", + &DIE); return false; } if (*LowPc > *HighPc) { - CU.warn("low_pc greater than high_pc. Range will be discarded.", &DIE); + Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.", + &DIE); return false; } - } else if (DIE.getTag() == dwarf::DW_TAG_variable) { - if (CU.hasLabelAt(*LowPc)) + } else if (DIE.getTag() == dwarf::DW_TAG_label) { + if (Entry.CU->hasLabelAt(*LowPc)) return false; // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider @@ -371,33 +809,29 @@ bool DependencyTracker::isLiveSubprogramEntry( // info generation bugs aside, this is really wrong in the case of labels, // where a label marking the end of a function will have a PC == CU's // high_pc. - if (dwarf::toAddress( - CU.getOrigUnit().getUnitDIE().find(dwarf::DW_AT_high_pc)) + if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc)) .value_or(UINT64_MAX) <= LowPc) return false; - CU.addLabelLowPc(*LowPc, *RelocAdjustment); + Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment); } - } + } else + Info.setHasAnAddress(); - if (CU.getGlobalData().getOptions().Verbose) { + if (Entry.CU->getGlobalData().getOptions().Verbose) { outs() << "Keeping subprogram DIE:"; DIDumpOptions DumpOpts; DumpOpts.ChildRecurseDepth = 0; - DumpOpts.Verbose = CU.getGlobalData().getOptions().Verbose; + DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose; DIE.dump(outs(), 8 /* Indent */, DumpOpts); } - if (!TrackLiveness || DIE.getTag() == dwarf::DW_TAG_label) + if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label) return true; - CU.addFunctionRange(*LowPc, *HighPc, *RelocAdjustment); + Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment); return true; } -void DependencyTracker::setDIEPlacementAndTypename(CompileUnit::DIEInfo &Info) { - Info.setPlacement(CompileUnit::PlainDwarf); -} - } // end of namespace dwarflinker_parallel } // namespace llvm diff --git a/llvm/lib/DWARFLinkerParallel/DependencyTracker.h b/llvm/lib/DWARFLinkerParallel/DependencyTracker.h index 69e57bc3ea4d26..abd5371471eb95 100644 --- a/llvm/lib/DWARFLinkerParallel/DependencyTracker.h +++ b/llvm/lib/DWARFLinkerParallel/DependencyTracker.h @@ -10,7 +10,7 @@ #define LLVM_LIB_DWARFLINKERPARALLEL_DEPENDENCYTRACKER_H #include "DWARFLinkerCompileUnit.h" -#include "DWARFLinkerImpl.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" namespace llvm { @@ -19,10 +19,12 @@ class DWARFDie; namespace dwarflinker_parallel { -/// This class discovers DIEs dependencies and marks "live" DIEs. +/// This class discovers DIEs dependencies: marks "live" DIEs, marks DIE +/// locations (whether DIE should be cloned as regular DIE or it should be put +/// into the artificial type unit). class DependencyTracker { public: - DependencyTracker(DWARFLinkerImpl::LinkContext &Context) : Context(Context) {} + DependencyTracker(CompileUnit &CU) : CU(CU) {} /// Recursively walk the \p DIE tree and look for DIEs to keep. Store that /// information in \p CU's DIEInfo. @@ -30,70 +32,223 @@ class DependencyTracker { /// This function is the entry point of the DIE selection algorithm. It is /// expected to walk the DIE tree and(through the mediation of /// Context.File.Addresses) ask for relocation adjustment value on each - /// DIE that might be a 'root DIE'. + /// DIE that might be a 'root DIE'(f.e. subprograms, variables). /// /// Returns true if all dependencies are correctly discovered. Inter-CU /// dependencies cannot be discovered if referenced CU is not analyzed yet. /// If that is the case this method returns false. - bool resolveDependenciesAndMarkLiveness(CompileUnit &CU); + bool resolveDependenciesAndMarkLiveness( + bool InterCUProcessingStarted, + std::atomic &HasNewInterconnectedCUs); - /// Recursively walk the \p DIE tree and check "keepness" information. - /// It is an error if parent node does not have "keep" flag, while - /// child have one. This function dump error at stderr in that case. -#ifndef NDEBUG - static void verifyKeepChain(CompileUnit &CU); -#endif + /// Check if dependencies have incompatible placement. + /// If that is the case modify placement to be compatible. + /// \returns true if any placement was updated, otherwise returns false. + /// This method should be called as a followup processing after + /// resolveDependenciesAndMarkLiveness(). + bool updateDependenciesCompleteness(); + + /// Recursively walk the \p DIE tree and check "keepness" and "placement" + /// information. It is an error if parent node does not have "keep" flag, + /// while child has one. It is an error if parent node has "TypeTable" + /// placement while child has "PlainDwarf" placement. This function dump error + /// at stderr in that case. + void verifyKeepChain(); protected: - struct RootEntryTy { - RootEntryTy(CompileUnit &CU, const DWARFDebugInfoEntry *RootEntry) - : CU(CU), RootEntry(RootEntry) {} + enum class LiveRootWorklistActionTy : uint8_t { + /// Mark current item as live entry. + MarkSingleLiveEntry = 0, + + /// Mark current item as type entry. + MarkSingleTypeEntry, + + /// Mark current item and all its children as live entry. + MarkLiveEntryRec, + + /// Mark current item and all its children as type entry. + MarkTypeEntryRec, + + /// Mark all children of current item as live entry. + MarkLiveChildrenRec, + + /// Mark all children of current item as type entry. + MarkTypeChildrenRec, + }; + + /// \returns true if the specified action is for the "PlainDwarf". + bool isLiveAction(LiveRootWorklistActionTy Action) { + switch (Action) { + default: + return false; + + case LiveRootWorklistActionTy::MarkSingleLiveEntry: + case LiveRootWorklistActionTy::MarkLiveEntryRec: + case LiveRootWorklistActionTy::MarkLiveChildrenRec: + return true; + } + } + + /// \returns true if the specified action is for the "TypeTable". + bool isTypeAction(LiveRootWorklistActionTy Action) { + switch (Action) { + default: + return false; + + case LiveRootWorklistActionTy::MarkSingleTypeEntry: + case LiveRootWorklistActionTy::MarkTypeEntryRec: + case LiveRootWorklistActionTy::MarkTypeChildrenRec: + return true; + } + } + + /// \returns true if the specified action affects only Root entry + /// itself and does not affect it`s children. + bool isSingleAction(LiveRootWorklistActionTy Action) { + switch (Action) { + default: + return false; + + case LiveRootWorklistActionTy::MarkSingleLiveEntry: + case LiveRootWorklistActionTy::MarkSingleTypeEntry: + return true; + } + } - // Compile unit keeping root entry. - CompileUnit &CU; + /// \returns true if the specified action affects only Root entry + /// itself and does not affect it`s children. + bool isChildrenAction(LiveRootWorklistActionTy Action) { + switch (Action) { + default: + return false; - // Root entry. - const DWARFDebugInfoEntry *RootEntry; + case LiveRootWorklistActionTy::MarkLiveChildrenRec: + case LiveRootWorklistActionTy::MarkTypeChildrenRec: + return true; + } + } + + /// Class keeping live worklist item data. + class LiveRootWorklistItemTy { + public: + LiveRootWorklistItemTy() = default; + LiveRootWorklistItemTy(const LiveRootWorklistItemTy &) = default; + LiveRootWorklistItemTy(LiveRootWorklistActionTy Action, + UnitEntryPairTy RootEntry) { + RootCU.setInt(static_cast(Action)); + RootCU.setPointer(RootEntry.CU); + + RootDieEntry = RootEntry.DieEntry; + } + LiveRootWorklistItemTy(LiveRootWorklistActionTy Action, + UnitEntryPairTy RootEntry, + UnitEntryPairTy ReferencedBy) { + RootCU.setPointer(RootEntry.CU); + RootCU.setInt(static_cast(Action)); + RootDieEntry = RootEntry.DieEntry; + + ReferencedByCU = ReferencedBy.CU; + ReferencedByDieEntry = ReferencedBy.DieEntry; + } + + UnitEntryPairTy getRootEntry() const { + return UnitEntryPairTy{RootCU.getPointer(), RootDieEntry}; + } + + CompileUnit::DieOutputPlacement getPlacement() const { + return static_cast(RootCU.getInt()); + } + + bool hasReferencedByOtherEntry() const { return ReferencedByCU != nullptr; } + + UnitEntryPairTy getReferencedByEntry() const { + assert(ReferencedByCU); + assert(ReferencedByDieEntry); + return UnitEntryPairTy{ReferencedByCU, ReferencedByDieEntry}; + } + + LiveRootWorklistActionTy getAction() const { + return static_cast(RootCU.getInt()); + } + + protected: + /// Root entry. + /// ASSUMPTION: 3 bits are used to store LiveRootWorklistActionTy value. + /// Thus LiveRootWorklistActionTy should have no more eight elements. + PointerIntPair RootCU; + const DWARFDebugInfoEntry *RootDieEntry = nullptr; + + /// Another root entry which references this RootDieEntry. + /// ReferencedByDieEntry is kept to update placement. + /// if RootDieEntry has placement incompatible with placement + /// of ReferencedByDieEntry then it should be updated. + CompileUnit *ReferencedByCU = nullptr; + const DWARFDebugInfoEntry *ReferencedByDieEntry = nullptr; }; - using RootEntriesListTy = SmallVector; + using RootEntriesListTy = SmallVector; /// This function navigates DIEs tree starting from specified \p Entry. - /// It puts 'root DIE' into the worklist. - void collectRootsToKeep(CompileUnit &CU, const DWARFDebugInfoEntry *Entry); + /// It puts found 'root DIE' into the worklist. The \p CollectLiveEntries + /// instructs to collect either live roots(like subprograms having live + /// DW_AT_low_pc) or otherwise roots which is not live(they need to be + /// collected if they are imported f.e. by DW_TAG_imported_module). + void collectRootsToKeep(const UnitEntryPairTy &Entry, + std::optional ReferencedBy, + bool IsLiveParent); /// Returns true if specified variable references live code section. - bool isLiveVariableEntry(CompileUnit &CU, const DWARFDebugInfoEntry *Entry); + static bool isLiveVariableEntry(const UnitEntryPairTy &Entry, + bool IsLiveParent); /// Returns true if specified subprogram references live code section. - bool isLiveSubprogramEntry(CompileUnit &CU, const DWARFDebugInfoEntry *Entry); + static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry); - /// Examine worklist and mark all 'root DIE's as kept. - bool markLiveRootsAsKept(); + /// Examine worklist and mark all 'root DIE's as kept and set "Placement" + /// property. + bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted, + std::atomic &HasNewInterconnectedCUs); /// Mark whole DIE tree as kept recursively. - bool markDIEEntryAsKeptRec(const RootEntryTy &RootItem, CompileUnit &CU, - const DWARFDebugInfoEntry *Entry); + bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action, + const UnitEntryPairTy &RootEntry, + const UnitEntryPairTy &Entry, + bool InterCUProcessingStarted, + std::atomic &HasNewInterconnectedCUs); + + /// Mark parents as keeping children. + void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry); + + /// Mark whole DIE tree as placed in "PlainDwarf". + void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry); + + /// Check referenced DIEs and add them into the worklist. + bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action, + const UnitEntryPairTy &RootEntry, + const UnitEntryPairTy &Entry, + bool InterCUProcessingStarted, + std::atomic &HasNewInterconnectedCUs); - /// Check referenced DIEs and add them into the worklist if neccessary. - bool maybeAddReferencedRoots(const RootEntryTy &RootItem, CompileUnit &CU, - const DWARFDebugInfoEntry *Entry); + /// \returns true if \p DIEEntry can possibly be put into the artificial type + /// unit. + bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry); - /// Add 'root DIE' into the worklist. - void addItemToWorklist(CompileUnit &CU, const DWARFDebugInfoEntry *Entry); + /// \returns root for the specified \p Entry. + UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry); - /// Set kind of placement(whether it goes into type table, plain dwarf or - /// both) for the specified die \p DieIdx. - void setDIEPlacementAndTypename(CompileUnit::DIEInfo &Info); + /// Add action item to the work list. + void + addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action, + const UnitEntryPairTy &Entry, + std::optional ReferencedBy); - /// Flag indicating whether liveness information should be examined. - bool TrackLiveness = false; + CompileUnit &CU; - /// List of CU, Entry pairs which are 'root DIE's. + /// List of entries which are 'root DIE's. RootEntriesListTy RootEntriesWorkList; - /// Link context for the analyzed CU. - DWARFLinkerImpl::LinkContext &Context; + /// List of entries dependencies. + RootEntriesListTy Dependencies; }; } // end namespace dwarflinker_parallel diff --git a/llvm/lib/DWARFLinkerParallel/OutputSections.cpp b/llvm/lib/DWARFLinkerParallel/OutputSections.cpp index 8e7caa7bb40742..9c3e3ebd220aaf 100644 --- a/llvm/lib/DWARFLinkerParallel/OutputSections.cpp +++ b/llvm/lib/DWARFLinkerParallel/OutputSections.cpp @@ -8,6 +8,7 @@ #include "OutputSections.h" #include "DWARFLinkerCompileUnit.h" +#include "DWARFLinkerTypeUnit.h" #include "llvm/ADT/StringSwitch.h" namespace llvm { @@ -92,6 +93,33 @@ DebugULEB128DieRefPatch::DebugULEB128DieRefPatch(uint64_t PatchOffset, RefCU(RefCU, SrcCU->getUniqueID() == RefCU->getUniqueID()), RefDieIdxOrClonedOffset(RefIdx) {} +DebugDieTypeRefPatch::DebugDieTypeRefPatch(uint64_t PatchOffset, + TypeEntry *RefTypeName) + : SectionPatch({PatchOffset}), RefTypeName(RefTypeName) {} + +DebugType2TypeDieRefPatch::DebugType2TypeDieRefPatch(uint64_t PatchOffset, + DIE *Die, + TypeEntry *TypeName, + TypeEntry *RefTypeName) + : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName), + RefTypeName(RefTypeName) {} + +DebugTypeStrPatch::DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die, + TypeEntry *TypeName, StringEntry *String) + : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName), + String(String) {} + +DebugTypeLineStrPatch::DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die, + TypeEntry *TypeName, + StringEntry *String) + : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName), + String(String) {} + +DebugTypeDeclFilePatch::DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName, + StringEntry *Directory, + StringEntry *FilePath) + : Die(Die), TypeName(TypeName), Directory(Directory), FilePath(FilePath) {} + void SectionDescriptor::clearAllSectionData() { StartOffset = 0; clearSectionContent(); @@ -102,6 +130,10 @@ void SectionDescriptor::clearAllSectionData() { ListDebugDieRefPatch.erase(); ListDebugULEB128DieRefPatch.erase(); ListDebugOffsetPatch.erase(); + ListDebugType2TypeDieRefPatch.erase(); + ListDebugTypeDeclFilePatch.erase(); + ListDebugTypeLineStrPatch.erase(); + ListDebugTypeStrPatch.erase(); } void SectionDescriptor::clearSectionContent() { Contents = OutSectionDataTy(); } @@ -144,6 +176,30 @@ void SectionDescriptor::setSizesForSectionCreatedByAsmPrinter() { } } +void SectionDescriptor::emitString(dwarf::Form StringForm, + const char *StringVal) { + assert(StringVal != nullptr); + + switch (StringForm) { + case dwarf::DW_FORM_string: { + emitInplaceString(StringVal); + } break; + case dwarf::DW_FORM_strp: { + notePatch(DebugStrPatch{ + {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first}); + emitStringPlaceholder(); + } break; + case dwarf::DW_FORM_line_strp: { + notePatch(DebugLineStrPatch{ + {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first}); + emitStringPlaceholder(); + } break; + default: + llvm_unreachable("Unsupported string form"); + break; + }; +} + void SectionDescriptor::emitIntVal(uint64_t Val, unsigned Size) { switch (Size) { case 1: { @@ -171,30 +227,6 @@ void SectionDescriptor::emitIntVal(uint64_t Val, unsigned Size) { } } -void SectionDescriptor::emitString(dwarf::Form StringForm, - const char *StringVal) { - assert(StringVal != nullptr); - - switch (StringForm) { - case dwarf::DW_FORM_string: { - emitInplaceString(StringVal); - } break; - case dwarf::DW_FORM_strp: { - notePatch(DebugStrPatch{ - {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first}); - emitStringPlaceholder(); - } break; - case dwarf::DW_FORM_line_strp: { - notePatch(DebugLineStrPatch{ - {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first}); - emitStringPlaceholder(); - } break; - default: - llvm_unreachable("Unsupported string form"); - break; - }; -} - void SectionDescriptor::apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val) { switch (AttrForm) { @@ -330,8 +362,8 @@ void SectionDescriptor::applySLEB128(uint64_t PatchOffset, uint64_t Val) { void OutputSections::applyPatches( SectionDescriptor &Section, StringEntryToDwarfStringPoolEntryMap &DebugStrStrings, - StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings) { - + StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings, + TypeUnit *TypeUnitPtr) { Section.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) { DwarfStringPoolEntryWithExtString *Entry = DebugStrStrings.getExistingEntry(Patch.String); @@ -339,6 +371,26 @@ void OutputSections::applyPatches( Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset); }); + Section.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) { + assert(TypeUnitPtr != nullptr); + TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load(); + assert(TypeEntry && + formatv("No data for type {0}", Patch.TypeName->getKey()) + .str() + .c_str()); + + if (&TypeEntry->getFinalDie() != Patch.Die) + return; + + DwarfStringPoolEntryWithExtString *Entry = + DebugStrStrings.getExistingEntry(Patch.String); + assert(Entry != nullptr); + + Patch.PatchOffset += + Patch.Die->getOffset() + getULEB128Size(Patch.Die->getAbbrevNumber()); + + Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset); + }); Section.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) { DwarfStringPoolEntryWithExtString *Entry = @@ -347,6 +399,26 @@ void OutputSections::applyPatches( Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset); }); + Section.ListDebugTypeLineStrPatch.forEach([&](DebugTypeLineStrPatch &Patch) { + assert(TypeUnitPtr != nullptr); + TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load(); + assert(TypeEntry && + formatv("No data for type {0}", Patch.TypeName->getKey()) + .str() + .c_str()); + + if (&TypeEntry->getFinalDie() != Patch.Die) + return; + + DwarfStringPoolEntryWithExtString *Entry = + DebugLineStrStrings.getExistingEntry(Patch.String); + assert(Entry != nullptr); + + Patch.PatchOffset += + Patch.Die->getOffset() + getULEB128Size(Patch.Die->getAbbrevNumber()); + + Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset); + }); std::optional RangeSection; if (Format.Version >= 5) @@ -404,6 +476,46 @@ void OutputSections::applyPatches( Patch.RefDieIdxOrClonedOffset); }); + Section.ListDebugDieTypeRefPatch.forEach([&](DebugDieTypeRefPatch &Patch) { + assert(TypeUnitPtr != nullptr); + assert(Patch.RefTypeName != nullptr); + + TypeEntryBody *TypeEntry = Patch.RefTypeName->getValue().load(); + assert(TypeEntry && + formatv("No data for type {0}", Patch.RefTypeName->getKey()) + .str() + .c_str()); + + Section.apply(Patch.PatchOffset, dwarf::DW_FORM_ref_addr, + TypeEntry->getFinalDie().getOffset()); + }); + + Section.ListDebugType2TypeDieRefPatch.forEach( + [&](DebugType2TypeDieRefPatch &Patch) { + assert(TypeUnitPtr != nullptr); + TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load(); + assert(TypeEntry && + formatv("No data for type {0}", Patch.TypeName->getKey()) + .str() + .c_str()); + + if (&TypeEntry->getFinalDie() != Patch.Die) + return; + + Patch.PatchOffset += Patch.Die->getOffset() + + getULEB128Size(Patch.Die->getAbbrevNumber()); + + assert(Patch.RefTypeName != nullptr); + TypeEntryBody *RefTypeEntry = Patch.RefTypeName->getValue().load(); + assert(TypeEntry && + formatv("No data for type {0}", Patch.RefTypeName->getKey()) + .str() + .c_str()); + + Section.apply(Patch.PatchOffset, dwarf::DW_FORM_ref4, + RefTypeEntry->getFinalDie().getOffset()); + }); + Section.ListDebugOffsetPatch.forEach([&](DebugOffsetPatch &Patch) { uint64_t FinalValue = Patch.SectionPtr.getPointer()->StartOffset; diff --git a/llvm/lib/DWARFLinkerParallel/OutputSections.h b/llvm/lib/DWARFLinkerParallel/OutputSections.h index b101ac61935c5c..f23b2efb869da8 100644 --- a/llvm/lib/DWARFLinkerParallel/OutputSections.h +++ b/llvm/lib/DWARFLinkerParallel/OutputSections.h @@ -31,6 +31,8 @@ namespace llvm { namespace dwarflinker_parallel { +class TypeUnit; + /// List of tracked debug tables. enum class DebugSectionKind : uint8_t { DebugInfo = 0, @@ -113,7 +115,7 @@ struct DebugDieRefPatch : SectionPatch { uint32_t RefIdx); PointerIntPair RefCU; - uint64_t RefDieIdxOrClonedOffset; + uint64_t RefDieIdxOrClonedOffset = 0; }; /// This structure is used to update reference to the DIE of ULEB128 form. @@ -122,7 +124,53 @@ struct DebugULEB128DieRefPatch : SectionPatch { CompileUnit *RefCU, uint32_t RefIdx); PointerIntPair RefCU; - uint64_t RefDieIdxOrClonedOffset; + uint64_t RefDieIdxOrClonedOffset = 0; +}; + +/// This structure is used to update reference to the type DIE. +struct DebugDieTypeRefPatch : SectionPatch { + DebugDieTypeRefPatch(uint64_t PatchOffset, TypeEntry *RefTypeName); + + TypeEntry *RefTypeName = nullptr; +}; + +/// This structure is used to update reference to the type DIE. +struct DebugType2TypeDieRefPatch : SectionPatch { + DebugType2TypeDieRefPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName, + TypeEntry *RefTypeName); + + DIE *Die = nullptr; + TypeEntry *TypeName = nullptr; + TypeEntry *RefTypeName = nullptr; +}; + +struct DebugTypeStrPatch : SectionPatch { + DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName, + StringEntry *String); + + DIE *Die = nullptr; + TypeEntry *TypeName = nullptr; + StringEntry *String = nullptr; +}; + +struct DebugTypeLineStrPatch : SectionPatch { + DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName, + StringEntry *String); + + DIE *Die = nullptr; + TypeEntry *TypeName = nullptr; + StringEntry *String = nullptr; +}; + +struct DebugTypeDeclFilePatch { + DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName, StringEntry *Directory, + StringEntry *FilePath); + + DIE *Die = nullptr; + TypeEntry *TypeName = nullptr; + StringEntry *Directory = nullptr; + StringEntry *FilePath = nullptr; + uint32_t FileID = 0; }; /// Type for section data. @@ -140,16 +188,20 @@ struct SectionDescriptor { SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData, dwarf::FormParams Format, llvm::endianness Endianess) - : OS(Contents), GlobalData(GlobalData), SectionKind(SectionKind), - Format(Format), Endianess(Endianess) { - ListDebugStrPatch.setAllocator(&GlobalData.getAllocator()); - ListDebugLineStrPatch.setAllocator(&GlobalData.getAllocator()); - ListDebugRangePatch.setAllocator(&GlobalData.getAllocator()); - ListDebugLocPatch.setAllocator(&GlobalData.getAllocator()); - ListDebugDieRefPatch.setAllocator(&GlobalData.getAllocator()); - ListDebugULEB128DieRefPatch.setAllocator(&GlobalData.getAllocator()); - ListDebugOffsetPatch.setAllocator(&GlobalData.getAllocator()); - } + : OS(Contents), ListDebugStrPatch(&GlobalData.getAllocator()), + ListDebugLineStrPatch(&GlobalData.getAllocator()), + ListDebugRangePatch(&GlobalData.getAllocator()), + ListDebugLocPatch(&GlobalData.getAllocator()), + ListDebugDieRefPatch(&GlobalData.getAllocator()), + ListDebugULEB128DieRefPatch(&GlobalData.getAllocator()), + ListDebugOffsetPatch(&GlobalData.getAllocator()), + ListDebugDieTypeRefPatch(&GlobalData.getAllocator()), + ListDebugType2TypeDieRefPatch(&GlobalData.getAllocator()), + ListDebugTypeStrPatch(&GlobalData.getAllocator()), + ListDebugTypeLineStrPatch(&GlobalData.getAllocator()), + ListDebugTypeDeclFilePatch(&GlobalData.getAllocator()), + GlobalData(GlobalData), SectionKind(SectionKind), Format(Format), + Endianess(Endianess) {} /// Erase whole section contents(data bits, list of patches). void clearAllSectionData(); @@ -178,9 +230,16 @@ struct SectionDescriptor { ADD_PATCHES_LIST(DebugDieRefPatch) ADD_PATCHES_LIST(DebugULEB128DieRefPatch) ADD_PATCHES_LIST(DebugOffsetPatch) - - /// Offsets to some fields are not known at the moment of noting patch. - /// In that case we remember pointers to patch offset to update them later. + ADD_PATCHES_LIST(DebugDieTypeRefPatch) + ADD_PATCHES_LIST(DebugType2TypeDieRefPatch) + ADD_PATCHES_LIST(DebugTypeStrPatch) + ADD_PATCHES_LIST(DebugTypeLineStrPatch) + ADD_PATCHES_LIST(DebugTypeDeclFilePatch) + + /// While creating patches, offsets to attributes may be partially + /// unknown(because size of abbreviation number is unknown). In such case we + /// remember patch itself and pointer to patch application offset to add size + /// of abbreviation number later. template void notePatchWithOffsetUpdate(const T &Patch, OffsetsPtrVector &PatchesOffsetsList) { @@ -222,7 +281,6 @@ struct SectionDescriptor { /// Emit specified integer value into the current section contents. void emitIntVal(uint64_t Val, unsigned Size); - /// Emit specified string value into the current section contents. void emitString(dwarf::Form StringForm, const char *StringVal); /// Emit specified inplace string value into the current section contents. @@ -395,7 +453,8 @@ class OutputSections { /// Enumerate all sections, for each section apply all section patches. void applyPatches(SectionDescriptor &Section, StringEntryToDwarfStringPoolEntryMap &DebugStrStrings, - StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings); + StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings, + TypeUnit *TypeUnitPtr); /// Endiannes for the sections. llvm::endianness getEndianness() const { return Endianness; } diff --git a/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp new file mode 100644 index 00000000000000..e0900f7a8e3d3e --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.cpp @@ -0,0 +1,767 @@ +//===- SyntheticTypeNameBuilder.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SyntheticTypeNameBuilder.h" +#include "DWARFLinkerCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +namespace dwarflinker_parallel { + +Error SyntheticTypeNameBuilder::assignName( + UnitEntryPairTy InputUnitEntryPair, + std::optional> ChildIndex) { + [[maybe_unused]] const CompileUnit::DIEInfo &Info = + InputUnitEntryPair.CU->getDIEInfo(InputUnitEntryPair.DieEntry); + assert(Info.needToPlaceInTypeTable() && + "Cann't assign name for non-type DIE"); + + if (InputUnitEntryPair.CU->getDieTypeEntry(InputUnitEntryPair.DieEntry) != + nullptr) + return Error::success(); + + SyntheticName.resize(0); + RecursionDepth = 0; + return addDIETypeName(InputUnitEntryPair, ChildIndex, true); +} + +void SyntheticTypeNameBuilder::addArrayDimension( + UnitEntryPairTy InputUnitEntryPair) { + for (const DWARFDebugInfoEntry *CurChild = + InputUnitEntryPair.CU->getFirstChildEntry( + InputUnitEntryPair.DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = InputUnitEntryPair.CU->getSiblingEntry(CurChild)) { + if (CurChild->getTag() == dwarf::DW_TAG_subrange_type || + CurChild->getTag() == dwarf::DW_TAG_generic_subrange) { + SyntheticName += "["; + if (std::optional Val = + InputUnitEntryPair.CU->find(CurChild, dwarf::DW_AT_count)) { + if (std::optional ConstVal = Val->getAsUnsignedConstant()) { + SyntheticName += std::to_string(*ConstVal); + } else if (std::optional ConstVal = + Val->getAsSignedConstant()) { + SyntheticName += std::to_string(*ConstVal); + } + } + + SyntheticName += "]"; + } + } +} + +static dwarf::Attribute TypeAttr[] = {dwarf::DW_AT_type}; +Error SyntheticTypeNameBuilder::addSignature(UnitEntryPairTy InputUnitEntryPair, + bool addTemplateParameters) { + // Add entry type. + if (Error Err = addReferencedODRDies(InputUnitEntryPair, false, TypeAttr)) + return Err; + SyntheticName += ':'; + + SmallVector TemplateParameters; + SmallVector FunctionParameters; + for (const DWARFDebugInfoEntry *CurChild = + InputUnitEntryPair.CU->getFirstChildEntry( + InputUnitEntryPair.DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = InputUnitEntryPair.CU->getSiblingEntry(CurChild)) { + dwarf::Tag ChildTag = CurChild->getTag(); + if (addTemplateParameters && + (ChildTag == dwarf::DW_TAG_template_type_parameter || + ChildTag == dwarf::DW_TAG_template_value_parameter)) + TemplateParameters.push_back(CurChild); + else if (ChildTag == dwarf::DW_TAG_formal_parameter || + ChildTag == dwarf::DW_TAG_unspecified_parameters) + FunctionParameters.push_back(CurChild); + else if (addTemplateParameters && + ChildTag == dwarf::DW_TAG_GNU_template_parameter_pack) { + for (const DWARFDebugInfoEntry *CurGNUChild = + InputUnitEntryPair.CU->getFirstChildEntry(CurChild); + CurGNUChild && CurGNUChild->getAbbreviationDeclarationPtr(); + CurGNUChild = InputUnitEntryPair.CU->getSiblingEntry(CurGNUChild)) + TemplateParameters.push_back(CurGNUChild); + } else if (ChildTag == dwarf::DW_TAG_GNU_formal_parameter_pack) { + for (const DWARFDebugInfoEntry *CurGNUChild = + InputUnitEntryPair.CU->getFirstChildEntry(CurChild); + CurGNUChild && CurGNUChild->getAbbreviationDeclarationPtr(); + CurGNUChild = InputUnitEntryPair.CU->getSiblingEntry(CurGNUChild)) + FunctionParameters.push_back(CurGNUChild); + } + } + + // Add parameters. + if (Error Err = addParamNames(*InputUnitEntryPair.CU, FunctionParameters)) + return Err; + + // Add template parameters. + if (Error Err = + addTemplateParamNames(*InputUnitEntryPair.CU, TemplateParameters)) + return Err; + + return Error::success(); +} + +Error SyntheticTypeNameBuilder::addParamNames( + CompileUnit &CU, + SmallVector &FunctionParameters) { + SyntheticName += '('; + for (const DWARFDebugInfoEntry *FunctionParameter : FunctionParameters) { + if (SyntheticName.back() != '(') + SyntheticName += ", "; + if (dwarf::toUnsigned(CU.find(FunctionParameter, dwarf::DW_AT_artificial), + 0)) + SyntheticName += "^"; + if (Error Err = addReferencedODRDies( + UnitEntryPairTy{&CU, FunctionParameter}, false, TypeAttr)) + return Err; + } + SyntheticName += ')'; + return Error::success(); +} + +Error SyntheticTypeNameBuilder::addTemplateParamNames( + CompileUnit &CU, + SmallVector &TemplateParameters) { + if (!TemplateParameters.empty()) { + SyntheticName += '<'; + for (const DWARFDebugInfoEntry *Parameter : TemplateParameters) { + if (SyntheticName.back() != '<') + SyntheticName += ", "; + + if (Parameter->getTag() == dwarf::DW_TAG_template_value_parameter) { + if (std::optional Val = + CU.find(Parameter, dwarf::DW_AT_const_value)) { + if (std::optional ConstVal = Val->getAsUnsignedConstant()) + SyntheticName += std::to_string(*ConstVal); + else if (std::optional ConstVal = Val->getAsSignedConstant()) + SyntheticName += std::to_string(*ConstVal); + } + } + + if (Error Err = addReferencedODRDies(UnitEntryPairTy{&CU, Parameter}, + false, TypeAttr)) + return Err; + } + SyntheticName += '>'; + } + return Error::success(); +} + +void SyntheticTypeNameBuilder::addOrderedName( + std::pair ChildIdx) { + std::string Name; + llvm::raw_string_ostream stream(Name); + stream << format_hex_no_prefix(ChildIdx.first, ChildIdx.second); + SyntheticName += Name; +} + +// Examine DIE and return type deduplication candidate: some DIEs could not be +// deduplicated, namespace may refer to another namespace. +static std::optional +getTypeDeduplicationCandidate(UnitEntryPairTy UnitEntryPair) { + switch (UnitEntryPair.DieEntry->getTag()) { + case dwarf::DW_TAG_null: + case dwarf::DW_TAG_compile_unit: + case dwarf::DW_TAG_partial_unit: + case dwarf::DW_TAG_type_unit: + case dwarf::DW_TAG_skeleton_unit: { + return std::nullopt; + } + case dwarf::DW_TAG_namespace: { + // Check if current namespace refers another. + if (UnitEntryPair.CU->find(UnitEntryPair.DieEntry, dwarf::DW_AT_extension)) + UnitEntryPair = UnitEntryPair.getNamespaceOrigin(); + + // Content of anonimous namespaces should not be deduplicated. + if (!UnitEntryPair.CU->find(UnitEntryPair.DieEntry, dwarf::DW_AT_name)) + llvm_unreachable("Cann't deduplicate anonimous namespace"); + + return UnitEntryPair; + } + default: + return UnitEntryPair; + } +} + +Error SyntheticTypeNameBuilder::addParentName( + UnitEntryPairTy &InputUnitEntryPair) { + std::optional UnitEntryPair = InputUnitEntryPair.getParent(); + if (!UnitEntryPair) + return Error::success(); + + UnitEntryPair = getTypeDeduplicationCandidate(*UnitEntryPair); + if (!UnitEntryPair) + return Error::success(); + + if (TypeEntry *ImmediateParentName = + UnitEntryPair->CU->getDieTypeEntry(UnitEntryPair->DieEntry)) { + SyntheticName += ImmediateParentName->getKey(); + SyntheticName += "."; + return Error::success(); + } + + // Collect parent entries. + SmallVector Parents; + do { + Parents.push_back(*UnitEntryPair); + + UnitEntryPair = UnitEntryPair->getParent(); + if (!UnitEntryPair) + break; + + UnitEntryPair = getTypeDeduplicationCandidate(*UnitEntryPair); + if (!UnitEntryPair) + break; + + } while (!UnitEntryPair->CU->getDieTypeEntry(UnitEntryPair->DieEntry)); + + // Assign name for each parent entry. + size_t NameStart = SyntheticName.size(); + for (UnitEntryPairTy Parent : reverse(Parents)) { + SyntheticName.resize(NameStart); + if (Error Err = addDIETypeName(Parent, std::nullopt, true)) + return Err; + } + + // Add parents delimiter. + SyntheticName += "."; + return Error::success(); +} + +void SyntheticTypeNameBuilder::addDieNameFromDeclFileAndDeclLine( + UnitEntryPairTy &InputUnitEntryPair, bool &HasDeclFileName) { + if (std::optional DeclFileVal = InputUnitEntryPair.CU->find( + InputUnitEntryPair.DieEntry, dwarf::DW_AT_decl_file)) { + if (std::optional DeclLineVal = InputUnitEntryPair.CU->find( + InputUnitEntryPair.DieEntry, dwarf::DW_AT_decl_line)) { + if (std::optional> DirAndFilename = + InputUnitEntryPair.CU->getDirAndFilenameFromLineTable( + *DeclFileVal)) { + SyntheticName += DirAndFilename->first; + SyntheticName += DirAndFilename->second; + + if (std::optional DeclLineIntVal = + dwarf::toUnsigned(*DeclLineVal)) { + SyntheticName += " "; + SyntheticName += utohexstr(*DeclLineIntVal); + } + + HasDeclFileName = true; + } + } + } +} + +void SyntheticTypeNameBuilder::addValueName(UnitEntryPairTy InputUnitEntryPair, + dwarf::Attribute Attr) { + if (std::optional Val = + InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, Attr)) { + if (std::optional ConstVal = Val->getAsUnsignedConstant()) { + SyntheticName += " "; + SyntheticName += std::to_string(*ConstVal); + } else if (std::optional ConstVal = Val->getAsSignedConstant()) { + SyntheticName += " "; + SyntheticName += std::to_string(*ConstVal); + } + } +} + +Error SyntheticTypeNameBuilder::addReferencedODRDies( + UnitEntryPairTy InputUnitEntryPair, bool AssignNameToTypeDescriptor, + ArrayRef ODRAttrs) { + bool FirstIteration = true; + for (dwarf::Attribute Attr : ODRAttrs) { + if (std::optional AttrValue = + InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, Attr)) { + std::optional RefDie = + InputUnitEntryPair.CU->resolveDIEReference( + *AttrValue, ResolveInterCUReferencesMode::Resolve); + + if (!RefDie) + continue; + + if (!RefDie->DieEntry) + return createStringError(std::errc::invalid_argument, + "Cann't resolve DIE reference"); + + if (!FirstIteration) + SyntheticName += ","; + + RecursionDepth++; + if (RecursionDepth > 1000) + return createStringError( + std::errc::invalid_argument, + "Cann't parse input DWARF. Recursive dependence."); + + if (Error Err = + addDIETypeName(*RefDie, std::nullopt, AssignNameToTypeDescriptor)) + return Err; + RecursionDepth--; + FirstIteration = false; + } + } + + return Error::success(); +} + +Error SyntheticTypeNameBuilder::addTypeName(UnitEntryPairTy InputUnitEntryPair, + bool AddParentNames) { + bool HasLinkageName = false; + bool HasShortName = false; + bool HasTemplatesInShortName = false; + bool HasDeclFileName = false; + + // Try to get name from the DIE. + if (std::optional Val = InputUnitEntryPair.CU->find( + InputUnitEntryPair.DieEntry, + {dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_AT_linkage_name})) { + // Firstly check for linkage name. + SyntheticName += dwarf::toStringRef(Val); + HasLinkageName = true; + } else if (std::optional Val = InputUnitEntryPair.CU->find( + InputUnitEntryPair.DieEntry, dwarf::DW_AT_name)) { + // Then check for short name. + StringRef Name = dwarf::toStringRef(Val); + SyntheticName += Name; + + HasShortName = true; + HasTemplatesInShortName = + Name.endswith(">") && Name.count("<") != 0 && !Name.endswith("<=>"); + } else { + // Finally check for declaration attributes. + addDieNameFromDeclFileAndDeclLine(InputUnitEntryPair, HasDeclFileName); + } + + // Add additional name parts for some DIEs. + switch (InputUnitEntryPair.DieEntry->getTag()) { + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_interface_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_subroutine_type: + case dwarf::DW_TAG_subprogram: { + if (InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, + dwarf::DW_AT_artificial)) + SyntheticName += "^"; + + // No need to add signature information for linkage name, + // also no need to add template parameters name if short name already + // includes them. + if (!HasLinkageName) + if (Error Err = + addSignature(InputUnitEntryPair, !HasTemplatesInShortName)) + return Err; + } break; + case dwarf::DW_TAG_coarray_type: + case dwarf::DW_TAG_array_type: { + addArrayDimension(InputUnitEntryPair); + } break; + case dwarf::DW_TAG_subrange_type: { + addValueName(InputUnitEntryPair, dwarf::DW_AT_count); + } break; + case dwarf::DW_TAG_template_value_parameter: { + if (!HasTemplatesInShortName) { + // TODO add support for DW_AT_location + addValueName(InputUnitEntryPair, dwarf::DW_AT_const_value); + } + } break; + default: { + // Nothing to do. + } break; + } + + // If name for the DIE is not determined yet add referenced types to the name. + if (!HasLinkageName && !HasShortName && !HasDeclFileName) { + if (InputUnitEntryPair.CU->find(InputUnitEntryPair.DieEntry, + getODRAttributes())) + if (Error Err = addReferencedODRDies(InputUnitEntryPair, AddParentNames, + getODRAttributes())) + return Err; + } + + return Error::success(); +} + +Error SyntheticTypeNameBuilder::addDIETypeName( + UnitEntryPairTy InputUnitEntryPair, + std::optional> ChildIndex, + bool AssignNameToTypeDescriptor) { + std::optional UnitEntryPair = + getTypeDeduplicationCandidate(InputUnitEntryPair); + if (!UnitEntryPair) + return Error::success(); + + TypeEntry *TypeEntryPtr = + InputUnitEntryPair.CU->getDieTypeEntry(InputUnitEntryPair.DieEntry); + // Check if DIE already has a name. + if (!TypeEntryPtr) { + size_t NameStart = SyntheticName.size(); + if (AssignNameToTypeDescriptor) { + if (Error Err = addParentName(*UnitEntryPair)) + return Err; + } + addTypePrefix(UnitEntryPair->DieEntry); + + if (ChildIndex) { + addOrderedName(*ChildIndex); + } else { + if (Error Err = addTypeName(*UnitEntryPair, AssignNameToTypeDescriptor)) + return Err; + } + + if (AssignNameToTypeDescriptor) { + // Add built name to the DIE. + TypeEntryPtr = TypePoolRef.insert(SyntheticName.substr(NameStart)); + InputUnitEntryPair.CU->setDieTypeEntry(InputUnitEntryPair.DieEntry, + TypeEntryPtr); + } + } else + SyntheticName += TypeEntryPtr->getKey(); + + return Error::success(); +} + +void SyntheticTypeNameBuilder::addTypePrefix( + const DWARFDebugInfoEntry *DieEntry) { + switch (DieEntry->getTag()) { + case dwarf::DW_TAG_base_type: { + SyntheticName += "{0}"; + } break; + case dwarf::DW_TAG_namespace: { + SyntheticName += "{1}"; + } break; + case dwarf::DW_TAG_formal_parameter: { + SyntheticName += "{2}"; + } break; + // dwarf::DW_TAG_unspecified_parameters have the same prefix as before. + case dwarf::DW_TAG_unspecified_parameters: { + SyntheticName += "{2}"; + } break; + case dwarf::DW_TAG_template_type_parameter: { + SyntheticName += "{3}"; + } break; + // dwarf::DW_TAG_template_value_parameter have the same prefix as before. + case dwarf::DW_TAG_template_value_parameter: { + SyntheticName += "{3}"; + } break; + case dwarf::DW_TAG_GNU_formal_parameter_pack: { + SyntheticName += "{4}"; + } break; + case dwarf::DW_TAG_GNU_template_parameter_pack: { + SyntheticName += "{5}"; + } break; + case dwarf::DW_TAG_inheritance: { + SyntheticName += "{6}"; + } break; + case dwarf::DW_TAG_array_type: { + SyntheticName += "{7}"; + } break; + case dwarf::DW_TAG_class_type: { + SyntheticName += "{8}"; + } break; + case dwarf::DW_TAG_enumeration_type: { + SyntheticName += "{9}"; + } break; + case dwarf::DW_TAG_imported_declaration: { + SyntheticName += "{A}"; + } break; + case dwarf::DW_TAG_member: { + SyntheticName += "{B}"; + } break; + case dwarf::DW_TAG_pointer_type: { + SyntheticName += "{C}"; + } break; + case dwarf::DW_TAG_reference_type: { + SyntheticName += "{D}"; + } break; + case dwarf::DW_TAG_string_type: { + SyntheticName += "{E}"; + } break; + case dwarf::DW_TAG_structure_type: { + SyntheticName += "{F}"; + } break; + case dwarf::DW_TAG_subroutine_type: { + SyntheticName += "{G}"; + } break; + case dwarf::DW_TAG_typedef: { + SyntheticName += "{H}"; + } break; + case dwarf::DW_TAG_union_type: { + SyntheticName += "{I}"; + } break; + case dwarf::DW_TAG_variant: { + SyntheticName += "{J}"; + } break; + case dwarf::DW_TAG_inlined_subroutine: { + SyntheticName += "{K}"; + } break; + case dwarf::DW_TAG_module: { + SyntheticName += "{L}"; + } break; + case dwarf::DW_TAG_ptr_to_member_type: { + SyntheticName += "{M}"; + } break; + case dwarf::DW_TAG_set_type: { + SyntheticName += "{N}"; + } break; + case dwarf::DW_TAG_subrange_type: { + SyntheticName += "{O}"; + } break; + case dwarf::DW_TAG_with_stmt: { + SyntheticName += "{P}"; + } break; + case dwarf::DW_TAG_access_declaration: { + SyntheticName += "{Q}"; + } break; + case dwarf::DW_TAG_catch_block: { + SyntheticName += "{R}"; + } break; + case dwarf::DW_TAG_const_type: { + SyntheticName += "{S}"; + } break; + case dwarf::DW_TAG_constant: { + SyntheticName += "{T}"; + } break; + case dwarf::DW_TAG_enumerator: { + SyntheticName += "{U}"; + } break; + case dwarf::DW_TAG_file_type: { + SyntheticName += "{V}"; + } break; + case dwarf::DW_TAG_friend: { + SyntheticName += "{W}"; + } break; + case dwarf::DW_TAG_namelist: { + SyntheticName += "{X}"; + } break; + case dwarf::DW_TAG_namelist_item: { + SyntheticName += "{Y}"; + } break; + case dwarf::DW_TAG_packed_type: { + SyntheticName += "{Z}"; + } break; + case dwarf::DW_TAG_subprogram: { + SyntheticName += "{a}"; + } break; + case dwarf::DW_TAG_thrown_type: { + SyntheticName += "{b}"; + } break; + case dwarf::DW_TAG_variant_part: { + SyntheticName += "{c}"; + } break; + case dwarf::DW_TAG_variable: { + SyntheticName += "{d}"; + } break; + case dwarf::DW_TAG_volatile_type: { + SyntheticName += "{e}"; + } break; + case dwarf::DW_TAG_dwarf_procedure: { + SyntheticName += "{f}"; + } break; + case dwarf::DW_TAG_restrict_type: { + SyntheticName += "{g}"; + } break; + case dwarf::DW_TAG_interface_type: { + SyntheticName += "{h}"; + } break; + case dwarf::DW_TAG_imported_module: { + SyntheticName += "{i}"; + } break; + case dwarf::DW_TAG_unspecified_type: { + SyntheticName += "{j}"; + } break; + case dwarf::DW_TAG_imported_unit: { + SyntheticName += "{k}"; + } break; + case dwarf::DW_TAG_condition: { + SyntheticName += "{l}"; + } break; + case dwarf::DW_TAG_shared_type: { + SyntheticName += "{m}"; + } break; + case dwarf::DW_TAG_rvalue_reference_type: { + SyntheticName += "{n}"; + } break; + case dwarf::DW_TAG_template_alias: { + SyntheticName += "{o}"; + } break; + case dwarf::DW_TAG_coarray_type: { + SyntheticName += "{p}"; + } break; + case dwarf::DW_TAG_generic_subrange: { + SyntheticName += "{q}"; + } break; + case dwarf::DW_TAG_dynamic_type: { + SyntheticName += "{r}"; + } break; + case dwarf::DW_TAG_atomic_type: { + SyntheticName += "{s}"; + } break; + case dwarf::DW_TAG_call_site: { + SyntheticName += "{t}"; + } break; + case dwarf::DW_TAG_call_site_parameter: { + SyntheticName += "{u}"; + } break; + case dwarf::DW_TAG_immutable_type: { + SyntheticName += "{v}"; + } break; + case dwarf::DW_TAG_entry_point: { + SyntheticName += "{w}"; + } break; + case dwarf::DW_TAG_label: { + SyntheticName += "{x}"; + } break; + case dwarf::DW_TAG_lexical_block: { + SyntheticName += "{y}"; + } break; + case dwarf::DW_TAG_common_block: { + SyntheticName += "{z}"; + } break; + case dwarf::DW_TAG_common_inclusion: { + SyntheticName += "{|}"; + } break; + case dwarf::DW_TAG_try_block: { + SyntheticName += "{~}"; + } break; + + case dwarf::DW_TAG_null: { + llvm_unreachable("No type prefix for DW_TAG_null"); + } break; + case dwarf::DW_TAG_compile_unit: { + llvm_unreachable("No type prefix for DW_TAG_compile_unit"); + } break; + case dwarf::DW_TAG_partial_unit: { + llvm_unreachable("No type prefix for DW_TAG_partial_unit"); + } break; + case dwarf::DW_TAG_type_unit: { + llvm_unreachable("No type prefix for DW_TAG_type_unit"); + } break; + case dwarf::DW_TAG_skeleton_unit: { + llvm_unreachable("No type prefix for DW_TAG_skeleton_unit"); + } break; + + default: { + SyntheticName += "{~~"; + SyntheticName += utohexstr(DieEntry->getTag()); + SyntheticName += "}"; + } break; + } +} + +OrderedChildrenIndexAssigner::OrderedChildrenIndexAssigner( + CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry) { + switch (DieEntry->getTag()) { + case dwarf::DW_TAG_array_type: + case dwarf::DW_TAG_coarray_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_common_block: + case dwarf::DW_TAG_lexical_block: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_subprogram: + case dwarf::DW_TAG_subroutine_type: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_GNU_template_template_param: + case dwarf::DW_TAG_GNU_formal_parameter_pack: { + NeedCountChildren = true; + } break; + case dwarf::DW_TAG_enumeration_type: { + // TODO : do we need to add condition + NeedCountChildren = true; + } break; + default: { + // Nothing to do. + } + } + + // Calculate maximal index value + if (NeedCountChildren) { + for (const DWARFDebugInfoEntry *CurChild = CU.getFirstChildEntry(DieEntry); + CurChild && CurChild->getAbbreviationDeclarationPtr(); + CurChild = CU.getSiblingEntry(CurChild)) { + std::optional ArrayIndex = tagToArrayIndex(CU, CurChild); + if (!ArrayIndex) + continue; + + assert((*ArrayIndex < ChildIndexesWidth.size()) && + "Wrong index for ChildIndexesWidth"); + ChildIndexesWidth[*ArrayIndex]++; + } + + // Calculate index field width(number of digits in hexadecimal + // representation). + for (size_t &Width : ChildIndexesWidth) { + size_t digitsCounter = 1; + size_t NumToCompare = 15; + + while (NumToCompare < Width) { + NumToCompare <<= 4; + digitsCounter++; + } + + Width = digitsCounter; + } + } +} + +std::optional OrderedChildrenIndexAssigner::tagToArrayIndex( + CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry) { + if (!NeedCountChildren) + return std::nullopt; + + switch (DieEntry->getTag()) { + case dwarf::DW_TAG_unspecified_parameters: + case dwarf::DW_TAG_formal_parameter: + return 0; + case dwarf::DW_TAG_template_value_parameter: + case dwarf::DW_TAG_template_type_parameter: + return 1; + case dwarf::DW_TAG_enumeration_type: + if (std::optional ParentIdx = DieEntry->getParentIdx()) { + if (*ParentIdx && CU.getDebugInfoEntry(*ParentIdx)->getTag() == + dwarf::DW_TAG_array_type) + return 2; + } + return std::nullopt; + case dwarf::DW_TAG_subrange_type: + return 3; + case dwarf::DW_TAG_generic_subrange: + return 4; + case dwarf::DW_TAG_enumerator: + return 5; + case dwarf::DW_TAG_namelist_item: + return 6; + case dwarf::DW_TAG_member: + return 7; + default: + return std::nullopt; + }; +} + +std::optional> +OrderedChildrenIndexAssigner::getChildIndex( + CompileUnit &CU, const DWARFDebugInfoEntry *ChildDieEntry) { + std::optional ArrayIndex = tagToArrayIndex(CU, ChildDieEntry); + if (!ArrayIndex) + return std::nullopt; + + assert((*ArrayIndex < OrderedChildIdxs.size()) && + "Wrong index for ChildIndexesWidth"); + assert(ChildIndexesWidth[*ArrayIndex] < 16 && + "Index width exceeds 16 digits."); + + std::pair Result = std::make_pair( + OrderedChildIdxs[*ArrayIndex], ChildIndexesWidth[*ArrayIndex]); + OrderedChildIdxs[*ArrayIndex]++; + return Result; +} + +} // end of namespace dwarflinker_parallel +} // namespace llvm diff --git a/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h new file mode 100644 index 00000000000000..c9dce4e94fb0dc --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/SyntheticTypeNameBuilder.h @@ -0,0 +1,155 @@ +//===- SyntheticTypeNameBuilder.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===/ + +#ifndef LLVM_LIB_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H +#define LLVM_LIB_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H + +#include "DWARFLinkerCompileUnit.h" +#include "DWARFLinkerGlobalData.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" + +namespace llvm { +class DWARFDebugInfoEntry; + +namespace dwarflinker_parallel { +struct LinkContext; +class TypeTableUnit; +class CompileUnit; + +/// The helper class to build type name based on DIE properties. +/// It builds synthetic name based on explicit attributes: DW_AT_name, +/// DW_AT_linkage_name or based on implicit attributes(DW_AT_decl*). +/// Names for specific DIEs(like subprograms, template classes...) include +/// additional attributes: subprogram parameters, template parameters, +/// array ranges. Examples of built name: +/// +/// class A { } : {8}A +/// +/// namspace llvm { class A { } } : {1}llvm{8}A +/// +/// template structure B { } : {F}B<{0}int> +/// +/// void foo ( int p1, float p3 ) : {a}void foo({0}int, {0}int) +/// +/// int *ptr; : {c}ptr {0}int +/// +/// int var; : {d}var +/// +/// These names is used to refer DIEs describing types. +class SyntheticTypeNameBuilder { +public: + SyntheticTypeNameBuilder(TypePool &TypePoolRef) : TypePoolRef(TypePoolRef) {} + + /// Create synthetic name for the specified DIE \p InputUnitEntryPair + /// and assign created name to the DIE type info. \p ChildIndex is used + /// to create name for ordered DIEs(function arguments f.e.). + Error assignName(UnitEntryPairTy InputUnitEntryPair, + std::optional> ChildIndex); + +protected: + /// Add array type dimension. + void addArrayDimension(UnitEntryPairTy InputUnitEntryPair); + + /// Add signature( entry type plus type of parameters plus type of template + /// parameters(if \p addTemplateParameters is true). + Error addSignature(UnitEntryPairTy InputUnitEntryPair, + bool addTemplateParameters); + + /// Add specified \p FunctionParameters to the built name. + Error addParamNames( + CompileUnit &CU, + SmallVector &FunctionParameters); + + /// Add specified \p TemplateParameters to the built name. + Error addTemplateParamNames( + CompileUnit &CU, + SmallVector &TemplateParameters); + + /// Add ordered name to the built name. + void addOrderedName(CompileUnit &CU, const DWARFDebugInfoEntry *DieEntry); + + /// Analyze \p InputUnitEntryPair's ODR attributes and put names + /// of the referenced type dies to the built name. + Error addReferencedODRDies(UnitEntryPairTy InputUnitEntryPair, + bool AssignNameToTypeDescriptor, + ArrayRef ODRAttrs); + + /// Add names of parent dies to the built name. + Error addParentName(UnitEntryPairTy &InputUnitEntryPair); + + /// \returns synthetic name of the specified \p DieEntry. + /// The name is constructed from the dwarf::DW_AT_decl_file + /// and dwarf::DW_AT_decl_line attributes. + void addDieNameFromDeclFileAndDeclLine(UnitEntryPairTy &InputUnitEntryPair, + bool &HasDeclFileName); + + /// Add type prefix to the built name. + void addTypePrefix(const DWARFDebugInfoEntry *DieEntry); + + /// Add type name to the built name. + Error addTypeName(UnitEntryPairTy InputUnitEntryPair, bool AddParentNames); + + /// Analyze \p InputUnitEntryPair for the type name and possibly assign + /// built type name to the DIE's type info. + /// NOTE: while analyzing types we may create different kind of names + /// for the same type depending on whether the type is part of another type. + /// f.e. DW_TAG_formal_parameter would receive "{02}01" name when + /// examined alone. Or "{0}int" name when it is a part of a function name: + /// {a}void foo({0}int). The \p AssignNameToTypeDescriptor tells whether + /// the type name is part of another type name and then should not be assigned + /// to DIE type descriptor. + Error addDIETypeName(UnitEntryPairTy InputUnitEntryPair, + std::optional> ChildIndex, + bool AssignNameToTypeDescriptor); + + /// Add ordered name to the built name. + void addOrderedName(std::pair ChildIdx); + + /// Add value name to the built name. + void addValueName(UnitEntryPairTy InputUnitEntryPair, dwarf::Attribute Attr); + + /// Buffer keeping bult name. + SmallString<1000> SyntheticName; + + /// Recursion counter + size_t RecursionDepth = 0; + + /// Type pool + TypePool &TypePoolRef; +}; + +/// This class helps to assign indexes for DIE children. +/// Indexes are used to create type name for children which +/// should be presented in the original order(function parameters, +/// array dimensions, enumeration members, class/structure members). +class OrderedChildrenIndexAssigner { +public: + OrderedChildrenIndexAssigner(CompileUnit &CU, + const DWARFDebugInfoEntry *DieEntry); + + /// Returns index of the specified child and width of hexadecimal + /// representation. + std::optional> + getChildIndex(CompileUnit &CU, const DWARFDebugInfoEntry *ChildDieEntry); + +protected: + using OrderedChildrenIndexesArrayTy = std::array; + + std::optional tagToArrayIndex(CompileUnit &CU, + const DWARFDebugInfoEntry *DieEntry); + + bool NeedCountChildren = false; + OrderedChildrenIndexesArrayTy OrderedChildIdxs = {0}; + OrderedChildrenIndexesArrayTy ChildIndexesWidth = {0}; +}; + +} // end namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_LIB_DWARFLINKERNEXT_SYNTHETICTYPENAMEBUILDER_H diff --git a/llvm/lib/DWARFLinkerParallel/TypePool.h b/llvm/lib/DWARFLinkerParallel/TypePool.h new file mode 100644 index 00000000000000..bbb3261027ce89 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/TypePool.h @@ -0,0 +1,177 @@ +//===- TypePool.h -----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DWARFLINKERPARALLEL_TYPEPOOL_H +#define LLVM_DWARFLINKERPARALLEL_TYPEPOOL_H + +#include "ArrayList.h" +#include "llvm/ADT/ConcurrentHashtable.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/Support/Allocator.h" +#include + +namespace llvm { +namespace dwarflinker_parallel { + +class TypePool; +class CompileUnit; +class TypeEntryBody; + +using TypeEntry = StringMapEntry>; + +/// Keeps cloned data for the type DIE. +class TypeEntryBody { +public: + /// Returns copy of type DIE which should be emitted into resulting file. + DIE &getFinalDie() const { + if (Die) + return *Die; + + assert(DeclarationDie); + return *DeclarationDie; + } + + /// Returns true if type die entry has only declaration die. + bool hasOnlyDeclaration() const { return Die == nullptr; } + + /// Creates type DIE for the specified name. + static TypeEntryBody *create(parallel::PerThreadBumpPtrAllocator &Allocator) { + TypeEntryBody *Result = Allocator.Allocate(); + new (Result) TypeEntryBody(Allocator); + return Result; + } + + /// TypeEntryBody keeps partially cloned DIEs corresponding to this type. + /// The two kinds of DIE can be kept: declaration and definition. + /// If definition DIE was met while parsing input DWARF then this DIE would + /// be used as a final DIE for this type. If definition DIE is not met then + /// declaration DIE would be used as a final DIE. + + // Keeps definition die. + std::atomic Die = {nullptr}; + + // Keeps declaration die. + std::atomic DeclarationDie = {nullptr}; + + // True if parent type die is declaration. + std::atomic ParentIsDeclaration = {true}; + + /// Children for current type. + ArrayList Children; + +protected: + TypeEntryBody() = delete; + TypeEntryBody(const TypeEntryBody &RHS) = delete; + TypeEntryBody(TypeEntryBody &&RHS) = delete; + TypeEntryBody &operator=(const TypeEntryBody &RHS) = delete; + TypeEntryBody &operator=(const TypeEntryBody &&RHS) = delete; + + TypeEntryBody(parallel::PerThreadBumpPtrAllocator &Allocator) + : Children(&Allocator) {} +}; + +class TypeEntryInfo { +public: + /// \returns Hash value for the specified \p Key. + static inline uint64_t getHashValue(const StringRef &Key) { + return xxh3_64bits(Key); + } + + /// \returns true if both \p LHS and \p RHS are equal. + static inline bool isEqual(const StringRef &LHS, const StringRef &RHS) { + return LHS == RHS; + } + + /// \returns key for the specified \p KeyData. + static inline StringRef getKey(const TypeEntry &KeyData) { + return KeyData.getKey(); + } + + /// \returns newly created object of KeyDataTy type. + static inline TypeEntry * + create(const StringRef &Key, parallel::PerThreadBumpPtrAllocator &Allocator) { + return TypeEntry::create(Key, Allocator); + } +}; + +/// TypePool keeps type descriptors which contain partially cloned DIE +/// correspinding to each type. Types are identified by names. +class TypePool : ConcurrentHashTableByPtr { +public: + TypePool() + : ConcurrentHashTableByPtr(Allocator) { + Root = TypeEntry::create("", Allocator); + Root->getValue().store(TypeEntryBody::create(Allocator)); + } + + TypeEntry *insert(StringRef Name) { + return ConcurrentHashTableByPtr::insert(Name) + .first; + } + + /// Create or return existing type entry body for the specified \p Entry. + /// Link that entry as child for the specified \p ParentEntry. + /// \returns The existing or created type entry body. + TypeEntryBody *getOrCreateTypeEntryBody(TypeEntry *Entry, + TypeEntry *ParentEntry) { + TypeEntryBody *DIE = Entry->getValue().load(); + if (DIE) + return DIE; + + TypeEntryBody *NewDIE = TypeEntryBody::create(Allocator); + if (Entry->getValue().compare_exchange_weak(DIE, NewDIE)) { + ParentEntry->getValue().load()->Children.add(Entry); + return NewDIE; + } + + return DIE; + } + + /// Sort children for each kept type entry. + void sortTypes() { + std::function SortChildrenRec = + [&](TypeEntry *Entry) { + Entry->getValue().load()->Children.sort(TypesComparator); + Entry->getValue().load()->Children.forEach(SortChildrenRec); + }; + + SortChildrenRec(getRoot()); + } + + /// Return root for all type entries. + TypeEntry *getRoot() const { return Root; } + + /// Return thread local allocator used by pool. + BumpPtrAllocator &getThreadLocalAllocator() { + return Allocator.getThreadLocalAllocator(); + } + +protected: + std::function + TypesComparator = [](const TypeEntry *LHS, const TypeEntry *RHS) -> bool { + return LHS->getKey() < RHS->getKey(); + }; + + // Root of all type entries. + TypeEntry *Root = nullptr; + +private: + parallel::PerThreadBumpPtrAllocator Allocator; +}; + +} // end of namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_DWARFLINKERPARALLEL_TYPEPOOL_H diff --git a/llvm/lib/DWARFLinkerParallel/Utils.h b/llvm/lib/DWARFLinkerParallel/Utils.h new file mode 100644 index 00000000000000..91f9dca46a82b1 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/Utils.h @@ -0,0 +1,40 @@ +//===- Utils.h --------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_DWARFLINKERPARALLEL_UTILS_H +#define LLVM_LIB_DWARFLINKERPARALLEL_UTILS_H + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace dwarflinker_parallel { + +/// This function calls \p Iteration() until it returns false. +/// If number of iterations exceeds \p MaxCounter then an Error is returned. +/// This function should be used for loops which assumed to have number of +/// iterations significantly smaller than \p MaxCounter to avoid infinite +/// looping in error cases. +inline Error finiteLoop(function_ref()> Iteration, + size_t MaxCounter = 100000) { + size_t iterationsCounter = 0; + while (iterationsCounter++ < MaxCounter) { + Expected IterationResultOrError = Iteration(); + if (!IterationResultOrError) + return IterationResultOrError.takeError(); + + if (!IterationResultOrError.get()) + return Error::success(); + } + + return createStringError(std::errc::invalid_argument, "Infinite recursion"); +} + +} // end of namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_LIB_DWARFLINKERPARALLEL_UTILS_H diff --git a/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test b/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test new file mode 100644 index 00000000000000..3f75991cdc471e --- /dev/null +++ b/llvm/test/tools/dsymutil/ARM/DWARFLinkerParallel/accel-imported-declarations.test @@ -0,0 +1,80 @@ +RUN: dsymutil --linker llvm -accelerator=Dwarf \ +RUN: -oso-prepend-path=%p/../../Inputs \ +RUN: %p/../../Inputs/accel-imported-declaration.macho-arm64 -o %t.dwarf.dSYM +RUN: dsymutil --linker llvm -accelerator=Apple \ +RUN: -oso-prepend-path=%p/../../Inputs \ +RUN: %p/../../Inputs/accel-imported-declaration.macho-arm64 -o %t.apple.dSYM + +RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON +RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON + +COMMON: .debug_info contents +COMMON: DW_TAG_compile_unit +COMMON: DW_AT_name{{.*}}"__artificial_type_unit" +COMMON: DW_TAG_base_type +COMMON: DW_AT_name{{.*}}"int" +COMMON: DW_TAG_namespace +COMMON: DW_AT_name{{.*}}"A" +COMMON: DW_TAG_namespace +COMMON: DW_AT_name{{.*}}"B" +COMMON: 0x[[NAMESPACE_C_1:[0-9a-f]*]]: DW_TAG_namespace +COMMON: DW_AT_name{{.*}}"C" +COMMON-NOT: DW_TAG_variable +COMMON: 0x[[NAMESPACE_C_2:[0-9a-f]*]]: DW_TAG_imported_declaration +COMMON: DW_AT_import{{.*}}[[NAMESPACE_C_1]] +COMMON: DW_AT_name{{.*}}"C" +COMMON: DW_TAG_imported_module +COMMON: DW_AT_import{{.*}}[[NAMESPACE_C_1]] + + +COMMON: DW_TAG_compile_unit +COMMON: {{.*}}DW_TAG_namespace +COMMON: DW_AT_name{{.*}}"A" +COMMON: {{.*}}DW_TAG_namespace +COMMON: DW_AT_name{{.*}}"B" +COMMON: 0x[[NAMESPACE_C_3:[0-9a-f]*]]: DW_TAG_namespace +COMMON: DW_AT_name{{.*}}"C" +COMMON: 0x[[VAR_A:[0-9a-f]*]]: DW_TAG_variable +COMMON: DW_TAG_imported_declaration +COMMON: DW_AT_import{{.*}}[[VAR_A]] + +DWARF: .debug_names contents: +DWARF: Bucket 0 [ +DWARF-NEXT: Name {{.*}} { +DWARF-NEXT: Hash: {{.*}} +DWARF-NEXT: String: {{.*}} "C" +DWARF-NEXT: Entry {{.*}} { +DWARF-NEXT: Abbrev: {{.*}} +DWARF-NEXT: Tag: DW_TAG_namespace +DWARF: DW_IDX_die_offset: 0x0000002f +DWARF-NEXT: } +DWARF-NEXT: Entry {{.*}} { +DWARF-NEXT: Abbrev: {{.*}} +DWARF: Tag: DW_TAG_imported_declaration +DWARF: DW_IDX_die_offset: 0x00000035 +DWARF-NEXT: } +DWARF-NEXT: Entry {{.*}} { +DWARF-NEXT: Abbrev: {{.*}} +DWARF-NEXT: Tag: DW_TAG_namespace +DWARF: DW_IDX_die_offset: 0x0000003c +DWARF-NEXT: } + +DWARF-NEXT: } + +APPLE: .apple_namespaces contents: +APPLE: Bucket 1 [ +APPLE-NEXT: Hash {{.*}} [ +APPLE-NEXT: Name@{{.*}} { +APPLE-NEXT: String: {{.*}} "C" +APPLE-NEXT: Data 0 [ +APPLE-NEXT: Atom[0]: 0x[[NAMESPACE_C_1]] +APPLE-NEXT: ] +APPLE-NEXT: Data 1 [ +APPLE-NEXT: Atom[0]: 0x[[NAMESPACE_C_2]] +APPLE-NEXT: ] +APPLE-NEXT: Data 2 [ +APPLE-NEXT: Atom[0]: 0x[[NAMESPACE_C_3]] +APPLE-NEXT: ] +APPLE: } +APPLE-NEXT: ] +APPLE-NEXT: ] diff --git a/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test b/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test index f1680ced6e5b4f..057e89d060b1d2 100644 --- a/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test +++ b/llvm/test/tools/dsymutil/ARM/accel-imported-declarations.test @@ -4,14 +4,6 @@ RUN: dsymutil -accelerator=Apple -oso-prepend-path=%p/../Inputs %p/../Inputs/acc RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON -RUN: dsymutil --linker llvm -accelerator=Dwarf -oso-prepend-path=%p/../Inputs \ -RUN: %p/../Inputs/accel-imported-declaration.macho-arm64 -o %t.dwarf.dSYM -RUN: dsymutil --linker llvm -accelerator=Apple -oso-prepend-path=%p/../Inputs \ -RUN: %p/../Inputs/accel-imported-declaration.macho-arm64 -o %t.apple.dSYM - -RUN: llvm-dwarfdump -v %t.dwarf.dSYM | FileCheck %s -check-prefixes=DWARF,COMMON -RUN: llvm-dwarfdump -v %t.apple.dSYM | FileCheck %s -check-prefixes=APPLE,COMMON - COMMON: .debug_info contents COMMON: {{.*}}DW_TAG_namespace COMMON: DW_AT_name{{.*}}"A" @@ -19,7 +11,7 @@ COMMON: {{.*}}DW_TAG_namespace COMMON: DW_AT_name{{.*}}"B" COMMON: [[NAMESPACE:0x[0-9a-f]*]]:{{.*}}DW_TAG_namespace COMMON: DW_AT_name{{.*}}"C" -COMMON: [[IMPORTED:0x[0-9a-f]*]]:{{.*}}DW_TAG_imported_declaration +COMMON: 0x0000005c:{{.*}}DW_TAG_imported_declaration COMMON: DW_AT_name{{.*}}"C" DWARF: .debug_names contents: @@ -30,12 +22,12 @@ DWARF-NEXT: String: {{.*}} "C" DWARF-NEXT: Entry {{.*}} { DWARF-NEXT: Abbrev: {{.*}} DWARF-NEXT: Tag: DW_TAG_namespace -DWARF-NEXT: DW_IDX_die_offset: [[NAMESPACE]] +DWARF: DW_IDX_die_offset: [[NAMESPACE]] DWARF-NEXT: } DWARF-NEXT: Entry {{.*}} { DWARF-NEXT: Abbrev: {{.*}} -DWARF-NEXT: Tag: DW_TAG_imported_declaration -DWARF-NEXT: DW_IDX_die_offset: [[IMPORTED]] +DWARF: Tag: DW_TAG_imported_declaration +DWARF: DW_IDX_die_offset: 0x0000005c DWARF-NEXT: } DWARF-NEXT: } @@ -48,8 +40,8 @@ APPLE-NEXT: Data 0 [ APPLE-NEXT: Atom[0]: [[NAMESPACE]] APPLE-NEXT: ] APPLE-NEXT: Data 1 [ -APPLE-NEXT: Atom[0]: [[IMPORTED]] +APPLE-NEXT: Atom[0]: {{0x0000005c|0x0000006f}} APPLE-NEXT: ] -APPLE-NEXT: } +APPLE: } APPLE-NEXT: ] APPLE-NEXT: ] diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test b/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test index 00dcde718e3622..ca4a951e770ba2 100644 --- a/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test +++ b/llvm/test/tools/dsymutil/ARM/dwarf5-addr-base.test @@ -50,15 +50,30 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s RUN: rm -rf %t.dir && mkdir -p %t.dir -RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \ +RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \ RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \ RUN: -o %t.dir/dwarf5-addr-base.dSYM RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s +RUN: rm -rf %t.dir && mkdir -p %t.dir +RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \ +RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \ +RUN: -o %t.dir/dwarf5-addr-base.dSYM +RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \ +RUN: FileCheck %s --check-prefixes=CHECK,CHECK-LLVM + + RUN: rm -rf %t.dir && mkdir -p %t.dir RUN: dsymutil --update -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefix=UPD +RUN: rm -rf %t.dir && mkdir -p %t.dir +RUN: dsymutil --linker llvm --no-odr --update -y %p/dummy-debug-map-amr64.map \ +RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \ +RUN: -o %t.dir/dwarf5-addr-base.dSYM +RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \ +RUN: FileCheck %s --check-prefix=UPD + RUN: rm -rf %t.dir && mkdir -p %t.dir RUN: dsymutil --linker llvm --update -y %p/dummy-debug-map-amr64.map \ RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \ @@ -66,30 +81,36 @@ RUN: -o %t.dir/dwarf5-addr-base.dSYM RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \ RUN: FileCheck %s --check-prefix=UPD + CHECK: .debug_info contents: -CHECK-NEXT: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 -CHECK: 0x0000000c: DW_TAG_compile_unit [1] * -CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008) +CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 +CHECK-LLVM: DW_TAG_compile_unit +CHECK-LLVM: DW_TAG_base_type + +CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 + +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008) -CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c) +CHECK: DW_TAG_subprogram CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[ADDR1:[0-9a-f]+]]) -CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08 +CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 -CHECK: 0x0000005a: DW_TAG_compile_unit [1] * +CHECK: DW_TAG_compile_unit CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000018) -CHECK: 0x0000007a: DW_TAG_subprogram [2] * (0x0000005a) +CHECK: DW_TAG_subprogram CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[ADDR2:[0-9a-f]+]]) -CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|b4}}, addr_size = 0x08 +CHECK: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 -CHECK: 0x000000a8: DW_TAG_compile_unit {{.*}} * +CHECK: DW_TAG_compile_unit CHECK: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000028) -CHECK: 0x000000c1: DW_TAG_subprogram [2] * (0x000000a8) +CHECK: DW_TAG_subprogram CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[ADDR3:[0-9a-f]+]]) CHECK: .debug_addr contents: diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test b/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test index 324a156484119f..0199bf28681bc4 100644 --- a/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test +++ b/llvm/test/tools/dsymutil/ARM/dwarf5-dwarf4-combination-macho.test @@ -34,17 +34,31 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM -a --verbose | FileCheck %s RUN: rm -rf %t.dir && mkdir -p %t.dir -RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \ +RUN: dsymutil --no-odr --linker llvm -y %p/dummy-debug-map-amr64.map \ RUN: -oso-prepend-path=%p/../Inputs/DWARF5-DWARF4-combination \ RUN: -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM RUN: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM \ RUN: -a --verbose | FileCheck %s +### Uncomment following when llvm-dwarfdump will dump address ranges +### correctly for severall compile units case. +COM: rm -rf %t.dir && mkdir -p %t.dir +COM: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \ +COM: -oso-prepend-path=%p/../Inputs/DWARF5-DWARF4-combination \ +COM: -o %t.dir/dwarf5-dwarf4-combination-macho.dSYM +COM: llvm-dwarfdump %t.dir/dwarf5-dwarf4-combination-macho.dSYM \ +COM: -a --verbose | FileCheck %s --check-prefixes=CHECK,CHECK-LLVM + + CHECK:.debug_abbrev contents: CHECK-NEXT: Abbrev table for offset: 0x00000000 CHECK: .debug_info contents: -CHECK: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 +CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 +CHECK-LLVM: DW_TAG_compile_unit +CHECK-LLVM: DW_TAG_base_type + +CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 14.0.3 (clang-1403.0.22.14.1)") CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000001) string = "a.cpp") CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk") @@ -54,17 +68,17 @@ CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/sh CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[RANGELIST_OFFSET:[0-9a-f]+]] CHECK-NEXT: [0x[[RANGELIST_OFFSET_START:[0-9a-f]+]], 0x[[RANGELIST_OFFSET_END:[0-9a-f]+]])) CHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008) -CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c) +CHECK: DW_TAG_subprogram CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[#%.16x,LOCLIST_LOWPC:]]) CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000005) string = "_Z4foo2i") CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000006) string = "foo2") -CHECK: 0x0000003c: DW_TAG_formal_parameter [3] (0x0000002c) +CHECK: DW_TAG_formal_parameter CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOCLIST_OFFSET:[0-9a-f]+]]: CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START:]], 0x[[#%.16x,LOCLIST_PAIR_END:]]): [[LOCLIST_EXPR:.*]] CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START2:]], 0x[[#%.16x,LOCLIST_PAIR_END2:]]): [[LOCLIST_EXPR2:.*]]) CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000007) string = "a") -CHECK: 0x0000004e: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08 +CHECK: Compile Unit: length = 0x00000072, format = DWARF32, version = 0x0004, abbr_offset = {{.*}}, addr_size = 0x08 CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple clang version 14.0.3 (clang-1403.0.22.14.1)") CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000e0] = "b.cpp") CHECK: DW_AT_LLVM_sysroot [DW_FORM_strp] ( .debug_str[0x00000039] = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk") @@ -74,11 +88,11 @@ CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x000000a3] = "/Users/shub CHECK: DW_AT_low_pc [DW_FORM_addr] (0x[[#%.16x,RANGE_LOWPC:]]) CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000 CHECK-NEXT: [0x[[#%.16x,RANGE_START:]], 0x[[#%.16x,RANGE_END:]])) -CHECK: 0x00000080: DW_TAG_subprogram {{.*}} * (0x00000059) +CHECK: DW_TAG_subprogram CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x[[#%.16x,LOC_LOWPC:]]) CHECK: DW_AT_linkage_name [DW_FORM_strp] ( .debug_str[0x000000e6] = "_Z3bari") CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x000000ee] = "bar") -CHECK: 0x0000009d: DW_TAG_formal_parameter {{.*}} (0x00000080) +CHECK: DW_TAG_formal_parameter CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOC_OFFSET:[0-9a-f]+]]: CHECK-NEXT: [0x[[#%.16x,LOC_PAIR_START:]], 0x[[#%.16x,LOC_PAIR_END:]]): [[LOC_EXPR:.*]] CHECK-NEXT: [0x[[#%.16x,LOC_PAIR_START2:]], 0x[[#%.16x,LOC_PAIR_END2:]]): [[LOC_EXPR2:.*]]) diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test b/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test index 3008db9a0d63c2..13409b2a07a31f 100644 --- a/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test +++ b/llvm/test/tools/dsymutil/ARM/dwarf5-macho.test @@ -22,21 +22,33 @@ RUN: dsymutil -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWA RUN: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s RUN: rm -rf %t.dir && mkdir -p %t.dir -RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \ +RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \ RUN: -oso-prepend-path=%p/../Inputs/DWARF5 -o %t.dir/dwarf5-macho.dSYM RUN: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s +### Uncomment following when llvm-dwarfdump will print resolved address ranges +### for the case mutiplue compile units. +COM: rm -rf %t.dir && mkdir -p %t.dir +COM: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \ +COM: -oso-prepend-path=%p/../Inputs/DWARF5 -o %t.dir/dwarf5-macho.dSYM +COM: llvm-dwarfdump %t.dir/dwarf5-macho.dSYM -a --verbose | FileCheck %s \ +COM: --check-prefixes=CHECK,CHECK-LLVM + + CHECK:.debug_abbrev contents: CHECK-NEXT: Abbrev table for offset: 0x00000000 CHECK: .debug_info contents: -CHECK-NEXT: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 +CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 +CHECK-LLVM: DW_TAG_compile_unit +CHECK-LLVM: DW_TAG_base_type +CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[RANGELIST_OFFSET:[0-9a-f]+]] CHECK-NEXT: [0x[[RANGELIST_OFFSET_START:[0-9a-f]+]], 0x[[RANGELIST_OFFSET_END:[0-9a-f]+]])) CHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008) -CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c) +CHECK: DW_TAG_subprogram CHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x[[#%.16x,LOCLIST_LOWPC:]]) -CHECK: 0x0000003c: DW_TAG_formal_parameter [3] (0x0000002c) +CHECK: DW_TAG_formal_parameter CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x[[LOC_OFFSET:[0-9a-f]+]]: CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START:]], 0x[[#%.16x,LOCLIST_PAIR_END:]]): [[LOCLIST_EXPR:.*]] CHECK-NEXT: [0x[[#%.16x,LOCLIST_PAIR_START2:]], 0x[[#%.16x,LOCLIST_PAIR_END2:]]): [[LOCLIST_EXPR2:.*]]) diff --git a/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test b/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test index ac813fc6203708..73decc497ea36e 100644 --- a/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test +++ b/llvm/test/tools/dsymutil/ARM/dwarf5-str-offsets-base-strx.test @@ -56,21 +56,40 @@ RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --c RUN: dsymutil --update -y %p/dummy-debug-map-amr64.map -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base -o %t.dir/dwarf5-addr-base.dSYM RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=UPD,GLOBALUPD +RUN: rm -rf %t.dir && mkdir -p %t.dir +RUN: dsymutil --linker llvm --no-odr -y %p/dummy-debug-map-amr64.map \ +RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \ +RUN: -o %t.dir/dwarf5-addr-base.dSYM +RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \ +RUN: FileCheck %s --check-prefixes=CHECK,LOCAL + RUN: rm -rf %t.dir && mkdir -p %t.dir RUN: dsymutil --linker llvm -y %p/dummy-debug-map-amr64.map \ RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \ RUN: -o %t.dir/dwarf5-addr-base.dSYM -RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=CHECK,LOCAL +RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \ +RUN: FileCheck %s --check-prefixes=CHECK,LOCAL,CHECK-LLVM + +RUN: dsymutil --linker llvm --no-odr --update -y %p/dummy-debug-map-amr64.map \ +RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \ +RUN: -o %t.dir/dwarf5-addr-base.dSYM +RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \ +RUN: FileCheck %s --check-prefixes=UPD,LOCALUPD RUN: dsymutil --linker llvm --update -y %p/dummy-debug-map-amr64.map \ RUN: -oso-prepend-path=%p/../Inputs/DWARF5-addr-base-str-off-base \ RUN: -o %t.dir/dwarf5-addr-base.dSYM -RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | FileCheck %s --check-prefixes=UPD,LOCALUPD +RUN: llvm-dwarfdump %t.dir/dwarf5-addr-base.dSYM -a --verbose | \ +RUN: FileCheck %s --check-prefixes=UPD,LOCALUPD + CHECK: .debug_info contents: -CHECK: 0x00000000: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x0000004e) +CHECK-LLVM: Compile Unit: length = 0x0000001f, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 +CHECK-LLVM: DW_TAG_compile_unit +CHECK-LLVM: DW_TAG_base_type +CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 -CHECK: 0x0000000c: DW_TAG_compile_unit [1] * +CHECK: DW_TAG_compile_unit CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)") CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000001) string = "a.cpp") CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk") @@ -78,24 +97,24 @@ CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) strin CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485") -CHECK: 0x0000002c: DW_TAG_subprogram [2] * (0x0000000c) +CHECK: DW_TAG_subprogram CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000010000) CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (00000005) string = "_Z4foo2i") CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000006) string = "foo2") -CHECK: 0x0000003c: DW_TAG_formal_parameter [3] (0x0000002c) +CHECK: DW_TAG_formal_parameter CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000007) string = "a") -CHECK: 0x00000048: NULL +CHECK: NULL -CHECK: 0x00000049: DW_TAG_base_type [4] (0x0000000c) +CHECK: DW_TAG_base_type CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000008) string = "int") -CHECK: 0x0000004d: NULL +CHECK: NULL -CHECK: 0x0000004e: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|5a}}, addr_size = 0x08 (next unit at 0x0000009c) +CHECK: Compile Unit: length = 0x0000004a, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 -CHECK: 0x0000005a: DW_TAG_compile_unit [1] * +CHECK: DW_TAG_compile_unit CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)") CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{9|1}}) string = "b.cpp") CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk") @@ -103,23 +122,23 @@ CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) strin CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x000000{{08|34}}) CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485") -CHECK: 0x0000007a: DW_TAG_subprogram [2] * (0x0000005a) +CHECK: DW_TAG_subprogram CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (0000000{{a|5}}) string = "_Z4bar2i") CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{b|6}}) string = "bar2") -CHECK: 0x0000008a: DW_TAG_formal_parameter [3] (0x0000007a) +CHECK: DW_TAG_formal_parameter CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000007) string = "a") -CHECK: 0x00000096: NULL +CHECK: NULL -CHECK: 0x00000097: DW_TAG_base_type [4] (0x0000005a) +CHECK: DW_TAG_base_type CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000008) string = "int") -CHECK: 0x0000009b: NULL +CHECK: NULL -CHECK: 0x0000009c: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x00{{00|b4}}, addr_size = 0x08 (next unit at 0x000000e3) +CHECK: Compile Unit: length = 0x00000043, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = {{.*}}, addr_size = 0x08 -CHECK: 0x000000a8: DW_TAG_compile_unit {{.*}} * +CHECK: DW_TAG_compile_unit CHECK: DW_AT_producer [DW_FORM_strx] (indexed (00000000) string = "Apple clang version 15.0.0 (clang-1500.0.31.1)") CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{c|1}}) string = "c.cpp") CHECK: DW_AT_LLVM_sysroot [DW_FORM_strx] (indexed (00000002) string = "/Users/shubham/apple-internal/Xcode-Rainbow/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk") @@ -127,19 +146,19 @@ CHECK: DW_AT_APPLE_sdk [DW_FORM_strx] (indexed (00000003) strin CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x000000{{08|60}}) CHECK: DW_AT_comp_dir [DW_FORM_strx] (indexed (00000004) string = "/Users/shubham/Development/test109275485") -CHECK: 0x000000c1: DW_TAG_subprogram [2] * (0x000000a8) +CHECK: DW_TAG_subprogram CHECK: DW_AT_linkage_name [DW_FORM_strx] (indexed (0000000{{d|5}}) string = "_Z3bazi") CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{e|6}}) string = "baz") -CHECK: 0x000000d1: DW_TAG_formal_parameter [3] (0x000000c1) +CHECK: DW_TAG_formal_parameter CHECK: DW_AT_name [DW_FORM_strx] (indexed (0000000{{f|7}}) string = "x") -CHECK: 0x000000dd: NULL +CHECK: NULL -CHECK: 0x000000de: DW_TAG_base_type [4] (0x000000a8) +CHECK: DW_TAG_base_type CHECK: DW_AT_name [DW_FORM_strx] (indexed (00000008) string = "int") -CHECK: 0x000000e2: NULL +CHECK: NULL CHECK: .debug_str contents: CHECK-NEXT: 0x00000000: "" diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp new file mode 100644 index 00000000000000..a94d06f2ab64d2 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/dead-stripped.cpp @@ -0,0 +1,67 @@ +// RUN: dsymutil --linker llvm --no-odr -f -y %p/../dummy-debug-map.map -oso-prepend-path \ +// RUN: %p/../../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \ +// RUN: FileCheck %s --implicit-check-not \ +// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" +// +// RUN: dsymutil --linker llvm -f -y %p/../dummy-debug-map.map -oso-prepend-path \ +// RUN: %p/../../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | \ +// RUN: FileCheck %s --implicit-check-not \ +// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \ +// RUN: --check-prefixes=CHECK-LLVM + +// The test was compiled with: +// clang++ -O2 -g -c dead-strip.cpp -o 1.o + +// The goal of the test is to exercise dsymutil's behavior in presence of +// functions/variables that have been dead-stripped by the linker but +// that are still present in the linked debug info (in this case because +// they have been DW_TAG_import'd in another namespace). + +// CHECK-LLVM: DW_TAG_compile_unit +// CHECK-LLVM: DW_AT_name{{.*}}"__artificial_type_unit" +// CHECK-LLVM: DW_TAG_namespace +// CHECK-LLVM: DW_AT_name{{.*}}"N" +// CHECK-LLVM: NULL +// +// CHECK-LLVM: DW_TAG_compile_unit +// CHECK-LLVM: DW_AT_low_pc +// CHECK-LLVM: DW_AT_high_pc +// CHECK-LLVM: DW_TAG_base_type +// CHECK-LLVM: DW_TAG_imported_module +// CHECK-LLVM: DW_TAG_subprogram +// CHECK-LLVM: DW_AT_low_pc +// CHECK-LLVM: DW_AT_high_pc +// CHECK-LLVM: DW_TAG_base_type +// CHECK-LLVM: NULL + +// Everything in the N namespace below doesn't have a debug map entry, and +// thus is considered dead (::foo() has a debug map entry, otherwise dsymutil +// would just drop the CU altogether). + +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_TAG_namespace +namespace N { +int blah = 42; + +__attribute__((always_inline)) int foo() { return blah; } + +int bar(unsigned i) { + int val = foo(); + if (i) + return val + bar(i-1); + return foo(); +} +} +// CHECK: DW_TAG_base_type +// CHECK: DW_TAG_imported_module +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_TAG_base_type +// CHECK: NULL + +using namespace N; + +void foo() {} diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test new file mode 100644 index 00000000000000..b2d178cee0282c --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/empty-CU.test @@ -0,0 +1,5 @@ +RUN: llvm-mc %p/../../Inputs/empty-CU.s -filetype obj -triple x86_64-apple-darwin -o %t.o +RUN: dsymutil --linker llvm --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s + +CHECK: .debug_info contents: +CHECK-NOT: DW_TAG_compile_unit diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp new file mode 100644 index 00000000000000..97d7e630e7c672 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/inlined-static-variable.cpp @@ -0,0 +1,74 @@ +// RUN: dsymutil --linker llvm -f -y %p/../dummy-debug-map.map -oso-prepend-path \ +// RUN: %p/../../Inputs/inlined-static-variable -o - -keep-function-for-static | \ +// RUN: llvm-dwarfdump - | FileCheck %s --implicit-check-not \ +// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \ +// RUN: --check-prefixes=CHECK + +// clang -g -c inlined-static-variable.cpp -o 4.o + +// The functions removed and not_removed are not in the debug map and are +// considered dead, but they are also inlined into the function foo which is +// in the debug map. Those function-local globals are alive and thus should +// have locations in the debug info even if their functions do not. + +inline __attribute__((always_inline)) int removed() { + static int a = 0; + return ++a; +} + +__attribute__((always_inline)) int not_removed() { + static int b = 0; + return ++b; +} + +int unused() { + static int c = 0; + return ++c; +} + +int foo() { + return removed() + not_removed(); +} + +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_name{{.*}}"__artificial_type_unit" +// CHECK: DW_TAG_base_type +// CHECK: DW_AT_name{{.*}}"int" +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_name{{.*}}"not_removed" +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_name{{.*}}"removed" +// CHECK: NULL + +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_name{{.*}}"removed" +// CHECK-NOT: DW_AT_low_pc +// CHECK-NOT: DW_AT_low_pc +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name{{.*}}"a" +// CHECK: {{.*}}DW_OP_addr +// CHECK: NULL +// CHECK: DW_TAG_base_type +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_name{{.*}}"not_removed" +// CHECK-NOT: DW_AT_low_pc +// CHECK-NOT: DW_AT_low_pc +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name{{.*}}"b" +// CHECK: {{.*}}DW_OP_addr +// CHECK: NULL +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_AT_name ("foo") +// CHECK: DW_TAG_inlined_subroutine +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_TAG_inlined_subroutine +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: NULL +// CHECK: NULL diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test new file mode 100644 index 00000000000000..6d8757391d6c68 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/keep-func.test @@ -0,0 +1,36 @@ +$ cat main.cpp +#include + +static void Foo(void) +{ + typedef struct { + int x1; + int x2; + } FOO_VAR_TYPE; + static FOO_VAR_TYPE MyDummyVar __attribute__((aligned(4), used, section("TAD_VIRTUAL, TAD_DUMMY_DATA"), nocommon)); + printf("Foo called"); +} + +int main() +{ + Foo(); + return 1; +} + +$ clang++ -O2 -g main.cpp -c -o main.o +$ clang++ main.o -o main.out + +RUN: dsymutil --linker llvm -oso-prepend-path %p/../../Inputs %p/../../Inputs/private/tmp/keep_func/main.out -o %t.omit.dSYM +RUN: dsymutil --linker llvm -oso-prepend-path %p/../../Inputs %p/../../Inputs/private/tmp/keep_func/main.out -o %t.keep.dSYM -keep-function-for-static +RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT +RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP + +KEEP: DW_AT_name ("x1") +KEEP: DW_AT_name ("x2") +KEEP: DW_AT_name ("FOO_VAR_TYPE") +KEEP: DW_AT_name ("MyDummyVar") + +OMIT-NOT: DW_AT_name ("MyDummyVar") +OMIT-NOT: DW_AT_name ("FOO_VAR_TYPE") +OMIT-NOT: DW_AT_name ("x1") +OMIT-NOT: DW_AT_name ("x2") diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp new file mode 100644 index 00000000000000..16aacd57517bd2 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-anon-namespace.cpp @@ -0,0 +1,68 @@ +/* Compile with: + for FILE in `seq 2`; do + clang -g -c odr-anon-namespace.cpp -DFILE$FILE -o odr-anon-namespace/$FILE.o + done + */ + +// RUN: dsymutil --linker llvm -f \ +// RUN: -oso-prepend-path=%p/../../Inputs/odr-anon-namespace \ +// RUN: -y %p/../dummy-debug-map.map -o - | \ +// RUN: llvm-dwarfdump -debug-info - | FileCheck %s + +#ifdef FILE1 +// Currently dsymutil will unique the contents of anonymous +// namespaces if they are from the same file/line. Force this +// namespace to appear different eventhough it's the same (this +// uniquing is actually a bug kept for backward compatibility, see the +// comments in DeclContextTree::getChildDeclContext()). +#line 42 +#endif +namespace { +class C {}; +} + +void foo() { + C c; +} + +// Keep the ifdef guards for FILE1 and FILE2 even if all the code is +// above to clearly show what the CHECK lines are testing. +#ifdef FILE1 + +// CHECK: TAG_compile_unit +// CHECK-NOT: DW_TAG +// CHECK: AT_name{{.*}}"odr-anon-namespace.cpp" + +// CHECK: DW_TAG_variable +// CHECK-NOT: DW_TAG +// CHECK: DW_AT_name {{.*}}"c" +// CHECK-NOT: DW_TAG +// CHECK: DW_AT_type {{.*}}0x[[C_FILE1:[0-9a-f]*]] + +// CHECK: DW_TAG_namespace +// CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}} +// CHECK: 0x[[C_FILE1]]:{{.*}}DW_TAG_class_type +// CHECK-NOT: DW_TAG +// CHECK: DW_AT_name{{.*}}"C" + +#elif defined(FILE2) + +// CHECK: TAG_compile_unit +// CHECK-NOT: DW_TAG +// CHECK: AT_name{{.*}}"odr-anon-namespace.cpp" + +// CHECK: DW_TAG_variable +// CHECK-NOT: DW_TAG +// CHECK: DW_AT_name {{.*}}"c" +// CHECK-NOT: DW_TAG +// CHECK: DW_AT_type {{.*}}0x[[C_FILE2:[0-9a-f]*]] + +// CHECK: DW_TAG_namespace +// CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}} +// CHECK: 0x[[C_FILE2]]:{{.*}}DW_TAG_class_type +// CHECK-NOT: DW_TAG +// CHECK: DW_AT_name{{.*}}"C" + +#else +#error "You must define which file you generate" +#endif diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test new file mode 100644 index 00000000000000..3e8d8557689e36 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration.test @@ -0,0 +1,101 @@ +/* Compile with: + for FILE in `seq 3`; do + clang -g -c X86/odr-fwd-declaration.cpp -DFILE$FILE -o + Inputs/odr-fwd-declaration/$FILE.o done +*/ + +// RUN: dsymutil --linker=llvm -f \ +// RUN: -oso-prepend-path=%p/../../Inputs/odr-fwd-declaration \ +// RUN: -y %p/../dummy-debug-map.map -o %t1.out +// RUN: llvm-dwarfdump -v -debug-info %t1.out | FileCheck %s + +#ifdef FILE1 +# 1 "Header.h" 1 +typedef struct S *Sptr; +typedef Sptr *Sptrptr; +# 3 "Source1.cpp" 2 +void foo() { Sptrptr ptr1 = 0; } + +// First we confirm that types are in type table. +// +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_name{{.*}}"__artificial_type_unit" + +// CHECK: DW_TAG_base_type + +// CHECK: 0x[[PTR_S:[a-f0-9]*]]: DW_TAG_pointer_type +// CHECK-NEXT: DW_AT_type{{.*}}{0x[[STRUCT_S:[a-f0-9]*]]} "S" + +// CHECK: 0x[[PTR_PTR_S:[a-f0-9]*]]: DW_TAG_pointer_type +// CHECK-NEXT: DW_AT_type{{.*}}{0x[[TYPEDEF_PTR_S:[a-f0-9]*]]} "Sptr" + +// CHECK: 0x[[STRUCT_S]]: DW_TAG_structure_type +// CHECK-NEXT: DW_AT_name{{.*}}"S" + +// CHECK: DW_TAG_member +// CHECK-NEXT: DW_AT_name{{.*}}"field" + +// CHECK: 0x[[TYPEDEF_PTR_S]]: DW_TAG_typedef +// CHECK-NEXT: DW_AT_type{{.*}}{0x[[PTR_S]]} "S *" +// CHECK-NEXT: DW_AT_name{{.*}}"Sptr" + +// CHECK: 0x[[TYPEDEF_PTR_PTR_S:[a-f0-9]*]]: DW_TAG_typedef +// CHECK-NEXT: DW_AT_type{{.*}}{0x[[PTR_PTR_S]]} "Sptr *" +// CHECK-NEXT: DW_AT_name{{.*}}"Sptrptr" + +// First we confirm that first compile unit properly references type. +// +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp" +// +// CHECK: TAG_variable +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "ptr1" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]] + +#elif defined(FILE2) +# 1 "Header.h" 1 +typedef struct S *Sptr; +typedef Sptr *Sptrptr; +# 3 "Source2.cpp" 2 +struct S { + int field; +}; +void bar() { Sptrptr ptr2 = 0; } + +// Next we confirm that the second compile unit properly references types. +// +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp" +// +// CHECK: TAG_variable +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "ptr2" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]] + +#elif defined(FILE3) +# 1 "Header.h" 1 +typedef struct S *Sptr; +typedef Sptr *Sptrptr; +# 3 "Source1.cpp" 2 +void foo() { Sptrptr ptr1 = 0; } + +// Finally we confirm that third compile unit references types correctly. +// +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_name{{.*}}"X86/odr-fwd-declaration.cpp" +// +// CHECK: TAG_variable +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}} "ptr1" +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_type{{.*}}0x00000000[[TYPEDEF_PTR_PTR_S]] +// CHECK-NOT: TAG_typedef +// CHECK-NOT: TAG_pointer +// CHECK-NOT: TAG_structure_type + +#else +#error "You must define which file you generate" +#endif diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test new file mode 100644 index 00000000000000..439b7d76bb69bf --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration2.test @@ -0,0 +1,131 @@ +/* Compile with: + for FILE in `seq 3`; do + clang -g -c X86/odr-fwd-declaration2.cpp -DFILE$FILE -o + Inputs/odr-fwd-declaration2/$FILE.o done +*/ + +// RUN: dsymutil --linker=llvm -f \ +// RUN: -oso-prepend-path=%p/../../Inputs/odr-fwd-declaration2 \ +// RUN: -y %p/../dummy-debug-map.map -o %t1.out +// RUN: llvm-dwarfdump -v %t1.out -debug-info | FileCheck %s + +#ifdef FILE1 +# 1 "Header.h" 1 +struct A { + struct B; + B *bPtr; + B &bRef; + int B::*bPtrToField; +}; +# 3 "Source1.cpp" 2 +void foo() { A *ptr1 = 0; } + +// First we check that types are in type table unit. + +// CHECK: DW_TAG_compile_unit +// CHECK: AT_name{{.*}}"__artificial_type_unit" + +// CHECK: 0x[[INT_BASE:[a-f0-9]*]]: DW_TAG_base_type +// CHECK: AT_name{{.*}}"int" + +// CHECK: 0x[[PTR_A:[a-f0-9]*]]: DW_TAG_pointer_type +// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}0x[[STRUCT_A:[a-f0-9]*]]} "A") + +// CHECK: 0x[[PTR_B:[a-f0-9]*]]: DW_TAG_pointer_type +// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}0x[[STRUCT_B:[a-f0-9]*]]} "A::B") + +// CHECK: 0x[[REF_B:[a-f0-9]*]]: DW_TAG_reference_type +// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}0x[[STRUCT_B]]} "A::B") + +// CHECK: 0x[[STRUCT_A]]: DW_TAG_structure_type +// CHECK: AT_name{{.*}}"A" + +// CHECK: DW_TAG_member +// CHECK-NEXT: AT_name{{.*}}"bPtr" +// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[PTR_B]]} "A::B *") + +// CHECK: DW_TAG_member +// CHECK-NEXT: AT_name{{.*}}"bRef" +// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[REF_B]]} "A::B &" + +// CHECK: DW_TAG_member +// CHECK-NEXT: AT_name{{.*}}"bPtrToField" +// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[PTR_TO_FIELD:[a-f0-9]*]]} "int A::B::*" + +// CHECK: 0x[[STRUCT_B]]: DW_TAG_structure_type +// CHECK: AT_name{{.*}}"B" + +// CHECK: DW_TAG_member +// CHECK: AT_name{{.*}}"x" + +// CHECK: 0x[[PTR_TO_FIELD]]: DW_TAG_ptr_to_member_type +// CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}{0x[[INT_BASE]]} "int" +// CHECK-NEXT: DW_AT_containing_type [DW_FORM_ref4] {{.*}}{0x[[STRUCT_B]]} "A::B") + +// Next we check that second compile unit references type from type table unit. +// + +// CHECK: DW_TAG_compile_unit +// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp" + +// CHECK: DW_TAG_subprogram + +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name{{.*}}"ptr1" +// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *" + +#elif defined(FILE2) +# 1 "Header.h" 1 +struct A { + struct B; + B *bPtr; + B &bRef; + int B::*bPtrToField; +}; +# 3 "Source2.cpp" 2 +struct A::B { + int x; +}; +void bar() { A *ptr2 = 0; } + +// Next we check that thrid compile unit references type from type table unit. +// + +// CHECK: DW_TAG_compile_unit +// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp" + +// CHECK: DW_TAG_subprogram + +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name{{.*}}"ptr2" +// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *" + +#elif defined(FILE3) +# 1 "Header.h" 1 +struct A { + struct B; + B *bPtr; + B &bRef; + int B::*bPtrToField; +}; +# 3 "Source2.cpp" 2 +struct A::B { + int x; +}; +void bar() { A *ptr2 = 0; } + +// Next we check that fourth compile unit references type from type table unit. +// + +// CHECK: DW_TAG_compile_unit +// CHECK: AT_name{{.*}}"X86/odr-fwd-declaration2.cpp" + +// CHECK: DW_TAG_subprogram + +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name{{.*}}"ptr2" +// CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[PTR_A]] "A *" + +#else +#error "You must define which file you generate" +#endif diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test new file mode 100644 index 00000000000000..9758e4ad421303 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-fwd-declaration3.test @@ -0,0 +1,381 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out +# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s + +## This test checks debug info for the case when one compilation unit +## contains forward declaration of the type and another compilation unit +## contains definition for that type. The result should have type table +## containing definition for that type and corresponding variables should +## properly reference that type. + +## CU1: +## +## class class1; +## template class class2; +## +## class1 *var1; +## class2 *var2; +## +## CU2: +## +## class class1 { +## char member1; +## float member2; +## }; +## +## template class class2 { +## char member1; +## }; +## +## class1 *var1; +## class2 *var2; + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: .debug_info contents: +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"__artificial_type_unit" + +# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"char" + +# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"float" + +# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"int" + +# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1" +# CHECK: DW_TAG_member +# CHECK: DW_AT_type{{.*}}0x[[CHAR]] "char" +# CHECK: DW_AT_name{{.*}}"member1" + +# CHECK: DW_TAG_member +# CHECK: DW_AT_type{{.*}}0x[[FLOAT]] "float" +# CHECK: DW_AT_name{{.*}}"member2" + +# CHECK: 0x[[CLASS2:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class2" +# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int" +# CHECK: DW_TAG_member +# CHECK: DW_AT_type{{.*}}0x[[CHAR]] "char" +# CHECK: DW_AT_name{{.*}}"member1" + +# CHECK: 0x[[PTR_CLASS1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CLASS1]] "class1" + +# CHECK: 0x[[PTR_CLASS2:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CLASS2]] "class2" + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU1" +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var1" +# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS1]] "class1 *" +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var2" +# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS2]] "class2 *" + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU2" +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var1" +# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS1]] "class1 *" +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var2" +# CHECK: DW_AT_type{{.*}}0x{{.*}}[[PTR_CLASS2]] "class2 *" + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x9c + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0xed + offset: 0x0000041c + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x000001FC + symbolnum: 1 + pcrel: true + length: 3 + extern: false + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 1 + stroff: 0x710 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_member + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_declaration + Form: DW_FORM_flag_present + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_declaration + Form: DW_FORM_flag_present + - Tag: DW_TAG_template_type_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_member + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_declaration + Form: DW_FORM_flag_present + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_declaration + Form: DW_FORM_flag_present + - Tag: DW_TAG_template_type_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU1 + - AbbrCode: 4 + Values: + - CStr: class1 + - AbbrCode: 5 + Values: + - CStr: class2 + - AbbrCode: 6 + Values: + - Value: 0x00000030 + - AbbrCode: 0 + - AbbrCode: 7 + Values: + - CStr: int + - AbbrCode: 8 + Values: + - Value: 0x0000001a + - AbbrCode: 8 + Values: + - Value: 0x00000022 + - AbbrCode: 9 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x00000035 + - AbbrCode: 9 + Values: + - CStr: var2 + - Value: 0x00000000 + - Value: 0x0000003a + - AbbrCode: 0 + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU2 + - AbbrCode: 2 + Values: + - CStr: class1 + - AbbrCode: 3 + Values: + - Value: 0x000000b9 + - CStr: member1 + - AbbrCode: 3 + Values: + - Value: 0x000000bf + - CStr: member2 + - AbbrCode: 0 + - AbbrCode: 2 + Values: + - CStr: class2 + - AbbrCode: 6 + Values: + - Value: 0x000000b4 + - AbbrCode: 3 + Values: + - Value: 0x000000b9 + - CStr: member1 + - AbbrCode: 0 + - AbbrCode: 7 + Values: + - CStr: int + - AbbrCode: 7 + Values: + - CStr: char + - AbbrCode: 7 + Values: + - CStr: float + - AbbrCode: 8 + Values: + - Value: 0x00000076 + - AbbrCode: 8 + Values: + - Value: 0x00000099 + - AbbrCode: 9 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x000000c6 + - AbbrCode: 9 + Values: + - CStr: var2 + - Value: 0x00000000 + - Value: 0x000000cb + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp new file mode 100644 index 00000000000000..7135c46630e13a --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-member-functions.cpp @@ -0,0 +1,192 @@ +/* Compile with: + for FILE in `seq 3`; do + clang -g -c odr-member-functions.cpp -DFILE$FILE -o + odr-member-functions/$FILE.o done + */ + +// RUN: dsymutil --linker=llvm -f \ +// RUN: -oso-prepend-path=%p/../../Inputs/odr-member-functions \ +// RUN: -y %p/../dummy-debug-map.map -o %t1.out +// RUN: llvm-dwarfdump -debug-info %t1.out | FileCheck %s + +struct S { + __attribute__((always_inline)) void foo() { bar(); } + __attribute__((always_inline)) void foo(int i) { + if (i) + bar(); + } + void bar(); + + template void baz(T t) {} +}; + +#ifdef FILE1 +void foo() { S s; } + +// First chack that types are moved into the type table unit. + +// CHECK: TAG_compile_unit +// CHECK: AT_name{{.*}}"__artificial_type_unit" + +// CHECK: 0x[[INT_BASE:[0-9a-f]*]]: DW_TAG_base_type +// CHECK-NEXT: DW_AT_name{{.*}}"int" + +// CHECK: 0x[[PTR_S:[0-9a-f]*]]:{{.*}}DW_TAG_pointer_type +// CHECK-NEXT: DW_AT_type{{.*}}0x[[STRUCT_S:[0-9a-f]*]] "S") + +// CHECK: 0x[[STRUCT_S]]:{{.*}}DW_TAG_structure_type +// CHECK-NEXT: DW_AT_name{{.*}}"S" + +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3barEv" +// CHECK: DW_AT_name{{.*}}"bar" + +// CHECK: DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *" + +// CHECK: 0x[[BAZ_SUBPROGRAM:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram +// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3bazIiEEvT_" +// CHECK: DW_AT_name{{.*}}"baz" + +// CHECK: DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *" + +// CHECK: DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int" + +// CHECK: DW_TAG_template_type_parameter +// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int" +// CHECK-NEXT: DW_AT_name{{.*}}"T" + +// CHECK: 0x[[FOO_Ei:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram +// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEi" +// CHECK: DW_AT_name{{.*}}"foo" + +// CHECK: DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *" + +// CHECK: DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_type{{.*}}0x[[INT_BASE]] "int" + +// CHECK: 0x[[FOO_Ev:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram +// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEv" +// CHECK: DW_AT_name{{.*}}"foo" + +// CHECK: DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_type{{.*}}0x[[PTR_S]] "S *" + +// For the second unit check that it references structure "S" + +// CHECK: TAG_compile_unit +// CHECK-NOT: {{DW_TAG|NULL}} +// CHECK: AT_name{{.*}}"odr-member-functions.cpp" + +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov" +// CHECK-NEXT: AT_name{{.*}}"foo" + +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name{{.*}}"s" +// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S" + +#elif defined(FILE2) +void foo() { + S s; + // Check that the overloaded member functions are resolved correctly + s.foo(); + s.foo(1); +} + +// For the third unit check that it references member functions of structure S. +// CHECK: TAG_compile_unit +// CHECK-NOT: DW_TAG +// CHECK: AT_name{{.*}}"odr-member-functions.cpp" + +// CHECK: 0x[[ABASE_FOO_Ev:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram +// CHECK-NEXT: DW_AT_specification {{.*}}(0x00000000[[FOO_Ev]] "_ZN1S3fooEv" +// CHECK-NEXT: DW_AT_inline (DW_INL_inlined) +// CHECK-NEXT: DW_AT_object_pointer {{.*}}(0x[[ABASE_FOO_Ev_PARAM1:[0-9a-f]*]] + +// CHECK: 0x[[ABASE_FOO_Ev_PARAM1]]:{{.*}}DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_name{{.*}}"this" +// CHECK-NEXT: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *" + +// CHECK: 0x[[ABASE_FOO_Ei:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram +// CHECK-NEXT: DW_AT_specification {{.*}}(0x00000000[[FOO_Ei]] "_ZN1S3fooEi" +// CHECK-NEXT: DW_AT_inline (DW_INL_inlined) +// CHECK-NEXT: DW_AT_object_pointer {{.*}}(0x[[ABASE_FOO_Ei_PARAM1:[0-9a-f]*]] + +// CHECK: 0x[[ABASE_FOO_Ei_PARAM1]]:{{.*}}DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_name{{.*}}"this" +// CHECK-NEXT: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *" + +// CHECK: 0x[[ABASE_FOO_Ei_PARAM2:[0-9a-f]*]]:{{.*}}DW_TAG_formal_parameter +// CHECK-NEXT: DW_AT_name{{.*}}"i" +// CHECK: DW_AT_type (0x00000000[[INT_BASE]] "int" + +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov" +// CHECK: DW_AT_name{{.*}}"foo" + +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name{{.*}}"s" +// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S" + +// CHECK: DW_TAG_inlined_subroutine +// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ev]] "_ZN1S3fooEv" +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc + +// CHECK: DW_TAG_formal_parameter +// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ev_PARAM1]] "this" + +// CHECK: DW_TAG_inlined_subroutine +// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei]] "_ZN1S3fooEi" +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc + +// CHECK: DW_TAG_formal_parameter +// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei_PARAM1]] "this" + +// CHECK: DW_TAG_formal_parameter +// CHECK: DW_AT_abstract_origin{{.*}}(0x[[ABASE_FOO_Ei_PARAM2]] "i" + +#elif defined(FILE3) +void foo() { + S s; + s.baz(42); +} + +// For the fourth unit check that it references member functions of structure S. + +// CHECK: TAG_compile_unit +// CHECK-NOT: DW_TAG +// CHECK: AT_name{{.*}}"odr-member-functions.cpp" + +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov" +// CHECK: DW_AT_name{{.*}}"foo" + +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name{{.*}}"s" +// CHECK: DW_AT_type{{.*}}(0x00000000[[STRUCT_S]] "S" + +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_object_pointer{{.*}}(0x[[INST_PARAM2:[0-9a-f]*]] +// CHECK: DW_AT_specification{{.*}}(0x00000000[[BAZ_SUBPROGRAM]] "_ZN1S3bazIiEEvT_" + +// CHECK: 0x[[INST_PARAM2]]:{{.*}}DW_TAG_formal_parameter +// CHECK: DW_AT_name{{.*}}"this" +// CHECK: DW_AT_type{{.*}}(0x00000000[[PTR_S]] "S *" + +// CHECK: DW_TAG_formal_parameter +// CHECK: DW_AT_name{{.*}}"t" +// CHECK: DW_AT_type{{.*}}(0x00000000[[INT_BASE]] "int" + +// CHECK: DW_TAG_template_type_parameter +// CHECK: DW_AT_type{{.*}}(0x00000000[[INT_BASE]] "int" +// CHECK: DW_AT_name{{.*}}"T" + +#else +#error "You must define which file you generate" +#endif diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test new file mode 100644 index 00000000000000..6c31b48978e982 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-namespace-extension.test @@ -0,0 +1,157 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out +# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s + +## This test checks that DW_TAG_namespace with DW_AT_extension +## attribute is joined with referenced namespace. + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: 0x0000000b: DW_TAG_compile_unit +# CHECK: DW_TAG_namespace +# CHECK: DW_AT_name{{.*}}"parent_namespace" +# CHECK-NOT: DW_TAG_namespace +# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"int" +# CHECK: DW_TAG_compile_unit +# CHECK: DW_TAG_variable +# CHECK: DW_AT_type (0x00000000[[INT]] + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x2A + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0x42 + offset: 0x000003AA + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x000001FC + symbolnum: 1 + pcrel: true + length: 3 + extern: false + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 1 + stroff: 0x710 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Tag: DW_TAG_namespace + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_namespace + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_extension + Form: DW_FORM_ref_addr + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - AbbrCode: 2 + Values: + - CStr: parent_namespace + - AbbrCode: 3 + Values: + - Value: 0x00000016 + - AbbrCode: 4 + Values: + - CStr: int + - AbbrCode: 0 + - AbbrCode: 0 + - AbbrCode: 5 + Values: + - CStr: var + - Value: 0x000000FF + - Value: 0x0000002d + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test new file mode 100644 index 00000000000000..22a142ab97657c --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types1.test @@ -0,0 +1,384 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out +# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s + +## This test checks that nested structure containing field of anonymuos type +## partially moved into the type table. Anonymous part of the structure should be +## left in the original containg compile unit: +## +## CU1: +## +## struct s1 { struct s2; } +## +## namespace { +## struct s3 {}; +## } +## +## struct s1::s2 { s3 m; }; +## +## struct s1::s2 *var1; +## struct s1::s2::s3 *var2; +## +## CU2: +## +## struct s1 { struct s2; } +## +## struct s1::s2 *var3; +## +## +## Final type table should contain: +## +## DW_TAG_compile_unit +## DW_AT_name ("__type_table") +## +## DW_TAG_structure_type +## DW_AT_name ("s1") +## +## DW_TAG_structure_type +## DW_AT_name ("s2") +## DW_AT_declaration (true) +## +## CU1 should contain: +## +## DW_TAG_compile_unit +## DW_AT_name ("CU1") +## +## DW_TAG_structure_type +## DW_AT_name ("s1") +## +## DW_TAG_structure_type +## DW_AT_name ("s2") +## +## DW_TAG_member +## DW_AT_name ("m") +## DW_AT_type ("(anonymous namespace)::s3") +## +## DW_TAG_namespace +## +## DW_TAG_structure_type +## DW_AT_name ("s3") +## +## DW_TAG_variable +## DW_AT_name ("var1") +## DW_AT_type ("s1::s2 *") +## +## DW_TAG_variable +## DW_AT_name ("var2") +## DW_AT_type ("s1::s2::m *") +## +## CU2 should contain: +## +## DW_TAG_compile_unit +## DW_AT_name ("CU2") +## +## DW_TAG_variable +## DW_AT_name ("var3") +## DW_AT_type ("s1::s2 *") +## + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: .debug_info contents: +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"__artificial_type_unit" + +# CHECK: 0x[[PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2") + +# CHECK: DW_TAG_structure_type +# CHECK: DW_AT_name{{.*}}"s1" + +# CHECK: 0x[[INNER_STRUCT:[0-9a-f]*]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s2" +# CHECK: DW_AT_declaration{{.*}}true + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU1" + +# CHECK: DW_TAG_structure_type +# CHECK: DW_AT_name{{.*}}"s1" + +# CHECK: DW_TAG_structure_type +# CHECK: DW_AT_name{{.*}}"s2" + +# CHECK: 0x[[INNER_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"m" +# CHECK: DW_AT_type{{.*}}0x[[ANON_STRUCT:[0-9a-f]*]] "(anonymous namespace)::s3" + +# CHECK: DW_TAG_namespace +# CHECK: 0x[[ANON_STRUCT]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s3" + +# CHECK: 0x[[ANON_PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2") + +# CHECK: 0x[[PTR_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT_MEMBER]] "m" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var1" +# CHECK: DW_AT_type{{.*}}0x[[ANON_PTR_INNER_STRUCT]] "s1::s2 *" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var2" +# CHECK: DW_AT_type{{.*}}0x[[PTR_STRUCT_MEMBER]] "m *" + + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU2" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var3" +# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var4" +# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *" + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x76 + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0xa7 + offset: 0x000003f6 + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x0 + symbolnum: 1 + pcrel: true + length: 3 + extern: true + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 2 + stroff: 0x720 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_member + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_namespace + Children: DW_CHILDREN_yes + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_declaration + Form: DW_FORM_flag_present + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU1 + - AbbrCode: 2 + Values: + - CStr: s1 + - AbbrCode: 2 + Values: + - CStr: s2 + - AbbrCode: 4 + Values: + - CStr: m + - Value: 0x0000002c + - AbbrCode: 0 + - AbbrCode: 0 + - AbbrCode: 7 + - AbbrCode: 3 + Values: + - CStr: s3 + - AbbrCode: 0 + - AbbrCode: 5 + Values: + - CStr: int + - AbbrCode: 6 + Values: + - Value: 0x0000001e + - AbbrCode: 6 + Values: + - Value: 0x00000022 + - AbbrCode: 8 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x00000036 + - AbbrCode: 8 + Values: + - CStr: var2 + - Value: 0x00000000 + - Value: 0x0000003b + - AbbrCode: 0 + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU2 + - AbbrCode: 2 + Values: + - CStr: s1 + - AbbrCode: 3 + Values: + - CStr: s2 + - AbbrCode: 0 + - AbbrCode: 4 + Values: + - CStr: int + - AbbrCode: 5 + Values: + - Value: 0x0000007b + - AbbrCode: 6 + Values: + - CStr: var3 + - Value: 0x00000000 + - Value: 0x00000085 + - AbbrCode: 6 + Values: + - CStr: var4 + - Value: 0x00000000 + - Value: 0x00000085 + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test new file mode 100644 index 00000000000000..35d3261e591cb3 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-nested-types2.test @@ -0,0 +1,374 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker=llvm -y %t2.map -f -o %t1.out +# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s + +## This test checks that nested structure containing field of type from other namespace +## fully moved into the type table. +## +## CU1: +## +## struct s1 { struct s2; } +## +## namespace namespace1 { +## struct s3 {}; +## } +## +## struct s1::s2 { s3 m; }; +## +## struct s1::s2 *var1; +## struct s1::s2::s3 *var2; +## +## CU2: +## +## struct s1 { struct s2; } +## +## struct s1::s2 *var3; +## +## +## Final type table should contain: +## +## DW_TAG_compile_unit +## DW_AT_name ("__type_table") +## +## DW_TAG_namespace +## DW_AT_name ("namespace1") +## +## DW_TAG_structure_type +## DW_AT_name ("s3") +## +## DW_TAG_structure_type +## DW_AT_name ("s1") +## +## DW_TAG_structure_type +## DW_AT_name ("s2") +## +## DW_TAG_member +## DW_AT_name ("m") +## DW_AT_type ("namespace1::s3") +## +## CU1 should contain: +## +## DW_TAG_compile_unit +## DW_AT_name ("CU1") +## +## DW_TAG_variable +## DW_AT_name ("var1") +## DW_AT_type ("s1::s2 *") +## +## DW_TAG_variable +## DW_AT_name ("var2") +## DW_AT_type ("s1::s2::m *") +## +## CU2 should contain: +## +## DW_TAG_compile_unit +## DW_AT_name ("CU2") +## +## DW_TAG_variable +## DW_AT_name ("var1") +## DW_AT_type ("s1::s2 *") + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: .debug_info contents: +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"__artificial_type_unit" + +# CHECK: DW_TAG_namespace +# CHECK: DW_AT_name{{.*}}"namespace1" +# CHECK: 0x[[NAMESPACE_STRUCT:[0-9a-f]*]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s3" + +# CHECK: 0x[[PTR_INNER_STRUCT:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT:[0-9a-f]*]] "s1::s2") + +# CHECK: 0x[[PTR_STRUCT_MEMBER:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_STRUCT_MEMBER:[0-9a-f]*]] "m" + +# CHECK: DW_TAG_structure_type +# CHECK: DW_AT_name{{.*}}"s1" + +# CHECK: 0x[[INNER_STRUCT]]: DW_TAG_structure_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"s2" +# CHECK-NOT: DW_AT_declaration + +# CHECK: 0x[[INNER_STRUCT_MEMBER]]: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"m" +# CHECK: DW_AT_type{{.*}}0x[[NAMESPACE_STRUCT]] "namespace1::s3" + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU1" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var1" +# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var2" +# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_STRUCT_MEMBER]] "m *" + + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU2" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var3" +# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var4" +# CHECK: DW_AT_type{{.*}}0x00000000[[PTR_INNER_STRUCT]] "s1::s2 *" + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x78 + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0xb2 + offset: 0x000003F8 + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x0 + symbolnum: 1 + pcrel: true + length: 3 + extern: true + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 2 + stroff: 0x720 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_member + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_namespace + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_declaration + Form: DW_FORM_flag_present + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU1 + - AbbrCode: 2 + Values: + - CStr: s1 + - AbbrCode: 2 + Values: + - CStr: s2 + - AbbrCode: 4 + Values: + - CStr: m + - Value: 0x00000037 + - AbbrCode: 0 + - AbbrCode: 0 + - AbbrCode: 7 + Values: + - CStr: namespace1 + - AbbrCode: 3 + Values: + - CStr: s3 + - AbbrCode: 0 + - AbbrCode: 5 + Values: + - CStr: int + - AbbrCode: 6 + Values: + - Value: 0x0000001e + - AbbrCode: 6 + Values: + - Value: 0x00000022 + - AbbrCode: 8 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x00000041 + - AbbrCode: 8 + Values: + - CStr: var2 + - Value: 0x00000000 + - Value: 0x00000046 + - AbbrCode: 0 + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU2 + - AbbrCode: 2 + Values: + - CStr: s1 + - AbbrCode: 3 + Values: + - CStr: s2 + - AbbrCode: 0 + - AbbrCode: 4 + Values: + - CStr: int + - AbbrCode: 5 + Values: + - Value: 0x00000086 + - AbbrCode: 6 + Values: + - CStr: var3 + - Value: 0x00000000 + - Value: 0x00000090 + - AbbrCode: 6 + Values: + - CStr: var4 + - Value: 0x00000000 + - Value: 0x00000090 + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test new file mode 100644 index 00000000000000..7c1c0d1b52e0ee --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-parents.test @@ -0,0 +1,238 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s + +## This test checks debug info for the equally named structures from +## different namespaces. The result should contain two variables which +## reference different types("A::C1::I1 *const" and "B::C1::I1 *const") + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: .debug_info contents: +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"__artificial_type_unit" + +# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"int" + +# CHECK: DW_TAG_namespace{{.*[[:space:]].*}}DW_AT_name{{.*}}"A" + +# CHECK: 0x[[A_C1:[0-9a-f]*]]: DW_TAG_structure_type +# CHECK: DW_AT_name{{.*}}"C1" +# CHECK: DW_TAG_member +# CHECK: DW_AT_type{{.*}}0x[[INT]] "int" +# CHECK: DW_AT_name{{.*}}"I1" + +# CHECK: DW_TAG_namespace{{.*[[:space:]].*}}DW_AT_name{{.*}}"B" + +# CHECK: 0x[[B_C1:[0-9a-f]*]]: DW_TAG_structure_type +# CHECK: DW_AT_name{{.*}}"C1" +# CHECK: DW_TAG_member +# CHECK: DW_AT_type{{.*}}0x[[INT]] "int" +# CHECK: DW_AT_name{{.*}}"I1" + +# CHECK: 0x[[PTR_A_C1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[A_C1:[0-9a-f]*]] "A::C1" + +# CHECK: 0x[[PTR_B_C1:[0-9a-f]*]]: DW_TAG_pointer_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[B_C1:[0-9a-f]*]] "B::C1" + +# CHECK: 0x[[CONST_A_C1:[0-9a-f]*]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[PTR_A_C1]] "A::C1 *" + +# CHECK: 0x[[CONST_B_C1:[0-9a-f]*]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[PTR_B_C1]] "B::C1 *" + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var1" +# CHECK: DW_AT_type{{.*}}0x00000000[[CONST_A_C1]] "A::C1 *const" +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var2" +# CHECK: DW_AT_type{{.*}}0x00000000[[CONST_B_C1]] "B::C1 *const" + + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x41 + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0x6e + offset: 0x000003C1 + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x000001FC + symbolnum: 1 + pcrel: true + length: 3 + extern: false + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 1 + stroff: 0x710 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Tag: DW_TAG_namespace + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_structure_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_member + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_const_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - AbbrCode: 2 + Values: + - CStr: A + - AbbrCode: 3 + Values: + - CStr: C1 + - AbbrCode: 4 + Values: + - Value: 0x00000038 + - CStr: I1 + - AbbrCode: 0 + - AbbrCode: 0 + - AbbrCode: 2 + Values: + - CStr: B + - AbbrCode: 3 + Values: + - CStr: C1 + - AbbrCode: 4 + Values: + - Value: 0x00000038 + - CStr: I1 + - AbbrCode: 0 + - AbbrCode: 0 + - AbbrCode: 5 + Values: + - CStr: int + - AbbrCode: 6 + Values: + - Value: 0x00000019 + - AbbrCode: 6 + Values: + - Value: 0x0000002a + - AbbrCode: 7 + Values: + - Value: 0x0000003D + - AbbrCode: 7 + Values: + - Value: 0x00000042 + - AbbrCode: 8 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x00000047 + - AbbrCode: 8 + Values: + - CStr: var2 + - Value: 0x00000000 + - Value: 0x0000004C + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test new file mode 100644 index 00000000000000..187a2ea9ecffdc --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output.test @@ -0,0 +1,117 @@ +# RUN: dsymutil --linker=llvm -f -o %t1.o -oso-prepend-path=%p/ -y %s +# RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s +# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 1 | llvm-dwarfdump -a - -o %t1 +# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 3 | llvm-dwarfdump -a - -o %t2 +# RUN: diff %t1 %t2 +# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s --num-threads 4 | llvm-dwarfdump -a - -o %t3 +# RUN: diff %t1 %t3 +# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/ -y %s | llvm-dwarfdump -a - -o %t4 +# RUN: diff %t1 %t4 + +# This test checks that generated output does not differ between runs. +# +# To recreate a test compile following example: +# +# main.cpp: +# +# include +# +# void PrintSize ( const std::string& String ); +# void PrintNewString ( const std::string& String ); +# void PrintNewString2 ( const char* String ); +# +# int main ( void ) { +# +# PrintSize("hello"); +# PrintNewString("hello"); +# PrintNewString2("hello"); +# printf("\n"); +# +# return 0; +# } +# +# foo1.cpp: +# +# #include +# +# void PrintSize ( const std::string& String ) { +# printf("\n String size %lu", String.size() ); +# }; +# +# foo2.cpp: +# +# #include +# +# void PrintNewString ( const std::string& String ) { +# std::string NewString(String); +# NewString += "++"; +# printf("\n String %s", NewString.c_str()); +#}; +# +# foo3.cpp: +# #include +# +# void PrintNewString2 ( const char* String ) { +# std::string NewString(String); +# NewString += "++"; +# printf("\n String2 %s", NewString.c_str()); +# }; +# +# with clang++ -O -fno-inline -g -std=c++11 + +--- +triple: 'x86_64-apple-darwin' +objects: + - filename: 'Inputs/String/foo1.o' + timestamp: 1638904719 + symbols: + - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 } + - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 } + - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 } + - filename: 'Inputs/String/foo2.o' + timestamp: 1638904723 + symbols: + - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 } + - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 } + - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 } + - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 } + - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 } + - filename: 'Inputs/String/foo3.o' + timestamp: 1638904727 + symbols: + - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D50, size: 0x00000040 } + - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 } + - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D40, size: 0x00000010 } + - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 } + - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 } + - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 } + - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 } + - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 } + - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 } + - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 } + - filename: 'Inputs/String/main.o' + timestamp: 1638904734 + symbols: + - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 } + - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 } +... + +VERIFY: Verifying .debug_abbrev... +VERIFY: Verifying .debug_info Unit Header Chain... +VERIFY: Verifying .apple_names... +VERIFY: Verifying .apple_types... +VERIFY: Verifying .apple_namespaces... +VERIFY: Verifying .apple_objc... +VERIFY: No errors. diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test new file mode 100644 index 00000000000000..93925c61c46b8b --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-predictable-output2.test @@ -0,0 +1,120 @@ +# RUN: dsymutil --linker=llvm -f -o %t1.o -oso-prepend-path=%p/../ -y %s +# RUN: llvm-dwarfdump --verify %t1.o | FileCheck -check-prefixes=VERIFY %s +# RUN: dsymutil --linker=llvm -f -o %t2.o -oso-prepend-path=%p/../ -y %s +# RUN: dsymutil --linker=llvm -f -o %t3.o -oso-prepend-path=%p/../ -y %s \ +# RUN: --num-threads 1 +# RUN: dsymutil --linker=llvm -f -o %t4.o -oso-prepend-path=%p/../ -y %s \ +# RUN: --num-threads 3 +# ### Following comparision will fail if files do not match +# RUN: diff %t1.o %t2.o +# RUN: diff %t1.o %t3.o +# RUN: diff %t1.o %t4.o + +# This test checks that generated output does not differ between runs. +# +# To recreate a test compile following example: +# +# main.cpp: +# +# include +# +# void PrintSize ( const std::string& String ); +# void PrintNewString ( const std::string& String ); +# void PrintNewString2 ( const char* String ); +# +# int main ( void ) { +# +# PrintSize("hello"); +# PrintNewString("hello"); +# PrintNewString2("hello"); +# printf("\n"); +# +# return 0; +# } +# +# foo1.cpp: +# +# #include +# +# void PrintSize ( const std::string& String ) { +# printf("\n String size %lu", String.size() ); +# }; +# +# foo2.cpp: +# +# #include +# +# void PrintNewString ( const std::string& String ) { +# std::string NewString(String); +# NewString += "++"; +# printf("\n String %s", NewString.c_str()); +#}; +# +# foo3.cpp: +# #include +# +# void PrintNewString2 ( const char* String ) { +# std::string NewString(String); +# NewString += "++"; +# printf("\n String2 %s", NewString.c_str()); +# }; +# +# with clang++ -O -fno-inline -g -std=c++11 + +--- +triple: 'x86_64-apple-darwin' +objects: + - filename: 'Inputs/String/foo1.o' + timestamp: 1638904719 + symbols: + - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 } + - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 } + - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 } + - filename: 'Inputs/String/foo2.o' + timestamp: 1638904723 + symbols: + - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 } + - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 } + - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 } + - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 } + - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 } + - filename: 'Inputs/String/foo3.o' + timestamp: 1638904727 + symbols: + - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D40, size: 0x00000040 } + - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 } + - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D50, size: 0x00000010 } + - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 } + - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 } + - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 } + - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 } + - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 } + - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 } + - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 } + - filename: 'Inputs/String/main.o' + timestamp: 1638904734 + symbols: + - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 } + - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 } +... + +VERIFY: Verifying .debug_abbrev... +VERIFY: Verifying .debug_info Unit Header Chain... +VERIFY: Verifying .debug_types Unit Header Chain... +VERIFY: Verifying .apple_names... +VERIFY: Verifying .apple_types... +VERIFY: Verifying .apple_namespaces... +VERIFY: Verifying .apple_objc... +VERIFY: No errors. diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test new file mode 100644 index 00000000000000..619bc8c15b8229 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-recursive-dependence.test @@ -0,0 +1,245 @@ +## This test checks output of dsymutil for the incorrect DWARF. +## CU1 has a type which references type in CU2. This referenced +## type references the same type in CU1 back. There is a recursive +## dependence between these two types. dsymutil should report a error, +## remove CU1 and CU2, put only CU3 into the output. + +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker llvm -y %t2.map --num-threads 1 -f -o %t1.out 2>&1 \ +# RUN: | FileCheck --check-prefix ERROR %s +# RUN: llvm-dwarfdump -a %t1.out | FileCheck %s + +# ERROR: error: Cann't parse input DWARF. Recursive dependence. +# ERROR: while processing CU1 +# ERROR: error: Cann't resolve DIE reference +# ERROR: while processing CU2 + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: .debug_info contents: +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"__artificial_type_unit" +# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1" + +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK-NOT: "CU1" +# CHECK-NOT: "CU2" +# CHECK: DW_AT_name{{.*}}"CU3" +# CHECK-NOT: DW_TAG_class_type +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var3" +# CHECK: DW_AT_const_value +# CHECK: DW_AT_type (0x00000000[[CLASS1]] + +# CHECK-NOT: Compile Unit: + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x5a + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0x8d + offset: 0x00000410 + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x1FC + symbolnum: 1 + pcrel: true + length: 3 + extern: true + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 2 + stroff: 0x720 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU1 + - AbbrCode: 2 + Values: + - Value: 0x48 + - AbbrCode: 3 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x0000001a + - AbbrCode: 0 + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU2 + - AbbrCode: 2 + Values: + - Value: 0x1a + - AbbrCode: 3 + Values: + - CStr: var2 + - Value: 0x00000000 + - Value: 0x0000001a + - AbbrCode: 0 + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU3 + - AbbrCode: 2 + Values: + - CStr: class1 + - AbbrCode: 3 + Values: + - CStr: var3 + - Value: 0x00000000 + - Value: 0x0000001a + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test new file mode 100644 index 00000000000000..a8fc3e82311ca5 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-string.test @@ -0,0 +1,180 @@ +# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/../ -y %s | llvm-dwarfdump --verify - | FileCheck -check-prefixes=VERIFY %s +# RUN: dsymutil --linker=llvm -f -o - -oso-prepend-path=%p/../ -y %s | llvm-dwarfdump -a - | FileCheck %s + +# This test checks that types from several object files are +# uniqued(moved into the artificial compile unit for types). +# It also checks that information between different debug +# tables is consistent. +# +# To recreate a test compile following example: +# +# main.cpp: +# +# include +# +# void PrintSize ( const std::string& String ); +# void PrintNewString ( const std::string& String ); +# void PrintNewString2 ( const char* String ); +# +# int main ( void ) { +# +# PrintSize("hello"); +# PrintNewString("hello"); +# PrintNewString2("hello"); +# printf("\n"); +# +# return 0; +# } +# +# foo1.cpp: +# +# #include +# +# void PrintSize ( const std::string& String ) { +# printf("\n String size %lu", String.size() ); +# }; +# +# foo2.cpp: +# +# #include +# +# void PrintNewString ( const std::string& String ) { +# std::string NewString(String); +# NewString += "++"; +# printf("\n String %s", NewString.c_str()); +#}; +# +# foo3.cpp: +# #include +# +# void PrintNewString2 ( const char* String ) { +# std::string NewString(String); +# NewString += "++"; +# printf("\n String2 %s", NewString.c_str()); +# }; +# +# with clang++ -O -fno-inline -g -std=c++11 + +--- +triple: 'x86_64-apple-darwin' +objects: + - filename: 'Inputs/String/foo1.o' + timestamp: 1638904719 + symbols: + - { sym: __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv, objAddr: 0x00000000000000A0, binAddr: 0x0000000100000B10, size: 0x00000009 } + - { sym: __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv, objAddr: 0x0000000000000090, binAddr: 0x0000000100000B00, size: 0x00000010 } + - { sym: __Z9PrintSizeRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000A70, size: 0x00000020 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE15__get_long_sizeEv, objAddr: 0x0000000000000060, binAddr: 0x0000000100000AD0, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4sizeEv, objAddr: 0x0000000000000020, binAddr: 0x0000000100000A90, size: 0x00000030 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE16__get_short_sizeEv, objAddr: 0x0000000000000070, binAddr: 0x0000000100000AE0, size: 0x00000020 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv, objAddr: 0x0000000000000050, binAddr: 0x0000000100000AC0, size: 0x00000010 } + - filename: 'Inputs/String/foo2.o' + timestamp: 1638904723 + symbols: + - { sym: __ZNSt3__112__to_addressIKcEEPT_S3_, objAddr: 0x00000000000000E0, binAddr: 0x0000000100000BD0, size: 0x00000010 } + - { sym: GCC_except_table0, objAddr: 0x000000000000016C, binAddr: 0x0000000100000F24, size: 0x00000000 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv, objAddr: 0x0000000000000120, binAddr: 0x0000000100000C10, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv, objAddr: 0x0000000000000130, binAddr: 0x0000000100000C20, size: 0x00000020 } + - { sym: __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_, objAddr: 0x0000000000000150, binAddr: 0x0000000100000C40, size: 0x00000010 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEpLEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000B90, size: 0x00000010 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv, objAddr: 0x00000000000000C0, binAddr: 0x0000000100000BB0, size: 0x00000020 } + - { sym: __Z14PrintNewStringRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE, objAddr: 0x0000000000000000, binAddr: 0x0000000100000B20, size: 0x00000070 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5c_strEv, objAddr: 0x0000000000000080, binAddr: 0x0000000100000BA1, size: 0x00000010 } + - { sym: __ZNSt3__19addressofIKcEEPT_RS2_, objAddr: 0x0000000000000160, binAddr: 0x0000000100000C50, size: 0x00000009 } + - { sym: __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv, objAddr: 0x00000000000000F0, binAddr: 0x0000000100000BE0, size: 0x00000030 } + - filename: 'Inputs/String/foo3.o' + timestamp: 1638904727 + symbols: + - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000130, binAddr: 0x0000000100000D40, size: 0x00000040 } + - { sym: __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_, objAddr: 0x0000000000000110, binAddr: 0x0000000100000D20, size: 0x00000010 } + - { sym: __ZNSt3__111char_traitsIcE6lengthEPKc, objAddr: 0x0000000000000120, binAddr: 0x0000000100000D50, size: 0x00000010 } + - { sym: __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev, objAddr: 0x00000000000001B0, binAddr: 0x0000000100000DC0, size: 0x00000010 } + - { sym: __ZNSt3__17forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE, objAddr: 0x0000000000000170, binAddr: 0x0000000100000D80, size: 0x00000010 } + - { sym: __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000180, binAddr: 0x0000000100000D90, size: 0x00000010 } + - { sym: __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE, objAddr: 0x0000000000000190, binAddr: 0x0000000100000DA0, size: 0x00000010 } + - { sym: __ZNSt3__19allocatorIcEC2Ev, objAddr: 0x00000000000001A0, binAddr: 0x0000000100000DB0, size: 0x00000010 } + - { sym: __Z15PrintNewString2PKc, objAddr: 0x0000000000000000, binAddr: 0x0000000100000C60, size: 0x00000070 } + - { sym: GCC_except_table0, objAddr: 0x000000000000026C, binAddr: 0x0000000100000F34, size: 0x00000000 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1IDnEEPKc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000CD0, size: 0x00000010 } + - { sym: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2IDnEEPKc, objAddr: 0x00000000000000D0, binAddr: 0x0000000100000CE0, size: 0x00000040 } + - filename: 'Inputs/String/main.o' + timestamp: 1638904734 + symbols: + - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000DD0, size: 0x00000090 } + - { sym: GCC_except_table0, objAddr: 0x0000000000000188, binAddr: 0x0000000100000F44, size: 0x00000000 } +... + +VERIFY: Verifying .debug_abbrev... +VERIFY: Verifying .debug_info Unit Header Chain... +VERIFY: Verifying .debug_types Unit Header Chain... +VERIFY: Verifying .apple_names... +VERIFY: Verifying .apple_types... +VERIFY: Verifying .apple_namespaces... +VERIFY: Verifying .apple_objc... +VERIFY: No errors. + +CHECK: .debug_info contents: +CHECK: Compile Unit: +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_name{{.*}}"__artificial_type_unit" + +CHECK:DW_TAG_base_type + +CHECK: 0x[[BASE_INT:[0-9a-f]*]]: DW_TAG_base_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"int" + +CHECK:DW_TAG_class_type + +CHECK: 0x[[BASIC_STRING:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_calling_convention{{.*}}{{.*[[:space:]].*}}DW_AT_name{{.*}}"basic_string, std::__1::allocator >" + +CHECK:DW_TAG_typedef + +CHECK: 0x[[STRING:[0-9a-f]*]]: DW_TAG_typedef{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[BASIC_STRING]] "std::__1::basic_string, std::__1::allocator >"){{.*[[:space:]].*}}DW_AT_name{{.*}}"string" + +CHECK:DW_TAG_reference_type + +CHECK: 0x[[CONST_STR_REF:[0-9a-f]*]]: DW_TAG_reference_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[CONST_STRING:[0-9a-f]*]] "const string" + +CHECK:DW_TAG_const_type + +CHECK: 0x[[CONST_STRING]]: DW_TAG_const_type{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[STRING]] "string" + + +CHECK: Compile Unit: +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_name{{.*}}"foo1.cpp" +CHECK: DW_TAG_subprogram +CHECK: DW_AT_low_pc +CHECK: DW_AT_high_pc +CHECK: DW_AT_name{{.*}}"PrintSize" +CHECK: DW_TAG_formal_parameter +CHECK: DW_AT_name{{.*}}"String" +CHECK: DW_AT_type{{.*}}0x00000000[[CONST_STR_REF]] "const string &" + +CHECK: Compile Unit: +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_name{{.*}}"foo2.cpp" +CHECK: DW_TAG_subprogram +CHECK: DW_AT_low_pc +CHECK: DW_AT_high_pc +CHECK: DW_AT_name{{.*}}"PrintNewString" +CHECK: DW_TAG_formal_parameter +CHECK: DW_AT_name{{.*}}"String" + +CHECK: Compile Unit: +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_name{{.*}}"foo3.cpp" +CHECK: DW_TAG_subprogram +CHECK: DW_AT_low_pc +CHECK: DW_AT_high_pc +CHECK: DW_AT_name{{.*}}"PrintNewString2" +CHECK: DW_TAG_formal_parameter +CHECK: DW_AT_name{{.*}}"String" + +CHECK: Compile Unit: +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_name{{.*}}"main.cpp" +CHECK: DW_TAG_subprogram +CHECK: DW_AT_low_pc +CHECK: DW_AT_high_pc +CHECK: DW_AT_name{{.*}}"main" +CHECK: DW_AT_type{{.*}}0x00000000[[BASE_INT]] "int" diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test new file mode 100644 index 00000000000000..67b5616ebd5922 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-template-parameters.test @@ -0,0 +1,201 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s + +## This test checks debug info for the template parameters of the class. +## (i.e. number of the parameters is correct, names of the parameters +## are correct, types of the parameters are correct) + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: 0x0000000b: DW_TAG_compile_unit +# CHECK: DW_AT_producer{{.*}}"llvm DWARFLinkerParallel library version +# CHECK: DW_AT_language{{.*}}DW_LANG_C_plus_plus +# CHECK: DW_AT_name{{.*}}"__artificial_type_unit" +# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"char" +# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"float" +# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"int" +# CHECK: 0x[[CLASS:[0-9a-f]*]]: DW_TAG_class_type +# CHECK: DW_AT_name{{.*}}"parametrized-class" +# CHECK: DW_TAG_template_type_parameter +# CHECK: DW_AT_type{{.*}}(0x[[INT]] "int" +# CHECK: DW_AT_name{{.*}}"Type1" +# CHECK: DW_AT_type{{.*}}(0x[[CHAR]] "char" +# CHECK: DW_AT_name{{.*}}"Type2" +# CHECK: DW_AT_type{{.*}}(0x[[FLOAT]] "float" +# CHECK: DW_AT_name{{.*}}"Type3" +# CHECK: DW_TAG_compile_unit +# CHECK: DW_TAG_variable +# CHECK: DW_AT_type (0x00000000[[CLASS]] + + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x37 + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0x7B + offset: 0x000003B7 + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x000001FC + symbolnum: 1 + pcrel: true + length: 3 + extern: false + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 1 + stroff: 0x710 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_template_type_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_template_value_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - AbbrCode: 2 + Values: + - CStr: parametrized-class + - AbbrCode: 3 + Values: + - Value: 0x0000005B + - CStr: Type1 + - AbbrCode: 3 + Values: + - Value: 0x00000060 + - CStr: Type2 + - AbbrCode: 4 + Values: + - Value: 0x0000005B + - CStr: Type1 + - Value: 0x0FE + - AbbrCode: 3 + Values: + - Value: 0x00000066 + - CStr: Type3 + - AbbrCode: 0 + - AbbrCode: 5 + Values: + - CStr: int + - AbbrCode: 5 + Values: + - CStr: char + - AbbrCode: 5 + Values: + - CStr: float + - AbbrCode: 6 + Values: + - CStr: var + - Value: 0x000000FF + - Value: 0x00000016 + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test new file mode 100644 index 00000000000000..5bc034b54df830 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-two-units-in-single-file.test @@ -0,0 +1,205 @@ +## This test checks debug info for the types located into the +## different compilation units from the single object file. +## Type definition for the "class1" should be moved to the +## artificial type unit from the first and second compilation unit. + +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: .debug_info contents: +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"__artificial_type_unit" +# CHECK: 0x[[CLASS1:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"class1" + +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU1" +# CHECK-NOT: DW_TAG_class_type +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var1" +# CHECK: DW_AT_const_value +# CHECK: DW_AT_type (0x00000000[[CLASS1]] + +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU2" +# CHECK-NOT: DW_TAG_class_type +# CHECK-NOT: "class1" +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var2" +# CHECK: DW_AT_const_value +# CHECK: DW_AT_type (0x00000000[[CLASS1]] + + + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x3c + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0x62 + offset: 0x00000410 + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x1FC + symbolnum: 1 + pcrel: true + length: 3 + extern: true + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 2 + stroff: 0x720 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU1 + - AbbrCode: 2 + Values: + - CStr: class1 + - AbbrCode: 3 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x0000001a + - AbbrCode: 0 + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU2 + - AbbrCode: 2 + Values: + - CStr: class1 + - AbbrCode: 3 + Values: + - CStr: var2 + - Value: 0x00000000 + - Value: 0x0000001a + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test new file mode 100644 index 00000000000000..1af38080c705fb --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-types-in-subprogram1.test @@ -0,0 +1,431 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: echo '---' > %t2.map +# RUN: echo "triple: 'x86_64-apple-darwin'" >> %t2.map +# RUN: echo 'objects:' >> %t2.map +# RUN: echo " - filename: '%t.o'" >> %t2.map +# RUN: echo ' symbols:' >> %t2.map +# RUN: echo ' - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }' >> %t2.map +# RUN: echo '...' >> %t2.map +# RUN: dsymutil --linker=llvm -y %t2.map -f -o - | llvm-dwarfdump -a - | FileCheck %s + +## This test checks debug info for the types located into the subprograms. +## Subprogram "float foo(int)" contains type "clas1". First compile unit +## contains partially defined class "Container" which has parametrized +## subprogram "ParametrizedFunc" which template parameter is the type +## "clas1" defined in the subprogram "foo". The second compilation unit +## contains partially defined class "Container" which has parametrized +## subprogram "ParametrizedFunc" which template parameter is the type +## "int". The type table in the final debug info should contain class +## "Container" which has two "ParametrizedFunc"(one has template parameter +## "clas1" and another has template parameter "int"). + +## class Container { +## template void ParametrizedFunc (); +## }; +## +## CU1: +## +## int foo (float) { +## class clas1 { +## char first; +## float second; +## } clas1; +## }; +## +## class Container { +## template void ParametrizedFunc (); +## }; +## +## CU2: +## +## class Container { +## template void ParametrizedFunc (); +## }; +## +## +## The final type table : +## +## class Container { +## template void ParametrizedFunc (); +## }; +## +## CU1: +## +## int foo (float) { +## class clas1 { +## char first; +## float second; +## } clas1; +## }; +## +## class Container { +## template void ParametrizedFunc (); +## }; +## +## + + +# CHECK: file format Mach-O 64-bit x86-64 +# CHECK: .debug_info contents: +# CHECK: Compile Unit: +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"__artificial_type_unit" + +# CHECK: 0x[[CHAR:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"char" + +# CHECK: 0x[[FLOAT:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"float" + +# CHECK: 0x[[INT:[0-9a-f]*]]: DW_TAG_base_type +# CHECK: DW_AT_name{{.*}}"int" + +# CHECK: 0x[[CONTAINER:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"Container" + +# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"ParametrizedFunc" +# CHECK: DW_AT_type{{.*}}[[INT]] "int" +# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int" + +# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"ParametrizedFunc" +# CHECK: DW_AT_type{{.*}}[[INT]] "int" +# CHECK: DW_TAG_template_type_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INNER_CLASS:[0-9a-f]*]] "clas1" + +# CHECK: 0x[[GLOBAL_CLASS:[0-9a-f]*]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"clas1" + +# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"first" + +# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float" + +# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"foo" +# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float" +# CHECK: DW_TAG_formal_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}0x[[INT]] "int" + +# CHECK: 0x[[INNER_CLASS]]: DW_TAG_class_type{{.*[[:space:]].*}}DW_AT_name{{.*}}"clas1" +# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"first" +# CHECK: DW_AT_type{{.*}}[[CHAR]] "char" +# CHECK: DW_TAG_member{{.*[[:space:]].*}}DW_AT_name{{.*}}"second" +# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float" + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU1" + +# CHECK: DW_TAG_subprogram{{.*[[:space:]].*}}DW_AT_name{{.*}}"foo" +# CHECK: DW_AT_type{{.*}}[[FLOAT]] "float" +# CHECK: DW_AT_low_pc +# CHECK: DW_AT_high_pc +# CHECK: DW_TAG_formal_parameter{{.*[[:space:]].*}}DW_AT_type{{.*}}[[INT]] "int" + +# CHECK-NOT: DW_TAG_class_type +# CHECK-NOT: DW_TAG_member + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var1" +# CHECK: DW_AT_type{{.*}}0x00000000[[GLOBAL_CLASS]] "clas1" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var2" +# CHECK: DW_AT_type{{.*}}0x00000000[[CONTAINER]] "Container" + +# CHECK: DW_TAG_compile_unit +# CHECK: DW_AT_name{{.*}}"CU2" + +# CHECK: DW_TAG_variable +# CHECK: DW_AT_name{{.*}}"var1" +# CHECK: DW_AT_type{{.*}}0x00000000[[CONTAINER]] "Container" + + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 2 + sizeofcmds: 376 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0x00 + vmsize: 0x300 + fileoff: 0x300 + filesize: 0x300 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __debug_abbrev + segname: __DWARF + addr: 0x000000000000000F + size: 0x90 + offset: 0x00000380 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x000000000000100 + size: 0x124 + offset: 0x00000410 + align: 0 + reloff: 0x00000600 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x2C + symbolnum: 1 + pcrel: true + length: 3 + extern: true + type: 0 + scattered: false + value: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 0x700 + nsyms: 2 + stroff: 0x720 + strsize: 10 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - '__Z3foov' + - '' +DWARF: + debug_abbrev: + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_subprogram + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_linkage_name + Form: DW_FORM_string + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + - Tag: DW_TAG_formal_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_member + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_subprogram + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_template_type_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Table: + - Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_string + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_class_type + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_subprogram + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_template_type_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + - Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_const_value + Form: DW_FORM_data4 + - Attribute: DW_AT_type + Form: DW_FORM_ref_addr + debug_info: + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU1 + - AbbrCode: 2 + Values: + - CStr: foo + - CStr: __Z3foov + - Value: 0x000000a3 + - Value: 0x00010000 + - Value: 0x00000010 + - AbbrCode: 3 + Values: + - Value: 0x00000098 + - AbbrCode: 4 + Values: + - CStr: clas1 + - AbbrCode: 5 + Values: + - CStr: first + - Value: 0x0000009d + - AbbrCode: 5 + Values: + - CStr: second + - Value: 0x000000a3 + - AbbrCode: 0 + - AbbrCode: 0 + - AbbrCode: 4 + Values: + - CStr: clas1 + - AbbrCode: 5 + Values: + - CStr: first + - Value: 0x000000a3 + - AbbrCode: 0 + - AbbrCode: 4 + Values: + - CStr: Container + - AbbrCode: 6 + Values: + - CStr: ParametrizedFunc + - Value: 0x00000098 + - AbbrCode: 7 + Values: + - Value: 0x0000003d + - AbbrCode: 0 + - AbbrCode: 0 + - AbbrCode: 8 + Values: + - CStr: int + - AbbrCode: 8 + Values: + - CStr: char + - AbbrCode: 8 + Values: + - CStr: float + - AbbrCode: 10 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x0000005d + - AbbrCode: 10 + Values: + - CStr: var2 + - Value: 0x00000000 + - Value: 0x00000070 + - AbbrCode: 0 + - Version: 4 + Entries: + - AbbrCode: 1 + Values: + - CStr: by_hand + - Value: 0x04 + - CStr: CU2 + - AbbrCode: 2 + Values: + - CStr: Container + - AbbrCode: 3 + Values: + - CStr: ParametrizedFunc + - Value: 0x00000109 + - AbbrCode: 4 + Values: + - Value: 0x00000109 + - AbbrCode: 0 + - AbbrCode: 0 + - AbbrCode: 5 + Values: + - CStr: int + - AbbrCode: 5 + Values: + - CStr: float + - AbbrCode: 6 + Values: + - CStr: var1 + - Value: 0x00000000 + - Value: 0x000000e1 + - AbbrCode: 0 +... diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp new file mode 100644 index 00000000000000..c7cb663d42febb --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/odr-uniquing.cpp @@ -0,0 +1,475 @@ +/* Compile with: + clang -g -c odr-uniquing.cpp -o odr-uniquing/1.o + cp odr-uniquing/1.o odr-uniquing/2.o + The aim of these test is to check that all the 'type types' that + should be uniqued through the ODR really are. + + The resulting object file is linked against itself using a fake + debug map. The end result is: + - with ODR uniquing: all types in second and third CUs should point back + to the types of the first CU(except types from anonymous namespace). + - without ODR uniquing: all types are re-emited in the second CU. + */ + +/* Check by llvm-dwarfdump --verify */ +// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \ +// RUN: -y %p/../dummy-debug-map.map -o - | llvm-dwarfdump --verify - | \ +// RUN: FileCheck -check-prefixes=VERIFY %s +// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \ +// RUN: -y %p/../dummy-debug-map.map -no-odr -o - | llvm-dwarfdump --verify - | \ +// RUN: FileCheck -check-prefixes=VERIFY %s + +/* Check for llvm-dwarfdump -a output */ +// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \ +// RUN: -y %p/../dummy-debug-map.map -o - | llvm-dwarfdump -v -a - | \ +// RUN: FileCheck -check-prefixes=CHECK %s +// RUN: dsymutil --linker=llvm -f -oso-prepend-path=%p/../../Inputs/odr-uniquing \ +// RUN: -y %p/../dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -a - | \ +// RUN: FileCheck -check-prefixes=CHECK-NOODR %s + +struct S { + struct Nested {}; +}; + +namespace N { +class C {}; +} // namespace N + +union U { + class C { + } C; + struct S { + } S; +}; + +typedef S AliasForS; + +namespace { +class AnonC {}; +} // namespace + +// This function is only here to hold objects that refer to the above types. +void foo() { + AliasForS s; + S::Nested n; + N::C nc; + AnonC ac; + U u; +} + +// VERIFY: Verifying .debug_abbrev... +// VERIFY: Verifying .debug_info Unit Header Chain... +// VERIFY: Verifying .debug_types Unit Header Chain... +// VERIFY: Verifying .apple_names... +// VERIFY: Verifying .apple_types... +// VERIFY: Verifying .apple_namespaces... +// VERIFY: Verifying .apple_objc... +// VERIFY: No errors. + +// The first compile unit contains all the types: +// CHECK: .debug_info contents +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_language{{.*}} (DW_LANG_C_plus_plus) +// CHECK: DW_AT_name{{.*}}"__artificial_type_unit") +// CHECK: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF1:[0-9a-f]*]]) + +// CHECK:0x[[N_NAMESPACE:[0-9a-f]*]]:{{.*}}DW_TAG_namespace +// CHECK:DW_AT_name{{.*}}"N" + +// CHECK:0x[[C_CLASS:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +// CHECK:DW_AT_name{{.*}}"C" +// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01) +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (35) + +// CHECK:0x[[S_STRUCTURE:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +// CHECK:DW_AT_name{{.*}}"S" +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (22) + +// CHECK:0x[[S_STRUCTURE_NESTED:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +// CHECK:DW_AT_name{{.*}}"Nested" +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp") +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (23) + +// CHECK:0x[[TYPEDEF_ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef +// CHECK:DW_AT_name{{.*}}"AliasForS" +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (58) + +// CHECK:0x[[U_UNION:[0-9a-f]*]]:{{.*}}DW_TAG_union_type +// CHECK:DW_AT_name{{.*}}"U" +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (45) + +// CHECK:0x[[U_C_CLASS:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +// CHECK:DW_AT_name{{.*}}"C" +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (46) + +// CHECK:0x[[U_C_MEMBER:[0-9a-f]*]]:{{.*}}DW_TAG_member +// CHECK:DW_AT_name{{.*}}"C" +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (46) + +// CHECK:0x[[U_S_MEMBER:[0-9a-f]*]]:{{.*}}DW_TAG_member +// CHECK:DW_AT_name{{.*}}"S" +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (47) + +// CHECK:0x[[U_S_STRUCT:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +// CHECK:DW_AT_name{{.*}}"S" +// CHECK-DAG:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK-DAG:DW_AT_decl_line [DW_FORM_data1] (47) + +// The second compile unit contains subprogram and its variables: +// CHECK:DW_TAG_compile_unit +// CHECK:DW_AT_name{{.*}}"odr-uniquing.cpp" +// CHECK-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF2:[0-9a-f]*]]) + +// CHECK:DW_TAG_subprogram +// CHECK:DW_AT_low_pc +// CHECK:DW_AT_high_pc +// CHECK:DW_AT_frame_base +// CHECK:DW_AT_MIPS_linkage_name{{.*}}"_Z3foov" +// CHECK:DW_AT_name{{.*}}"foo" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (74) +// CHECK:DW_AT_external + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"s" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (75) +// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[TYPEDEF_ALIASFORS]] "AliasForS + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"n" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (76) +// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[S_STRUCTURE_NESTED]] "S::Neste + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"nc" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (77) +// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[C_CLASS]] "N::C" + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"ac" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (78) +// CHECK:DW_AT_type [DW_FORM_ref4]{{.*}} {0x[[ANON_CLASS1:[0-9a-f]*]]} "(anonymous namespace)::AnonC") + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"u" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (79) +// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[U_UNION]] "U" + +// CHECK:0x[[ANON_NAMESPACE1:[0-9a-f]*]]:{{.*}}DW_TAG_namespace +// CHECK-NEXT:DW_AT_decl_file{{.*}}"{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp" + +// CHECK:0x[[ANON_CLASS1]]:{{.*}}DW_TAG_class_type +// CHECK:DW_AT_name{{.*}}"AnonC" +// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01) +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (65) + +// The third compile unit contains subprogram and its variables: +// CHECK:DW_TAG_compile_unit +// CHECK:DW_AT_name{{.*}}"odr-uniquing.cpp" +// CHECK-NEXT:DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF3:[0-9a-f]*]]) + +// CHECK:DW_TAG_subprogram +// CHECK:DW_AT_low_pc +// CHECK:DW_AT_high_pc +// CHECK:DW_AT_frame_base +// CHECK:DW_AT_MIPS_linkage_name{{.*}}"_Z3foov" +// CHECK:DW_AT_name{{.*}}"foo" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (74) +// CHECK:DW_AT_external + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"s" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (75) +// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[TYPEDEF_ALIASFORS]] "AliasForS + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"n" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (76) +// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[S_STRUCTURE_NESTED]] "S::Neste + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"nc" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (77) +// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[C_CLASS]] "N::C" + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"ac" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (78) +// CHECK:DW_AT_type [DW_FORM_ref4]{{.*}} {0x[[ANON_CLASS2:[0-9a-f]*]]} "(anonymous namespace)::AnonC") + +// CHECK:DW_TAG_variable +// CHECK:DW_AT_name{{.*}}"u" +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (79) +// CHECK:DW_AT_type [DW_FORM_ref_addr] (0x{{0*}}[[U_UNION]] "U" + +// CHECK:0x[[ANON_NAMESPACE2:[0-9a-f]*]]:{{.*}}DW_TAG_namespace +// CHECK-NEXT:DW_AT_decl_file{{.*}}"{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp" + +// CHECK:0x[[ANON_CLASS2]]:{{.*}}DW_TAG_class_type +// CHECK:DW_AT_name{{.*}}"AnonC" +// CHECK:DW_AT_byte_size [DW_FORM_data1] (0x01) +// CHECK:DW_AT_decl_file [DW_FORM_data1] ("{{[\\/]}}tmp{{[\\/]}}odr-uniquing.cpp +// CHECK:DW_AT_decl_line [DW_FORM_data1] (65) + +// CHECK:.debug_aranges contents + +// CHECK:debug_line[0x[[LINE_TABLE_OFF1]]] + +// CHECK:debug_line[0x[[LINE_TABLE_OFF2]]] + +// CHECK:debug_line[0x[[LINE_TABLE_OFF3]]] + +// CHECK:.debug_str contents: +// CHECK:0x00000000: "" +// CHECK:0x00000001: "clang version 3.8.0 (trunk 244290) (llvm/trunk 244270)" +// CHECK:0x00000038: "odr-uniquing.cpp" +// CHECK:0x00000049: "/tmp" +// CHECK:0x0000004e: "_Z3foov" +// CHECK:0x00000056: "foo" +// CHECK:0x0000005a: "s" +// CHECK:0x0000005c: "n" +// CHECK:0x0000005e: "nc" +// CHECK:0x00000061: "ac" +// CHECK:0x00000064: "u" +// CHECK:0x00000066: "AnonC" +// CHECK:0x0000006c: "(anonymous namespace)" +// CHECK:0x00000082: "llvm DWARFLinkerParallel library version " +// CHECK:0x000000ac: "__artificial_type_unit" +// CHECK:0x000000c3: "" +// CHECK:0x000000c4: "AliasForS" +// CHECK:0x000000ce: "C" +// CHECK:0x000000d0: "N" +// CHECK:0x000000d2: "Nested" +// CHECK:0x000000d9: "S" +// CHECK:0x000000db: "U" + + +// CHECK:.apple_names +// CHECK: Bucket count: 2 +// CHECK: String: {{.*}} "foo" +// CHECK: String: {{.*}} "_Z3foov" + +// CHECK:.apple_types +// CHECK: Bucket count: 6 +// CHECK: String: {{.*}} "AnonC" +// CHECK: String: {{.*}} "Nested" +// CHECK: String: {{.*}} "S" +// CHECK: String: {{.*}} "C" +// CHECK: String: {{.*}} "U" +// CHECK: String: {{.*}} "AliasForS" + +// CHECK:.apple_namespaces +// CHECK: Bucket count: 2 +// CHECK: String: {{.*}} "(anonymous namespace)" +// CHECK: String: {{.*}} "N" + +// CHECK:.apple_objc +// CHECK:Bucket count: 1 + +// CHECK-NOODR: .debug_info contents + +// CHECK-NOODR: DW_TAG_compile_unit +// CHECK-NOODR: DW_AT_name{{.*}}"odr-uniquing.cpp" +// CHECK-NOODR-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF1:[0-9a-f]*]]) +// CHECK-NOODR: DW_AT_low_pc{{.*}}(0x{{0*}}[[LOW_PC1:[0-9a-f]*]]) +// CHECK-NOODR-NEXT: DW_AT_high_pc{{.*}}(0x{{0*}}[[HIGH_PC1:[0-9a-f]*]]) + +// CHECK-NOODR: DW_TAG_structure_type +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S" + +// CHECK-NOODR: DW_TAG_structure_type +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"Nested" + +// CHECK-NOODR: DW_TAG_namespace +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"N" + +// CHECK-NOODR: DW_TAG_class_type +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C" + +// CHECK-NOODR: DW_TAG_union_type +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"U" + +// CHECK-NOODR: DW_TAG_member +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C" + +// CHECK-NOODR: DW_TAG_class_type +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"C" + +// CHECK-NOODR: DW_TAG_member +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S" + +// CHECK-NOODR: DW_TAG_structure_type +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"S" + +// CHECK-NOODR: DW_TAG_subprogram +// CHECK-NOODR-NEXT: DW_AT_low_pc +// CHECK-NOODR-NEXT: DW_AT_high_pc +// CHECK-NOODR: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov" +// CHECK-NOODR-NEXT: DW_AT_name{{.*}}"foo" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"s" +// CHECK-NOODR: DW_AT_type{{.*}}"AliasForS" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"n" +// CHECK-NOODR: DW_AT_type{{.*}}"S::Nested" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"nc" +// CHECK-NOODR: DW_AT_type{{.*}}"N::C" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"ac" +// CHECK-NOODR: DW_AT_type{{.*}}"(anonymous namespace)::AnonC" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"u" +// CHECK-NOODR: DW_AT_type{{.*}}"U" + +// CHECK-NOODR: DW_TAG_typedef +// CHECK-NOODR: DW_AT_type{{.*}}"S" +// CHECK-NOODR: DW_AT_name{{.*}}"AliasForS" + +// CHECK-NOODR: DW_TAG_namespace + +// CHECK-NOODR: DW_TAG_class_type +// CHECK-NOODR: DW_AT_name{{.*}}"AnonC" + +// CHECK-NOODR: DW_TAG_compile_unit +// CHECK-NOODR: DW_AT_name{{.*}}"odr-uniquing.cpp" +// CHECK-NOODR-NEXT: DW_AT_stmt_list{{.*}}(0x[[LINE_TABLE_OFF2:[0-9a-f]*]]) +// CHECK-NOODR: DW_AT_low_pc +// CHECK-NOODR: DW_AT_high_pc + +// CHECK-NOODR: DW_TAG_structure_type +// CHECK-NOODR: DW_AT_name{{.*}}"S" + +// CHECK-NOODR: DW_TAG_structure_type +// CHECK-NOODR: DW_AT_name{{.*}}"Nested" + +// CHECK-NOODR: DW_TAG_namespace +// CHECK-NOODR: DW_AT_name{{.*}}"N" + +// CHECK-NOODR: DW_TAG_class_type +// CHECK-NOODR: DW_AT_name{{.*}}"C" + +// CHECK-NOODR: DW_TAG_union_type +// CHECK-NOODR: DW_AT_name{{.*}}"U" + +// CHECK-NOODR: DW_TAG_member +// CHECK-NOODR: DW_AT_name{{.*}}"C" +// CHECK-NOODR: DW_AT_type{{.*}}"U::C" + +// CHECK-NOODR: DW_TAG_class_type +// CHECK-NOODR: DW_AT_name{{.*}}"C" + +// CHECK-NOODR: DW_TAG_member +// CHECK-NOODR: DW_AT_name{{.*}}"S" +// CHECK-NOODR: DW_AT_type{{.*}}"U::S" + +// CHECK-NOODR: DW_TAG_structure_type +// CHECK-NOODR: DW_AT_name{{.*}}"S" + +// CHECK-NOODR: DW_TAG_subprogram +// CHECK-NOODR: DW_AT_low_pc +// CHECK-NOODR: DW_AT_high_pc +// CHECK-NOODR: DW_AT_MIPS_linkage_name{{.*}}"_Z3foov" +// CHECK-NOODR: DW_AT_name{{.*}}"foo" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"s" +// CHECK-NOODR: DW_AT_type{{.*}}"AliasForS" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"n" +// CHECK-NOODR: DW_AT_type{{.*}}"S::Nested" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"nc" +// CHECK-NOODR: DW_AT_type{{.*}} "N::C" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"ac" +// CHECK-NOODR: DW_AT_type{{.*}}"(anonymous namespace)::AnonC" + +// CHECK-NOODR: DW_TAG_variable +// CHECK-NOODR: DW_AT_name{{.*}}"u" +// CHECK-NOODR: DW_AT_type{{.*}}"U" + +// CHECK-NOODR: DW_TAG_typedef +// CHECK-NOODR: DW_AT_type{{.*}}"S" +// CHECK-NOODR: DW_AT_name{{.*}}"AliasForS" + +// CHECK-NOODR: DW_TAG_namespace + +// CHECK-NOODR: DW_TAG_class_type +// CHECK-NOODR: DW_AT_name{{.*}}"AnonC" + +// CHECK-NOODR:.debug_aranges contents + +// CHECK-NOODR:debug_line[0x[[LINE_TABLE_OFF1]]] + +// CHECK-NOODR:debug_line[0x[[LINE_TABLE_OFF2]]] + +// CHECK-NOODR:.debug_str contents: +// CHECK-NOODR:0x00000000: "" +// CHECK-NOODR:0x00000001: "clang version 3.8.0 (trunk 244290) (llvm/trunk 244270)" +// CHECK-NOODR:0x00000038: "odr-uniquing.cpp" +// CHECK-NOODR:0x00000049: "/tmp" +// CHECK-NOODR:0x0000004e: "S" +// CHECK-NOODR:0x00000050: "Nested" +// CHECK-NOODR:0x00000057: "N" +// CHECK-NOODR:0x00000059: "C" +// CHECK-NOODR:0x0000005b: "U" +// CHECK-NOODR:0x0000005d: "_Z3foov" +// CHECK-NOODR:0x00000065: "foo" +// CHECK-NOODR:0x00000069: "s" +// CHECK-NOODR:0x0000006b: "n" +// CHECK-NOODR:0x0000006d: "nc" +// CHECK-NOODR:0x00000070: "ac" +// CHECK-NOODR:0x00000073: "u" +// CHECK-NOODR:0x00000075: "AliasForS" +// CHECK-NOODR:0x0000007f: "AnonC" +// CHECK-NOODR:0x00000085: "(anonymous namespace)" + +// CHECK-NOODR: .apple_names +// CHECK-NOODR: Bucket count: 2 +// CHECK-NOODR: String: {{.*}} "foo" +// CHECK-NOODR: String: {{.*}} "_Z3foov" + +// CHECK-NOODR: .apple_types +// CHECK-NOODR: Bucket count: 6 +// CHECK-NOODR: String: {{.*}} "AnonC" +// CHECK-NOODR: String: {{.*}} "Nested" +// CHECK-NOODR: String: {{.*}} "S" +// CHECK-NOODR: String: {{.*}} "C" +// CHECK-NOODR: String: {{.*}} "U" +// CHECK-NOODR: String: {{.*}} "AliasForS" + +// CHECK-NOODR: .apple_namespaces +// CHECK-NOODR: Bucket count: 2 +// CHECK-NOODR: String: {{.*}} "(anonymous namespace)" +// CHECK-NOODR: String: {{.*}} "N" + +// CHECK-NOODR: .apple_objc +// CHECK-NOODR:Bucket count: 1 diff --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o new file mode 100644 index 0000000000000000000000000000000000000000..a837de81a4f295dc6f3d8d625bfc7f508f311b3d GIT binary patch literal 47448 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 [0x0000000100000f79, 0x0000000100000f96) -#DWARF-CHECK: 0x00000011: [DW_RLE_offset_pair ]: 0x0000000000000034, 0x000000000000003b => [0x0000000100000fad, 0x0000000100000fb4) +#DWARF-CHECK: 0x0000000e: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x000000000000001d +#DWARF-CHECK: 0x00000011: [DW_RLE_offset_pair ]: 0x0000000000000034, 0x000000000000003b #DWARF-CHECK: 0x00000014: [DW_RLE_end_of_list ] # #UPD-DWARF-CHECK: DW_TAG_compile_unit diff --git a/llvm/test/tools/dsymutil/X86/empty-CU.test b/llvm/test/tools/dsymutil/X86/empty-CU.test index db9f70874971b3..7b06607a74cbc0 100644 --- a/llvm/test/tools/dsymutil/X86/empty-CU.test +++ b/llvm/test/tools/dsymutil/X86/empty-CU.test @@ -1,8 +1,6 @@ RUN: llvm-mc %p/../Inputs/empty-CU.s -filetype obj -triple x86_64-apple-darwin -o %t.o RUN: dsymutil --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s -RUN: dsymutil --linker llvm --update -f %t.o -o - | llvm-dwarfdump -v - -debug-info | FileCheck %s - CHECK: .debug_info contents: CHECK: 0x00000000: Compile Unit: length = 0x00000008, format = DWARF32, version = 0x0003, abbr_offset = 0x0000, addr_size = 0x04 (next unit at 0x0000000c) diff --git a/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp b/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp index e933be8fd9bdb0..928b14b62bc672 100644 --- a/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp +++ b/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp @@ -1,9 +1,15 @@ -// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" - -// RUN: dsymutil --linker llvm -f -y %p/dummy-debug-map.map -oso-prepend-path \ -// RUN: %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | \ -// RUN: FileCheck %s --implicit-check-not \ -// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" +// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path \ +// RUN: %p/../Inputs/inlined-static-variable -o - -keep-function-for-static \ +// RUN: | llvm-dwarfdump - | FileCheck %s --implicit-check-not \ +// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \ +// RUN: --check-prefixes=CHECK +// +// RUN: dsymutil --linker llvm --no-odr -f -y %p/dummy-debug-map.map \ +// RUN: -oso-prepend-path %p/../Inputs/inlined-static-variable -o - \ +// RUN: -keep-function-for-static | llvm-dwarfdump - | FileCheck %s \ +// RUN: --implicit-check-not \ +// RUN: "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" \ +// RUN: --check-prefixes=CHECK // clang -g -c inlined-static-variable.cpp -o 4.o diff --git a/llvm/test/tools/dsymutil/X86/keep-func.test b/llvm/test/tools/dsymutil/X86/keep-func.test index f307f5ad89900d..021c7212bd8319 100644 --- a/llvm/test/tools/dsymutil/X86/keep-func.test +++ b/llvm/test/tools/dsymutil/X86/keep-func.test @@ -25,11 +25,6 @@ RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/ RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP -RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.omit.dSYM -RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/keep_func/main.out -o %t.keep.dSYM -keep-function-for-static -RUN: llvm-dwarfdump %t.omit.dSYM | FileCheck %s --check-prefix OMIT -RUN: llvm-dwarfdump %t.keep.dSYM | FileCheck %s --check-prefix KEEP - KEEP: DW_AT_name ("MyDummyVar") KEEP: DW_AT_name ("FOO_VAR_TYPE") KEEP: DW_AT_name ("x1") diff --git a/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test b/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test new file mode 100644 index 00000000000000..627df30344d8b7 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/linker-llvm-union-fwd-decl.test @@ -0,0 +1,65 @@ +Test binaries created with the following commands: + +$ cat container.cpp +#include "container.h" +#include + +struct Container_ivars { + // real definition here +}; + +ContainerPtr allocateContainer() { + Container *c = (Container *)malloc(sizeof(Container)); + c->ivars = (Container_ivars *)malloc(sizeof(Container_ivars)); + return c; +} + +extern void doSomething(ContainerPtr); + +int main() { + ContainerPtr c = allocateContainer(); + doSomething(c); + return 0; +} + +$ cat container.h +struct Container_ivars; + +struct Container { + union { + struct Container_ivars *ivars; + }; +}; + +typedef Container *ContainerPtr; + +$ cat use.cpp +#include "container.h" + +void doSomething(ContainerPtr c) {} + + +$ clang++ -O0 -g container.cpp -c -o container.o +$ clang++ -O0 -g use.cpp -c -o use.o +$ clang++ use.o container.o -o a.out + +Note that the link order in the last command matters for this test. + +RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM +RUN: llvm-dwarfdump --debug-info %t.dSYM | FileCheck %s + +CHECK: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer ("llvm DWARFLinkerParallel library +CHECK-NEXT: DW_AT_language (DW_LANG_C_plus_plus_14) +CHECK-NEXT: DW_AT_name ("__artificial_type_unit") +CHECK-NEXT: DW_AT_stmt_list (0x00000000) + +CHECK: DW_TAG_structure_type +CHECK: DW_AT_calling_convention (DW_CC_pass_by_value) +CHECK: DW_AT_name ("Container_ivars") +CHECK-NEXT: DW_AT_byte_size (0x01) +CHECK-NEXT: DW_AT_decl_line (4) +CHECK-NEXT: DW_AT_decl_file ("{{.*}}container.cpp") + +CHECK: DW_TAG_compile_unit +CHECK-NOT: DW_AT_declaration diff --git a/llvm/test/tools/dsymutil/X86/location-expression.test b/llvm/test/tools/dsymutil/X86/location-expression.test index 5414dff3745b28..3bffc9aeacca77 100644 --- a/llvm/test/tools/dsymutil/X86/location-expression.test +++ b/llvm/test/tools/dsymutil/X86/location-expression.test @@ -18,15 +18,15 @@ # CHECK: Compile Unit: # CHECK: DW_TAG_compile_unit # CHECK: DW_AT_name{{.*}}"CU1" -# CHECK: 0x0000001b: DW_TAG_variable +# CHECK: DW_TAG_variable # CHECK: DW_AT_name {{.*}}"var1" # CHECK: DW_AT_type {{.*}}"class1" # CHECK: DW_AT_location [DW_FORM_block1] (DW_OP_const8u 0x{{.*}}, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address) -# CHECK: 0x000000ab: DW_TAG_variable +# CHECK: DW_TAG_variable # CHECK: DW_AT_name {{.*}}"var2" # CHECK: DW_AT_type {{.*}}"class1" # CHECK: DW_AT_location [DW_FORM_block] (DW_OP_const8u 0x{{.*}}, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address, DW_OP_const8u 0x2000, DW_OP_form_tls_address) -# CHECK: 0x00000146: DW_TAG_variable +# CHECK: DW_TAG_variable # CHECK: DW_AT_name {{.*}}"var3" # CHECK: DW_AT_type {{.*}}"class1" # diff --git a/llvm/test/tools/dsymutil/X86/modules-empty.m b/llvm/test/tools/dsymutil/X86/modules-empty.m index fc415acc59f6d6..eb70f51230de91 100644 --- a/llvm/test/tools/dsymutil/X86/modules-empty.m +++ b/llvm/test/tools/dsymutil/X86/modules-empty.m @@ -29,6 +29,6 @@ int main() { } // The empty CU from the pcm should not get copied into the dSYM. -// CHECK: DW_TAG_compile_unit -// CHECK-NOT: DW_TAG_compile_unit - +// Check that module name occured only once. +// CHECK: "Empty" +// CHECK-NOT: "Empty" diff --git a/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp b/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp index 0e3b974ba00593..d87bb5b73c240e 100644 --- a/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp +++ b/llvm/test/tools/dsymutil/X86/odr-uniquing.cpp @@ -14,6 +14,8 @@ // RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=ODR,CHECK %s // RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=NOODR,CHECK %s +// RUN: dsymutil --linker llvm -f -oso-prepend-path=%p/../Inputs/odr-uniquing -y %p/dummy-debug-map.map -no-odr -o - | llvm-dwarfdump -v -debug-info - | FileCheck -check-prefixes=NOODR,CHECK %s + // The first compile unit contains all the types: // CHECK: TAG_compile_unit // CHECK-NOT: DW_TAG diff --git a/llvm/test/tools/dsymutil/X86/op-convert.test b/llvm/test/tools/dsymutil/X86/op-convert.test index 15725a0435d488..9960d1996496d6 100644 --- a/llvm/test/tools/dsymutil/X86/op-convert.test +++ b/llvm/test/tools/dsymutil/X86/op-convert.test @@ -12,21 +12,23 @@ objects: - { sym: _foo, objAddr: 0x0, binAddr: 0x1000, size: 0x4 } ... +CHECK: DW_TAG_compile_unit +CHECK: DW_AT_name ("dbg.c") -CHECK: DW_TAG_base_type +CHECK:0x[[ADDR1:[0-9a-f]+]]: DW_TAG_base_type CHECK-NEXT: DW_AT_name ("DW_ATE_signed_8") CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) CHECK-NEXT: DW_AT_byte_size (0x01) -CHECK: DW_TAG_base_type +CHECK:0x[[ADDR2:[0-9a-f]+]]: DW_TAG_base_type CHECK-NEXT: DW_AT_name ("DW_ATE_signed_32") CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) CHECK-NEXT: DW_AT_byte_size (0x04) CHECK: DW_TAG_variable CHECK-NEXT: DW_AT_location ( -CHECK-NEXT: [0x0000000000001000, 0x0000000000001002): DW_OP_breg5 RDI+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x0000002a) "DW_ATE_signed_8", DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value -CHECK-NEXT: [0x0000000000001002, 0x0000000000001003): DW_OP_breg0 RAX+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x0000002a) "DW_ATE_signed_8", DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value) +CHECK-NEXT: [0x0000000000001000, 0x0000000000001002): DW_OP_breg5 RDI+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x[[ADDR1]]) "DW_ATE_signed_8", DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value +CHECK-NEXT: [0x0000000000001002, 0x0000000000001003): DW_OP_breg0 RAX+0, DW_OP_constu 0xffffffff, DW_OP_and, DW_OP_convert (0x[[ADDR1]]) "DW_ATE_signed_8", DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value) CHECK-NEXT: DW_AT_name ("y") CHECK: DW_TAG_variable @@ -34,6 +36,6 @@ CHECK-NEXT: DW_AT_location (DW_OP_constu 0x33, DW_OP_convert 0x0, DW_OP_stac CHECK-NEXT: DW_AT_name ("d") CHECK: DW_TAG_variable -CHECK-NEXT: DW_AT_location (DW_OP_constu 0x2a, DW_OP_convert (0x00000031) "DW_ATE_signed_32", DW_OP_stack_value) +CHECK-NEXT: DW_AT_location (DW_OP_constu 0x2a, DW_OP_convert (0x[[ADDR2]]) "DW_ATE_signed_32", DW_OP_stack_value) CHECK-NEXT: DW_AT_name ("c") diff --git a/llvm/test/tools/dsymutil/X86/union-fwd-decl.test b/llvm/test/tools/dsymutil/X86/union-fwd-decl.test index c5c8c9e93e0a06..c73db0e3f5532e 100644 --- a/llvm/test/tools/dsymutil/X86/union-fwd-decl.test +++ b/llvm/test/tools/dsymutil/X86/union-fwd-decl.test @@ -48,9 +48,6 @@ Note that the link order in the last command matters for this test. RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -RUN: dsymutil --linker llvm -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/union/a.out -o %t.dSYM -RUN: llvm-dwarfdump %t.dSYM | FileCheck %s - CHECK: DW_TAG_compile_unit CHECK: DW_AT_name ("Container_ivars") diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test index 90c40fd1e4ab62..b63668c39c9018 100644 --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-addresses.test @@ -39,7 +39,7 @@ #DWARF-CHECK: DW_AT_name [DW_FORM_strx] {{.*}} "CU1" #DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000001130) #DWARF-CHECK: DW_AT_high_pc [DW_FORM_data8] (0x0000000000000060) -#DWARF-CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +#DWARF-CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] #DWARF-CHECK: DW_TAG_subprogram #DWARF-CHECK: DW_AT_name [DW_FORM_strx] {{.*}} "foo1" #DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000001130) diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test index 78b53897346c48..a1bb3ec7d846d8 100644 --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-rnglists.test @@ -35,7 +35,7 @@ #DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000001130) #DWARF-CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[CURANGE_OFF:[0-9a-f]*]] #DWARF-CHECK: [0x0000000000001130, 0x0000000000001170)) -#DWARF-CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] (0x00000008) +#DWARF-CHECK: DW_AT_str_offsets_base [DW_FORM_sec_offset] #DWARF-CHECK: DW_TAG_subprogram #DWARF-CHECK: DW_AT_name [DW_FORM_strx] {{.*}} "foo1" #DWARF-CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed (00000000) address = 0x0000000000001130) @@ -65,7 +65,7 @@ #DWARF-CHECK: DW_AT_ranges [DW_FORM_sec_offset] (0x[[F4RANGE_OFF:[0-9a-f]*]] #DWARF-CHECK: [0x0000000000001160, 0x0000000000001170)) #DWARF-CHECK: .debug_aranges contents: -#DWARF-CHECK: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x08, seg_size = 0x00 +#DWARF-CHECK: Address Range Header: length = 0x0000002c, format = DWARF32, version = 0x0002, cu_offset = 0x000000{{00|21}}, addr_size = 0x08, seg_size = 0x00 #DWARF-CHECK: [0x0000000000001130, 0x0000000000001170) #DWARF-CHECK: .debug_addr contents: #DWARF-CHECK: 0x00000000: Address table header: length = 0x00000024, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00 @@ -79,19 +79,19 @@ #DWARF-CHECK: 0x00000000: range list header: length = 0x00000026, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 #DWARF-CHECK: ranges: #DWARF-CHECK: 0x[[F1RANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000000 -#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001130, 0x0000000000001140) +#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ] #DWARF-CHECK: 0x[[F2RANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000001 -#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001140, 0x0000000000001150) +#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ] #DWARF-CHECK: 0x[[F3RANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000002 -#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001150, 0x0000000000001160) +#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ] #DWARF-CHECK: 0x[[F4RANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000003 -#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001160, 0x0000000000001170) +#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000010 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ] #DWARF-CHECK 0x[[CURANGE_OFF]]: [DW_RLE_base_addressx]: 0x0000000000000000 -#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000040 => [0x0000000000001130, 0x0000000000001170) +#DWARF-CHECK: {{.}}: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x0000000000000040 #DWARF-CHECK: {{.}}: [DW_RLE_end_of_list ] #UPD-DWARF-CHECK: DW_TAG_compile_unit @@ -145,15 +145,15 @@ #UPD-DWARF-CHECK: 0x00000032 => 0x0000003e #UPD-DWARF-CHECK: ] #UPD-DWARF-CHECK: ranges: -#UPD-DWARF-CHECK: 0x00000020: [DW_RLE_startx_length]: 0x0000000000000000, 0x0000000000000010 => [0x0000000000001130, 0x0000000000001140) +#UPD-DWARF-CHECK: 0x00000020: [DW_RLE_startx_length]: 0x0000000000000000, 0x0000000000000010 #UPD-DWARF-CHECK: 0x00000023: [DW_RLE_end_of_list ] -#UPD-DWARF-CHECK: 0x00000024: [DW_RLE_startx_length]: 0x0000000000000001, 0x0000000000000010 => [0x0000000000001140, 0x0000000000001150) +#UPD-DWARF-CHECK: 0x00000024: [DW_RLE_startx_length]: 0x0000000000000001, 0x0000000000000010 #UPD-DWARF-CHECK: 0x00000027: [DW_RLE_end_of_list ] -#UPD-DWARF-CHECK: 0x00000028: [DW_RLE_start_length ]: 0x0000000000001150, 0x0000000000000010 => [0x0000000000001150, 0x0000000000001160) +#UPD-DWARF-CHECK: 0x00000028: [DW_RLE_start_length ]: 0x0000000000001150, 0x0000000000000010 #UPD-DWARF-CHECK: 0x00000032: [DW_RLE_end_of_list ] -#UPD-DWARF-CHECK: 0x00000033: [DW_RLE_start_length ]: 0x0000000000001160, 0x0000000000000010 => [0x0000000000001160, 0x0000000000001170) +#UPD-DWARF-CHECK: 0x00000033: [DW_RLE_start_length ]: 0x0000000000001160, 0x0000000000000010 #UPD-DWARF-CHECK: 0x0000003d: [DW_RLE_end_of_list ] -#UPD-DWARF-CHECK: 0x0000003e: [DW_RLE_startx_length]: 0x0000000000000000, 0x0000000000000040 => [0x0000000000001130, 0x0000000000001170) +#UPD-DWARF-CHECK: 0x0000003e: [DW_RLE_startx_length]: 0x0000000000000000, 0x0000000000000040 #UPD-DWARF-CHECK: 0x00000041: [DW_RLE_end_of_list ] ## Following yaml description has Content of the .debug_rnglists exactly like above data ^^^^^^ diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test index 90cb99858c9efc..2c4caa158258d2 100644 --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test @@ -3,23 +3,23 @@ # RUN: yaml2obj %s -o %t.o -# RUN: llvm-dwarfutil %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC +# RUN: llvm-dwarfutil --no-odr %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC -# RUN: llvm-dwarfutil --linker apple %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC +# RUN: llvm-dwarfutil --no-odr --linker apple %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC -# RUN: llvm-dwarfutil --linker llvm %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC +# RUN: llvm-dwarfutil --no-odr --linker llvm %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC -# RUN: llvm-dwarfutil --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC +# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC -# RUN: llvm-dwarfutil --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC +# RUN: llvm-dwarfutil --no-odr --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC -# RUN: llvm-dwarfutil --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC +# RUN: llvm-dwarfutil --no-odr --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC -# RUN: llvm-dwarfutil --linker llvm --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC +# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC -# RUN: llvm-dwarfutil %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC +# RUN: llvm-dwarfutil --no-odr %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC -# RUN: llvm-dwarfutil --linker llvm %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC +# RUN: llvm-dwarfutil --no-odr --linker llvm %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC # CHECK: DW_TAG_compile_unit # CHECK: DW_AT_name{{.*}}"CU1" diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test index 232f6a5553e571..46ebcf24fe64dc 100644 --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-func-overlapping-address-ranges.test @@ -2,10 +2,10 @@ ## are combined during --garbage-collection optimisation. # RUN: yaml2obj %s -o %t.o -# RUN: llvm-dwarfutil --garbage-collection %t.o %t1 +# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o %t1 # RUN: llvm-dwarfdump -a %t1 | FileCheck %s -# RUN: llvm-dwarfutil --linker llvm --garbage-collection %t.o %t1 +# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection %t.o %t1 # RUN: llvm-dwarfdump -a %t1 | FileCheck %s # CHECK: DW_TAG_compile_unit diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test index cb3b435ea9aa4c..7f0533a882dd8b 100644 --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-maxpc.test @@ -3,11 +3,11 @@ ## RUN: yaml2obj %s -o %t.o -# RUN: llvm-dwarfutil --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s -# RUN: llvm-dwarfutil --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s +# RUN: llvm-dwarfutil --no-odr --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s +# RUN: llvm-dwarfutil --no-odr --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s -# RUN: llvm-dwarfutil --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s -# RUN: llvm-dwarfutil --linker llvm --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s +# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s +# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=universal --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s # CHECK: DW_TAG_compile_unit # CHECK: DW_AT_name{{.*}}"CU1" diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test index 1f5ddd78adaa24..1a3f29d127cefc 100644 --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-no-garbage.test @@ -2,9 +2,9 @@ ## does not affect files which do not have dead debug info. # RUN: yaml2obj %s -o %t.o -# RUN: llvm-dwarfutil --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s +# RUN: llvm-dwarfutil --no-odr --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s -# RUN: llvm-dwarfutil --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s +# RUN: llvm-dwarfutil --no-odr --linker llvm --tombstone=maxpc --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s # CHECK: DW_TAG_compile_unit # CHECK: DW_AT_name{{.*}}"CU1" diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test index 2ee1d73b6f92f0..1a8010e364d25a 100644 --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-unit-overlapping-address-ranges.test @@ -3,10 +3,10 @@ ## optimisation. # RUN: yaml2obj %s -o %t.o -# RUN: llvm-dwarfutil --garbage-collection %t.o %t1 +# RUN: llvm-dwarfutil --no-odr --garbage-collection %t.o %t1 # RUN: llvm-dwarfdump -a %t1 | FileCheck %s -# RUN: llvm-dwarfutil --linker llvm --garbage-collection %t.o %t1 +# RUN: llvm-dwarfutil --no-odr --linker llvm --garbage-collection %t.o %t1 # RUN: llvm-dwarfdump -a %t1 | FileCheck %s # CHECK: DW_TAG_compile_unit diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp index a1f18e6f169db9..d00ef1a8c228b0 100644 --- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp @@ -1059,7 +1059,6 @@ DwarfLinkerForBinary::AddressManager::hasValidRelocationAt( uint64_t EndOffset) { std::vector Relocs = getRelocations(AllRelocs, StartOffset, EndOffset); - if (Relocs.size() == 0) return std::nullopt;