]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
A major overhaul of how malloc/free intercepts are done. The general
authorJulian Seward <jseward@acm.org>
Sat, 2 Apr 2005 17:38:59 +0000 (17:38 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 2 Apr 2005 17:38:59 +0000 (17:38 +0000)
idea is the same -- write functions with special names encoding
sonames and fn names, and have the redir mechanism notice them.
However the way the functions are generated is significantly changed:

* The name mangling scheme has been replaced with one which is just about
  simple enough not to need a preprocessing phase.  Hence
  vg_replace_malloc.c.base is replaced by vg_replace_malloc.c, and
  the preprocessor disappears.  The demangler in vg_symtab2.c changes
  accordingly.

* Kill off the horrendous LIBALIAS macro.  In return we have to
  enumerate all the redirections longhand, but this is not a big deal.

* Remove use of the GNUisms "attribute alias" and "attribute
  protected".

* Remove the hardwired assumption that any C++ new/new[]/etc symbols
  we might want to intercept are mangled in GNU style.

* Add more comments.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3510

coregrind/Makefile.am
coregrind/core.h
coregrind/gen_intercepts.pl [deleted file]
coregrind/vg_replace_malloc.c [new file with mode: 0644]
coregrind/vg_replace_malloc.c.base [deleted file]
coregrind/vg_symtab2.c

index 50450e885766b37ce477bd94c1aa3f1a6c592ecf..ed1d7ed0ecf09557153d9a086bd9817192ba140b 100644 (file)
@@ -37,10 +37,10 @@ noinst_HEADERS = \
 EXTRA_DIST = \
        valgrind.vs \
        gen_toolint.pl toolfuncs.def \
-       gen_intercepts.pl vg_replace_malloc.c.base
+       gen_intercepts.pl
 
 BUILT_SOURCES = vg_toolint.c vg_toolint.h
-CLEANFILES = vg_toolint.c vg_toolint.h vg_replace_malloc.c
+CLEANFILES = vg_toolint.c vg_toolint.h
 
 valgrind_SOURCES = \
        ume.c \
@@ -61,6 +61,7 @@ stage2_SOURCES = \
        vg_demangle.c \
        vg_errcontext.c \
        vg_hashtable.c \
+       vg_replace_malloc.c \
        vg_main.c \
        vg_malloc2.c \
        vg_memory.c \
@@ -114,10 +115,6 @@ endif
 stage2_LDADD= $(stage2_extra) -ldl
 
 
-vg_replace_malloc.c: $(srcdir)/gen_intercepts.pl $(srcdir)/vg_replace_malloc.c.base
-       rm -f $@
-       $(PERL) $(srcdir)/gen_intercepts.pl < $(srcdir)/vg_replace_malloc.c.base > $@
-
 vg_toolint.c: $(srcdir)/gen_toolint.pl $(srcdir)/toolfuncs.def ./Makefile
        rm -f $@
        $(PERL) $(srcdir)/gen_toolint.pl callwrap     < $(srcdir)/toolfuncs.def >  $@ || rm -f $@
index 04889d16e9c5a6d637a3e77d9b8253786c8b0c0f..3204d11460d9c205252a0c2fe5ff1dea21b9e038 100644 (file)
@@ -468,15 +468,18 @@ extern void  VG_(print_all_arena_stats) ( void );
    A synonym for exit. */
 #define VG_USERREQ__LIBC_FREERES_DONE       0x3029
 
-#define VG_INTERCEPT_PREFIX "_vgi__"
-#define VG_INTERCEPT_PREFIX_LEN 6
-#define VG_INTERCEPT(name) _vgi__##name
-#define VG_INTERCEPT_ALIAS(name) "_vgi__" #name
-
-#define VG_WRAPPER_PREFIX "_vgw__"
-#define VG_WRAPPER_PREFIX_LEN 6
-#define VG_WRAPPER(name) _vgw__##name
-#define VG_WRAPPER_ALIAS(name) "_vgw__" #name
+/* Intercept prefix stuff.  See coregrind/vg_replace_malloc.c for
+   details.  Unfortunately the "_vgi_" literal is also hardcoded in
+   that file, so if you change this one you must also change the other
+   one. */
+#define VG_INTERCEPT_PREFIX "_vgi_"
+#define VG_INTERCEPT_PREFIX_LEN 5
+
+/* Not sure what these are for.  Todo: clarify */
+#define VG_WRAPPER_PREFIX "_vgw_"
+#define VG_WRAPPER_PREFIX_LEN 5
+#define VG_WRAPPER(name) _vgw_##name
+#define VG_WRAPPER_ALIAS(name) "_vgw_" #name
 
 
 struct vg_mallocfunc_info {
diff --git a/coregrind/gen_intercepts.pl b/coregrind/gen_intercepts.pl
deleted file mode 100644 (file)
index 18fed7c..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/perl -w
-
-#  This file is part of Valgrind, a dynamic binary instrumentation
-#  framework.
-#
-#  Copyright (C) 2000-2005 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.
-
-use strict;
-
-while(<>) {
-  if(/VG_INTERCEPT\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/) {
-    my $ver = $1 . ":" . $2;
-    ($ver =~ /J/) and die "Argh, 'J' in intercept muck...";
-    $ver =~ s/\*/J2A/g;
-    $ver =~ s/\+/J2B/g;
-    $ver =~ s/\-/J2D/g;
-    $ver =~ s/\./J2E/g;
-    $ver =~ s/\:/J3A/g;
-    s/VG_INTERCEPT\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/VG_INTERCEPT($ver)/g;
-  } elsif(/VG_INTERCEPT_ALIAS\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/) {
-    my $ver = $1 . ":" . $2;
-    ($ver =~ /J/) and die "Argh, 'J' in intercept muck...";
-    $ver =~ s/\*/J2A/g;
-    $ver =~ s/\+/J2B/g;
-    $ver =~ s/\-/J2D/g;
-    $ver =~ s/\./J2E/g;
-    $ver =~ s/\:/J3A/g;
-    s/VG_INTERCEPT_ALIAS\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/VG_INTERCEPT_ALIAS($ver)/g;
-  }
-  print $_;
-}
diff --git a/coregrind/vg_replace_malloc.c b/coregrind/vg_replace_malloc.c
new file mode 100644 (file)
index 0000000..0fd0cf3
--- /dev/null
@@ -0,0 +1,525 @@
+
+/*--------------------------------------------------------------------*/
+/*--- 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-2005 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.  It is intended
+   for various reasons as drop-in replacements for malloc() and friends.
+   These functions have global scope, but are not intended to be called
+   directly.  See the comments in coregrind/vg_intercept.c for the
+   gory details.
+
+   This file can be linked into the injected so file for any tool that
+   wishes to know about calls to malloc().  It should define functions
+   TL_(malloc) et al that will be called.
+   ------------------------------------------------------------------ */
+
+#include "valgrind.h"            /* for VALGRIND_NON_SIMD_CALL[12] */
+#include "core.h"
+
+/* The general idea is: you can write a function like this:
+
+      retty ENCODE(foo, bar) ( ... args ... )
+      {
+         ... body ...
+      }
+
+   If foo is a Z-encoded soname and bar is an unencoded fn name, then
+   the core's symbol-table reading machinery and redirection machinery
+   will conspire to cause calls to the function 'bar' in object with
+   soname 'foo' to actually be routed to the function written here.
+   We use this below to define dozens of replacements of malloc, free,
+   etc.
+
+   The soname must be a Z-encoded bit of text because sonames can
+   contain dots etc which are not valid symbol names.  However, it is
+   better not to Z-encode the function name, because C++ function names
+   are already mangled, and we don't want our own Z encoding to interact
+   badly with them; furthermore there's no point, because mangled C++
+   function names are by definition already valid symbol names.
+   
+   It is important that the Z-encoded soname contains no unencoded 
+   underscores, since the intercept-handlers in vg_symtab2.c detect
+   the end of the soname by looking for the first trailing underscore.
+*/
+
+/* We use a Z-encoding scheme here, a la GHC.  This is just about
+   readable enough to make a preprocessor unnecessary.
+
+   The intercept-me function names are encoded as
+
+      _vgi_zEncodedSoname_fnname
+
+   where soname is Z-encoded but fnname isn't.
+
+   The Z-encoding scheme is as follows:
+
+   *         -->  Za    (asterisk)
+   +         -->  Zp
+   :         -->  Zc
+   .         -->  Zd
+   _         -->  Zu
+   (space)   -->  Zs
+   Z         -->  ZZ
+*/
+
+
+/* It would be nice to be able to write VG_INTERCEPT_PREFIX instead of
+   "_vgi_" here, but I can't figure out how to get cpp to cooperate.
+   If you change this "_vgi_" you should also change the definitiion
+   of VG_INTERCEPT_PREFIX in core.h accordingly.
+*/
+#define ENCODE(libname,fnname) _vgi_##libname##_##fnname
+
+
+/* Some handy mangled names */
+#define  m_libstc_plus_plus_star  libstdcZpZpZa   // libstdc++*
+#define  m_libc_dot_so_dot_6      libcZdsoZd6     // libc.so.6
+//#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));
+
+// Functions for printing from code within Valgrind, but which runs on the
+// sim'd CPU.  They must be functions rather than macros so that va_list can
+// be used.
+// Nb: at one point, these were used by multiple files that run on the sim'd
+// CPU, and so were *defined* in core.h with the 'weak' attribute.  That was
+// pretty ugly.  It's much better if this is the only file that needs them.
+
+__attribute__((format(__printf__, 1, 2)))
+static int
+internal_printf(char *format, ...)
+{
+   UWord _qzz_res = 0;
+   va_list vargs;
+   va_start(vargs, format);
+   VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, VG_USERREQ__INTERNAL_PRINTF,
+                           (UWord)format, (UWord)vargs, 0, 0);
+   va_end(vargs);
+   return _qzz_res;
+}
+
+#define MALLOC_TRACE(format, args...)  \
+   if (info.clo_trace_malloc)          \
+      internal_printf(format, ## args )
+
+#define MAYBE_SLOPPIFY(n)           \
+   if (info.clo_sloppy_malloc) {    \
+      n = (n+(VG_SLOPPY_MALLOC_SZB-1)) & ~(VG_SLOPPY_MALLOC_SZB-1); \
+   }
+
+
+/* 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* ENCODE(soname,fnname) (SizeT n); \
+   void* ENCODE(soname,fnname) (SizeT n)  \
+   { \
+      void* v; \
+      \
+      MALLOC_TRACE(#fnname "(%llu)", (ULong)n ); \
+      MAYBE_SLOPPIFY(n); \
+      if (!init_done) init(); \
+      \
+      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* ENCODE(soname,fnname) (SizeT n); \
+   void* ENCODE(soname,fnname) (SizeT n)  \
+   { \
+      void* v; \
+      \
+      MALLOC_TRACE(#fnname "(%llu)", (ULong)n ); \
+      MAYBE_SLOPPIFY(n); \
+      if (!init_done) init(); \
+      \
+      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_dot_6,     malloc,      malloc);
+//ALLOC_or_NULL(m_libpgc_dot_so,         malloc,      malloc);
+
+// operator new(unsigned int), GNU mangling
+ALLOC_or_BOMB(m_libstc_plus_plus_star, builtin_new,    __builtin_new);
+ALLOC_or_BOMB(m_libc_dot_so_dot_6,     builtin_new,    __builtin_new);
+
+ALLOC_or_BOMB(m_libstc_plus_plus_star, __builtin_new,  __builtin_new);
+ALLOC_or_BOMB(m_libc_dot_so_dot_6,     __builtin_new,  __builtin_new);
+
+ALLOC_or_BOMB(m_libstc_plus_plus_star, _Znwj,          __builtin_new);
+ALLOC_or_BOMB(m_libc_dot_so_dot_6,     _Znwj,          __builtin_new);
+
+// 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
+ALLOC_or_NULL(m_libstc_plus_plus_star, _ZnwjRKSt9nothrow_t,  __builtin_new);
+ALLOC_or_NULL(m_libc_dot_so_dot_6,     _ZnwjRKSt9nothrow_t,  __builtin_new);
+
+// operator new[](unsigned int), GNU mangling
+ALLOC_or_BOMB(m_libstc_plus_plus_star, __builtin_vec_new, __builtin_vec_new );
+ALLOC_or_BOMB(m_libc_dot_so_dot_6,     __builtin_vec_new, __builtin_vec_new );
+ALLOC_or_BOMB(m_libstc_plus_plus_star, _Znaj,             __builtin_vec_new );
+ALLOC_or_BOMB(m_libc_dot_so_dot_6,     _Znaj,             __builtin_vec_new );
+
+// operator new[](unsigned, std::nothrow_t const&), GNU mangling
+ALLOC_or_NULL(m_libstc_plus_plus_star, _ZnajRKSt9nothrow_t, __builtin_vec_new );
+ALLOC_or_NULL(m_libc_dot_so_dot_6,     _ZnajRKSt9nothrow_t, __builtin_vec_new );
+
+
+/* Generate a replacement for 'fnname' in object 'soname', which calls
+   'vg_replacement' to free previously allocated memory.
+*/
+#define FREE(soname, fnname, vg_replacement) \
+   \
+   void ENCODE(soname,fnname) (void *p); \
+   void ENCODE(soname,fnname) (void *p)  \
+   { \
+      MALLOC_TRACE(#vg_replacement "(%p)", p ); \
+      if (p == NULL)  \
+         return; \
+      if (!init_done) init(); \
+      (void)VALGRIND_NON_SIMD_CALL1( info.tl_##vg_replacement, p ); \
+   }
+
+// free
+FREE(m_libstc_plus_plus_star,  free,                 free );
+FREE(m_libc_dot_so_dot_6,      free,                 free );
+
+// cfree
+FREE(m_libstc_plus_plus_star,  cfree,                free );
+FREE(m_libc_dot_so_dot_6,      cfree,                free );
+
+// do we really need these?
+FREE(m_libstc_plus_plus_star,  __builtin_delete,     __builtin_delete );
+FREE(m_libc_dot_so_dot_6,      __builtin_delete,     __builtin_delete );
+
+// operator delete(void*), GNU mangling
+FREE(m_libstc_plus_plus_star,  _ZdlPv,               __builtin_delete );
+FREE(m_libc_dot_so_dot_6,      _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_dot_6,     _ZdlPvRKSt9nothrow_t,  __builtin_delete );
+
+// operator delete[](void*), GNU mangling
+FREE(m_libstc_plus_plus_star,  __builtin_vec_delete, __builtin_vec_delete );
+FREE(m_libc_dot_so_dot_6,      __builtin_vec_delete, __builtin_vec_delete );
+FREE(m_libstc_plus_plus_star,  _ZdaPv,               __builtin_vec_delete );
+FREE(m_libc_dot_so_dot_6,      _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_dot_6,      _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
+
+
+#define CALLOC(soname, fnname) \
+   \
+   void* ENCODE(soname,fnname) ( SizeT nmemb, SizeT size ); \
+   void* ENCODE(soname,fnname) ( SizeT nmemb, SizeT size )  \
+   { \
+      void* v; \
+      \
+      MALLOC_TRACE("calloc(%llu,%llu)", (ULong)nmemb, (ULong)size ); \
+      MAYBE_SLOPPIFY(size); \
+      \
+      if (!init_done) init(); \
+      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_calloc, nmemb, size ); \
+      MALLOC_TRACE(" = %p", v ); \
+      return v; \
+   }
+
+CALLOC(m_libc_dot_so_dot_6, calloc);
+
+
+#define REALLOC(soname, fnname) \
+   \
+   void* ENCODE(soname,fnname) ( void* ptrV, SizeT new_size ); \
+   void* ENCODE(soname,fnname) ( void* ptrV, SizeT new_size )  \
+   { \
+      void* v; \
+      \
+      MALLOC_TRACE("realloc(%p,%llu)", ptrV, (ULong)new_size ); \
+      MAYBE_SLOPPIFY(new_size); \
+      \
+      if (ptrV == NULL) \
+         /* We need to call a malloc-like function; so let's use \
+            one which we know exists. */ \
+         return ENCODE(libcZdsoZd6,malloc) (new_size); \
+      if (new_size <= 0) { \
+         ENCODE(libcZdsoZd6,free)(ptrV); \
+         if (info.clo_trace_malloc) \
+            internal_printf(" = 0" ); \
+         return NULL; \
+      } \
+      if (!init_done) init(); \
+      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_realloc, ptrV, new_size ); \
+      MALLOC_TRACE(" = %p", v ); \
+      return v; \
+   }
+
+REALLOC(m_libc_dot_so_dot_6, realloc);
+
+
+#define MEMALIGN(soname, fnname) \
+   \
+   void* ENCODE(soname,fnname) ( SizeT alignment, SizeT n ); \
+   void* ENCODE(soname,fnname) ( SizeT alignment, SizeT n )  \
+   { \
+      void* v; \
+      \
+      MALLOC_TRACE("memalign(al %llu, size %llu)", \
+                   (ULong)alignment, (ULong)n ); \
+      MAYBE_SLOPPIFY(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++; \
+      \
+      if (!init_done) init(); \
+      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_memalign, alignment, n ); \
+      MALLOC_TRACE(" = %p", v ); \
+      return v; \
+   }
+
+MEMALIGN(m_libc_dot_so_dot_6, memalign);
+
+
+#define VALLOC(soname, fnname) \
+   \
+   void* ENCODE(soname,fnname) ( SizeT size ); \
+   void* ENCODE(soname,fnname) ( SizeT size )  \
+   { \
+      return ENCODE(libcZdsoZd6,memalign)(VKI_PAGE_SIZE, size); \
+   }
+
+VALLOC(m_libc_dot_so_dot_6, valloc);
+
+
+/* Various compatibility wrapper functions, for glibc and libstdc++. */
+
+#define MALLOPT(soname, fnname) \
+   \
+   int ENCODE(soname, fnname) ( int cmd, int value ); \
+   int ENCODE(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_dot_6, mallopt);
+
+
+#define POSIX_MEMALIGN(soname, fnname) \
+   \
+   int ENCODE(soname, fnname) ( void **memptr, SizeT alignment, SizeT size ); \
+   int ENCODE(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 = ENCODE(libcZdsoZd6,memalign)(alignment, size); \
+      \
+      if (mem != NULL) { \
+        *memptr = mem; \
+        return 0; \
+      } \
+      \
+      return VKI_ENOMEM; \
+   }
+
+POSIX_MEMALIGN(m_libc_dot_so_dot_6, posix_memalign);
+
+
+#define MALLOC_USABLE_SIZE(soname, fnname) \
+   \
+   int ENCODE(soname, fnname) ( void* p ); \
+   int ENCODE(soname, fnname) ( void* p )  \
+   {  \
+      SizeT pszB; \
+      \
+      MALLOC_TRACE("malloc_usable_size(%p)", p ); \
+      if (NULL == p) \
+         return 0; \
+      \
+      if (!init_done) init(); \
+      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_dot_6, 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 ENCODE(soname, fnname) ( void ); \
+   void ENCODE(soname, fnname) ( void )  \
+   { \
+      panic(#fnname); \
+   }
+
+PANIC(m_libc_dot_so_dot_6, pvalloc);
+PANIC(m_libc_dot_so_dot_6, malloc_stats);
+PANIC(m_libc_dot_so_dot_6, malloc_trim);
+PANIC(m_libc_dot_so_dot_6, malloc_get_state);
+PANIC(m_libc_dot_so_dot_6, malloc_set_state);
+
+
+/* Yet another ugly hack.  Cannot include <malloc.h> because we
+   implement functions implemented there with different signatures.
+   This struct definition MUST match the system one. */
+
+/* SVID2/XPG mallinfo structure */
+struct mallinfo {
+   int arena;    /* total space allocated from system */
+   int ordblks;  /* number of non-inuse chunks */
+   int smblks;   /* unused -- always zero */
+   int hblks;    /* number of mmapped regions */
+   int hblkhd;   /* total space in mmapped regions */
+   int usmblks;  /* unused -- always zero */
+   int fsmblks;  /* unused -- always zero */
+   int uordblks; /* total allocated space */
+   int fordblks; /* total non-inuse space */
+   int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+#define MALLINFO(soname, fnname) \
+   \
+   struct mallinfo ENCODE(soname, fnname) ( void ); \
+   struct mallinfo ENCODE(soname, fnname) ( void )  \
+   { \
+      /* Should really try to return something a bit more meaningful */ \
+      UInt            i; \
+      struct mallinfo mi; \
+      UChar*          pmi = (UChar*)(&mi); \
+      for (i = 0; i < sizeof(mi); i++) \
+         pmi[i] = 0; \
+      return mi; \
+   }
+
+MALLINFO(m_libc_dot_so_dot_6, 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_MAGIC_SEQUENCE(res, -1, VG_USERREQ__GET_MALLOCFUNCS, &info,
+                           0, 0, 0);
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                      vg_replace_malloc.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_replace_malloc.c.base b/coregrind/vg_replace_malloc.c.base
deleted file mode 100644 (file)
index 602a911..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- 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-2005 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.  It is intended
-   for various reasons as drop-in replacements for malloc() and friends.
-   These functions have global scope, but are not intended to be called
-   directly.  See the comments in coregrind/vg_intercept.c for the
-   gory details.
-
-   This file can be linked into the injected so file for any tool that
-   wishes to know about calls to malloc().  It should define functions
-   TL_(malloc) et al that will be called.
-   ------------------------------------------------------------------ */
-
-#include "valgrind.h"            /* for VALGRIND_NON_SIMD_CALL[12] */
-#include "core.h"
-
-// Nb: the last line is repeated -- once for the declaration, once for the
-// definition.  If we don't have the declaration there GCC complains.
-#define LIBALIAS(ret, name, args) \
-   ret VG_INTERCEPT(soname:libstdc++*, __libc_##name) args \
-      __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
-                     visibility("protected"))); \
-   ret VG_INTERCEPT(soname:libc.so.6, __libc_##name) args \
-      __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
-                     visibility("protected"))); \
-   ret VG_INTERCEPT(soname:libstdc++*, __##name) args \
-      __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
-                     visibility("protected"))); \
-   ret VG_INTERCEPT(soname:libc.so.6, __##name) args \
-      __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
-                     visibility("protected"))); \
-   ret VG_INTERCEPT(soname:libstdc++*, ##name) args \
-      __attribute__((alias(VG_INTERCEPT_ALIAS(soname:libc.so.6, ##name)), \
-                     visibility("protected"))); \
-   ret VG_INTERCEPT(soname:libc.so.6, ##name) args; \
-   ret VG_INTERCEPT(soname:libc.so.6, ##name) args
-
-extern void _exit(int);
-
-/*------------------------------------------------------------*/
-/*--- Replacing malloc() et al                             ---*/
-/*------------------------------------------------------------*/
-
-static struct vg_mallocfunc_info info;
-static int init_done;
-
-/* Startup hook - called as init section */
-static void init(void) __attribute__((constructor));
-
-// Functions for printing from code within Valgrind, but which runs on the
-// sim'd CPU.  They must be functions rather than macros so that va_list can
-// be used.
-// Nb: at one point, these were used by multiple files that run on the sim'd
-// CPU, and so were *defined* in core.h with the 'weak' attribute.  That was
-// pretty ugly.  It's much better if this is the only file that needs them.
-
-__attribute__((format(__printf__, 1, 2)))
-static int
-internal_printf(char *format, ...)
-{
-   UWord _qzz_res = 0;
-   va_list vargs;
-   va_start(vargs, format);
-   VALGRIND_MAGIC_SEQUENCE(_qzz_res, 0, VG_USERREQ__INTERNAL_PRINTF,
-                           (UWord)format, (UWord)vargs, 0, 0);
-   va_end(vargs);
-   return _qzz_res;
-}
-
-#define MALLOC_TRACE(format, args...)  \
-   if (info.clo_trace_malloc)          \
-      internal_printf(format, ## args )
-
-#define MAYBE_SLOPPIFY(n)           \
-   if (info.clo_sloppy_malloc) {    \
-      n = (n+(VG_SLOPPY_MALLOC_SZB-1)) & ~(VG_SLOPPY_MALLOC_SZB-1); \
-   }
-
-/* 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. */
-
-#define ALLOC(fff, vgfff) \
-LIBALIAS(void *, fff, (SizeT n)) \
-{ \
-   void* v; \
- \
-   MALLOC_TRACE(#fff "(%llu)", (ULong)n ); \
-   MAYBE_SLOPPIFY(n); \
-   if (!init_done) init(); \
- \
-   v = (void*)VALGRIND_NON_SIMD_CALL1( info.tl_##vgfff, n ); \
-   MALLOC_TRACE(" = %p", v ); \
-   return v; \
-}
-
-#define ALLOC2(fff, vgfff) \
-LIBALIAS(void *, fff, (SizeT n)) \
-{ \
-   void* v; \
- \
-   MALLOC_TRACE(#fff "(%llu)", (ULong)n ); \
-   MAYBE_SLOPPIFY(n); \
-   if (!init_done) init(); \
- \
-   v = (void*)VALGRIND_NON_SIMD_CALL1( info.tl_##vgfff, 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; \
-}
-ALLOC( malloc,              malloc            );
-ALLOC2(__builtin_new,       __builtin_new     );
-ALLOC2(_Znwj,               __builtin_new     );
-
-// operator new(unsigned, std::nothrow_t const&)
-ALLOC( _ZnwjRKSt9nothrow_t, __builtin_new     );
-
-ALLOC2(__builtin_vec_new,   __builtin_vec_new );
-ALLOC2(_Znaj,               __builtin_vec_new );
-
-// operator new[](unsigned, std::nothrow_t const&)
-ALLOC( _ZnajRKSt9nothrow_t, __builtin_vec_new );
-
-#define FREE(fff, vgfff) \
-LIBALIAS(void, fff, (void *p)) \
-{ \
-   MALLOC_TRACE(#fff "(%p)", p ); \
-   if (p == NULL)  \
-      return; \
-   if (!init_done) init(); \
-   (void)VALGRIND_NON_SIMD_CALL1( info.tl_##vgfff, p ); \
-}
-FREE( free,                 free                 );
-FREE( cfree,                free                 );
-FREE( __builtin_delete,     __builtin_delete     );
-FREE( _ZdlPv,               __builtin_delete     );
-
-// operator delete(void*, std::nothrow_t const&)
-FREE( _ZdlPvRKSt9nothrow_t, __builtin_delete     );
-
-FREE( __builtin_vec_delete, __builtin_vec_delete );
-FREE( _ZdaPv,               __builtin_vec_delete );
-
-// operator delete[](void*, std::nothrow_t const&)
-FREE( _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
-
-
-LIBALIAS(void*, calloc, ( SizeT nmemb, SizeT size ))
-{
-   void* v;
-
-   MALLOC_TRACE("calloc(%llu,%llu)", (ULong)nmemb, (ULong)size );
-   MAYBE_SLOPPIFY(size);
-
-   if (!init_done) init();
-   v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_calloc, nmemb, size );
-   MALLOC_TRACE(" = %p", v );
-   return v;
-}
-
-LIBALIAS(void*, realloc, ( void* ptrV, SizeT new_size ))
-{
-   void* v;
-
-   MALLOC_TRACE("realloc(%p,%llu)", ptrV, (ULong)new_size );
-   MAYBE_SLOPPIFY(new_size);
-
-   if (ptrV == NULL)
-      return VG_INTERCEPT(soname:libc.so.6, malloc)(new_size);
-   if (new_size <= 0) {
-      VG_INTERCEPT(soname:libc.so.6, free)(ptrV);
-      if (info.clo_trace_malloc) 
-         internal_printf(" = 0" );
-      return NULL;
-   }   
-   if (!init_done) init();
-   v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_realloc, ptrV, new_size );
-   MALLOC_TRACE(" = %p", v );
-   return v;
-}
-
-
-LIBALIAS(void*, memalign, ( SizeT alignment, SizeT n ))
-{
-   void* v;
-
-   MALLOC_TRACE("memalign(al %llu, size %llu)", (ULong)alignment, (ULong)n );
-   MAYBE_SLOPPIFY(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++;
-
-   if (!init_done) init();
-   v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_memalign, alignment, n );
-   MALLOC_TRACE(" = %p", v );
-   return v;
-}
-
-
-LIBALIAS(void*, valloc, ( SizeT size ))
-{
-   return VG_INTERCEPT(soname:libc.so.6, memalign)(VKI_PAGE_SIZE, size);
-}
-
-
-/* Various compatibility wrapper functions, for glibc and libstdc++. */
-
-LIBALIAS(int, mallopt, ( int cmd, int value ))
-{
-   /* In glibc-2.2.4, 1 denotes a successful return value for mallopt */
-   return 1;
-}
-
-
-LIBALIAS(int, posix_memalign, ( 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 /*22*/ /*EINVAL*/;
-
-    mem = VG_INTERCEPT(soname:libc.so.6, memalign)(alignment, size);
-
-    if (mem != NULL) {
-       *memptr = mem;
-       return 0;
-    }
-
-    return VKI_ENOMEM /*12*/ /*ENOMEM*/;
-}
-
-LIBALIAS(int, malloc_usable_size, ( void* p ))
-{ 
-   SizeT pszB;
-   
-   MALLOC_TRACE("malloc_usable_size(%p)", p );
-   if (NULL == p)
-      return 0;
-
-   if (!init_done) init();
-   pszB = (SizeT)VALGRIND_NON_SIMD_CALL2( info.arena_payload_szB, 
-                                          VG_AR_CLIENT, p );
-   MALLOC_TRACE(" = %llu", (ULong)pszB );
-
-   return pszB;
-}
-
-
-/* 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';
-}
-
-// As for LIBALIAS, we have the declaration to shut GCC up.
-#define PANIC(x) \
-   void VG_INTERCEPT(soname:libc.so.6, ## x)(void); \
-   void VG_INTERCEPT(soname:libc.so.6, ## x)(void) \
-   { \
-      panic(#x); \
-   }
-
-PANIC(pvalloc);
-PANIC(malloc_stats);
-PANIC(malloc_trim);
-PANIC(malloc_get_state);
-PANIC(malloc_set_state);
-
-
-/* Yet another ugly hack.  Cannot include <malloc.h> because we
-   implement functions implemented there with different signatures.
-   This struct definition MUST match the system one. */
-
-/* SVID2/XPG mallinfo structure */
-struct mallinfo {
-   int arena;    /* total space allocated from system */
-   int ordblks;  /* number of non-inuse chunks */
-   int smblks;   /* unused -- always zero */
-   int hblks;    /* number of mmapped regions */
-   int hblkhd;   /* total space in mmapped regions */
-   int usmblks;  /* unused -- always zero */
-   int fsmblks;  /* unused -- always zero */
-   int uordblks; /* total allocated space */
-   int fordblks; /* total non-inuse space */
-   int keepcost; /* top-most, releasable (via malloc_trim) space */
-};
-
-LIBALIAS(struct mallinfo, mallinfo, ( void ))
-{
-   /* Should really try to return something a bit more meaningful */
-   UInt            i;
-   struct mallinfo mi;
-   UChar*          pmi = (UChar*)(&mi);
-   for (i = 0; i < sizeof(mi); i++)
-      pmi[i] = 0;
-   return mi;
-}
-
-/* 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_MAGIC_SEQUENCE(res, -1, VG_USERREQ__GET_MALLOCFUNCS, &info,
-                           0, 0, 0);
-}
-
-/*--------------------------------------------------------------------*/
-/*--- end                                      vg_replace_malloc.c ---*/
-/*--------------------------------------------------------------------*/
index 066b3d891c75c657d284f9e1daf27411979329dc..391688e207c5a2b37472bcb76c8f17686ab036b9 100644 (file)
@@ -799,73 +799,121 @@ Bool VG_(is_object_file)(const void *buf)
    return False;
 }
 
-/*
- * Demangle an intercept symbol into library:func form
+/* Demangle an intercept symbol into library:func form
+   eg "_vgi_libcZdsoZd6__ZdlPv"  -->  "libc.so.6:_ZdlPv"
+   Uses the Z-encoding scheme described in vg_replace_malloc.c.
+   Returns True if demangle OK, False otherwise.
  */
 
 static Bool
 intercept_demangle(const Char* symbol, Char* result, Int nbytes)
 {
-   int i, j = 0;
-   int len = VG_(strlen)(symbol);
+#  define EMIT(ch)                    \
+      do {                            \
+         if (j >= nbytes)             \
+            result[j-1] = 0;          \
+         else                         \
+            result[j++] = ch;         \
+      } while (0)
+
+   Bool error = False;
+   Int i, j = 0;
+   Int len = VG_(strlen)(symbol);
+   if (0) VG_(printf)("idm: %s\n", symbol);
+
+   i = VG_INTERCEPT_PREFIX_LEN;
+
+   /* Chew though the Z-encoded soname part. */
+   while (True) {
+
+      if (i >= len) 
+         break;
+
+      if (symbol[i] == '_')
+         /* We found the underscore following the Z-encoded soname.
+            Just copy the rest literally. */
+         break;
 
-   for(i = VG_INTERCEPT_PREFIX_LEN; i < len; i++) {
-      if(symbol[i] == 'J') {
+      if (symbol[i] != 'Z') {
+         EMIT(symbol[i]);
          i++;
-         vg_assert('J' != symbol[i]);
-         if((symbol[i] >= '0' && symbol[i] <= '9') ||
-            (symbol[i] >= 'a' && symbol[i] <= 'f') ||
-            (symbol[i] >= 'A' && symbol[i] <= 'F')) 
-         {
-            int x = symbol[i++];
-            int y = symbol[i];
-            if(x >= '0' && x <= '9') {
-               x -= '0';
-            } else if(x >= 'a' && x <= 'f') {
-               x -= 'a';
-            } else if(x >= 'A' && x <= 'F') {
-               x -= 'A';
-            }
-            if(y >= '0' && y <= '9') {
-               y -= '0';
-            } else if(y >= 'a' && y <= 'f') {
-               y = y - 'a' + 10;
-            } else if(y >= 'A' && y <= 'F') {
-               y = y - 'A' + 10;
-            } else {
-               return False;
-            }
-            result[j] = (x << 4) | y;
-         } else {
-            return False;
-         }
-      } else {
-         result[j] = symbol[i];
+         continue;
       }
-      if(j >= nbytes) {
-         result[j] = '\0';
-         return True;
+
+      /* We've got a Z-escape.  Act accordingly. */
+      i++;
+      if (i >= len) {
+         /* Hmm, Z right at the end.  Something's wrong. */
+         error = True;
+         EMIT('Z');
+         break;
       }
-      j++;
+      switch (symbol[i]) {
+         case 'a': EMIT('*'); break;
+         case 'p': EMIT('+'); break;
+         case 'c': EMIT(':'); break;
+         case 'd': EMIT('.'); break;
+         case 'u': EMIT('_'); break;
+         case 's': EMIT(' '); break;
+         case 'Z': EMIT('Z'); break;
+         default: error = True; EMIT('Z'); EMIT(symbol[i]); break;
+      }
+      i++;
+   }
+
+   if (error || i >= len || symbol[i] != '_') {
+      /* Something's wrong.  Give up. */
+      VG_(message)(Vg_UserMsg, "intercept: error demangling: %s", symbol);
+      EMIT(0);
+      return False;
+   }
+
+   /* Copy the rest of the string verbatim. */
+   i++;
+   EMIT(':');
+   while (True) {
+     if (i >= len)
+        break;
+     EMIT(symbol[i]);
+     i++;
    }
-   result[j] = '\0';
+
+   EMIT(0);
+   if (0) VG_(printf)("%s\n", result);
    return True;
+
+#  undef EMIT
 }
 
 static
 void handle_intercept( SegInfo* si, Char* symbol, ElfXX_Sym* sym)
 {
-   Int len = VG_(strlen)(symbol) + 1 - VG_INTERCEPT_PREFIX_LEN;
-   Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len);
+   Bool ok;
+   Int  len  = VG_(strlen)(symbol) + 1 - VG_INTERCEPT_PREFIX_LEN;
+   Char *lib = VG_(arena_malloc)(VG_AR_SYMTAB, len+8);
    Char *func;
 
-   intercept_demangle(symbol, lib, len);
-   func = lib + VG_(strlen)(lib)-1;
-
-   while(*func != ':') func--;
-   *func = '\0';
+   /* Put "soname:" at the start of lib. */
+   lib[0] = 's';
+   lib[1] = 'o';
+   lib[2] = 'n';
+   lib[3] = 'a';
+   lib[4] = 'm';
+   lib[5] = 'e';
+   lib[6] = ':';
+   lib[7] = 0;
+
+   ok = intercept_demangle(symbol, lib+7, len);
+   if (ok) {
+      func = lib + VG_(strlen)(lib)-1;
+
+      while(*func != ':') func--;
+      *func = '\0';
+
+      if (0) VG_(printf)("lib A%sZ, func A%sZ\n", lib, func+1);
+      VG_(add_redirect_sym_to_addr)(lib, func+1, si->offset + sym->st_value);
+   }
 
-   VG_(add_redirect_sym_to_addr)(lib, func+1, si->offset + sym->st_value);
    VG_(arena_free)(VG_AR_SYMTAB, lib);
 }