111 lines · cpp
1//===- Reproducer.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 "Reproducer.h"10#include "llvm/Support/Path.h"11#include "llvm/Support/Process.h"12 13using namespace llvm;14using namespace llvm::dsymutil;15 16static std::string createReproducerDir(std::error_code &EC) {17 SmallString<128> Root;18 if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) {19 Root.assign(Path);20 EC = sys::fs::create_directories(Root);21 } else if (const char *Path = getenv("LLVM_DIAGNOSTIC_DIR")) {22 Root.assign(Path);23 llvm::sys::path::append(24 Root, "dsymutil-" + llvm::Twine(llvm::sys::Process::getProcessId()));25 EC = sys::fs::create_directories(Root);26 } else {27 EC = sys::fs::createUniqueDirectory("dsymutil", Root);28 }29 sys::fs::make_absolute(Root);30 return EC ? "" : std::string(Root);31}32 33Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {}34Reproducer::~Reproducer() = default;35 36ReproducerGenerate::ReproducerGenerate(std::error_code &EC, int Argc,37 char **Argv, bool GenerateOnExit)38 : Root(createReproducerDir(EC)), GenerateOnExit(GenerateOnExit) {39 llvm::append_range(Args, ArrayRef(Argv, Argc));40 auto RealFS = vfs::getRealFileSystem();41 if (!Root.empty())42 FC = std::make_shared<FileCollector>(Root, Root, RealFS);43 VFS = FileCollector::createCollectorVFS(std::move(RealFS), FC);44}45 46ReproducerGenerate::~ReproducerGenerate() {47 if (GenerateOnExit && !Generated)48 generate();49 else if (!Generated && !Root.empty())50 sys::fs::remove_directories(Root, /* IgnoreErrors */ true);51}52 53void ReproducerGenerate::generate() {54 if (!FC)55 return;56 Generated = true;57 FC->copyFiles(false);58 SmallString<128> Mapping(Root);59 sys::path::append(Mapping, "mapping.yaml");60 FC->writeMapping(Mapping.str());61 errs() << "********************\n";62 errs() << "Reproducer written to " << Root << '\n';63 errs() << "Please include the reproducer and the following invocation in "64 "your bug report:\n";65 for (llvm::StringRef Arg : Args)66 errs() << Arg << ' ';67 errs() << "--use-reproducer " << Root << '\n';68 errs() << "********************\n";69}70 71ReproducerUse::~ReproducerUse() = default;72 73ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) {74 SmallString<128> Mapping(Root);75 sys::path::append(Mapping, "mapping.yaml");76 ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =77 vfs::getRealFileSystem()->getBufferForFile(Mapping.str());78 79 if (!Buffer) {80 EC = Buffer.getError();81 return;82 }83 84 VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping);85}86 87llvm::Expected<std::unique_ptr<Reproducer>>88Reproducer::createReproducer(ReproducerMode Mode, StringRef Root, int Argc,89 char **Argv) {90 91 std::error_code EC;92 std::unique_ptr<Reproducer> Repro;93 switch (Mode) {94 case ReproducerMode::GenerateOnExit:95 Repro = std::make_unique<ReproducerGenerate>(EC, Argc, Argv, true);96 break;97 case ReproducerMode::GenerateOnCrash:98 Repro = std::make_unique<ReproducerGenerate>(EC, Argc, Argv, false);99 break;100 case ReproducerMode::Use:101 Repro = std::make_unique<ReproducerUse>(Root, EC);102 break;103 case ReproducerMode::Off:104 Repro = std::make_unique<Reproducer>();105 break;106 }107 if (EC)108 return errorCodeToError(EC);109 return {std::move(Repro)};110}111