Skip to content

Commit fb21d6e

Browse files
update (#301)
Co-authored-by: yunwei37 <yunwei356@gmail.com>
1 parent b54598e commit fb21d6e

22 files changed

+279
-125
lines changed

.github/workflows/test-examples.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,19 @@ jobs:
3131
- name: Build and install runtime (with llvm-jit)
3232
if: ${{matrix.enable_jit}}
3333
run: |
34-
make release-with-llvm-jit -j
34+
cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
35+
-DBPFTIME_LLVM_JIT=1 \
36+
-DBUILD_BPFTIME_DAEMON=1 \
37+
-DCMAKE_CXX_FLAGS="-DDEFAULT_LOGGER_OUTPUT_PATH='\"console\"'"
38+
cmake --build build --config RelWithDebInfo --target install -j
3539
- name: Build and install runtime (without llvm-jit)
3640
if: ${{!matrix.enable_jit}}
3741
run: |
38-
make release -j
42+
cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \
43+
-DBPFTIME_LLVM_JIT=0 \
44+
-DBUILD_BPFTIME_DAEMON=1 \
45+
-DCMAKE_CXX_FLAGS="-DDEFAULT_LOGGER_OUTPUT_PATH='\"console\"'"
46+
cmake --build build --config RelWithDebInfo --target install -j
3947
- name: Upload build results (without jit)
4048
uses: actions/upload-artifact@v3
4149
if: ${{!matrix.enable_jit}}

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ message(STATUS "Started CMake for ${PROJECT_NAME} v${PROJECT_VERSION}...\n")
8686

8787
# if option to build without libbpf is set
8888
if(${BPFTIME_BUILD_WITH_LIBBPF})
89-
add_definitions(-DUSE_LIBBPF)
89+
add_definitions(-DBPFTIME_BUILD_WITH_LIBBPF=1)
9090
endif()
9191

9292
if(UNIX)
@@ -135,7 +135,7 @@ endif()
135135
add_subdirectory(third_party/spdlog)
136136
if(NOT DEFINED SPDLOG_ACTIVE_LEVEL)
137137
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
138-
add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG)
138+
add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE)
139139
else()
140140
add_compile_definitions(SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO)
141141
endif()

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@
1717

1818
## Key Features
1919

20-
- **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.
21-
- **Performance**: Experience up to a `10x` speedup in Uprobe overhead compared to kernel uprobe and uretprobe.
20+
- **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.
21+
- **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.
2222
- **Interprocess eBPF Maps**: Implement userspace `eBPF maps` in shared userspace memory for summary aggregation or control plane communication.
23-
- **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.
24-
- **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.
25-
- **No instrumentation**: Can inject eBPF runtime into any running process without the need for a restart or manual recompilation.
23+
- **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.
24+
- **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.
2625
- **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.
2726

2827
## Components
2928

30-
- [`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.
31-
- [`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.
29+
- [`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.
30+
- [`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.
31+
- [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.
3232
- [`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.
3333

3434
## Quick Start

attach/text_segment_transformer/agent-transformer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
6969
"Please set AGENT_SO to the bpftime-agent when use this tranformer");
7070
return;
7171
}
72-
SPDLOG_INFO("Using agent {}", agent_so);
72+
SPDLOG_DEBUG("Using agent {}", agent_so);
7373
cs_arch_register_x86();
7474
bpftime::setup_syscall_tracer();
7575
SPDLOG_DEBUG("Loading dynamic library..");
@@ -98,5 +98,5 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
9898
bpftime::get_call_hook();
9999
entry_func(&orig_syscall_hooker_func);
100100
bpftime::set_call_hook(orig_syscall_hooker_func);
101-
SPDLOG_INFO("Transformer exiting, trace will be usable now");
101+
SPDLOG_DEBUG("Transformer exiting, syscall trace is usable now");
102102
}

runtime/CMakeLists.txt

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ set(sources
7878
extension/extension_helper.cpp
7979
)
8080

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

97-
98-
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
99-
add_definitions(-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_DEBUG)
100-
else()
101-
add_definitions(-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO)
102-
endif()
103-
10497
add_library(
10598
${PROJECT_NAME}
10699
${sources}
@@ -238,16 +231,17 @@ message(DEBUG "Successfully added all dependencies and linked against them.")
238231

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

241-
234+
if (BPFTIME_BUILD_WITH_LIBBPF)
242235
add_subdirectory(object)
236+
endif()
243237
add_subdirectory(agent)
244238
add_subdirectory(syscall-server)
245239
#
246240
# Unit testing setup
247241
#
248-
if(BPFTIME_ENABLE_UNIT_TESTING)
242+
if(BPFTIME_ENABLE_UNIT_TESTING AND BPFTIME_BUILD_WITH_LIBBPF)
249243
enable_testing()
250-
message(STATUS "Build unit tests for the project. Tests should always be found in the test folder\n")
244+
message(STATUS "Build unit tests for the runtime. Tests should always be found in the test folder\n")
251245
add_subdirectory(test)
252246
add_subdirectory(unit-test)
253247
endif()

runtime/agent/agent.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "spdlog/common.h"
77
#include "spdlog/sinks/stdout_color_sinks.h"
88
#include "spdlog/sinks/stdout_sinks.h"
9+
#include "bpftime_logger.hpp"
910
#include <chrono>
1011
#include <csignal>
1112
#include <exception>
@@ -21,10 +22,11 @@
2122
#include "bpftime_shm.hpp"
2223
#include <spdlog/spdlog.h>
2324
#include <spdlog/cfg/env.h>
24-
#if __linux__
25+
#if __linux__ && BPFTIME_BUILD_WITH_LIBBPF
2526
#include "syscall_trace_attach_impl.hpp"
2627
#include "syscall_trace_attach_private_data.hpp"
2728
#endif
29+
2830
using namespace bpftime;
2931
using namespace bpftime::attach;
3032
using main_func_t = int (*)(int, char **, char **);
@@ -94,18 +96,17 @@ static void sig_handler_sigusr1(int sig)
9496
shm_holder.global_shared_memory.remove_pid_from_alive_agent_set(
9597
getpid());
9698
SPDLOG_DEBUG("Detaching done");
99+
bpftime_logger_flush();
97100
}
98101

99102
extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
100103
{
101-
auto logger = spdlog::stderr_color_mt("stderr");
102-
logger->set_pattern("[%Y-%m-%d %H:%M:%S][%^%l%$][%t] %v");
103-
spdlog::set_default_logger(logger);
104+
auto runtime_config = bpftime_get_agent_config();
105+
bpftime_set_logger(runtime_config.logger_output_path);
104106
SPDLOG_DEBUG("Entered bpftime_agent_main");
105107
SPDLOG_DEBUG("Registering signal handler");
106108
// We use SIGUSR1 to indicate the detaching
107109
signal(SIGUSR1, sig_handler_sigusr1);
108-
spdlog::cfg::load_env_levels();
109110
try {
110111
// If we are unable to initialize shared memory..
111112
bpftime_initialize_global_shm(shm_open_type::SHM_OPEN_ONLY);
@@ -121,7 +122,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
121122
getpid());
122123
}
123124
ctx_holder.init();
124-
#if __linux__
125+
#if __linux__ && BPFTIME_BUILD_WITH_LIBBPF
125126
// Register syscall trace impl
126127
auto syscall_trace_impl = std::make_unique<syscall_trace_attach_impl>();
127128
syscall_trace_impl->set_original_syscall_function(orig_hooker);
@@ -164,7 +165,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
164165
SPDLOG_DEBUG("Set environment variable BPFTIME_USED");
165166
try {
166167
res = ctx_holder.ctx.init_attach_ctx_from_handlers(
167-
bpftime_get_agent_config());
168+
runtime_config);
168169
if (res != 0) {
169170
SPDLOG_INFO("Failed to initialize attach context, exiting..");
170171
return;
@@ -178,7 +179,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident)
178179

179180
// using definition for libbpf for syscall issues
180181
// maybe should separate libbpf and kernel features separately
181-
#if __linux__
182+
#if __linux__ && BPFTIME_BUILD_WITH_LIBBPF
182183
extern "C" int64_t syscall_callback(int64_t sys_nr, int64_t arg1, int64_t arg2,
183184
int64_t arg3, int64_t arg4, int64_t arg5,
184185
int64_t arg6)

runtime/include/bpftime_config.hpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
#include <cstdlib>
55
#include <string>
66

7+
#ifndef DEFAULT_LOGGER_OUTPUT_PATH
8+
#define DEFAULT_LOGGER_OUTPUT_PATH "~/.bpftime/runtime.log"
9+
#endif
10+
#define stringize(x) #x
11+
712
namespace bpftime
813
{
914
// Configuration for the bpftime runtime
@@ -28,10 +33,16 @@ struct agent_config {
2833
// available for the eBPF programs and maps
2934
// The value is in MB
3035
int shm_memory_size = 20; // 20MB
36+
37+
// specify the where the logger output should be written to
38+
// It can be a file path or "console".
39+
// If it is "console", the logger will output to stderr
40+
std::string logger_output_path = DEFAULT_LOGGER_OUTPUT_PATH;
3141
};
3242

3343
// Get the bpftime configuration from the environment variables
34-
const agent_config get_agent_config_from_env();
44+
// If the shared memory is not int, this should be called first
45+
const agent_config get_agent_config_from_env() noexcept;
3546

3647
} // namespace bpftime
3748

runtime/include/bpftime_logger.hpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include <string>
2+
#include "spdlog/spdlog.h"
3+
#include "spdlog/cfg/env.h"
4+
#include "spdlog/sinks/rotating_file_sink.h"
5+
#include "spdlog/sinks/stdout_color_sinks.h"
6+
#include <cstdlib>
7+
#include <iostream>
8+
#include <filesystem>
9+
#include <fstream>
10+
11+
namespace bpftime
12+
{
13+
14+
inline std::string expand_user_path(const std::string &input_path)
15+
{
16+
if (input_path.empty()) {
17+
return "console";
18+
}
19+
20+
if (input_path[0] == '~') {
21+
const char *homeDir = getenv("HOME");
22+
if (!homeDir) {
23+
return "console";
24+
}
25+
26+
if (input_path.size() == 1 || input_path[1] == '/') {
27+
// Replace "~" with the home directory
28+
std::string expandedPath = homeDir +
29+
input_path.substr(1);
30+
return expandedPath;
31+
} else {
32+
return "console"; // Unsupported path format
33+
}
34+
}
35+
36+
// Return the original path if no tilde expansion is needed
37+
return input_path;
38+
}
39+
40+
inline void bpftime_set_logger(const std::string &target) noexcept
41+
{
42+
std::string logger_target = expand_user_path(target);
43+
44+
if (logger_target == "console") {
45+
// Set logger to stderr
46+
auto logger = spdlog::stderr_color_mt("stderr");
47+
logger->set_pattern("[%Y-%m-%d %H:%M:%S][%^%l%$][%t] %v");
48+
logger->flush_on(spdlog::level::info);
49+
spdlog::set_default_logger(logger);
50+
} else {
51+
// Set logger to file, with rotation 5MB and 3 files
52+
auto max_size = 1048576 * 5;
53+
auto max_files = 3;
54+
auto logger = spdlog::rotating_logger_mt(
55+
"bpftime_logger", logger_target, max_size, max_files);
56+
logger->set_pattern("[%Y-%m-%d %H:%M:%S][%^%l%$][%t] %v");
57+
logger->flush_on(spdlog::level::info);
58+
spdlog::set_default_logger(logger);
59+
}
60+
61+
// Load log level from environment
62+
spdlog::cfg::load_env_levels();
63+
}
64+
65+
/*
66+
Flush the logger.
67+
*/
68+
inline void bpftime_logger_flush()
69+
{
70+
spdlog::default_logger()->flush();
71+
}
72+
73+
} // namespace bpftime

runtime/include/bpftime_shm.hpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@
1010
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
1111
#include <boost/interprocess/containers/string.hpp>
1212
#include <cstdint>
13-
#include <ebpf-vm.h>
1413
#if __linux__
1514
#include <sys/epoll.h>
1615
#elif __APPLE__
1716
#include "bpftime_epoll.h"
1817
#endif
1918

19+
extern "C" {
20+
struct ebpf_inst;
21+
}
22+
2023
namespace bpftime
2124
{
2225

@@ -153,7 +156,13 @@ enum class bpf_prog_type {
153156
};
154157

155158
extern const shm_open_type global_shm_open_type;
159+
160+
// Get the runtime config in the shared memory.
161+
// The shared memory should be initialized before calling this function.
162+
// This should be called by the agent side instead of the server side.
156163
const bpftime::agent_config &bpftime_get_agent_config();
164+
165+
// Set the runtime config in the shared memory.
157166
void bpftime_set_agent_config(const bpftime::agent_config &cfg);
158167

159168
// Map ops for register external map types and operations
@@ -272,7 +281,6 @@ int bpftime_link_create(int fd, struct bpf_link_create_args *args);
272281
int bpftime_progs_create(int fd, const ebpf_inst *insn, size_t insn_cnt,
273282
const char *prog_name, int prog_type);
274283

275-
276284
// create a bpf map in the global shared memory
277285
//
278286
// @param[fd]: fd is the fd allocated by the kernel. if fd is -1, then the
@@ -314,20 +322,27 @@ int bpftime_perf_event_enable(int fd);
314322
// disable the perf event
315323
int bpftime_perf_event_disable(int fd);
316324

325+
// find the minimal unused fd in shared memory
326+
// Which is a available handler for bpf related object
317327
int bpftime_find_minimal_unused_fd();
318328

319329
int bpftime_attach_perf_to_bpf(int perf_fd, int bpf_fd);
320330
int bpftime_attach_perf_to_bpf_with_cookie(int perf_fd, int bpf_fd,
321331
uint64_t cookie);
332+
322333
int bpftime_add_ringbuf_fd_to_epoll(int ringbuf_fd, int epoll_fd,
323334
epoll_data_t extra_data);
335+
324336
int bpftime_add_software_perf_event_fd_to_epoll(int swpe_fd, int epoll_fd,
325337
epoll_data_t extra_data);
326338

327339
int bpftime_epoll_create();
328340
void *bpftime_get_ringbuf_consumer_page(int ringbuf_fd);
329341
void *bpftime_get_ringbuf_producer_page(int ringbuf_fd);
330342

343+
int bpftime_poll_from_ringbuf(int rb_fd, void *ctx,
344+
int (*cb)(void *, void *, size_t));
345+
331346
int bpftime_is_ringbuf_map(int fd);
332347
int bpftime_is_array_map(int fd);
333348
int bpftime_is_epoll_handler(int fd);
@@ -350,7 +365,7 @@ int bpftime_add_software_perf_event(int cpu, int32_t sample_type,
350365
int bpftime_is_software_perf_event(int fd);
351366
void *bpftime_get_software_perf_event_raw_buffer(int fd, size_t expected_size);
352367
int bpftime_perf_event_output(int fd, const void *buf, size_t sz);
353-
#if __linux__
368+
#if __linux__ && BPFTIME_BUILD_WITH_LIBBPF
354369
int bpftime_shared_perf_event_output(int map_fd, const void *buf, size_t sz);
355370
#endif
356371
int bpftime_add_ureplace_or_override(int fd, int pid, const char *name,
@@ -359,9 +374,6 @@ int bpftime_add_ureplace_or_override(int fd, int pid, const char *name,
359374
int bpftime_get_current_thread_cookie(uint64_t *out);
360375

361376
int bpftime_add_custom_perf_event(int type, const char *attach_argument);
362-
363-
int bpftime_poll_from_ringbuf(int rb_fd, void *ctx,
364-
int (*cb)(void *, void *, size_t));
365377
}
366378

367379
#endif // BPFTIME_SHM_CPP_H

runtime/object/bpf_object.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ using namespace bpftime;
1515
using namespace bpftime_epoll;
1616
#endif
1717

18-
#ifdef USE_LIBBPF
18+
#ifdef BPFTIME_BUILD_WITH_LIBBPF
1919
extern "C" {
2020
#include <bpf/libbpf.h>
2121
#include <bpf/btf.h>

0 commit comments

Comments
 (0)