freewtp/lib/debug.c

179 lines
4.1 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef USE_DEBUG_BACKTRACE
#include <execinfo.h>
#endif
#include "logging.h"
#include "error.h"
#define BACKTRACE_BUFFER 256
/* Memory block */
struct capwap_memory_block {
void* item;
size_t size;
const char* file;
int line;
#ifdef USE_DEBUG_BACKTRACE
void* backtrace[BACKTRACE_BUFFER];
int backtrace_count;
#endif
struct capwap_memory_block* next;
};
static struct capwap_memory_block* g_memoryblocks = NULL;
/* Alloc memory block */
void* capwap_alloc_debug(size_t size, const char* file, const int line) {
struct capwap_memory_block* block;
/* Request size > 0 */
if (size <= 0) {
log_printf(LOG_DEBUG, "%s(%d): Invalid memory size %zu", file, line, size);
exit(CAPWAP_ASSERT_CONDITION);
}
/* Alloc block with memory block */
block = (struct capwap_memory_block*)malloc(sizeof(struct capwap_memory_block) + size);
if (!block) {
log_printf(LOG_DEBUG, "Out of memory %s(%d)", file, line);
exit(CAPWAP_OUT_OF_MEMORY);
}
/* Info memory block */
block->item = (void*)(((char*)block) + sizeof(struct capwap_memory_block));
block->size = size;
block->file = file;
block->line = line;
#ifdef USE_DEBUG_BACKTRACE
block->backtrace_count = backtrace(block->backtrace, BACKTRACE_BUFFER);
#endif
block->next = g_memoryblocks;
g_memoryblocks = block;
return block->item;
}
/* Free memory block */
void capwap_free_debug(void* p, const char* file, const int line) {
struct capwap_memory_block* block;
struct capwap_memory_block* findblock;
struct capwap_memory_block* prevblock;
if (!p) {
log_printf(LOG_DEBUG, "%s(%d): Free NULL pointer", file, line);
exit(CAPWAP_ASSERT_CONDITION);
}
/* Memory block */
if ((size_t)p <= sizeof(struct capwap_memory_block)) {
log_printf(LOG_DEBUG, "%s(%d): Invalid pointer", file, line);
exit(CAPWAP_ASSERT_CONDITION);
}
block = (struct capwap_memory_block*)((char*)p - sizeof(struct capwap_memory_block));
if (block->item != p) {
log_printf(LOG_DEBUG, "%s(%d): Invalid pointer", file, line);
exit(CAPWAP_ASSERT_CONDITION);
}
/* Find memory block */
prevblock = NULL;
findblock = g_memoryblocks;
while (findblock != NULL) {
if (findblock == block) {
if (!prevblock) {
g_memoryblocks = block->next;
} else {
prevblock->next = block->next;
}
/* Invalidate block */
memset(block, 0, sizeof(struct capwap_memory_block));
free(block);
return;
}
/* Next */
prevblock = findblock;
findblock = findblock->next;
}
log_printf(LOG_DEBUG, "%s(%d): Unable to find memory block", file, line);
}
/* Dump memory alloced */
void capwap_dump_memory(void) {
#ifdef USE_DEBUG_BACKTRACE
char** backtrace_functions;
#endif
struct capwap_memory_block* findblock;
findblock = g_memoryblocks;
while (findblock != NULL) {
log_printf(LOG_DEBUG, "%s(%d): block at %p, %zu bytes long",
findblock->file, findblock->line, findblock->item, findblock->size);
#ifdef USE_DEBUG_BACKTRACE
backtrace_functions = backtrace_symbols(findblock->backtrace, findblock->backtrace_count);
if (backtrace_functions) {
int j;
/* Skipping capwap_alloc_debug function print out */
for (j = 1; j < findblock->backtrace_count; j++) {
log_printf(LOG_DEBUG, "\t%s", backtrace_functions[j]);
}
free(backtrace_functions);
}
#endif
/* Next */
findblock = findblock->next;
}
}
/* Check if all memory is free */
int capwap_check_memory_leak(int verbose) {
if ((g_memoryblocks != NULL) && (verbose != 0)) {
log_printf(LOG_DEBUG, "*** Detected memory leaks ! ***");
capwap_dump_memory();
log_printf(LOG_DEBUG, "*******************************");
}
return ((g_memoryblocks != NULL) ? 1 : 0);
}
/* Backtrace call stack */
#ifdef USE_DEBUG_BACKTRACE
void capwap_backtrace_callstack(void) {
int i;
int count;
char** functions;
void* buffer[BACKTRACE_BUFFER];
/* */
count = backtrace(buffer, BACKTRACE_BUFFER);
if (count) {
functions = backtrace_symbols(buffer, count);
if (functions) {
/* Skipping capwap_backtrace_callstack function print out */
for (i = 1; i < count; i++) {
log_printf(LOG_DEBUG, "\t%s", functions[i]);
}
free(functions);
}
}
}
#endif