From 914b6295ebd8e354ec291ff5b8c303d39b5f3b10 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 10 Aug 2023 15:26:52 +0800 Subject: [PATCH 01/17] [feat] use gdb to pause the program to handle short processes --- .../User_Function_Tracer/src/gdb.c | 50 +++++++++++++ .../User_Function_Tracer/src/gdb.h | 74 +++++++++++++++++++ .../User_Function_Tracer/src/symbol.c | 2 - .../User_Function_Tracer/src/utrace.c | 71 +++++++++++++----- .../User_Function_Tracer/src/vmap.c | 16 ++++ .../User_Function_Tracer/src/vmap.h | 8 ++ 6 files changed, 201 insertions(+), 20 deletions(-) create mode 100644 eBPF_Supermarket/User_Function_Tracer/src/gdb.c create mode 100644 eBPF_Supermarket/User_Function_Tracer/src/gdb.h diff --git a/eBPF_Supermarket/User_Function_Tracer/src/gdb.c b/eBPF_Supermarket/User_Function_Tracer/src/gdb.c new file mode 100644 index 000000000..e486f3abb --- /dev/null +++ b/eBPF_Supermarket/User_Function_Tracer/src/gdb.c @@ -0,0 +1,50 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: jinyufeng2000@gmail.com +// +// 设置断点,为探针提供时间 + +#include "gdb.h" + +#include +#include +#include + +struct gdb* new_gdb() { + return (struct gdb*)malloc(sizeof(struct gdb)); +} + +void enable_breakpoint(struct gdb* gdb, pid_t pid, uint64_t addr) { + long data = ptrace(PTRACE_PEEKDATA, pid, addr, NULL); + gdb->inst = (uint8_t)data & 0xFF; + + uint64_t int3 = 0xCC; + ptrace(PTRACE_POKEDATA, pid, addr, (data & ~0xFF) | int3); +} + +void disable_breakpoint(struct gdb* gdb, pid_t pid, uint64_t addr) { + long data = ptrace(PTRACE_PEEKDATA, pid, addr, NULL); + ptrace(PTRACE_POKEDATA, pid, (data & ~0xFF) | gdb->inst); +} + +void continue_execution(pid_t pid) { ptrace(PTRACE_CONT, pid, NULL, NULL); } + +void delete_gdb(struct gdb* gdb) { free(gdb); } + +void wait_for_signal(pid_t pid) { + int wstatus; + int options = 0; + waitpid(pid, &wstatus, options); +} diff --git a/eBPF_Supermarket/User_Function_Tracer/src/gdb.h b/eBPF_Supermarket/User_Function_Tracer/src/gdb.h new file mode 100644 index 000000000..fb9e9bc90 --- /dev/null +++ b/eBPF_Supermarket/User_Function_Tracer/src/gdb.h @@ -0,0 +1,74 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: jinyufeng2000@gmail.com +// +// 设置断点,为探针提供时间 + +#ifndef UTRACE_GDB_H +#define UTRACE_GDB_H + +#include +#include + +/* + * @brief 记录跨函数传递的信息 + */ +struct gdb { + uint8_t inst; /*< 被int3覆盖的单字节指令 */ +}; + +/* + * @brief 创建一个gdb结构体 + * @return 指向gdb结构体的指针 + * @note 从堆中申请空间 + */ +struct gdb* new_gdb(); + +/* + * @brief 设置一个断点 + * @param[in] gdb 指向一个gdb结构体 + * @param[in] pid 进程号 + * @param[in] addr 物理地址 + */ +void enable_breakpoint(struct gdb* gdb, pid_t pid, uint64_t addr); + +/* + * @brief 取消一个断点 + * @param[in] gdb 指向一个gdb结构体 + * @param[in] pid 进程号 + * @param[in] addr 物理地址 + * @note 需要保证之前调用过enable_breakpoint(gdb, pid, addr) + */ +void disable_breakpoint(struct gdb* gdb, pid_t pid, uint64_t addr); + +/* + * @brief 继续执行 + * @param[in] pid 进程号 + */ +void continue_execution(pid_t pid); + +/* + * @brief 释放gdb结构体的空间 + * @param[in] gdb 指向要释放的gdb结构体 + */ +void delete_gdb(struct gdb* gdb); + +/* + * @brief 等待进程收到信号 + * @param[in] pid 进程号 + */ +void wait_for_signal(pid_t pid); + +#endif // UTRACE_GDB_H diff --git a/eBPF_Supermarket/User_Function_Tracer/src/symbol.c b/eBPF_Supermarket/User_Function_Tracer/src/symbol.c index 6574fb1cd..184580e50 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/symbol.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/symbol.c @@ -109,8 +109,6 @@ struct symbol_arr* new_symbol_arr(char* libname, struct dyn_symbol_set* dyn_syms if (sym.size == 0) continue; if (lib && !contain_dyn_symbol(dyn_symset, sym.name)) continue; - // if (strcmp(sym.name, "_start") == 0) continue; - push_symbol(symbols, &sym); prev_sym_value = elf_e.sym.st_value; } diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index 58c22d732..11da2154d 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -20,6 +20,7 @@ #include "utrace.skel.h" +#include "gdb.h" #include "log.h" #include "symbol.h" #include "vmap.h" @@ -30,6 +31,7 @@ #include #include #include +#include #include #include @@ -62,9 +64,6 @@ void uprobe_attach(struct utrace_bpf *skel, pid_t pid, const char *exe, size_t a bpf_program__attach_uprobe(skel->progs.uretprobe, true /* uretprobe */, pid, exe, addr); assert(skel->links.uretprobe); - - /* Attach tracepoints */ - assert(utrace_bpf__attach(skel) == 0); } bool symbolize(size_t addr) { @@ -156,14 +155,6 @@ int main(int argc, char **argv) { goto cleanup; } - symtab = new_symbol_tab(); - dyn_symset = new_dyn_symbol_set(); - push_symbol_arr(symtab, new_symbol_arr(exe, dyn_symset, 0)); - for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; - sym++) { - uprobe_attach(skel, -1, exe, sym->addr); - } - /* Set up ring buffer polling */ records = ring_buffer__new(bpf_map__fd(skel->maps.records), handle_event, NULL, NULL); if (!records) { @@ -172,17 +163,52 @@ int main(int argc, char **argv) { goto cleanup; } + symtab = new_symbol_tab(); + dyn_symset = new_dyn_symbol_set(); + size_t break_addr = 0; + push_symbol_arr(symtab, new_symbol_arr(exe, dyn_symset, 0)); + for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; + sym++) { + if (strcmp(sym->name, "_start") == 0) { // NOTE + break_addr = sym->addr; + break; + } + } + pid_t pid = fork(); if (pid < 0) { ERROR("Fork error\n"); goto cleanup; } else if (pid == 0) { - execlp(exe, exe, NULL); - ERROR("Execlp %s error\n", exe); + ptrace(PTRACE_TRACEME, 0, 0, 0); + execl(exe, exe, NULL); + ERROR("Execl %s error\n", exe); exit(1); } else { - // TODO: short live process - sleep(1); // wait for the address mapping + struct gdb *gdb = new_gdb(); + wait_for_signal(pid); + + vmaps = new_vmap_list(pid); + delete_vmap_list(vmaps); + break_addr += get_base_addr(pid); + DEBUG("break address: %zx\n", break_addr); + + enable_breakpoint(gdb, pid, break_addr); + continue_execution(pid); + wait_for_signal(pid); + + for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; + sym++) { + if (strcmp(sym->name, "_start") == 0) + continue; + else if (strcmp(sym->name, "__libc_csu_init") == 0) + continue; + else if (strcmp(sym->name, "__libc_csu_fini") == 0) + continue; + else + uprobe_attach(skel, pid, exe, sym->addr); + } + vmaps = new_vmap_list(pid); for (struct vmap *vmap = vmaps->head, *prev_vmap = NULL; vmap != NULL; prev_vmap = vmap, vmap = vmap->next) { @@ -191,14 +217,22 @@ int main(int argc, char **argv) { push_symbol_arr(symtab, new_symbol_arr(vmap->libname, dyn_symset, 1)); for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; sym++) { - if (sym->addr != 0x48a80) continue; + if (strcmp(sym->name, "__cxa_finalize") == 0) + continue; + else if (strcmp(sym->name, "__libc_start_main") == 0) + continue; uprobe_attach(skel, pid, vmap->libname, sym->addr); } } + /* Attach tracepoints */ + assert(utrace_bpf__attach(skel) == 0); + + disable_breakpoint(gdb, pid, break_addr); + continue_execution(pid); + print_header(); /* Process events */ - int status = 0; while (true) { err = ring_buffer__poll(records, 100 /* timeout, ms */); /* Ctrl-C will cause -EINTR */ @@ -211,7 +245,8 @@ int main(int argc, char **argv) { break; } if (err == 0) { - pid_t ret = waitpid(pid, &status, WNOHANG); + int wstatus; + pid_t ret = waitpid(pid, &wstatus, WNOHANG); if (ret > 0) break; else if (ret < 0) { diff --git a/eBPF_Supermarket/User_Function_Tracer/src/vmap.c b/eBPF_Supermarket/User_Function_Tracer/src/vmap.c index 3ae2df9e8..19e47b068 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/vmap.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/vmap.c @@ -102,3 +102,19 @@ struct vmap *find_vmap(struct vmap_list *vmaps, size_t addr) { } return NULL; } + +size_t get_base_addr(pid_t pid) { + static char buf[MAX_PATH_LEN]; + size_t base_addr = 0; + snprintf(buf, sizeof(buf), "/proc/%d/maps", pid); + + FILE *fmap = fopen(buf, "r"); + if (fmap == NULL) { + ERROR("Cannot open %s\n", buf); + exit(1); + } + + fgets(buf, sizeof(buf), fmap); + sscanf(buf, "%zx", &base_addr); + return base_addr; +} \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/vmap.h b/eBPF_Supermarket/User_Function_Tracer/src/vmap.h index ec9413473..8fc57df5d 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/vmap.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/vmap.h @@ -74,4 +74,12 @@ void delete_vmap_list(struct vmap_list* vmaps); */ struct vmap* find_vmap(struct vmap_list* vmaps, size_t addr); +/** + * @brief 获得进程在运行时的起始物理地址 + * @param[in] pid 对应进程的进程号 + * @return 起始地址 + * @details 虚拟文件/proc/pid/maps中第一行的第一个字段 + */ +size_t get_base_addr(pid_t pid); + #endif // UTRACE_VMAP_H From 52675c229a59f5f2bc0337a58d5fab3f2cf71621 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 10 Aug 2023 15:36:13 +0800 Subject: [PATCH 02/17] [feat] update log format --- .../User_Function_Tracer/src/log.c | 18 +++--- .../User_Function_Tracer/src/log.h | 29 ++++++--- .../User_Function_Tracer/src/utrace.bpf.c | 12 ++-- .../User_Function_Tracer/src/utrace.c | 60 ++++++++++++------- .../User_Function_Tracer/src/utrace.h | 6 +- 5 files changed, 81 insertions(+), 44 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/src/log.c b/eBPF_Supermarket/User_Function_Tracer/src/log.c index 35ec9e2a6..c953b2cc3 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/log.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/log.c @@ -18,20 +18,22 @@ #include "log.h" -#include +int debug; -void print_char(char c, int cnt) { +void log_char(char c, int cnt) { while (cnt > 0) { - printf("%c", c); + LOG("%c", c); --cnt; } } -void print_header() { printf("# DURATION TID FUNCTION\n"); } +void log_header() { LOG(" CPU | TID | DURATION | FUNCTION CALLS\n"); } -void print_tid(int tid) { printf("[%6d]", tid); } +void log_tid(int tid) { LOG("%6d", tid); } -void print_time_unit(size_t ns) { +void log_cpuid(int cpuid) { LOG("%4d", cpuid); } + +void log_time(size_t ns) { static char *units[] = { "ns", "us", "ms", " s", " m", " h", }; @@ -48,5 +50,5 @@ void print_time_unit(size_t ns) { ++i; } - printf("%3zu.%03zu %s", t, t_mod, units[i]); -} + LOG("%4zu.%03zu %s", t, t_mod, units[i]); +} \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/log.h b/eBPF_Supermarket/User_Function_Tracer/src/log.h index 4eab7d57b..604abc85a 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/log.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/log.h @@ -20,31 +20,38 @@ #define UTRACE_LOG_H #include +#include /** * @brief 输出cnt个字符c * @param[in] c 字符 * @param[in] cnt 个数 */ -void print_char(char c, int cnt); +void log_char(char c, int cnt); /** * @brief 输出头部 */ -void print_header(); +void log_header(); /** * @brief 输出线程号 * @param[in] tid 线程号 */ -void print_tid(int tid); +void log_tid(int tid); /** - * @brief 根据参数打印合适时间单位 + * @brief 输出CPU编号 + * @param[in] cpuid CPU编号 + */ +void log_cpuid(int cpuid); + +/** + * @brief 输出时间及其单位 * @param[in] ns 时间(单位纳秒) - * @details 从[ns,us,ms,s,m,h]中选择合适的单位输出 + * @details 从[ns,us,ms,s,m,h]中选择合适的单位输出时间信息 */ -void print_time_unit(size_t ns); +void log_time(size_t ns); /** 控制是否显示调试信息,在utrace.c中定义 */ extern int debug; @@ -71,4 +78,12 @@ extern int debug; fprintf(stderr, fmt, ##__VA_ARGS__); \ } while (0) -#endif // UTRACE_LOG_H +/** + * @brief 输出到stderr + */ +#define LOG(fmt, ...) \ + do { \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + } while (0) + +#endif // UTRACE_LOG_H \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c index fd6b39937..2fc8867b9 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c @@ -35,22 +35,24 @@ struct { struct { __uint(type, BPF_MAP_TYPE_RINGBUF); - __uint(max_entries, 256 * 1024); + __uint(max_entries, 8192 * 1024); } records SEC(".maps"); SEC("uprobe/trace") int BPF_KPROBE(uprobe) { struct profile_record *r; - pid_t pid, tid; + pid_t pid, tid, cpu_id; u64 id, ts; id = bpf_get_current_pid_tgid(); tid = (u32)id; pid = id >> 32; + cpu_id = bpf_get_smp_processor_id(); r = bpf_ringbuf_reserve(&records, sizeof(*r), 0); if (!r) return 0; r->tid = tid; + r->cpu_id = cpu_id; r->duration_ns = 0; r->ustack_sz = bpf_get_stack(ctx, r->ustack, sizeof(r->ustack), BPF_F_USER_STACK) / sizeof(r->ustack[0]); @@ -65,18 +67,20 @@ int BPF_KPROBE(uprobe) { SEC("uretprobe/trace") int BPF_KRETPROBE(uretprobe) { struct profile_record *r; - pid_t pid, tid; + pid_t pid, tid, cpu_id; u64 id, end_ts = bpf_ktime_get_ns(); u64 *start_ts; s32 ustack_sz; id = bpf_get_current_pid_tgid(); + cpu_id = bpf_get_smp_processor_id(); pid = id >> 32; tid = (u32)id; r = bpf_ringbuf_reserve(&records, sizeof(*r), 0); if (!r) return 0; r->tid = tid; + r->cpu_id = cpu_id; r->ustack_sz = bpf_get_stack(ctx, r->ustack, sizeof(r->ustack), BPF_F_USER_STACK) / sizeof(sizeof(r->ustack[0])); ustack_sz = r->ustack_sz; @@ -86,4 +90,4 @@ int BPF_KRETPROBE(uretprobe) { r->exit = 1; bpf_ringbuf_submit(r, 0); return 0; -} +} \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index 11da2154d..bef26bf76 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -85,39 +85,53 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { const struct profile_record *r = data; if (r->exit) { - // for (int i = 0; i < r->ustack_sz; i++) printf("%llx ", r->ustack[i]); + // LOG("EXIT"); + // for (int i = 0; i < r->ustack_sz; i++) LOG(" %llx", r->ustack[i]); + // LOG(" %s\n", stack_func[r->ustack_sz]); + // return 0; if (status == 0 && r->ustack_sz == pre_ustack_sz) { - printf(" "); - print_time_unit(r->duration_ns); - printf(" "); - print_tid(r->tid); - printf(" | "); - print_char(' ', 2 * r->ustack_sz - 2); - printf("%s();\n", stack_func[r->ustack_sz]); + log_cpuid(r->cpu_id); + LOG(" | "); + log_tid(r->tid); + LOG(" | "); + log_time(r->duration_ns); + LOG(" | "); + log_char(' ', 2 * r->ustack_sz - 2); + LOG("%s();\n", stack_func[r->ustack_sz]); status = 1; pre_ustack_sz = r->ustack_sz; } else if (status == 1 && r->ustack_sz == pre_ustack_sz - 1) { - printf(" "); - print_time_unit(r->duration_ns); - printf(" "); - print_tid(r->tid); - printf(" | "); - print_char(' ', 2 * r->ustack_sz - 2); - printf("} // %s\n", stack_func[r->ustack_sz]); + log_cpuid(r->cpu_id); + LOG(" | "); + log_tid(r->tid); + LOG(" | "); + log_time(r->duration_ns); + LOG(" | "); + log_char(' ', 2 * r->ustack_sz - 2); + LOG("} /* %s */\n", stack_func[r->ustack_sz]); status = 1; pre_ustack_sz = r->ustack_sz; } } else { - // for (int i = 0; i < r->ustack_sz; i++) printf("%llx ", r->ustack[i]); + // LOG("EXEC"); + // for (int i = 0; i < r->ustack_sz; i++) LOG(" %llx", r->ustack[i]); + // if (symbolize(r->ustack[0])) { + // memcpy(stack_func[r->ustack_sz], buf, sizeof(buf)); + // } + // LOG(" %s\n", stack_func[r->ustack_sz]); + // return 0; if (status == -1 && r->ustack_sz != 1) return 0; if (status == 0 && r->ustack_sz != pre_ustack_sz + 1) return 0; if (status == 1 && r->ustack_sz != pre_ustack_sz) return 0; if (status == 0) { - print_char(' ', 12); - print_tid(r->tid); - printf(" | "); - print_char(' ', 2 * r->ustack_sz - 4); - printf("%s() {\n", stack_func[r->ustack_sz - 1]); + log_cpuid(r->cpu_id); + LOG(" | "); + log_tid(r->tid); + LOG(" |"); + log_char(' ', 12); + LOG(" | "); + log_char(' ', 2 * r->ustack_sz - 4); + LOG("%s() {\n", stack_func[r->ustack_sz - 1]); } if (symbolize(r->ustack[0])) { memcpy(stack_func[r->ustack_sz], buf, sizeof(buf)); @@ -231,7 +245,7 @@ int main(int argc, char **argv) { disable_breakpoint(gdb, pid, break_addr); continue_execution(pid); - print_header(); + log_header(); /* Process events */ while (true) { err = ring_buffer__poll(records, 100 /* timeout, ms */); @@ -267,4 +281,4 @@ int main(int argc, char **argv) { delete_vmap_list(vmaps); return err < 0 ? -err : 0; -} +} \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.h b/eBPF_Supermarket/User_Function_Tracer/src/utrace.h index b79fe384d..4272f0de2 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.h @@ -29,7 +29,9 @@ typedef unsigned long long stack_trace_t[MAX_STACK_DEPTH]; * @brief 内核态传给用户态的数据 */ struct profile_record { - unsigned int tid; /**< 线程编号 */ + unsigned int tid; /**< 线程编号 */ + unsigned int cpu_id; /**< CPU编号 */ + unsigned long long duration_ns; /**< 函数时延 */ unsigned int kstack_sz; /**< 内核栈大小 */ @@ -41,4 +43,4 @@ struct profile_record { int exit; /**< 是否为函数退出时 */ }; -#endif // UTRACE_UTRACE_H +#endif // UTRACE_UTRACE_H \ No newline at end of file From 5b222891952b604b603839553f6a162b87965a03 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 10 Aug 2023 15:42:55 +0800 Subject: [PATCH 03/17] [feat] update clang-format --- .../User_Function_Tracer/.clang-format | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/.clang-format b/eBPF_Supermarket/User_Function_Tracer/.clang-format index d35c6c267..d54fdc095 100644 --- a/eBPF_Supermarket/User_Function_Tracer/.clang-format +++ b/eBPF_Supermarket/User_Function_Tracer/.clang-format @@ -5,8 +5,14 @@ ColumnLimit: 100 PointerAlignment: Right IncludeCategories: - Regex: '"vmlinux.h"' # let vmlinux.h come first - Priority: -1000 - - Regex: '"utrace.h"' - Priority: -1001 - - Regex: '"utrace.skel.h"' - Priority: -1000 + Priority: -1 + - Regex: '"utrace.*h"' + Priority: 0 + - Regex: '' + Priority: -1 + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|isl|json)/)' + Priority: 2 + - Regex: '.\*' + Priority: 1 \ No newline at end of file From caf02d0d09bf49d8ef082d0c2840b4f77ee95753 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 10 Aug 2023 15:49:47 +0800 Subject: [PATCH 04/17] [feat] add arg parser --- .../User_Function_Tracer/src/demangle.c | 4 +- .../User_Function_Tracer/src/symbol.c | 7 +- .../User_Function_Tracer/src/symbol.h | 3 +- .../User_Function_Tracer/src/utrace.bpf.c | 4 +- .../User_Function_Tracer/src/utrace.c | 247 +++++++++++++----- .../User_Function_Tracer/src/vmap.c | 27 +- .../User_Function_Tracer/src/vmap.h | 8 + 7 files changed, 226 insertions(+), 74 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/src/demangle.c b/eBPF_Supermarket/User_Function_Tracer/src/demangle.c index 6d5694f0f..21edf2e85 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/demangle.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/demangle.c @@ -18,11 +18,11 @@ #include "utrace.h" -#include "demangle.h" - #include #include +#include "demangle.h" + char *demangle(const char *mangled_name) { char *original_name; long len = MAX_SYMBOL_LEN; diff --git a/eBPF_Supermarket/User_Function_Tracer/src/symbol.c b/eBPF_Supermarket/User_Function_Tracer/src/symbol.c index 184580e50..2e1381ea9 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/symbol.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/symbol.c @@ -18,15 +18,16 @@ #include "symbol.h" -#include "demangle.h" -#include "elf.h" -#include "log.h" #include #include #include #include #include +#include "demangle.h" +#include "elf.h" +#include "log.h" + static int addrsort(const void* lhs, const void* rhs) { const size_t addrl = ((const struct symbol*)(lhs))->addr; const size_t addrr = ((const struct symbol*)(rhs))->addr; diff --git a/eBPF_Supermarket/User_Function_Tracer/src/symbol.h b/eBPF_Supermarket/User_Function_Tracer/src/symbol.h index 7dfa27833..5a639d1c7 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/symbol.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/symbol.h @@ -19,9 +19,10 @@ #ifndef UTRACE_SYMBOL_H #define UTRACE_SYMBOL_H -#include "elf.h" #include +#include "elf.h" + /** * @brief 表示一个符号条目 */ diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c index 2fc8867b9..228511fdd 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c @@ -16,10 +16,10 @@ // // eBPF用户态探针部分 -#include "utrace.h" - #include "vmlinux.h" +#include "utrace.h" + #include #include #include diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index bef26bf76..8f8106bd0 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -16,14 +16,11 @@ // // 基于eBPF的用户态函数观测主程序 -#include "utrace.h" +#include +#include "utrace.h" #include "utrace.skel.h" -#include "gdb.h" -#include "log.h" -#include "symbol.h" -#include "vmap.h" #include #include #include @@ -35,8 +32,89 @@ #include #include -// TODO: delete global variables -int debug = 1; +#include "gdb.h" +#include "log.h" +#include "symbol.h" +#include "vmap.h" + +static const struct option longopts[] = {{"command", required_argument, NULL, 'c'}, + {"pid", required_argument, NULL, 'p'}, + {"help", no_argument, NULL, 'h'}, + {"debug", no_argument, NULL, 'd'}, + {NULL, 0, NULL, 0}}; + +static const char *optstring = "c:p:hd"; + +struct args { + pid_t pid; + char **argv; +}; + +void print_usage(char *program) { + LOG("Usage: %s [$OPTIONS...]\n", program); + LOG("\n"); + LOG("Options:\n"); + LOG(" -c --command: the command to run the program to be traced.\n"); + LOG(" -p --pid: the PID of the program to be traced.\n"); + LOG(" -d --debug: enable debug mode.\n"); + LOG(" -h --help: disaply this usage information.\n"); + LOG("\n"); + LOG("Examples:\n"); + LOG(" %s -c \"$PROGRAM $ARGS\"\n", program); + LOG(" %s -p $PID\n", program); +} + +void parse_args(int argc, char *argv[], struct args *arg) { + int len, c = 0; + + arg->pid = 0; + arg->argv = (char **)malloc(sizeof(char *) * 16); + + debug = 0; + + int opt, opt_index = 1; + while ((opt = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) { + switch ((char)opt) { + case 'c': // -c --command + len = strlen(optarg); + for (int i = 0; i < len; i++) { + if (optarg[i] != ' ') { + int j = i + 1; + while (j < len && optarg[j] != ' ') { + ++j; + } + optarg[j] = 0; + arg->argv[c] = strdup(optarg + i); + ++c; + optarg[j] = ' '; + i = j; + } + } + arg->argv[c] = NULL; + opt_index += 2; + break; + case 'p': // -p --pid + arg->pid = atoi(optarg); + opt_index += 2; + break; + case 'd': // -d --debug + debug = 1; + opt_index += 1; + break; + case 'h': // -h --help + print_usage(argv[0]); + exit(0); + default: + print_usage(argv[0]); + exit(1); + } + } + + if (!c) { + print_usage(argv[0]); + exit(1); + } +} struct symbol_tab *symtab; struct dyn_symbol_set *dyn_symset; @@ -145,12 +223,12 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { int main(int argc, char **argv) { struct ring_buffer *records = NULL; struct utrace_bpf *skel; - char *exe; + struct args arg; + pid_t pid; + char *program; int err; - // TODO: arg parser - if (argc <= 1) return 1; - exe = argv[1]; + parse_args(argc, argv, &arg); /* Set up libbpf errors and debug info callback */ libbpf_set_print(libbpf_print_fn); @@ -177,40 +255,13 @@ int main(int argc, char **argv) { goto cleanup; } - symtab = new_symbol_tab(); - dyn_symset = new_dyn_symbol_set(); - size_t break_addr = 0; - push_symbol_arr(symtab, new_symbol_arr(exe, dyn_symset, 0)); - for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; - sym++) { - if (strcmp(sym->name, "_start") == 0) { // NOTE - break_addr = sym->addr; - break; - } - } - - pid_t pid = fork(); - if (pid < 0) { - ERROR("Fork error\n"); - goto cleanup; - } else if (pid == 0) { - ptrace(PTRACE_TRACEME, 0, 0, 0); - execl(exe, exe, NULL); - ERROR("Execl %s error\n", exe); - exit(1); - } else { - struct gdb *gdb = new_gdb(); - wait_for_signal(pid); - - vmaps = new_vmap_list(pid); - delete_vmap_list(vmaps); - break_addr += get_base_addr(pid); - DEBUG("break address: %zx\n", break_addr); - - enable_breakpoint(gdb, pid, break_addr); - continue_execution(pid); - wait_for_signal(pid); + if (arg.pid) { + pid = arg.pid; + program = get_program(pid); + symtab = new_symbol_tab(); + dyn_symset = new_dyn_symbol_set(); + push_symbol_arr(symtab, new_symbol_arr(program, dyn_symset, 0)); for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; sym++) { if (strcmp(sym->name, "_start") == 0) @@ -220,13 +271,13 @@ int main(int argc, char **argv) { else if (strcmp(sym->name, "__libc_csu_fini") == 0) continue; else - uprobe_attach(skel, pid, exe, sym->addr); + uprobe_attach(skel, pid, program, sym->addr); } vmaps = new_vmap_list(pid); for (struct vmap *vmap = vmaps->head, *prev_vmap = NULL; vmap != NULL; prev_vmap = vmap, vmap = vmap->next) { - if (strcmp(basename(vmap->libname), basename(exe)) == 0) continue; + if (strcmp(basename(vmap->libname), basename(program)) == 0) continue; if (prev_vmap != NULL && strcmp(prev_vmap->libname, vmap->libname) == 0) continue; push_symbol_arr(symtab, new_symbol_arr(vmap->libname, dyn_symset, 1)); for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; @@ -237,34 +288,104 @@ int main(int argc, char **argv) { continue; uprobe_attach(skel, pid, vmap->libname, sym->addr); } + + /* Attach tracepoints */ + assert(utrace_bpf__attach(skel) == 0); } + } else { + program = strdup(arg.argv[0]); - /* Attach tracepoints */ - assert(utrace_bpf__attach(skel) == 0); + symtab = new_symbol_tab(); + dyn_symset = new_dyn_symbol_set(); + size_t break_addr = 0; + push_symbol_arr(symtab, new_symbol_arr(program, dyn_symset, 0)); + for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; + sym++) { + if (strcmp(sym->name, "_start") == 0) { + break_addr = sym->addr; + break; + } + } - disable_breakpoint(gdb, pid, break_addr); - continue_execution(pid); + pid = fork(); + if (pid < 0) { + ERROR("Fork error\n"); + goto cleanup; + } else if (pid == 0) { + ptrace(PTRACE_TRACEME, 0, 0, 0); + execv(program, arg.argv); + ERROR("Execv %s error\n", program); + exit(1); + } else { + struct gdb *gdb = new_gdb(); + wait_for_signal(pid); + + break_addr += get_base_addr(pid); + DEBUG("break address: %zx\n", break_addr); + + enable_breakpoint(gdb, pid, break_addr); + continue_execution(pid); + wait_for_signal(pid); - log_header(); - /* Process events */ - while (true) { - err = ring_buffer__poll(records, 100 /* timeout, ms */); - /* Ctrl-C will cause -EINTR */ - if (err == -EINTR) { - err = 0; - break; + for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; + sym++) { + if (strcmp(sym->name, "_start") == 0) + continue; + else if (strcmp(sym->name, "__libc_csu_init") == 0) + continue; + else if (strcmp(sym->name, "__libc_csu_fini") == 0) + continue; + else + uprobe_attach(skel, pid, program, sym->addr); } - if (err < 0) { - ERROR("Error polling perf buffer: %d\n", err); - break; + + vmaps = new_vmap_list(pid); + for (struct vmap *vmap = vmaps->head, *prev_vmap = NULL; vmap != NULL; + prev_vmap = vmap, vmap = vmap->next) { + if (strcmp(basename(vmap->libname), basename(program)) == 0) continue; + if (prev_vmap != NULL && strcmp(prev_vmap->libname, vmap->libname) == 0) continue; + push_symbol_arr(symtab, new_symbol_arr(vmap->libname, dyn_symset, 1)); + for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; + sym++) { + if (strcmp(sym->name, "__cxa_finalize") == 0) + continue; + else if (strcmp(sym->name, "__libc_start_main") == 0) + continue; + uprobe_attach(skel, pid, vmap->libname, sym->addr); + } } - if (err == 0) { + + /* Attach tracepoints */ + assert(utrace_bpf__attach(skel) == 0); + + disable_breakpoint(gdb, pid, break_addr); + continue_execution(pid); + } + } + + log_header(); + /* Process events */ + while (true) { + err = ring_buffer__poll(records, 100 /* timeout, ms */); + /* Ctrl-C will cause -EINTR */ + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + ERROR("Error polling perf buffer: %d\n", err); + break; + } + if (err == 0) { + if (arg.pid) { + if (kill(pid, 0)) break; + } else { int wstatus; pid_t ret = waitpid(pid, &wstatus, WNOHANG); if (ret > 0) break; else if (ret < 0) { - ERROR("Exec %s error\n", exe); + ERROR("Exec %s error\n", program); break; } } diff --git a/eBPF_Supermarket/User_Function_Tracer/src/vmap.c b/eBPF_Supermarket/User_Function_Tracer/src/vmap.c index 19e47b068..404209044 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/vmap.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/vmap.c @@ -18,13 +18,13 @@ #include "utrace.h" -#include "vmap.h" - -#include "log.h" #include #include #include +#include "log.h" +#include "vmap.h" + static struct vmap *new_vmap() { struct vmap *v = (struct vmap *)malloc(sizeof(struct vmap)); v->next = NULL; @@ -117,4 +117,25 @@ size_t get_base_addr(pid_t pid) { fgets(buf, sizeof(buf), fmap); sscanf(buf, "%zx", &base_addr); return base_addr; +} + +char *get_program(pid_t pid) { + static char buf[MAX_PATH_LEN]; + size_t base_addr = 0; + snprintf(buf, sizeof(buf), "/proc/%d/maps", pid); + + FILE *fmap = fopen(buf, "r"); + if (fmap == NULL) { + ERROR("Cannot open %s\n", buf); + exit(1); + } + + fgets(buf, sizeof(buf), fmap); + int i = strlen(buf) - 1; + buf[i] = 0; // '\n' + while (i >= 0) { + if (buf[i] == ' ') break; + --i; + } + return strdup(buf + i + 1); } \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/vmap.h b/eBPF_Supermarket/User_Function_Tracer/src/vmap.h index 8fc57df5d..4937afce4 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/vmap.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/vmap.h @@ -82,4 +82,12 @@ struct vmap* find_vmap(struct vmap_list* vmaps, size_t addr); */ size_t get_base_addr(pid_t pid); +/** + * @brief 获得进程的名称 + * @param[in] pid 对应进程的进程号 + * @return 进程名称 + * @details 虚拟文件/proc/pid/maps中第一行的最后一个字段 + */ +char* get_program(pid_t pid); + #endif // UTRACE_VMAP_H From cf5ab71908f791a89af61e0f71bb11c20fac9342 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 10 Aug 2023 15:54:18 +0800 Subject: [PATCH 05/17] [bug] fix github action --- .github/workflows/user_function_tracer.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/user_function_tracer.yml b/.github/workflows/user_function_tracer.yml index 91dfff2af..0d9b1dc93 100644 --- a/.github/workflows/user_function_tracer.yml +++ b/.github/workflows/user_function_tracer.yml @@ -34,4 +34,6 @@ jobs: cmake -B build -S . -G Ninja cmake --build build gcc test/sleep.c -o test/sleep - sudo build/utrace test/sleep + gcc test/mmap.c -o test/mmap + sudo build/utrace -c test/sleep + sudo build/utrace -c test/mmap From 581477047d1f7a74f0f7def8d1f9062ba89f6216 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 10 Aug 2023 16:17:59 +0800 Subject: [PATCH 06/17] [bug] fix name demangling --- .../User_Function_Tracer/src/demangle.c | 36 ++++++++++++------- .../User_Function_Tracer/src/demangle.h | 4 +-- .../User_Function_Tracer/src/utrace.c | 2 +- .../User_Function_Tracer/src/utrace.h | 3 +- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/src/demangle.c b/eBPF_Supermarket/User_Function_Tracer/src/demangle.c index 21edf2e85..b9f5d09b0 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/demangle.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/demangle.c @@ -18,6 +18,7 @@ #include "utrace.h" +#include #include #include @@ -25,17 +26,28 @@ char *demangle(const char *mangled_name) { char *original_name; - long len = MAX_SYMBOL_LEN; + long len = MAX_MANGLED_LEN; + long name_len; int status; - /** 确保只还原重整过的符号(以"_Z"起始)*/ - if (mangled_name[0] != '_' || mangled_name[1] != 'Z') return strdup(mangled_name); - - __cxa_demangle(mangled_name, NULL, &len, &status); - if (status < 0) return strdup(mangled_name); - - original_name = malloc(len); - __cxa_demangle(mangled_name, original_name, &len, &status); - - return original_name; -} + if (strncmp(mangled_name, "_Z", 2) == 0) { + __cxa_demangle(mangled_name, NULL, &len, &status); + if (status < 0) return strdup(mangled_name); + + original_name = malloc(len); + __cxa_demangle(mangled_name, original_name, &len, &status); + + name_len = strlen(original_name); + if (original_name[name_len - 1] == ')') { + int cont = 1; + while (cont) { + --name_len; + if (original_name[name_len] == '(') cont = 0; + original_name[name_len] = 0; + } + } + return original_name; + } + + return strdup(mangled_name); +} \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/demangle.h b/eBPF_Supermarket/User_Function_Tracer/src/demangle.h index fc9b035c3..cd93410c3 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/demangle.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/demangle.h @@ -26,9 +26,9 @@ extern char *__cxa_demangle(const char *name, char *output, long *len, int *stat * @param[in] mangled_name 符号 * @return 还原后的符号 * @details 对于未重整的符号,调用strdup() - * 对于重整过的符号(以"_Z"起始),调用abi::__cxa_demangle() + * 对于重整过的符号(以"_GLOBAL__sub_I__Z"或"_Z"起始),调用abi::__cxa_demangle() * @retval 指向堆内存 */ char *demangle(const char *mangled_name); -#endif // UTRACE_DEMANGLE_H +#endif // UTRACE_DEMANGLE_H \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index 8f8106bd0..fff42049c 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -120,7 +120,7 @@ struct symbol_tab *symtab; struct dyn_symbol_set *dyn_symset; struct vmap_list *vmaps; -char buf[256]; +char buf[MAX_SYMBOL_LEN]; char stack_func[MAX_STACK_DEPTH][MAX_SYMBOL_LEN]; int status = -1, pre_ustack_sz = 0; diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.h b/eBPF_Supermarket/User_Function_Tracer/src/utrace.h index 4272f0de2..2401407c6 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.h @@ -19,8 +19,9 @@ #ifndef UTRACE_UTRACE_H #define UTRACE_UTRACE_H -#define MAX_SYMBOL_LEN 64 #define MAX_STACK_DEPTH 128 +#define MAX_MANGLED_LEN 128 +#define MAX_SYMBOL_LEN 1024 #define MAX_PATH_LEN 256 typedef unsigned long long stack_trace_t[MAX_STACK_DEPTH]; From d595984a844c57d3a559bd3568066afb49538837 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 10 Aug 2023 17:04:09 +0800 Subject: [PATCH 07/17] [feat] add support for no-ASLR and no-pie --- .../User_Function_Tracer/src/demangle.c | 1 - .../User_Function_Tracer/src/demangle.h | 2 +- .../User_Function_Tracer/src/utrace.c | 46 +++++++++++++------ 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/src/demangle.c b/eBPF_Supermarket/User_Function_Tracer/src/demangle.c index b9f5d09b0..fd8ec6488 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/demangle.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/demangle.c @@ -18,7 +18,6 @@ #include "utrace.h" -#include #include #include diff --git a/eBPF_Supermarket/User_Function_Tracer/src/demangle.h b/eBPF_Supermarket/User_Function_Tracer/src/demangle.h index cd93410c3..77d8f81ab 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/demangle.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/demangle.h @@ -26,7 +26,7 @@ extern char *__cxa_demangle(const char *name, char *output, long *len, int *stat * @param[in] mangled_name 符号 * @return 还原后的符号 * @details 对于未重整的符号,调用strdup() - * 对于重整过的符号(以"_GLOBAL__sub_I__Z"或"_Z"起始),调用abi::__cxa_demangle() + * 对于重整过的符号(以"_Z"起始),调用abi::__cxa_demangle() * @retval 指向堆内存 */ char *demangle(const char *mangled_name); diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index fff42049c..6cf3b2b83 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -37,16 +38,20 @@ #include "symbol.h" #include "vmap.h" +#define BASE_ADDR 0x400000 // for no-pie option + +#define NOASLR 1000 static const struct option longopts[] = {{"command", required_argument, NULL, 'c'}, {"pid", required_argument, NULL, 'p'}, + {"no-ASLR", no_argument, NULL, NOASLR}, {"help", no_argument, NULL, 'h'}, - {"debug", no_argument, NULL, 'd'}, {NULL, 0, NULL, 0}}; static const char *optstring = "c:p:hd"; struct args { pid_t pid; + int aslr; char **argv; }; @@ -57,6 +62,7 @@ void print_usage(char *program) { LOG(" -c --command: the command to run the program to be traced.\n"); LOG(" -p --pid: the PID of the program to be traced.\n"); LOG(" -d --debug: enable debug mode.\n"); + LOG(" --no-ASLR: disable Address Space Layout Randomization (ASLR).\n"); LOG(" -h --help: disaply this usage information.\n"); LOG("\n"); LOG("Examples:\n"); @@ -68,13 +74,14 @@ void parse_args(int argc, char *argv[], struct args *arg) { int len, c = 0; arg->pid = 0; + arg->aslr = 1; arg->argv = (char **)malloc(sizeof(char *) * 16); debug = 0; int opt, opt_index = 1; while ((opt = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) { - switch ((char)opt) { + switch (opt) { case 'c': // -c --command len = strlen(optarg); for (int i = 0; i < len; i++) { @@ -101,6 +108,9 @@ void parse_args(int argc, char *argv[], struct args *arg) { debug = 1; opt_index += 1; break; + case NOASLR: + arg->aslr = 0; + break; case 'h': // -h --help print_usage(argv[0]); exit(0); @@ -258,10 +268,19 @@ int main(int argc, char **argv) { if (arg.pid) { pid = arg.pid; program = get_program(pid); + } else { + program = strdup(arg.argv[0]); + } + + symtab = new_symbol_tab(); + dyn_symset = new_dyn_symbol_set(); + push_symbol_arr(symtab, new_symbol_arr(program, dyn_symset, 0)); + for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; + sym++) { + if (sym->addr >= BASE_ADDR) sym->addr -= BASE_ADDR; + } - symtab = new_symbol_tab(); - dyn_symset = new_dyn_symbol_set(); - push_symbol_arr(symtab, new_symbol_arr(program, dyn_symset, 0)); + if (arg.pid) { for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; sym++) { if (strcmp(sym->name, "_start") == 0) @@ -270,8 +289,7 @@ int main(int argc, char **argv) { continue; else if (strcmp(sym->name, "__libc_csu_fini") == 0) continue; - else - uprobe_attach(skel, pid, program, sym->addr); + else uprobe_attach(skel, pid, program, sym->addr); } vmaps = new_vmap_list(pid); @@ -288,17 +306,12 @@ int main(int argc, char **argv) { continue; uprobe_attach(skel, pid, vmap->libname, sym->addr); } - - /* Attach tracepoints */ - assert(utrace_bpf__attach(skel) == 0); } - } else { - program = strdup(arg.argv[0]); - symtab = new_symbol_tab(); - dyn_symset = new_dyn_symbol_set(); + /* Attach tracepoints */ + assert(utrace_bpf__attach(skel) == 0); + } else { size_t break_addr = 0; - push_symbol_arr(symtab, new_symbol_arr(program, dyn_symset, 0)); for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; sym++) { if (strcmp(sym->name, "_start") == 0) { @@ -312,6 +325,7 @@ int main(int argc, char **argv) { ERROR("Fork error\n"); goto cleanup; } else if (pid == 0) { + if (!arg.aslr) personality(ADDR_NO_RANDOMIZE); ptrace(PTRACE_TRACEME, 0, 0, 0); execv(program, arg.argv); ERROR("Execv %s error\n", program); @@ -401,5 +415,7 @@ int main(int argc, char **argv) { delete_dyn_symbol_set(dyn_symset); delete_vmap_list(vmaps); + free(program); + return err < 0 ? -err : 0; } \ No newline at end of file From 4d61717afa905f75a29478dc3f2d3d58dfdf3273 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 10 Aug 2023 21:30:22 +0800 Subject: [PATCH 08/17] update README --- .../User_Function_Tracer/README.md | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/README.md b/eBPF_Supermarket/User_Function_Tracer/README.md index ed4e6d40f..e395ad221 100644 --- a/eBPF_Supermarket/User_Function_Tracer/README.md +++ b/eBPF_Supermarket/User_Function_Tracer/README.md @@ -11,12 +11,23 @@ sudo apt install -y clang cmake ninja-build libelf1 libelf-dev zlib1g-dev libbpf ### 编译运行 ```shell -mkdir -p vmlinux -bash tools/gen_vmlinux_h.sh > vmlinux/vmlinux.h -cmake -B build -S . -G Ninja -cmake --build build +$ mkdir -p vmlinux +$ bash tools/gen_vmlinux_h.sh > vmlinux/vmlinux.h +$ cmake -B build -S . -G Ninja +$ cmake --build build +$ build/utrace -h +Usage: build/utrace [$OPTIONS...] -build/utrace PROGRAM|PID +Options: + -c --command: the command to run the program to be traced. + -p --pid: the PID of the program to be traced. + -d --debug: enable debug mode. + --no-ASLR: disable Address Space Layout Randomization (ASLR). + -h --help: disaply this usage information. + +Examples: + build/utrace -c "$PROGRAM $ARGS" + build/utrace -p $PID ``` ### 特点 @@ -25,9 +36,7 @@ build/utrace PROGRAM|PID + 不同于`perf`, `gprof`等性能分析工具,`eBPF-utrace`输出准确的函数调用时延,而不是基于perf_event()的采样方式。 ### TODO -- [] short live process -- [] arg parser -- [] input pid -- [] more tests -- [] colorful log -- [] multithread +- simplify c++ symbols +- more tests +- colorful log +- multithread From 0f1977c3eeec495ae2abc7a3a41f1785b905aea3 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Fri, 11 Aug 2023 17:36:49 +0800 Subject: [PATCH 09/17] [test] add strcpy.c --- .github/workflows/user_function_tracer.yml | 2 ++ .../User_Function_Tracer/test/strcpy.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 eBPF_Supermarket/User_Function_Tracer/test/strcpy.c diff --git a/.github/workflows/user_function_tracer.yml b/.github/workflows/user_function_tracer.yml index 0d9b1dc93..f658b8461 100644 --- a/.github/workflows/user_function_tracer.yml +++ b/.github/workflows/user_function_tracer.yml @@ -35,5 +35,7 @@ jobs: cmake --build build gcc test/sleep.c -o test/sleep gcc test/mmap.c -o test/mmap + gcc test/strcpy.c -o test/strcpy sudo build/utrace -c test/sleep sudo build/utrace -c test/mmap + sudo build/utrace -c test/strcpy diff --git a/eBPF_Supermarket/User_Function_Tracer/test/strcpy.c b/eBPF_Supermarket/User_Function_Tracer/test/strcpy.c new file mode 100644 index 000000000..eefccaded --- /dev/null +++ b/eBPF_Supermarket/User_Function_Tracer/test/strcpy.c @@ -0,0 +1,15 @@ +#include +#include +int main() { + char *s = "Hello!"; + char *t = malloc(15 * sizeof(char)); + int m = strlen(s); + memcpy(t, s, m); + int n = strlen(t); + int ss = strlen(s) + strlen(t); + memset(t, 0, n); + free(t); + t = malloc(12 * sizeof(char)); + free(t); + return 0; +} From c2149bc847f9975765c5f5cd1ab710c5f05065b0 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Sat, 12 Aug 2023 22:24:23 +0800 Subject: [PATCH 10/17] [bug] avoid duplicate symbols --- .../User_Function_Tracer/src/symbol.c | 5 +-- .../User_Function_Tracer/src/symbol.h | 2 +- .../User_Function_Tracer/src/utrace.c | 31 ++++++++++++++----- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/src/symbol.c b/eBPF_Supermarket/User_Function_Tracer/src/symbol.c index 2e1381ea9..5f69975a1 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/symbol.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/symbol.c @@ -88,7 +88,6 @@ struct symbol_arr* new_symbol_arr(char* libname, struct dyn_symbol_set* dyn_syms if (elf_s.shdr.sh_type != SHT_SYMTAB && elf_s.shdr.sh_type != SHT_DYNSYM) continue; struct elf_entry elf_e; struct symbol sym; - size_t prev_sym_value = 0; for (elf_symbol_entry_begin(&elf_e, &elf_s); elf_symbol_entry_next(&elf_e, &elf_s);) { if (GELF_ST_TYPE(elf_e.sym.st_info) != STT_FUNC && // GELF_ST_TYPE(elf_e.sym.st_info) != STT_OBJECT && @@ -105,13 +104,11 @@ struct symbol_arr* new_symbol_arr(char* libname, struct dyn_symbol_set* dyn_syms DEBUG("Dynamic symbol: %s\n", sym.name); } - if (elf_e.sym.st_value == prev_sym_value) continue; if (elf_e.sym.st_shndx == STN_UNDEF) continue; if (sym.size == 0) continue; if (lib && !contain_dyn_symbol(dyn_symset, sym.name)) continue; push_symbol(symbols, &sym); - prev_sym_value = elf_e.sym.st_value; } } elf_head_end(&elf); @@ -168,4 +165,4 @@ char* find_symbol_name(struct symbol_arr* symbols, size_t addr) { } } return NULL; -} +} \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/symbol.h b/eBPF_Supermarket/User_Function_Tracer/src/symbol.h index 5a639d1c7..4421ddb81 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/symbol.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/symbol.h @@ -140,4 +140,4 @@ void push_symbol_arr(struct symbol_tab* symbol_tab, struct symbol_arr* symbols); */ void delete_symbol_tab(struct symbol_tab* symbol_tab); -#endif // UTRACE_SYMTAB_H +#endif // UTRACE_SYMTAB_H \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index 6cf3b2b83..18715aff9 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -276,11 +276,12 @@ int main(int argc, char **argv) { dyn_symset = new_dyn_symbol_set(); push_symbol_arr(symtab, new_symbol_arr(program, dyn_symset, 0)); for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; - sym++) { - if (sym->addr >= BASE_ADDR) sym->addr -= BASE_ADDR; - } + sym++) { + if (sym->addr >= BASE_ADDR) sym->addr -= BASE_ADDR; + } if (arg.pid) { + size_t pre_addr = 0; for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; sym++) { if (strcmp(sym->name, "_start") == 0) @@ -289,7 +290,10 @@ int main(int argc, char **argv) { continue; else if (strcmp(sym->name, "__libc_csu_fini") == 0) continue; - else uprobe_attach(skel, pid, program, sym->addr); + if (sym->addr != pre_addr) { + uprobe_attach(skel, pid, program, sym->addr); + pre_addr = sym->addr; + } } vmaps = new_vmap_list(pid); @@ -298,13 +302,17 @@ int main(int argc, char **argv) { if (strcmp(basename(vmap->libname), basename(program)) == 0) continue; if (prev_vmap != NULL && strcmp(prev_vmap->libname, vmap->libname) == 0) continue; push_symbol_arr(symtab, new_symbol_arr(vmap->libname, dyn_symset, 1)); + size_t pre_addr = 0; for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; sym++) { if (strcmp(sym->name, "__cxa_finalize") == 0) continue; else if (strcmp(sym->name, "__libc_start_main") == 0) continue; - uprobe_attach(skel, pid, vmap->libname, sym->addr); + if (sym->addr != pre_addr) { + uprobe_attach(skel, pid, vmap->libname, sym->addr); + pre_addr = sym->addr; + } } } @@ -341,6 +349,7 @@ int main(int argc, char **argv) { continue_execution(pid); wait_for_signal(pid); + size_t pre_addr = 0; for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; sym++) { if (strcmp(sym->name, "_start") == 0) @@ -349,8 +358,12 @@ int main(int argc, char **argv) { continue; else if (strcmp(sym->name, "__libc_csu_fini") == 0) continue; - else + else if (strcmp(sym->name, "_dl_relocate_static_pie") == 0) + continue; + if (sym->addr != pre_addr) { uprobe_attach(skel, pid, program, sym->addr); + pre_addr = sym->addr; + } } vmaps = new_vmap_list(pid); @@ -359,13 +372,17 @@ int main(int argc, char **argv) { if (strcmp(basename(vmap->libname), basename(program)) == 0) continue; if (prev_vmap != NULL && strcmp(prev_vmap->libname, vmap->libname) == 0) continue; push_symbol_arr(symtab, new_symbol_arr(vmap->libname, dyn_symset, 1)); + size_t pre_addr = 0; for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; sym++) { if (strcmp(sym->name, "__cxa_finalize") == 0) continue; else if (strcmp(sym->name, "__libc_start_main") == 0) continue; - uprobe_attach(skel, pid, vmap->libname, sym->addr); + if (sym->addr != pre_addr) { + uprobe_attach(skel, pid, vmap->libname, sym->addr); + pre_addr = sym->addr; + } } } From 184d632e98ea8c2130c0de5a0047cf266c7fc6bb Mon Sep 17 00:00:00 2001 From: jyf111 Date: Sat, 12 Aug 2023 22:53:18 +0800 Subject: [PATCH 11/17] [feat] support color log --- .../User_Function_Tracer/README.md | 1 - .../User_Function_Tracer/src/log.c | 15 ++++++++++- .../User_Function_Tracer/src/log.h | 19 +++++++++++++- .../User_Function_Tracer/src/utrace.c | 26 +++++++++++-------- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/README.md b/eBPF_Supermarket/User_Function_Tracer/README.md index e395ad221..2752194a3 100644 --- a/eBPF_Supermarket/User_Function_Tracer/README.md +++ b/eBPF_Supermarket/User_Function_Tracer/README.md @@ -38,5 +38,4 @@ Examples: ### TODO - simplify c++ symbols - more tests -- colorful log - multithread diff --git a/eBPF_Supermarket/User_Function_Tracer/src/log.c b/eBPF_Supermarket/User_Function_Tracer/src/log.c index c953b2cc3..46b1cc877 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/log.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/log.c @@ -18,8 +18,19 @@ #include "log.h" +#include +#include +#include + int debug; +void log_color(const char* color) { + char* term = getenv("TERM"); + if (isatty(fileno(stdout)) && !(term && !strcmp(term, "dumb"))) { + LOG("%s", color); + } +} + void log_char(char c, int cnt) { while (cnt > 0) { LOG("%c", c); @@ -33,8 +44,10 @@ void log_tid(int tid) { LOG("%6d", tid); } void log_cpuid(int cpuid) { LOG("%4d", cpuid); } +void log_split() { LOG(" | "); } + void log_time(size_t ns) { - static char *units[] = { + static char* units[] = { "ns", "us", "ms", " s", " m", " h", }; static size_t limit[] = { diff --git a/eBPF_Supermarket/User_Function_Tracer/src/log.h b/eBPF_Supermarket/User_Function_Tracer/src/log.h index 604abc85a..fec5ec1c0 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/log.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/log.h @@ -23,7 +23,13 @@ #include /** - * @brief 输出cnt个字符c + * @brief 设置输出的颜色 + * @param[in] color 颜色控制符 + */ +void log_color(const char* color); + +/** + * @brief 输出连续cnt个字符c * @param[in] c 字符 * @param[in] cnt 个数 */ @@ -46,6 +52,12 @@ void log_tid(int tid); */ void log_cpuid(int cpuid); +/** + * @brief 输出分隔符 + * @details 分隔符为" | " + */ +void log_split(); + /** * @brief 输出时间及其单位 * @param[in] ns 时间(单位纳秒) @@ -86,4 +98,9 @@ extern int debug; fprintf(stderr, fmt, ##__VA_ARGS__); \ } while (0) +#define TERM_RED "\033[0;31m" +#define TERM_GREEN "\033[0;32m" +#define TERM_GRAY "\033[0;90m" +#define TERM_NC "\033[0m" + #endif // UTRACE_LOG_H \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index 18715aff9..f6ec83e7e 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -179,24 +179,28 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { // return 0; if (status == 0 && r->ustack_sz == pre_ustack_sz) { log_cpuid(r->cpu_id); - LOG(" | "); + log_split(); log_tid(r->tid); - LOG(" | "); + log_split(); log_time(r->duration_ns); - LOG(" | "); + log_split(); log_char(' ', 2 * r->ustack_sz - 2); LOG("%s();\n", stack_func[r->ustack_sz]); status = 1; pre_ustack_sz = r->ustack_sz; } else if (status == 1 && r->ustack_sz == pre_ustack_sz - 1) { log_cpuid(r->cpu_id); - LOG(" | "); + log_split(); log_tid(r->tid); - LOG(" | "); + log_split(); log_time(r->duration_ns); - LOG(" | "); + log_split(); log_char(' ', 2 * r->ustack_sz - 2); - LOG("} /* %s */\n", stack_func[r->ustack_sz]); + LOG("} "); + log_color(TERM_GRAY); + LOG("/* %s */", stack_func[r->ustack_sz]); + log_color(TERM_NC); + LOG("\n"); status = 1; pre_ustack_sz = r->ustack_sz; } @@ -213,11 +217,11 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { if (status == 1 && r->ustack_sz != pre_ustack_sz) return 0; if (status == 0) { log_cpuid(r->cpu_id); - LOG(" | "); + log_split(); log_tid(r->tid); - LOG(" |"); - log_char(' ', 12); - LOG(" | "); + log_split(); + log_char(' ', 11); + log_split(); log_char(' ', 2 * r->ustack_sz - 4); LOG("%s() {\n", stack_func[r->ustack_sz - 1]); } From 8a3eefead56959ceaf02650420f6f83fa816e9fb Mon Sep 17 00:00:00 2001 From: jyf111 Date: Sat, 12 Aug 2023 23:01:35 +0800 Subject: [PATCH 12/17] [bug] fix multi-thread stack depth problem --- .../User_Function_Tracer/README.md | 1 - .../User_Function_Tracer/src/utrace.bpf.c | 82 +++++++++++++------ .../User_Function_Tracer/src/utrace.c | 50 ++++++----- .../User_Function_Tracer/src/utrace.h | 11 ++- 4 files changed, 86 insertions(+), 58 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/README.md b/eBPF_Supermarket/User_Function_Tracer/README.md index 2752194a3..aa095c62c 100644 --- a/eBPF_Supermarket/User_Function_Tracer/README.md +++ b/eBPF_Supermarket/User_Function_Tracer/README.md @@ -38,4 +38,3 @@ Examples: ### TODO - simplify c++ symbols - more tests -- multithread diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c index 228511fdd..6a5c8ef7a 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.bpf.c @@ -26,68 +26,96 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; +static int global_sz; +static int current_pid; struct { __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 8192); - __type(key, s32); - __type(value, u64); + __type(key, __u32); + __type(value, __u64); + __uint(max_entries, MAX_STACK_DEPTH); } function_start SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, __u32); + __uint(max_entries, MAX_THREAD_NUM); +} stack_depth SEC(".maps"); + struct { __uint(type, BPF_MAP_TYPE_RINGBUF); - __uint(max_entries, 8192 * 1024); + __uint(max_entries, 2048 * 4096); } records SEC(".maps"); SEC("uprobe/trace") int BPF_KPROBE(uprobe) { struct profile_record *r; - pid_t pid, tid, cpu_id; - u64 id, ts; + pid_t tid, cpu_id; + __u64 ts; + __u32 *depth_ptr; + __u32 depth; - id = bpf_get_current_pid_tgid(); - tid = (u32)id; - pid = id >> 32; + current_pid = tid = (__u32)bpf_get_current_pid_tgid(); cpu_id = bpf_get_smp_processor_id(); r = bpf_ringbuf_reserve(&records, sizeof(*r), 0); if (!r) return 0; + r->tid = tid; r->cpu_id = cpu_id; + r->timestamp = 0; r->duration_ns = 0; - r->ustack_sz = - bpf_get_stack(ctx, r->ustack, sizeof(r->ustack), BPF_F_USER_STACK) / sizeof(r->ustack[0]); + bpf_get_stack(ctx, &r->ustack, sizeof(r->ustack), BPF_F_USER_STACK); + depth_ptr = bpf_map_lookup_elem(&stack_depth, &tid); + if (depth_ptr) + r->ustack_sz = depth = *depth_ptr + 1; + else + r->ustack_sz = depth = 0; + r->global_sz = global_sz; r->exit = 0; - s32 ustack_sz = r->ustack_sz; - ts = bpf_ktime_get_ns(); - bpf_map_update_elem(&function_start, &ustack_sz, &ts, BPF_ANY); + bpf_ringbuf_submit(r, 0); + + ts = bpf_ktime_get_ns(); + bpf_map_update_elem(&function_start, &global_sz, &ts, BPF_NOEXIST); + ++global_sz; + bpf_map_update_elem(&stack_depth, &tid, &depth, BPF_ANY); return 0; } SEC("uretprobe/trace") int BPF_KRETPROBE(uretprobe) { struct profile_record *r; - pid_t pid, tid, cpu_id; - u64 id, end_ts = bpf_ktime_get_ns(); - u64 *start_ts; - s32 ustack_sz; + pid_t tid, cpu_id; + __u64 *start_ts_ptr; + __u64 end_ts = bpf_ktime_get_ns(); + __u32 *depth_ptr; - id = bpf_get_current_pid_tgid(); + current_pid = tid = (__u32)bpf_get_current_pid_tgid(); cpu_id = bpf_get_smp_processor_id(); - pid = id >> 32; - tid = (u32)id; + + depth_ptr = bpf_map_lookup_elem(&stack_depth, &tid); + if (!depth_ptr) return 0; r = bpf_ringbuf_reserve(&records, sizeof(*r), 0); if (!r) return 0; + + --global_sz; + r->tid = tid; r->cpu_id = cpu_id; - r->ustack_sz = bpf_get_stack(ctx, r->ustack, sizeof(r->ustack), BPF_F_USER_STACK) / - sizeof(sizeof(r->ustack[0])); - ustack_sz = r->ustack_sz; - start_ts = bpf_map_lookup_elem(&function_start, &ustack_sz); - if (start_ts) r->duration_ns = end_ts - *start_ts; - bpf_map_delete_elem(&function_start, &ustack_sz); + r->timestamp = 0; + start_ts_ptr = bpf_map_lookup_elem(&function_start, &global_sz); + if (start_ts_ptr) r->duration_ns = end_ts - *start_ts_ptr; + bpf_get_stack(ctx, &r->ustack, sizeof(r->ustack), BPF_F_USER_STACK); + r->ustack_sz = *depth_ptr; + r->global_sz = global_sz; r->exit = 1; + bpf_ringbuf_submit(r, 0); + + bpf_map_delete_elem(&function_start, &global_sz); + --*depth_ptr; + bpf_map_update_elem(&stack_depth, &tid, depth_ptr, BPF_ANY); return 0; } \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index f6ec83e7e..f614dc776 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -170,6 +170,10 @@ bool symbolize(size_t addr) { } static int handle_event(void *ctx, void *data, size_t data_sz) { + static struct profile_record pending_r; + static int pending = 0; + static int status = -1; /**< 0: exec 1: exit */ + const struct profile_record *r = data; if (r->exit) { @@ -177,58 +181,50 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { // for (int i = 0; i < r->ustack_sz; i++) LOG(" %llx", r->ustack[i]); // LOG(" %s\n", stack_func[r->ustack_sz]); // return 0; - if (status == 0 && r->ustack_sz == pre_ustack_sz) { - log_cpuid(r->cpu_id); + if (status == 0) { + log_cpuid(pending_r.cpu_id); log_split(); - log_tid(r->tid); + log_tid(pending_r.tid); log_split(); log_time(r->duration_ns); log_split(); - log_char(' ', 2 * r->ustack_sz - 2); - LOG("%s();\n", stack_func[r->ustack_sz]); - status = 1; - pre_ustack_sz = r->ustack_sz; - } else if (status == 1 && r->ustack_sz == pre_ustack_sz - 1) { + log_char(' ', 2 * pending_r.ustack_sz); + LOG("%s();\n", stack_func[pending_r.global_sz]); + } else { // status == 1 log_cpuid(r->cpu_id); log_split(); log_tid(r->tid); log_split(); log_time(r->duration_ns); log_split(); - log_char(' ', 2 * r->ustack_sz - 2); - LOG("} "); - log_color(TERM_GRAY); - LOG("/* %s */", stack_func[r->ustack_sz]); - log_color(TERM_NC); - LOG("\n"); - status = 1; - pre_ustack_sz = r->ustack_sz; + log_char(' ', 2 * r->ustack_sz); + LOG("} " TERM_GRAY "/* %s */" TERM_NC "\n", stack_func[r->global_sz]); } + pending = 0; + status = 1; } else { // LOG("EXEC"); // for (int i = 0; i < r->ustack_sz; i++) LOG(" %llx", r->ustack[i]); // if (symbolize(r->ustack[0])) { - // memcpy(stack_func[r->ustack_sz], buf, sizeof(buf)); + // memcpy(stack_func[r->ustack_sz], buf, sizeof(buf)); // } // LOG(" %s\n", stack_func[r->ustack_sz]); // return 0; - if (status == -1 && r->ustack_sz != 1) return 0; - if (status == 0 && r->ustack_sz != pre_ustack_sz + 1) return 0; - if (status == 1 && r->ustack_sz != pre_ustack_sz) return 0; if (status == 0) { - log_cpuid(r->cpu_id); + log_cpuid(pending_r.cpu_id); log_split(); - log_tid(r->tid); + log_tid(pending_r.tid); log_split(); log_char(' ', 11); log_split(); - log_char(' ', 2 * r->ustack_sz - 4); - LOG("%s() {\n", stack_func[r->ustack_sz - 1]); + log_char(' ', 2 * pending_r.ustack_sz); + LOG("%s() {\n", stack_func[pending_r.global_sz]); } - if (symbolize(r->ustack[0])) { - memcpy(stack_func[r->ustack_sz], buf, sizeof(buf)); + if (symbolize(r->ustack)) { + memcpy(stack_func[r->global_sz], buf, sizeof(buf)); + pending_r = *r; + pending = 1; status = 0; - pre_ustack_sz = r->ustack_sz; } } return 0; diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.h b/eBPF_Supermarket/User_Function_Tracer/src/utrace.h index 2401407c6..77fce87d1 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.h @@ -19,20 +19,23 @@ #ifndef UTRACE_UTRACE_H #define UTRACE_UTRACE_H +#define MAX_THREAD_NUM 32 #define MAX_STACK_DEPTH 128 #define MAX_MANGLED_LEN 128 #define MAX_SYMBOL_LEN 1024 #define MAX_PATH_LEN 256 -typedef unsigned long long stack_trace_t[MAX_STACK_DEPTH]; +typedef unsigned long long stack_trace_t; /** * @brief 内核态传给用户态的数据 */ struct profile_record { - unsigned int tid; /**< 线程编号 */ - unsigned int cpu_id; /**< CPU编号 */ + unsigned int tid; /**< 线程编号 */ + unsigned int next_tid; /**< 切换后的线程编号 */ + unsigned int cpu_id; /**< CPU编号 */ + unsigned long long timestamp; /**< 时间戳 */ unsigned long long duration_ns; /**< 函数时延 */ unsigned int kstack_sz; /**< 内核栈大小 */ @@ -41,6 +44,8 @@ struct profile_record { unsigned int ustack_sz; /**< 用户栈大小 */ stack_trace_t ustack; /**< 用户栈 */ + unsigned int global_sz; /**< 当前函数深度(考虑了多线程) */ + int exit; /**< 是否为函数退出时 */ }; From 584bcaf25377793fc722ff0abb22c77dd35e41c8 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Sat, 12 Aug 2023 23:07:30 +0800 Subject: [PATCH 13/17] [feat] check root permission and modify fd limit --- .../User_Function_Tracer/src/utrace.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index f614dc776..664de8a79 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -240,6 +240,11 @@ int main(int argc, char **argv) { parse_args(argc, argv, &arg); + if (geteuid() != 0) { + ERROR("Failed to run %s: permission denied\n", argv[0]); + return 1; + } + /* Set up libbpf errors and debug info callback */ libbpf_set_print(libbpf_print_fn); @@ -280,6 +285,19 @@ int main(int argc, char **argv) { if (sym->addr >= BASE_ADDR) sym->addr -= BASE_ADDR; } + if (getrlimit(RLIMIT_NOFILE, &old_rlim) == -1) { + ERROR("getrlimit error"); + exit(1); + } + struct rlimit rlim = { + .rlim_cur = 1048576, + .rlim_max = 1048576, + }; + if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) { + ERROR("setrlimit error"); + exit(1); + } + if (arg.pid) { size_t pre_addr = 0; for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; @@ -434,5 +452,10 @@ int main(int argc, char **argv) { free(program); + if (setrlimit(RLIMIT_NOFILE, &old_rlim) == -1) { + ERROR("setrlimit error"); + exit(1); + } + return err < 0 ? -err : 0; } \ No newline at end of file From 655a715dec6fdd583e9c42b9f866a10e5dcccbd1 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Sat, 12 Aug 2023 23:15:04 +0800 Subject: [PATCH 14/17] [bug] call ptrace_detach after diabling the breakpoint --- .../User_Function_Tracer/src/gdb.c | 31 +++++++++++-------- .../User_Function_Tracer/src/gdb.h | 30 +++++++++--------- .../User_Function_Tracer/src/utrace.c | 16 +++++----- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/src/gdb.c b/eBPF_Supermarket/User_Function_Tracer/src/gdb.c index e486f3abb..a256577f2 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/gdb.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/gdb.c @@ -22,29 +22,34 @@ #include #include -struct gdb* new_gdb() { - return (struct gdb*)malloc(sizeof(struct gdb)); +struct gdb* new_gdb(pid_t pid) { + struct gdb* gdb = (struct gdb*)malloc(sizeof(struct gdb)); + gdb->pid = pid; + return gdb; } -void enable_breakpoint(struct gdb* gdb, pid_t pid, uint64_t addr) { - long data = ptrace(PTRACE_PEEKDATA, pid, addr, NULL); +void enable_breakpoint(struct gdb* gdb, uint64_t addr) { + long data = ptrace(PTRACE_PEEKDATA, gdb->pid, addr, NULL); gdb->inst = (uint8_t)data & 0xFF; uint64_t int3 = 0xCC; - ptrace(PTRACE_POKEDATA, pid, addr, (data & ~0xFF) | int3); + ptrace(PTRACE_POKEDATA, gdb->pid, addr, (data & ~0xFF) | int3); } -void disable_breakpoint(struct gdb* gdb, pid_t pid, uint64_t addr) { - long data = ptrace(PTRACE_PEEKDATA, pid, addr, NULL); - ptrace(PTRACE_POKEDATA, pid, (data & ~0xFF) | gdb->inst); +void disable_breakpoint(struct gdb* gdb, uint64_t addr) { + long data = ptrace(PTRACE_PEEKDATA, gdb->pid, addr, NULL); + ptrace(PTRACE_POKEDATA, gdb->pid, (data & ~0xFF) | gdb->inst); } -void continue_execution(pid_t pid) { ptrace(PTRACE_CONT, pid, NULL, NULL); } +long continue_execution(struct gdb* gdb) { return ptrace(PTRACE_CONT, gdb->pid, NULL, NULL); } -void delete_gdb(struct gdb* gdb) { free(gdb); } - -void wait_for_signal(pid_t pid) { +long wait_for_signal(struct gdb* gdb) { int wstatus; int options = 0; - waitpid(pid, &wstatus, options); + return waitpid(gdb->pid, &wstatus, options); } + +void delete_gdb(struct gdb* gdb) { + ptrace(PTRACE_DETACH, gdb->pid, NULL, NULL); + free(gdb); +} \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/gdb.h b/eBPF_Supermarket/User_Function_Tracer/src/gdb.h index fb9e9bc90..7c1de535a 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/gdb.h +++ b/eBPF_Supermarket/User_Function_Tracer/src/gdb.h @@ -26,49 +26,49 @@ * @brief 记录跨函数传递的信息 */ struct gdb { - uint8_t inst; /*< 被int3覆盖的单字节指令 */ + pid_t pid; /**< gdb附加到的进程的编号 */ + uint8_t inst; /**< 被int3覆盖的单字节指令 */ }; /* * @brief 创建一个gdb结构体 + * @param[in] pid 进程号 * @return 指向gdb结构体的指针 * @note 从堆中申请空间 */ -struct gdb* new_gdb(); +struct gdb* new_gdb(pid_t pid); /* * @brief 设置一个断点 * @param[in] gdb 指向一个gdb结构体 - * @param[in] pid 进程号 * @param[in] addr 物理地址 */ -void enable_breakpoint(struct gdb* gdb, pid_t pid, uint64_t addr); +void enable_breakpoint(struct gdb* gdb, uint64_t addr); /* * @brief 取消一个断点 * @param[in] gdb 指向一个gdb结构体 - * @param[in] pid 进程号 * @param[in] addr 物理地址 * @note 需要保证之前调用过enable_breakpoint(gdb, pid, addr) */ -void disable_breakpoint(struct gdb* gdb, pid_t pid, uint64_t addr); +void disable_breakpoint(struct gdb* gdb, uint64_t addr); /* * @brief 继续执行 - * @param[in] pid 进程号 + * @param[in] gdb 指向一个gdb结构体 */ -void continue_execution(pid_t pid); +long continue_execution(struct gdb* gdb); /* - * @brief 释放gdb结构体的空间 - * @param[in] gdb 指向要释放的gdb结构体 + * @brief 等待进程收到信号 + * @param[in] gdb 指向一个gdb结构体 */ -void delete_gdb(struct gdb* gdb); +long wait_for_signal(struct gdb* gdb); /* - * @brief 等待进程收到信号 - * @param[in] pid 进程号 + * @brief 取消ptrace并释放gdb结构体的空间 + * @param[in] gdb 指向要释放的gdb结构体 */ -void wait_for_signal(pid_t pid); +void delete_gdb(struct gdb* gdb); -#endif // UTRACE_GDB_H +#endif // UTRACE_GDB_H \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index 664de8a79..60c63d085 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -234,6 +235,7 @@ int main(int argc, char **argv) { struct ring_buffer *records = NULL; struct utrace_bpf *skel; struct args arg; + struct rlimit old_rlim; pid_t pid; char *program; int err; @@ -357,15 +359,15 @@ int main(int argc, char **argv) { ERROR("Execv %s error\n", program); exit(1); } else { - struct gdb *gdb = new_gdb(); - wait_for_signal(pid); + struct gdb *gdb = new_gdb(pid); + wait_for_signal(gdb); break_addr += get_base_addr(pid); DEBUG("break address: %zx\n", break_addr); - enable_breakpoint(gdb, pid, break_addr); - continue_execution(pid); - wait_for_signal(pid); + enable_breakpoint(gdb, break_addr); + continue_execution(gdb); + wait_for_signal(gdb); size_t pre_addr = 0; for (struct symbol *sym = symtab->head->sym; sym != symtab->head->sym + symtab->head->size; @@ -407,8 +409,8 @@ int main(int argc, char **argv) { /* Attach tracepoints */ assert(utrace_bpf__attach(skel) == 0); - disable_breakpoint(gdb, pid, break_addr); - continue_execution(pid); + disable_breakpoint(gdb, break_addr); + delete_gdb(gdb); } } From 9dd6a756785f60e1723d0d8ad893955f6b038804 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Sun, 13 Aug 2023 00:18:13 +0800 Subject: [PATCH 15/17] [bug] fix log_color --- eBPF_Supermarket/User_Function_Tracer/.clang-format | 12 ++++++------ eBPF_Supermarket/User_Function_Tracer/src/log.c | 2 +- eBPF_Supermarket/User_Function_Tracer/src/utrace.c | 5 ++++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/eBPF_Supermarket/User_Function_Tracer/.clang-format b/eBPF_Supermarket/User_Function_Tracer/.clang-format index d54fdc095..5af6aa680 100644 --- a/eBPF_Supermarket/User_Function_Tracer/.clang-format +++ b/eBPF_Supermarket/User_Function_Tracer/.clang-format @@ -10,9 +10,9 @@ IncludeCategories: Priority: 0 - Regex: '' Priority: -1 - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - - Regex: '^(<|"(gtest|isl|json)/)' - Priority: 2 - - Regex: '.\*' - Priority: 1 \ No newline at end of file + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|isl|json)/)' + Priority: 2 + - Regex: '.\*' + Priority: 1 \ No newline at end of file diff --git a/eBPF_Supermarket/User_Function_Tracer/src/log.c b/eBPF_Supermarket/User_Function_Tracer/src/log.c index 46b1cc877..8d28babd7 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/log.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/log.c @@ -26,7 +26,7 @@ int debug; void log_color(const char* color) { char* term = getenv("TERM"); - if (isatty(fileno(stdout)) && !(term && !strcmp(term, "dumb"))) { + if (isatty(fileno(stderr)) && !(term && !strcmp(term, "dumb"))) { LOG("%s", color); } } diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index 60c63d085..51cdb1b9e 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -199,7 +199,10 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { log_time(r->duration_ns); log_split(); log_char(' ', 2 * r->ustack_sz); - LOG("} " TERM_GRAY "/* %s */" TERM_NC "\n", stack_func[r->global_sz]); + LOG("} "); + log_color(TERM_GRAY); + LOG("/* %s */\n", stack_func[r->global_sz]); + log_color(TERM_NC); } pending = 0; status = 1; From fbfff20c6ea0aa488cd5b9f2a6b857e2dc4a6d29 Mon Sep 17 00:00:00 2001 From: jyf111 Date: Tue, 15 Aug 2023 16:59:56 +0800 Subject: [PATCH 16/17] [bug] fix arg parser and update README --- .../User_Function_Tracer/README.md | 17 +++++++++++------ .../User_Function_Tracer/src/demangle.c | 5 +++-- .../User_Function_Tracer/src/utrace.c | 11 +++++------ .../User_Function_Tracer/test/mmap | Bin 0 -> 16896 bytes .../User_Function_Tracer/test/mmap.c | 11 +++++------ .../User_Function_Tracer/test/short.c | 2 +- 6 files changed, 25 insertions(+), 21 deletions(-) create mode 100755 eBPF_Supermarket/User_Function_Tracer/test/mmap diff --git a/eBPF_Supermarket/User_Function_Tracer/README.md b/eBPF_Supermarket/User_Function_Tracer/README.md index aa095c62c..72e471624 100644 --- a/eBPF_Supermarket/User_Function_Tracer/README.md +++ b/eBPF_Supermarket/User_Function_Tracer/README.md @@ -26,15 +26,20 @@ Options: -h --help: disaply this usage information. Examples: - build/utrace -c "$PROGRAM $ARGS" - build/utrace -p $PID + sudo build/utrace -c "$PROGRAM $ARGS" + sudo build/utrace -p $PID ``` ### 特点 +- 观测用户态函数调用流程以及调用时延 +- 非侵入式,不依赖任何编译选项 +- 支持多线程程序、已经运行的程序(输入进程PID号) + 不同于`ftrace`,`eBPF-utrace`用于观测用户态函数。 -+ 不同于`uftrace`,`eBPF-utrace`基于eBPF,不依赖于任何编译技术,但是需要内核的支持,需要root权限,且可能有更高的开销。 -+ 不同于`perf`, `gprof`等性能分析工具,`eBPF-utrace`输出准确的函数调用时延,而不是基于perf_event()的采样方式。 ++ 不同于`uftrace`,`eBPF-utrace`基于eBPF,不依赖于任何编译技术,但是需要内核的支持,需要root权限。 ++ 不同于`perf`, `gprof`等性能分析工具,`eBPF-utrace`输出准确的函数调用时延,而不是基于perf_event的采样方式。 ### TODO -- simplify c++ symbols -- more tests +- IFUNC符号的观测 +- 嵌套的共享库观测 +- 简化C++符号的展示 +- 更多的测试 diff --git a/eBPF_Supermarket/User_Function_Tracer/src/demangle.c b/eBPF_Supermarket/User_Function_Tracer/src/demangle.c index fd8ec6488..107ca5b48 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/demangle.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/demangle.c @@ -31,8 +31,9 @@ char *demangle(const char *mangled_name) { if (strncmp(mangled_name, "_Z", 2) == 0) { __cxa_demangle(mangled_name, NULL, &len, &status); - if (status < 0) return strdup(mangled_name); - + if (status < 0) { + return strdup(mangled_name); + } original_name = malloc(len); __cxa_demangle(mangled_name, original_name, &len, &status); diff --git a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c index 51cdb1b9e..0ad40b892 100644 --- a/eBPF_Supermarket/User_Function_Tracer/src/utrace.c +++ b/eBPF_Supermarket/User_Function_Tracer/src/utrace.c @@ -67,8 +67,8 @@ void print_usage(char *program) { LOG(" -h --help: disaply this usage information.\n"); LOG("\n"); LOG("Examples:\n"); - LOG(" %s -c \"$PROGRAM $ARGS\"\n", program); - LOG(" %s -p $PID\n", program); + LOG(" sudo %s -c \"$PROGRAM $ARGS\"\n", program); + LOG(" sudo %s -p $PID\n", program); } void parse_args(int argc, char *argv[], struct args *arg) { @@ -120,8 +120,7 @@ void parse_args(int argc, char *argv[], struct args *arg) { exit(1); } } - - if (!c) { + if (!c && !arg->pid) { print_usage(argv[0]); exit(1); } @@ -295,8 +294,8 @@ int main(int argc, char **argv) { exit(1); } struct rlimit rlim = { - .rlim_cur = 1048576, - .rlim_max = 1048576, + .rlim_cur = 1 << 20, + .rlim_max = 1 << 20, }; if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) { ERROR("setrlimit error"); diff --git a/eBPF_Supermarket/User_Function_Tracer/test/mmap b/eBPF_Supermarket/User_Function_Tracer/test/mmap new file mode 100755 index 0000000000000000000000000000000000000000..e71531007ce9516ff505e42845d4d02dee9041bc GIT binary patch literal 16896 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 +#include #include #include #include @@ -13,14 +14,12 @@ int foo(long sz) { munmap(ptr, sz); close(fd); + printf("Finish mmap.\n"); + return 0; } -int main(int argc, char *argv[]) { - sleep(2); - - int n = 4096; - - foo(n); +int main() { + foo(4096); return 0; } diff --git a/eBPF_Supermarket/User_Function_Tracer/test/short.c b/eBPF_Supermarket/User_Function_Tracer/test/short.c index 3308f521b..7ec36c1aa 100644 --- a/eBPF_Supermarket/User_Function_Tracer/test/short.c +++ b/eBPF_Supermarket/User_Function_Tracer/test/short.c @@ -1,6 +1,6 @@ #include -void h() { printf("h!"); } +void h() {} void g() { h(); } void f() { g(); } From fa867ea8ccf8124b37c2ccb5a467bd71bffaf05f Mon Sep 17 00:00:00 2001 From: jyf111 Date: Thu, 17 Aug 2023 23:57:48 +0800 Subject: [PATCH 17/17] update test --- .github/workflows/user_function_tracer.yml | 4 ++ .../User_Function_Tracer/test/args.c | 68 ------------------ .../User_Function_Tracer/test/fib.c | 26 +++++-- .../User_Function_Tracer/test/mmap | Bin 16896 -> 0 bytes .../User_Function_Tracer/test/mmap.c | 18 +++++ .../User_Function_Tracer/test/short.c | 10 --- .../User_Function_Tracer/test/sleep.c | 19 ++++- .../User_Function_Tracer/test/strcpy.c | 18 +++++ .../User_Function_Tracer/test/test.c | 6 -- .../User_Function_Tracer/test/thread.c | 41 +++++++++++ 10 files changed, 118 insertions(+), 92 deletions(-) delete mode 100644 eBPF_Supermarket/User_Function_Tracer/test/args.c delete mode 100755 eBPF_Supermarket/User_Function_Tracer/test/mmap delete mode 100644 eBPF_Supermarket/User_Function_Tracer/test/short.c delete mode 100644 eBPF_Supermarket/User_Function_Tracer/test/test.c create mode 100644 eBPF_Supermarket/User_Function_Tracer/test/thread.c diff --git a/.github/workflows/user_function_tracer.yml b/.github/workflows/user_function_tracer.yml index f658b8461..f4a998425 100644 --- a/.github/workflows/user_function_tracer.yml +++ b/.github/workflows/user_function_tracer.yml @@ -36,6 +36,10 @@ jobs: gcc test/sleep.c -o test/sleep gcc test/mmap.c -o test/mmap gcc test/strcpy.c -o test/strcpy + gcc test/fib.c -o test/fib + gcc test/thread.c -o test/thread sudo build/utrace -c test/sleep sudo build/utrace -c test/mmap sudo build/utrace -c test/strcpy + sudo build/utrace -c test/fib + sudo build/utrace -c test/thread diff --git a/eBPF_Supermarket/User_Function_Tracer/test/args.c b/eBPF_Supermarket/User_Function_Tracer/test/args.c deleted file mode 100644 index b91582ef9..000000000 --- a/eBPF_Supermarket/User_Function_Tracer/test/args.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include - -void foobar() {} - -void foo() {} - -void bar() { - foobar(); - foobar(); -} - -void tf1() {} - -void tf2() {} - -void arg_int3(int x, int y, int z) { - /* - printf("&x: %p\n", &x); - printf("&y: %p\n", &y); - printf("&z: %p\n", &z); - */ -} -void arg_int2(int a, int b) { arg_int3(a, b, b + 1); } -void arg_int1(int i) { arg_int2(i, i + 1); } - -void arg_uint3(unsigned int x, unsigned int y, unsigned int z) {} -void arg_uint2(unsigned int a, unsigned int b) { arg_uint3(a, b, b + 1); } -void arg_uint1(unsigned int i) { arg_uint2(i, i + 1); } - -void arg_char3(char x, char y, char z) {} -void arg_char2(char a, char b) { arg_char3(a, b, b + 1); } -void arg_char1(char i) { arg_char2(i, i + 1); } - -void arg_short3(short x, short y, short z) {} -void arg_short2(short a, short b) { arg_short3(a, b, b + 1); } -void arg_short1(short i) { arg_short2(i, i + 1); } - -void arg_long3(long x, long y, long z) {} -void arg_long2(long a, long b) { arg_long3(a, b, b + 1); } -void arg_long1(long i) { arg_long2(i, i + 1); } -void arg_ulong3(unsigned long x, unsigned long y, unsigned long z) {} -void arg_ulong2(unsigned long a, unsigned long b) { arg_ulong3(a, b, b + 1); } -void arg_ulong1(long i) { arg_ulong2(i, i + 1); } - -void arg_longlong3(long long x, long long y, long long z) {} -void arg_longlong2(long long a, long long b) { arg_longlong3(a, b, b + 1); } -void arg_longlong1(long long i) { arg_longlong2(i, i + 1); } -void arg_ulonglong3(unsigned long long x, unsigned long long y, unsigned long long z) {} -void arg_ulonglong2(unsigned long long a, unsigned long long b) { arg_ulonglong3(a, b, b + 1); } -void arg_ulonglong1(unsigned long long i) { arg_ulonglong2(i, i + 1); } - -void arg_test(int x, char *z) {} - -int main(int argc, char *argv[]) { - sleep(2); - arg_int1(10); - arg_uint1(10); - arg_char1(20); - arg_short1(30); - arg_long1(40); - arg_ulong1(50); - arg_longlong1(60); - arg_ulonglong1(70); - arg_test(100, NULL); - return 0; -} diff --git a/eBPF_Supermarket/User_Function_Tracer/test/fib.c b/eBPF_Supermarket/User_Function_Tracer/test/fib.c index b610a5c01..a3d112d9b 100644 --- a/eBPF_Supermarket/User_Function_Tracer/test/fib.c +++ b/eBPF_Supermarket/User_Function_Tracer/test/fib.c @@ -1,6 +1,20 @@ -#include -#include -#include +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: jinyufeng2000@gmail.com +// +// 测试递归函数调用 int fib(int n) { if (n <= 2) return 1; @@ -8,8 +22,6 @@ int fib(int n) { } int main() { - sleep(2); - int n = 8; - - return !!fib(n); + fib(9); + return 0; } diff --git a/eBPF_Supermarket/User_Function_Tracer/test/mmap b/eBPF_Supermarket/User_Function_Tracer/test/mmap deleted file mode 100755 index e71531007ce9516ff505e42845d4d02dee9041bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16896 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 #include #include diff --git a/eBPF_Supermarket/User_Function_Tracer/test/short.c b/eBPF_Supermarket/User_Function_Tracer/test/short.c deleted file mode 100644 index 7ec36c1aa..000000000 --- a/eBPF_Supermarket/User_Function_Tracer/test/short.c +++ /dev/null @@ -1,10 +0,0 @@ -#include - -void h() {} -void g() { h(); } -void f() { g(); } - -int main() { - f(); - return 0; -} diff --git a/eBPF_Supermarket/User_Function_Tracer/test/sleep.c b/eBPF_Supermarket/User_Function_Tracer/test/sleep.c index 761a3e1ad..53ed5583b 100644 --- a/eBPF_Supermarket/User_Function_Tracer/test/sleep.c +++ b/eBPF_Supermarket/User_Function_Tracer/test/sleep.c @@ -1,4 +1,21 @@ -#include +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: jinyufeng2000@gmail.com +// +// 测试函数时延统计 + #include void g() { sleep(2); } diff --git a/eBPF_Supermarket/User_Function_Tracer/test/strcpy.c b/eBPF_Supermarket/User_Function_Tracer/test/strcpy.c index eefccaded..0552347a2 100644 --- a/eBPF_Supermarket/User_Function_Tracer/test/strcpy.c +++ b/eBPF_Supermarket/User_Function_Tracer/test/strcpy.c @@ -1,3 +1,21 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: jinyufeng2000@gmail.com +// +// 测试库函数调用,涉及IFUNC符号 + #include #include int main() { diff --git a/eBPF_Supermarket/User_Function_Tracer/test/test.c b/eBPF_Supermarket/User_Function_Tracer/test/test.c deleted file mode 100644 index f07b4e027..000000000 --- a/eBPF_Supermarket/User_Function_Tracer/test/test.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - sleep(2); - return 0; -} diff --git a/eBPF_Supermarket/User_Function_Tracer/test/thread.c b/eBPF_Supermarket/User_Function_Tracer/test/thread.c new file mode 100644 index 000000000..1ee2c463d --- /dev/null +++ b/eBPF_Supermarket/User_Function_Tracer/test/thread.c @@ -0,0 +1,41 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: jinyufeng2000@gmail.com +// +// 测试多线程程序 + +#include +#include + +static void* c(void* n) { return n; } + +static void* b(void* n) { return c(n); } + +static void* a(void* n) { return b(n); } + +int main() { + int i; + void* v; + int n = 10; + pthread_t t[4]; + + for (i = 0; i < 4; i++) pthread_create(&t[i], NULL, a, &n); + for (i = 0; i < 4; i++) { + pthread_join(t[i], &v); + } + + assert(*(int*)v == n); + return 0; +}