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