• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <cstdlib>
16 #include <memory>
17 #include <string>
18 #include <vector>
19 
20 #include "absl/base/attributes.h"
21 #include "absl/base/no_destructor.h"
22 #include "absl/status/status.h"
23 #include "absl/strings/match.h"
24 #include "absl/strings/str_format.h"
25 #include "clang/Tooling/CommonOptionsParser.h"
26 #include "clang/Tooling/CompilationDatabase.h"
27 #include "clang/Tooling/Tooling.h"
28 #include "llvm/Support/CommandLine.h"
29 #include "llvm/Support/Error.h"
30 #include "sandboxed_api/tools/clang_generator/compilation_database.h"
31 #include "sandboxed_api/tools/clang_generator/emitter.h"
32 #include "sandboxed_api/tools/clang_generator/generator.h"
33 #include "sandboxed_api/util/file_helpers.h"
34 #include "sandboxed_api/util/fileops.h"
35 #include "sandboxed_api/util/path.h"
36 #include "sandboxed_api/util/status_macros.h"
37 
38 namespace sapi {
39 namespace {
40 
41 absl::NoDestructor<llvm::cl::OptionCategory> g_tool_category(
42     "Sandboxed API Options");
43 
44 absl::NoDestructor<llvm::cl::extrahelp> g_common_help(
45     clang::tooling::CommonOptionsParser::HelpMessage);
46 absl::NoDestructor<llvm::cl::extrahelp> g_extra_help(
47     "Full documentation at: "
48     "<https://developers.google.com/code-sandboxing/sandboxed-api>\n"
49     "Report bugs to <https://github.com/google/sandboxed-api/issues>\n");
50 
51 // Command line options
52 absl::NoDestructor<llvm::cl::opt<std::string>> g_sapi_embed_dir(
53     "sapi_embed_dir", llvm::cl::desc("Directory with embedded includes"),
54     llvm::cl::cat(*g_tool_category));
55 
56 absl::NoDestructor<llvm::cl::opt<std::string>> g_sapi_embed_name(
57     "sapi_embed_name", llvm::cl::desc("Identifier of the embed object"),
58     llvm::cl::cat(*g_tool_category));
59 
60 absl::NoDestructor<llvm::cl::list<std::string>> g_sapi_functions(
61     "sapi_functions", llvm::cl::CommaSeparated,
62     llvm::cl::desc("List of functions to generate a Sandboxed API for. If "
63                    "empty, generates a SAPI for all functions found."),
64     llvm::cl::cat(*g_tool_category));
65 
66 ABSL_DEPRECATED("Pass the input files directly to the tool.")
67 absl::NoDestructor<llvm::cl::list<std::string>> g_sapi_in(
68     "sapi_in", llvm::cl::CommaSeparated,
69     llvm::cl::desc("List of input files to analyze (DEPRECATED)"),
70     llvm::cl::cat(*g_tool_category));
71 
72 ABSL_DEPRECATED("Ignored for compatibility.")
73 absl::NoDestructor<llvm::cl::opt<std::string>> g_sapi_isystem(
74     "sapi_isystem",
75     llvm::cl::desc(
76         "Parameter file with extra system include paths (DEPRECATED)"),
77     llvm::cl::cat(*g_tool_category));
78 
79 absl::NoDestructor<llvm::cl::opt<bool>> g_sapi_limit_scan_depth(
80     "sapi_limit_scan_depth",
81     llvm::cl::desc("Whether to only scan for functions "
82                    "in the top-most translation unit"),
83     llvm::cl::cat(*g_tool_category));
84 
85 absl::NoDestructor<llvm::cl::opt<std::string>> g_sapi_name(
86     "sapi_name", llvm::cl::desc("Name of the Sandboxed API library"),
87     llvm::cl::cat(*g_tool_category));
88 
89 absl::NoDestructor<llvm::cl::opt<std::string>> g_sapi_ns(
90     "sapi_ns", llvm::cl::desc("C++ namespace to wrap Sandboxed API class in"),
91     llvm::cl::cat(*g_tool_category));
92 
93 absl::NoDestructor<llvm::cl::opt<std::string>> g_sapi_out(
94     "sapi_out",
95     llvm::cl::desc("Output path of the generated header. If empty, simply "
96                    "appends .sapi.h "
97                    "to the basename of the first source file specified."),
98     llvm::cl::cat(*g_tool_category));
99 
100 }  // namespace
101 
GeneratorOptionsFromFlags(const std::vector<std::string> & sources)102 GeneratorOptions GeneratorOptionsFromFlags(
103     const std::vector<std::string>& sources) {
104   GeneratorOptions options;
105   options.work_dir = file_util::fileops::GetCWD();
106   options.set_function_names(*g_sapi_functions);
107   for (const auto& input : sources) {
108     // Keep absolute paths as is, turn
109     options.in_files.insert(absl::StartsWith(input, "/")
110                                 ? input
111                                 : file::JoinPath(options.work_dir, input));
112   }
113   options.set_limit_scan_depth(*g_sapi_limit_scan_depth);
114   options.name = *g_sapi_name;
115   options.namespace_name = *g_sapi_ns;
116   options.out_file =
117       !g_sapi_out->empty() ? *g_sapi_out : GetOutputFilename(sources.front());
118   options.embed_dir = *g_sapi_embed_dir;
119   options.embed_name = *g_sapi_embed_name;
120   return options;
121 }
122 
GeneratorMain(int argc,char * argv[])123 absl::Status GeneratorMain(int argc, char* argv[]) {
124   auto expected_opt_parser = OptionsParser::create(
125       argc, const_cast<const char**>(argv), *g_tool_category,
126       llvm::cl::ZeroOrMore,
127       "Generates a Sandboxed API header for C/C++ translation units.");
128   if (!expected_opt_parser) {
129     return absl::InternalError(llvm::toString(expected_opt_parser.takeError()));
130   }
131   OptionsParser& opt_parser = expected_opt_parser.get();
132 
133   std::vector<std::string> sources = opt_parser.getSourcePathList();
134   for (const auto& sapi_in : *g_sapi_in) {  // NOLINT
135     sources.push_back(sapi_in);
136   }
137   if (sources.empty()) {
138     return absl::InvalidArgumentError("Error: No input files.");
139   }
140 
141   auto options = GeneratorOptionsFromFlags(sources);
142 
143   std::unique_ptr<clang::tooling::CompilationDatabase> db =
144       FromCxxAjustedCompileCommands(
145           NonOwningCompileCommands(opt_parser.getCompilations()));
146   clang::tooling::ClangTool tool(*db, sources);
147 
148   if (!g_sapi_isystem->empty()) {  // NOLINT(deprecated)
149     absl::FPrintF(
150         stderr,
151         "Note: Ignoring deprecated command-line option: sapi_isystem\n");
152   }
153 
154   // Process SAPI header generation.
155   Emitter emitter;
156   if (int result =
157           tool.run(std::make_unique<GeneratorFactory>(emitter, options).get());
158       result != 0) {
159     return absl::UnknownError("Error: Header generation failed.");
160   }
161 
162   SAPI_ASSIGN_OR_RETURN(std::string header, emitter.EmitHeader(options));
163   SAPI_RETURN_IF_ERROR(
164       file::SetContents(options.out_file, header, file::Defaults()));
165   return absl::OkStatus();
166 }
167 
168 }  // namespace sapi
169 
main(int argc,char * argv[])170 int main(int argc, char* argv[]) {
171   if (absl::Status status = sapi::GeneratorMain(argc, argv); !status.ok()) {
172     absl::FPrintF(stderr, "%s\n", status.message());
173     return EXIT_FAILURE;
174   }
175   return EXIT_SUCCESS;
176 }
177