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