Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
yunwei37 committed Aug 17, 2024
1 parent 87a8901 commit f60034d
Show file tree
Hide file tree
Showing 25 changed files with 294 additions and 133 deletions.
15 changes: 13 additions & 2 deletions .github/workflows/test-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,19 @@ jobs:
- name: Build and install runtime (with llvm-jit)
if: ${{matrix.enable_jit}}
run: |
make release-with-llvm-jit -j
cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
-DBPFTIME_LLVM_JIT=1 \
-DBUILD_BPFTIME_DAEMON=1 \
-DCMAKE_CXX_FLAGS="-DDEFAULT_LOGGER_OUTPUT_PATH=\"console\""
cmake --build build --config RelWithDebInfo --target install -j
- name: Build and install runtime (without llvm-jit)
if: ${{!matrix.enable_jit}}
run: |
make release -j
cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
-DBPFTIME_LLVM_JIT=0 \
-DBUILD_BPFTIME_DAEMON=1 \
-DCMAKE_CXX_FLAGS="-DDEFAULT_LOGGER_OUTPUT_PATH=\"console\""
cmake --build build --config RelWithDebInfo --target install -j
- name: Upload build results (without jit)
uses: actions/upload-artifact@v3
if: ${{!matrix.enable_jit}}
Expand Down Expand Up @@ -163,17 +171,20 @@ jobs:
- name: Build test assets
run: |
make -C example/${{matrix.examples.path}} -j
- name: Test CLI - show help
run: |
export PATH=$PATH:~/.bpftime
bpftime --help
- name: Test CLI - attach by running (syscall_trace)
if: matrix.examples.syscall_trace
shell: bash
run: |
ROOT=$(pwd)
cd example/${{matrix.examples.path}}
python3 $ROOT/.github/script/run_example.py "${{matrix.examples.executable}}" "${{matrix.examples.victim}}" "${{matrix.examples.expected_str}}" "/github/home/.bpftime/bpftime -i /github/home/.bpftime" 1
- name: Test CLI - attach by running (uprobe)
if: '!matrix.examples.syscall_trace'
shell: bash
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ message(STATUS "Started CMake for ${PROJECT_NAME} v${PROJECT_VERSION}...\n")

# if option to build without libbpf is set
if(${BPFTIME_BUILD_WITH_LIBBPF})
add_definitions(-DUSE_LIBBPF)
add_definitions(-DBPFTIME_BUILD_WITH_LIBBPF=1)
endif()

if(UNIX)
Expand Down Expand Up @@ -135,7 +135,7 @@ endif()
add_subdirectory(third_party/spdlog)
if(NOT DEFINED SPDLOG_ACTIVE_LEVEL)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG)
add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE)
else()
add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO)
endif()
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ release: ## build the release version

release-with-llvm-jit: ## build the package, with llvm-jit
cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
-DBPFTIME_LLVM_JIT=1
-DBPFTIME_LLVM_JIT=1 \
-DBUILD_BPFTIME_DAEMON=1
cmake --build build --config RelWithDebInfo --target install -j$(JOBS)

Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@

## Key Features

- **Uprobe and Syscall hooks based on binary rewriting**: Run eBPF programs in userspace, attaching them to Uprobes and Syscall tracepoints: **No manual instrumentation or restart required!**. It can `trace` or `change` the execution of a function, `hook` or `filter` all syscalls of a process safely, and efficiently with an eBPF userspace runtime.
- **Performance**: Experience up to a `10x` speedup in Uprobe overhead compared to kernel uprobe and uretprobe.
- **Uprobe and Syscall hooks based on binary rewriting**: Run eBPF programs in userspace, attaching them to Uprobes and Syscall tracepoints: **No manual instrumentation or restart required!**. It can `trace` or `change` the execution of a function, `hook` or `filter` all syscalls of a process safely, and efficiently with an eBPF userspace runtime. Can inject eBPF runtime into any running process without the need for a restart or manual recompilation.
- **Performance**: Experience up to a `10x` speedup in Uprobe overhead compared to kernel uprobe and uretprobe. Read/Write userspace memory is also faster than kernel eBPF.
- **Interprocess eBPF Maps**: Implement userspace `eBPF maps` in shared userspace memory for summary aggregation or control plane communication.
- **Compatibility**: use `existing eBPF toolchains` like clang and libbpf to develop userspace eBPF without any modifications. Supporting CO-RE via BTF, and offering userspace host function access.
- **JIT Support**: Benefit from a cross-platform eBPF interpreter and a high-speed `JIT/AOT` compiler powered by LLVM. It also includes a handcrafted x86 JIT in C for limited resources. The vm can be built as `a standalone library` like ubpf.
- **No instrumentation**: Can inject eBPF runtime into any running process without the need for a restart or manual recompilation.
- **Compatibility**: use `existing eBPF toolchains` like clang, libbpf and bpftrace to develop userspace eBPF application without any modifications. Supporting CO-RE via BTF, and offering userspace `ufunc` access.
- **Multi JIT Support**: Support [llvmbpf](https://github.com/eunomia-bpf/llvmbpf), a high-speed `JIT/AOT` compiler powered by LLVM, or using `ubpf JIT` and INTERPRETER. The vm can be built as `a standalone library` like ubpf.
- **Run with kernel eBPF**: Can load userspace eBPF from kernel, and using kernel eBPF maps to cooperate with kernel eBPF programs like kprobes and network filters.

## Components

- [`vm`](https://github.com/eunomia-bpf/bpftime/tree/master/vm): The eBPF VM and JIT for eBPF, you can choose from bpftime LLVM JIT and a simple JIT/interpreter based on ubpf. It can be built as a standalone library and integrated into other projects. The API is similar to ubpf.
- [`runtime`](https://github.com/eunomia-bpf/bpftime/tree/master/runtime): The userspace runtime for eBPF, including the syscall server and agent, attaching eBPF programs to Uprobes and Syscall tracepoints, and eBPF maps in shared memory.
- [`vm`](https://github.com/eunomia-bpf/bpftime/tree/master/vm): The eBPF VM and JIT compiler for bpftime, you can choose from [bpftime LLVM JIT/AOT compiler](https://github.com/eunomia-bpf/llvmbpf) and [ubpf](https://github.com/iovisor/ubpf). The [llvm-based vm](https://github.com/eunomia-bpf/llvmbpf) in bpftime can also be built as a standalone library and integrated into other projects, similar to ubpf.
- [`runtime`](https://github.com/eunomia-bpf/bpftime/tree/master/runtime): The userspace runtime for eBPF, including the bpf-syscall loader(`syscall-server`) and agent, support attaching eBPF programs to Uprobes, Syscall tracepoints and other events, as well as eBPF maps in shared memory.
- [verifier](https://github.com/eunomia-bpf/bpftime/tree/master/bpftime-verifier): Support using [PREVAIL](https://github.com/vbpf/ebpf-verifier) as userspace verifier, or using Linux kernel verifier as an option.
- [`daemon`](https://github.com/eunomia-bpf/bpftime/tree/master/daemon): A daemon to make userspace eBPF working with kernel and compatible with kernel uprobe. Monitor and modify kernel eBPF events and syscalls, load eBPF in userspace from kernel.

## Quick Start
Expand Down
2 changes: 2 additions & 0 deletions attach/text_segment_transformer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ target_include_directories(bpftime_text_segment_transformer
PRIVATE
${FRIDA_GUM_INSTALL_DIR}
${SPDLOG_INCLUDE}
# for the logger
../../runtime/include
)
13 changes: 5 additions & 8 deletions attach/text_segment_transformer/agent-transformer.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
#include "spdlog/cfg/env.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "spdlog/spdlog.h"
#include "bpftime_shm.hpp"
#include "bpftime_logger.hpp"
#include <cstdlib>
#include <dlfcn.h>
#include <frida-gum.h>
#include "text_segment_transformer.hpp"
#include <spdlog/cfg/env.h>
#include <string>
#include <frida-gum.h>

Expand Down Expand Up @@ -47,9 +44,9 @@ extern "C" int __libc_start_main(int (*main)(int, char **, char **), int argc,

extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
{
auto logger = spdlog::stderr_color_mt("stderr");
spdlog::set_default_logger(logger);
spdlog::cfg::load_env_levels();
// use the config for agent
auto runtime_config = bpftime::bpftime_get_agent_config();
bpftime::bpftime_set_logger(runtime_config.logger_output_path);
/* We don't want to our library to be unloaded after we return. */
*stay_resident = TRUE;

Expand Down
16 changes: 5 additions & 11 deletions runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ set(sources
extension/extension_helper.cpp
)

if(UNIX AND NOT APPLE)
if(UNIX AND NOT APPLE AND BPFTIME_BUILD_WITH_LIBBPF)
list(APPEND sources
src/bpf_map/shared/array_map_kernel_user.cpp
src/bpf_map/shared/hash_map_kernel_user.cpp
Expand All @@ -94,13 +94,6 @@ set(headers
message(INFO " Headers: ${headers}")
message(INFO " Found the following sources: ${sources}")


if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG)
else()
add_definitions(-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO)
endif()

add_library(
${PROJECT_NAME}
${sources}
Expand Down Expand Up @@ -238,16 +231,17 @@ message(DEBUG "Successfully added all dependencies and linked against them.")

set(BPFTIME_RUNTIME_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src)


if (BPFTIME_BUILD_WITH_LIBBPF)
add_subdirectory(object)
endif()
add_subdirectory(agent)
add_subdirectory(syscall-server)
#
# Unit testing setup
#
if(BPFTIME_ENABLE_UNIT_TESTING)
if(BPFTIME_ENABLE_UNIT_TESTING AND BPFTIME_BUILD_WITH_LIBBPF)
enable_testing()
message(STATUS "Build unit tests for the project. Tests should always be found in the test folder\n")
message(STATUS "Build unit tests for the runtime. Tests should always be found in the test folder\n")
add_subdirectory(test)
add_subdirectory(unit-test)
endif()
17 changes: 9 additions & 8 deletions runtime/agent/agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "spdlog/common.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "bpftime_logger.hpp"
#include <chrono>
#include <csignal>
#include <exception>
Expand All @@ -21,10 +22,11 @@
#include "bpftime_shm.hpp"
#include <spdlog/spdlog.h>
#include <spdlog/cfg/env.h>
#if __linux__
#if __linux__ && BPFTIME_BUILD_WITH_LIBBPF
#include "syscall_trace_attach_impl.hpp"
#include "syscall_trace_attach_private_data.hpp"
#endif

using namespace bpftime;
using namespace bpftime::attach;
using main_func_t = int (*)(int, char **, char **);
Expand Down Expand Up @@ -94,18 +96,17 @@ static void sig_handler_sigusr1(int sig)
shm_holder.global_shared_memory.remove_pid_from_alive_agent_set(
getpid());
SPDLOG_DEBUG("Detaching done");
bpftime_logger_flush();
}

extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
{
auto logger = spdlog::stderr_color_mt("stderr");
logger->set_pattern("[%Y-%m-%d %H:%M:%S][%^%l%$][%t] %v");
spdlog::set_default_logger(logger);
auto runtime_config = bpftime_get_agent_config();
bpftime_set_logger(runtime_config.logger_output_path);
SPDLOG_DEBUG("Entered bpftime_agent_main");
SPDLOG_DEBUG("Registering signal handler");
// We use SIGUSR1 to indicate the detaching
signal(SIGUSR1, sig_handler_sigusr1);
spdlog::cfg::load_env_levels();
try {
// If we are unable to initialize shared memory..
bpftime_initialize_global_shm(shm_open_type::SHM_OPEN_ONLY);
Expand All @@ -121,7 +122,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
getpid());
}
ctx_holder.init();
#if __linux__
#if __linux__ && BPFTIME_BUILD_WITH_LIBBPF
// Register syscall trace impl
auto syscall_trace_impl = std::make_unique<syscall_trace_attach_impl>();
syscall_trace_impl->set_original_syscall_function(orig_hooker);
Expand Down Expand Up @@ -164,7 +165,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
SPDLOG_DEBUG("Set environment variable BPFTIME_USED");
try {
res = ctx_holder.ctx.init_attach_ctx_from_handlers(
bpftime_get_agent_config());
runtime_config);
if (res != 0) {
SPDLOG_INFO("Failed to initialize attach context, exiting..");
return;
Expand All @@ -178,7 +179,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)

// using definition for libbpf for syscall issues
// maybe should separate libbpf and kernel features separately
#if __linux__
#if __linux__ && BPFTIME_BUILD_WITH_LIBBPF
extern "C" int64_t syscall_callback(int64_t sys_nr, int64_t arg1, int64_t arg2,
int64_t arg3, int64_t arg4, int64_t arg5,
int64_t arg6)
Expand Down
13 changes: 12 additions & 1 deletion runtime/include/bpftime_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
#include <cstdlib>
#include <string>

#ifndef DEFAULT_LOGGER_OUTPUT_PATH
#define DEFAULT_LOGGER_OUTPUT_PATH "~/.bpftime/runtime.log"
#endif
#define stringize(x) #x

namespace bpftime
{
// Configuration for the bpftime runtime
Expand All @@ -28,10 +33,16 @@ struct agent_config {
// available for the eBPF programs and maps
// The value is in MB
int shm_memory_size = 20; // 20MB

// specify the where the logger output should be written to
// It can be a file path or "console".
// If it is "console", the logger will output to stderr
std::string logger_output_path = stringize(DEFAULT_LOGGER_OUTPUT_PATH);
};

// Get the bpftime configuration from the environment variables
const agent_config get_agent_config_from_env();
// If the shared memory is not int, this should be called first
const agent_config get_agent_config_from_env() noexcept;

} // namespace bpftime

Expand Down
73 changes: 73 additions & 0 deletions runtime/include/bpftime_logger.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <string>
#include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include <cstdlib>
#include <iostream>
#include <filesystem>
#include <fstream>

namespace bpftime
{

inline std::string expand_user_path(const std::string &input_path)
{
if (input_path.empty()) {
return "console";
}

if (input_path[0] == '~') {
const char *homeDir = getenv("HOME");
if (!homeDir) {
return "console";
}

if (input_path.size() == 1 || input_path[1] == '/') {
// Replace "~" with the home directory
std::string expandedPath = homeDir +
input_path.substr(1);
return expandedPath;
} else {
return "console"; // Unsupported path format
}
}

// Return the original path if no tilde expansion is needed
return input_path;
}

inline void bpftime_set_logger(const std::string &target) noexcept
{
std::string logger_target = expand_user_path(target);

if (logger_target == "console") {
// Set logger to stderr
auto logger = spdlog::stderr_color_mt("stderr");
logger->set_pattern("[%Y-%m-%d %H:%M:%S][%^%l%$][%t] %v");
logger->flush_on(spdlog::level::info);
spdlog::set_default_logger(logger);
} else {
// Set logger to file, with rotation 5MB and 3 files
auto max_size = 1048576 * 5;
auto max_files = 3;
auto logger = spdlog::rotating_logger_mt(
"bpftime_logger", logger_target, max_size, max_files);
logger->set_pattern("[%Y-%m-%d %H:%M:%S][%^%l%$][%t] %v");
logger->flush_on(spdlog::level::info);
spdlog::set_default_logger(logger);
}

// Load log level from environment
spdlog::cfg::load_env_levels();
}

/*
Flush the logger.
*/
inline void bpftime_logger_flush()
{
spdlog::default_logger()->flush();
}

} // namespace bpftime
Loading

0 comments on commit f60034d

Please sign in to comment.