Skip to content

Commit

Permalink
runtime: implement Daemon tracing (#49)
Browse files Browse the repository at this point in the history
* daemon: add handler for events

* doc: fix unit test

* fix ci

* rename to daemon

* daemon: add trace for close

* enable modify attach target

* fix docker

* fix ci

* Update Makefile

* move daemon to project root

* rename and update helpers for test

---------

Co-authored-by: Littlefisher619 <i@littlefisher.me>
  • Loading branch information
yunwei37 and Littlefisher619 authored Oct 21, 2023
1 parent c0fb4d4 commit e530cc3
Show file tree
Hide file tree
Showing 40 changed files with 1,063 additions and 544 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name: Build and public docker image
on:
push:
branches: "master"
pull_request:
# Why wildcard? Because we want to see test results when examing prs from non-master branches..
branches: "master"

jobs:
build-and-push-image:
Expand All @@ -27,9 +30,13 @@ jobs:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build docker
run: |
docker build .
- name: Build image and push to GitHub Container Registry
uses: docker/build-push-action@v2
if: github.repository_owner == 'eunomia-bpf'
with:
# relative path to the place where source code with Dockerfile is located
context: ./
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ jobs:
- name: Build the target
run: |
CC=gcc-12 CXX=g++-12 make build-unit-test
- name: Run the test
- name: Run the unit test
run: |
make unit-test
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ set(SPDLOG_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/spdlog/include)
# main library
add_subdirectory(vm)
add_subdirectory(runtime)
add_subdirectory(daemon)

# benchmark that requires bpftime libraries
add_subdirectory(benchmark)
Expand Down
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
FROM ubuntu:23.04
WORKDIR /bpftime
RUN apt-get update && apt install -y --no-install-recommends \
RUN apt-get update && apt-get install -y --no-install-recommends \
libelf1 libelf-dev zlib1g-dev make cmake git libboost1.74-all-dev \
binutils-dev libyaml-cpp-dev gcc g++ ca-certificates clang llvm
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
RUN apt-get install -y --no-install-recommends curl && \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
COPY . .
RUN git submodule update --init --recursive
ENV CXX=g++
ENV CC=gcc
ENV PATH="${PATH}:/root/.cargo/bin"
RUN make release && make install
130 changes: 63 additions & 67 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,67 +1,63 @@
.PHONY: install coverage test docs help build clean build-arm run-arm run-arm64 build-arm64 build-arm32
.DEFAULT_GOAL := help

define BROWSER_PYSCRIPT
import os, webbrowser, sys

try:
from urllib import pathname2url
except:
from urllib.request import pathname2url

webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
endef
export BROWSER_PYSCRIPT

define PRINT_HELP_PYSCRIPT
import re, sys

for line in sys.stdin:
match = re.match(r'^([a-zA-Z\d_-]+):.*?## (.*)$$', line)
if match:
target, help = match.groups()
print("%-20s %s" % (target, help))
endef
export PRINT_HELP_PYSCRIPT

BROWSER := python3 -c "$$BROWSER_PYSCRIPT"
INSTALL_LOCATION := ~/.local

help:
@python3 -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)

build-unit-test:
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=1 -DCMAKE_BUILD_TYPE:STRING=Debug
cmake --build build --config Debug -j --target bpftime_runtime_tests
unit-test:
./build/runtime/unit-test/bpftime_runtime_tests
test: ## test the package
make -C third_party/libbpf/src
make -C runtime/test/bpf
cp -r runtime/test/bpf/* build/runtime/test/
cd build/runtime && ctest -VV

build: ## build the package
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=1
cmake --build build --config Debug -j
cd tools/cli-rs && cargo build

release: ## build the package
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=0 -DCMAKE_BUILD_TYPE:STRING=Release
cmake --build build --config Release --target install
cd tools/cli-rs && cargo build

build-vm: ## build only the core library
make -C vm build

build-llvm: ## build with llvm as jit backend
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=1 -DBPFTIME_LLVM_JIT=1
cmake --build build --config Debug

clean: ## clean the project
rm -rf build
make -C runtime clean
make -C vm clean

install: release ## Invoke cmake to install..
cd tools/cli-rs && mkdir -p ~/.bpftime && cp ./target/release/bpftime ~/.bpftime
.PHONY: install coverage test docs help build clean build-arm run-arm run-arm64 build-arm64 build-arm32
.DEFAULT_GOAL := help

define BROWSER_PYSCRIPT
import os, webbrowser, sys

try:
from urllib import pathname2url
except:
from urllib.request import pathname2url

webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
endef
export BROWSER_PYSCRIPT

define PRINT_HELP_PYSCRIPT
import re, sys

for line in sys.stdin:
match = re.match(r'^([a-zA-Z\d_-]+):.*?## (.*)$$', line)
if match:
target, help = match.groups()
print("%-20s %s" % (target, help))
endef
export PRINT_HELP_PYSCRIPT

BROWSER := python3 -c "$$BROWSER_PYSCRIPT"
INSTALL_LOCATION := ~/.local

help:
@python3 -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)

build-unit-test:
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=1 -DCMAKE_BUILD_TYPE:STRING=Debug
cmake --build build --config Debug --target bpftime_runtime_tests

unit-test:
./build/runtime/unit-test/bpftime_runtime_tests

build: ## build the package
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=1
cmake --build build --config Debug
cd tools/cli-rs && cargo build

release: ## build the package
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=0 -DCMAKE_BUILD_TYPE:STRING=Release
cmake --build build --config Release --target install
cd tools/cli-rs && cargo build --release

build-vm: ## build only the core library
make -C vm build

build-llvm: ## build with llvm as jit backend
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=1 -DBPFTIME_LLVM_JIT=1
cmake --build build --config Debug

clean: ## clean the project
rm -rf build
make -C runtime clean
make -C vm clean

install: release ## Invoke cmake to install..
cd tools/cli-rs && mkdir -p ~/.bpftime && cp ./target/release/bpftime ~/.bpftime
Binary file removed benchmark/uprobe/uprobe
Binary file not shown.
Binary file removed benchmark/uretprobe/uretprobe
Binary file not shown.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ add_bpf_skel_generating_target(bpftime_daemon_ebpf_skel ${CMAKE_CURRENT_BINARY_D

add_dependencies(bpftime_daemon_ebpf_skel bpftime_daemon_ebpf_target)

add_executable(bpftime_daemon bpf-mocker.cpp)
add_dependencies(bpftime_daemon bpftime_daemon_ebpf_skel libbpf)
add_executable(bpftime_daemon main.cpp bpf-mocker.cpp handle_bpf_event.cpp)
add_dependencies(bpftime_daemon bpftime_daemon_ebpf_skel libbpf spdlog::spdlog)

target_include_directories(bpftime_daemon PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${LIBBPF_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(bpftime_daemon PRIVATE ${LIBBPF_LIBRARIES} elf z)
target_link_libraries(bpftime_daemon PRIVATE ${LIBBPF_LIBRARIES} elf z spdlog::spdlog)
set_property(TARGET bpftime_daemon PROPERTY CXX_STANDARD 20)
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

enum event_type {
SYS_OPEN,
SYS_CLOSE,
SYS_BPF,
SYS_PERF_EVENT_OPEN,
BPF_PROG_LOAD_EVENT,
Expand Down Expand Up @@ -43,6 +44,10 @@ struct event {
struct perf_event_attr attr;
int pid;
int cpu;

// uprobe data
uint64_t offset;
char name_or_path[NAME_MAX];
} perf_event_data;

struct {
Expand All @@ -51,6 +56,10 @@ struct event {
char prog_name[BPF_OBJ_NAME_LEN];
unsigned int insns[MAX_INSN_SIZE];
} bpf_loaded_prog;

struct {
int fd;
} close_data;
};
};

Expand Down
88 changes: 78 additions & 10 deletions runtime/bpftime-daemon/bpf-mocker.bpf.c → daemon/bpf-mocker.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct open_args_t {
int flags;
};

// track open syscall args
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 10240);
Expand Down Expand Up @@ -99,7 +100,7 @@ int tracepoint__syscalls__sys_exit_openat(struct trace_event_raw_sys_exit *ctx)

struct bpf_args_t {
enum bpf_cmd cmd;
void *attr;
union bpf_attr attr;
u32 attr_size;
};

Expand Down Expand Up @@ -208,7 +209,8 @@ int tracepoint__syscalls__sys_enter_bpf(struct trace_event_raw_sys_enter *ctx)
/* store arg info for later lookup */
struct bpf_args_t args = {};
args.cmd = (u32)ctx->args[0];
args.attr = (void *)ctx->args[1];
bpf_probe_read_user(&args.attr, sizeof(args.attr),
(void *)ctx->args[1]);
args.attr_size = (u32)ctx->args[2];

u32 pid = bpf_get_current_pid_tgid() >> 32;
Expand All @@ -218,6 +220,30 @@ int tracepoint__syscalls__sys_enter_bpf(struct trace_event_raw_sys_enter *ctx)
return 0;
}

static int process_bpf_syscall_exit(enum bpf_cmd cmd, union bpf_attr *attr,
unsigned int size, int ret,
struct trace_event_raw_sys_exit *ctx)
{
if (!attr || size < sizeof(*attr)) {
return 0;
}

switch (cmd) {
case BPF_PROG_LOAD:
set_bpf_fd_if_positive(ret);
break;
case BPF_MAP_CREATE:
set_bpf_fd_if_positive(ret);
break;
case BPF_LINK_CREATE:
set_bpf_fd_if_positive(ret);
break;
default:
break;
}
return 0;
}

SEC("tracepoint/syscalls/sys_exit_bpf")
int tracepoint__syscalls__sys_exit_bpf(struct trace_event_raw_sys_exit *ctx)
{
Expand All @@ -238,12 +264,16 @@ int tracepoint__syscalls__sys_exit_bpf(struct trace_event_raw_sys_exit *ctx)
return 0;
}
event->type = SYS_BPF;
bpf_probe_read_user_str(&event->bpf_data.attr,
sizeof(event->bpf_data.attr), ap->attr);
bpf_probe_read(&event->bpf_data.attr,
sizeof(event->bpf_data.attr), &ap->attr);
event->bpf_data.attr_size = ap->attr_size;
event->bpf_data.bpf_cmd = ap->cmd;
event->bpf_data.ret = ctx->ret;

process_bpf_syscall_exit(event->bpf_data.bpf_cmd, &event->bpf_data.attr,
event->bpf_data.attr_size, event->bpf_data.ret,
ctx);

/* emit event */
bpf_ringbuf_submit(event, 0);
cleanup:
Expand All @@ -255,16 +285,25 @@ static __always_inline int
process_perf_event_open_enter(struct trace_event_raw_sys_enter *ctx)
{
struct perf_event_attr *attr = (struct perf_event_attr *)ctx->args[0];
struct perf_event_attr empty_attr = {};
struct perf_event_attr new_attr = {};
if (!attr) {
return 0;
}
// bpf_probe_write_user(attr, &empty_attr, sizeof(empty_attr));
bpf_probe_read_user(&new_attr, sizeof(new_attr), attr);
// if (new_attr.type == uprobe_perf_type) {
// // found uprobe
// char new_path[] = "/home/yunwei/bpftime/benchmark/syscall/victim";
// new_attr.probe_offset = 0;
// bpf_probe_write_user(attr, &new_attr, sizeof(new_attr));
// bpf_probe_write_user(&new_attr.uprobe_path, &new_path,
// sizeof(new_path));
// return 0;
// }
return 0;
}

struct perf_event_args_t {
struct perf_event_attr *attr;
struct perf_event_attr attr;
int pid;
int cpu;
};
Expand All @@ -288,7 +327,8 @@ int tracepoint__syscalls__sys_enter_perf_event_open(

/* store arg info for later lookup */
struct perf_event_args_t args = {};
args.attr = (void *)ctx->args[0];
bpf_probe_read_user(&args.attr, sizeof(args.attr),
(void *)ctx->args[0]);
args.pid = (int)ctx->args[1];
args.cpu = (int)ctx->args[2];

Expand All @@ -314,6 +354,8 @@ int tracepoint__syscalls__sys_exit_perf_event_open(
ap = bpf_map_lookup_elem(&perf_event_open_param_start, &pid);
if (!ap)
return 0; /* missed entry */

set_bpf_fd_if_positive(ctx->ret);

/* event data */
event = fill_basic_event_info();
Expand All @@ -322,8 +364,8 @@ int tracepoint__syscalls__sys_exit_perf_event_open(
}
event->type = SYS_PERF_EVENT_OPEN;

bpf_probe_read_user_str(&event->perf_event_data.attr,
sizeof(event->perf_event_data.attr), ap->attr);
bpf_probe_read(&event->perf_event_data.attr,
sizeof(event->perf_event_data.attr), &ap->attr);
event->perf_event_data.pid = ap->pid;
event->perf_event_data.cpu = ap->cpu;
event->perf_event_data.ret = ctx->ret;
Expand All @@ -335,4 +377,30 @@ int tracepoint__syscalls__sys_exit_perf_event_open(
return 0;
}

SEC("tracepoint/syscalls/sys_enter_close")
int tracepoint__syscalls__sys_enter_close(struct trace_event_raw_sys_enter *ctx)
{
struct event *event = NULL;

if (!filter_target()) {
return 0;
}
int fd = (int)ctx->args[0];
if (!is_bpf_fd(fd)) {
return 0;
}
/* event data */
event = fill_basic_event_info();
if (!event) {
return 0;
}
event->type = SYS_CLOSE;

event->close_data.fd = fd;
/* emit event */
bpf_ringbuf_submit(event, 0);

return 0;
}

char LICENSE[] SEC("license") = "GPL";
Loading

0 comments on commit e530cc3

Please sign in to comment.