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