~bkerensa/ubuntu/raring/valgrind/merge-from-deb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
/*--------------------------------------------------------------------*/
/*--- Replacements for malloc() et al, which run on the simulated  ---*/
/*--- CPU.                                     vg_replace_malloc.c ---*/
/*--------------------------------------------------------------------*/

/*
   This file is part of Valgrind, a dynamic binary instrumentation
   framework.

   Copyright (C) 2000-2006 Julian Seward 
      jseward@acm.org

   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 2 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, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.

   The GNU General Public License is contained in the file COPYING.
*/

/* ---------------------------------------------------------------------
   ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.  
   
   These functions are drop-in replacements for malloc() and friends.
   They have global scope, but are not intended to be called directly.
   See pub_core_redir.h for the gory details.

   This file can be linked into the vg_preload_<tool>.so file for any tool
   that wishes to know about calls to malloc().  The tool must define all
   the functions that will be called via 'info'.

   It is called vg_replace_malloc.c because this filename appears in stack
   traces, so we want the name to be (hopefully!) meaningful to users.
   ------------------------------------------------------------------ */

#include "pub_core_basics.h"
#include "pub_core_clreq.h"         // for VALGRIND_INTERNAL_PRINTF,
                                    //   VALGRIND_NON_SIMD_CALL[12]
#include "pub_core_debuginfo.h"     // needed for pub_core_redir.h :(
#include "pub_core_mallocfree.h"    // for VG_MIN_MALLOC_SZB, VG_AR_CLIENT
#include "pub_core_redir.h"         // for VG_REDIRECT_FUNCTION_*
#include "pub_core_replacemalloc.h"

/* Some handy Z-encoded names */
#define  m_libstc_plus_plus_star  libstdcZpZpZa   // libstdc++*
#define  m_libc_dot_so_star       libcZdsoZa      // libc.so*
//#define  m_libpgc_dot_so          libpgcZdso      // libpgc.so

/* 2 Apr 05: the Portland Group compiler, which uses cfront/ARM style
   mangling, could be supported properly by the redirects in this
   module.  Except we can't because it doesn't put its allocation
   functions in libpgc.so but instead hardwires them into the
   compilation unit holding main(), which makes them impossible to
   intercept directly.  Fortunately those fns seem to route everything
   through to malloc/free.
*/

extern void _exit(int);

/*------------------------------------------------------------*/
/*--- Replacing malloc() et al                             ---*/
/*------------------------------------------------------------*/

/* This struct is initially empty.  Before the first use of any of
   these functions, we make a client request which fills in the
   fields. 
*/
static struct vg_mallocfunc_info info;
static int init_done;

/* Startup hook - called as init section */
static void init(void) __attribute__((constructor));

#define MALLOC_TRACE(format, args...)  \
   if (info.clo_trace_malloc)          \
      VALGRIND_INTERNAL_PRINTF(format, ## args )

/* Below are new versions of malloc, __builtin_new, free, 
   __builtin_delete, calloc, realloc, memalign, and friends.

   None of these functions are called directly - they are not meant to
   be found by the dynamic linker.  But ALL client calls to malloc()
   and friends wind up here eventually.  They get called because
   vg_replace_malloc installs a bunch of code redirects which causes
   Valgrind to use these functions rather than the ones they're
   replacing.
*/

/* Generate a replacement for 'fnname' in object 'soname', which calls
   'vg_replacement' to allocate memory.  If that fails, return NULL.
*/
#define ALLOC_or_NULL(soname, fnname, vg_replacement) \
   \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (SizeT n); \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (SizeT n)  \
   { \
      void* v; \
      \
      if (!init_done) init(); \
      MALLOC_TRACE(#fnname "(%llu)", (ULong)n ); \
      \
      v = (void*)VALGRIND_NON_SIMD_CALL1( info.tl_##vg_replacement, n ); \
      MALLOC_TRACE(" = %p", v ); \
      return v; \
   }


/* Generate a replacement for 'fnname' in object 'soname', which calls
   'vg_replacement' to allocate memory.  If that fails, it bombs the
   system.
*/
#define ALLOC_or_BOMB(soname, fnname, vg_replacement)  \
   \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (SizeT n); \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (SizeT n)  \
   { \
      void* v; \
      \
      if (!init_done) init(); \
      MALLOC_TRACE(#fnname "(%llu)", (ULong)n );        \
      \
      v = (void*)VALGRIND_NON_SIMD_CALL1( info.tl_##vg_replacement, n ); \
      MALLOC_TRACE(" = %p", v ); \
      if (NULL == v) { \
         VALGRIND_PRINTF_BACKTRACE( \
            "new/new[] failed and should throw an exception, but Valgrind\n" \
            "   cannot throw exceptions and so is aborting instead.  Sorry."); \
            _exit(1); \
      } \
      return v; \
   }

// Each of these lines generates a replacement function:
//     (from_so, from_fn,  v's replacement)

// malloc
ALLOC_or_NULL(m_libstc_plus_plus_star, malloc,      malloc);
ALLOC_or_NULL(m_libc_dot_so_star,      malloc,      malloc);
//ALLOC_or_NULL(m_libpgc_dot_so,         malloc,      malloc);


// operator new(unsigned int), not mangled (for gcc 2.96)
ALLOC_or_BOMB(m_libstc_plus_plus_star, builtin_new,    __builtin_new);
ALLOC_or_BOMB(m_libc_dot_so_star,      builtin_new,    __builtin_new);

ALLOC_or_BOMB(m_libstc_plus_plus_star, __builtin_new,  __builtin_new);
ALLOC_or_BOMB(m_libc_dot_so_star,      __builtin_new,  __builtin_new);

// operator new(unsigned int), GNU mangling, 32-bit platforms
// operator new(unsigned long), GNU mangling, 64-bit platforms
#if VG_WORDSIZE == 4
 ALLOC_or_BOMB(m_libstc_plus_plus_star, _Znwj,          __builtin_new);
 ALLOC_or_BOMB(m_libc_dot_so_star,      _Znwj,          __builtin_new);
#endif
#if VG_WORDSIZE == 8
 ALLOC_or_BOMB(m_libstc_plus_plus_star, _Znwm,          __builtin_new);
 ALLOC_or_BOMB(m_libc_dot_so_star,      _Znwm,          __builtin_new);
#endif


// operator new(unsigned int), ARM/cfront mangling
//ALLOC_or_BOMB(m_libpgc_dot_so,         __nw__FUi,      __builtin_new);


// operator new(unsigned, std::nothrow_t const&), GNU mangling, 32-bit
// operator new(unsigned long, std::nothrow_t const&), GNU mangling, 64-bit
#if VG_WORDSIZE == 4
 ALLOC_or_NULL(m_libstc_plus_plus_star, _ZnwjRKSt9nothrow_t,  __builtin_new);
 ALLOC_or_NULL(m_libc_dot_so_star,      _ZnwjRKSt9nothrow_t,  __builtin_new);
#endif
#if VG_WORDSIZE == 8
 ALLOC_or_NULL(m_libstc_plus_plus_star, _ZnwmRKSt9nothrow_t,  __builtin_new);
 ALLOC_or_NULL(m_libc_dot_so_star,      _ZnwmRKSt9nothrow_t,  __builtin_new);
#endif


// operator new[](unsigned int), not mangled (for gcc 2.96)
ALLOC_or_BOMB(m_libstc_plus_plus_star, __builtin_vec_new, __builtin_vec_new );
ALLOC_or_BOMB(m_libc_dot_so_star,      __builtin_vec_new, __builtin_vec_new );

// operator new[](unsigned int), GNU mangling, 32-bit platforms
// operator new[](unsigned long), GNU mangling, 64-bit platforms
#if VG_WORDSIZE == 4
 ALLOC_or_BOMB(m_libstc_plus_plus_star, _Znaj,             __builtin_vec_new );
 ALLOC_or_BOMB(m_libc_dot_so_star,      _Znaj,             __builtin_vec_new );
#endif
#if VG_WORDSIZE == 8
 ALLOC_or_BOMB(m_libstc_plus_plus_star, _Znam,             __builtin_vec_new );
 ALLOC_or_BOMB(m_libc_dot_so_star,     _Znam,             __builtin_vec_new );
#endif


// operator new[](unsigned, std::nothrow_t const&), GNU mangling, 32-bit
// operator new[](unsigned long, std::nothrow_t const&), GNU mangling, 64-bit
#if VG_WORDSIZE == 4
 ALLOC_or_NULL(m_libstc_plus_plus_star, _ZnajRKSt9nothrow_t, __builtin_vec_new );
 ALLOC_or_NULL(m_libc_dot_so_star,      _ZnajRKSt9nothrow_t, __builtin_vec_new );
#endif
#if VG_WORDSIZE == 8
 ALLOC_or_NULL(m_libstc_plus_plus_star, _ZnamRKSt9nothrow_t, __builtin_vec_new );
 ALLOC_or_NULL(m_libc_dot_so_star,      _ZnamRKSt9nothrow_t, __builtin_vec_new );
#endif


/* Generate a replacement for 'fnname' in object 'soname', which calls
   'vg_replacement' to free previously allocated memory.
*/
#define FREE(soname, fnname, vg_replacement) \
   \
   void VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *p); \
   void VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *p)  \
   { \
      if (!init_done) init(); \
      MALLOC_TRACE(#vg_replacement "(%p)", p ); \
      if (p == NULL)  \
         return; \
      (void)VALGRIND_NON_SIMD_CALL1( info.tl_##vg_replacement, p ); \
   }

// free
FREE(m_libstc_plus_plus_star,  free,                 free );
FREE(m_libc_dot_so_star,       free,                 free );

// cfree
FREE(m_libstc_plus_plus_star,  cfree,                free );
FREE(m_libc_dot_so_star,       cfree,                free );

// operator delete(void*), not mangled (for gcc 2.96)
FREE(m_libstc_plus_plus_star,  __builtin_delete,     __builtin_delete );
FREE(m_libc_dot_so_star,       __builtin_delete,     __builtin_delete );

// operator delete(void*), GNU mangling
FREE(m_libstc_plus_plus_star,  _ZdlPv,               __builtin_delete );
FREE(m_libc_dot_so_star,       _ZdlPv,               __builtin_delete );

// operator delete(void*, std::nothrow_t const&), GNU mangling
FREE(m_libstc_plus_plus_star, _ZdlPvRKSt9nothrow_t,  __builtin_delete );
FREE(m_libc_dot_so_star,      _ZdlPvRKSt9nothrow_t,  __builtin_delete );

// operator delete[](void*), not mangled (for gcc 2.96)
FREE(m_libstc_plus_plus_star,  __builtin_vec_delete, __builtin_vec_delete );
FREE(m_libc_dot_so_star,       __builtin_vec_delete, __builtin_vec_delete );

// operator delete[](void*), GNU mangling
FREE(m_libstc_plus_plus_star,  _ZdaPv,               __builtin_vec_delete );
FREE(m_libc_dot_so_star,       _ZdaPv,               __builtin_vec_delete );

// operator delete[](void*, std::nothrow_t const&), GNU mangling
FREE(m_libstc_plus_plus_star,  _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
FREE(m_libc_dot_so_star,       _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );


#define CALLOC(soname, fnname) \
   \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT nmemb, SizeT size ); \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT nmemb, SizeT size )  \
   { \
      void* v; \
      \
      if (!init_done) init(); \
      MALLOC_TRACE("calloc(%llu,%llu)", (ULong)nmemb, (ULong)size ); \
      \
      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_calloc, nmemb, size ); \
      MALLOC_TRACE(" = %p", v ); \
      return v; \
   }

CALLOC(m_libc_dot_so_star, calloc);


#define REALLOC(soname, fnname) \
   \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void* ptrV, SizeT new_size );\
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void* ptrV, SizeT new_size ) \
   { \
      void* v; \
      \
      if (!init_done) init(); \
      MALLOC_TRACE("realloc(%p,%llu)", ptrV, (ULong)new_size ); \
      \
      if (ptrV == NULL) \
         /* We need to call a malloc-like function; so let's use \
            one which we know exists. */ \
         return VG_REPLACE_FUNCTION_ZU(libcZdsoZa,malloc) (new_size); \
      if (new_size <= 0) { \
         VG_REPLACE_FUNCTION_ZU(libcZdsoZa,free)(ptrV); \
         MALLOC_TRACE(" = 0"); \
         return NULL; \
      } \
      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_realloc, ptrV, new_size ); \
      MALLOC_TRACE(" = %p", v ); \
      return v; \
   }

REALLOC(m_libc_dot_so_star, realloc);


#define MEMALIGN(soname, fnname) \
   \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT alignment, SizeT n ); \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT alignment, SizeT n )  \
   { \
      void* v; \
      \
      if (!init_done) init(); \
      MALLOC_TRACE("memalign(al %llu, size %llu)", \
                   (ULong)alignment, (ULong)n ); \
      \
      /* Round up to minimum alignment if necessary. */ \
      if (alignment < VG_MIN_MALLOC_SZB) \
         alignment = VG_MIN_MALLOC_SZB; \
      \
      /* Round up to nearest power-of-two if necessary (like glibc). */ \
      while (0 != (alignment & (alignment - 1))) alignment++; \
      \
      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_memalign, alignment, n ); \
      MALLOC_TRACE(" = %p", v ); \
      return v; \
   }

MEMALIGN(m_libc_dot_so_star, memalign);


#define VALLOC(soname, fnname) \
   \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT size ); \
   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT size )  \
   { \
      return VG_REPLACE_FUNCTION_ZU(libcZdsoZa,memalign)(VKI_PAGE_SIZE, size); \
   }

VALLOC(m_libc_dot_so_star, valloc);


/* Various compatibility wrapper functions, for glibc and libstdc++. */

#define MALLOPT(soname, fnname) \
   \
   int VG_REPLACE_FUNCTION_ZU(soname, fnname) ( int cmd, int value ); \
   int VG_REPLACE_FUNCTION_ZU(soname, fnname) ( int cmd, int value )  \
   { \
      /* In glibc-2.2.4, 1 denotes a successful return value for \
         mallopt */ \
      return 1; \
   }

MALLOPT(m_libc_dot_so_star, mallopt);


// Documentation says:
//   malloc_trim(size_t pad);
// 
//   If possible, gives memory back to the system (via negative arguments to
//   sbrk) if there is unused memory at the `high' end of the malloc pool.
//   You can call this after freeing large blocks of memory to potentially
//   reduce the system-level memory requirements of a program. However, it
//   cannot guarantee to reduce memory.  Under some allocation patterns,
//   some large free blocks of memory will be locked between two used
//   chunks, so they cannot be given back to the system.
// 
//   The `pad' argument to malloc_trim represents the amount of free
//   trailing space to leave untrimmed. If this argument is zero, only the
//   minimum amount of memory to maintain internal data structures will be
//   left (one page or less). Non-zero arguments can be supplied to maintain
//   enough trailing space to service future expected allocations without
//   having to re-obtain memory from the system.
// 
//   Malloc_trim returns 1 if it actually released any memory, else 0. On
//   systems that do not support "negative sbrks", it will always return 0. 
//
// For simplicity, we always return 0.
#define MALLOC_TRIM(soname, fnname) \
   \
   int VG_REPLACE_FUNCTION_ZU(soname, fnname) ( SizeT pad ); \
   int VG_REPLACE_FUNCTION_ZU(soname, fnname) ( SizeT pad )  \
   { \
      /* 0 denotes that malloc_trim() either wasn't able \
         to do anything, or was not implemented */ \
      return 0; \
   }

MALLOC_TRIM(m_libc_dot_so_star, malloc_trim);


#define POSIX_MEMALIGN(soname, fnname) \
   \
   int VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void **memptr, \
                                                 SizeT alignment, SizeT size ); \
   int VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void **memptr, \
                                                 SizeT alignment, SizeT size )  \
   { \
      void *mem; \
      \
      /* Test whether the alignment argument is valid.  It must be \
         a power of two multiple of sizeof (void *).  */ \
      if (alignment % sizeof (void *) != 0 \
          || (alignment & (alignment - 1)) != 0) \
         return VKI_EINVAL; \
      \
      mem = VG_REPLACE_FUNCTION_ZU(libcZdsoZa,memalign)(alignment, size); \
      \
      if (mem != NULL) { \
        *memptr = mem; \
        return 0; \
      } \
      \
      return VKI_ENOMEM; \
   }

POSIX_MEMALIGN(m_libc_dot_so_star, posix_memalign);


#define MALLOC_USABLE_SIZE(soname, fnname) \
   \
   int VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void* p ); \
   int VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void* p )  \
   {  \
      SizeT pszB; \
      \
      if (!init_done) init(); \
      MALLOC_TRACE("malloc_usable_size(%p)", p ); \
      if (NULL == p) \
         return 0; \
      \
      pszB = (SizeT)VALGRIND_NON_SIMD_CALL2( info.arena_payload_szB, \
                                             VG_AR_CLIENT, p ); \
      MALLOC_TRACE(" = %llu", (ULong)pszB ); \
      \
      return pszB; \
   }

MALLOC_USABLE_SIZE(m_libc_dot_so_star, malloc_usable_size);


/* Bomb out if we get any of these. */

static void panic(const char *str)
{
   VALGRIND_PRINTF_BACKTRACE("Program aborting because of call to %s", str);
   _exit(99);
   *(int *)0 = 'x';
}

#define PANIC(soname, fnname) \
   \
   void VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void ); \
   void VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void )  \
   { \
      panic(#fnname); \
   }

PANIC(m_libc_dot_so_star, pvalloc);
PANIC(m_libc_dot_so_star, malloc_stats);
PANIC(m_libc_dot_so_star, malloc_get_state);
PANIC(m_libc_dot_so_star, malloc_set_state);

// mi must be static;  if it is auto then Memcheck thinks it is
// uninitialised when used by the caller of this function, because Memcheck
// doesn't know that the call to mallinfo fills in mi.
#define MALLINFO(soname, fnname) \
   \
   struct vg_mallinfo VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void ); \
   struct vg_mallinfo VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void )  \
   { \
      static struct vg_mallinfo mi; \
      if (!init_done) init(); \
      MALLOC_TRACE("mallinfo()"); \
      (void)VALGRIND_NON_SIMD_CALL1( info.mallinfo, &mi ); \
      return mi; \
   }

MALLINFO(m_libc_dot_so_star, mallinfo);


/* All the code in here is unused until this function is called */

static void init(void)
{
   int res;

   if (init_done)
      return;

   init_done = 1;

   VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__GET_MALLOCFUNCS, &info,
                              0, 0, 0, 0);
}

/*--------------------------------------------------------------------*/
/*--- end                                      vg_replace_malloc.c ---*/
/*--------------------------------------------------------------------*/