From 88a79587639afd59103b88747940c6627a434cc4 Mon Sep 17 00:00:00 2001 From: hp <24816726+hp77-creator@users.noreply.github.com> Date: Tue, 25 Jun 2024 09:41:08 +0530 Subject: [PATCH] hp77 | Add Option for build without libbpf (#302) * hp77 | Add options to include build without libbpf and fix errors * Failing at spinlock implementation * Fix volatile errors * Add more preprocessors * first successful build on macOS * Add suggestion and fix cli issue * Fix clock_gettime method * Fix failing tests * Fix definition variable * Fix sched_getpu() * Fix get_sched_cpu * fix cpu_getsched * Add deleted syscall dependency * add changes for spinlock and include suggestions * Add apple guard in map_handler and handler_manager * Add syscall-server as well * use [[maybe_unused]] * undo changes in daemon CMakeList and remove daemon at project level * Add static archive library under the flag condition * Define variables at global level for cli * remove debug log * Remove libbpf flag from daemon * Change nanosecond to assembly instruction * remove for loop for spin-lock implementation * remove gnu/lib-names.h * remove define for consts, include gnu-lib-names-header, convert function from define to inline, change __thread to thread_local * add error log for no cpu * Remove benchmark checks * Fix dependency * Replace (void)variable name with [[maybe_unused]] * remove guard from bpftimetool * fix spacing * fix spacing issue * Remove ENABLE_IO_URING flag from makefile * Fix indent * Remove unnecessary header, change preprocessor directives * Remove guard for object directory --- CMakeLists.txt | 26 +- Makefile | 4 + attach/CMakeLists.txt | 6 +- .../src/frida_attach_utils.cpp | 30 +- .../agent-transformer.cpp | 3 +- cmake/StandardSettings.cmake | 5 +- cmake/frida.cmake | 8 +- daemon/CMakeLists.txt | 1 + runtime/CMakeLists.txt | 53 +- runtime/agent/CMakeLists.txt | 27 +- runtime/agent/agent.cpp | 12 +- runtime/extension/extension_helper.cpp | 10 +- runtime/include/bpftime_epoll.h | 1300 +++++++++++++++++ runtime/include/bpftime_shm.hpp | 6 + runtime/include/platform_utils.hpp | 31 + runtime/include/spinlock.hpp | 55 + runtime/include/spinlock_wrapper.hpp | 74 + runtime/object/CMakeLists.txt | 83 +- runtime/object/bpf_object.cpp | 9 + runtime/src/attach/bpf_attach_ctx.cpp | 2 + runtime/src/bpf_helper.cpp | 47 +- runtime/src/bpf_map/map_common_def.hpp | 6 +- .../bpf_map/shared/array_map_kernel_user.cpp | 3 + .../bpf_map/shared/hash_map_kernel_user.cpp | 1 + .../shared/perf_event_array_kernel_user.hpp | 2 + .../bpf_map/userspace/per_cpu_hash_map.cpp | 7 +- runtime/src/bpf_map/userspace/prog_array.cpp | 18 +- runtime/src/bpf_map/userspace/ringbuf_map.cpp | 3 + runtime/src/bpftime_prog.cpp | 2 + runtime/src/bpftime_shm.cpp | 39 +- runtime/src/bpftime_shm_internal.cpp | 4 + runtime/src/bpftime_shm_json.cpp | 4 + runtime/src/handler/epoll_handler.cpp | 4 + runtime/src/handler/epoll_handler.hpp | 4 + runtime/src/handler/handler_manager.cpp | 3 + runtime/src/handler/map_handler.cpp | 14 + runtime/src/handler/map_handler.hpp | 4 +- runtime/src/handler/perf_event_handler.cpp | 4 + runtime/src/handler/perf_event_handler.hpp | 2 + runtime/src/platform_utils.cpp | 37 + runtime/syscall-server/CMakeLists.txt | 8 + runtime/syscall-server/syscall_context.cpp | 22 +- runtime/syscall-server/syscall_context.hpp | 7 + .../syscall-server/syscall_server_main.cpp | 6 +- tools/bpftimetool/CMakeLists.txt | 16 +- tools/bpftimetool/main.cpp | 2 +- tools/cli/main.cpp | 52 +- 47 files changed, 1969 insertions(+), 97 deletions(-) create mode 100644 runtime/include/bpftime_epoll.h create mode 100644 runtime/include/platform_utils.hpp create mode 100644 runtime/include/spinlock.hpp create mode 100644 runtime/include/spinlock_wrapper.hpp create mode 100644 runtime/src/platform_utils.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fc1e4cd2..24b2b282 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,11 @@ endif() 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) +endif() + if(UNIX) add_compile_options("$<$:-D_DEBUG>") # this will allow to use same _DEBUG macro available in both Linux as well as Windows - MSCV environment. Easy to put Debug specific code. endif(UNIX) @@ -109,8 +114,9 @@ if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n") endif() -include(cmake/libbpf.cmake) - +if(${BPFTIME_BUILD_WITH_LIBBPF}) + include(cmake/libbpf.cmake) +endif() # install frida include(cmake/frida.cmake) @@ -153,9 +159,11 @@ bpftime_add_static_lib_component_command(bpftime_ubpf_vm) bpftime_add_libs_component_command(${UBPF_BUILD_DIR}/lib/libubpf.a) endif() bpftime_add_libs_component_command(${FRIDA_GUM_INSTALL_DIR}/libfrida-gum.a) -bpftime_add_libs_component_command(${CMAKE_CURRENT_BUILD_DIR}/libbpf/libbpf/libbpf.a) bpftime_add_static_lib_component_command(bpftime_frida_uprobe_attach_impl) +if(${BPFTIME_BUILD_WITH_LIBBPF}) +bpftime_add_libs_component_command(${CMAKE_CURRENT_BUILD_DIR}/libbpf/libbpf/libbpf.a) bpftime_add_static_lib_component_command(bpftime_syscall_trace_attach_impl) +endif() bpftime_add_static_lib_component_command(runtime) bpftime_add_static_lib_component_command(spdlog) add_custom_command(OUTPUT "libbpftime.a" @@ -181,7 +189,7 @@ DESTINATION ~/.bpftime endif() -if (${BUILD_BPFTIME_DAEMON}) +if (${BUILD_BPFTIME_DAEMON} AND ${BPFTIME_BUILD_WITH_LIBBPF}) add_subdirectory(daemon) endif() add_subdirectory(tools) @@ -191,9 +199,17 @@ if(${BUILD_ATTACH_IMPL_EXAMPLE}) endif() # benchmark that requires bpftime libraries +if(${BPFTIME_BUILD_WITH_LIBBPF}) +# Currently benchmark is using libbpf add_subdirectory(benchmark) +endif() set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") -install(TARGETS bpftime-agent bpftime_text_segment_transformer bpftime-syscall-server CONFIGURATIONS Release Debug RelWithDebInfo DESTINATION ~/.bpftime) +set(DEST_DIR "$ENV{HOME}/.bpftime") +if(${BPFTIME_BUILD_WITH_LIBBPF}) + install(TARGETS bpftime-agent bpftime_text_segment_transformer bpftime-syscall-server CONFIGURATIONS Release Debug RelWithDebInfo DESTINATION ${DEST_DIR}) +else() + install(TARGETS bpftime-agent bpftime-syscall-server CONFIGURATIONS Release Debug RelWithDebInfo DESTINATION ${DEST_DIR}) +endif() diff --git a/Makefile b/Makefile index 87f787a7..214e7030 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,10 @@ build-iouring: ## build the package with iouring extension cmake -Bbuild -DBPFTIME_ENABLE_IOURING_EXT=1 -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo cmake --build build --config RelWithDebInfo -j$(JOBS) +build-wo-libbpf: ## build the package with iouring extension + cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo -DBPFTIME_BUILD_WITH_LIBBPF=OFF -DBPFTIME_BUILD_KERNEL_BPF=OFF + cmake --build build --config RelWithDebInfo --target install -j$(JOBS) + release: ## build the release version cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \ -DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO diff --git a/attach/CMakeLists.txt b/attach/CMakeLists.txt index 70654644..4d9fa2fe 100644 --- a/attach/CMakeLists.txt +++ b/attach/CMakeLists.txt @@ -5,5 +5,7 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") endif() add_subdirectory(base_attach_impl) add_subdirectory(frida_uprobe_attach_impl) -add_subdirectory(syscall_trace_attach_impl) -add_subdirectory(text_segment_transformer) +if(UNIX AND NOT APPLE) + add_subdirectory(syscall_trace_attach_impl) + add_subdirectory(text_segment_transformer) +endif() diff --git a/attach/frida_uprobe_attach_impl/src/frida_attach_utils.cpp b/attach/frida_uprobe_attach_impl/src/frida_attach_utils.cpp index 90093db7..68a4cfac 100644 --- a/attach/frida_uprobe_attach_impl/src/frida_attach_utils.cpp +++ b/attach/frida_uprobe_attach_impl/src/frida_attach_utils.cpp @@ -3,17 +3,31 @@ #include #include #include +#include +#if __APPLE__ +#include +#endif static std::string get_executable_path() { char exec_path[PATH_MAX] = { 0 }; - ssize_t len = - readlink("/proc/self/exe", exec_path, sizeof(exec_path) - 1); - if (len != -1) { - exec_path[len] = '\0'; // Null-terminate the string - SPDLOG_INFO("Executable path: {}", exec_path); - } else { - SPDLOG_ERROR("Error retrieving executable path: {}", errno); - } + + #if __linux__ + ssize_t len = + readlink("/proc/self/exe", exec_path, sizeof(exec_path) - 1); + if (len != -1) { + exec_path[len] = '\0'; // Null-terminate the string + SPDLOG_INFO("Executable path: {}", exec_path); + } else { + SPDLOG_ERROR("Error retrieving executable path: {}", errno); + } + #elif __APPLE__ + pid_t pid = getpid(); + if (proc_pidpath(pid, exec_path, sizeof(exec_path)) > 0) { + SPDLOG_INFO("Executable path: {}", exec_path); + } else { + SPDLOG_ERROR("Error retrieving executable path: {}", errno); + } + #endif return exec_path; } namespace bpftime diff --git a/attach/text_segment_transformer/agent-transformer.cpp b/attach/text_segment_transformer/agent-transformer.cpp index 9ce9bfea..c75684e6 100644 --- a/attach/text_segment_transformer/agent-transformer.cpp +++ b/attach/text_segment_transformer/agent-transformer.cpp @@ -73,8 +73,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident) cs_arch_register_x86(); bpftime::setup_syscall_tracer(); SPDLOG_DEBUG("Loading dynamic library.."); - auto next_handle = - dlmopen(LM_ID_NEWLM, agent_so, RTLD_NOW | RTLD_LOCAL); + auto next_handle = dlmopen(LM_ID_NEWLM, agent_so, RTLD_NOW | RTLD_LOCAL); if (next_handle == nullptr) { SPDLOG_ERROR("Failed to open agent: {}", dlerror()); exit(1); diff --git a/cmake/StandardSettings.cmake b/cmake/StandardSettings.cmake index 2404225f..95f29580 100644 --- a/cmake/StandardSettings.cmake +++ b/cmake/StandardSettings.cmake @@ -84,4 +84,7 @@ option(BUILD_BPFTIME_DAEMON "Whether to build the bpftime daemon" ON) option(BPFTIME_BUILD_KERNEL_BPF "Whether to build with bpf share maps" ON) # whether to build single static library -option(BPFTIME_BUILD_STATIC_LIB "Whether to build a single static library for different archive files" OFF) \ No newline at end of file +option(BPFTIME_BUILD_STATIC_LIB "Whether to build a single static library for different archive files" OFF) + +# whether to build bpftime with libbpf and other linux headers +option(BPFTIME_BUILD_WITH_LIBBPF "Whether to build with libbpf and other linux headers" ON) \ No newline at end of file diff --git a/cmake/frida.cmake b/cmake/frida.cmake index 67419a2a..fa6b8640 100644 --- a/cmake/frida.cmake +++ b/cmake/frida.cmake @@ -26,11 +26,11 @@ elseif(${FRIDA_OS_ARCH} MATCHES "linux-arm.*") set(FRIDA_GUM_DEVKIT_SHA256 "6b5963eb740062aec6c22c46ec2944a68006f72d290f714fb747ffe75b448a60") # Frida only has armhf builds.. set(FRIDA_OS_ARCH "linux-armhf") -elseif(${FRIDA_OS_ARCH} MATCHES "darwin-arm.*") - set(FRIDA_CORE_DEVKIT_SHA256 "50aea2d5dfff000ed1f1dc1fdb2db67a02e4c4f44e782fa311f8afa31df327b6") - set(FRIDA_GUM_DEVKIT_SHA256 "b40c08bebd6958d41d91b7819171a457448cccad5faf417c9b4901be54b6c633") +elseif(${FRIDA_OS_ARCH} MATCHES "darwin-arm64") + set(FRIDA_CORE_DEVKIT_SHA256 "7811e516e6b7bbc0153d30095560e0b1133f154060c5542764100d3e0eb2ab2b") + set(FRIDA_GUM_DEVKIT_SHA256 "03f6085ae5330cf38e0a498784500675fc5bd7361bb551a9097ba5fe397aceda") # for macos-arm m* chip series - set(FRIDA_OS_ARCH "macos-arm64e") + set(FRIDA_OS_ARCH "macos-arm64") else() message(FATAL_ERROR "Unsupported frida arch ${FRIDA_OS_ARCH}") endif() diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 12cc6c03..a6e89870 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -52,6 +52,7 @@ target_link_libraries(libbpftime_daemon PRIVATE PUBLIC rt ) + set_property(TARGET libbpftime_daemon PROPERTY CXX_STANDARD 20) add_dependencies(bpftime_daemon libbpftime_daemon) diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 4ec1f325..529aa2e6 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -43,7 +43,6 @@ endif() # Create library, setup header and source files # find_package(Boost REQUIRED) - # Find all headers and implementation files if(NOT DEFINED ARCH) set(ARCH ${CMAKE_SYSTEM_PROCESSOR}) @@ -65,6 +64,7 @@ set(sources src/bpftime_prog.cpp src/ufunc.cpp src/bpf_helper.cpp + src/platform_utils.cpp src/bpf_map/userspace/array_map.cpp src/bpf_map/userspace/hash_map.cpp @@ -76,7 +76,7 @@ set(sources extension/extension_helper.cpp ) -if(BPFTIME_BUILD_KERNEL_BPF) +if(UNIX AND NOT APPLE) list(APPEND sources src/bpf_map/shared/array_map_kernel_user.cpp src/bpf_map/shared/hash_map_kernel_user.cpp @@ -90,9 +90,9 @@ set(headers include/ ) 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() @@ -114,6 +114,7 @@ add_custom_target( DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/syscall_id_list.h ) +message(INFO " Found the following boost include dirs : ${Boost_INCLUDE_DIRS}") target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../vm/include @@ -122,6 +123,7 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../third_party ${SPDLOG_INCLUDE} + ${Boost_INCLUDE_DIRS} ) target_link_libraries(${PROJECT_NAME} @@ -130,7 +132,11 @@ target_link_libraries(${PROJECT_NAME} spdlog::spdlog bpftime_base_attach_impl ) -add_dependencies(${PROJECT_NAME} bpftime_vm FridaGum spdlog::spdlog libbpf bpftime_base_attach_impl) +if(${BPFTIME_BUILD_WITH_LIBBPF}) + add_dependencies(${PROJECT_NAME} bpftime_vm FridaGum spdlog::spdlog libbpf bpftime_base_attach_impl) +else() + add_dependencies(${PROJECT_NAME} bpftime_vm FridaGum spdlog::spdlog bpftime_base_attach_impl) +endif() if(BPFTIME_ENABLE_IOURING_EXT) target_link_libraries(${PROJECT_NAME} @@ -166,6 +172,17 @@ set_project_warnings(runtime) message(DEBUG "Applied compiler warnings. Using standard ${CMAKE_CXX_STANDARD}.") +if(APPLE) + find_library(COCOA_LIBRARY Cocoa) + find_library(FOUNDATION_LIBRARY Foundation) + find_library(APPKIT_LIBRARY AppKit) + find_library(COREF_LIBRARY CoreFoundation) + find_library(RESOLV_LIBRARY resolv) + mark_as_advanced(COCOA_LIBRARY FOUNDATION_LIBRARY APPKIT_LIBRARY COREF_LIBRARY RESOLV_LIBRARY) + set(EXTRA_LIBS ${COCOA_LIBRARY} ${FOUNDATION_LIBRARY} ${APPKIT_LIBRARY} ${COREF_LIBRARY} ${RESOLV_LIBRARY}) +endif() + +if(${BPFTIME_BUILD_WITH_LIBBPF}) target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBBPF_LIBRARIES} @@ -176,8 +193,24 @@ target_link_libraries(${PROJECT_NAME} -lz -lelf bpftime_base_attach_impl + ${EXTRA_LIBS} +) +else() +target_link_libraries(${PROJECT_NAME} + PUBLIC + ${FRIDA_GUM_INSTALL_DIR}/libfrida-gum.a + -lpthread + -lm + -ldl + -lz + bpftime_base_attach_impl + ${EXTRA_LIBS} ) +endif() + + +if(BPFTIME_BUILD_WITH_LIBBPF) target_include_directories(${PROJECT_NAME} PUBLIC ${LIBBPF_INCLUDE_DIRS}/uapi ${LIBBPF_INCLUDE_DIRS} @@ -188,15 +221,25 @@ target_include_directories(${PROJECT_NAME} PUBLIC $ $ ) +else() +target_include_directories(${PROJECT_NAME} PUBLIC + ${FRIDA_GUM_INSTALL_DIR} + $ + $ + $ + $ + $ +) +endif() message(DEBUG "Successfully added all dependencies and linked against them.") set(BPFTIME_RUNTIME_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) + add_subdirectory(object) add_subdirectory(agent) add_subdirectory(syscall-server) - # # Unit testing setup # diff --git a/runtime/agent/CMakeLists.txt b/runtime/agent/CMakeLists.txt index f94ad81c..a081b350 100644 --- a/runtime/agent/CMakeLists.txt +++ b/runtime/agent/CMakeLists.txt @@ -1,9 +1,14 @@ add_library(bpftime-agent SHARED agent.cpp ) -add_dependencies(bpftime-agent FridaGum spdlog::spdlog bpftime_frida_uprobe_attach_impl bpftime_syscall_trace_attach_impl) +if(${BPFTIME_BUILD_WITH_LIBBPF}) + add_dependencies(bpftime-agent FridaGum spdlog::spdlog bpftime_frida_uprobe_attach_impl bpftime_syscall_trace_attach_impl) +else() + add_dependencies(bpftime-agent FridaGum spdlog::spdlog bpftime_frida_uprobe_attach_impl) +endif() set_target_properties(bpftime-agent PROPERTIES CXX_STANDARD 20 LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/agent.version) target_link_options(bpftime-agent PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/agent.version) +if(${BPFTIME_BUILD_WITH_LIBBPF}) target_include_directories(bpftime-agent PRIVATE ${FRIDA_GUM_INSTALL_DIR} @@ -23,3 +28,23 @@ target_link_libraries(bpftime-agent bpftime_frida_uprobe_attach_impl bpftime_syscall_trace_attach_impl ) + +else() +target_include_directories(bpftime-agent + PRIVATE + ${FRIDA_GUM_INSTALL_DIR} + ../include + ../../third_party/ + ${SPDLOG_INCLUDE} + ${FRIDA_UPROBE_ATTACH_IMPL_INCLUDE} +) +target_link_libraries(bpftime-agent + ${FRIDA_GUM_INSTALL_DIR}/libfrida-gum.a + runtime + -lpthread + -lm + -ldl + spdlog::spdlog + bpftime_frida_uprobe_attach_impl +) +endif() diff --git a/runtime/agent/agent.cpp b/runtime/agent/agent.cpp index 5fe1744b..f4a59b5e 100644 --- a/runtime/agent/agent.cpp +++ b/runtime/agent/agent.cpp @@ -6,8 +6,6 @@ #include "spdlog/common.h" #include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/stdout_sinks.h" -#include "syscall_trace_attach_impl.hpp" -#include "syscall_trace_attach_private_data.hpp" #include #include #include @@ -23,6 +21,10 @@ #include "bpftime_shm.hpp" #include #include +#if __linux__ +#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 **); @@ -119,6 +121,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident) getpid()); } ctx_holder.init(); + #if __linux__ // Register syscall trace impl auto syscall_trace_impl = std::make_unique(); syscall_trace_impl->set_original_syscall_function(orig_hooker); @@ -136,6 +139,7 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident) } return priv_data; }); + #endif // Register uprobe attach impl ctx_holder.ctx.register_attach_impl( { ATTACH_UPROBE, ATTACH_URETPROBE, ATTACH_UPROBE_OVERRIDE, @@ -172,6 +176,9 @@ extern "C" void bpftime_agent_main(const gchar *data, gboolean *stay_resident) SPDLOG_INFO("Attach successfully"); } +// using definition for libbpf for syscall issues +// maybe should separate libbpf and kernel features separately +#if __linux__ 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) @@ -189,3 +196,4 @@ _bpftime__setup_syscall_trace_callback(syscall_hooker_func_t *hooker) bpftime_agent_main("", &val); SPDLOG_INFO("Agent syscall trace setup exiting.."); } +#endif \ No newline at end of file diff --git a/runtime/extension/extension_helper.cpp b/runtime/extension/extension_helper.cpp index 6d7fa843..82787573 100644 --- a/runtime/extension/extension_helper.cpp +++ b/runtime/extension/extension_helper.cpp @@ -19,7 +19,7 @@ #include #include -#ifdef BPFTIME_ENABLE_IOURING_EXT +#if defined (BPFTIME_ENABLE_IOURING_EXT) && __linux__ #include "liburing.h" #endif @@ -46,8 +46,12 @@ uint64_t bpftime_path_join(const char *filename1, const char *filename2, namespace bpftime { -#ifdef BPFTIME_ENABLE_IOURING_EXT +/* +io_uring are only available in linux atm +so adding linux guards to the following code +*/ +#if defined (BPFTIME_ENABLE_IOURING_EXT) && __linux__ static int submit_io_uring_write(struct io_uring *ring, int fd, char *buf, size_t size) { @@ -154,7 +158,7 @@ extern const bpftime_helper_group extesion_group = { { .fn = (void *)bpftime_path_join, } }, #endif -#ifdef BPFTIME_ENABLE_IOURING_EXT +#if defined (BPFTIME_ENABLE_IOURING_EXT) && __linux__ { EXTENDED_HELPER_IOURING_INIT, bpftime_helper_info{ .index = EXTENDED_HELPER_IOURING_INIT, diff --git a/runtime/include/bpftime_epoll.h b/runtime/include/bpftime_epoll.h new file mode 100644 index 00000000..e25fde6c --- /dev/null +++ b/runtime/include/bpftime_epoll.h @@ -0,0 +1,1300 @@ +#ifndef BPFTIME_EPOLL_H +#define BPFTIME_EPOLL_H +#include +#include +#include +#include +/* + Keeping declaration for structs that are specific to linux + structures added from + + + +*/ + +#define EPOLLIN 0x001 +#define BPF_OBJ_NAME_LEN 16U +#define BPF_TAG_SIZE 8 +#define offsetofend(type, member) (offsetof(type, member) + sizeof(((type *)0)->member)) + + + +#ifndef __NR_bpf +#define __NR_bpf 515 // This is a placeholder value. Linux assigns syscall numbers dynamically. +#endif + +#if __GNUC__ >= 4 +#define LIBBPF_API __attribute__((visibility("default"))) +#else +#define LIBBPF_API +#endif + +#ifndef __NR_perf_event_open +#define __NR_perf_event_open 516 // This is a placeholder value. Linux assigns syscall numbers dynamically. +#endif + +// Define a placeholder for PERF_EVENT_IOC_ENABLE. macOS doesn't have any equivalent for ioctl +#define PERF_EVENT_IOC_ENABLE 0 +// Define a placeholder for PERF_EVENT_IOC_DISABLE +#define PERF_EVENT_IOC_DISABLE 1 +// Define a placeholder for PERF_EVENT_IOC_SET_BPF +#define PERF_EVENT_IOC_SET_BPF 2 + +/* Valid opcodes to issue to sys_epoll_ctl() */ +// link: https://github.com/torvalds/linux/blob/2ef5971ff345d3c000873725db555085e0131961/include/uapi/linux/eventpoll.h#L26 +#define EPOLL_CTL_ADD 1 + +// https://github.com/torvalds/linux/blob/2ef5971ff345d3c000873725db555085e0131961/include/uapi/linux/bpf.h#L18 +#define BPF_ALU64 0x07 /* alu mode in double word width */ +#define BPF_MOV 0xb0 /* mov reg to reg */ +#define BPF_K 0x00 //https://github.com/torvalds/linux/blob/2ef5971ff345d3c000873725db555085e0131961/include/uapi/linux/bpf_common.h#L12 +#define BPF_JMP 0x05 +#define BPF_EXIT 0x90 /* function return */ +union epoll_data { + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; + }; + +typedef union epoll_data epoll_data_t; +struct epoll_event { + uint32_t events; /* Epoll events */ + epoll_data_t data; /* User data variable */ + }; +typedef uint64_t __u64; +typedef uint64_t __aligned_u64; +typedef uint32_t __u32; +typedef uint16_t __u16; +typedef uint8_t __u8; + +typedef int16_t __s16; +typedef int32_t __s32; +typedef int64_t __s64; + +typedef off_t off64_t; + +struct perf_event_header { + __u32 type; + __u16 misc; + __u16 size; + }; + +/* +https://github.com/torvalds/linux/blob/f06ce441457d4abc4d76be7acba26868a2d02b1c/include/uapi/linux/perf_event.h#L571 +*/ +struct perf_event_mmap_page { + + __u32 version; /* version number of this structure */ + __u32 compat_version; /* lowest version this is compat with */ + + /* + * Bits needed to read the hw events in user-space. + * + * u32 seq, time_mult, time_shift, index, width; + * u64 count, enabled, running; + * u64 cyc, time_offset; + * s64 pmc = 0; + * + * do { + * seq = pc->lock; + * barrier() + * + * enabled = pc->time_enabled; + * running = pc->time_running; + * + * if (pc->cap_usr_time && enabled != running) { + * cyc = rdtsc(); + * time_offset = pc->time_offset; + * time_mult = pc->time_mult; + * time_shift = pc->time_shift; + * } + * + * index = pc->index; + * count = pc->offset; + * if (pc->cap_user_rdpmc && index) { + * width = pc->pmc_width; + * pmc = rdpmc(index - 1); + * } + * + * barrier(); + * } while (pc->lock != seq); + * + * NOTE: for obvious reason this only works on self-monitoring + * processes. + */ + __u32 lock; /* seqlock for synchronization */ + __u32 index; /* hardware event identifier */ + __s64 offset; /* add to hardware event value */ + __u64 time_enabled; /* time event active */ + __u64 time_running; /* time event on cpu */ + union { + __u64 capabilities; + struct { + __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */ + cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */ + + cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */ + cap_user_time : 1, /* The time_{shift,mult,offset} fields are used */ + cap_user_time_zero : 1, /* The time_zero field is used */ + cap_user_time_short : 1, /* the time_{cycle,mask} fields are used */ + cap_____res : 58; + }; + }; + + /* + * If cap_user_rdpmc this field provides the bit-width of the value + * read using the rdpmc() or equivalent instruction. This can be used + * to sign extend the result like: + * + * pmc <<= 64 - width; + * pmc >>= 64 - width; // signed shift right + * count += pmc; + */ + __u16 pmc_width; + + /* + * If cap_usr_time the below fields can be used to compute the time + * delta since time_enabled (in ns) using rdtsc or similar. + * + * u64 quot, rem; + * u64 delta; + * + * quot = (cyc >> time_shift); + * rem = cyc & (((u64)1 << time_shift) - 1); + * delta = time_offset + quot * time_mult + + * ((rem * time_mult) >> time_shift); + * + * Where time_offset,time_mult,time_shift and cyc are read in the + * seqcount loop described above. This delta can then be added to + * enabled and possible running (if index), improving the scaling: + * + * enabled += delta; + * if (index) + * running += delta; + * + * quot = count / running; + * rem = count % running; + * count = quot * enabled + (rem * enabled) / running; + */ + __u16 time_shift; + __u32 time_mult; + __u64 time_offset; + /* + * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated + * from sample timestamps. + * + * time = timestamp - time_zero; + * quot = time / time_mult; + * rem = time % time_mult; + * cyc = (quot << time_shift) + (rem << time_shift) / time_mult; + * + * And vice versa: + * + * quot = cyc >> time_shift; + * rem = cyc & (((u64)1 << time_shift) - 1); + * timestamp = time_zero + quot * time_mult + + * ((rem * time_mult) >> time_shift); + */ + __u64 time_zero; + + __u32 size; /* Header size up to __reserved[] fields. */ + __u32 __reserved_1; + + /* + * If cap_usr_time_short, the hardware clock is less than 64bit wide + * and we must compute the 'cyc' value, as used by cap_usr_time, as: + * + * cyc = time_cycles + ((cyc - time_cycles) & time_mask) + * + * NOTE: this form is explicitly chosen such that cap_usr_time_short + * is a correction on top of cap_usr_time, and code that doesn't + * know about cap_usr_time_short still works under the assumption + * the counter doesn't wrap. + */ + __u64 time_cycles; + __u64 time_mask; + + /* + * Hole for extension of the self monitor capabilities + */ + + __u8 __reserved[116*8]; /* align to 1k. */ + + /* + * Control data for the mmap() data buffer. + * + * User-space reading the @data_head value should issue an smp_rmb(), + * after reading this value. + * + * When the mapping is PROT_WRITE the @data_tail value should be + * written by userspace to reflect the last read data, after issueing + * an smp_mb() to separate the data read from the ->data_tail store. + * In this case the kernel will not over-write unread data. + * + * See perf_output_put_handle() for the data ordering. + * + * data_{offset,size} indicate the location and size of the perf record + * buffer within the mmapped area. + */ + __u64 data_head; /* head in the data section */ + __u64 data_tail; /* user-space written tail */ + __u64 data_offset; /* where the buffer starts */ + __u64 data_size; /* data buffer size */ + + /* + * AUX area is defined by aux_{offset,size} fields that should be set + * by the userspace, so that + * + * aux_offset >= data_offset + data_size + * + * prior to mmap()ing it. Size of the mmap()ed area should be aux_size. + * + * Ring buffer pointers aux_{head,tail} have the same semantics as + * data_{head,tail} and same ordering rules apply. + */ + __u64 aux_head; + __u64 aux_tail; + __u64 aux_offset; + __u64 aux_size; +}; + + +enum perf_event_type { + + /* + * If perf_event_attr.sample_id_all is set then all event types will + * have the sample_type selected fields related to where/when + * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU, + * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed + * just after the perf_event_header and the fields already present for + * the existing fields, i.e. at the end of the payload. That way a newer + * perf.data file will be supported by older perf tools, with these new + * optional fields being ignored. + * + * struct sample_id { + * { u32 pid, tid; } && PERF_SAMPLE_TID + * { u64 time; } && PERF_SAMPLE_TIME + * { u64 id; } && PERF_SAMPLE_ID + * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID + * { u32 cpu, res; } && PERF_SAMPLE_CPU + * { u64 id; } && PERF_SAMPLE_IDENTIFIER + * } && perf_event_attr::sample_id_all + * + * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The + * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed + * relative to header.size. + */ + + /* + * The MMAP events record the PROT_EXEC mappings so that we can + * correlate userspace IPs to code. They have the following structure: + * + * struct { + * struct perf_event_header header; + * + * u32 pid, tid; + * u64 addr; + * u64 len; + * u64 pgoff; + * char filename[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_MMAP = 1, + + /* + * struct { + * struct perf_event_header header; + * u64 id; + * u64 lost; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_LOST = 2, + + /* + * struct { + * struct perf_event_header header; + * + * u32 pid, tid; + * char comm[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_COMM = 3, + + /* + * struct { + * struct perf_event_header header; + * u32 pid, ppid; + * u32 tid, ptid; + * u64 time; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_EXIT = 4, + + /* + * struct { + * struct perf_event_header header; + * u64 time; + * u64 id; + * u64 stream_id; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_THROTTLE = 5, + PERF_RECORD_UNTHROTTLE = 6, + + /* + * struct { + * struct perf_event_header header; + * u32 pid, ppid; + * u32 tid, ptid; + * u64 time; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_FORK = 7, + + /* + * struct { + * struct perf_event_header header; + * u32 pid, tid; + * + * struct read_format values; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_READ = 8, + + /* + * struct { + * struct perf_event_header header; + * + * # + * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. + * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position + * # is fixed relative to header. + * # + * + * { u64 id; } && PERF_SAMPLE_IDENTIFIER + * { u64 ip; } && PERF_SAMPLE_IP + * { u32 pid, tid; } && PERF_SAMPLE_TID + * { u64 time; } && PERF_SAMPLE_TIME + * { u64 addr; } && PERF_SAMPLE_ADDR + * { u64 id; } && PERF_SAMPLE_ID + * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID + * { u32 cpu, res; } && PERF_SAMPLE_CPU + * { u64 period; } && PERF_SAMPLE_PERIOD + * + * { struct read_format values; } && PERF_SAMPLE_READ + * + * { u64 nr, + * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN + * + * # + * # The RAW record below is opaque data wrt the ABI + * # + * # That is, the ABI doesn't make any promises wrt to + * # the stability of its content, it may vary depending + * # on event, hardware, kernel version and phase of + * # the moon. + * # + * # In other words, PERF_SAMPLE_RAW contents are not an ABI. + * # + * + * { u32 size; + * char data[size];}&& PERF_SAMPLE_RAW + * + * { u64 nr; + * { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX + * { u64 from, to, flags } lbr[nr]; + * } && PERF_SAMPLE_BRANCH_STACK + * + * { u64 abi; # enum perf_sample_regs_abi + * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER + * + * { u64 size; + * char data[size]; + * u64 dyn_size; } && PERF_SAMPLE_STACK_USER + * + * { union perf_sample_weight + * { + * u64 full; && PERF_SAMPLE_WEIGHT + * #if defined(__LITTLE_ENDIAN_BITFIELD) + * struct { + * u32 var1_dw; + * u16 var2_w; + * u16 var3_w; + * } && PERF_SAMPLE_WEIGHT_STRUCT + * #elif defined(__BIG_ENDIAN_BITFIELD) + * struct { + * u16 var3_w; + * u16 var2_w; + * u32 var1_dw; + * } && PERF_SAMPLE_WEIGHT_STRUCT + * #endif + * } + * } + * { u64 data_src; } && PERF_SAMPLE_DATA_SRC + * { u64 transaction; } && PERF_SAMPLE_TRANSACTION + * { u64 abi; # enum perf_sample_regs_abi + * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR + * { u64 phys_addr;} && PERF_SAMPLE_PHYS_ADDR + * { u64 size; + * char data[size]; } && PERF_SAMPLE_AUX + * { u64 data_page_size;} && PERF_SAMPLE_DATA_PAGE_SIZE + * { u64 code_page_size;} && PERF_SAMPLE_CODE_PAGE_SIZE + * }; + */ + PERF_RECORD_SAMPLE = 9, + + /* + * The MMAP2 records are an augmented version of MMAP, they add + * maj, min, ino numbers to be used to uniquely identify each mapping + * + * struct { + * struct perf_event_header header; + * + * u32 pid, tid; + * u64 addr; + * u64 len; + * u64 pgoff; + * union { + * struct { + * u32 maj; + * u32 min; + * u64 ino; + * u64 ino_generation; + * }; + * struct { + * u8 build_id_size; + * u8 __reserved_1; + * u16 __reserved_2; + * u8 build_id[20]; + * }; + * }; + * u32 prot, flags; + * char filename[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_MMAP2 = 10, + + /* + * Records that new data landed in the AUX buffer part. + * + * struct { + * struct perf_event_header header; + * + * u64 aux_offset; + * u64 aux_size; + * u64 flags; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_AUX = 11, + + /* + * Indicates that instruction trace has started + * + * struct { + * struct perf_event_header header; + * u32 pid; + * u32 tid; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_ITRACE_START = 12, + + /* + * Records the dropped/lost sample number. + * + * struct { + * struct perf_event_header header; + * + * u64 lost; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_LOST_SAMPLES = 13, + + /* + * Records a context switch in or out (flagged by + * PERF_RECORD_MISC_SWITCH_OUT). See also + * PERF_RECORD_SWITCH_CPU_WIDE. + * + * struct { + * struct perf_event_header header; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_SWITCH = 14, + + /* + * CPU-wide version of PERF_RECORD_SWITCH with next_prev_pid and + * next_prev_tid that are the next (switching out) or previous + * (switching in) pid/tid. + * + * struct { + * struct perf_event_header header; + * u32 next_prev_pid; + * u32 next_prev_tid; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_SWITCH_CPU_WIDE = 15, + + /* + * struct { + * struct perf_event_header header; + * u32 pid; + * u32 tid; + * u64 nr_namespaces; + * { u64 dev, inode; } [nr_namespaces]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_NAMESPACES = 16, + + /* + * Record ksymbol register/unregister events: + * + * struct { + * struct perf_event_header header; + * u64 addr; + * u32 len; + * u16 ksym_type; + * u16 flags; + * char name[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_KSYMBOL = 17, + + /* + * Record bpf events: + * enum perf_bpf_event_type { + * PERF_BPF_EVENT_UNKNOWN = 0, + * PERF_BPF_EVENT_PROG_LOAD = 1, + * PERF_BPF_EVENT_PROG_UNLOAD = 2, + * }; + * + * struct { + * struct perf_event_header header; + * u16 type; + * u16 flags; + * u32 id; + * u8 tag[BPF_TAG_SIZE]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_BPF_EVENT = 18, + + /* + * struct { + * struct perf_event_header header; + * u64 id; + * char path[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_CGROUP = 19, + + /* + * Records changes to kernel text i.e. self-modified code. 'old_len' is + * the number of old bytes, 'new_len' is the number of new bytes. Either + * 'old_len' or 'new_len' may be zero to indicate, for example, the + * addition or removal of a trampoline. 'bytes' contains the old bytes + * followed immediately by the new bytes. + * + * struct { + * struct perf_event_header header; + * u64 addr; + * u16 old_len; + * u16 new_len; + * u8 bytes[]; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_TEXT_POKE = 20, + + /* + * Data written to the AUX area by hardware due to aux_output, may need + * to be matched to the event by an architecture-specific hardware ID. + * This records the hardware ID, but requires sample_id to provide the + * event ID. e.g. Intel PT uses this record to disambiguate PEBS-via-PT + * records from multiple events. + * + * struct { + * struct perf_event_header header; + * u64 hw_id; + * struct sample_id sample_id; + * }; + */ + PERF_RECORD_AUX_OUTPUT_HW_ID = 21, + + PERF_RECORD_MAX, /* non-ABI */ + +}; + +struct perf_event_attr { +/* + * Major type: hardware/software/tracepoint/etc. + */ + __u32 type; + + /* + * Size of the attr structure, for fwd/bwd compat. + */ + __u32 size; + + /* + * Type specific configuration information. + */ + __u64 config; + + union { + __u64 sample_period; + __u64 sample_freq; + }; + + __u64 sample_type; + __u64 read_format; + + __u64 disabled : 1, /* off by default */ + inherit : 1, /* children inherit it */ + pinned : 1, /* must always be on PMU */ + exclusive : 1, /* only group on PMU */ + exclude_user : 1, /* don't count user */ + exclude_kernel : 1, /* ditto kernel */ + exclude_hv : 1, /* ditto hypervisor */ + exclude_idle : 1, /* don't count when idle */ + mmap : 1, /* include mmap data */ + comm : 1, /* include comm data */ + freq : 1, /* use freq, not period */ + inherit_stat : 1, /* per task counts */ + enable_on_exec : 1, /* next exec enables */ + task : 1, /* trace fork/exit */ + watermark : 1, /* wakeup_watermark */ + /* + * precise_ip: + * + * 0 - SAMPLE_IP can have arbitrary skid + * 1 - SAMPLE_IP must have constant skid + * 2 - SAMPLE_IP requested to have 0 skid + * 3 - SAMPLE_IP must have 0 skid + * + * See also PERF_RECORD_MISC_EXACT_IP + */ + precise_ip : 2, /* skid constraint */ + mmap_data : 1, /* non-exec mmap data */ + sample_id_all : 1, /* sample_type all events */ + + exclude_host : 1, /* don't count in host */ + exclude_guest : 1, /* don't count in guest */ + + exclude_callchain_kernel : 1, /* exclude kernel callchains */ + exclude_callchain_user : 1, /* exclude user callchains */ + mmap2 : 1, /* include mmap with inode data */ + comm_exec : 1, /* flag comm events that are due to an exec */ + use_clockid : 1, /* use @clockid for time fields */ + context_switch : 1, /* context switch data */ + write_backward : 1, /* Write ring buffer from end to beginning */ + namespaces : 1, /* include namespaces data */ + ksymbol : 1, /* include ksymbol events */ + bpf_event : 1, /* include bpf events */ + aux_output : 1, /* generate AUX records instead of events */ + cgroup : 1, /* include cgroup events */ + text_poke : 1, /* include text poke events */ + build_id : 1, /* use build id in mmap2 events */ + inherit_thread : 1, /* children only inherit if cloned with CLONE_THREAD */ + remove_on_exec : 1, /* event is removed from task on exec */ + sigtrap : 1, /* send synchronous SIGTRAP on event */ + __reserved_1 : 26; + + union { + __u32 wakeup_events; /* wakeup every n events */ + __u32 wakeup_watermark; /* bytes before wakeup */ + }; + + __u32 bp_type; + union { + __u64 bp_addr; + __u64 kprobe_func; /* for perf_kprobe */ + __u64 uprobe_path; /* for perf_uprobe */ + __u64 config1; /* extension of config */ + }; + union { + __u64 bp_len; + __u64 kprobe_addr; /* when kprobe_func == NULL */ + __u64 probe_offset; /* for perf_[k,u]probe */ + __u64 config2; /* extension of config1 */ + }; + __u64 branch_sample_type; /* enum perf_branch_sample_type */ + + /* + * Defines set of user regs to dump on samples. + * See asm/perf_regs.h for details. + */ + __u64 sample_regs_user; + + /* + * Defines size of the user stack to dump on samples. + */ + __u32 sample_stack_user; + + __s32 clockid; + /* + * Defines set of regs to dump for each sample + * state captured on: + * - precise = 0: PMU interrupt + * - precise > 0: sampled instruction + * + * See asm/perf_regs.h for details. + */ + __u64 sample_regs_intr; + + /* + * Wakeup watermark for AUX area + */ + __u32 aux_watermark; + __u16 sample_max_stack; + __u16 __reserved_2; + __u32 aux_sample_size; + __u32 __reserved_3; + + /* + * User provided data if sigtrap=1, passed back to user via + * siginfo_t::si_perf_data, e.g. to permit user to identify the event. + * Note, siginfo_t::si_perf_data is long-sized, and sig_data will be + * truncated accordingly on 32 bit architectures. + */ + __u64 sig_data; + + __u64 config3; /* extension of config2 */ +}; + +namespace bpftime_epoll{ +struct bpf_map_info { + __u32 type; + __u32 id; + __u32 key_size; + __u32 value_size; + __u32 max_entries; + __u32 map_flags; + char name[BPF_OBJ_NAME_LEN]; + __u32 ifindex; + __u32 btf_vmlinux_value_type_id; + __u64 netns_dev; + __u64 netns_ino; + __u32 btf_id; + __u32 btf_key_type_id; + __u32 btf_value_type_id; + __u32 btf_vmlinux_id; + __u64 map_extra; +} __attribute__((aligned(8))); + +//https://codebrowser.dev/linux/include/linux/bpf.h.html +union bpf_attr { + struct { /* anonymous struct used by BPF_MAP_CREATE command */ + __u32 map_type; /* one of enum bpf_map_type */ + __u32 key_size; /* size of key in bytes */ + __u32 value_size; /* size of value in bytes */ + __u32 max_entries; /* max number of entries in a map */ + __u32 map_flags; /* BPF_MAP_CREATE related + * flags defined above. + */ + __u32 inner_map_fd; /* fd pointing to the inner map */ + __u32 numa_node; /* numa node (effective only if + * BPF_F_NUMA_NODE is set). + */ + char map_name[BPF_OBJ_NAME_LEN]; + __u32 map_ifindex; /* ifindex of netdev to create on */ + __u32 btf_fd; /* fd pointing to a BTF type data */ + __u32 btf_key_type_id; /* BTF type_id of the key */ + __u32 btf_value_type_id; /* BTF type_id of the value */ + __u32 btf_vmlinux_value_type_id;/* BTF type_id of a kernel- + * struct stored as the + * map value + */ + __u64 map_extra; + }; + struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ + __u32 map_fd; + __aligned_u64 key; + union { + __aligned_u64 value; + __aligned_u64 next_key; + }; + __u64 flags; + }; + struct { /* struct used by BPF_MAP_*_BATCH commands */ + __aligned_u64 in_batch; /* start batch, + * NULL to start from beginning + */ + __aligned_u64 out_batch; /* output: next start batch */ + __aligned_u64 keys; + __aligned_u64 values; + __u32 count; /* input/output: + * input: # of key/value + * elements + * output: # of filled elements + */ + __u32 map_fd; + __u64 elem_flags; + __u64 flags; + } batch; + struct { /* anonymous struct used by BPF_PROG_LOAD command */ + __u32 prog_type; /* one of enum bpf_prog_type */ + __u32 insn_cnt; + __aligned_u64 insns; + __aligned_u64 license; + __u32 log_level; /* verbosity level of verifier */ + __u32 log_size; /* size of user buffer */ + __aligned_u64 log_buf; /* user supplied buffer */ + __u32 kern_version; /* not used */ + __u32 prog_flags; + char prog_name[BPF_OBJ_NAME_LEN]; + __u32 prog_ifindex; /* ifindex of netdev to prep for */ + /* For some prog types expected attach type must be known at + * load time to verify attach type specific parts of prog + * (context accesses, allowed helpers, etc). + */ + __u32 expected_attach_type; + __u32 prog_btf_fd; /* fd pointing to BTF type data */ + __u32 func_info_rec_size; /* userspace bpf_func_info size */ + __aligned_u64 func_info; /* func info */ + __u32 func_info_cnt; /* number of bpf_func_info records */ + __u32 line_info_rec_size; /* userspace bpf_line_info size */ + __aligned_u64 line_info; /* line info */ + __u32 line_info_cnt; /* number of bpf_line_info records */ + __u32 attach_btf_id; /* in-kernel BTF type id to attach to */ + union { + /* valid prog_fd to attach to bpf prog */ + __u32 attach_prog_fd; + /* or valid module BTF object fd or 0 to attach to vmlinux */ + __u32 attach_btf_obj_fd; + }; + __u32 :32; /* pad */ + __aligned_u64 fd_array; /* array of FDs */ + }; + struct { /* anonymous struct used by BPF_OBJ_* commands */ + __aligned_u64 pathname; + __u32 bpf_fd; + __u32 file_flags; + }; + struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ + __u32 target_fd; /* container object to attach to */ + __u32 attach_bpf_fd; /* eBPF program to attach */ + __u32 attach_type; + __u32 attach_flags; + __u32 replace_bpf_fd; /* previously attached eBPF + * program to replace if + * BPF_F_REPLACE is used + */ + }; + struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */ + __u32 prog_fd; + __u32 retval; + __u32 data_size_in; /* input: len of data_in */ + __u32 data_size_out; /* input/output: len of data_out + * returns ENOSPC if data_out + * is too small. + */ + __aligned_u64 data_in; + __aligned_u64 data_out; + __u32 repeat; + __u32 duration; + __u32 ctx_size_in; /* input: len of ctx_in */ + __u32 ctx_size_out; /* input/output: len of ctx_out + * returns ENOSPC if ctx_out + * is too small. + */ + __aligned_u64 ctx_in; + __aligned_u64 ctx_out; + __u32 flags; + __u32 cpu; + } test; + struct { /* anonymous struct used by BPF_*_GET_*_ID */ + union { + __u32 start_id; + __u32 prog_id; + __u32 map_id; + __u32 btf_id; + __u32 link_id; + }; + __u32 next_id; + __u32 open_flags; + }; + struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */ + __u32 bpf_fd; + __u32 info_len; + __aligned_u64 info; + } info; + struct { /* anonymous struct used by BPF_PROG_QUERY command */ + __u32 target_fd; /* container object to query */ + __u32 attach_type; + __u32 query_flags; + __u32 attach_flags; + __aligned_u64 prog_ids; + __u32 prog_cnt; + } query; + struct { /* anonymous struct used by BPF_RAW_TRACEPOINT_OPEN command */ + __u64 name; + __u32 prog_fd; + } raw_tracepoint; + struct { /* anonymous struct for BPF_BTF_LOAD */ + __aligned_u64 btf; + __aligned_u64 btf_log_buf; + __u32 btf_size; + __u32 btf_log_size; + __u32 btf_log_level; + }; + struct { + __u32 pid; /* input: pid */ + __u32 fd; /* input: fd */ + __u32 flags; /* input: flags */ + __u32 buf_len; /* input/output: buf len */ + __aligned_u64 buf; /* input/output: + * tp_name for tracepoint + * symbol for kprobe + * filename for uprobe + */ + __u32 prog_id; /* output: prod_id */ + __u32 fd_type; /* output: BPF_FD_TYPE_* */ + __u64 probe_offset; /* output: probe_offset */ + __u64 probe_addr; /* output: probe_addr */ + } task_fd_query; + struct { /* struct used by BPF_LINK_CREATE command */ + __u32 prog_fd; /* eBPF program to attach */ + union { + __u32 target_fd; /* object to attach to */ + __u32 target_ifindex; /* target ifindex */ + }; + __u32 attach_type; /* attach type */ + __u32 flags; /* extra flags */ + union { + __u32 target_btf_id; /* btf_id of target to attach to */ + struct { + __aligned_u64 iter_info; /* extra bpf_iter_link_info */ + __u32 iter_info_len; /* iter_info length */ + }; + struct { + /* black box user-provided value passed through + * to BPF program at the execution time and + * accessible through bpf_get_attach_cookie() BPF helper + */ + __u64 bpf_cookie; + } perf_event; + }; + } link_create; + struct { /* struct used by BPF_LINK_UPDATE command */ + __u32 link_fd; /* link fd */ + /* new program fd to update link with */ + __u32 new_prog_fd; + __u32 flags; /* extra flags */ + /* expected link's program fd; is specified only if + * BPF_F_REPLACE flag is set in flags */ + __u32 old_prog_fd; + } link_update; + struct { + __u32 link_fd; + } link_detach; + struct { /* struct used by BPF_ENABLE_STATS command */ + __u32 type; + } enable_stats; + struct { /* struct used by BPF_ITER_CREATE command */ + __u32 link_fd; + __u32 flags; + } iter_create; + struct { /* struct used by BPF_PROG_BIND_MAP command */ + __u32 prog_fd; + __u32 map_fd; + __u32 flags; /* extra flags */ + } prog_bind_map; +} __attribute__((aligned(8))); + +struct bpf_insn { + __u8 code; /* opcode */ + __u8 dst_reg:4; /* dest register */ + __u8 src_reg:4; /* source register */ + __s16 off; /* signed offset */ + __s32 imm; /* signed immediate constant */ +}; + +enum { + BPF_REG_0 = 0, + BPF_REG_1, + BPF_REG_2, + BPF_REG_3, + BPF_REG_4, + BPF_REG_5, + BPF_REG_6, + BPF_REG_7, + BPF_REG_8, + BPF_REG_9, + BPF_REG_10, + __MAX_BPF_REG, +}; + +enum bpf_cmd { + BPF_MAP_CREATE, + BPF_MAP_LOOKUP_ELEM, + BPF_MAP_UPDATE_ELEM, + BPF_MAP_DELETE_ELEM, + BPF_MAP_GET_NEXT_KEY, + BPF_PROG_LOAD, + BPF_OBJ_PIN, + BPF_OBJ_GET, + BPF_PROG_ATTACH, + BPF_PROG_DETACH, + BPF_PROG_TEST_RUN, + BPF_PROG_RUN = BPF_PROG_TEST_RUN, + BPF_PROG_GET_NEXT_ID, + BPF_MAP_GET_NEXT_ID, + BPF_PROG_GET_FD_BY_ID, + BPF_MAP_GET_FD_BY_ID, + BPF_OBJ_GET_INFO_BY_FD, + BPF_PROG_QUERY, + BPF_RAW_TRACEPOINT_OPEN, + BPF_BTF_LOAD, + BPF_BTF_GET_FD_BY_ID, + BPF_TASK_FD_QUERY, + BPF_MAP_LOOKUP_AND_DELETE_ELEM, + BPF_MAP_FREEZE, + BPF_BTF_GET_NEXT_ID, + BPF_MAP_LOOKUP_BATCH, + BPF_MAP_LOOKUP_AND_DELETE_BATCH, + BPF_MAP_UPDATE_BATCH, + BPF_MAP_DELETE_BATCH, + BPF_LINK_CREATE, + BPF_LINK_UPDATE, + BPF_LINK_GET_FD_BY_ID, + BPF_LINK_GET_NEXT_ID, + BPF_ENABLE_STATS, + BPF_ITER_CREATE, + BPF_LINK_DETACH, + BPF_PROG_BIND_MAP, +}; + +enum bpf_prog_type { + BPF_PROG_TYPE_UNSPEC, + BPF_PROG_TYPE_SOCKET_FILTER, + BPF_PROG_TYPE_KPROBE, + BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, + BPF_PROG_TYPE_TRACEPOINT, + BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_PERF_EVENT, + BPF_PROG_TYPE_CGROUP_SKB, + BPF_PROG_TYPE_CGROUP_SOCK, + BPF_PROG_TYPE_LWT_IN, + BPF_PROG_TYPE_LWT_OUT, + BPF_PROG_TYPE_LWT_XMIT, + BPF_PROG_TYPE_SOCK_OPS, + BPF_PROG_TYPE_SK_SKB, + BPF_PROG_TYPE_CGROUP_DEVICE, + BPF_PROG_TYPE_SK_MSG, + BPF_PROG_TYPE_RAW_TRACEPOINT, + BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_PROG_TYPE_LWT_SEG6LOCAL, + BPF_PROG_TYPE_LIRC_MODE2, + BPF_PROG_TYPE_SK_REUSEPORT, + BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_CGROUP_SYSCTL, + BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, + BPF_PROG_TYPE_CGROUP_SOCKOPT, + BPF_PROG_TYPE_TRACING, + BPF_PROG_TYPE_STRUCT_OPS, + BPF_PROG_TYPE_EXT, + BPF_PROG_TYPE_LSM, + BPF_PROG_TYPE_SK_LOOKUP, + BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */ + BPF_PROG_TYPE_NETFILTER, + __MAX_BPF_PROG_TYPE +}; + +enum bpf_attach_type { + BPF_CGROUP_INET_INGRESS, + BPF_CGROUP_INET_EGRESS, + BPF_CGROUP_INET_SOCK_CREATE, + BPF_CGROUP_SOCK_OPS, + BPF_SK_SKB_STREAM_PARSER, + BPF_SK_SKB_STREAM_VERDICT, + BPF_CGROUP_DEVICE, + BPF_SK_MSG_VERDICT, + BPF_CGROUP_INET4_BIND, + BPF_CGROUP_INET6_BIND, + BPF_CGROUP_INET4_CONNECT, + BPF_CGROUP_INET6_CONNECT, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_UDP4_SENDMSG, + BPF_CGROUP_UDP6_SENDMSG, + BPF_LIRC_MODE2, + BPF_FLOW_DISSECTOR, + BPF_CGROUP_SYSCTL, + BPF_CGROUP_UDP4_RECVMSG, + BPF_CGROUP_UDP6_RECVMSG, + BPF_CGROUP_GETSOCKOPT, + BPF_CGROUP_SETSOCKOPT, + BPF_TRACE_RAW_TP, + BPF_TRACE_FENTRY, + BPF_TRACE_FEXIT, + BPF_MODIFY_RETURN, + BPF_LSM_MAC, + BPF_TRACE_ITER, + BPF_CGROUP_INET4_GETPEERNAME, + BPF_CGROUP_INET6_GETPEERNAME, + BPF_CGROUP_INET4_GETSOCKNAME, + BPF_CGROUP_INET6_GETSOCKNAME, + BPF_XDP_DEVMAP, + BPF_CGROUP_INET_SOCK_RELEASE, + BPF_XDP_CPUMAP, + BPF_SK_LOOKUP, + BPF_XDP, + BPF_SK_SKB_VERDICT, + BPF_SK_REUSEPORT_SELECT, + BPF_SK_REUSEPORT_SELECT_OR_MIGRATE, + BPF_PERF_EVENT, + BPF_TRACE_KPROBE_MULTI, + BPF_LSM_CGROUP, + BPF_STRUCT_OPS, + BPF_NETFILTER, + BPF_TCX_INGRESS, + BPF_TCX_EGRESS, + BPF_TRACE_UPROBE_MULTI, + BPF_CGROUP_UNIX_CONNECT, + BPF_CGROUP_UNIX_SENDMSG, + BPF_CGROUP_UNIX_RECVMSG, + BPF_CGROUP_UNIX_GETPEERNAME, + BPF_CGROUP_UNIX_GETSOCKNAME, + BPF_NETKIT_PRIMARY, + BPF_NETKIT_PEER, + BPF_TRACE_KPROBE_SESSION, + __MAX_BPF_ATTACH_TYPE +}; + +/* Short form of mov, dst_reg = imm32 */ + +#define BPF_MOV64_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +#define BPF_EXIT_INSN() \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_EXIT, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = 0 }) + +struct bpf_prog_info { + __u32 type; + __u32 id; + __u8 tag[BPF_TAG_SIZE]; + __u32 jited_prog_len; + __u32 xlated_prog_len; + __aligned_u64 jited_prog_insns; + __aligned_u64 xlated_prog_insns; + __u64 load_time; /* ns since boottime */ + __u32 created_by_uid; + __u32 nr_map_ids; + __aligned_u64 map_ids; + char name[BPF_OBJ_NAME_LEN]; + __u32 ifindex; + __u32 gpl_compatible:1; + __u32 :31; /* alignment pad */ + __u64 netns_dev; + __u64 netns_ino; + __u32 nr_jited_ksyms; + __u32 nr_jited_func_lens; + __aligned_u64 jited_ksyms; + __aligned_u64 jited_func_lens; + __u32 btf_id; + __u32 func_info_rec_size; + __aligned_u64 func_info; + __u32 nr_func_info; + __u32 nr_line_info; + __aligned_u64 line_info; + __aligned_u64 jited_line_info; + __u32 nr_jited_line_info; + __u32 line_info_rec_size; + __u32 jited_line_info_rec_size; + __u32 nr_prog_tags; + __aligned_u64 prog_tags; + __u64 run_time_ns; + __u64 run_cnt; + __u64 recursion_misses; + __u32 verified_insns; + __u32 attach_btf_obj_id; + __u32 attach_btf_id; +} __attribute__((aligned(8))); + +static inline __u64 ptr_to_u64(const void *ptr) +{ + return (__u64) (unsigned long) ptr; +} +static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, + unsigned int size) +{ + // No-op stub + return 0; +} + +// from libbpf/btf +void btf__free(struct btf *btf); +// from libbpf +void +bpf_object__close(struct bpf_object* object); + +LIBBPF_API struct bpf_program * +bpf_object__next_program(const struct bpf_object *obj, struct bpf_program *prog); + +#define bpf_object__for_each_program(pos, obj) \ + for ((pos) = bpf_object__next_program((obj), NULL); \ + (pos) != NULL; \ + (pos) = bpf_object__next_program((obj), (pos))) + +struct bpf_program; + +LIBBPF_API const struct bpf_insn *bpf_program__insns(const struct bpf_program *prog); +LIBBPF_API size_t bpf_program__insn_cnt(const struct bpf_program *prog); +LIBBPF_API const char *bpf_program__name(const struct bpf_program *prog); +LIBBPF_API const char *bpf_program__section_name(const struct bpf_program *prog); +LIBBPF_API struct bpf_object *bpf_object__open(const char *path); + +enum libbpf_print_level { + LIBBPF_WARN, + LIBBPF_INFO, + LIBBPF_DEBUG, +}; + +// https://github.com/torvalds/linux/blob/2ef5971ff345d3c000873725db555085e0131961/tools/lib/bpf/bpf.h#L503 +inline int bpf_obj_get_info_by_fd(int bpf_fd, void *info, __u32 *info_len) +{ + const size_t attr_sz = offsetofend(union bpf_attr, info); + union bpf_attr attr; + int err; + + memset(&attr, 0, attr_sz); + attr.info.bpf_fd = bpf_fd; + attr.info.info_len = *info_len; + attr.info.info = ptr_to_u64(info); + + err = sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, attr_sz); + if (!err) + *info_len = attr.info.info_len; + // no-op stub + // return libbpf_err_errno(err); + return 1; +} +} +#endif \ No newline at end of file diff --git a/runtime/include/bpftime_shm.hpp b/runtime/include/bpftime_shm.hpp index e2c58fcf..f03a67ed 100644 --- a/runtime/include/bpftime_shm.hpp +++ b/runtime/include/bpftime_shm.hpp @@ -11,7 +11,11 @@ #include #include #include +#if __linux__ #include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif namespace bpftime { @@ -347,7 +351,9 @@ int bpftime_add_software_perf_event(int cpu, int32_t sample_type, int bpftime_is_software_perf_event(int fd); void *bpftime_get_software_perf_event_raw_buffer(int fd, size_t expected_size); int bpftime_perf_event_output(int fd, const void *buf, size_t sz); +#if __linux__ int bpftime_shared_perf_event_output(int map_fd, const void *buf, size_t sz); +#endif int bpftime_add_ureplace_or_override(int fd, int pid, const char *name, uint64_t offset, bool is_replace); diff --git a/runtime/include/platform_utils.hpp b/runtime/include/platform_utils.hpp new file mode 100644 index 00000000..ece4f9fa --- /dev/null +++ b/runtime/include/platform_utils.hpp @@ -0,0 +1,31 @@ +#ifndef PLATFORM_UTIL_H +#define PLATFORM_UTIL_H +#include +#include + +#if __linux__ +#include +#elif __APPLE__ +#include +#include + typedef int cpu_set_t; + + inline void CPU_ZERO(cpu_set_t *set) { + *set = 0; + } + + inline void CPU_SET(int cpu, cpu_set_t *set) { + *set |= (1 << cpu); + } + + inline int CPU_ISSET(int cpu, const cpu_set_t *set) { + return (*set & (1 << cpu)) != 0; + } + int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask); + int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask); +#else + #error "Unsupported platform" +#endif + +int my_sched_getcpu(); +#endif \ No newline at end of file diff --git a/runtime/include/spinlock.hpp b/runtime/include/spinlock.hpp new file mode 100644 index 00000000..458f97bf --- /dev/null +++ b/runtime/include/spinlock.hpp @@ -0,0 +1,55 @@ +#ifndef SPINLOCK_HPP +#define SPINLOCK_HPP + +#include +#include +#include +#include + +class Spinlock { + std::atomic lock; +public: + + // Default constructor to initialize the atomic_flag + Spinlock() : lock(0) {} + + // Deleted copy constructor to prevent copying + Spinlock(const Spinlock&) = delete; + Spinlock& operator=(const Spinlock&) = delete; + + Spinlock(Spinlock&& other) noexcept : lock() { + if (other.lock.exchange(1, std::memory_order_acquire)) { + lock.store(0, std::memory_order_release); + } + } + + Spinlock& operator=(Spinlock&& other) noexcept { + if (this != &other) { + if (other.lock.exchange(1, std::memory_order_acquire)) { + lock.store(0, std::memory_order_release); + } + } + return *this; + } + + void spin_lock() { + while(lock.load(std::memory_order_relaxed) || lock.exchange(1, std::memory_order_acquire)){ + __asm__ __volatile__ ("yield"); + } + } + + void spin_unlock() { + lock.store(0, std::memory_order_release); + } +}; + +// Global functions to match pthread_spin_lock/unlock interface +inline void spin_lock(Spinlock* spinlock) { + spinlock->spin_lock(); +} + +inline void spin_unlock(Spinlock* spinlock) { + spinlock->spin_unlock(); +} + +#endif // SPINLOCK_HPP diff --git a/runtime/include/spinlock_wrapper.hpp b/runtime/include/spinlock_wrapper.hpp new file mode 100644 index 00000000..0e0281dd --- /dev/null +++ b/runtime/include/spinlock_wrapper.hpp @@ -0,0 +1,74 @@ +#ifndef SPINLOCK_WRAPPER_HPP +#define SPINLOCK_WRAPPER_HPP + +#include +#include +#include + +// Include the custom spinlock implementation +#include "spinlock.hpp" + +// Define the custom spinlock type and functions only if the standard library is not available +#if !defined(_POSIX_SPIN_LOCKS) || _POSIX_SPIN_LOCKS <= 0 +typedef Spinlock pthread_spinlock_t; // Define custom spinlock type + +// Non-volatile version +inline int pthread_spin_init(pthread_spinlock_t* lock, [[maybe_unused]]int pshared) { + new(lock) pthread_spinlock_t(); // Placement new to initialize the Spinlock object + return 0; +} + +inline int pthread_spin_destroy(pthread_spinlock_t* lock) { + lock->~Spinlock(); // Explicitly call the destructor + return 0; +} + +inline int pthread_spin_lock(pthread_spinlock_t* lock) { + spin_lock(lock); + return 0; +} + +inline int pthread_spin_unlock(pthread_spinlock_t* lock) { + spin_unlock(lock); + return 0; +} + +// Volatile version +inline int pthread_spin_init(volatile pthread_spinlock_t* lock, int pshared) { + return pthread_spin_init(const_cast(lock), pshared); +} + +inline int pthread_spin_destroy(volatile pthread_spinlock_t* lock) { + return pthread_spin_destroy(const_cast(lock)); +} + +inline int pthread_spin_lock(volatile pthread_spinlock_t* lock) { + return pthread_spin_lock(const_cast(lock)); +} + +inline int pthread_spin_unlock(volatile pthread_spinlock_t* lock) { + return pthread_spin_unlock(const_cast(lock)); +} + +#else +// Ensure the volatile versions of the standard library functions + +inline int pthread_spin_init(volatile pthread_spinlock_t* lock, int pshared) { + return pthread_spin_init(const_cast(lock), pshared); +} + +inline int pthread_spin_destroy(volatile pthread_spinlock_t* lock) { + return pthread_spin_destroy(const_cast(lock)); +} + +inline int pthread_spin_lock(volatile pthread_spinlock_t* lock) { + return pthread_spin_lock(const_cast(lock)); +} + +inline int pthread_spin_unlock(volatile pthread_spinlock_t* lock) { + return pthread_spin_unlock(const_cast(lock)); +} + +#endif // _POSIX_SPIN_LOCKS + +#endif // SPINLOCK_WRAPPER_HPP diff --git a/runtime/object/CMakeLists.txt b/runtime/object/CMakeLists.txt index b57f956f..2b2b3675 100644 --- a/runtime/object/CMakeLists.txt +++ b/runtime/object/CMakeLists.txt @@ -1,34 +1,59 @@ add_library(bpftime-object OBJECT - bpf_object.cpp -) + bpf_object.cpp + ) +if(${BPFTIME_BUILD_WITH_LIBBPF}) + add_dependencies(bpftime-object copy_headers libbpf spdlog::spdlog bpftime_vm) + target_link_libraries(bpftime-object + PUBLIC + ${LIBBPF_LIBRARIES} + ${FRIDA_GUM_INSTALL_DIR}/libfrida-gum.a + -lpthread + -lm + -ldl + -lelf + -lz + spdlog::spdlog + bpftime_vm + ) -add_dependencies(bpftime-object copy_headers libbpf spdlog::spdlog bpftime_vm) + target_include_directories(bpftime-object PUBLIC + ${LIBBPF_INCLUDE_DIRS}/uapi + ${LIBBPF_INCLUDE_DIRS} + ${FRIDA_GUM_INSTALL_DIR} + $ + $ + $ + $ + $ + $ + ${SPDLOG_INCLUDE} + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} + ) +else() + add_dependencies(bpftime-object spdlog::spdlog bpftime_vm) + target_link_libraries(bpftime-object + PUBLIC + ${FRIDA_GUM_INSTALL_DIR}/libfrida-gum.a + -lpthread + -lm + -ldl + -lelf + -lz + spdlog::spdlog + bpftime_vm + ) -target_link_libraries(bpftime-object - PUBLIC - ${LIBBPF_LIBRARIES} - ${FRIDA_GUM_INSTALL_DIR}/libfrida-gum.a - -lpthread - -lm - -ldl - -lelf - -lz - spdlog::spdlog - bpftime_vm -) - -target_include_directories(bpftime-object PUBLIC - ${LIBBPF_INCLUDE_DIRS}/uapi - ${LIBBPF_INCLUDE_DIRS} - ${FRIDA_GUM_INSTALL_DIR} - $ - $ - $ - $ - $ - $ - ${SPDLOG_INCLUDE} - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} -) + target_include_directories(bpftime-object PUBLIC + ${FRIDA_GUM_INSTALL_DIR} + $ + $ + $ + $ + $ + $ + ${SPDLOG_INCLUDE} + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} + ) +endif() set(BPFTIME_OBJECT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) diff --git a/runtime/object/bpf_object.cpp b/runtime/object/bpf_object.cpp index 756b5c7b..7357fa6f 100644 --- a/runtime/object/bpf_object.cpp +++ b/runtime/object/bpf_object.cpp @@ -1,4 +1,8 @@ +#if __linux__ #include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include #include #include @@ -7,12 +11,17 @@ #include using namespace std; using namespace bpftime; +#if __APPLE__ +using namespace bpftime_epoll; +#endif +#ifdef USE_LIBBPF extern "C" { #include #include #include } +#endif namespace bpftime { diff --git a/runtime/src/attach/bpf_attach_ctx.cpp b/runtime/src/attach/bpf_attach_ctx.cpp index 7bfc3f0a..bba56dfd 100644 --- a/runtime/src/attach/bpf_attach_ctx.cpp +++ b/runtime/src/attach/bpf_attach_ctx.cpp @@ -33,10 +33,12 @@ namespace bpftime static int load_prog_and_helpers(bpftime_prog *prog, const agent_config &config) { + #if __linux__ if (config.enable_kernel_helper_group) { bpftime_helper_group::get_kernel_utils_helper_group() .add_helper_group_to_prog(prog); } + #endif if (config.enable_ufunc_helper_group) { bpftime_helper_group::get_ufunc_helper_group() .add_helper_group_to_prog(prog); diff --git a/runtime/src/bpf_helper.cpp b/runtime/src/bpf_helper.cpp index 9bd71dd0..29675031 100644 --- a/runtime/src/bpf_helper.cpp +++ b/runtime/src/bpf_helper.cpp @@ -3,14 +3,21 @@ * Copyright (c) 2022, eunomia-bpf org * All rights reserved. */ +#if __APPLE__ +#include +#include +#endif +#ifdef USE_LIBBPF #include "bpf/bpf.h" #include "bpf/libbpf_common.h" +#endif #include "bpftime_helper_group.hpp" #include -#include #ifdef ENABLE_BPFTIME_VERIFIER #include "bpftime-verifier.hpp" #endif + +#include "platform_utils.hpp" #include "spdlog/spdlog.h" #include #include @@ -82,7 +89,11 @@ uint64_t bpftime_ktime_get_coarse_ns(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) { timespec spec; + #ifdef __APPLE__ + clock_gettime(CLOCK_MONOTONIC, &spec); // or CLOCK_MONOTONIC_RAW + #else clock_gettime(CLOCK_MONOTONIC_COARSE, &spec); + #endif return spec.tv_sec * (uint64_t)1000000000 + spec.tv_nsec; } @@ -90,9 +101,19 @@ uint64_t bpftime_get_current_pid_tgid(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) { static int tgid = getpid(); + #if __linux__ static thread_local int tid = -1; - if (tid == -1) + if(tid == -1) + { tid = gettid(); + } + #elif __APPLE__ + static thread_local uint64_t tid = UINT64_MAX; //cannot use int because pthread_threadid_np expects only uint64_t + if (tid == UINT64_MAX) + { + pthread_threadid_np(NULL, &tid); + } + #endif return ((uint64_t)tgid << 32) | tid; } @@ -175,7 +196,11 @@ uint64_t bpf_ktime_get_coarse_ns(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t) { struct timespec ts; + #if __APPLE__ + clock_gettime(CLOCK_MONOTONIC, &ts); // or CLOCK_MONOTONIC_RAW + #else clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); + #endif return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; } @@ -237,7 +262,7 @@ uint64_t bpf_ringbuf_discard(uint64_t data, uint64_t flags, uint64_t, uint64_t, uint64_t bpf_perf_event_output(uint64_t ctx, uint64_t map, uint64_t flags, uint64_t data, uint64_t size) { - int32_t current_cpu = sched_getcpu(); + int32_t current_cpu = my_sched_getcpu(); if (current_cpu == -1) { SPDLOG_ERROR( "Unable to get current cpu when running perf event output"); @@ -278,12 +303,16 @@ uint64_t bpf_perf_event_output(uint64_t ctx, uint64_t map, uint64_t flags, ret = bpftime_perf_event_output(perf_handler_fd, (const void *)(uintptr_t)data, (size_t)size); - } else if (map_ty == + } + #if __linux__ + else if (map_ty == bpftime::bpf_map_type:: BPF_MAP_TYPE_KERNEL_USER_PERF_EVENT_ARRAY) { ret = bpftime_shared_perf_event_output( fd, (const void *)(uintptr_t)data, (size_t)size); - } else { + } + #endif + else { SPDLOG_ERROR( "Attempting to run perf_output on a non-perf array map"); ret = -1; @@ -292,7 +321,6 @@ uint64_t bpf_perf_event_output(uint64_t ctx, uint64_t map, uint64_t flags, sched_setaffinity(0, sizeof(orig), &orig); return (uint64_t)ret; } - uint64_t bpftime_tail_call(uint64_t ctx, uint64_t prog_array, uint64_t index) { int fd = prog_array >> 32; @@ -316,6 +344,7 @@ uint64_t bpftime_tail_call(uint64_t ctx, uint64_t prog_array, uint64_t index) } else { memset(context, 0, sizeof(context)); } + #ifdef USE_LIBBPF LIBBPF_OPTS(bpf_test_run_opts, run_opts, .ctx_in = context, // .ctx_out = context_out, .ctx_size_in = sizeof(context), @@ -329,6 +358,7 @@ uint64_t bpftime_tail_call(uint64_t ctx, uint64_t prog_array, uint64_t index) } close(to_call_fd); return run_opts.retval; + #endif } uint64_t bpftime_get_attach_cookie(uint64_t ctx, uint64_t, uint64_t, uint64_t, @@ -346,7 +376,7 @@ uint64_t bpftime_get_attach_cookie(uint64_t ctx, uint64_t, uint64_t, uint64_t, uint64_t bpftime_get_smp_processor_id() { - int cpu = sched_getcpu(); + int cpu = my_sched_getcpu(); if (cpu == -1) { SPDLOG_ERROR("sched_getcpu error"); return 0; // unlikely @@ -727,7 +757,6 @@ const bpftime_helper_group shm_maps_group = { { } }; extern const bpftime_helper_group extesion_group; - const bpftime_helper_group kernel_helper_group = { { { BPF_FUNC_probe_read, bpftime_helper_info{ @@ -886,7 +915,6 @@ const bpftime_helper_group kernel_helper_group = { .fn = (void *)bpftime_get_attach_cookie } } } }; - // Utility function to get the UFUNC helper group const bpftime_helper_group &bpftime_helper_group::get_ufunc_helper_group() { @@ -899,7 +927,6 @@ bpftime_helper_group::get_kernel_utils_helper_group() { return kernel_helper_group; } - const bpftime_helper_group &bpftime_helper_group::get_shm_maps_helper_group() { return shm_maps_group; diff --git a/runtime/src/bpf_map/map_common_def.hpp b/runtime/src/bpf_map/map_common_def.hpp index de520fb1..5fbce558 100644 --- a/runtime/src/bpf_map/map_common_def.hpp +++ b/runtime/src/bpf_map/map_common_def.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include "platform_utils.hpp" namespace bpftime { @@ -23,14 +23,14 @@ using bytes_vec = boost::interprocess::vector; template static inline T ensure_on_current_cpu(std::function func) { - return func(sched_getcpu()); + return func(my_sched_getcpu()); } template static inline T ensure_on_certain_cpu(int cpu, std::function func) { static thread_local int currcpu = -1; - if (currcpu == sched_getcpu()) { + if (currcpu == my_sched_getcpu()) { return func(currcpu); } cpu_set_t orig, set; diff --git a/runtime/src/bpf_map/shared/array_map_kernel_user.cpp b/runtime/src/bpf_map/shared/array_map_kernel_user.cpp index 2260b68a..2cdb3ead 100644 --- a/runtime/src/bpf_map/shared/array_map_kernel_user.cpp +++ b/runtime/src/bpf_map/shared/array_map_kernel_user.cpp @@ -6,8 +6,10 @@ #include "spdlog/spdlog.h" #include #include +#if __linux__ #include #include +#endif #ifndef roundup #define roundup(x, y) \ @@ -30,6 +32,7 @@ static size_t bpf_map_mmap_sz(unsigned int value_sz, unsigned int max_entries) return map_sz; } + void array_map_kernel_user_impl::init_map_fd() { map_fd = bpf_map_get_fd_by_id(kernel_map_id); diff --git a/runtime/src/bpf_map/shared/hash_map_kernel_user.cpp b/runtime/src/bpf_map/shared/hash_map_kernel_user.cpp index 0ed0dc8e..dbf6944b 100644 --- a/runtime/src/bpf_map/shared/hash_map_kernel_user.cpp +++ b/runtime/src/bpf_map/shared/hash_map_kernel_user.cpp @@ -6,6 +6,7 @@ #include "spdlog/spdlog.h" #include #include + #include #include diff --git a/runtime/src/bpf_map/shared/perf_event_array_kernel_user.hpp b/runtime/src/bpf_map/shared/perf_event_array_kernel_user.hpp index 1886e956..e58c43e6 100644 --- a/runtime/src/bpf_map/shared/perf_event_array_kernel_user.hpp +++ b/runtime/src/bpf_map/shared/perf_event_array_kernel_user.hpp @@ -6,7 +6,9 @@ #ifndef _BPFTIME_PERF_EVENT_ARRAY_KERNEL_USER #define _BPFTIME_PERF_EVENT_ARRAY_KERNEL_USER #include +#if __linux__ #include +#endif #include #include diff --git a/runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp b/runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp index b034cc91..8b19bc1f 100644 --- a/runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp +++ b/runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp @@ -9,6 +9,7 @@ #include #include #include +#include "platform_utils.hpp" namespace bpftime { @@ -42,7 +43,7 @@ per_cpu_hash_map_impl::per_cpu_hash_map_impl( void *per_cpu_hash_map_impl::elem_lookup(const void *key) { - int cpu = sched_getcpu(); + int cpu = my_sched_getcpu(); SPDLOG_DEBUG("Run per cpu hash lookup at cpu {}", cpu); if (key == nullptr) { errno = ENOENT; @@ -63,7 +64,7 @@ void *per_cpu_hash_map_impl::elem_lookup(const void *key) long per_cpu_hash_map_impl::elem_update(const void *key, const void *value, uint64_t flags) { - int cpu = sched_getcpu(); + int cpu = my_sched_getcpu(); SPDLOG_DEBUG("Per cpu update, key {}, value {}", (const char *)key, *(long *)value); @@ -88,7 +89,7 @@ long per_cpu_hash_map_impl::elem_update(const void *key, const void *value, long per_cpu_hash_map_impl::elem_delete(const void *key) { - int cpu = sched_getcpu(); + int cpu = my_sched_getcpu(); SPDLOG_DEBUG("Run per cpu hash delete at cpu {}", cpu); bytes_vec &key_vec = this->key_templates[cpu]; key_vec.assign((uint8_t *)key, (uint8_t *)key + key_size); diff --git a/runtime/src/bpf_map/userspace/prog_array.cpp b/runtime/src/bpf_map/userspace/prog_array.cpp index 63e5e647..22ae84ec 100644 --- a/runtime/src/bpf_map/userspace/prog_array.cpp +++ b/runtime/src/bpf_map/userspace/prog_array.cpp @@ -3,15 +3,20 @@ * Copyright (c) 2022, eunomia-bpf org * All rights reserved. */ + +#if __linux__ #include "bpf/bpf.h" #include "linux/bpf.h" +#include +#include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include "spdlog/spdlog.h" #include #include #include -#include #include -#include #include #ifndef offsetofend @@ -19,6 +24,9 @@ (offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD)) #endif + +#if __linux__ + // syscall() function was hooked by syscall server, direct call to it will lead // to a result provided by bpftime. So if we want to get things from kernel, we // must manually execute `syscall` from libc @@ -67,6 +75,8 @@ int my_bpf_prog_get_fd_by_id(__u32 id) return fd; } +#endif + namespace bpftime { static thread_local uint32_t current_thread_lookup_val = 0; @@ -83,6 +93,8 @@ prog_array_map_impl::prog_array_map_impl( } } +#if __linux__ + void *prog_array_map_impl::elem_lookup(const void *key) { int32_t k = *(int32_t *)key; @@ -123,6 +135,8 @@ long prog_array_map_impl::elem_update(const void *key, const void *value, return 0; } +#endif + long prog_array_map_impl::elem_delete(const void *key) { int32_t k = *(int32_t *)key; diff --git a/runtime/src/bpf_map/userspace/ringbuf_map.cpp b/runtime/src/bpf_map/userspace/ringbuf_map.cpp index ce94e8ef..ce2d9799 100644 --- a/runtime/src/bpf_map/userspace/ringbuf_map.cpp +++ b/runtime/src/bpf_map/userspace/ringbuf_map.cpp @@ -10,6 +10,9 @@ #include #include #include +#if __APPLE__ +#include "bpftime_epoll.h" +#endif enum { BPF_RINGBUF_BUSY_BIT = 2147483648, diff --git a/runtime/src/bpftime_prog.cpp b/runtime/src/bpftime_prog.cpp index 7e947de8..7c4ccfaa 100644 --- a/runtime/src/bpftime_prog.cpp +++ b/runtime/src/bpftime_prog.cpp @@ -18,8 +18,10 @@ using namespace std; namespace bpftime { + thread_local std::optional current_thread_bpf_cookie; + bpftime_prog::bpftime_prog(const struct ebpf_inst *insn, size_t insn_cnt, const char *name) : name(name) diff --git a/runtime/src/bpftime_shm.cpp b/runtime/src/bpftime_shm.cpp index 763a7796..77817725 100644 --- a/runtime/src/bpftime_shm.cpp +++ b/runtime/src/bpftime_shm.cpp @@ -15,11 +15,46 @@ #include #include #include +#if __linux__ #include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include #include #include +#ifdef __APPLE__ +// Custom implementation for sigtimedwait +int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) { + struct timespec start, now; + clock_gettime(CLOCK_REALTIME, &start); + int sig; + + while (true) { + // Try to wait for a signal + if (sigwait(set, &sig) == 0) { + if (info != nullptr) { + memset(info, 0, sizeof(*info)); + info->si_signo = sig; + } + return sig; + } + + // Check if the timeout has expired + clock_gettime(CLOCK_REALTIME, &now); + if ((now.tv_sec - start.tv_sec) > timeout->tv_sec || + ((now.tv_sec - start.tv_sec) == timeout->tv_sec && (now.tv_nsec - start.tv_nsec) > timeout->tv_nsec)) { + errno = EAGAIN; + return -1; + } + + // Sleep for a short time before retrying + usleep(1000); // Sleep for 1ms before retrying + } +} +#endif + using namespace bpftime; int bpftime_find_minimal_unused_fd() @@ -326,7 +361,7 @@ int bpftime_epoll_wait(int fd, struct epoll_event *out_evts, int max_evt, sigaddset(&to_block, SIGINT); sigaddset(&to_block, SIGTERM); - // Block the develivery of some signals, so we would be able to catch + // Block the delivery of some signals, so we would be able to catch // them when sleeping if (int err = sigprocmask(SIG_BLOCK, &to_block, &orig_sigset); err == -1) { @@ -481,6 +516,7 @@ int bpftime_perf_event_output(int fd, const void *buf, size_t sz) } } +#if __linux__ int bpftime_shared_perf_event_output(int map_fd, const void *buf, size_t sz) { SPDLOG_DEBUG("Output data into shared perf event array fd {}", map_fd); @@ -508,6 +544,7 @@ int bpftime_shared_perf_event_output(int map_fd, const void *buf, size_t sz) return -1; } } +#endif int bpftime_is_prog_array(int fd) { diff --git a/runtime/src/bpftime_shm_internal.cpp b/runtime/src/bpftime_shm_internal.cpp index 39084e9d..3295e554 100644 --- a/runtime/src/bpftime_shm_internal.cpp +++ b/runtime/src/bpftime_shm_internal.cpp @@ -12,7 +12,11 @@ #include #include #include +#if __linux__ #include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include #include #include diff --git a/runtime/src/bpftime_shm_json.cpp b/runtime/src/bpftime_shm_json.cpp index db445a6a..2c27fb18 100644 --- a/runtime/src/bpftime_shm_json.cpp +++ b/runtime/src/bpftime_shm_json.cpp @@ -9,7 +9,11 @@ #include "spdlog/spdlog.h" #include #include +#if __linux__ #include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include #include #include diff --git a/runtime/src/handler/epoll_handler.cpp b/runtime/src/handler/epoll_handler.cpp index bf5bc7a8..7dbe99b5 100644 --- a/runtime/src/handler/epoll_handler.cpp +++ b/runtime/src/handler/epoll_handler.cpp @@ -4,7 +4,11 @@ * All rights reserved. */ #include +#if __linux__ #include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif namespace bpftime { epoll_handler::epoll_handler(boost::interprocess::managed_shared_memory &memory) diff --git a/runtime/src/handler/epoll_handler.hpp b/runtime/src/handler/epoll_handler.hpp index ce9287b7..e81826a5 100644 --- a/runtime/src/handler/epoll_handler.hpp +++ b/runtime/src/handler/epoll_handler.hpp @@ -9,7 +9,11 @@ #include #include #include +#if __linux__ #include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include namespace bpftime { diff --git a/runtime/src/handler/handler_manager.cpp b/runtime/src/handler/handler_manager.cpp index 4d35a417..4df11275 100644 --- a/runtime/src/handler/handler_manager.cpp +++ b/runtime/src/handler/handler_manager.cpp @@ -11,6 +11,9 @@ #include #include #include +#if __APPLE__ +#include "spinlock_wrapper.hpp" +#endif namespace bpftime { handler_manager::handler_manager(managed_shared_memory &mem, diff --git a/runtime/src/handler/map_handler.cpp b/runtime/src/handler/map_handler.cpp index e90fa69d..fd91d24d 100644 --- a/runtime/src/handler/map_handler.cpp +++ b/runtime/src/handler/map_handler.cpp @@ -11,10 +11,12 @@ #include #include #include +#ifdef USE_LIBBPF #include #include #include #include +#endif #include #include #include @@ -110,6 +112,7 @@ const void *bpf_map_handler::map_lookup_elem(const void *key, return from_syscall ? do_lookup_userspace(impl) : do_lookup(impl); } + #ifdef USE_LIBBPF case bpf_map_type::BPF_MAP_TYPE_KERNEL_USER_ARRAY: { auto impl = static_cast( map_impl_ptr.get()); @@ -135,6 +138,7 @@ const void *bpf_map_handler::map_lookup_elem(const void *key, static_cast(map_impl_ptr.get()); return do_lookup(impl); } + #endif case bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS: { auto impl = static_cast( map_impl_ptr.get()); @@ -202,6 +206,7 @@ long bpf_map_handler::map_update_elem(const void *key, const void *value, return from_syscall ? do_update_userspace(impl) : do_update(impl); } + #ifdef USE_LIBBPF case bpf_map_type::BPF_MAP_TYPE_KERNEL_USER_ARRAY: { auto impl = static_cast( map_impl_ptr.get()); @@ -227,6 +232,7 @@ long bpf_map_handler::map_update_elem(const void *key, const void *value, static_cast(map_impl_ptr.get()); return do_update(impl); } + #endif case bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS: { if (!from_syscall) { // Map in maps only support update from syscall @@ -287,6 +293,7 @@ int bpf_map_handler::bpf_map_get_next_key(const void *key, void *next_key, map_impl_ptr.get()); return do_get_next_key(impl); } + #if __linux__ case bpf_map_type::BPF_MAP_TYPE_KERNEL_USER_ARRAY: { auto impl = static_cast( map_impl_ptr.get()); @@ -312,6 +319,7 @@ int bpf_map_handler::bpf_map_get_next_key(const void *key, void *next_key, static_cast(map_impl_ptr.get()); return do_get_next_key(impl); } + #endif case bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS: { auto impl = static_cast( map_impl_ptr.get()); @@ -379,6 +387,7 @@ long bpf_map_handler::map_delete_elem(const void *key, bool from_syscall) const return from_syscall ? do_delete_userspace(impl) : do_delete(impl); } + #ifdef USE_LIBBPF case bpf_map_type::BPF_MAP_TYPE_KERNEL_USER_ARRAY: { auto impl = static_cast( map_impl_ptr.get()); @@ -404,6 +413,7 @@ long bpf_map_handler::map_delete_elem(const void *key, bool from_syscall) const static_cast(map_impl_ptr.get()); return do_delete(impl); } + #endif case bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS: { if (!from_syscall) { // Map in maps only support update from syscall @@ -474,6 +484,7 @@ int bpf_map_handler::map_init(managed_shared_memory &memory) container_name.c_str())(memory, key_size, value_size); return 0; } + #ifdef USE_LIBBPF case bpf_map_type::BPF_MAP_TYPE_KERNEL_USER_ARRAY: { map_impl_ptr = memory.construct( container_name.c_str())(memory, attr.kernel_bpf_map_id); @@ -505,6 +516,7 @@ int bpf_map_handler::map_init(managed_shared_memory &memory) max_entries); return 0; } + #endif case bpf_map_type::BPF_MAP_TYPE_ARRAY_OF_MAPS: { map_impl_ptr = memory.construct( container_name.c_str())(memory, max_entries); @@ -551,6 +563,7 @@ void bpf_map_handler::map_free(managed_shared_memory &memory) case bpf_map_type::BPF_MAP_TYPE_PERCPU_HASH: memory.destroy(container_name.c_str()); break; + #ifdef USE_LIBBPF case bpf_map_type::BPF_MAP_TYPE_KERNEL_USER_ARRAY: memory.destroy( container_name.c_str()); @@ -570,6 +583,7 @@ void bpf_map_handler::map_free(managed_shared_memory &memory) case bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY: memory.destroy(container_name.c_str()); break; + #endif default: auto func_ptr = global_map_ops_table[(int)type].map_free; if (func_ptr) { diff --git a/runtime/src/handler/map_handler.hpp b/runtime/src/handler/map_handler.hpp index 20184172..38d1234d 100644 --- a/runtime/src/handler/map_handler.hpp +++ b/runtime/src/handler/map_handler.hpp @@ -18,6 +18,9 @@ #include #include #include +#if __APPLE__ +#include "spinlock_wrapper.hpp" +#endif namespace bpftime { using char_allocator = boost::interprocess::allocator< @@ -46,7 +49,6 @@ class bpftime_lock_guard { { pthread_spin_unlock(&spinlock); } - // Delete copy constructor and assignment operator bpftime_lock_guard(const bpftime_lock_guard &) = delete; bpftime_lock_guard &operator=(const bpftime_lock_guard &) = delete; diff --git a/runtime/src/handler/perf_event_handler.cpp b/runtime/src/handler/perf_event_handler.cpp index 2569d695..1818c3bd 100644 --- a/runtime/src/handler/perf_event_handler.cpp +++ b/runtime/src/handler/perf_event_handler.cpp @@ -3,7 +3,11 @@ * Copyright (c) 2022, eunomia-bpf org * All rights reserved. */ +#if __linux__ #include "linux/perf_event.h" +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include "spdlog/spdlog.h" #include #include diff --git a/runtime/src/handler/perf_event_handler.hpp b/runtime/src/handler/perf_event_handler.hpp index ef37b7b2..ca23bf89 100644 --- a/runtime/src/handler/perf_event_handler.hpp +++ b/runtime/src/handler/perf_event_handler.hpp @@ -14,7 +14,9 @@ #include #include #include +#if __linux__ #include "linux/perf_event.h" +#endif #include "bpftime_shm.hpp" #include diff --git a/runtime/src/platform_utils.cpp b/runtime/src/platform_utils.cpp new file mode 100644 index 00000000..08f0f07a --- /dev/null +++ b/runtime/src/platform_utils.cpp @@ -0,0 +1,37 @@ +#include "platform_utils.hpp" +#include "spdlog/spdlog.h" + +#if __linux__ +#include + +int my_sched_getcpu() { + return ::sched_getcpu(); +} + +#elif __APPLE__ +#include +#include + +int my_sched_getcpu() { + int cpu = -1; + size_t len = sizeof(cpu); + + if (sysctlbyname("hw.cpulocation", &cpu, &len, NULL, 0) == -1) { + SPDLOG_ERROR("Couldn't get cpu location for the system"); + return -1; + } + return cpu; +} + +int sched_getaffinity([[maybe_unused]] pid_t pid, [[maybe_unused]]size_t cpusetsize, cpu_set_t *mask) { + CPU_ZERO(mask); + CPU_SET(my_sched_getcpu(), mask); + return 0; +} + +int sched_setaffinity([[maybe_unused]]pid_t pid, [[maybe_unused]]size_t cpusetsize, [[maybe_unused]]const cpu_set_t *mask) { + return 0; +} + +#endif + diff --git a/runtime/syscall-server/CMakeLists.txt b/runtime/syscall-server/CMakeLists.txt index e5f4dc28..13a13589 100644 --- a/runtime/syscall-server/CMakeLists.txt +++ b/runtime/syscall-server/CMakeLists.txt @@ -16,6 +16,7 @@ target_link_libraries(bpftime-syscall-server PUBLIC -ldl spdlog::spdlog) add_dependencies(bpftime-syscall-server spdlog::spdlog) +if(${BPFTIME_BUILD_WITH_LIBBPF}) target_include_directories(bpftime-syscall-server PUBLIC "../../core" @@ -23,6 +24,13 @@ target_include_directories(bpftime-syscall-server "../../third_party/libbpf/include/uapi" ${SPDLOG_INCLUDE} ) +else() +target_include_directories(bpftime-syscall-server + PUBLIC + "../../core" + ${SPDLOG_INCLUDE} +) +endif() set_target_properties(bpftime-syscall-server PROPERTIES CXX_STANDARD 20 LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/syscall-server.version) target_link_options(bpftime-syscall-server PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/syscall-server.version) if(${ENABLE_EBPF_VERIFIER}) diff --git a/runtime/syscall-server/syscall_context.cpp b/runtime/syscall-server/syscall_context.cpp index 620e7843..46285a28 100644 --- a/runtime/syscall-server/syscall_context.cpp +++ b/runtime/syscall-server/syscall_context.cpp @@ -3,26 +3,32 @@ * Copyright (c) 2022, eunomia-bpf org * All rights reserved. */ -#include "syscall_context.hpp" #include "bpftime_shm.hpp" +#include "syscall_context.hpp" #include "handler/perf_event_handler.hpp" +#if __linux__ #include "linux/perf_event.h" +#include +#include +#include +#include +#include +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include "spdlog/spdlog.h" #include #include -#include #include "syscall_server_utils.hpp" #include -#include #include #include -#include #include -#include -#include -#include using namespace bpftime; +#if __APPLE__ +using namespace bpftime_epoll; +#endif void syscall_context::load_config_from_env() { @@ -58,7 +64,6 @@ int syscall_context::handle_close(int fd) bpftime_close(fd); return orig_close_fn(fd); } - int syscall_context::create_kernel_bpf_map(int map_fd) { bpf_map_info info = {}; @@ -442,7 +447,6 @@ long syscall_context::handle_sysbpf(int cmd, union bpf_attr *attr, size_t size) }; return 0; } - int syscall_context::handle_perfevent(perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags) { diff --git a/runtime/syscall-server/syscall_context.hpp b/runtime/syscall-server/syscall_context.hpp index a9a88779..74e1d767 100644 --- a/runtime/syscall-server/syscall_context.hpp +++ b/runtime/syscall-server/syscall_context.hpp @@ -5,7 +5,11 @@ */ #ifndef _SYSCALL_CONTEXT_HPP #define _SYSCALL_CONTEXT_HPP +#if __linux__ #include "linux/perf_event.h" +#elif __APPLE__ +#include "bpftime_epoll.h" +#endif #include #include #include @@ -13,6 +17,9 @@ #include #include +#if __APPLE__ +using namespace bpftime_epoll; +#endif class syscall_context { using syscall_fn = long (*)(long, ...); using close_fn = int (*)(int); diff --git a/runtime/syscall-server/syscall_server_main.cpp b/runtime/syscall-server/syscall_server_main.cpp index a025e9d2..fd95e8f8 100644 --- a/runtime/syscall-server/syscall_server_main.cpp +++ b/runtime/syscall-server/syscall_server_main.cpp @@ -5,13 +5,15 @@ */ #include "syscall_context.hpp" #include "bpftime_shm.hpp" +#if __linux__ #include "linux/bpf.h" #include +#include +#endif #include #include #include #include -#include #include #include using namespace bpftime; @@ -64,6 +66,7 @@ extern "C" int close(int fd) return context.handle_close(fd); } +#if __linux__ extern "C" long syscall(long sysno, ...) { // glibc directly reads the arguments without considering @@ -97,6 +100,7 @@ extern "C" long syscall(long sysno, ...) return context.orig_syscall_fn(sysno, arg1, arg2, arg3, arg4, arg5, arg6); } +#endif extern "C" int munmap(void *addr, size_t size) { diff --git a/tools/bpftimetool/CMakeLists.txt b/tools/bpftimetool/CMakeLists.txt index 9705cadb..974ef98b 100644 --- a/tools/bpftimetool/CMakeLists.txt +++ b/tools/bpftimetool/CMakeLists.txt @@ -2,6 +2,9 @@ add_executable(bpftimetool main.cpp ) + +if(${BPFTIME_BUILD_WITH_LIBBPF}) + target_include_directories(bpftimetool PUBLIC set(LIBBPF_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/../../runtime/object/libbpf) ../../third_party/ @@ -9,7 +12,6 @@ target_include_directories(bpftimetool PUBLIC ${LIBBPF_INCLUDE_DIRS}/uapi ${LIBBPF_INCLUDE_DIRS} ) - target_link_libraries(bpftimetool -lpthread -lm @@ -17,5 +19,17 @@ target_link_libraries(bpftimetool runtime bpftime-object ) +else() +target_include_directories(bpftimetool PUBLIC + ../../third_party/ + ../../runtime/include +) +target_link_libraries(bpftimetool + -lpthread + -lm + -ldl + runtime +) +endif() install(TARGETS bpftimetool CONFIGURATIONS Release Debug RelWithDebInfo DESTINATION ~/.bpftime) diff --git a/tools/bpftimetool/main.cpp b/tools/bpftimetool/main.cpp index 09fab2a0..1f97becf 100644 --- a/tools/bpftimetool/main.cpp +++ b/tools/bpftimetool/main.cpp @@ -83,7 +83,7 @@ int bpftime_run_ebpf_program(int id, auto new_prog = bpftime_prog(prog.insns.data(), prog.insns.size(), prog.name.c_str()); - bpftime::bpftime_helper_group::get_kernel_utils_helper_group() + bpftime::bpftime_helper_group::get_kernel_utils_helper_group() .add_helper_group_to_prog(&new_prog); bpftime::bpftime_helper_group::get_shm_maps_helper_group() .add_helper_group_to_prog(&new_prog); diff --git a/tools/cli/main.cpp b/tools/cli/main.cpp index d88b577a..056674ca 100644 --- a/tools/cli/main.cpp +++ b/tools/cli/main.cpp @@ -19,6 +19,48 @@ #include #include +#ifdef __APPLE__ +#include +#include +#include +#include +#include +inline char** get_environ() { + return *_NSGetEnviron(); +} +constexpr const char* AGENT_LIBRARY = "libbpftime-agent.dylib"; +constexpr const char* SYSCALL_SERVER_LIBRARY = "libbpftime-syscall-server.dylib"; +constexpr const char* AGENT_TRANSFORMER_LIBRARY = "libbpftime-agent-transformer.dylib"; +const char *strchrnul(const char *s, int c) { + while (*s && *s != (char)c) { + s++; + } + return s; +} +int execvpe(const char *file, char *const argv[], char *const envp[]) { + for (const char *path = getenv("PATH"); path && *path; path = strchr(path, ':') + 1) { + char buf[PATH_MAX]; + const char *end = strchrnul(path, ':'); + size_t len = end - path; + memcpy(buf, path, len); + buf[len] = '/'; + strcpy(buf + len + 1, file); + execve(buf, argv, envp); + if (errno != ENOENT) + return -1; + } + errno = ENOENT; + return -1; +} +#elif __linux__ +extern char **environ; +constexpr const char* AGENT_LIBRARY = "libbpftime-agent.so"; +constexpr const char* SYSCALL_SERVER_LIBRARY = "libbpftime-syscall-server.so"; +constexpr const char* AGENT_TRANSFORMER_LIBRARY = "libbpftime-agent-transformer.so"; +#else +#error "Unsupported Platform" +#endif + static int subprocess_pid = 0; static bool str_starts_with(const char *main, const char *pat) @@ -41,7 +83,11 @@ static int run_command(const char *path, const std::vector &argv, agent_so_str += agent_so; } std::vector env_arr; + #if __APPLE__ + char **p = get_environ(); + #else char **p = environ; + #endif while (*p) { env_arr.push_back(*p); p++; @@ -209,7 +255,7 @@ int main(int argc, const char **argv) } std::filesystem::path install_path(program.get("install-location")); if (program.is_subcommand_used("load")) { - auto so_path = install_path / "libbpftime-syscall-server.so"; + auto so_path = install_path / SYSCALL_SERVER_LIBRARY; if (!std::filesystem::exists(so_path)) { spdlog::error("Library not found: {}", so_path.c_str()); return 1; @@ -219,7 +265,7 @@ int main(int argc, const char **argv) return run_command(executable_path.c_str(), extra_args, so_path.c_str(), nullptr); } else if (program.is_subcommand_used("start")) { - auto agent_path = install_path / "libbpftime-agent.so"; + auto agent_path = install_path / AGENT_LIBRARY; if (!std::filesystem::exists(agent_path)) { spdlog::error("Library not found: {}", agent_path.c_str()); @@ -245,7 +291,7 @@ int main(int argc, const char **argv) agent_path.c_str(), nullptr); } } else if (program.is_subcommand_used("attach")) { - auto agent_path = install_path / "libbpftime-agent.so"; + auto agent_path = install_path / AGENT_LIBRARY; if (!std::filesystem::exists(agent_path)) { spdlog::error("Library not found: {}", agent_path.c_str());