]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/drd/drd_malloc_wrappers.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / drd / drd_malloc_wrappers.c
1 /* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
2 /*
3   This file is part of drd, a thread error detector.
4
5   Copyright (C) 2006-2011 Bart Van Assche <bvanassche@acm.org>.
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20   02111-1307, USA.
21
22   The GNU General Public License is contained in the file COPYING.
23 */
24
25
26 #include "drd_malloc_wrappers.h"
27 #include "drd_thread.h"
28 #include "pub_tool_basics.h"
29 #include "pub_tool_execontext.h"
30 #include "pub_tool_hashtable.h"
31 #include "pub_tool_libcassert.h"
32 #include "pub_tool_libcbase.h"
33 #include "pub_tool_libcprint.h"
34 #include "pub_tool_mallocfree.h"
35 #include "pub_tool_options.h"
36 #include "pub_tool_replacemalloc.h"
37 #include "pub_tool_threadstate.h"
38 #include "pub_tool_tooliface.h"
39
40
41 /* Local type definitions. */
42
43 /**
44  * Node with per-allocation information that will be stored in a hash map.
45  * As specified in <pub_tool_hashtable.h>, the first member must be a pointer
46  * and the second member must be an UWord.
47  */
48 typedef struct _DRD_Chunk {
49    struct _DRD_Chunk* next;
50    UWord              data;   // pointer to actual block
51    SizeT              size;   // size requested
52    ExeContext*        where;  // where it was allocated
53 } DRD_Chunk;
54
55
56 /* Local variables. */
57
58 static StartUsingMem s_start_using_mem_callback;
59 static StopUsingMem  s_stop_using_mem_callback;
60 /* Statistics. */
61 static SizeT s_cmalloc_n_mallocs  = 0;
62 static SizeT s_cmalloc_n_frees    = 0;
63 static SizeT s_cmalloc_bs_mallocd = 0;
64 /* Record malloc'd blocks. */
65 static VgHashTable s_malloc_list = NULL;
66
67
68 /* Function definitions. */
69
70 /** Allocate client memory memory and update the hash map. */
71 static void* new_block(ThreadId tid, SizeT size, SizeT align, Bool is_zeroed)
72 {
73    void* p;
74
75    p = VG_(cli_malloc)(align, size);
76    if (!p)
77       return NULL;
78    if (is_zeroed)
79       VG_(memset)(p, 0, size);
80
81    DRD_(malloclike_block)(tid, (Addr)p, size);
82
83    return p;
84 }
85
86 /**
87  * Store information about a memory block that has been allocated by
88  * malloc() or a malloc() replacement in the hash map.
89  */
90 void DRD_(malloclike_block)(const ThreadId tid, const Addr p, const SizeT size)
91 {
92    DRD_Chunk* mc;
93
94    tl_assert(p);
95
96    if (size > 0)
97       s_start_using_mem_callback(p, size, 0/*ec_uniq*/);
98
99    s_cmalloc_n_mallocs++;
100    // Only update this stat if allocation succeeded.
101    s_cmalloc_bs_mallocd += size;
102
103    mc = VG_(malloc)("drd.malloc_wrappers.cDC.1", sizeof(DRD_Chunk));
104    mc->data  = p;
105    mc->size  = size;
106    mc->where = VG_(record_ExeContext)(tid, 0);
107    VG_(HT_add_node)(s_malloc_list, mc);
108 }
109
110 static void handle_free(ThreadId tid, void* p)
111 {
112    Bool success;
113
114    tl_assert(p);
115    success = DRD_(freelike_block)(tid, (Addr)p, True);
116    tl_assert(success);
117 }
118
119 /**
120  * Remove the information that was stored by DRD_(malloclike_block)() about
121  * a memory block.
122  */
123 Bool DRD_(freelike_block)(const ThreadId tid, const Addr p, const Bool dealloc)
124 {
125    DRD_Chunk* mc;
126
127    tl_assert(p);
128
129    s_cmalloc_n_frees++;
130
131    mc = VG_(HT_lookup)(s_malloc_list, (UWord)p);
132    if (mc)
133    {
134       tl_assert(p == mc->data);
135       if (dealloc)
136          VG_(cli_free)((void*)p);
137       if (mc->size > 0)
138          s_stop_using_mem_callback(mc->data, mc->size);
139       VG_(HT_remove)(s_malloc_list, (UWord)p);
140       VG_(free)(mc);
141       return True;
142    }
143    return False;
144 }
145
146 /** Wrapper for malloc(). */
147 static void* drd_malloc(ThreadId tid, SizeT n)
148 {
149    return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
150 }
151
152 /** Wrapper for memalign(). */
153 static void* drd_memalign(ThreadId tid, SizeT align, SizeT n)
154 {
155    return new_block(tid, n, align, /*is_zeroed*/False);
156 }
157
158 /** Wrapper for calloc(). */
159 static void* drd_calloc(ThreadId tid, SizeT nmemb, SizeT size1)
160 {
161    return new_block(tid, nmemb*size1, VG_(clo_alignment),
162                           /*is_zeroed*/True);
163 }
164
165 /** Wrapper for free(). */
166 static void drd_free(ThreadId tid, void* p)
167 {
168    handle_free(tid, p);
169 }
170
171 /**
172  * Wrapper for realloc(). Returns a pointer to the new block of memory, or
173  * NULL if no new block could not be allocated. Notes:
174  * - realloc(NULL, size) has the same effect as malloc(size).
175  * - realloc(p, 0) has the same effect as free(p).
176  * - success is not guaranteed even if the requested size is smaller than the
177  *   allocated size.
178 */
179 static void* drd_realloc(ThreadId tid, void* p_old, SizeT new_size)
180 {
181    DRD_Chunk* mc;
182    void*      p_new;
183    SizeT      old_size;
184
185    if (! p_old)
186       return drd_malloc(tid, new_size);
187
188    if (new_size == 0)
189    {
190       drd_free(tid, p_old);
191       return NULL;
192    }
193
194    s_cmalloc_n_mallocs++;
195    s_cmalloc_n_frees++;
196    s_cmalloc_bs_mallocd += new_size;
197
198    mc = VG_(HT_lookup)(s_malloc_list, (UWord)p_old);
199    if (mc == NULL)
200    {
201       tl_assert(0);
202       return NULL;
203    }
204
205    old_size = mc->size;
206
207    if (old_size == new_size)
208    {
209       /* size unchanged */
210       mc->where = VG_(record_ExeContext)(tid, 0);
211       p_new = p_old;
212    }
213    else if (new_size < old_size)
214    {
215       /* new size is smaller but nonzero */
216       s_stop_using_mem_callback(mc->data + new_size, old_size - new_size);
217       mc->size = new_size;
218       mc->where = VG_(record_ExeContext)(tid, 0);
219       p_new = p_old;
220    }
221    else
222    {
223       /* new size is bigger */
224       p_new = VG_(cli_malloc)(VG_(clo_alignment), new_size);
225
226       if (p_new)
227       {
228          /* Copy from old to new. */
229          VG_(memcpy)(p_new, p_old, mc->size);
230
231          /* Free old memory. */
232          VG_(cli_free)(p_old);
233          if (mc->size > 0)
234             s_stop_using_mem_callback(mc->data, mc->size);
235          VG_(HT_remove)(s_malloc_list, (UWord)p_old);
236
237          /* Update state information. */
238          mc->data  = (Addr)p_new;
239          mc->size  = new_size;
240          mc->where = VG_(record_ExeContext)(tid, 0);
241          VG_(HT_add_node)(s_malloc_list, mc);
242          s_start_using_mem_callback((Addr)p_new, new_size, 0/*ec_uniq*/);
243       }
244       else
245       {
246          /* Allocation failed -- leave original block untouched. */
247       }
248    }
249
250    return p_new;
251 }
252
253 /** Wrapper for __builtin_new(). */
254 static void* drd___builtin_new(ThreadId tid, SizeT n)
255 {
256    return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
257 }
258
259 /** Wrapper for __builtin_delete(). */
260 static void drd___builtin_delete(ThreadId tid, void* p)
261 {
262    handle_free(tid, p);
263 }
264
265 /** Wrapper for __builtin_vec_new(). */
266 static void* drd___builtin_vec_new(ThreadId tid, SizeT n)
267 {
268    return new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
269 }
270
271 /** Wrapper for __builtin_vec_delete(). */
272 static void drd___builtin_vec_delete(ThreadId tid, void* p)
273 {
274    handle_free(tid, p);
275 }
276
277 /**
278  * Wrapper for malloc_usable_size() / malloc_size(). This function takes
279  * a pointer to a block allocated by `malloc' and returns the amount of space
280  * that is available in the block. This may or may not be more than the size
281  * requested from `malloc', due to alignment or minimum size constraints.
282  */
283 static SizeT drd_malloc_usable_size(ThreadId tid, void* p)
284 {
285    DRD_Chunk* mc;
286
287    mc = VG_(HT_lookup)(s_malloc_list, (UWord)p);
288
289    return mc ? mc->size : 0;
290 }
291
292 void DRD_(register_malloc_wrappers)(const StartUsingMem start_callback,
293                                     const StopUsingMem stop_callback)
294 {
295    tl_assert(s_malloc_list == 0);
296    s_malloc_list = VG_(HT_construct)("drd_malloc_list");
297    tl_assert(s_malloc_list);
298    tl_assert(start_callback);
299    tl_assert(stop_callback);
300
301    s_start_using_mem_callback = start_callback;
302    s_stop_using_mem_callback  = stop_callback;
303
304    VG_(needs_malloc_replacement)(drd_malloc,
305                                  drd___builtin_new,
306                                  drd___builtin_vec_new,
307                                  drd_memalign,
308                                  drd_calloc,
309                                  drd_free,
310                                  drd___builtin_delete,
311                                  drd___builtin_vec_delete,
312                                  drd_realloc,
313                                  drd_malloc_usable_size,
314                                  0);
315 }
316
317 Bool DRD_(heap_addrinfo)(Addr const a,
318                          Addr* const data,
319                          SizeT* const size,
320                          ExeContext** const where)
321 {
322    DRD_Chunk* mc;
323
324    tl_assert(data);
325    tl_assert(size);
326    tl_assert(where);
327
328    VG_(HT_ResetIter)(s_malloc_list);
329    while ((mc = VG_(HT_Next)(s_malloc_list)))
330    {
331       if (mc->data <= a && a < mc->data + mc->size)
332       {
333          *data  = mc->data;
334          *size  = mc->size;
335          *where = mc->where;
336          return True;
337       }
338    }
339    return False;
340 }
341
342 /*------------------------------------------------------------*/
343 /*--- Statistics printing                                  ---*/
344 /*------------------------------------------------------------*/
345
346 void DRD_(print_malloc_stats)(void)
347 {
348    DRD_Chunk* mc;
349    SizeT     nblocks = 0;
350    SizeT     nbytes  = 0;
351
352    if (VG_(clo_verbosity) == 0)
353       return;
354    if (VG_(clo_xml))
355       return;
356
357    /* Count memory still in use. */
358    VG_(HT_ResetIter)(s_malloc_list);
359    while ((mc = VG_(HT_Next)(s_malloc_list)))
360    {
361       nblocks++;
362       nbytes += mc->size;
363    }
364
365    VG_(message)(Vg_DebugMsg,
366                 "malloc/free: in use at exit: %lu bytes in %lu blocks.\n",
367                 nbytes, nblocks);
368    VG_(message)(Vg_DebugMsg,
369                 "malloc/free: %lu allocs, %lu frees, %lu bytes allocated.\n",
370                 s_cmalloc_n_mallocs,
371                 s_cmalloc_n_frees, s_cmalloc_bs_mallocd);
372    if (VG_(clo_verbosity) > 1)
373       VG_(message)(Vg_DebugMsg, " \n");
374 }
375
376 /*--------------------------------------------------------------------*/
377 /*--- end                                                          ---*/
378 /*--------------------------------------------------------------------*/