//===- Reproducer.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Reproducer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" using namespace llvm; using namespace llvm::dsymutil; static std::string createReproducerDir(std::error_code &EC) { SmallString<128> Root; if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) { Root.assign(Path); EC = sys::fs::create_directories(Root); } else if (const char *Path = getenv("LLVM_DIAGNOSTIC_DIR")) { Root.assign(Path); llvm::sys::path::append( Root, "dsymutil-" + llvm::Twine(llvm::sys::Process::getProcessId())); EC = sys::fs::create_directories(Root); } else { EC = sys::fs::createUniqueDirectory("dsymutil", Root); } sys::fs::make_absolute(Root); return EC ? "" : std::string(Root); } Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {} Reproducer::~Reproducer() = default; ReproducerGenerate::ReproducerGenerate(std::error_code &EC, int Argc, char **Argv, bool GenerateOnExit) : Root(createReproducerDir(EC)), GenerateOnExit(GenerateOnExit) { for (int I = 0; I < Argc; ++I) Args.push_back(Argv[I]); if (!Root.empty()) FC = std::make_shared(Root, Root); VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC); } ReproducerGenerate::~ReproducerGenerate() { if (GenerateOnExit && !Generated) generate(); else if (!Generated && !Root.empty()) sys::fs::remove_directories(Root, /* IgnoreErrors */ true); } void ReproducerGenerate::generate() { if (!FC) return; Generated = true; FC->copyFiles(false); SmallString<128> Mapping(Root); sys::path::append(Mapping, "mapping.yaml"); FC->writeMapping(Mapping.str()); errs() << "********************\n"; errs() << "Reproducer written to " << Root << '\n'; errs() << "Please include the reproducer and the following invocation in " "your bug report:\n"; for (llvm::StringRef Arg : Args) errs() << Arg << ' '; errs() << "--use-reproducer " << Root << '\n'; errs() << "********************\n"; } ReproducerUse::~ReproducerUse() = default; ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) { SmallString<128> Mapping(Root); sys::path::append(Mapping, "mapping.yaml"); ErrorOr> Buffer = vfs::getRealFileSystem()->getBufferForFile(Mapping.str()); if (!Buffer) { EC = Buffer.getError(); return; } VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping); } llvm::Expected> Reproducer::createReproducer(ReproducerMode Mode, StringRef Root, int Argc, char **Argv) { std::error_code EC; std::unique_ptr Repro; switch (Mode) { case ReproducerMode::GenerateOnExit: Repro = std::make_unique(EC, Argc, Argv, true); break; case ReproducerMode::GenerateOnCrash: Repro = std::make_unique(EC, Argc, Argv, false); break; case ReproducerMode::Use: Repro = std::make_unique(Root, EC); break; case ReproducerMode::Off: Repro = std::make_unique(); break; } if (EC) return errorCodeToError(EC); return {std::move(Repro)}; }