/* * uhub - A tiny ADC p2p connection hub * Copyright (C) 2007-2009, Jan Vidar Krey * * 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 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "uhub.h" #ifdef MEMORY_DEBUG #define REALTIME_MALLOC_TRACKING #ifdef REALTIME_MALLOC_TRACKING #define UHUB_MAX_ALLOCS 50000 struct malloc_info { void* ptr; size_t size; void* stack1; void* stack2; }; static int hub_alloc_count = 0; static size_t hub_alloc_size = 0; static int hub_alloc_peak_count = 0; static size_t hub_alloc_peak_size = 0; static size_t hub_alloc_oom = 0; static struct malloc_info hub_allocs[UHUB_MAX_ALLOCS] = { { 0, }, }; static int malloc_slot = -1; /* free slot (-1, no slot) */ void internal_debug_print_leaks() { size_t n = 0; size_t leak = 0; size_t count = 0; LOG_MEMORY("--- exit (allocs: %d, size: " PRINTF_SIZE_T ") ---", hub_alloc_count, hub_alloc_size); for (; n < UHUB_MAX_ALLOCS; n++) { if (hub_allocs[n].ptr) { leak += hub_allocs[n].size; count++; LOG_MEMORY("leak %p size: " PRINTF_SIZE_T " (bt: %p %p)", hub_allocs[n].ptr, hub_allocs[n].size, hub_allocs[n].stack1, hub_allocs[n].stack2); } } LOG_MEMORY("--- done (allocs: %d, size: " PRINTF_SIZE_T ", peak: %d/" PRINTF_SIZE_T ", oom: " PRINTF_SIZE_T ") ---", count, leak, hub_alloc_peak_count, hub_alloc_peak_size, hub_alloc_oom); } #endif /* REALTIME_MALLOC_TRACKING */ void* internal_debug_mem_malloc(size_t size, const char* where) { size_t n = 0; char* ptr = malloc(size); #ifdef REALTIME_MALLOC_TRACKING /* Make sure the malloc info struct is initialized */ if (!hub_alloc_count) { LOG_MEMORY("--- start ---"); for (n = 0; n < UHUB_MAX_ALLOCS; n++) { hub_allocs[n].ptr = 0; hub_allocs[n].size = 0; hub_allocs[n].stack1 = 0; hub_allocs[n].stack2 = 0; } atexit(&internal_debug_print_leaks); } if (ptr) { if (malloc_slot != -1) n = (size_t) malloc_slot; else n = 0; for (; n < UHUB_MAX_ALLOCS; n++) { if (!hub_allocs[n].ptr) { hub_allocs[n].ptr = ptr; hub_allocs[n].size = size; hub_allocs[n].stack1 = __builtin_return_address(1); hub_allocs[n].stack2 = __builtin_return_address(2); hub_alloc_size += size; hub_alloc_count++; hub_alloc_peak_count = MAX(hub_alloc_count, hub_alloc_peak_count); hub_alloc_peak_size = MAX(hub_alloc_size, hub_alloc_peak_size); LOG_MEMORY("%s %p (%d bytes) (bt: %p %p) {allocs: %d, size: " PRINTF_SIZE_T "}", where, ptr, (int) size, hub_allocs[n].stack1, hub_allocs[n].stack2, hub_alloc_count, hub_alloc_size); break; } } } else { LOG_MEMORY("%s *** OOM for %d bytes", where, size); hub_alloc_oom++; return 0; } #endif /* REALTIME_MALLOC_TRACKING */ return ptr; } void internal_debug_mem_free(void* ptr) { #ifdef REALTIME_MALLOC_TRACKING size_t n = 0; void* stack1 = __builtin_return_address(1); void* stack2 = __builtin_return_address(2); if (!ptr) return; for (; n < UHUB_MAX_ALLOCS; n++) { if (hub_allocs[n].ptr == ptr) { hub_alloc_size -= hub_allocs[n].size; hub_alloc_count--; hub_allocs[n].ptr = 0; hub_allocs[n].size = 0; hub_allocs[n].stack1 = 0; hub_allocs[n].stack2 = 0; LOG_MEMORY("free %p (bt: %p %p) {allocs: %d, size: " PRINTF_SIZE_T "}", ptr, stack1, stack2, hub_alloc_count, hub_alloc_size); malloc_slot = n; free(ptr); return; } } malloc_slot = -1; abort(); LOG_MEMORY("free %p *** NOT ALLOCATED *** (bt: %p %p)", ptr, stack1, stack2); #else free(ptr); #endif /* REALTIME_MALLOC_TRACKING */ } char* debug_mem_strdup(const char* s) { size_t size = strlen(s); char* ptr = internal_debug_mem_malloc(size+1, "strdup"); if (ptr) { memcpy(ptr, s, size); ptr[size] = 0; } return ptr; } char* debug_mem_strndup(const char* s, size_t n) { size_t size = MIN(strlen(s), n); char* ptr = internal_debug_mem_malloc(size+1, "strndup"); if (ptr) { memcpy(ptr, s, size); ptr[size] = 0; } return ptr; } void* debug_mem_malloc(size_t size) { void* ptr = internal_debug_mem_malloc(size, "malloc"); return ptr; } void debug_mem_free(void *ptr) { internal_debug_mem_free(ptr); } #endif void* hub_malloc_zero(size_t size) { void* data = hub_malloc(size); if (data) { memset(data, 0, size); } return data; } #ifdef DEBUG_FUNCTION_TRACE #define FTRACE_LOG "ftrace.log" static FILE* functrace = 0; void main_constructor() __attribute__ ((no_instrument_function, constructor)); void main_deconstructor() __attribute__ ((no_instrument_function, destructor)); void __cyg_profile_func_enter(void* frame, void* callsite) __attribute__ ((no_instrument_function)); void __cyg_profile_func_exit(void* frame, void* callsite) __attribute__ ((no_instrument_function)); void main_constructor() { functrace = fopen(FTRACE_LOG, "w"); if (functrace == NULL) { fprintf(stderr, "Cannot create function trace file: " FTRACE_LOG "\n"); exit(-1); } } void main_deconstructor() { fclose(functrace); } void __cyg_profile_func_enter(void* frame, void* callsite) { if (functrace) fprintf(functrace, "E%p\n", frame); } void __cyg_profile_func_exit(void* frame, void* callsite) { if (functrace) fprintf(functrace, "X%p\n", frame); } #endif /* DEBUG_FUNCTION_TRACE */