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 <memory>
18 #include <vector>
19
20 namespace llvm {
21 namespace dwarfutil {
22
23 // ObjFileAddressMap allows to check whether specified DIE referencing
24 // dead addresses. It uses tombstone values to determine dead addresses.
25 // The concrete values of tombstone constants were discussed in
26 // https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.
27 // So we use following values as indicators of dead addresses:
28 //
29 // bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and DWARF v4 (or less))
30 // or ([LowPC, HighPC] is not inside address ranges of .text sections).
31 //
32 // maxpc: (LowPC == -1) or (LowPC == -2 and DWARF v4 (or less))
33 // That value is assumed to be compatible with
34 // http://www.dwarfstd.org/ShowIssue.php?issue=200609.1
35 //
36 // exec: [LowPC, HighPC] is not inside address ranges of .text sections
37 //
38 // universal: maxpc and bfd
39 class ObjFileAddressMap : public AddressesMap {
40 public:
ObjFileAddressMap(DWARFContext & Context,const Options & Options,object::ObjectFile & ObjFile)41 ObjFileAddressMap(DWARFContext &Context, const Options &Options,
42 object::ObjectFile &ObjFile)
43 : Opts(Options) {
44 // Remember addresses of existing text sections.
45 for (const object::SectionRef &Sect : ObjFile.sections()) {
46 if (!Sect.isText())
47 continue;
48 const uint64_t Size = Sect.getSize();
49 if (Size == 0)
50 continue;
51 const uint64_t StartAddr = Sect.getAddress();
52 TextAddressRanges.insert({StartAddr, StartAddr + Size});
53 }
54
55 // Check CU address ranges for tombstone value.
56 for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) {
57 Expected<llvm::DWARFAddressRangesVector> ARanges =
58 CU->getUnitDIE().getAddressRanges();
59 if (ARanges) {
60 for (auto &Range : *ARanges) {
61 if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),
62 Options.Tombstone, CU->getAddressByteSize()))
63 DWARFAddressRanges.insert({Range.LowPC, Range.HighPC}, 0);
64 }
65 }
66 }
67 }
68
69 // should be renamed into has valid address ranges
hasValidRelocs()70 bool hasValidRelocs() override { return !DWARFAddressRanges.empty(); }
71
isLiveSubprogram(const DWARFDie & DIE,CompileUnit::DIEInfo & Info)72 bool isLiveSubprogram(const DWARFDie &DIE,
73 CompileUnit::DIEInfo &Info) override {
74 assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||
75 DIE.getTag() == dwarf::DW_TAG_label) &&
76 "Wrong type of input die");
77
78 if (Optional<uint64_t> LowPC =
79 dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {
80 if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),
81 Opts.Tombstone,
82 DIE.getDwarfUnit()->getAddressByteSize())) {
83 Info.AddrAdjust = 0;
84 Info.InDebugMap = true;
85 return true;
86 }
87 }
88
89 return false;
90 }
91
isLiveVariable(const DWARFDie & DIE,CompileUnit::DIEInfo & Info)92 bool isLiveVariable(const DWARFDie &DIE,
93 CompileUnit::DIEInfo &Info) override {
94 assert((DIE.getTag() == dwarf::DW_TAG_variable ||
95 DIE.getTag() == dwarf::DW_TAG_constant) &&
96 "Wrong type of input die");
97
98 if (Expected<DWARFLocationExpressionsVector> Loc =
99 DIE.getLocations(dwarf::DW_AT_location)) {
100 DWARFUnit *U = DIE.getDwarfUnit();
101 for (const auto &Entry : *Loc) {
102 DataExtractor Data(toStringRef(Entry.Expr),
103 U->getContext().isLittleEndian(), 0);
104 DWARFExpression Expression(Data, U->getAddressByteSize(),
105 U->getFormParams().Format);
106 bool HasLiveAddresses =
107 any_of(Expression, [&](const DWARFExpression::Operation &Op) {
108 // TODO: add handling of dwarf::DW_OP_addrx
109 return !Op.isError() &&
110 (Op.getCode() == dwarf::DW_OP_addr &&
111 !isDeadAddress(Op.getRawOperand(0), U->getVersion(),
112 Opts.Tombstone,
113 DIE.getDwarfUnit()->getAddressByteSize()));
114 });
115
116 if (HasLiveAddresses) {
117 Info.AddrAdjust = 0;
118 Info.InDebugMap = true;
119 return true;
120 }
121 }
122 } else {
123 // FIXME: missing DW_AT_location is OK here, but other errors should be
124 // reported to the user.
125 consumeError(Loc.takeError());
126 }
127
128 return false;
129 }
130
applyValidRelocs(MutableArrayRef<char>,uint64_t,bool)131 bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
132 // no need to apply relocations to the linked binary.
133 return false;
134 }
135
getValidAddressRanges()136 RangesTy &getValidAddressRanges() override { return DWARFAddressRanges; };
137
clear()138 void clear() override { DWARFAddressRanges.clear(); }
139
relocateIndexedAddr(uint64_t,uint64_t)140 llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t, uint64_t) override {
141 // should not be called.
142 return object::createError("no relocations in linked binary");
143 }
144
145 protected:
146 // returns true if specified address range is inside address ranges
147 // of executable sections.
isInsideExecutableSectionsAddressRange(uint64_t LowPC,Optional<uint64_t> HighPC)148 bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,
149 Optional<uint64_t> HighPC) {
150 Optional<AddressRange> Range =
151 TextAddressRanges.getRangeThatContains(LowPC);
152
153 if (HighPC)
154 return Range.has_value() && Range->end() >= *HighPC;
155
156 return Range.has_value();
157 }
158
isBFDDeadAddressRange(uint64_t LowPC,Optional<uint64_t> HighPC,uint16_t Version)159 uint64_t isBFDDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
160 uint16_t Version) {
161 if (LowPC == 0)
162 return true;
163
164 if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))
165 return true;
166
167 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
168 }
169
isMAXPCDeadAddressRange(uint64_t LowPC,Optional<uint64_t> HighPC,uint16_t Version,uint8_t AddressByteSize)170 uint64_t isMAXPCDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
171 uint16_t Version, uint8_t AddressByteSize) {
172 if (Version <= 4 && HighPC) {
173 if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))
174 return true;
175 } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))
176 return true;
177
178 if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))
179 warning("Address referencing invalid text section is not marked with "
180 "tombstone value");
181
182 return false;
183 }
184
isDeadAddressRange(uint64_t LowPC,Optional<uint64_t> HighPC,uint16_t Version,TombstoneKind Tombstone,uint8_t AddressByteSize)185 bool isDeadAddressRange(uint64_t LowPC, Optional<uint64_t> HighPC,
186 uint16_t Version, TombstoneKind Tombstone,
187 uint8_t AddressByteSize) {
188 switch (Tombstone) {
189 case TombstoneKind::BFD:
190 return isBFDDeadAddressRange(LowPC, HighPC, Version);
191 case TombstoneKind::MaxPC:
192 return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
193 case TombstoneKind::Universal:
194 return isBFDDeadAddressRange(LowPC, HighPC, Version) ||
195 isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);
196 case TombstoneKind::Exec:
197 return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);
198 }
199
200 llvm_unreachable("Unknown tombstone value");
201 }
202
isDeadAddress(uint64_t LowPC,uint16_t Version,TombstoneKind Tombstone,uint8_t AddressByteSize)203 bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,
204 uint8_t AddressByteSize) {
205 return isDeadAddressRange(LowPC, None, Version, Tombstone, AddressByteSize);
206 }
207
208 private:
209 RangesTy DWARFAddressRanges;
210 AddressRanges TextAddressRanges;
211 const Options &Opts;
212 };
213
knownByDWARFUtil(StringRef SecName)214 static bool knownByDWARFUtil(StringRef SecName) {
215 return llvm::StringSwitch<bool>(SecName)
216 .Case(".debug_info", true)
217 .Case(".debug_types", true)
218 .Case(".debug_abbrev", true)
219 .Case(".debug_loc", true)
220 .Case(".debug_loclists", true)
221 .Case(".debug_frame", true)
222 .Case(".debug_aranges", true)
223 .Case(".debug_ranges", true)
224 .Case(".debug_rnglists", true)
225 .Case(".debug_line", true)
226 .Case(".debug_line_str", true)
227 .Case(".debug_addr", true)
228 .Case(".debug_macro", true)
229 .Case(".debug_macinfo", true)
230 .Case(".debug_str", true)
231 .Case(".debug_str_offsets", true)
232 .Default(false);
233 }
234
linkDebugInfo(object::ObjectFile & File,const Options & Options,raw_pwrite_stream & OutStream)235 Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
236 raw_pwrite_stream &OutStream) {
237
238 auto ReportWarn = [&](const Twine &Message, StringRef Context,
239 const DWARFDie *Die) {
240 warning(Message, Context);
241
242 if (!Options.Verbose || !Die)
243 return;
244
245 DIDumpOptions DumpOpts;
246 DumpOpts.ChildRecurseDepth = 0;
247 DumpOpts.Verbose = Options.Verbose;
248
249 WithColor::note() << " in DIE:\n";
250 Die->dump(errs(), /*Indent=*/6, DumpOpts);
251 };
252 auto ReportErr = [&](const Twine &Message, StringRef Context,
253 const DWARFDie *) {
254 WithColor::error(errs(), Context) << Message << '\n';
255 };
256
257 // Create output streamer.
258 DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr,
259 ReportWarn, ReportWarn);
260 Triple TargetTriple = File.makeTriple();
261 if (!OutStreamer.init(TargetTriple, formatv("cannot create a stream for {0}",
262 TargetTriple.getTriple())
263 .str()))
264 return createStringError(std::errc::invalid_argument, "");
265
266 // Create DWARF linker.
267 DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD);
268
269 DebugInfoLinker.setEstimatedObjfilesAmount(1);
270 DebugInfoLinker.setAccelTableKind(DwarfLinkerAccelTableKind::None);
271 DebugInfoLinker.setErrorHandler(ReportErr);
272 DebugInfoLinker.setWarningHandler(ReportWarn);
273 DebugInfoLinker.setNumThreads(Options.NumThreads);
274 DebugInfoLinker.setNoODR(!Options.DoODRDeduplication);
275 DebugInfoLinker.setVerbosity(Options.Verbose);
276 DebugInfoLinker.setUpdate(!Options.DoGarbageCollection);
277
278 std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
279 std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1);
280 std::vector<std::string> EmptyWarnings;
281
282 std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
283
284 // Unknown debug sections would be removed. Display warning
285 // for such sections.
286 for (SectionName Sec : Context->getDWARFObj().getSectionNames()) {
287 if (isDebugSection(Sec.Name) && !knownByDWARFUtil(Sec.Name))
288 warning(
289 formatv("'{0}' is not currently supported: section will be skipped",
290 Sec.Name),
291 Options.InputFileName);
292 }
293
294 // Add object files to the DWARFLinker.
295 AddresssMapForLinking[0] =
296 std::make_unique<ObjFileAddressMap>(*Context, Options, File);
297
298 ObjectsForLinking[0] = std::make_unique<DWARFFile>(
299 File.getFileName(), &*Context, AddresssMapForLinking[0].get(),
300 EmptyWarnings);
301
302 for (size_t I = 0; I < ObjectsForLinking.size(); I++)
303 DebugInfoLinker.addObjectFile(*ObjectsForLinking[I]);
304
305 // Link debug info.
306 if (Error Err = DebugInfoLinker.link())
307 return Err;
308
309 OutStreamer.finish();
310 return Error::success();
311 }
312
313 } // end of namespace dwarfutil
314 } // end of namespace llvm
315