479 lines · cpp
1//=== DebugInfoLinker.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 "DebugInfoLinker.h"10#include "Error.h"11#include "llvm/ADT/StringSwitch.h"12#include "llvm/DWARFLinker/Classic/DWARFLinker.h"13#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"14#include "llvm/DWARFLinker/Parallel/DWARFLinker.h"15#include "llvm/DebugInfo/DWARF/DWARFContext.h"16#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"17#include "llvm/Object/ObjectFile.h"18#include <memory>19#include <vector>20 21namespace llvm {22using namespace dwarf_linker;23 24namespace dwarfutil {25 26// ObjFileAddressMap allows to check whether specified DIE referencing27// dead addresses. It uses tombstone values to determine dead addresses.28// The concrete values of tombstone constants were discussed in29// https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.30// So we use following values as indicators of dead addresses:31//32// bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less))33// or ([LowPC, HighPC] is not inside address ranges of .text sections).34//35// maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less))36// That value is assumed to be compatible with37// http://www.dwarfstd.org/ShowIssue.php?issue=200609.138//39// exec: [LowPC, HighPC] is not inside address ranges of .text sections40//41// universal: maxpc and bfd42class ObjFileAddressMap : public AddressesMap {43public:44 ObjFileAddressMap(DWARFContext &Context, const Options &Options,45 object::ObjectFile &ObjFile)46 : Opts(Options) {47 // Remember addresses of existing text sections.48 for (const object::SectionRef &Sect : ObjFile.sections()) {49 if (!Sect.isText())50 continue;51 const uint64_t Size = Sect.getSize();52 if (Size == 0)53 continue;54 const uint64_t StartAddr = Sect.getAddress();55 TextAddressRanges.insert({StartAddr, StartAddr + Size});56 }57 58 // Check CU address ranges for tombstone value.59 for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) {60 Expected<llvm::DWARFAddressRangesVector> ARanges =61 CU->getUnitDIE().getAddressRanges();62 if (!ARanges) {63 llvm::consumeError(ARanges.takeError());64 continue;65 }66 67 for (auto &Range : *ARanges) {68 if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),69 Options.Tombstone, CU->getAddressByteSize())) {70 HasValidAddressRanges = true;71 break;72 }73 }74 75 if (HasValidAddressRanges)76 break;77 }78 }79 80 // should be renamed into has valid address ranges81 bool hasValidRelocs() override { return HasValidAddressRanges; }82 83 std::optional<int64_t> getSubprogramRelocAdjustment(const DWARFDie &DIE,84 bool Verbose) override {85 assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||86 DIE.getTag() == dwarf::DW_TAG_label) &&87 "Wrong type of input die");88 89 if (std::optional<uint64_t> LowPC =90 dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {91 if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),92 Opts.Tombstone,93 DIE.getDwarfUnit()->getAddressByteSize()))94 // Relocation value for the linked binary is 0.95 return 0;96 }97 98 return std::nullopt;99 }100 101 std::optional<int64_t>102 getExprOpAddressRelocAdjustment(DWARFUnit &U,103 const DWARFExpression::Operation &Op,104 uint64_t, uint64_t, bool Verbose) override {105 switch (Op.getCode()) {106 default: {107 assert(false && "Specified operation does not have address operand");108 } break;109 case dwarf::DW_OP_const2u:110 case dwarf::DW_OP_const4u:111 case dwarf::DW_OP_const8u:112 case dwarf::DW_OP_const2s:113 case dwarf::DW_OP_const4s:114 case dwarf::DW_OP_const8s:115 case dwarf::DW_OP_addr: {116 if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone,117 U.getAddressByteSize()))118 // Relocation value for the linked binary is 0.119 return 0;120 } break;121 case dwarf::DW_OP_constx:122 case dwarf::DW_OP_addrx: {123 if (std::optional<object::SectionedAddress> Address =124 U.getAddrOffsetSectionItem(Op.getRawOperand(0))) {125 if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone,126 U.getAddressByteSize()))127 // Relocation value for the linked binary is 0.128 return 0;129 }130 } break;131 }132 133 return std::nullopt;134 }135 136 std::optional<StringRef> getLibraryInstallName() override {137 return std::nullopt;138 }139 140 bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {141 // no need to apply relocations to the linked binary.142 return false;143 }144 145 bool needToSaveValidRelocs() override { return false; }146 147 void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,148 uint64_t) override {}149 150 void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,151 uint64_t OutputUnitOffset) override {}152 153 void clear() override {}154 155protected:156 // returns true if specified address range is inside address ranges157 // of executable sections.158 bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,159 std::optional<uint64_t> HighPC) {160 std::optional<AddressRange> Range =161 TextAddressRanges.getRangeThatContains(LowPC);162 163 if (HighPC)164 return Range.has_value() && Range->end() >= *HighPC;165 166 return Range.has_value();167 }168 169 uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,170 uint16_t Version) {171 if (LowPC == 0)172 return true;173 174 if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))175 return true;176 177 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);178 }179 180 uint64_t isMAXPCDeadAddressRange(uint64_t LowPC,181 std::optional<uint64_t> HighPC,182 uint16_t Version, uint8_t AddressByteSize) {183 if (Version <= 4 && HighPC) {184 if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))185 return true;186 } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))187 return true;188 189 if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))190 warning("Address referencing invalid text section is not marked with "191 "tombstone value");192 193 return false;194 }195 196 bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,197 uint16_t Version, TombstoneKind Tombstone,198 uint8_t AddressByteSize) {199 switch (Tombstone) {200 case TombstoneKind::BFD:201 return isBFDDeadAddressRange(LowPC, HighPC, Version);202 case TombstoneKind::MaxPC:203 return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);204 case TombstoneKind::Universal:205 return isBFDDeadAddressRange(LowPC, HighPC, Version) ||206 isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);207 case TombstoneKind::Exec:208 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);209 }210 211 llvm_unreachable("Unknown tombstone value");212 }213 214 bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,215 uint8_t AddressByteSize) {216 return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone,217 AddressByteSize);218 }219 220private:221 AddressRanges TextAddressRanges;222 const Options &Opts;223 bool HasValidAddressRanges = false;224};225 226static bool knownByDWARFUtil(StringRef SecName) {227 return llvm::StringSwitch<bool>(SecName)228 .Case(".debug_info", true)229 .Case(".debug_types", true)230 .Case(".debug_abbrev", true)231 .Case(".debug_loc", true)232 .Case(".debug_loclists", true)233 .Case(".debug_frame", true)234 .Case(".debug_aranges", true)235 .Case(".debug_ranges", true)236 .Case(".debug_rnglists", true)237 .Case(".debug_line", true)238 .Case(".debug_line_str", true)239 .Case(".debug_addr", true)240 .Case(".debug_macro", true)241 .Case(".debug_macinfo", true)242 .Case(".debug_str", true)243 .Case(".debug_str_offsets", true)244 .Case(".debug_pubnames", true)245 .Case(".debug_pubtypes", true)246 .Case(".debug_names", true)247 .Default(false);248}249 250template <typename AccelTableKind>251static std::optional<AccelTableKind>252getAcceleratorTableKind(StringRef SecName) {253 return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)254 .Case(".debug_pubnames", AccelTableKind::Pub)255 .Case(".debug_pubtypes", AccelTableKind::Pub)256 .Case(".debug_names", AccelTableKind::DebugNames)257 .Default(std::nullopt);258}259 260static std::string getMessageForReplacedAcceleratorTables(261 SmallVector<StringRef> &AccelTableNamesToReplace,262 DwarfUtilAccelKind TargetTable) {263 std::string Message;264 265 Message += "'";266 for (StringRef Name : AccelTableNamesToReplace) {267 if (Message.size() > 1)268 Message += ", ";269 Message += Name;270 }271 272 Message += "' will be replaced with requested ";273 274 switch (TargetTable) {275 case DwarfUtilAccelKind::DWARF:276 Message += ".debug_names table";277 break;278 279 default:280 assert(false);281 }282 283 return Message;284}285 286static std::string getMessageForDeletedAcceleratorTables(287 SmallVector<StringRef> &AccelTableNamesToReplace) {288 std::string Message;289 290 Message += "'";291 for (StringRef Name : AccelTableNamesToReplace) {292 if (Message.size() > 1)293 Message += ", ";294 Message += Name;295 }296 297 Message += "' will be deleted as no accelerator tables are requested";298 299 return Message;300}301 302template <typename Linker>303Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,304 raw_pwrite_stream &OutStream) {305 std::mutex ErrorHandlerMutex;306 307 auto ReportWarn = [&](const Twine &Message, StringRef Context,308 const DWARFDie *Die) {309 // FIXME: implement warning logging which does not block other threads.310 if (!ErrorHandlerMutex.try_lock())311 return;312 313 warning(Message, Context);314 if (Options.Verbose && Die) {315 DIDumpOptions DumpOpts;316 DumpOpts.ChildRecurseDepth = 0;317 DumpOpts.Verbose = Options.Verbose;318 319 WithColor::note() << " in DIE:\n";320 Die->dump(errs(), /*Indent=*/6, DumpOpts);321 }322 ErrorHandlerMutex.unlock();323 };324 auto ReportErr = [&](const Twine &Message, StringRef Context,325 const DWARFDie *) {326 // FIXME: implement error logging which does not block other threads.327 if (!ErrorHandlerMutex.try_lock())328 return;329 330 WithColor::error(errs(), Context) << Message << '\n';331 ErrorHandlerMutex.unlock();332 };333 334 // Create DWARF linker.335 std::unique_ptr<Linker> DebugInfoLinker =336 Linker::createLinker(ReportErr, ReportWarn);337 338 Triple TargetTriple = File.makeTriple();339 std::unique_ptr<classic::DwarfStreamer> Streamer;340 if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =341 classic::DwarfStreamer::createStreamer(TargetTriple,342 Linker::OutputFileType::Object,343 OutStream, ReportWarn))344 Streamer = std::move(*StreamerOrErr);345 else346 return StreamerOrErr.takeError();347 348 if constexpr (std::is_same<Linker,349 dwarf_linker::parallel::DWARFLinker>::value) {350 DebugInfoLinker->setOutputDWARFHandler(351 TargetTriple,352 [&](std::shared_ptr<dwarf_linker::parallel::SectionDescriptorBase>353 Section) {354 Streamer->emitSectionContents(Section->getContents(),355 Section->getKind());356 });357 } else358 DebugInfoLinker->setOutputDWARFEmitter(Streamer.get());359 360 DebugInfoLinker->setEstimatedObjfilesAmount(1);361 DebugInfoLinker->setNumThreads(Options.NumThreads);362 DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);363 DebugInfoLinker->setVerbosity(Options.Verbose);364 DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);365 366 std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);367 368 // Add object files to the DWARFLinker.369 std::unique_ptr<DWARFContext> Context = DWARFContext::create(370 File, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",371 [&](Error Err) {372 handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {373 ReportErr(Info.message(), "", nullptr);374 });375 },376 [&](Error Warning) {377 handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {378 ReportWarn(Info.message(), "", nullptr);379 });380 });381 std::unique_ptr<ObjFileAddressMap> AddressesMap(382 std::make_unique<ObjFileAddressMap>(*Context, Options, File));383 384 ObjectsForLinking[0] = std::make_unique<DWARFFile>(385 File.getFileName(), std::move(Context), std::move(AddressesMap));386 387 uint16_t MaxDWARFVersion = 0;388 std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =389 [&MaxDWARFVersion](const DWARFUnit &Unit) {390 MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);391 };392 393 for (size_t I = 0; I < ObjectsForLinking.size(); I++)394 DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,395 OnCUDieLoaded);396 397 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.398 if (MaxDWARFVersion == 0)399 MaxDWARFVersion = 3;400 401 if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))402 return Err;403 404 SmallVector<typename Linker::AccelTableKind> AccelTables;405 406 switch (Options.AccelTableKind) {407 case DwarfUtilAccelKind::None:408 // Nothing to do.409 break;410 case DwarfUtilAccelKind::DWARF:411 // use .debug_names for all DWARF versions.412 AccelTables.push_back(Linker::AccelTableKind::DebugNames);413 break;414 }415 416 // Add accelerator tables to DWARFLinker.417 for (typename Linker::AccelTableKind Table : AccelTables)418 DebugInfoLinker->addAccelTableKind(Table);419 420 for (std::unique_ptr<DWARFFile> &CurFile : ObjectsForLinking) {421 SmallVector<StringRef> AccelTableNamesToReplace;422 SmallVector<StringRef> AccelTableNamesToDelete;423 424 // Unknown debug sections or non-requested accelerator sections would be425 // removed. Display warning for such sections.426 for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) {427 if (isDebugSection(Sec.Name)) {428 std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =429 getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);430 431 if (SrcAccelTableKind) {432 assert(knownByDWARFUtil(Sec.Name));433 434 if (Options.AccelTableKind == DwarfUtilAccelKind::None)435 AccelTableNamesToDelete.push_back(Sec.Name);436 else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind))437 AccelTableNamesToReplace.push_back(Sec.Name);438 } else if (!knownByDWARFUtil(Sec.Name)) {439 assert(!SrcAccelTableKind);440 warning(441 formatv(442 "'{0}' is not currently supported: section will be skipped",443 Sec.Name),444 Options.InputFileName);445 }446 }447 }448 449 // Display message for the replaced accelerator tables.450 if (!AccelTableNamesToReplace.empty())451 warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,452 Options.AccelTableKind),453 Options.InputFileName);454 455 // Display message for the removed accelerator tables.456 if (!AccelTableNamesToDelete.empty())457 warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),458 Options.InputFileName);459 }460 461 // Link debug info.462 if (Error Err = DebugInfoLinker->link())463 return Err;464 465 Streamer->finish();466 return Error::success();467}468 469Error linkDebugInfo(object::ObjectFile &File, const Options &Options,470 raw_pwrite_stream &OutStream) {471 if (Options.UseDWARFLinkerParallel)472 return linkDebugInfoImpl<parallel::DWARFLinker>(File, Options, OutStream);473 else474 return linkDebugInfoImpl<classic::DWARFLinker>(File, Options, OutStream);475}476 477} // end of namespace dwarfutil478} // end of namespace llvm479