812 lines · cpp
1//===- bolt/Rewrite/DebugNames.cpp -------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "bolt/Core/DebugNames.h"10#include "bolt/Core/BinaryContext.h"11#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"12#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"13#include "llvm/Support/EndianStream.h"14#include "llvm/Support/LEB128.h"15#include <cstdint>16#include <optional>17 18namespace llvm {19namespace bolt {20DWARF5AcceleratorTable::DWARF5AcceleratorTable(21 const bool CreateDebugNames, BinaryContext &BC,22 DebugStrWriter &MainBinaryStrWriter)23 : BC(BC), MainBinaryStrWriter(MainBinaryStrWriter) {24 NeedToCreate = CreateDebugNames || BC.getDebugNamesSection();25 if (!NeedToCreate)26 return;27 FullTableBuffer = std::make_unique<DebugStrBufferVector>();28 FullTableStream = std::make_unique<raw_svector_ostream>(*FullTableBuffer);29 StrBuffer = std::make_unique<DebugStrBufferVector>();30 StrStream = std::make_unique<raw_svector_ostream>(*StrBuffer);31 EntriesBuffer = std::make_unique<DebugStrBufferVector>();32 Entriestream = std::make_unique<raw_svector_ostream>(*EntriesBuffer);33 AugStringBuffer = std::make_unique<DebugStrBufferVector>();34 AugStringtream = std::make_unique<raw_svector_ostream>(*AugStringBuffer);35 36 // Binary has split-dwarf CUs.37 // Even thought for non-skeleton-cu all names are in .debug_str.dwo section,38 // for the .debug_names contributions they are in .debug_str section.39 if (BC.getNumDWOCUs()) {40 DataExtractor StrData(BC.DwCtx->getDWARFObj().getStrSection(),41 BC.DwCtx->isLittleEndian(), 0);42 uint64_t Offset = 0;43 uint64_t StrOffset = 0;44 while (StrData.isValidOffset(Offset)) {45 Error Err = Error::success();46 const char *CStr = StrData.getCStr(&Offset, &Err);47 if (Err) {48 NeedToCreate = false;49 BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: Could not extract "50 "string from .debug_str section at offset: "51 << Twine::utohexstr(StrOffset) << ".\n";52 return;53 }54 auto R = StrCacheToOffsetMap.try_emplace(55 llvm::hash_value(llvm::StringRef(CStr)), StrOffset);56 if (!R.second)57 BC.errs()58 << "BOLT-WARNING: [internal-dwarf-error]: collision occurred on "59 << CStr << " at offset : 0x" << Twine::utohexstr(StrOffset)60 << ". Previous string offset is: 0x"61 << Twine::utohexstr(R.first->second) << ".\n";62 StrOffset = Offset;63 }64 }65}66 67void DWARF5AcceleratorTable::setCurrentUnit(DWARFUnit &Unit,68 const uint64_t UnitStartOffset) {69 CurrentUnit = nullptr;70 CurrentUnitOffset = UnitStartOffset;71 std::optional<uint64_t> DWOID = Unit.getDWOId();72 // We process skeleton CUs after DWO Units for it.73 // Patching offset in CU list to correct one.74 if (!Unit.isDWOUnit() && DWOID) {75 auto Iter = CUOffsetsToPatch.find(*DWOID);76 // Check in case no entries were added from non skeleton DWO section.77 if (Iter != CUOffsetsToPatch.end())78 CUList[Iter->second] = UnitStartOffset;79 }80}81 82void DWARF5AcceleratorTable::addUnit(DWARFUnit &Unit,83 const std::optional<uint64_t> &DWOID) {84 constexpr uint32_t BADCUOFFSET = 0xBADBAD;85 StrSection = Unit.getStringSection();86 if (Unit.isTypeUnit()) {87 if (DWOID) {88 // We adding an entry for a DWO TU. The DWO CU might not have any entries,89 // so need to add it to the list preemptively.90 auto Iter = CUOffsetsToPatch.insert({*DWOID, CUList.size()});91 if (Iter.second)92 CUList.push_back(BADCUOFFSET);93 const uint64_t TUHash = cast<DWARFTypeUnit>(&Unit)->getTypeHash();94 if (!TUHashToIndexMap.count(TUHash)) {95 TUHashToIndexMap.insert({TUHash, ForeignTUList.size()});96 ForeignTUList.push_back(TUHash);97 }98 } else {99 LocalTUList.push_back(CurrentUnitOffset);100 }101 } else {102 if (DWOID) {103 // This is a path for split dwarf without type units.104 // We process DWO Units before Skeleton CU. So at this point we don't know105 // the offset of Skeleton CU. Adding CULit index to a map to patch later106 // with the correct offset.107 auto Iter = CUOffsetsToPatch.insert({*DWOID, CUList.size()});108 if (Iter.second)109 CUList.push_back(BADCUOFFSET);110 } else {111 CUList.push_back(CurrentUnitOffset);112 }113 }114}115 116// Returns true if DW_TAG_variable should be included in .debug-names based on117// section 6.1.1.1 for DWARF5 spec.118static bool shouldIncludeVariable(const DWARFUnit &Unit, const DIE &Die) {119 const DIEValue LocAttrInfo =120 Die.findAttribute(dwarf::Attribute::DW_AT_location);121 if (!LocAttrInfo)122 return false;123 if (!(doesFormBelongToClass(LocAttrInfo.getForm(), DWARFFormValue::FC_Exprloc,124 Unit.getVersion()) ||125 doesFormBelongToClass(LocAttrInfo.getForm(), DWARFFormValue::FC_Block,126 Unit.getVersion())))127 return false;128 std::vector<uint8_t> Sblock;129 auto constructVect =130 [&](const DIEValueList::const_value_range &Iter) -> void {131 for (const DIEValue &Val : Iter)132 Sblock.push_back(Val.getDIEInteger().getValue());133 };134 if (doesFormBelongToClass(LocAttrInfo.getForm(), DWARFFormValue::FC_Exprloc,135 Unit.getVersion()))136 constructVect(LocAttrInfo.getDIELoc().values());137 else138 constructVect(LocAttrInfo.getDIEBlock().values());139 ArrayRef<uint8_t> Expr = ArrayRef<uint8_t>(Sblock);140 DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),141 Unit.getContext().isLittleEndian(), 0);142 DWARFExpression LocExpr(Data, Unit.getAddressByteSize(),143 Unit.getFormParams().Format);144 for (const DWARFExpression::Operation &Expr : LocExpr)145 if (Expr.getCode() == dwarf::DW_OP_addrx ||146 Expr.getCode() == dwarf::DW_OP_form_tls_address ||147 Expr.getCode() == dwarf::DW_OP_GNU_push_tls_address)148 return true;149 return false;150}151 152bool static canProcess(const DWARFUnit &Unit, const DIE &Die,153 std::string &NameToUse, const bool TagsOnly) {154 if (Die.findAttribute(dwarf::Attribute::DW_AT_declaration))155 return false;156 switch (Die.getTag()) {157 case dwarf::DW_TAG_base_type:158 case dwarf::DW_TAG_class_type:159 case dwarf::DW_TAG_enumeration_type:160 case dwarf::DW_TAG_imported_declaration:161 case dwarf::DW_TAG_pointer_type:162 case dwarf::DW_TAG_structure_type:163 case dwarf::DW_TAG_typedef:164 case dwarf::DW_TAG_unspecified_type:165 case dwarf::DW_TAG_union_type:166 if (TagsOnly || Die.findAttribute(dwarf::Attribute::DW_AT_name))167 return true;168 return false;169 case dwarf::DW_TAG_namespace:170 // According to DWARF5 spec namespaces without DW_AT_name needs to have171 // "(anonymous namespace)"172 if (!Die.findAttribute(dwarf::Attribute::DW_AT_name))173 NameToUse = "(anonymous namespace)";174 return true;175 case dwarf::DW_TAG_inlined_subroutine:176 case dwarf::DW_TAG_label:177 case dwarf::DW_TAG_subprogram:178 if (TagsOnly || Die.findAttribute(dwarf::Attribute::DW_AT_low_pc) ||179 Die.findAttribute(dwarf::Attribute::DW_AT_high_pc) ||180 Die.findAttribute(dwarf::Attribute::DW_AT_ranges) ||181 Die.findAttribute(dwarf::Attribute::DW_AT_entry_pc))182 return true;183 return false;184 case dwarf::DW_TAG_variable:185 return TagsOnly || shouldIncludeVariable(Unit, Die);186 default:187 break;188 }189 return false;190}191 192bool DWARF5AcceleratorTable::canGenerateEntryWithCrossCUReference(193 const DWARFUnit &Unit, const DIE &Die,194 const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) {195 if (!isCreated())196 return false;197 std::string NameToUse = "";198 if (!canProcess(Unit, Die, NameToUse, true))199 return false;200 return (AttrSpec.Attr == dwarf::Attribute::DW_AT_abstract_origin ||201 AttrSpec.Attr == dwarf::Attribute::DW_AT_specification) &&202 AttrSpec.Form == dwarf::DW_FORM_ref_addr;203}204/// Returns name offset in String Offset section.205static uint64_t getNameOffset(BinaryContext &BC, DWARFUnit &Unit,206 const uint64_t Index) {207 const DWARFSection &StrOffsetsSection = Unit.getStringOffsetSection();208 const std::optional<StrOffsetsContributionDescriptor> &Contr =209 Unit.getStringOffsetsTableContribution();210 if (!Contr) {211 BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not get "212 "StringOffsetsTableContribution for unit at offset: "213 << Twine::utohexstr(Unit.getOffset()) << ".\n";214 return 0;215 }216 217 const uint8_t DwarfOffsetByteSize = Contr->getDwarfOffsetByteSize();218 return support::endian::read32le(StrOffsetsSection.Data.data() + Contr->Base +219 Index * DwarfOffsetByteSize);220}221 222static uint64_t getEntryID(const BOLTDWARF5AccelTableData &Entry) {223 return reinterpret_cast<uint64_t>(&Entry);224}225 226uint32_t DWARF5AcceleratorTable::getUnitID(const DWARFUnit &Unit,227 const std::optional<uint64_t> &DWOID,228 bool &IsTU) {229 IsTU = Unit.isTypeUnit();230 if (IsTU) {231 if (DWOID) {232 const uint64_t TUHash = cast<DWARFTypeUnit>(&Unit)->getTypeHash();233 auto Iter = TUHashToIndexMap.find(TUHash);234 assert(Iter != TUHashToIndexMap.end() && "Could not find TU hash in map");235 return Iter->second;236 }237 return LocalTUList.size() - 1;238 }239 return CUList.size() - 1;240}241 242std::optional<std::string> DWARF5AcceleratorTable::getName(243 DWARFUnit &Unit, const std::optional<uint64_t> &DWOID,244 const std::string &NameToUse, DIEValue ValName) {245 if ((!ValName || ValName.getForm() == dwarf::DW_FORM_string) &&246 NameToUse.empty())247 return std::nullopt;248 std::string Name = "";249 uint64_t NameIndexOffset = 0;250 if (NameToUse.empty()) {251 NameIndexOffset = ValName.getDIEInteger().getValue();252 if (ValName.getForm() != dwarf::DW_FORM_strp)253 NameIndexOffset = getNameOffset(BC, Unit, NameIndexOffset);254 // Counts on strings end with '\0'.255 Name = std::string(&StrSection.data()[NameIndexOffset]);256 } else {257 Name = NameToUse;258 }259 auto &It = Entries[Name];260 if (It.Values.empty()) {261 if (DWOID && NameToUse.empty()) {262 // For DWO Unit the offset is in the .debug_str.dwo section.263 // Need to find offset for the name in the .debug_str section.264 llvm::hash_code Hash = llvm::hash_value(llvm::StringRef(Name));265 auto ItCache = StrCacheToOffsetMap.find(Hash);266 if (ItCache == StrCacheToOffsetMap.end())267 NameIndexOffset = MainBinaryStrWriter.addString(Name);268 else269 NameIndexOffset = ItCache->second;270 }271 if (!NameToUse.empty())272 NameIndexOffset = MainBinaryStrWriter.addString(Name);273 It.StrOffset = NameIndexOffset;274 // This is the same hash function used in DWARF5AccelTableData.275 It.HashValue = caseFoldingDjbHash(Name);276 }277 return Name;278}279 280std::optional<BOLTDWARF5AccelTableData *> DWARF5AcceleratorTable::addEntry(281 DWARFUnit &DU, const DIE &CurrDie, const std::optional<uint64_t> &DWOID,282 const std::optional<BOLTDWARF5AccelTableData *> &Parent,283 const std::optional<std::string> &Name,284 const uint32_t NumberParentsInChain) {285 if (!Name)286 return std::nullopt;287 288 auto &It = Entries[*Name];289 bool IsTU = false;290 uint32_t DieTag = CurrDie.getTag();291 uint32_t UnitID = getUnitID(DU, DWOID, IsTU);292 std::optional<unsigned> SecondIndex = std::nullopt;293 if (IsTU && DWOID) {294 auto Iter = CUOffsetsToPatch.find(*DWOID);295 if (Iter == CUOffsetsToPatch.end())296 BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "297 "DWO ID in CU offsets for second Unit Index "298 << *Name << ". For DIE at offset: "299 << Twine::utohexstr(CurrentUnitOffset + CurrDie.getOffset())300 << ".\n";301 SecondIndex = Iter->second;302 }303 std::optional<uint64_t> ParentOffset =304 (Parent ? std::optional<uint64_t>(getEntryID(**Parent)) : std::nullopt);305 // This will be only populated in writeEntry, in order to keep only the parent306 // entries, and keep the footprint down.307 if (ParentOffset)308 EntryRelativeOffsets.insert({*ParentOffset, 0});309 bool IsParentRoot = false;310 // If there is no parent and no valid Entries in parent chain this is a root311 // to be marked with a flag.312 if (!Parent && !NumberParentsInChain)313 IsParentRoot = true;314 It.Values.push_back(new (Allocator) BOLTDWARF5AccelTableData(315 CurrDie.getOffset(), ParentOffset, DieTag, UnitID, IsParentRoot, IsTU,316 SecondIndex));317 return It.Values.back();318}319 320std::optional<BOLTDWARF5AccelTableData *>321DWARF5AcceleratorTable::processReferencedDie(322 DWARFUnit &Unit, const DIE &Die, const std::optional<uint64_t> &DWOID,323 const std::optional<BOLTDWARF5AccelTableData *> &Parent,324 const std::string &NameToUse, const uint32_t NumberParentsInChain,325 const dwarf::Attribute &Attr) {326 DIEValue Value = Die.findAttribute(Attr);327 if (!Value)328 return std::nullopt;329 auto getReferenceDie = [&](const DIEValue &Value, const DIE *RefDieUsed)330 -> std::optional<std::pair<DWARFUnit *, const DIE *>> {331 if (!Value)332 return std::nullopt;333 if (Value.getForm() == dwarf::DW_FORM_ref_addr) {334 auto Iter = CrossCUDies.find(Value.getDIEInteger().getValue());335 if (Iter == CrossCUDies.end()) {336 BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "337 "referenced DIE in CrossCUDies for "338 << Twine::utohexstr(Value.getDIEInteger().getValue())339 << ".\n";340 return std::nullopt;341 }342 return Iter->second;343 }344 const DIEEntry &DIEENtry = Value.getDIEEntry();345 return {{&Unit, &DIEENtry.getEntry()}};346 };347 348 DIEValue AttrValLinkageName;349 DIEValue AttrValName = Die.findAttribute(dwarf::Attribute::DW_AT_name);350 DWARFUnit *RefUnit = &Unit;351 const DIE *RefDieUsed = &Die;352 // It is possible to have DW_TAG_subprogram only with DW_AT_linkage_name that353 // DW_AT_abstract_origin/DW_AT_specification point to.354 while (!AttrValName) {355 std::optional<std::pair<DWARFUnit *, const DIE *>> RefDUDie =356 getReferenceDie(Value, RefDieUsed);357 if (!RefDUDie)358 break;359 RefUnit = RefDUDie->first;360 const DIE &RefDie = *RefDUDie->second;361 RefDieUsed = &RefDie;362 if (!AttrValLinkageName)363 AttrValLinkageName =364 RefDie.findAttribute(dwarf::Attribute::DW_AT_linkage_name);365 AttrValName = RefDie.findAttribute(dwarf::Attribute::DW_AT_name);366 Value = RefDie.findAttribute(dwarf::Attribute::DW_AT_abstract_origin);367 if (!Value)368 Value = RefDie.findAttribute(dwarf::Attribute::DW_AT_specification);369 }370 addEntry(Unit, Die, DWOID, Parent,371 getName(*RefUnit, DWOID, NameToUse, AttrValLinkageName),372 NumberParentsInChain);373 return addEntry(Unit, Die, DWOID, Parent,374 getName(*RefUnit, DWOID, NameToUse, AttrValName),375 NumberParentsInChain);376}377 378std::optional<BOLTDWARF5AccelTableData *>379DWARF5AcceleratorTable::addAccelTableEntry(380 DWARFUnit &Unit, const DIE &Die, const std::optional<uint64_t> &DWOID,381 const uint32_t NumberParentsInChain,382 std::optional<BOLTDWARF5AccelTableData *> &Parent) {383 if (Unit.getVersion() < 5 || !NeedToCreate)384 return std::nullopt;385 std::string NameToUse = "";386 387 if (!canProcess(Unit, Die, NameToUse, false))388 return std::nullopt;389 390 // Adds a Unit to either CU, LocalTU or ForeignTU list the first time we391 // encounter it.392 // Invoking it here so that we don't add Units that don't have any entries.393 if (&Unit != CurrentUnit) {394 CurrentUnit = &Unit;395 addUnit(Unit, DWOID);396 }397 398 // Minor optimization not to add entry twice for DW_TAG_namespace if it has no399 // DW_AT_name.400 std::optional<BOLTDWARF5AccelTableData *> LinkageEntry = std::nullopt;401 DIEValue NameVal = Die.findAttribute(dwarf::Attribute::DW_AT_name);402 DIEValue LinkageNameVal =403 Die.findAttribute(dwarf::Attribute::DW_AT_linkage_name);404 if (!(Die.getTag() == dwarf::DW_TAG_namespace && !NameVal))405 LinkageEntry = addEntry(Unit, Die, DWOID, Parent,406 getName(Unit, DWOID, NameToUse, LinkageNameVal),407 NumberParentsInChain);408 409 std::optional<BOLTDWARF5AccelTableData *> NameEntry =410 addEntry(Unit, Die, DWOID, Parent,411 getName(Unit, DWOID, NameToUse, NameVal), NumberParentsInChain);412 if (NameEntry)413 return NameEntry;414 415 // The DIE doesn't have DW_AT_name or DW_AT_linkage_name, so we need to see if416 // we can follow other attributes to find them. For the purposes of417 // determining whether a debug information entry has a particular418 // attribute (such as DW_AT_name), if debug information entry A has a419 // DW_AT_specification or DW_AT_abstract_origin attribute pointing to another420 // debug information entry B, any attributes of B are considered to be421 // part of A.422 if (std::optional<BOLTDWARF5AccelTableData *> Entry = processReferencedDie(423 Unit, Die, DWOID, Parent, NameToUse, NumberParentsInChain,424 dwarf::Attribute::DW_AT_abstract_origin))425 return *Entry;426 if (std::optional<BOLTDWARF5AccelTableData *> Entry = processReferencedDie(427 Unit, Die, DWOID, Parent, NameToUse, NumberParentsInChain,428 dwarf::Attribute::DW_AT_specification))429 return *Entry;430 431 // This point can be hit by DW_TAG_varialbe that has no DW_AT_name.432 return std::nullopt;433}434 435/// Algorithm from llvm implementation.436void DWARF5AcceleratorTable::computeBucketCount() {437 // First get the number of unique hashes.438 std::vector<uint32_t> Uniques;439 Uniques.reserve(Entries.size());440 for (const auto &E : Entries)441 Uniques.push_back(E.second.HashValue);442 array_pod_sort(Uniques.begin(), Uniques.end());443 std::vector<uint32_t>::iterator P = llvm::unique(Uniques);444 445 UniqueHashCount = std::distance(Uniques.begin(), P);446 447 if (UniqueHashCount > 1024)448 BucketCount = UniqueHashCount / 4;449 else if (UniqueHashCount > 16)450 BucketCount = UniqueHashCount / 2;451 else452 BucketCount = std::max<uint32_t>(UniqueHashCount, 1);453}454 455/// Bucket code as in: AccelTableBase::finalize()456void DWARF5AcceleratorTable::finalize() {457 if (!NeedToCreate)458 return;459 // Figure out how many buckets we need, then compute the bucket contents and460 // the final ordering. The hashes and offsets can be emitted by walking these461 // data structures.462 computeBucketCount();463 464 // Compute bucket contents and final ordering.465 Buckets.resize(BucketCount);466 for (auto &E : Entries) {467 uint32_t Bucket = E.second.HashValue % BucketCount;468 Buckets[Bucket].push_back(&E.second);469 }470 471 // Sort the contents of the buckets by hash value so that hash collisions end472 // up together. Stable sort makes testing easier and doesn't cost much more.473 for (HashList &Bucket : Buckets) {474 llvm::stable_sort(Bucket, [](const HashData *LHS, const HashData *RHS) {475 return LHS->HashValue < RHS->HashValue;476 });477 for (HashData *H : Bucket)478 llvm::stable_sort(H->Values, [](const BOLTDWARF5AccelTableData *LHS,479 const BOLTDWARF5AccelTableData *RHS) {480 return LHS->getDieOffset() < RHS->getDieOffset();481 });482 }483 484 CUIndexForm = DIEInteger::BestForm(/*IsSigned*/ false, CUList.size() - 1);485 TUIndexForm = DIEInteger::BestForm(486 /*IsSigned*/ false, LocalTUList.size() + ForeignTUList.size() - 1);487 const dwarf::FormParams FormParams{5, 4, dwarf::DwarfFormat::DWARF32, false};488 CUIndexEncodingSize = *dwarf::getFixedFormByteSize(CUIndexForm, FormParams);489 TUIndexEncodingSize = *dwarf::getFixedFormByteSize(TUIndexForm, FormParams);490}491 492std::optional<DWARF5AccelTable::UnitIndexAndEncoding>493DWARF5AcceleratorTable::getIndexForEntry(494 const BOLTDWARF5AccelTableData &Value) const {495 // The foreign TU list immediately follows the local TU list and they both496 // use the same index, so that if there are N local TU entries, the index for497 // the first foreign TU is N.498 if (Value.isTU())499 return {{(Value.getSecondUnitID() ? (unsigned)LocalTUList.size() : 0) +500 Value.getUnitID(),501 {dwarf::DW_IDX_type_unit, TUIndexForm}}};502 if (CUList.size() > 1)503 return {{Value.getUnitID(), {dwarf::DW_IDX_compile_unit, CUIndexForm}}};504 return std::nullopt;505}506 507std::optional<DWARF5AccelTable::UnitIndexAndEncoding>508DWARF5AcceleratorTable::getSecondIndexForEntry(509 const BOLTDWARF5AccelTableData &Value) const {510 if (Value.isTU() && CUList.size() > 1 && Value.getSecondUnitID())511 return {512 {*Value.getSecondUnitID(), {dwarf::DW_IDX_compile_unit, CUIndexForm}}};513 return std::nullopt;514}515 516void DWARF5AcceleratorTable::populateAbbrevsMap() {517 for (auto &Bucket : getBuckets()) {518 for (DWARF5AcceleratorTable::HashData *Hash : Bucket) {519 for (BOLTDWARF5AccelTableData *Value : Hash->Values) {520 const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =521 getIndexForEntry(*Value);522 // For entries that need to refer to the foreign type units and to523 // the CU.524 const std::optional<DWARF5AccelTable::UnitIndexAndEncoding>525 SecondEntryRet = getSecondIndexForEntry(*Value);526 DebugNamesAbbrev Abbrev(Value->getDieTag());527 if (EntryRet)528 Abbrev.addAttribute(EntryRet->Encoding);529 if (SecondEntryRet)530 Abbrev.addAttribute(SecondEntryRet->Encoding);531 Abbrev.addAttribute({dwarf::DW_IDX_die_offset, dwarf::DW_FORM_ref4});532 if (std::optional<uint64_t> Offset = Value->getParentDieOffset())533 Abbrev.addAttribute({dwarf::DW_IDX_parent, dwarf::DW_FORM_ref4});534 else if (Value->isParentRoot())535 Abbrev.addAttribute(536 {dwarf::DW_IDX_parent, dwarf::DW_FORM_flag_present});537 FoldingSetNodeID ID;538 Abbrev.Profile(ID);539 void *InsertPos;540 if (DebugNamesAbbrev *Existing =541 AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) {542 Value->setAbbrevNumber(Existing->getNumber());543 continue;544 }545 DebugNamesAbbrev *NewAbbrev =546 new (Alloc) DebugNamesAbbrev(std::move(Abbrev));547 AbbreviationsVector.push_back(NewAbbrev);548 NewAbbrev->setNumber(AbbreviationsVector.size());549 AbbreviationsSet.InsertNode(NewAbbrev, InsertPos);550 Value->setAbbrevNumber(NewAbbrev->getNumber());551 }552 }553 }554}555 556void DWARF5AcceleratorTable::writeEntry(BOLTDWARF5AccelTableData &Entry) {557 const uint64_t EntryID = getEntryID(Entry);558 if (EntryRelativeOffsets.contains(EntryID))559 EntryRelativeOffsets[EntryID] = EntriesBuffer->size();560 561 const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> EntryRet =562 getIndexForEntry(Entry);563 // For forgeign type (FTU) units that need to refer to the FTU and to the CU.564 const std::optional<DWARF5AccelTable::UnitIndexAndEncoding> SecondEntryRet =565 getSecondIndexForEntry(Entry);566 const unsigned AbbrevIndex = Entry.getAbbrevNumber() - 1;567 assert(AbbrevIndex < AbbreviationsVector.size() &&568 "Entry abbrev index is outside of abbreviations vector range.");569 const DebugNamesAbbrev *Abbrev = AbbreviationsVector[AbbrevIndex];570 encodeULEB128(Entry.getAbbrevNumber(), *Entriestream);571 auto writeIndex = [&](uint32_t Index, uint32_t IndexSize) -> void {572 switch (IndexSize) {573 default:574 llvm_unreachable("Unsupported Index Size!");575 break;576 case 1:577 support::endian::write(*Entriestream, static_cast<uint8_t>(Index),578 llvm::endianness::little);579 break;580 case 2:581 support::endian::write(*Entriestream, static_cast<uint16_t>(Index),582 llvm::endianness::little);583 break;584 case 4:585 support::endian::write(*Entriestream, static_cast<uint32_t>(Index),586 llvm::endianness::little);587 break;588 };589 };590 591 for (const DebugNamesAbbrev::AttributeEncoding &AttrEnc :592 Abbrev->getAttributes()) {593 switch (AttrEnc.Index) {594 default: {595 llvm_unreachable("Unexpected index attribute!");596 break;597 }598 case dwarf::DW_IDX_compile_unit: {599 const unsigned CUIndex =600 SecondEntryRet ? SecondEntryRet->Index : EntryRet->Index;601 writeIndex(CUIndex, CUIndexEncodingSize);602 break;603 }604 case dwarf::DW_IDX_type_unit: {605 writeIndex(EntryRet->Index, TUIndexEncodingSize);606 break;607 }608 case dwarf::DW_IDX_die_offset: {609 assert(AttrEnc.Form == dwarf::DW_FORM_ref4);610 support::endian::write(*Entriestream,611 static_cast<uint32_t>(Entry.getDieOffset()),612 llvm::endianness::little);613 break;614 }615 case dwarf::DW_IDX_parent: {616 assert(617 (AttrEnc.Form == dwarf::DW_FORM_ref4 && Entry.getParentDieOffset()) ||618 AttrEnc.Form == dwarf::DW_FORM_flag_present);619 if (std::optional<uint64_t> ParentOffset = Entry.getParentDieOffset()) {620 Entry.setPatchOffset(EntriesBuffer->size());621 support::endian::write(*Entriestream, static_cast<uint32_t>(UINT32_MAX),622 llvm::endianness::little);623 }624 break;625 }626 }627 }628}629 630void DWARF5AcceleratorTable::writeEntries() {631 for (auto &Bucket : getBuckets()) {632 for (DWARF5AcceleratorTable::HashData *Hash : Bucket) {633 Hash->EntryOffset = EntriesBuffer->size();634 for (BOLTDWARF5AccelTableData *Value : Hash->Values) {635 writeEntry(*Value);636 }637 support::endian::write(*Entriestream, static_cast<uint8_t>(0),638 llvm::endianness::little);639 }640 }641 // Patching parent offsets.642 for (auto &Bucket : getBuckets()) {643 for (DWARF5AcceleratorTable::HashData *Hash : Bucket) {644 for (BOLTDWARF5AccelTableData *Entry : Hash->Values) {645 std::optional<uint64_t> ParentOffset = Entry->getParentDieOffset();646 if (!ParentOffset)647 continue;648 if (const auto Iter = EntryRelativeOffsets.find(*ParentOffset);649 Iter != EntryRelativeOffsets.end()) {650 const uint64_t PatchOffset = Entry->getPatchOffset();651 uint32_t *Ptr =652 reinterpret_cast<uint32_t *>(&EntriesBuffer->data()[PatchOffset]);653 *Ptr = Iter->second;654 } else {655 BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find "656 "entry with offset "657 << *ParentOffset << "\n";658 }659 }660 }661 }662}663 664void DWARF5AcceleratorTable::writeAugmentationString() {665 // String needs to be multiple of 4 bytes.666 *AugStringtream << "BOLT";667 AugmentationStringSize = AugStringBuffer->size();668}669 670/// Calculates size of .debug_names header without Length field.671static constexpr uint32_t getDebugNamesHeaderSize() {672 constexpr uint16_t VersionLength = sizeof(uint16_t);673 constexpr uint16_t PaddingLength = sizeof(uint16_t);674 constexpr uint32_t CompUnitCountLength = sizeof(uint32_t);675 constexpr uint32_t LocalTypeUnitCountLength = sizeof(uint32_t);676 constexpr uint32_t ForeignTypeUnitCountLength = sizeof(uint32_t);677 constexpr uint32_t BucketCountLength = sizeof(uint32_t);678 constexpr uint32_t NameCountLength = sizeof(uint32_t);679 constexpr uint32_t AbbrevTableSizeLength = sizeof(uint32_t);680 constexpr uint32_t AugmentationStringSizeLenght = sizeof(uint32_t);681 return VersionLength + PaddingLength + CompUnitCountLength +682 LocalTypeUnitCountLength + ForeignTypeUnitCountLength +683 BucketCountLength + NameCountLength + AbbrevTableSizeLength +684 AugmentationStringSizeLenght;685}686 687void DWARF5AcceleratorTable::emitHeader() const {688 constexpr uint32_t HeaderSize = getDebugNamesHeaderSize();689 // Header Length690 support::endian::write(*FullTableStream,691 static_cast<uint32_t>(HeaderSize + StrBuffer->size() +692 AugmentationStringSize),693 llvm::endianness::little);694 // Version695 support::endian::write(*FullTableStream, static_cast<uint16_t>(5),696 llvm::endianness::little);697 // Padding698 support::endian::write(*FullTableStream, static_cast<uint16_t>(0),699 llvm::endianness::little);700 // Compilation Unit Count701 support::endian::write(*FullTableStream, static_cast<uint32_t>(CUList.size()),702 llvm::endianness::little);703 // Local Type Unit Count704 support::endian::write(*FullTableStream,705 static_cast<uint32_t>(LocalTUList.size()),706 llvm::endianness::little);707 // Foreign Type Unit Count708 support::endian::write(*FullTableStream,709 static_cast<uint32_t>(ForeignTUList.size()),710 llvm::endianness::little);711 // Bucket Count712 support::endian::write(*FullTableStream, static_cast<uint32_t>(BucketCount),713 llvm::endianness::little);714 // Name Count715 support::endian::write(*FullTableStream,716 static_cast<uint32_t>(Entries.size()),717 llvm::endianness::little);718 // Abbrev Table Size719 support::endian::write(*FullTableStream,720 static_cast<uint32_t>(AbbrevTableSize),721 llvm::endianness::little);722 // Augmentation String Size723 support::endian::write(*FullTableStream,724 static_cast<uint32_t>(AugmentationStringSize),725 llvm::endianness::little);726 727 emitAugmentationString();728 FullTableStream->write(StrBuffer->data(), StrBuffer->size());729}730 731void DWARF5AcceleratorTable::emitCUList() const {732 for (const uint32_t CUID : CUList)733 support::endian::write(*StrStream, CUID, llvm::endianness::little);734}735void DWARF5AcceleratorTable::emitTUList() const {736 for (const uint32_t TUID : LocalTUList)737 support::endian::write(*StrStream, TUID, llvm::endianness::little);738 739 for (const uint64_t TUID : ForeignTUList)740 support::endian::write(*StrStream, TUID, llvm::endianness::little);741}742void DWARF5AcceleratorTable::emitBuckets() const {743 uint32_t Index = 1;744 for (const auto &Bucket : enumerate(getBuckets())) {745 const uint32_t TempIndex = Bucket.value().empty() ? 0 : Index;746 support::endian::write(*StrStream, TempIndex, llvm::endianness::little);747 Index += Bucket.value().size();748 }749}750void DWARF5AcceleratorTable::emitHashes() const {751 for (const auto &Bucket : getBuckets()) {752 for (const DWARF5AcceleratorTable::HashData *Hash : Bucket)753 support::endian::write(*StrStream, Hash->HashValue,754 llvm::endianness::little);755 }756}757void DWARF5AcceleratorTable::emitStringOffsets() const {758 for (const auto &Bucket : getBuckets()) {759 for (const DWARF5AcceleratorTable::HashData *Hash : Bucket)760 support::endian::write(*StrStream, static_cast<uint32_t>(Hash->StrOffset),761 llvm::endianness::little);762 }763}764void DWARF5AcceleratorTable::emitOffsets() const {765 for (const auto &Bucket : getBuckets()) {766 for (const DWARF5AcceleratorTable::HashData *Hash : Bucket)767 support::endian::write(*StrStream,768 static_cast<uint32_t>(Hash->EntryOffset),769 llvm::endianness::little);770 }771}772void DWARF5AcceleratorTable::emitAbbrevs() {773 const uint32_t AbbrevTableStart = StrBuffer->size();774 for (const auto *Abbrev : AbbreviationsVector) {775 encodeULEB128(Abbrev->getNumber(), *StrStream);776 encodeULEB128(Abbrev->getDieTag(), *StrStream);777 for (const auto &AttrEnc : Abbrev->getAttributes()) {778 encodeULEB128(AttrEnc.Index, *StrStream);779 encodeULEB128(AttrEnc.Form, *StrStream);780 }781 encodeULEB128(0, *StrStream);782 encodeULEB128(0, *StrStream);783 }784 encodeULEB128(0, *StrStream);785 AbbrevTableSize = StrBuffer->size() - AbbrevTableStart;786}787void DWARF5AcceleratorTable::emitData() {788 StrStream->write(EntriesBuffer->data(), EntriesBuffer->size());789}790void DWARF5AcceleratorTable::emitAugmentationString() const {791 FullTableStream->write(AugStringBuffer->data(), AugStringBuffer->size());792}793void DWARF5AcceleratorTable::emitAccelTable() {794 if (!NeedToCreate)795 return;796 finalize();797 populateAbbrevsMap();798 writeEntries();799 writeAugmentationString();800 emitCUList();801 emitTUList();802 emitBuckets();803 emitHashes();804 emitStringOffsets();805 emitOffsets();806 emitAbbrevs();807 emitData();808 emitHeader();809}810} // namespace bolt811} // namespace llvm812