Rename mac_needs.c as mac_shared.c, which is much more sensible and
actually matches mac_shared.h.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3645 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/memcheck/mac_shared.c b/memcheck/mac_shared.c
new file mode 100644
index 0000000..55a2bec
--- /dev/null
+++ b/memcheck/mac_shared.c
@@ -0,0 +1,977 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Code that is shared between MemCheck and AddrCheck.          ---*/
+/*---                                                 mac_shared.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of MemCheck, a heavyweight Valgrind tool for
+   detecting memory errors, and AddrCheck, a lightweight Valgrind tool 
+   for detecting memory errors.
+
+   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.
+*/
+
+
+#include "mac_shared.h"
+
+#include "memcheck.h"   /* for VG_USERREQ__* */
+
+/*------------------------------------------------------------*/
+/*--- Defns                                                ---*/
+/*------------------------------------------------------------*/
+
+/* These many bytes below %ESP are considered addressible if we're
+   doing the --workaround-gcc296-bugs hack. */
+#define VG_GCC296_BUG_STACK_SLOP 1024
+
+/*------------------------------------------------------------*/
+/*--- Command line options                                 ---*/
+/*------------------------------------------------------------*/
+
+Bool          MAC_(clo_partial_loads_ok)       = True;
+Int           MAC_(clo_freelist_vol)           = 1000000;
+LeakCheckMode MAC_(clo_leak_check)             = LC_Summary;
+VgRes         MAC_(clo_leak_resolution)        = Vg_LowRes;
+Bool          MAC_(clo_show_reachable)         = False;
+Bool          MAC_(clo_workaround_gcc296_bugs) = False;
+
+Bool MAC_(process_common_cmd_line_option)(Char* arg)
+{
+	VG_BOOL_CLO(arg, "--partial-loads-ok",      MAC_(clo_partial_loads_ok))
+   else VG_BOOL_CLO(arg, "--show-reachable",        MAC_(clo_show_reachable))
+   else VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",MAC_(clo_workaround_gcc296_bugs))
+   
+   else VG_BNUM_CLO(arg, "--freelist-vol",  MAC_(clo_freelist_vol), 0, 1000000000)
+   
+   else if (VG_CLO_STREQ(arg, "--leak-check=no"))
+      MAC_(clo_leak_check) = LC_Off;
+   else if (VG_CLO_STREQ(arg, "--leak-check=summary"))
+      MAC_(clo_leak_check) = LC_Summary;
+   else if (VG_CLO_STREQ(arg, "--leak-check=yes") ||
+	    VG_CLO_STREQ(arg, "--leak-check=full"))
+      MAC_(clo_leak_check) = LC_Full;
+
+   else if (VG_CLO_STREQ(arg, "--leak-resolution=low"))
+      MAC_(clo_leak_resolution) = Vg_LowRes;
+   else if (VG_CLO_STREQ(arg, "--leak-resolution=med"))
+      MAC_(clo_leak_resolution) = Vg_MedRes;
+   else if (VG_CLO_STREQ(arg, "--leak-resolution=high"))
+      MAC_(clo_leak_resolution) = Vg_HighRes;
+
+   else
+      return VG_(replacement_malloc_process_cmd_line_option)(arg);
+
+   return True;
+}
+
+void MAC_(print_common_usage)(void)
+{
+   VG_(printf)(
+"    --partial-loads-ok=no|yes        too hard to explain here; see manual [yes]\n"
+"    --freelist-vol=<number>          volume of freed blocks queue [1000000]\n"
+"    --leak-check=no|summary|full     search for memory leaks at exit?  [summary]\n"
+"    --leak-resolution=low|med|high   how much bt merging in leak check [low]\n"
+"    --show-reachable=no|yes          show reachable blocks in leak check? [no]\n"
+"    --workaround-gcc296-bugs=no|yes  self explanatory [no]\n"
+   );
+   VG_(replacement_malloc_print_usage)();
+}
+
+void MAC_(print_common_debug_usage)(void)
+{
+   VG_(replacement_malloc_print_debug_usage)();
+}
+
+/*------------------------------------------------------------*/
+/*--- Comparing and printing errors                        ---*/
+/*------------------------------------------------------------*/
+
+static __inline__
+void clear_AddrInfo ( AddrInfo* ai )
+{
+   ai->akind      = Unknown;
+   ai->blksize    = 0;
+   ai->rwoffset   = 0;
+   ai->lastchange = NULL;
+   ai->stack_tid  = VG_INVALID_THREADID;
+   ai->maybe_gcc  = False;
+   ai->desc       = NULL;
+}
+
+void MAC_(clear_MAC_Error) ( MAC_Error* err_extra )
+{
+   err_extra->axskind   = ReadAxs;
+   err_extra->size      = 0;
+   clear_AddrInfo ( &err_extra->addrinfo );
+   err_extra->isUnaddr  = True;
+}
+
+__attribute__ ((unused))
+static Bool eq_AddrInfo ( VgRes res, AddrInfo* ai1, AddrInfo* ai2 )
+{
+   if (ai1->akind != Undescribed 
+       && ai2->akind != Undescribed
+       && ai1->akind != ai2->akind) 
+      return False;
+   if (ai1->akind == Freed || ai1->akind == Mallocd) {
+      if (ai1->blksize != ai2->blksize)
+         return False;
+      if (!VG_(eq_ExeContext)(res, ai1->lastchange, ai2->lastchange))
+         return False;
+   }
+   return True;
+}
+
+/* Compare error contexts, to detect duplicates.  Note that if they
+   are otherwise the same, the faulting addrs and associated rwoffsets
+   are allowed to be different.  */
+
+Bool MAC_(eq_Error) ( VgRes res, Error* e1, Error* e2 )
+{
+   MAC_Error* e1_extra = VG_(get_error_extra)(e1);
+   MAC_Error* e2_extra = VG_(get_error_extra)(e2);
+
+   /* Guaranteed by calling function */
+   tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
+   
+   switch (VG_(get_error_kind)(e1)) {
+      case CoreMemErr: {
+         Char *e1s, *e2s;
+         if (e1_extra->isUnaddr != e2_extra->isUnaddr) return False;
+         e1s = VG_(get_error_string)(e1);
+         e2s = VG_(get_error_string)(e2);
+         if (e1s == e2s)                               return True;
+         if (0 == VG_(strcmp)(e1s, e2s))               return True;
+         return False;
+      }
+
+      // Perhaps we should also check the addrinfo.akinds for equality.
+      // That would result in more error reports, but only in cases where
+      // a register contains uninitialised bytes and points to memory
+      // containing uninitialised bytes.  Currently, the 2nd of those to be
+      // detected won't be reported.  That is (nearly?) always the memory
+      // error, which is good.
+      case ParamErr:
+         if (0 != VG_(strcmp)(VG_(get_error_string)(e1),
+                              VG_(get_error_string)(e2)))   return False;
+         // fall through
+      case UserErr:
+         if (e1_extra->isUnaddr != e2_extra->isUnaddr)      return False;
+         return True;
+
+      case FreeErr:
+      case FreeMismatchErr:
+         /* JRS 2002-Aug-26: comparing addrs seems overkill and can
+            cause excessive duplication of errors.  Not even AddrErr
+            below does that.  So don't compare either the .addr field
+            or the .addrinfo fields. */
+         /* if (e1->addr != e2->addr) return False; */
+         /* if (!eq_AddrInfo(res, &e1_extra->addrinfo, &e2_extra->addrinfo)) 
+               return False;
+         */
+         return True;
+
+      case AddrErr:
+         /* if (e1_extra->axskind != e2_extra->axskind) return False; */
+         if (e1_extra->size != e2_extra->size) return False;
+         /*
+         if (!eq_AddrInfo(res, &e1_extra->addrinfo, &e2_extra->addrinfo)) 
+            return False;
+         */
+         return True;
+
+      case ValueErr:
+         if (e1_extra->size != e2_extra->size) return False;
+         return True;
+
+      case OverlapErr:
+         return True;
+
+      case LeakErr:
+         VG_(tool_panic)("Shouldn't get LeakErr in MAC_(eq_Error),\n"
+                         "since it's handled with VG_(unique_error)()!");
+
+      case IllegalMempoolErr:
+         return True;
+
+      default: 
+         VG_(printf)("Error:\n  unknown error code %d\n",
+                     VG_(get_error_kind)(e1));
+         VG_(tool_panic)("unknown error code in MAC_(eq_Error)");
+   }
+}
+
+void MAC_(pp_AddrInfo) ( Addr a, AddrInfo* ai )
+{
+   switch (ai->akind) {
+      case Stack: 
+         VG_(message)(Vg_UserMsg, 
+                      " Address 0x%lx is on thread %d's stack", 
+                      (ULong)a, ai->stack_tid);
+         break;
+      case Unknown:
+         if (ai->maybe_gcc) {
+            VG_(message)(Vg_UserMsg, 
+               " Address 0x%lx is just below %%esp.  Possibly a bug in GCC/G++",
+               (ULong)a);
+            VG_(message)(Vg_UserMsg, 
+               "  v 2.96 or 3.0.X.  To suppress, use: --workaround-gcc296-bugs=yes");
+	 } else {
+            VG_(message)(Vg_UserMsg, 
+               " Address 0x%lx is not stack'd, malloc'd or (recently) free'd",
+               (ULong)a);
+         }
+         break;
+      case Freed: case Mallocd: case UserG: case Mempool: {
+         SizeT delta;
+         const Char* relative;
+         const Char* kind;
+         if (ai->akind == Mempool) {
+            kind = "mempool";
+         } else {
+            kind = "block";
+         }
+	 if (ai->desc != NULL)
+	    kind = ai->desc;
+
+         if (ai->rwoffset < 0) {
+            delta    = (SizeT)(- ai->rwoffset);
+            relative = "before";
+         } else if (ai->rwoffset >= ai->blksize) {
+            delta    = ai->rwoffset - ai->blksize;
+            relative = "after";
+         } else {
+            delta    = ai->rwoffset;
+            relative = "inside";
+         }
+         VG_(message)(Vg_UserMsg, 
+            " Address 0x%lx is %llu bytes %s a %s of size %d %s",
+            (ULong)a, (ULong)delta, relative, kind,
+            ai->blksize,
+            ai->akind==Mallocd ? "alloc'd" 
+               : ai->akind==Freed ? "free'd" 
+                                  : "client-defined");
+         VG_(pp_ExeContext)(ai->lastchange);
+         break;
+      }
+      case Register:
+         // print nothing
+         tl_assert(0 == a);
+         break;
+      default:
+         VG_(tool_panic)("MAC_(pp_AddrInfo)");
+   }
+}
+
+/* This prints out the message for the error types where Memcheck and
+   Addrcheck have identical messages */
+void MAC_(pp_shared_Error) ( Error* err )
+{
+   MAC_Error* err_extra = VG_(get_error_extra)(err);
+
+   switch (VG_(get_error_kind)(err)) {
+      case FreeErr:
+         VG_(message)(Vg_UserMsg, "Invalid free() / delete / delete[]");
+         /* fall through */
+      case FreeMismatchErr:
+         if (VG_(get_error_kind)(err) == FreeMismatchErr)
+            VG_(message)(Vg_UserMsg, 
+                         "Mismatched free() / delete / delete []");
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+         MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         break;
+
+      case AddrErr:
+         switch (err_extra->axskind) {
+            case ReadAxs:
+               VG_(message)(Vg_UserMsg, "Invalid read of size %d", 
+                                        err_extra->size ); 
+               break;
+            case WriteAxs:
+               VG_(message)(Vg_UserMsg, "Invalid write of size %d", 
+                                        err_extra->size ); 
+               break;
+            case ExecAxs:
+               VG_(message)(Vg_UserMsg, "Jump to the invalid address "
+                                        "stated on the next line");
+               break;
+            default: 
+               VG_(tool_panic)("MAC_(pp_shared_Error)(axskind)");
+         }
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+         MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         break;
+
+      case OverlapErr: {
+         OverlapExtra* ov_extra = (OverlapExtra*)VG_(get_error_extra)(err);
+         if (ov_extra->len == -1)
+            VG_(message)(Vg_UserMsg,
+                         "Source and destination overlap in %s(%p, %p)",
+                         VG_(get_error_string)(err),
+                         ov_extra->dst, ov_extra->src);
+         else
+            VG_(message)(Vg_UserMsg,
+                         "Source and destination overlap in %s(%p, %p, %d)",
+                         VG_(get_error_string)(err),
+                         ov_extra->dst, ov_extra->src, ov_extra->len);
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+         break;
+      }
+      case LeakErr: {
+         /* Totally abusing the types of these spare fields... oh well. */
+         UInt n_this_record   = (UWord)VG_(get_error_address)(err);
+         UInt n_total_records = (UWord)VG_(get_error_string) (err);
+
+         MAC_(pp_LeakError)(err_extra, n_this_record, n_total_records);
+         break;
+      }
+
+      case IllegalMempoolErr:
+         VG_(message)(Vg_UserMsg, "Illegal memory pool address");
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+         MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         break;
+
+      default: 
+         VG_(printf)("Error:\n  unknown Memcheck/Addrcheck error code %d\n",
+                     VG_(get_error_kind)(err));
+         VG_(tool_panic)("unknown error code in MAC_(pp_shared_Error)");
+   }
+}
+
+/*------------------------------------------------------------*/
+/*--- Recording errors                                     ---*/
+/*------------------------------------------------------------*/
+
+/* Additional description function for describe_addr();  used by
+   MemCheck for user blocks, which Addrcheck doesn't support. */
+Bool (*MAC_(describe_addr_supp)) ( Addr a, AddrInfo* ai ) = NULL;
+
+/* Callback for searching thread stacks */
+static Bool addr_is_in_bounds(Addr stack_min, Addr stack_max, void *ap)
+{
+   Addr a = *(Addr *)ap;
+  
+   return (stack_min <= a && a <= stack_max);
+}
+
+/* Callback for searching free'd list */
+static Bool addr_is_in_MAC_Chunk(MAC_Chunk* mc, void *ap)
+{
+   Addr a = *(Addr *)ap;
+  
+   return VG_(addr_is_in_block)( a, mc->data, mc->size );
+}
+
+/* Callback for searching malloc'd lists */
+static Bool addr_is_in_HashNode(VgHashNode* sh_ch, void *ap)
+{
+   return addr_is_in_MAC_Chunk( (MAC_Chunk*)sh_ch, ap );
+}
+
+/* Describe an address as best you can, for error messages,
+   putting the result in ai. */
+static void describe_addr ( Addr a, AddrInfo* ai )
+{
+   MAC_Chunk* sc;
+   ThreadId   tid;
+
+   /* Perhaps it's a user-def'd block ?  (only check if requested, though) */
+   if (NULL != MAC_(describe_addr_supp)) {
+      if (MAC_(describe_addr_supp)( a, ai ))
+         return;
+   }
+   /* Perhaps it's on a thread's stack? */
+   tid = VG_(first_matching_thread_stack)(addr_is_in_bounds, &a);
+   if (tid != VG_INVALID_THREADID) {
+      ai->akind     = Stack;
+      ai->stack_tid = tid;
+      return;
+   }
+   /* Search for a recently freed block which might bracket it. */
+   sc = MAC_(first_matching_freed_MAC_Chunk)(addr_is_in_MAC_Chunk, &a);
+   if (NULL != sc) {
+      ai->akind      = Freed;
+      ai->blksize    = sc->size;
+      ai->rwoffset   = (Int)a - (Int)sc->data;
+      ai->lastchange = sc->where;
+      return;
+   }
+   /* Search for a currently malloc'd block which might bracket it. */
+   sc = (MAC_Chunk*)VG_(HT_first_match)(MAC_(malloc_list), addr_is_in_HashNode, &a);
+   if (NULL != sc) {
+      ai->akind      = Mallocd;
+      ai->blksize    = sc->size;
+      ai->rwoffset   = (Int)(a) - (Int)sc->data;
+      ai->lastchange = sc->where;
+      return;
+   }
+   /* Clueless ... */
+   ai->akind = Unknown;
+   return;
+}
+
+/* Is this address within some small distance below %ESP?  Used only
+   for the --workaround-gcc296-bugs kludge. */
+static Bool is_just_below_ESP( Addr esp, Addr aa )
+{
+   if (esp > aa && (esp - aa) <= VG_GCC296_BUG_STACK_SLOP)
+      return True;
+   else
+      return False;
+}
+
+/* This one called from generated code and non-generated code. */
+
+void MAC_(record_address_error) ( ThreadId tid, Addr a, Int size,
+                                  Bool isWrite )
+{
+   MAC_Error err_extra;
+   Bool      just_below_esp;
+
+   just_below_esp = is_just_below_ESP( VG_(get_SP)(tid), a );
+
+   /* If this is caused by an access immediately below %ESP, and the
+      user asks nicely, we just ignore it. */
+   if (MAC_(clo_workaround_gcc296_bugs) && just_below_esp)
+      return;
+
+   MAC_(clear_MAC_Error)( &err_extra );
+   err_extra.axskind = isWrite ? WriteAxs : ReadAxs;
+   err_extra.size    = size;
+   err_extra.addrinfo.akind     = Undescribed;
+   err_extra.addrinfo.maybe_gcc = just_below_esp;
+   VG_(maybe_record_error)( tid, AddrErr, a, /*s*/NULL, &err_extra );
+}
+
+/* These ones are called from non-generated code */
+
+/* This is for memory errors in pthread functions, as opposed to pthread API
+   errors which are found by the core. */
+void MAC_(record_core_mem_error) ( ThreadId tid, Bool isUnaddr, Char* msg )
+{
+   MAC_Error err_extra;
+
+   MAC_(clear_MAC_Error)( &err_extra );
+   err_extra.isUnaddr = isUnaddr;
+   VG_(maybe_record_error)( tid, CoreMemErr, /*addr*/0, msg, &err_extra );
+}
+
+// Three kinds of param errors:
+// - register arg contains undefined bytes
+// - memory arg is unaddressable
+// - memory arg contains undefined bytes
+// 'isReg' and 'isUnaddr' dictate which of these it is.
+void MAC_(record_param_error) ( ThreadId tid, Addr a, Bool isReg,
+                                Bool isUnaddr, Char* msg )
+{
+   MAC_Error err_extra;
+
+   tl_assert(VG_INVALID_THREADID != tid);
+   if (isUnaddr) tl_assert(!isReg);    // unaddressable register is impossible
+   MAC_(clear_MAC_Error)( &err_extra );
+   err_extra.addrinfo.akind = ( isReg ? Register : Undescribed );
+   err_extra.isUnaddr = isUnaddr;
+   VG_(maybe_record_error)( tid, ParamErr, a, msg, &err_extra );
+}
+
+void MAC_(record_jump_error) ( ThreadId tid, Addr a )
+{
+   MAC_Error err_extra;
+
+   tl_assert(VG_INVALID_THREADID != tid);
+   MAC_(clear_MAC_Error)( &err_extra );
+   err_extra.axskind = ExecAxs;
+   err_extra.size    = 1;     // size only used for suppressions
+   err_extra.addrinfo.akind = Undescribed;
+   VG_(maybe_record_error)( tid, AddrErr, a, /*s*/NULL, &err_extra );
+}
+
+void MAC_(record_free_error) ( ThreadId tid, Addr a ) 
+{
+   MAC_Error err_extra;
+
+   tl_assert(VG_INVALID_THREADID != tid);
+   MAC_(clear_MAC_Error)( &err_extra );
+   err_extra.addrinfo.akind = Undescribed;
+   VG_(maybe_record_error)( tid, FreeErr, a, /*s*/NULL, &err_extra );
+}
+
+void MAC_(record_illegal_mempool_error) ( ThreadId tid, Addr a ) 
+{
+   MAC_Error err_extra;
+
+   tl_assert(VG_INVALID_THREADID != tid);
+   MAC_(clear_MAC_Error)( &err_extra );
+   err_extra.addrinfo.akind = Undescribed;
+   VG_(maybe_record_error)( tid, IllegalMempoolErr, a, /*s*/NULL, &err_extra );
+}
+
+void MAC_(record_freemismatch_error) ( ThreadId tid, Addr a )
+{
+   MAC_Error err_extra;
+
+   tl_assert(VG_INVALID_THREADID != tid);
+   MAC_(clear_MAC_Error)( &err_extra );
+   err_extra.addrinfo.akind = Undescribed;
+   VG_(maybe_record_error)( tid, FreeMismatchErr, a, /*s*/NULL, &err_extra );
+}
+
+void MAC_(record_overlap_error) ( ThreadId tid, 
+                                  Char* function, OverlapExtra* ov_extra )
+{
+   VG_(maybe_record_error)( 
+      tid, OverlapErr, /*addr*/0, /*s*/function, ov_extra );
+}
+
+
+/* Updates the copy with address info if necessary (but not for all errors). */
+UInt MAC_(update_extra)( Error* err )
+{
+   switch (VG_(get_error_kind)(err)) {
+   case ValueErr:
+   case CoreMemErr:
+   case AddrErr: 
+   case ParamErr:
+   case UserErr:
+   case FreeErr:
+   case IllegalMempoolErr:
+   case FreeMismatchErr: {
+      MAC_Error* extra = VG_(get_error_extra)(err);
+      if (extra != NULL && Undescribed == extra->addrinfo.akind) {
+         describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
+      }
+      return sizeof(MAC_Error);
+   }
+   /* Don't need to return the correct size -- LeakErrs are always shown with
+      VG_(unique_error)() so they're not copied anyway. */
+   case LeakErr:     return 0;
+   case OverlapErr:  return sizeof(OverlapExtra);
+   default: VG_(tool_panic)("update_extra: bad errkind");
+   }
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Suppressions                                         ---*/
+/*------------------------------------------------------------*/
+
+Bool MAC_(shared_recognised_suppression) ( Char* name, Supp* su )
+{
+   SuppKind skind;
+
+   if      (VG_STREQ(name, "Param"))   skind = ParamSupp;
+   else if (VG_STREQ(name, "CoreMem")) skind = CoreMemSupp;
+   else if (VG_STREQ(name, "Addr1"))   skind = Addr1Supp;
+   else if (VG_STREQ(name, "Addr2"))   skind = Addr2Supp;
+   else if (VG_STREQ(name, "Addr4"))   skind = Addr4Supp;
+   else if (VG_STREQ(name, "Addr8"))   skind = Addr8Supp;
+   else if (VG_STREQ(name, "Addr16"))  skind = Addr16Supp;
+   else if (VG_STREQ(name, "Free"))    skind = FreeSupp;
+   else if (VG_STREQ(name, "Leak"))    skind = LeakSupp;
+   else if (VG_STREQ(name, "Overlap")) skind = OverlapSupp;
+   else if (VG_STREQ(name, "Mempool")) skind = MempoolSupp;
+   else
+      return False;
+
+   VG_(set_supp_kind)(su, skind);
+   return True;
+}
+
+Bool MAC_(read_extra_suppression_info) ( Int fd, Char* buf, Int nBuf, Supp *su )
+{
+   Bool eof;
+
+   if (VG_(get_supp_kind)(su) == ParamSupp) {
+      eof = VG_(get_line) ( fd, buf, nBuf );
+      if (eof) return False;
+      VG_(set_supp_string)(su, VG_(strdup)(buf));
+   }
+   return True;
+}
+
+Bool MAC_(error_matches_suppression)(Error* err, Supp* su)
+{
+   Int        su_size;
+   MAC_Error* err_extra = VG_(get_error_extra)(err);
+   ErrorKind  ekind     = VG_(get_error_kind )(err);
+
+   switch (VG_(get_supp_kind)(su)) {
+      case ParamSupp:
+         return (ekind == ParamErr 
+              && VG_STREQ(VG_(get_error_string)(err), 
+                          VG_(get_supp_string)(su)));
+
+      case CoreMemSupp:
+         return (ekind == CoreMemErr
+              && VG_STREQ(VG_(get_error_string)(err),
+                          VG_(get_supp_string)(su)));
+
+      case Value0Supp: su_size = 0; goto value_case;
+      case Value1Supp: su_size = 1; goto value_case;
+      case Value2Supp: su_size = 2; goto value_case;
+      case Value4Supp: su_size = 4; goto value_case;
+      case Value8Supp: su_size = 8; goto value_case;
+      case Value16Supp:su_size =16; goto value_case;
+      value_case:
+         return (ekind == ValueErr && err_extra->size == su_size);
+
+      case Addr1Supp: su_size = 1; goto addr_case;
+      case Addr2Supp: su_size = 2; goto addr_case;
+      case Addr4Supp: su_size = 4; goto addr_case;
+      case Addr8Supp: su_size = 8; goto addr_case;
+      case Addr16Supp:su_size =16; goto addr_case;
+      addr_case:
+         return (ekind == AddrErr && err_extra->size == su_size);
+
+      case FreeSupp:
+         return (ekind == FreeErr || ekind == FreeMismatchErr);
+
+      case OverlapSupp:
+         return (ekind = OverlapErr);
+
+      case LeakSupp:
+         return (ekind == LeakErr);
+
+      case MempoolSupp:
+         return (ekind == IllegalMempoolErr);
+
+      default:
+         VG_(printf)("Error:\n"
+                     "  unknown suppression type %d\n",
+                     VG_(get_supp_kind)(su));
+         VG_(tool_panic)("unknown suppression type in "
+                         "MAC_(error_matches_suppression)");
+   }
+}
+
+Char* MAC_(get_error_name) ( Error* err )
+{
+   Char* s;
+   switch (VG_(get_error_kind)(err)) {
+   case ParamErr:           return "Param";
+   case UserErr:            return NULL;  /* Can't suppress User errors */
+   case FreeMismatchErr:    return "Free";
+   case IllegalMempoolErr:  return "Mempool";
+   case FreeErr:            return "Free";
+   case AddrErr:            
+      switch ( ((MAC_Error*)VG_(get_error_extra)(err))->size ) {
+      case 1:               return "Addr1";
+      case 2:               return "Addr2";
+      case 4:               return "Addr4";
+      case 8:               return "Addr8";
+      case 16:              return "Addr16";
+      default:              VG_(tool_panic)("unexpected size for Addr");
+      }
+     
+   case ValueErr:
+      switch ( ((MAC_Error*)VG_(get_error_extra)(err))->size ) {
+      case 0:               return "Cond";
+      case 1:               return "Value1";
+      case 2:               return "Value2";
+      case 4:               return "Value4";
+      case 8:               return "Value8";
+      case 16:              return "Value16";
+      default:              VG_(tool_panic)("unexpected size for Value");
+      }
+   case CoreMemErr:         return "CoreMem";
+   case OverlapErr:         return "Overlap";
+   case LeakErr:            return "Leak";
+   default:                 VG_(tool_panic)("get_error_name: unexpected type");
+   }
+   VG_(printf)(s);
+}
+
+void MAC_(print_extra_suppression_info) ( Error* err )
+{
+   if (ParamErr == VG_(get_error_kind)(err)) {
+      VG_(printf)("   %s\n", VG_(get_error_string)(err));
+   }
+}
+
+/*------------------------------------------------------------*/
+/*--- Crude profiling machinery.                           ---*/
+/*------------------------------------------------------------*/
+
+/* Event index.  If just the name of the fn is given, this means the
+   number of calls to the fn.  Otherwise it is the specified event.
+   Ones marked 'M' are MemCheck only.  Ones marked 'A' are AddrCheck only.
+   The rest are shared.
+
+   10   alloc_secondary_map
+
+   20   get_abit
+M  21   get_vbyte
+   22   set_abit
+M  23   set_vbyte
+   24   get_abits4_ALIGNED
+M  25   get_vbytes4_ALIGNED       
+
+   30   set_address_range_perms
+   31   set_address_range_perms(lower byte loop)
+   32   set_address_range_perms(quadword loop)
+   33   set_address_range_perms(upper byte loop)
+   
+   35   make_noaccess
+   36   make_writable
+   37   make_readable
+A  38   make_accessible
+
+   40   copy_address_range_state
+   41   copy_address_range_state(byte loop)
+   42   check_writable
+   43   check_writable(byte loop)
+   44   check_readable
+   45   check_readable(byte loop)
+   46   check_readable_asciiz
+   47   check_readable_asciiz(byte loop)
+A  48   check_accessible
+A  49   check_accessible(byte loop)
+
+   50   make_noaccess_aligned
+   51   make_writable_aligned
+
+M  60   helperc_LOADV4
+M  61   helperc_STOREV4
+M  62   helperc_LOADV2
+M  63   helperc_STOREV2
+M  64   helperc_LOADV1
+M  65   helperc_STOREV1
+
+A  66   helperc_ACCESS4
+A  67   helperc_ACCESS2
+A  68   helperc_ACCESS1
+
+M  70   rim_rd_V4_SLOWLY
+M  71   rim_wr_V4_SLOWLY
+M  72   rim_rd_V2_SLOWLY
+M  73   rim_wr_V2_SLOWLY
+M  74   rim_rd_V1_SLOWLY
+M  75   rim_wr_V1_SLOWLY
+
+A  76   ACCESS4_SLOWLY
+A  77   ACCESS2_SLOWLY
+A  78   ACCESS1_SLOWLY
+
+   80   fpu_read
+   81   fpu_read aligned 4
+   82   fpu_read aligned 8
+   83   fpu_read 2
+   84   fpu_read 10/28/108/512
+
+M  85   fpu_write
+M  86   fpu_write aligned 4
+M  87   fpu_write aligned 8
+M  88   fpu_write 2
+M  89   fpu_write 10/28/108/512
+
+   90   fpu_access
+   91   fpu_access aligned 4
+   92   fpu_access aligned 8
+   93   fpu_access 2
+   94   fpu_access 10/28/108/512
+
+   100  fpu_access_check_SLOWLY
+   101  fpu_access_check_SLOWLY(byte loop)
+
+   110  new_mem_stack_4
+   111  new_mem_stack_8
+   112  new_mem_stack_12
+   113  new_mem_stack_16
+   114  new_mem_stack_32
+   115  new_mem_stack
+
+   120  die_mem_stack_4
+   121  die_mem_stack_8
+   122  die_mem_stack_12
+   123  die_mem_stack_16
+   124  die_mem_stack_32
+   125  die_mem_stack
+*/
+
+#ifdef MAC_PROFILE_MEMORY
+
+UInt   MAC_(event_ctr)[N_PROF_EVENTS];
+HChar* MAC_(event_ctr_name)[N_PROF_EVENTS];
+
+static void init_prof_mem ( void )
+{
+   Int i;
+   for (i = 0; i < N_PROF_EVENTS; i++) {
+      MAC_(event_ctr)[i] = 0;
+      MAC_(event_ctr_name)[i] = NULL;
+   }
+}
+
+static void done_prof_mem ( void )
+{
+   Int  i;
+   Bool spaced = False;
+   for (i = 0; i < N_PROF_EVENTS; i++) {
+      if (!spaced && (i % 10) == 0) {
+         VG_(printf)("\n");
+         spaced = True;
+      }
+      if (MAC_(event_ctr)[i] > 0) {
+         spaced = False;
+         VG_(printf)( "prof mem event %3d: %9d   %s\n", 
+                      i, MAC_(event_ctr)[i],
+                      MAC_(event_ctr_name)[i] 
+                         ? MAC_(event_ctr_name)[i] : "unnamed");
+      }
+   }
+}
+
+#else
+
+static void init_prof_mem ( void ) { }
+static void done_prof_mem ( void ) { }
+
+#endif
+
+/*------------------------------------------------------------*/
+/*--- Common initialisation + finalisation                 ---*/
+/*------------------------------------------------------------*/
+
+void MAC_(common_pre_clo_init)(void)
+{
+   MAC_(malloc_list) = VG_(HT_construct)();
+   MAC_(mempool_list) = VG_(HT_construct)();
+   init_prof_mem();
+}
+
+void MAC_(common_fini)(void (*leak_check)(ThreadId tid, LeakCheckMode mode))
+{
+   MAC_(print_malloc_stats)();
+
+   if (VG_(clo_verbosity) == 1) {
+      if (MAC_(clo_leak_check) == LC_Off)
+         VG_(message)(Vg_UserMsg, 
+             "For a detailed leak analysis,  rerun with: --leak-check=yes");
+
+      VG_(message)(Vg_UserMsg, 
+                   "For counts of detected errors, rerun with: -v");
+   }
+   if (MAC_(clo_leak_check) != LC_Off)
+      leak_check(1/*bogus ThreadId*/, MAC_(clo_leak_check));
+
+   done_prof_mem();
+}
+
+/*------------------------------------------------------------*/
+/*--- Common client request handling                       ---*/
+/*------------------------------------------------------------*/
+
+Bool MAC_(handle_common_client_requests)(ThreadId tid, UWord* arg, UWord* ret )
+{
+   Char* err  = 
+         "The client requests VALGRIND_MALLOCLIKE_BLOCK and\n"
+      "   VALGRIND_FREELIKE_BLOCK have moved.  Please recompile your\n"
+      "   program to incorporate the updates in the Valgrind header files.\n"
+      "   You shouldn't need to change the text of your program at all.\n"
+      "   Everything should then work as before.  Sorry for the bother.\n";
+   
+   switch (arg[0]) {
+   case VG_USERREQ__COUNT_LEAKS: { /* count leaked bytes */
+      UWord** argp = (UWord**)arg;
+      // MAC_(bytes_leaked) et al were set by the last leak check (or zero
+      // if no prior leak checks performed).
+      *argp[1] = MAC_(bytes_leaked) + MAC_(bytes_indirect);
+      *argp[2] = MAC_(bytes_dubious);
+      *argp[3] = MAC_(bytes_reachable);
+      *argp[4] = MAC_(bytes_suppressed);
+      // there is no argp[5]
+      //*argp[5] = MAC_(bytes_indirect);
+      // XXX need to make *argp[1-4] readable
+      *ret = 0;
+      return True;
+   }
+   case VG_USERREQ__MALLOCLIKE_BLOCK__OLD_DO_NOT_USE:
+   case VG_USERREQ__FREELIKE_BLOCK__OLD_DO_NOT_USE:
+      VG_(tool_panic)(err);
+
+   case VG_USERREQ__MALLOCLIKE_BLOCK: {
+      Addr p         = (Addr)arg[1];
+      SizeT sizeB    =       arg[2];
+      UInt rzB       =       arg[3];
+      Bool is_zeroed = (Bool)arg[4];
+
+      MAC_(new_block) ( tid, p, sizeB, /*ignored*/0, rzB, is_zeroed, 
+                        MAC_AllocCustom, MAC_(malloc_list) );
+      return True;
+   }
+   case VG_USERREQ__FREELIKE_BLOCK: {
+      Addr p         = (Addr)arg[1];
+      UInt rzB       =       arg[2];
+
+      MAC_(handle_free) ( tid, p, rzB, MAC_AllocCustom );
+      return True;
+   }
+
+   case _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR: {
+      Char*         s     = (Char*)        arg[1];
+      OverlapExtra* extra = (OverlapExtra*)arg[2];
+      MAC_(record_overlap_error)(tid, s, extra);
+      return True;
+   }
+
+   case VG_USERREQ__CREATE_MEMPOOL: {
+      Addr pool      = (Addr)arg[1];
+      UInt rzB       =       arg[2];
+      Bool is_zeroed = (Bool)arg[3];
+
+      MAC_(create_mempool) ( pool, rzB, is_zeroed );
+      return True;
+   }
+
+   case VG_USERREQ__DESTROY_MEMPOOL: {
+      Addr pool      = (Addr)arg[1];
+
+      MAC_(destroy_mempool) ( pool );
+      return True;
+   }
+
+   case VG_USERREQ__MEMPOOL_ALLOC: {
+      Addr pool      = (Addr)arg[1];
+      Addr addr      = (Addr)arg[2];
+      UInt size      =       arg[3];
+
+      MAC_(mempool_alloc) ( tid, pool, addr, size );
+      return True;
+   }
+
+   case VG_USERREQ__MEMPOOL_FREE: {
+      Addr pool      = (Addr)arg[1];
+      Addr addr      = (Addr)arg[2];
+
+      MAC_(mempool_free) ( pool, addr );
+      return True;
+   }
+
+   default:
+      return False;
+   }
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/