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