2116 lines · cpp
1//===- bolt/Rewrite/DWARFRewriter.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/Rewrite/DWARFRewriter.h"10#include "bolt/Core/BinaryContext.h"11#include "bolt/Core/BinaryFunction.h"12#include "bolt/Core/DIEBuilder.h"13#include "bolt/Core/DebugData.h"14#include "bolt/Core/DynoStats.h"15#include "bolt/Core/ParallelUtilities.h"16#include "bolt/Rewrite/RewriteInstance.h"17#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/SmallVector.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/BinaryFormat/Dwarf.h"21#include "llvm/CodeGen/AsmPrinter.h"22#include "llvm/CodeGen/DIE.h"23#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"24#include "llvm/DebugInfo/DWARF/DWARFContext.h"25#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"26#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"27#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"28#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"29#include "llvm/DebugInfo/DWARF/DWARFUnit.h"30#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"31#include "llvm/MC/MCAsmBackend.h"32#include "llvm/MC/MCAssembler.h"33#include "llvm/MC/MCObjectWriter.h"34#include "llvm/MC/MCStreamer.h"35#include "llvm/MC/MCTargetOptionsCommandFlags.h"36#include "llvm/Object/ObjectFile.h"37#include "llvm/Support/Casting.h"38#include "llvm/Support/CommandLine.h"39#include "llvm/Support/Debug.h"40#include "llvm/Support/Endian.h"41#include "llvm/Support/Error.h"42#include "llvm/Support/FileSystem.h"43#include "llvm/Support/LEB128.h"44#include "llvm/Support/ThreadPool.h"45#include "llvm/Support/raw_ostream.h"46#include <algorithm>47#include <cstdint>48#include <functional>49#include <iterator>50#include <memory>51#include <optional>52#include <string>53#include <unordered_map>54#include <utility>55#include <vector>56 57#undef DEBUG_TYPE58#define DEBUG_TYPE "bolt"59 60static mc::RegisterMCTargetOptionsFlags MOF;61 62static void printDie(const DWARFDie &DIE) {63 DIDumpOptions DumpOpts;64 DumpOpts.ShowForm = true;65 DumpOpts.Verbose = true;66 DumpOpts.ChildRecurseDepth = 0;67 DumpOpts.ShowChildren = false;68 DIE.dump(dbgs(), 0, DumpOpts);69}70 71/// Lazily parse DWARF DIE and print it out.72[[maybe_unused]]73static void printDie(DWARFUnit &DU, uint64_t DIEOffset) {74 uint64_t OriginalOffsets = DIEOffset;75 uint64_t NextCUOffset = DU.getNextUnitOffset();76 DWARFDataExtractor DebugInfoData = DU.getDebugInfoExtractor();77 DWARFDebugInfoEntry DIEEntry;78 if (DIEEntry.extractFast(DU, &DIEOffset, DebugInfoData, NextCUOffset, 0)) {79 if (DIEEntry.getAbbreviationDeclarationPtr()) {80 DWARFDie DDie(&DU, &DIEEntry);81 printDie(DDie);82 } else {83 dbgs() << "Failed to extract abbreviation for"84 << Twine::utohexstr(OriginalOffsets) << "\n";85 }86 } else {87 dbgs() << "Failed to extract DIE for " << Twine::utohexstr(OriginalOffsets)88 << " \n";89 }90}91 92using namespace bolt;93 94/// Take a set of DWARF address ranges corresponding to the input binary and95/// translate them to a set of address ranges in the output binary.96static DebugAddressRangesVector97translateInputToOutputRanges(const BinaryFunction &BF,98 const DWARFAddressRangesVector &InputRanges) {99 DebugAddressRangesVector OutputRanges;100 101 // If the function hasn't changed return the same ranges.102 if (!BF.isEmitted()) {103 OutputRanges.resize(InputRanges.size());104 llvm::transform(InputRanges, OutputRanges.begin(),105 [](const DWARFAddressRange &Range) {106 return DebugAddressRange(Range.LowPC, Range.HighPC);107 });108 return OutputRanges;109 }110 111 for (const DWARFAddressRange &Range : InputRanges)112 llvm::append_range(OutputRanges, BF.translateInputToOutputRange(113 {Range.LowPC, Range.HighPC}));114 115 // Post-processing pass to sort and merge ranges.116 llvm::sort(OutputRanges);117 DebugAddressRangesVector MergedRanges;118 uint64_t PrevHighPC = 0;119 for (const DebugAddressRange &Range : OutputRanges) {120 if (Range.LowPC <= PrevHighPC) {121 MergedRanges.back().HighPC =122 std::max(MergedRanges.back().HighPC, Range.HighPC);123 } else {124 MergedRanges.emplace_back(Range.LowPC, Range.HighPC);125 }126 PrevHighPC = MergedRanges.back().HighPC;127 }128 129 return MergedRanges;130}131 132/// Similar to translateInputToOutputRanges() but operates on location lists.133static DebugLocationsVector134translateInputToOutputLocationList(const BinaryFunction &BF,135 const DebugLocationsVector &InputLL) {136 DebugLocationsVector OutputLL;137 138 // If the function hasn't changed - there's nothing to update.139 if (!BF.isEmitted())140 return InputLL;141 142 for (const DebugLocationEntry &Entry : InputLL) {143 DebugAddressRangesVector OutRanges =144 BF.translateInputToOutputRange({Entry.LowPC, Entry.HighPC});145 if (!OutRanges.empty() && !OutputLL.empty()) {146 if (OutRanges.front().LowPC == OutputLL.back().HighPC &&147 Entry.Expr == OutputLL.back().Expr) {148 OutputLL.back().HighPC =149 std::max(OutputLL.back().HighPC, OutRanges.front().HighPC);150 OutRanges.erase(OutRanges.begin());151 }152 }153 llvm::transform(OutRanges, std::back_inserter(OutputLL),154 [&Entry](const DebugAddressRange &R) {155 return DebugLocationEntry{R.LowPC, R.HighPC, Entry.Expr};156 });157 }158 159 // Sort and merge adjacent entries with identical locations.160 llvm::stable_sort(161 OutputLL, [](const DebugLocationEntry &A, const DebugLocationEntry &B) {162 return A.LowPC < B.LowPC;163 });164 DebugLocationsVector MergedLL;165 uint64_t PrevHighPC = 0;166 const SmallVectorImpl<uint8_t> *PrevExpr = nullptr;167 for (const DebugLocationEntry &Entry : OutputLL) {168 if (Entry.LowPC <= PrevHighPC && *PrevExpr == Entry.Expr) {169 MergedLL.back().HighPC = std::max(Entry.HighPC, MergedLL.back().HighPC);170 } else {171 const uint64_t Begin = std::max(Entry.LowPC, PrevHighPC);172 const uint64_t End = std::max(Begin, Entry.HighPC);173 MergedLL.emplace_back(DebugLocationEntry{Begin, End, Entry.Expr});174 }175 PrevHighPC = MergedLL.back().HighPC;176 PrevExpr = &MergedLL.back().Expr;177 }178 179 return MergedLL;180}181 182using namespace dwarf_linker;183using namespace dwarf_linker::classic;184 185namespace llvm {186namespace bolt {187/// Emits debug information into .debug_info or .debug_types section.188class DIEStreamer : public DwarfStreamer {189 DIEBuilder *DIEBldr;190 GDBIndex &GDBIndexSection;191 192private:193 /// Emit the compilation unit header for \p Unit in the debug_info194 /// section.195 ///196 /// A Dwarf 4 section header is encoded as:197 /// uint32_t Unit length (omitting this field)198 /// uint16_t Version199 /// uint32_t Abbreviation table offset200 /// uint8_t Address size201 /// Leading to a total of 11 bytes.202 ///203 /// A Dwarf 5 section header is encoded as:204 /// uint32_t Unit length (omitting this field)205 /// uint16_t Version206 /// uint8_t Unit type207 /// uint8_t Address size208 /// uint32_t Abbreviation table offset209 /// Leading to a total of 12 bytes.210 void emitCompileUnitHeader(DWARFUnit &Unit, DIE &UnitDIE,211 unsigned DwarfVersion) {212 213 AsmPrinter &Asm = getAsmPrinter();214 switchToDebugInfoSection(DwarfVersion);215 216 emitCommonHeader(Unit, UnitDIE, DwarfVersion);217 218 if (DwarfVersion >= 5 &&219 Unit.getUnitType() != dwarf::UnitType::DW_UT_compile) {220 std::optional<uint64_t> DWOId = Unit.getDWOId();221 assert(DWOId &&222 "DWOId does not exist and this is not a DW_UT_compile Unit");223 Asm.emitInt64(*DWOId);224 }225 }226 227 void emitCommonHeader(DWARFUnit &Unit, DIE &UnitDIE, uint16_t Version) {228 dwarf::UnitType UT = dwarf::UnitType(Unit.getUnitType());229 llvm::AsmPrinter &Asm = getAsmPrinter();230 231 // Emit size of content not including length itself232 Asm.emitInt32(Unit.getHeaderSize() + UnitDIE.getSize() - 4);233 Asm.emitInt16(Version);234 235 // DWARF v5 reorders the address size and adds a unit type.236 if (Version >= 5) {237 Asm.emitInt8(UT);238 Asm.emitInt8(Asm.MAI->getCodePointerSize());239 }240 241 Asm.emitInt32(0);242 if (Version <= 4) {243 Asm.emitInt8(Asm.MAI->getCodePointerSize());244 }245 }246 247 void emitTypeUnitHeader(DWARFUnit &Unit, DIE &UnitDIE,248 unsigned DwarfVersion) {249 AsmPrinter &Asm = getAsmPrinter();250 const uint64_t TypeSignature = cast<DWARFTypeUnit>(Unit).getTypeHash();251 DIE *TypeDIE = DIEBldr->getTypeDIE(Unit);252 const DIEBuilder::DWARFUnitInfo &UI = DIEBldr->getUnitInfoByDwarfUnit(Unit);253 GDBIndexSection.addGDBTypeUnitEntry(254 {UI.UnitOffset, TypeSignature, TypeDIE->getOffset()});255 if (Unit.getVersion() < 5) {256 // Switch the section to .debug_types section.257 std::unique_ptr<MCStreamer> &MS = Asm.OutStreamer;258 llvm::MCContext &MC = Asm.OutContext;259 const llvm::MCObjectFileInfo *MOFI = MC.getObjectFileInfo();260 261 MS->switchSection(MOFI->getDwarfTypesSection(0));262 MC.setDwarfVersion(DwarfVersion);263 } else264 switchToDebugInfoSection(DwarfVersion);265 266 emitCommonHeader(Unit, UnitDIE, DwarfVersion);267 Asm.OutStreamer->emitIntValue(TypeSignature, sizeof(TypeSignature));268 Asm.emitDwarfLengthOrOffset(TypeDIE ? TypeDIE->getOffset() : 0);269 }270 271 void emitUnitHeader(DWARFUnit &Unit, DIE &UnitDIE) {272 if (Unit.isTypeUnit())273 emitTypeUnitHeader(Unit, UnitDIE, Unit.getVersion());274 else275 emitCompileUnitHeader(Unit, UnitDIE, Unit.getVersion());276 }277 278 void emitDIE(DIE &Die) override {279 AsmPrinter &Asm = getAsmPrinter();280 Asm.emitDwarfDIE(Die);281 }282 283public:284 DIEStreamer(DIEBuilder *DIEBldr, GDBIndex &GDBIndexSection,285 DWARFLinkerBase::OutputFileType OutFileType,286 raw_pwrite_stream &OutFile,287 DWARFLinkerBase::MessageHandlerTy Warning)288 : DwarfStreamer(OutFileType, OutFile, Warning), DIEBldr(DIEBldr),289 GDBIndexSection(GDBIndexSection) {};290 291 using DwarfStreamer::emitCompileUnitHeader;292 293 void emitUnit(DWARFUnit &Unit, DIE &UnitDIE) {294 emitUnitHeader(Unit, UnitDIE);295 emitDIE(UnitDIE);296 }297};298 299/// Finds attributes FormValue and Offset.300///301/// \param DIE die to look up in.302/// \param Attrs finds the first attribute that matches and extracts it.303/// \return an optional AttrInfo with DWARFFormValue and Offset.304std::optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,305 std::vector<dwarf::Attribute> Attrs) {306 for (dwarf::Attribute &Attr : Attrs)307 if (std::optional<AttrInfo> Info = findAttributeInfo(DIE, Attr))308 return Info;309 return std::nullopt;310}311 312} // namespace bolt313} // namespace llvm314 315using namespace llvm;316using namespace llvm::support::endian;317using namespace object;318using namespace bolt;319 320namespace opts {321 322extern cl::OptionCategory BoltCategory;323extern cl::opt<unsigned> Verbosity;324extern cl::opt<std::string> OutputFilename;325 326static cl::opt<bool> KeepARanges(327 "keep-aranges",328 cl::desc(329 "keep or generate .debug_aranges section if .gdb_index is written"),330 cl::Hidden, cl::cat(BoltCategory));331 332static cl::opt<unsigned>333 DebugThreadCount("debug-thread-count",334 cl::desc("specifies thread count for the multithreading "335 "for updating DWO debug info"),336 cl::init(1), cl::cat(BoltCategory));337 338static cl::opt<std::string> DwarfOutputPath(339 "dwarf-output-path",340 cl::desc("Path to where .dwo files will be written out to."), cl::init(""),341 cl::cat(BoltCategory));342 343static cl::opt<bool> CreateDebugNames(344 "create-debug-names-section",345 cl::desc("Creates .debug_names section, if the input binary doesn't have "346 "it already, for DWARF5 CU/TUs."),347 cl::init(false), cl::cat(BoltCategory));348 349static cl::opt<bool>350 DebugSkeletonCu("debug-skeleton-cu",351 cl::desc("prints out offsets for abbrev and debug_info of "352 "Skeleton CUs that get patched."),353 cl::ZeroOrMore, cl::Hidden, cl::init(false),354 cl::cat(BoltCategory));355 356static cl::opt<unsigned> BatchSize(357 "cu-processing-batch-size",358 cl::desc(359 "Specifies the size of batches for processing CUs. Higher number has "360 "better performance, but more memory usage. Default value is 1."),361 cl::Hidden, cl::init(1), cl::cat(BoltCategory));362 363static cl::opt<bool> AlwaysConvertToRanges(364 "always-convert-to-ranges",365 cl::desc("This option is for testing purposes only. It forces BOLT to "366 "convert low_pc/high_pc to ranges always."),367 cl::ReallyHidden, cl::init(false), cl::cat(BoltCategory));368 369extern cl::opt<std::string> CompDirOverride;370} // namespace opts371 372/// If DW_AT_low_pc exists sets LowPC and returns true.373static bool getLowPC(const DIE &Die, const DWARFUnit &DU, uint64_t &LowPC,374 uint64_t &SectionIndex) {375 DIEValue DvalLowPc = Die.findAttribute(dwarf::DW_AT_low_pc);376 if (!DvalLowPc)377 return false;378 379 dwarf::Form Form = DvalLowPc.getForm();380 bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset;381 uint64_t LowPcValue = DvalLowPc.getDIEInteger().getValue();382 if (Form == dwarf::DW_FORM_GNU_addr_index || Form == dwarf::DW_FORM_addrx ||383 AddrOffset) {384 385 uint32_t Index = AddrOffset ? (LowPcValue >> 32) : LowPcValue;386 std::optional<object::SectionedAddress> SA =387 DU.getAddrOffsetSectionItem(Index);388 if (!SA)389 return false;390 if (AddrOffset)391 SA->Address += (LowPcValue & 0xffffffff);392 393 LowPC = SA->Address;394 SectionIndex = SA->SectionIndex;395 } else {396 LowPC = LowPcValue;397 SectionIndex = 0;398 }399 return true;400}401 402/// If DW_AT_high_pc exists sets HighPC and returns true.403static bool getHighPC(const DIE &Die, const uint64_t LowPC, uint64_t &HighPC) {404 DIEValue DvalHighPc = Die.findAttribute(dwarf::DW_AT_high_pc);405 if (!DvalHighPc)406 return false;407 if (DvalHighPc.getForm() == dwarf::DW_FORM_addr)408 HighPC = DvalHighPc.getDIEInteger().getValue();409 else410 HighPC = LowPC + DvalHighPc.getDIEInteger().getValue();411 return true;412}413 414/// If DW_AT_low_pc and DW_AT_high_pc exist sets LowPC and HighPC and returns415/// true.416static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU,417 uint64_t &LowPC, uint64_t &HighPC,418 uint64_t &SectionIndex) {419 uint64_t TempLowPC = LowPC;420 uint64_t TempHighPC = HighPC;421 uint64_t TempSectionIndex = SectionIndex;422 if (getLowPC(Die, DU, TempLowPC, TempSectionIndex) &&423 getHighPC(Die, TempLowPC, TempHighPC)) {424 LowPC = TempLowPC;425 HighPC = TempHighPC;426 SectionIndex = TempSectionIndex;427 return true;428 }429 return false;430}431 432static Expected<llvm::DWARFAddressRangesVector>433getDIEAddressRanges(const DIE &Die, DWARFUnit &DU) {434 uint64_t LowPC, HighPC, Index;435 if (getLowAndHighPC(Die, DU, LowPC, HighPC, Index))436 return DWARFAddressRangesVector{{LowPC, HighPC, Index}};437 if (DIEValue Dval = Die.findAttribute(dwarf::DW_AT_ranges)) {438 if (Dval.getForm() == dwarf::DW_FORM_rnglistx)439 return DU.findRnglistFromIndex(Dval.getDIEInteger().getValue());440 441 return DU.findRnglistFromOffset(Dval.getDIEInteger().getValue());442 }443 444 return DWARFAddressRangesVector();445}446 447static std::optional<uint64_t> getAsAddress(const DWARFUnit &DU,448 const DIEValue &AttrVal) {449 DWARFFormValue::ValueType Value(AttrVal.getDIEInteger().getValue());450 if (std::optional<object::SectionedAddress> SA =451 DWARFFormValue::getAsSectionedAddress(Value, AttrVal.getForm(), &DU))452 return SA->Address;453 return std::nullopt;454}455 456static std::unique_ptr<DIEStreamer>457createDIEStreamer(const Triple &TheTriple, raw_pwrite_stream &OutFile,458 StringRef Swift5ReflectionSegmentName, DIEBuilder &DIEBldr,459 GDBIndex &GDBIndexSection) {460 461 std::unique_ptr<DIEStreamer> Streamer = std::make_unique<DIEStreamer>(462 &DIEBldr, GDBIndexSection, DWARFLinkerBase::OutputFileType::Object,463 OutFile,464 [&](const Twine &Warning, StringRef Context, const DWARFDie *) {});465 Error Err = Streamer->init(TheTriple, Swift5ReflectionSegmentName);466 if (Err)467 errs()468 << "BOLT-WARNING: [internal-dwarf-error]: Could not init DIEStreamer!"469 << toString(std::move(Err)) << "\n";470 return Streamer;471}472 473static void emitUnit(DIEBuilder &DIEBldr, DIEStreamer &Streamer,474 DWARFUnit &Unit) {475 DIE *UnitDIE = DIEBldr.getUnitDIEbyUnit(Unit);476 Streamer.emitUnit(Unit, *UnitDIE);477}478 479static void emitDWOBuilder(const std::string &DWOName,480 DIEBuilder &DWODIEBuilder, DWARFRewriter &Rewriter,481 DWARFUnit &SplitCU, DWARFUnit &CU,482 DebugLocWriter &LocWriter,483 DebugStrOffsetsWriter &StrOffstsWriter,484 DebugStrWriter &StrWriter, GDBIndex &GDBIndexSection,485 DebugRangesSectionWriter &TempRangesSectionWriter) {486 // Populate debug_info and debug_abbrev for current dwo into StringRef.487 DWODIEBuilder.generateAbbrevs();488 DWODIEBuilder.finish();489 490 SmallVector<char, 20> OutBuffer;491 std::shared_ptr<raw_svector_ostream> ObjOS =492 std::make_shared<raw_svector_ostream>(OutBuffer);493 const object::ObjectFile *File = SplitCU.getContext().getDWARFObj().getFile();494 auto TheTriple = std::make_unique<Triple>(File->makeTriple());495 std::unique_ptr<DIEStreamer> Streamer =496 createDIEStreamer(*TheTriple, *ObjOS, "DwoStreamerInitAug2",497 DWODIEBuilder, GDBIndexSection);498 if (SplitCU.getContext().getMaxDWOVersion() >= 5) {499 for (std::unique_ptr<llvm::DWARFUnit> &CU :500 SplitCU.getContext().dwo_info_section_units()) {501 if (!CU->isTypeUnit())502 continue;503 emitUnit(DWODIEBuilder, *Streamer, *CU);504 }505 emitUnit(DWODIEBuilder, *Streamer, SplitCU);506 } else {507 emitUnit(DWODIEBuilder, *Streamer, SplitCU);508 509 // emit debug_types sections for dwarf4510 for (DWARFUnit *CU : DWODIEBuilder.getDWARF4TUVector())511 emitUnit(DWODIEBuilder, *Streamer, *CU);512 }513 514 Streamer->emitAbbrevs(DWODIEBuilder.getAbbrevs(),515 SplitCU.getContext().getMaxVersion());516 Streamer->finish();517 518 std::unique_ptr<MemoryBuffer> ObjectMemBuffer =519 MemoryBuffer::getMemBuffer(ObjOS->str(), "in-memory object file", false);520 std::unique_ptr<object::ObjectFile> Obj = cantFail(521 object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()),522 "error creating in-memory object");523 524 DWARFRewriter::OverriddenSectionsMap OverriddenSections;525 for (const SectionRef &Secs : Obj->sections()) {526 StringRef Contents = cantFail(Secs.getContents());527 StringRef Name = cantFail(Secs.getName());528 DWARFSectionKind Kind =529 StringSwitch<DWARFSectionKind>(Name)530 .Case(".debug_abbrev", DWARFSectionKind::DW_SECT_ABBREV)531 .Case(".debug_info", DWARFSectionKind::DW_SECT_INFO)532 .Case(".debug_types", DWARFSectionKind::DW_SECT_EXT_TYPES)533 .Default(DWARFSectionKind::DW_SECT_EXT_unknown);534 if (Kind == DWARFSectionKind::DW_SECT_EXT_unknown)535 continue;536 OverriddenSections[Kind] = Contents;537 }538 Rewriter.writeDWOFiles(CU, OverriddenSections, DWOName, LocWriter,539 StrOffstsWriter, StrWriter, TempRangesSectionWriter);540}541 542using DWARFUnitVec = std::vector<DWARFUnit *>;543using CUPartitionVector = std::vector<DWARFUnitVec>;544/// Partitions CUs in to buckets. Bucket size is controlled by545/// cu-processing-batch-size. All the CUs that have cross CU reference reference546/// as a source are put in to the same initial bucket.547static CUPartitionVector partitionCUs(DWARFContext &DwCtx) {548 CUPartitionVector Vec(2);549 unsigned Counter = 0;550 const DWARFDebugAbbrev *Abbr = DwCtx.getDebugAbbrev();551 for (std::unique_ptr<DWARFUnit> &CU : DwCtx.compile_units()) {552 Expected<const DWARFAbbreviationDeclarationSet *> AbbrDeclSet =553 Abbr->getAbbreviationDeclarationSet(CU->getAbbreviationsOffset());554 if (!AbbrDeclSet) {555 consumeError(AbbrDeclSet.takeError());556 return Vec;557 }558 bool CrossCURefFound = false;559 for (const DWARFAbbreviationDeclaration &Decl : *AbbrDeclSet.get()) {560 for (const DWARFAbbreviationDeclaration::AttributeSpec &Attr :561 Decl.attributes()) {562 if (Attr.Form == dwarf::DW_FORM_ref_addr) {563 CrossCURefFound = true;564 break;565 }566 }567 if (CrossCURefFound)568 break;569 }570 if (CrossCURefFound) {571 Vec[0].push_back(CU.get());572 } else {573 ++Counter;574 Vec.back().push_back(CU.get());575 }576 if (Counter % opts::BatchSize == 0 && !Vec.back().empty())577 Vec.push_back({});578 }579 return Vec;580}581 582void DWARFRewriter::updateDebugInfo() {583 ErrorOr<BinarySection &> DebugInfo = BC.getUniqueSectionByName(".debug_info");584 if (!DebugInfo)585 return;586 587 ARangesSectionWriter = std::make_unique<DebugARangesSectionWriter>();588 StrWriter = std::make_unique<DebugStrWriter>(*BC.DwCtx, false);589 StrOffstsWriter = std::make_unique<DebugStrOffsetsWriter>(BC);590 591 /// Stores and serializes information that will be put into the592 /// .debug_addr DWARF section.593 std::unique_ptr<DebugAddrWriter> FinalAddrWriter;594 595 if (BC.isDWARF5Used()) {596 FinalAddrWriter = std::make_unique<DebugAddrWriterDwarf5>(&BC);597 RangeListsSectionWriter = std::make_unique<DebugRangeListsSectionWriter>();598 } else {599 FinalAddrWriter = std::make_unique<DebugAddrWriter>(&BC);600 }601 602 if (BC.isDWARFLegacyUsed()) {603 LegacyRangesSectionWriter = std::make_unique<DebugRangesSectionWriter>();604 LegacyRangesSectionWriter->initSection();605 }606 607 uint32_t CUIndex = 0;608 std::mutex AccessMutex;609 // Needs to be invoked in the same order as CUs are processed.610 llvm::DenseMap<uint64_t, uint64_t> LocListWritersIndexByCU;611 auto createRangeLocListAddressWriters = [&](DWARFUnit &CU) {612 std::lock_guard<std::mutex> Lock(AccessMutex);613 const uint16_t DwarfVersion = CU.getVersion();614 if (DwarfVersion >= 5) {615 auto AddrW = std::make_unique<DebugAddrWriterDwarf5>(616 &BC, CU.getAddressByteSize(), CU.getAddrOffsetSectionBase());617 RangeListsSectionWriter->setAddressWriter(AddrW.get());618 LocListWritersByCU[CUIndex] =619 std::make_unique<DebugLoclistWriter>(CU, DwarfVersion, false, *AddrW);620 621 if (std::optional<uint64_t> DWOId = CU.getDWOId()) {622 assert(RangeListsWritersByCU.count(*DWOId) == 0 &&623 "RangeLists writer for DWO unit already exists.");624 auto DWORangeListsSectionWriter =625 std::make_unique<DebugRangeListsSectionWriter>();626 DWORangeListsSectionWriter->initSection(CU);627 DWORangeListsSectionWriter->setAddressWriter(AddrW.get());628 RangeListsWritersByCU[*DWOId] = std::move(DWORangeListsSectionWriter);629 }630 AddressWritersByCU[CU.getOffset()] = std::move(AddrW);631 } else {632 auto AddrW =633 std::make_unique<DebugAddrWriter>(&BC, CU.getAddressByteSize());634 AddressWritersByCU[CU.getOffset()] = std::move(AddrW);635 LocListWritersByCU[CUIndex] = std::make_unique<DebugLocWriter>();636 if (std::optional<uint64_t> DWOId = CU.getDWOId()) {637 assert(LegacyRangesWritersByCU.count(*DWOId) == 0 &&638 "LegacyRangeLists writer for DWO unit already exists.");639 auto LegacyRangesSectionWriterByCU =640 std::make_unique<DebugRangesSectionWriter>();641 LegacyRangesSectionWriterByCU->initSection(CU);642 LegacyRangesWritersByCU[*DWOId] =643 std::move(LegacyRangesSectionWriterByCU);644 }645 }646 LocListWritersIndexByCU[CU.getOffset()] = CUIndex++;647 };648 649 DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC,650 *StrWriter);651 GDBIndex GDBIndexSection(BC);652 auto processSplitCU = [&](DWARFUnit &Unit, DWARFUnit &SplitCU,653 DebugRangesSectionWriter &TempRangesSectionWriter,654 DebugAddrWriter &AddressWriter,655 const std::string &DWOName,656 const std::optional<std::string> &DwarfOutputPath,657 DIEBuilder &DWODIEBuilder) {658 DWODIEBuilder.buildDWOUnit(SplitCU);659 DebugStrOffsetsWriter DWOStrOffstsWriter(BC);660 DebugStrWriter DWOStrWriter((SplitCU).getContext(), true);661 DWODIEBuilder.updateDWONameCompDirForTypes(662 DWOStrOffstsWriter, DWOStrWriter, SplitCU, DwarfOutputPath, DWOName);663 DebugLoclistWriter DebugLocDWoWriter(Unit, Unit.getVersion(), true,664 AddressWriter);665 666 updateUnitDebugInfo(SplitCU, DWODIEBuilder, DebugLocDWoWriter,667 TempRangesSectionWriter, AddressWriter);668 DebugLocDWoWriter.finalize(DWODIEBuilder,669 *DWODIEBuilder.getUnitDIEbyUnit(SplitCU));670 if (Unit.getVersion() >= 5)671 TempRangesSectionWriter.finalizeSection();672 673 emitDWOBuilder(DWOName, DWODIEBuilder, *this, SplitCU, Unit,674 DebugLocDWoWriter, DWOStrOffstsWriter, DWOStrWriter,675 GDBIndexSection, TempRangesSectionWriter);676 };677 auto processMainBinaryCU = [&](DWARFUnit &Unit, DIEBuilder &DIEBlder) {678 std::optional<DWARFUnit *> SplitCU;679 std::optional<uint64_t> RangesBase;680 std::optional<uint64_t> DWOId = Unit.getDWOId();681 if (DWOId)682 SplitCU = BC.getDWOCU(*DWOId);683 DebugLocWriter &DebugLocWriter =684 *LocListWritersByCU[LocListWritersIndexByCU[Unit.getOffset()]].get();685 DebugRangesSectionWriter &RangesSectionWriter =686 Unit.getVersion() >= 5 ? *RangeListsSectionWriter687 : *LegacyRangesSectionWriter;688 DebugAddrWriter &AddressWriter =689 *AddressWritersByCU[Unit.getOffset()].get();690 if (Unit.getVersion() >= 5)691 RangeListsSectionWriter->setAddressWriter(&AddressWriter);692 if (Unit.getVersion() >= 5) {693 RangesBase = RangesSectionWriter.getSectionOffset() +694 getDWARF5RngListLocListHeaderSize();695 RangesSectionWriter.initSection(Unit);696 if (!SplitCU)697 StrOffstsWriter->finalizeSection(Unit, DIEBlder);698 } else if (SplitCU) {699 RangesBase = LegacyRangesSectionWriter->getSectionOffset();700 }701 702 updateUnitDebugInfo(Unit, DIEBlder, DebugLocWriter, RangesSectionWriter,703 AddressWriter, RangesBase);704 DebugLocWriter.finalize(DIEBlder, *DIEBlder.getUnitDIEbyUnit(Unit));705 if (Unit.getVersion() >= 5)706 RangesSectionWriter.finalizeSection();707 };708 709 DIEBuilder DIEBlder(BC, BC.DwCtx.get(), DebugNamesTable);710 DIEBlder.buildTypeUnits(StrOffstsWriter.get());711 SmallVector<char, 20> OutBuffer;712 std::unique_ptr<raw_svector_ostream> ObjOS =713 std::make_unique<raw_svector_ostream>(OutBuffer);714 const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile();715 auto TheTriple = std::make_unique<Triple>(File->makeTriple());716 std::unique_ptr<DIEStreamer> Streamer = createDIEStreamer(717 *TheTriple, *ObjOS, "TypeStreamer", DIEBlder, GDBIndexSection);718 CUOffsetMap OffsetMap =719 finalizeTypeSections(DIEBlder, *Streamer, GDBIndexSection);720 721 CUPartitionVector PartVec = partitionCUs(*BC.DwCtx);722 const unsigned int ThreadCount =723 std::min(opts::DebugThreadCount, opts::ThreadCount);724 for (std::vector<DWARFUnit *> &Vec : PartVec) {725 DIEBlder.buildCompileUnits(Vec);726 llvm::SmallVector<std::unique_ptr<DIEBuilder>, 72> DWODIEBuildersByCU;727 ThreadPoolInterface &ThreadPool =728 ParallelUtilities::getThreadPool(ThreadCount);729 for (DWARFUnit *CU : DIEBlder.getProcessedCUs()) {730 createRangeLocListAddressWriters(*CU);731 std::optional<DWARFUnit *> SplitCU;732 std::optional<uint64_t> DWOId = CU->getDWOId();733 if (DWOId)734 SplitCU = BC.getDWOCU(*DWOId);735 if (!SplitCU)736 continue;737 DebugAddrWriter &AddressWriter =738 *AddressWritersByCU[CU->getOffset()].get();739 DebugRangesSectionWriter &TempRangesSectionWriter =740 CU->getVersion() >= 5 ? *RangeListsWritersByCU[*DWOId].get()741 : *LegacyRangesWritersByCU[*DWOId].get();742 std::optional<std::string> DwarfOutputPath =743 opts::DwarfOutputPath.empty()744 ? std::nullopt745 : std::optional<std::string>(opts::DwarfOutputPath.c_str());746 std::string DWOName = DIEBlder.updateDWONameCompDir(747 *StrOffstsWriter, *StrWriter, *CU, DwarfOutputPath, std::nullopt);748 auto DWODIEBuilderPtr = std::make_unique<DIEBuilder>(749 BC, &(**SplitCU).getContext(), DebugNamesTable, CU);750 DIEBuilder &DWODIEBuilder =751 *DWODIEBuildersByCU.emplace_back(std::move(DWODIEBuilderPtr));752 if (CU->getVersion() >= 5)753 StrOffstsWriter->finalizeSection(*CU, DIEBlder);754 // Important to capture CU and SplitCU by value here, otherwise when the755 // thread is executed at some point after the current iteration of the756 // loop, dereferencing CU/SplitCU in the call to processSplitCU means it757 // will dereference a different variable than the one intended, causing a758 // seg fault.759 ThreadPool.async([&, DwarfOutputPath, DWOName, CU, SplitCU] {760 processSplitCU(*CU, **SplitCU, TempRangesSectionWriter, AddressWriter,761 DWOName, DwarfOutputPath, DWODIEBuilder);762 });763 }764 ThreadPool.wait();765 for (std::unique_ptr<DIEBuilder> &DWODIEBuilderPtr : DWODIEBuildersByCU)766 DWODIEBuilderPtr->updateDebugNamesTable();767 for (DWARFUnit *CU : DIEBlder.getProcessedCUs())768 processMainBinaryCU(*CU, DIEBlder);769 finalizeCompileUnits(DIEBlder, *Streamer, OffsetMap,770 DIEBlder.getProcessedCUs(), *FinalAddrWriter);771 }772 773 DebugNamesTable.emitAccelTable();774 775 finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS, OffsetMap,776 *FinalAddrWriter);777 GDBIndexSection.updateGdbIndexSection(OffsetMap, CUIndex,778 *ARangesSectionWriter);779}780 781void DWARFRewriter::updateUnitDebugInfo(782 DWARFUnit &Unit, DIEBuilder &DIEBldr, DebugLocWriter &DebugLocWriter,783 DebugRangesSectionWriter &RangesSectionWriter,784 DebugAddrWriter &AddressWriter, std::optional<uint64_t> RangesBase) {785 // Cache debug ranges so that the offset for identical ranges could be reused.786 std::map<DebugAddressRangesVector, uint64_t> CachedRanges;787 788 uint64_t DIEOffset = Unit.getOffset() + Unit.getHeaderSize();789 uint64_t NextCUOffset = Unit.getNextUnitOffset();790 const std::vector<std::unique_ptr<DIEBuilder::DIEInfo>> &DIs =791 DIEBldr.getDIEsByUnit(Unit);792 793 // Either updates or normalizes DW_AT_range to DW_AT_low_pc and DW_AT_high_pc.794 auto updateLowPCHighPC = [&](DIE *Die, const DIEValue &LowPCVal,795 const DIEValue &HighPCVal, uint64_t LowPC,796 const uint64_t HighPC) {797 dwarf::Attribute AttrLowPC = dwarf::DW_AT_low_pc;798 dwarf::Form FormLowPC = dwarf::DW_FORM_addr;799 dwarf::Attribute AttrHighPC = dwarf::DW_AT_high_pc;800 dwarf::Form FormHighPC = dwarf::DW_FORM_data4;801 const uint32_t Size = HighPC - LowPC;802 // Whatever was generated is not low_pc/high_pc, so will reset to803 // default for size 1.804 if (!LowPCVal || !HighPCVal) {805 if (Unit.getVersion() >= 5)806 FormLowPC = dwarf::DW_FORM_addrx;807 else if (Unit.isDWOUnit())808 FormLowPC = dwarf::DW_FORM_GNU_addr_index;809 } else {810 AttrLowPC = LowPCVal.getAttribute();811 FormLowPC = LowPCVal.getForm();812 AttrHighPC = HighPCVal.getAttribute();813 FormHighPC = HighPCVal.getForm();814 }815 816 if (FormLowPC == dwarf::DW_FORM_addrx ||817 FormLowPC == dwarf::DW_FORM_GNU_addr_index)818 LowPC = AddressWriter.getIndexFromAddress(LowPC, Unit);819 820 if (LowPCVal)821 DIEBldr.replaceValue(Die, AttrLowPC, FormLowPC, DIEInteger(LowPC));822 else823 DIEBldr.addValue(Die, AttrLowPC, FormLowPC, DIEInteger(LowPC));824 if (HighPCVal) {825 DIEBldr.replaceValue(Die, AttrHighPC, FormHighPC, DIEInteger(Size));826 } else {827 DIEBldr.deleteValue(Die, dwarf::DW_AT_ranges);828 DIEBldr.addValue(Die, AttrHighPC, FormHighPC, DIEInteger(Size));829 }830 };831 832 for (const std::unique_ptr<DIEBuilder::DIEInfo> &DI : DIs) {833 DIE *Die = DI->Die;834 switch (Die->getTag()) {835 case dwarf::DW_TAG_compile_unit:836 case dwarf::DW_TAG_skeleton_unit: {837 // For dwarf5 section 3.1.3838 // The following attributes are not part of a split full compilation unit839 // entry but instead are inherited (if present) from the corresponding840 // skeleton compilation unit: DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges,841 // DW_AT_stmt_list, DW_AT_comp_dir, DW_AT_str_offsets_base,842 // DW_AT_addr_base and DW_AT_rnglists_base.843 if (Unit.getVersion() == 5 && Unit.isDWOUnit())844 continue;845 auto ModuleRangesOrError = getDIEAddressRanges(*Die, Unit);846 if (!ModuleRangesOrError) {847 consumeError(ModuleRangesOrError.takeError());848 break;849 }850 DWARFAddressRangesVector &ModuleRanges = *ModuleRangesOrError;851 DebugAddressRangesVector OutputRanges =852 BC.translateModuleAddressRanges(ModuleRanges);853 DIEValue LowPCAttrInfo = Die->findAttribute(dwarf::DW_AT_low_pc);854 // For a case where LLD GCs only function used in the CU.855 // If CU doesn't have DW_AT_low_pc we are not going to convert,856 // so don't need to do anything.857 if (OutputRanges.empty() && !Unit.isDWOUnit() && LowPCAttrInfo)858 OutputRanges.push_back({0, 0});859 const uint64_t RangesSectionOffset =860 RangesSectionWriter.addRanges(OutputRanges);861 // Don't emit the zero low_pc arange.862 if (!Unit.isDWOUnit() && !OutputRanges.empty() &&863 OutputRanges.back().LowPC)864 ARangesSectionWriter->addCURanges(Unit.getOffset(),865 std::move(OutputRanges));866 updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset,867 RangesBase);868 DIEValue StmtListAttrVal = Die->findAttribute(dwarf::DW_AT_stmt_list);869 if (LineTablePatchMap.count(&Unit))870 DIEBldr.replaceValue(Die, dwarf::DW_AT_stmt_list,871 StmtListAttrVal.getForm(),872 DIEInteger(LineTablePatchMap[&Unit]));873 break;874 }875 876 case dwarf::DW_TAG_subprogram: {877 // Get function address either from ranges or [LowPC, HighPC) pair.878 uint64_t Address = UINT64_MAX;879 uint64_t SectionIndex, HighPC;880 DebugAddressRangesVector FunctionRanges;881 if (!getLowAndHighPC(*Die, Unit, Address, HighPC, SectionIndex)) {882 Expected<DWARFAddressRangesVector> RangesOrError =883 getDIEAddressRanges(*Die, Unit);884 if (!RangesOrError) {885 consumeError(RangesOrError.takeError());886 break;887 }888 DWARFAddressRangesVector Ranges = *RangesOrError;889 // Not a function definition.890 if (Ranges.empty())891 break;892 893 for (const DWARFAddressRange &Range : Ranges) {894 if (const BinaryFunction *Function =895 BC.getBinaryFunctionAtAddress(Range.LowPC))896 FunctionRanges.append(Function->getOutputAddressRanges());897 }898 } else {899 if (const BinaryFunction *Function =900 BC.getBinaryFunctionAtAddress(Address))901 FunctionRanges = Function->getOutputAddressRanges();902 }903 904 // Clear cached ranges as the new function will have its own set.905 CachedRanges.clear();906 DIEValue LowPCVal = Die->findAttribute(dwarf::DW_AT_low_pc);907 DIEValue HighPCVal = Die->findAttribute(dwarf::DW_AT_high_pc);908 if (FunctionRanges.empty()) {909 if (LowPCVal && HighPCVal)910 FunctionRanges.push_back({0, HighPCVal.getDIEInteger().getValue()});911 else912 FunctionRanges.push_back({0, 1});913 }914 915 if (FunctionRanges.size() == 1 && !opts::AlwaysConvertToRanges) {916 updateLowPCHighPC(Die, LowPCVal, HighPCVal, FunctionRanges.back().LowPC,917 FunctionRanges.back().HighPC);918 break;919 }920 921 updateDWARFObjectAddressRanges(922 Unit, DIEBldr, *Die, RangesSectionWriter.addRanges(FunctionRanges));923 924 break;925 }926 case dwarf::DW_TAG_lexical_block:927 case dwarf::DW_TAG_inlined_subroutine:928 case dwarf::DW_TAG_try_block:929 case dwarf::DW_TAG_catch_block: {930 uint64_t RangesSectionOffset = 0;931 Expected<DWARFAddressRangesVector> RangesOrError =932 getDIEAddressRanges(*Die, Unit);933 const BinaryFunction *Function =934 RangesOrError && !RangesOrError->empty()935 ? BC.getBinaryFunctionContainingAddress(936 RangesOrError->front().LowPC)937 : nullptr;938 DebugAddressRangesVector OutputRanges;939 if (Function) {940 OutputRanges = translateInputToOutputRanges(*Function, *RangesOrError);941 LLVM_DEBUG(if (OutputRanges.empty() != RangesOrError->empty()) {942 dbgs() << "BOLT-DEBUG: problem with DIE at 0x"943 << Twine::utohexstr(Die->getOffset()) << " in CU at 0x"944 << Twine::utohexstr(Unit.getOffset()) << '\n';945 });946 if (opts::AlwaysConvertToRanges || OutputRanges.size() > 1) {947 RangesSectionOffset = RangesSectionWriter.addRanges(948 std::move(OutputRanges), CachedRanges);949 OutputRanges.clear();950 } else if (OutputRanges.empty()) {951 OutputRanges.push_back({0, RangesOrError.get().front().HighPC});952 }953 } else if (!RangesOrError) {954 consumeError(RangesOrError.takeError());955 } else {956 OutputRanges.push_back({0, !RangesOrError->empty()957 ? RangesOrError.get().front().HighPC958 : 0});959 }960 DIEValue LowPCVal = Die->findAttribute(dwarf::DW_AT_low_pc);961 DIEValue HighPCVal = Die->findAttribute(dwarf::DW_AT_high_pc);962 if (OutputRanges.size() == 1) {963 updateLowPCHighPC(Die, LowPCVal, HighPCVal, OutputRanges.back().LowPC,964 OutputRanges.back().HighPC);965 break;966 }967 updateDWARFObjectAddressRanges(Unit, DIEBldr, *Die, RangesSectionOffset);968 break;969 }970 case dwarf::DW_TAG_call_site: {971 auto patchPC = [&](DIE *Die, DIEValue &AttrVal, StringRef Entry) -> void {972 std::optional<uint64_t> Address = getAsAddress(Unit, AttrVal);973 const BinaryFunction *Function =974 BC.getBinaryFunctionContainingAddress(*Address);975 uint64_t UpdatedAddress = *Address;976 if (Function)977 UpdatedAddress =978 Function->translateInputToOutputAddress(UpdatedAddress);979 980 if (AttrVal.getForm() == dwarf::DW_FORM_addrx) {981 const uint32_t Index =982 AddressWriter.getIndexFromAddress(UpdatedAddress, Unit);983 DIEBldr.replaceValue(Die, AttrVal.getAttribute(), AttrVal.getForm(),984 DIEInteger(Index));985 } else if (AttrVal.getForm() == dwarf::DW_FORM_addr) {986 DIEBldr.replaceValue(Die, AttrVal.getAttribute(), AttrVal.getForm(),987 DIEInteger(UpdatedAddress));988 } else {989 errs() << "BOLT-ERROR: unsupported form for " << Entry << "\n";990 }991 };992 DIEValue CallPcAttrVal = Die->findAttribute(dwarf::DW_AT_call_pc);993 if (CallPcAttrVal)994 patchPC(Die, CallPcAttrVal, "DW_AT_call_pc");995 996 DIEValue CallRetPcAttrVal =997 Die->findAttribute(dwarf::DW_AT_call_return_pc);998 if (CallRetPcAttrVal)999 patchPC(Die, CallRetPcAttrVal, "DW_AT_call_return_pc");1000 1001 break;1002 }1003 default: {1004 // Handle any tag that can have DW_AT_location attribute.1005 DIEValue LocAttrInfo = Die->findAttribute(dwarf::DW_AT_location);1006 DIEValue LowPCAttrInfo = Die->findAttribute(dwarf::DW_AT_low_pc);1007 if (LocAttrInfo) {1008 if (doesFormBelongToClass(LocAttrInfo.getForm(),1009 DWARFFormValue::FC_Constant,1010 Unit.getVersion()) ||1011 doesFormBelongToClass(LocAttrInfo.getForm(),1012 DWARFFormValue::FC_SectionOffset,1013 Unit.getVersion())) {1014 uint64_t Offset = LocAttrInfo.getForm() == dwarf::DW_FORM_loclistx1015 ? LocAttrInfo.getDIELocList().getValue()1016 : LocAttrInfo.getDIEInteger().getValue();1017 DebugLocationsVector InputLL;1018 1019 std::optional<object::SectionedAddress> SectionAddress =1020 Unit.getBaseAddress();1021 uint64_t BaseAddress = 0;1022 if (SectionAddress)1023 BaseAddress = SectionAddress->Address;1024 1025 if (Unit.getVersion() >= 5 &&1026 LocAttrInfo.getForm() == dwarf::DW_FORM_loclistx) {1027 std::optional<uint64_t> LocOffset = Unit.getLoclistOffset(Offset);1028 assert(LocOffset && "Location Offset is invalid.");1029 Offset = *LocOffset;1030 }1031 1032 Error E = Unit.getLocationTable().visitLocationList(1033 &Offset, [&](const DWARFLocationEntry &Entry) {1034 switch (Entry.Kind) {1035 default:1036 llvm_unreachable("Unsupported DWARFLocationEntry Kind.");1037 case dwarf::DW_LLE_end_of_list:1038 return false;1039 case dwarf::DW_LLE_base_address: {1040 assert(Entry.SectionIndex == SectionedAddress::UndefSection &&1041 "absolute address expected");1042 BaseAddress = Entry.Value0;1043 break;1044 }1045 case dwarf::DW_LLE_offset_pair:1046 assert(1047 (Entry.SectionIndex == SectionedAddress::UndefSection &&1048 (!Unit.isDWOUnit() || Unit.getVersion() == 5)) &&1049 "absolute address expected");1050 InputLL.emplace_back(DebugLocationEntry{1051 BaseAddress + Entry.Value0, BaseAddress + Entry.Value1,1052 Entry.Loc});1053 break;1054 case dwarf::DW_LLE_start_length:1055 InputLL.emplace_back(DebugLocationEntry{1056 Entry.Value0, Entry.Value0 + Entry.Value1, Entry.Loc});1057 break;1058 case dwarf::DW_LLE_base_addressx: {1059 std::optional<object::SectionedAddress> EntryAddress =1060 Unit.getAddrOffsetSectionItem(Entry.Value0);1061 assert(EntryAddress && "base Address not found.");1062 BaseAddress = EntryAddress->Address;1063 break;1064 }1065 case dwarf::DW_LLE_startx_length: {1066 std::optional<object::SectionedAddress> EntryAddress =1067 Unit.getAddrOffsetSectionItem(Entry.Value0);1068 assert(EntryAddress && "Address does not exist.");1069 InputLL.emplace_back(DebugLocationEntry{1070 EntryAddress->Address,1071 EntryAddress->Address + Entry.Value1, Entry.Loc});1072 break;1073 }1074 case dwarf::DW_LLE_startx_endx: {1075 std::optional<object::SectionedAddress> StartAddress =1076 Unit.getAddrOffsetSectionItem(Entry.Value0);1077 assert(StartAddress && "Start Address does not exist.");1078 std::optional<object::SectionedAddress> EndAddress =1079 Unit.getAddrOffsetSectionItem(Entry.Value1);1080 assert(EndAddress && "Start Address does not exist.");1081 InputLL.emplace_back(DebugLocationEntry{1082 StartAddress->Address, EndAddress->Address, Entry.Loc});1083 break;1084 }1085 }1086 return true;1087 });1088 1089 if (E || InputLL.empty()) {1090 consumeError(std::move(E));1091 errs() << "BOLT-WARNING: empty location list detected at 0x"1092 << Twine::utohexstr(Offset) << " for DIE at 0x" << Die1093 << " in CU at 0x" << Twine::utohexstr(Unit.getOffset())1094 << '\n';1095 } else {1096 const uint64_t Address = InputLL.front().LowPC;1097 DebugLocationsVector OutputLL;1098 if (const BinaryFunction *Function =1099 BC.getBinaryFunctionContainingAddress(Address)) {1100 OutputLL = translateInputToOutputLocationList(*Function, InputLL);1101 LLVM_DEBUG(if (OutputLL.empty()) {1102 dbgs() << "BOLT-DEBUG: location list translated to an empty "1103 "one at 0x"1104 << Die << " in CU at 0x"1105 << Twine::utohexstr(Unit.getOffset()) << '\n';1106 });1107 } else {1108 // It's possible for a subprogram to be removed and to have1109 // address of 0. Adding this entry to output to preserve debug1110 // information.1111 OutputLL = InputLL;1112 }1113 DebugLocWriter.addList(DIEBldr, *Die, LocAttrInfo, OutputLL);1114 }1115 } else {1116 assert((doesFormBelongToClass(LocAttrInfo.getForm(),1117 DWARFFormValue::FC_Exprloc,1118 Unit.getVersion()) ||1119 doesFormBelongToClass(LocAttrInfo.getForm(),1120 DWARFFormValue::FC_Block,1121 Unit.getVersion())) &&1122 "unexpected DW_AT_location form");1123 if (Unit.isDWOUnit() || Unit.getVersion() >= 5) {1124 std::vector<uint8_t> Sblock;1125 DIEValueList *AttrLocValList;1126 if (doesFormBelongToClass(LocAttrInfo.getForm(),1127 DWARFFormValue::FC_Exprloc,1128 Unit.getVersion())) {1129 for (const DIEValue &Val : LocAttrInfo.getDIELoc().values()) {1130 Sblock.push_back(Val.getDIEInteger().getValue());1131 }1132 DIELoc *LocAttr = const_cast<DIELoc *>(&LocAttrInfo.getDIELoc());1133 AttrLocValList = static_cast<DIEValueList *>(LocAttr);1134 } else {1135 for (const DIEValue &Val : LocAttrInfo.getDIEBlock().values()) {1136 Sblock.push_back(Val.getDIEInteger().getValue());1137 }1138 DIEBlock *BlockAttr =1139 const_cast<DIEBlock *>(&LocAttrInfo.getDIEBlock());1140 AttrLocValList = static_cast<DIEValueList *>(BlockAttr);1141 }1142 ArrayRef<uint8_t> Expr = ArrayRef<uint8_t>(Sblock);1143 DataExtractor Data(1144 StringRef((const char *)Expr.data(), Expr.size()),1145 Unit.getContext().isLittleEndian(), 0);1146 DWARFExpression LocExpr(Data, Unit.getAddressByteSize(),1147 Unit.getFormParams().Format);1148 uint32_t PrevOffset = 0;1149 DIEValueList *NewAttr;1150 DIEValue Value;1151 uint32_t NewExprSize = 0;1152 DIELoc *Loc = nullptr;1153 DIEBlock *Block = nullptr;1154 if (LocAttrInfo.getForm() == dwarf::DW_FORM_exprloc) {1155 Loc = DIEBldr.allocateDIEValue<DIELoc>();1156 NewAttr = Loc;1157 Value = DIEValue(LocAttrInfo.getAttribute(),1158 LocAttrInfo.getForm(), Loc);1159 } else if (doesFormBelongToClass(LocAttrInfo.getForm(),1160 DWARFFormValue::FC_Block,1161 Unit.getVersion())) {1162 Block = DIEBldr.allocateDIEValue<DIEBlock>();1163 NewAttr = Block;1164 Value = DIEValue(LocAttrInfo.getAttribute(),1165 LocAttrInfo.getForm(), Block);1166 } else {1167 errs() << "BOLT-WARNING: Unexpected Form value in Updating "1168 "DW_AT_Location\n";1169 continue;1170 }1171 1172 for (const DWARFExpression::Operation &Expr : LocExpr) {1173 uint32_t CurEndOffset = PrevOffset + 1;1174 if (Expr.getDescription().Op.size() == 1)1175 CurEndOffset = Expr.getOperandEndOffset(0);1176 if (Expr.getDescription().Op.size() == 2)1177 CurEndOffset = Expr.getOperandEndOffset(1);1178 if (Expr.getDescription().Op.size() > 2)1179 errs() << "BOLT-WARNING: [internal-dwarf-error]: Unsupported "1180 "number of operands.\n";1181 // not addr index, just copy.1182 if (!(Expr.getCode() == dwarf::DW_OP_GNU_addr_index ||1183 Expr.getCode() == dwarf::DW_OP_addrx)) {1184 auto Itr = AttrLocValList->values().begin();1185 std::advance(Itr, PrevOffset);1186 uint32_t CopyNum = CurEndOffset - PrevOffset;1187 NewExprSize += CopyNum;1188 while (CopyNum--) {1189 DIEBldr.addValue(NewAttr, *Itr);1190 std::advance(Itr, 1);1191 }1192 } else {1193 const uint64_t Index = Expr.getRawOperand(0);1194 std::optional<object::SectionedAddress> EntryAddress =1195 Unit.getAddrOffsetSectionItem(Index);1196 assert(EntryAddress && "Address is not found.");1197 assert(Index <= std::numeric_limits<uint32_t>::max() &&1198 "Invalid Operand Index.");1199 const uint32_t AddrIndex = AddressWriter.getIndexFromAddress(1200 EntryAddress->Address, Unit);1201 // update Index into .debug_address section for DW_AT_location.1202 // The Size field is not stored in IR, we need to minus 1 in1203 // offset for each expr.1204 SmallString<8> Tmp;1205 raw_svector_ostream OSE(Tmp);1206 encodeULEB128(AddrIndex, OSE);1207 1208 DIEBldr.addValue(NewAttr, static_cast<dwarf::Attribute>(0),1209 dwarf::DW_FORM_data1,1210 DIEInteger(Expr.getCode()));1211 NewExprSize += 1;1212 for (uint8_t Byte : Tmp) {1213 DIEBldr.addValue(NewAttr, static_cast<dwarf::Attribute>(0),1214 dwarf::DW_FORM_data1, DIEInteger(Byte));1215 NewExprSize += 1;1216 }1217 }1218 PrevOffset = CurEndOffset;1219 }1220 1221 // update the size since the index might be changed1222 if (Loc)1223 Loc->setSize(NewExprSize);1224 else1225 Block->setSize(NewExprSize);1226 DIEBldr.replaceValue(Die, LocAttrInfo.getAttribute(),1227 LocAttrInfo.getForm(), Value);1228 }1229 }1230 } else if (LowPCAttrInfo) {1231 uint64_t Address = 0;1232 uint64_t SectionIndex = 0;1233 if (getLowPC(*Die, Unit, Address, SectionIndex)) {1234 uint64_t NewAddress = 0;1235 if (const BinaryFunction *Function =1236 BC.getBinaryFunctionContainingAddress(Address)) {1237 NewAddress = Function->translateInputToOutputAddress(Address);1238 LLVM_DEBUG(dbgs()1239 << "BOLT-DEBUG: Fixing low_pc 0x"1240 << Twine::utohexstr(Address) << " for DIE with tag "1241 << Die->getTag() << " to 0x"1242 << Twine::utohexstr(NewAddress) << '\n');1243 }1244 1245 dwarf::Form Form = LowPCAttrInfo.getForm();1246 assert(Form != dwarf::DW_FORM_LLVM_addrx_offset &&1247 "DW_FORM_LLVM_addrx_offset is not supported");1248 std::lock_guard<std::mutex> Lock(DWARFRewriterMutex);1249 if (Form == dwarf::DW_FORM_addrx ||1250 Form == dwarf::DW_FORM_GNU_addr_index) {1251 const uint32_t Index = AddressWriter.getIndexFromAddress(1252 NewAddress ? NewAddress : Address, Unit);1253 DIEBldr.replaceValue(Die, LowPCAttrInfo.getAttribute(),1254 LowPCAttrInfo.getForm(), DIEInteger(Index));1255 } else {1256 DIEBldr.replaceValue(Die, LowPCAttrInfo.getAttribute(),1257 LowPCAttrInfo.getForm(),1258 DIEInteger(NewAddress));1259 }1260 } else if (opts::Verbosity >= 1) {1261 errs() << "BOLT-WARNING: unexpected form value for attribute "1262 "LowPCAttrInfo\n";1263 }1264 }1265 }1266 }1267 }1268 if (DIEOffset > NextCUOffset)1269 errs() << "BOLT-WARNING: corrupt DWARF detected at 0x"1270 << Twine::utohexstr(Unit.getOffset()) << '\n';1271}1272 1273void DWARFRewriter::updateDWARFObjectAddressRanges(1274 DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die, uint64_t DebugRangesOffset,1275 std::optional<uint64_t> RangesBase) {1276 1277 if (RangesBase) {1278 // If DW_AT_GNU_ranges_base is present, update it. No further modifications1279 // are needed for ranges base.1280 1281 DIEValue RangesBaseInfo = Die.findAttribute(dwarf::DW_AT_GNU_ranges_base);1282 if (!RangesBaseInfo) {1283 RangesBaseInfo = Die.findAttribute(dwarf::DW_AT_rnglists_base);1284 }1285 1286 if (RangesBaseInfo) {1287 if (RangesBaseInfo.getAttribute() == dwarf::DW_AT_GNU_ranges_base) {1288 auto RangesWriterIterator =1289 LegacyRangesWritersByCU.find(*Unit.getDWOId());1290 assert(RangesWriterIterator != LegacyRangesWritersByCU.end() &&1291 "RangesWriter does not exist for DWOId");1292 RangesWriterIterator->second->setDie(&Die);1293 } else {1294 DIEBldr.replaceValue(&Die, RangesBaseInfo.getAttribute(),1295 RangesBaseInfo.getForm(),1296 DIEInteger(static_cast<uint32_t>(*RangesBase)));1297 }1298 RangesBase = std::nullopt;1299 }1300 }1301 1302 DIEValue LowPCAttrInfo = Die.findAttribute(dwarf::DW_AT_low_pc);1303 DIEValue RangesAttrInfo = Die.findAttribute(dwarf::DW_AT_ranges);1304 if (RangesAttrInfo) {1305 // Case 1: The object was already non-contiguous and had DW_AT_ranges.1306 // In this case we simply need to update the value of DW_AT_ranges1307 // and introduce DW_AT_GNU_ranges_base if required.1308 // For DWARF5 converting all of DW_AT_ranges into DW_FORM_rnglistx1309 bool NeedConverted = false;1310 1311 if (Unit.getVersion() >= 5 &&1312 RangesAttrInfo.getForm() == dwarf::DW_FORM_sec_offset)1313 NeedConverted = true;1314 1315 if (NeedConverted || RangesAttrInfo.getForm() == dwarf::DW_FORM_rnglistx)1316 DIEBldr.replaceValue(&Die, dwarf::DW_AT_ranges, dwarf::DW_FORM_rnglistx,1317 DIEInteger(DebugRangesOffset));1318 else1319 DIEBldr.replaceValue(&Die, dwarf::DW_AT_ranges, RangesAttrInfo.getForm(),1320 DIEInteger(DebugRangesOffset));1321 1322 if (!RangesBase) {1323 if (LowPCAttrInfo &&1324 LowPCAttrInfo.getForm() != dwarf::DW_FORM_GNU_addr_index &&1325 LowPCAttrInfo.getForm() != dwarf::DW_FORM_addrx)1326 DIEBldr.replaceValue(&Die, dwarf::DW_AT_low_pc, LowPCAttrInfo.getForm(),1327 DIEInteger(0));1328 return;1329 }1330 1331 if (!(Die.getTag() == dwarf::DW_TAG_compile_unit ||1332 Die.getTag() == dwarf::DW_TAG_skeleton_unit))1333 return;1334 1335 // If we are at this point we are in the CU/Skeleton CU, and1336 // DW_AT_GNU_ranges_base or DW_AT_rnglists_base doesn't exist.1337 if (Unit.getVersion() <= 4) {1338 DIEBldr.addValue(&Die, dwarf::DW_AT_GNU_ranges_base, dwarf::DW_FORM_data4,1339 DIEInteger(INT_MAX));1340 auto RangesWriterIterator =1341 LegacyRangesWritersByCU.find(*Unit.getDWOId());1342 assert(RangesWriterIterator != LegacyRangesWritersByCU.end() &&1343 "RangesWriter does not exist for DWOId");1344 RangesWriterIterator->second->setDie(&Die);1345 } else if (Unit.getVersion() >= 5) {1346 DIEBldr.addValue(&Die, dwarf::DW_AT_rnglists_base,1347 dwarf::DW_FORM_sec_offset, DIEInteger(*RangesBase));1348 }1349 return;1350 }1351 1352 // Case 2: The object has both DW_AT_low_pc and DW_AT_high_pc emitted back1353 // to back. Replace with new attributes and patch the DIE.1354 DIEValue HighPCAttrInfo = Die.findAttribute(dwarf::DW_AT_high_pc);1355 if (LowPCAttrInfo && HighPCAttrInfo) {1356 1357 convertToRangesPatchDebugInfo(Unit, DIEBldr, Die, DebugRangesOffset,1358 LowPCAttrInfo, HighPCAttrInfo, RangesBase);1359 } else if (!(Unit.isDWOUnit() &&1360 Die.getTag() == dwarf::DW_TAG_compile_unit)) {1361 if (opts::Verbosity >= 1)1362 errs() << "BOLT-WARNING: cannot update ranges for DIE in Unit offset 0x"1363 << Twine::utohexstr(Unit.getOffset()) << '\n';1364 }1365}1366 1367void DWARFRewriter::updateLineTableOffsets(const MCAssembler &Asm) {1368 ErrorOr<BinarySection &> DbgInfoSection =1369 BC.getUniqueSectionByName(".debug_info");1370 ErrorOr<BinarySection &> TypeInfoSection =1371 BC.getUniqueSectionByName(".debug_types");1372 assert(((BC.DwCtx->getNumTypeUnits() > 0 && TypeInfoSection) ||1373 BC.DwCtx->getNumTypeUnits() == 0) &&1374 "Was not able to retrieve Debug Types section.");1375 1376 // There is no direct connection between CU and TU, but same offsets,1377 // encoded in DW_AT_stmt_list, into .debug_line get modified.1378 // We take advantage of that to map original CU line table offsets to new1379 // ones.1380 std::unordered_map<uint64_t, uint64_t> DebugLineOffsetMap;1381 1382 auto GetStatementListValue =1383 [](const DWARFDie &DIE) -> std::optional<uint64_t> {1384 std::optional<DWARFFormValue> StmtList = DIE.find(dwarf::DW_AT_stmt_list);1385 if (!StmtList)1386 return std::nullopt;1387 std::optional<uint64_t> Offset = dwarf::toSectionOffset(StmtList);1388 assert(Offset && "Was not able to retrieve value of DW_AT_stmt_list.");1389 return *Offset;1390 };1391 1392 SmallVector<DWARFUnit *, 1> TUs;1393 for (const std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->info_section_units()) {1394 if (CU->isTypeUnit()) {1395 TUs.push_back(CU.get());1396 continue;1397 }1398 const unsigned CUID = CU->getOffset();1399 MCSymbol *Label = BC.getDwarfLineTable(CUID).getLabel();1400 if (!Label)1401 continue;1402 1403 std::optional<uint64_t> StmtOffset =1404 GetStatementListValue(CU->getUnitDIE());1405 if (!StmtOffset)1406 continue;1407 1408 const uint64_t LineTableOffset =1409 Asm.getSymbolOffset(*Label);1410 DebugLineOffsetMap[*StmtOffset] = LineTableOffset;1411 assert(DbgInfoSection && ".debug_info section must exist");1412 LineTablePatchMap[CU.get()] = LineTableOffset;1413 }1414 1415 for (const std::unique_ptr<DWARFUnit> &TU : BC.DwCtx->types_section_units())1416 TUs.push_back(TU.get());1417 1418 for (DWARFUnit *TU : TUs) {1419 std::optional<uint64_t> StmtOffset =1420 GetStatementListValue(TU->getUnitDIE());1421 if (!StmtOffset)1422 continue;1423 auto Iter = DebugLineOffsetMap.find(*StmtOffset);1424 if (Iter == DebugLineOffsetMap.end()) {1425 // Implementation depends on TU sharing DW_AT_stmt_list with a CU.1426 // Only case that it hasn't been true was for manually modified assembly1427 // file. Adding this warning in case assumption is false.1428 errs()1429 << "BOLT-WARNING: [internal-dwarf-error]: A TU at offset: 0x"1430 << Twine::utohexstr(TU->getOffset())1431 << " is not sharing "1432 ".debug_line entry with CU. DW_AT_stmt_list for this TU won't be "1433 "updated.\n";1434 continue;1435 }1436 TypeUnitRelocMap[TU] = Iter->second;1437 }1438 1439 // Set .debug_info as finalized so it won't be skipped over when1440 // we process sections while writing out the new binary. This ensures1441 // that the pending relocations will be processed and not ignored.1442 if (DbgInfoSection)1443 DbgInfoSection->setIsFinalized();1444 1445 if (TypeInfoSection)1446 TypeInfoSection->setIsFinalized();1447}1448 1449CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,1450 DIEStreamer &Streamer,1451 GDBIndex &GDBIndexSection) {1452 // update TypeUnit DW_AT_stmt_list with new .debug_line information.1453 auto updateLineTable = [&](const DWARFUnit &Unit) -> void {1454 DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(Unit);1455 DIEValue StmtAttrInfo = UnitDIE->findAttribute(dwarf::DW_AT_stmt_list);1456 if (!StmtAttrInfo || !TypeUnitRelocMap.count(&Unit))1457 return;1458 DIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_stmt_list,1459 StmtAttrInfo.getForm(),1460 DIEInteger(TypeUnitRelocMap[&Unit]));1461 };1462 1463 // generate and populate abbrevs here1464 DIEBlder.generateAbbrevs();1465 DIEBlder.finish();1466 DIEBlder.updateDebugNamesTable();1467 SmallVector<char, 20> OutBuffer;1468 std::shared_ptr<raw_svector_ostream> ObjOS =1469 std::make_shared<raw_svector_ostream>(OutBuffer);1470 const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile();1471 auto TheTriple = std::make_unique<Triple>(File->makeTriple());1472 std::unique_ptr<DIEStreamer> TypeStreamer = createDIEStreamer(1473 *TheTriple, *ObjOS, "TypeStreamer", DIEBlder, GDBIndexSection);1474 1475 // generate debug_info and CUMap1476 CUOffsetMap CUMap;1477 for (std::unique_ptr<llvm::DWARFUnit> &CU : BC.DwCtx->info_section_units()) {1478 if (!CU->isTypeUnit())1479 continue;1480 updateLineTable(*CU);1481 emitUnit(DIEBlder, Streamer, *CU);1482 uint32_t StartOffset = CUOffset;1483 DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU);1484 CUOffset += CU->getHeaderSize();1485 CUOffset += UnitDIE->getSize();1486 CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};1487 }1488 1489 // Emit Type Unit of DWARF 4 to .debug_type section1490 for (DWARFUnit *TU : DIEBlder.getDWARF4TUVector()) {1491 updateLineTable(*TU);1492 emitUnit(DIEBlder, *TypeStreamer, *TU);1493 }1494 1495 TypeStreamer->finish();1496 1497 std::unique_ptr<MemoryBuffer> ObjectMemBuffer =1498 MemoryBuffer::getMemBuffer(ObjOS->str(), "in-memory object file", false);1499 std::unique_ptr<object::ObjectFile> Obj = cantFail(1500 object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()),1501 "error creating in-memory object");1502 1503 for (const SectionRef &Section : Obj->sections()) {1504 StringRef Contents = cantFail(Section.getContents());1505 StringRef Name = cantFail(Section.getName());1506 if (Name == ".debug_types")1507 BC.registerOrUpdateNoteSection(".debug_types", copyByteArray(Contents),1508 Contents.size());1509 }1510 return CUMap;1511}1512 1513void DWARFRewriter::finalizeDebugSections(1514 DIEBuilder &DIEBlder, DWARF5AcceleratorTable &DebugNamesTable,1515 DIEStreamer &Streamer, raw_svector_ostream &ObjOS, CUOffsetMap &CUMap,1516 DebugAddrWriter &FinalAddrWriter) {1517 if (StrWriter->isInitialized()) {1518 RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");1519 std::unique_ptr<DebugStrBufferVector> DebugStrSectionContents =1520 StrWriter->releaseBuffer();1521 BC.registerOrUpdateNoteSection(".debug_str",1522 copyByteArray(*DebugStrSectionContents),1523 DebugStrSectionContents->size());1524 }1525 1526 if (StrOffstsWriter->isFinalized()) {1527 RewriteInstance::addToDebugSectionsToOverwrite(".debug_str_offsets");1528 std::unique_ptr<DebugStrOffsetsBufferVector>1529 DebugStrOffsetsSectionContents = StrOffstsWriter->releaseBuffer();1530 BC.registerOrUpdateNoteSection(1531 ".debug_str_offsets", copyByteArray(*DebugStrOffsetsSectionContents),1532 DebugStrOffsetsSectionContents->size());1533 }1534 1535 if (BC.isDWARFLegacyUsed()) {1536 std::unique_ptr<DebugBufferVector> RangesSectionContents =1537 LegacyRangesSectionWriter->releaseBuffer();1538 BC.registerOrUpdateNoteSection(".debug_ranges",1539 copyByteArray(*RangesSectionContents),1540 RangesSectionContents->size());1541 }1542 1543 if (BC.isDWARF5Used()) {1544 std::unique_ptr<DebugBufferVector> RangesSectionContents =1545 RangeListsSectionWriter->releaseBuffer();1546 BC.registerOrUpdateNoteSection(".debug_rnglists",1547 copyByteArray(*RangesSectionContents),1548 RangesSectionContents->size());1549 }1550 1551 if (BC.isDWARF5Used()) {1552 std::unique_ptr<DebugBufferVector> LocationListSectionContents =1553 makeFinalLocListsSection(DWARFVersion::DWARF5);1554 if (!LocationListSectionContents->empty())1555 BC.registerOrUpdateNoteSection(1556 ".debug_loclists", copyByteArray(*LocationListSectionContents),1557 LocationListSectionContents->size());1558 }1559 1560 if (BC.isDWARFLegacyUsed()) {1561 std::unique_ptr<DebugBufferVector> LocationListSectionContents =1562 makeFinalLocListsSection(DWARFVersion::DWARFLegacy);1563 if (!LocationListSectionContents->empty())1564 BC.registerOrUpdateNoteSection(1565 ".debug_loc", copyByteArray(*LocationListSectionContents),1566 LocationListSectionContents->size());1567 }1568 1569 if (FinalAddrWriter.isInitialized()) {1570 std::unique_ptr<AddressSectionBuffer> AddressSectionContents =1571 FinalAddrWriter.releaseBuffer();1572 BC.registerOrUpdateNoteSection(".debug_addr",1573 copyByteArray(*AddressSectionContents),1574 AddressSectionContents->size());1575 }1576 1577 Streamer.emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion());1578 Streamer.finish();1579 1580 std::unique_ptr<MemoryBuffer> ObjectMemBuffer =1581 MemoryBuffer::getMemBuffer(ObjOS.str(), "in-memory object file", false);1582 std::unique_ptr<object::ObjectFile> Obj = cantFail(1583 object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()),1584 "error creating in-memory object");1585 1586 for (const SectionRef &Secs : Obj->sections()) {1587 StringRef Contents = cantFail(Secs.getContents());1588 StringRef Name = cantFail(Secs.getName());1589 if (Name == ".debug_abbrev") {1590 BC.registerOrUpdateNoteSection(".debug_abbrev", copyByteArray(Contents),1591 Contents.size());1592 } else if (Name == ".debug_info") {1593 BC.registerOrUpdateNoteSection(".debug_info", copyByteArray(Contents),1594 Contents.size());1595 }1596 }1597 1598 // Skip .debug_aranges if we are re-generating .gdb_index.1599 if (opts::KeepARanges || !BC.getGdbIndexSection()) {1600 SmallVector<char, 16> ARangesBuffer;1601 raw_svector_ostream OS(ARangesBuffer);1602 1603 auto MAB = std::unique_ptr<MCAsmBackend>(1604 BC.TheTarget->createMCAsmBackend(*BC.STI, *BC.MRI, MCTargetOptions()));1605 1606 ARangesSectionWriter->writeARangesSection(OS, CUMap);1607 const StringRef &ARangesContents = OS.str();1608 1609 BC.registerOrUpdateNoteSection(".debug_aranges",1610 copyByteArray(ARangesContents),1611 ARangesContents.size());1612 }1613 1614 if (DebugNamesTable.isCreated()) {1615 RewriteInstance::addToDebugSectionsToOverwrite(".debug_names");1616 std::unique_ptr<DebugBufferVector> DebugNamesSectionContents =1617 DebugNamesTable.releaseBuffer();1618 BC.registerOrUpdateNoteSection(".debug_names",1619 copyByteArray(*DebugNamesSectionContents),1620 DebugNamesSectionContents->size());1621 }1622}1623 1624void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,1625 DIEStreamer &Streamer,1626 CUOffsetMap &CUMap,1627 const std::list<DWARFUnit *> &CUs,1628 DebugAddrWriter &FinalAddrWriter) {1629 for (DWARFUnit *CU : CUs) {1630 auto AddressWriterIterator = AddressWritersByCU.find(CU->getOffset());1631 assert(AddressWriterIterator != AddressWritersByCU.end() &&1632 "AddressWriter does not exist for CU");1633 DebugAddrWriter *AddressWriter = AddressWriterIterator->second.get();1634 const size_t BufferOffset = FinalAddrWriter.getBufferSize();1635 std::optional<uint64_t> Offset = AddressWriter->finalize(BufferOffset);1636 /// If Offset already exists in UnmodifiedAddressOffsets, then update with1637 /// Offset, else update with BufferOffset.1638 if (Offset)1639 AddressWriter->updateAddrBase(DIEBlder, *CU, *Offset);1640 else if (AddressWriter->isInitialized())1641 AddressWriter->updateAddrBase(DIEBlder, *CU, BufferOffset);1642 if (AddressWriter->isInitialized()) {1643 std::unique_ptr<AddressSectionBuffer> AddressSectionContents =1644 AddressWriter->releaseBuffer();1645 FinalAddrWriter.appendToAddressBuffer(*AddressSectionContents);1646 }1647 if (CU->getVersion() != 4)1648 continue;1649 std::optional<uint64_t> DWOId = CU->getDWOId();1650 if (!DWOId)1651 continue;1652 auto RangesWriterIterator = LegacyRangesWritersByCU.find(*DWOId);1653 assert(RangesWriterIterator != LegacyRangesWritersByCU.end() &&1654 "RangesWriter does not exist for DWOId");1655 std::unique_ptr<DebugRangesSectionWriter> &LegacyRangesWriter =1656 RangesWriterIterator->second;1657 DIE *Die = LegacyRangesWriter->getDie();1658 if (!Die)1659 continue;1660 DIEValue DvalGNUBase = Die->findAttribute(dwarf::DW_AT_GNU_ranges_base);1661 assert(DvalGNUBase && "GNU_ranges_base attribute does not exist for DWOId");1662 DIEBlder.replaceValue(1663 Die, dwarf::DW_AT_GNU_ranges_base, DvalGNUBase.getForm(),1664 DIEInteger(LegacyRangesSectionWriter->getSectionOffset()));1665 std::unique_ptr<DebugBufferVector> RangesWritersContents =1666 LegacyRangesWriter->releaseBuffer();1667 LegacyRangesSectionWriter->appendToRangeBuffer(*RangesWritersContents);1668 }1669 DIEBlder.generateAbbrevs();1670 DIEBlder.finish();1671 DIEBlder.updateDebugNamesTable();1672 // generate debug_info and CUMap1673 for (DWARFUnit *CU : CUs) {1674 emitUnit(DIEBlder, Streamer, *CU);1675 const uint32_t StartOffset = CUOffset;1676 DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU);1677 CUOffset += CU->getHeaderSize();1678 CUOffset += UnitDIE->getSize();1679 CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};1680 }1681}1682 1683// Creates all the data structures necessary for creating MCStreamer.1684// They are passed by reference because they need to be kept around.1685// Also creates known debug sections. These are sections handled by1686// handleDebugDataPatching.1687namespace {1688 1689std::unique_ptr<BinaryContext>1690createDwarfOnlyBC(const object::ObjectFile &File) {1691 return cantFail(BinaryContext::createBinaryContext(1692 File.makeTriple(), std::make_shared<orc::SymbolStringPool>(),1693 File.getFileName(), nullptr, false,1694 DWARFContext::create(File, DWARFContext::ProcessDebugRelocations::Ignore,1695 nullptr, "", WithColor::defaultErrorHandler,1696 WithColor::defaultWarningHandler),1697 {llvm::outs(), llvm::errs()}));1698}1699 1700StringMap<DWARFRewriter::KnownSectionsEntry>1701createKnownSectionsMap(const MCObjectFileInfo &MCOFI) {1702 StringMap<DWARFRewriter::KnownSectionsEntry> KnownSectionsTemp = {1703 {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}},1704 {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}},1705 {"debug_str_offsets.dwo",1706 {MCOFI.getDwarfStrOffDWOSection(), DW_SECT_STR_OFFSETS}},1707 {"debug_str.dwo", {MCOFI.getDwarfStrDWOSection(), DW_SECT_EXT_unknown}},1708 {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}},1709 {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}},1710 {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}},1711 {"debug_loclists.dwo",1712 {MCOFI.getDwarfLoclistsDWOSection(), DW_SECT_LOCLISTS}},1713 {"debug_rnglists.dwo",1714 {MCOFI.getDwarfRnglistsDWOSection(), DW_SECT_RNGLISTS}}};1715 return KnownSectionsTemp;1716}1717 1718StringRef getSectionName(const SectionRef &Section) {1719 Expected<StringRef> SectionName = Section.getName();1720 assert(SectionName && "Invalid section name.");1721 StringRef Name = *SectionName;1722 Name = Name.substr(Name.find_first_not_of("._"));1723 return Name;1724}1725 1726/// Extracts the slice of the .debug_str.dwo section for a given CU from a DWP1727/// file, based on the .debug_str_offsets.dwo section. This helps address DWO1728/// bloat that may occur after updates.1729///1730/// A slice of .debug_str.dwo may be composed of several non-contiguous1731/// fragments. These non-contiguous string views will be written out1732/// sequentially, avoiding the copying overhead caused by assembling them.1733///1734/// The .debug_str_offsets for the first CU often does not need to be updated,1735/// so copying is only performed when .debug_str_offsets requires updating.1736static void UpdateStrAndStrOffsets(StringRef StrDWOContent,1737 StringRef StrOffsetsContent,1738 SmallVectorImpl<StringRef> &StrDWOOutData,1739 std::string &StrOffsetsOutData,1740 unsigned DwarfVersion, bool IsLittleEndian) {1741 const llvm::endianness Endian =1742 IsLittleEndian ? llvm::endianness::little : llvm::endianness::big;1743 const uint64_t HeaderOffset = (DwarfVersion >= 5) ? 8 : 0;1744 constexpr size_t SizeOfOffset = sizeof(int32_t);1745 const uint64_t NumOffsets =1746 (StrOffsetsContent.size() - HeaderOffset) / SizeOfOffset;1747 1748 DataExtractor Extractor(StrOffsetsContent, IsLittleEndian, 0);1749 uint64_t ExtractionOffset = HeaderOffset;1750 1751 using StringFragment = DWARFUnitIndex::Entry::SectionContribution;1752 const auto getStringLength = [](StringRef Content,1753 uint64_t Offset) -> uint64_t {1754 size_t NullPos = Content.find('\0', Offset);1755 return (NullPos != StringRef::npos) ? (NullPos - Offset + 1) : 0;1756 };1757 const auto isContiguous = [](const StringFragment &Fragment,1758 uint64_t NextOffset) -> bool {1759 return NextOffset == Fragment.getOffset() + Fragment.getLength();1760 };1761 std::optional<StringFragment> CurrentFragment;1762 uint64_t AccumulatedStrLen = 0;1763 for (uint64_t I = 0; I < NumOffsets; ++I) {1764 const uint64_t StrOffset = Extractor.getU32(&ExtractionOffset);1765 const uint64_t StringLength = getStringLength(StrDWOContent, StrOffset);1766 if (!CurrentFragment) {1767 // First init.1768 CurrentFragment = StringFragment(StrOffset, StringLength);1769 } else {1770 if (isContiguous(*CurrentFragment, StrOffset)) {1771 // Expanding the current fragment.1772 CurrentFragment->setLength(CurrentFragment->getLength() + StringLength);1773 } else {1774 // Saving the current fragment and start a new one.1775 StrDWOOutData.push_back(StrDWOContent.substr(1776 CurrentFragment->getOffset(), CurrentFragment->getLength()));1777 CurrentFragment = StringFragment(StrOffset, StringLength);1778 }1779 }1780 if (AccumulatedStrLen != StrOffset) {1781 // Updating str offsets.1782 if (StrOffsetsOutData.empty())1783 StrOffsetsOutData = StrOffsetsContent.str();1784 llvm::support::endian::write32(1785 &StrOffsetsOutData[HeaderOffset + I * SizeOfOffset],1786 static_cast<uint32_t>(AccumulatedStrLen), Endian);1787 }1788 AccumulatedStrLen += StringLength;1789 }1790 if (CurrentFragment)1791 StrDWOOutData.push_back(StrDWOContent.substr(CurrentFragment->getOffset(),1792 CurrentFragment->getLength()));1793}1794 1795// Exctracts an appropriate slice if input is DWP.1796// Applies patches or overwrites the section.1797std::optional<StringRef> updateDebugData(1798 DWARFContext &DWCtx, StringRef SectionName, StringRef SectionContents,1799 const StringMap<DWARFRewriter::KnownSectionsEntry> &KnownSections,1800 MCStreamer &Streamer, DWARFRewriter &Writer,1801 const DWARFUnitIndex::Entry *CUDWOEntry, uint64_t DWOId,1802 std::unique_ptr<DebugBufferVector> &OutputBuffer,1803 DebugRangeListsSectionWriter *RangeListsWriter, DebugLocWriter &LocWriter,1804 DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,1805 const llvm::bolt::DWARFRewriter::OverriddenSectionsMap &OverridenSections) {1806 1807 using DWOSectionContribution =1808 const DWARFUnitIndex::Entry::SectionContribution;1809 auto getSliceData = [&](const DWARFUnitIndex::Entry *DWOEntry,1810 StringRef OutData, DWARFSectionKind Sec,1811 uint64_t &DWPOffset) -> StringRef {1812 if (DWOEntry) {1813 DWOSectionContribution *DWOContrubution = DWOEntry->getContribution(Sec);1814 DWPOffset = DWOContrubution->getOffset();1815 OutData = OutData.substr(DWPOffset, DWOContrubution->getLength());1816 }1817 return OutData;1818 };1819 1820 auto SectionIter = KnownSections.find(SectionName);1821 if (SectionIter == KnownSections.end())1822 return std::nullopt;1823 Streamer.switchSection(SectionIter->second.first);1824 uint64_t DWPOffset = 0;1825 1826 auto getOverridenSection =1827 [&](DWARFSectionKind Kind) -> std::optional<StringRef> {1828 auto Iter = OverridenSections.find(Kind);1829 if (Iter == OverridenSections.end()) {1830 errs()1831 << "BOLT-WARNING: [internal-dwarf-error]: Could not find overridden "1832 "section for: "1833 << Twine::utohexstr(DWOId) << ".\n";1834 return std::nullopt;1835 }1836 return Iter->second;1837 };1838 switch (SectionIter->second.second) {1839 default: {1840 if (SectionName != "debug_str.dwo")1841 errs() << "BOLT-WARNING: unsupported debug section: " << SectionName1842 << "\n";1843 if (StrWriter.isInitialized()) {1844 if (CUDWOEntry)1845 return StrWriter.getBufferStr();1846 OutputBuffer = StrWriter.releaseBuffer();1847 return StringRef(reinterpret_cast<const char *>(OutputBuffer->data()),1848 OutputBuffer->size());1849 }1850 return SectionContents;1851 }1852 case DWARFSectionKind::DW_SECT_INFO: {1853 return getOverridenSection(DWARFSectionKind::DW_SECT_INFO);1854 }1855 case DWARFSectionKind::DW_SECT_EXT_TYPES: {1856 return getOverridenSection(DWARFSectionKind::DW_SECT_EXT_TYPES);1857 }1858 case DWARFSectionKind::DW_SECT_STR_OFFSETS: {1859 if (StrOffstsWriter.isFinalized()) {1860 if (CUDWOEntry)1861 return StrOffstsWriter.getBufferStr();1862 OutputBuffer = StrOffstsWriter.releaseBuffer();1863 return StringRef(reinterpret_cast<const char *>(OutputBuffer->data()),1864 OutputBuffer->size());1865 }1866 return getSliceData(CUDWOEntry, SectionContents,1867 DWARFSectionKind::DW_SECT_STR_OFFSETS, DWPOffset);1868 }1869 case DWARFSectionKind::DW_SECT_ABBREV: {1870 return getOverridenSection(DWARFSectionKind::DW_SECT_ABBREV);1871 }1872 case DWARFSectionKind::DW_SECT_EXT_LOC:1873 case DWARFSectionKind::DW_SECT_LOCLISTS: {1874 OutputBuffer = LocWriter.getBuffer();1875 // Creating explicit StringRef here, otherwise1876 // with implicit conversion it will take null byte as end of1877 // string.1878 return StringRef(reinterpret_cast<const char *>(OutputBuffer->data()),1879 OutputBuffer->size());1880 }1881 case DWARFSectionKind::DW_SECT_LINE: {1882 return getSliceData(CUDWOEntry, SectionContents,1883 DWARFSectionKind::DW_SECT_LINE, DWPOffset);1884 }1885 case DWARFSectionKind::DW_SECT_RNGLISTS: {1886 assert(RangeListsWriter && "RangeListsWriter was not created.");1887 OutputBuffer = RangeListsWriter->releaseBuffer();1888 return StringRef(reinterpret_cast<const char *>(OutputBuffer->data()),1889 OutputBuffer->size());1890 }1891 }1892}1893 1894} // namespace1895 1896void DWARFRewriter::writeDWOFiles(1897 DWARFUnit &CU, const OverriddenSectionsMap &OverridenSections,1898 const std::string &DWOName, DebugLocWriter &LocWriter,1899 DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter,1900 DebugRangesSectionWriter &TempRangesSectionWriter) {1901 // Setup DWP code once.1902 DWARFContext *DWOCtx = BC.getDWOContext();1903 const uint64_t DWOId = *CU.getDWOId();1904 const DWARFUnitIndex *CUIndex = nullptr;1905 bool IsDWP = false;1906 if (DWOCtx) {1907 CUIndex = &DWOCtx->getCUIndex();1908 IsDWP = !CUIndex->getRows().empty();1909 }1910 1911 // Skipping CUs that we failed to load.1912 std::optional<DWARFUnit *> DWOCU = BC.getDWOCU(DWOId);1913 if (!DWOCU) {1914 errs() << "BOLT-WARNING: [internal-dwarf-error]: CU for DWO_ID "1915 << Twine::utohexstr(DWOId) << " is not found.\n";1916 return;1917 }1918 1919 std::string CompDir = CU.getCompilationDir();1920 SmallString<16> AbsolutePath(DWOName);1921 1922 if (!opts::DwarfOutputPath.empty())1923 CompDir = opts::DwarfOutputPath.c_str();1924 else if (!opts::CompDirOverride.empty())1925 CompDir = opts::CompDirOverride;1926 else if (!sys::fs::exists(CompDir))1927 CompDir = ".";1928 // Prevent failures when DWOName is already an absolute path.1929 sys::path::make_absolute(CompDir, AbsolutePath);1930 1931 std::error_code EC;1932 std::unique_ptr<ToolOutputFile> TempOut =1933 std::make_unique<ToolOutputFile>(AbsolutePath, EC, sys::fs::OF_None);1934 1935 const DWARFUnitIndex::Entry *CUDWOEntry = nullptr;1936 if (IsDWP)1937 CUDWOEntry = CUIndex->getFromHash(DWOId);1938 1939 const object::ObjectFile *File =1940 (*DWOCU)->getContext().getDWARFObj().getFile();1941 std::unique_ptr<BinaryContext> TmpBC = createDwarfOnlyBC(*File);1942 std::unique_ptr<MCStreamer> Streamer = TmpBC->createStreamer(TempOut->os());1943 const MCObjectFileInfo &MCOFI = *Streamer->getContext().getObjectFileInfo();1944 StringMap<KnownSectionsEntry> KnownSections = createKnownSectionsMap(MCOFI);1945 1946 DebugRangeListsSectionWriter *RangeListssWriter = nullptr;1947 if (CU.getVersion() == 5) {1948 RangeListssWriter =1949 llvm::dyn_cast<DebugRangeListsSectionWriter>(&TempRangesSectionWriter);1950 1951 // Handling .debug_rnglists.dwo separately. The original .o/.dwo might not1952 // have .debug_rnglists so won't be part of the loop below.1953 if (!RangeListssWriter->empty()) {1954 std::unique_ptr<DebugBufferVector> OutputData;1955 if (std::optional<StringRef> OutData =1956 updateDebugData((*DWOCU)->getContext(), "debug_rnglists.dwo", "",1957 KnownSections, *Streamer, *this, CUDWOEntry,1958 DWOId, OutputData, RangeListssWriter, LocWriter,1959 StrOffstsWriter, StrWriter, OverridenSections))1960 Streamer->emitBytes(*OutData);1961 }1962 }1963 1964 StringRef StrDWOContent;1965 StringRef StrOffsetsContent;1966 llvm::SmallVector<StringRef, 3> StrDWOOutData;1967 std::string StrOffsetsOutData;1968 for (const SectionRef &Section : File->sections()) {1969 std::unique_ptr<DebugBufferVector> OutputData;1970 StringRef SectionName = getSectionName(Section);1971 if (SectionName == "debug_rnglists.dwo")1972 continue;1973 Expected<StringRef> ContentsExp = Section.getContents();1974 assert(ContentsExp && "Invalid contents.");1975 if (IsDWP && SectionName == "debug_str.dwo") {1976 if (StrWriter.isInitialized())1977 StrDWOContent = StrWriter.getBufferStr();1978 else1979 StrDWOContent = *ContentsExp;1980 continue;1981 }1982 if (std::optional<StringRef> OutData = updateDebugData(1983 (*DWOCU)->getContext(), SectionName, *ContentsExp, KnownSections,1984 *Streamer, *this, CUDWOEntry, DWOId, OutputData, RangeListssWriter,1985 LocWriter, StrOffstsWriter, StrWriter, OverridenSections)) {1986 if (IsDWP && SectionName == "debug_str_offsets.dwo") {1987 StrOffsetsContent = *OutData;1988 continue;1989 }1990 Streamer->emitBytes(*OutData);1991 }1992 }1993 1994 if (IsDWP) {1995 // Handling both .debug_str.dwo and .debug_str_offsets.dwo concurrently. In1996 // the original DWP, .debug_str is a deduplicated global table, and the1997 // .debug_str.dwo slice for a single CU needs to be extracted according to1998 // .debug_str_offsets.dwo.1999 UpdateStrAndStrOffsets(StrDWOContent, StrOffsetsContent, StrDWOOutData,2000 StrOffsetsOutData, CU.getVersion(),2001 (*DWOCU)->getContext().isLittleEndian());2002 auto SectionIter = KnownSections.find("debug_str.dwo");2003 if (SectionIter != KnownSections.end()) {2004 Streamer->switchSection(SectionIter->second.first);2005 for (size_t i = 0; i < StrDWOOutData.size(); ++i) {2006 StringRef OutData = StrDWOOutData[i];2007 if (!OutData.empty())2008 Streamer->emitBytes(OutData);2009 }2010 }2011 SectionIter = KnownSections.find("debug_str_offsets.dwo");2012 if (SectionIter != KnownSections.end()) {2013 Streamer->switchSection(SectionIter->second.first);2014 if (!StrOffsetsOutData.empty())2015 Streamer->emitBytes(StrOffsetsOutData);2016 else2017 Streamer->emitBytes(StrOffsetsContent);2018 }2019 }2020 Streamer->finish();2021 TempOut->keep();2022}2023 2024std::unique_ptr<DebugBufferVector>2025DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) {2026 auto LocBuffer = std::make_unique<DebugBufferVector>();2027 auto LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);2028 auto Writer =2029 std::unique_ptr<MCObjectWriter>(BC.createObjectWriter(*LocStream));2030 2031 for (std::pair<const uint64_t, std::unique_ptr<DebugLocWriter>> &Loc :2032 LocListWritersByCU) {2033 DebugLocWriter *LocWriter = Loc.second.get();2034 auto *LocListWriter = llvm::dyn_cast<DebugLoclistWriter>(LocWriter);2035 2036 // Filter out DWARF4, writing out DWARF52037 if (Version == DWARFVersion::DWARF5 &&2038 (!LocListWriter || LocListWriter->getDwarfVersion() <= 4))2039 continue;2040 2041 // Filter out DWARF5, writing out DWARF42042 if (Version == DWARFVersion::DWARFLegacy &&2043 (LocListWriter && LocListWriter->getDwarfVersion() >= 5))2044 continue;2045 2046 // Skipping DWARF4/5 split dwarf.2047 if (LocListWriter && LocListWriter->getDwarfVersion() <= 4)2048 continue;2049 std::unique_ptr<DebugBufferVector> CurrCULocationLists =2050 LocWriter->getBuffer();2051 *LocStream << *CurrCULocationLists;2052 }2053 2054 return LocBuffer;2055}2056 2057void DWARFRewriter::convertToRangesPatchDebugInfo(2058 DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die,2059 uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo,2060 DIEValue &HighPCAttrInfo, std::optional<uint64_t> RangesBase) {2061 dwarf::Form LowForm = LowPCAttrInfo.getForm();2062 dwarf::Attribute RangeBaseAttribute = dwarf::DW_AT_GNU_ranges_base;2063 dwarf::Form RangesForm = dwarf::DW_FORM_sec_offset;2064 2065 if (Unit.getVersion() >= 5) {2066 RangeBaseAttribute = dwarf::DW_AT_rnglists_base;2067 RangesForm = dwarf::DW_FORM_rnglistx;2068 } else if (Unit.getVersion() < 4) {2069 RangesForm = dwarf::DW_FORM_data4;2070 }2071 bool IsUnitDie = Die.getTag() == dwarf::DW_TAG_compile_unit ||2072 Die.getTag() == dwarf::DW_TAG_skeleton_unit;2073 if (!IsUnitDie)2074 DIEBldr.deleteValue(&Die, LowPCAttrInfo.getAttribute());2075 2076 // In DWARF 5 we can have DW_AT_low_pc either as DW_FORM_addr, or2077 // DW_FORM_addrx. Former is when DW_AT_rnglists_base is present. Latter is2078 // when it's absent.2079 if (IsUnitDie) {2080 if (LowForm == dwarf::DW_FORM_addrx) {2081 auto AddrWriterIterator = AddressWritersByCU.find(Unit.getOffset());2082 assert(AddrWriterIterator != AddressWritersByCU.end() &&2083 "AddressWriter does not exist for CU");2084 DebugAddrWriter *AddrWriter = AddrWriterIterator->second.get();2085 const uint32_t Index = AddrWriter->getIndexFromAddress(0, Unit);2086 DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(),2087 LowPCAttrInfo.getForm(), DIEInteger(Index));2088 } else {2089 DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(),2090 LowPCAttrInfo.getForm(), DIEInteger(0));2091 }2092 // Original CU didn't have DW_AT_*_base. We converted it's children (or2093 // dwo), so need to insert it into CU.2094 if (RangesBase) {2095 if (Unit.getVersion() >= 5) {2096 DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset,2097 DIEInteger(*RangesBase));2098 } else {2099 DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset,2100 DIEInteger(INT_MAX));2101 auto RangesWriterIterator =2102 LegacyRangesWritersByCU.find(*Unit.getDWOId());2103 assert(RangesWriterIterator != LegacyRangesWritersByCU.end() &&2104 "RangesWriter does not exist for DWOId");2105 RangesWriterIterator->second->setDie(&Die);2106 }2107 }2108 }2109 2110 // HighPC was converted into DW_AT_ranges.2111 // For DWARF5 we only access ranges through index.2112 2113 DIEBldr.replaceValue(&Die, HighPCAttrInfo.getAttribute(), dwarf::DW_AT_ranges,2114 RangesForm, DIEInteger(RangesSectionOffset));2115}2116