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