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 | #include "llvm/Support/Process.h" |
12 | |
13 | using namespace llvm; |
14 | using namespace llvm::dsymutil; |
15 | |
16 | static std::string createReproducerDir(std::error_code &EC) { |
17 | SmallString<128> Root; |
18 | if (const char *Path = getenv(name: "DSYMUTIL_REPRODUCER_PATH" )) { |
19 | Root.assign(RHS: Path); |
20 | EC = sys::fs::create_directories(path: Root); |
21 | } else if (const char *Path = getenv(name: "LLVM_DIAGNOSTIC_DIR" )) { |
22 | Root.assign(RHS: Path); |
23 | llvm::sys::path::append( |
24 | path&: Root, a: "dsymutil-" + llvm::Twine(llvm::sys::Process::getProcessId())); |
25 | EC = sys::fs::create_directories(path: Root); |
26 | } else { |
27 | EC = sys::fs::createUniqueDirectory(Prefix: "dsymutil" , ResultPath&: Root); |
28 | } |
29 | sys::fs::make_absolute(path&: Root); |
30 | return EC ? "" : std::string(Root); |
31 | } |
32 | |
33 | Reproducer::Reproducer() : VFS(vfs::getRealFileSystem()) {} |
34 | Reproducer::~Reproducer() = default; |
35 | |
36 | ReproducerGenerate::ReproducerGenerate(std::error_code &EC, int Argc, |
37 | char **Argv, bool GenerateOnExit) |
38 | : Root(createReproducerDir(EC)), GenerateOnExit(GenerateOnExit) { |
39 | for (int I = 0; I < Argc; ++I) |
40 | Args.push_back(Elt: Argv[I]); |
41 | if (!Root.empty()) |
42 | FC = std::make_shared<FileCollector>(args&: Root, args&: Root); |
43 | VFS = FileCollector::createCollectorVFS(BaseFS: vfs::getRealFileSystem(), Collector: FC); |
44 | } |
45 | |
46 | ReproducerGenerate::~ReproducerGenerate() { |
47 | if (GenerateOnExit && !Generated) |
48 | generate(); |
49 | else if (!Generated && !Root.empty()) |
50 | sys::fs::remove_directories(path: Root, /* IgnoreErrors */ true); |
51 | } |
52 | |
53 | void ReproducerGenerate::generate() { |
54 | if (!FC) |
55 | return; |
56 | Generated = true; |
57 | FC->copyFiles(StopOnError: false); |
58 | SmallString<128> Mapping(Root); |
59 | sys::path::append(path&: Mapping, a: "mapping.yaml" ); |
60 | FC->writeMapping(MappingFile: 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 | |
71 | ReproducerUse::~ReproducerUse() = default; |
72 | |
73 | ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) { |
74 | SmallString<128> Mapping(Root); |
75 | sys::path::append(path&: Mapping, a: "mapping.yaml" ); |
76 | ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = |
77 | vfs::getRealFileSystem()->getBufferForFile(Name: Mapping.str()); |
78 | |
79 | if (!Buffer) { |
80 | EC = Buffer.getError(); |
81 | return; |
82 | } |
83 | |
84 | VFS = llvm::vfs::getVFSFromYAML(Buffer: std::move(Buffer.get()), DiagHandler: nullptr, YAMLFilePath: Mapping); |
85 | } |
86 | |
87 | llvm::Expected<std::unique_ptr<Reproducer>> |
88 | Reproducer::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>(args&: EC, args&: Argc, args&: Argv, args: true); |
96 | break; |
97 | case ReproducerMode::GenerateOnCrash: |
98 | Repro = std::make_unique<ReproducerGenerate>(args&: EC, args&: Argc, args&: Argv, args: false); |
99 | break; |
100 | case ReproducerMode::Use: |
101 | Repro = std::make_unique<ReproducerUse>(args&: Root, args&: 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 | |