14539b441SAlexey Lapshin //=== DebugInfoLinker.cpp -------------------------------------------------===//
24539b441SAlexey Lapshin //
34539b441SAlexey Lapshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44539b441SAlexey Lapshin // See https://llvm.org/LICENSE.txt for license information.
54539b441SAlexey Lapshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64539b441SAlexey Lapshin //
74539b441SAlexey Lapshin //===----------------------------------------------------------------------===//
84539b441SAlexey Lapshin
94539b441SAlexey Lapshin #include "DebugInfoLinker.h"
104539b441SAlexey Lapshin #include "Error.h"
11e74197bcSAlexey Lapshin #include "llvm/ADT/StringSwitch.h"
122357e899Savl-llvm #include "llvm/DWARFLinker/Classic/DWARFLinker.h"
132357e899Savl-llvm #include "llvm/DWARFLinker/Classic/DWARFStreamer.h"
142357e899Savl-llvm #include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
154539b441SAlexey Lapshin #include "llvm/DebugInfo/DWARF/DWARFContext.h"
164539b441SAlexey Lapshin #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
174539b441SAlexey Lapshin #include "llvm/Object/ObjectFile.h"
184539b441SAlexey Lapshin #include <memory>
194539b441SAlexey Lapshin #include <vector>
204539b441SAlexey Lapshin
214539b441SAlexey Lapshin namespace llvm {
222357e899Savl-llvm using namespace dwarf_linker;
232357e899Savl-llvm
244539b441SAlexey Lapshin namespace dwarfutil {
254539b441SAlexey Lapshin
264539b441SAlexey Lapshin // ObjFileAddressMap allows to check whether specified DIE referencing
274539b441SAlexey Lapshin // dead addresses. It uses tombstone values to determine dead addresses.
284539b441SAlexey Lapshin // The concrete values of tombstone constants were discussed in
294539b441SAlexey Lapshin // https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.
304539b441SAlexey Lapshin // So we use following values as indicators of dead addresses:
314539b441SAlexey Lapshin //
324539b441SAlexey Lapshin // bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less))
334539b441SAlexey Lapshin // or ([LowPC, HighPC] is not inside address ranges of .text sections).
344539b441SAlexey Lapshin //
354539b441SAlexey Lapshin // maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less))
364539b441SAlexey Lapshin // That value is assumed to be compatible with
374539b441SAlexey Lapshin // http://www.dwarfstd.org/ShowIssue.php?issue=200609.1
384539b441SAlexey Lapshin //
394539b441SAlexey Lapshin // exec: [LowPC, HighPC] is not inside address ranges of .text sections
404539b441SAlexey Lapshin //
414539b441SAlexey Lapshin // universal: maxpc and bfd
422357e899Savl-llvm class ObjFileAddressMap : public AddressesMap {
434539b441SAlexey Lapshin public:
ObjFileAddressMap(DWARFContext & Context,const Options & Options,object::ObjectFile & ObjFile)444539b441SAlexey Lapshin ObjFileAddressMap(DWARFContext &Context, const Options &Options,
454539b441SAlexey Lapshin object::ObjectFile &ObjFile)
464c273cd0SAlexey Lapshin : Opts(Options) {
474539b441SAlexey Lapshin // Remember addresses of existing text sections.
484539b441SAlexey Lapshin for (const object::SectionRef &Sect : ObjFile.sections()) {
494539b441SAlexey Lapshin if (!Sect.isText())
504539b441SAlexey Lapshin continue;
514539b441SAlexey Lapshin const uint64_t Size = Sect.getSize();
524539b441SAlexey Lapshin if (Size == 0)
534539b441SAlexey Lapshin continue;
544539b441SAlexey Lapshin const uint64_t StartAddr = Sect.getAddress();
558bb4451aSAlexey Lapshin TextAddressRanges.insert({StartAddr, StartAddr + Size});
564539b441SAlexey Lapshin }
574539b441SAlexey Lapshin
584539b441SAlexey Lapshin // Check CU address ranges for tombstone value.
594539b441SAlexey Lapshin for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) {
604539b441SAlexey Lapshin Expected<llvm::DWARFAddressRangesVector> ARanges =
614539b441SAlexey Lapshin CU->getUnitDIE().getAddressRanges();
628f5a68abSAlexey Lapshin if (!ARanges) {
638f5a68abSAlexey Lapshin llvm::consumeError(ARanges.takeError());
648f5a68abSAlexey Lapshin continue;
658f5a68abSAlexey Lapshin }
668f5a68abSAlexey Lapshin
674539b441SAlexey Lapshin for (auto &Range : *ARanges) {
684539b441SAlexey Lapshin if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
698f5a68abSAlexey Lapshin Options.Tombstone, CU->getAddressByteSize())) {
708f5a68abSAlexey Lapshin HasValidAddressRanges = true;
718f5a68abSAlexey Lapshin break;
724539b441SAlexey Lapshin }
734539b441SAlexey Lapshin }
748f5a68abSAlexey Lapshin
758f5a68abSAlexey Lapshin if (HasValidAddressRanges)
768f5a68abSAlexey Lapshin break;
774539b441SAlexey Lapshin }
784539b441SAlexey Lapshin }
794539b441SAlexey Lapshin
804539b441SAlexey Lapshin // should be renamed into has valid address ranges
hasValidRelocs()818f5a68abSAlexey Lapshin bool hasValidRelocs() override { return HasValidAddressRanges; }
824539b441SAlexey Lapshin
getSubprogramRelocAdjustment(const DWARFDie & DIE,bool Verbose)830ed81942SAlexey Lapshin std::optional<int64_t> getSubprogramRelocAdjustment(const DWARFDie &DIE,
840ed81942SAlexey Lapshin bool Verbose) override {
854539b441SAlexey Lapshin assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||
864539b441SAlexey Lapshin DIE.getTag() == dwarf::DW_TAG_label) &&
874539b441SAlexey Lapshin "Wrong type of input die");
884539b441SAlexey Lapshin
8989fab98eSFangrui Song if (std::optional<uint64_t> LowPC =
904539b441SAlexey Lapshin dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {
914539b441SAlexey Lapshin if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),
924539b441SAlexey Lapshin Opts.Tombstone,
93709bc112SAlexey Lapshin DIE.getDwarfUnit()->getAddressByteSize()))
94709bc112SAlexey Lapshin // Relocation value for the linked binary is 0.
95709bc112SAlexey Lapshin return 0;
964539b441SAlexey Lapshin }
974539b441SAlexey Lapshin
98709bc112SAlexey Lapshin return std::nullopt;
994539b441SAlexey Lapshin }
1004539b441SAlexey Lapshin
1015f2a7fa6SAlexey Lapshin std::optional<int64_t>
getExprOpAddressRelocAdjustment(DWARFUnit & U,const DWARFExpression::Operation & Op,uint64_t,uint64_t,bool Verbose)1025f2a7fa6SAlexey Lapshin getExprOpAddressRelocAdjustment(DWARFUnit &U,
1035f2a7fa6SAlexey Lapshin const DWARFExpression::Operation &Op,
1040ed81942SAlexey Lapshin uint64_t, uint64_t, bool Verbose) override {
105bd0dd27bSAlexey Lapshin switch (Op.getCode()) {
106bd0dd27bSAlexey Lapshin default: {
107bd0dd27bSAlexey Lapshin assert(false && "Specified operation does not have address operand");
108bd0dd27bSAlexey Lapshin } break;
1095f2a7fa6SAlexey Lapshin case dwarf::DW_OP_const2u:
110bd0dd27bSAlexey Lapshin case dwarf::DW_OP_const4u:
111bd0dd27bSAlexey Lapshin case dwarf::DW_OP_const8u:
1125f2a7fa6SAlexey Lapshin case dwarf::DW_OP_const2s:
113bd0dd27bSAlexey Lapshin case dwarf::DW_OP_const4s:
114bd0dd27bSAlexey Lapshin case dwarf::DW_OP_const8s:
115bd0dd27bSAlexey Lapshin case dwarf::DW_OP_addr: {
116bd0dd27bSAlexey Lapshin if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone,
117bd0dd27bSAlexey Lapshin U.getAddressByteSize()))
118bd0dd27bSAlexey Lapshin // Relocation value for the linked binary is 0.
119bd0dd27bSAlexey Lapshin return 0;
120bd0dd27bSAlexey Lapshin } break;
121bd0dd27bSAlexey Lapshin case dwarf::DW_OP_constx:
122bd0dd27bSAlexey Lapshin case dwarf::DW_OP_addrx: {
123bd0dd27bSAlexey Lapshin if (std::optional<object::SectionedAddress> Address =
124bd0dd27bSAlexey Lapshin U.getAddrOffsetSectionItem(Op.getRawOperand(0))) {
125bd0dd27bSAlexey Lapshin if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone,
126bd0dd27bSAlexey Lapshin U.getAddressByteSize()))
127709bc112SAlexey Lapshin // Relocation value for the linked binary is 0.
128709bc112SAlexey Lapshin return 0;
1294539b441SAlexey Lapshin }
130bd0dd27bSAlexey Lapshin } break;
1314539b441SAlexey Lapshin }
1324539b441SAlexey Lapshin
133709bc112SAlexey Lapshin return std::nullopt;
1344539b441SAlexey Lapshin }
1354539b441SAlexey Lapshin
getLibraryInstallName()13688d00a68SAlpha Abdoulaye std::optional<StringRef> getLibraryInstallName() override {
13788d00a68SAlpha Abdoulaye return std::nullopt;
13888d00a68SAlpha Abdoulaye }
13988d00a68SAlpha Abdoulaye
applyValidRelocs(MutableArrayRef<char>,uint64_t,bool)1404539b441SAlexey Lapshin bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
1414539b441SAlexey Lapshin // no need to apply relocations to the linked binary.
1424539b441SAlexey Lapshin return false;
1434539b441SAlexey Lapshin }
1444539b441SAlexey Lapshin
needToSaveValidRelocs()14588d00a68SAlpha Abdoulaye bool needToSaveValidRelocs() override { return false; }
14688d00a68SAlpha Abdoulaye
updateAndSaveValidRelocs(bool,uint64_t,int64_t,uint64_t,uint64_t)14788d00a68SAlpha Abdoulaye void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,
14888d00a68SAlpha Abdoulaye uint64_t) override {}
14988d00a68SAlpha Abdoulaye
updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,uint64_t OutputUnitOffset)15088d00a68SAlpha Abdoulaye void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
15188d00a68SAlpha Abdoulaye uint64_t OutputUnitOffset) override {}
15288d00a68SAlpha Abdoulaye
clear()1538f5a68abSAlexey Lapshin void clear() override {}
1544539b441SAlexey Lapshin
1554539b441SAlexey Lapshin protected:
1564539b441SAlexey Lapshin // returns true if specified address range is inside address ranges
1574539b441SAlexey Lapshin // of executable sections.
isInsideExecutableSectionsAddressRange(uint64_t LowPC,std::optional<uint64_t> HighPC)1584539b441SAlexey Lapshin bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
159da2f5d0aSFangrui Song std::optional<uint64_t> HighPC) {
1605ec724d9SFangrui Song std::optional<AddressRange> Range =
1618bb4451aSAlexey Lapshin TextAddressRanges.getRangeThatContains(LowPC);
1624539b441SAlexey Lapshin
1638bb4451aSAlexey Lapshin if (HighPC)
1646fa6901bSKazu Hirata return Range.has_value() && Range->end() >= *HighPC;
1654539b441SAlexey Lapshin
1666fa6901bSKazu Hirata return Range.has_value();
1674539b441SAlexey Lapshin }
1684539b441SAlexey Lapshin
isBFDDeadAddressRange(uint64_t LowPC,std::optional<uint64_t> HighPC,uint16_t Version)169da2f5d0aSFangrui Song uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
1704539b441SAlexey Lapshin uint16_t Version) {
1714539b441SAlexey Lapshin if (LowPC == 0)
1724539b441SAlexey Lapshin return true;
1734539b441SAlexey Lapshin
1744539b441SAlexey Lapshin if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
1754539b441SAlexey Lapshin return true;
1764539b441SAlexey Lapshin
1774539b441SAlexey Lapshin return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
1784539b441SAlexey Lapshin }
1794539b441SAlexey Lapshin
isMAXPCDeadAddressRange(uint64_t LowPC,std::optional<uint64_t> HighPC,uint16_t Version,uint8_t AddressByteSize)180da2f5d0aSFangrui Song uint64_t isMAXPCDeadAddressRange(uint64_t LowPC,
181da2f5d0aSFangrui Song std::optional<uint64_t> HighPC,
1824539b441SAlexey Lapshin uint16_t Version, uint8_t AddressByteSize) {
1834539b441SAlexey Lapshin if (Version <= 4 && HighPC) {
1844539b441SAlexey Lapshin if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))
1854539b441SAlexey Lapshin return true;
1864539b441SAlexey Lapshin } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))
1874539b441SAlexey Lapshin return true;
1884539b441SAlexey Lapshin
1894539b441SAlexey Lapshin if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
1904539b441SAlexey Lapshin warning("Address referencing invalid text section is not marked with "
1914539b441SAlexey Lapshin "tombstone value");
1924539b441SAlexey Lapshin
1934539b441SAlexey Lapshin return false;
1944539b441SAlexey Lapshin }
1954539b441SAlexey Lapshin
isDeadAddressRange(uint64_t LowPC,std::optional<uint64_t> HighPC,uint16_t Version,TombstoneKind Tombstone,uint8_t AddressByteSize)196da2f5d0aSFangrui Song bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
1974539b441SAlexey Lapshin uint16_t Version, TombstoneKind Tombstone,
1984539b441SAlexey Lapshin uint8_t AddressByteSize) {
1994539b441SAlexey Lapshin switch (Tombstone) {
2004539b441SAlexey Lapshin case TombstoneKind::BFD:
2014539b441SAlexey Lapshin return isBFDDeadAddressRange(LowPC, HighPC, Version);
2024539b441SAlexey Lapshin case TombstoneKind::MaxPC:
2034539b441SAlexey Lapshin return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
2044539b441SAlexey Lapshin case TombstoneKind::Universal:
2054539b441SAlexey Lapshin return isBFDDeadAddressRange(LowPC, HighPC, Version) ||
2064539b441SAlexey Lapshin isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
2074539b441SAlexey Lapshin case TombstoneKind::Exec:
2084539b441SAlexey Lapshin return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
2094539b441SAlexey Lapshin }
2104539b441SAlexey Lapshin
2114539b441SAlexey Lapshin llvm_unreachable("Unknown tombstone value");
2124539b441SAlexey Lapshin }
2134539b441SAlexey Lapshin
isDeadAddress(uint64_t LowPC,uint16_t Version,TombstoneKind Tombstone,uint8_t AddressByteSize)2144539b441SAlexey Lapshin bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
2154539b441SAlexey Lapshin uint8_t AddressByteSize) {
216b4482f7cSKazu Hirata return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone,
217b4482f7cSKazu Hirata AddressByteSize);
2184539b441SAlexey Lapshin }
2194539b441SAlexey Lapshin
2204539b441SAlexey Lapshin private:
2218bb4451aSAlexey Lapshin AddressRanges TextAddressRanges;
2224539b441SAlexey Lapshin const Options &Opts;
2238f5a68abSAlexey Lapshin bool HasValidAddressRanges = false;
2244539b441SAlexey Lapshin };
2254539b441SAlexey Lapshin
knownByDWARFUtil(StringRef SecName)226e74197bcSAlexey Lapshin static bool knownByDWARFUtil(StringRef SecName) {
227e74197bcSAlexey Lapshin return llvm::StringSwitch<bool>(SecName)
228e74197bcSAlexey Lapshin .Case(".debug_info", true)
229e74197bcSAlexey Lapshin .Case(".debug_types", true)
230e74197bcSAlexey Lapshin .Case(".debug_abbrev", true)
231e74197bcSAlexey Lapshin .Case(".debug_loc", true)
232e74197bcSAlexey Lapshin .Case(".debug_loclists", true)
233e74197bcSAlexey Lapshin .Case(".debug_frame", true)
234e74197bcSAlexey Lapshin .Case(".debug_aranges", true)
235e74197bcSAlexey Lapshin .Case(".debug_ranges", true)
236e74197bcSAlexey Lapshin .Case(".debug_rnglists", true)
237e74197bcSAlexey Lapshin .Case(".debug_line", true)
238e74197bcSAlexey Lapshin .Case(".debug_line_str", true)
239e74197bcSAlexey Lapshin .Case(".debug_addr", true)
240e74197bcSAlexey Lapshin .Case(".debug_macro", true)
241e74197bcSAlexey Lapshin .Case(".debug_macinfo", true)
242e74197bcSAlexey Lapshin .Case(".debug_str", true)
243e74197bcSAlexey Lapshin .Case(".debug_str_offsets", true)
2442216ee49SAlexey Lapshin .Case(".debug_pubnames", true)
2452216ee49SAlexey Lapshin .Case(".debug_pubtypes", true)
2462216ee49SAlexey Lapshin .Case(".debug_names", true)
247e74197bcSAlexey Lapshin .Default(false);
248e74197bcSAlexey Lapshin }
249e74197bcSAlexey Lapshin
25036f35109SAlexey Lapshin template <typename AccelTableKind>
25136f35109SAlexey Lapshin static std::optional<AccelTableKind>
getAcceleratorTableKind(StringRef SecName)2522216ee49SAlexey Lapshin getAcceleratorTableKind(StringRef SecName) {
25336f35109SAlexey Lapshin return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)
25436f35109SAlexey Lapshin .Case(".debug_pubnames", AccelTableKind::Pub)
25536f35109SAlexey Lapshin .Case(".debug_pubtypes", AccelTableKind::Pub)
25636f35109SAlexey Lapshin .Case(".debug_names", AccelTableKind::DebugNames)
2572216ee49SAlexey Lapshin .Default(std::nullopt);
2582216ee49SAlexey Lapshin }
2592216ee49SAlexey Lapshin
getMessageForReplacedAcceleratorTables(SmallVector<StringRef> & AccelTableNamesToReplace,DwarfUtilAccelKind TargetTable)2602216ee49SAlexey Lapshin static std::string getMessageForReplacedAcceleratorTables(
2612216ee49SAlexey Lapshin SmallVector<StringRef> &AccelTableNamesToReplace,
2622216ee49SAlexey Lapshin DwarfUtilAccelKind TargetTable) {
2632216ee49SAlexey Lapshin std::string Message;
2642216ee49SAlexey Lapshin
2652216ee49SAlexey Lapshin Message += "'";
2662216ee49SAlexey Lapshin for (StringRef Name : AccelTableNamesToReplace) {
2672216ee49SAlexey Lapshin if (Message.size() > 1)
2682216ee49SAlexey Lapshin Message += ", ";
2692216ee49SAlexey Lapshin Message += Name;
2702216ee49SAlexey Lapshin }
2712216ee49SAlexey Lapshin
2722216ee49SAlexey Lapshin Message += "' will be replaced with requested ";
2732216ee49SAlexey Lapshin
2742216ee49SAlexey Lapshin switch (TargetTable) {
2752216ee49SAlexey Lapshin case DwarfUtilAccelKind::DWARF:
2762216ee49SAlexey Lapshin Message += ".debug_names table";
2772216ee49SAlexey Lapshin break;
2782216ee49SAlexey Lapshin
2792216ee49SAlexey Lapshin default:
2802216ee49SAlexey Lapshin assert(false);
2812216ee49SAlexey Lapshin }
2822216ee49SAlexey Lapshin
2832216ee49SAlexey Lapshin return Message;
2842216ee49SAlexey Lapshin }
2852216ee49SAlexey Lapshin
getMessageForDeletedAcceleratorTables(SmallVector<StringRef> & AccelTableNamesToReplace)2862216ee49SAlexey Lapshin static std::string getMessageForDeletedAcceleratorTables(
2872216ee49SAlexey Lapshin SmallVector<StringRef> &AccelTableNamesToReplace) {
2882216ee49SAlexey Lapshin std::string Message;
2892216ee49SAlexey Lapshin
2902216ee49SAlexey Lapshin Message += "'";
2912216ee49SAlexey Lapshin for (StringRef Name : AccelTableNamesToReplace) {
2922216ee49SAlexey Lapshin if (Message.size() > 1)
2932216ee49SAlexey Lapshin Message += ", ";
2942216ee49SAlexey Lapshin Message += Name;
2952216ee49SAlexey Lapshin }
2962216ee49SAlexey Lapshin
2972216ee49SAlexey Lapshin Message += "' will be deleted as no accelerator tables are requested";
2982216ee49SAlexey Lapshin
2992216ee49SAlexey Lapshin return Message;
3002216ee49SAlexey Lapshin }
3012216ee49SAlexey Lapshin
3022357e899Savl-llvm template <typename Linker>
linkDebugInfoImpl(object::ObjectFile & File,const Options & Options,raw_pwrite_stream & OutStream)30336f35109SAlexey Lapshin Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
3044539b441SAlexey Lapshin raw_pwrite_stream &OutStream) {
3055f2a7fa6SAlexey Lapshin std::mutex ErrorHandlerMutex;
3065f2a7fa6SAlexey Lapshin
3074539b441SAlexey Lapshin auto ReportWarn = [&](const Twine &Message, StringRef Context,
3084539b441SAlexey Lapshin const DWARFDie *Die) {
3095f2a7fa6SAlexey Lapshin // FIXME: implement warning logging which does not block other threads.
3105f2a7fa6SAlexey Lapshin if (!ErrorHandlerMutex.try_lock())
3114539b441SAlexey Lapshin return;
3124539b441SAlexey Lapshin
3135f2a7fa6SAlexey Lapshin warning(Message, Context);
3145f2a7fa6SAlexey Lapshin if (Options.Verbose && Die) {
3154539b441SAlexey Lapshin DIDumpOptions DumpOpts;
3164539b441SAlexey Lapshin DumpOpts.ChildRecurseDepth = 0;
3174539b441SAlexey Lapshin DumpOpts.Verbose = Options.Verbose;
3184539b441SAlexey Lapshin
3194539b441SAlexey Lapshin WithColor::note() << " in DIE:\n";
3204539b441SAlexey Lapshin Die->dump(errs(), /*Indent=*/6, DumpOpts);
3215f2a7fa6SAlexey Lapshin }
3225f2a7fa6SAlexey Lapshin ErrorHandlerMutex.unlock();
3234539b441SAlexey Lapshin };
3244539b441SAlexey Lapshin auto ReportErr = [&](const Twine &Message, StringRef Context,
3254539b441SAlexey Lapshin const DWARFDie *) {
3265f2a7fa6SAlexey Lapshin // FIXME: implement error logging which does not block other threads.
3275f2a7fa6SAlexey Lapshin if (!ErrorHandlerMutex.try_lock())
3285f2a7fa6SAlexey Lapshin return;
3295f2a7fa6SAlexey Lapshin
3304539b441SAlexey Lapshin WithColor::error(errs(), Context) << Message << '\n';
3315f2a7fa6SAlexey Lapshin ErrorHandlerMutex.unlock();
3324539b441SAlexey Lapshin };
3334539b441SAlexey Lapshin
33466e5678fSAlexey Lapshin // Create DWARF linker.
33536f35109SAlexey Lapshin std::unique_ptr<Linker> DebugInfoLinker =
33636f35109SAlexey Lapshin Linker::createLinker(ReportErr, ReportWarn);
33766e5678fSAlexey Lapshin
33836f35109SAlexey Lapshin Triple TargetTriple = File.makeTriple();
3399ff4be64SAlexey Lapshin std::unique_ptr<classic::DwarfStreamer> Streamer;
3409ff4be64SAlexey Lapshin if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =
341*32a6e9d6SJonas Devlieghere classic::DwarfStreamer::createStreamer(TargetTriple,
342*32a6e9d6SJonas Devlieghere Linker::OutputFileType::Object,
343*32a6e9d6SJonas Devlieghere OutStream, ReportWarn))
3449ff4be64SAlexey Lapshin Streamer = std::move(*StreamerOrErr);
3459ff4be64SAlexey Lapshin else
3469ff4be64SAlexey Lapshin return StreamerOrErr.takeError();
3479ff4be64SAlexey Lapshin
3489ff4be64SAlexey Lapshin if constexpr (std::is_same<Linker,
3499ff4be64SAlexey Lapshin dwarf_linker::parallel::DWARFLinker>::value) {
3509ff4be64SAlexey Lapshin DebugInfoLinker->setOutputDWARFHandler(
3519ff4be64SAlexey Lapshin TargetTriple,
3529ff4be64SAlexey Lapshin [&](std::shared_ptr<dwarf_linker::parallel::SectionDescriptorBase>
3539ff4be64SAlexey Lapshin Section) {
3549ff4be64SAlexey Lapshin Streamer->emitSectionContents(Section->getContents(),
3559ff4be64SAlexey Lapshin Section->getKind());
3569ff4be64SAlexey Lapshin });
3579ff4be64SAlexey Lapshin } else
3589ff4be64SAlexey Lapshin DebugInfoLinker->setOutputDWARFEmitter(Streamer.get());
35966e5678fSAlexey Lapshin
36036f35109SAlexey Lapshin DebugInfoLinker->setEstimatedObjfilesAmount(1);
36136f35109SAlexey Lapshin DebugInfoLinker->setNumThreads(Options.NumThreads);
36236f35109SAlexey Lapshin DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);
36336f35109SAlexey Lapshin DebugInfoLinker->setVerbosity(Options.Verbose);
36436f35109SAlexey Lapshin DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
36536f35109SAlexey Lapshin
3662357e899Savl-llvm std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
3674539b441SAlexey Lapshin
3684539b441SAlexey Lapshin // Add object files to the DWARFLinker.
3695f2a7fa6SAlexey Lapshin std::unique_ptr<DWARFContext> Context = DWARFContext::create(
3705f2a7fa6SAlexey Lapshin File, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
3715f2a7fa6SAlexey Lapshin [&](Error Err) {
3725f2a7fa6SAlexey Lapshin handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
3735f2a7fa6SAlexey Lapshin ReportErr(Info.message(), "", nullptr);
3745f2a7fa6SAlexey Lapshin });
3755f2a7fa6SAlexey Lapshin },
3765f2a7fa6SAlexey Lapshin [&](Error Warning) {
3775f2a7fa6SAlexey Lapshin handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
3785f2a7fa6SAlexey Lapshin ReportWarn(Info.message(), "", nullptr);
3795f2a7fa6SAlexey Lapshin });
3805f2a7fa6SAlexey Lapshin });
3812357e899Savl-llvm std::unique_ptr<ObjFileAddressMap> AddressesMap(
3822357e899Savl-llvm std::make_unique<ObjFileAddressMap>(*Context, Options, File));
3834539b441SAlexey Lapshin
3842357e899Savl-llvm ObjectsForLinking[0] = std::make_unique<DWARFFile>(
385697b34fdSJonas Devlieghere File.getFileName(), std::move(Context), std::move(AddressesMap));
3864539b441SAlexey Lapshin
3872216ee49SAlexey Lapshin uint16_t MaxDWARFVersion = 0;
3882216ee49SAlexey Lapshin std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
3892216ee49SAlexey Lapshin [&MaxDWARFVersion](const DWARFUnit &Unit) {
3902216ee49SAlexey Lapshin MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
3912216ee49SAlexey Lapshin };
3922216ee49SAlexey Lapshin
3934539b441SAlexey Lapshin for (size_t I = 0; I < ObjectsForLinking.size(); I++)
39436f35109SAlexey Lapshin DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,
395adabfb5eSAlexey Lapshin OnCUDieLoaded);
396adabfb5eSAlexey Lapshin
397adabfb5eSAlexey Lapshin // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
398adabfb5eSAlexey Lapshin if (MaxDWARFVersion == 0)
399adabfb5eSAlexey Lapshin MaxDWARFVersion = 3;
400adabfb5eSAlexey Lapshin
40136f35109SAlexey Lapshin if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))
402adabfb5eSAlexey Lapshin return Err;
4034539b441SAlexey Lapshin
40436f35109SAlexey Lapshin SmallVector<typename Linker::AccelTableKind> AccelTables;
4052216ee49SAlexey Lapshin
4062216ee49SAlexey Lapshin switch (Options.AccelTableKind) {
4072216ee49SAlexey Lapshin case DwarfUtilAccelKind::None:
4082216ee49SAlexey Lapshin // Nothing to do.
4092216ee49SAlexey Lapshin break;
4102216ee49SAlexey Lapshin case DwarfUtilAccelKind::DWARF:
4112216ee49SAlexey Lapshin // use .debug_names for all DWARF versions.
41236f35109SAlexey Lapshin AccelTables.push_back(Linker::AccelTableKind::DebugNames);
4132216ee49SAlexey Lapshin break;
4142216ee49SAlexey Lapshin }
4152216ee49SAlexey Lapshin
4162216ee49SAlexey Lapshin // Add accelerator tables to DWARFLinker.
41736f35109SAlexey Lapshin for (typename Linker::AccelTableKind Table : AccelTables)
41836f35109SAlexey Lapshin DebugInfoLinker->addAccelTableKind(Table);
4192216ee49SAlexey Lapshin
4202357e899Savl-llvm for (std::unique_ptr<DWARFFile> &CurFile : ObjectsForLinking) {
4212216ee49SAlexey Lapshin SmallVector<StringRef> AccelTableNamesToReplace;
4222216ee49SAlexey Lapshin SmallVector<StringRef> AccelTableNamesToDelete;
4232216ee49SAlexey Lapshin
4242216ee49SAlexey Lapshin // Unknown debug sections or non-requested accelerator sections would be
4252216ee49SAlexey Lapshin // removed. Display warning for such sections.
42636f35109SAlexey Lapshin for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) {
4272216ee49SAlexey Lapshin if (isDebugSection(Sec.Name)) {
42836f35109SAlexey Lapshin std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =
42936f35109SAlexey Lapshin getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);
4302216ee49SAlexey Lapshin
4312216ee49SAlexey Lapshin if (SrcAccelTableKind) {
4322216ee49SAlexey Lapshin assert(knownByDWARFUtil(Sec.Name));
4332216ee49SAlexey Lapshin
4342216ee49SAlexey Lapshin if (Options.AccelTableKind == DwarfUtilAccelKind::None)
4352216ee49SAlexey Lapshin AccelTableNamesToDelete.push_back(Sec.Name);
436a3b9c153SKazu Hirata else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind))
4372216ee49SAlexey Lapshin AccelTableNamesToReplace.push_back(Sec.Name);
4382216ee49SAlexey Lapshin } else if (!knownByDWARFUtil(Sec.Name)) {
4392216ee49SAlexey Lapshin assert(!SrcAccelTableKind);
4402216ee49SAlexey Lapshin warning(
44136f35109SAlexey Lapshin formatv(
44236f35109SAlexey Lapshin "'{0}' is not currently supported: section will be skipped",
4432216ee49SAlexey Lapshin Sec.Name),
4442216ee49SAlexey Lapshin Options.InputFileName);
4452216ee49SAlexey Lapshin }
4462216ee49SAlexey Lapshin }
4472216ee49SAlexey Lapshin }
4482216ee49SAlexey Lapshin
4492216ee49SAlexey Lapshin // Display message for the replaced accelerator tables.
4502216ee49SAlexey Lapshin if (!AccelTableNamesToReplace.empty())
4512216ee49SAlexey Lapshin warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
4522216ee49SAlexey Lapshin Options.AccelTableKind),
4532216ee49SAlexey Lapshin Options.InputFileName);
4542216ee49SAlexey Lapshin
4552216ee49SAlexey Lapshin // Display message for the removed accelerator tables.
4562216ee49SAlexey Lapshin if (!AccelTableNamesToDelete.empty())
4572216ee49SAlexey Lapshin warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
4582216ee49SAlexey Lapshin Options.InputFileName);
45936f35109SAlexey Lapshin }
4602216ee49SAlexey Lapshin
4614539b441SAlexey Lapshin // Link debug info.
46236f35109SAlexey Lapshin if (Error Err = DebugInfoLinker->link())
463e74197bcSAlexey Lapshin return Err;
464e74197bcSAlexey Lapshin
4659ff4be64SAlexey Lapshin Streamer->finish();
466e74197bcSAlexey Lapshin return Error::success();
4674539b441SAlexey Lapshin }
4684539b441SAlexey Lapshin
linkDebugInfo(object::ObjectFile & File,const Options & Options,raw_pwrite_stream & OutStream)46936f35109SAlexey Lapshin Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
47036f35109SAlexey Lapshin raw_pwrite_stream &OutStream) {
471f1fdfe68SAlexey Lapshin if (Options.UseDWARFLinkerParallel)
4722357e899Savl-llvm return linkDebugInfoImpl<parallel::DWARFLinker>(File, Options, OutStream);
47336f35109SAlexey Lapshin else
4742357e899Savl-llvm return linkDebugInfoImpl<classic::DWARFLinker>(File, Options, OutStream);
47536f35109SAlexey Lapshin }
47636f35109SAlexey Lapshin
4774539b441SAlexey Lapshin } // end of namespace dwarfutil
4784539b441SAlexey Lapshin } // end of namespace llvm
479