diff --git a/CMakeLists.txt b/CMakeLists.txt index 74531968..fc1e4cd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,51 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Debug") endif() +get_filename_component(CMAKE_AR_NAME "${CMAKE_AR}" NAME) +function(bpftime_add_static_lib_component_command target) + if(APPLE) + if(CMAKE_AR_NAME STREQUAL "ar") + list(APPEND CMDS + COMMAND ${CMAKE_COMMAND} -E make_directory objs/${target} + COMMAND bash ${CMAKE_SOURCE_DIR}/cmake/extract_and_rename.sh $ objs/${target} + ) + set(BPFTIME_STATIC_LIB_AR_CMDS ${BPFTIME_STATIC_LIB_AR_CMDS} ${CMDS} PARENT_SCOPE) + else() + message(ERROR " CMAKE_AR is not `ar`. Only archiving with `ar` is supported.") + endif() + else() + list(APPEND CMDS + COMMAND ${CMAKE_COMMAND} -E make_directory objs/${target} + COMMAND bash ${CMAKE_SOURCE_DIR}/cmake/extract_and_rename.sh $ objs/${target} + ) + set(BPFTIME_STATIC_LIB_AR_CMDS ${BPFTIME_STATIC_LIB_AR_CMDS} ${CMDS} PARENT_SCOPE) + endif() + set(BPFTIME_STATIC_LIB_DEPS ${BPFTIME_STATIC_LIB_DEPS} ${target} PARENT_SCOPE) +endfunction() + +function(bpftime_add_libs_component_command target_path) + get_filename_component(target_name ${target_path} NAME) + string(REGEX REPLACE "^lib" "" target_name ${target_name}) + string(REGEX REPLACE "\.a$" "" target_name ${target_name}) + if(APPLE) + if(CMAKE_AR_NAME STREQUAL "ar") + list(APPEND CMDS + COMMAND ${CMAKE_COMMAND} -E make_directory objs/${target_name} + COMMAND ${CMAKE_COMMAND} -E env bash ${CMAKE_SOURCE_DIR}/cmake/extract_and_rename.sh ${target_path} ${CMAKE_BINARY_DIR}/objs/${target_name} + ) + set(BPFTIME_STATIC_LLVM_LIB_AR_CMDS ${BPFTIME_STATIC_LLVM_LIB_AR_CMDS} ${CMDS} PARENT_SCOPE) + else() + message(ERROR " CMAKE_AR is not `ar`. Only archiving with `ar` is supported.") + endif() + else() + list(APPEND CMDS + COMMAND ${CMAKE_COMMAND} -E make_directory objs/${target_name} + COMMAND ${CMAKE_COMMAND} -E env bash ${CMAKE_SOURCE_DIR}/cmake/extract_and_rename.sh ${target_path} ${CMAKE_BINARY_DIR}/objs/${target_name} + ) + set(BPFTIME_STATIC_LLVM_LIB_AR_CMDS ${BPFTIME_STATIC_LLVM_LIB_AR_CMDS} ${CMDS} PARENT_SCOPE) + endif() +endfunction() + if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") message(STATUS "Enabling ubsan for Debug builds; Processor=${CMAKE_SYSTEM_PROCESSOR}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") @@ -94,6 +139,48 @@ add_subdirectory(vm) add_subdirectory(attach) add_subdirectory(runtime) + + +# add to single archive if option is enabled +if (${BPFTIME_BUILD_STATIC_LIB}) +set(UBPF_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/vm/ubpf-vm/ubpf) +message(STATUS " Adding libraries to single static archive file") +bpftime_add_static_lib_component_command(bpftime_vm) +if(${BPFTIME_LLVM_JIT}) +bpftime_add_static_lib_component_command(bpftime_llvm_jit_vm) +else() +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) +bpftime_add_static_lib_component_command(bpftime_syscall_trace_attach_impl) +bpftime_add_static_lib_component_command(runtime) +bpftime_add_static_lib_component_command(spdlog) +add_custom_command(OUTPUT "libbpftime.a" + ${BPFTIME_STATIC_LIB_AR_CMDS} + ${BPFTIME_STATIC_LLVM_LIB_AR_CMDS} + COMMAND ${CMAKE_AR} -qcs libbpftime.a objs/*/*.o + COMMAND ${CMAKE_COMMAND} -E remove_directory objs + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${BPFTIME_STATIC_LIB_DEPS} + ) +add_custom_target(bpftime_static_target ALL DEPENDS "libbpftime.a") +add_library(bpftime_static STATIC IMPORTED GLOBAL) +add_dependencies(bpftime_static bpftime_static_target) + +set_target_properties(bpftime_static +PROPERTIES +IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/libbpftime.a" +) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libbpftime.a +DESTINATION ~/.bpftime +) + +endif() + if (${BUILD_BPFTIME_DAEMON}) add_subdirectory(daemon) endif() diff --git a/Makefile b/Makefile index 9c7a0aca..87f787a7 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,11 @@ release-with-llvm-jit: ## build the package, with llvm-jit -DBPFTIME_LLVM_JIT=1 cmake --build build --config RelWithDebInfo --target install -j$(JOBS) +release-with-static-lib: ## build the release version with libbpftime archive + cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo \ + -DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO -DBPFTIME_BUILD_STATIC_LIB=ON + cmake --build build --config RelWithDebInfo --target install -j$(JOBS) + build-vm: ## build only the core library make -C vm build diff --git a/cmake/StandardSettings.cmake b/cmake/StandardSettings.cmake index 9be48091..2404225f 100644 --- a/cmake/StandardSettings.cmake +++ b/cmake/StandardSettings.cmake @@ -81,4 +81,7 @@ option(ENABLE_EBPF_VERIFIER "Whether to enable ebpf verifier" OFF) option(BUILD_BPFTIME_DAEMON "Whether to build the bpftime daemon" ON) # whether to build with shared bpf_map -option(BPFTIME_BUILD_KERNEL_BPF "Whether to build with bpf share maps" ON) \ No newline at end of file +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 diff --git a/cmake/extract_and_rename.sh b/cmake/extract_and_rename.sh new file mode 100644 index 00000000..a78f9957 --- /dev/null +++ b/cmake/extract_and_rename.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Check if the correct number of arguments is provided +if [[ $# -ne 2 ]]; then + echo "Usage: $0 " + exit 1 +fi + +archive=$1 +output_dir=$2 + +# Ensure the output directory exists +mkdir -p "$output_dir" + +# List files in the archive +files=$(ar t "$archive") + +# Declare an associative array to count occurrences of each file +declare -A file_count + +# Count occurrences of each file +for file in $files; do + ((file_count["$file"]++)) +done + +# Extract files individually, renaming duplicates +for file in "${!file_count[@]}"; do + count=${file_count["$file"]} + if [[ $count -gt 1 ]]; then + for ((i = 1; i <= count; i++)); do + ar xN $i "$archive" "$file" + new_file="${file%.o}.$i.o" + mv "$file" "$output_dir/$new_file" + done + else + ar x "$archive" "$file" + mv "$file" "$output_dir/$file" + fi +done \ No newline at end of file diff --git a/example/libbpftime_example/Makefile b/example/libbpftime_example/Makefile new file mode 100644 index 00000000..700317f9 --- /dev/null +++ b/example/libbpftime_example/Makefile @@ -0,0 +1,27 @@ +CXX = g++ + +CXXFLAGS = -I../../runtime/include \ + -I../../vm/compat/include \ + -I../../third_party/spdlog/include \ + -I../../vm/vm-core/include + +.DEFAULT_GOAL := help + +LDFLAGS = -L$(HOME)/.bpftime +LDLIBS = -lbpftime -lboost_system -lrt -lbpf + +SHM_SRC = main.cpp + +SHM_TARGET = shm_example + +help: + @echo "Available targets:" + @grep -E '^[a-zA-Z_-]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*## "}; {printf " %-20s %s\n", $$1, $$2}' + + +shm_example: $(SHM_SRC) ## build shared memory example + $(CXX) -o $(SHM_TARGET) $(SHM_SRC) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) + +.PHONY: clean +clean: ## clean the build + rm -f $(SHM_TARGET) example_shm.json diff --git a/example/libbpftime_example/README.md b/example/libbpftime_example/README.md new file mode 100644 index 00000000..a28466fc --- /dev/null +++ b/example/libbpftime_example/README.md @@ -0,0 +1,39 @@ +## Example program + +This is a sample program showcasing the use of libbpftime. + +I am using headers from runtime and I am linking `libbpftime.a` which is installed in `~/.bpftime` + + +### Prerequisites + +following command should have been run, so that `libbpftime.a` exists in `~/.bpftime` directory + +```shell +cmake -Bbuild -DCMAKE_BUILD_TYPE:STRING=Release \ + -DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO -DBPFTIME_BUILD_STATIC_LIB=ON +cmake --build build --config Release --target install +``` + + +### Build + +- Makefile + +You can make examples using makefile: + +> Using make to run examples is preferred + +run `make` and you will see the following output + +```shell +Available targets: + shm_example build shared memory example + clean clean the build +``` + +command to execute the code: +when not using llvm-jit +```shell +g++ -o example main.cpp -I../../runtime/include -I../../vm/compat/include/ -I../../third_party/spdlog/include -I../../vm/vm-core/include -L~/.bpftime -lbpftime -lboost_system -lrt -lbpf +``` \ No newline at end of file diff --git a/example/libbpftime_example/ebpf.json b/example/libbpftime_example/ebpf.json new file mode 100644 index 00000000..c9f1ff27 --- /dev/null +++ b/example/libbpftime_example/ebpf.json @@ -0,0 +1,12 @@ +{ + "1": { + "type": "bpf_prog_handler", + "name": "example_prog", + "attr": { + "insns": "abcd1234ef567890", + "type": 1, + "cnt": 1, + "attach_fds": [2, 3] + } + } +} \ No newline at end of file diff --git a/example/libbpftime_example/main.cpp b/example/libbpftime_example/main.cpp new file mode 100644 index 00000000..e712a4df --- /dev/null +++ b/example/libbpftime_example/main.cpp @@ -0,0 +1,17 @@ +#include +#include "bpftime_shm.hpp" +#include "spdlog/spdlog.h" + +int main() { + bpftime_initialize_global_shm(bpftime::shm_open_type::SHM_CREATE_OR_OPEN); + const char* jsonFileName = "example_shm.json"; + const char* importJsonName = "ebpf.json"; + SPDLOG_INFO("GLOBAL memory initialized "); + // load json program to shm + bpftime_import_global_shm_from_json(importJsonName); + // export it to another json file + bpftime_export_global_shm_to_json(jsonFileName); + // remove content from global shm + bpftime_remove_global_shm(); + return 0; +} \ No newline at end of file diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index b9dc398d..4ec1f325 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -45,6 +45,9 @@ endif() find_package(Boost REQUIRED) # Find all headers and implementation files +if(NOT DEFINED ARCH) + set(ARCH ${CMAKE_SYSTEM_PROCESSOR}) +endif() message(STATUS "Building for architecture: ${ARCH}") set(sources