brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · 2892450 Raw
311 lines · cpp
1//===-- llvm-dwp.cpp - Split DWARF merging tool for llvm ------------------===//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// A utility for merging DWARF 5 Split DWARF .dwo files into .dwp (DWARF10// package files).11//12//===----------------------------------------------------------------------===//13#include "llvm/DWP/DWP.h"14#include "llvm/DWP/DWPError.h"15#include "llvm/DWP/DWPStringPool.h"16#include "llvm/MC/MCAsmBackend.h"17#include "llvm/MC/MCAsmInfo.h"18#include "llvm/MC/MCCodeEmitter.h"19#include "llvm/MC/MCContext.h"20#include "llvm/MC/MCInstrInfo.h"21#include "llvm/MC/MCObjectWriter.h"22#include "llvm/MC/MCRegisterInfo.h"23#include "llvm/MC/MCSubtargetInfo.h"24#include "llvm/MC/MCTargetOptionsCommandFlags.h"25#include "llvm/MC/TargetRegistry.h"26#include "llvm/Option/ArgList.h"27#include "llvm/Option/Option.h"28#include "llvm/Support/CommandLine.h"29#include "llvm/Support/FileSystem.h"30#include "llvm/Support/LLVMDriver.h"31#include "llvm/Support/MemoryBuffer.h"32#include "llvm/Support/TargetSelect.h"33#include "llvm/Support/ToolOutputFile.h"34#include <optional>35 36using namespace llvm;37using namespace llvm::object;38 39static mc::RegisterMCTargetOptionsFlags MCTargetOptionsFlags;40 41// Command-line option boilerplate.42namespace {43enum ID {44  OPT_INVALID = 0, // This is not an option ID.45#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),46#include "Opts.inc"47#undef OPTION48};49 50#define OPTTABLE_STR_TABLE_CODE51#include "Opts.inc"52#undef OPTTABLE_STR_TABLE_CODE53 54#define OPTTABLE_PREFIXES_TABLE_CODE55#include "Opts.inc"56#undef OPTTABLE_PREFIXES_TABLE_CODE57 58using namespace llvm::opt;59static constexpr opt::OptTable::Info InfoTable[] = {60#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),61#include "Opts.inc"62#undef OPTION63};64 65class DwpOptTable : public opt::GenericOptTable {66public:67  DwpOptTable()68      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}69};70} // end anonymous namespace71 72// Options73static std::vector<std::string> ExecFilenames;74static std::string OutputFilename;75static std::string ContinueOption;76 77static Expected<SmallVector<std::string, 16>>78getDWOFilenames(StringRef ExecFilename) {79  auto ErrOrObj = object::ObjectFile::createObjectFile(ExecFilename);80  if (!ErrOrObj)81    return ErrOrObj.takeError();82 83  const ObjectFile &Obj = *ErrOrObj.get().getBinary();84  std::unique_ptr<DWARFContext> DWARFCtx = DWARFContext::create(Obj);85 86  SmallVector<std::string, 16> DWOPaths;87  for (const auto &CU : DWARFCtx->compile_units()) {88    const DWARFDie &Die = CU->getUnitDIE();89    std::string DWOName = dwarf::toString(90        Die.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), "");91    if (DWOName.empty())92      continue;93    std::string DWOCompDir =94        dwarf::toString(Die.find(dwarf::DW_AT_comp_dir), "");95    if (!DWOCompDir.empty()) {96      SmallString<16> DWOPath(DWOName);97      sys::path::make_absolute(DWOCompDir, DWOPath);98      if (!sys::fs::exists(DWOPath) && sys::fs::exists(DWOName))99        DWOPaths.push_back(std::move(DWOName));100      else101        DWOPaths.emplace_back(DWOPath.data(), DWOPath.size());102    } else {103      DWOPaths.push_back(std::move(DWOName));104    }105  }106  return std::move(DWOPaths);107}108 109static int error(const Twine &Error, const Twine &Context) {110  errs() << Twine("while processing ") + Context + ":\n";111  errs() << Twine("error: ") + Error + "\n";112  return 1;113}114 115static Expected<Triple> readTargetTriple(StringRef FileName) {116  auto ErrOrObj = object::ObjectFile::createObjectFile(FileName);117  if (!ErrOrObj)118    return ErrOrObj.takeError();119 120  return ErrOrObj->getBinary()->makeTriple();121}122 123int llvm_dwp_main(int argc, char **argv, const llvm::ToolContext &) {124  DwpOptTable Tbl;125  llvm::BumpPtrAllocator A;126  llvm::StringSaver Saver{A};127  OnCuIndexOverflow OverflowOptValue = OnCuIndexOverflow::HardStop;128  Dwarf64StrOffsetsPromotion Dwarf64StrOffsetsValue =129      Dwarf64StrOffsetsPromotion::Disabled;130 131  opt::InputArgList Args =132      Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {133        llvm::errs() << Msg << '\n';134        std::exit(1);135      });136 137  if (Args.hasArg(OPT_help)) {138    Tbl.printHelp(llvm::outs(), "llvm-dwp [options] <input files>",139                  "merge split dwarf (.dwo) files");140    std::exit(0);141  }142 143  if (Args.hasArg(OPT_version)) {144    llvm::cl::PrintVersionMessage();145    std::exit(0);146  }147 148  OutputFilename = Args.getLastArgValue(OPT_outputFileName, "");149  if (Arg *Arg = Args.getLastArg(OPT_continueOnCuIndexOverflow,150                                 OPT_continueOnCuIndexOverflow_EQ)) {151    if (Arg->getOption().matches(OPT_continueOnCuIndexOverflow)) {152      OverflowOptValue = OnCuIndexOverflow::Continue;153    } else {154      ContinueOption = Arg->getValue();155      if (ContinueOption == "soft-stop") {156        OverflowOptValue = OnCuIndexOverflow::SoftStop;157      } else if (ContinueOption == "continue") {158        OverflowOptValue = OnCuIndexOverflow::Continue;159      } else {160        llvm::errs() << "invalid value for --continue-on-cu-index-overflow"161                     << ContinueOption << '\n';162        exit(1);163      }164    }165  }166 167  if (Arg *Arg = Args.getLastArg(OPT_dwarf64StringOffsets,168                                 OPT_dwarf64StringOffsets_EQ)) {169    if (Arg->getOption().matches(OPT_dwarf64StringOffsets)) {170      Dwarf64StrOffsetsValue = Dwarf64StrOffsetsPromotion::Enabled;171    } else {172      std::string OptValue = Arg->getValue();173      if (OptValue == "disabled") {174        Dwarf64StrOffsetsValue = Dwarf64StrOffsetsPromotion::Disabled;175      } else if (OptValue == "enabled") {176        Dwarf64StrOffsetsValue = Dwarf64StrOffsetsPromotion::Enabled;177      } else if (OptValue == "always") {178        Dwarf64StrOffsetsValue = Dwarf64StrOffsetsPromotion::Always;179      } else {180        llvm::errs()181            << "invalid value for --dwarf64-str-offsets-promotion. Valid "182               "values are one of: \"enabled\", \"disabled\" or \"always\".\n";183        exit(1);184      }185    }186  }187 188  for (const llvm::opt::Arg *A : Args.filtered(OPT_execFileNames))189    ExecFilenames.emplace_back(A->getValue());190 191  std::vector<std::string> DWOFilenames;192  for (const llvm::opt::Arg *A : Args.filtered(OPT_INPUT))193    DWOFilenames.emplace_back(A->getValue());194 195  llvm::InitializeAllTargetInfos();196  llvm::InitializeAllTargetMCs();197  llvm::InitializeAllTargets();198  llvm::InitializeAllAsmPrinters();199 200  for (const auto &ExecFilename : ExecFilenames) {201    auto DWOs = getDWOFilenames(ExecFilename);202    if (!DWOs) {203      logAllUnhandledErrors(204          handleErrors(DWOs.takeError(),205                       [&](std::unique_ptr<ECError> EC) -> Error {206                         return createFileError(ExecFilename,207                                                Error(std::move(EC)));208                       }),209          WithColor::error());210      return 1;211    }212    DWOFilenames.insert(DWOFilenames.end(),213                        std::make_move_iterator(DWOs->begin()),214                        std::make_move_iterator(DWOs->end()));215  }216 217  if (DWOFilenames.empty()) {218    WithColor::defaultWarningHandler(make_error<DWPError>(219        "executable file does not contain any references to dwo files"));220    return 0;221  }222 223  std::string ErrorStr;224  StringRef Context = "dwarf streamer init";225 226  auto ErrOrTriple = readTargetTriple(DWOFilenames.front());227  if (!ErrOrTriple) {228    logAllUnhandledErrors(229        handleErrors(ErrOrTriple.takeError(),230                     [&](std::unique_ptr<ECError> EC) -> Error {231                       return createFileError(DWOFilenames.front(),232                                              Error(std::move(EC)));233                     }),234        WithColor::error());235    return 1;236  }237 238  // Get the target.239  const Target *TheTarget =240      TargetRegistry::lookupTarget("", *ErrOrTriple, ErrorStr);241  if (!TheTarget)242    return error(ErrorStr, Context);243  std::string TripleName = ErrOrTriple->getTriple();244  Triple TheTriple(TripleName);245 246  // Create all the MC Objects.247  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TheTriple));248  if (!MRI)249    return error(Twine("no register info for target ") + TripleName, Context);250 251  MCTargetOptions MCOptions = llvm::mc::InitMCTargetOptionsFromFlags();252  std::unique_ptr<MCAsmInfo> MAI(253      TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));254  if (!MAI)255    return error("no asm info for target " + TripleName, Context);256 257  std::unique_ptr<MCSubtargetInfo> MSTI(258      TheTarget->createMCSubtargetInfo(TheTriple, "", ""));259  if (!MSTI)260    return error("no subtarget info for target " + TripleName, Context);261 262  MCContext MC(*ErrOrTriple, MAI.get(), MRI.get(), MSTI.get());263  std::unique_ptr<MCObjectFileInfo> MOFI(264      TheTarget->createMCObjectFileInfo(MC, /*PIC=*/false));265  MC.setObjectFileInfo(MOFI.get());266 267  MCTargetOptions Options;268  auto MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, Options);269  if (!MAB)270    return error("no asm backend for target " + TripleName, Context);271 272  std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());273  if (!MII)274    return error("no instr info info for target " + TripleName, Context);275 276  MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*MII, MC);277  if (!MCE)278    return error("no code emitter for target " + TripleName, Context);279 280  // Create the output file.281  std::error_code EC;282  ToolOutputFile OutFile(OutputFilename, EC, sys::fs::OF_None);283  std::optional<buffer_ostream> BOS;284  raw_pwrite_stream *OS;285  if (EC)286    return error(Twine(OutputFilename) + ": " + EC.message(), Context);287  if (OutFile.os().supportsSeeking()) {288    OS = &OutFile.os();289  } else {290    BOS.emplace(OutFile.os());291    OS = &*BOS;292  }293 294  std::unique_ptr<MCStreamer> MS(TheTarget->createMCObjectStreamer(295      *ErrOrTriple, MC, std::unique_ptr<MCAsmBackend>(MAB),296      MAB->createObjectWriter(*OS), std::unique_ptr<MCCodeEmitter>(MCE),297      *MSTI));298  if (!MS)299    return error("no object streamer for target " + TripleName, Context);300 301  if (auto Err =302          write(*MS, DWOFilenames, OverflowOptValue, Dwarf64StrOffsetsValue)) {303    logAllUnhandledErrors(std::move(Err), WithColor::error());304    return 1;305  }306 307  MS->finish();308  OutFile.keep();309  return 0;310}311