From 001f11505dd188ecb4513900031b1b9bd70d0282 Mon Sep 17 00:00:00 2001 From: Ray Dudu Date: Wed, 27 Apr 2016 15:16:51 +0200 Subject: [PATCH] Basic implementation of json allocations dump --- allocdb.c | 60 +++++++++++++++++++++++++++++++++-------------- allocdb.h | 3 ++- backtrace.c | 13 ++++++---- backtrace.h | 1 + config.h | 2 +- dmm.c | 2 +- external/htable.c | 10 ++++++-- external/htable.h | 4 ++-- external/json2f.h | 24 +++++++++++++++++++ hooks_stdlib.c | 5 +++- 10 files changed, 94 insertions(+), 30 deletions(-) diff --git a/allocdb.c b/allocdb.c index ad0028f..952fe3c 100644 --- a/allocdb.c +++ b/allocdb.c @@ -6,6 +6,7 @@ #include "config.h" #include +#include #include "backtrace.h" #include "allocdb.h" @@ -163,26 +164,49 @@ void allocdb_release(allocdb_t *db) { } -static void allocdb_print(htable_entry_t *e) { - allocdb_bt_t *p; - /* allocdb_alloc_t *a; */ +static int allocdb_print(htable_entry_t *e, json2f_t *jd) { + allocdb_bt_t *p = (allocdb_bt_t *)e; + allocdb_alloc_t *a; + char **bt; + + json2f_obj(jd); + json2f_namedarr(jd, "backtrace"); + bt = get_backtrace_symbols(p->e.key, p->e.key_len); + json2f_arr_str(jd, bt, p->e.key_len); + free(bt); + json2f_arr_end(jd); + json2f_long(jd, "allocations_amount", p->allocs_num); + json2f_namedarr(jd, "allocations"); + for(a = p->allocs; a != NULL; a = a->next){ + json2f_arr(jd); + json2f_arr_ulong(jd, ((unsigned long *)a->e.key), 1); + json2f_arr_ulong(jd, &(a->size), 1); + json2f_arr_end(jd); + } + json2f_arr_end(jd); + json2f_obj_end(jd); + + return json2f_geterr(jd); +} - p = (allocdb_bt_t *)e; +int allocdb_dump(allocdb_t *db, FILE *fd, char *subsys) { + json2f_t jd; + int ret; - print_backtrace(e->key, e->key_len); - printf(" TOTAL ALLOCS: %zu\n", p->allocs_num); - /* a = p->allocs; */ - /* while (a != NULL) { */ - /* printf(" ALLOC: [%p, %zd]\n", *((void **)a->e.key), a->size); */ - /* a = a->next; */ - /* } */ -} + D(printf("++%s\n", __func__)); + json2f_init(&jd, fd); -void allocdb_dump(allocdb_t *db) { - printf("++ALLOCATIONS\n"); - pthread_mutex_lock(&db->mtx); - htable_foreach(db->backtraces, allocdb_print); - pthread_mutex_unlock(&db->mtx); - printf("--ALLOCATIONS\n"); + json2f_obj(&jd); + json2f_str(&jd, "subsystem", subsys); + json2f_namedarr(&jd, "allocations"); + + pthread_mutex_lock(&db->mtx); + ret = htable_foreach(db->backtraces, (htable_callback_fn)allocdb_print, &jd); + pthread_mutex_unlock(&db->mtx); + + json2f_arr_end(&jd); + json2f_obj_end(&jd); + printf("--%s\n", __func__); + return ret; } diff --git a/allocdb.h b/allocdb.h index 29431de..84a073b 100644 --- a/allocdb.h +++ b/allocdb.h @@ -2,6 +2,7 @@ #define __ALLOCDB_H__ #include +#include #include typedef struct allocdb_t allocdb_t; @@ -29,6 +30,6 @@ void allocdb_log_release(allocdb_t *db, void *addr); void allocdb_log_realloc(allocdb_t *db, void *old_addr, void *new_addr, size_t new_size); void allocdb_release(allocdb_t *db); -void allocdb_dump(allocdb_t *db); +int allocdb_dump(allocdb_t *db, FILE *fd, char *subsys); #endif diff --git a/backtrace.c b/backtrace.c index 230cf3c..6ae6706 100644 --- a/backtrace.c +++ b/backtrace.c @@ -6,9 +6,13 @@ #include "config.h" +char **get_backtrace_symbols(void **addr, int len) { + return backtrace_symbols(addr, len); +} + void print_backtrace(void **addr, int len) { int i; - char **symbollist = backtrace_symbols(addr, len); + char **symbollist = get_backtrace_symbols(addr, len); for(i = 0; i < len && addr[i] != NULL; i++) { printf("[%02d]: %s\n", i, symbollist[i]); @@ -16,7 +20,7 @@ void print_backtrace(void **addr, int len) { free(symbollist); } -static void out_of_stack_marker() { +static void __attribute__ ((unused)) out_of_stack_marker() { }; #ifdef DMM_OWN_BACKTRACE @@ -27,8 +31,9 @@ static void out_of_stack_marker() { * long pc = *(topfp - 0); */ -//assuming stack is less than 64k -#define STACK_ADDR_MASK (((1UL << 16) - 1) << (CHAR_BIT * sizeof(unsigned long) - 16)) +//assuming stack is less than 2048k +//TODO use getrlimit(RLIMIT_STACK ... or parse /proc/self/maps +#define STACK_ADDR_MASK (((1UL << 16) - 1) << (CHAR_BIT * sizeof(unsigned long) - 21)) int get_backtrace(void **addr, int len) { int i; diff --git a/backtrace.h b/backtrace.h index f774f18..7c58b24 100644 --- a/backtrace.h +++ b/backtrace.h @@ -3,5 +3,6 @@ int get_backtrace(void **addr, int len); void print_backtrace(void **addr, int len); +char **get_backtrace_symbols(void **addr, int len); #endif /* __BACKTRACE_H__ */ diff --git a/config.h b/config.h index 3483e42..f23bc83 100644 --- a/config.h +++ b/config.h @@ -16,6 +16,6 @@ #define DMM_DEFAULT_ALIGNMENT sizeof(unsigned long) -#define DMM_DEFAULT_DUMP_LOCATION "/tmp" +#define DMM_DEFAULT_DUMP_LOCATION "./" #endif /* __CONFIG_H__ */ diff --git a/dmm.c b/dmm.c index f6d888c..440c519 100644 --- a/dmm.c +++ b/dmm.c @@ -19,7 +19,7 @@ static void dmm_make_snapshot(int sig) { FILE *fd; int save_error = 0; - snprintf(fn, FNAME_MAX_LEN, "%s/dmm_%d_%d.json", dumps_location, pid, dump_seq); + snprintf(fn, FNAME_MAX_LEN, "%s/dmm_%d_%04d.json", dumps_location, pid, dump_seq); printf("Saving allocation snapshot to: %s\n", fn); fd = fopen(fn, "w"); if (fd == NULL) { diff --git a/external/htable.c b/external/htable.c index 33512f4..1155cd4 100644 --- a/external/htable.c +++ b/external/htable.c @@ -171,17 +171,23 @@ void htable_delete(htable_t *table, void (*entry_free)(htable_entry_t *)) { free(table); } -void htable_foreach(htable_t *table, htable_callback_fn callback) { +int htable_foreach(htable_t *table, htable_callback_fn callback, void *context) { size_t i; + int ret = -1; + for (i = 0; i < table->size; i++) { if (table->entries[i] != NULL) { htable_entry_t *e = table->entries[i]; while (e != NULL) { - callback(e); + ret = callback(e, context); + if (ret != 0) { + break; + } e = e->next; } } } + return ret; } #ifdef HTABLE_DEBUG diff --git a/external/htable.h b/external/htable.h index 2c00b74..9355af1 100644 --- a/external/htable.h +++ b/external/htable.h @@ -36,7 +36,7 @@ typedef struct htable_entry_t { typedef struct htable_t htable_t; -typedef void (*htable_callback_fn)(htable_entry_t *); +typedef int (*htable_callback_fn)(htable_entry_t *, void *context); htable_t *htable_new(size_t size); void htable_push(htable_t *table, htable_entry_t *entry); @@ -46,7 +46,7 @@ void htable_scrap(htable_t *table, htable_entry_t *entry); void htable_delete(htable_t *table, void (*entry_free)(htable_entry_t *)); -void htable_foreach(htable_t *table, htable_callback_fn); +int htable_foreach(htable_t *table, htable_callback_fn, void *context); #ifdef HTABLE_DEBUG void htable_dump(htable_t *table); diff --git a/external/json2f.h b/external/json2f.h index b63ac01..fe14fcb 100644 --- a/external/json2f.h +++ b/external/json2f.h @@ -98,6 +98,16 @@ void inline json2f_long(json2f_t *jd, char *name, long l) { jd->delim = ','; } +void inline json2f_ulong(json2f_t *jd, char *name, unsigned long ul) { + if (jd->error) { + return; + } + if(fprintf(jd->fd, "%c\"%s\":%lu", jd->delim, name, ul) < 0) { + jd->error = errno; + } + jd->delim = ','; +} + void inline json2f_str(json2f_t *jd, char *name, char *s) { if (jd->error) { return; @@ -190,6 +200,20 @@ void inline json2f_arr_long(json2f_t *jd, long *arr, int len) { } } +void inline json2f_arr_ulong(json2f_t *jd, unsigned long *arr, int len) { + int i; + if (jd->error) { + return; + } + for (i = 0; i < len; i++) { + if (fprintf(jd->fd, "%c%ld", jd->delim, arr[i]) < 0) { + jd->error = errno; + break; + } + jd->delim = ','; + } +} + int inline json2f_geterr(json2f_t *jd) { return jd->error; } diff --git a/hooks_stdlib.c b/hooks_stdlib.c index ae89bf9..f4c80f6 100644 --- a/hooks_stdlib.c +++ b/hooks_stdlib.c @@ -165,13 +165,16 @@ void stdlib_init() { } int stdlib_snapshot(FILE *fd) { + int ret = -1; tlocker_acquire(); if (allocs != NULL) { - allocdb_dump(allocs); + ret = allocdb_dump(allocs, fd, "STDLIB"); } tlocker_release(); + + return ret; } void stdlib_release(){