192fd3971SJonas Devlieghere //===- Reproducer.cpp -----------------------------------------------------===//
292fd3971SJonas Devlieghere //
392fd3971SJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
492fd3971SJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information.
592fd3971SJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
692fd3971SJonas Devlieghere //
792fd3971SJonas Devlieghere //===----------------------------------------------------------------------===//
892fd3971SJonas Devlieghere
9d395eaccSJonas Devlieghere #include "Reproducer.h"
1007ffcef4SJonas Devlieghere #include "llvm/Support/Path.h"
11*bd206a36SJonas Devlieghere #include "llvm/Support/Process.h"
1292fd3971SJonas Devlieghere
1392fd3971SJonas Devlieghere using namespace llvm;
1492fd3971SJonas Devlieghere using namespace llvm::dsymutil;
1592fd3971SJonas Devlieghere
createReproducerDir(std::error_code & EC)1692fd3971SJonas Devlieghere static std::string createReproducerDir(std::error_code &EC) {
1792fd3971SJonas Devlieghere SmallString<128> Root;
18*bd206a36SJonas Devlieghere if (const char *Path = getenv("DSYMUTIL_REPRODUCER_PATH")) {
1992fd3971SJonas Devlieghere Root.assign(Path);
20*bd206a36SJonas Devlieghere EC = sys::fs::create_directories(Root);
21*bd206a36SJonas Devlieghere } else if (const char *Path = getenv("LLVM_DIAGNOSTIC_DIR")) {
22*bd206a36SJonas Devlieghere Root.assign(Path);
23*bd206a36SJonas Devlieghere llvm::sys::path::append(
24*bd206a36SJonas Devlieghere Root, "dsymutil-" + llvm::Twine(llvm::sys::Process::getProcessId()));
25*bd206a36SJonas Devlieghere EC = sys::fs::create_directories(Root);
2692fd3971SJonas Devlieghere } else {
2792fd3971SJonas Devlieghere EC = sys::fs::createUniqueDirectory("dsymutil", Root);
2892fd3971SJonas Devlieghere }
2917737437SJonas Devlieghere sys::fs::make_absolute(Root);
3092fd3971SJonas Devlieghere return EC ? "" : std::string(Root);
3192fd3971SJonas Devlieghere }
3292fd3971SJonas Devlieghere
Reproducer()3392fd3971SJonas Devlieghere Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {}
3492fd3971SJonas Devlieghere Reproducer::~Reproducer() = default;
3592fd3971SJonas Devlieghere
ReproducerGenerate(std::error_code & EC,int Argc,char ** Argv,bool GenerateOnExit)3633b6891dSJonas Devlieghere ReproducerGenerate::ReproducerGenerate(std::error_code &EC, int Argc,
3733b6891dSJonas Devlieghere char **Argv, bool GenerateOnExit)
3833b6891dSJonas Devlieghere : Root(createReproducerDir(EC)), GenerateOnExit(GenerateOnExit) {
3933b6891dSJonas Devlieghere for (int I = 0; I < Argc; ++I)
4033b6891dSJonas Devlieghere Args.push_back(Argv[I]);
4192fd3971SJonas Devlieghere if (!Root.empty())
4292fd3971SJonas Devlieghere FC = std::make_shared<FileCollector>(Root, Root);
4392fd3971SJonas Devlieghere VFS = FileCollector::createCollectorVFS(vfs::getRealFileSystem(), FC);
4492fd3971SJonas Devlieghere }
4592fd3971SJonas Devlieghere
~ReproducerGenerate()4692fd3971SJonas Devlieghere ReproducerGenerate::~ReproducerGenerate() {
4733b6891dSJonas Devlieghere if (GenerateOnExit && !Generated)
4833b6891dSJonas Devlieghere generate();
498245f266SKeith Smiley else if (!Generated && !Root.empty())
508245f266SKeith Smiley sys::fs::remove_directories(Root, /* IgnoreErrors */ true);
5133b6891dSJonas Devlieghere }
5233b6891dSJonas Devlieghere
generate()5333b6891dSJonas Devlieghere void ReproducerGenerate::generate() {
5492fd3971SJonas Devlieghere if (!FC)
5592fd3971SJonas Devlieghere return;
5633b6891dSJonas Devlieghere Generated = true;
5792fd3971SJonas Devlieghere FC->copyFiles(false);
5892fd3971SJonas Devlieghere SmallString<128> Mapping(Root);
5992fd3971SJonas Devlieghere sys::path::append(Mapping, "mapping.yaml");
6092fd3971SJonas Devlieghere FC->writeMapping(Mapping.str());
6133b6891dSJonas Devlieghere errs() << "********************\n";
6233b6891dSJonas Devlieghere errs() << "Reproducer written to " << Root << '\n';
6333b6891dSJonas Devlieghere errs() << "Please include the reproducer and the following invocation in "
6433b6891dSJonas Devlieghere "your bug report:\n";
6533b6891dSJonas Devlieghere for (llvm::StringRef Arg : Args)
6633b6891dSJonas Devlieghere errs() << Arg << ' ';
6733b6891dSJonas Devlieghere errs() << "--use-reproducer " << Root << '\n';
6833b6891dSJonas Devlieghere errs() << "********************\n";
6992fd3971SJonas Devlieghere }
7092fd3971SJonas Devlieghere
7192fd3971SJonas Devlieghere ReproducerUse::~ReproducerUse() = default;
7292fd3971SJonas Devlieghere
ReproducerUse(StringRef Root,std::error_code & EC)7392fd3971SJonas Devlieghere ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) {
7492fd3971SJonas Devlieghere SmallString<128> Mapping(Root);
7592fd3971SJonas Devlieghere sys::path::append(Mapping, "mapping.yaml");
7692fd3971SJonas Devlieghere ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
7792fd3971SJonas Devlieghere vfs::getRealFileSystem()->getBufferForFile(Mapping.str());
7892fd3971SJonas Devlieghere
7992fd3971SJonas Devlieghere if (!Buffer) {
8092fd3971SJonas Devlieghere EC = Buffer.getError();
8192fd3971SJonas Devlieghere return;
8292fd3971SJonas Devlieghere }
8392fd3971SJonas Devlieghere
8492fd3971SJonas Devlieghere VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping);
8592fd3971SJonas Devlieghere }
8692fd3971SJonas Devlieghere
8792fd3971SJonas Devlieghere llvm::Expected<std::unique_ptr<Reproducer>>
createReproducer(ReproducerMode Mode,StringRef Root,int Argc,char ** Argv)8833b6891dSJonas Devlieghere Reproducer::createReproducer(ReproducerMode Mode, StringRef Root, int Argc,
8933b6891dSJonas Devlieghere char **Argv) {
9033b6891dSJonas Devlieghere
9133b6891dSJonas Devlieghere std::error_code EC;
9233b6891dSJonas Devlieghere std::unique_ptr<Reproducer> Repro;
9392fd3971SJonas Devlieghere switch (Mode) {
9433b6891dSJonas Devlieghere case ReproducerMode::GenerateOnExit:
9533b6891dSJonas Devlieghere Repro = std::make_unique<ReproducerGenerate>(EC, Argc, Argv, true);
9633b6891dSJonas Devlieghere break;
9733b6891dSJonas Devlieghere case ReproducerMode::GenerateOnCrash:
9833b6891dSJonas Devlieghere Repro = std::make_unique<ReproducerGenerate>(EC, Argc, Argv, false);
9933b6891dSJonas Devlieghere break;
10033b6891dSJonas Devlieghere case ReproducerMode::Use:
10133b6891dSJonas Devlieghere Repro = std::make_unique<ReproducerUse>(Root, EC);
10233b6891dSJonas Devlieghere break;
10392fd3971SJonas Devlieghere case ReproducerMode::Off:
10433b6891dSJonas Devlieghere Repro = std::make_unique<Reproducer>();
10533b6891dSJonas Devlieghere break;
10692fd3971SJonas Devlieghere }
10733b6891dSJonas Devlieghere if (EC)
10833b6891dSJonas Devlieghere return errorCodeToError(EC);
10998fe8693SJonas Devlieghere return {std::move(Repro)};
11092fd3971SJonas Devlieghere }
111