xref: /llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp (revision 1f12223cf411b79cfc9f552ff8711958a7856002)
1 //=== DebugInfoLinker.cpp -------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "DebugInfoLinker.h"
10 #include "Error.h"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/DWARFLinker/DWARFLinker.h"
13 #include "llvm/DWARFLinker/DWARFStreamer.h"
14 #include "llvm/DWARFLinkerParallel/DWARFLinker.h"
15 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
16 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
17 #include "llvm/Object/ObjectFile.h"
18 #include <memory>
19 #include <vector>
20 
21 namespace llvm {
22 namespace dwarfutil {
23 
24 // ObjFileAddressMap allows to check whether specified DIE referencing
25 // dead addresses. It uses tombstone values to determine dead addresses.
26 // The concrete values of tombstone constants were discussed in
27 // https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.
28 // So we use following values as indicators of dead addresses:
29 //
30 // bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and  DWARF v4 (or less))
31 //      or ([LowPC, HighPC] is not inside address ranges of .text sections).
32 //
33 // maxpc: (LowPC == -1) or (LowPC == -2 and  DWARF v4 (or less))
34 //        That value is assumed to be compatible with
35 //        http://www.dwarfstd.org/ShowIssue.php?issue=200609.1
36 //
37 // exec: [LowPC, HighPC] is not inside address ranges of .text sections
38 //
39 // universal: maxpc and bfd
40 template <typename AddressMapBase>
41 class ObjFileAddressMap : public AddressMapBase {
42 public:
43   ObjFileAddressMap(DWARFContext &Context, const Options &Options,
44                     object::ObjectFile &ObjFile)
45       : Opts(Options) {
46     // Remember addresses of existing text sections.
47     for (const object::SectionRef &Sect : ObjFile.sections()) {
48       if (!Sect.isText())
49         continue;
50       const uint64_t Size = Sect.getSize();
51       if (Size == 0)
52         continue;
53       const uint64_t StartAddr = Sect.getAddress();
54       TextAddressRanges.insert({StartAddr, StartAddr + Size});
55     }
56 
57     // Check CU address ranges for tombstone value.
58     for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) {
59       Expected<llvm::DWARFAddressRangesVector> ARanges =
60           CU->getUnitDIE().getAddressRanges();
61       if (!ARanges) {
62         llvm::consumeError(ARanges.takeError());
63         continue;
64       }
65 
66       for (auto &Range : *ARanges) {
67         if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
68                                 Options.Tombstone, CU->getAddressByteSize())) {
69           HasValidAddressRanges = true;
70           break;
71         }
72       }
73 
74       if (HasValidAddressRanges)
75         break;
76     }
77   }
78 
79   // should be renamed into has valid address ranges
80   bool hasValidRelocs() override { return HasValidAddressRanges; }
81 
82   std::optional<int64_t>
83   getSubprogramRelocAdjustment(const DWARFDie &DIE) override {
84     assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||
85             DIE.getTag() == dwarf::DW_TAG_label) &&
86            "Wrong type of input die");
87 
88     if (std::optional<uint64_t> LowPC =
89             dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {
90       if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),
91                          Opts.Tombstone,
92                          DIE.getDwarfUnit()->getAddressByteSize()))
93         // Relocation value for the linked binary is 0.
94         return 0;
95     }
96 
97     return std::nullopt;
98   }
99 
100   std::optional<int64_t>
101   getExprOpAddressRelocAdjustment(DWARFUnit &U,
102                                   const DWARFExpression::Operation &Op,
103                                   uint64_t, uint64_t) override {
104     switch (Op.getCode()) {
105     default: {
106       assert(false && "Specified operation does not have address operand");
107     } break;
108     case dwarf::DW_OP_const2u:
109     case dwarf::DW_OP_const4u:
110     case dwarf::DW_OP_const8u:
111     case dwarf::DW_OP_const2s:
112     case dwarf::DW_OP_const4s:
113     case dwarf::DW_OP_const8s:
114     case dwarf::DW_OP_addr: {
115       if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone,
116                          U.getAddressByteSize()))
117         // Relocation value for the linked binary is 0.
118         return 0;
119     } break;
120     case dwarf::DW_OP_constx:
121     case dwarf::DW_OP_addrx: {
122       if (std::optional<object::SectionedAddress> Address =
123               U.getAddrOffsetSectionItem(Op.getRawOperand(0))) {
124         if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone,
125                            U.getAddressByteSize()))
126           // Relocation value for the linked binary is 0.
127           return 0;
128       }
129     } break;
130     }
131 
132     return std::nullopt;
133   }
134 
135   bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
136     // no need to apply relocations to the linked binary.
137     return false;
138   }
139 
140   void clear() override {}
141 
142 protected:
143   // returns true if specified address range is inside address ranges
144   // of executable sections.
145   bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
146                                               std::optional<uint64_t> HighPC) {
147     std::optional<AddressRange> Range =
148         TextAddressRanges.getRangeThatContains(LowPC);
149 
150     if (HighPC)
151       return Range.has_value() && Range->end() >= *HighPC;
152 
153     return Range.has_value();
154   }
155 
156   uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
157                                  uint16_t Version) {
158     if (LowPC == 0)
159       return true;
160 
161     if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
162       return true;
163 
164     return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
165   }
166 
167   uint64_t isMAXPCDeadAddressRange(uint64_t LowPC,
168                                    std::optional<uint64_t> HighPC,
169                                    uint16_t Version, uint8_t AddressByteSize) {
170     if (Version <= 4 && HighPC) {
171       if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))
172         return true;
173     } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))
174       return true;
175 
176     if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
177       warning("Address referencing invalid text section is not marked with "
178               "tombstone value");
179 
180     return false;
181   }
182 
183   bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
184                           uint16_t Version, TombstoneKind Tombstone,
185                           uint8_t AddressByteSize) {
186     switch (Tombstone) {
187     case TombstoneKind::BFD:
188       return isBFDDeadAddressRange(LowPC, HighPC, Version);
189     case TombstoneKind::MaxPC:
190       return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
191     case TombstoneKind::Universal:
192       return isBFDDeadAddressRange(LowPC, HighPC, Version) ||
193              isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
194     case TombstoneKind::Exec:
195       return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
196     }
197 
198     llvm_unreachable("Unknown tombstone value");
199   }
200 
201   bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
202                      uint8_t AddressByteSize) {
203     return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone,
204                               AddressByteSize);
205   }
206 
207 private:
208   AddressRanges TextAddressRanges;
209   const Options &Opts;
210   bool HasValidAddressRanges = false;
211 };
212 
213 static bool knownByDWARFUtil(StringRef SecName) {
214   return llvm::StringSwitch<bool>(SecName)
215       .Case(".debug_info", true)
216       .Case(".debug_types", true)
217       .Case(".debug_abbrev", true)
218       .Case(".debug_loc", true)
219       .Case(".debug_loclists", true)
220       .Case(".debug_frame", true)
221       .Case(".debug_aranges", true)
222       .Case(".debug_ranges", true)
223       .Case(".debug_rnglists", true)
224       .Case(".debug_line", true)
225       .Case(".debug_line_str", true)
226       .Case(".debug_addr", true)
227       .Case(".debug_macro", true)
228       .Case(".debug_macinfo", true)
229       .Case(".debug_str", true)
230       .Case(".debug_str_offsets", true)
231       .Case(".debug_pubnames", true)
232       .Case(".debug_pubtypes", true)
233       .Case(".debug_names", true)
234       .Default(false);
235 }
236 
237 template <typename AccelTableKind>
238 static std::optional<AccelTableKind>
239 getAcceleratorTableKind(StringRef SecName) {
240   return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)
241       .Case(".debug_pubnames", AccelTableKind::Pub)
242       .Case(".debug_pubtypes", AccelTableKind::Pub)
243       .Case(".debug_names", AccelTableKind::DebugNames)
244       .Default(std::nullopt);
245 }
246 
247 static std::string getMessageForReplacedAcceleratorTables(
248     SmallVector<StringRef> &AccelTableNamesToReplace,
249     DwarfUtilAccelKind TargetTable) {
250   std::string Message;
251 
252   Message += "'";
253   for (StringRef Name : AccelTableNamesToReplace) {
254     if (Message.size() > 1)
255       Message += ", ";
256     Message += Name;
257   }
258 
259   Message += "' will be replaced with requested ";
260 
261   switch (TargetTable) {
262   case DwarfUtilAccelKind::DWARF:
263     Message += ".debug_names table";
264     break;
265 
266   default:
267     assert(false);
268   }
269 
270   return Message;
271 }
272 
273 static std::string getMessageForDeletedAcceleratorTables(
274     SmallVector<StringRef> &AccelTableNamesToReplace) {
275   std::string Message;
276 
277   Message += "'";
278   for (StringRef Name : AccelTableNamesToReplace) {
279     if (Message.size() > 1)
280       Message += ", ";
281     Message += Name;
282   }
283 
284   Message += "' will be deleted as no accelerator tables are requested";
285 
286   return Message;
287 }
288 
289 template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
290 Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
291                         raw_pwrite_stream &OutStream) {
292   std::mutex ErrorHandlerMutex;
293 
294   auto ReportWarn = [&](const Twine &Message, StringRef Context,
295                         const DWARFDie *Die) {
296     // FIXME: implement warning logging which does not block other threads.
297     if (!ErrorHandlerMutex.try_lock())
298       return;
299 
300     warning(Message, Context);
301     if (Options.Verbose && Die) {
302       DIDumpOptions DumpOpts;
303       DumpOpts.ChildRecurseDepth = 0;
304       DumpOpts.Verbose = Options.Verbose;
305 
306       WithColor::note() << "    in DIE:\n";
307       Die->dump(errs(), /*Indent=*/6, DumpOpts);
308     }
309     ErrorHandlerMutex.unlock();
310   };
311   auto ReportErr = [&](const Twine &Message, StringRef Context,
312                        const DWARFDie *) {
313     // FIXME: implement error logging which does not block other threads.
314     if (!ErrorHandlerMutex.try_lock())
315       return;
316 
317     WithColor::error(errs(), Context) << Message << '\n';
318     ErrorHandlerMutex.unlock();
319   };
320 
321   // Create DWARF linker.
322   std::unique_ptr<Linker> DebugInfoLinker =
323       Linker::createLinker(ReportErr, ReportWarn);
324 
325   Triple TargetTriple = File.makeTriple();
326   if (Error Err = DebugInfoLinker->createEmitter(
327           TargetTriple, Linker::OutputFileType::Object, OutStream))
328     return Err;
329 
330   DebugInfoLinker->setEstimatedObjfilesAmount(1);
331   DebugInfoLinker->setNumThreads(Options.NumThreads);
332   DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);
333   DebugInfoLinker->setVerbosity(Options.Verbose);
334   DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
335 
336   std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking(1);
337 
338   // Add object files to the DWARFLinker.
339   std::unique_ptr<DWARFContext> Context = DWARFContext::create(
340       File, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
341       [&](Error Err) {
342         handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
343           ReportErr(Info.message(), "", nullptr);
344         });
345       },
346       [&](Error Warning) {
347         handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
348           ReportWarn(Info.message(), "", nullptr);
349         });
350       });
351   std::unique_ptr<ObjFileAddressMap<AddressMapBase>> AddressesMap(
352       std::make_unique<ObjFileAddressMap<AddressMapBase>>(*Context, Options,
353                                                           File));
354 
355   ObjectsForLinking[0] = std::make_unique<OutDwarfFile>(
356       File.getFileName(), std::move(Context), std::move(AddressesMap));
357 
358   uint16_t MaxDWARFVersion = 0;
359   std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
360       [&MaxDWARFVersion](const DWARFUnit &Unit) {
361         MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
362       };
363 
364   for (size_t I = 0; I < ObjectsForLinking.size(); I++)
365     DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,
366                                    OnCUDieLoaded);
367 
368   // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
369   if (MaxDWARFVersion == 0)
370     MaxDWARFVersion = 3;
371 
372   if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))
373     return Err;
374 
375   SmallVector<typename Linker::AccelTableKind> AccelTables;
376 
377   switch (Options.AccelTableKind) {
378   case DwarfUtilAccelKind::None:
379     // Nothing to do.
380     break;
381   case DwarfUtilAccelKind::DWARF:
382     // use .debug_names for all DWARF versions.
383     AccelTables.push_back(Linker::AccelTableKind::DebugNames);
384     break;
385   }
386 
387   // Add accelerator tables to DWARFLinker.
388   for (typename Linker::AccelTableKind Table : AccelTables)
389     DebugInfoLinker->addAccelTableKind(Table);
390 
391   for (std::unique_ptr<OutDwarfFile> &CurFile : ObjectsForLinking) {
392     SmallVector<StringRef> AccelTableNamesToReplace;
393     SmallVector<StringRef> AccelTableNamesToDelete;
394 
395     // Unknown debug sections or non-requested accelerator sections would be
396     // removed. Display warning for such sections.
397     for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) {
398       if (isDebugSection(Sec.Name)) {
399         std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =
400             getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);
401 
402         if (SrcAccelTableKind) {
403           assert(knownByDWARFUtil(Sec.Name));
404 
405           if (Options.AccelTableKind == DwarfUtilAccelKind::None)
406             AccelTableNamesToDelete.push_back(Sec.Name);
407           else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind))
408             AccelTableNamesToReplace.push_back(Sec.Name);
409         } else if (!knownByDWARFUtil(Sec.Name)) {
410           assert(!SrcAccelTableKind);
411           warning(
412               formatv(
413                   "'{0}' is not currently supported: section will be skipped",
414                   Sec.Name),
415               Options.InputFileName);
416         }
417       }
418     }
419 
420     // Display message for the replaced accelerator tables.
421     if (!AccelTableNamesToReplace.empty())
422       warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
423                                                      Options.AccelTableKind),
424               Options.InputFileName);
425 
426     // Display message for the removed accelerator tables.
427     if (!AccelTableNamesToDelete.empty())
428       warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
429               Options.InputFileName);
430   }
431 
432   // Link debug info.
433   if (Error Err = DebugInfoLinker->link())
434     return Err;
435 
436   DebugInfoLinker->getEmitter()->finish();
437   return Error::success();
438 }
439 
440 Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
441                     raw_pwrite_stream &OutStream) {
442   if (Options.UseLLVMDWARFLinker)
443     return linkDebugInfoImpl<dwarflinker_parallel::DWARFLinker,
444                              dwarflinker_parallel::DWARFFile,
445                              dwarflinker_parallel::AddressesMap>(File, Options,
446                                                                  OutStream);
447   else
448     return linkDebugInfoImpl<DWARFLinker, DWARFFile, AddressesMap>(
449         File, Options, OutStream);
450 }
451 
452 } // end of namespace dwarfutil
453 } // end of namespace llvm
454