diff --git a/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp b/llvm/lib/DWARFLinkerParallel/AcceleratorRecordsSaver.cpp new file mode 100644 index 0000000000000..5ec25cfe5fd26 --- /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 0000000000000..5e7f4d0c3166f --- /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 58d550982c8df..def83f91bc6f3 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 d321ecf8d5ce8..b0f0b3910e586 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 d05fd8d61b857..81fc57f7cabbb 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 74d80e1314801..e18c0a15cefc6 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 c0bbce0f52014..42bf00f55ff18 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 f082fd6036100..269f24b1a13b9 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 c1181a264f879..48e7cb1fd7e2f 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 54666f684f3a3..39e010fd63239 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 78d0b5468d049..220739a1214c6 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 a755d540aef99..c49b9ef0cdf98 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 45dc506b9947e..60018eea121f2 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 0000000000000..9d5c213085c29 --- /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 0000000000000..97e620eee0c42 --- /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 1503015f01557..b1da1900d65ef 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 0835fad1e667a..9640a8ee711eb 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 4aef0d0d67303..fc7f8cbc4a8e7 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 3a69c3821e8b5..8767cc0fc6e77 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 69e57bc3ea4d2..abd5371471eb9 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 8e7caa7bb4074..9c3e3ebd220aa 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 b101ac61935c5..f23b2efb869da 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 0000000000000..e0900f7a8e3d3 --- /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 0000000000000..c9dce4e94fb0d --- /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 0000000000000..bbb3261027ce8 --- /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 0000000000000..91f9dca46a82b --- /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 0000000000000..3f75991cdc471 --- /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 f1680ced6e5b4..057e89d060b1d 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 00dcde718e362..ca4a951e770ba 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 324a156484119..0199bf28681bc 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 3008db9a0d63c..13409b2a07a31 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 ac813fc620370..73decc497ea36 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 0000000000000..a94d06f2ab64d --- /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 0000000000000..b2d178cee0282 --- /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 0000000000000..97d7e630e7c67 --- /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 0000000000000..6d8757391d6c6 --- /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 0000000000000..16aacd57517bd --- /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 0000000000000..3e8d8557689e3 --- /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 0000000000000..439b7d76bb69b --- /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 0000000000000..9758e4ad42130 --- /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 0000000000000..7135c46630e13 --- /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 0000000000000..6c31b48978e98 --- /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 0000000000000..22a142ab97657 --- /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 0000000000000..35d3261e591cb --- /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 0000000000000..7c1c0d1b52e0e --- /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 0000000000000..187a2ea9ecffd --- /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 0000000000000..93925c61c46b8 --- /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 0000000000000..619bc8c15b822 --- /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 0000000000000..a8fc3e82311ca --- /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 0000000000000..67b5616ebd592 --- /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 0000000000000..5bc034b54df83 --- /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 0000000000000..1af38080c705f --- /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 0000000000000..c7cb663d42feb --- /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 0000000000000..a837de81a4f29 Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo1.o differ diff --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o new file mode 100644 index 0000000000000..a0d093389d424 Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo2.o differ diff --git a/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o b/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o new file mode 100644 index 0000000000000..9b3a9acd4a6cd Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/foo3.o differ diff --git a/llvm/test/tools/dsymutil/X86/Inputs/String/main.o b/llvm/test/tools/dsymutil/X86/Inputs/String/main.o new file mode 100644 index 0000000000000..29716a88f5c07 Binary files /dev/null and b/llvm/test/tools/dsymutil/X86/Inputs/String/main.o differ diff --git a/llvm/test/tools/dsymutil/X86/dead-stripped.cpp b/llvm/test/tools/dsymutil/X86/dead-stripped.cpp index 8a72aee6fb38f..6ea5ef22a65ac 100644 --- a/llvm/test/tools/dsymutil/X86/dead-stripped.cpp +++ b/llvm/test/tools/dsymutil/X86/dead-stripped.cpp @@ -1,10 +1,5 @@ // RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | 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/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}}" - // The test was compiled with: // clang++ -O2 -g -c dead-strip.cpp -o 1.o diff --git a/llvm/test/tools/dsymutil/X86/dummy-debug-map.map b/llvm/test/tools/dsymutil/X86/dummy-debug-map.map index 95b1f726d4ff9..ec5d8e4f15031 100644 --- a/llvm/test/tools/dsymutil/X86/dummy-debug-map.map +++ b/llvm/test/tools/dsymutil/X86/dummy-debug-map.map @@ -16,8 +16,8 @@ objects: - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x20000, size: 0x10 } - filename: 3.o symbols: - - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x30000, size: 0x10 } - - { sym: __ZN1S3bazIiEEvT_, objAddr: 0x0, binAddr: 0x30010, size: 0x10 } + - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x30000, size: 0x20 } + - { sym: __ZN1S3bazIiEEvT_, objAddr: 0x0, binAddr: 0x30020, size: 0x10 } - filename: 4.o symbols: - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x40000, size: 0x10 } diff --git a/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test b/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test index b6d2f4391c70e..651a874ff3ec4 100644 --- a/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test +++ b/llvm/test/tools/dsymutil/X86/dwarf5-rnglists.test @@ -57,8 +57,8 @@ #DWARF-CHECK: 0x00000000: range list header: length = 0x00000011, format = DWARF32, version = 0x0005, addr_size = 0x08, seg_size = 0x00, offset_entry_count = 0x00000000 #DWARF-CHECK: ranges: #DWARF-CHECK: 0x0000000c: [DW_RLE_base_addressx]: 0x0000000000000003 -#DWARF-CHECK: 0x0000000e: [DW_RLE_offset_pair ]: 0x0000000000000000, 0x000000000000001d => [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 db9f70874971b..7b06607a74cbc 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 e933be8fd9bdb..928b14b62bc67 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 f307f5ad89900..021c7212bd831 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 0000000000000..627df30344d8b --- /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 5414dff3745b2..3bffc9aeacca7 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 fc415acc59f6d..eb70f51230de9 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 0e3b974ba0059..d87bb5b73c240 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 15725a0435d48..9960d1996496d 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 c5c8c9e93e0a0..c73db0e3f5532 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 90c40fd1e4ab6..b63668c39c901 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 78b53897346c4..a1bb3ec7d846d 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 90cb99858c9ef..2c4caa158258d 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 232f6a5553e57..46ebcf24fe64d 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 cb3b435ea9aa4..7f0533a882dd8 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 1f5ddd78adaa2..1a3f29d127cef 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 2ee1d73b6f92f..1a8010e364d25 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 a1f18e6f169db..d00ef1a8c228b 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;