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