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