From 1bc3ea672fe37888d753b3d32b6010b606d83699 Mon Sep 17 00:00:00 2001 From: syxl-time <953879556@qq.com> Date: Fri, 7 Jun 2024 18:31:41 +0800 Subject: [PATCH 1/3] =?UTF-8?q?mem=5Fwatcher:=E6=89=93=E5=8D=B0=E5=86=85?= =?UTF-8?q?=E5=AD=98=E5=88=86=E9=85=8D=E5=9C=B0=E5=9D=80=E5=92=8C=E5=88=86?= =?UTF-8?q?=E9=85=8D=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mem_watcher/mem_watcher.c | 657 +++++++++--------- .../mem_watcher/memleak.bpf.c | 22 + 2 files changed, 368 insertions(+), 311 deletions(-) diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c index 5156eb2b1..d2630075f 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c @@ -47,6 +47,7 @@ static size_t g_stacks_size = 0; static struct blaze_symbolizer *symbolizer; static int attach_pid; +pid_t own_pid; static char binary_path[128] = { 0 }; struct allocation { @@ -57,6 +58,8 @@ struct allocation { static struct allocation *allocs; +static volatile bool exiting = false; + #define __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe) \ do { \ LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts, \ @@ -90,6 +93,48 @@ static struct allocation *allocs; #define ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name) __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, false) #define ATTACH_URETPROBE_CHECKED(skel, sym_name, prog_name) __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, true) +#define PROCESS_SKEL(skel, func) \ + skel = func##_bpf__open(); \ + if (!skel) { \ + fprintf(stderr, "Failed to open and load BPF skeleton\n"); \ + return 1; \ + } \ + process_##func(skel) + +#define POLL_RING_BUFFER(rb, timeout, err) \ + while (!exiting) { \ + err = ring_buffer__poll(rb, timeout); \ + if (err == -EINTR) { \ + err = 0; \ + break; \ + } \ + if (err < 0) { \ + printf("Error polling perf buffer: %d\n", err); \ + break; \ + } \ + } + +#define LOAD_AND_ATTACH_SKELETON(skel, event) \ + do { \ + skel->bss->user_pid = own_pid; \ + err = event##_bpf__load(skel); \ + if (err) { \ + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + err = event##_bpf__attach(skel); \ + if (err) { \ + fprintf(stderr, "Failed to attach BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event_##event, NULL, NULL); \ + if (!rb) { \ + fprintf(stderr, "Failed to create ring buffer\n"); \ + goto event##_cleanup; \ + } \ + } while(0) static struct env { int time; @@ -99,6 +144,7 @@ static struct env { bool sysstat; bool memleak; bool kernel_trace; + bool print_time; bool part2; @@ -112,6 +158,7 @@ static struct env { .sysstat = false, .memleak = false, .kernel_trace = true, + .print_time = false, .rss = false, .part2 = false, .choose_pid = 0, @@ -141,50 +188,33 @@ static const struct argp_option opts[] = { {0, 0, 0, 0, "memleak:", 8}, {"memleak", 'l', 0, 0, "print memleak (内核态内存泄漏检测)", 8}, {"choose_pid", 'P', "PID", 0, "选择进程号打印, print memleak (用户态内存泄漏检测)", 9}, + {"print_time", 'm', 0, 0, "打印申请地址时间 (用户态)", 10}, + - {"time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)", 10}, + {"time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)", 11}, {NULL, 'h', NULL, OPTION_HIDDEN, "show the full help"}, {0}, }; static error_t parse_arg(int key, char *arg, struct argp_state *state) { - switch (key) { - case 't': - env.time = strtol(arg, NULL, 10); - if (env.time) - alarm(env.time); - break; - case 'a': - env.paf = true; - break; - case 'p': - env.pr = true; - break; - case 'r': - env.procstat = true; - break; - case 's': - env.sysstat = true; - break; - case 'n': - env.part2 = true; - break; - case 'h': - argp_state_help(state, stderr, ARGP_HELP_STD_HELP); - break; - case 'P': - env.choose_pid = strtol(arg, NULL, 10); - break; - case 'R': - env.rss = true; - break; - case 'l': - env.memleak = true; - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; + switch (key) { + case 't': + env.time = strtol(arg, NULL, 10); + if (env.time) alarm(env.time); + break; + case 'a': env.paf = true; break; + case 'p': env.pr = true; break; + case 'r': env.procstat = true; break; + case 's': env.sysstat = true; break; + case 'n': env.part2 = true; break; + case 'P': env.choose_pid = strtol(arg, NULL, 10); break; + case 'R': env.rss = true; break; + case 'l': env.memleak = true; break; + case 'm': env.print_time = true; break; + case 'h': argp_state_help(state, stderr, ARGP_HELP_STD_HELP); break; + default: return ARGP_ERR_UNKNOWN; + } + return 0; } static const struct argp argp = { @@ -193,6 +223,83 @@ static const struct argp argp = { .doc = argp_program_doc, }; +// Function prototypes +static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args); +static void sig_handler(int sig); +static void setup_signals(void); +static void disable_kernel_tracepoints(struct memleak_bpf *skel); +static void print_frame(const char *name, uintptr_t input_addr, uintptr_t addr, uint64_t offset, const blaze_symbolize_code_info *code_info); +static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid); +static int print_outstanding_allocs(struct memleak_bpf *skel); +static int print_outstanding_combined_allocs(struct memleak_bpf *skel, pid_t pid); +static int handle_event_paf(void *ctx, void *data, size_t data_sz); +static int handle_event_pr(void *ctx, void *data, size_t data_sz); +static int handle_event_procstat(void *ctx, void *data, size_t data_sz); +static int handle_event_sysstat(void *ctx, void *data, size_t data_sz); +static int attach_uprobes(struct memleak_bpf *skel); +static int process_paf(struct paf_bpf *skel_paf); +static int process_pr(struct pr_bpf *skel_pr); +static int process_procstat(struct procstat_bpf *skel_procstat); +static int process_sysstat(struct sysstat_bpf *skel_sysstat); +static int process_memleak(struct memleak_bpf *skel_memleak, struct env); +static __u64 adjust_time_to_program_start_time(__u64 first_query_time); +static int update_addr_times(struct memleak_bpf *skel_memleak); +static int print_time(struct memleak_bpf *skel_memleak); + +// Main function +int main(int argc, char **argv) { + int err; + struct paf_bpf *skel_paf; + struct pr_bpf *skel_pr; + struct procstat_bpf *skel_procstat; + struct sysstat_bpf *skel_sysstat; + struct memleak_bpf *skel_memleak; + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (err) + return err; + + own_pid = getpid(); + libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + libbpf_set_print(libbpf_print_fn); + + setup_signals(); + + if (env.paf) { + PROCESS_SKEL(skel_paf, paf); + } else if (env.pr) { + PROCESS_SKEL(skel_pr, pr); + } else if (env.procstat) { + PROCESS_SKEL(skel_procstat, procstat); + } else if (env.sysstat) { + PROCESS_SKEL(skel_sysstat, sysstat); + } else if (env.memleak) { + if (env.choose_pid != 0) { + printf("用户态内存泄漏\n"); + env.kernel_trace = false; + attach_pid = env.choose_pid; + } + else + attach_pid = 0; + + strcpy(binary_path, "/lib/x86_64-linux-gnu/libc.so.6"); + + allocs = calloc(ALLOCS_MAX_ENTRIES, sizeof(*allocs)); + + /* Set up libbpf errors and debug info callback */ + libbpf_set_print(libbpf_print_fn); + + /* Load and verify BPF application */ + skel_memleak = memleak_bpf__open(); + if (!skel_memleak) { + fprintf(stderr, "Failed to open BPF skeleton\n"); + return 1; + } + process_memleak(skel_memleak, env); + } + return 0; +} + int alloc_size_compare(const void *a, const void *b) { const struct allocation *x = (struct allocation *)a; @@ -422,6 +529,91 @@ int print_outstanding_combined_allocs(struct memleak_bpf *skel, pid_t pid) { return 0; } +// 在更新时间之前获取当前时间并调整为相对于程序启动时的时间 +static __u64 adjust_time_to_program_start_time(__u64 first_query_time) { + struct timespec current_time; + clock_gettime(CLOCK_MONOTONIC, ¤t_time); + //printf("current_time: %ld\n", current_time.tv_sec); + __u64 adjusted_time; + adjusted_time = current_time.tv_sec - first_query_time; + + //printf("adjusted_time: %lld\n", adjusted_time); + return adjusted_time; +} + + +// 在更新时间时,先将时间调整为相对于程序启动的时间 +static int update_addr_times(struct memleak_bpf *skel) { + const size_t addr_times_key_size = bpf_map__key_size(skel->maps.addr_times); + const size_t first_time_key_size = bpf_map__key_size(skel->maps.first_time); + for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) { + if (bpf_map__get_next_key(skel->maps.addr_times, &prev_key, &curr_key, addr_times_key_size)) { + if (errno == ENOENT) { + break; // no more keys, done! + } + + perror("map get next key failed!"); + return -errno; + } + + // Check if the address exists in the first_time map + __u64 first_query_time; + if (bpf_map__lookup_elem(skel->maps.first_time, &curr_key, first_time_key_size, &first_query_time, sizeof(first_query_time), 0)) { + // Address doesn't exist in the first_time map, add it with the current time + struct timespec first_time_alloc; + clock_gettime(CLOCK_MONOTONIC, &first_time_alloc); + if (bpf_map__update_elem(skel->maps.first_time, &curr_key, first_time_key_size, &first_time_alloc.tv_sec, sizeof(first_time_alloc.tv_sec), 0)) { + perror("map update failed!"); + return -errno; + } + } + else { + // Address exists in the first_time map + // This is the first time updating timestamp + __u64 adjusted_time = adjust_time_to_program_start_time(first_query_time); + //printf("update_addr_times adjusted_time: %lld\n", adjusted_time); + + // Save the adjusted time to addr_times map + __u64 timestamp = adjusted_time; + + // write the updated timestamp back to the map + if (bpf_map__update_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0)) { + perror("map update failed!"); + return -errno; + } + } + } + return 0; +} + +// 在打印时间时,先将时间调整为相对于程序启动的时间 +static int print_time(struct memleak_bpf *skel) { + const size_t addr_times_key_size = bpf_map__key_size(skel->maps.addr_times); + + // Iterate over the addr_times map to print address and time + for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) { + if (bpf_map__get_next_key(skel->maps.addr_times, &prev_key, &curr_key, addr_times_key_size)) { + if (errno == ENOENT) { + break; // no more keys, done! + } + perror("map get next key failed!"); + return -errno; + } + + // Read the timestamp for the current address + __u64 timestamp; + if (bpf_map__lookup_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0) == 0) { + printf("Address: 0x%llx, Time: %llds\n", curr_key, timestamp); + } + else { + perror("map lookup failed!"); + return -errno; + } + } + printf("------------------------------------------------------\n"); + return 0; +} + void disable_kernel_tracepoints(struct memleak_bpf *skel) { bpf_program__set_autoload(skel->progs.memleak__kmalloc, false); bpf_program__set_autoload(skel->progs.memleak__kmalloc_node, false); @@ -437,13 +629,17 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va return vfprintf(stderr, format, args); } -static volatile bool exiting = false; - static void sig_handler(int sig) { exiting = true; exit(EXIT_SUCCESS); } +static void setup_signals(void) { + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + signal(SIGALRM, sig_handler); +} + /* static char* flags(int flag) { @@ -551,8 +747,6 @@ static int handle_event_sysstat(void *ctx, void *data, size_t data_sz) { return 0; } -pid_t own_pid; - int attach_uprobes(struct memleak_bpf *skel) { ATTACH_UPROBE_CHECKED(skel, malloc, malloc_enter); ATTACH_URETPROBE_CHECKED(skel, malloc, malloc_exit); @@ -593,315 +787,156 @@ int attach_uprobes(struct memleak_bpf *skel) { return 0; } -int main(int argc, char **argv) { - struct ring_buffer *rb = NULL; - struct paf_bpf *skel_paf; - struct pr_bpf *skel_pr; - struct procstat_bpf *skel_procstat; - struct sysstat_bpf *skel_sysstat; - struct memleak_bpf *skel; - - int err, i; - LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts); - - err = argp_parse(&argp, argc, argv, 0, NULL, NULL); - if (err) - return err; - own_pid = getpid(); - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - - /* Set up libbpf errors and debug info callback */ - libbpf_set_print(libbpf_print_fn); - - /* Cleaner handling of Ctrl-C */ - signal(SIGINT, sig_handler); - signal(SIGTERM, sig_handler); - signal(SIGALRM, sig_handler); - - if (env.paf) { - /* Load and verify BPF application */ - skel_paf = paf_bpf__open(); - if (!skel_paf) { - fprintf(stderr, "Failed to open and load BPF skeleton\n"); - return 1; - } +// Functions to process different BPF programs +static int process_paf(struct paf_bpf *skel_paf) { + int err; + struct ring_buffer *rb; - skel_paf->bss->user_pid = own_pid; + LOAD_AND_ATTACH_SKELETON(skel_paf, paf); - /* Load & verify BPF programs */ - err = paf_bpf__load(skel_paf); - if (err) { - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); - goto paf_cleanup; - } + printf("%-8s %-8s %-8s %-8s %-8s\n", "MIN", "LOW", "HIGH", "PRESENT", "FLAG"); - /* Attach tracepoints */ - err = paf_bpf__attach(skel_paf); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto paf_cleanup; - } + POLL_RING_BUFFER(rb, 1000, err); - /* Set up ring buffer polling */ - rb = ring_buffer__new(bpf_map__fd(skel_paf->maps.rb), handle_event_paf, NULL, NULL); - if (!rb) { - err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); - goto paf_cleanup; - } +paf_cleanup: + ring_buffer__free(rb); + paf_bpf__destroy(skel_paf); + return err; +} - /* Process events */ - printf("%-8s %-8s %-8s %-8s %-8s\n", "MIN", "LOW", "HIGH", "PRESENT", "FLAG"); - } - else if (env.pr) { - /* Load and verify BPF application */ - skel_pr = pr_bpf__open(); - if (!skel_pr) { - fprintf(stderr, "Failed to open and load BPF skeleton\n"); - return 1; - } +static int process_pr(struct pr_bpf *skel_pr) { + int err; + struct ring_buffer *rb; - skel_pr->bss->user_pid = own_pid; + LOAD_AND_ATTACH_SKELETON(skel_pr, pr); - /* Load & verify BPF programs */ - err = pr_bpf__load(skel_pr); - if (err) { - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); - goto pr_cleanup; - } + printf("%-8s %-8s %-8s %-8s %-8s\n", "RECLAIM", "RECLAIMED", "UNQUEUE", "CONGESTED", "WRITEBACK"); - /* Attach tracepoints */ - err = pr_bpf__attach(skel_pr); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto pr_cleanup; - } + POLL_RING_BUFFER(rb, 1000, err); - /* Set up ring buffer polling */ - rb = ring_buffer__new(bpf_map__fd(skel_pr->maps.rb), handle_event_pr, NULL, NULL); - if (!rb) { - err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); - goto pr_cleanup; - } +pr_cleanup: + ring_buffer__free(rb); + pr_bpf__destroy(skel_pr); + return err; +} - /* Process events */ - printf("%-8s %-8s %-8s %-8s %-8s\n", "RECLAIM", "RECLAIMED", "UNQUEUE", "CONGESTED", "WRITEBACK"); - } +static int process_procstat(struct procstat_bpf *skel_procstat) { + int err; + struct ring_buffer *rb; - else if (env.procstat) { - /* Load and verify BPF application */ - skel_procstat = procstat_bpf__open(); - if (!skel_procstat) { - fprintf(stderr, "Failed to open and load BPF skeleton\n"); - return 1; - } + LOAD_AND_ATTACH_SKELETON(skel_procstat, procstat); - skel_procstat->bss->user_pid = own_pid; + if (env.rss) { + printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "VMSIZE", "VMDATA", "VMSTK", "VMPTE", "VMSWAP"); + } else { + printf("%-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "SIZE", "RSSANON", "RSSFILE", "RSSSHMEM"); + } - /* Load & verify BPF programs */ - err = procstat_bpf__load(skel_procstat); - if (err) { - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); - goto procstat_cleanup; - } + POLL_RING_BUFFER(rb, 1000, err); - /* Attach tracepoints */ - err = procstat_bpf__attach(skel_procstat); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto procstat_cleanup; - } +procstat_cleanup: + ring_buffer__free(rb); + procstat_bpf__destroy(skel_procstat); + return err; +} - /* Set up ring buffer polling */ - rb = ring_buffer__new(bpf_map__fd(skel_procstat->maps.rb), handle_event_procstat, NULL, NULL); - if (!rb) { - err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); - goto procstat_cleanup; - } +static int process_sysstat(struct sysstat_bpf *skel_sysstat) { + int err; + struct ring_buffer *rb; - /* Process events */ - if (env.rss == true) { - printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "VMSIZE", "VMDATA", "VMSTK", "VMPTE", "VMSWAP"); - } - else { - printf("%-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "SIZE", "RSSANON", "RSSFILE", "RSSSHMEM"); - } - } + LOAD_AND_ATTACH_SKELETON(skel_sysstat, sysstat); - else if (env.sysstat) { - /* Load and verify BPF application */ - skel_sysstat = sysstat_bpf__open(); - if (!skel_sysstat) { - fprintf(stderr, "Failed to open and load BPF skeleton\n"); - return 1; - } + if (env.part2) { + printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "KRECLM", "SLAB", "SRECLM", "SUNRECL", "NFSUNSTB", "WRITEBACKTMP", "KMAP", "UNMAP", "PAGE"); + } else { + printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "CPU", "MEM", "READ", "WRITE", "IOWAIT", "SWAP"); + } + POLL_RING_BUFFER(rb, 1000, err); - skel_sysstat->bss->user_pid = own_pid; +sysstat_cleanup: + ring_buffer__free(rb); + sysstat_bpf__destroy(skel_sysstat); + return err; +} - /* Load & verify BPF programs */ - err = sysstat_bpf__load(skel_sysstat); - if (err) { - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); - goto sysstat_cleanup; - } +static int process_memleak(struct memleak_bpf *skel_memleak, struct env env) { + skel_memleak->rodata->stack_flags = env.kernel_trace ? KERN_STACKID_FLAGS : USER_STACKID_FLAGS; - /* Attach tracepoints */ - err = sysstat_bpf__attach(skel_sysstat); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto sysstat_cleanup; - } + bpf_map__set_value_size(skel_memleak->maps.stack_traces, perf_max_stack_depth * sizeof(__u64)); + bpf_map__set_max_entries(skel_memleak->maps.stack_traces, stack_map_max_entries); - /* Set up ring buffer polling */ - rb = ring_buffer__new(bpf_map__fd(skel_sysstat->maps.rb), handle_event_sysstat, NULL, NULL); - if (!rb) { - err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); - goto sysstat_cleanup; - } + if (!env.kernel_trace) + disable_kernel_tracepoints(skel_memleak); - /* Process events */ - if (env.part2 == true) { - printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "KRECLM", "SLAB", "SRECLM", "SUNRECLMA", "UNSTABLE", "WRITEBK_T", "ANONHUGE", "SHMEMHUGE", "PMDMAPP"); - } - else { - printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "ACTIVE", "INACTVE", "ANON_ACT", "ANON_INA", "FILE_ACT", "FILE_INA", "UNEVICT", "DIRTY", "WRITEBK", "ANONPAG", "MAP", "SHMEM"); - } + int err = memleak_bpf__load(skel_memleak); + if (err) { + fprintf(stderr, "Failed to load BPF skeleton\n"); + goto memleak_cleanup; } - else if (env.memleak) { - if (env.choose_pid != 0) { - printf("用户态内存泄漏\n"); - env.kernel_trace = false; - attach_pid = env.choose_pid; - } - else - attach_pid = 0; - - strcpy(binary_path, "/lib/x86_64-linux-gnu/libc.so.6"); - - allocs = calloc(ALLOCS_MAX_ENTRIES, sizeof(*allocs)); - - /* Set up libbpf errors and debug info callback */ - libbpf_set_print(libbpf_print_fn); - - /* Load and verify BPF application */ - skel = memleak_bpf__open(); - if (!skel) { - fprintf(stderr, "Failed to open BPF skeleton\n"); - return 1; - } - //skel->rodata->stack_flags = KERN_STACKID_FLAGS; - skel->rodata->stack_flags = env.kernel_trace ? KERN_STACKID_FLAGS : USER_STACKID_FLAGS; - - bpf_map__set_value_size(skel->maps.stack_traces, perf_max_stack_depth * sizeof(__u64)); - bpf_map__set_max_entries(skel->maps.stack_traces, stack_map_max_entries); - - if (!env.kernel_trace) - disable_kernel_tracepoints(skel); - - /* Load & verify BPF programs */ - err = memleak_bpf__load(skel); + if (!env.kernel_trace) { + err = attach_uprobes(skel_memleak); if (err) { - fprintf(stderr, "Failed to load BPF skeleton\n"); + fprintf(stderr, "Failed to attach uprobes\n"); goto memleak_cleanup; } + } - if (!env.kernel_trace) { - err = attach_uprobes(skel); - if (err) { - fprintf(stderr, "failed to attach uprobes\n"); - - goto memleak_cleanup; - } - } - - /* Let libbpf perform auto-attach for uprobe_sub/uretprobe_sub - * NOTICE: we provide path and symbol info in SEC for BPF programs - */ - err = memleak_bpf__attach(skel); - if (err) { - fprintf(stderr, "Failed to auto-attach BPF skeleton: %d\n", err); - goto memleak_cleanup; - } + err = memleak_bpf__attach(skel_memleak); + if (err) { + fprintf(stderr, "Failed to auto-attach BPF skeleton: %d\n", err); + goto memleak_cleanup; + } - g_stacks_size = perf_max_stack_depth * sizeof(*g_stacks); - g_stacks = (__u64 *)malloc(g_stacks_size); - memset(g_stacks, 0, g_stacks_size); + g_stacks_size = perf_max_stack_depth * sizeof(*g_stacks); + g_stacks = (__u64 *)malloc(g_stacks_size); + if (!g_stacks) { + fprintf(stderr, "Failed to allocate memory\n"); + err = -1; + goto memleak_cleanup; + } + memset(g_stacks, 0, g_stacks_size); - symbolizer = blaze_symbolizer_new(); - if (!symbolizer) { - fprintf(stderr, "Fail to create a symbolizer\n"); - err = -1; - goto memleak_cleanup; - } + symbolizer = blaze_symbolizer_new(); + if (!symbolizer) { + fprintf(stderr, "Fail to create a symbolizer\n"); + err = -1; + goto memleak_cleanup; + } - for (i = 0;; i++) { - /* trigger our BPF programs */ - if (!env.kernel_trace) - print_outstanding_combined_allocs(skel, attach_pid); + for (;;) { + if (!env.kernel_trace) + if (env.print_time) { + update_addr_times(skel_memleak); + print_time(skel_memleak); + } else - print_outstanding_allocs(skel); + print_outstanding_combined_allocs(skel_memleak, attach_pid); + else + print_outstanding_allocs(skel_memleak); - sleep(1); - } + sleep(1); } while (!exiting) { - if (env.paf || env.pr || env.procstat || env.sysstat) { - err = ring_buffer__poll(rb, 1000 /* timeout, ms */); - /* Ctrl-C will cause -EINTR */ - if (err == -EINTR) { - err = 0; - break; - } - if (err < 0) { - printf("Error polling perf buffer: %d\n", err); - break; - } - } - else if (env.memleak) { - /* Ctrl-C will cause -EINTR */ - if (err == -EINTR) { - err = 0; - break; - } - if (err < 0) { - printf("Error polling perf buffer: %d\n", err); - break; - } + /* Ctrl-C will cause -EINTR */ + if (err == -EINTR) { + err = 0; + break; } - else { - printf("请输入要使用的功能...\n"); + if (err < 0) { + printf("Error polling perf buffer: %d\n", err); break; } } -paf_cleanup: - ring_buffer__free(rb); - paf_bpf__destroy(skel_paf); - return err < 0 ? -err : 0; - -pr_cleanup: - ring_buffer__free(rb); - pr_bpf__destroy(skel_pr); - return err < 0 ? -err : 0; - -procstat_cleanup: - ring_buffer__free(rb); - procstat_bpf__destroy(skel_procstat); - return err < 0 ? -err : 0; - -sysstat_cleanup: - ring_buffer__free(rb); - sysstat_bpf__destroy(skel_sysstat); - return err < 0 ? -err : 0; - memleak_cleanup: - memleak_bpf__destroy(skel); - blaze_symbolizer_free(symbolizer); - free(g_stacks); - return err < 0 ? -err : 0; + memleak_bpf__destroy(skel_memleak); + if (symbolizer) + blaze_symbolizer_free(symbolizer); + if (g_stacks) + free(g_stacks); + if (allocs) + free(allocs); + return err; } \ No newline at end of file diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.bpf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.bpf.c index 4ae642682..00ef2efe1 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.bpf.c +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/memleak.bpf.c @@ -62,6 +62,20 @@ struct { __type(value, u64); // 用户态指针变量 memptr } memptrs SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, u64); /* alloc return address */ + __type(value, u64); /* timestamp */ + __uint(max_entries, 10240); +} addr_times SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, u64); /* alloc return address */ + __type(value, u64); /* timestamp */ + __uint(max_entries, 10240); +} first_time SEC(".maps"); + char LICENSE[] SEC("license") = "Dual BSD/GPL"; static int gen_alloc_enter(size_t size) { @@ -92,6 +106,10 @@ static int gen_alloc_exit2(void *ctx, u64 address) { bpf_map_update_elem(&allocs, &addr, &info, BPF_ANY); + // Initialize the addr_times map to 0 + __u64 zero_ts = 0; + bpf_map_update_elem(&addr_times, &addr, &zero_ts, BPF_ANY); + union combined_alloc_info add_cinfo = { .total_size = info.size, .number_of_allocs = 1 @@ -135,6 +153,10 @@ static int gen_free_enter(const void *address) { bpf_map_delete_elem(&allocs, &addr); + // Initialize the addr_times map to 0 + __u64 zero_ts = 0; + bpf_map_update_elem(&addr_times, &addr, &zero_ts, BPF_ANY); + return 0; } From 4b3bc3b4f2c273308a0c5cd1f8c51dbc4eb7364c Mon Sep 17 00:00:00 2001 From: syxl-time <953879556@qq.com> Date: Sat, 8 Jun 2024 10:30:09 +0800 Subject: [PATCH 2/3] =?UTF-8?q?mem=5Fwatcher=EF=BC=9A=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=A1=A8=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mem_watcher/mem_watcher.c | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c index d2630075f..33d65f514 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c @@ -587,31 +587,32 @@ static int update_addr_times(struct memleak_bpf *skel) { } // 在打印时间时,先将时间调整为相对于程序启动的时间 -static int print_time(struct memleak_bpf *skel) { +int print_time(struct memleak_bpf *skel) { const size_t addr_times_key_size = bpf_map__key_size(skel->maps.addr_times); + printf("%-16s %9s\n", "AL_ADDR", "AL_Time"); + // Iterate over the addr_times map to print address and time - for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) { - if (bpf_map__get_next_key(skel->maps.addr_times, &prev_key, &curr_key, addr_times_key_size)) { - if (errno == ENOENT) { - break; // no more keys, done! - } - perror("map get next key failed!"); - return -errno; - } + for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) { + if (bpf_map__get_next_key(skel->maps.addr_times, &prev_key, &curr_key, addr_times_key_size)) { + if (errno == ENOENT) { + break; // no more keys, done! + } + perror("map get next key failed!"); + return -errno; + } - // Read the timestamp for the current address - __u64 timestamp; - if (bpf_map__lookup_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0) == 0) { - printf("Address: 0x%llx, Time: %llds\n", curr_key, timestamp); - } - else { - perror("map lookup failed!"); - return -errno; - } - } - printf("------------------------------------------------------\n"); - return 0; + // Read the timestamp for the current address + __u64 timestamp; + if (bpf_map__lookup_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0) == 0) { + printf("0x%-16llx %llds\n", curr_key, timestamp); // 添加时间单位"s" + } + else { + perror("map lookup failed!"); + return -errno; + } + } + return 0; } void disable_kernel_tracepoints(struct memleak_bpf *skel) { @@ -907,6 +908,7 @@ static int process_memleak(struct memleak_bpf *skel_memleak, struct env env) { for (;;) { if (!env.kernel_trace) if (env.print_time) { + system("clear"); update_addr_times(skel_memleak); print_time(skel_memleak); } From c6aad62c6d7858d7419863e38383ef80be5bdcfd Mon Sep 17 00:00:00 2001 From: syxl-time <953879556@qq.com> Date: Fri, 14 Jun 2024 17:27:55 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=A1=A8=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c index 33d65f514..91735d5ea 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c @@ -590,7 +590,7 @@ static int update_addr_times(struct memleak_bpf *skel) { int print_time(struct memleak_bpf *skel) { const size_t addr_times_key_size = bpf_map__key_size(skel->maps.addr_times); - printf("%-16s %9s\n", "AL_ADDR", "AL_Time"); + printf("%-16s %12s\n", "AL_ADDR", "AL_Time(s)"); // Iterate over the addr_times map to print address and time for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) { @@ -605,7 +605,7 @@ int print_time(struct memleak_bpf *skel) { // Read the timestamp for the current address __u64 timestamp; if (bpf_map__lookup_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0) == 0) { - printf("0x%-16llx %llds\n", curr_key, timestamp); // 添加时间单位"s" + printf("0x%-16llx %lld\n", curr_key, timestamp); } else { perror("map lookup failed!");