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
21namespace llvm {
22using namespace dwarf_linker;
23
24namespace 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
42class ObjFileAddressMap : public AddressesMap {
43public:
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(Range: {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(Err: ARanges.takeError());
64 continue;
65 }
66
67 for (auto &Range : *ARanges) {
68 if (!isDeadAddressRange(LowPC: Range.LowPC, HighPC: Range.HighPC, Version: CU->getVersion(),
69 Tombstone: Options.Tombstone, AddressByteSize: 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> 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(V: DIE.find(Attr: dwarf::DW_AT_low_pc))) {
91 if (!isDeadAddress(LowPC: *LowPC, Version: DIE.getDwarfUnit()->getVersion(),
92 Tombstone: Opts.Tombstone,
93 AddressByteSize: 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>
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(LowPC: Op.getRawOperand(Idx: 0), Version: U.getVersion(), Tombstone: Opts.Tombstone,
117 AddressByteSize: 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(Index: Op.getRawOperand(Idx: 0))) {
125 if (!isDeadAddress(LowPC: Address->Address, Version: U.getVersion(), Tombstone: Opts.Tombstone,
126 AddressByteSize: 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
136 std::optional<StringRef> getLibraryInstallName() override {
137 return std::nullopt;
138 }
139
140 bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
141 // no need to apply relocations to the linked binary.
142 return false;
143 }
144
145 bool needToSaveValidRelocs() override { return false; }
146
147 void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,
148 uint64_t) override {}
149
150 void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
151 uint64_t OutputUnitOffset) override {}
152
153 void clear() override {}
154
155protected:
156 // returns true if specified address range is inside address ranges
157 // of executable sections.
158 bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
159 std::optional<uint64_t> HighPC) {
160 std::optional<AddressRange> Range =
161 TextAddressRanges.getRangeThatContains(Addr: LowPC);
162
163 if (HighPC)
164 return Range.has_value() && Range->end() >= *HighPC;
165
166 return Range.has_value();
167 }
168
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
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(Message: "Address referencing invalid text section is not marked with "
191 "tombstone value");
192
193 return false;
194 }
195
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
214 bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
215 uint8_t AddressByteSize) {
216 return isDeadAddressRange(LowPC, HighPC: std::nullopt, Version, Tombstone,
217 AddressByteSize);
218 }
219
220private:
221 AddressRanges TextAddressRanges;
222 const Options &Opts;
223 bool HasValidAddressRanges = false;
224};
225
226static bool knownByDWARFUtil(StringRef SecName) {
227 return llvm::StringSwitch<bool>(SecName)
228 .Case(S: ".debug_info", Value: true)
229 .Case(S: ".debug_types", Value: true)
230 .Case(S: ".debug_abbrev", Value: true)
231 .Case(S: ".debug_loc", Value: true)
232 .Case(S: ".debug_loclists", Value: true)
233 .Case(S: ".debug_frame", Value: true)
234 .Case(S: ".debug_aranges", Value: true)
235 .Case(S: ".debug_ranges", Value: true)
236 .Case(S: ".debug_rnglists", Value: true)
237 .Case(S: ".debug_line", Value: true)
238 .Case(S: ".debug_line_str", Value: true)
239 .Case(S: ".debug_addr", Value: true)
240 .Case(S: ".debug_macro", Value: true)
241 .Case(S: ".debug_macinfo", Value: true)
242 .Case(S: ".debug_str", Value: true)
243 .Case(S: ".debug_str_offsets", Value: true)
244 .Case(S: ".debug_pubnames", Value: true)
245 .Case(S: ".debug_pubtypes", Value: true)
246 .Case(S: ".debug_names", Value: true)
247 .Default(Value: false);
248}
249
250template <typename AccelTableKind>
251static std::optional<AccelTableKind>
252getAcceleratorTableKind(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
260static 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
286static 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
302template <typename Linker>
303Error 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, Prefix: 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(OS&: errs(), /*Indent=*/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(OS&: errs(), Prefix: 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(TheTriple: TargetTriple,
342 FileType: Linker::OutputFileType::Object,
343 OutFile&: OutStream, Warning: 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(SecData: Section->getContents(),
355 SecKind: 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>(args&: *Context, args: Options, args&: File));
383
384 ObjectsForLinking[0] = std::make_unique<DWARFFile>(
385 args: File.getFileName(), args: std::move(Context), args: 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(a: Unit.getVersion(), b: 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(SecName: 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(Elt: Sec.Name);
436 else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind))
437 AccelTableNamesToReplace.push_back(Elt: Sec.Name);
438 } else if (!knownByDWARFUtil(SecName: Sec.Name)) {
439 assert(!SrcAccelTableKind);
440 warning(
441 Message: formatv(
442 Fmt: "'{0}' is not currently supported: section will be skipped",
443 Vals&: Sec.Name),
444 Prefix: Options.InputFileName);
445 }
446 }
447 }
448
449 // Display message for the replaced accelerator tables.
450 if (!AccelTableNamesToReplace.empty())
451 warning(Message: getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
452 TargetTable: Options.AccelTableKind),
453 Prefix: Options.InputFileName);
454
455 // Display message for the removed accelerator tables.
456 if (!AccelTableNamesToDelete.empty())
457 warning(Message: getMessageForDeletedAcceleratorTables(AccelTableNamesToReplace&: AccelTableNamesToDelete),
458 Prefix: 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
469Error 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

source code of llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp