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