1 /*
2  * uhub - A tiny ADC p2p connection hub
3  * Copyright (C) 2007-2014, Jan Vidar Krey
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "uhub.h"
21 
22 #ifdef MEMORY_DEBUG
23 
24 #define REALTIME_MALLOC_TRACKING
25 
26 #ifdef REALTIME_MALLOC_TRACKING
27 #define UHUB_MAX_ALLOCS 50000
28 struct malloc_info
29 {
30 	void* ptr;
31 	size_t size;
32 	void* stack1;
33 	void* stack2;
34 };
35 
36 static int hub_alloc_count = 0;
37 static size_t hub_alloc_size  = 0;
38 static int hub_alloc_peak_count = 0;
39 static size_t hub_alloc_peak_size  = 0;
40 static size_t hub_alloc_oom = 0;
41 
42 static struct malloc_info hub_allocs[UHUB_MAX_ALLOCS] = { { 0, },  };
43 static int    malloc_slot = -1; /* free slot (-1, no slot) */
44 
internal_debug_print_leaks()45 void internal_debug_print_leaks()
46 {
47 	size_t n = 0;
48 	size_t leak = 0;
49 	size_t count = 0;
50 	LOG_MEMORY("--- exit (allocs: %d, size: " PRINTF_SIZE_T ") ---", hub_alloc_count, hub_alloc_size);
51 
52 	for (; n < UHUB_MAX_ALLOCS; n++)
53 	{
54 		if (hub_allocs[n].ptr)
55 		{
56 			leak += hub_allocs[n].size;
57 			count++;
58 			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);
59 		}
60 	}
61 
62 	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);
63 }
64 #endif /* REALTIME_MALLOC_TRACKING */
65 
internal_debug_mem_malloc(size_t size,const char * where)66 void* internal_debug_mem_malloc(size_t size, const char* where)
67 {
68 	size_t n = 0;
69 	char* ptr = malloc(size);
70 
71 #ifdef REALTIME_MALLOC_TRACKING
72 
73 	/* Make sure the malloc info struct is initialized */
74 	if (!hub_alloc_count)
75 	{
76 		LOG_MEMORY("--- start ---");
77 		for (n = 0; n < UHUB_MAX_ALLOCS; n++)
78 		{
79 			hub_allocs[n].ptr    = 0;
80 			hub_allocs[n].size   = 0;
81 			hub_allocs[n].stack1 = 0;
82 			hub_allocs[n].stack2 = 0;
83 		}
84 
85 		atexit(&internal_debug_print_leaks);
86 	}
87 
88 	if (ptr)
89 	{
90 		if (malloc_slot != -1)
91 			n = (size_t) malloc_slot;
92 		else
93 			n = 0;
94 
95 		for (; n < UHUB_MAX_ALLOCS; n++)
96 		{
97 			if (!hub_allocs[n].ptr)
98 			{
99 				hub_allocs[n].ptr    = ptr;
100 				hub_allocs[n].size   = size;
101 				hub_allocs[n].stack1 = __builtin_return_address(1);
102 				hub_allocs[n].stack2 = __builtin_return_address(2);
103 
104 				hub_alloc_size += size;
105 				hub_alloc_count++;
106 
107 				hub_alloc_peak_count = MAX(hub_alloc_count, hub_alloc_peak_count);
108 				hub_alloc_peak_size  = MAX(hub_alloc_size,  hub_alloc_peak_size);
109 
110 				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);
111 				break;
112 			}
113 		}
114 	}
115 	else
116 	{
117 		LOG_MEMORY("%s *** OOM for %d bytes", where, size);
118 		hub_alloc_oom++;
119 		return 0;
120 	}
121 #endif /* REALTIME_MALLOC_TRACKING */
122 	return ptr;
123 }
124 
internal_debug_mem_free(void * ptr)125 void internal_debug_mem_free(void* ptr)
126 {
127 #ifdef REALTIME_MALLOC_TRACKING
128 	size_t n = 0;
129 	void* stack1 = __builtin_return_address(1);
130 	void* stack2 = __builtin_return_address(2);
131 
132 	if (!ptr) return;
133 
134 	for (; n < UHUB_MAX_ALLOCS; n++)
135 	{
136 		if (hub_allocs[n].ptr == ptr)
137 		{
138 			hub_alloc_size -= hub_allocs[n].size;
139 			hub_alloc_count--;
140 			hub_allocs[n].ptr    = 0;
141 			hub_allocs[n].size   = 0;
142 			hub_allocs[n].stack1 = 0;
143 			hub_allocs[n].stack2 = 0;
144 			LOG_MEMORY("free %p (bt: %p %p) {allocs: %d, size: " PRINTF_SIZE_T "}", ptr, stack1, stack2, hub_alloc_count, hub_alloc_size);
145 			malloc_slot = n;
146 			free(ptr);
147 			return;
148 		}
149 	}
150 
151 	malloc_slot = -1;
152 	abort();
153 	LOG_MEMORY("free %p *** NOT ALLOCATED *** (bt: %p %p)", ptr, stack1, stack2);
154 #else
155 	free(ptr);
156 #endif /* REALTIME_MALLOC_TRACKING */
157 }
158 
debug_mem_strdup(const char * s)159 char* debug_mem_strdup(const char* s)
160 {
161 	size_t size = strlen(s);
162 	char* ptr = internal_debug_mem_malloc(size+1, "strdup");
163 	if (ptr)
164 	{
165 		memcpy(ptr, s, size);
166 		ptr[size] = 0;
167 	}
168 	return ptr;
169 }
170 
debug_mem_strndup(const char * s,size_t n)171 char* debug_mem_strndup(const char* s, size_t n)
172 {
173 	size_t size = MIN(strlen(s), n);
174 	char* ptr = internal_debug_mem_malloc(size+1, "strndup");
175 	if (ptr)
176 	{
177 		memcpy(ptr, s, size);
178 		ptr[size] = 0;
179 	}
180 	return ptr;
181 }
182 
debug_mem_malloc(size_t size)183 void* debug_mem_malloc(size_t size)
184 {
185 	void* ptr = internal_debug_mem_malloc(size, "malloc");
186 	return ptr;
187 }
188 
debug_mem_free(void * ptr)189 void debug_mem_free(void *ptr)
190 {
191 	internal_debug_mem_free(ptr);
192 }
193 
194 
195 #endif
196 
hub_malloc_zero(size_t size)197 void* hub_malloc_zero(size_t size)
198 {
199 	void* data = hub_malloc(size);
200 	if (data)
201 	{
202 		memset(data, 0, size);
203 	}
204 	return data;
205 }
206 
207 #ifdef DEBUG_FUNCTION_TRACE
208 #define FTRACE_LOG "ftrace.log"
209 static FILE* functrace = 0;
210 
211 void main_constructor() __attribute__ ((no_instrument_function, constructor));
212 void main_deconstructor() __attribute__ ((no_instrument_function, destructor));
213 void __cyg_profile_func_enter(void* frame, void* callsite) __attribute__ ((no_instrument_function));
214 void __cyg_profile_func_exit(void* frame, void* callsite) __attribute__ ((no_instrument_function));
215 
216 
main_constructor()217 void main_constructor()
218 {
219 	functrace = fopen(FTRACE_LOG, "w");
220 	if (functrace == NULL)
221 	{
222 		fprintf(stderr, "Cannot create function trace file: " FTRACE_LOG "\n");
223 		exit(-1);
224 	}
225 }
226 
227 
main_deconstructor()228 void main_deconstructor()
229 {
230 	fclose(functrace);
231 }
232 
233 
__cyg_profile_func_enter(void * frame,void * callsite)234 void __cyg_profile_func_enter(void* frame, void* callsite)
235 {
236 	if (functrace)
237 		fprintf(functrace, "E%p\n", frame);
238 }
239 
__cyg_profile_func_exit(void * frame,void * callsite)240 void __cyg_profile_func_exit(void* frame, void* callsite)
241 {
242 	if (functrace)
243 		fprintf(functrace, "X%p\n", frame);
244 }
245 
246 #endif /* DEBUG_FUNCTION_TRACE */
247 
248 
249