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