xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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   std::optional<StringRef> getLibraryInstallName() override {
136     return std::nullopt;
137   }
138 
139   bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
140     // no need to apply relocations to the linked binary.
141     return false;
142   }
143 
144   bool needToSaveValidRelocs() override { return false; }
145 
146   void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,
147                                 uint64_t) override {}
148 
149   void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
150                                        uint64_t OutputUnitOffset) override {}
151 
152   void clear() override {}
153 
154 protected:
155   // returns true if specified address range is inside address ranges
156   // of executable sections.
157   bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
158                                               std::optional<uint64_t> HighPC) {
159     std::optional<AddressRange> Range =
160         TextAddressRanges.getRangeThatContains(LowPC);
161 
162     if (HighPC)
163       return Range.has_value() && Range->end() >= *HighPC;
164 
165     return Range.has_value();
166   }
167 
168   uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
169                                  uint16_t Version) {
170     if (LowPC == 0)
171       return true;
172 
173     if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
174       return true;
175 
176     return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
177   }
178 
179   uint64_t isMAXPCDeadAddressRange(uint64_t LowPC,
180                                    std::optional<uint64_t> HighPC,
181                                    uint16_t Version, uint8_t AddressByteSize) {
182     if (Version <= 4 && HighPC) {
183       if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))
184         return true;
185     } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))
186       return true;
187 
188     if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
189       warning("Address referencing invalid text section is not marked with "
190               "tombstone value");
191 
192     return false;
193   }
194 
195   bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
196                           uint16_t Version, TombstoneKind Tombstone,
197                           uint8_t AddressByteSize) {
198     switch (Tombstone) {
199     case TombstoneKind::BFD:
200       return isBFDDeadAddressRange(LowPC, HighPC, Version);
201     case TombstoneKind::MaxPC:
202       return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
203     case TombstoneKind::Universal:
204       return isBFDDeadAddressRange(LowPC, HighPC, Version) ||
205              isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
206     case TombstoneKind::Exec:
207       return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
208     }
209 
210     llvm_unreachable("Unknown tombstone value");
211   }
212 
213   bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
214                      uint8_t AddressByteSize) {
215     return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone,
216                               AddressByteSize);
217   }
218 
219 private:
220   AddressRanges TextAddressRanges;
221   const Options &Opts;
222   bool HasValidAddressRanges = false;
223 };
224 
225 static bool knownByDWARFUtil(StringRef SecName) {
226   return llvm::StringSwitch<bool>(SecName)
227       .Case(".debug_info", true)
228       .Case(".debug_types", true)
229       .Case(".debug_abbrev", true)
230       .Case(".debug_loc", true)
231       .Case(".debug_loclists", true)
232       .Case(".debug_frame", true)
233       .Case(".debug_aranges", true)
234       .Case(".debug_ranges", true)
235       .Case(".debug_rnglists", true)
236       .Case(".debug_line", true)
237       .Case(".debug_line_str", true)
238       .Case(".debug_addr", true)
239       .Case(".debug_macro", true)
240       .Case(".debug_macinfo", true)
241       .Case(".debug_str", true)
242       .Case(".debug_str_offsets", true)
243       .Case(".debug_pubnames", true)
244       .Case(".debug_pubtypes", true)
245       .Case(".debug_names", true)
246       .Default(false);
247 }
248 
249 template <typename AccelTableKind>
250 static std::optional<AccelTableKind>
251 getAcceleratorTableKind(StringRef SecName) {
252   return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)
253       .Case(".debug_pubnames", AccelTableKind::Pub)
254       .Case(".debug_pubtypes", AccelTableKind::Pub)
255       .Case(".debug_names", AccelTableKind::DebugNames)
256       .Default(std::nullopt);
257 }
258 
259 static std::string getMessageForReplacedAcceleratorTables(
260     SmallVector<StringRef> &AccelTableNamesToReplace,
261     DwarfUtilAccelKind TargetTable) {
262   std::string Message;
263 
264   Message += "'";
265   for (StringRef Name : AccelTableNamesToReplace) {
266     if (Message.size() > 1)
267       Message += ", ";
268     Message += Name;
269   }
270 
271   Message += "' will be replaced with requested ";
272 
273   switch (TargetTable) {
274   case DwarfUtilAccelKind::DWARF:
275     Message += ".debug_names table";
276     break;
277 
278   default:
279     assert(false);
280   }
281 
282   return Message;
283 }
284 
285 static std::string getMessageForDeletedAcceleratorTables(
286     SmallVector<StringRef> &AccelTableNamesToReplace) {
287   std::string Message;
288 
289   Message += "'";
290   for (StringRef Name : AccelTableNamesToReplace) {
291     if (Message.size() > 1)
292       Message += ", ";
293     Message += Name;
294   }
295 
296   Message += "' will be deleted as no accelerator tables are requested";
297 
298   return Message;
299 }
300 
301 template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
302 Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
303                         raw_pwrite_stream &OutStream) {
304   std::mutex ErrorHandlerMutex;
305 
306   auto ReportWarn = [&](const Twine &Message, StringRef Context,
307                         const DWARFDie *Die) {
308     // FIXME: implement warning logging which does not block other threads.
309     if (!ErrorHandlerMutex.try_lock())
310       return;
311 
312     warning(Message, Context);
313     if (Options.Verbose && Die) {
314       DIDumpOptions DumpOpts;
315       DumpOpts.ChildRecurseDepth = 0;
316       DumpOpts.Verbose = Options.Verbose;
317 
318       WithColor::note() << "    in DIE:\n";
319       Die->dump(errs(), /*Indent=*/6, DumpOpts);
320     }
321     ErrorHandlerMutex.unlock();
322   };
323   auto ReportErr = [&](const Twine &Message, StringRef Context,
324                        const DWARFDie *) {
325     // FIXME: implement error logging which does not block other threads.
326     if (!ErrorHandlerMutex.try_lock())
327       return;
328 
329     WithColor::error(errs(), Context) << Message << '\n';
330     ErrorHandlerMutex.unlock();
331   };
332 
333   // Create DWARF linker.
334   std::unique_ptr<Linker> DebugInfoLinker =
335       Linker::createLinker(ReportErr, ReportWarn);
336 
337   Triple TargetTriple = File.makeTriple();
338   if (Error Err = DebugInfoLinker->createEmitter(
339           TargetTriple, Linker::OutputFileType::Object, OutStream))
340     return Err;
341 
342   DebugInfoLinker->setEstimatedObjfilesAmount(1);
343   DebugInfoLinker->setNumThreads(Options.NumThreads);
344   DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);
345   DebugInfoLinker->setVerbosity(Options.Verbose);
346   DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
347 
348   std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking(1);
349 
350   // Add object files to the DWARFLinker.
351   std::unique_ptr<DWARFContext> Context = DWARFContext::create(
352       File, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
353       [&](Error Err) {
354         handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
355           ReportErr(Info.message(), "", nullptr);
356         });
357       },
358       [&](Error Warning) {
359         handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
360           ReportWarn(Info.message(), "", nullptr);
361         });
362       });
363   std::unique_ptr<ObjFileAddressMap<AddressMapBase>> AddressesMap(
364       std::make_unique<ObjFileAddressMap<AddressMapBase>>(*Context, Options,
365                                                           File));
366 
367   ObjectsForLinking[0] = std::make_unique<OutDwarfFile>(
368       File.getFileName(), std::move(Context), std::move(AddressesMap));
369 
370   uint16_t MaxDWARFVersion = 0;
371   std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
372       [&MaxDWARFVersion](const DWARFUnit &Unit) {
373         MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
374       };
375 
376   for (size_t I = 0; I < ObjectsForLinking.size(); I++)
377     DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,
378                                    OnCUDieLoaded);
379 
380   // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
381   if (MaxDWARFVersion == 0)
382     MaxDWARFVersion = 3;
383 
384   if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))
385     return Err;
386 
387   SmallVector<typename Linker::AccelTableKind> AccelTables;
388 
389   switch (Options.AccelTableKind) {
390   case DwarfUtilAccelKind::None:
391     // Nothing to do.
392     break;
393   case DwarfUtilAccelKind::DWARF:
394     // use .debug_names for all DWARF versions.
395     AccelTables.push_back(Linker::AccelTableKind::DebugNames);
396     break;
397   }
398 
399   // Add accelerator tables to DWARFLinker.
400   for (typename Linker::AccelTableKind Table : AccelTables)
401     DebugInfoLinker->addAccelTableKind(Table);
402 
403   for (std::unique_ptr<OutDwarfFile> &CurFile : ObjectsForLinking) {
404     SmallVector<StringRef> AccelTableNamesToReplace;
405     SmallVector<StringRef> AccelTableNamesToDelete;
406 
407     // Unknown debug sections or non-requested accelerator sections would be
408     // removed. Display warning for such sections.
409     for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) {
410       if (isDebugSection(Sec.Name)) {
411         std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =
412             getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);
413 
414         if (SrcAccelTableKind) {
415           assert(knownByDWARFUtil(Sec.Name));
416 
417           if (Options.AccelTableKind == DwarfUtilAccelKind::None)
418             AccelTableNamesToDelete.push_back(Sec.Name);
419           else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind))
420             AccelTableNamesToReplace.push_back(Sec.Name);
421         } else if (!knownByDWARFUtil(Sec.Name)) {
422           assert(!SrcAccelTableKind);
423           warning(
424               formatv(
425                   "'{0}' is not currently supported: section will be skipped",
426                   Sec.Name),
427               Options.InputFileName);
428         }
429       }
430     }
431 
432     // Display message for the replaced accelerator tables.
433     if (!AccelTableNamesToReplace.empty())
434       warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
435                                                      Options.AccelTableKind),
436               Options.InputFileName);
437 
438     // Display message for the removed accelerator tables.
439     if (!AccelTableNamesToDelete.empty())
440       warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
441               Options.InputFileName);
442   }
443 
444   // Link debug info.
445   if (Error Err = DebugInfoLinker->link())
446     return Err;
447 
448   DebugInfoLinker->getEmitter()->finish();
449   return Error::success();
450 }
451 
452 Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
453                     raw_pwrite_stream &OutStream) {
454   if (Options.UseLLVMDWARFLinker)
455     return linkDebugInfoImpl<dwarflinker_parallel::DWARFLinker,
456                              dwarflinker_parallel::DWARFFile,
457                              dwarflinker_parallel::AddressesMap>(File, Options,
458                                                                  OutStream);
459   else
460     return linkDebugInfoImpl<DWARFLinker, DWARFFile, AddressesMap>(
461         File, Options, OutStream);
462 }
463 
464 } // end of namespace dwarfutil
465 } // end of namespace llvm
466