[dsymutil][llvm-dwarfutil] Rename command line options to avoid using vendor names...
[llvm-project.git] / llvm / tools / llvm-dwarfutil / DebugInfoLinker.cpp
blobd677bb0962669ff42f58f477dd055d2047378088
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 //===----------------------------------------------------------------------===//
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>
21 namespace llvm {
22 using namespace dwarf_linker;
24 namespace dwarfutil {
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:
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).
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
39 // exec: [LowPC, HighPC] is not inside address ranges of .text sections
41 // universal: maxpc and bfd
42 class ObjFileAddressMap : public AddressesMap {
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});
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;
67 for (auto &Range : *ARanges) {
68 if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
69 Options.Tombstone, CU->getAddressByteSize())) {
70 HasValidAddressRanges = true;
71 break;
75 if (HasValidAddressRanges)
76 break;
80 // should be renamed into has valid address ranges
81 bool hasValidRelocs() override { return HasValidAddressRanges; }
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");
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;
98 return std::nullopt;
101 std::optional<int64_t>
102 getExprOpAddressRelocAdjustment(DWARFUnit &U,
103 const DWARFExpression::Operation &Op,
104 uint64_t, uint64_t) 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;
130 } break;
133 return std::nullopt;
136 std::optional<StringRef> getLibraryInstallName() override {
137 return std::nullopt;
140 bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
141 // no need to apply relocations to the linked binary.
142 return false;
145 bool needToSaveValidRelocs() override { return false; }
147 void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,
148 uint64_t) override {}
150 void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
151 uint64_t OutputUnitOffset) override {}
153 void clear() override {}
155 protected:
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(LowPC);
163 if (HighPC)
164 return Range.has_value() && Range->end() >= *HighPC;
166 return Range.has_value();
169 uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,
170 uint16_t Version) {
171 if (LowPC == 0)
172 return true;
174 if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
175 return true;
177 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
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;
189 if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
190 warning("Address referencing invalid text section is not marked with "
191 "tombstone value");
193 return false;
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);
211 llvm_unreachable("Unknown tombstone value");
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);
220 private:
221 AddressRanges TextAddressRanges;
222 const Options &Opts;
223 bool HasValidAddressRanges = false;
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);
250 template <typename AccelTableKind>
251 static std::optional<AccelTableKind>
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);
260 static std::string getMessageForReplacedAcceleratorTables(
261 SmallVector<StringRef> &AccelTableNamesToReplace,
262 DwarfUtilAccelKind TargetTable) {
263 std::string Message;
265 Message += "'";
266 for (StringRef Name : AccelTableNamesToReplace) {
267 if (Message.size() > 1)
268 Message += ", ";
269 Message += Name;
272 Message += "' will be replaced with requested ";
274 switch (TargetTable) {
275 case DwarfUtilAccelKind::DWARF:
276 Message += ".debug_names table";
277 break;
279 default:
280 assert(false);
283 return Message;
286 static std::string getMessageForDeletedAcceleratorTables(
287 SmallVector<StringRef> &AccelTableNamesToReplace) {
288 std::string Message;
290 Message += "'";
291 for (StringRef Name : AccelTableNamesToReplace) {
292 if (Message.size() > 1)
293 Message += ", ";
294 Message += Name;
297 Message += "' will be deleted as no accelerator tables are requested";
299 return Message;
302 template <typename Linker>
303 Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
304 raw_pwrite_stream &OutStream) {
305 std::mutex ErrorHandlerMutex;
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;
313 warning(Message, Context);
314 if (Options.Verbose && Die) {
315 DIDumpOptions DumpOpts;
316 DumpOpts.ChildRecurseDepth = 0;
317 DumpOpts.Verbose = Options.Verbose;
319 WithColor::note() << " in DIE:\n";
320 Die->dump(errs(), /*Indent=*/6, DumpOpts);
322 ErrorHandlerMutex.unlock();
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;
330 WithColor::error(errs(), Context) << Message << '\n';
331 ErrorHandlerMutex.unlock();
334 // Create DWARF linker.
335 std::unique_ptr<Linker> DebugInfoLinker =
336 Linker::createLinker(ReportErr, ReportWarn);
338 Triple TargetTriple = File.makeTriple();
339 if (Error Err = DebugInfoLinker->createEmitter(
340 TargetTriple, Linker::OutputFileType::Object, OutStream))
341 return Err;
343 DebugInfoLinker->setEstimatedObjfilesAmount(1);
344 DebugInfoLinker->setNumThreads(Options.NumThreads);
345 DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);
346 DebugInfoLinker->setVerbosity(Options.Verbose);
347 DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
349 std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
351 // Add object files to the DWARFLinker.
352 std::unique_ptr<DWARFContext> Context = DWARFContext::create(
353 File, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",
354 [&](Error Err) {
355 handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
356 ReportErr(Info.message(), "", nullptr);
359 [&](Error Warning) {
360 handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
361 ReportWarn(Info.message(), "", nullptr);
364 std::unique_ptr<ObjFileAddressMap> AddressesMap(
365 std::make_unique<ObjFileAddressMap>(*Context, Options, File));
367 ObjectsForLinking[0] = std::make_unique<DWARFFile>(
368 File.getFileName(), std::move(Context), std::move(AddressesMap));
370 uint16_t MaxDWARFVersion = 0;
371 std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
372 [&MaxDWARFVersion](const DWARFUnit &Unit) {
373 MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);
376 for (size_t I = 0; I < ObjectsForLinking.size(); I++)
377 DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,
378 OnCUDieLoaded);
380 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
381 if (MaxDWARFVersion == 0)
382 MaxDWARFVersion = 3;
384 if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))
385 return Err;
387 SmallVector<typename Linker::AccelTableKind> AccelTables;
389 switch (Options.AccelTableKind) {
390 case DwarfUtilAccelKind::None:
391 // Nothing to do.
392 break;
393 case DwarfUtilAccelKind::DWARF:
394 // use .debug_names for all DWARF versions.
395 AccelTables.push_back(Linker::AccelTableKind::DebugNames);
396 break;
399 // Add accelerator tables to DWARFLinker.
400 for (typename Linker::AccelTableKind Table : AccelTables)
401 DebugInfoLinker->addAccelTableKind(Table);
403 for (std::unique_ptr<DWARFFile> &CurFile : ObjectsForLinking) {
404 SmallVector<StringRef> AccelTableNamesToReplace;
405 SmallVector<StringRef> AccelTableNamesToDelete;
407 // Unknown debug sections or non-requested accelerator sections would be
408 // removed. Display warning for such sections.
409 for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) {
410 if (isDebugSection(Sec.Name)) {
411 std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =
412 getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);
414 if (SrcAccelTableKind) {
415 assert(knownByDWARFUtil(Sec.Name));
417 if (Options.AccelTableKind == DwarfUtilAccelKind::None)
418 AccelTableNamesToDelete.push_back(Sec.Name);
419 else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind))
420 AccelTableNamesToReplace.push_back(Sec.Name);
421 } else if (!knownByDWARFUtil(Sec.Name)) {
422 assert(!SrcAccelTableKind);
423 warning(
424 formatv(
425 "'{0}' is not currently supported: section will be skipped",
426 Sec.Name),
427 Options.InputFileName);
432 // Display message for the replaced accelerator tables.
433 if (!AccelTableNamesToReplace.empty())
434 warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,
435 Options.AccelTableKind),
436 Options.InputFileName);
438 // Display message for the removed accelerator tables.
439 if (!AccelTableNamesToDelete.empty())
440 warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
441 Options.InputFileName);
444 // Link debug info.
445 if (Error Err = DebugInfoLinker->link())
446 return Err;
448 DebugInfoLinker->getEmitter()->finish();
449 return Error::success();
452 Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
453 raw_pwrite_stream &OutStream) {
454 if (Options.UseDWARFLinkerParallel)
455 return linkDebugInfoImpl<parallel::DWARFLinker>(File, Options, OutStream);
456 else
457 return linkDebugInfoImpl<classic::DWARFLinker>(File, Options, OutStream);
460 } // end of namespace dwarfutil
461 } // end of namespace llvm