From c597c29cb0561f7404d3f9c4e045eb2f6f7b432c Mon Sep 17 00:00:00 2001 From: Brenden Blanco Date: Wed, 17 Feb 2016 19:26:01 -0800 Subject: [PATCH] Embed runtime header files in libbcc.so To avoid installing header files needed by clang to disk (/usr/share/bcc), embed the files as strings inside the library and feed them to clang as memory buffers. The mechanism that we use to do this retains all of the existing features, as in one can still do `#include `, even though it is redundant, and clang will pick up the embedded file. Fixes: #333 Signed-off-by: Brenden Blanco --- SPECS/bcc.el6.spec | 2 -- SPECS/bcc.el6.spec.in | 2 -- SPECS/bcc.el7.spec | 2 -- SPECS/bcc.el7.spec.in | 2 -- SPECS/bcc.f22.spec | 2 -- SPECS/bcc.f22.spec.in | 2 -- SPECS/bcc.spec | 2 -- debian/libbcc.install | 2 -- src/cc/CMakeLists.txt | 11 +------ src/cc/bpf_module.cc | 12 +++++-- src/cc/bpf_module.h | 2 +- src/cc/clang/include/stdarg.h | 2 ++ src/cc/export/helpers.h | 2 ++ src/cc/export/proto.h | 2 ++ src/cc/exported_files.cc | 42 +++++++++++++++++++++++ src/cc/exported_files.h | 30 +++++++++++++++++ src/cc/frontends/clang/kbuild_helper.cc | 2 +- src/cc/frontends/clang/loader.cc | 44 ++++++++++++++++++------- src/cc/frontends/clang/loader.h | 2 ++ 19 files changed, 125 insertions(+), 42 deletions(-) create mode 100644 src/cc/exported_files.cc create mode 100644 src/cc/exported_files.h diff --git a/SPECS/bcc.el6.spec b/SPECS/bcc.el6.spec index 9bf72554e557..f25e34ab30da 100644 --- a/SPECS/bcc.el6.spec +++ b/SPECS/bcc.el6.spec @@ -107,8 +107,6 @@ Python bindings for BPF Compiler Collection (BCC) %files -n libbcc /usr/lib64/* -/usr/share/bcc/include/* -/usr/share/bcc/lib/* /usr/include/bcc/* %files -n libbcc-examples diff --git a/SPECS/bcc.el6.spec.in b/SPECS/bcc.el6.spec.in index f684c7cf534c..4493f9ff980a 100644 --- a/SPECS/bcc.el6.spec.in +++ b/SPECS/bcc.el6.spec.in @@ -107,8 +107,6 @@ Python bindings for BPF Compiler Collection (BCC) %files -n libbcc /usr/lib64/* -/usr/share/bcc/include/* -/usr/share/bcc/lib/* /usr/include/bcc/* %files -n libbcc-examples diff --git a/SPECS/bcc.el7.spec b/SPECS/bcc.el7.spec index ba21a3298bee..6a99d624e515 100644 --- a/SPECS/bcc.el7.spec +++ b/SPECS/bcc.el7.spec @@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC) %files -n libbcc /usr/lib64/* -/usr/share/bcc/include/* -/usr/share/bcc/lib/* /usr/include/bcc/* %files -n libbcc-examples diff --git a/SPECS/bcc.el7.spec.in b/SPECS/bcc.el7.spec.in index a6531fe7d176..32cd9a487d4d 100644 --- a/SPECS/bcc.el7.spec.in +++ b/SPECS/bcc.el7.spec.in @@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC) %files -n libbcc /usr/lib64/* -/usr/share/bcc/include/* -/usr/share/bcc/lib/* /usr/include/bcc/* %files -n libbcc-examples diff --git a/SPECS/bcc.f22.spec b/SPECS/bcc.f22.spec index ba21a3298bee..6a99d624e515 100644 --- a/SPECS/bcc.f22.spec +++ b/SPECS/bcc.f22.spec @@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC) %files -n libbcc /usr/lib64/* -/usr/share/bcc/include/* -/usr/share/bcc/lib/* /usr/include/bcc/* %files -n libbcc-examples diff --git a/SPECS/bcc.f22.spec.in b/SPECS/bcc.f22.spec.in index a6531fe7d176..32cd9a487d4d 100644 --- a/SPECS/bcc.f22.spec.in +++ b/SPECS/bcc.f22.spec.in @@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC) %files -n libbcc /usr/lib64/* -/usr/share/bcc/include/* -/usr/share/bcc/lib/* /usr/include/bcc/* %files -n libbcc-examples diff --git a/SPECS/bcc.spec b/SPECS/bcc.spec index 8eb193b43af2..08e13feb4624 100644 --- a/SPECS/bcc.spec +++ b/SPECS/bcc.spec @@ -71,8 +71,6 @@ Command line tools for BPF Compiler Collection (BCC) %files -n libbcc /usr/lib64/* -/usr/share/bcc/include/* -/usr/share/bcc/lib/* /usr/include/bcc/* %files -n libbcc-examples diff --git a/debian/libbcc.install b/debian/libbcc.install index c60b682413fc..cd38d8df562f 100644 --- a/debian/libbcc.install +++ b/debian/libbcc.install @@ -1,4 +1,2 @@ usr/include/bcc/* usr/lib/x86_64-linux-gnu/libbcc* -usr/share/bcc/include/* -usr/share/bcc/lib/* diff --git a/src/cc/CMakeLists.txt b/src/cc/CMakeLists.txt index ca7dfdf99d76..197f32087102 100644 --- a/src/cc/CMakeLists.txt +++ b/src/cc/CMakeLists.txt @@ -32,10 +32,7 @@ if (CMAKE_COMPILER_IS_GNUCC) endif() endif() -# tell the shared library where it is being installed so it can find shared header files -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBCC_INSTALL_PREFIX='\"${CMAKE_INSTALL_PREFIX}\"'") - -add_library(bcc SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc) +add_library(bcc SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc) set_target_properties(bcc PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0) # BPF is still experimental otherwise it should be available @@ -52,9 +49,6 @@ target_link_libraries(bcc b_frontend clang_frontend ${clang_libs} ${llvm_libs} L install(TARGETS bcc LIBRARY COMPONENT libbcc DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(DIRECTORY export/ COMPONENT libbcc - DESTINATION share/bcc/include/bcc - FILES_MATCHING PATTERN "*.h") install(FILES bpf_common.h bpf_module.h ../libbpf.h COMPONENT libbcc DESTINATION include/bcc) install(DIRECTORY compat/linux/ COMPONENT libbcc @@ -62,8 +56,5 @@ install(DIRECTORY compat/linux/ COMPONENT libbcc FILES_MATCHING PATTERN "*.h") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libbcc.pc COMPONENT libbcc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -install(DIRECTORY clang COMPONENT libbcc - DESTINATION share/bcc/lib - FILES_MATCHING PATTERN "*.h") add_subdirectory(frontends) diff --git a/src/cc/bpf_module.cc b/src/cc/bpf_module.cc index 1d427820c1e5..cc5aae1a6578 100644 --- a/src/cc/bpf_module.cc +++ b/src/cc/bpf_module.cc @@ -48,6 +48,7 @@ #include "frontends/clang/loader.h" #include "frontends/clang/b_frontend_action.h" #include "bpf_module.h" +#include "exported_files.h" #include "kbuild_helper.h" #include "shared_table.h" #include "libbpf.h" @@ -331,9 +332,9 @@ int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags // Load in a pre-built list of functions into the initial Module object, then // build an ExecutionEngine. -int BPFModule::load_includes(const string &tmpfile) { +int BPFModule::load_includes(const string &text) { clang_loader_ = make_unique(&*ctx_, flags_); - if (clang_loader_->parse(&mod_, &tables_, tmpfile, false, nullptr, 0)) + if (clang_loader_->parse(&mod_, &tables_, text, true, nullptr, 0)) return -1; return 0; } @@ -683,7 +684,12 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) { // Helpers are inlined in the following file (C). Load the definitions and // pass the partially compiled module to the B frontend to continue with. - if (int rc = load_includes(BCC_INSTALL_PREFIX "/share/bcc/include/bcc/helpers.h")) + auto helpers_h = ExportedFiles::headers().find("/virtual/include/bcc/helpers.h"); + if (helpers_h == ExportedFiles::headers().end()) { + fprintf(stderr, "Internal error: missing bcc/helpers.h"); + return -1; + } + if (int rc = load_includes(helpers_h->second)) return rc; b_loader_.reset(new BLoader(flags_)); diff --git a/src/cc/bpf_module.h b/src/cc/bpf_module.h index f9df6f47a4a2..86fbdcf42bb2 100644 --- a/src/cc/bpf_module.h +++ b/src/cc/bpf_module.h @@ -47,7 +47,7 @@ class BPFModule { llvm::Function * make_writer(llvm::Module *mod, llvm::Type *type); void dump_ir(llvm::Module &mod); int load_file_module(std::unique_ptr *mod, const std::string &file, bool in_memory); - int load_includes(const std::string &tmpfile); + int load_includes(const std::string &text); int load_cfile(const std::string &file, bool in_memory, const char *cflags[], int ncflags); int kbuild_flags(const char *uname_release, std::vector *cflags); int run_pass_manager(llvm::Module &mod); diff --git a/src/cc/clang/include/stdarg.h b/src/cc/clang/include/stdarg.h index a57e18364871..e0a43f5ae7b5 100644 --- a/src/cc/clang/include/stdarg.h +++ b/src/cc/clang/include/stdarg.h @@ -1,3 +1,4 @@ +R"********( /*===---- stdarg.h - Variable argument handling ----------------------------=== * * Copyright (c) 2008 Eli Friedman @@ -50,3 +51,4 @@ typedef __builtin_va_list va_list; typedef __builtin_va_list __gnuc_va_list; #endif /* __STDARG_H */ +)********" diff --git a/src/cc/export/helpers.h b/src/cc/export/helpers.h index a75f9f400723..9dfc060cdfc3 100644 --- a/src/cc/export/helpers.h +++ b/src/cc/export/helpers.h @@ -1,3 +1,4 @@ +R"********( /* * Copyright (c) 2015 PLUMgrid, Inc. * @@ -392,3 +393,4 @@ int bpf_num_cpus() asm("llvm.bpf.extra"); #define lock_xadd(ptr, val) ((void)__sync_fetch_and_add(ptr, val)) #endif +)********" diff --git a/src/cc/export/proto.h b/src/cc/export/proto.h index a7fe4606a40c..b2f50ede99f5 100644 --- a/src/cc/export/proto.h +++ b/src/cc/export/proto.h @@ -1,3 +1,4 @@ +R"********( /* * Copyright (c) 2015 PLUMgrid, Inc. * @@ -95,3 +96,4 @@ struct vxlan_t { unsigned int key:24; unsigned int rsv4:8; } BPF_PACKET_HEADER; +)********" diff --git a/src/cc/exported_files.cc b/src/cc/exported_files.cc new file mode 100644 index 000000000000..9dde0147cd93 --- /dev/null +++ b/src/cc/exported_files.cc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 PLUMgrid, Inc. + * + * 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 "exported_files.h" + +using std::map; +using std::string; + +namespace ebpf { + +// c++11 feature for including raw string literals +// see http://www.stroustrup.com/C++11FAQ.html#raw-strings + +map ExportedFiles::headers_ = { + { + "/virtual/include/bcc/proto.h", + #include "export/proto.h" + }, + { + "/virtual/include/bcc/helpers.h", + #include "export/helpers.h" + }, + { + "/virtual/lib/clang/include/stdarg.h", + #include "clang/include/stdarg.h" + }, +}; + +} diff --git a/src/cc/exported_files.h b/src/cc/exported_files.h new file mode 100644 index 000000000000..80a06a76f944 --- /dev/null +++ b/src/cc/exported_files.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 PLUMgrid, Inc. + * + * 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. + */ + +#pragma once + +#include +#include + +namespace ebpf { + +class ExportedFiles { + static std::map headers_; + public: + static const std::map & headers() { return headers_; } +}; + +} diff --git a/src/cc/frontends/clang/kbuild_helper.cc b/src/cc/frontends/clang/kbuild_helper.cc index f60266ec2548..dc1675b1293b 100644 --- a/src/cc/frontends/clang/kbuild_helper.cc +++ b/src/cc/frontends/clang/kbuild_helper.cc @@ -57,7 +57,7 @@ int KBuildHelper::get_flags(const char *uname_machine, vector *cflags) { cflags->push_back("-nostdinc"); cflags->push_back("-isystem"); - cflags->push_back(BCC_INSTALL_PREFIX "/share/bcc/lib/clang/include"); + cflags->push_back("/virtual/lib/clang/include"); cflags->push_back("-I./arch/"+arch+"/include"); cflags->push_back("-Iarch/"+arch+"/include/generated/uapi"); cflags->push_back("-Iarch/"+arch+"/include/generated"); diff --git a/src/cc/frontends/clang/loader.cc b/src/cc/frontends/clang/loader.cc index 7b2de839448e..a138d93abf2d 100644 --- a/src/cc/frontends/clang/loader.cc +++ b/src/cc/frontends/clang/loader.cc @@ -47,6 +47,7 @@ #include "common.h" #include "exception.h" +#include "exported_files.h" #include "kbuild_helper.h" #include "b_frontend_action.h" #include "loader.h" @@ -58,9 +59,16 @@ using std::vector; namespace ebpf { +map> ClangLoader::remapped_files_; + ClangLoader::ClangLoader(llvm::LLVMContext *ctx, unsigned flags) : ctx_(ctx), flags_(flags) -{} +{ + if (remapped_files_.empty()) { + for (auto f : ExportedFiles::headers()) + remapped_files_[f.first] = llvm::MemoryBuffer::getMemBuffer(f.second); + } +} ClangLoader::~ClangLoader() {} @@ -68,6 +76,10 @@ int ClangLoader::parse(unique_ptr *mod, unique_ptr main_buf; struct utsname un; uname(&un); char kdir[256]; @@ -80,7 +92,8 @@ int ClangLoader::parse(unique_ptr *mod, unique_ptr *mod, unique_ptrc_str()); if (cflags) { @@ -156,11 +169,17 @@ int ClangLoader::parse(unique_ptr *mod, unique_ptr(ccargs.data()) + ccargs.size(), diags)) return -1; + // This option instructs clang whether or not to free the file buffers that we + // give to it. Since the embedded header files should be copied fewer times + // and reused if possible, set this flag to true. + invocation1->getPreprocessorOpts().RetainRemappedFileBuffers = true; + for (const auto &f : remapped_files_) + invocation1->getPreprocessorOpts().addRemappedFile(f.first, &*f.second); + if (in_memory) { - invocation1->getPreprocessorOpts().addRemappedFile("", - llvm::MemoryBuffer::getMemBuffer(file).release()); + invocation1->getPreprocessorOpts().addRemappedFile(main_path, &*main_buf); invocation1->getFrontendOpts().Inputs.clear(); - invocation1->getFrontendOpts().Inputs.push_back(FrontendInputFile("", IK_C)); + invocation1->getFrontendOpts().Inputs.push_back(FrontendInputFile(main_path, IK_C)); } invocation1->getFrontendOpts().DisableFree = false; @@ -174,6 +193,7 @@ int ClangLoader::parse(unique_ptr *mod, unique_ptr out_buf = llvm::MemoryBuffer::getMemBuffer(out_str); // this contains the open FDs *tables = bact.take_tables(); @@ -183,10 +203,12 @@ int ClangLoader::parse(unique_ptr *mod, unique_ptr(ccargs.data()) + ccargs.size(), diags)) return -1; CompilerInstance compiler2; - invocation2->getPreprocessorOpts().addRemappedFile("", - llvm::MemoryBuffer::getMemBuffer(out_str).release()); + invocation2->getPreprocessorOpts().RetainRemappedFileBuffers = true; + for (const auto &f : remapped_files_) + invocation2->getPreprocessorOpts().addRemappedFile(f.first, &*f.second); + invocation2->getPreprocessorOpts().addRemappedFile(main_path, &*out_buf); invocation2->getFrontendOpts().Inputs.clear(); - invocation2->getFrontendOpts().Inputs.push_back(FrontendInputFile("", IK_C)); + invocation2->getFrontendOpts().Inputs.push_back(FrontendInputFile(main_path, IK_C)); invocation2->getFrontendOpts().DisableFree = false; // suppress warnings in the 2nd pass, but bail out on errors (our fault) invocation2->getDiagnosticOpts().IgnoreWarnings = true; diff --git a/src/cc/frontends/clang/loader.h b/src/cc/frontends/clang/loader.h index 22c64e1ba811..67b996987d98 100644 --- a/src/cc/frontends/clang/loader.h +++ b/src/cc/frontends/clang/loader.h @@ -23,6 +23,7 @@ namespace llvm { class Module; class LLVMContext; +class MemoryBuffer; } namespace ebpf { @@ -41,6 +42,7 @@ class ClangLoader { int parse(std::unique_ptr *mod, std::unique_ptr> *tables, const std::string &file, bool in_memory, const char *cflags[], int ncflags); private: + static std::map> remapped_files_; llvm::LLVMContext *ctx_; unsigned flags_; };