aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp')
-rw-r--r--llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp185
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())