Commit c597c29c authored by Brenden Blanco's avatar Brenden Blanco

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
<bcc/helpers.h>`, even though it is redundant, and clang will pick up
the embedded file.

Fixes: #333
Signed-off-by: default avatarBrenden Blanco <bblanco@plumgrid.com>
parent aaeea7bb
...@@ -107,8 +107,6 @@ Python bindings for BPF Compiler Collection (BCC) ...@@ -107,8 +107,6 @@ Python bindings for BPF Compiler Collection (BCC)
%files -n libbcc %files -n libbcc
/usr/lib64/* /usr/lib64/*
/usr/share/bcc/include/*
/usr/share/bcc/lib/*
/usr/include/bcc/* /usr/include/bcc/*
%files -n libbcc-examples %files -n libbcc-examples
......
...@@ -107,8 +107,6 @@ Python bindings for BPF Compiler Collection (BCC) ...@@ -107,8 +107,6 @@ Python bindings for BPF Compiler Collection (BCC)
%files -n libbcc %files -n libbcc
/usr/lib64/* /usr/lib64/*
/usr/share/bcc/include/*
/usr/share/bcc/lib/*
/usr/include/bcc/* /usr/include/bcc/*
%files -n libbcc-examples %files -n libbcc-examples
......
...@@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC) ...@@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC)
%files -n libbcc %files -n libbcc
/usr/lib64/* /usr/lib64/*
/usr/share/bcc/include/*
/usr/share/bcc/lib/*
/usr/include/bcc/* /usr/include/bcc/*
%files -n libbcc-examples %files -n libbcc-examples
......
...@@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC) ...@@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC)
%files -n libbcc %files -n libbcc
/usr/lib64/* /usr/lib64/*
/usr/share/bcc/include/*
/usr/share/bcc/lib/*
/usr/include/bcc/* /usr/include/bcc/*
%files -n libbcc-examples %files -n libbcc-examples
......
...@@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC) ...@@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC)
%files -n libbcc %files -n libbcc
/usr/lib64/* /usr/lib64/*
/usr/share/bcc/include/*
/usr/share/bcc/lib/*
/usr/include/bcc/* /usr/include/bcc/*
%files -n libbcc-examples %files -n libbcc-examples
......
...@@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC) ...@@ -76,8 +76,6 @@ Python bindings for BPF Compiler Collection (BCC)
%files -n libbcc %files -n libbcc
/usr/lib64/* /usr/lib64/*
/usr/share/bcc/include/*
/usr/share/bcc/lib/*
/usr/include/bcc/* /usr/include/bcc/*
%files -n libbcc-examples %files -n libbcc-examples
......
...@@ -71,8 +71,6 @@ Command line tools for BPF Compiler Collection (BCC) ...@@ -71,8 +71,6 @@ Command line tools for BPF Compiler Collection (BCC)
%files -n libbcc %files -n libbcc
/usr/lib64/* /usr/lib64/*
/usr/share/bcc/include/*
/usr/share/bcc/lib/*
/usr/include/bcc/* /usr/include/bcc/*
%files -n libbcc-examples %files -n libbcc-examples
......
usr/include/bcc/* usr/include/bcc/*
usr/lib/x86_64-linux-gnu/libbcc* usr/lib/x86_64-linux-gnu/libbcc*
usr/share/bcc/include/*
usr/share/bcc/lib/*
...@@ -32,10 +32,7 @@ if (CMAKE_COMPILER_IS_GNUCC) ...@@ -32,10 +32,7 @@ if (CMAKE_COMPILER_IS_GNUCC)
endif() endif()
endif() endif()
# tell the shared library where it is being installed so it can find shared header files add_library(bcc SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc)
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)
set_target_properties(bcc PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0) set_target_properties(bcc PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0)
# BPF is still experimental otherwise it should be available # 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 ...@@ -52,9 +49,6 @@ target_link_libraries(bcc b_frontend clang_frontend ${clang_libs} ${llvm_libs} L
install(TARGETS bcc LIBRARY COMPONENT libbcc install(TARGETS bcc LIBRARY COMPONENT libbcc
DESTINATION ${CMAKE_INSTALL_LIBDIR}) 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 install(FILES bpf_common.h bpf_module.h ../libbpf.h COMPONENT libbcc
DESTINATION include/bcc) DESTINATION include/bcc)
install(DIRECTORY compat/linux/ COMPONENT libbcc install(DIRECTORY compat/linux/ COMPONENT libbcc
...@@ -62,8 +56,5 @@ install(DIRECTORY compat/linux/ COMPONENT libbcc ...@@ -62,8 +56,5 @@ install(DIRECTORY compat/linux/ COMPONENT libbcc
FILES_MATCHING PATTERN "*.h") FILES_MATCHING PATTERN "*.h")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libbcc.pc COMPONENT libbcc install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libbcc.pc COMPONENT libbcc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install(DIRECTORY clang COMPONENT libbcc
DESTINATION share/bcc/lib
FILES_MATCHING PATTERN "*.h")
add_subdirectory(frontends) add_subdirectory(frontends)
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "frontends/clang/loader.h" #include "frontends/clang/loader.h"
#include "frontends/clang/b_frontend_action.h" #include "frontends/clang/b_frontend_action.h"
#include "bpf_module.h" #include "bpf_module.h"
#include "exported_files.h"
#include "kbuild_helper.h" #include "kbuild_helper.h"
#include "shared_table.h" #include "shared_table.h"
#include "libbpf.h" #include "libbpf.h"
...@@ -331,9 +332,9 @@ int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags ...@@ -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 // Load in a pre-built list of functions into the initial Module object, then
// build an ExecutionEngine. // build an ExecutionEngine.
int BPFModule::load_includes(const string &tmpfile) { int BPFModule::load_includes(const string &text) {
clang_loader_ = make_unique<ClangLoader>(&*ctx_, flags_); clang_loader_ = make_unique<ClangLoader>(&*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 -1;
return 0; return 0;
} }
...@@ -683,7 +684,12 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) { ...@@ -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 // Helpers are inlined in the following file (C). Load the definitions and
// pass the partially compiled module to the B frontend to continue with. // 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; return rc;
b_loader_.reset(new BLoader(flags_)); b_loader_.reset(new BLoader(flags_));
......
...@@ -47,7 +47,7 @@ class BPFModule { ...@@ -47,7 +47,7 @@ class BPFModule {
llvm::Function * make_writer(llvm::Module *mod, llvm::Type *type); llvm::Function * make_writer(llvm::Module *mod, llvm::Type *type);
void dump_ir(llvm::Module &mod); void dump_ir(llvm::Module &mod);
int load_file_module(std::unique_ptr<llvm::Module> *mod, const std::string &file, bool in_memory); int load_file_module(std::unique_ptr<llvm::Module> *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 load_cfile(const std::string &file, bool in_memory, const char *cflags[], int ncflags);
int kbuild_flags(const char *uname_release, std::vector<std::string> *cflags); int kbuild_flags(const char *uname_release, std::vector<std::string> *cflags);
int run_pass_manager(llvm::Module &mod); int run_pass_manager(llvm::Module &mod);
......
R"********(
/*===---- stdarg.h - Variable argument handling ----------------------------=== /*===---- stdarg.h - Variable argument handling ----------------------------===
* *
* Copyright (c) 2008 Eli Friedman * Copyright (c) 2008 Eli Friedman
...@@ -50,3 +51,4 @@ typedef __builtin_va_list va_list; ...@@ -50,3 +51,4 @@ typedef __builtin_va_list va_list;
typedef __builtin_va_list __gnuc_va_list; typedef __builtin_va_list __gnuc_va_list;
#endif /* __STDARG_H */ #endif /* __STDARG_H */
)********"
R"********(
/* /*
* Copyright (c) 2015 PLUMgrid, Inc. * Copyright (c) 2015 PLUMgrid, Inc.
* *
...@@ -392,3 +393,4 @@ int bpf_num_cpus() asm("llvm.bpf.extra"); ...@@ -392,3 +393,4 @@ int bpf_num_cpus() asm("llvm.bpf.extra");
#define lock_xadd(ptr, val) ((void)__sync_fetch_and_add(ptr, val)) #define lock_xadd(ptr, val) ((void)__sync_fetch_and_add(ptr, val))
#endif #endif
)********"
R"********(
/* /*
* Copyright (c) 2015 PLUMgrid, Inc. * Copyright (c) 2015 PLUMgrid, Inc.
* *
...@@ -95,3 +96,4 @@ struct vxlan_t { ...@@ -95,3 +96,4 @@ struct vxlan_t {
unsigned int key:24; unsigned int key:24;
unsigned int rsv4:8; unsigned int rsv4:8;
} BPF_PACKET_HEADER; } BPF_PACKET_HEADER;
)********"
/*
* 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<string, const char *> 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"
},
};
}
/*
* 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 <map>
#include <string>
namespace ebpf {
class ExportedFiles {
static std::map<std::string, const char *> headers_;
public:
static const std::map<std::string, const char *> & headers() { return headers_; }
};
}
...@@ -57,7 +57,7 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) { ...@@ -57,7 +57,7 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) {
cflags->push_back("-nostdinc"); cflags->push_back("-nostdinc");
cflags->push_back("-isystem"); 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("-I./arch/"+arch+"/include");
cflags->push_back("-Iarch/"+arch+"/include/generated/uapi"); cflags->push_back("-Iarch/"+arch+"/include/generated/uapi");
cflags->push_back("-Iarch/"+arch+"/include/generated"); cflags->push_back("-Iarch/"+arch+"/include/generated");
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "common.h" #include "common.h"
#include "exception.h" #include "exception.h"
#include "exported_files.h"
#include "kbuild_helper.h" #include "kbuild_helper.h"
#include "b_frontend_action.h" #include "b_frontend_action.h"
#include "loader.h" #include "loader.h"
...@@ -58,9 +59,16 @@ using std::vector; ...@@ -58,9 +59,16 @@ using std::vector;
namespace ebpf { namespace ebpf {
map<string, unique_ptr<llvm::MemoryBuffer>> ClangLoader::remapped_files_;
ClangLoader::ClangLoader(llvm::LLVMContext *ctx, unsigned flags) ClangLoader::ClangLoader(llvm::LLVMContext *ctx, unsigned flags)
: ctx_(ctx), flags_(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() {} ClangLoader::~ClangLoader() {}
...@@ -68,6 +76,10 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes ...@@ -68,6 +76,10 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes
const string &file, bool in_memory, const char *cflags[], int ncflags) { const string &file, bool in_memory, const char *cflags[], int ncflags) {
using namespace clang; using namespace clang;
string main_path = "/virtual/main.c";
string proto_path = "/virtual/include/bcc/proto.h";
string helpers_path = "/virtual/include/bcc/helpers.h";
unique_ptr<llvm::MemoryBuffer> main_buf;
struct utsname un; struct utsname un;
uname(&un); uname(&un);
char kdir[256]; char kdir[256];
...@@ -80,7 +92,8 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes ...@@ -80,7 +92,8 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes
string abs_file; string abs_file;
if (in_memory) { if (in_memory) {
abs_file = "<bcc-memory-buffer>"; abs_file = main_path;
main_buf = llvm::MemoryBuffer::getMemBuffer(file);
} else { } else {
if (file.substr(0, 1) == "/") if (file.substr(0, 1) == "/")
abs_file = file; abs_file = file;
...@@ -98,9 +111,9 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes ...@@ -98,9 +111,9 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes
if (kbuild_helper.get_flags(un.machine, &kflags)) if (kbuild_helper.get_flags(un.machine, &kflags))
return -1; return -1;
kflags.push_back("-include"); kflags.push_back("-include");
kflags.push_back(BCC_INSTALL_PREFIX "/share/bcc/include/bcc/helpers.h"); kflags.push_back("/virtual/include/bcc/helpers.h");
kflags.push_back("-I"); kflags.push_back("-isystem");
kflags.push_back(BCC_INSTALL_PREFIX "/share/bcc/include"); kflags.push_back("/virtual/include");
for (auto it = kflags.begin(); it != kflags.end(); ++it) for (auto it = kflags.begin(); it != kflags.end(); ++it)
flags_cstr.push_back(it->c_str()); flags_cstr.push_back(it->c_str());
if (cflags) { if (cflags) {
...@@ -156,11 +169,17 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes ...@@ -156,11 +169,17 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes
const_cast<const char **>(ccargs.data()) + ccargs.size(), diags)) const_cast<const char **>(ccargs.data()) + ccargs.size(), diags))
return -1; 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) { if (in_memory) {
invocation1->getPreprocessorOpts().addRemappedFile("<bcc-memory-buffer>", invocation1->getPreprocessorOpts().addRemappedFile(main_path, &*main_buf);
llvm::MemoryBuffer::getMemBuffer(file).release());
invocation1->getFrontendOpts().Inputs.clear(); invocation1->getFrontendOpts().Inputs.clear();
invocation1->getFrontendOpts().Inputs.push_back(FrontendInputFile("<bcc-memory-buffer>", IK_C)); invocation1->getFrontendOpts().Inputs.push_back(FrontendInputFile(main_path, IK_C));
} }
invocation1->getFrontendOpts().DisableFree = false; invocation1->getFrontendOpts().DisableFree = false;
...@@ -174,6 +193,7 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes ...@@ -174,6 +193,7 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes
BFrontendAction bact(os, flags_); BFrontendAction bact(os, flags_);
if (!compiler1.ExecuteAction(bact)) if (!compiler1.ExecuteAction(bact))
return -1; return -1;
unique_ptr<llvm::MemoryBuffer> out_buf = llvm::MemoryBuffer::getMemBuffer(out_str);
// this contains the open FDs // this contains the open FDs
*tables = bact.take_tables(); *tables = bact.take_tables();
...@@ -183,10 +203,12 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes ...@@ -183,10 +203,12 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes
const_cast<const char **>(ccargs.data()) + ccargs.size(), diags)) const_cast<const char **>(ccargs.data()) + ccargs.size(), diags))
return -1; return -1;
CompilerInstance compiler2; CompilerInstance compiler2;
invocation2->getPreprocessorOpts().addRemappedFile("<bcc-memory-buffer>", invocation2->getPreprocessorOpts().RetainRemappedFileBuffers = true;
llvm::MemoryBuffer::getMemBuffer(out_str).release()); 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.clear();
invocation2->getFrontendOpts().Inputs.push_back(FrontendInputFile("<bcc-memory-buffer>", IK_C)); invocation2->getFrontendOpts().Inputs.push_back(FrontendInputFile(main_path, IK_C));
invocation2->getFrontendOpts().DisableFree = false; invocation2->getFrontendOpts().DisableFree = false;
// suppress warnings in the 2nd pass, but bail out on errors (our fault) // suppress warnings in the 2nd pass, but bail out on errors (our fault)
invocation2->getDiagnosticOpts().IgnoreWarnings = true; invocation2->getDiagnosticOpts().IgnoreWarnings = true;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
namespace llvm { namespace llvm {
class Module; class Module;
class LLVMContext; class LLVMContext;
class MemoryBuffer;
} }
namespace ebpf { namespace ebpf {
...@@ -41,6 +42,7 @@ class ClangLoader { ...@@ -41,6 +42,7 @@ class ClangLoader {
int parse(std::unique_ptr<llvm::Module> *mod, std::unique_ptr<std::vector<TableDesc>> *tables, int parse(std::unique_ptr<llvm::Module> *mod, std::unique_ptr<std::vector<TableDesc>> *tables,
const std::string &file, bool in_memory, const char *cflags[], int ncflags); const std::string &file, bool in_memory, const char *cflags[], int ncflags);
private: private:
static std::map<std::string, std::unique_ptr<llvm::MemoryBuffer>> remapped_files_;
llvm::LLVMContext *ctx_; llvm::LLVMContext *ctx_;
unsigned flags_; unsigned flags_;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment