xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp (revision 7ef62cebc2f965b0f640263e179276928885e33d)
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/DebugInfo/DWARF/DWARFContext.h"
15 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
16 #include "llvm/Object/ObjectFile.h"
17 #include "llvm/Support/Endian.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 class ObjFileAddressMap : public AddressesMap {
41 public:
42   ObjFileAddressMap(DWARFContext &Context, const Options &Options,
43                     object::ObjectFile &ObjFile)
44       : Opts(Options), Context(Context) {
45     // Remember addresses of existing text sections.
46     for (const object::SectionRef &Sect : ObjFile.sections()) {
47       if (!Sect.isText())
48         continue;
49       const uint64_t Size = Sect.getSize();
50       if (Size == 0)
51         continue;
52       const uint64_t StartAddr = Sect.getAddress();
53       TextAddressRanges.insert({StartAddr, StartAddr + Size});
54     }
55 
56     // Check CU address ranges for tombstone value.
57     for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) {
58       Expected<llvm::DWARFAddressRangesVector> ARanges =
59           CU->getUnitDIE().getAddressRanges();
60       if (ARanges) {
61         for (auto &Range : *ARanges) {
62           if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
63                                   Options.Tombstone, CU->getAddressByteSize()))
64             DWARFAddressRanges.insert({Range.LowPC, Range.HighPC}, 0);
65         }
66       }
67     }
68   }
69 
70   // should be renamed into has valid address ranges
71   bool hasValidRelocs() override { return !DWARFAddressRanges.empty(); }
72 
73   bool isLiveSubprogram(const DWARFDie &DIE,
74                         CompileUnit::DIEInfo &Info) override {
75     assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||
76             DIE.getTag() == dwarf::DW_TAG_label) &&
77            "Wrong type of input die");
78 
79     if (std::optional<uint64_t> LowPC =
80             dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {
81       if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),
82                          Opts.Tombstone,
83                          DIE.getDwarfUnit()->getAddressByteSize())) {
84         Info.AddrAdjust = 0;
85         Info.InDebugMap = true;
86         return true;
87       }
88     }
89 
90     return false;
91   }
92 
93   bool isLiveVariable(const DWARFDie &DIE,
94                       CompileUnit::DIEInfo &Info) override {
95     assert((DIE.getTag() == dwarf::DW_TAG_variable ||
96             DIE.getTag() == dwarf::DW_TAG_constant) &&
97            "Wrong type of input die");
98 
99     if (Expected<DWARFLocationExpressionsVector> Loc =
100             DIE.getLocations(dwarf::DW_AT_location)) {
101       DWARFUnit *U = DIE.getDwarfUnit();
102       for (const auto &Entry : *Loc) {
103         DataExtractor Data(toStringRef(Entry.Expr),
104                            U->getContext().isLittleEndian(), 0);
105         DWARFExpression Expression(Data, U->getAddressByteSize(),
106                                    U->getFormParams().Format);
107         bool HasLiveAddresses =
108             any_of(Expression, [&](const DWARFExpression::Operation &Op) {
109               // TODO: add handling of dwarf::DW_OP_addrx
110               return !Op.isError() &&
111                      (Op.getCode() == dwarf::DW_OP_addr &&
112                       !isDeadAddress(Op.getRawOperand(0), U->getVersion(),
113                                      Opts.Tombstone,
114                                      DIE.getDwarfUnit()->getAddressByteSize()));
115             });
116 
117         if (HasLiveAddresses) {
118           Info.AddrAdjust = 0;
119           Info.InDebugMap = true;
120           return true;
121         }
122       }
123     } else {
124       // FIXME: missing DW_AT_location is OK here, but other errors should be
125       // reported to the user.
126       consumeError(Loc.takeError());
127     }
128 
129     return false;
130   }
131 
132   bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
133     // no need to apply relocations to the linked binary.
134     return false;
135   }
136 
137   RangesTy &getValidAddressRanges() override { return DWARFAddressRanges; };
138 
139   void clear() override { DWARFAddressRanges.clear(); }
140 
141   llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t StartOffset,
142                                                uint64_t EndOffset) override {
143     // No relocations in linked binary. Return just address value.
144 
145     const char *AddrPtr =
146         Context.getDWARFObj().getAddrSection().Data.data() + StartOffset;
147     support::endianness Endianess =
148         Context.getDWARFObj().isLittleEndian() ? support::little : support::big;
149 
150     assert(EndOffset > StartOffset);
151     switch (EndOffset - StartOffset) {
152     case 1:
153       return *AddrPtr;
154     case 2:
155       return support::endian::read16(AddrPtr, Endianess);
156     case 4:
157       return support::endian::read32(AddrPtr, Endianess);
158     case 8:
159       return support::endian::read64(AddrPtr, Endianess);
160     }
161 
162     llvm_unreachable("relocateIndexedAddr unhandled case!");
163   }
164 
165 protected:
166   // returns true if specified address range is inside address ranges
167   // of executable sections.
168   bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
169                                               std::optional<uint64_t> HighPC) {
170     std::optional<AddressRange> Range =
171         TextAddressRanges.getRangeThatContains(LowPC);
172 
173     if (HighPC)
174       return Range.has_value() && Range->end() >= *HighPC;
175 
176     return Range.has_value();
177   }
178 
179   uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
180                                  uint16_t Version) {
181     if (LowPC == 0)
182       return true;
183 
184     if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
185       return true;
186 
187     return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
188   }
189 
190   uint64_t isMAXPCDeadAddressRange(uint64_t LowPC,
191                                    std::optional<uint64_t> HighPC,
192                                    uint16_t Version, uint8_t AddressByteSize) {
193     if (Version <= 4 && HighPC) {
194       if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))
195         return true;
196     } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))
197       return true;
198 
199     if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
200       warning("Address referencing invalid text section is not marked with "
201               "tombstone value");
202 
203     return false;
204   }
205 
206   bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
207                           uint16_t Version, TombstoneKind Tombstone,
208                           uint8_t AddressByteSize) {
209     switch (Tombstone) {
210     case TombstoneKind::BFD:
211       return isBFDDeadAddressRange(LowPC, HighPC, Version);
212     case TombstoneKind::MaxPC:
213       return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
214     case TombstoneKind::Universal:
215       return isBFDDeadAddressRange(LowPC, HighPC, Version) ||
216              isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
217     case TombstoneKind::Exec:
218       return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
219     }
220 
221     llvm_unreachable("Unknown tombstone value");
222   }
223 
224   bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
225                      uint8_t AddressByteSize) {
226     return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone,
227                               AddressByteSize);
228   }
229 
230 private:
231   RangesTy DWARFAddressRanges;
232   AddressRanges TextAddressRanges;
233   const Options &Opts;
234   DWARFContext &Context;
235 };
236 
237 static bool knownByDWARFUtil(StringRef SecName) {
238   return llvm::StringSwitch<bool>(SecName)
239       .Case(".debug_info", true)
240       .Case(".debug_types", true)
241       .Case(".debug_abbrev", true)
242       .Case(".debug_loc", true)
243       .Case(".debug_loclists", true)
244       .Case(".debug_frame", true)
245       .Case(".debug_aranges", true)
246       .Case(".debug_ranges", true)
247       .Case(".debug_rnglists", true)
248       .Case(".debug_line", true)
249       .Case(".debug_line_str", true)
250       .Case(".debug_addr", true)
251       .Case(".debug_macro", true)
252       .Case(".debug_macinfo", true)
253       .Case(".debug_str", true)
254       .Case(".debug_str_offsets", true)
255       .Case(".debug_pubnames", true)
256       .Case(".debug_pubtypes", true)
257       .Case(".debug_names", true)
258       .Default(false);
259 }
260 
261 static std::optional<DwarfLinkerAccelTableKind>
262 getAcceleratorTableKind(StringRef SecName) {
263   return llvm::StringSwitch<std::optional<DwarfLinkerAccelTableKind>>(SecName)
264       .Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub)
265       .Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub)
266       .Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames)
267       .Default(std::nullopt);
268 }
269 
270 static std::string getMessageForReplacedAcceleratorTables(
271     SmallVector<StringRef> &AccelTableNamesToReplace,
272     DwarfUtilAccelKind TargetTable) {
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 replaced with requested ";
283 
284   switch (TargetTable) {
285   case DwarfUtilAccelKind::DWARF:
286     Message += ".debug_names table";
287     break;
288 
289   default:
290     assert(false);
291   }
292 
293   return Message;
294 }
295 
296 static std::string getMessageForDeletedAcceleratorTables(
297     SmallVector<StringRef> &AccelTableNamesToReplace) {
298   std::string Message;
299 
300   Message += "'";
301   for (StringRef Name : AccelTableNamesToReplace) {
302     if (Message.size() > 1)
303       Message += ", ";
304     Message += Name;
305   }
306 
307   Message += "' will be deleted as no accelerator tables are requested";
308 
309   return Message;
310 }
311 
312 Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
313                     raw_pwrite_stream &OutStream) {
314 
315   auto ReportWarn = [&](const Twine &Message, StringRef Context,
316                         const DWARFDie *Die) {
317     warning(Message, Context);
318 
319     if (!Options.Verbose || !Die)
320       return;
321 
322     DIDumpOptions DumpOpts;
323     DumpOpts.ChildRecurseDepth = 0;
324     DumpOpts.Verbose = Options.Verbose;
325 
326     WithColor::note() << "    in DIE:\n";
327     Die->dump(errs(), /*Indent=*/6, DumpOpts);
328   };
329   auto ReportErr = [&](const Twine &Message, StringRef Context,
330                        const DWARFDie *) {
331     WithColor::error(errs(), Context) << Message << '\n';
332   };
333 
334   // Create output streamer.
335   DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr,
336                             ReportWarn, ReportWarn);
337   Triple TargetTriple = File.makeTriple();
338   if (!OutStreamer.init(TargetTriple, formatv("cannot create a stream for {0}",
339                                               TargetTriple.getTriple())
340                                           .str()))
341     return createStringError(std::errc::invalid_argument, "");
342 
343   std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
344 
345   // Create DWARF linker.
346   DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD);
347 
348   DebugInfoLinker.setEstimatedObjfilesAmount(1);
349   DebugInfoLinker.setErrorHandler(ReportErr);
350   DebugInfoLinker.setWarningHandler(ReportWarn);
351   DebugInfoLinker.setNumThreads(Options.NumThreads);
352   DebugInfoLinker.setNoODR(!Options.DoODRDeduplication);
353   DebugInfoLinker.setVerbosity(Options.Verbose);
354   DebugInfoLinker.setUpdate(!Options.DoGarbageCollection);
355 
356   std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
357   std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1);
358   std::vector<std::string> EmptyWarnings;
359 
360   // Add object files to the DWARFLinker.
361   AddresssMapForLinking[0] =
362       std::make_unique<ObjFileAddressMap>(*Context, Options, File);
363 
364   ObjectsForLinking[0] = std::make_unique<DWARFFile>(
365       File.getFileName(), &*Context, AddresssMapForLinking[0].get(),
366       EmptyWarnings);
367 
368   uint16_t MaxDWARFVersion = 0;
369   std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
370       [&MaxDWARFVersion](const DWARFUnit &Unit) {
371         MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
372       };
373 
374   for (size_t I = 0; I < ObjectsForLinking.size(); I++)
375     DebugInfoLinker.addObjectFile(*ObjectsForLinking[I], nullptr,
376                                   OnCUDieLoaded);
377 
378   // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
379   if (MaxDWARFVersion == 0)
380     MaxDWARFVersion = 3;
381 
382   if (Error Err = DebugInfoLinker.setTargetDWARFVersion(MaxDWARFVersion))
383     return Err;
384 
385   SmallVector<DwarfLinkerAccelTableKind> AccelTables;
386 
387   switch (Options.AccelTableKind) {
388   case DwarfUtilAccelKind::None:
389     // Nothing to do.
390     break;
391   case DwarfUtilAccelKind::DWARF:
392     // use .debug_names for all DWARF versions.
393     AccelTables.push_back(DwarfLinkerAccelTableKind::DebugNames);
394     break;
395   }
396 
397   // Add accelerator tables to DWARFLinker.
398   for (DwarfLinkerAccelTableKind Table : AccelTables)
399     DebugInfoLinker.addAccelTableKind(Table);
400 
401   SmallVector<StringRef> AccelTableNamesToReplace;
402   SmallVector<StringRef> AccelTableNamesToDelete;
403 
404   // Unknown debug sections or non-requested accelerator sections would be
405   // removed. Display warning for such sections.
406   for (SectionName Sec : Context->getDWARFObj().getSectionNames()) {
407     if (isDebugSection(Sec.Name)) {
408       std::optional<DwarfLinkerAccelTableKind> SrcAccelTableKind =
409           getAcceleratorTableKind(Sec.Name);
410 
411       if (SrcAccelTableKind) {
412         assert(knownByDWARFUtil(Sec.Name));
413 
414         if (Options.AccelTableKind == DwarfUtilAccelKind::None)
415           AccelTableNamesToDelete.push_back(Sec.Name);
416         else if (std::find(AccelTables.begin(), AccelTables.end(),
417                            *SrcAccelTableKind) == AccelTables.end())
418           AccelTableNamesToReplace.push_back(Sec.Name);
419       } else if (!knownByDWARFUtil(Sec.Name)) {
420         assert(!SrcAccelTableKind);
421         warning(
422             formatv("'{0}' is not currently supported: section will be skipped",
423                     Sec.Name),
424             Options.InputFileName);
425       }
426     }
427   }
428 
429   // Display message for the replaced accelerator tables.
430   if (!AccelTableNamesToReplace.empty())
431     warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
432                                                    Options.AccelTableKind),
433             Options.InputFileName);
434 
435   // Display message for the removed accelerator tables.
436   if (!AccelTableNamesToDelete.empty())
437     warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
438             Options.InputFileName);
439 
440   // Link debug info.
441   if (Error Err = DebugInfoLinker.link())
442     return Err;
443 
444   OutStreamer.finish();
445   return Error::success();
446 }
447 
448 } // end of namespace dwarfutil
449 } // end of namespace llvm
450