diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) |
Diffstat (limited to 'llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp')
-rw-r--r-- | llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp | 185 |
1 files changed, 160 insertions, 25 deletions
diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp index 3e70f460bc58..ef222f8cc1a4 100644 --- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp +++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Endian.h" #include <memory> #include <vector> @@ -40,7 +41,7 @@ class ObjFileAddressMap : public AddressesMap { public: ObjFileAddressMap(DWARFContext &Context, const Options &Options, object::ObjectFile &ObjFile) - : Opts(Options) { + : Opts(Options), Context(Context) { // Remember addresses of existing text sections. for (const object::SectionRef &Sect : ObjFile.sections()) { if (!Sect.isText()) @@ -75,7 +76,7 @@ public: DIE.getTag() == dwarf::DW_TAG_label) && "Wrong type of input die"); - if (Optional<uint64_t> LowPC = + if (std::optional<uint64_t> LowPC = dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) { if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(), Opts.Tombstone, @@ -137,17 +138,36 @@ public: void clear() override { DWARFAddressRanges.clear(); } - llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t, uint64_t) override { - // should not be called. - return object::createError("no relocations in linked binary"); + llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t StartOffset, + uint64_t EndOffset) override { + // No relocations in linked binary. Return just address value. + + const char *AddrPtr = + Context.getDWARFObj().getAddrSection().Data.data() + StartOffset; + support::endianness Endianess = + Context.getDWARFObj().isLittleEndian() ? support::little : support::big; + + assert(EndOffset > StartOffset); + switch (EndOffset - StartOffset) { + case 1: + return *AddrPtr; + case 2: + return support::endian::read16(AddrPtr, Endianess); + case 4: + return support::endian::read32(AddrPtr, Endianess); + case 8: + return support::endian::read64(AddrPtr, Endianess); + } + + llvm_unreachable("relocateIndexedAddr unhandled case!"); } protected: // returns true if specified address range is inside address ranges // of executable sections. bool isInsideExecutableSectionsAddressRange(uint64_t LowPC, - Optional<uint64_t> HighPC) { - Optional<AddressRange> Range = + std::optional<uint64_t> HighPC) { + std::optional<AddressRange> Range = TextAddressRanges.getRangeThatContains(LowPC); if (HighPC) @@ -156,7 +176,7 @@ protected: return Range.has_value(); } - uint64_t isBFDDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, + uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC, uint16_t Version) { if (LowPC == 0) return true; @@ -167,7 +187,8 @@ protected: return !isInsideExecutableSectionsAddressRange(LowPC, HighPC); } - uint64_t isMAXPCDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, + uint64_t isMAXPCDeadAddressRange(uint64_t LowPC, + std::optional<uint64_t> HighPC, uint16_t Version, uint8_t AddressByteSize) { if (Version <= 4 && HighPC) { if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1)) @@ -182,7 +203,7 @@ protected: return false; } - bool isDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC, + bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC, uint16_t Version, TombstoneKind Tombstone, uint8_t AddressByteSize) { switch (Tombstone) { @@ -202,13 +223,15 @@ protected: bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone, uint8_t AddressByteSize) { - return isDeadAddressRange(LowPC, None, Version, Tombstone, AddressByteSize); + return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone, + AddressByteSize); } private: RangesTy DWARFAddressRanges; AddressRanges TextAddressRanges; const Options &Opts; + DWARFContext &Context; }; static bool knownByDWARFUtil(StringRef SecName) { @@ -229,9 +252,63 @@ static bool knownByDWARFUtil(StringRef SecName) { .Case(".debug_macinfo", true) .Case(".debug_str", true) .Case(".debug_str_offsets", true) + .Case(".debug_pubnames", true) + .Case(".debug_pubtypes", true) + .Case(".debug_names", true) .Default(false); } +static std::optional<DwarfLinkerAccelTableKind> +getAcceleratorTableKind(StringRef SecName) { + return llvm::StringSwitch<std::optional<DwarfLinkerAccelTableKind>>(SecName) + .Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub) + .Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub) + .Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames) + .Default(std::nullopt); +} + +static std::string getMessageForReplacedAcceleratorTables( + SmallVector<StringRef> &AccelTableNamesToReplace, + DwarfUtilAccelKind TargetTable) { + std::string Message; + + Message += "'"; + for (StringRef Name : AccelTableNamesToReplace) { + if (Message.size() > 1) + Message += ", "; + Message += Name; + } + + Message += "' will be replaced with requested "; + + switch (TargetTable) { + case DwarfUtilAccelKind::DWARF: + Message += ".debug_names table"; + break; + + default: + assert(false); + } + + return Message; +} + +static std::string getMessageForDeletedAcceleratorTables( + SmallVector<StringRef> &AccelTableNamesToReplace) { + std::string Message; + + Message += "'"; + for (StringRef Name : AccelTableNamesToReplace) { + if (Message.size() > 1) + Message += ", "; + Message += Name; + } + + Message += "' will be deleted as no accelerator tables are requested"; + + return Message; +} + Error linkDebugInfo(object::ObjectFile &File, const Options &Options, raw_pwrite_stream &OutStream) { @@ -263,11 +340,12 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options, .str())) return createStringError(std::errc::invalid_argument, ""); + std::unique_ptr<DWARFContext> Context = DWARFContext::create(File); + // Create DWARF linker. DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD); DebugInfoLinker.setEstimatedObjfilesAmount(1); - DebugInfoLinker.setAccelTableKind(DwarfLinkerAccelTableKind::None); DebugInfoLinker.setErrorHandler(ReportErr); DebugInfoLinker.setWarningHandler(ReportWarn); DebugInfoLinker.setNumThreads(Options.NumThreads); @@ -279,18 +357,6 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options, std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1); std::vector<std::string> EmptyWarnings; - std::unique_ptr<DWARFContext> Context = DWARFContext::create(File); - - // Unknown debug sections would be removed. Display warning - // for such sections. - for (SectionName Sec : Context->getDWARFObj().getSectionNames()) { - if (isDebugSection(Sec.Name) && !knownByDWARFUtil(Sec.Name)) - warning( - formatv("'{0}' is not currently supported: section will be skipped", - Sec.Name), - Options.InputFileName); - } - // Add object files to the DWARFLinker. AddresssMapForLinking[0] = std::make_unique<ObjFileAddressMap>(*Context, Options, File); @@ -299,8 +365,77 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options, File.getFileName(), &*Context, AddresssMapForLinking[0].get(), EmptyWarnings); + uint16_t MaxDWARFVersion = 0; + std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded = + [&MaxDWARFVersion](const DWARFUnit &Unit) { + MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion); + }; + for (size_t I = 0; I < ObjectsForLinking.size(); I++) - DebugInfoLinker.addObjectFile(*ObjectsForLinking[I]); + DebugInfoLinker.addObjectFile(*ObjectsForLinking[I], nullptr, + OnCUDieLoaded); + + // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway. + if (MaxDWARFVersion == 0) + MaxDWARFVersion = 3; + + if (Error Err = DebugInfoLinker.setTargetDWARFVersion(MaxDWARFVersion)) + return Err; + + SmallVector<DwarfLinkerAccelTableKind> AccelTables; + + switch (Options.AccelTableKind) { + case DwarfUtilAccelKind::None: + // Nothing to do. + break; + case DwarfUtilAccelKind::DWARF: + // use .debug_names for all DWARF versions. + AccelTables.push_back(DwarfLinkerAccelTableKind::DebugNames); + break; + } + + // Add accelerator tables to DWARFLinker. + for (DwarfLinkerAccelTableKind Table : AccelTables) + DebugInfoLinker.addAccelTableKind(Table); + + SmallVector<StringRef> AccelTableNamesToReplace; + SmallVector<StringRef> AccelTableNamesToDelete; + + // Unknown debug sections or non-requested accelerator sections would be + // removed. Display warning for such sections. + for (SectionName Sec : Context->getDWARFObj().getSectionNames()) { + if (isDebugSection(Sec.Name)) { + std::optional<DwarfLinkerAccelTableKind> SrcAccelTableKind = + getAcceleratorTableKind(Sec.Name); + + if (SrcAccelTableKind) { + assert(knownByDWARFUtil(Sec.Name)); + + if (Options.AccelTableKind == DwarfUtilAccelKind::None) + AccelTableNamesToDelete.push_back(Sec.Name); + else if (std::find(AccelTables.begin(), AccelTables.end(), + *SrcAccelTableKind) == AccelTables.end()) + AccelTableNamesToReplace.push_back(Sec.Name); + } else if (!knownByDWARFUtil(Sec.Name)) { + assert(!SrcAccelTableKind); + warning( + formatv("'{0}' is not currently supported: section will be skipped", + Sec.Name), + Options.InputFileName); + } + } + } + + // Display message for the replaced accelerator tables. + if (!AccelTableNamesToReplace.empty()) + warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace, + Options.AccelTableKind), + Options.InputFileName); + + // Display message for the removed accelerator tables. + if (!AccelTableNamesToDelete.empty()) + warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete), + Options.InputFileName); // Link debug info. if (Error Err = DebugInfoLinker.link()) |