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:
ObjFileAddressMap(DWARFContext & Context,const Options & Options,object::ObjectFile & ObjFile)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
hasValidRelocs()71 bool hasValidRelocs() override { return !DWARFAddressRanges.empty(); }
72
isLiveSubprogram(const DWARFDie & DIE,CompileUnit::DIEInfo & Info)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
isLiveVariable(const DWARFDie & DIE,CompileUnit::DIEInfo & Info)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
applyValidRelocs(MutableArrayRef<char>,uint64_t,bool)132 bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
133 // no need to apply relocations to the linked binary.
134 return false;
135 }
136
getValidAddressRanges()137 RangesTy &getValidAddressRanges() override { return DWARFAddressRanges; };
138
clear()139 void clear() override { DWARFAddressRanges.clear(); }
140
relocateIndexedAddr(uint64_t StartOffset,uint64_t EndOffset)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.
isInsideExecutableSectionsAddressRange(uint64_t LowPC,std::optional<uint64_t> HighPC)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
isBFDDeadAddressRange(uint64_t LowPC,std::optional<uint64_t> HighPC,uint16_t Version)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
isMAXPCDeadAddressRange(uint64_t LowPC,std::optional<uint64_t> HighPC,uint16_t Version,uint8_t AddressByteSize)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
isDeadAddressRange(uint64_t LowPC,std::optional<uint64_t> HighPC,uint16_t Version,TombstoneKind Tombstone,uint8_t AddressByteSize)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
isDeadAddress(uint64_t LowPC,uint16_t Version,TombstoneKind Tombstone,uint8_t AddressByteSize)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
knownByDWARFUtil(StringRef SecName)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>
getAcceleratorTableKind(StringRef SecName)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
getMessageForReplacedAcceleratorTables(SmallVector<StringRef> & AccelTableNamesToReplace,DwarfUtilAccelKind TargetTable)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
getMessageForDeletedAcceleratorTables(SmallVector<StringRef> & AccelTableNamesToReplace)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
linkDebugInfo(object::ObjectFile & File,const Options & Options,raw_pwrite_stream & OutStream)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