summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild-prebuilts.sh3
l---------interceptor/.clang-format1
-rw-r--r--interceptor/Android.bp58
-rw-r--r--interceptor/CMakeLists.txt54
-rw-r--r--interceptor/OWNERS2
-rw-r--r--interceptor/analysis.cc221
-rw-r--r--interceptor/interceptor.cc344
-rw-r--r--interceptor/interceptor.h47
-rw-r--r--interceptor/log.proto55
-rw-r--r--interceptor/main.cc162
10 files changed, 0 insertions, 947 deletions
diff --git a/build-prebuilts.sh b/build-prebuilts.sh
index 8925111..fd5736b 100755
--- a/build-prebuilts.sh
+++ b/build-prebuilts.sh
@@ -36,8 +36,6 @@ EOF
e2fsck
e2fsdroid
img2simg
- interceptor
- interceptor_analysis
lpmake
lz4
mkbootfs
@@ -57,7 +55,6 @@ EOF
SOONG_LIBRARIES=(
libcrypto-host.so
libelf.so
- libinterceptor.so
)
binaries="${SOONG_BINARIES[@]/#/${SOONG_HOST_OUT}/bin/}"
diff --git a/interceptor/.clang-format b/interceptor/.clang-format
deleted file mode 120000
index 5f196c3..0000000
--- a/interceptor/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../../../build/soong/scripts/system-clang-format-2 \ No newline at end of file
diff --git a/interceptor/Android.bp b/interceptor/Android.bp
deleted file mode 100644
index c538546..0000000
--- a/interceptor/Android.bp
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_defaults {
- name: "interceptor_defaults",
- static_libs: [
- "libc++fs",
- "libinterceptor_log",
- "libprotobuf-cpp-full",
- ],
-}
-
-cc_library_host_shared {
- name: "libinterceptor",
- srcs: ["interceptor.cc"],
- defaults: ["interceptor_defaults"],
- static_libs: [
- "libbase",
- ],
-}
-
-cc_library_host_static {
- name: "libinterceptor_log",
- srcs: ["log.proto"],
- proto: {
- type: "full",
- static: true,
- export_proto_headers: true,
- canonical_path_from_root: false,
- },
-}
-
-cc_binary_host {
- name: "interceptor",
- srcs: ["main.cc"],
- defaults: ["interceptor_defaults"],
-}
-
-cc_binary_host {
- name: "interceptor_analysis",
- srcs: ["analysis.cc"],
- defaults: ["interceptor_defaults"],
-
- // unused parameters in protobuf/stubs/bytestream.h
- cflags: ["-Wno-error=unused-parameter"],
-}
diff --git a/interceptor/CMakeLists.txt b/interceptor/CMakeLists.txt
deleted file mode 100644
index 13eefb0..0000000
--- a/interceptor/CMakeLists.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Copyright (C) 2021 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-cmake_minimum_required(VERSION 3.21)
-
-Project(interceptor)
-
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
-set(CMAKE_POSITION_INDEPENDENT_CODE ON)
-set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) # LTO
-
-set(EXECUTABLE_OUTPUT_PATH bin)
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY lib64)
-
-find_package(Protobuf REQUIRED)
-
-# just enough libbase from the android-base
-add_library(android-base STATIC ../../../system/libbase/strings.cpp)
-target_include_directories(android-base SYSTEM PUBLIC ../../../system/libbase/include/ )
-
-# interceptor_log - the protobuf library
-include_directories(${Protobuf_INCLUDE_DIRS})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS log.proto)
-add_library(interceptor_log STATIC ${PROTO_SRCS} ${PROTO_HDRS})
-target_link_libraries(interceptor_log ${Protobuf_LIBRARIES})
-
-set(common_libraries interceptor_log android-base)
-
-# libinterceptor.so
-add_library(libinterceptor SHARED interceptor.cc)
-target_link_libraries(libinterceptor ${common_libraries})
-set_target_properties(libinterceptor PROPERTIES LIBRARY_OUTPUT_NAME interceptor)
-
-# interceptor
-add_executable(interceptor main.cc)
-target_link_libraries(interceptor ${common_libraries})
-
-# interceptor_analysis
-add_executable(interceptor_analysis analysis.cc)
-target_link_libraries(interceptor_analysis ${common_libraries})
diff --git a/interceptor/OWNERS b/interceptor/OWNERS
deleted file mode 100644
index 91a69d0..0000000
--- a/interceptor/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-maennich@google.com
-elsk@google.com
diff --git a/interceptor/analysis.cc b/interceptor/analysis.cc
deleted file mode 100644
index 03292af..0000000
--- a/interceptor/analysis.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <getopt.h>
-#include <google/protobuf/text_format.h>
-#include <google/protobuf/util/json_util.h>
-#include <sysexits.h>
-#include <cstdlib>
-#include <cstring>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <iterator>
-#include <unordered_set>
-
-#include "log.pb.h"
-
-namespace fs = std::filesystem;
-
-enum class OutputFormat { TEXT, COMPDB };
-
-struct Options {
- fs::path command_log;
- OutputFormat output_format = OutputFormat::TEXT;
- fs::path output;
-};
-
-static Options parse_arguments(int argc, char* argv[]) {
- Options result;
-
- const static option opts[] = {
- {"command-log", required_argument, nullptr, 'l'},
- {"output-type", required_argument, nullptr, 't'},
- {"output", required_argument, nullptr, 'o'},
- {nullptr, 0, nullptr, 0},
- };
- const auto usage = [&]() {
- std::cerr << "usage: " << argv[0] << '\n'
- << " -l|--command-log filename\n"
- << " -o|--output filename\n"
- << " [-t|--output-type (text|compdb)]\n";
- exit(EX_USAGE);
- };
- while (true) {
- int ix;
- int c = getopt_long(argc, argv, "-l:t:o:", opts, &ix);
- if (c == -1) {
- break;
- }
- switch (c) {
- case 'l':
- result.command_log = fs::absolute(optarg);
- break;
- case 't':
- if (strcmp(optarg, "text") == 0) {
- result.output_format = OutputFormat::TEXT;
- }
- if (strcmp(optarg, "compdb") == 0) {
- result.output_format = OutputFormat::COMPDB;
- } else {
- usage();
- }
- break;
- case 'o':
- result.output = fs::absolute(optarg);
- break;
- default:
- usage();
- }
- }
-
- if (result.command_log.empty() || result.output.empty()) {
- usage();
- }
-
- if (!fs::exists(result.command_log)) {
- std::cerr << "No such file: " << result.command_log << "\n";
- }
-
- return result;
-}
-
-interceptor::Log read_log(const fs::path& log_file) {
- interceptor::Log result;
- std::ifstream input(log_file);
- if (!input) {
- std::cerr << "Could not open input file for reading.\n";
- exit(EX_NOINPUT);
- }
- result.ParseFromIstream(&input);
- return result;
-}
-
-void text_to_file(const interceptor::Log& log, const fs::path& output) {
- std::string content;
- google::protobuf::TextFormat::PrintToString(log, &content);
- std::ofstream os(output);
- if (!os) {
- std::cerr << "Could not open output file for writing.\n";
- exit(EX_CANTCREAT);
- }
- os << content;
- if (!os.flush()) {
- std::cerr << "Failed to write to output file.\n";
- exit(EX_CANTCREAT);
- }
-}
-
-void compdb_to_file(const interceptor::Log& log, const fs::path& output) {
- static const std::unordered_set<std::string_view> kCompileExtensions = {
- ".c", ".cc", ".cpp", ".cxx", ".S",
- };
- static const std::unordered_set<std::string_view> kCompilers = {
- "clang",
- "clang++",
- "gcc",
- "g++",
- };
-
- interceptor::CompilationDatabase compdb;
-
- for (const auto& command : log.commands()) {
- if (command.arguments().empty()) {
- continue;
- }
-
- // skip anything that is not a compiler invocation
- if (!kCompilers.count(fs::path(command.arguments(0)).filename().native())) {
- continue;
- }
-
- // determine if we have a uniquely identifyable output
- const std::string single_output = [&]() {
- std::vector<std::string> outputs;
- for (const auto& output : command.outputs()) {
- // skip .d files. They are conventionally used for make dependency files
- if (fs::path(output).extension() != ".d") {
- outputs.push_back(output);
- }
- }
- return (outputs.size() == 1) ? outputs[0] : "";
- }();
-
- // skip preprocessor invocations
- if (std::find(command.arguments().cbegin(), command.arguments().cend(), "-E") !=
- command.arguments().cend()) {
- continue;
- }
-
- // now iterate over all inputs, emitting an entry for each source file
- for (const auto& input : command.inputs()) {
- // skip anything that does not look like a source file (object files,
- // force included headers, etc.)
- if (!kCompileExtensions.count(fs::path(input).extension().native())) {
- continue;
- }
-
- // ok, now we have a new command
- auto& compile_command = *compdb.add_commands();
-
- compile_command.set_directory(fs::path(log.root_directory()) / command.current_directory());
- compile_command.set_file(input);
- if (!single_output.empty()) {
- compile_command.set_output(single_output);
- }
- *compile_command.mutable_arguments() = {command.arguments().cbegin(),
- command.arguments().cend()};
- }
- }
-
- std::ofstream out(output);
-
- if (!compdb.commands_size()) {
- out << "[]\n";
- return;
- }
-
- std::string out_str;
- auto options = google::protobuf::util::JsonPrintOptions{};
- options.add_whitespace = true;
- google::protobuf::util::MessageToJsonString(compdb, &out_str, options);
-
- // this would emit {"command":[yadayada]}, but we want only [yadayada]
- // the additional characters come from options.add_whitespace
- //
- // TODO: make this better, but as of now there is not much we can do as
- // util::MessageToJsonString() takes a message and that is always represented
- // as a dictionary, while the top level structure of compile_command.json is
- // an array. So, we have to chop of the leading and trailing characters to
- // find the contained array.
- const auto left_offset = out_str.find('[');
- const auto length = out_str.rfind(']') - left_offset + 1;
- out << std::string_view(out_str).substr(left_offset, length);
-}
-
-int main(int argc, char* argv[]) {
- const auto options = parse_arguments(argc, argv);
- const auto log = read_log(options.command_log);
-
- switch (options.output_format) {
- case OutputFormat::TEXT:
- text_to_file(log, options.output);
- break;
- case OutputFormat::COMPDB:
- compdb_to_file(log, options.output);
- break;
- }
-}
diff --git a/interceptor/interceptor.cc b/interceptor/interceptor.cc
deleted file mode 100644
index 8ce5cb7..0000000
--- a/interceptor/interceptor.cc
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "interceptor.h"
-
-#include <dlfcn.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <array>
-#include <filesystem>
-#include <fstream>
-#include <initializer_list>
-#include <iomanip>
-#include <iostream>
-#include <iterator>
-#include <regex>
-#include <sstream>
-#include <string>
-#include <string_view>
-#include <type_traits>
-#include <utility>
-
-#include <android-base/strings.h>
-#include <google/protobuf/util/delimited_message_util.h>
-
-namespace fs = std::filesystem;
-
-// UTILITY function declarations
-
-// process applicable calls (i.e. programs that we might be able to handle)
-static void process_command(const char* filename, char* const argv[], char* const envp[]);
-
-// log command if logging is enabled
-static void log(const interceptor::Command&);
-
-// execute potentially modified command
-static void execute(const interceptor::Command&, char* const envp[]);
-
-// OVERLOADS for LD_PRELOAD USE
-
-// Intercept execve calls, for that capture the original execve call
-static auto const old_execve = reinterpret_cast<decltype(execve)*>(dlsym(RTLD_NEXT, "execve"));
-
-extern "C" {
-int execve(const char* filename, char* const argv[], char* const envp[]) {
- // pass on to process_command(), if unhandled, fall back to the original
- // execve
- process_command(filename, argv, envp);
- return old_execve(filename, argv, envp);
-}
-} // extern "C"
-
-// LIBRARY IMPLEMENTATION
-
-namespace interceptor {
-
-static Command instantiate_command(const char* program, char* const argv[], char* const envp[]) {
- Command result;
- result.set_program(program);
- result.set_current_directory(fs::current_path());
-
- for (auto current_argument = argv; *current_argument; ++current_argument) {
- result.add_arguments(*current_argument);
- }
-
- for (auto current_env_var = envp; *current_env_var; ++current_env_var) {
- const std::string s(*current_env_var);
- const auto pos = s.find('=');
- if (pos == std::string::npos) {
- continue;
- }
-
- (*result.mutable_environment_variables())[s.substr(0, pos)] = s.substr(pos + 1);
- }
-
- return result;
-}
-
-static void make_relative(Command* command) {
- // determine the ROOT_DIR
- std::string root_directory;
- if (auto it = command->environment_variables().find(kEnvRootDirectory);
- it != command->environment_variables().cend()) {
- root_directory = it->second;
- if (root_directory[root_directory.size() - 1] != '/') {
- root_directory += '/';
- }
- } else {
- return;
- }
-
- // determine the relative path to ROOT_DIR from the current working dir
- std::string relative_root = fs::relative(root_directory);
- if (relative_root[relative_root.size() - 1] != '/') {
- relative_root += '/';
- }
- if (relative_root == "./") {
- relative_root.clear();
- }
-
- // TODO: This is generally bad as this means we can't make anything relative.
- // This happens if the out dir is outside of the root.
- if (relative_root.find(root_directory) != std::string::npos) {
- return;
- }
-
- command->set_current_directory(fs::relative(command->current_directory(), root_directory));
-
- // replacement functor
- const auto replace_all = [&](auto& str) {
- auto pos = std::string::npos;
- while ((pos = str.find(root_directory)) != std::string::npos) {
- str.replace(pos, root_directory.length(), relative_root);
- }
- };
-
- // now go and replace everything
- replace_all(*command->mutable_program());
- std::for_each(command->mutable_arguments()->begin(), command->mutable_arguments()->end(), replace_all);
-}
-
-template <typename V>
-static void dump_vector(std::ostream& os, const V& vec) {
- bool comma = false;
- for (const auto& e : vec) {
- if (comma) {
- os << ", ";
- }
- os << std::quoted(e);
- comma = true;
- }
-}
-
-std::ostream& operator<<(std::ostream& os, const interceptor::Command& command) {
-
- os << "[(";
- dump_vector(os, command.inputs());
- os << ") => (";
- dump_vector(os, command.outputs());
- os << ")] ";
-
- // TODO: chain output iterators instead and find a common expression
- const static auto escape = [](auto in) {
- in = android::base::StringReplace(in, "\t", "\\t", true);
- in = android::base::StringReplace(in, "\n", "\\n", true);
- return in;
- };
-
- std::ostringstream cmd;
- cmd << command.program();
- for (auto I = std::next(command.arguments().cbegin()), E = command.arguments().cend(); I != E; ++I) {
- cmd << ' ' << escape(*I);
- }
-
- os << cmd.str();
- return os;
-
-}
-
-static AnalysisResult analyze_command(const interceptor::Command& command);
-
-static void analyze(Command* command) {
- auto [inputs, outputs] = analyze_command(*command);
-
- // TODO: this sanitizing should be done during make_relative
- for (auto& input : inputs) {
- if (input.rfind("./", 0) == 0) {
- input = input.substr(2);
- }
- }
- for (auto& output : outputs) {
- if (output.rfind("./", 0) == 0) {
- output = output.substr(2);
- }
- }
- for (const auto& input : inputs) {
- if (!fs::is_regular_file(input)) {
- std::cerr << "missing input: " << input << "\n" << *command << "\n";
- exit(1);
- }
- }
-
- *command->mutable_inputs() = {inputs.cbegin(), inputs.cend()};
- *command->mutable_outputs() = {outputs.cbegin(), outputs.cend()};
-}
-
-/// COMMAND ANALYSIS
-
-using Analyzer = std::function<AnalysisResult(const std::string&, const ArgVec&, const EnvMap&)>;
-
-static AnalysisResult analyze_compiler_linker(const std::string&, const ArgVec& arguments,
- const EnvMap&) {
- static constexpr std::array kSkipNextArguments{
- "-isystem", "-I", "-L", "-m", "-soname", "-z",
- };
- static constexpr std::string_view kOutputOption = "-Wp,-MMD,";
-
- AnalysisResult result;
- bool next_is_out = false;
- bool skip_next = false;
- // skip arguments[0] as this is the program itself
- for (auto it = arguments.cbegin() + 1; it != arguments.cend(); ++it) {
- const auto& argument = *it;
- if (argument == "-o") {
- next_is_out = true;
- continue;
- }
- if (next_is_out) {
- result.outputs.push_back(argument);
- next_is_out = false;
- continue;
- }
- if (argument.rfind(kOutputOption, 0) == 0) {
- result.outputs.push_back(argument.substr(kOutputOption.size()));
- }
- if (skip_next) {
- skip_next = false;
- continue;
- }
- if (std::find(kSkipNextArguments.cbegin(), kSkipNextArguments.cend(), argument) !=
- kSkipNextArguments.cend()) {
- skip_next = true;
- }
- // ignore test compilations
- if (argument == "/dev/null" || argument == "-") {
- return {};
- }
- if (argument[0] == '-') { // ignore flags
- continue;
- }
- result.inputs.push_back(argument);
- }
-
- return result;
-}
-
-static AnalysisResult analyze_archiver(const std::string&, const ArgVec& arguments, const EnvMap&) {
- AnalysisResult result;
-
- if (arguments.size() < 3) {
- return result;
- }
- // skip arguments[0] as this is the program itself
- // skip arguments[1] are the archiver flags
- // arguments[2] is the output
- result.outputs.push_back(arguments[2]);
- // arguments[3:] are the inputs
- result.inputs.insert(result.inputs.cend(), arguments.cbegin() + 3, arguments.cend());
- return result;
-}
-
-static const std::initializer_list<std::pair<std::regex, Analyzer>> analyzers{
- {
- std::regex("^(.*/)?(clang|clang\\+\\+|gcc|g\\+\\+|ld(\\.lld)?|llvm-strip)$"),
- analyze_compiler_linker,
- },
- {
- std::regex("^(.*/)?(llvm-)?ar$"),
- analyze_archiver,
- },
-};
-
-static AnalysisResult analyze_command(const Command& command) {
- for (const auto& [regex, analyzer] : analyzers) {
- if (std::regex_match(command.arguments()[0], regex)) {
- return analyzer(command.program(), command.arguments(), command.environment_variables());
- }
- }
- return {};
-}
-
-} // namespace interceptor
-
-/// UTILITY FUNCTIONS
-
-static void process_command(const char* filename, char* const argv[], char* const envp[]) {
- // First, try to find out whether we at all can handle this command. If not,
- // simply return and fall back to the original handler.
-
- if (!fs::is_regular_file(filename)) {
- return;
- }
-
- // Ok, we can handle that one, let's transform it.
-
- auto command = interceptor::instantiate_command(filename, argv, envp);
-
- // rewrite all command line arguments (including the program itself) to use
- // paths relative to ROOT_DIR. This is essential for reproducible builds and
- // furthermore necessary to produce cache hits in RBE.
- make_relative(&command);
-
- analyze(&command);
-
- log(command);
-
- // pass down the transformed command to execve
- execute(command, envp);
-}
-
-static void log(const interceptor::Command& command) {
- const auto& env = command.environment_variables();
-
- if (const auto env_it = env.find(kEnvCommandLog); env_it != env.cend()) {
- std::ofstream file;
- file.open(std::string(env_it->second),
- std::ofstream::out | std::ofstream::app | std::ofstream::binary);
- interceptor::Message message;
- *message.mutable_command() = command;
- message.mutable_command()->clear_environment_variables();
- if (file.is_open()) {
- google::protobuf::util::SerializeDelimitedToOstream(message, &file);
- }
- }
-}
-
-static void execute(const interceptor::Command& command, char* const envp[]) {
- std::vector<const char*> c_arguments;
- c_arguments.reserve(command.arguments().size() + 1);
- c_arguments[command.arguments().size()] = nullptr;
- for (const auto& arg : command.arguments()) {
- c_arguments.push_back(arg.data());
- }
- // TODO: at this point, we could free some memory that is held in Command.
- // While the arguments vector is reused for arguments, we could free
- // the EnvMap and the original arguments.
-
- // does not return
- old_execve(command.program().c_str(), const_cast<char**>(c_arguments.data()), envp);
-}
diff --git a/interceptor/interceptor.h b/interceptor/interceptor.h
deleted file mode 100644
index 6bf349e..0000000
--- a/interceptor/interceptor.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <functional>
-#include <optional>
-#include <string>
-#include <type_traits>
-#include <unordered_map>
-#include <vector>
-
-#include "log.pb.h"
-
-// Options passed via environment variables from the interceptor starter
-constexpr static auto kEnvCommandLog = "INTERCEPTOR_command_log";
-constexpr static auto kEnvRootDirectory = "INTERCEPTOR_root_directory";
-
-namespace interceptor {
-
-// Some type definitions to gain some type safety
-using ArgVec = std::remove_pointer_t<decltype(Command().mutable_arguments())>;
-using EnvMap = std::remove_pointer_t<decltype(Command().mutable_environment_variables())>;
-
-using Inputs = std::vector<std::string>;
-using Outputs = Inputs;
-
-std::ostream& operator<<(std::ostream& os, const interceptor::Command& command);
-
-// Command analysis
-
-struct AnalysisResult {
- Inputs inputs;
- Outputs outputs;
-};
-} // namespace interceptor
diff --git a/interceptor/log.proto b/interceptor/log.proto
deleted file mode 100644
index 7bd027c..0000000
--- a/interceptor/log.proto
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto3";
-
-package interceptor;
-
-// A Command as traced by intercepting an execve() invocation.
-message Command {
- string program = 1;
- repeated string arguments = 2;
- map<string, string> environment_variables = 3;
- string current_directory = 4;
- repeated string inputs = 5;
- repeated string outputs = 6;
-};
-
-// A single message as emitted by an intercepted process. It can contain any of
-// the above messages.
-message Message {
- oneof message { Command command = 1; }
-}
-
-// The entirety of a the final log should be stored as just this Log.
-message Log {
- string root_directory = 1; // ${ROOT_DIR} or cwd() if unset
- repeated Command commands = 2;
-}
-
-// A compile_command.json entry as specified in
-// https://clang.llvm.org/docs/JSONCompilationDatabase.html
-message CompileCommand {
- string directory = 1;
- string file = 2;
- string command = 3;
- repeated string arguments = 4;
- string output = 5;
-}
-
-message CompilationDatabase {
- repeated CompileCommand commands = 1;
-}
diff --git a/interceptor/main.cc b/interceptor/main.cc
deleted file mode 100644
index 16082a7..0000000
--- a/interceptor/main.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <getopt.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <cstdlib>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <optional>
-#include <sstream>
-
-#include <google/protobuf/util/delimited_message_util.h>
-
-#include "interceptor.h"
-
-namespace fs = std::filesystem;
-
-struct Options {
- std::string command_line;
- std::optional<fs::path> command_log;
-};
-
-static Options parse_args(int argc, char* argv[]) {
- Options result;
-
- while (1) {
- static struct option long_options[] = {{"command-log", required_argument, 0, 'l'},
- {0, 0, 0, 0}};
- /* getopt_long stores the option index here. */
- int option_index = 0;
-
- auto c = getopt_long(argc, argv, "l:", long_options, &option_index);
-
- /* Detect the end of the options. */
- if (c == -1) {
- break;
- }
-
- switch (c) {
- case 'l':
- result.command_log = fs::absolute(optarg);
- break;
-
- case '?':
- /* getopt_long already printed an error message. */
- break;
-
- default:
- abort();
- }
- }
-
- std::stringstream ss;
- if (optind < argc) {
- while (optind < argc) {
- ss << argv[optind++];
- ss << ' ';
- }
- }
- result.command_line = ss.str();
-
- return result;
-}
-
-static void setup_interceptor_library_path() {
- auto interceptor_library = fs::read_symlink("/proc/self/exe").parent_path().parent_path() /
- "lib64" / "libinterceptor.so";
- while (fs::is_symlink(interceptor_library)) {
- interceptor_library = fs::read_symlink(interceptor_library);
- }
- if (!fs::is_regular_file(interceptor_library)) {
- std::cerr << "Interceptor library could not be found!\n";
- exit(EX_CONFIG);
- }
- setenv("LD_PRELOAD", interceptor_library.c_str(), 1);
-}
-
-static fs::path set_up_root_directory() {
- const auto root_directory = getenv("ROOT_DIR");
- fs::path result;
- if (root_directory != nullptr) {
- result = root_directory;
- } else {
- result = fs::current_path();
- }
-
- setenv(kEnvRootDirectory, result.c_str(), 1);
-
- return result;
-}
-
-class CommandLog {
- const decltype(Options::command_log) command_log_file_;
- const fs::path root_directory_;
-
- public:
- CommandLog(decltype(command_log_file_) command_log_file, const fs::path& root_directory)
- : command_log_file_(std::move(command_log_file)), root_directory_(root_directory) {
- if (command_log_file_) {
- setenv(kEnvCommandLog, command_log_file_->c_str(), 1);
- std::ofstream command_log(command_log_file_->c_str(), std::ios_base::trunc);
- if (!command_log) {
- std::cerr << "Could not open command log for writing: " << *command_log_file_ << "\n";
- exit(EX_CANTCREAT);
- }
- }
- }
-
- ~CommandLog() {
- if (command_log_file_) {
- // compact the log by re-reading the individual log::Message's to combine
- // them to a log::Log
- interceptor::Log log;
- log.set_root_directory(root_directory_);
- {
- std::ifstream command_log(command_log_file_->c_str(), std::ios_base::binary);
-
- google::protobuf::io::IstreamInputStream input_stream(&command_log);
- interceptor::Message message;
- while (true) {
- if (!google::protobuf::util::ParseDelimitedFromZeroCopyStream(&message, &input_stream,
- nullptr)) {
- break;
- }
- if (message.has_command()) {
- log.add_commands()->Swap(message.release_command());
- }
- }
- }
- std::ofstream command_log(command_log_file_->c_str(), std::ios_base::binary);
- log.SerializeToOstream(&command_log);
- }
- }
-};
-
-int main(int argc, char* argv[]) {
- const auto& options = parse_args(argc, argv);
-
- setup_interceptor_library_path();
- const auto root_directory = set_up_root_directory();
-
- CommandLog command_log(options.command_log, root_directory);
-
- // TODO: cleanly to google::protobuf::ShutdownProtobufLibrary();
-
- return std::system(options.command_line.c_str());
-}