xref: /llvm-project/bolt/lib/Core/DebugNames.cpp (revision 331c2dd8b482e441d8ccddc09f21a02cc9454786)
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