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