16de5fcc7SAlexander Yermolovich //===- bolt/Rewrite/DebugNames.cpp -------------------------------------===// 26de5fcc7SAlexander Yermolovich // 36de5fcc7SAlexander Yermolovich // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 46de5fcc7SAlexander Yermolovich // See https://llvm.org/LICENSE.txt for license information. 56de5fcc7SAlexander Yermolovich // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 66de5fcc7SAlexander Yermolovich // 76de5fcc7SAlexander Yermolovich //===----------------------------------------------------------------------===// 86de5fcc7SAlexander Yermolovich 96de5fcc7SAlexander Yermolovich #include "bolt/Core/DebugNames.h" 106de5fcc7SAlexander Yermolovich #include "bolt/Core/BinaryContext.h" 116de5fcc7SAlexander Yermolovich #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 126de5fcc7SAlexander Yermolovich #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" 136de5fcc7SAlexander Yermolovich #include "llvm/Support/EndianStream.h" 146de5fcc7SAlexander Yermolovich #include "llvm/Support/LEB128.h" 156de5fcc7SAlexander Yermolovich #include <cstdint> 16a4610c71SAlexander Yermolovich #include <optional> 176de5fcc7SAlexander Yermolovich 186de5fcc7SAlexander Yermolovich namespace llvm { 196de5fcc7SAlexander Yermolovich namespace bolt { 206de5fcc7SAlexander Yermolovich DWARF5AcceleratorTable::DWARF5AcceleratorTable( 216de5fcc7SAlexander Yermolovich const bool CreateDebugNames, BinaryContext &BC, 226de5fcc7SAlexander Yermolovich DebugStrWriter &MainBinaryStrWriter) 236de5fcc7SAlexander Yermolovich : BC(BC), MainBinaryStrWriter(MainBinaryStrWriter) { 246de5fcc7SAlexander Yermolovich NeedToCreate = CreateDebugNames || BC.getDebugNamesSection(); 256de5fcc7SAlexander Yermolovich if (!NeedToCreate) 266de5fcc7SAlexander Yermolovich return; 276de5fcc7SAlexander Yermolovich FullTableBuffer = std::make_unique<DebugStrBufferVector>(); 286de5fcc7SAlexander Yermolovich FullTableStream = std::make_unique<raw_svector_ostream>(*FullTableBuffer); 296de5fcc7SAlexander Yermolovich StrBuffer = std::make_unique<DebugStrBufferVector>(); 306de5fcc7SAlexander Yermolovich StrStream = std::make_unique<raw_svector_ostream>(*StrBuffer); 316de5fcc7SAlexander Yermolovich EntriesBuffer = std::make_unique<DebugStrBufferVector>(); 326de5fcc7SAlexander Yermolovich Entriestream = std::make_unique<raw_svector_ostream>(*EntriesBuffer); 336de5fcc7SAlexander Yermolovich AugStringBuffer = std::make_unique<DebugStrBufferVector>(); 346de5fcc7SAlexander Yermolovich AugStringtream = std::make_unique<raw_svector_ostream>(*AugStringBuffer); 356de5fcc7SAlexander Yermolovich 366de5fcc7SAlexander Yermolovich // Binary has split-dwarf CUs. 376de5fcc7SAlexander Yermolovich // Even thought for non-skeleton-cu all names are in .debug_str.dwo section, 386de5fcc7SAlexander Yermolovich // for the .debug_names contributions they are in .debug_str section. 396de5fcc7SAlexander Yermolovich if (BC.getNumDWOCUs()) { 406de5fcc7SAlexander Yermolovich DataExtractor StrData(BC.DwCtx->getDWARFObj().getStrSection(), 416de5fcc7SAlexander Yermolovich BC.DwCtx->isLittleEndian(), 0); 426de5fcc7SAlexander Yermolovich uint64_t Offset = 0; 436de5fcc7SAlexander Yermolovich uint64_t StrOffset = 0; 446de5fcc7SAlexander Yermolovich while (StrData.isValidOffset(Offset)) { 456de5fcc7SAlexander Yermolovich Error Err = Error::success(); 466de5fcc7SAlexander Yermolovich const char *CStr = StrData.getCStr(&Offset, &Err); 476de5fcc7SAlexander Yermolovich if (Err) { 486de5fcc7SAlexander Yermolovich NeedToCreate = false; 496de5fcc7SAlexander Yermolovich BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: Could not extract " 506de5fcc7SAlexander Yermolovich "string from .debug_str section at offset: " 516de5fcc7SAlexander Yermolovich << Twine::utohexstr(StrOffset) << ".\n"; 526de5fcc7SAlexander Yermolovich return; 536de5fcc7SAlexander Yermolovich } 546de5fcc7SAlexander Yermolovich auto R = StrCacheToOffsetMap.try_emplace( 556de5fcc7SAlexander Yermolovich llvm::hash_value(llvm::StringRef(CStr)), StrOffset); 566de5fcc7SAlexander Yermolovich if (!R.second) 576de5fcc7SAlexander Yermolovich BC.errs() 586de5fcc7SAlexander Yermolovich << "BOLT-WARNING: [internal-dwarf-error]: collision occured on " 596de5fcc7SAlexander Yermolovich << CStr << " at offset : 0x" << Twine::utohexstr(StrOffset) 606de5fcc7SAlexander Yermolovich << ". Previous string offset is: 0x" 616de5fcc7SAlexander Yermolovich << Twine::utohexstr(R.first->second) << ".\n"; 626de5fcc7SAlexander Yermolovich StrOffset = Offset; 636de5fcc7SAlexander Yermolovich } 646de5fcc7SAlexander Yermolovich } 656de5fcc7SAlexander Yermolovich } 666de5fcc7SAlexander Yermolovich 676de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::setCurrentUnit(DWARFUnit &Unit, 686de5fcc7SAlexander Yermolovich const uint64_t UnitStartOffset) { 696de5fcc7SAlexander Yermolovich CurrentUnit = nullptr; 706de5fcc7SAlexander Yermolovich CurrentUnitOffset = UnitStartOffset; 716de5fcc7SAlexander Yermolovich std::optional<uint64_t> DWOID = Unit.getDWOId(); 726de5fcc7SAlexander Yermolovich // We process skeleton CUs after DWO Units for it. 736de5fcc7SAlexander Yermolovich // Patching offset in CU list to correct one. 746de5fcc7SAlexander Yermolovich if (!Unit.isDWOUnit() && DWOID) { 756de5fcc7SAlexander Yermolovich auto Iter = CUOffsetsToPatch.find(*DWOID); 766de5fcc7SAlexander Yermolovich // Check in case no entries were added from non skeleton DWO section. 776de5fcc7SAlexander Yermolovich if (Iter != CUOffsetsToPatch.end()) 786de5fcc7SAlexander Yermolovich CUList[Iter->second] = UnitStartOffset; 796de5fcc7SAlexander Yermolovich } 806de5fcc7SAlexander Yermolovich } 816de5fcc7SAlexander Yermolovich 826de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::addUnit(DWARFUnit &Unit, 836de5fcc7SAlexander Yermolovich const std::optional<uint64_t> &DWOID) { 846de5fcc7SAlexander Yermolovich constexpr uint32_t BADCUOFFSET = 0xBADBAD; 856de5fcc7SAlexander Yermolovich StrSection = Unit.getStringSection(); 866de5fcc7SAlexander Yermolovich if (Unit.isTypeUnit()) { 876de5fcc7SAlexander Yermolovich if (DWOID) { 886de5fcc7SAlexander Yermolovich // We adding an entry for a DWO TU. The DWO CU might not have any entries, 896de5fcc7SAlexander Yermolovich // so need to add it to the list pre-emptively. 906de5fcc7SAlexander Yermolovich auto Iter = CUOffsetsToPatch.insert({*DWOID, CUList.size()}); 916de5fcc7SAlexander Yermolovich if (Iter.second) 926de5fcc7SAlexander Yermolovich CUList.push_back(BADCUOFFSET); 93361350fcSAlexander Yermolovich const uint64_t TUHash = cast<DWARFTypeUnit>(&Unit)->getTypeHash(); 94361350fcSAlexander Yermolovich if (!TUHashToIndexMap.count(TUHash)) { 95361350fcSAlexander Yermolovich TUHashToIndexMap.insert({TUHash, ForeignTUList.size()}); 96361350fcSAlexander Yermolovich ForeignTUList.push_back(TUHash); 97361350fcSAlexander Yermolovich } 986de5fcc7SAlexander Yermolovich } else { 996de5fcc7SAlexander Yermolovich LocalTUList.push_back(CurrentUnitOffset); 1006de5fcc7SAlexander Yermolovich } 1016de5fcc7SAlexander Yermolovich } else { 1026de5fcc7SAlexander Yermolovich if (DWOID) { 1036de5fcc7SAlexander Yermolovich // This is a path for split dwarf without type units. 1046de5fcc7SAlexander Yermolovich // We process DWO Units before Skeleton CU. So at this point we don't know 1056de5fcc7SAlexander Yermolovich // the offset of Skeleton CU. Adding CULit index to a map to patch later 1066de5fcc7SAlexander Yermolovich // with the correct offset. 1076de5fcc7SAlexander Yermolovich auto Iter = CUOffsetsToPatch.insert({*DWOID, CUList.size()}); 1086de5fcc7SAlexander Yermolovich if (Iter.second) 1096de5fcc7SAlexander Yermolovich CUList.push_back(BADCUOFFSET); 1106de5fcc7SAlexander Yermolovich } else { 1116de5fcc7SAlexander Yermolovich CUList.push_back(CurrentUnitOffset); 1126de5fcc7SAlexander Yermolovich } 1136de5fcc7SAlexander Yermolovich } 1146de5fcc7SAlexander Yermolovich } 1156de5fcc7SAlexander Yermolovich 1166de5fcc7SAlexander Yermolovich // Returns true if DW_TAG_variable should be included in .debug-names based on 1176de5fcc7SAlexander Yermolovich // section 6.1.1.1 for DWARF5 spec. 1186de5fcc7SAlexander Yermolovich static bool shouldIncludeVariable(const DWARFUnit &Unit, const DIE &Die) { 1196de5fcc7SAlexander Yermolovich const DIEValue LocAttrInfo = 1206de5fcc7SAlexander Yermolovich Die.findAttribute(dwarf::Attribute::DW_AT_location); 1216de5fcc7SAlexander Yermolovich if (!LocAttrInfo) 1226de5fcc7SAlexander Yermolovich return false; 1236de5fcc7SAlexander Yermolovich if (!(doesFormBelongToClass(LocAttrInfo.getForm(), DWARFFormValue::FC_Exprloc, 1246de5fcc7SAlexander Yermolovich Unit.getVersion()) || 1256de5fcc7SAlexander Yermolovich doesFormBelongToClass(LocAttrInfo.getForm(), DWARFFormValue::FC_Block, 1266de5fcc7SAlexander Yermolovich Unit.getVersion()))) 1276de5fcc7SAlexander Yermolovich return false; 1286de5fcc7SAlexander Yermolovich std::vector<uint8_t> Sblock; 1296de5fcc7SAlexander Yermolovich auto constructVect = 1306de5fcc7SAlexander Yermolovich [&](const DIEValueList::const_value_range &Iter) -> void { 1316de5fcc7SAlexander Yermolovich for (const DIEValue &Val : Iter) 1326de5fcc7SAlexander Yermolovich Sblock.push_back(Val.getDIEInteger().getValue()); 1336de5fcc7SAlexander Yermolovich }; 1346de5fcc7SAlexander Yermolovich if (doesFormBelongToClass(LocAttrInfo.getForm(), DWARFFormValue::FC_Exprloc, 1356de5fcc7SAlexander Yermolovich Unit.getVersion())) 1366de5fcc7SAlexander Yermolovich constructVect(LocAttrInfo.getDIELoc().values()); 1376de5fcc7SAlexander Yermolovich else 1386de5fcc7SAlexander Yermolovich constructVect(LocAttrInfo.getDIEBlock().values()); 1396de5fcc7SAlexander Yermolovich ArrayRef<uint8_t> Expr = ArrayRef<uint8_t>(Sblock); 1406de5fcc7SAlexander Yermolovich DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), 1416de5fcc7SAlexander Yermolovich Unit.getContext().isLittleEndian(), 0); 1426de5fcc7SAlexander Yermolovich DWARFExpression LocExpr(Data, Unit.getAddressByteSize(), 1436de5fcc7SAlexander Yermolovich Unit.getFormParams().Format); 1446de5fcc7SAlexander Yermolovich for (const DWARFExpression::Operation &Expr : LocExpr) 1456de5fcc7SAlexander Yermolovich if (Expr.getCode() == dwarf::DW_OP_addrx || 146*331c2dd8SAlexander Yermolovich Expr.getCode() == dwarf::DW_OP_form_tls_address || 147*331c2dd8SAlexander Yermolovich Expr.getCode() == dwarf::DW_OP_GNU_push_tls_address) 1486de5fcc7SAlexander Yermolovich return true; 1496de5fcc7SAlexander Yermolovich return false; 1506de5fcc7SAlexander Yermolovich } 1516de5fcc7SAlexander Yermolovich 152f3cfe016SAlexander Yermolovich bool static canProcess(const DWARFUnit &Unit, const DIE &Die, 153f3cfe016SAlexander Yermolovich std::string &NameToUse, const bool TagsOnly) { 1548c2da89eSAlexander Yermolovich if (Die.findAttribute(dwarf::Attribute::DW_AT_declaration)) 1558c2da89eSAlexander Yermolovich return false; 156f3cfe016SAlexander Yermolovich switch (Die.getTag()) { 157f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_base_type: 158f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_class_type: 159f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_enumeration_type: 160f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_imported_declaration: 161f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_pointer_type: 162f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_structure_type: 163f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_typedef: 164f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_unspecified_type: 16550c0e679SAlexander Yermolovich case dwarf::DW_TAG_union_type: 166f3cfe016SAlexander Yermolovich if (TagsOnly || Die.findAttribute(dwarf::Attribute::DW_AT_name)) 167f3cfe016SAlexander Yermolovich return true; 168f3cfe016SAlexander Yermolovich return false; 169f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_namespace: 170f3cfe016SAlexander Yermolovich // According to DWARF5 spec namespaces without DW_AT_name needs to have 171f3cfe016SAlexander Yermolovich // "(anonymous namespace)" 172f3cfe016SAlexander Yermolovich if (!Die.findAttribute(dwarf::Attribute::DW_AT_name)) 173f3cfe016SAlexander Yermolovich NameToUse = "(anonymous namespace)"; 174f3cfe016SAlexander Yermolovich return true; 175f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_inlined_subroutine: 176f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_label: 177f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_subprogram: 178f3cfe016SAlexander Yermolovich if (TagsOnly || Die.findAttribute(dwarf::Attribute::DW_AT_low_pc) || 179f3cfe016SAlexander Yermolovich Die.findAttribute(dwarf::Attribute::DW_AT_high_pc) || 180f3cfe016SAlexander Yermolovich Die.findAttribute(dwarf::Attribute::DW_AT_ranges) || 181f3cfe016SAlexander Yermolovich Die.findAttribute(dwarf::Attribute::DW_AT_entry_pc)) 182f3cfe016SAlexander Yermolovich return true; 183f3cfe016SAlexander Yermolovich return false; 184f3cfe016SAlexander Yermolovich case dwarf::DW_TAG_variable: 185f3cfe016SAlexander Yermolovich return TagsOnly || shouldIncludeVariable(Unit, Die); 186f3cfe016SAlexander Yermolovich default: 187f3cfe016SAlexander Yermolovich break; 188f3cfe016SAlexander Yermolovich } 189f3cfe016SAlexander Yermolovich return false; 190f3cfe016SAlexander Yermolovich } 191f3cfe016SAlexander Yermolovich 192f3cfe016SAlexander Yermolovich bool DWARF5AcceleratorTable::canGenerateEntryWithCrossCUReference( 193f3cfe016SAlexander Yermolovich const DWARFUnit &Unit, const DIE &Die, 194f3cfe016SAlexander Yermolovich const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { 195f3cfe016SAlexander Yermolovich if (!isCreated()) 196f3cfe016SAlexander Yermolovich return false; 197f3cfe016SAlexander Yermolovich std::string NameToUse = ""; 198f3cfe016SAlexander Yermolovich if (!canProcess(Unit, Die, NameToUse, true)) 199f3cfe016SAlexander Yermolovich return false; 200f3cfe016SAlexander Yermolovich return (AttrSpec.Attr == dwarf::Attribute::DW_AT_abstract_origin || 201f3cfe016SAlexander Yermolovich AttrSpec.Attr == dwarf::Attribute::DW_AT_specification) && 202f3cfe016SAlexander Yermolovich AttrSpec.Form == dwarf::DW_FORM_ref_addr; 203f3cfe016SAlexander Yermolovich } 2046de5fcc7SAlexander Yermolovich /// Returns name offset in String Offset section. 2056de5fcc7SAlexander Yermolovich static uint64_t getNameOffset(BinaryContext &BC, DWARFUnit &Unit, 2066de5fcc7SAlexander Yermolovich const uint64_t Index) { 2076de5fcc7SAlexander Yermolovich const DWARFSection &StrOffsetsSection = Unit.getStringOffsetSection(); 2086de5fcc7SAlexander Yermolovich const std::optional<StrOffsetsContributionDescriptor> &Contr = 2096de5fcc7SAlexander Yermolovich Unit.getStringOffsetsTableContribution(); 2106de5fcc7SAlexander Yermolovich if (!Contr) { 2116de5fcc7SAlexander Yermolovich BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not get " 2126de5fcc7SAlexander Yermolovich "StringOffsetsTableContribution for unit at offset: " 2136de5fcc7SAlexander Yermolovich << Twine::utohexstr(Unit.getOffset()) << ".\n"; 2146de5fcc7SAlexander Yermolovich return 0; 2156de5fcc7SAlexander Yermolovich } 2166de5fcc7SAlexander Yermolovich 2176de5fcc7SAlexander Yermolovich const uint8_t DwarfOffsetByteSize = Contr->getDwarfOffsetByteSize(); 2186de5fcc7SAlexander Yermolovich return support::endian::read32le(StrOffsetsSection.Data.data() + Contr->Base + 2196de5fcc7SAlexander Yermolovich Index * DwarfOffsetByteSize); 2206de5fcc7SAlexander Yermolovich } 2216de5fcc7SAlexander Yermolovich 222a4610c71SAlexander Yermolovich static uint64_t getEntryID(const BOLTDWARF5AccelTableData &Entry) { 223a4610c71SAlexander Yermolovich return reinterpret_cast<uint64_t>(&Entry); 224a4610c71SAlexander Yermolovich } 225a4610c71SAlexander Yermolovich 2264b825c74SAlexander Yermolovich uint32_t DWARF5AcceleratorTable::getUnitID(const DWARFUnit &Unit, 2274b825c74SAlexander Yermolovich const std::optional<uint64_t> &DWOID, 2284b825c74SAlexander Yermolovich bool &IsTU) { 2296de5fcc7SAlexander Yermolovich IsTU = Unit.isTypeUnit(); 2306de5fcc7SAlexander Yermolovich if (IsTU) { 231361350fcSAlexander Yermolovich if (DWOID) { 232361350fcSAlexander Yermolovich const uint64_t TUHash = cast<DWARFTypeUnit>(&Unit)->getTypeHash(); 233361350fcSAlexander Yermolovich auto Iter = TUHashToIndexMap.find(TUHash); 2344b825c74SAlexander Yermolovich assert(Iter != TUHashToIndexMap.end() && "Could not find TU hash in map"); 235361350fcSAlexander Yermolovich return Iter->second; 236361350fcSAlexander Yermolovich } 2376de5fcc7SAlexander Yermolovich return LocalTUList.size() - 1; 2386de5fcc7SAlexander Yermolovich } 2396de5fcc7SAlexander Yermolovich return CUList.size() - 1; 2406de5fcc7SAlexander Yermolovich } 2416de5fcc7SAlexander Yermolovich 2424b825c74SAlexander Yermolovich std::optional<std::string> DWARF5AcceleratorTable::getName( 2434b825c74SAlexander Yermolovich DWARFUnit &Unit, const std::optional<uint64_t> &DWOID, 2444b825c74SAlexander Yermolovich const std::string &NameToUse, DIEValue ValName) { 2456de5fcc7SAlexander Yermolovich if ((!ValName || ValName.getForm() == dwarf::DW_FORM_string) && 2466de5fcc7SAlexander Yermolovich NameToUse.empty()) 247a4610c71SAlexander Yermolovich return std::nullopt; 2486de5fcc7SAlexander Yermolovich std::string Name = ""; 2496de5fcc7SAlexander Yermolovich uint64_t NameIndexOffset = 0; 2506de5fcc7SAlexander Yermolovich if (NameToUse.empty()) { 2516de5fcc7SAlexander Yermolovich NameIndexOffset = ValName.getDIEInteger().getValue(); 2526de5fcc7SAlexander Yermolovich if (ValName.getForm() != dwarf::DW_FORM_strp) 2536de5fcc7SAlexander Yermolovich NameIndexOffset = getNameOffset(BC, Unit, NameIndexOffset); 2546de5fcc7SAlexander Yermolovich // Counts on strings end with '\0'. 2556de5fcc7SAlexander Yermolovich Name = std::string(&StrSection.data()[NameIndexOffset]); 2566de5fcc7SAlexander Yermolovich } else { 2576de5fcc7SAlexander Yermolovich Name = NameToUse; 2586de5fcc7SAlexander Yermolovich } 2596de5fcc7SAlexander Yermolovich auto &It = Entries[Name]; 2606de5fcc7SAlexander Yermolovich if (It.Values.empty()) { 2616de5fcc7SAlexander Yermolovich if (DWOID && NameToUse.empty()) { 2626de5fcc7SAlexander Yermolovich // For DWO Unit the offset is in the .debug_str.dwo section. 2636de5fcc7SAlexander Yermolovich // Need to find offset for the name in the .debug_str section. 2646de5fcc7SAlexander Yermolovich llvm::hash_code Hash = llvm::hash_value(llvm::StringRef(Name)); 2656de5fcc7SAlexander Yermolovich auto ItCache = StrCacheToOffsetMap.find(Hash); 2666de5fcc7SAlexander Yermolovich if (ItCache == StrCacheToOffsetMap.end()) 2676de5fcc7SAlexander Yermolovich NameIndexOffset = MainBinaryStrWriter.addString(Name); 2686de5fcc7SAlexander Yermolovich else 2696de5fcc7SAlexander Yermolovich NameIndexOffset = ItCache->second; 2706de5fcc7SAlexander Yermolovich } 2716de5fcc7SAlexander Yermolovich if (!NameToUse.empty()) 2726de5fcc7SAlexander Yermolovich NameIndexOffset = MainBinaryStrWriter.addString(Name); 2736de5fcc7SAlexander Yermolovich It.StrOffset = NameIndexOffset; 2744b825c74SAlexander Yermolovich // This is the same hash function used in DWARF5AccelTableData. 2756de5fcc7SAlexander Yermolovich It.HashValue = caseFoldingDjbHash(Name); 2766de5fcc7SAlexander Yermolovich } 27748418588SAlexander Yermolovich return Name; 2784b825c74SAlexander Yermolovich } 2796de5fcc7SAlexander Yermolovich 2804b825c74SAlexander Yermolovich std::optional<BOLTDWARF5AccelTableData *> DWARF5AcceleratorTable::addEntry( 2814b825c74SAlexander Yermolovich DWARFUnit &DU, const DIE &CurrDie, const std::optional<uint64_t> &DWOID, 2824b825c74SAlexander Yermolovich const std::optional<BOLTDWARF5AccelTableData *> &Parent, 2834b825c74SAlexander Yermolovich const std::optional<std::string> &Name, 2844b825c74SAlexander Yermolovich const uint32_t NumberParentsInChain) { 28548418588SAlexander Yermolovich if (!Name) 28648418588SAlexander Yermolovich return std::nullopt; 28748418588SAlexander Yermolovich 28848418588SAlexander Yermolovich auto &It = Entries[*Name]; 2896de5fcc7SAlexander Yermolovich bool IsTU = false; 2904b825c74SAlexander Yermolovich uint32_t DieTag = CurrDie.getTag(); 2914b825c74SAlexander Yermolovich uint32_t UnitID = getUnitID(DU, DWOID, IsTU); 2926de5fcc7SAlexander Yermolovich std::optional<unsigned> SecondIndex = std::nullopt; 2936de5fcc7SAlexander Yermolovich if (IsTU && DWOID) { 2946de5fcc7SAlexander Yermolovich auto Iter = CUOffsetsToPatch.find(*DWOID); 2956de5fcc7SAlexander Yermolovich if (Iter == CUOffsetsToPatch.end()) 2966de5fcc7SAlexander Yermolovich BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find " 2976de5fcc7SAlexander Yermolovich "DWO ID in CU offsets for second Unit Index " 29848418588SAlexander Yermolovich << *Name << ". For DIE at offset: " 2994b825c74SAlexander Yermolovich << Twine::utohexstr(CurrentUnitOffset + CurrDie.getOffset()) 3006de5fcc7SAlexander Yermolovich << ".\n"; 3016de5fcc7SAlexander Yermolovich SecondIndex = Iter->second; 3026de5fcc7SAlexander Yermolovich } 303a4610c71SAlexander Yermolovich std::optional<uint64_t> ParentOffset = 304a4610c71SAlexander Yermolovich (Parent ? std::optional<uint64_t>(getEntryID(**Parent)) : std::nullopt); 3054b825c74SAlexander Yermolovich // This will be only populated in writeEntry, in order to keep only the parent 3064b825c74SAlexander Yermolovich // entries, and keep the footprint down. 307a4610c71SAlexander Yermolovich if (ParentOffset) 308a4610c71SAlexander Yermolovich EntryRelativeOffsets.insert({*ParentOffset, 0}); 30961589b85SAlexander Yermolovich bool IsParentRoot = false; 31061589b85SAlexander Yermolovich // If there is no parent and no valid Entries in parent chain this is a root 31161589b85SAlexander Yermolovich // to be marked with a flag. 31261589b85SAlexander Yermolovich if (!Parent && !NumberParentsInChain) 31361589b85SAlexander Yermolovich IsParentRoot = true; 3146de5fcc7SAlexander Yermolovich It.Values.push_back(new (Allocator) BOLTDWARF5AccelTableData( 3154b825c74SAlexander Yermolovich CurrDie.getOffset(), ParentOffset, DieTag, UnitID, IsParentRoot, IsTU, 31661589b85SAlexander Yermolovich SecondIndex)); 317a4610c71SAlexander Yermolovich return It.Values.back(); 3184b825c74SAlexander Yermolovich } 3196de5fcc7SAlexander Yermolovich 3204b825c74SAlexander Yermolovich std::optional<BOLTDWARF5AccelTableData *> 3214b825c74SAlexander Yermolovich DWARF5AcceleratorTable::processReferencedDie( 3224b825c74SAlexander Yermolovich DWARFUnit &Unit, const DIE &Die, const std::optional<uint64_t> &DWOID, 3234b825c74SAlexander Yermolovich const std::optional<BOLTDWARF5AccelTableData *> &Parent, 3244b825c74SAlexander Yermolovich const std::string &NameToUse, const uint32_t NumberParentsInChain, 3254b825c74SAlexander Yermolovich const dwarf::Attribute &Attr) { 3264b825c74SAlexander Yermolovich DIEValue Value = Die.findAttribute(Attr); 32748418588SAlexander Yermolovich if (!Value) 32848418588SAlexander Yermolovich return std::nullopt; 3294b825c74SAlexander Yermolovich auto getReferenceDie = [&](const DIEValue &Value, const DIE *RefDieUsed) 3304b825c74SAlexander Yermolovich -> std::optional<std::pair<DWARFUnit *, const DIE *>> { 3314b825c74SAlexander Yermolovich if (!Value) 3324b825c74SAlexander Yermolovich return std::nullopt; 333f3cfe016SAlexander Yermolovich if (Value.getForm() == dwarf::DW_FORM_ref_addr) { 334f3cfe016SAlexander Yermolovich auto Iter = CrossCUDies.find(Value.getDIEInteger().getValue()); 335f3cfe016SAlexander Yermolovich if (Iter == CrossCUDies.end()) { 336f3cfe016SAlexander Yermolovich BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find " 337f3cfe016SAlexander Yermolovich "referenced DIE in CrossCUDies for " 338f3cfe016SAlexander Yermolovich << Twine::utohexstr(Value.getDIEInteger().getValue()) 339f3cfe016SAlexander Yermolovich << ".\n"; 340f3cfe016SAlexander Yermolovich return std::nullopt; 341f3cfe016SAlexander Yermolovich } 3424b825c74SAlexander Yermolovich return Iter->second; 343f3cfe016SAlexander Yermolovich } 3444b825c74SAlexander Yermolovich const DIEEntry &DIEENtry = Value.getDIEEntry(); 3454b825c74SAlexander Yermolovich return {{&Unit, &DIEENtry.getEntry()}}; 34648418588SAlexander Yermolovich }; 34748418588SAlexander Yermolovich 3484b825c74SAlexander Yermolovich DIEValue AttrValLinkageName; 3494b825c74SAlexander Yermolovich DIEValue AttrValName = Die.findAttribute(dwarf::Attribute::DW_AT_name); 3504b825c74SAlexander Yermolovich DWARFUnit *RefUnit = &Unit; 3514b825c74SAlexander Yermolovich const DIE *RefDieUsed = &Die; 3524b825c74SAlexander Yermolovich // It is possible to have DW_TAG_subprogram only with DW_AT_linkage_name that 3534b825c74SAlexander Yermolovich // DW_AT_abstract_origin/DW_AT_specification point to. 3544b825c74SAlexander Yermolovich while (!AttrValName) { 3554b825c74SAlexander Yermolovich std::optional<std::pair<DWARFUnit *, const DIE *>> RefDUDie = 3564b825c74SAlexander Yermolovich getReferenceDie(Value, RefDieUsed); 3574b825c74SAlexander Yermolovich if (!RefDUDie) 3584b825c74SAlexander Yermolovich break; 3594b825c74SAlexander Yermolovich RefUnit = RefDUDie->first; 3604b825c74SAlexander Yermolovich const DIE &RefDie = *RefDUDie->second; 3614b825c74SAlexander Yermolovich RefDieUsed = &RefDie; 3624b825c74SAlexander Yermolovich if (!AttrValLinkageName) 3634b825c74SAlexander Yermolovich AttrValLinkageName = 3644b825c74SAlexander Yermolovich RefDie.findAttribute(dwarf::Attribute::DW_AT_linkage_name); 3654b825c74SAlexander Yermolovich AttrValName = RefDie.findAttribute(dwarf::Attribute::DW_AT_name); 3664b825c74SAlexander Yermolovich Value = RefDie.findAttribute(dwarf::Attribute::DW_AT_abstract_origin); 3674b825c74SAlexander Yermolovich if (!Value) 3684b825c74SAlexander Yermolovich Value = RefDie.findAttribute(dwarf::Attribute::DW_AT_specification); 3694b825c74SAlexander Yermolovich } 3704b825c74SAlexander Yermolovich addEntry(Unit, Die, DWOID, Parent, 3714b825c74SAlexander Yermolovich getName(*RefUnit, DWOID, NameToUse, AttrValLinkageName), 3724b825c74SAlexander Yermolovich NumberParentsInChain); 3734b825c74SAlexander Yermolovich return addEntry(Unit, Die, DWOID, Parent, 3744b825c74SAlexander Yermolovich getName(*RefUnit, DWOID, NameToUse, AttrValName), 3754b825c74SAlexander Yermolovich NumberParentsInChain); 3764b825c74SAlexander Yermolovich } 3774b825c74SAlexander Yermolovich 3784b825c74SAlexander Yermolovich std::optional<BOLTDWARF5AccelTableData *> 3794b825c74SAlexander Yermolovich DWARF5AcceleratorTable::addAccelTableEntry( 3804b825c74SAlexander Yermolovich DWARFUnit &Unit, const DIE &Die, const std::optional<uint64_t> &DWOID, 3814b825c74SAlexander Yermolovich const uint32_t NumberParentsInChain, 3824b825c74SAlexander Yermolovich std::optional<BOLTDWARF5AccelTableData *> &Parent) { 3834b825c74SAlexander Yermolovich if (Unit.getVersion() < 5 || !NeedToCreate) 3844b825c74SAlexander Yermolovich return std::nullopt; 3854b825c74SAlexander Yermolovich std::string NameToUse = ""; 3864b825c74SAlexander Yermolovich 3874b825c74SAlexander Yermolovich if (!canProcess(Unit, Die, NameToUse, false)) 3884b825c74SAlexander Yermolovich return std::nullopt; 3894b825c74SAlexander Yermolovich 3904b825c74SAlexander Yermolovich // Adds a Unit to either CU, LocalTU or ForeignTU list the first time we 3914b825c74SAlexander Yermolovich // encounter it. 3924b825c74SAlexander Yermolovich // Invoking it here so that we don't add Units that don't have any entries. 3934b825c74SAlexander Yermolovich if (&Unit != CurrentUnit) { 3944b825c74SAlexander Yermolovich CurrentUnit = &Unit; 3954b825c74SAlexander Yermolovich addUnit(Unit, DWOID); 3964b825c74SAlexander Yermolovich } 3974b825c74SAlexander Yermolovich 3984b825c74SAlexander Yermolovich // Minor optimization not to add entry twice for DW_TAG_namespace if it has no 3994b825c74SAlexander Yermolovich // DW_AT_name. 4004b825c74SAlexander Yermolovich std::optional<BOLTDWARF5AccelTableData *> LinkageEntry = std::nullopt; 4014b825c74SAlexander Yermolovich DIEValue NameVal = Die.findAttribute(dwarf::Attribute::DW_AT_name); 4024b825c74SAlexander Yermolovich DIEValue LinkageNameVal = 4034b825c74SAlexander Yermolovich Die.findAttribute(dwarf::Attribute::DW_AT_linkage_name); 4044b825c74SAlexander Yermolovich if (!(Die.getTag() == dwarf::DW_TAG_namespace && !NameVal)) 4054b825c74SAlexander Yermolovich LinkageEntry = addEntry(Unit, Die, DWOID, Parent, 4064b825c74SAlexander Yermolovich getName(Unit, DWOID, NameToUse, LinkageNameVal), 4074b825c74SAlexander Yermolovich NumberParentsInChain); 4084b825c74SAlexander Yermolovich 4094b825c74SAlexander Yermolovich std::optional<BOLTDWARF5AccelTableData *> NameEntry = 4104b825c74SAlexander Yermolovich addEntry(Unit, Die, DWOID, Parent, 4114b825c74SAlexander Yermolovich getName(Unit, DWOID, NameToUse, NameVal), NumberParentsInChain); 4124b825c74SAlexander Yermolovich if (NameEntry) 4134b825c74SAlexander Yermolovich return NameEntry; 4144b825c74SAlexander Yermolovich 4154b825c74SAlexander Yermolovich // The DIE doesn't have DW_AT_name or DW_AT_linkage_name, so we need to see if 4164b825c74SAlexander Yermolovich // we can follow other attributes to find them. For the purposes of 4174b825c74SAlexander Yermolovich // determining whether a debug information entry has a particular 4184b825c74SAlexander Yermolovich // attribute (such as DW_AT_name), if debug information entry A has a 4194b825c74SAlexander Yermolovich // DW_AT_specification or DW_AT_abstract_origin attribute pointing to another 4204b825c74SAlexander Yermolovich // debug information entry B, any attributes of B are considered to be 4214b825c74SAlexander Yermolovich // part of A. 4224b825c74SAlexander Yermolovich if (std::optional<BOLTDWARF5AccelTableData *> Entry = processReferencedDie( 4234b825c74SAlexander Yermolovich Unit, Die, DWOID, Parent, NameToUse, NumberParentsInChain, 4244b825c74SAlexander Yermolovich dwarf::Attribute::DW_AT_abstract_origin)) 42548418588SAlexander Yermolovich return *Entry; 4264b825c74SAlexander Yermolovich if (std::optional<BOLTDWARF5AccelTableData *> Entry = processReferencedDie( 4274b825c74SAlexander Yermolovich Unit, Die, DWOID, Parent, NameToUse, NumberParentsInChain, 4284b825c74SAlexander Yermolovich dwarf::Attribute::DW_AT_specification)) 42948418588SAlexander Yermolovich return *Entry; 43048418588SAlexander Yermolovich 4314b825c74SAlexander Yermolovich // This point can be hit by DW_TAG_varialbe that has no DW_AT_name. 4324b825c74SAlexander Yermolovich return std::nullopt; 4336de5fcc7SAlexander Yermolovich } 4346de5fcc7SAlexander Yermolovich 4356de5fcc7SAlexander Yermolovich /// Algorithm from llvm implementation. 4366de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::computeBucketCount() { 4376de5fcc7SAlexander Yermolovich // First get the number of unique hashes. 4386de5fcc7SAlexander Yermolovich std::vector<uint32_t> Uniques; 4396de5fcc7SAlexander Yermolovich Uniques.reserve(Entries.size()); 4406de5fcc7SAlexander Yermolovich for (const auto &E : Entries) 4416de5fcc7SAlexander Yermolovich Uniques.push_back(E.second.HashValue); 4426de5fcc7SAlexander Yermolovich array_pod_sort(Uniques.begin(), Uniques.end()); 4436de5fcc7SAlexander Yermolovich std::vector<uint32_t>::iterator P = 4446de5fcc7SAlexander Yermolovich std::unique(Uniques.begin(), Uniques.end()); 4456de5fcc7SAlexander Yermolovich 4466de5fcc7SAlexander Yermolovich UniqueHashCount = std::distance(Uniques.begin(), P); 4476de5fcc7SAlexander Yermolovich 4486de5fcc7SAlexander Yermolovich if (UniqueHashCount > 1024) 4496de5fcc7SAlexander Yermolovich BucketCount = UniqueHashCount / 4; 4506de5fcc7SAlexander Yermolovich else if (UniqueHashCount > 16) 4516de5fcc7SAlexander Yermolovich BucketCount = UniqueHashCount / 2; 4526de5fcc7SAlexander Yermolovich else 4536de5fcc7SAlexander Yermolovich BucketCount = std::max<uint32_t>(UniqueHashCount, 1); 4546de5fcc7SAlexander Yermolovich } 4556de5fcc7SAlexander Yermolovich 4566de5fcc7SAlexander Yermolovich /// Bucket code as in: AccelTableBase::finalize() 4576de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::finalize() { 4586de5fcc7SAlexander Yermolovich if (!NeedToCreate) 4596de5fcc7SAlexander Yermolovich return; 4606de5fcc7SAlexander Yermolovich // Figure out how many buckets we need, then compute the bucket contents and 4616de5fcc7SAlexander Yermolovich // the final ordering. The hashes and offsets can be emitted by walking these 4626de5fcc7SAlexander Yermolovich // data structures. 4636de5fcc7SAlexander Yermolovich computeBucketCount(); 4646de5fcc7SAlexander Yermolovich 4656de5fcc7SAlexander Yermolovich // Compute bucket contents and final ordering. 4666de5fcc7SAlexander Yermolovich Buckets.resize(BucketCount); 4676de5fcc7SAlexander Yermolovich for (auto &E : Entries) { 4686de5fcc7SAlexander Yermolovich uint32_t Bucket = E.second.HashValue % BucketCount; 4696de5fcc7SAlexander Yermolovich Buckets[Bucket].push_back(&E.second); 4706de5fcc7SAlexander Yermolovich } 4716de5fcc7SAlexander Yermolovich 4726de5fcc7SAlexander Yermolovich // Sort the contents of the buckets by hash value so that hash collisions end 4736de5fcc7SAlexander Yermolovich // up together. Stable sort makes testing easier and doesn't cost much more. 4746de5fcc7SAlexander Yermolovich for (HashList &Bucket : Buckets) { 4756de5fcc7SAlexander Yermolovich llvm::stable_sort(Bucket, [](const HashData *LHS, const HashData *RHS) { 4766de5fcc7SAlexander Yermolovich return LHS->HashValue < RHS->HashValue; 4776de5fcc7SAlexander Yermolovich }); 4786de5fcc7SAlexander Yermolovich for (HashData *H : Bucket) 4796de5fcc7SAlexander Yermolovich llvm::stable_sort(H->Values, [](const BOLTDWARF5AccelTableData *LHS, 4806de5fcc7SAlexander Yermolovich const BOLTDWARF5AccelTableData *RHS) { 4816de5fcc7SAlexander Yermolovich return LHS->getDieOffset() < RHS->getDieOffset(); 4826de5fcc7SAlexander Yermolovich }); 4836de5fcc7SAlexander Yermolovich } 4846de5fcc7SAlexander Yermolovich 4856de5fcc7SAlexander Yermolovich CUIndexForm = DIEInteger::BestForm(/*IsSigned*/ false, CUList.size() - 1); 4866de5fcc7SAlexander Yermolovich TUIndexForm = DIEInteger::BestForm( 4876de5fcc7SAlexander Yermolovich /*IsSigned*/ false, LocalTUList.size() + ForeignTUList.size() - 1); 4886de5fcc7SAlexander Yermolovich const dwarf::FormParams FormParams{5, 4, dwarf::DwarfFormat::DWARF32, false}; 4896de5fcc7SAlexander Yermolovich CUIndexEncodingSize = *dwarf::getFixedFormByteSize(CUIndexForm, FormParams); 4906de5fcc7SAlexander Yermolovich TUIndexEncodingSize = *dwarf::getFixedFormByteSize(TUIndexForm, FormParams); 4916de5fcc7SAlexander Yermolovich } 4926de5fcc7SAlexander Yermolovich 4936de5fcc7SAlexander Yermolovich std::optional<DWARF5AccelTable::UnitIndexAndEncoding> 4946de5fcc7SAlexander Yermolovich DWARF5AcceleratorTable::getIndexForEntry( 4956de5fcc7SAlexander Yermolovich const BOLTDWARF5AccelTableData &Value) const { 4966d4aa9d7SAlexander Yermolovich // The foreign TU list immediately follows the local TU list and they both 4976d4aa9d7SAlexander Yermolovich // use the same index, so that if there are N local TU entries, the index for 4986d4aa9d7SAlexander Yermolovich // the first foreign TU is N. 4996de5fcc7SAlexander Yermolovich if (Value.isTU()) 5006d4aa9d7SAlexander Yermolovich return {{(Value.getSecondUnitID() ? (unsigned)LocalTUList.size() : 0) + 5016d4aa9d7SAlexander Yermolovich Value.getUnitID(), 5026d4aa9d7SAlexander Yermolovich {dwarf::DW_IDX_type_unit, TUIndexForm}}}; 5036de5fcc7SAlexander Yermolovich if (CUList.size() > 1) 5046de5fcc7SAlexander Yermolovich return {{Value.getUnitID(), {dwarf::DW_IDX_compile_unit, CUIndexForm}}}; 5056de5fcc7SAlexander Yermolovich return std::nullopt; 5066de5fcc7SAlexander Yermolovich } 5076de5fcc7SAlexander Yermolovich 5086de5fcc7SAlexander Yermolovich std::optional<DWARF5AccelTable::UnitIndexAndEncoding> 5096de5fcc7SAlexander Yermolovich DWARF5AcceleratorTable::getSecondIndexForEntry( 5106de5fcc7SAlexander Yermolovich const BOLTDWARF5AccelTableData &Value) const { 5116de5fcc7SAlexander Yermolovich if (Value.isTU() && CUList.size() > 1 && Value.getSecondUnitID()) 5126de5fcc7SAlexander Yermolovich return { 5136de5fcc7SAlexander Yermolovich {*Value.getSecondUnitID(), {dwarf::DW_IDX_compile_unit, CUIndexForm}}}; 5146de5fcc7SAlexander Yermolovich return std::nullopt; 5156de5fcc7SAlexander Yermolovich } 5166de5fcc7SAlexander Yermolovich 5176de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::populateAbbrevsMap() { 5186de5fcc7SAlexander Yermolovich for (auto &Bucket : getBuckets()) { 5196de5fcc7SAlexander Yermolovich for (DWARF5AcceleratorTable::HashData *Hash : Bucket) { 5206de5fcc7SAlexander Yermolovich for (BOLTDWARF5AccelTableData *Value : Hash->Values) { 5216de5fcc7SAlexander Yermolovich const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet = 5226de5fcc7SAlexander Yermolovich getIndexForEntry(*Value); 5236de5fcc7SAlexander Yermolovich // For entries that need to refer to the foreign type units and to 5246de5fcc7SAlexander Yermolovich // the CU. 5256de5fcc7SAlexander Yermolovich const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> 5266de5fcc7SAlexander Yermolovich SecondEntryRet = getSecondIndexForEntry(*Value); 5276de5fcc7SAlexander Yermolovich DebugNamesAbbrev Abbrev(Value->getDieTag()); 5286de5fcc7SAlexander Yermolovich if (EntryRet) 5296de5fcc7SAlexander Yermolovich Abbrev.addAttribute(EntryRet->Encoding); 5306de5fcc7SAlexander Yermolovich if (SecondEntryRet) 5316de5fcc7SAlexander Yermolovich Abbrev.addAttribute(SecondEntryRet->Encoding); 5326de5fcc7SAlexander Yermolovich Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4}); 533a4610c71SAlexander Yermolovich if (std::optional<uint64_t> Offset = Value->getParentDieOffset()) 534a4610c71SAlexander Yermolovich Abbrev.addAttribute({dwarf::DW_IDX_parent, dwarf::DW_FORM_ref4}); 53561589b85SAlexander Yermolovich else if (Value->isParentRoot()) 536a4610c71SAlexander Yermolovich Abbrev.addAttribute( 537a4610c71SAlexander Yermolovich {dwarf::DW_IDX_parent, dwarf::DW_FORM_flag_present}); 5386de5fcc7SAlexander Yermolovich FoldingSetNodeID ID; 5396de5fcc7SAlexander Yermolovich Abbrev.Profile(ID); 5406de5fcc7SAlexander Yermolovich void *InsertPos; 5416de5fcc7SAlexander Yermolovich if (DebugNamesAbbrev *Existing = 5426de5fcc7SAlexander Yermolovich AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) { 5436de5fcc7SAlexander Yermolovich Value->setAbbrevNumber(Existing->getNumber()); 5446de5fcc7SAlexander Yermolovich continue; 5456de5fcc7SAlexander Yermolovich } 5466de5fcc7SAlexander Yermolovich DebugNamesAbbrev *NewAbbrev = 5476de5fcc7SAlexander Yermolovich new (Alloc) DebugNamesAbbrev(std::move(Abbrev)); 5486de5fcc7SAlexander Yermolovich AbbreviationsVector.push_back(NewAbbrev); 5496de5fcc7SAlexander Yermolovich NewAbbrev->setNumber(AbbreviationsVector.size()); 5506de5fcc7SAlexander Yermolovich AbbreviationsSet.InsertNode(NewAbbrev, InsertPos); 5516de5fcc7SAlexander Yermolovich Value->setAbbrevNumber(NewAbbrev->getNumber()); 5526de5fcc7SAlexander Yermolovich } 5536de5fcc7SAlexander Yermolovich } 5546de5fcc7SAlexander Yermolovich } 5556de5fcc7SAlexander Yermolovich } 5566de5fcc7SAlexander Yermolovich 557a4610c71SAlexander Yermolovich void DWARF5AcceleratorTable::writeEntry(BOLTDWARF5AccelTableData &Entry) { 558a4610c71SAlexander Yermolovich const uint64_t EntryID = getEntryID(Entry); 559a4610c71SAlexander Yermolovich if (EntryRelativeOffsets.find(EntryID) != EntryRelativeOffsets.end()) 560a4610c71SAlexander Yermolovich EntryRelativeOffsets[EntryID] = EntriesBuffer->size(); 561a4610c71SAlexander Yermolovich 5626de5fcc7SAlexander Yermolovich const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet = 5636de5fcc7SAlexander Yermolovich getIndexForEntry(Entry); 5646de5fcc7SAlexander Yermolovich // For forgeign type (FTU) units that need to refer to the FTU and to the CU. 5656de5fcc7SAlexander Yermolovich const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> SecondEntryRet = 5666de5fcc7SAlexander Yermolovich getSecondIndexForEntry(Entry); 5676de5fcc7SAlexander Yermolovich const unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1; 5686de5fcc7SAlexander Yermolovich assert(AbbrevIndex < AbbreviationsVector.size() && 5696de5fcc7SAlexander Yermolovich "Entry abbrev index is outside of abbreviations vector range."); 5706de5fcc7SAlexander Yermolovich const DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex]; 5716de5fcc7SAlexander Yermolovich encodeULEB128(Entry.getAbbrevNumber(), *Entriestream); 5726de5fcc7SAlexander Yermolovich auto writeIndex = [&](uint32_t Index, uint32_t IndexSize) -> void { 5736de5fcc7SAlexander Yermolovich switch (IndexSize) { 5746de5fcc7SAlexander Yermolovich default: 5756de5fcc7SAlexander Yermolovich llvm_unreachable("Unsupported Index Size!"); 5766de5fcc7SAlexander Yermolovich break; 5776de5fcc7SAlexander Yermolovich case 1: 5786de5fcc7SAlexander Yermolovich support::endian::write(*Entriestream, static_cast<uint8_t>(Index), 5796de5fcc7SAlexander Yermolovich llvm::endianness::little); 5806de5fcc7SAlexander Yermolovich break; 5816de5fcc7SAlexander Yermolovich case 2: 5826de5fcc7SAlexander Yermolovich support::endian::write(*Entriestream, static_cast<uint16_t>(Index), 5836de5fcc7SAlexander Yermolovich llvm::endianness::little); 5846de5fcc7SAlexander Yermolovich break; 5856de5fcc7SAlexander Yermolovich case 4: 5866de5fcc7SAlexander Yermolovich support::endian::write(*Entriestream, static_cast<uint32_t>(Index), 5876de5fcc7SAlexander Yermolovich llvm::endianness::little); 5886de5fcc7SAlexander Yermolovich break; 5896de5fcc7SAlexander Yermolovich }; 5906de5fcc7SAlexander Yermolovich }; 5916de5fcc7SAlexander Yermolovich 5926de5fcc7SAlexander Yermolovich for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc : 5936de5fcc7SAlexander Yermolovich Abbrev->getAttributes()) { 5946de5fcc7SAlexander Yermolovich switch (AttrEnc.Index) { 5956de5fcc7SAlexander Yermolovich default: { 5966de5fcc7SAlexander Yermolovich llvm_unreachable("Unexpected index attribute!"); 5976de5fcc7SAlexander Yermolovich break; 5986de5fcc7SAlexander Yermolovich } 5996de5fcc7SAlexander Yermolovich case dwarf::DW_IDX_compile_unit: { 6006de5fcc7SAlexander Yermolovich const unsigned CUIndex = 6016de5fcc7SAlexander Yermolovich SecondEntryRet ? SecondEntryRet->Index : EntryRet->Index; 6026de5fcc7SAlexander Yermolovich writeIndex(CUIndex, CUIndexEncodingSize); 6036de5fcc7SAlexander Yermolovich break; 6046de5fcc7SAlexander Yermolovich } 6056de5fcc7SAlexander Yermolovich case dwarf::DW_IDX_type_unit: { 6066de5fcc7SAlexander Yermolovich writeIndex(EntryRet->Index, TUIndexEncodingSize); 6076de5fcc7SAlexander Yermolovich break; 6086de5fcc7SAlexander Yermolovich } 6096de5fcc7SAlexander Yermolovich case dwarf::DW_IDX_die_offset: { 6106de5fcc7SAlexander Yermolovich assert(AttrEnc.Form == dwarf::DW_FORM_ref4); 6116de5fcc7SAlexander Yermolovich support::endian::write(*Entriestream, 6126de5fcc7SAlexander Yermolovich static_cast<uint32_t>(Entry.getDieOffset()), 6136de5fcc7SAlexander Yermolovich llvm::endianness::little); 6146de5fcc7SAlexander Yermolovich break; 6156de5fcc7SAlexander Yermolovich } 616a4610c71SAlexander Yermolovich case dwarf::DW_IDX_parent: { 617a4610c71SAlexander Yermolovich assert( 618a4610c71SAlexander Yermolovich (AttrEnc.Form == dwarf::DW_FORM_ref4 && Entry.getParentDieOffset()) || 619a4610c71SAlexander Yermolovich AttrEnc.Form == dwarf::DW_FORM_flag_present); 620a4610c71SAlexander Yermolovich if (std::optional<uint64_t> ParentOffset = Entry.getParentDieOffset()) { 621a4610c71SAlexander Yermolovich Entry.setPatchOffset(EntriesBuffer->size()); 622a4610c71SAlexander Yermolovich support::endian::write(*Entriestream, static_cast<uint32_t>(UINT32_MAX), 623a4610c71SAlexander Yermolovich llvm::endianness::little); 624a4610c71SAlexander Yermolovich } 625a4610c71SAlexander Yermolovich break; 626a4610c71SAlexander Yermolovich } 6276de5fcc7SAlexander Yermolovich } 6286de5fcc7SAlexander Yermolovich } 6296de5fcc7SAlexander Yermolovich } 6306de5fcc7SAlexander Yermolovich 6316de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::writeEntries() { 6326de5fcc7SAlexander Yermolovich for (auto &Bucket : getBuckets()) { 6336de5fcc7SAlexander Yermolovich for (DWARF5AcceleratorTable::HashData *Hash : Bucket) { 6346de5fcc7SAlexander Yermolovich Hash->EntryOffset = EntriesBuffer->size(); 635a4610c71SAlexander Yermolovich for (BOLTDWARF5AccelTableData *Value : Hash->Values) { 6366de5fcc7SAlexander Yermolovich writeEntry(*Value); 6376de5fcc7SAlexander Yermolovich } 6386de5fcc7SAlexander Yermolovich support::endian::write(*Entriestream, static_cast<uint8_t>(0), 6396de5fcc7SAlexander Yermolovich llvm::endianness::little); 6406de5fcc7SAlexander Yermolovich } 6416de5fcc7SAlexander Yermolovich } 642a4610c71SAlexander Yermolovich // Patching parent offsets. 643a4610c71SAlexander Yermolovich for (auto &Bucket : getBuckets()) { 644a4610c71SAlexander Yermolovich for (DWARF5AcceleratorTable::HashData *Hash : Bucket) { 645a4610c71SAlexander Yermolovich for (BOLTDWARF5AccelTableData *Entry : Hash->Values) { 646a4610c71SAlexander Yermolovich std::optional<uint64_t> ParentOffset = Entry->getParentDieOffset(); 647a4610c71SAlexander Yermolovich if (!ParentOffset) 648a4610c71SAlexander Yermolovich continue; 649a4610c71SAlexander Yermolovich if (const auto Iter = EntryRelativeOffsets.find(*ParentOffset); 650a4610c71SAlexander Yermolovich Iter != EntryRelativeOffsets.end()) { 651a4610c71SAlexander Yermolovich const uint64_t PatchOffset = Entry->getPatchOffset(); 652a4610c71SAlexander Yermolovich uint32_t *Ptr = reinterpret_cast<uint32_t *>( 653a4610c71SAlexander Yermolovich &EntriesBuffer.get()->data()[PatchOffset]); 654a4610c71SAlexander Yermolovich *Ptr = Iter->second; 655a4610c71SAlexander Yermolovich } else { 656a4610c71SAlexander Yermolovich BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find " 657a4610c71SAlexander Yermolovich "entry with offset " 658a4610c71SAlexander Yermolovich << *ParentOffset << "\n"; 659a4610c71SAlexander Yermolovich } 660a4610c71SAlexander Yermolovich } 661a4610c71SAlexander Yermolovich } 662a4610c71SAlexander Yermolovich } 6636de5fcc7SAlexander Yermolovich } 6646de5fcc7SAlexander Yermolovich 6656de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::writeAugmentationString() { 6666de5fcc7SAlexander Yermolovich // String needs to be multiple of 4 bytes. 6676de5fcc7SAlexander Yermolovich *AugStringtream << "BOLT"; 6686de5fcc7SAlexander Yermolovich AugmentationStringSize = AugStringBuffer->size(); 6696de5fcc7SAlexander Yermolovich } 6706de5fcc7SAlexander Yermolovich 6716de5fcc7SAlexander Yermolovich /// Calculates size of .debug_names header without Length field. 6726de5fcc7SAlexander Yermolovich static constexpr uint32_t getDebugNamesHeaderSize() { 6736de5fcc7SAlexander Yermolovich constexpr uint16_t VersionLength = sizeof(uint16_t); 6746de5fcc7SAlexander Yermolovich constexpr uint16_t PaddingLength = sizeof(uint16_t); 6756de5fcc7SAlexander Yermolovich constexpr uint32_t CompUnitCountLength = sizeof(uint32_t); 6766de5fcc7SAlexander Yermolovich constexpr uint32_t LocalTypeUnitCountLength = sizeof(uint32_t); 6776de5fcc7SAlexander Yermolovich constexpr uint32_t ForeignTypeUnitCountLength = sizeof(uint32_t); 6786de5fcc7SAlexander Yermolovich constexpr uint32_t BucketCountLength = sizeof(uint32_t); 6796de5fcc7SAlexander Yermolovich constexpr uint32_t NameCountLength = sizeof(uint32_t); 6806de5fcc7SAlexander Yermolovich constexpr uint32_t AbbrevTableSizeLength = sizeof(uint32_t); 6816de5fcc7SAlexander Yermolovich constexpr uint32_t AugmentationStringSizeLenght = sizeof(uint32_t); 6826de5fcc7SAlexander Yermolovich return VersionLength + PaddingLength + CompUnitCountLength + 6836de5fcc7SAlexander Yermolovich LocalTypeUnitCountLength + ForeignTypeUnitCountLength + 6846de5fcc7SAlexander Yermolovich BucketCountLength + NameCountLength + AbbrevTableSizeLength + 6856de5fcc7SAlexander Yermolovich AugmentationStringSizeLenght; 6866de5fcc7SAlexander Yermolovich } 6876de5fcc7SAlexander Yermolovich 6886de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitHeader() const { 6896de5fcc7SAlexander Yermolovich constexpr uint32_t HeaderSize = getDebugNamesHeaderSize(); 6906de5fcc7SAlexander Yermolovich // Header Length 6916de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, 6926de5fcc7SAlexander Yermolovich static_cast<uint32_t>(HeaderSize + StrBuffer->size() + 6936de5fcc7SAlexander Yermolovich AugmentationStringSize), 6946de5fcc7SAlexander Yermolovich llvm::endianness::little); 6956de5fcc7SAlexander Yermolovich // Version 6966de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, static_cast<uint16_t>(5), 6976de5fcc7SAlexander Yermolovich llvm::endianness::little); 6986de5fcc7SAlexander Yermolovich // Padding 6996de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, static_cast<uint16_t>(0), 7006de5fcc7SAlexander Yermolovich llvm::endianness::little); 7016de5fcc7SAlexander Yermolovich // Compilation Unit Count 7026de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, static_cast<uint32_t>(CUList.size()), 7036de5fcc7SAlexander Yermolovich llvm::endianness::little); 7046de5fcc7SAlexander Yermolovich // Local Type Unit Count 7056de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, 7066de5fcc7SAlexander Yermolovich static_cast<uint32_t>(LocalTUList.size()), 7076de5fcc7SAlexander Yermolovich llvm::endianness::little); 7086de5fcc7SAlexander Yermolovich // Foreign Type Unit Count 7096de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, 7106de5fcc7SAlexander Yermolovich static_cast<uint32_t>(ForeignTUList.size()), 7116de5fcc7SAlexander Yermolovich llvm::endianness::little); 7126de5fcc7SAlexander Yermolovich // Bucket Count 7136de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, static_cast<uint32_t>(BucketCount), 7146de5fcc7SAlexander Yermolovich llvm::endianness::little); 7156de5fcc7SAlexander Yermolovich // Name Count 7166de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, 7176de5fcc7SAlexander Yermolovich static_cast<uint32_t>(Entries.size()), 7186de5fcc7SAlexander Yermolovich llvm::endianness::little); 7196de5fcc7SAlexander Yermolovich // Abbrev Table Size 7206de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, 7216de5fcc7SAlexander Yermolovich static_cast<uint32_t>(AbbrevTableSize), 7226de5fcc7SAlexander Yermolovich llvm::endianness::little); 7236de5fcc7SAlexander Yermolovich // Augmentation String Size 7246de5fcc7SAlexander Yermolovich support::endian::write(*FullTableStream, 7256de5fcc7SAlexander Yermolovich static_cast<uint32_t>(AugmentationStringSize), 7266de5fcc7SAlexander Yermolovich llvm::endianness::little); 7276de5fcc7SAlexander Yermolovich 7286de5fcc7SAlexander Yermolovich emitAugmentationString(); 7296de5fcc7SAlexander Yermolovich FullTableStream->write(StrBuffer->data(), StrBuffer->size()); 7306de5fcc7SAlexander Yermolovich } 7316de5fcc7SAlexander Yermolovich 7326de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitCUList() const { 7336de5fcc7SAlexander Yermolovich for (const uint32_t CUID : CUList) 7346de5fcc7SAlexander Yermolovich support::endian::write(*StrStream, CUID, llvm::endianness::little); 7356de5fcc7SAlexander Yermolovich } 7366de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitTUList() const { 7376de5fcc7SAlexander Yermolovich for (const uint32_t TUID : LocalTUList) 7386de5fcc7SAlexander Yermolovich support::endian::write(*StrStream, TUID, llvm::endianness::little); 7396de5fcc7SAlexander Yermolovich 7406de5fcc7SAlexander Yermolovich for (const uint64_t TUID : ForeignTUList) 7416de5fcc7SAlexander Yermolovich support::endian::write(*StrStream, TUID, llvm::endianness::little); 7426de5fcc7SAlexander Yermolovich } 7436de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitBuckets() const { 7446de5fcc7SAlexander Yermolovich uint32_t Index = 1; 7456de5fcc7SAlexander Yermolovich for (const auto &Bucket : enumerate(getBuckets())) { 7466de5fcc7SAlexander Yermolovich const uint32_t TempIndex = Bucket.value().empty() ? 0 : Index; 7476de5fcc7SAlexander Yermolovich support::endian::write(*StrStream, TempIndex, llvm::endianness::little); 7486de5fcc7SAlexander Yermolovich Index += Bucket.value().size(); 7496de5fcc7SAlexander Yermolovich } 7506de5fcc7SAlexander Yermolovich } 7516de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitHashes() const { 7526de5fcc7SAlexander Yermolovich for (const auto &Bucket : getBuckets()) { 7536de5fcc7SAlexander Yermolovich for (const DWARF5AcceleratorTable::HashData *Hash : Bucket) 7546de5fcc7SAlexander Yermolovich support::endian::write(*StrStream, Hash->HashValue, 7556de5fcc7SAlexander Yermolovich llvm::endianness::little); 7566de5fcc7SAlexander Yermolovich } 7576de5fcc7SAlexander Yermolovich } 7586de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitStringOffsets() const { 7596de5fcc7SAlexander Yermolovich for (const auto &Bucket : getBuckets()) { 7606de5fcc7SAlexander Yermolovich for (const DWARF5AcceleratorTable::HashData *Hash : Bucket) 7616de5fcc7SAlexander Yermolovich support::endian::write(*StrStream, static_cast<uint32_t>(Hash->StrOffset), 7626de5fcc7SAlexander Yermolovich llvm::endianness::little); 7636de5fcc7SAlexander Yermolovich } 7646de5fcc7SAlexander Yermolovich } 7656de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitOffsets() const { 7666de5fcc7SAlexander Yermolovich for (const auto &Bucket : getBuckets()) { 7676de5fcc7SAlexander Yermolovich for (const DWARF5AcceleratorTable::HashData *Hash : Bucket) 7686de5fcc7SAlexander Yermolovich support::endian::write(*StrStream, 7696de5fcc7SAlexander Yermolovich static_cast<uint32_t>(Hash->EntryOffset), 7706de5fcc7SAlexander Yermolovich llvm::endianness::little); 7716de5fcc7SAlexander Yermolovich } 7726de5fcc7SAlexander Yermolovich } 7736de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitAbbrevs() { 7746de5fcc7SAlexander Yermolovich const uint32_t AbbrevTableStart = StrBuffer->size(); 7756de5fcc7SAlexander Yermolovich for (const auto *Abbrev : AbbreviationsVector) { 7766de5fcc7SAlexander Yermolovich encodeULEB128(Abbrev->getNumber(), *StrStream); 7776de5fcc7SAlexander Yermolovich encodeULEB128(Abbrev->getDieTag(), *StrStream); 7786de5fcc7SAlexander Yermolovich for (const auto &AttrEnc : Abbrev->getAttributes()) { 7796de5fcc7SAlexander Yermolovich encodeULEB128(AttrEnc.Index, *StrStream); 7806de5fcc7SAlexander Yermolovich encodeULEB128(AttrEnc.Form, *StrStream); 7816de5fcc7SAlexander Yermolovich } 7826de5fcc7SAlexander Yermolovich encodeULEB128(0, *StrStream); 7836de5fcc7SAlexander Yermolovich encodeULEB128(0, *StrStream); 7846de5fcc7SAlexander Yermolovich } 7856de5fcc7SAlexander Yermolovich encodeULEB128(0, *StrStream); 7866de5fcc7SAlexander Yermolovich AbbrevTableSize = StrBuffer->size() - AbbrevTableStart; 7876de5fcc7SAlexander Yermolovich } 7886de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitData() { 7896de5fcc7SAlexander Yermolovich StrStream->write(EntriesBuffer->data(), EntriesBuffer->size()); 7906de5fcc7SAlexander Yermolovich } 7916de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitAugmentationString() const { 7926de5fcc7SAlexander Yermolovich FullTableStream->write(AugStringBuffer->data(), AugStringBuffer->size()); 7936de5fcc7SAlexander Yermolovich } 7946de5fcc7SAlexander Yermolovich void DWARF5AcceleratorTable::emitAccelTable() { 7956de5fcc7SAlexander Yermolovich if (!NeedToCreate) 7966de5fcc7SAlexander Yermolovich return; 7976de5fcc7SAlexander Yermolovich finalize(); 7986de5fcc7SAlexander Yermolovich populateAbbrevsMap(); 7996de5fcc7SAlexander Yermolovich writeEntries(); 8006de5fcc7SAlexander Yermolovich writeAugmentationString(); 8016de5fcc7SAlexander Yermolovich emitCUList(); 8026de5fcc7SAlexander Yermolovich emitTUList(); 8036de5fcc7SAlexander Yermolovich emitBuckets(); 8046de5fcc7SAlexander Yermolovich emitHashes(); 8056de5fcc7SAlexander Yermolovich emitStringOffsets(); 8066de5fcc7SAlexander Yermolovich emitOffsets(); 8076de5fcc7SAlexander Yermolovich emitAbbrevs(); 8086de5fcc7SAlexander Yermolovich emitData(); 8096de5fcc7SAlexander Yermolovich emitHeader(); 8106de5fcc7SAlexander Yermolovich } 8116de5fcc7SAlexander Yermolovich } // namespace bolt 8126de5fcc7SAlexander Yermolovich } // namespace llvm 813