| 1 | //===- SSAFAnalyzer.cpp - SSAF Analyzer Tool ------------------------------===// |
| 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 | // This file implements the SSAF analyzer tool that runs whole-program |
| 10 | // analyses over an LUSummary and writes the resulting WPASuite to an |
| 11 | // output file. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummary.h" |
| 16 | #include "clang/ScalableStaticAnalysis/Core/WholeProgramAnalysis/AnalysisDriver.h" |
| 17 | #include "clang/ScalableStaticAnalysis/Core/WholeProgramAnalysis/AnalysisName.h" |
| 18 | #include "clang/ScalableStaticAnalysis/SSAFForceLinker.h" // IWYU pragma: keep |
| 19 | #include "clang/ScalableStaticAnalysis/Tool/Utils.h" |
| 20 | #include "llvm/ADT/SmallVector.h" |
| 21 | #include "llvm/Support/CommandLine.h" |
| 22 | #include "llvm/Support/InitLLVM.h" |
| 23 | #include <memory> |
| 24 | #include <string> |
| 25 | |
| 26 | using namespace llvm; |
| 27 | using namespace clang::ssaf; |
| 28 | |
| 29 | namespace { |
| 30 | |
| 31 | //===----------------------------------------------------------------------===// |
| 32 | // Command-Line Options |
| 33 | //===----------------------------------------------------------------------===// |
| 34 | |
| 35 | cl::OptionCategory SsafAnalyzerCategory("clang-ssaf-analyzer options" ); |
| 36 | |
| 37 | cl::opt<std::string> InputPath(cl::Positional, cl::desc("<input file>" ), |
| 38 | cl::Required, cl::cat(SsafAnalyzerCategory)); |
| 39 | |
| 40 | cl::opt<std::string> OutputPath("o" , cl::desc("Output file path" ), |
| 41 | cl::value_desc("path" ), cl::Required, |
| 42 | cl::cat(SsafAnalyzerCategory)); |
| 43 | |
| 44 | cl::list<std::string> AnalysisNames("a" , cl::desc("Analysis name to run" ), |
| 45 | cl::value_desc("name" ), |
| 46 | cl::cat(SsafAnalyzerCategory)); |
| 47 | |
| 48 | cl::alias AnalysisNamesAlias("analysis" , cl::aliasopt(AnalysisNames), |
| 49 | cl::desc("Alias for -a" )); |
| 50 | |
| 51 | cl::list<std::string> LoadPlugins("load" , |
| 52 | cl::desc("Load a plugin shared library" ), |
| 53 | cl::value_desc("path" ), |
| 54 | cl::cat(SsafAnalyzerCategory)); |
| 55 | |
| 56 | cl::alias LoadPluginsAlias("l" , cl::aliasopt(LoadPlugins), |
| 57 | cl::desc("Alias for --load" )); |
| 58 | |
| 59 | //===----------------------------------------------------------------------===// |
| 60 | // Input Validation |
| 61 | //===----------------------------------------------------------------------===// |
| 62 | |
| 63 | struct AnalyzerInput { |
| 64 | FormatFile InputFile; |
| 65 | FormatFile OutputFile; |
| 66 | llvm::SmallVector<AnalysisName> Names; |
| 67 | }; |
| 68 | |
| 69 | AnalyzerInput validate() { |
| 70 | AnalyzerInput AI; |
| 71 | |
| 72 | // Validate the input path. |
| 73 | AI.InputFile = FormatFile::fromInputPath(Path: InputPath); |
| 74 | |
| 75 | // Validate the output path. |
| 76 | AI.OutputFile = FormatFile::fromOutputPath(Path: OutputPath); |
| 77 | |
| 78 | // Build and validate analysis names. |
| 79 | for (const auto &Name : AnalysisNames) { |
| 80 | if (Name.empty()) { |
| 81 | fail(Msg: "analysis name must not be empty" ); |
| 82 | } |
| 83 | AI.Names.push_back(Elt: AnalysisName(Name)); |
| 84 | } |
| 85 | |
| 86 | return AI; |
| 87 | } |
| 88 | |
| 89 | //===----------------------------------------------------------------------===// |
| 90 | // Analysis Pipeline |
| 91 | //===----------------------------------------------------------------------===// |
| 92 | |
| 93 | void analyze(const AnalyzerInput &AI) { |
| 94 | // Read the LUSummary. |
| 95 | auto ExpectedLU = AI.InputFile.Format->readLUSummary(Path: AI.InputFile.Path); |
| 96 | if (!ExpectedLU) { |
| 97 | fail(Err: ExpectedLU.takeError()); |
| 98 | } |
| 99 | |
| 100 | // Run analyses. If specific names were given, run only those; |
| 101 | // otherwise run all registered analyses. |
| 102 | AnalysisDriver Driver(std::make_unique<LUSummary>(args: std::move(*ExpectedLU))); |
| 103 | auto ExpectedSuite = |
| 104 | AI.Names.empty() ? std::move(Driver).run() : Driver.run(Names: AI.Names); |
| 105 | if (!ExpectedSuite) { |
| 106 | fail(Err: ExpectedSuite.takeError()); |
| 107 | } |
| 108 | |
| 109 | // Write the WPASuite. |
| 110 | if (auto Err = AI.OutputFile.Format->writeWPASuite(Suite: *ExpectedSuite, |
| 111 | Path: AI.OutputFile.Path)) { |
| 112 | fail(Err: std::move(Err)); |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | } // namespace |
| 117 | |
| 118 | //===----------------------------------------------------------------------===// |
| 119 | // Driver |
| 120 | //===----------------------------------------------------------------------===// |
| 121 | |
| 122 | int main(int argc, const char **argv) { |
| 123 | llvm::StringRef ToolHeading = "SSAF Analyzer" ; |
| 124 | |
| 125 | InitLLVM X(argc, argv); |
| 126 | initTool(argc, argv, Version: "0.1" , Category&: SsafAnalyzerCategory, ToolHeading); |
| 127 | |
| 128 | loadPlugins(Paths: LoadPlugins); |
| 129 | |
| 130 | AnalyzerInput AI = validate(); |
| 131 | analyze(AI); |
| 132 | |
| 133 | return 0; |
| 134 | } |
| 135 | |