2022-07-10 20:11:55 +03:00
|
|
|
//=== DebugInfoLinker.cpp -------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "DebugInfoLinker.h"
|
|
|
|
#include "Error.h"
|
2022-07-28 19:20:58 +03:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2024-01-09 11:32:08 +03:00
|
|
|
#include "llvm/DWARFLinker/Classic/DWARFLinker.h"
|
|
|
|
#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"
|
|
|
|
#include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
|
2022-07-10 20:11:55 +03:00
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
|
|
|
|
#include "llvm/Object/ObjectFile.h"
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace llvm {
|
2024-01-09 11:32:08 +03:00
|
|
|
using namespace dwarf_linker;
|
|
|
|
|
2022-07-10 20:11:55 +03:00
|
|
|
namespace dwarfutil {
|
|
|
|
|
|
|
|
// ObjFileAddressMap allows to check whether specified DIE referencing
|
|
|
|
// dead addresses. It uses tombstone values to determine dead addresses.
|
|
|
|
// The concrete values of tombstone constants were discussed in
|
|
|
|
// https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.
|
|
|
|
// So we use following values as indicators of dead addresses:
|
|
|
|
//
|
|
|
|
// bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less))
|
|
|
|
// or ([LowPC, HighPC] is not inside address ranges of .text sections).
|
|
|
|
//
|
|
|
|
// maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less))
|
|
|
|
// That value is assumed to be compatible with
|
|
|
|
// http://www.dwarfstd.org/ShowIssue.php?issue=200609.1
|
|
|
|
//
|
|
|
|
// exec: [LowPC, HighPC] is not inside address ranges of .text sections
|
|
|
|
//
|
|
|
|
// universal: maxpc and bfd
|
2024-01-09 11:32:08 +03:00
|
|
|
class ObjFileAddressMap : public AddressesMap {
|
2022-07-10 20:11:55 +03:00
|
|
|
public:
|
|
|
|
ObjFileAddressMap(DWARFContext &Context, const Options &Options,
|
|
|
|
object::ObjectFile &ObjFile)
|
2023-02-02 17:17:52 +01:00
|
|
|
: Opts(Options) {
|
2022-07-10 20:11:55 +03:00
|
|
|
// Remember addresses of existing text sections.
|
|
|
|
for (const object::SectionRef &Sect : ObjFile.sections()) {
|
|
|
|
if (!Sect.isText())
|
|
|
|
continue;
|
|
|
|
const uint64_t Size = Sect.getSize();
|
|
|
|
if (Size == 0)
|
|
|
|
continue;
|
|
|
|
const uint64_t StartAddr = Sect.getAddress();
|
2022-07-19 18:11:07 +03:00
|
|
|
TextAddressRanges.insert({StartAddr, StartAddr + Size});
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check CU address ranges for tombstone value.
|
|
|
|
for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) {
|
|
|
|
Expected<llvm::DWARFAddressRangesVector> ARanges =
|
|
|
|
CU->getUnitDIE().getAddressRanges();
|
2023-07-01 12:20:50 +02:00
|
|
|
if (!ARanges) {
|
|
|
|
llvm::consumeError(ARanges.takeError());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &Range : *ARanges) {
|
|
|
|
if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
|
|
|
|
Options.Tombstone, CU->getAddressByteSize())) {
|
|
|
|
HasValidAddressRanges = true;
|
|
|
|
break;
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
}
|
2023-07-01 12:20:50 +02:00
|
|
|
|
|
|
|
if (HasValidAddressRanges)
|
|
|
|
break;
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// should be renamed into has valid address ranges
|
2023-07-01 12:20:50 +02:00
|
|
|
bool hasValidRelocs() override { return HasValidAddressRanges; }
|
2022-07-10 20:11:55 +03:00
|
|
|
|
2024-01-23 13:00:49 +03:00
|
|
|
std::optional<int64_t> getSubprogramRelocAdjustment(const DWARFDie &DIE,
|
|
|
|
bool Verbose) override {
|
2022-07-10 20:11:55 +03:00
|
|
|
assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||
|
|
|
|
DIE.getTag() == dwarf::DW_TAG_label) &&
|
|
|
|
"Wrong type of input die");
|
|
|
|
|
2022-12-05 00:09:22 +00:00
|
|
|
if (std::optional<uint64_t> LowPC =
|
2022-07-10 20:11:55 +03:00
|
|
|
dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {
|
|
|
|
if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),
|
|
|
|
Opts.Tombstone,
|
2023-03-31 17:10:11 +02:00
|
|
|
DIE.getDwarfUnit()->getAddressByteSize()))
|
|
|
|
// Relocation value for the linked binary is 0.
|
|
|
|
return 0;
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
|
2023-03-31 17:10:11 +02:00
|
|
|
return std::nullopt;
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
|
2023-05-20 11:47:34 +02:00
|
|
|
std::optional<int64_t>
|
|
|
|
getExprOpAddressRelocAdjustment(DWARFUnit &U,
|
|
|
|
const DWARFExpression::Operation &Op,
|
2024-01-23 13:00:49 +03:00
|
|
|
uint64_t, uint64_t, bool Verbose) override {
|
2023-03-21 18:55:57 +01:00
|
|
|
switch (Op.getCode()) {
|
|
|
|
default: {
|
|
|
|
assert(false && "Specified operation does not have address operand");
|
|
|
|
} break;
|
2023-05-20 11:47:34 +02:00
|
|
|
case dwarf::DW_OP_const2u:
|
2023-03-21 18:55:57 +01:00
|
|
|
case dwarf::DW_OP_const4u:
|
|
|
|
case dwarf::DW_OP_const8u:
|
2023-05-20 11:47:34 +02:00
|
|
|
case dwarf::DW_OP_const2s:
|
2023-03-21 18:55:57 +01:00
|
|
|
case dwarf::DW_OP_const4s:
|
|
|
|
case dwarf::DW_OP_const8s:
|
|
|
|
case dwarf::DW_OP_addr: {
|
|
|
|
if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone,
|
|
|
|
U.getAddressByteSize()))
|
|
|
|
// Relocation value for the linked binary is 0.
|
|
|
|
return 0;
|
|
|
|
} break;
|
|
|
|
case dwarf::DW_OP_constx:
|
|
|
|
case dwarf::DW_OP_addrx: {
|
|
|
|
if (std::optional<object::SectionedAddress> Address =
|
|
|
|
U.getAddrOffsetSectionItem(Op.getRawOperand(0))) {
|
|
|
|
if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone,
|
|
|
|
U.getAddressByteSize()))
|
2023-03-31 17:10:11 +02:00
|
|
|
// Relocation value for the linked binary is 0.
|
|
|
|
return 0;
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
2023-03-21 18:55:57 +01:00
|
|
|
} break;
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
|
2023-03-31 17:10:11 +02:00
|
|
|
return std::nullopt;
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
|
2023-10-26 10:45:08 -07:00
|
|
|
std::optional<StringRef> getLibraryInstallName() override {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2022-07-10 20:11:55 +03:00
|
|
|
bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
|
|
|
|
// no need to apply relocations to the linked binary.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-10-26 10:45:08 -07:00
|
|
|
bool needToSaveValidRelocs() override { return false; }
|
|
|
|
|
|
|
|
void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,
|
|
|
|
uint64_t) override {}
|
|
|
|
|
|
|
|
void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
|
|
|
|
uint64_t OutputUnitOffset) override {}
|
|
|
|
|
2023-07-01 12:20:50 +02:00
|
|
|
void clear() override {}
|
2022-07-10 20:11:55 +03:00
|
|
|
|
|
|
|
protected:
|
|
|
|
// returns true if specified address range is inside address ranges
|
|
|
|
// of executable sections.
|
|
|
|
bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
|
2022-12-14 08:01:04 +00:00
|
|
|
std::optional<uint64_t> HighPC) {
|
2022-12-13 10:14:09 +00:00
|
|
|
std::optional<AddressRange> Range =
|
2022-07-19 18:11:07 +03:00
|
|
|
TextAddressRanges.getRangeThatContains(LowPC);
|
2022-07-19 18:11:07 +03:00
|
|
|
|
2022-07-19 18:11:07 +03:00
|
|
|
if (HighPC)
|
2022-07-22 23:04:38 -07:00
|
|
|
return Range.has_value() && Range->end() >= *HighPC;
|
2022-07-19 18:11:07 +03:00
|
|
|
|
2022-07-22 23:04:38 -07:00
|
|
|
return Range.has_value();
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
|
2022-12-14 08:01:04 +00:00
|
|
|
uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
|
2022-07-10 20:11:55 +03:00
|
|
|
uint16_t Version) {
|
|
|
|
if (LowPC == 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
|
|
|
|
}
|
|
|
|
|
2022-12-14 08:01:04 +00:00
|
|
|
uint64_t isMAXPCDeadAddressRange(uint64_t LowPC,
|
|
|
|
std::optional<uint64_t> HighPC,
|
2022-07-10 20:11:55 +03:00
|
|
|
uint16_t Version, uint8_t AddressByteSize) {
|
|
|
|
if (Version <= 4 && HighPC) {
|
|
|
|
if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))
|
|
|
|
return true;
|
|
|
|
} else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
|
|
|
|
warning("Address referencing invalid text section is not marked with "
|
|
|
|
"tombstone value");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-12-14 08:01:04 +00:00
|
|
|
bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
|
2022-07-10 20:11:55 +03:00
|
|
|
uint16_t Version, TombstoneKind Tombstone,
|
|
|
|
uint8_t AddressByteSize) {
|
|
|
|
switch (Tombstone) {
|
|
|
|
case TombstoneKind::BFD:
|
|
|
|
return isBFDDeadAddressRange(LowPC, HighPC, Version);
|
|
|
|
case TombstoneKind::MaxPC:
|
|
|
|
return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
|
|
|
|
case TombstoneKind::Universal:
|
|
|
|
return isBFDDeadAddressRange(LowPC, HighPC, Version) ||
|
|
|
|
isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
|
|
|
|
case TombstoneKind::Exec:
|
|
|
|
return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Unknown tombstone value");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
|
|
|
|
uint8_t AddressByteSize) {
|
2022-12-02 21:11:40 -08:00
|
|
|
return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone,
|
|
|
|
AddressByteSize);
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-07-19 18:11:07 +03:00
|
|
|
AddressRanges TextAddressRanges;
|
2022-07-10 20:11:55 +03:00
|
|
|
const Options &Opts;
|
2023-07-01 12:20:50 +02:00
|
|
|
bool HasValidAddressRanges = false;
|
2022-07-10 20:11:55 +03:00
|
|
|
};
|
|
|
|
|
2022-07-28 19:20:58 +03:00
|
|
|
static bool knownByDWARFUtil(StringRef SecName) {
|
|
|
|
return llvm::StringSwitch<bool>(SecName)
|
|
|
|
.Case(".debug_info", true)
|
|
|
|
.Case(".debug_types", true)
|
|
|
|
.Case(".debug_abbrev", true)
|
|
|
|
.Case(".debug_loc", true)
|
|
|
|
.Case(".debug_loclists", true)
|
|
|
|
.Case(".debug_frame", true)
|
|
|
|
.Case(".debug_aranges", true)
|
|
|
|
.Case(".debug_ranges", true)
|
|
|
|
.Case(".debug_rnglists", true)
|
|
|
|
.Case(".debug_line", true)
|
|
|
|
.Case(".debug_line_str", true)
|
|
|
|
.Case(".debug_addr", true)
|
|
|
|
.Case(".debug_macro", true)
|
|
|
|
.Case(".debug_macinfo", true)
|
|
|
|
.Case(".debug_str", true)
|
|
|
|
.Case(".debug_str_offsets", true)
|
2023-01-15 22:31:35 +01:00
|
|
|
.Case(".debug_pubnames", true)
|
|
|
|
.Case(".debug_pubtypes", true)
|
|
|
|
.Case(".debug_names", true)
|
2022-07-28 19:20:58 +03:00
|
|
|
.Default(false);
|
|
|
|
}
|
|
|
|
|
2023-04-01 00:12:29 +02:00
|
|
|
template <typename AccelTableKind>
|
|
|
|
static std::optional<AccelTableKind>
|
2023-01-15 22:31:35 +01:00
|
|
|
getAcceleratorTableKind(StringRef SecName) {
|
2023-04-01 00:12:29 +02:00
|
|
|
return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)
|
|
|
|
.Case(".debug_pubnames", AccelTableKind::Pub)
|
|
|
|
.Case(".debug_pubtypes", AccelTableKind::Pub)
|
|
|
|
.Case(".debug_names", AccelTableKind::DebugNames)
|
2023-01-15 22:31:35 +01:00
|
|
|
.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;
|
|
|
|
}
|
|
|
|
|
2024-01-09 11:32:08 +03:00
|
|
|
template <typename Linker>
|
2023-04-01 00:12:29 +02:00
|
|
|
Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
|
|
|
|
raw_pwrite_stream &OutStream) {
|
2023-05-20 11:47:34 +02:00
|
|
|
std::mutex ErrorHandlerMutex;
|
|
|
|
|
2022-07-10 20:11:55 +03:00
|
|
|
auto ReportWarn = [&](const Twine &Message, StringRef Context,
|
|
|
|
const DWARFDie *Die) {
|
2023-05-20 11:47:34 +02:00
|
|
|
// FIXME: implement warning logging which does not block other threads.
|
|
|
|
if (!ErrorHandlerMutex.try_lock())
|
2022-07-10 20:11:55 +03:00
|
|
|
return;
|
|
|
|
|
2023-05-20 11:47:34 +02:00
|
|
|
warning(Message, Context);
|
|
|
|
if (Options.Verbose && Die) {
|
|
|
|
DIDumpOptions DumpOpts;
|
|
|
|
DumpOpts.ChildRecurseDepth = 0;
|
|
|
|
DumpOpts.Verbose = Options.Verbose;
|
2022-07-10 20:11:55 +03:00
|
|
|
|
2023-05-20 11:47:34 +02:00
|
|
|
WithColor::note() << " in DIE:\n";
|
|
|
|
Die->dump(errs(), /*Indent=*/6, DumpOpts);
|
|
|
|
}
|
|
|
|
ErrorHandlerMutex.unlock();
|
2022-07-10 20:11:55 +03:00
|
|
|
};
|
|
|
|
auto ReportErr = [&](const Twine &Message, StringRef Context,
|
|
|
|
const DWARFDie *) {
|
2023-05-20 11:47:34 +02:00
|
|
|
// FIXME: implement error logging which does not block other threads.
|
|
|
|
if (!ErrorHandlerMutex.try_lock())
|
|
|
|
return;
|
|
|
|
|
2022-07-10 20:11:55 +03:00
|
|
|
WithColor::error(errs(), Context) << Message << '\n';
|
2023-05-20 11:47:34 +02:00
|
|
|
ErrorHandlerMutex.unlock();
|
2022-07-10 20:11:55 +03:00
|
|
|
};
|
|
|
|
|
2023-04-01 00:12:29 +02:00
|
|
|
// Create DWARF linker.
|
|
|
|
std::unique_ptr<Linker> DebugInfoLinker =
|
|
|
|
Linker::createLinker(ReportErr, ReportWarn);
|
|
|
|
|
2022-07-28 19:20:58 +03:00
|
|
|
Triple TargetTriple = File.makeTriple();
|
2024-01-19 16:57:09 +03:00
|
|
|
std::unique_ptr<classic::DwarfStreamer> Streamer;
|
|
|
|
if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =
|
2024-03-19 08:30:47 -07:00
|
|
|
classic::DwarfStreamer::createStreamer(TargetTriple,
|
|
|
|
Linker::OutputFileType::Object,
|
|
|
|
OutStream, ReportWarn))
|
2024-01-19 16:57:09 +03:00
|
|
|
Streamer = std::move(*StreamerOrErr);
|
|
|
|
else
|
|
|
|
return StreamerOrErr.takeError();
|
|
|
|
|
|
|
|
if constexpr (std::is_same<Linker,
|
|
|
|
dwarf_linker::parallel::DWARFLinker>::value) {
|
|
|
|
DebugInfoLinker->setOutputDWARFHandler(
|
|
|
|
TargetTriple,
|
|
|
|
[&](std::shared_ptr<dwarf_linker::parallel::SectionDescriptorBase>
|
|
|
|
Section) {
|
|
|
|
Streamer->emitSectionContents(Section->getContents(),
|
|
|
|
Section->getKind());
|
|
|
|
});
|
|
|
|
} else
|
|
|
|
DebugInfoLinker->setOutputDWARFEmitter(Streamer.get());
|
2022-07-10 20:11:55 +03:00
|
|
|
|
2023-04-01 00:12:29 +02:00
|
|
|
DebugInfoLinker->setEstimatedObjfilesAmount(1);
|
|
|
|
DebugInfoLinker->setNumThreads(Options.NumThreads);
|
|
|
|
DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);
|
|
|
|
DebugInfoLinker->setVerbosity(Options.Verbose);
|
|
|
|
DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
|
2022-09-04 12:38:36 +03:00
|
|
|
|
2024-01-09 11:32:08 +03:00
|
|
|
std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
|
2022-07-10 20:11:55 +03:00
|
|
|
|
|
|
|
// Add object files to the DWARFLinker.
|
2023-05-20 11:47:34 +02:00
|
|
|
std::unique_ptr<DWARFContext> Context = DWARFContext::create(
|
|
|
|
File, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
|
|
|
|
[&](Error Err) {
|
|
|
|
handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
|
|
|
|
ReportErr(Info.message(), "", nullptr);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
[&](Error Warning) {
|
|
|
|
handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
|
|
|
|
ReportWarn(Info.message(), "", nullptr);
|
|
|
|
});
|
|
|
|
});
|
2024-01-09 11:32:08 +03:00
|
|
|
std::unique_ptr<ObjFileAddressMap> AddressesMap(
|
|
|
|
std::make_unique<ObjFileAddressMap>(*Context, Options, File));
|
2022-07-10 20:11:55 +03:00
|
|
|
|
2024-01-09 11:32:08 +03:00
|
|
|
ObjectsForLinking[0] = std::make_unique<DWARFFile>(
|
2023-09-22 11:27:33 -07:00
|
|
|
File.getFileName(), std::move(Context), std::move(AddressesMap));
|
2022-07-10 20:11:55 +03:00
|
|
|
|
2023-01-15 22:31:35 +01:00
|
|
|
uint16_t MaxDWARFVersion = 0;
|
|
|
|
std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
|
|
|
|
[&MaxDWARFVersion](const DWARFUnit &Unit) {
|
|
|
|
MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
|
|
|
|
};
|
|
|
|
|
2022-07-10 20:11:55 +03:00
|
|
|
for (size_t I = 0; I < ObjectsForLinking.size(); I++)
|
2023-04-01 00:12:29 +02:00
|
|
|
DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,
|
|
|
|
OnCUDieLoaded);
|
2022-09-04 12:38:36 +03:00
|
|
|
|
|
|
|
// If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
|
|
|
|
if (MaxDWARFVersion == 0)
|
|
|
|
MaxDWARFVersion = 3;
|
|
|
|
|
2023-04-01 00:12:29 +02:00
|
|
|
if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))
|
2022-09-04 12:38:36 +03:00
|
|
|
return Err;
|
2022-07-10 20:11:55 +03:00
|
|
|
|
2023-04-01 00:12:29 +02:00
|
|
|
SmallVector<typename Linker::AccelTableKind> AccelTables;
|
2023-01-15 22:31:35 +01:00
|
|
|
|
|
|
|
switch (Options.AccelTableKind) {
|
|
|
|
case DwarfUtilAccelKind::None:
|
|
|
|
// Nothing to do.
|
|
|
|
break;
|
|
|
|
case DwarfUtilAccelKind::DWARF:
|
|
|
|
// use .debug_names for all DWARF versions.
|
2023-04-01 00:12:29 +02:00
|
|
|
AccelTables.push_back(Linker::AccelTableKind::DebugNames);
|
2023-01-15 22:31:35 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add accelerator tables to DWARFLinker.
|
2023-04-01 00:12:29 +02:00
|
|
|
for (typename Linker::AccelTableKind Table : AccelTables)
|
|
|
|
DebugInfoLinker->addAccelTableKind(Table);
|
|
|
|
|
2024-01-09 11:32:08 +03:00
|
|
|
for (std::unique_ptr<DWARFFile> &CurFile : ObjectsForLinking) {
|
2023-04-01 00:12:29 +02:00
|
|
|
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 : CurFile->Dwarf->getDWARFObj().getSectionNames()) {
|
|
|
|
if (isDebugSection(Sec.Name)) {
|
|
|
|
std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =
|
|
|
|
getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);
|
|
|
|
|
|
|
|
if (SrcAccelTableKind) {
|
|
|
|
assert(knownByDWARFUtil(Sec.Name));
|
|
|
|
|
|
|
|
if (Options.AccelTableKind == DwarfUtilAccelKind::None)
|
|
|
|
AccelTableNamesToDelete.push_back(Sec.Name);
|
2023-06-19 23:36:14 -07:00
|
|
|
else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind))
|
2023-04-01 00:12:29 +02:00
|
|
|
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);
|
|
|
|
}
|
2023-01-15 22:31:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-01 00:12:29 +02:00
|
|
|
// Display message for the replaced accelerator tables.
|
|
|
|
if (!AccelTableNamesToReplace.empty())
|
|
|
|
warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
|
|
|
|
Options.AccelTableKind),
|
|
|
|
Options.InputFileName);
|
2023-01-15 22:31:35 +01:00
|
|
|
|
2023-04-01 00:12:29 +02:00
|
|
|
// Display message for the removed accelerator tables.
|
|
|
|
if (!AccelTableNamesToDelete.empty())
|
|
|
|
warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
|
|
|
|
Options.InputFileName);
|
|
|
|
}
|
2023-01-15 22:31:35 +01:00
|
|
|
|
2022-07-10 20:11:55 +03:00
|
|
|
// Link debug info.
|
2023-04-01 00:12:29 +02:00
|
|
|
if (Error Err = DebugInfoLinker->link())
|
2022-07-28 19:20:58 +03:00
|
|
|
return Err;
|
|
|
|
|
2024-01-19 16:57:09 +03:00
|
|
|
Streamer->finish();
|
2022-07-28 19:20:58 +03:00
|
|
|
return Error::success();
|
2022-07-10 20:11:55 +03:00
|
|
|
}
|
|
|
|
|
2023-04-01 00:12:29 +02:00
|
|
|
Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
|
|
|
|
raw_pwrite_stream &OutStream) {
|
2024-01-18 12:55:04 +03:00
|
|
|
if (Options.UseDWARFLinkerParallel)
|
2024-01-09 11:32:08 +03:00
|
|
|
return linkDebugInfoImpl<parallel::DWARFLinker>(File, Options, OutStream);
|
2023-04-01 00:12:29 +02:00
|
|
|
else
|
2024-01-09 11:32:08 +03:00
|
|
|
return linkDebugInfoImpl<classic::DWARFLinker>(File, Options, OutStream);
|
2023-04-01 00:12:29 +02:00
|
|
|
}
|
|
|
|
|
2022-07-10 20:11:55 +03:00
|
|
|
} // end of namespace dwarfutil
|
|
|
|
} // end of namespace llvm
|