diff options
author | Martin Willi <martin@strongswan.org> | 2008-11-05 13:58:19 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2008-11-05 13:58:19 +0000 |
commit | f7237cf37abae7253a3ef24c38d7d6835224c76b (patch) | |
tree | a17de4507af1b1c8c822bf0adb3efa1c264ce716 /src/libstrongswan/utils | |
parent | 2abc66b977c41f1a1240fe21c921a6df58bd4157 (diff) | |
download | strongswan-f7237cf37abae7253a3ef24c38d7d6835224c76b.tar.bz2 strongswan-f7237cf37abae7253a3ef24c38d7d6835224c76b.tar.xz |
separated backtrace functionality from leak_detective, used in
leak_detective
mutex profiling
signal handler
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r-- | src/libstrongswan/utils/backtrace.c | 179 | ||||
-rw-r--r-- | src/libstrongswan/utils/backtrace.h | 63 | ||||
-rw-r--r-- | src/libstrongswan/utils/leak_detective.c | 152 | ||||
-rw-r--r-- | src/libstrongswan/utils/leak_detective.h | 5 | ||||
-rw-r--r-- | src/libstrongswan/utils/mutex.c | 45 |
5 files changed, 293 insertions, 151 deletions
diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c new file mode 100644 index 000000000..be3857248 --- /dev/null +++ b/src/libstrongswan/utils/backtrace.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * $Id$ + */ + +#define _GNU_SOURCE + +#ifdef HAVE_DLADDR +# include <dlfcn.h> +#endif /* HAVE_DLADDR */ + +#ifdef HAVE_BACKTRACE +# include <execinfo.h> +#endif /* HAVE_BACKTRACE */ + +#include "backtrace.h" + +typedef struct private_backtrace_t private_backtrace_t; + +/** + * Private data of an backtrace_t object. + */ +struct private_backtrace_t { + + /** + * Public backtrace_t interface. + */ + backtrace_t public; + + /** + * Number of stacks frames obtained in stack_frames + */ + int frame_count; + + /** + * Recorded stack frames. + */ + void *frames[]; +}; + +/** + * Implementation of backtrace_t.log + */ +static void log_(private_backtrace_t *this, FILE *file) +{ +#ifdef HAVE_BACKTRACE + size_t i; + char **strings; + + strings = backtrace_symbols(this->frames, this->frame_count); + + fprintf(file, " dumping %d stack frame addresses:\n", this->frame_count); + for (i = 0; i < this->frame_count; i++) + { +#ifdef HAVE_DLADDR + Dl_info info; + + if (dladdr(this->frames[i], &info)) + { + char cmd[1024]; + FILE *output; + char c; + void *ptr = this->frames[i]; + + if (strstr(info.dli_fname, ".so")) + { + ptr = (void*)(this->frames[i] - info.dli_fbase); + } + snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", info.dli_fname, ptr); + if (info.dli_sname) + { + fprintf(file, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%x) [%p]\n", + info.dli_fname, info.dli_fbase, info.dli_sname, + this->frames[i] - info.dli_saddr, this->frames[i]); + } + else + { + fprintf(file, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname, + info.dli_fbase, this->frames[i]); + } + fprintf(file, " -> \e[32m"); + output = popen(cmd, "r"); + if (output) + { + while (TRUE) + { + c = getc(output); + if (c == '\n' || c == EOF) + { + break; + } + fputc(c, file); + } + } + else + { +#endif /* HAVE_DLADDR */ + fprintf(file, " %s\n", strings[i]); +#ifdef HAVE_DLADDR + } + fprintf(file, "\n\e[0m"); + } + else + { + fprintf(file, " %s\n", strings[i]); + } +#endif /* HAVE_DLADDR */ + } + free (strings); +#else /* !HAVE_BACKTRACE */ + fprintf(file, "C library does not support backtrace().\n"); +#endif /* HAVE_BACKTRACE */ +} + +/** + * Implementation of backtrace_t.contains_function + */ +static bool contains_function(private_backtrace_t *this, char *function) +{ +#ifdef HAVE_DLADDR + int i; + + for (i = 0; i< this->frame_count; i++) + { + Dl_info info; + + if (dladdr(this->frames[i], &info) && info.dli_sname) + { + if (streq(info.dli_sname, function)) + { + return TRUE; + } + } + } +#endif /* HAVE_DLADDR */ + return FALSE; +} + +/** + * Implementation of backtrace_t.destroy. + */ +static void destroy(private_backtrace_t *this) +{ + free(this); +} + +/** + * See header + */ +backtrace_t *backtrace_create(int skip) +{ + private_backtrace_t *this; + void *frames[50]; + int frame_count; + + frame_count = backtrace(frames, countof(frames)); + this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*)); + this->frame_count = frame_count - skip; + memcpy(this->frames, frames + skip, this->frame_count * sizeof(void*)); + + this->public.log = (void(*)(backtrace_t*,FILE*))log_; + this->public.contains_function = (bool(*)(backtrace_t*, char *function))contains_function; + this->public.destroy = (void(*)(backtrace_t*))destroy; + + return &this->public; +} + diff --git a/src/libstrongswan/utils/backtrace.h b/src/libstrongswan/utils/backtrace.h new file mode 100644 index 000000000..72effd01e --- /dev/null +++ b/src/libstrongswan/utils/backtrace.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup backtrace backtrace + * @{ @ingroup utils + */ + +#ifndef BACKTRACE_H_ +#define BACKTRACE_H_ + +#include <stdio.h> + +#include <library.h> + +typedef struct backtrace_t backtrace_t; + +/** + * A backtrace registers the frames on the stack during creation. + */ +struct backtrace_t { + + /** + * Log the backtrace to a FILE stream. + */ + void (*log)(backtrace_t *this, FILE *file); + + /** + * Check if the backtrace contains a frame in a specific function. + * + * @param function name + * @return TRUE if function is in the stack + */ + bool (*contains_function)(backtrace_t *this, char *function); + + /** + * Destroy a backtrace instance. + */ + void (*destroy)(backtrace_t *this); +}; + +/** + * Create a backtrace of the current stack. + * + * @param skip how many of the innerst frames to skip + * @return backtrace + */ +backtrace_t *backtrace_create(int skip); + +#endif /* BACKTRACE_H_ @}*/ + diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 70726da3b..bb33259ff 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -14,11 +14,6 @@ * * $Id$ */ - -#ifdef HAVE_DLADDR -# define _GNU_SOURCE -# include <dlfcn.h> -#endif /* HAVE_DLADDR */ #include <stddef.h> #include <string.h> @@ -28,21 +23,18 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <dlfcn.h> #include <unistd.h> #include <syslog.h> #include <pthread.h> #include <netdb.h> #include <printf.h> #include <locale.h> -#ifdef HAVE_BACKTRACE -# include <execinfo.h> -#endif /* HAVE_BACKTRACE */ #include "leak_detective.h" #include <library.h> #include <debug.h> +#include <utils/backtrace.h> typedef struct private_leak_detective_t private_leak_detective_t; @@ -106,16 +98,6 @@ struct memory_header_t { u_int bytes; /** - * Stack frames at the time of allocation - */ - void *stack_frames[STACK_FRAMES_COUNT]; - - /** - * Number of stacks frames obtained in stack_frames - */ - int stack_frame_count; - - /** * Pointer to previous entry in linked list */ memory_header_t *previous; @@ -126,6 +108,11 @@ struct memory_header_t { memory_header_t *next; /** + * backtrace taken during (re-)allocation + */ + backtrace_t *backtrace; + + /** * magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC */ u_int32_t magic; @@ -151,7 +138,7 @@ struct memory_tail_t { static memory_header_t first_header = { magic: MEMORY_HEADER_MAGIC, bytes: 0, - stack_frame_count: 0, + backtrace: NULL, previous: NULL, next: NULL }; @@ -162,82 +149,14 @@ static memory_header_t first_header = { static bool installed = FALSE; /** - * log stack frames queried by backtrace() - * TODO: Dump symbols of static functions. This could be done with - * the addr2line utility or the GNU BFD Library... - */ -static void log_stack_frames(void **stack_frames, int stack_frame_count) -{ -#ifdef HAVE_BACKTRACE - size_t i; - char **strings; - - strings = backtrace_symbols(stack_frames, stack_frame_count); - - fprintf(stderr, " dumping %d stack frame addresses:\n", stack_frame_count); - for (i = 0; i < stack_frame_count; i++) - { -#ifdef HAVE_DLADDR - Dl_info info; - - if (dladdr(stack_frames[i], &info)) - { - char cmd[1024]; - FILE *output; - char c; - void *ptr = stack_frames[i]; - - if (strstr(info.dli_fname, ".so")) - { - ptr = (void*)(stack_frames[i] - info.dli_fbase); - } - snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", info.dli_fname, ptr); - if (info.dli_sname) - { - fprintf(stderr, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%x) [%p]\n", - info.dli_fname, info.dli_fbase, info.dli_sname, - stack_frames[i] - info.dli_saddr, stack_frames[i]); - } - else - { - fprintf(stderr, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname, - info.dli_fbase, stack_frames[i]); - } - fprintf(stderr, " -> \e[32m"); - output = popen(cmd, "r"); - if (output) - { - while (TRUE) - { - c = getc(output); - if (c == '\n' || c == EOF) - { - break; - } - fputc(c, stderr); - } - } - else - { -#endif /* HAVE_DLADDR */ - fprintf(stderr, " %s\n", strings[i]); -#ifdef HAVE_DLADDR - } - fprintf(stderr, "\n\e[0m"); - } -#endif /* HAVE_DLADDR */ - } - free (strings); -#endif /* HAVE_BACKTRACE */ -} - -/** * Leak report white list * * List of functions using static allocation buffers or should be suppressed * otherwise on leak report. */ char *whitelist[] = { + /* backtraces, including own */ + "backtrace_create", /* pthread stuff */ "pthread_create", "pthread_setspecific", @@ -284,27 +203,16 @@ char *whitelist[] = { /** * check if a stack frame contains functions listed above */ -static bool is_whitelisted(void **stack_frames, int stack_frame_count) +static bool is_whitelisted(backtrace_t *backtrace) { - int i, j; - -#ifdef HAVE_DLADDR - for (i=0; i< stack_frame_count; i++) + int i; + for (i = 0; i < sizeof(whitelist)/sizeof(char*); i++) { - Dl_info info; - - if (dladdr(stack_frames[i], &info) && info.dli_sname) - { - for (j = 0; j < sizeof(whitelist)/sizeof(char*); j++) - { - if (streq(info.dli_sname, whitelist[j])) - { - return TRUE; - } - } + if (backtrace->contains_function(backtrace, whitelist[i])) + { + return TRUE; } } -#endif /* HAVE_DLADDR */ return FALSE; } @@ -318,7 +226,7 @@ void report_leaks() for (hdr = first_header.next; hdr != NULL; hdr = hdr->next) { - if (is_whitelisted(hdr->stack_frames, hdr->stack_frame_count)) + if (is_whitelisted(hdr->backtrace)) { whitelisted++; } @@ -326,7 +234,7 @@ void report_leaks() { fprintf(stderr, "Leak (%d bytes at %p):\n", hdr->bytes, hdr + 1); /* skip the first frame, contains leak detective logic */ - log_stack_frames(hdr->stack_frames + 1, hdr->stack_frame_count - 1); + hdr->backtrace->log(hdr->backtrace, stderr); leaks++; } } @@ -403,7 +311,7 @@ void *malloc_hook(size_t bytes, const void *caller) hdr->magic = MEMORY_HEADER_MAGIC; hdr->bytes = bytes; - hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT); + hdr->backtrace = backtrace_create(3); tail->magic = MEMORY_TAIL_MAGIC; install_hooks(); @@ -426,10 +334,9 @@ void *malloc_hook(size_t bytes, const void *caller) */ void free_hook(void *ptr, const void *caller) { - void *stack_frames[STACK_FRAMES_COUNT]; - int stack_frame_count; memory_header_t *hdr; memory_tail_t *tail; + backtrace_t *backtrace; pthread_t thread_id = pthread_self(); int oldpolicy; struct sched_param oldparams, params; @@ -455,8 +362,9 @@ void free_hook(void *ptr, const void *caller) fprintf(stderr, "freeing invalid memory (%p): " "header magic 0x%x, tail magic 0x%x:\n", ptr, hdr->magic, tail->magic); - stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); - log_stack_frames(stack_frames, stack_frame_count); + backtrace = backtrace_create(3); + backtrace->log(backtrace, stderr); + backtrace->destroy(backtrace); } else { @@ -466,10 +374,11 @@ void free_hook(void *ptr, const void *caller) hdr->next->previous = hdr->previous; } hdr->previous->next = hdr->next; - + hdr->backtrace->destroy(hdr->backtrace); + /* clear MAGIC, set mem to something remarkable */ memset(hdr, MEMORY_FREE_PATTERN, hdr->bytes + sizeof(memory_header_t)); - + free(hdr); } @@ -483,9 +392,8 @@ void free_hook(void *ptr, const void *caller) void *realloc_hook(void *old, size_t bytes, const void *caller) { memory_header_t *hdr; - void *stack_frames[STACK_FRAMES_COUNT]; - int stack_frame_count; memory_tail_t *tail; + backtrace_t *backtrace; pthread_t thread_id = pthread_self(); int oldpolicy; struct sched_param oldparams, params; @@ -512,8 +420,9 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) fprintf(stderr, "reallocating invalid memory (%p): " "header magic 0x%x, tail magic 0x%x:\n", old, hdr->magic, tail->magic); - stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT); - log_stack_frames(stack_frames, stack_frame_count); + backtrace = backtrace_create(3); + backtrace->log(backtrace, stderr); + backtrace->destroy(backtrace); } /* clear tail magic, allocate, set tail magic */ memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic)); @@ -523,7 +432,8 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) /* update statistics */ hdr->bytes = bytes; - hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT); + hdr->backtrace->destroy(hdr->backtrace); + hdr->backtrace = backtrace_create(3); /* update header of linked list neighbours */ if (hdr->next) diff --git a/src/libstrongswan/utils/leak_detective.h b/src/libstrongswan/utils/leak_detective.h index 763814726..3773fb8e5 100644 --- a/src/libstrongswan/utils/leak_detective.h +++ b/src/libstrongswan/utils/leak_detective.h @@ -21,11 +21,6 @@ #ifndef LEAK_DETECTIVE_H_ #define LEAK_DETECTIVE_H_ -/** - * Maximum depth stack frames to register - */ -#define STACK_FRAMES_COUNT 20 - typedef struct leak_detective_t leak_detective_t; /** diff --git a/src/libstrongswan/utils/mutex.c b/src/libstrongswan/utils/mutex.c index 71d59ca42..25d2788aa 100644 --- a/src/libstrongswan/utils/mutex.c +++ b/src/libstrongswan/utils/mutex.c @@ -19,6 +19,7 @@ #include <library.h> #include <debug.h> +#include <utils/backtrace.h> #include <pthread.h> #include <sys/time.h> @@ -53,14 +54,9 @@ struct private_mutex_t { struct timeval waited; /** - * creator of the mutex + * backtrace where mutex has been created */ - void *stack[10]; - - /** - * number of pointers in stack - */ - int stack_size; + backtrace_t *backtrace; #endif /* LOCK_PROFILER */ /** @@ -111,23 +107,22 @@ struct private_condvar_t { #include <execinfo.h> /** - * print mutex locking statistics + * Print and cleanup mutex profiler */ -static void print_stats(private_mutex_t *this) +static void profiler_cleanup(private_mutex_t *this) { - int i; - - DBG1("waited %d.%06ds in mutex, created at:", - this->waited.tv_sec, this->waited.tv_usec); - for (i = 0; i < this->stack_size; i++) - { - DBG1(" %p", this->stack[i]); - } + fprintf(stderr, "waited %d.%06ds in mutex, created at:", + this->waited.tv_sec, this->waited.tv_usec); + this->backtrace->log(this->backtrace, stderr); + this->backtrace->destroy(this->backtrace); } -static void init_stats(private_mutex_t *this) +/** + * Initialize mutex profiler + */ +static void profiler_init(private_mutex_t *this) { - this->stack_size = backtrace(this->stack, countof(this->stack)); + this->backtrace = backtrace_create(3); timerclear(&this->waited); } @@ -151,8 +146,8 @@ static void lock(private_mutex_t *this) #else /* !LOCK_PROFILER */ /** dummy implementations */ -static void print_stats(private_mutex_t *this) {} -static void init_stats(private_mutex_t *this) {} +static void profiler_cleanup(private_mutex_t *this) {} +static void profiler_init(private_mutex_t *this) {} /** * Implementation of mutex_t.lock. @@ -224,7 +219,7 @@ static void unlock_r(private_r_mutex_t *this) */ static void mutex_destroy(private_mutex_t *this) { - print_stats(this); + profiler_cleanup(this); pthread_mutex_destroy(&this->mutex); free(this); } @@ -234,7 +229,7 @@ static void mutex_destroy(private_mutex_t *this) */ static void mutex_destroy_r(private_r_mutex_t *this) { - print_stats(&this->generic); + profiler_cleanup(&this->generic); pthread_mutex_destroy(&this->generic.mutex); pthread_key_delete(this->times); free(this); @@ -258,7 +253,7 @@ mutex_t *mutex_create(mutex_type_t type) pthread_mutex_init(&this->generic.mutex, NULL); pthread_key_create(&this->times, NULL); this->generic.recursive = TRUE; - init_stats(&this->generic); + profiler_init(&this->generic); this->thread = 0; return &this->generic.public; @@ -274,7 +269,7 @@ mutex_t *mutex_create(mutex_type_t type) pthread_mutex_init(&this->mutex, NULL); this->recursive = FALSE; - init_stats(this); + profiler_init(this); return &this->public; } |