xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp (revision 953efa5b200f060564a090ab71b3d7f614a35e3f)
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