separated backtrace functionality from leak_detective, used in
leak_detective mutex profiling signal handler
This commit is contained in:
+7
-45
@@ -16,11 +16,6 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_DLADDR
|
|
||||||
# define _GNU_SOURCE
|
|
||||||
# include <dlfcn.h>
|
|
||||||
#endif /* HAVE_DLADDR */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@@ -34,9 +29,6 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#ifdef HAVE_BACKTRACE
|
|
||||||
# include <execinfo.h>
|
|
||||||
#endif /* HAVE_BACKTRACE */
|
|
||||||
#ifdef CAPABILITIES
|
#ifdef CAPABILITIES
|
||||||
#include <sys/capability.h>
|
#include <sys/capability.h>
|
||||||
#endif /* CAPABILITIES */
|
#endif /* CAPABILITIES */
|
||||||
@@ -44,6 +36,7 @@
|
|||||||
#include "daemon.h"
|
#include "daemon.h"
|
||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
|
#include <utils/backtrace.h>
|
||||||
#include <config/traffic_selector.h>
|
#include <config/traffic_selector.h>
|
||||||
#include <config/proposal.h>
|
#include <config/proposal.h>
|
||||||
|
|
||||||
@@ -433,45 +426,13 @@ static bool initialize(private_daemon_t *this, bool syslog, level_t levels[])
|
|||||||
*/
|
*/
|
||||||
static void segv_handler(int signal)
|
static void segv_handler(int signal)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_BACKTRACE
|
backtrace_t *backtrace;
|
||||||
void *array[20];
|
|
||||||
size_t size;
|
|
||||||
char **strings;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
size = backtrace(array, 20);
|
DBG1(DBG_DMN, "thread %u received %d", pthread_self(), signal);
|
||||||
strings = backtrace_symbols(array, size);
|
backtrace = backtrace_create(2);
|
||||||
|
backtrace->log(backtrace, stderr);
|
||||||
|
backtrace->destroy(backtrace);
|
||||||
|
|
||||||
DBG1(DBG_JOB, "thread %u received %s. Dumping %d frames from stack:",
|
|
||||||
pthread_self(), signal == SIGSEGV ? "SIGSEGV" : "SIGILL", size);
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_DLADDR
|
|
||||||
Dl_info info;
|
|
||||||
|
|
||||||
if (dladdr(array[i], &info))
|
|
||||||
{
|
|
||||||
void *ptr = array[i];
|
|
||||||
if (strstr(info.dli_fname, ".so"))
|
|
||||||
{
|
|
||||||
ptr = (void*)(array[i] - info.dli_fbase);
|
|
||||||
}
|
|
||||||
DBG1(DBG_DMN, " %s [%p]", info.dli_fname, ptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#endif /* HAVE_DLADDR */
|
|
||||||
DBG1(DBG_DMN, " %s", strings[i]);
|
|
||||||
#ifdef HAVE_DLADDR
|
|
||||||
}
|
|
||||||
#endif /* HAVE_DLADDR */
|
|
||||||
}
|
|
||||||
free (strings);
|
|
||||||
#else /* !HAVE_BACKTRACE */
|
|
||||||
DBG1(DBG_DMN, "thread %u received %s",
|
|
||||||
pthread_self(), signal == SIGSEGV ? "SIGSEGV" : "SIGILL");
|
|
||||||
#endif /* HAVE_BACKTRACE */
|
|
||||||
DBG1(DBG_DMN, "killing ourself, received critical signal");
|
DBG1(DBG_DMN, "killing ourself, received critical signal");
|
||||||
raise(SIGKILL);
|
raise(SIGKILL);
|
||||||
}
|
}
|
||||||
@@ -534,6 +495,7 @@ private_daemon_t *daemon_create(void)
|
|||||||
sigaddset(&action.sa_mask, SIGHUP);
|
sigaddset(&action.sa_mask, SIGHUP);
|
||||||
sigaction(SIGSEGV, &action, NULL);
|
sigaction(SIGSEGV, &action, NULL);
|
||||||
sigaction(SIGILL, &action, NULL);
|
sigaction(SIGILL, &action, NULL);
|
||||||
|
sigaction(SIGBUS, &action, NULL);
|
||||||
action.sa_handler = SIG_IGN;
|
action.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGPIPE, &action, NULL);
|
sigaction(SIGPIPE, &action, NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ utils/linked_list.c utils/linked_list.h \
|
|||||||
utils/enumerator.c utils/enumerator.h \
|
utils/enumerator.c utils/enumerator.h \
|
||||||
utils/optionsfrom.c utils/optionsfrom.h \
|
utils/optionsfrom.c utils/optionsfrom.h \
|
||||||
utils/mutex.c utils/mutex.h \
|
utils/mutex.c utils/mutex.h \
|
||||||
|
utils/backtrace.c utils/backtrace.h \
|
||||||
plugins/plugin_loader.c plugins/plugin_loader.h plugins/plugin.h
|
plugins/plugin_loader.c plugins/plugin_loader.h plugins/plugin.h
|
||||||
|
|
||||||
libstrongswan_la_LIBADD = -lpthread -ldl
|
libstrongswan_la_LIBADD = -lpthread -ldl
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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_ @}*/
|
||||||
|
|
||||||
@@ -15,11 +15,6 @@
|
|||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_DLADDR
|
|
||||||
# define _GNU_SOURCE
|
|
||||||
# include <dlfcn.h>
|
|
||||||
#endif /* HAVE_DLADDR */
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -28,21 +23,18 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <printf.h>
|
#include <printf.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#ifdef HAVE_BACKTRACE
|
|
||||||
# include <execinfo.h>
|
|
||||||
#endif /* HAVE_BACKTRACE */
|
|
||||||
|
|
||||||
#include "leak_detective.h"
|
#include "leak_detective.h"
|
||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
#include <utils/backtrace.h>
|
||||||
|
|
||||||
typedef struct private_leak_detective_t private_leak_detective_t;
|
typedef struct private_leak_detective_t private_leak_detective_t;
|
||||||
|
|
||||||
@@ -105,16 +97,6 @@ struct memory_header_t {
|
|||||||
*/
|
*/
|
||||||
u_int bytes;
|
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
|
* Pointer to previous entry in linked list
|
||||||
*/
|
*/
|
||||||
@@ -125,6 +107,11 @@ struct memory_header_t {
|
|||||||
*/
|
*/
|
||||||
memory_header_t *next;
|
memory_header_t *next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* backtrace taken during (re-)allocation
|
||||||
|
*/
|
||||||
|
backtrace_t *backtrace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC
|
* magic bytes to detect bad free or heap underflow, MEMORY_HEADER_MAGIC
|
||||||
*/
|
*/
|
||||||
@@ -151,7 +138,7 @@ struct memory_tail_t {
|
|||||||
static memory_header_t first_header = {
|
static memory_header_t first_header = {
|
||||||
magic: MEMORY_HEADER_MAGIC,
|
magic: MEMORY_HEADER_MAGIC,
|
||||||
bytes: 0,
|
bytes: 0,
|
||||||
stack_frame_count: 0,
|
backtrace: NULL,
|
||||||
previous: NULL,
|
previous: NULL,
|
||||||
next: NULL
|
next: NULL
|
||||||
};
|
};
|
||||||
@@ -161,76 +148,6 @@ static memory_header_t first_header = {
|
|||||||
*/
|
*/
|
||||||
static bool installed = FALSE;
|
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
|
* Leak report white list
|
||||||
*
|
*
|
||||||
@@ -238,6 +155,8 @@ static void log_stack_frames(void **stack_frames, int stack_frame_count)
|
|||||||
* otherwise on leak report.
|
* otherwise on leak report.
|
||||||
*/
|
*/
|
||||||
char *whitelist[] = {
|
char *whitelist[] = {
|
||||||
|
/* backtraces, including own */
|
||||||
|
"backtrace_create",
|
||||||
/* pthread stuff */
|
/* pthread stuff */
|
||||||
"pthread_create",
|
"pthread_create",
|
||||||
"pthread_setspecific",
|
"pthread_setspecific",
|
||||||
@@ -284,27 +203,16 @@ char *whitelist[] = {
|
|||||||
/**
|
/**
|
||||||
* check if a stack frame contains functions listed above
|
* 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;
|
int i;
|
||||||
|
for (i = 0; i < sizeof(whitelist)/sizeof(char*); i++)
|
||||||
#ifdef HAVE_DLADDR
|
|
||||||
for (i=0; i< stack_frame_count; i++)
|
|
||||||
{
|
{
|
||||||
Dl_info info;
|
if (backtrace->contains_function(backtrace, whitelist[i]))
|
||||||
|
|
||||||
if (dladdr(stack_frames[i], &info) && info.dli_sname)
|
|
||||||
{
|
{
|
||||||
for (j = 0; j < sizeof(whitelist)/sizeof(char*); j++)
|
return TRUE;
|
||||||
{
|
|
||||||
if (streq(info.dli_sname, whitelist[j]))
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* HAVE_DLADDR */
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +226,7 @@ void report_leaks()
|
|||||||
|
|
||||||
for (hdr = first_header.next; hdr != NULL; hdr = hdr->next)
|
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++;
|
whitelisted++;
|
||||||
}
|
}
|
||||||
@@ -326,7 +234,7 @@ void report_leaks()
|
|||||||
{
|
{
|
||||||
fprintf(stderr, "Leak (%d bytes at %p):\n", hdr->bytes, hdr + 1);
|
fprintf(stderr, "Leak (%d bytes at %p):\n", hdr->bytes, hdr + 1);
|
||||||
/* skip the first frame, contains leak detective logic */
|
/* 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++;
|
leaks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,7 +311,7 @@ void *malloc_hook(size_t bytes, const void *caller)
|
|||||||
|
|
||||||
hdr->magic = MEMORY_HEADER_MAGIC;
|
hdr->magic = MEMORY_HEADER_MAGIC;
|
||||||
hdr->bytes = bytes;
|
hdr->bytes = bytes;
|
||||||
hdr->stack_frame_count = backtrace(hdr->stack_frames, STACK_FRAMES_COUNT);
|
hdr->backtrace = backtrace_create(3);
|
||||||
tail->magic = MEMORY_TAIL_MAGIC;
|
tail->magic = MEMORY_TAIL_MAGIC;
|
||||||
install_hooks();
|
install_hooks();
|
||||||
|
|
||||||
@@ -426,10 +334,9 @@ void *malloc_hook(size_t bytes, const void *caller)
|
|||||||
*/
|
*/
|
||||||
void free_hook(void *ptr, 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_header_t *hdr;
|
||||||
memory_tail_t *tail;
|
memory_tail_t *tail;
|
||||||
|
backtrace_t *backtrace;
|
||||||
pthread_t thread_id = pthread_self();
|
pthread_t thread_id = pthread_self();
|
||||||
int oldpolicy;
|
int oldpolicy;
|
||||||
struct sched_param oldparams, params;
|
struct sched_param oldparams, params;
|
||||||
@@ -455,8 +362,9 @@ void free_hook(void *ptr, const void *caller)
|
|||||||
fprintf(stderr, "freeing invalid memory (%p): "
|
fprintf(stderr, "freeing invalid memory (%p): "
|
||||||
"header magic 0x%x, tail magic 0x%x:\n",
|
"header magic 0x%x, tail magic 0x%x:\n",
|
||||||
ptr, hdr->magic, tail->magic);
|
ptr, hdr->magic, tail->magic);
|
||||||
stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT);
|
backtrace = backtrace_create(3);
|
||||||
log_stack_frames(stack_frames, stack_frame_count);
|
backtrace->log(backtrace, stderr);
|
||||||
|
backtrace->destroy(backtrace);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -466,6 +374,7 @@ void free_hook(void *ptr, const void *caller)
|
|||||||
hdr->next->previous = hdr->previous;
|
hdr->next->previous = hdr->previous;
|
||||||
}
|
}
|
||||||
hdr->previous->next = hdr->next;
|
hdr->previous->next = hdr->next;
|
||||||
|
hdr->backtrace->destroy(hdr->backtrace);
|
||||||
|
|
||||||
/* clear MAGIC, set mem to something remarkable */
|
/* clear MAGIC, set mem to something remarkable */
|
||||||
memset(hdr, MEMORY_FREE_PATTERN, hdr->bytes + sizeof(memory_header_t));
|
memset(hdr, MEMORY_FREE_PATTERN, hdr->bytes + sizeof(memory_header_t));
|
||||||
@@ -483,9 +392,8 @@ void free_hook(void *ptr, const void *caller)
|
|||||||
void *realloc_hook(void *old, size_t bytes, const void *caller)
|
void *realloc_hook(void *old, size_t bytes, const void *caller)
|
||||||
{
|
{
|
||||||
memory_header_t *hdr;
|
memory_header_t *hdr;
|
||||||
void *stack_frames[STACK_FRAMES_COUNT];
|
|
||||||
int stack_frame_count;
|
|
||||||
memory_tail_t *tail;
|
memory_tail_t *tail;
|
||||||
|
backtrace_t *backtrace;
|
||||||
pthread_t thread_id = pthread_self();
|
pthread_t thread_id = pthread_self();
|
||||||
int oldpolicy;
|
int oldpolicy;
|
||||||
struct sched_param oldparams, params;
|
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): "
|
fprintf(stderr, "reallocating invalid memory (%p): "
|
||||||
"header magic 0x%x, tail magic 0x%x:\n",
|
"header magic 0x%x, tail magic 0x%x:\n",
|
||||||
old, hdr->magic, tail->magic);
|
old, hdr->magic, tail->magic);
|
||||||
stack_frame_count = backtrace(stack_frames, STACK_FRAMES_COUNT);
|
backtrace = backtrace_create(3);
|
||||||
log_stack_frames(stack_frames, stack_frame_count);
|
backtrace->log(backtrace, stderr);
|
||||||
|
backtrace->destroy(backtrace);
|
||||||
}
|
}
|
||||||
/* clear tail magic, allocate, set tail magic */
|
/* clear tail magic, allocate, set tail magic */
|
||||||
memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(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 */
|
/* update statistics */
|
||||||
hdr->bytes = bytes;
|
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 */
|
/* update header of linked list neighbours */
|
||||||
if (hdr->next)
|
if (hdr->next)
|
||||||
|
|||||||
@@ -21,11 +21,6 @@
|
|||||||
#ifndef LEAK_DETECTIVE_H_
|
#ifndef LEAK_DETECTIVE_H_
|
||||||
#define 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;
|
typedef struct leak_detective_t leak_detective_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
#include <utils/backtrace.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@@ -53,14 +54,9 @@ struct private_mutex_t {
|
|||||||
struct timeval waited;
|
struct timeval waited;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creator of the mutex
|
* backtrace where mutex has been created
|
||||||
*/
|
*/
|
||||||
void *stack[10];
|
backtrace_t *backtrace;
|
||||||
|
|
||||||
/**
|
|
||||||
* number of pointers in stack
|
|
||||||
*/
|
|
||||||
int stack_size;
|
|
||||||
#endif /* LOCK_PROFILER */
|
#endif /* LOCK_PROFILER */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,23 +107,22 @@ struct private_condvar_t {
|
|||||||
#include <execinfo.h>
|
#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;
|
fprintf(stderr, "waited %d.%06ds in mutex, created at:",
|
||||||
|
this->waited.tv_sec, this->waited.tv_usec);
|
||||||
DBG1("waited %d.%06ds in mutex, created at:",
|
this->backtrace->log(this->backtrace, stderr);
|
||||||
this->waited.tv_sec, this->waited.tv_usec);
|
this->backtrace->destroy(this->backtrace);
|
||||||
for (i = 0; i < this->stack_size; i++)
|
|
||||||
{
|
|
||||||
DBG1(" %p", this->stack[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
timerclear(&this->waited);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,8 +146,8 @@ static void lock(private_mutex_t *this)
|
|||||||
#else /* !LOCK_PROFILER */
|
#else /* !LOCK_PROFILER */
|
||||||
|
|
||||||
/** dummy implementations */
|
/** dummy implementations */
|
||||||
static void print_stats(private_mutex_t *this) {}
|
static void profiler_cleanup(private_mutex_t *this) {}
|
||||||
static void init_stats(private_mutex_t *this) {}
|
static void profiler_init(private_mutex_t *this) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of mutex_t.lock.
|
* 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)
|
static void mutex_destroy(private_mutex_t *this)
|
||||||
{
|
{
|
||||||
print_stats(this);
|
profiler_cleanup(this);
|
||||||
pthread_mutex_destroy(&this->mutex);
|
pthread_mutex_destroy(&this->mutex);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
@@ -234,7 +229,7 @@ static void mutex_destroy(private_mutex_t *this)
|
|||||||
*/
|
*/
|
||||||
static void mutex_destroy_r(private_r_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_mutex_destroy(&this->generic.mutex);
|
||||||
pthread_key_delete(this->times);
|
pthread_key_delete(this->times);
|
||||||
free(this);
|
free(this);
|
||||||
@@ -258,7 +253,7 @@ mutex_t *mutex_create(mutex_type_t type)
|
|||||||
pthread_mutex_init(&this->generic.mutex, NULL);
|
pthread_mutex_init(&this->generic.mutex, NULL);
|
||||||
pthread_key_create(&this->times, NULL);
|
pthread_key_create(&this->times, NULL);
|
||||||
this->generic.recursive = TRUE;
|
this->generic.recursive = TRUE;
|
||||||
init_stats(&this->generic);
|
profiler_init(&this->generic);
|
||||||
this->thread = 0;
|
this->thread = 0;
|
||||||
|
|
||||||
return &this->generic.public;
|
return &this->generic.public;
|
||||||
@@ -274,7 +269,7 @@ mutex_t *mutex_create(mutex_type_t type)
|
|||||||
|
|
||||||
pthread_mutex_init(&this->mutex, NULL);
|
pthread_mutex_init(&this->mutex, NULL);
|
||||||
this->recursive = FALSE;
|
this->recursive = FALSE;
|
||||||
init_stats(this);
|
profiler_init(this);
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user