Option to skip slow addr2line resolution in leak-detective

This commit is contained in:
Martin Willi 2010-05-19 15:22:12 +02:00
parent 36c1650b19
commit 091d178060
7 changed files with 81 additions and 54 deletions

View File

@ -190,7 +190,7 @@ static void segv_handler(int signal)
DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal);
backtrace = backtrace_create(2); backtrace = backtrace_create(2);
backtrace->log(backtrace, stderr); backtrace->log(backtrace, stderr, TRUE);
backtrace->destroy(backtrace); backtrace->destroy(backtrace);
DBG1(DBG_DMN, "killing ourself, received critical signal"); DBG1(DBG_DMN, "killing ourself, received critical signal");

View File

@ -59,6 +59,10 @@ library_t *lib;
void library_deinit() void library_deinit()
{ {
private_library_t *this = (private_library_t*)lib; private_library_t *this = (private_library_t*)lib;
bool detailed;
detailed = lib->settings->get_bool(lib->settings,
"libstrongswan.leak_detective.detailed", TRUE);
this->public.plugins->destroy(this->public.plugins); this->public.plugins->destroy(this->public.plugins);
this->public.settings->destroy(this->public.settings); this->public.settings->destroy(this->public.settings);
@ -76,6 +80,7 @@ void library_deinit()
#ifdef LEAK_DETECTIVE #ifdef LEAK_DETECTIVE
if (this->detective) if (this->detective)
{ {
this->detective->report(this->detective, detailed);
this->detective->destroy(this->detective); this->detective->destroy(this->detective);
} }
#endif /* LEAK_DETECTIVE */ #endif /* LEAK_DETECTIVE */

View File

@ -63,7 +63,7 @@ static inline void profiler_cleanup(lock_profile_t *profile)
{ {
fprintf(stderr, "%d.%03ds / %d times in lock created at:", fprintf(stderr, "%d.%03ds / %d times in lock created at:",
profile->waited.tv_sec, profile->waited.tv_usec, profile->locked); profile->waited.tv_sec, profile->waited.tv_usec, profile->locked);
profile->backtrace->log(profile->backtrace, stderr); profile->backtrace->log(profile->backtrace, stderr, TRUE);
} }
profile->backtrace->destroy(profile->backtrace); profile->backtrace->destroy(profile->backtrace);
} }

View File

@ -53,7 +53,7 @@ struct private_backtrace_t {
/** /**
* Implementation of backtrace_t.log * Implementation of backtrace_t.log
*/ */
static void log_(private_backtrace_t *this, FILE *file) static void log_(private_backtrace_t *this, FILE *file, bool detailed)
{ {
#ifdef HAVE_BACKTRACE #ifdef HAVE_BACKTRACE
size_t i; size_t i;
@ -78,7 +78,6 @@ static void log_(private_backtrace_t *this, FILE *file)
{ {
ptr = (void*)(this->frames[i] - info.dli_fbase); ptr = (void*)(this->frames[i] - info.dli_fbase);
} }
snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", info.dli_fname, ptr);
if (info.dli_sname) if (info.dli_sname)
{ {
fprintf(file, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%x) [%p]\n", fprintf(file, " \e[33m%s\e[0m @ %p (\e[31m%s\e[0m+0x%x) [%p]\n",
@ -90,7 +89,11 @@ static void log_(private_backtrace_t *this, FILE *file)
fprintf(file, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname, fprintf(file, " \e[33m%s\e[0m @ %p [%p]\n", info.dli_fname,
info.dli_fbase, this->frames[i]); info.dli_fbase, this->frames[i]);
} }
if (detailed)
{
fprintf(file, " -> \e[32m"); fprintf(file, " -> \e[32m");
snprintf(cmd, sizeof(cmd), "addr2line -e %s %p",
info.dli_fname, ptr);
output = popen(cmd, "r"); output = popen(cmd, "r");
if (output) if (output)
{ {
@ -113,6 +116,7 @@ static void log_(private_backtrace_t *this, FILE *file)
} }
fprintf(file, "\n\e[0m"); fprintf(file, "\n\e[0m");
} }
}
else else
{ {
fprintf(file, " %s\n", strings[i]); fprintf(file, " %s\n", strings[i]);
@ -174,7 +178,7 @@ backtrace_t *backtrace_create(int skip)
memcpy(this->frames, frames + skip, frame_count * sizeof(void*)); memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
this->frame_count = frame_count; this->frame_count = frame_count;
this->public.log = (void(*)(backtrace_t*,FILE*))log_; this->public.log = (void(*)(backtrace_t*,FILE*,bool))log_;
this->public.contains_function = (bool(*)(backtrace_t*, char *function))contains_function; this->public.contains_function = (bool(*)(backtrace_t*, char *function))contains_function;
this->public.destroy = (void(*)(backtrace_t*))destroy; this->public.destroy = (void(*)(backtrace_t*))destroy;

View File

@ -34,8 +34,11 @@ struct backtrace_t {
/** /**
* Log the backtrace to a FILE stream. * Log the backtrace to a FILE stream.
*
* @param file FILE to log backtrace to
* @param detailed TRUE to resolve line/file using addr2line (slow)
*/ */
void (*log)(backtrace_t *this, FILE *file); void (*log)(backtrace_t *this, FILE *file, bool detailed);
/** /**
* Check if the backtrace contains a frame in a specific function. * Check if the backtrace contains a frame in a specific function.

View File

@ -233,7 +233,9 @@ static bool is_whitelisted(backtrace_t *backtrace)
/** /**
* Report leaks at library destruction * Report leaks at library destruction
*/ */
void report_leaks() static void report(private_leak_detective_t *this, bool detailed)
{
if (lib->leak_detective)
{ {
memory_header_t *hdr; memory_header_t *hdr;
int leaks = 0, whitelisted = 0; int leaks = 0, whitelisted = 0;
@ -248,11 +250,10 @@ 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 */
hdr->backtrace->log(hdr->backtrace, stderr); hdr->backtrace->log(hdr->backtrace, stderr, detailed);
leaks++; leaks++;
} }
} }
switch (leaks) switch (leaks)
{ {
case 0: case 0:
@ -267,6 +268,11 @@ void report_leaks()
} }
fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted); fprintf(stderr, ", %d suppressed by whitelist\n", whitelisted);
} }
else
{
fprintf(stderr, "Leak detective disabled\n");
}
}
/** /**
* Installs the malloc hooks, enables leak detection * Installs the malloc hooks, enables leak detection
@ -395,7 +401,7 @@ void free_hook(void *ptr, const void *caller)
fprintf(stderr, "freeing invalid memory (%p)", ptr); fprintf(stderr, "freeing invalid memory (%p)", ptr);
} }
backtrace = backtrace_create(3); backtrace = backtrace_create(3);
backtrace->log(backtrace, stderr); backtrace->log(backtrace, stderr, TRUE);
backtrace->destroy(backtrace); backtrace->destroy(backtrace);
} }
else else
@ -454,7 +460,7 @@ void *realloc_hook(void *old, size_t bytes, const void *caller)
"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);
backtrace = backtrace_create(3); backtrace = backtrace_create(3);
backtrace->log(backtrace, stderr); backtrace->log(backtrace, stderr, TRUE);
backtrace->destroy(backtrace); backtrace->destroy(backtrace);
} }
/* clear tail magic, allocate, set tail magic */ /* clear tail magic, allocate, set tail magic */
@ -487,7 +493,6 @@ static void destroy(private_leak_detective_t *this)
if (installed) if (installed)
{ {
uninstall_hooks(); uninstall_hooks();
report_leaks();
} }
free(this); free(this);
} }
@ -499,6 +504,7 @@ leak_detective_t *leak_detective_create()
{ {
private_leak_detective_t *this = malloc_thing(private_leak_detective_t); private_leak_detective_t *this = malloc_thing(private_leak_detective_t);
this->public.report = (void(*)(leak_detective_t*,bool))report;
this->public.destroy = (void(*)(leak_detective_t*))destroy; this->public.destroy = (void(*)(leak_detective_t*))destroy;
if (getenv("LEAK_DETECTIVE_DISABLE") == NULL) if (getenv("LEAK_DETECTIVE_DISABLE") == NULL)

View File

@ -23,6 +23,8 @@
typedef struct leak_detective_t leak_detective_t; typedef struct leak_detective_t leak_detective_t;
#include <library.h>
/** /**
* Leak detective finds leaks and bad frees using malloc hooks. * Leak detective finds leaks and bad frees using malloc hooks.
* *
@ -33,6 +35,13 @@ typedef struct leak_detective_t leak_detective_t;
*/ */
struct leak_detective_t { struct leak_detective_t {
/**
* Report leaks to stderr.
*
* @param detailed TRUE to resolve line/filename of leak (slow)
*/
void (*report)(leak_detective_t *this, bool detailed);
/** /**
* Destroy a leak_detective instance. * Destroy a leak_detective instance.
*/ */