From 8a0375fa148a604cb74389b1ca77bb742eb6d93b Mon Sep 17 00:00:00 2001 From: Littlefisher619 Date: Fri, 20 Oct 2023 19:30:53 +0000 Subject: [PATCH] daemon: add trace for close --- runtime/daemon/CMakeLists.txt | 6 +- runtime/daemon/bpf-mocker-event.h | 5 + runtime/daemon/bpf-mocker.bpf.c | 57 ++++++++++ runtime/daemon/bpf-mocker.cpp | 109 +++---------------- runtime/daemon/bpf-utils.h | 41 ++++++++ runtime/daemon/daemon.hpp | 11 ++ runtime/daemon/handle_bpf_event.cpp | 155 +++++++++++++++++++--------- runtime/daemon/handle_bpf_event.hpp | 1 + runtime/daemon/main.cpp | 92 +++++++++++++++++ runtime/unit-test/test_daemon.cpp | 13 +++ 10 files changed, 344 insertions(+), 146 deletions(-) create mode 100644 runtime/daemon/daemon.hpp create mode 100644 runtime/unit-test/test_daemon.cpp diff --git a/runtime/daemon/CMakeLists.txt b/runtime/daemon/CMakeLists.txt index ad5ff9f1..a4f461ab 100644 --- a/runtime/daemon/CMakeLists.txt +++ b/runtime/daemon/CMakeLists.txt @@ -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 handle_bpf_event.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) diff --git a/runtime/daemon/bpf-mocker-event.h b/runtime/daemon/bpf-mocker-event.h index dfedcca4..3a8bdda8 100644 --- a/runtime/daemon/bpf-mocker-event.h +++ b/runtime/daemon/bpf-mocker-event.h @@ -12,6 +12,7 @@ enum event_type { SYS_OPEN, + SYS_CLOSE, SYS_BPF, SYS_PERF_EVENT_OPEN, BPF_PROG_LOAD_EVENT, @@ -51,6 +52,10 @@ struct event { char prog_name[BPF_OBJ_NAME_LEN]; unsigned int insns[MAX_INSN_SIZE]; } bpf_loaded_prog; + + struct { + int fd; + } close_data; }; }; diff --git a/runtime/daemon/bpf-mocker.bpf.c b/runtime/daemon/bpf-mocker.bpf.c index 54fd7b0c..8d342a33 100644 --- a/runtime/daemon/bpf-mocker.bpf.c +++ b/runtime/daemon/bpf-mocker.bpf.c @@ -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); @@ -218,6 +219,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) { @@ -244,6 +269,10 @@ int tracepoint__syscalls__sys_exit_bpf(struct trace_event_raw_sys_exit *ctx) 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: @@ -299,6 +328,32 @@ int tracepoint__syscalls__sys_enter_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; +} + SEC("tracepoint/syscalls/sys_exit_perf_event_open") int tracepoint__syscalls__sys_exit_perf_event_open( struct trace_event_raw_sys_exit *ctx) @@ -314,6 +369,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(); diff --git a/runtime/daemon/bpf-mocker.cpp b/runtime/daemon/bpf-mocker.cpp index 768bff4f..4e2ad50c 100644 --- a/runtime/daemon/bpf-mocker.cpp +++ b/runtime/daemon/bpf-mocker.cpp @@ -1,9 +1,4 @@ -// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -// Copyright (c) 2019 Facebook -// Copyright (c) 2020 Netflix -// -// Based on bpf_mocker(8) from BCC by Brendan Gregg and others. -// 14-Feb-2020 Brendan Gregg Created this. +// Description: bpf-mocker daemon #include #include #include @@ -19,89 +14,20 @@ #include "bpf-mocker.skel.h" #include "daemon_config.hpp" #include "handle_bpf_event.hpp" - -/* Tune the buffer size and wakeup rate. These settings cope with roughly - * 50k opens/sec. - */ -#define PERF_BUFFER_PAGES 64 -#define PERF_BUFFER_TIME_MS 10 - -/* Set the poll timeout when no events occur. This can affect -d accuracy. */ -#define PERF_POLL_TIMEOUT_MS 100 +#include "daemon.hpp" #define NSEC_PER_SEC 1000000000ULL using namespace bpftime; static volatile sig_atomic_t exiting = 0; - -static struct env env = { .uid = INVALID_UID }; +static bool verbose = false; static bpf_event_handler handler({}); -const char *argp_program_version = "bpftime-daemon 0.1"; -const char *argp_program_bug_address = "https://github.com/eunomia-bpf/bpftime"; -const char argp_program_doc[] = "Trace and modify bpf syscalls\n"; - -static const struct argp_option opts[] = { - { "pid", 'p', "PID", 0, "Process ID to trace" }, - { "uid", 'u', "UID", 0, "User ID to trace" }, - { "open", 'o', "OPEN", 0, "Show open events" }, - { "verbose", 'v', NULL, 0, "Verbose debug output" }, - { "failed", 'x', NULL, 0, "Failed opens only" }, - {}, -}; - -static error_t parse_arg(int key, char *arg, struct argp_state *state) -{ - static int pos_args; - long int pid, uid; - - switch (key) { - case 'v': - env.verbose = true; - break; - case 'x': - env.failed = true; - break; - case 'o': - env.show_open = true; - break; - case 'p': - errno = 0; - pid = strtol(arg, NULL, 10); - if (errno || pid <= 0) { - fprintf(stderr, "Invalid PID: %s\n", arg); - argp_usage(state); - } - env.pid = pid; - break; - case 'u': - errno = 0; - uid = strtol(arg, NULL, 10); - if (errno || uid < 0 || uid >= INVALID_UID) { - fprintf(stderr, "Invalid UID %s\n", arg); - argp_usage(state); - } - env.uid = uid; - break; - case ARGP_KEY_ARG: - if (pos_args++) { - fprintf(stderr, - "Unrecognized positional argument: %s\n", arg); - argp_usage(state); - } - errno = 0; - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) { - if (level == LIBBPF_DEBUG && !env.verbose) + if (level == LIBBPF_DEBUG && !verbose) return 0; return vfprintf(stderr, format, args); } @@ -124,25 +50,25 @@ void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt) fprintf(stderr, "Lost %llu events on CPU #%d!\n", lost_cnt, cpu); } -int main(int argc, char **argv) +int bpftime::start_daemon(struct env env) { LIBBPF_OPTS(bpf_object_open_opts, open_opts); - static const struct argp argp = { - .options = opts, - .parser = parse_arg, - .doc = argp_program_doc, - }; struct ring_buffer *rb = NULL; struct bpf_mocker_bpf *obj = NULL; int err; libbpf_set_print(libbpf_print_fn); - err = argp_parse(&argp, argc, argv, 0, NULL, NULL); - if (err) - return err; // update handler config handler = bpf_event_handler(env); + verbose = env.verbose; + + if (signal(SIGINT, sig_int) == SIG_ERR) { + fprintf(stderr, "can't set signal handler: %s\n", + strerror(errno)); + err = 1; + goto cleanup; + } obj = bpf_mocker_bpf__open(); if (!obj) { @@ -153,6 +79,8 @@ int main(int argc, char **argv) /* initialize global data (filtering options) */ obj->rodata->target_pid = env.pid; obj->rodata->disable_modify = true; + obj->rodata->uprobe_perf_type = determine_uprobe_perf_type(); + obj->rodata->kprobe_perf_type = determine_kprobe_perf_type(); err = bpf_mocker_bpf__load(obj); if (err) { @@ -175,13 +103,6 @@ int main(int argc, char **argv) goto cleanup; } - if (signal(SIGINT, sig_int) == SIG_ERR) { - fprintf(stderr, "can't set signal handler: %s\n", - strerror(errno)); - err = 1; - goto cleanup; - } - /* main: poll */ while (!exiting) { err = ring_buffer__poll(rb, 100 /* timeout, ms */); diff --git a/runtime/daemon/bpf-utils.h b/runtime/daemon/bpf-utils.h index ca1db761..61634606 100644 --- a/runtime/daemon/bpf-utils.h +++ b/runtime/daemon/bpf-utils.h @@ -14,11 +14,52 @@ const volatile int current_pid = 0; // disable modify bpf program const volatile bool disable_modify = 0; +const volatile int uprobe_perf_type = 0; +const volatile int kprobe_perf_type = 0; + +// print event to userspace struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } rb SEC(".maps"); +// pid & fd for all bpf related fds +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10240); + __type(key, u64); + __type(value, u64); +} bpf_fd_map SEC(".maps"); + +#define PID_MASK_FOR_PFD 0xffffffff00000000 +#define FD_MASK_FOR_PFD 0x00000000ffffffff +#define MAKE_PFD(pid, fd) (((u64)pid << 32) | fd) + +static __always_inline bool is_bpf_fd(u32 fd) { + u32 pid = bpf_get_current_pid_tgid() >> 32; + u64 key = MAKE_PFD(pid, fd); + u64 *pfd = bpf_map_lookup_elem(&bpf_fd_map, &key); + if (!pfd) { + return false; + } + return true; +} + +static __always_inline void set_bpf_fd_if_positive(u32 fd) { + if (fd < 0) { + return; + } + u32 pid = bpf_get_current_pid_tgid() >> 32; + u64 key = MAKE_PFD(pid, fd); + bpf_map_update_elem(&bpf_fd_map, &key, &key, 0); +} + +static __always_inline void clear_bpf_fd(int fd) { + u32 pid = bpf_get_current_pid_tgid() >> 32; + u64 key = MAKE_PFD(pid, fd); + bpf_map_delete_elem(&bpf_fd_map, &key); +} + static __always_inline bool filter_target(void) { u64 pid = bpf_get_current_pid_tgid() >> 32; diff --git a/runtime/daemon/daemon.hpp b/runtime/daemon/daemon.hpp new file mode 100644 index 00000000..ac18146b --- /dev/null +++ b/runtime/daemon/daemon.hpp @@ -0,0 +1,11 @@ +#ifndef BPFTIME_DAEMON_HPP +#define BPFTIME_DAEMON_HPP + +#include "daemon_config.hpp" + +namespace bpftime +{ +int start_daemon(struct env env); +} // namespace bpftime + +#endif // BPFTIME_DAEMON_HPP \ No newline at end of file diff --git a/runtime/daemon/handle_bpf_event.cpp b/runtime/daemon/handle_bpf_event.cpp index c4c5c848..de3d7035 100644 --- a/runtime/daemon/handle_bpf_event.cpp +++ b/runtime/daemon/handle_bpf_event.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "handle_bpf_event.hpp" #include "bpf-mocker-event.h" @@ -24,14 +25,14 @@ static int parse_uint_from_file(const char *file, const char *fmt) if (!f) { err = -errno; fprintf(stderr, "failed to open '%s\n", file); - return err; + exit(1); } err = fscanf(f, fmt, &ret); if (err != 1) { err = err == EOF ? -EIO : -errno; fprintf(stderr, "failed to parse '%s'\n", file); fclose(f); - return err; + exit(1); } fclose(f); return ret; @@ -62,9 +63,6 @@ int bpf_event_handler::handle_open_events(const struct event *e) } /* prepare fields */ - time(&t); - tm = localtime(&t); - strftime(ts, sizeof(ts), "%H:%M:%S", tm); if (e->open_data.ret >= 0) { fd = e->open_data.ret; err = 0; @@ -74,8 +72,7 @@ int bpf_event_handler::handle_open_events(const struct event *e) } /* print output */ - printf("OPEN %-6d %-16s %3d %3d ", e->pid, e->comm, fd, err); - printf("%s\n", e->open_data.fname); + spdlog::info("OPEN {:<6} {:<16}", e->pid, e->comm); return 0; } @@ -135,50 +132,105 @@ static const char *bpf_prog_type_strings[] = { "BPF_PROG_TYPE_SYSCALL", }; -int bpf_event_handler::handle_bpf_event(const struct event *e) +static const char *const bpf_map_type_strings[] = { + "BPF_MAP_TYPE_UNSPEC", + "BPF_MAP_TYPE_HASH", + "BPF_MAP_TYPE_ARRAY", + "BPF_MAP_TYPE_PROG_ARRAY", + "BPF_MAP_TYPE_PERF_EVENT_ARRAY", + "BPF_MAP_TYPE_PERCPU_HASH", + "BPF_MAP_TYPE_PERCPU_ARRAY", + "BPF_MAP_TYPE_STACK_TRACE", + "BPF_MAP_TYPE_CGROUP_ARRAY", + "BPF_MAP_TYPE_LRU_HASH", + "BPF_MAP_TYPE_LRU_PERCPU_HASH", + "BPF_MAP_TYPE_LPM_TRIE", + "BPF_MAP_TYPE_ARRAY_OF_MAPS", + "BPF_MAP_TYPE_HASH_OF_MAPS", + "BPF_MAP_TYPE_DEVMAP", + "BPF_MAP_TYPE_SOCKMAP", + "BPF_MAP_TYPE_CPUMAP", + "BPF_MAP_TYPE_XSKMAP", + "BPF_MAP_TYPE_SOCKHASH", + "BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED", + "BPF_MAP_TYPE_CGROUP_STORAGE", + "BPF_MAP_TYPE_REUSEPORT_SOCKARRAY", + "BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE", + "BPF_MAP_TYPE_QUEUE", + "BPF_MAP_TYPE_STACK", + "BPF_MAP_TYPE_SK_STORAGE", + "BPF_MAP_TYPE_DEVMAP_HASH", + "BPF_MAP_TYPE_STRUCT_OPS", + "BPF_MAP_TYPE_RINGBUF", + "BPF_MAP_TYPE_INODE_STORAGE", + "BPF_MAP_TYPE_TASK_STORAGE", + "BPF_MAP_TYPE_BLOOM_FILTER", + "BPF_MAP_TYPE_USER_RINGBUF", + "BPF_MAP_TYPE_CGRP_STORAGE" +}; + +#define BPF_MAP_TYPE_MAX \ + (sizeof(bpf_map_type_strings) / sizeof(bpf_map_type_strings[0])) + +static const char *get_bpf_map_type_string(enum bpf_map_type type) { - struct tm *tm; - char ts[32]; - time_t t; + if (type >= 0 && type < BPF_MAP_TYPE_MAX) { + return bpf_map_type_strings[type]; + } + return "Unknown"; +} - /* prepare fields */ - time(&t); - tm = localtime(&t); - strftime(ts, sizeof(ts), "%H:%M:%S", tm); +int bpf_event_handler::handle_close_event(const struct event *e) { + spdlog::info("CLOSE {:<6} {:<16} fd:{}", e->pid, e->comm, e->close_data.fd); + return 0; +} +int bpf_event_handler::handle_bpf_event(const struct event *e) +{ + /* prepare fields */ const char *cmd_str = e->bpf_data.bpf_cmd >= (sizeof(bpf_cmd_strings) / sizeof(bpf_cmd_strings[0])) ? "UNKNOWN COMMAND" : bpf_cmd_strings[e->bpf_data.bpf_cmd]; - /* print output */ - printf("BPF %-6d %-16s %-16s %d\n", e->pid, e->comm, cmd_str, - e->bpf_data.ret); + spdlog::info("BPF {:<6} {:<16} cmd:{:<16} ret:{}", e->pid, e->comm, + cmd_str, e->bpf_data.ret); + + switch (e->bpf_data.bpf_cmd) { + case BPF_MAP_CREATE: + /* code */ + spdlog::info( + " BPF_MAP_CREATE map_type:{:<16} map_name:{:<16}", + get_bpf_map_type_string( + (enum bpf_map_type)e->bpf_data.attr.map_type), + e->bpf_data.attr.map_name); + break; + case BPF_LINK_CREATE: + /* code */ + spdlog::info(" BPF_LINK_CREATE prog_fd:{} target_fd:{}", + e->bpf_data.attr.link_create.prog_fd, + e->bpf_data.attr.link_create.target_fd); + break; + default: + break; + } + return 0; } #define PERF_TYPE_MAX_ID 16 static const char *perf_type_id_strings[PERF_TYPE_MAX_ID] = { - [PERF_TYPE_HARDWARE] = "PERF_TYPE_HARDWARE", - [PERF_TYPE_SOFTWARE] = "PERF_TYPE_SOFTWARE", - [PERF_TYPE_TRACEPOINT] = "PERF_TYPE_TRACEPOINT", - [PERF_TYPE_HW_CACHE] = "PERF_TYPE_HW_CACHE", - [PERF_TYPE_RAW] = "PERF_TYPE_RAW", - [PERF_TYPE_BREAKPOINT] = "PERF_TYPE_BREAKPOINT", + "PERF_TYPE_HARDWARE", + "PERF_TYPE_SOFTWARE", + "PERF_TYPE_TRACEPOINT", + "PERF_TYPE_HW_CACHE", + "PERF_TYPE_RAW", + "PERF_TYPE_BREAKPOINT", }; int bpf_event_handler::handle_perf_event(const struct event *e) { - struct tm *tm; - char ts[32]; - time_t t; - - /* prepare fields */ - time(&t); - tm = localtime(&t); - strftime(ts, sizeof(ts), "%H:%M:%S", tm); - const char *type_id_str = e->perf_event_data.attr.type >= (sizeof(perf_type_id_strings) / @@ -187,22 +239,13 @@ int bpf_event_handler::handle_perf_event(const struct event *e) perf_type_id_strings[e->perf_event_data.attr.type]; /* print output */ - printf("PERF %-6d %-16s %-8s %d\n", e->pid, e->comm, type_id_str, - e->perf_event_data.pid); + spdlog::info("PERF {:<6} {:<16} type:{:<16} ret:{}\n", e->pid, e->comm, + type_id_str, e->perf_event_data.ret); return 0; } int bpf_event_handler::handle_load_bpf_prog_event(const struct event *e) { - struct tm *tm; - char ts[32]; - time_t t; - - /* prepare fields */ - time(&t); - tm = localtime(&t); - strftime(ts, sizeof(ts), "%H:%M:%S", tm); - const char *prog_type_str = e->bpf_loaded_prog.type >= (sizeof(bpf_prog_type_strings) / sizeof(bpf_prog_type_strings[0])) ? @@ -210,9 +253,10 @@ int bpf_event_handler::handle_load_bpf_prog_event(const struct event *e) bpf_prog_type_strings[e->bpf_loaded_prog.type]; /* print output */ - printf("LOAD %-6d %-16s %-16s %-16s %d\n", e->pid, e->comm, - prog_type_str, e->bpf_loaded_prog.prog_name, - e->bpf_loaded_prog.insn_cnt); + spdlog::info( + "BPF_LOAD {:<6} {:<16} name:{:<16} type:{:<16} insn_cnt:{:<6}", + e->pid, e->comm, e->bpf_loaded_prog.prog_name, prog_type_str, + e->bpf_loaded_prog.insn_cnt); return 0; } @@ -231,12 +275,25 @@ int bpf_event_handler::handle_event(const struct event *e) case BPF_PROG_LOAD_EVENT: return handle_load_bpf_prog_event(e); break; + case SYS_CLOSE: + return handle_close_event(e); + break; } return 0; } bpf_event_handler::bpf_event_handler(struct env config) : config(config) { - perf_type_id_strings[determine_uprobe_perf_type()] = "PERF_TYPE_UPROBE"; - perf_type_id_strings[determine_kprobe_perf_type()] = "PERF_TYPE_KPROBE"; + int uprobe_type = determine_uprobe_perf_type(); + if (uprobe_type < 0 || uprobe_type >= PERF_TYPE_MAX_ID) { + spdlog::error("Failed to determine uprobe perf type"); + exit(1); + } + perf_type_id_strings[uprobe_type] = "PERF_TYPE_UPROBE"; + int kprobe_type = determine_kprobe_perf_type(); + if (kprobe_type < 0 || kprobe_type >= PERF_TYPE_MAX_ID) { + spdlog::error("Failed to determine kprobe perf type"); + exit(1); + } + perf_type_id_strings[kprobe_type] = "PERF_TYPE_KPROBE"; } \ No newline at end of file diff --git a/runtime/daemon/handle_bpf_event.hpp b/runtime/daemon/handle_bpf_event.hpp index 48d9c13d..a241543d 100644 --- a/runtime/daemon/handle_bpf_event.hpp +++ b/runtime/daemon/handle_bpf_event.hpp @@ -9,6 +9,7 @@ namespace bpftime { class bpf_event_handler { struct env config; + int handle_close_event(const struct event *e); int handle_bpf_event(const struct event *e); int handle_open_events(const struct event *e); int handle_perf_event(const struct event *e); diff --git a/runtime/daemon/main.cpp b/runtime/daemon/main.cpp index e69de29b..b585bf47 100644 --- a/runtime/daemon/main.cpp +++ b/runtime/daemon/main.cpp @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +// Copyright (c) 2019 Facebook +// Copyright (c) 2020 Netflix +// +// Based on bpf_mocker(8) from BCC by Brendan Gregg and others. +// 14-Feb-2020 Brendan Gregg Created this. +#include +#include +#include +#include +#include +#include "daemon.hpp" + +using namespace bpftime; + +static struct env env = { .uid = static_cast(-1) }; + +const char *argp_program_version = "bpftime-daemon 0.1"; +const char *argp_program_bug_address = "https://github.com/eunomia-bpf/bpftime"; +const char argp_program_doc[] = "Trace and modify bpf syscalls\n"; + +static const struct argp_option opts[] = { + { "pid", 'p', "PID", 0, "Process ID to trace" }, + { "uid", 'u', "UID", 0, "User ID to trace" }, + { "open", 'o', "OPEN", 0, "Show open events" }, + { "verbose", 'v', NULL, 0, "Verbose debug output" }, + { "failed", 'x', NULL, 0, "Failed opens only" }, + {}, +}; + +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + static int pos_args; + long int pid, uid; + + switch (key) { + case 'v': + env.verbose = true; + break; + case 'x': + env.failed = true; + break; + case 'o': + env.show_open = true; + break; + case 'p': + errno = 0; + pid = strtol(arg, NULL, 10); + if (errno || pid <= 0) { + fprintf(stderr, "Invalid PID: %s\n", arg); + argp_usage(state); + } + env.pid = pid; + break; + case 'u': + errno = 0; + uid = strtol(arg, NULL, 10); + if (errno || uid < 0 || uid >= -1) { + fprintf(stderr, "Invalid UID %s\n", arg); + argp_usage(state); + } + env.uid = uid; + break; + case ARGP_KEY_ARG: + if (pos_args++) { + fprintf(stderr, + "Unrecognized positional argument: %s\n", arg); + argp_usage(state); + } + errno = 0; + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +int main(int argc, char **argv) +{ + static const struct argp argp = { + .options = opts, + .parser = parse_arg, + .doc = argp_program_doc, + }; + int err; + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (err) + return err; + + return start_daemon(env); +} diff --git a/runtime/unit-test/test_daemon.cpp b/runtime/unit-test/test_daemon.cpp new file mode 100644 index 00000000..5315d9e0 --- /dev/null +++ b/runtime/unit-test/test_daemon.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#if !defined(__x86_64__) && defined(_M_X64) +#error Only supports x86_64 +#endif +using namespace bpftime; + + +TEST_CASE("Test attaching filter programs and revert") +{ + +}