Commit 25245bfa authored by Brenden Blanco's avatar Brenden Blanco

Use clang as a lib to parse the helper file live

* Add clang as a library to the .so...this adds about 16M of stuff
* Compute the build flags for clang from the current kernel's header
  build tree. It generates a makefile on the fly and caches the minimal
  flags as an output.
* Followup to this would be to migrate bitops.c to be #include'd as well
  as the proto.d/kprobe.d stuff.
* For now, requires clang to be installed in /opt/local/llvm...see cmake
  files to override this.
Signed-off-by: default avatarBrenden Blanco <bblanco@plumgrid.com>
parent ba97c279
......@@ -9,20 +9,21 @@ find_package(BISON)
find_package(FLEX)
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM: ${LLVM_INCLUDE_DIRS}")
find_program(XXD xxd)
if (${XXD} STREQUAL "XXD-NOTFOUND")
message(FATAL_ERROR "program xxd not found, install vim-common")
endif()
find_program(CLANG clang)
if (${CLANG} STREQUAL "CLANG-NOTFOUND")
message(FATAL_ERROR "program clang not found, install clang with bpf support")
endif()
execute_process(COMMAND ${CLANG} --version OUTPUT_VARIABLE CLANG_VERSION_RAW)
string(REGEX MATCH "[0-9]+[.][0-9]+[.][0-9]+" CLANG_VERSION ${CLANG_VERSION_RAW})
message(STATUS "Found CLANG: ${CLANG} (found version \"${CLANG_VERSION}\")")
if (CLANG_VERSION VERSION_LESS 3.0.0)
message(FATAL_ERROR "requires clang version >= 3.0.0, ${CLANG_VERSION} found")
endif()
# clang is linked as a library, but the library path searching is
# primitively supported, unlike libLLVM
set(CLANG_SEARCH "/opt/local/llvm/lib")
find_library(libclangAnalysis NAMES clangAnalysis HINTS ${CLANG_SEARCH})
find_library(libclangAST NAMES clangAST HINTS ${CLANG_SEARCH})
find_library(libclangBasic NAMES clangBasic HINTS ${CLANG_SEARCH})
find_library(libclangCodeGen NAMES clangCodeGen HINTS ${CLANG_SEARCH})
find_library(libclangDriver NAMES clangDriver HINTS ${CLANG_SEARCH})
find_library(libclangEdit NAMES clangEdit HINTS ${CLANG_SEARCH})
find_library(libclangFrontend NAMES clangFrontend HINTS ${CLANG_SEARCH})
find_library(libclangLex NAMES clangLex HINTS ${CLANG_SEARCH})
find_library(libclangParse NAMES clangParse HINTS ${CLANG_SEARCH})
find_library(libclangSema NAMES clangSema HINTS ${CLANG_SEARCH})
find_library(libclangSerialization NAMES clangSerialization HINTS ${CLANG_SEARCH})
set(CMAKE_C_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall")
......
......@@ -7,31 +7,19 @@ BISON_TARGET(Parser parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.yy.cc COMPILE_F
FLEX_TARGET(Lexer lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.ll.cc COMPILE_FLAGS "--c++ --o lexer.ll.cc")
ADD_FLEX_BISON_DEPENDENCY(Lexer Parser)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bitops.bc
COMMAND ${CLANG}
ARGS -O3 -emit-llvm -o bitops.bc -I${CMAKE_SOURCE_DIR}/jit/compat/include
-c ${CMAKE_CURRENT_SOURCE_DIR}/bitops.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bitops.c ${CMAKE_CURRENT_SOURCE_DIR}/bpf_helpers.h
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating bitops IR")
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bitops.h
COMMAND ${XXD} ARGS -i bitops.bc bitops.h
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bitops.bc
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating bitops.h")
add_custom_target(bitops DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bitops.h)
set(CMAKE_SHARED_LINKER_FLAGS "-static-libstdc++ -Wl,--exclude-libs=ALL")
add_library(bpfprog SHARED bpf_common.cc bpf_program.cc codegen_llvm.cc
node.cc parser.cc printer.cc type_check.cc libbpf.c
${BISON_Parser_OUTPUTS} ${FLEX_Lexer_OUTPUTS} ${CMAKE_CURRENT_BINARY_DIR}/bitops.h)
${BISON_Parser_OUTPUTS} ${FLEX_Lexer_OUTPUTS})
# BPF is still experimental otherwise it should be available
#llvm_map_components_to_libnames(llvm_libs bpf mcjit irreader passes)
llvm_map_components_to_libnames(llvm_libs mcjit irreader passes)
llvm_map_components_to_libnames(llvm_libs mcjit irreader passes linker instrumentation objcarcopts bitwriter option)
# order is important
set(clang_libs ${libclangFrontend} ${libclangParse} ${libclangSema} ${libclangCodeGen}
${libclangDriver} ${libclangAnalysis} ${libclangSerialization} ${libclangEdit}
${libclangLex} ${libclangAST} ${libclangBasic})
# Link against LLVM libraries
target_link_libraries(bpfprog ${llvm_libs} LLVMBPFCodeGen mnl)
target_link_libraries(bpfprog ${clang_libs} ${llvm_libs} LLVMBPFCodeGen mnl)
......@@ -16,57 +16,57 @@
* ====================================================================
*/
#include <stdint.h>
#include "linux/bpf.h"
#include <linux/skbuff.h>
#include <linux/bpf.h>
#include "bpf_helpers.h"
#define assert(v)
static inline uint16_t bpf_ntohs(uint16_t val) {
static inline u16 bpf_ntohs(u16 val) {
/* will be recognized by gcc into rotate insn and eventually rolw 8 */
return (val << 8) | (val >> 8);
}
static inline uint32_t bpf_ntohl(uint32_t val) {
static inline u32 bpf_ntohl(u32 val) {
/* gcc will use bswapsi2 insn */
return __builtin_bswap32(val);
}
static inline uint64_t bpf_ntohll(uint64_t val) {
static inline u64 bpf_ntohll(u64 val) {
/* gcc will use bswapdi2 insn */
return __builtin_bswap64(val);
}
static inline unsigned __int128 bpf_ntoh128(unsigned __int128 val) {
return (((unsigned __int128)bpf_ntohll(val) << 64) | (uint64_t)bpf_ntohll(val >> 64));
return (((unsigned __int128)bpf_ntohll(val) << 64) | (u64)bpf_ntohll(val >> 64));
}
static inline uint16_t bpf_htons(uint16_t val) {
static inline u16 bpf_htons(u16 val) {
return bpf_ntohs(val);
}
static inline uint32_t bpf_htonl(uint32_t val) {
static inline u32 bpf_htonl(u32 val) {
return bpf_ntohl(val);
}
static inline uint64_t bpf_htonll(uint64_t val) {
static inline u64 bpf_htonll(u64 val) {
return bpf_ntohll(val);
}
static inline unsigned __int128 bpf_hton128(unsigned __int128 val) {
return bpf_ntoh128(val);
}
static inline uint64_t load_dword(void *skb, uint64_t off) {
return ((uint64_t)load_word(skb, off) << 4) | load_word(skb, off + 4);
static inline u64 load_dword(void *skb, u64 off) {
return ((u64)load_word(skb, off) << 4) | load_word(skb, off + 4);
}
void bpf_store_byte(void *skb, uint64_t off, uint64_t val) asm("llvm.bpf.store.byte");
void bpf_store_half(void *skb, uint64_t off, uint64_t val) asm("llvm.bpf.store.half");
void bpf_store_word(void *skb, uint64_t off, uint64_t val) asm("llvm.bpf.store.word");
static inline void bpf_store_dword(void *skb, uint64_t off, uint64_t val) {
bpf_store_word(skb, off, (uint32_t)val);
void bpf_store_byte(void *skb, u64 off, u64 val) asm("llvm.bpf.store.byte");
void bpf_store_half(void *skb, u64 off, u64 val) asm("llvm.bpf.store.half");
void bpf_store_word(void *skb, u64 off, u64 val) asm("llvm.bpf.store.word");
static inline void bpf_store_dword(void *skb, u64 off, u64 val) {
bpf_store_word(skb, off, (u32)val);
bpf_store_word(skb, off + 4, val >> 32);
}
#define MASK(_n) ((_n) < 64 ? (1ull << (_n)) - 1 : ((uint64_t)-1LL))
#define MASK(_n) ((_n) < 64 ? (1ull << (_n)) - 1 : ((u64)-1LL))
#define MASK128(_n) ((_n) < 128 ? ((unsigned __int128)1 << (_n)) - 1 : ((unsigned __int128)-1))
struct _skbuff;
......@@ -74,7 +74,7 @@ struct bpf_context;
//static inline __attribute__((always_inline))
SEC("helpers")
uint64_t bpf_dext_pkt(void *pkt, uint64_t off, uint64_t bofs, uint64_t bsz) {
u64 bpf_dext_pkt(void *pkt, u64 off, u64 bofs, u64 bsz) {
if (bofs == 0 && bsz == 8) {
return load_byte(pkt, off);
} else if (bofs + bsz <= 8) {
......@@ -97,40 +97,40 @@ uint64_t bpf_dext_pkt(void *pkt, uint64_t off, uint64_t bofs, uint64_t bsz) {
//static inline __attribute__((always_inline))
SEC("helpers")
void bpf_dins_pkt(void *pkt, uint64_t off, uint64_t bofs, uint64_t bsz, uint64_t val) {
void bpf_dins_pkt(void *pkt, u64 off, u64 bofs, u64 bsz, u64 val) {
// The load_xxx function does a bswap before returning the short/word/dword,
// so the value in register will always be host endian. However, the bytes
// written back need to be in network order.
if (bofs == 0 && bsz == 8) {
bpf_skb_store_bytes(pkt, off, &val, 1, 0);
} else if (bofs + bsz <= 8) {
uint8_t v = load_byte(pkt, off);
u8 v = load_byte(pkt, off);
v &= ~(MASK(bsz) << (8 - (bofs + bsz)));
v |= ((val & MASK(bsz)) << (8 - (bofs + bsz)));
bpf_skb_store_bytes(pkt, off, &v, 1, 0);
} else if (bofs == 0 && bsz == 16) {
uint16_t v = bpf_htons(val);
u16 v = bpf_htons(val);
bpf_skb_store_bytes(pkt, off, &v, 2, 0);
} else if (bofs + bsz <= 16) {
uint16_t v = load_half(pkt, off);
u16 v = load_half(pkt, off);
v &= ~(MASK(bsz) << (16 - (bofs + bsz)));
v |= ((val & MASK(bsz)) << (16 - (bofs + bsz)));
v = bpf_htons(v);
bpf_skb_store_bytes(pkt, off, &v, 2, 0);
} else if (bofs == 0 && bsz == 32) {
uint32_t v = bpf_htonl(val);
u32 v = bpf_htonl(val);
bpf_skb_store_bytes(pkt, off, &v, 4, 0);
} else if (bofs + bsz <= 32) {
uint32_t v = load_word(pkt, off);
u32 v = load_word(pkt, off);
v &= ~(MASK(bsz) << (32 - (bofs + bsz)));
v |= ((val & MASK(bsz)) << (32 - (bofs + bsz)));
v = bpf_htonl(v);
bpf_skb_store_bytes(pkt, off, &v, 4, 0);
} else if (bofs == 0 && bsz == 64) {
uint64_t v = bpf_htonll(val);
u64 v = bpf_htonll(val);
bpf_skb_store_bytes(pkt, off, &v, 8, 0);
} else if (bofs + bsz <= 64) {
uint64_t v = load_dword(pkt, off);
u64 v = load_dword(pkt, off);
v &= ~(MASK(bsz) << (64 - (bofs + bsz)));
v |= ((val & MASK(bsz)) << (64 - (bofs + bsz)));
v = bpf_htonll(v);
......@@ -150,7 +150,7 @@ void * bpf_map_lookup_elem_(uintptr_t map, void *key) {
}
SEC("helpers")
int bpf_map_update_elem_(uintptr_t map, void *key, void *value, uint64_t flags) {
int bpf_map_update_elem_(uintptr_t map, void *key, void *value, u64 flags) {
return bpf_map_update_elem((void *)map, key, value, flags);
}
......@@ -160,12 +160,12 @@ int bpf_map_delete_elem_(uintptr_t map, void *key) {
}
SEC("helpers")
int bpf_skb_store_bytes_(void *ctx, uint64_t off, void *from, uint64_t len, uint64_t flags) {
int bpf_skb_store_bytes_(void *ctx, u64 off, void *from, u64 len, u64 flags) {
return bpf_skb_store_bytes(ctx, off, from, len, flags);
}
SEC("helpers")
int bpf_l3_csum_replace_(void *ctx, uint64_t off, uint64_t from, uint64_t to, uint64_t flags) {
int bpf_l3_csum_replace_(void *ctx, u64 off, u64 from, u64 to, u64 flags) {
switch (flags & 0xf) {
case 2:
return bpf_l3_csum_replace(ctx, off, bpf_htons(from), bpf_htons(to), flags);
......@@ -180,7 +180,7 @@ int bpf_l3_csum_replace_(void *ctx, uint64_t off, uint64_t from, uint64_t to, ui
}
SEC("helpers")
int bpf_l4_csum_replace_(void *ctx, uint64_t off, uint64_t from, uint64_t to, uint64_t flags) {
int bpf_l4_csum_replace_(void *ctx, u64 off, u64 from, u64 to, u64 flags) {
switch (flags & 0xf) {
case 2:
return bpf_l4_csum_replace(ctx, off, bpf_htons(from), bpf_htons(to), flags);
......
// Generated by llvm2cpp - DO NOT MODIFY!
#include <algorithm>
#include <fcntl.h>
#include <ftw.h>
#include <map>
#include <stdio.h>
#include <string>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <vector>
#include <clang/Basic/FileManager.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/CodeGen/BackendUtil.h>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/CodeGen/ModuleBuilder.h>
#include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h>
#include <clang/Driver/Job.h>
#include <clang/Driver/Tool.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/FrontendDiagnostic.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/FrontendTool/Utils.h>
#include "clang/Parse/ParseAST.h"
#include <llvm/ADT/STLExtras.h>
#include <llvm/ExecutionEngine/MCJIT.h>
......@@ -15,6 +36,7 @@
#include <llvm/IR/Verifier.h>
#include <llvm/Object/ObjectFile.h>
#include <llvm/Support/FormattedStream.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
......@@ -25,6 +47,11 @@
#include "codegen_llvm.h"
#include "bpf_program.h"
#define KERNEL_MODULES_DIR "/lib/modules"
// This is temporary, to be removed in the next commit
#define HELPER_FILE "../../src/cc/bitops.c"
namespace ebpf {
using std::get;
......@@ -34,6 +61,7 @@ using std::move;
using std::string;
using std::tuple;
using std::unique_ptr;
using std::vector;
using namespace llvm;
// Snooping class to remember the sections as the JIT creates them
......@@ -67,7 +95,7 @@ class MyMemoryManager : public SectionMemoryManager {
};
BPFProgram::BPFProgram(unsigned flags)
: flags_(flags) {
: flags_(flags), ctx_(new LLVMContext) {
LLVMInitializeBPFTarget();
LLVMInitializeBPFTargetMC();
LLVMInitializeBPFTargetInfo();
......@@ -77,7 +105,7 @@ BPFProgram::BPFProgram(unsigned flags)
BPFProgram::~BPFProgram() {
engine_.reset();
LLVMShutdown();
ctx_.reset();
}
int BPFProgram::parse() {
......@@ -117,27 +145,230 @@ int BPFProgram::parse() {
return 0;
}
string BPFProgram::load_helper() const {
// generated from bitops.cc -> bitops.bc -> hexdump -> bitops.h
#include "cc/bitops.h"
return string((const char *)bitops_bc, bitops_bc_len);
// Helper with pushd/popd semantics
class DirStack {
public:
explicit DirStack(const char *dst) : ok_(false) {
if (getcwd(cwd_, sizeof(cwd_)) == NULL) {
::perror("getcwd");
return;
}
if (::chdir(dst)) {
fprintf(stderr, "chdir(%s): %s\n", dst, strerror(errno));
return;
}
ok_ = true;
}
~DirStack() {
if (!ok_) return;
if (::chdir(cwd_)) {
fprintf(stderr, "chdir(%s): %s\n", cwd_, strerror(errno));
}
}
bool ok() const { return ok_; }
const char * cwd() const { return cwd_; }
private:
bool ok_;
char cwd_[256];
};
struct FileDeleter {
void operator() (FILE *fp) {
fclose(fp);
}
};
typedef std::unique_ptr<FILE, FileDeleter> FILEPtr;
// Scoped class to manage the creation/deletion of tmpdirs
class TmpDir {
public:
explicit TmpDir(const string &prefix = "/tmp/bcc-")
: ok_(false), prefix_(prefix) {
prefix_ += "XXXXXX";
if (::mkdtemp((char *)prefix.data()) == NULL)
::perror("mkdtemp");
else
ok_ = true;
}
~TmpDir() {
auto fn = [] (const char *path, const struct stat *, int) -> int {
return ::remove(path);
};
if (::ftw(prefix_.c_str(), fn, 20) < 0)
::perror("ftw");
else
::remove(prefix_.c_str());
}
bool ok() const { return ok_; }
const string & str() const { return prefix_; }
private:
bool ok_;
string prefix_;
};
// Compute the kbuild flags for the currently running kernel
// Do this by:
// 1. Create temp Makefile with stub dummy.c
// 2. Run module build on that makefile, saving the computed flags to a file
// 3. Cache the file for fast flag lookup in subsequent runs
// Note: Depending on environment, different cache locations may be desired. In
// case we eventually support non-root user programs, cache in $HOME.
// Makefile helper for kbuild_flags
static int learn_flags(const string &tmpdir, const char *uname_release, const char *cachefile) {
{
// Create a kbuild file to generate the flags
string makefile = tmpdir + "/Makefile";
FILEPtr mf(::fopen(makefile.c_str(), "w"));
if (!mf)
return -1;
fprintf(&*mf, "obj-y := dummy.o\n");
fprintf(&*mf, "CACHEDIR=$(dir %s)\n", cachefile);
fprintf(&*mf, "$(CACHEDIR):\n");
fprintf(&*mf, "\t@mkdir -p $(CACHEDIR)\n");
fprintf(&*mf, "$(obj)/%%.o: $(src)/%%.c $(CACHEDIR)\n");
fprintf(&*mf, "\t@echo -n \"$(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) "
"-D__KERNEL__ -Wno-unused-value -Wno-pointer-sign \" > %s\n", cachefile);
}
{
string cfile = tmpdir + "/dummy.c";
FILEPtr cf(::fopen(cfile.c_str(), "w"));
if (!cf)
return -1;
}
string cmd = "make -s";
cmd += " -C " KERNEL_MODULES_DIR "/" + string(uname_release) + "/build";
cmd += " M=" + tmpdir + " dummy.o";
int rc = ::system(cmd.c_str());
if (rc < 0) {
::perror("system");
return -1;
}
return ::open(cachefile, O_RDONLY);
}
// read the flags from cache or learn
int BPFProgram::kbuild_flags(const char *uname_release, vector<string> *cflags) {
char cachefile[256];
char *home = ::getenv("HOME");
if (home)
snprintf(cachefile, sizeof(cachefile), "%s/.cache/bcc/%s.flags", home, uname_release);
else
snprintf(cachefile, sizeof(cachefile), "/var/run/bcc/%s.flags", uname_release);
int cachefd = ::open(cachefile, O_RDONLY);
if (cachefd < 0) {
TmpDir tmpdir;
if (!tmpdir.ok())
return -1;
cachefd = learn_flags(tmpdir.str(), uname_release, cachefile);
if (cachefd < 0)
return -1;
}
FILEPtr f(::fdopen(cachefd, "r"));
size_t len = 0;
char *line = NULL;
ssize_t nread;
while ((nread = getdelim(&line, &len, ' ', &*f)) >= 0) {
if (nread == 0 || (nread == 1 && line[0] == ' ')) continue;
if (line[nread - 1] == ' ')
--nread;
cflags->push_back(string(line, nread));
}
free(line);
return 0;
}
int BPFProgram::load_helper(unique_ptr<llvm::Module> *mod) {
using namespace clang;
struct utsname un;
uname(&un);
char kdir[256];
snprintf(kdir, sizeof(kdir), "%s/%s/build", KERNEL_MODULES_DIR, un.release);
DirStack dstack(kdir);
if (!dstack.ok())
return -1;
string file = string(dstack.cwd()) + "/" HELPER_FILE;
vector<const char *> flags_cstr({"-fsyntax-only", "-emit-llvm", "-o", "/dev/null",
"-c", file.c_str()});
vector<string> kflags;
if (kbuild_flags(un.release, &kflags))
return -1;
for (auto it = kflags.begin(); it != kflags.end(); ++it)
flags_cstr.push_back(it->c_str());
IntrusiveRefCntPtr<DiagnosticOptions> diag_opts(new DiagnosticOptions());
auto diag_client = new TextDiagnosticPrinter(llvm::errs(), &*diag_opts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine diags(DiagID, &*diag_opts, diag_client);
driver::Driver drv("", "x86_64-unknown-linux-gnu", diags);
drv.setTitle("bcc-clang-driver");
drv.setCheckInputsExist(false);
unique_ptr<driver::Compilation> compilation(drv.BuildCompilation(flags_cstr));
if (!compilation)
return 0;
// expect exactly 1 job, otherwise error
const driver::JobList &jobs = compilation->getJobs();
if (jobs.size() != 1 || !isa<driver::Command>(*jobs.begin())) {
SmallString<256> msg;
llvm::raw_svector_ostream os(msg);
jobs.Print(os, "; ", true);
diags.Report(diag::err_fe_expected_compiler_job) << os.str();
return -1;
}
const driver::Command &cmd = cast<driver::Command>(*jobs.begin());
if (llvm::StringRef(cmd.getCreator().getName()) != "clang") {
diags.Report(diag::err_fe_expected_clang_command);
return -1;
}
// Initialize a compiler invocation object from the clang (-cc1) arguments.
const driver::ArgStringList &ccargs = cmd.getArguments();
auto invocation = make_unique<CompilerInvocation>();
CompilerInvocation::CreateFromArgs(*invocation, const_cast<const char **>(ccargs.data()),
const_cast<const char **>(ccargs.data()) + ccargs.size(), diags);
// Show the invocation, with -v.
if (invocation->getHeaderSearchOpts().Verbose)
jobs.Print(llvm::errs(), "\n", true);
// Create a compiler instance to handle the actual work.
CompilerInstance compiler;
compiler.setInvocation(invocation.release());
// Create the compilers actual diagnostics engine.
compiler.createDiagnostics();
if (!compiler.hasDiagnostics())
return -1;
// Create and execute the frontend to generate an LLVM bitcode module.
EmitLLVMOnlyAction act(&*ctx_);
if (!compiler.ExecuteAction(act))
return -1;
*mod = act.takeModule();
return 0;
}
// Load in a pre-built list of functions into the initial Module object, then
// build an ExecutionEngine.
int BPFProgram::init_engine() {
SMDiagnostic diag;
string helper = load_helper();
MemoryBufferRef helper_mem(helper, "helper");
unique_ptr<Module> mod = parseIR(helper_mem, diag, getGlobalContext());
if (!mod) {
diag.print("bitops", errs());
exit(1);
}
mod_ = mod.get();
unique_ptr<Module> mod;
if (load_helper(&mod))
return -1;
mod_ = &*mod;
mod_->setDataLayout("e-m:e-i64:64-f80:128-n8:16:32:64-S128");
mod_->setTargetTriple("bpf");
mod_->setTargetTriple("bpf-pc-linux");
for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn)
fn->addFnAttr(Attribute::AlwaysInline);
......
......@@ -26,6 +26,7 @@
namespace llvm {
class ExecutionEngine;
class LLVMContext;
class Module;
}
......@@ -42,7 +43,8 @@ class BPFProgram {
int parse();
int finalize();
void dump_ir();
std::string load_helper() const;
int load_helper(std::unique_ptr<llvm::Module> *mod);
int kbuild_flags(const char *uname_release, std::vector<std::string> *cflags);
public:
BPFProgram(unsigned flags);
~BPFProgram();
......@@ -55,6 +57,7 @@ class BPFProgram {
unsigned flags_; // 0x1 for printing
std::string filename_;
std::string proto_filename_;
std::unique_ptr<llvm::LLVMContext> ctx_;
std::unique_ptr<llvm::ExecutionEngine> engine_;
llvm::Module *mod_;
std::unique_ptr<ebpf::cc::Parser> parser_;
......
......@@ -440,15 +440,17 @@ numeric
;
assign_expr
: dotted_ident TEQUAL expr
: expr TEQUAL expr
{ $$ = new AssignExprNode(ExprNode::Ptr($1), ExprNode::Ptr($3));
parser.set_loc($$, @$); }
/* The below has a reduce/reduce conflict.
TODO: ensure the above is handled in the type check properly */
/*| dotted_ident TEQUAL expr
{ $$ = new AssignExprNode(IdentExprNode::Ptr($1), ExprNode::Ptr($3));
parser.set_loc($$, @$); }
| dotted_ident bitop TEQUAL expr
{ $$ = new AssignExprNode(IdentExprNode::Ptr($1), ExprNode::Ptr($4)); $$->bitop_ = BitopExprNode::Ptr($2);
parser.set_loc($$, @$); }
| expr TEQUAL expr
{ $$ = new AssignExprNode(ExprNode::Ptr($1), ExprNode::Ptr($3));
parser.set_loc($$, @$); }
parser.set_loc($$, @$); }*/
;
return_expr
......
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