xref: /llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp (revision 32a6e9d66945c28a9cae476b6d2eb803ca2ab098)
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