xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp (revision 2b8331622f0b212cf3bb4fc4914a501e5321d506)
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:
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
70   bool hasValidRelocs() override { return !DWARFAddressRanges.empty(); }
71 
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 
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 
131   bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {
132     // no need to apply relocations to the linked binary.
133     return false;
134   }
135 
136   RangesTy &getValidAddressRanges() override { return DWARFAddressRanges; };
137 
138   void clear() override { DWARFAddressRanges.clear(); }
139 
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.
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 
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 
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 
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 
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 
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 
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