This change reduces the number of calls to dlsym() when loading tools from a
lot to one.  This required two basic changes.

1. Tools are responsible for telling the tool about any functions they
provide that the tool may call.  This includes basic functions like
TL_(instrument)(), functions that assist core services such as
TL_(pp_Error)(), and malloc-replacement-related functions like
TL_(malloc)().  

2. Tools that replace malloc now specify the size of the heap block redzones
through an arg to the VG_(malloc_funcs)() function, rather than with a
variable VG_(vg_malloc_redzone_szB).

One consequence of these changes is that VG_(tool_init_dlsym)() no longer
needs to be generated by gen_toolint.pl.

There are a number of further improvements that could follow on from this one.
- Avoid the confusingly different definitions of the TL_() macro in the
  core vs. for tools.  Indeed, the functions provided by the tools now don't
  need to use the TL_() macro at all, as they can have arbitrary names.
- Remove a lot of the auto-generated stuff in vg_toolint.c and vg_toolint.h
  (indeed, it might be possible to not auto-generate these at all, which
  would be nice).
- The handling of VgToolInterface is currently split across vg_needs.c and
  vg_toolint.c, which isn't nice.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3487 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/addrcheck/ac_main.c b/addrcheck/ac_main.c
index 41de6d4..343799c 100644
--- a/addrcheck/ac_main.c
+++ b/addrcheck/ac_main.c
@@ -1318,14 +1318,39 @@
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
    VG_(details_avg_translation_sizeB) ( 135 );
 
+   VG_(basic_tool_funcs)          (TL_(post_clo_init),
+                                   TL_(instrument),
+                                   TL_(fini));
+
    VG_(needs_core_errors)         ();
-   VG_(needs_tool_errors)         ();
+   VG_(needs_tool_errors)         (TL_(eq_Error),
+                                   TL_(pp_Error),
+                                   TL_(update_extra),
+                                   TL_(recognised_suppression),
+                                   TL_(read_extra_suppression_info),
+                                   TL_(error_matches_suppression),
+                                   TL_(get_error_name),
+                                   TL_(print_extra_suppression_info));
    VG_(needs_libc_freeres)        ();
-   VG_(needs_command_line_options)();
-   VG_(needs_client_requests)     ();
-   VG_(needs_sanity_checks)       ();
+   VG_(needs_command_line_options)(TL_(process_cmd_line_option),
+                                   TL_(print_usage),
+                                   TL_(print_debug_usage));
+   VG_(needs_client_requests)     (TL_(handle_client_request));
+   VG_(needs_sanity_checks)       (TL_(cheap_sanity_check),
+                                   TL_(expensive_sanity_check));
    VG_(needs_shadow_memory)       ();
 
+   VG_(malloc_funcs)              (TL_(malloc),
+                                   TL_(__builtin_new),
+                                   TL_(__builtin_vec_new),
+                                   TL_(memalign),
+                                   TL_(calloc),
+                                   TL_(free),
+                                   TL_(__builtin_delete),
+                                   TL_(__builtin_vec_delete),
+                                   TL_(realloc),
+                                   MALLOC_REDZONE_SZB );
+
    MAC_( new_mem_heap)             = & ac_new_mem_heap;
    MAC_( ban_mem_heap)             = & ac_make_noaccess;
    MAC_(copy_mem_heap)             = & ac_copy_address_range_state;
diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c
index 7c1c071..1570c8f 100644
--- a/cachegrind/cg_main.c
+++ b/cachegrind/cg_main.c
@@ -1132,8 +1132,14 @@
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
    VG_(details_avg_translation_sizeB) ( 155 );
 
-   VG_(needs_basic_block_discards)();
-   VG_(needs_command_line_options)();
+   VG_(basic_tool_funcs)          (TL_(post_clo_init),
+                                   TL_(instrument),
+                                   TL_(fini));
+
+   VG_(needs_basic_block_discards)(TL_(discard_basic_block_info));
+   VG_(needs_command_line_options)(TL_(process_cmd_line_option),
+                                   TL_(print_usage),
+                                   TL_(print_debug_usage));
 
    /* Get working directory */
    tl_assert( VG_(getcwd_alloc)(&base_dir) );
diff --git a/corecheck/cc_main.c b/corecheck/cc_main.c
index 0d81512..2e81a00 100644
--- a/corecheck/cc_main.c
+++ b/corecheck/cc_main.c
@@ -40,13 +40,15 @@
       "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
 
+   VG_(basic_tool_funcs)          (TL_(post_clo_init),
+                                   TL_(instrument),
+                                   TL_(fini));
+
    VG_(needs_core_errors)();
 
    /* No core events to track */
 }
 
-VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 0)
-
 void TL_(post_clo_init)(void)
 {
 }
@@ -61,6 +63,8 @@
 {
 }
 
+VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 0)
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                cc_main.c ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index df822ac..4dc709a 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -124,7 +124,6 @@
 	$(PERL) $(srcdir)/gen_toolint.pl callwrap     < $(srcdir)/toolfuncs.def >  $@ || rm -f $@
 	$(PERL) $(srcdir)/gen_toolint.pl missingfuncs < $(srcdir)/toolfuncs.def >> $@ || rm -f $@
 	$(PERL) $(srcdir)/gen_toolint.pl initfunc     < $(srcdir)/toolfuncs.def >> $@ || rm -f $@
-	$(PERL) $(srcdir)/gen_toolint.pl initdlsym    < $(srcdir)/toolfuncs.def >> $@ || rm -f $@
 	$(PERL) $(srcdir)/gen_toolint.pl structdef    < $(srcdir)/toolfuncs.def >> $@ || rm -f $@
 
 vg_toolint.h:  $(srcdir)/gen_toolint.pl $(srcdir)/toolfuncs.def ./Makefile
diff --git a/coregrind/core.h b/coregrind/core.h
index 8c6f1ae..4bad763 100644
--- a/coregrind/core.h
+++ b/coregrind/core.h
@@ -337,8 +337,6 @@
 
 extern VgNeeds VG_(needs);
 
-extern void VG_(tool_init_dlsym)(void *dlhandle);
-
 #include "vg_toolint.h"
 
 
@@ -392,6 +390,10 @@
                                   SizeT nmemb, SizeT bytes_per_memb );
 extern void* VG_(arena_realloc) ( ArenaId arena, void* ptr, SizeT size );
 
+/* Sets the size of the redzones at the start and end of heap blocks.  This
+   must be called before any of VG_(malloc) and friends are called. */
+extern void  VG_(set_client_malloc_redzone_szB) ( SizeT rz_szB );
+
 extern SizeT VG_(arena_payload_szB) ( ArenaId aid, void* payload );
 
 extern void  VG_(sanity_check_malloc_all) ( void );
diff --git a/coregrind/gen_toolint.pl b/coregrind/gen_toolint.pl
index 2fb519a..62494f1 100644
--- a/coregrind/gen_toolint.pl
+++ b/coregrind/gen_toolint.pl
@@ -166,32 +166,6 @@
 	print "void VG_(init_$func)($ret (*func)($args));\n";
     };
     $headerguard=$output;
-} elsif ($output eq "initdlsym") {
-    $pre = sub () {
-	print <<EOF;
-#include <dlfcn.h>
-void VG_(tool_init_dlsym)(void *dlhandle)
-{
-   void *ret;
-
-EOF
-    };
-    $post = sub () {
-	print "}\n";
-    };
-    $generate = sub ($$$@) {
-	my ($pfx, $ret, $func, @args) = @_;
-	my $args = join ", ", getargtypes(@args);
-
-	print <<EOF;
-   ret = dlsym(dlhandle, "vgTool_$func");
-   if (ret != NULL)
-      VG_(init_$func)(($ret (*)($args))ret);
-
-EOF
-    };
-
-    $passcomment = 0;
 }
 
 die "Unknown output format \"$output\"" unless defined $generate;
diff --git a/coregrind/vg_default.c b/coregrind/vg_default.c
index d9c58b7..5c6979c 100644
--- a/coregrind/vg_default.c
+++ b/coregrind/vg_default.c
@@ -66,10 +66,6 @@
 /*--- Replacing malloc et al                               ---*/
 /*------------------------------------------------------------*/
 
-/* Default redzone size for CLIENT arena of Valgrind's malloc() */
-__attribute__ ((weak))
-SizeT VG_(vg_malloc_redzone_szB) = 8;
-
 Bool VG_(tl_malloc_called_deliberately) = False;
 
 /* If the tool hasn't replaced malloc(), this one can be called
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index dbbe03b..9e6ff21 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -1172,7 +1172,7 @@
 
 /* Find and load a tool, and check it looks ok.  Also looks to see if there's 
  * a matching vgpreload_*.so file, and returns its name in *preloadpath. */
-static void load_tool( const char *toolname, void** handle_out,
+static void load_tool( const char *toolname,
                        ToolInfo** toolinfo_out, char **preloadpath_out )
 {
    Bool      ok;
@@ -1181,7 +1181,6 @@
    void*     handle;
    ToolInfo* toolinfo;
    char*     preloadpath = NULL;
-   Int*      vg_malloc_redzonep;
 
    // XXX: allowing full paths for --tool option -- does it make sense?
    // Doesn't allow for vgpreload_<tool>.so.
@@ -1240,14 +1239,7 @@
       goto bad_load;
    }
 
-   // Set redzone size for V's allocator
-   vg_malloc_redzonep = dlsym(handle, VG_STRINGIFY(VG_(vg_malloc_redzone_szB)));
-   if ( NULL != vg_malloc_redzonep ) {
-      VG_(vg_malloc_redzone_szB) = *vg_malloc_redzonep;
-   }
-
-   vg_assert(NULL != handle && NULL != toolinfo);
-   *handle_out      = handle;
+   vg_assert(NULL != toolinfo);
    *toolinfo_out    = toolinfo;
    *preloadpath_out = preloadpath;
    return;
@@ -2419,7 +2411,6 @@
    Int need_help = 0;      // 0 = no, 1 = --help, 2 = --help-debug
    struct exeinfo info;
    ToolInfo *toolinfo = NULL;
-   void *tool_dlhandle;
    Addr client_eip;
    Addr sp_at_startup;     /* client's SP at the point we gained control. */
    UInt * client_auxv;
@@ -2492,7 +2483,7 @@
    //   p: set-libdir                     [for VG_(libdir)]
    //   p: pre_process_cmd_line_options() [for 'tool']
    //--------------------------------------------------------------
-   load_tool(tool, &tool_dlhandle, &toolinfo, &preload);
+   load_tool(tool, &toolinfo, &preload);
 
    //==============================================================
    // Can use VG_(malloc)() and VG_(arena_malloc)() only after load_tool()
@@ -2569,13 +2560,12 @@
    //--------------------------------------------------------------
    // Init tool: pre_clo_init, process cmd line, post_clo_init
    //   p: setup_client_stack()      [for 'VG_(client_arg[cv]']
-   //   p: load_tool()               [for 'tool']
+   //   p: load_tool()               [for 'toolinfo']
    //   p: setup_file_descriptors()  [for 'VG_(fd_xxx_limit)']
    //   p: parse_procselfmaps        [so VG segments are setup so tool can
    //                                 call VG_(malloc)]
    //--------------------------------------------------------------
    (*toolinfo->tl_pre_clo_init)();
-   VG_(tool_init_dlsym)(tool_dlhandle);
    VG_(sanity_check_needs)();
 
    // If --tool and --help/--help-debug was given, now give the core+tool
diff --git a/coregrind/vg_malloc2.c b/coregrind/vg_malloc2.c
index ca3cbe1..ae9463b 100644
--- a/coregrind/vg_malloc2.c
+++ b/coregrind/vg_malloc2.c
@@ -378,6 +378,29 @@
    }
 }
 
+static Bool init_done = False;
+static SizeT client_malloc_redzone_szB = 8;   // default: be paranoid
+
+// Nb: this must be called before the client arena is initialised, ie.
+// before any memory is allocated.
+void VG_(set_client_malloc_redzone_szB)(SizeT rz_szB)
+{
+   if (init_done) {
+      VG_(printf)(
+         "\nTool error:\n"
+         "  __FUNCTION__ cannot be called after the first allocation.\n");
+      VG_(exit)(1);
+   }
+   // This limit is no special figure, just something not too big
+   if (rz_szB > 128) {
+      VG_(printf)(
+         "\nTool error:\n"
+         "  __FUNCTION__ passed a too-big value (%llu)", (ULong)rz_szB);
+      VG_(exit)(1);
+   }
+   client_malloc_redzone_szB = rz_szB;
+}
+
 /* This library is self-initialising, as it makes this more self-contained,
    less coupled with the outside world.  Hence VG_(arena_malloc)() and
    VG_(arena_free)() below always call ensure_mm_init() to ensure things are
@@ -385,21 +408,10 @@
 static
 void ensure_mm_init ( void )
 {
-   static SizeT client_rz_szB;
-   static Bool  init_done = False;
-   
    if (init_done) {
-      // Make sure the client arena's redzone size never changes.  Could
-      // happen if VG_(arena_malloc) was called too early, ie. before the
-      // tool was loaded.
-      vg_assert(client_rz_szB == VG_(vg_malloc_redzone_szB));
       return;
    }
 
-   /* No particular reason for this figure, it's just smallish */
-   tl_assert(VG_(vg_malloc_redzone_szB) < 128);
-   client_rz_szB = VG_(vg_malloc_redzone_szB);
-
    /* Use checked red zones (of various sizes) for our internal stuff,
       and an unchecked zone of arbitrary size for the client.  Of
       course the client's red zone can be checked by the tool, eg. 
@@ -415,7 +427,7 @@
    arena_init ( VG_AR_CORE,      "core",     4, CORE_ARENA_MIN_SZB );
    arena_init ( VG_AR_TOOL,      "tool",     4,            1048576 );
    arena_init ( VG_AR_SYMTAB,    "symtab",   4,            1048576 );
-   arena_init ( VG_AR_CLIENT,    "client",  client_rz_szB, 1048576 );
+   arena_init ( VG_AR_CLIENT,    "client", client_malloc_redzone_szB, 1048576 );
    arena_init ( VG_AR_DEMANGLE,  "demangle", 12/*paranoid*/, 65536 );
    arena_init ( VG_AR_EXECTXT,   "exectxt",  4,              65536 );
    arena_init ( VG_AR_ERRORS,    "errors",   4,              65536 );
@@ -1354,8 +1366,8 @@
 
 Bool VG_(addr_is_in_block)( Addr a, Addr start, SizeT size )
 {  
-   return (start - VG_(vg_malloc_redzone_szB) <= a
-           && a < start + size + VG_(vg_malloc_redzone_szB));
+   return (start - client_malloc_redzone_szB <= a
+           && a < start + size + client_malloc_redzone_szB);
 }
 
 
diff --git a/coregrind/vg_needs.c b/coregrind/vg_needs.c
index 688eb0c..baa913f 100644
--- a/coregrind/vg_needs.c
+++ b/coregrind/vg_needs.c
@@ -36,6 +36,23 @@
    Tool data structure initialisation
    ------------------------------------------------------------------ */
 
+/*--------------------------------------------------------------------*/
+/* Setting basic functions */
+
+void VG_(basic_tool_funcs)(
+   void(*post_clo_init)(void),
+   IRBB*(*instrument)(IRBB*, VexGuestLayout*, IRType, IRType ),
+   void(*fini)(Int)
+)
+{
+   VG_(tool_interface).tool_post_clo_init = post_clo_init;
+   VG_(tool_interface).tool_instrument    = instrument;
+   VG_(tool_interface).tool_fini          = fini;
+}
+
+/*--------------------------------------------------------------------*/
+/* Setting details */
+
 /* Init with default values. */
 VgDetails VG_(details) = {
    .name                  = NULL,
@@ -46,6 +63,23 @@
    .avg_translation_sizeB = VG_DEFAULT_TRANS_SIZEB,
 };
 
+/* Use macro because they're so repetitive */
+#define DETAILS(type, detail)                       \
+   extern void VG_(details_##detail)(type detail)   \
+   {                                                \
+      VG_(details).detail = detail;                 \
+   }
+
+DETAILS(Char*, name)
+DETAILS(Char*, version)
+DETAILS(Char*, description)
+DETAILS(Char*, copyright_author)
+DETAILS(Char*, bug_reports_to)
+DETAILS(UInt,  avg_translation_sizeB)
+
+/*--------------------------------------------------------------------*/
+/* Setting needs */
+
 VgNeeds VG_(needs) = {
    .core_errors          = False,
    .tool_errors          = False,
@@ -115,26 +149,6 @@
 #undef CHECK_NOT
 }
 
-/*--------------------------------------------------------------------*/
-/* Setting details */
-
-/* Use macro because they're so repetitive */
-#define DETAILS(type, detail)                       \
-   extern void VG_(details_##detail)(type detail)   \
-   {                                                \
-      VG_(details).detail = detail;                 \
-   }
-
-DETAILS(Char*, name)
-DETAILS(Char*, version)
-DETAILS(Char*, description)
-DETAILS(Char*, copyright_author)
-DETAILS(Char*, bug_reports_to)
-DETAILS(UInt,  avg_translation_sizeB)
-
-/*--------------------------------------------------------------------*/
-/* Setting needs */
-
 /* Use macro because they're so repetitive */
 #define NEEDS(need)  \
    extern void VG_(needs_##need)(void) \
@@ -142,17 +156,111 @@
       VG_(needs).need = True;          \
    }
 
+// These ones don't require any tool-supplied functions
 NEEDS(libc_freeres)
 NEEDS(core_errors)
-NEEDS(tool_errors)
-NEEDS(basic_block_discards)
-NEEDS(command_line_options)
-NEEDS(client_requests)
-NEEDS(syscall_wrapper)
-NEEDS(sanity_checks)
 NEEDS(data_syms)
 NEEDS(shadow_memory)
 
+void VG_(needs_basic_block_discards)(
+   void (*discard)(Addr, SizeT)
+)
+{
+   VG_(needs).basic_block_discards = True;
+   VG_(tool_interface).tool_discard_basic_block_info = discard;
+}
+
+void VG_(needs_tool_errors)(
+   Bool (*eq)         (VgRes, Error*, Error*),
+   void (*pp)         (Error*),
+   UInt (*update)     (Error*),
+   Bool (*recog)      (Char*, Supp*),
+   Bool (*read_extra) (Int, Char*, Int, Supp*),
+   Bool (*matches)    (Error*, Supp*),
+   Char* (*name)      (Error*),
+   void (*print_extra)(Error*)
+)
+{
+   VG_(needs).tool_errors = True;
+   VG_(tool_interface).tool_eq_Error                     = eq;
+   VG_(tool_interface).tool_pp_Error                     = pp;
+   VG_(tool_interface).tool_update_extra                 = update;
+   VG_(tool_interface).tool_recognised_suppression       = recog;
+   VG_(tool_interface).tool_read_extra_suppression_info  = read_extra;
+   VG_(tool_interface).tool_error_matches_suppression    = matches;
+   VG_(tool_interface).tool_get_error_name               = name;
+   VG_(tool_interface).tool_print_extra_suppression_info = print_extra;
+}
+
+void VG_(needs_command_line_options)(
+   Bool (*process)(Char*),
+   void (*usage)(void),
+   void (*debug_usage)(void)
+)
+{
+   VG_(needs).command_line_options = True;
+   VG_(tool_interface).tool_process_cmd_line_option = process;
+   VG_(tool_interface).tool_print_usage             = usage;
+   VG_(tool_interface).tool_print_debug_usage       = debug_usage;
+}
+
+void VG_(needs_client_requests)(
+   Bool (*handle)(ThreadId, UWord*, UWord*)
+)
+{
+   VG_(needs).client_requests = True;
+   VG_(tool_interface).tool_handle_client_request = handle;
+}
+
+void VG_(needs_syscall_wrapper)(
+   void(*pre) (ThreadId, UInt),
+   void(*post)(ThreadId, UInt, Int res)
+)
+{
+   VG_(needs).syscall_wrapper = True;
+   VG_(tool_interface).tool_pre_syscall  = pre;
+   VG_(tool_interface).tool_post_syscall = post;
+}
+
+void VG_(needs_sanity_checks)(
+   Bool(*cheap)(void),
+   Bool(*expen)(void)
+)
+{
+   VG_(needs).sanity_checks = True;
+   VG_(tool_interface).tool_cheap_sanity_check     = cheap;
+   VG_(tool_interface).tool_expensive_sanity_check = expen;
+}
+
+
+/* Replacing malloc() */
+
+extern void VG_(malloc_funcs)(
+   void* (*malloc)               ( ThreadId, SizeT ),
+   void* (*__builtin_new)        ( ThreadId, SizeT ),
+   void* (*__builtin_vec_new)    ( ThreadId, SizeT ),
+   void* (*memalign)             ( ThreadId, SizeT, SizeT ),
+   void* (*calloc)               ( ThreadId, SizeT, SizeT ),
+   void  (*free)                 ( ThreadId, void* ),
+   void  (*__builtin_delete)     ( ThreadId, void* ),
+   void  (*__builtin_vec_delete) ( ThreadId, void* ),
+   void* (*realloc)              ( ThreadId, void*, SizeT ),
+   SizeT client_malloc_redzone_szB
+)
+{
+   VG_(tool_interface).malloc_malloc               = malloc;
+   VG_(tool_interface).malloc___builtin_new        = __builtin_new;
+   VG_(tool_interface).malloc___builtin_vec_new    = __builtin_vec_new;
+   VG_(tool_interface).malloc_memalign             = memalign;
+   VG_(tool_interface).malloc_calloc               = calloc;
+   VG_(tool_interface).malloc_free                 = free;
+   VG_(tool_interface).malloc___builtin_delete     = __builtin_delete;
+   VG_(tool_interface).malloc___builtin_vec_delete = __builtin_vec_delete;
+   VG_(tool_interface).malloc_realloc              = realloc;
+
+   VG_(set_client_malloc_redzone_szB)( client_malloc_redzone_szB );
+}
+
 /*--------------------------------------------------------------------*/
 /*--- end                                               vg_needs.c ---*/
 /*--------------------------------------------------------------------*/
diff --git a/include/tool.h.base b/include/tool.h.base
index efb2551..58fdcf7 100644
--- a/include/tool.h.base
+++ b/include/tool.h.base
@@ -331,8 +331,8 @@
 extern void* VG_(realloc)        ( void* p, SizeT size );
 
 /* terminate everything */
-extern void  VG_(exit)( Int status )
-             __attribute__ ((__noreturn__));
+extern void VG_(exit)( Int status )
+            __attribute__ ((__noreturn__));
 
 /* terminate the calling thread - probably not what you want */
 extern void  VG_(exit_single)( Int status )
@@ -908,15 +908,6 @@
    follow the following instructions.  You can do it from scratch,
    though, if you enjoy that sort of thing. */
 
-/* Arena size for valgrind's own malloc();  default value is 0, but can
-   be overridden by tool -- but must be done so *statically*, eg:
-
-     SizeT VG_(vg_malloc_redzone_szB) = 4;
-
-   It can't be done from a function like TL_(pre_clo_init)().  So it can't,
-   for example, be controlled with a command line option, unfortunately. */
-extern SizeT VG_(vg_malloc_redzone_szB);
-
 /* Can be called from TL_(malloc) et al to do the actual alloc/freeing. */
 extern void* VG_(cli_malloc) ( SizeT align, SizeT nbytes );
 extern void  VG_(cli_free)   ( void* p );
@@ -947,6 +938,16 @@
 /*====================================================================*/
 
 /* ------------------------------------------------------------------ */
+/* Basic tool functions */
+
+extern void VG_(basic_tool_funcs)(
+   void(*post_clo_init)(void),
+   IRBB*(*instrument)(IRBB* bb_in, VexGuestLayout* layout, 
+                      IRType gWordTy, IRType hWordTy ),
+   void(*fini)(Int)
+);
+
+/* ------------------------------------------------------------------ */
 /* Details */
 
 /* Default value for avg_translations_sizeB (in bytes), indicating typical
@@ -995,7 +996,52 @@
    lot like being a member of a type class. */
 
 /* Want to report errors from tool?  This implies use of suppressions, too. */
-extern void VG_(needs_tool_errors) ( void );
+extern void VG_(needs_tool_errors) (
+   // Identify if two errors are equal, or equal enough.  `res' indicates how
+   // close is "close enough".  `res' should be passed on as necessary, eg. if
+   // the Error's `extra' part contains an ExeContext, `res' should be
+   // passed to VG_(eq_ExeContext)() if the ExeContexts are considered.  Other
+   // than that, probably don't worry about it unless you have lots of very
+   // similar errors occurring.
+   Bool (*eq_Error)(VgRes res, Error* e1, Error* e2),
+
+   // Print error context.
+   void (*pp_Error)(Error* err),
+
+   // Should fill in any details that could be postponed until after the
+   // decision whether to ignore the error (ie. details not affecting the
+   // result of TL_(eq_Error)()).  This saves time when errors are ignored.
+   // Yuk.
+   // Return value: must be the size of the `extra' part in bytes -- used by
+   // the core to make a copy.
+   UInt (*update_extra)(Error* err),
+
+   // Return value indicates recognition.  If recognised, must set skind using
+   // VG_(set_supp_kind)().
+   Bool (*recognised_suppression)(Char* name, Supp* su),
+
+   // Read any extra info for this suppression kind.  Most likely for filling
+   // in the `extra' and `string' parts (with VG_(set_supp_{extra, string})())
+   // of a suppression if necessary.  Should return False if a syntax error
+   // occurred, True otherwise.
+   Bool (*read_extra_suppression_info)(Int fd, Char* buf, Int nBuf, Supp* su),
+
+   // This should just check the kinds match and maybe some stuff in the
+   // `string' and `extra' field if appropriate (using VG_(get_supp_*)() to
+   // get the relevant suppression parts).
+   Bool (*error_matches_suppression)(Error* err, Supp* su),
+
+   // This should return the suppression name, for --gen-suppressions, or NULL
+   // if that error type cannot be suppressed.  This is the inverse of
+   // TL_(recognised_suppression)().
+   Char* (*get_error_name)(Error* err),
+
+   // This should print any extra info for the error, for --gen-suppressions,
+   // including the newline.  This is the inverse of
+   // TL_(read_extra_suppression_info)().
+   void (*print_extra_suppression_info)(Error* err)
+);
+
 
 /* Is information kept about specific individual basic blocks?  (Eg. for
    cachegrind there are cost-centres for every instruction, stored at a
@@ -1003,19 +1049,57 @@
    .so mmap/munmap-ping or self-modifying code (informed by the
    DISCARD_TRANSLATIONS user request) can cause one instruction address
    to be used for more than one instruction in one program run...  */
-extern void VG_(needs_basic_block_discards) ( void );
+extern void VG_(needs_basic_block_discards) (
+   // Should discard any information that pertains to specific basic blocks
+   // or instructions within the address range given.
+   void (*discard_basic_block_info)(Addr a, SizeT size)
+);
 
 /* Tool defines its own command line options? */
-extern void VG_(needs_command_line_options) ( void );
+extern void VG_(needs_command_line_options) (
+   // Return True if option was recognised.  Presumably sets some state to
+   // record the option as well.
+   Bool (*process_cmd_line_option)(Char* argv),
+
+   // Print out command line usage for options for normal tool operation.
+   void (*print_usage)(void),
+
+   // Print out command line usage for options for debugging the tool.
+   void (*print_debug_usage)(void)
+);
 
 /* Tool defines its own client requests? */
-extern void VG_(needs_client_requests) ( void );
+extern void VG_(needs_client_requests) (
+   // If using client requests, the number of the first request should be equal
+   // to VG_USERREQ_TOOL_BASE('X', 'Y'), where 'X' and 'Y' form a suitable two
+   // character identification for the string.  The second and subsequent
+   // requests should follow.
+   //
+   // This function should use the VG_IS_TOOL_USERREQ macro (in
+   // include/valgrind.h) to first check if it's a request for this tool.  Then
+   // should handle it if it's recognised (and return True), or return False if
+   // not recognised.  arg_block[0] holds the request number, any further args
+   // from the request are in arg_block[1..].  'ret' is for the return value...
+   // it should probably be filled, if only with 0.
+   Bool (*handle_client_request)(ThreadId tid, UWord* arg_block, UWord* ret)
+);
 
 /* Tool does stuff before and/or after system calls? */
-extern void VG_(needs_syscall_wrapper) ( void );
+// Nb: If either of the pre_ functions malloc() something to return, the
+// corresponding post_ function had better free() it!
+extern void VG_(needs_syscall_wrapper) (
+   void (* pre_syscall)(ThreadId tid, UInt syscallno),
+   void (*post_syscall)(ThreadId tid, UInt syscallno, Int res)
+);
 
 /* Are tool-state sanity checks performed? */
-extern void VG_(needs_sanity_checks) ( void );
+// Can be useful for ensuring a tool's correctness.  TL_(cheap_sanity_check)
+// is called very frequently;  TL_(expensive_sanity_check) is called less
+// frequently and can be more involved.
+extern void VG_(needs_sanity_checks) (
+   Bool(*cheap_sanity_check)(void),
+   Bool(*expensive_sanity_check)(void)
+);
 
 /* Do we need to see data symbols? */
 extern void VG_(needs_data_syms) ( void );
@@ -1028,6 +1112,23 @@
 extern float TL_(shadow_ratio);
 
 /* ------------------------------------------------------------------ */
+/* Malloc replacement */
+
+// The 'p' prefix avoids GCC complaints about overshadowing global names.
+extern void VG_(malloc_funcs)(
+   void* (*pmalloc)               ( ThreadId tid, SizeT n ),
+   void* (*p__builtin_new)        ( ThreadId tid, SizeT n ),
+   void* (*p__builtin_vec_new)    ( ThreadId tid, SizeT n ),
+   void* (*pmemalign)             ( ThreadId tid, SizeT align, SizeT n ),
+   void* (*pcalloc)               ( ThreadId tid, SizeT nmemb, SizeT size1 ),
+   void  (*pfree)                 ( ThreadId tid, void* p ),
+   void  (*p__builtin_delete)     ( ThreadId tid, void* p ),
+   void  (*p__builtin_vec_delete) ( ThreadId tid, void* p ),
+   void* (*prealloc)              ( ThreadId tid, void* p, SizeT new_size ),
+   SizeT client_malloc_redzone_szB
+);
+
+/* ------------------------------------------------------------------ */
 /* Core events to track */
 
 /* Part of the core from which this call was made.  Useful for determining
diff --git a/lackey/lk_main.c b/lackey/lk_main.c
index 55fdc7e..6a863ff 100644
--- a/lackey/lk_main.c
+++ b/lackey/lk_main.c
@@ -81,6 +81,10 @@
       "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
    VG_(details_avg_translation_sizeB) ( 175 );
+
+   VG_(basic_tool_funcs)          (TL_(post_clo_init),
+                                   TL_(instrument),
+                                   TL_(fini));
 }
 
 void TL_(post_clo_init)(void)
@@ -280,7 +284,6 @@
 
 VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 0)
 
-
 /*--------------------------------------------------------------------*/
 /*--- end                                                lk_main.c ---*/
 /*--------------------------------------------------------------------*/
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 7ac1832..1e987f3 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -1159,8 +1159,6 @@
 // Current directory at startup.
 static Char* base_dir;
 
-SizeT VG_(vg_malloc_redzone_szB) = 0;
-
 void TL_(pre_clo_init)()
 { 
    VG_(details_name)            ("Massif");
@@ -1169,10 +1167,29 @@
    VG_(details_copyright_author)("Copyright (C) 2003, Nicholas Nethercote");
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
 
+   // Basic functions
+   VG_(basic_tool_funcs)          (TL_(post_clo_init),
+                                   TL_(instrument),
+                                   TL_(fini));
+
    // Needs
    VG_(needs_libc_freeres)();
-   VG_(needs_command_line_options)();
-   VG_(needs_client_requests)     ();
+   VG_(needs_command_line_options)(TL_(process_cmd_line_option),
+                                   TL_(print_usage),
+                                   TL_(print_debug_usage));
+   VG_(needs_client_requests)     (TL_(handle_client_request));
+
+   // Malloc replacement
+   VG_(malloc_funcs)              (TL_(malloc),
+                                   TL_(__builtin_new),
+                                   TL_(__builtin_vec_new),
+                                   TL_(memalign),
+                                   TL_(calloc),
+                                   TL_(free),
+                                   TL_(__builtin_delete),
+                                   TL_(__builtin_vec_delete),
+                                   TL_(realloc),
+                                   0 );
 
    // Events to track
    VG_(init_new_mem_stack_signal) ( new_mem_stack_signal );
diff --git a/memcheck/mac_malloc_wrappers.c b/memcheck/mac_malloc_wrappers.c
index 5510a06..c14e33f 100644
--- a/memcheck/mac_malloc_wrappers.c
+++ b/memcheck/mac_malloc_wrappers.c
@@ -41,9 +41,6 @@
 static SizeT cmalloc_n_frees    = 0;
 static SizeT cmalloc_bs_mallocd = 0;
 
-/* We want a 16B redzone on heap blocks for Addrcheck and Memcheck */
-SizeT VG_(vg_malloc_redzone_szB) = 16;
-
 /* Function pointers for the two tools to track interesting events. */
 void (*MAC_(new_mem_heap)) ( Addr a, SizeT len, Bool is_inited )  = NULL;
 void (*MAC_(ban_mem_heap)) ( Addr a, SizeT len )                  = NULL;
@@ -221,7 +218,7 @@
       return NULL;
    } else {
       return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment), 
-         VG_(vg_malloc_redzone_szB), /*is_zeroed*/False, MAC_AllocMalloc,
+         MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocMalloc,
          MAC_(malloc_list));
    }
 }
@@ -232,7 +229,7 @@
       return NULL;
    } else {
       return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment), 
-         VG_(vg_malloc_redzone_szB), /*is_zeroed*/False, MAC_AllocNew,
+         MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocNew,
          MAC_(malloc_list));
    }
 }
@@ -243,7 +240,7 @@
       return NULL;
    } else {
       return MAC_(new_block) ( tid, 0, n, VG_(clo_alignment), 
-         VG_(vg_malloc_redzone_szB), /*is_zeroed*/False, MAC_AllocNewVec,
+         MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocNewVec,
          MAC_(malloc_list));
    }
 }
@@ -254,7 +251,7 @@
       return NULL;
    } else {
       return MAC_(new_block) ( tid, 0, n, align, 
-         VG_(vg_malloc_redzone_szB), /*is_zeroed*/False, MAC_AllocMalloc,
+         MALLOC_REDZONE_SZB, /*is_zeroed*/False, MAC_AllocMalloc,
          MAC_(malloc_list));
    }
 }
@@ -265,7 +262,7 @@
       return NULL;
    } else {
       return MAC_(new_block) ( tid, 0, nmemb*size1, VG_(clo_alignment),
-         VG_(vg_malloc_redzone_szB), /*is_zeroed*/True, MAC_AllocMalloc,
+         MALLOC_REDZONE_SZB, /*is_zeroed*/True, MAC_AllocMalloc,
          MAC_(malloc_list));
    }
 }
@@ -326,19 +323,19 @@
 void TL_(free) ( ThreadId tid, void* p )
 {
    MAC_(handle_free)( 
-      tid, (Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocMalloc );
+      tid, (Addr)p, MALLOC_REDZONE_SZB, MAC_AllocMalloc );
 }
 
 void TL_(__builtin_delete) ( ThreadId tid, void* p )
 {
    MAC_(handle_free)(
-      tid, (Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocNew);
+      tid, (Addr)p, MALLOC_REDZONE_SZB, MAC_AllocNew);
 }
 
 void TL_(__builtin_vec_delete) ( ThreadId tid, void* p )
 {
    MAC_(handle_free)(
-      tid, (Addr)p, VG_(vg_malloc_redzone_szB), MAC_AllocNewVec);
+      tid, (Addr)p, MALLOC_REDZONE_SZB, MAC_AllocNewVec);
 }
 
 void* TL_(realloc) ( ThreadId tid, void* p, SizeT new_size )
@@ -397,19 +394,17 @@
 
       /* First half kept and copied, second half new, 
          red zones as normal */
-      MAC_(ban_mem_heap) ( p_new-VG_(vg_malloc_redzone_szB), 
-                                 VG_(vg_malloc_redzone_szB) );
+      MAC_(ban_mem_heap) ( p_new-MALLOC_REDZONE_SZB, MALLOC_REDZONE_SZB );
       MAC_(copy_mem_heap)( (Addr)p, p_new, mc->size );
       MAC_(new_mem_heap) ( p_new+mc->size, new_size-mc->size, /*inited*/False );
-      MAC_(ban_mem_heap) ( p_new+new_size, VG_(vg_malloc_redzone_szB) );
+      MAC_(ban_mem_heap) ( p_new+new_size, MALLOC_REDZONE_SZB );
 
       /* Copy from old to new */
       for (i = 0; i < mc->size; i++)
          ((UChar*)p_new)[i] = ((UChar*)p)[i];
 
       /* Free old memory */
-      die_and_free_mem ( tid, mc, prev_chunks_next_ptr,
-                         VG_(vg_malloc_redzone_szB) );
+      die_and_free_mem ( tid, mc, prev_chunks_next_ptr, MALLOC_REDZONE_SZB );
 
       /* this has to be after die_and_free_mem, otherwise the
          former succeeds in shorting out the new block, not the
diff --git a/memcheck/mac_shared.h b/memcheck/mac_shared.h
index c6092e2..f3a82be 100644
--- a/memcheck/mac_shared.h
+++ b/memcheck/mac_shared.h
@@ -290,6 +290,8 @@
 extern void MAC_(print_common_usage)             ( void );
 extern void MAC_(print_common_debug_usage)       ( void );
 
+/* We want a 16B redzone on heap blocks for Addrcheck and Memcheck */
+#define MALLOC_REDZONE_SZB    16
 
 /*------------------------------------------------------------*/
 /*--- Variables                                            ---*/
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index 99f45ce..c90513d 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -1873,14 +1873,39 @@
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
    VG_(details_avg_translation_sizeB) ( 370 );
 
+   VG_(basic_tool_funcs)          (TL_(post_clo_init),
+                                   TL_(instrument),
+                                   TL_(fini));
+
    VG_(needs_core_errors)         ();
-   VG_(needs_tool_errors)         ();
+   VG_(needs_tool_errors)         (TL_(eq_Error),
+                                   TL_(pp_Error),
+                                   TL_(update_extra),
+                                   TL_(recognised_suppression),
+                                   TL_(read_extra_suppression_info),
+                                   TL_(error_matches_suppression),
+                                   TL_(get_error_name),
+                                   TL_(print_extra_suppression_info));
    VG_(needs_libc_freeres)        ();
-   VG_(needs_command_line_options)();
-   VG_(needs_client_requests)     ();
-   VG_(needs_sanity_checks)       ();
+   VG_(needs_command_line_options)(TL_(process_cmd_line_option),
+                                   TL_(print_usage),
+                                   TL_(print_debug_usage));
+   VG_(needs_client_requests)     (TL_(handle_client_request));
+   VG_(needs_sanity_checks)       (TL_(cheap_sanity_check),
+                                   TL_(expensive_sanity_check));
    VG_(needs_shadow_memory)       ();
 
+   VG_(malloc_funcs)              (TL_(malloc),
+                                   TL_(__builtin_new),
+                                   TL_(__builtin_vec_new),
+                                   TL_(memalign),
+                                   TL_(calloc),
+                                   TL_(free),
+                                   TL_(__builtin_delete),
+                                   TL_(__builtin_vec_delete),
+                                   TL_(realloc),
+                                   MALLOC_REDZONE_SZB );
+
    MAC_( new_mem_heap)             = & mc_new_mem_heap;
    MAC_( ban_mem_heap)             = & mc_make_noaccess;
    MAC_(copy_mem_heap)             = & mc_copy_address_range_state;
@@ -1893,7 +1918,6 @@
    VG_(init_new_mem_mmap)         ( & mc_new_mem_mmap );
    
    VG_(init_copy_mem_remap)       ( & mc_copy_address_range_state );
-   //VG_(init_change_mem_mprotect)  ( & mc_set_perms );
       
    VG_(init_die_mem_stack_signal) ( & mc_make_noaccess ); 
    VG_(init_die_mem_brk)          ( & mc_make_noaccess );
diff --git a/none/nl_main.c b/none/nl_main.c
index 2f136c2..c181d82 100644
--- a/none/nl_main.c
+++ b/none/nl_main.c
@@ -39,6 +39,10 @@
       "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
 
+   VG_(basic_tool_funcs)          (TL_(post_clo_init),
+                                   TL_(instrument),
+                                   TL_(fini));
+
    /* No needs, no core events to track */
 }