diff --git a/source/lib/internal/kernel_module/modules/memleak/hashlist.c b/source/lib/internal/kernel_module/modules/memleak/hashlist.c index 720cad401b714a658d2f5cc43e1ebc4f4b76c406..eff16c02bf874a0a89e64ce863c7df32bd4130d7 100755 --- a/source/lib/internal/kernel_module/modules/memleak/hashlist.c +++ b/source/lib/internal/kernel_module/modules/memleak/hashlist.c @@ -75,6 +75,7 @@ int memleak_hashlist_init(struct memleak_htab *htab) for (i = 0; i < htab->total; i++) { desc = internal_alloc(size, GFP_KERNEL | __GFP_ZERO); if (desc) { + desc->num = htab->stack_deep; list_add(&desc->node, &htab->freelist); htab->free++; } @@ -89,14 +90,21 @@ struct alloc_desc * memleak_alloc_desc(struct memleak_htab *htab) unsigned long flags; int size = sizeof(struct alloc_desc) + sizeof(u64) * htab->stack_deep; - if (!htab->free) - return internal_alloc(size, GFP_ATOMIC | __GFP_ZERO); + if (!htab->set.ext) + htab->stack_deep = 0; + if (!htab->free) { + desc = internal_alloc(size, GFP_ATOMIC | __GFP_ZERO); + if (desc) + desc->num = htab->stack_deep; + return desc; + } spin_lock_irqsave(&htab->lock, flags); desc = list_first_entry_or_null(&htab->freelist, struct alloc_desc, node); if (desc) { htab->free--; + desc->num = htab->stack_deep; list_del_init(&desc->node); } @@ -254,6 +262,7 @@ int memleak_dump_leak(struct memleak_htab *htab, struct user_result __user *resu unsigned long long curr_ts = sched_clock(); if ((count <= 0) || copy_from_user(&res, result, sizeof(res))) { + pr_err("count zero %d:%d\n",count,__LINE__); ret = copy_to_user(result, &i, sizeof(i)); return 0; } @@ -271,6 +280,7 @@ int memleak_dump_leak(struct memleak_htab *htab, struct user_result __user *resu desc = vmalloc(sizeof(*desc) * num); if (!desc) { + pr_err("vmalloc error %d:%d\n",count,__LINE__); ret = copy_to_user(result, &i, sizeof(i)); return 0; } @@ -287,6 +297,7 @@ int memleak_dump_leak(struct memleak_htab *htab, struct user_result __user *resu } for (i = 0; i < htab->n_buckets; i++) { + int z = 0; bucket = &htab->buckets[i]; if (bucket->nr <= 0) { continue; @@ -306,7 +317,10 @@ int memleak_dump_leak(struct memleak_htab *htab, struct user_result __user *resu desc->call_site = tmp1->call_site; strcpy(desc->comm,tmp1->comm); snprintf(desc->function, NAME_LEN, "%pS", (void *)tmp1->call_site); - + desc->num = tmp1->num; + for (z = 0; z < desc->num; z++) { + snprintf(desc->backtrace[z], 128, "%pS", tmp1->backtrace[z]); + } desc++; j++; _skip: diff --git a/source/lib/internal/kernel_module/modules/memleak/mem.h b/source/lib/internal/kernel_module/modules/memleak/mem.h index f1333723d8c2ced709705d2512a83598dea44c7a..4ae995657bfd704d01aff73b75cbdb5d00278938 100755 --- a/source/lib/internal/kernel_module/modules/memleak/mem.h +++ b/source/lib/internal/kernel_module/modules/memleak/mem.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -86,6 +85,7 @@ struct alloc_desc { int order; char comm[TASK_COMM_LEN]; u32 hash; + u32 num; u64 backtrace[]; }; diff --git a/source/lib/internal/kernel_module/modules/memleak/memleak.c b/source/lib/internal/kernel_module/modules/memleak/memleak.c index f07c7be488ae8a538ec6f26888643cc540f07155..d36476dcd3fb22fb11bf7678804efc6e0a652374 100755 --- a/source/lib/internal/kernel_module/modules/memleak/memleak.c +++ b/source/lib/internal/kernel_module/modules/memleak/memleak.c @@ -4,7 +4,7 @@ #include #include #include - +#include #include "sysak_mods.h" #include"mem.h" #include"common/hook.h" @@ -12,8 +12,8 @@ #define HASH_SIZE (1024) #define PRE_ALLOC (2048) -static int memleak_ref; static struct memleak_htab *tab; +static int memleak_ref; static ssize_t (*show_slab_objects)(struct kmem_cache *s, char *buf); static int memleak_is_target(struct memleak_htab *htab, const void *x) @@ -35,6 +35,26 @@ static int memleak_is_target(struct memleak_htab *htab, const void *x) return (page->slab_cache == htab->check.cache); } +static unsigned long get_stack_rip(unsigned long *arr, int max_entries) +{ + struct stack_trace stack_trace; + unsigned long trace[16] = {0}; + + stack_trace.nr_entries = 0; + stack_trace.skip = 3; + if (arr && max_entries) { + stack_trace.max_entries = max_entries; + stack_trace.entries = arr; + } else { + stack_trace.max_entries = 16; + stack_trace.entries = trace; + } + + save_stack_trace(&stack_trace); + + return stack_trace.nr_entries; +} + static void memleak_alloc_desc_push(struct memleak_htab *htab, unsigned long call_site, const void *ptr, int order) { @@ -59,6 +79,12 @@ static void memleak_alloc_desc_push(struct memleak_htab *htab, unsigned long cal desc->pid = current->pid; strcpy(desc->comm, current->comm); + if (desc->num) { + desc->num = get_stack_rip((unsigned long *)desc->backtrace, desc->num); + } + if (!call_site && desc->num) + desc->call_site = desc->backtrace[2]; + memleak_insert_desc(htab, desc); _out: @@ -122,20 +148,6 @@ static void trace_slab_alloc_node(unsigned long call_site, const void *ptr, #endif -static unsigned long get_stack_rip(void) -{ - struct stack_trace stack_trace; - unsigned long trace[16] = {0}; - - stack_trace.max_entries = 16; - stack_trace.nr_entries = 0; - stack_trace.entries = trace; - stack_trace.skip = 2; - save_stack_trace(&stack_trace); - - return trace[4]; -} - #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) static void trace_page_alloc(void *ignore, struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype) @@ -149,7 +161,7 @@ static void trace_page_alloc(struct page *page, return; } - memleak_alloc_desc_push(tab, get_stack_rip(), page, order); + memleak_alloc_desc_push(tab, 0, page, order); } @@ -164,7 +176,7 @@ static void trace_page_free(struct page *page, if (((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) != 0) return; - memleak_alloc_desc_pop(tab, get_stack_rip(), page, order); + memleak_alloc_desc_pop(tab, 0, page, order); } @@ -395,7 +407,7 @@ static int memleak_mem_init(struct memleak_htab *htab) htab->n_buckets = HASH_SIZE; htab->total = PRE_ALLOC; - htab->stack_deep = 0; + htab->stack_deep = 16; return memleak_hashlist_init(tab); } @@ -527,7 +539,7 @@ int memleak_release(void) printk("memleak release\n"); memleak_trace_off(tab); memleak_clear_leak(tab); - sysak_module_put(&memleak_ref); + return 0; } @@ -540,7 +552,13 @@ int memleak_handler_cmd(int cmd, unsigned long arg) if (!htab) return -EBUSY; - if (htab->state != MEMLEAK_STATE_OFF) { + if (htab->state != MEMLEAK_STATE_OFF && + (cmd == MEMLEAK_CMD_RESULT)) { + pr_info("htab off busy wait\n"); + return -EAGAIN; + } + if ((htab->state != MEMLEAK_STATE_OFF) && + (cmd == MEMLEAK_CMD_ENALBE)) { pr_info("htab is busy\n"); memleak_release(); } @@ -554,8 +572,8 @@ int memleak_handler_cmd(int cmd, unsigned long arg) pr_info("type = %d time = %d,slabname %s ext %d,rate=%d\n",set.type, set.monitor_time, set.name, set.ext,set.rate); htab->set = set; ret = memleak_trace_on(htab); - if (!ret) - sysak_module_get(&memleak_ref); + if (!ret) + sysak_module_get(&memleak_ref); break; case MEMLEAK_CMD_RESULT: @@ -564,9 +582,8 @@ int memleak_handler_cmd(int cmd, unsigned long arg) break; case MEMLEAK_CMD_DISABLE: - pr_info("disable\n"); memleak_release(); - + sysak_module_put(&memleak_ref); }; return ret; diff --git a/source/lib/internal/kernel_module/modules/memleak/user.h b/source/lib/internal/kernel_module/modules/memleak/user.h index c592f1f7b09aed6fceca41f77922ce45b788fdc6..aa623484107c3ace120ffbf9904e2d7d9ee4583c 100644 --- a/source/lib/internal/kernel_module/modules/memleak/user.h +++ b/source/lib/internal/kernel_module/modules/memleak/user.h @@ -40,7 +40,8 @@ struct user_alloc_desc { char function[NAME_LEN]; unsigned long long call_site; unsigned long long ts; - unsigned long long backtrace[]; + int num; + char backtrace[32][128]; }; struct user_call_site { diff --git a/source/tools/detect/memleak/main.c b/source/tools/detect/memleak/main.c index df51faecc8ea37f359eea1e83dd0bddbc0cde6df..f88c7d42386be41eaadf9f21376e6522625bc5bc 100644 --- a/source/tools/detect/memleak/main.c +++ b/source/tools/detect/memleak/main.c @@ -18,7 +18,7 @@ extern int slab_main(struct memleak_settings *set); extern int vmalloc_main(int argc, char **argv); extern int page_main(struct memleak_settings *set); static int error = 0; - +static int off = 0; static void show_usage(void) { @@ -27,6 +27,8 @@ static void show_usage(void) printf(" page: trace alloc page leak\n"); printf(" vmalloc: trace vmalloc leak, must use root \n"); printf("-i: trace internal,default 300s \n"); + printf("-s: stacktrace for memory alloc \n"); + printf("-d: memleak off \n"); printf("-n: trace slab name, defualt select the max size or objects \n"); } @@ -35,7 +37,7 @@ int get_arg(struct memleak_settings *set, int argc, char * argv[]) { int ch; - while ((ch = getopt(argc, argv, "hi:r:n:t:")) != -1) + while ((ch = getopt(argc, argv, "dshi:r:n:t:")) != -1) { switch (ch) { @@ -60,6 +62,12 @@ int get_arg(struct memleak_settings *set, int argc, char * argv[]) show_usage(); error = 1; break; + case 's': + set->ext = 1; + break; + case 'd': + off = 1; + break; case '?': printf("Unknown option: %c\n",(char)optopt); error = 1; @@ -69,6 +77,20 @@ int get_arg(struct memleak_settings *set, int argc, char * argv[]) } +static int memleak_off(void) +{ + int fd = 0; + + fd = open("/dev/sysak", O_RDWR); + if (fd < 0) { + printf("open memleak check error\n"); + return -1; + } + ioctl(fd, MEMLEAK_OFF); + close(fd); + return 0; +} + int main(int argc, char **argv) { struct memleak_settings set; @@ -80,7 +102,11 @@ int main(int argc, char **argv) if (error) return 0; - + if (off) { + memleak_off(); + printf("memleak off success\n"); + return 0; + } printf("type %d\n", set.type); switch (set.type) { diff --git a/source/tools/detect/memleak/page.c b/source/tools/detect/memleak/page.c index b0ff815fb43a081d0aab056d5587878250d7d789..165ca37181f6a152ef1720cef0dfb7faa4003ffa 100644 --- a/source/tools/detect/memleak/page.c +++ b/source/tools/detect/memleak/page.c @@ -107,9 +107,8 @@ int page_main(struct memleak_settings *set) if (!set->monitor_time) set->monitor_time = detect_time; - + set->ext = 1; detect_time = set->monitor_time; - ret = ioctl(fd, MEMLEAK_ON, set); if (ret) { printf("ioctl error %s \n", strerror(ret)); @@ -144,7 +143,11 @@ _retry: desc = res.desc; printf("未释放内存详细列表:\n"); for (ret = 0; ret < res.num; ret++) { + int j = 0; printf("%s:%d %s ptr=%p order %d ts_delta=%llu\n", desc->comm, desc->pid, desc->function, desc->ptr, desc->order, desc->ts); + for (j = 0; j < desc->num; j++) + printf("%s\n", desc->backtrace[j]); + printf("\n"); desc++; } diff --git a/source/tools/detect/memleak/slab.c b/source/tools/detect/memleak/slab.c index 9429ae2c890686cdf6862265a6684c9a67769f0c..8586696b3c006854ea342ea8ac0c6f59d3eba71e 100644 --- a/source/tools/detect/memleak/slab.c +++ b/source/tools/detect/memleak/slab.c @@ -165,7 +165,11 @@ _retry: desc = res.desc; printf("未释放内存详细列表:\n"); for (ret = 0; ret < res.num; ret++) { + int j; printf("%s:%-15d %15s ptr=%p mark %d delta = %llu\n", desc->comm, desc->pid, desc->function, desc->ptr, desc->mark, desc->ts); + for(j = 0; j < desc->num; j++) + printf("%s\n",desc->backtrace[j]); + printf("\n"); desc++; } diff --git a/source/tools/detect/memleak/user_api.h b/source/tools/detect/memleak/user_api.h index 1d023444517931f1c01714a2e1d1dd78264bf81e..b7ab77fb0111a8cf50ec77bde64a91fbc16f0cbe 100644 --- a/source/tools/detect/memleak/user_api.h +++ b/source/tools/detect/memleak/user_api.h @@ -42,7 +42,8 @@ struct user_alloc_desc { char function[NAME_LEN]; unsigned long long call_site; unsigned long long ts; - unsigned long long backtrace[]; + int num; + char backtrace[32][128]; }; struct user_call_site {