Skip to content

Commit

Permalink
fix: refactor error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
yunwei37 committed Aug 30, 2024
1 parent f6a726c commit 0d60a51
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 134 deletions.
31 changes: 21 additions & 10 deletions include/llvmbpf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include <ebpf_inst.h>
#include <string>

#ifndef MAX_EXT_FUNCS
#define MAX_EXT_FUNCS 8192
#endif

namespace bpftime
{

Expand All @@ -25,37 +29,44 @@ class llvmbpf_vm {
public:
llvmbpf_vm();
~llvmbpf_vm(); // Destructor declared
std::string get_error_message();
std::string get_error_message() noexcept;

// register external function, e.g. helper functions for eBPF
// return 0 on success
int register_external_function(size_t index, const std::string &name,
void *fn);
void *fn) noexcept;

// load the eBPF bytecode into the vm
// The eBPF bytecode now can be JIT/AOT compiled
// Or executed directly.
int load_code(const void *code, size_t code_len);
// return 0 on success
int load_code(const void *code, size_t code_len) noexcept;

// unload the bytecode and remove the JIT/AOT compiled results
void unload_code();
void unload_code() noexcept;

// execute the eBPF program
// If the program is JIT compiled, it will be executed directly
// If not, it will be JIT compiled, cached and executed
int exec(void *mem, size_t mem_len, uint64_t &bpf_return_value);
// return 0 on success
int exec(void *mem, size_t mem_len, uint64_t &bpf_return_value) noexcept;

// Do AOT compile and generate the ELF object file
// The external functions are required to be registered before
// calling this function. The compile result can be linked with
// other object files to generate the final executable.
std::vector<uint8_t> do_aot_compile(bool print_ir = false);
// return the ELF object file content
std::optional<std::vector<uint8_t>> do_aot_compile(bool print_ir = false) noexcept;

// Load the AOT object file into the vm and link it with the
// external functions
// return the JITed function if success
std::optional<precompiled_ebpf_function>
load_aot_object(const std::vector<uint8_t> &object);
load_aot_object(const std::vector<uint8_t> &object) noexcept;

// Compile the eBPF program into a JITed function
std::optional<precompiled_ebpf_function> compile();
// return the JITed function if success
std::optional<precompiled_ebpf_function> compile() noexcept;

// See the spec for details.
// If the code involve array map access, the map_val function
Expand All @@ -66,7 +77,7 @@ class llvmbpf_vm {
uint64_t (*map_by_idx)(uint32_t),
uint64_t (*map_val)(uint64_t),
uint64_t (*var_addr)(uint32_t),
uint64_t (*code_addr)(uint32_t));
uint64_t (*code_addr)(uint32_t)) noexcept;

private:
// See spec for details
Expand All @@ -86,7 +97,7 @@ class llvmbpf_vm {

std::string error_msg;

std::optional<precompiled_ebpf_function> jitted_function;
std::optional<precompiled_ebpf_function> jitted_function = std::nullopt;
};

} // namespace bpftime
Expand Down
72 changes: 54 additions & 18 deletions src/llvm_jit_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,6 @@ struct spin_lock_guard {
}
};

static ExitOnError ExitOnErr;

static void optimizeModule(llvm::Module &M)
{
// std::cout << "LLVM_VERSION_MAJOR: " << LLVM_VERSION_MAJOR <<
Expand Down Expand Up @@ -246,26 +244,47 @@ llvm_bpf_jit_context::llvm_bpf_jit_context(llvmbpf_vm &vm) : vm(vm)
compiling = std::make_unique<pthread_spinlock_t>();
pthread_spin_init(compiling.get(), PTHREAD_PROCESS_PRIVATE);
}
void llvm_bpf_jit_context::do_jit_compile()

llvm::Error llvm_bpf_jit_context::do_jit_compile()
{
auto [jit, extFuncNames, definedLddwHelpers] =
create_and_initialize_lljit_instance();
auto bpfModule = ExitOnErr(
generateModule(extFuncNames, definedLddwHelpers, true));
if (!jit) {
return llvm::make_error<llvm::StringError>(
"jit initialization failed",
llvm::inconvertibleErrorCode());
}
// Handle the error from generateModule
auto bpfModuleOrErr =
generateModule(extFuncNames, definedLddwHelpers, true);
if (!bpfModuleOrErr) {
return bpfModuleOrErr.takeError();
}
// If successful, get the module
auto bpfModule = std::move(*bpfModuleOrErr);
// Optimize the module
bpfModule.withModuleDo([](auto &M) { optimizeModule(M); });
ExitOnErr(jit->addIRModule(std::move(bpfModule)));
// Handle the error from addIRModule
if (auto err = jit->addIRModule(std::move(bpfModule))) {
return err;
}
// If everything succeeds, move the JIT instance
this->jit = std::move(jit);
return llvm::Error::success();
}

precompiled_ebpf_function llvm_bpf_jit_context::compile()
{
spin_lock_guard guard(compiling.get());
if (!this->jit.has_value()) {
do_jit_compile();
auto res = do_jit_compile();
if (res) {
SPDLOG_ERROR("LLVM-JIT: failed to compile");
return nullptr;
}
} else {
SPDLOG_DEBUG("LLVM-JIT: already compiled");
}

return this->get_entry_address();
}

Expand Down Expand Up @@ -387,7 +406,8 @@ std::vector<uint8_t> llvm_bpf_jit_context::do_aot_compile(bool print_ir)
return this->do_aot_compile(extNames, lddwNames, print_ir);
}

void llvm_bpf_jit_context::load_aot_object(const std::vector<uint8_t> &buf)
llvm::Error
llvm_bpf_jit_context::load_aot_object(const std::vector<uint8_t> &buf)
{
SPDLOG_INFO("LLVM-JIT: Loading aot object");
if (jit.has_value()) {
Expand All @@ -399,16 +419,19 @@ void llvm_bpf_jit_context::load_aot_object(const std::vector<uint8_t> &buf)
StringRef((const char *)buf.data(), buf.size()));
auto [jit, extFuncNames, definedLddwHelpers] =
create_and_initialize_lljit_instance();
if (!jit) {
return llvm::make_error<llvm::StringError>(
"jit initialization failed",
llvm::inconvertibleErrorCode());
}
if (auto err = jit->addObjectFile(std::move(buffer)); err) {
std::string buf;
raw_string_ostream os(buf);
os << err;
SPDLOG_CRITICAL("Unable to add object file: {}", buf);
throw std::runtime_error("Failed to load AOT object");
SPDLOG_ERROR("Unable to add object file");
return err;
}
this->jit = std::move(jit);
// Test getting entry function
this->get_entry_address();
return llvm::Error::success();
}

std::tuple<std::unique_ptr<llvm::orc::LLJIT>, std::vector<std::string>,
Expand All @@ -417,7 +440,13 @@ llvm_bpf_jit_context::create_and_initialize_lljit_instance()
{
// Create a JIT builder
SPDLOG_DEBUG("LLVM-JIT: Creating LLJIT instance");
auto jit = ExitOnErr(LLJITBuilder().create());
auto jit_err = LLJITBuilder().create();
if (!jit_err) {
(void) jit_err.takeError();
return std::make_tuple(nullptr, std::vector<std::string>{},
std::vector<std::string>{});
}
auto jit = std::move(*jit_err);

auto &mainDylib = jit->getMainJITDylib();
std::vector<std::string> extFuncNames;
Expand Down Expand Up @@ -450,7 +479,11 @@ llvm_bpf_jit_context::create_and_initialize_lljit_instance()
jit->getExecutionSession().intern("__aeabi_unwind_cpp_pr1"),
JITEvaluatedSymbol::fromPointer(__aeabi_unwind_cpp_pr1));
#endif
ExitOnErr(mainDylib.define(absoluteSymbols(extSymbols)));
auto define_extSymbols_err =
mainDylib.define(absoluteSymbols(extSymbols));
if (auto err = mainDylib.define(absoluteSymbols(extSymbols)); !err) {
SPDLOG_INFO("LLVM-JIT: failed to define external symbols");
}
// Define lddw helpers
SymbolMap lddwSyms;
std::vector<std::string> definedLddwHelpers;
Expand Down Expand Up @@ -481,12 +514,15 @@ llvm_bpf_jit_context::create_and_initialize_lljit_instance()
// Only map_val will have a chance to be called at runtime, so it's the
// only symbol to be defined
tryDefineLddwHelper(LDDW_HELPER_MAP_VAL, (void *)vm.map_val);
// These symbols won't be used at runtime
// These symbols won't be used at runtime, because we have already
// do relocation when loading the eBPF bytecode
// tryDefineLddwHelper(LDDW_HELPER_MAP_BY_FD, (void *)vm.map_by_fd);
// tryDefineLddwHelper(LDDW_HELPER_MAP_BY_IDX, (void *)vm.map_by_idx);
// tryDefineLddwHelper(LDDW_HELPER_CODE_ADDR, (void *)vm.code_addr);
// tryDefineLddwHelper(LDDW_HELPER_VAR_ADDR, (void *)vm.var_addr);
ExitOnErr(mainDylib.define(absoluteSymbols(lddwSyms)));
if (auto err = mainDylib.define(absoluteSymbols(lddwSyms)); !err) {
SPDLOG_INFO("LLVM-JIT: failed to define lddw helpers symbols");
}
return { std::move(jit), extFuncNames, definedLddwHelpers };
}

Expand Down
8 changes: 2 additions & 6 deletions src/llvm_jit_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ const static char *LDDW_HELPER_CODE_ADDR = "__lddw_helper_code_addr";

#define IS_ALIGNED(x, a) (((uintptr_t)(x) & ((a) - 1)) == 0)

#ifndef MAX_EXT_FUNCS
#define MAX_EXT_FUNCS 8192
#endif

#ifndef EBPF_STACK_SIZE
// Compatible to C headers
#define EBPF_STACK_SIZE 512
Expand All @@ -56,13 +52,13 @@ class llvm_bpf_jit_context {
create_and_initialize_lljit_instance();

public:
void do_jit_compile();
llvm::Error do_jit_compile();
llvm_bpf_jit_context(llvmbpf_vm &vm);
virtual ~llvm_bpf_jit_context();
precompiled_ebpf_function compile();
precompiled_ebpf_function get_entry_address();
std::vector<uint8_t> do_aot_compile(bool print_ir = false);
void load_aot_object(const std::vector<uint8_t> &buf);
llvm::Error load_aot_object(const std::vector<uint8_t> &buf);
};

} // namespace bpftime
Expand Down
Loading

0 comments on commit 0d60a51

Please sign in to comment.