aboutsummaryrefslogtreecommitdiffstats
path: root/src/libstrongswan/utils
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2008-11-05 13:58:19 +0000
committerMartin Willi <martin@strongswan.org>2008-11-05 13:58:19 +0000
commitf7237cf37abae7253a3ef24c38d7d6835224c76b (patch)
treea17de4507af1b1c8c822bf0adb3efa1c264ce716 /src/libstrongswan/utils
parent2abc66b977c41f1a1240fe21c921a6df58bd4157 (diff)
downloadstrongswan-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.c179
-rw-r--r--src/libstrongswan/utils/backtrace.h63
-rw-r--r--src/libstrongswan/utils/leak_detective.c152
-rw-r--r--src/libstrongswan/utils/leak_detective.h5
-rw-r--r--src/libstrongswan/utils/mutex.c45
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;
}