brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.3 KiB · ccc1324 Raw
479 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DebugInfoLinker.h"10#include "Error.h"11#include "llvm/ADT/StringSwitch.h"12#include "llvm/DWARFLinker/Classic/DWARFLinker.h"13#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"14#include "llvm/DWARFLinker/Parallel/DWARFLinker.h"15#include "llvm/DebugInfo/DWARF/DWARFContext.h"16#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"17#include "llvm/Object/ObjectFile.h"18#include <memory>19#include <vector>20 21namespace llvm {22using namespace dwarf_linker;23 24namespace dwarfutil {25 26// ObjFileAddressMap allows to check whether specified DIE referencing27// dead addresses. It uses tombstone values to determine dead addresses.28// The concrete values of tombstone constants were discussed in29// https://reviews.llvm.org/D81784 and https://reviews.llvm.org/D84825.30// So we use following values as indicators of dead addresses:31//32// bfd: (LowPC == 0) or (LowPC == 1 and HighPC == 1 and  DWARF v4 (or less))33//      or ([LowPC, HighPC] is not inside address ranges of .text sections).34//35// maxpc: (LowPC == -1) or (LowPC == -2 and  DWARF v4 (or less))36//        That value is assumed to be compatible with37//        http://www.dwarfstd.org/ShowIssue.php?issue=200609.138//39// exec: [LowPC, HighPC] is not inside address ranges of .text sections40//41// universal: maxpc and bfd42class ObjFileAddressMap : public AddressesMap {43public:44  ObjFileAddressMap(DWARFContext &Context, const Options &Options,45                    object::ObjectFile &ObjFile)46      : Opts(Options) {47    // Remember addresses of existing text sections.48    for (const object::SectionRef &Sect : ObjFile.sections()) {49      if (!Sect.isText())50        continue;51      const uint64_t Size = Sect.getSize();52      if (Size == 0)53        continue;54      const uint64_t StartAddr = Sect.getAddress();55      TextAddressRanges.insert({StartAddr, StartAddr + Size});56    }57 58    // Check CU address ranges for tombstone value.59    for (std::unique_ptr<DWARFUnit> &CU : Context.compile_units()) {60      Expected<llvm::DWARFAddressRangesVector> ARanges =61          CU->getUnitDIE().getAddressRanges();62      if (!ARanges) {63        llvm::consumeError(ARanges.takeError());64        continue;65      }66 67      for (auto &Range : *ARanges) {68        if (!isDeadAddressRange(Range.LowPC, Range.HighPC, CU->getVersion(),69                                Options.Tombstone, CU->getAddressByteSize())) {70          HasValidAddressRanges = true;71          break;72        }73      }74 75      if (HasValidAddressRanges)76        break;77    }78  }79 80  // should be renamed into has valid address ranges81  bool hasValidRelocs() override { return HasValidAddressRanges; }82 83  std::optional<int64_t> getSubprogramRelocAdjustment(const DWARFDie &DIE,84                                                      bool Verbose) override {85    assert((DIE.getTag() == dwarf::DW_TAG_subprogram ||86            DIE.getTag() == dwarf::DW_TAG_label) &&87           "Wrong type of input die");88 89    if (std::optional<uint64_t> LowPC =90            dwarf::toAddress(DIE.find(dwarf::DW_AT_low_pc))) {91      if (!isDeadAddress(*LowPC, DIE.getDwarfUnit()->getVersion(),92                         Opts.Tombstone,93                         DIE.getDwarfUnit()->getAddressByteSize()))94        // Relocation value for the linked binary is 0.95        return 0;96    }97 98    return std::nullopt;99  }100 101  std::optional<int64_t>102  getExprOpAddressRelocAdjustment(DWARFUnit &U,103                                  const DWARFExpression::Operation &Op,104                                  uint64_t, uint64_t, bool Verbose) override {105    switch (Op.getCode()) {106    default: {107      assert(false && "Specified operation does not have address operand");108    } break;109    case dwarf::DW_OP_const2u:110    case dwarf::DW_OP_const4u:111    case dwarf::DW_OP_const8u:112    case dwarf::DW_OP_const2s:113    case dwarf::DW_OP_const4s:114    case dwarf::DW_OP_const8s:115    case dwarf::DW_OP_addr: {116      if (!isDeadAddress(Op.getRawOperand(0), U.getVersion(), Opts.Tombstone,117                         U.getAddressByteSize()))118        // Relocation value for the linked binary is 0.119        return 0;120    } break;121    case dwarf::DW_OP_constx:122    case dwarf::DW_OP_addrx: {123      if (std::optional<object::SectionedAddress> Address =124              U.getAddrOffsetSectionItem(Op.getRawOperand(0))) {125        if (!isDeadAddress(Address->Address, U.getVersion(), Opts.Tombstone,126                           U.getAddressByteSize()))127          // Relocation value for the linked binary is 0.128          return 0;129      }130    } break;131    }132 133    return std::nullopt;134  }135 136  std::optional<StringRef> getLibraryInstallName() override {137    return std::nullopt;138  }139 140  bool applyValidRelocs(MutableArrayRef<char>, uint64_t, bool) override {141    // no need to apply relocations to the linked binary.142    return false;143  }144 145  bool needToSaveValidRelocs() override { return false; }146 147  void updateAndSaveValidRelocs(bool, uint64_t, int64_t, uint64_t,148                                uint64_t) override {}149 150  void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,151                                       uint64_t OutputUnitOffset) override {}152 153  void clear() override {}154 155protected:156  // returns true if specified address range is inside address ranges157  // of executable sections.158  bool isInsideExecutableSectionsAddressRange(uint64_t LowPC,159                                              std::optional<uint64_t> HighPC) {160    std::optional<AddressRange> Range =161        TextAddressRanges.getRangeThatContains(LowPC);162 163    if (HighPC)164      return Range.has_value() && Range->end() >= *HighPC;165 166    return Range.has_value();167  }168 169  uint64_t isBFDDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,170                                 uint16_t Version) {171    if (LowPC == 0)172      return true;173 174    if ((Version <= 4) && HighPC && (LowPC == 1 && *HighPC == 1))175      return true;176 177    return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);178  }179 180  uint64_t isMAXPCDeadAddressRange(uint64_t LowPC,181                                   std::optional<uint64_t> HighPC,182                                   uint16_t Version, uint8_t AddressByteSize) {183    if (Version <= 4 && HighPC) {184      if (LowPC == (dwarf::computeTombstoneAddress(AddressByteSize) - 1))185        return true;186    } else if (LowPC == dwarf::computeTombstoneAddress(AddressByteSize))187      return true;188 189    if (!isInsideExecutableSectionsAddressRange(LowPC, HighPC))190      warning("Address referencing invalid text section is not marked with "191              "tombstone value");192 193    return false;194  }195 196  bool isDeadAddressRange(uint64_t LowPC, std::optional<uint64_t> HighPC,197                          uint16_t Version, TombstoneKind Tombstone,198                          uint8_t AddressByteSize) {199    switch (Tombstone) {200    case TombstoneKind::BFD:201      return isBFDDeadAddressRange(LowPC, HighPC, Version);202    case TombstoneKind::MaxPC:203      return isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);204    case TombstoneKind::Universal:205      return isBFDDeadAddressRange(LowPC, HighPC, Version) ||206             isMAXPCDeadAddressRange(LowPC, HighPC, Version, AddressByteSize);207    case TombstoneKind::Exec:208      return !isInsideExecutableSectionsAddressRange(LowPC, HighPC);209    }210 211    llvm_unreachable("Unknown tombstone value");212  }213 214  bool isDeadAddress(uint64_t LowPC, uint16_t Version, TombstoneKind Tombstone,215                     uint8_t AddressByteSize) {216    return isDeadAddressRange(LowPC, std::nullopt, Version, Tombstone,217                              AddressByteSize);218  }219 220private:221  AddressRanges TextAddressRanges;222  const Options &Opts;223  bool HasValidAddressRanges = false;224};225 226static bool knownByDWARFUtil(StringRef SecName) {227  return llvm::StringSwitch<bool>(SecName)228      .Case(".debug_info", true)229      .Case(".debug_types", true)230      .Case(".debug_abbrev", true)231      .Case(".debug_loc", true)232      .Case(".debug_loclists", true)233      .Case(".debug_frame", true)234      .Case(".debug_aranges", true)235      .Case(".debug_ranges", true)236      .Case(".debug_rnglists", true)237      .Case(".debug_line", true)238      .Case(".debug_line_str", true)239      .Case(".debug_addr", true)240      .Case(".debug_macro", true)241      .Case(".debug_macinfo", true)242      .Case(".debug_str", true)243      .Case(".debug_str_offsets", true)244      .Case(".debug_pubnames", true)245      .Case(".debug_pubtypes", true)246      .Case(".debug_names", true)247      .Default(false);248}249 250template <typename AccelTableKind>251static std::optional<AccelTableKind>252getAcceleratorTableKind(StringRef SecName) {253  return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)254      .Case(".debug_pubnames", AccelTableKind::Pub)255      .Case(".debug_pubtypes", AccelTableKind::Pub)256      .Case(".debug_names", AccelTableKind::DebugNames)257      .Default(std::nullopt);258}259 260static std::string getMessageForReplacedAcceleratorTables(261    SmallVector<StringRef> &AccelTableNamesToReplace,262    DwarfUtilAccelKind TargetTable) {263  std::string Message;264 265  Message += "'";266  for (StringRef Name : AccelTableNamesToReplace) {267    if (Message.size() > 1)268      Message += ", ";269    Message += Name;270  }271 272  Message += "' will be replaced with requested ";273 274  switch (TargetTable) {275  case DwarfUtilAccelKind::DWARF:276    Message += ".debug_names table";277    break;278 279  default:280    assert(false);281  }282 283  return Message;284}285 286static std::string getMessageForDeletedAcceleratorTables(287    SmallVector<StringRef> &AccelTableNamesToReplace) {288  std::string Message;289 290  Message += "'";291  for (StringRef Name : AccelTableNamesToReplace) {292    if (Message.size() > 1)293      Message += ", ";294    Message += Name;295  }296 297  Message += "' will be deleted as no accelerator tables are requested";298 299  return Message;300}301 302template <typename Linker>303Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,304                        raw_pwrite_stream &OutStream) {305  std::mutex ErrorHandlerMutex;306 307  auto ReportWarn = [&](const Twine &Message, StringRef Context,308                        const DWARFDie *Die) {309    // FIXME: implement warning logging which does not block other threads.310    if (!ErrorHandlerMutex.try_lock())311      return;312 313    warning(Message, Context);314    if (Options.Verbose && Die) {315      DIDumpOptions DumpOpts;316      DumpOpts.ChildRecurseDepth = 0;317      DumpOpts.Verbose = Options.Verbose;318 319      WithColor::note() << "    in DIE:\n";320      Die->dump(errs(), /*Indent=*/6, DumpOpts);321    }322    ErrorHandlerMutex.unlock();323  };324  auto ReportErr = [&](const Twine &Message, StringRef Context,325                       const DWARFDie *) {326    // FIXME: implement error logging which does not block other threads.327    if (!ErrorHandlerMutex.try_lock())328      return;329 330    WithColor::error(errs(), Context) << Message << '\n';331    ErrorHandlerMutex.unlock();332  };333 334  // Create DWARF linker.335  std::unique_ptr<Linker> DebugInfoLinker =336      Linker::createLinker(ReportErr, ReportWarn);337 338  Triple TargetTriple = File.makeTriple();339  std::unique_ptr<classic::DwarfStreamer> Streamer;340  if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =341          classic::DwarfStreamer::createStreamer(TargetTriple,342                                                 Linker::OutputFileType::Object,343                                                 OutStream, ReportWarn))344    Streamer = std::move(*StreamerOrErr);345  else346    return StreamerOrErr.takeError();347 348  if constexpr (std::is_same<Linker,349                             dwarf_linker::parallel::DWARFLinker>::value) {350    DebugInfoLinker->setOutputDWARFHandler(351        TargetTriple,352        [&](std::shared_ptr<dwarf_linker::parallel::SectionDescriptorBase>353                Section) {354          Streamer->emitSectionContents(Section->getContents(),355                                        Section->getKind());356        });357  } else358    DebugInfoLinker->setOutputDWARFEmitter(Streamer.get());359 360  DebugInfoLinker->setEstimatedObjfilesAmount(1);361  DebugInfoLinker->setNumThreads(Options.NumThreads);362  DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);363  DebugInfoLinker->setVerbosity(Options.Verbose);364  DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);365 366  std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);367 368  // Add object files to the DWARFLinker.369  std::unique_ptr<DWARFContext> Context = DWARFContext::create(370      File, DWARFContext::ProcessDebugRelocations::Process, nullptr, "",371      [&](Error Err) {372        handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {373          ReportErr(Info.message(), "", nullptr);374        });375      },376      [&](Error Warning) {377        handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {378          ReportWarn(Info.message(), "", nullptr);379        });380      });381  std::unique_ptr<ObjFileAddressMap> AddressesMap(382      std::make_unique<ObjFileAddressMap>(*Context, Options, File));383 384  ObjectsForLinking[0] = std::make_unique<DWARFFile>(385      File.getFileName(), std::move(Context), std::move(AddressesMap));386 387  uint16_t MaxDWARFVersion = 0;388  std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =389      [&MaxDWARFVersion](const DWARFUnit &Unit) {390        MaxDWARFVersion = std::max(Unit.getVersion(), MaxDWARFVersion);391      };392 393  for (size_t I = 0; I < ObjectsForLinking.size(); I++)394    DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,395                                   OnCUDieLoaded);396 397  // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.398  if (MaxDWARFVersion == 0)399    MaxDWARFVersion = 3;400 401  if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))402    return Err;403 404  SmallVector<typename Linker::AccelTableKind> AccelTables;405 406  switch (Options.AccelTableKind) {407  case DwarfUtilAccelKind::None:408    // Nothing to do.409    break;410  case DwarfUtilAccelKind::DWARF:411    // use .debug_names for all DWARF versions.412    AccelTables.push_back(Linker::AccelTableKind::DebugNames);413    break;414  }415 416  // Add accelerator tables to DWARFLinker.417  for (typename Linker::AccelTableKind Table : AccelTables)418    DebugInfoLinker->addAccelTableKind(Table);419 420  for (std::unique_ptr<DWARFFile> &CurFile : ObjectsForLinking) {421    SmallVector<StringRef> AccelTableNamesToReplace;422    SmallVector<StringRef> AccelTableNamesToDelete;423 424    // Unknown debug sections or non-requested accelerator sections would be425    // removed. Display warning for such sections.426    for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) {427      if (isDebugSection(Sec.Name)) {428        std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =429            getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);430 431        if (SrcAccelTableKind) {432          assert(knownByDWARFUtil(Sec.Name));433 434          if (Options.AccelTableKind == DwarfUtilAccelKind::None)435            AccelTableNamesToDelete.push_back(Sec.Name);436          else if (!llvm::is_contained(AccelTables, *SrcAccelTableKind))437            AccelTableNamesToReplace.push_back(Sec.Name);438        } else if (!knownByDWARFUtil(Sec.Name)) {439          assert(!SrcAccelTableKind);440          warning(441              formatv(442                  "'{0}' is not currently supported: section will be skipped",443                  Sec.Name),444              Options.InputFileName);445        }446      }447    }448 449    // Display message for the replaced accelerator tables.450    if (!AccelTableNamesToReplace.empty())451      warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace,452                                                     Options.AccelTableKind),453              Options.InputFileName);454 455    // Display message for the removed accelerator tables.456    if (!AccelTableNamesToDelete.empty())457      warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),458              Options.InputFileName);459  }460 461  // Link debug info.462  if (Error Err = DebugInfoLinker->link())463    return Err;464 465  Streamer->finish();466  return Error::success();467}468 469Error linkDebugInfo(object::ObjectFile &File, const Options &Options,470                    raw_pwrite_stream &OutStream) {471  if (Options.UseDWARFLinkerParallel)472    return linkDebugInfoImpl<parallel::DWARFLinker>(File, Options, OutStream);473  else474    return linkDebugInfoImpl<classic::DWARFLinker>(File, Options, OutStream);475}476 477} // end of namespace dwarfutil478} // end of namespace llvm479