src/main.c: Make it possible to pass options to the app under test
[memprof.git] / lib / memintercept.c
blob19fec5e78966b55602e9522437f51ee840c2e9e2
1 /* -*- mode: C; c-file-style: "linux" -*- */
3 /* MemProf -- memory profiler and leak detector
4 * Copyright 1999, 2000, 2001, Red Hat, Inc.
5 * Copyright 2002, Kristian Rietveld
6 * Copyright 2009, Holger Hans Peter Freyther
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 /*====*/
24 #define _GNU_SOURCE
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <dlfcn.h>
31 #include "intercept.h"
32 #include "memintercept.h"
33 #include "memintercept-utils.h"
34 #include "stack-frame.h"
36 static void *(*old_malloc) (size_t size);
37 static void *(*old_calloc) (size_t nmemb, size_t size);
38 static void *(*old_memalign) (size_t boundary, size_t size);
39 static void *(*old_realloc) (void *ptr, size_t size);
40 static void (*old_free) (void *ptr);
42 /* helpers for WebKit */
43 static void *(*old_fastMalloc) (size_t size);
44 static void *(*old_fastCalloc) (size_t nmemb, size_t size);
45 static void *(*old_fastRealloc) (void *ptr, size_t size);
46 static void (*old_fastFree) (void *ptr);
48 static void
49 abort_unitialized (const char *call)
51 mi_debug ("MemProf: unexpected library call during initialization: %s\n", call);
52 abort();
55 static void *
56 do_malloc (size_t size, int to_skip)
58 void *result;
59 MIInfo info;
61 /* It's possible to get recursion here, since dlsym() can trigger
62 * memory allocation. To deal with this, we flag the initialization
63 * condition specially, then use the special knowledge that it's
64 * OK for malloc to fail during initialization (libc degrades
65 * gracefully), so we just return NULL from malloc(), realloc().
67 * This trick is borrowed from from libc's memusage.
69 if (!mi_check_init ())
70 return NULL;
72 result = (*old_malloc) (size);
74 if (mi_tracing ()) {
75 info.alloc.operation = MI_MALLOC;
76 info.alloc.old_ptr = NULL;
77 info.alloc.new_ptr = result;
78 info.alloc.size = size;
80 mi_call_with_backtrace (to_skip + 1, mi_write_stack, &info);
83 return result;
86 void *
87 __libc_malloc (size_t size)
89 return do_malloc (size, 1);
92 void *
93 malloc (size_t size)
95 return do_malloc (size, 1);
98 static void *
99 do_calloc (size_t nmemb, size_t size)
101 int total = nmemb * size;
102 void *result = do_malloc (total, 2);
104 if (result)
105 memset (result, 0, total);
107 return result;
111 void *
112 __libc_calloc (size_t nmemb, size_t size)
114 return do_calloc (nmemb, size);
117 void *
118 calloc (size_t nmemb, size_t size)
120 return do_calloc (nmemb, size);
123 static void *
124 do_memalign (size_t boundary, size_t size)
126 void *result;
127 MIInfo info;
129 if (!mi_check_init ())
130 abort_unitialized ("memalign");
132 result = (*old_memalign) (boundary, size);
134 if (mi_tracing ()) {
135 info.alloc.operation = MI_MALLOC;
136 info.alloc.old_ptr = NULL;
137 info.alloc.new_ptr = result;
138 info.alloc.size = size;
140 mi_call_with_backtrace (2, mi_write_stack, &info);
143 return result;
146 void *
147 __libc_memalign (size_t boundary, size_t size)
149 return do_memalign (boundary, size);
152 void *
153 memalign (size_t boundary, size_t size)
155 return do_memalign (boundary, size);
158 static void *
159 do_realloc (void *ptr, size_t size)
161 void *result;
162 MIInfo info;
164 if (!mi_check_init ())
165 return NULL;/* See comment in initialize() */
167 result = (*old_realloc) (ptr, size);
169 if (mi_tracing ()) {
170 info.alloc.operation = MI_REALLOC;
171 info.alloc.old_ptr = ptr;
172 info.alloc.new_ptr = result;
173 info.alloc.size = size;
175 mi_call_with_backtrace (2, mi_write_stack, &info);
178 return result;
181 void *
182 __libc_realloc (void *ptr, size_t size)
184 return do_realloc (ptr, size);
187 void *
188 realloc (void *ptr, size_t size)
190 return do_realloc (ptr, size);
193 static void
194 do_free (void *ptr)
196 MIInfo info;
198 if (!mi_check_init ())
199 return;
201 (*old_free) (ptr);
203 if (mi_tracing ()) {
204 info.alloc.operation = MI_FREE;
205 info.alloc.old_ptr = ptr;
206 info.alloc.new_ptr = NULL;
207 info.alloc.size = 0;
209 mi_call_with_backtrace (2, mi_write_stack, &info);
213 void
214 __libc_free (void *ptr)
216 do_free (ptr);
219 void
220 free (void *ptr)
222 do_free (ptr);
225 void *
226 _ZN3WTF10fastMallocEj(size_t size)
228 void *result;
229 MIInfo info;
231 if (!mi_check_init ())
232 return NULL;/* See comment in initialize() */
234 result = (*old_fastMalloc) (size);
236 if (mi_tracing ()) {
237 info.alloc.operation = MI_MALLOC;
238 info.alloc.old_ptr = NULL;
239 info.alloc.new_ptr = result;
240 info.alloc.size = size;
242 mi_call_with_backtrace (2, mi_write_stack, &info);
245 return result;
248 void *
249 _ZN3WTF11fastReallocEPvj(void *ptr, size_t size)
251 void *result;
252 MIInfo info;
254 if (!mi_check_init ())
255 return NULL;/* See comment in initialize() */
257 result = (*old_fastRealloc) (ptr, size);
259 if (mi_tracing ()) {
260 info.alloc.operation = MI_REALLOC;
261 info.alloc.old_ptr = ptr;
262 info.alloc.new_ptr = result;
263 info.alloc.size = size;
265 mi_call_with_backtrace (1, mi_write_stack, &info);
268 return result;
271 void
272 _ZN3WTF8fastFreeEPv(void *ptr)
274 MIInfo info;
276 if (!mi_check_init ())
277 return;/* See comment in initialize() */
279 (*old_fastFree) (ptr);
281 if (mi_tracing ()) {
282 info.alloc.operation = MI_FREE;
283 info.alloc.old_ptr = ptr;
284 info.alloc.new_ptr = NULL;
285 info.alloc.size = 0;
287 mi_call_with_backtrace (1, mi_write_stack, &info);
291 void *
292 _ZN3WTF10fastCallocEjj(size_t nmemb, size_t size)
294 void *result;
295 MIInfo info;
297 if (!mi_check_init ())
298 return NULL;/* See comment in initialize() */
300 result = (*old_fastCalloc) (nmemb, size);
302 if (mi_tracing ()) {
303 info.alloc.operation = MI_MALLOC;
304 info.alloc.old_ptr = NULL;
305 info.alloc.new_ptr = result;
306 info.alloc.size = nmemb * size;
308 mi_call_with_backtrace (1, mi_write_stack, &info);
311 return result;
314 void
315 mi_init (void)
317 old_malloc = dlsym(RTLD_NEXT, "malloc");
318 old_realloc = dlsym(RTLD_NEXT, "realloc");
319 old_free = dlsym(RTLD_NEXT, "free");
320 old_calloc = dlsym(RTLD_NEXT, "calloc");
321 old_memalign = dlsym(RTLD_NEXT, "memalign");
323 /* to ease debugging webkit */
324 old_fastMalloc = dlsym(RTLD_NEXT, "_ZN3WTF10fastMallocEj");
325 old_fastRealloc = dlsym(RTLD_NEXT, "_ZN3WTF11fastReallocEPvj");
326 old_fastFree = dlsym(RTLD_NEXT, "_ZN3WTF8fastFreeEPv");
327 old_fastCalloc = dlsym(RTLD_NEXT, "_ZN3WTF10fastCallocEjj");
330 void
331 mi_start (void)
335 void
336 mi_stop (void)