]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
This commit moves some skin-specific stuff out of core, and generally
authorNicholas Nethercote <njn@valgrind.org>
Tue, 8 Apr 2003 00:08:52 +0000 (00:08 +0000)
committerNicholas Nethercote <njn@valgrind.org>
Tue, 8 Apr 2003 00:08:52 +0000 (00:08 +0000)
neatens other things up.

Also, it adds the --gen-suppressions option for automatically generating
suppressions for each error.

Note that it changes the core/skin interface:
SK_(dup_extra_and_update)() is replaced by SK_(update_extra)(), and
SK_(get_error_name)() and SK_(print_extra_suppression_info)() are added.

-----------------------------------------------------------------------------
details
-----------------------------------------------------------------------------
Removed ac_common.c -- it just #included another .c file;  moved the
#include into ac_main.c.

Introduced "mac_" prefixes for files shared between Addrcheck and Memcheck,
to make it clearer which code is shared.  Also using a "MAC_" prefix for
functions and variables and types that are shared.  Addrcheck doesn't see
the "MC_" prefix at all.

Factored out almost-identical mc_describe_addr() and describe_addr()
(AddrCheck's version) into MAC_(describe_addr)().

Got rid of the "pp_ExeContext" closure passed to SK_(pp_SkinError)(), it
wasn't really necessary.

Introduced MAC_(pp_shared_SkinError)() for the error printing code shared by
Addrcheck and Memcheck.  Fixed some bogus stuff in Addrcheck error messages
about "uninitialised bytes" (there because of an imperfect conversion from
Memcheck).

Moved the leak checker out of core (vg_memory.c), into mac_leakcheck.c.
 - This meant the hacky way of recording Leak errors, which was different to
   normal errors, could be changed to something better:  introduced a
   function VG_(unique_error)(), which unlike VG_(maybe_record_error)() just
   prints the error (unless suppressed) but doesn't record it.  Used for
   leaks;  a much better solution all round as it allowed me to remove a lot
   of almost-identical code from leak handling (is_suppressible_leak(),
   leaksupp_matches_callers()).

 - As part of this, changed the horrible SK_(dup_extra_and_update) into the
   slightly less horrible SK_(update_extra), which returns the size of the
   `extra' part for the core to duplicate.

 - Also renamed it from VG_(generic_detect_memory_leaks)() to
   MAC_(do_detect_memory_leaks).  In making the code nicer w.r.t suppressions
   and error reporting, I tied it a bit more closely to Memcheck/Addrcheck,
   and got rid of some of the args.  It's not really "generic" any more, but
   then it never really was.  (This could be undone, but there doesn't seem
   to be much point.)

STREQ and STREQN were #defined in several places, and in two different ways.
Made global macros VG_STREQ, VG_CLO_STREQ and VG_CLO_STREQN in vg_skin.h.

Added the --gen-suppressions code.  This required adding the functions
SK_(get_error_name)() and SK_(print_extra_suppression_info)() for skins that
use the error handling need.

Added documentation for --gen-suppressions, and fixed some other minor document
problems.

Various other minor related changes too.

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

22 files changed:
Makefile.am
addrcheck/Makefile.am
addrcheck/ac_main.c
coregrind/docs/coregrind_core.html
coregrind/vg_clientmalloc.c
coregrind/vg_default.c
coregrind/vg_errcontext.c
coregrind/vg_include.h
coregrind/vg_main.c
coregrind/vg_memory.c
coregrind/vg_scheduler.c
coregrind/vg_symtab2.c
helgrind/hg_main.c
include/vg_skin.h
memcheck/Makefile.am
memcheck/docs/mc_main.html
memcheck/mac_leakcheck.c [new file with mode: 0644]
memcheck/mac_needs.c [moved from memcheck/mc_common.c with 62% similarity]
memcheck/mac_shared.h [moved from memcheck/mc_common.h with 78% similarity]
memcheck/mc_errcontext.c
memcheck/mc_include.h
memcheck/mc_main.c

index 59981ddf0e158bb1f15a8fbfbe92c49fcac16ef5..15e552ef599de0746fffd13759a9c65f55cb5350 100644 (file)
@@ -1,5 +1,5 @@
 
-AUTOMAKE_OPTIONS = 1.5
+AUTOMAKE_OPTIONS = 1.4
 
 SUBDIRS =      coregrind . docs tests include auxprogs \
                addrcheck \
index af1d54fa366b16d79c7063c89ee9aa432bc74615..1fd6b3853d199f708374c37d4144992665d2f3e3 100644 (file)
@@ -14,6 +14,3 @@ val_PROGRAMS = vgskin_addrcheck.so
 vgskin_addrcheck_so_SOURCES = ac_main.c
 vgskin_addrcheck_so_LDFLAGS = -shared
 
-##vgskin_addrcheck.so$(EXEEXT): $(vgskin_addrcheck_so_OBJECTS)
-##     $(CC) $(CFLAGS) $(LDFLAGS) -shared -o vgskin_addrcheck.so \
-##             $(vgskin_addrcheck_so_OBJECTS)
index 5b3cc6bd61bf4b04cb620d67440cf4cc8b8b7cbe..fc13efc733bf2b55d7f74e45341c96f79f02dc6b 100644 (file)
    The GNU General Public License is contained in the file COPYING.
 */
 
-#include "mc_common.h"
+#include "mac_shared.h"
 #include "memcheck.h"
 //#include "vg_profile.c"
 
-#include "mc_common.c"
+#include "mac_leakcheck.c"
+#include "mac_needs.c"
 
 
 
@@ -44,22 +45,15 @@ VG_DETERMINE_INTERFACE_VERSION
 /*--- Comparing and printing errors                        ---*/
 /*------------------------------------------------------------*/
 
-void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
+void SK_(pp_SkinError) ( Error* err )
 {
-   MemCheckError* err_extra = VG_(get_error_extra)(err);
+   MAC_Error* err_extra = VG_(get_error_extra)(err);
 
    switch (VG_(get_error_kind)(err)) {
       case CoreMemErr:
-         if (err_extra->isWrite) {
-            VG_(message)(Vg_UserMsg, 
-               "%s contains unaddressable byte(s)", 
-               VG_(get_error_string)(err));
-         } else {
-            VG_(message)(Vg_UserMsg, 
-               "%s contains unaddressable byte(s)", 
-               VG_(get_error_string)(err));
-         }
-         pp_ExeContext();
+         VG_(message)(Vg_UserMsg, "%s contains unaddressable byte(s)", 
+         VG_(get_error_string)(err));
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
          break;
       
       case AddrErr:
@@ -77,161 +71,40 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
             default: 
                VG_(skin_panic)("SK_(pp_SkinError)(axskind)");
          }
-         pp_ExeContext();
-         MC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
-         break;
-
-      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 []");
-         pp_ExeContext();
-         MC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+         MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
          break;
 
       case ParamErr:
-         if (err_extra->isWrite) {
-            VG_(message)(Vg_UserMsg, 
-                         "Syscall param %s contains unaddressable byte(s)",
-                         VG_(get_error_string)(err) );
-         } else {
-            VG_(message)(Vg_UserMsg, 
-                "Syscall param %s contains uninitialised or "
-                "unaddressable byte(s)",
-                VG_(get_error_string)(err));
-         }
-         pp_ExeContext();
-         MC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         VG_(message)(Vg_UserMsg, 
+                      "Syscall param %s contains unaddressable byte(s)",
+                      VG_(get_error_string)(err) );
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+         MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
          break;
 
       case UserErr:
-         if (err_extra->isWrite) {
-            VG_(message)(Vg_UserMsg, 
-               "Unaddressable byte(s) found during client check request");
-         } else {
-            VG_(message)(Vg_UserMsg, 
-               "Uninitialised or "
-               "unaddressable byte(s) found during client check request");
-         }
-         pp_ExeContext();
-         MC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         VG_(message)(Vg_UserMsg, 
+            "Unaddressable byte(s) found during client check request");
+         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 AddrCheck error code %d\n",
-                     VG_(get_error_kind)(err));
-         VG_(skin_panic)("unknown error code in SK_(pp_SkinError)");
-   }
-}
-
-/*------------------------------------------------------------*/
-/*--- Recording errors                                     ---*/
-/*------------------------------------------------------------*/
-
-/* Describe an address as best you can, for error messages,
-   putting the result in ai. */
-
-static void describe_addr ( Addr a, AddrInfo* ai )
-{
-   ShadowChunk* sc;
-   ThreadId     tid;
-
-   /* Nested functions, yeah.  Need the lexical scoping of 'a'. */ 
-
-   /* Closure for searching thread stacks */
-   Bool addr_is_in_bounds(Addr stack_min, Addr stack_max)
-   {
-      return (stack_min <= a && a <= stack_max);
-   }
-   /* Closure for searching malloc'd and free'd lists */
-   Bool addr_is_in_block(ShadowChunk *sh_ch)
-   {
-      return VG_(addr_is_in_block) ( a, VG_(get_sc_data)(sh_ch),
-                                        VG_(get_sc_size)(sh_ch) );
-   }
-   /* Perhaps it's on a thread's stack? */
-   tid = VG_(any_matching_thread_stack)(addr_is_in_bounds);
-   if (tid != VG_INVALID_THREADID) {
-      ai->akind     = Stack;
-      ai->stack_tid = tid;
-      return;
-   }
-   /* Search for a recently freed block which might bracket it. */
-   sc = MC_(any_matching_freed_ShadowChunks)(addr_is_in_block);
-   if (NULL != sc) {
-      ai->akind      = Freed;
-      ai->blksize    = VG_(get_sc_size)(sc);
-      ai->rwoffset   = (Int)(a) - (Int)(VG_(get_sc_data)(sc));
-      ai->lastchange = (ExeContext*)( VG_(get_sc_extra)(sc, 0) );
-      return;
+         MAC_(pp_shared_SkinError)(err);
+         break;
    }
-   /* Search for a currently malloc'd block which might bracket it. */
-   sc = VG_(any_matching_mallocd_ShadowChunks)(addr_is_in_block);
-   if (NULL != sc) {
-      ai->akind      = Mallocd;
-      ai->blksize    = VG_(get_sc_size)(sc);
-      ai->rwoffset   = (Int)(a) - (Int)(VG_(get_sc_data)(sc));
-      ai->lastchange = (ExeContext*)( VG_(get_sc_extra)(sc, 0) );
-      return;
-   } 
-   /* Clueless ... */
-   ai->akind = Unknown;
-   return;
-}
-
-
-/* Creates a copy of the `extra' part, updates the copy with address info if
-   necessary, and returns the copy. */
-void* SK_(dup_extra_and_update)(Error* err)
-{
-   MemCheckError* extra;
-   MemCheckError* new_extra = NULL;
-
-   extra = ((MemCheckError*)VG_(get_error_extra)(err));
-   if (extra != NULL) {
-      new_extra  = VG_(malloc)(sizeof(MemCheckError));
-      *new_extra = *extra;
-      if (new_extra->addrinfo.akind == Undescribed)
-         describe_addr ( VG_(get_error_address)(err), &(new_extra->addrinfo) );
-   }
-
-
-
-   return new_extra;
 }
 
 /*------------------------------------------------------------*/
 /*--- Suppressions                                         ---*/
 /*------------------------------------------------------------*/
 
-#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
-                      && VG_(strcmp)((s1),(s2))==0)
-
 Bool SK_(recognised_suppression) ( Char* name, Supp* su )
 {
-   SuppKind skind;
-   
-   if      (STREQ(name, "Param"))   skind = ParamSupp;
-   else if (STREQ(name, "CoreMem")) skind = CoreMemSupp;
-   else if (STREQ(name, "Addr1"))   skind = Addr1Supp;
-   else if (STREQ(name, "Addr2"))   skind = Addr2Supp;
-   else if (STREQ(name, "Addr4"))   skind = Addr4Supp;
-   else if (STREQ(name, "Addr8"))   skind = Addr8Supp;
-   else if (STREQ(name, "Free"))    skind = FreeSupp;
-   else if (STREQ(name, "Leak"))    skind = LeakSupp;
-   else 
-      return False;
-
-   VG_(set_supp_kind)(su, skind);
-   return True;
+   return MAC_(shared_recognised_suppression)(name, su);
 }
 
-#  undef STREQ
-
-
 #define DEBUG(fmt, args...) //VG_(printf)(fmt, ## args)
 
 /*------------------------------------------------------------*/
@@ -685,21 +558,21 @@ void ac_check_is_accessible ( CorePart part, ThreadState* tst,
    if (!ok) {
       switch (part) {
       case Vg_CoreSysCall:
-         MC_(record_param_error) ( tst, bad_addr, isWrite, s );
+         MAC_(record_param_error) ( tst, bad_addr, isWrite, s );
          break;
 
       case Vg_CoreSignal:
          sk_assert(isWrite);     /* Should only happen with isWrite case */
          /* fall through */
       case Vg_CorePThread:
-         MC_(record_core_mem_error)( tst, isWrite, s );
+         MAC_(record_core_mem_error)( tst, isWrite, s );
          break;
 
       /* If we're being asked to jump to a silly address, record an error 
          message before potentially crashing the entire system. */
       case Vg_CoreTranslate:
          sk_assert(!isWrite);    /* Should only happen with !isWrite case */
-         MC_(record_jump_error)( tst, bad_addr );
+         MAC_(record_jump_error)( tst, bad_addr );
          break;
 
       default:
@@ -737,7 +610,7 @@ void ac_check_is_readable_asciiz ( CorePart part, ThreadState* tst,
    sk_assert(part == Vg_CoreSysCall);
    ok = ac_check_readable_asciiz ( (Addr)str, &bad_addr );
    if (!ok) {
-      MC_(record_param_error) ( tst, bad_addr, /*is_writable =*/False, s );
+      MAC_(record_param_error) ( tst, bad_addr, /*is_writable =*/False, s );
    }
 
    VGP_POPCC(VgpCheckMem);
@@ -890,20 +763,20 @@ static void ac_ACCESS4_SLOWLY ( Addr a )
       - emit addressing error
    */
    /* VG_(printf)("%p (%d %d %d %d)\n", a, a0ok, a1ok, a2ok, a3ok); */
-   if (!MC_(clo_partial_loads_ok) 
+   if (!MAC_(clo_partial_loads_ok) 
        || ((a & 3) != 0)
        || (!a0ok && !a1ok && !a2ok && !a3ok)) {
-      MC_(record_address_error)( a, 4, False );
+      MAC_(record_address_error)( a, 4, False );
       return;
    }
 
    /* Case 3: the address is partially valid.  
       - no addressing error
-      Case 3 is only allowed if MC_(clo_partial_loads_ok) is True
+      Case 3 is only allowed if MAC_(clo_partial_loads_ok) is True
       (which is the default), and the address is 4-aligned.  
       If not, Case 2 will have applied.
    */
-   sk_assert(MC_(clo_partial_loads_ok));
+   sk_assert(MAC_(clo_partial_loads_ok));
    {
       return;
    }
@@ -920,7 +793,7 @@ static void ac_ACCESS2_SLOWLY ( Addr a )
 
    /* If an address error has happened, report it. */
    if (aerr) {
-      MC_(record_address_error)( a, 2, False );
+      MAC_(record_address_error)( a, 2, False );
    }
 }
 
@@ -934,7 +807,7 @@ static void ac_ACCESS1_SLOWLY ( Addr a )
 
    /* If an address error has happened, report it. */
    if (aerr) {
-      MC_(record_address_error)( a, 1, False );
+      MAC_(record_address_error)( a, 1, False );
    }
 }
 
@@ -1039,7 +912,7 @@ void ac_fpu_ACCESS_check_SLOWLY ( Addr addr, Int size )
    }
 
    if (aerr) {
-      MC_(record_address_error)( addr, size, False );
+      MAC_(record_address_error)( addr, size, False );
    }
 }
 
@@ -1168,14 +1041,7 @@ Bool ac_is_valid_address ( Addr a )
    skin. */
 static void ac_detect_memory_leaks ( void )
 {
-   VG_(generic_detect_memory_leaks) ( 
-      ac_is_valid_64k_chunk,
-      ac_is_valid_address,
-      MC_(get_where),
-      MC_(clo_leak_resolution),
-      MC_(clo_show_reachable),
-      (UInt)LeakSupp
-   );
+   MAC_(do_detect_memory_leaks) ( ac_is_valid_64k_chunk, ac_is_valid_address );
 }
 
 
@@ -1285,7 +1151,7 @@ Bool SK_(handle_client_request) ( ThreadState* tst, UInt* arg_block, UInt *ret )
 
 Bool SK_(process_cmd_line_option)(Char* arg)
 {
-   return MC_(process_common_cmd_line_option)(arg);
+   return MAC_(process_common_cmd_line_option)(arg);
 }
 
 Char* SK_(usage)(void)
@@ -1333,12 +1199,12 @@ void SK_(pre_clo_init)(void)
    VG_(track_new_mem_brk)          ( & ac_make_accessible );
    VG_(track_new_mem_mmap)         ( & ac_set_perms );
    
-   VG_(track_new_mem_stack_4)      ( & MC_(new_mem_stack_4)  );
-   VG_(track_new_mem_stack_8)      ( & MC_(new_mem_stack_8)  );
-   VG_(track_new_mem_stack_12)     ( & MC_(new_mem_stack_12) );
-   VG_(track_new_mem_stack_16)     ( & MC_(new_mem_stack_16) );
-   VG_(track_new_mem_stack_32)     ( & MC_(new_mem_stack_32) );
-   VG_(track_new_mem_stack)        ( & MC_(new_mem_stack)    );
+   VG_(track_new_mem_stack_4)      ( & MAC_(new_mem_stack_4)  );
+   VG_(track_new_mem_stack_8)      ( & MAC_(new_mem_stack_8)  );
+   VG_(track_new_mem_stack_12)     ( & MAC_(new_mem_stack_12) );
+   VG_(track_new_mem_stack_16)     ( & MAC_(new_mem_stack_16) );
+   VG_(track_new_mem_stack_32)     ( & MAC_(new_mem_stack_32) );
+   VG_(track_new_mem_stack)        ( & MAC_(new_mem_stack)    );
 
    VG_(track_copy_mem_heap)        ( & ac_copy_address_range_state );
    VG_(track_copy_mem_remap)       ( & ac_copy_address_range_state );
@@ -1352,15 +1218,15 @@ void SK_(pre_clo_init)(void)
    VG_(track_die_mem_brk)          ( & ac_make_noaccess );
    VG_(track_die_mem_munmap)       ( & ac_make_noaccess ); 
 
-   VG_(track_die_mem_stack_4)      ( & MC_(die_mem_stack_4)  );
-   VG_(track_die_mem_stack_8)      ( & MC_(die_mem_stack_8)  );
-   VG_(track_die_mem_stack_12)     ( & MC_(die_mem_stack_12) );
-   VG_(track_die_mem_stack_16)     ( & MC_(die_mem_stack_16) );
-   VG_(track_die_mem_stack_32)     ( & MC_(die_mem_stack_32) );
-   VG_(track_die_mem_stack)        ( & MC_(die_mem_stack)    );
+   VG_(track_die_mem_stack_4)      ( & MAC_(die_mem_stack_4)  );
+   VG_(track_die_mem_stack_8)      ( & MAC_(die_mem_stack_8)  );
+   VG_(track_die_mem_stack_12)     ( & MAC_(die_mem_stack_12) );
+   VG_(track_die_mem_stack_16)     ( & MAC_(die_mem_stack_16) );
+   VG_(track_die_mem_stack_32)     ( & MAC_(die_mem_stack_32) );
+   VG_(track_die_mem_stack)        ( & MAC_(die_mem_stack)    );
    
-   VG_(track_bad_free)             ( & MC_(record_free_error) );
-   VG_(track_mismatched_free)      ( & MC_(record_freemismatch_error) );
+   VG_(track_bad_free)             ( & MAC_(record_free_error) );
+   VG_(track_mismatched_free)      ( & MAC_(record_freemismatch_error) );
 
    VG_(track_pre_mem_read)         ( & ac_check_is_readable );
    VG_(track_pre_mem_read_asciiz)  ( & ac_check_is_readable_asciiz );
@@ -1377,7 +1243,7 @@ void SK_(pre_clo_init)(void)
    VGP_(register_profile_event) ( VgpESPAdj,   "adjust-ESP" );
 
    init_shadow_memory();
-   MC_(init_prof_mem)();
+   MAC_(init_prof_mem)();
 }
 
 void SK_(post_clo_init) ( void )
@@ -1389,16 +1255,16 @@ void SK_(fini) ( void )
    VG_(print_malloc_stats)();
 
    if (VG_(clo_verbosity) == 1) {
-      if (!MC_(clo_leak_check))
+      if (!MAC_(clo_leak_check))
          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 (MC_(clo_leak_check)) ac_detect_memory_leaks();
+   if (MAC_(clo_leak_check)) ac_detect_memory_leaks();
 
-   MC_(done_prof_mem)();
+   MAC_(done_prof_mem)();
 }
 
 /*--------------------------------------------------------------------*/
index 16b7c1bf8bc84eaf44130447d43977b61e7865a0..14a235e4719588acbbe2842379708a16714bf0be 100644 (file)
@@ -72,7 +72,10 @@ interested, Valgrind allows you to selectively suppress errors, by
 recording them in a suppressions file which is read when Valgrind
 starts up.  The build mechanism attempts to select suppressions which
 give reasonable behaviour for the libc and XFree86 versions detected
-on your machine.
+on your machine.  To make it easier to write suppressions, you can use
+the <code>--gen-suppressions=yes</code> option which tells Valgrind to
+print out a suppression for each error that appears, which you can
+then copy into a suppressions file.
 
 <p>
 Different skins report different kinds of errors.  The suppression
@@ -189,7 +192,7 @@ does about where that stream is sent to.  You have three options:
     for technical reasons, valgrind's core itself can't use the GNU C
     library, and this makes it difficult to do hostname-to-IP lookups.
     <p>
-    Writing to a network socket it pretty useless if you don't have
+    Writing to a network socket is pretty useless if you don't have
     something listening at the other end.  We provide a simple
     listener program, <code>valgrind-listener</code>, which accepts 
     connections on the specified port and copies whatever it is sent
@@ -453,6 +456,34 @@ follows:
       socket, I guess this option doesn't make any sense.  Caveat emptor.
       </li><br><p>
 
+  <li><code>--gen-suppressions=no</code> [the default]<br>
+      <code>--gen-suppressions=yes</code>
+      <p>When enabled, Valgrind will pause after every error shown,
+      and print the line
+      <br>
+      <code>---- Print suppression ? --- [Return/N/n/Y/y/C/c] ----</code>
+      <p>
+      The prompt's behaviour is the same as for the <code>--gdb-attach</code>
+      option.
+      <p>
+      If you choose to, Valgrind will print out a suppression for this error.
+      You can then cut and paste it into a suppression file if you don't want
+      to hear about the error in the future.
+      <p>
+      This option is particularly useful with C++ programs, as it prints out
+      the suppressions with mangled names, as required.
+      <p>
+      Note that the suppressions printed are as specific as possible.  You
+      may want to common up similar ones, eg. by adding wildcards to function
+      names.  Also, sometimes two different errors are suppressed by the same
+      suppression, in which case Valgrind will output the suppression more than
+      once, but you only need to have one copy in your suppression file (but
+      having more than one won't cause problems).  Also, the suppression
+      name is given as <code>&lt;insert a suppression name here&gt;</code>;
+      the name doesn't really matter, it's only used with the
+      <code>-v</code> option which prints out all used suppression records.
+      </li><br><p>
+
   <li><code>--alignment=&lt;number></code> [default: 4]<br> <p>By
       default valgrind's <code>malloc</code>, <code>realloc</code>,
       etc, return 4-byte aligned addresses.  These are suitable for
@@ -620,6 +651,12 @@ follows:
           unexpectedly in the <code>write()</code> system call, you
           may find the <code>--trace-syscalls=yes
           --trace-sched=yes</code> flags useful.
+      <p>
+      <li><code>lax-ioctls</code> Be very lax about ioctl handling; the only
+          assumption is that the size is correct. Doesn't require the full
+          buffer to be initialized when writing.  Without this, using some
+          device drivers with a large number of strange ioctl commands becomes
+          very tiresome.
       </ul>
       </li><br><p>
 </ul>
@@ -685,6 +722,13 @@ shouldn't need to use them in the normal run of things.  Nevertheless:
       </li><br>
       <p>
 
+  <li><code>--trace-codegen=XXXXX</code> [default: 00000]
+      <p>Enable/disable tracing of code generation.  Code can be printed
+      at five different stages of translation;  each <code>X</code> element
+      must be 0 or 1.
+      </li><br>
+      <p>
+
   <li><code>--stop-after=&lt;number></code> 
       [default: infinity, more or less]
       <p>After &lt;number> basic blocks have been executed, shut down
@@ -709,6 +753,11 @@ shouldn't need to use them in the normal run of things.  Nevertheless:
 (NOTE 20021117: this subsection is illogical here now; it jumbles up
 core and skin issues.  To be fixed.).
 
+(NOTE 20030318: the most important correction is that
+<code>valgrind.h</code> should not be included in your program, but
+instead <code>memcheck.h</code> (for the Memcheck and Addrcheck skins)
+or <code>helgrind.h</code> (for Helgrind).)
+
 <p>
 Valgrind has a trapdoor mechanism via which the client program can
 pass all manner of requests and queries to Valgrind.  Internally, this
@@ -937,7 +986,7 @@ build problems.
 <h3>2.11&nbsp; If you have problems</h3>
 Mail me (<a href="mailto:jseward@acm.org">jseward@acm.org</a>).
 
-<p>See <a href="#limits">Section 4</a> for the known limitations of
+<p>See <a href="#limits">this section</a> for the known limitations of
 Valgrind, and for a list of programs which are known not to work on
 it.
 
index 653dc06edb94a23b2e3090534b2282309490dc96..025de27ac47506ce1e6bdeb460462d397c0a965d 100644 (file)
@@ -153,6 +153,38 @@ void VG_(free_ShadowChunk) ( ShadowChunk* sc )
    VG_(arena_free) ( VG_AR_CORE,   sc );
 }
 
+static 
+void sort_malloc_shadows ( ShadowChunk** shadows, UInt n_shadows )
+{
+   Int   incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+                      9841, 29524, 88573, 265720,
+                      797161, 2391484 };
+   Int          lo = 0;
+   Int          hi = n_shadows-1;
+   Int          i, j, h, bigN, hp;
+   ShadowChunk* v;
+   
+   bigN = hi - lo + 1; if (bigN < 2) return;
+   hp = 0; while (hp < 14 && incs[hp] < bigN) hp++; hp--;
+   vg_assert(0 <= hp && hp < 14);
+   
+   for (; hp >= 0; hp--) {
+      h = incs[hp];
+      i = lo + h;
+      while (1) {
+         if (i > hi) break;
+         v = shadows[i];
+         j = i;
+         while (shadows[j-h]->data > v->data) {
+            shadows[j] = shadows[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         shadows[j] = v;
+         i++;
+      }
+   }
+}
 
 /* Allocate a suitably-sized array, copy all the malloc-d block
    shadows into it, and return both the array and the size of it.
@@ -180,6 +212,16 @@ ShadowChunk** VG_(get_malloc_shadows) ( /*OUT*/ UInt* n_shadows )
       }
    }
    vg_assert(i == *n_shadows);
+
+   sort_malloc_shadows(arr, *n_shadows);
+
+   /* Sanity check; assert that the blocks are now in order and that
+      they don't overlap. */
+   for (i = 0; i < *n_shadows-1; i++) {
+      sk_assert( arr[i]->data                < arr[i+1]->data );
+      sk_assert( arr[i]->data + arr[i]->size < arr[i+1]->data );
+   }
+
    return arr;
 }
 
@@ -190,7 +232,7 @@ Bool VG_(addr_is_in_block)( Addr a, Addr start, UInt size )
 }
 
 /* Return the first shadow chunk satisfying the predicate p. */
-ShadowChunk* VG_(any_matching_mallocd_ShadowChunks)
+ShadowChunk* VG_(first_matching_mallocd_ShadowChunk)
                         ( Bool (*p) ( ShadowChunk* ))
 {
    UInt ml_no;
index 8778b846857746e1f1f7c4876d080564b159bb67..1bd36ff87b0528e613b3c7e867c33771389c37c6 100644 (file)
@@ -105,15 +105,15 @@ Bool SK_(eq_SkinError)(VgRes res, Error* e1, Error* e2)
 }
 
 __attribute__ ((weak))
-void SK_(pp_SkinError)(Error* err, void (*pp_ExeContext)(void))
+void SK_(pp_SkinError)(Error* err)
 {
    non_fund_panic("SK_(pp_SkinError)");
 }
 
 __attribute__ ((weak))
-void* SK_(dup_extra_and_update)(Error* err)
+UInt SK_(update_extra)(Error* err)
 {
-   non_fund_panic("SK_(dup_extra_and_update)");
+   non_fund_panic("SK_(update_extra)");
 }
 
 __attribute__ ((weak))
@@ -134,6 +134,18 @@ Bool SK_(error_matches_suppression)(Error* err, Supp* su)
    non_fund_panic("SK_(error_matches_suppression)");
 }
 
+__attribute__ ((weak))
+Char* SK_(get_error_name)(Error* err)
+{
+   non_fund_panic("SK_(get_error_name)");
+}
+
+__attribute__ ((weak))
+void SK_(print_extra_suppression_info)(Error* err)
+{
+   non_fund_panic("SK_(print_extra_suppression_info)");
+}
+
 
 /* ---------------------------------------------------------------------
    For throwing out basic block level info when code is invalidated
index 6ba7343a9115c77bdcecd2cd16b29497b20014e4..3040fb2f3a3a8610d2d109e214a9aebba1fe4ff6 100644 (file)
@@ -91,13 +91,6 @@ static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
 
 static void pp_Error ( Error* err, Bool printCount )
 {
-   /* Closure for printing where the error occurred.  Abstracts details
-      about the `where' field away from the skin. */
-   void pp_ExeContextClosure(void)
-   {
-      VG_(pp_ExeContext) ( err->where );
-   }
-   
    if (printCount)
       VG_(message)(Vg_UserMsg, "Observed %d times:", err->count );
    if (err->tid > 1)
@@ -111,7 +104,7 @@ static void pp_Error ( Error* err, Bool printCount )
          break;
       default: 
          if (VG_(needs).skin_errors)
-            SK_(pp_SkinError)( err, &pp_ExeContextClosure );
+            SK_(pp_SkinError)( err );
          else {
             VG_(printf)("\nUnhandled error type: %u.  VG_(needs).skin_errors\n"
                         "probably needs to be set?\n",
@@ -123,13 +116,12 @@ static void pp_Error ( Error* err, Bool printCount )
 
 /* Figure out if we want to attach for GDB for this error, possibly
    by asking the user. */
-static
-Bool vg_is_GDB_attach_requested ( void )
+Bool VG_(is_action_requested) ( Char* action, Bool* clo )
 {
    Char ch, ch2;
    Int res;
 
-   if (VG_(clo_GDB_attach) == False)
+   if (*clo == False)
       return False;
 
    VG_(message)(Vg_UserMsg, "");
@@ -137,8 +129,8 @@ Bool vg_is_GDB_attach_requested ( void )
   again:
    VG_(printf)(
       "==%d== "
-      "---- Attach to GDB ? --- [Return/N/n/Y/y/C/c] ---- ", 
-      VG_(getpid)()
+      "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ", 
+      VG_(getpid)(), action
    );
 
    res = VG_(read)(0 /*stdin*/, &ch, 1);
@@ -152,15 +144,15 @@ Bool vg_is_GDB_attach_requested ( void )
    if (res != 1) goto ioerror;
    if (ch2 != '\n') goto again;
 
-   /* No, don't want to attach. */
+   /* No, don't want to do action. */
    if (ch == 'n' || ch == 'N') return False;
-   /* Yes, want to attach. */
+   /* Yes, want to do action. */
    if (ch == 'y' || ch == 'Y') return True;
-   /* No, don't want to attach, and don't ask again either. */
+   /* No, don't want to do action, and don't ask again either. */
    vg_assert(ch == 'c' || ch == 'C');
 
   ioerror:
-   VG_(clo_GDB_attach) = False;
+   *clo = False;
    return False;
 }
 
@@ -178,14 +170,17 @@ Bool vg_is_GDB_attach_requested ( void )
      stored thread state, not from VG_(baseBlock).  
 */
 static __inline__
-void construct_error ( Error* err, ThreadState* tst, 
-                       ErrorKind ekind, Addr a, Char* s, void* extra )
+void construct_error ( Error* err, ThreadState* tst, ErrorKind ekind, Addr a,
+                       Char* s, void* extra, ExeContext* where )
 {
    /* Core-only parts */
    err->next     = NULL;
    err->supp     = NULL;
    err->count    = 1;
-   err->where    = VG_(get_ExeContext)( tst );
+   if (NULL == where)
+      err->where = VG_(get_ExeContext)( tst );
+   else
+      err->where = where;
 
    if (NULL == tst) {
       err->tid   = VG_(get_current_tid)();
@@ -209,6 +204,66 @@ void construct_error ( Error* err, ThreadState* tst,
    vg_assert(err->tid >= 0 && err->tid < VG_N_THREADS);
 }
 
+void VG_(gen_suppression)(Error* err)
+{
+   UInt        i;
+   UChar       buf[M_VG_ERRTXT];
+   ExeContext* ec      = VG_(get_error_where)(err);
+   Int         stop_at = VG_(clo_backtrace_size);
+   Char*       name    = SK_(get_error_name)(err);
+
+   if (NULL == name) {
+      VG_(message)(Vg_UserMsg, "(skin does not allow error to be suppressed)");
+      return;
+   }
+
+   if (stop_at > 3) stop_at = 3;    /* At most three names */
+   vg_assert(stop_at > 0);
+
+   VG_(printf)("{\n");
+   VG_(printf)("   <insert a suppression name here>\n");
+   VG_(printf)("   %s:%s\n", VG_(details).name, name);
+   SK_(print_extra_suppression_info)(err);
+
+   /* This loop condensed from VG_(mini_stack_dump)() */
+   i = 0;
+   do {
+      Addr eip = ec->eips[i];
+      if (i > 0)
+         eip--;                 /* point to calling line */
+
+      if ( VG_(get_fnname_nodemangle) (eip, buf,  M_VG_ERRTXT) ) {
+         VG_(printf)("   fun:%s\n", buf);
+      } else if ( VG_(get_objname)(eip, buf, M_VG_ERRTXT) ) {
+         VG_(printf)("   obj:%s\n", buf);
+      } else {
+         VG_(printf)("   ???:???       "
+                     "# unknown, suppression will not work, sorry)\n");
+      }
+      i++;
+   } while (i < stop_at && ec->eips[i] != 0);
+
+   VG_(printf)("}\n");
+}
+
+void do_actions_on_error(Error* err)
+{
+   /* Perhaps we want a GDB attach at this point? */
+   if (VG_(is_action_requested)( "Attach to GDB", & VG_(clo_GDB_attach) )) {
+      VG_(swizzle_esp_then_start_GDB)(
+         err->m_eip, err->m_esp, err->m_ebp);
+   }
+   /* Or maybe we want to generate the error's suppression? */
+   if (VG_(is_action_requested)( "Print suppression",
+                                 & VG_(clo_gen_suppressions) )) {
+      VG_(gen_suppression)(err);
+   }
+}
+
+/* Shared between VG_(maybe_record_error)() and VG_(unique_error)(),
+   just for pretty printing purposes. */
+static Bool is_first_shown_context = True;
+
 /* Top-level entry point to the error management subsystem.
    All detected errors are notified here; this routine decides if/when the
    user should see the error. */
@@ -218,8 +273,8 @@ void VG_(maybe_record_error) ( ThreadState* tst,
           Error  err;
           Error* p;
           Error* p_prev;
+          UInt   extra_size;
           VgRes  exe_res                = Vg_MedRes;
-   static Bool   is_first_shown_context = True;
    static Bool   stopping_message       = False;
    static Bool   slowdown_message       = False;
    static Int    vg_n_errs_shown        = 0;
@@ -279,7 +334,7 @@ void VG_(maybe_record_error) ( ThreadState* tst,
    }
 
    /* Build ourselves the error */
-   construct_error ( &err, tst, ekind, a, s, extra );
+   construct_error ( &err, tst, ekind, a, s, extra, NULL );
 
    /* First, see if we've got an error record matching this one. */
    p      = vg_errors;
@@ -312,20 +367,34 @@ void VG_(maybe_record_error) ( ThreadState* tst,
 
    /* Didn't see it.  Copy and add. */
 
-   /* OK, we're really going to collect it.  First make a copy,
-      because the error context is on the stack and will disappear shortly.
-      We can duplicate the main part ourselves, but use
-      SK_(dup_extra_and_update) to duplicate the `extra' part.
+   /* OK, we're really going to collect it.  The context is on the stack and
+      will disappear shortly, so we must copy it.  First do the main
+      (non-`extra') part.
      
-      SK_(dup_extra_and_update) can also update the `extra' part.  This is
-      for when there are more details to fill in which take time to work out
-      but don't affect our earlier decision to include the error -- by
+      Then SK_(update_extra) can update the `extra' part.  This is for when
+      there are more details to fill in which take time to work out but
+      don't affect our earlier decision to include the error -- by
       postponing those details until now, we avoid the extra work in the
       case where we ignore the error.  Ugly.
-    */
+
+      Then, if there is an `extra' part, copy it too, using the size that
+      SK_(update_extra) returned.
+   */
+
+   /* copy main part */
    p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
    *p = err;
-   p->extra = SK_(dup_extra_and_update)(p);
+
+   /* update `extra' */
+   extra_size = SK_(update_extra)(p);
+
+   /* copy `extra' if there is one */
+   if (NULL != p->extra) {
+      void* new_extra = VG_(malloc)(extra_size);
+      VG_(memcpy)(new_extra, p->extra, extra_size);
+      p->extra = new_extra;
+   }
+
    p->next = vg_errors;
    p->supp = is_suppressible_error(&err);
    vg_errors = p;
@@ -333,20 +402,56 @@ void VG_(maybe_record_error) ( ThreadState* tst,
       vg_n_errs_found++;
       if (!is_first_shown_context)
          VG_(message)(Vg_UserMsg, "");
-      pp_Error(p, False);      
+      pp_Error(p, False);
       is_first_shown_context = False;
       vg_n_errs_shown++;
-      /* Perhaps we want a GDB attach at this point? */
-      if (vg_is_GDB_attach_requested()) {
-         VG_(swizzle_esp_then_start_GDB)(
-            err.m_eip, err.m_esp, err.m_ebp);
-      }
+      do_actions_on_error(p);
    } else {
       vg_n_errs_suppressed++;
       p->supp->count++;
    }
 }
 
+/* Second top-level entry point to the error management subsystem, for
+   errors that the skin want to report immediately, eg. because they're
+   guaranteed to only happen once.  This avoids all the recording and
+   comparing stuff.  But they can be suppressed;  returns True if it is
+   suppressed.  Bool `print_error' dictates whether to print the error. */
+Bool VG_(unique_error) ( ThreadState* tst, ErrorKind ekind, Addr a, Char* s,
+                         void* extra, ExeContext* where, Bool print_error )
+{
+   Error  err;
+
+   /* Build ourselves the error */
+   construct_error ( &err, tst, ekind, a, s, extra, where );
+
+   /* Unless it's suppressed, we're going to show it.  Don't need to make
+      a copy, because it's only temporary anyway.
+
+      Then update the `extra' part with SK_(update_extra), because that can
+      have an affect on whether it's suppressed.  Ignore the size return
+      value of SK_(update_extra), because we're not copying `extra'. */
+   (void)SK_(update_extra)(&err);
+
+   if (NULL == is_suppressible_error(&err)) {
+      vg_n_errs_found++;
+
+      if (print_error) {
+         if (!is_first_shown_context)
+            VG_(message)(Vg_UserMsg, "");
+         pp_Error(&err, False);
+         is_first_shown_context = False;
+      }
+      do_actions_on_error(&err);
+
+      return False;
+
+   } else {
+      vg_n_errs_suppressed++;
+      return True;
+   }
+}
+
 
 /*------------------------------------------------------------*/
 /*--- Exported fns                                         ---*/
@@ -529,9 +634,6 @@ Bool skin_name_present(Char *name, Char *names)
    return found;
 }
 
-#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
-                      && VG_(strcmp)((s1),(s2))==0)
-
 /* Read suppressions from the file specified in vg_clo_suppressions
    and place them in the suppressions list.  If there's any difficulty
    doing this, just give up -- there's no point in trying to recover.  
@@ -563,10 +665,10 @@ static void load_one_suppressions_file ( Char* filename )
       eof = VG_(get_line) ( fd, buf, N_BUF );
       if (eof) break;
 
-      if (!STREQ(buf, "{")) goto syntax_error;
+      if (!VG_STREQ(buf, "{")) goto syntax_error;
       
       eof = VG_(get_line) ( fd, buf, N_BUF );
-      if (eof || STREQ(buf, "}")) goto syntax_error;
+      if (eof || VG_STREQ(buf, "}")) goto syntax_error;
       supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
 
       eof = VG_(get_line) ( fd, buf, N_BUF );
@@ -588,7 +690,7 @@ static void load_one_suppressions_file ( Char* filename )
       /* Is it a core suppression? */
       if (VG_(needs).core_errors && skin_name_present("core", skin_names))
       {
-         if (STREQ(supp_name, "PThread"))
+         if (VG_STREQ(supp_name, "PThread"))
             supp->skind = PThreadSupp;
          else
             goto syntax_error;
@@ -610,7 +712,7 @@ static void load_one_suppressions_file ( Char* filename )
          while (True) {
             eof = VG_(get_line) ( fd, buf, N_BUF );
             if (eof) goto syntax_error;
-            if (STREQ(buf, "}"))
+            if (VG_STREQ(buf, "}"))
                break;
          }
          continue;
@@ -624,7 +726,7 @@ static void load_one_suppressions_file ( Char* filename )
       for (i = 0; i < VG_N_SUPP_CALLERS; i++) {
          eof = VG_(get_line) ( fd, buf, N_BUF );
          if (eof) goto syntax_error;
-         if (i > 0 && STREQ(buf, "}")) 
+         if (i > 0 && VG_STREQ(buf, "}")) 
             break;
          supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
          if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
@@ -673,9 +775,8 @@ void VG_(load_suppressions) ( void )
    Doesn't demangle the fn name, because we want to refer to 
    mangled names in the suppressions file.
 */
-void VG_(get_objname_fnname) ( Addr a,
-                               Char* obj_buf, Int n_obj_buf,
-                               Char* fun_buf, Int n_fun_buf )
+static void get_objname_fnname ( Addr a, Char* obj_buf, Int n_obj_buf,
+                                         Char* fun_buf, Int n_fun_buf )
 {     
    (void)VG_(get_objname)          ( a, obj_buf, n_obj_buf );
    (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
@@ -714,7 +815,7 @@ Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT],
          case FunName: if (VG_(string_match)(su->caller[i], 
                                              caller_fun[i])) break;
                        return False;
-         default: VG_(skin_panic)("is_suppressible_error");
+         default: VG_(skin_panic)("supp_matches_callers");
       }
    }
 
@@ -736,7 +837,7 @@ static Supp* is_suppressible_error ( Error* err )
    Supp* su;
 
    /* get_objname_fnname() writes the function name and object name if
-      it finds them in the debug info.  so the strings in the suppression
+      it finds them in the debug info.  So the strings in the suppression
       file should match these.
    */
 
@@ -746,9 +847,8 @@ static Supp* is_suppressible_error ( Error* err )
       caller_obj[i][0] = caller_fun[i][0] = 0;
 
    for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
-      VG_(get_objname_fnname) ( err->where->eips[i], 
-                                caller_obj[i], M_VG_ERRTXT,
-                                caller_fun[i], M_VG_ERRTXT );
+      get_objname_fnname ( err->where->eips[i], caller_obj[i], M_VG_ERRTXT,
+                                                caller_fun[i], M_VG_ERRTXT );
    }
 
    /* See if the error context matches any suppression. */
@@ -761,8 +861,6 @@ static Supp* is_suppressible_error ( Error* err )
    return NULL;      /* no matches */
 }
 
-#undef STREQ
-
 /*--------------------------------------------------------------------*/
 /*--- end                                          vg_errcontext.c ---*/
 /*--------------------------------------------------------------------*/
index a420d456f4bbd578fda90955fc3995b18687c5dc..85ba492b16a83d93a7d655726225f22278811838 100644 (file)
@@ -171,6 +171,8 @@ typedef
 extern Bool  VG_(clo_error_limit);
 /* Enquire about whether to attach to GDB at errors?   default: NO */
 extern Bool  VG_(clo_GDB_attach);
+/* Enquire about generating a suppression for each error?   default: NO */
+extern Bool  VG_(clo_gen_suppressions);
 /* Sanity-check level: 0 = none, 1 (default), > 1 = expensive. */
 extern Int   VG_(sanity_level);
 /* Automatically attempt to demangle C++ names?  default: YES */
@@ -1192,14 +1194,13 @@ extern void VG_(record_pthread_error) ( ThreadId tid, Char* msg );
 
 extern void VG_(show_all_errors)      ( void );
 
-extern void VG_(get_objname_fnname) ( Addr a,
-                                      Char* obj_buf, Int n_obj_buf,
-                                      Char* fun_buf, Int n_fun_buf );
-
 /* Get hold of the suppression list ... just so we don't have to
    make it global. */
 extern Supp* VG_(get_suppressions) ( void );
 
+extern Bool VG_(is_action_requested) ( Char* action, Bool* clo );
+
+extern void VG_(gen_suppression) ( Error* err );
 
 /* ---------------------------------------------------------------------
    Exports of vg_procselfmaps.c
index 351aa50f3ec49ff3114349d0bf0a6695d68cfbd7..aca07cc7f70a10894b4af45d60da05d57d444377 100644 (file)
@@ -487,6 +487,7 @@ UInt VG_(num_scheduling_events_MAJOR) = 0;
 /* Define, and set defaults. */
 Bool   VG_(clo_error_limit)    = True;
 Bool   VG_(clo_GDB_attach)     = False;
+Bool   VG_(clo_gen_suppressions) = False;
 Int    VG_(sanity_level)       = 1;
 Int    VG_(clo_verbosity)      = 1;
 Bool   VG_(clo_demangle)       = True;
@@ -588,6 +589,7 @@ static void usage ( void )
 "    -q --quiet                run silently; only print error msgs\n"
 "    -v --verbose              be more verbose, incl counts of errors\n"
 "    --gdb-attach=no|yes       start GDB when errors detected? [no]\n"
+"    --gen-suppressions=no|yes print suppressions for errors detected [no]\n"
 "    --demangle=no|yes         automatically demangle C++ names? [yes]\n"
 "    --num-callers=<number>    show <num> callers in stack traces [4]\n"
 "    --error-limit=no|yes      stop showing new errors if too many? [yes]\n"
@@ -685,8 +687,6 @@ static void process_cmd_line_options ( void )
    Int   i, eventually_logfile_fd, ctr;
 
 #  define ISSPACE(cc)      ((cc) == ' ' || (cc) == '\t' || (cc) == '\n')
-#  define STREQ(s1,s2)     (0==VG_(strcmp_ws)((s1),(s2)))
-#  define STREQN(nn,s1,s2) (0==VG_(strncmp_ws)((s1),(s2),(nn)))
 
    eventually_logfile_fd = VG_(clo_logfile_fd);
 
@@ -863,64 +863,71 @@ static void process_cmd_line_options ( void )
 
    for (i = 0; i < argc; i++) {
 
-      if      (STREQ(argv[i], "-v") || STREQ(argv[i], "--verbose"))
+      if      (VG_CLO_STREQ(argv[i], "-v") ||
+               VG_CLO_STREQ(argv[i], "--verbose"))
          VG_(clo_verbosity)++;
-      else if (STREQ(argv[i], "-q") || STREQ(argv[i], "--quiet"))
+      else if (VG_CLO_STREQ(argv[i], "-q") ||
+               VG_CLO_STREQ(argv[i], "--quiet"))
          VG_(clo_verbosity)--;
 
-      else if (STREQ(argv[i], "--error-limit=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--error-limit=yes"))
          VG_(clo_error_limit) = True;
-      else if (STREQ(argv[i], "--error-limit=no"))
+      else if (VG_CLO_STREQ(argv[i], "--error-limit=no"))
          VG_(clo_error_limit) = False;
 
-      else if (STREQ(argv[i], "--gdb-attach=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--gdb-attach=yes"))
          VG_(clo_GDB_attach) = True;
-      else if (STREQ(argv[i], "--gdb-attach=no"))
+      else if (VG_CLO_STREQ(argv[i], "--gdb-attach=no"))
          VG_(clo_GDB_attach) = False;
 
-      else if (STREQ(argv[i], "--demangle=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--gen-suppressions=yes"))
+         VG_(clo_gen_suppressions) = True;
+      else if (VG_CLO_STREQ(argv[i], "--gen-suppressions=no"))
+         VG_(clo_gen_suppressions) = False;
+
+      else if (VG_CLO_STREQ(argv[i], "--demangle=yes"))
          VG_(clo_demangle) = True;
-      else if (STREQ(argv[i], "--demangle=no"))
+      else if (VG_CLO_STREQ(argv[i], "--demangle=no"))
          VG_(clo_demangle) = False;
 
-      else if (STREQ(argv[i], "--sloppy-malloc=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--sloppy-malloc=yes"))
          VG_(clo_sloppy_malloc) = True;
-      else if (STREQ(argv[i], "--sloppy-malloc=no"))
+      else if (VG_CLO_STREQ(argv[i], "--sloppy-malloc=no"))
          VG_(clo_sloppy_malloc) = False;
 
-      else if (STREQN(12, argv[i], "--alignment="))
+      else if (VG_CLO_STREQN(12, argv[i], "--alignment="))
          VG_(clo_alignment) = (Int)VG_(atoll)(&argv[i][12]);
 
-      else if (STREQ(argv[i], "--trace-children=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-children=yes"))
          VG_(clo_trace_children) = True;
-      else if (STREQ(argv[i], "--trace-children=no"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-children=no"))
          VG_(clo_trace_children) = False;
 
-      else if (STREQ(argv[i], "--run-libc-freeres=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--run-libc-freeres=yes"))
          VG_(clo_run_libc_freeres) = True;
-      else if (STREQ(argv[i], "--run-libc-freeres=no"))
+      else if (VG_CLO_STREQ(argv[i], "--run-libc-freeres=no"))
          VG_(clo_run_libc_freeres) = False;
 
-      else if (STREQN(15, argv[i], "--sanity-level="))
+      else if (VG_CLO_STREQN(15, argv[i], "--sanity-level="))
          VG_(sanity_level) = (Int)VG_(atoll)(&argv[i][15]);
 
-      else if (STREQN(13, argv[i], "--logfile-fd=")) {
+      else if (VG_CLO_STREQN(13, argv[i], "--logfile-fd=")) {
          VG_(clo_log_to)       = VgLogTo_Fd;
          VG_(clo_logfile_name) = NULL;
          eventually_logfile_fd = (Int)VG_(atoll)(&argv[i][13]);
       }
 
-      else if (STREQN(10, argv[i], "--logfile=")) {
+      else if (VG_CLO_STREQN(10, argv[i], "--logfile=")) {
          VG_(clo_log_to)       = VgLogTo_File;
          VG_(clo_logfile_name) = &argv[i][10];
       }
 
-      else if (STREQN(12, argv[i], "--logsocket=")) {
+      else if (VG_CLO_STREQN(12, argv[i], "--logsocket=")) {
          VG_(clo_log_to)       = VgLogTo_Socket;
          VG_(clo_logfile_name) = &argv[i][12];
       }
 
-      else if (STREQN(15, argv[i], "--suppressions=")) {
+      else if (VG_CLO_STREQN(15, argv[i], "--suppressions=")) {
          if (VG_(clo_n_suppressions) >= VG_CLO_MAX_SFILES) {
             VG_(message)(Vg_UserMsg, "Too many suppression files specified.");
             VG_(message)(Vg_UserMsg, 
@@ -930,28 +937,28 @@ static void process_cmd_line_options ( void )
          VG_(clo_suppressions)[VG_(clo_n_suppressions)] = &argv[i][15];
          VG_(clo_n_suppressions)++;
       }
-      else if (STREQ(argv[i], "--profile=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--profile=yes"))
          VG_(clo_profile) = True;
-      else if (STREQ(argv[i], "--profile=no"))
+      else if (VG_CLO_STREQ(argv[i], "--profile=no"))
          VG_(clo_profile) = False;
 
-      else if (STREQ(argv[i], "--chain-bb=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--chain-bb=yes"))
         VG_(clo_chain_bb) = True;
-      else if (STREQ(argv[i], "--chain-bb=no"))
+      else if (VG_CLO_STREQ(argv[i], "--chain-bb=no"))
         VG_(clo_chain_bb) = False;
 
-      else if (STREQ(argv[i], "--single-step=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--single-step=yes"))
          VG_(clo_single_step) = True;
-      else if (STREQ(argv[i], "--single-step=no"))
+      else if (VG_CLO_STREQ(argv[i], "--single-step=no"))
          VG_(clo_single_step) = False;
 
-      else if (STREQ(argv[i], "--optimise=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--optimise=yes"))
          VG_(clo_optimise) = True;
-      else if (STREQ(argv[i], "--optimise=no"))
+      else if (VG_CLO_STREQ(argv[i], "--optimise=no"))
          VG_(clo_optimise) = False;
 
       /* "vwxyz" --> 000zyxwv (binary) */
-      else if (STREQN(16, argv[i], "--trace-codegen=")) {
+      else if (VG_CLO_STREQN(16, argv[i], "--trace-codegen=")) {
          Int j;
          char* opt = & argv[i][16];
    
@@ -971,48 +978,48 @@ static void process_cmd_line_options ( void )
          }
       }
 
-      else if (STREQ(argv[i], "--trace-syscalls=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-syscalls=yes"))
          VG_(clo_trace_syscalls) = True;
-      else if (STREQ(argv[i], "--trace-syscalls=no"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-syscalls=no"))
          VG_(clo_trace_syscalls) = False;
 
-      else if (STREQ(argv[i], "--trace-signals=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-signals=yes"))
          VG_(clo_trace_signals) = True;
-      else if (STREQ(argv[i], "--trace-signals=no"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-signals=no"))
          VG_(clo_trace_signals) = False;
 
-      else if (STREQ(argv[i], "--trace-symtab=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-symtab=yes"))
          VG_(clo_trace_symtab) = True;
-      else if (STREQ(argv[i], "--trace-symtab=no"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-symtab=no"))
          VG_(clo_trace_symtab) = False;
 
-      else if (STREQ(argv[i], "--trace-malloc=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-malloc=yes"))
          VG_(clo_trace_malloc) = True;
-      else if (STREQ(argv[i], "--trace-malloc=no"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-malloc=no"))
          VG_(clo_trace_malloc) = False;
 
-      else if (STREQ(argv[i], "--trace-sched=yes"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-sched=yes"))
          VG_(clo_trace_sched) = True;
-      else if (STREQ(argv[i], "--trace-sched=no"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-sched=no"))
          VG_(clo_trace_sched) = False;
 
-      else if (STREQ(argv[i], "--trace-pthread=none"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-pthread=none"))
          VG_(clo_trace_pthread_level) = 0;
-      else if (STREQ(argv[i], "--trace-pthread=some"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-pthread=some"))
          VG_(clo_trace_pthread_level) = 1;
-      else if (STREQ(argv[i], "--trace-pthread=all"))
+      else if (VG_CLO_STREQ(argv[i], "--trace-pthread=all"))
          VG_(clo_trace_pthread_level) = 2;
 
-      else if (STREQN(14, argv[i], "--weird-hacks="))
+      else if (VG_CLO_STREQN(14, argv[i], "--weird-hacks="))
          VG_(clo_weird_hacks) = &argv[i][14];
 
-      else if (STREQN(13, argv[i], "--stop-after="))
+      else if (VG_CLO_STREQN(13, argv[i], "--stop-after="))
          VG_(clo_stop_after) = VG_(atoll)(&argv[i][13]);
 
-      else if (STREQN(13, argv[i], "--dump-error="))
+      else if (VG_CLO_STREQN(13, argv[i], "--dump-error="))
          VG_(clo_dump_error) = (Int)VG_(atoll)(&argv[i][13]);
 
-      else if (STREQN(14, argv[i], "--num-callers=")) {
+      else if (VG_CLO_STREQN(14, argv[i], "--num-callers=")) {
          /* Make sure it's sane. */
         VG_(clo_backtrace_size) = (Int)VG_(atoll)(&argv[i][14]);
          if (VG_(clo_backtrace_size) < 2)
@@ -1031,8 +1038,6 @@ static void process_cmd_line_options ( void )
    }
 
 #  undef ISSPACE
-#  undef STREQ
-#  undef STREQN
 
    if (VG_(clo_verbosity < 0))
       VG_(clo_verbosity) = 0;
index 64200ed7acab4b4633a172b796323f62c1eed35f..6ade64268b01a2652761a917b5b95d73a23b51c2 100644 (file)
@@ -292,612 +292,6 @@ void VG_(unknown_esp_update)(Addr new_ESP)
    }
 }
 
-/*--------------------------------------------------------------------*/
-/*--- Support for memory leak detectors                            ---*/
-/*--------------------------------------------------------------------*/
-
-/*------------------------------------------------------------*/
-/*--- Low-level address-space scanning, for the leak       ---*/
-/*--- detector.                                            ---*/
-/*------------------------------------------------------------*/
-
-static 
-jmp_buf memscan_jmpbuf;
-
-
-static
-void vg_scan_all_valid_memory_sighandler ( Int sigNo )
-{
-   __builtin_longjmp(memscan_jmpbuf, 1);
-}
-
-
-/* Safely (avoiding SIGSEGV / SIGBUS) scan the entire valid address
-   space and pass the addresses and values of all addressible,
-   defined, aligned words to notify_word.  This is the basis for the
-   leak detector.  Returns the number of calls made to notify_word.
-
-   Addresses are validated 3 ways.  First we enquire whether (addr >>
-   16) denotes a 64k chunk in use, by asking is_valid_64k_chunk().  If
-   so, we decide for ourselves whether each x86-level (4 K) page in
-   the chunk is safe to inspect.  If yes, we enquire with
-   is_valid_address() whether or not each of the 1024 word-locations
-   on the page is valid.  Only if so are that address and its contents
-   passed to notify_word.
-
-   This is all to avoid duplication of this machinery between the
-   memcheck and addrcheck skins.  
-*/
-static
-UInt vg_scan_all_valid_memory ( Bool is_valid_64k_chunk ( UInt ),
-                                Bool is_valid_address ( Addr ),
-                                void (*notify_word)( Addr, UInt ) )
-{
-   /* All volatile, because some gccs seem paranoid about longjmp(). */
-   volatile Bool anyValid;
-   volatile Addr pageBase, addr;
-   volatile UInt res, numPages, page, primaryMapNo;
-   volatile UInt page_first_word, nWordsNotified;
-
-   vki_ksigaction sigbus_saved;
-   vki_ksigaction sigbus_new;
-   vki_ksigaction sigsegv_saved;
-   vki_ksigaction sigsegv_new;
-   vki_ksigset_t  blockmask_saved;
-   vki_ksigset_t  unblockmask_new;
-
-   /* Temporarily install a new sigsegv and sigbus handler, and make
-      sure SIGBUS, SIGSEGV and SIGTERM are unblocked.  (Perhaps the
-      first two can never be blocked anyway?)  */
-
-   sigbus_new.ksa_handler = vg_scan_all_valid_memory_sighandler;
-   sigbus_new.ksa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
-   sigbus_new.ksa_restorer = NULL;
-   res = VG_(ksigemptyset)( &sigbus_new.ksa_mask );
-   sk_assert(res == 0);
-
-   sigsegv_new.ksa_handler = vg_scan_all_valid_memory_sighandler;
-   sigsegv_new.ksa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
-   sigsegv_new.ksa_restorer = NULL;
-   res = VG_(ksigemptyset)( &sigsegv_new.ksa_mask );
-   sk_assert(res == 0+0);
-
-   res =  VG_(ksigemptyset)( &unblockmask_new );
-   res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGBUS );
-   res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGSEGV );
-   res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGTERM );
-   sk_assert(res == 0+0+0);
-
-   res = VG_(ksigaction)( VKI_SIGBUS, &sigbus_new, &sigbus_saved );
-   sk_assert(res == 0+0+0+0);
-
-   res = VG_(ksigaction)( VKI_SIGSEGV, &sigsegv_new, &sigsegv_saved );
-   sk_assert(res == 0+0+0+0+0);
-
-   res = VG_(ksigprocmask)( VKI_SIG_UNBLOCK, &unblockmask_new, &blockmask_saved );
-   sk_assert(res == 0+0+0+0+0+0);
-
-   /* The signal handlers are installed.  Actually do the memory scan. */
-   numPages = 1 << (32-VKI_BYTES_PER_PAGE_BITS);
-   sk_assert(numPages == 1048576);
-   sk_assert(4096 == (1 << VKI_BYTES_PER_PAGE_BITS));
-
-   nWordsNotified = 0;
-
-   for (page = 0; page < numPages; page++) {
-
-      /* Base address of this 4k page. */
-      pageBase = page << VKI_BYTES_PER_PAGE_BITS;
-
-      /* Skip if this page is in an unused 64k chunk. */
-      primaryMapNo = pageBase >> 16;
-      if (!is_valid_64k_chunk(primaryMapNo))
-         continue;
-
-      /* Next, establish whether or not we want to consider any
-         locations on this page.  We need to do so before actually
-         prodding it, because prodding it when in fact it is not
-         needed can cause a page fault which under some rare
-         circumstances can cause the kernel to extend the stack
-         segment all the way down to here, which is seriously bad.
-         Hence: */
-      anyValid = False;
-      for (addr = pageBase; addr < pageBase+VKI_BYTES_PER_PAGE; addr += 4) {
-         if (is_valid_address(addr)) {
-            anyValid = True;
-            break;
-         }
-      }
-
-      if (!anyValid)
-         continue;  /* nothing interesting here .. move to the next page */
-
-      /* Ok, we have to prod cautiously at the page and see if it
-         explodes or not. */
-      if (__builtin_setjmp(memscan_jmpbuf) == 0) {
-         /* try this ... */
-         page_first_word = * (volatile UInt*)pageBase;
-         /* we get here if we didn't get a fault */
-         /* Scan the page */
-         for (addr = pageBase; addr < pageBase+VKI_BYTES_PER_PAGE; addr += 4) {
-            if (is_valid_address(addr)) {
-               nWordsNotified++;
-               notify_word ( addr, *(UInt*)addr );
-           }
-         }
-      } else {
-         /* We get here if reading the first word of the page caused a
-            fault, which in turn caused the signal handler to longjmp.
-            Ignore this page. */
-         if (0)
-         VG_(printf)(
-            "vg_scan_all_valid_memory_sighandler: ignoring page at %p\n",
-            (void*)pageBase 
-         );
-      }
-   }
-
-   /* Restore signal state to whatever it was before. */
-   res = VG_(ksigaction)( VKI_SIGBUS, &sigbus_saved, NULL );
-   sk_assert(res == 0 +0);
-
-   res = VG_(ksigaction)( VKI_SIGSEGV, &sigsegv_saved, NULL );
-   sk_assert(res == 0 +0 +0);
-
-   res = VG_(ksigprocmask)( VKI_SIG_SETMASK, &blockmask_saved, NULL );
-   sk_assert(res == 0 +0 +0 +0);
-
-   return nWordsNotified;
-}
-
-
-/*------------------------------------------------------------*/
-/*--- Detecting leaked (unreachable) malloc'd blocks.      ---*/
-/*------------------------------------------------------------*/
-
-/* A block is either 
-   -- Proper-ly reached; a pointer to its start has been found
-   -- Interior-ly reached; only an interior pointer to it has been found
-   -- Unreached; so far, no pointers to any part of it have been found. 
-*/
-typedef 
-   enum { Unreached, Interior, Proper } 
-   Reachedness;
-
-/* A block record, used for generating err msgs. */
-typedef
-   struct _LossRecord {
-      struct _LossRecord* next;
-      /* Where these lost blocks were allocated. */
-      ExeContext*  allocated_at;
-      /* Their reachability. */
-      Reachedness  loss_mode;
-      /* Number of blocks and total # bytes involved. */
-      UInt         total_bytes;
-      UInt         num_blocks;
-   }
-   LossRecord;
-
-
-/* Find the i such that ptr points at or inside the block described by
-   shadows[i].  Return -1 if none found.  This assumes that shadows[]
-   has been sorted on the ->data field. */
-
-#ifdef VG_DEBUG_LEAKCHECK
-/* Used to sanity-check the fast binary-search mechanism. */
-static 
-Int find_shadow_for_OLD ( Addr          ptr, 
-                          ShadowChunk** shadows,
-                          Int           n_shadows )
-
-{
-   Int  i;
-   Addr a_lo, a_hi;
-   PROF_EVENT(70);
-   for (i = 0; i < n_shadows; i++) {
-      PROF_EVENT(71);
-      a_lo = shadows[i]->data;
-      a_hi = ((Addr)shadows[i]->data) + shadows[i]->size - 1;
-      if (a_lo <= ptr && ptr <= a_hi)
-         return i;
-   }
-   return -1;
-}
-#endif
-
-
-static 
-Int find_shadow_for ( Addr          ptr, 
-                      ShadowChunk** shadows,
-                      Int           n_shadows )
-{
-   Addr a_mid_lo, a_mid_hi;
-   Int lo, mid, hi, retVal;
-   /* VG_(printf)("find shadow for %p = ", ptr); */
-   retVal = -1;
-   lo = 0;
-   hi = n_shadows-1;
-   while (True) {
-      /* invariant: current unsearched space is from lo to hi,
-         inclusive. */
-      if (lo > hi) break; /* not found */
-
-      mid      = (lo + hi) / 2;
-      a_mid_lo = shadows[mid]->data;
-      a_mid_hi = ((Addr)shadows[mid]->data) + shadows[mid]->size - 1;
-
-      if (ptr < a_mid_lo) {
-         hi = mid-1;
-         continue;
-      } 
-      if (ptr > a_mid_hi) {
-         lo = mid+1;
-         continue;
-      }
-      sk_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
-      retVal = mid;
-      break;
-   }
-
-#  ifdef VG_DEBUG_LEAKCHECK
-   vg_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows ));
-#  endif
-   /* VG_(printf)("%d\n", retVal); */
-   return retVal;
-}
-
-
-
-static 
-void sort_malloc_shadows ( ShadowChunk** shadows, UInt n_shadows )
-{
-   Int   incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
-                      9841, 29524, 88573, 265720,
-                      797161, 2391484 };
-   Int          lo = 0;
-   Int          hi = n_shadows-1;
-   Int          i, j, h, bigN, hp;
-   ShadowChunk* v;
-
-   bigN = hi - lo + 1; if (bigN < 2) return;
-   hp = 0; while (hp < 14 && incs[hp] < bigN) hp++; hp--;
-   vg_assert(0 <= hp && hp < 14);
-
-   for (; hp >= 0; hp--) {
-      h = incs[hp];
-      i = lo + h;
-      while (1) {
-         if (i > hi) break;
-         v = shadows[i];
-         j = i;
-         while (shadows[j-h]->data > v->data) {
-            shadows[j] = shadows[j-h];
-            j = j - h;
-            if (j <= (lo + h - 1)) break;
-         }
-         shadows[j] = v;
-         i++;
-      }
-   }
-}
-
-
-/* Globals, for the callback used by VG_(detect_memory_leaks). */
-
-static ShadowChunk** vglc_shadows;
-static Int           vglc_n_shadows;
-static Reachedness*  vglc_reachedness;
-static Addr          vglc_min_mallocd_addr;
-static Addr          vglc_max_mallocd_addr;
-
-static 
-void vg_detect_memory_leaks_notify_addr ( Addr a, UInt word_at_a )
-{
-   Int  sh_no;
-   Addr ptr;
-
-   /* Rule out some known causes of bogus pointers.  Mostly these do
-      not cause much trouble because only a few false pointers can
-      ever lurk in these places.  This mainly stops it reporting that
-      blocks are still reachable in stupid test programs like this
-
-         int main (void) { char* a = malloc(100); return 0; }
-
-      which people seem inordinately fond of writing, for some reason.  
-
-      Note that this is a complete kludge.  It would be better to
-      ignore any addresses corresponding to valgrind.so's .bss and
-      .data segments, but I cannot think of a reliable way to identify
-      where the .bss segment has been put.  If you can, drop me a
-      line.  
-   */
-   if (VG_(within_stack)(a))                return;
-   if (VG_(within_m_state_static)(a))       return;
-   if (a == (Addr)(&vglc_min_mallocd_addr)) return;
-   if (a == (Addr)(&vglc_max_mallocd_addr)) return;
-
-   /* OK, let's get on and do something Useful for a change. */
-
-   ptr = (Addr)word_at_a;
-   if (ptr >= vglc_min_mallocd_addr && ptr <= vglc_max_mallocd_addr) {
-      /* Might be legitimate; we'll have to investigate further. */
-      sh_no = find_shadow_for ( ptr, vglc_shadows, vglc_n_shadows );
-      if (sh_no != -1) {
-         /* Found a block at/into which ptr points. */
-         sk_assert(sh_no >= 0 && sh_no < vglc_n_shadows);
-         sk_assert(ptr < vglc_shadows[sh_no]->data 
-                         + vglc_shadows[sh_no]->size);
-         /* Decide whether Proper-ly or Interior-ly reached. */
-         if (ptr == vglc_shadows[sh_no]->data) {
-            if (0) VG_(printf)("pointer at %p to %p\n", a, word_at_a );
-            vglc_reachedness[sh_no] = Proper;
-         } else {
-            if (vglc_reachedness[sh_no] == Unreached)
-               vglc_reachedness[sh_no] = Interior;
-         }
-      }
-   }
-}
-
-
-/* Stuff for figuring out if a leak report should be suppressed. */
-static
-Bool leaksupp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT], 
-                                        Char caller_fun[][M_VG_ERRTXT])
-{
-   Int i;
-
-   for (i = 0; su->caller[i] != NULL; i++) {
-      switch (su->caller_ty[i]) {
-         case ObjName: if (VG_(string_match)(su->caller[i],
-                                             caller_obj[i])) break;
-                       return False;
-         case FunName: if (VG_(string_match)(su->caller[i], 
-                                             caller_fun[i])) break;
-                       return False;
-         default: VG_(skin_panic)("leaksupp_matches_callers");
-      }
-   }
-
-   /* If we reach here, it's a match */
-   return True;
-}
-
-
-/* Does a leak record match a suppression?  ie is this a suppressible
-   leak?  Tries to minimise the number of symbol searches since they
-   are expensive.  Copy n paste (more or less) of
-   is_suppressible_error.  We have to pass in the actual value of
-   LeakSupp for comparison since this is the core and LeakSupp is a
-   skin-specific value. */
-static
-Bool is_suppressible_leak ( ExeContext* allocated_at, 
-                            UInt /*CoreErrorKind*/ leakSupp )
-{
-   Int i;
-
-   Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
-   Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
-
-   Supp* su;
-
-   /* get_objname_fnname() writes the function name and object name if
-      it finds them in the debug info.  so the strings in the suppression
-      file should match these.
-   */
-
-   /* Initialise these strs so they are always safe to compare, even
-      if get_objname_fnname doesn't write anything to them. */
-   for (i = 0; i < VG_N_SUPP_CALLERS; i++)
-      caller_obj[i][0] = caller_fun[i][0] = 0;
-
-   for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
-      VG_(get_objname_fnname) ( allocated_at->eips[i], 
-                                caller_obj[i], M_VG_ERRTXT,
-                                caller_fun[i], M_VG_ERRTXT );
-   }
-
-   /* See if the leak record any suppression. */
-   for (su = VG_(get_suppressions)(); su != NULL; su = su->next) {
-      if (VG_(get_supp_kind)(su) == (CoreErrorKind)leakSupp
-          && leaksupp_matches_callers(su, caller_obj, caller_fun)) {
-         return True;
-      }
-   }
-   return False;      /* no matches */
-}
-
-/* Top level entry point to leak detector.  Call here, passing in
-   suitable address-validating functions (see comment at top of
-   vg_scan_all_valid_memory above).  All this is to avoid duplication
-   of the leak-detection code for the Memcheck and Addrcheck skins.
-   Also pass in a skin-specific function to extract the .where field
-   for allocated blocks, an indication of the resolution wanted for
-   distinguishing different allocation points, and whether or not
-   reachable blocks should be shown.
-*/
-void VG_(generic_detect_memory_leaks) (
-   Bool is_valid_64k_chunk ( UInt ),
-   Bool is_valid_address ( Addr ),
-   ExeContext* get_where ( ShadowChunk* ),
-   VgRes leak_resolution,
-   Bool  show_reachable,
-   UInt /*CoreErrorKind*/ leakSupp
-)
-{
-   Int    i;
-   Int    blocks_leaked, bytes_leaked;
-   Int    blocks_dubious, bytes_dubious;
-   Int    blocks_reachable, bytes_reachable;
-   Int    blocks_suppressed, bytes_suppressed;
-   Int    n_lossrecords;
-   UInt   bytes_notified;
-   
-   LossRecord*  errlist;
-   LossRecord*  p;
-
-   /* VG_(get_malloc_shadows) allocates storage for shadows */
-   vglc_shadows = VG_(get_malloc_shadows)( &vglc_n_shadows );
-   if (vglc_n_shadows == 0) {
-      sk_assert(vglc_shadows == NULL);
-      VG_(message)(Vg_UserMsg, 
-                   "No malloc'd blocks -- no leaks are possible.");
-      return;
-   }
-
-   VG_(message)(Vg_UserMsg, 
-                "searching for pointers to %d not-freed blocks.", 
-                vglc_n_shadows );
-   sort_malloc_shadows ( vglc_shadows, vglc_n_shadows );
-
-   /* Sanity check; assert that the blocks are now in order and that
-      they don't overlap. */
-   for (i = 0; i < vglc_n_shadows-1; i++) {
-      sk_assert( ((Addr)vglc_shadows[i]->data)
-                 < ((Addr)vglc_shadows[i+1]->data) );
-      sk_assert( ((Addr)vglc_shadows[i]->data) + vglc_shadows[i]->size
-                 < ((Addr)vglc_shadows[i+1]->data) );
-   }
-
-   vglc_min_mallocd_addr = ((Addr)vglc_shadows[0]->data);
-   vglc_max_mallocd_addr = ((Addr)vglc_shadows[vglc_n_shadows-1]->data)
-                         + vglc_shadows[vglc_n_shadows-1]->size - 1;
-
-   vglc_reachedness 
-      = VG_(malloc)( vglc_n_shadows * sizeof(Reachedness) );
-   for (i = 0; i < vglc_n_shadows; i++)
-      vglc_reachedness[i] = Unreached;
-
-   /* Do the scan of memory. */
-   bytes_notified
-       = VKI_BYTES_PER_WORD
-         * vg_scan_all_valid_memory (
-              is_valid_64k_chunk,
-              is_valid_address,
-              &vg_detect_memory_leaks_notify_addr
-           );
-
-   VG_(message)(Vg_UserMsg, "checked %d bytes.", bytes_notified);
-
-   /* Common up the lost blocks so we can print sensible error
-      messages. */
-
-   n_lossrecords = 0;
-   errlist       = NULL;
-   for (i = 0; i < vglc_n_shadows; i++) {
-     
-      /* 'where' stored in 'skin_extra' field; extract using function
-         supplied by the calling skin. */
-      ExeContext* where = get_where ( vglc_shadows[i] );
-
-      for (p = errlist; p != NULL; p = p->next) {
-         if (p->loss_mode == vglc_reachedness[i]
-             && VG_(eq_ExeContext) ( leak_resolution,
-                                     p->allocated_at, 
-                                     where) ) {
-            break;
-        }
-      }
-      if (p != NULL) {
-         p->num_blocks  ++;
-         p->total_bytes += vglc_shadows[i]->size;
-      } else {
-         n_lossrecords ++;
-         p = VG_(malloc)(sizeof(LossRecord));
-         p->loss_mode    = vglc_reachedness[i];
-         p->allocated_at = where;
-         p->total_bytes  = vglc_shadows[i]->size;
-         p->num_blocks   = 1;
-         p->next         = errlist;
-         errlist         = p;
-      }
-   }
-
-   /* Print out the commoned-up blocks and collect summary stats. */
-   
-   blocks_leaked     = bytes_leaked     = 0;
-   blocks_dubious    = bytes_dubious    = 0;
-   blocks_reachable  = bytes_reachable  = 0;
-   blocks_suppressed = bytes_suppressed = 0;
-
-   for (i = 0; i < n_lossrecords; i++) {
-      LossRecord* p_min = NULL;
-      UInt        n_min = 0xFFFFFFFF;
-      for (p = errlist; p != NULL; p = p->next) {
-         if (p->num_blocks > 0 && p->total_bytes < n_min) {
-            n_min = p->total_bytes;
-            p_min = p;
-         }
-      }
-      sk_assert(p_min != NULL);
-
-      if (is_suppressible_leak(p_min->allocated_at, leakSupp)) {
-         blocks_suppressed += p_min->num_blocks;
-         bytes_suppressed += p_min->total_bytes;
-         p_min->num_blocks = 0;
-         continue;
-      } else {
-         switch (p_min->loss_mode) {
-            case Unreached:
-               blocks_leaked += p_min->num_blocks;
-               bytes_leaked  += p_min->total_bytes;
-               break;
-            case Interior:
-               blocks_dubious += p_min->num_blocks;
-               bytes_dubious  += p_min->total_bytes;
-               break;
-            case Proper:
-               blocks_reachable  += p_min->num_blocks;
-               bytes_reachable += p_min->total_bytes;
-               break;
-            default: 
-               VG_(core_panic)("generic_detect_memory_leaks: "
-                               "unknown loss mode");
-         }
-      }
-
-      if ( (!show_reachable) && (p_min->loss_mode == Proper)) {
-         p_min->num_blocks = 0;
-         continue;
-      }
-
-      VG_(message)(Vg_UserMsg, "");
-      VG_(message)(
-         Vg_UserMsg,
-         "%d bytes in %d blocks are %s in loss record %d of %d",
-         p_min->total_bytes, p_min->num_blocks,
-         p_min->loss_mode==Unreached ? "definitely lost" :
-            (p_min->loss_mode==Interior ? "possibly lost"
-                                        : "still reachable"),
-         i+1, n_lossrecords
-      );
-      VG_(pp_ExeContext)(p_min->allocated_at);
-      p_min->num_blocks = 0;
-   }
-
-   VG_(message)(Vg_UserMsg, "");
-   VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
-   VG_(message)(Vg_UserMsg, "   definitely lost: %d bytes in %d blocks.", 
-                            bytes_leaked, blocks_leaked );
-   VG_(message)(Vg_UserMsg, "   possibly lost:   %d bytes in %d blocks.", 
-                            bytes_dubious, blocks_dubious );
-   VG_(message)(Vg_UserMsg, "   still reachable: %d bytes in %d blocks.", 
-                            bytes_reachable, blocks_reachable );
-   VG_(message)(Vg_UserMsg, "        suppressed: %d bytes in %d blocks.", 
-                            bytes_suppressed, blocks_suppressed );
-   if (!show_reachable) {
-      VG_(message)(Vg_UserMsg, 
-         "Reachable blocks (those to which a pointer was found) are not shown.");
-      VG_(message)(Vg_UserMsg, 
-         "To see them, rerun with: --show-reachable=yes");
-   }
-   VG_(message)(Vg_UserMsg, "");
-
-   VG_(free) ( vglc_shadows );
-   VG_(free) ( vglc_reachedness );
-}
-
-
 /*--------------------------------------------------------------------*/
 /*--- end                                              vg_memory.c ---*/
 /*--------------------------------------------------------------------*/
index 90b2ac65b26862f88fa154fdaaa1340875ec4ada..72f33d6a263265ae6cbad551bded79472529b248 100644 (file)
@@ -197,7 +197,7 @@ Bool VG_(is_valid_or_empty_tid) ( ThreadId tid )
    if none do.  A small complication is dealing with any currently
    VG_(baseBlock)-resident thread. 
 */
-ThreadId VG_(any_matching_thread_stack)
+ThreadId VG_(first_matching_thread_stack)
               ( Bool (*p) ( Addr stack_min, Addr stack_max ))
 {
    ThreadId tid, tid_to_skip;
index c36d32b258cb1c015638577a822ddb82d5da3937..5f641563013f324a049bf789a97c9e26bcdb63c1 100644 (file)
@@ -2272,10 +2272,9 @@ void VG_(mini_stack_dump) ( ExeContext* ec )
       n = 0;
       if (i > 0)
         eip--;                 /* point to calling line */
-      know_fnname  = get_fnname (True, eip, buf_fn,  M_VG_ERRTXT, True, False);
+      know_fnname  = VG_(get_fnname) (eip, buf_fn,  M_VG_ERRTXT);
       know_objname = VG_(get_objname)(eip, buf_obj, M_VG_ERRTXT);
-      know_srcloc  = VG_(get_filename_linenum)(eip, 
-                                               buf_srcloc, M_VG_ERRTXT, 
+      know_srcloc  = VG_(get_filename_linenum)(eip, buf_srcloc, M_VG_ERRTXT, 
                                                &lineno);
       if (i == 0) APPEND("   at ") else APPEND("   by ");
       
index d56f681d3279ec9f1079c237647c097970f09c8b..21bfe7431d0088ba870d13aed39f4a291a336755 100644 (file)
@@ -2247,7 +2247,7 @@ static void describe_addr ( Addr a, AddrInfo* ai )
    }
 
    /* Search for a currently malloc'd block which might bracket it. */
-   sc = VG_(any_matching_mallocd_ShadowChunks)(addr_is_in_block);
+   sc = VG_(first_matching_mallocd_ShadowChunk)(addr_is_in_block);
    if (NULL != sc) {
       ai->akind      = Mallocd;
       ai->blksize    = VG_(get_sc_size)(sc);
@@ -2462,7 +2462,7 @@ static Char *lockset_str(const Char *prefix, const LockSet *lockset)
    return buf;
 }
 
-void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
+void SK_(pp_SkinError) ( Error* err )
 {
    HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
    Char buf[100];
@@ -2477,7 +2477,7 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
                       
       VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
                   VG_(get_error_string)(err), err_addr, err_addr);
-      pp_ExeContext();
+      VG_(pp_ExeContext)( VG_(get_error_where)(err) );
       pp_AddrInfo(err_addr, &extra->addrinfo);
 
       switch(extra->prevstate.state) {
@@ -2550,7 +2550,7 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
                   VG_(get_error_address)(err),
                   VG_(get_error_address)(err),
                   VG_(get_error_string)(err));
-      pp_ExeContext();
+      VG_(pp_ExeContext)( VG_(get_error_where)(err) );
       if (extra->lasttouched.uu_ec_eip.ec != NULL) {
         VG_(message)(Vg_UserMsg, "  last touched by thread %d", extra->lasttid);
         VG_(pp_ExeContext)(extra->lasttouched.uu_ec_eip.ec);
@@ -2567,7 +2567,7 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
 
       VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
                   err_addr, err_addr);
-      pp_ExeContext();
+      VG_(pp_ExeContext)( VG_(get_error_where)(err) );
       VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
 
       for(i = 0; i < heldset->setsize; i++) {
@@ -2620,6 +2620,19 @@ Bool SK_(error_matches_suppression)(Error* err, Supp* su)
    return True;
 }
 
+extern Char* SK_(get_error_name) ( Error* err )
+{
+   if (EraserErr == VG_(get_error_kind)(err)) {
+      return "Eraser";
+   } else {
+      return NULL;      /* Other errors types can't be suppressed */
+   }
+}
+
+extern void SK_(print_extra_suppression_info) ( Error* err )
+{
+   /* Do nothing */
+}
 
 static void eraser_pre_mutex_lock(ThreadId tid, void* void_mutex)
 {
index 986b8f321c81c52a8da5a327f89fc32a2290e631..723555f4e4db7c2695eb7ebdb4578705504e51f0 100644 (file)
@@ -132,6 +132,15 @@ const Int VG_(skin_interface_minor_version) = VG_CORE_INTERFACE_MINOR_VERSION;
 /*=== Command-line options                                         ===*/
 /*====================================================================*/
 
+/* Use this for normal null-termination-style string comparison */
+#define VG_STREQ(s1,s2) (s1 != NULL && s2 != NULL \
+                         && VG_(strcmp)((s1),(s2))==0)
+
+/* Use these for recognising skin command line options -- stops comparing
+   once whitespace is reached. */
+#  define VG_CLO_STREQ(s1,s2)     (0==VG_(strcmp_ws)((s1),(s2)))
+#  define VG_CLO_STREQN(nn,s1,s2) (0==VG_(strncmp_ws)((s1),(s2),(nn)))
+
 /* Verbosity level: 0 = silent, 1 (default), > 1 = more verbose. */
 extern Int   VG_(clo_verbosity);
 
@@ -1175,9 +1184,8 @@ void*       VG_(get_error_extra)   ( Error* err );
    
    If the error occurs in generated code, 'tst' should be NULL.  If the
    error occurs in non-generated code, 'tst' should be non-NULL.  The
-   `extra' field can be stack-allocated;  it will be copied (using
-   SKN_(dup_extra_and_update)()) if needed.  But it won't be copied
-   if it's NULL.
+   `extra' field can be stack-allocated;  it will be copied by the core
+   if needed.  But it won't be copied if it's NULL.
 
    If no 'a', 's' or 'extra' of interest needs to be recorded, just use
    NULL for them.
@@ -1185,6 +1193,16 @@ void*       VG_(get_error_extra)   ( Error* err );
 extern void VG_(maybe_record_error) ( ThreadState* tst, ErrorKind ekind, 
                                       Addr a, Char* s, void* extra );
 
+/* Similar to VG_(maybe_record_error)(), except this one doesn't record the
+   error -- useful for errors that can only happen once.  The errors can be
+   suppressed, though.  Return value is True if it was suppressed.
+   `print_error' dictates whether to print the error, which is a bit of a 
+   hack that's useful sometimes if you just want to know if the error would
+   be suppressed without possibly printing it. */
+extern Bool VG_(unique_error) ( ThreadState* tst, ErrorKind ekind,
+                                Addr a, Char* s, void* extra,
+                                ExeContext* where, Bool print_error );
+
 /* Gets a non-blank, non-comment line of at most nBuf chars from fd.
    Skips leading spaces on the line.  Returns True if EOF was hit instead. 
    Useful for reading in extra skin-specific suppression lines.
@@ -1296,12 +1314,12 @@ extern Bool VG_(addr_is_in_block) ( Addr a, Addr start, UInt size );
 /* Searches through currently malloc'd blocks until a matching one is found.
    Returns NULL if none match.  Extra arguments can be implicitly passed to
    p using nested functions; see memcheck/mc_errcontext.c for an example. */
-extern ShadowChunk* VG_(any_matching_mallocd_ShadowChunks
+extern ShadowChunk* VG_(first_matching_mallocd_ShadowChunk
                         ( Bool (*p) ( ShadowChunk* ));
 
 /* Searches through all thread's stacks to see if any match.  Returns
  * VG_INVALID_THREADID if none match. */
-extern ThreadId VG_(any_matching_thread_stack)
+extern ThreadId VG_(first_matching_thread_stack)
                         ( Bool (*p) ( Addr stack_min, Addr stack_max ));
 
 /* Do memory leak detection. */
@@ -1585,21 +1603,18 @@ extern void        SK_(fini)         ( void );
  */
 extern Bool SK_(eq_SkinError) ( VgRes res, Error* e1, Error* e2 );
 
-/* Print error context.  The passed function pp_ExeContext() can be (and
-   probably should be) used to print the location of the error. */
-extern void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) );
+/* Print error context. */
+extern void SK_(pp_SkinError) ( Error* err );
 
-/* Should copy the `extra' part which the core uses to override the old
-   version.  This is necessary to move from a temporary stack copy to a
-   permanent heap one.
-  
-   Then should fill in any details that could be postponed until after the
+/* 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 SK_(eq_SkinError)()).  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.
 */
-extern void* SK_(dup_extra_and_update) ( Error* err );
+extern UInt SK_(update_extra) ( Error* err );
 
 /* Return value indicates recognition.  If recognised, must set skind using
    VG_(set_supp_kind)(). */
@@ -1615,7 +1630,17 @@ extern Bool SK_(read_extra_suppression_info) ( Int fd, Char* buf, Int nBuf,
 /* 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). */
-extern Bool SK_(error_matches_suppression)(Error* err, Supp* su);
+extern Bool SK_(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
+   SK_(recognised_suppression)(). */
+extern Char* SK_(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
+   SK_(read_extra_suppression_info)(). */
+extern void SK_(print_extra_suppression_info) ( Error* err );
 
 
 /* ------------------------------------------------------------------ */
index af140b925a008219af2a05fd2acc3bdb656579fe..9c32164c04873ac5d4a11375650bb66b414c01a6 100644 (file)
@@ -14,9 +14,10 @@ valdir = $(libdir)/valgrind
 val_PROGRAMS = vgskin_memcheck.so
 
 vgskin_memcheck_so_SOURCES = \
+       mac_leakcheck.c \
+       mac_needs.c \
        mc_main.c \
        mc_clientreqs.c \
-       mc_common.c \
        mc_errcontext.c \
        mc_from_ucode.c \
        mc_translate.c \
@@ -29,10 +30,7 @@ mcinclude_HEADERS = \
        memcheck.h
 
 noinst_HEADERS =       \
-       mc_common.h     \
+       mac_shared.h    \
        mc_constants.h  \
        mc_include.h
 
-##vgskin_memcheck.so$(EXEEXT): $(vgskin_memcheck_so_OBJECTS)
-##     $(CC) $(CFLAGS) $(LDFLAGS) -shared -o vgskin_memcheck.so \
-##             $(vgskin_memcheck_so_OBJECTS)
index 41e9c57f70181f2fda9921de6825ef9b73e773fa..55e56bc892d75da560f4af7da6a8097aab40b43a 100644 (file)
@@ -138,7 +138,7 @@ Memcheck is Valgrind-1.0.X checking mechanism bundled up into a skin.
 
 
 <a name="errormsgs"></a>
-<h3>3.3&nbsp; Explaination of error messages from Memcheck</h3>
+<h3>3.3&nbsp; Explanation of error messages from Memcheck</h3>
 
 Despite considerable sophistication under the hood, Memcheck can only
 really detect two kinds of errors, use of illegal addresses, and use
@@ -146,7 +146,7 @@ of undefined values.  Nevertheless, this is enough to help you
 discover all sorts of memory-management nasties in your code.  This
 section presents a quick summary of what error messages mean.  The
 precise behaviour of the error-checking machinery is described in
-<a href="#machine">Section 4</a>.
+<a href="#machine">this section</a>.
 
 
 <h4>3.3.1&nbsp; Illegal read / Illegal write errors</h4>
diff --git a/memcheck/mac_leakcheck.c b/memcheck/mac_leakcheck.c
new file mode 100644 (file)
index 0000000..83d3ada
--- /dev/null
@@ -0,0 +1,526 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The leak checker, shared between Memcheck and Addrcheck.     ---*/
+/*---                                              mac_leakcheck.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of MemCheck, a heavyweight Valgrind skin for
+   detecting memory errors, and AddrCheck, a lightweight Valgrind skin 
+   for detecting memory errors.
+
+   Copyright (C) 2000-2002 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"
+
+/* Define to debug the memory-leak-detector. */
+/* #define VG_DEBUG_LEAKCHECK */
+
+/*------------------------------------------------------------*/
+/*--- Low-level address-space scanning, for the leak       ---*/
+/*--- detector.                                            ---*/
+/*------------------------------------------------------------*/
+
+static 
+jmp_buf memscan_jmpbuf;
+
+
+static
+void vg_scan_all_valid_memory_sighandler ( Int sigNo )
+{
+   __builtin_longjmp(memscan_jmpbuf, 1);
+}
+
+
+/* Safely (avoiding SIGSEGV / SIGBUS) scan the entire valid address
+   space and pass the addresses and values of all addressible,
+   defined, aligned words to notify_word.  This is the basis for the
+   leak detector.  Returns the number of calls made to notify_word.
+
+   Addresses are validated 3 ways.  First we enquire whether (addr >>
+   16) denotes a 64k chunk in use, by asking is_valid_64k_chunk().  If
+   so, we decide for ourselves whether each x86-level (4 K) page in
+   the chunk is safe to inspect.  If yes, we enquire with
+   is_valid_address() whether or not each of the 1024 word-locations
+   on the page is valid.  Only if so are that address and its contents
+   passed to notify_word.
+
+   This is all to avoid duplication of this machinery between the
+   memcheck and addrcheck skins.  
+*/
+static
+UInt vg_scan_all_valid_memory ( Bool is_valid_64k_chunk ( UInt ),
+                                Bool is_valid_address ( Addr ),
+                                void (*notify_word)( Addr, UInt ) )
+{
+   /* All volatile, because some gccs seem paranoid about longjmp(). */
+   volatile Bool anyValid;
+   volatile Addr pageBase, addr;
+   volatile UInt res, numPages, page, primaryMapNo;
+   volatile UInt page_first_word, nWordsNotified;
+
+   vki_ksigaction sigbus_saved;
+   vki_ksigaction sigbus_new;
+   vki_ksigaction sigsegv_saved;
+   vki_ksigaction sigsegv_new;
+   vki_ksigset_t  blockmask_saved;
+   vki_ksigset_t  unblockmask_new;
+
+   /* Temporarily install a new sigsegv and sigbus handler, and make
+      sure SIGBUS, SIGSEGV and SIGTERM are unblocked.  (Perhaps the
+      first two can never be blocked anyway?)  */
+
+   sigbus_new.ksa_handler = vg_scan_all_valid_memory_sighandler;
+   sigbus_new.ksa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
+   sigbus_new.ksa_restorer = NULL;
+   res = VG_(ksigemptyset)( &sigbus_new.ksa_mask );
+   sk_assert(res == 0);
+
+   sigsegv_new.ksa_handler = vg_scan_all_valid_memory_sighandler;
+   sigsegv_new.ksa_flags = VKI_SA_ONSTACK | VKI_SA_RESTART;
+   sigsegv_new.ksa_restorer = NULL;
+   res = VG_(ksigemptyset)( &sigsegv_new.ksa_mask );
+   sk_assert(res == 0+0);
+
+   res =  VG_(ksigemptyset)( &unblockmask_new );
+   res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGBUS );
+   res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGSEGV );
+   res |= VG_(ksigaddset)( &unblockmask_new, VKI_SIGTERM );
+   sk_assert(res == 0+0+0);
+
+   res = VG_(ksigaction)( VKI_SIGBUS, &sigbus_new, &sigbus_saved );
+   sk_assert(res == 0+0+0+0);
+
+   res = VG_(ksigaction)( VKI_SIGSEGV, &sigsegv_new, &sigsegv_saved );
+   sk_assert(res == 0+0+0+0+0);
+
+   res = VG_(ksigprocmask)( VKI_SIG_UNBLOCK, &unblockmask_new, &blockmask_saved );
+   sk_assert(res == 0+0+0+0+0+0);
+
+   /* The signal handlers are installed.  Actually do the memory scan. */
+   numPages = 1 << (32-VKI_BYTES_PER_PAGE_BITS);
+   sk_assert(numPages == 1048576);
+   sk_assert(4096 == (1 << VKI_BYTES_PER_PAGE_BITS));
+
+   nWordsNotified = 0;
+
+   for (page = 0; page < numPages; page++) {
+
+      /* Base address of this 4k page. */
+      pageBase = page << VKI_BYTES_PER_PAGE_BITS;
+
+      /* Skip if this page is in an unused 64k chunk. */
+      primaryMapNo = pageBase >> 16;
+      if (!is_valid_64k_chunk(primaryMapNo))
+         continue;
+
+      /* Next, establish whether or not we want to consider any
+         locations on this page.  We need to do so before actually
+         prodding it, because prodding it when in fact it is not
+         needed can cause a page fault which under some rare
+         circumstances can cause the kernel to extend the stack
+         segment all the way down to here, which is seriously bad.
+         Hence: */
+      anyValid = False;
+      for (addr = pageBase; addr < pageBase+VKI_BYTES_PER_PAGE; addr += 4) {
+         if (is_valid_address(addr)) {
+            anyValid = True;
+            break;
+         }
+      }
+
+      if (!anyValid)
+         continue;  /* nothing interesting here .. move to the next page */
+
+      /* Ok, we have to prod cautiously at the page and see if it
+         explodes or not. */
+      if (__builtin_setjmp(memscan_jmpbuf) == 0) {
+         /* try this ... */
+         page_first_word = * (volatile UInt*)pageBase;
+         /* we get here if we didn't get a fault */
+         /* Scan the page */
+         for (addr = pageBase; addr < pageBase+VKI_BYTES_PER_PAGE; addr += 4) {
+            if (is_valid_address(addr)) {
+               nWordsNotified++;
+               notify_word ( addr, *(UInt*)addr );
+           }
+         }
+      } else {
+         /* We get here if reading the first word of the page caused a
+            fault, which in turn caused the signal handler to longjmp.
+            Ignore this page. */
+         if (0)
+         VG_(printf)(
+            "vg_scan_all_valid_memory_sighandler: ignoring page at %p\n",
+            (void*)pageBase 
+         );
+      }
+   }
+
+   /* Restore signal state to whatever it was before. */
+   res = VG_(ksigaction)( VKI_SIGBUS, &sigbus_saved, NULL );
+   sk_assert(res == 0 +0);
+
+   res = VG_(ksigaction)( VKI_SIGSEGV, &sigsegv_saved, NULL );
+   sk_assert(res == 0 +0 +0);
+
+   res = VG_(ksigprocmask)( VKI_SIG_SETMASK, &blockmask_saved, NULL );
+   sk_assert(res == 0 +0 +0 +0);
+
+   return nWordsNotified;
+}
+
+/*------------------------------------------------------------*/
+/*--- Detecting leaked (unreachable) malloc'd blocks.      ---*/
+/*------------------------------------------------------------*/
+
+/* A block is either 
+   -- Proper-ly reached; a pointer to its start has been found
+   -- Interior-ly reached; only an interior pointer to it has been found
+   -- Unreached; so far, no pointers to any part of it have been found. 
+*/
+typedef 
+   enum { Unreached, Interior, Proper } 
+   Reachedness;
+
+/* A block record, used for generating err msgs. */
+typedef
+   struct _LossRecord {
+      struct _LossRecord* next;
+      /* Where these lost blocks were allocated. */
+      ExeContext*  allocated_at;
+      /* Their reachability. */
+      Reachedness  loss_mode;
+      /* Number of blocks and total # bytes involved. */
+      UInt         total_bytes;
+      UInt         num_blocks;
+   }
+   LossRecord;
+
+
+/* Find the i such that ptr points at or inside the block described by
+   shadows[i].  Return -1 if none found.  This assumes that shadows[]
+   has been sorted on the ->data field. */
+
+#ifdef VG_DEBUG_LEAKCHECK
+/* Used to sanity-check the fast binary-search mechanism. */
+static 
+Int find_shadow_for_OLD ( Addr          ptr, 
+                          ShadowChunk** shadows,
+                          Int           n_shadows )
+
+{
+   Int  i;
+   Addr a_lo, a_hi;
+   PROF_EVENT(70);
+   for (i = 0; i < n_shadows; i++) {
+      PROF_EVENT(71);
+      a_lo = shadows[i]->data;
+      a_hi = ((Addr)shadows[i]->data) + shadows[i]->size - 1;
+      if (a_lo <= ptr && ptr <= a_hi)
+         return i;
+   }
+   return -1;
+}
+#endif
+
+
+static 
+Int find_shadow_for ( Addr          ptr, 
+                      ShadowChunk** shadows,
+                      Int           n_shadows )
+{
+   Addr a_mid_lo, a_mid_hi;
+   Int lo, mid, hi, retVal;
+   /* VG_(printf)("find shadow for %p = ", ptr); */
+   retVal = -1;
+   lo = 0;
+   hi = n_shadows-1;
+   while (True) {
+      /* invariant: current unsearched space is from lo to hi,
+         inclusive. */
+      if (lo > hi) break; /* not found */
+
+      mid      = (lo + hi) / 2;
+      a_mid_lo = VG_(get_sc_data)(shadows[mid]);
+      a_mid_hi = VG_(get_sc_data)(shadows[mid]) + 
+                 VG_(get_sc_size)(shadows[mid]) - 1;
+
+      if (ptr < a_mid_lo) {
+         hi = mid-1;
+         continue;
+      } 
+      if (ptr > a_mid_hi) {
+         lo = mid+1;
+         continue;
+      }
+      sk_assert(ptr >= a_mid_lo && ptr <= a_mid_hi);
+      retVal = mid;
+      break;
+   }
+
+#  ifdef VG_DEBUG_LEAKCHECK
+   sk_assert(retVal == find_shadow_for_OLD ( ptr, shadows, n_shadows ));
+#  endif
+   /* VG_(printf)("%d\n", retVal); */
+   return retVal;
+}
+
+/* Globals, for the following callback used by VG_(detect_memory_leaks). */
+static ShadowChunk**  vglc_shadows;
+static Int            vglc_n_shadows;
+static Reachedness*   vglc_reachedness;
+static Addr           vglc_min_mallocd_addr;
+static Addr           vglc_max_mallocd_addr;
+
+static 
+void vg_detect_memory_leaks_notify_addr ( Addr a, UInt word_at_a )
+{
+   Int  sh_no;
+   Addr ptr;
+
+   /* Rule out some known causes of bogus pointers.  Mostly these do
+      not cause much trouble because only a few false pointers can
+      ever lurk in these places.  This mainly stops it reporting that
+      blocks are still reachable in stupid test programs like this
+
+         int main (void) { char* a = malloc(100); return 0; }
+
+      which people seem inordinately fond of writing, for some reason.  
+
+      Note that this is a complete kludge.  It would be better to
+      ignore any addresses corresponding to valgrind.so's .bss and
+      .data segments, but I cannot think of a reliable way to identify
+      where the .bss segment has been put.  If you can, drop me a
+      line.  
+   */
+   if (VG_(within_stack)(a))                return;
+   if (VG_(within_m_state_static)(a))       return;
+   if (a == (Addr)(&vglc_min_mallocd_addr)) return;
+   if (a == (Addr)(&vglc_max_mallocd_addr)) return;
+
+   /* OK, let's get on and do something Useful for a change. */
+
+   ptr = (Addr)word_at_a;
+   if (ptr >= vglc_min_mallocd_addr && ptr <= vglc_max_mallocd_addr) {
+      /* Might be legitimate; we'll have to investigate further. */
+      sh_no = find_shadow_for ( ptr, vglc_shadows, vglc_n_shadows );
+      if (sh_no != -1) {
+         /* Found a block at/into which ptr points. */
+         sk_assert(sh_no >= 0 && sh_no < vglc_n_shadows);
+         sk_assert(ptr < VG_(get_sc_data)(vglc_shadows[sh_no])
+                       + VG_(get_sc_size)(vglc_shadows[sh_no]));
+         /* Decide whether Proper-ly or Interior-ly reached. */
+         if (ptr == VG_(get_sc_data)(vglc_shadows[sh_no])) {
+            if (0) VG_(printf)("pointer at %p to %p\n", a, word_at_a );
+            vglc_reachedness[sh_no] = Proper;
+         } else {
+            if (vglc_reachedness[sh_no] == Unreached)
+               vglc_reachedness[sh_no] = Interior;
+         }
+      }
+   }
+}
+
+/* Used for printing leak errors, avoids exposing the LossRecord type (which
+   comes in as void*, requiring a cast. */
+void MAC_(pp_LeakError)(void* vl, UInt n_this_record, UInt n_total_records)
+{
+   LossRecord* l = (LossRecord*)vl;
+
+   VG_(message)(Vg_UserMsg, "");
+   VG_(message)(Vg_UserMsg, 
+                "%d bytes in %d blocks are %s in loss record %d of %d",
+                l->total_bytes, l->num_blocks,
+                l->loss_mode==Unreached ?    "definitely lost"
+                 : (l->loss_mode==Interior ? "possibly lost"
+                                           : "still reachable"),
+                n_this_record, n_total_records
+   );
+   VG_(pp_ExeContext)(l->allocated_at);
+}
+
+/* Top level entry point to leak detector.  Call here, passing in
+   suitable address-validating functions (see comment at top of
+   vg_scan_all_valid_memory above).  All this is to avoid duplication
+   of the leak-detection code for the Memcheck and Addrcheck skins.
+   Also pass in a skin-specific function to extract the .where field
+   for allocated blocks, an indication of the resolution wanted for
+   distinguishing different allocation points, and whether or not
+   reachable blocks should be shown.
+*/
+void MAC_(do_detect_memory_leaks) (
+   Bool is_valid_64k_chunk ( UInt ),
+   Bool is_valid_address ( Addr )
+)
+{
+   Int    i;
+   Int    blocks_leaked, bytes_leaked;
+   Int    blocks_dubious, bytes_dubious;
+   Int    blocks_reachable, bytes_reachable;
+   Int    blocks_suppressed, bytes_suppressed;
+   Int    n_lossrecords;
+   UInt   bytes_notified;
+   Bool   is_suppressed;
+   
+   LossRecord* errlist;
+   LossRecord* p;
+
+   /* VG_(get_malloc_shadows) allocates storage for shadows */
+   vglc_shadows = VG_(get_malloc_shadows)( &vglc_n_shadows );
+   if (vglc_n_shadows == 0) {
+      sk_assert(vglc_shadows == NULL);
+      VG_(message)(Vg_UserMsg, 
+                   "No malloc'd blocks -- no leaks are possible.");
+      return;
+   }
+
+   VG_(message)(Vg_UserMsg, "searching for pointers to %d not-freed blocks.", 
+                vglc_n_shadows );
+
+   vglc_min_mallocd_addr = VG_(get_sc_data)(vglc_shadows[0]);
+   vglc_max_mallocd_addr = VG_(get_sc_data)(vglc_shadows[vglc_n_shadows-1])
+                         + VG_(get_sc_size)(vglc_shadows[vglc_n_shadows-1]) - 1;
+
+   vglc_reachedness = VG_(malloc)( vglc_n_shadows * sizeof(Reachedness) );
+   for (i = 0; i < vglc_n_shadows; i++)
+      vglc_reachedness[i] = Unreached;
+
+   /* Do the scan of memory. */
+   bytes_notified
+       = VKI_BYTES_PER_WORD
+         * vg_scan_all_valid_memory (
+              is_valid_64k_chunk,
+              is_valid_address,
+              &vg_detect_memory_leaks_notify_addr
+           );
+
+   VG_(message)(Vg_UserMsg, "checked %d bytes.", bytes_notified);
+
+   /* Common up the lost blocks so we can print sensible error messages. */
+   n_lossrecords = 0;
+   errlist       = NULL;
+   for (i = 0; i < vglc_n_shadows; i++) {
+     
+      ExeContext* where = MAC_(get_where) ( vglc_shadows[i] );
+      
+      for (p = errlist; p != NULL; p = p->next) {
+         if (p->loss_mode == vglc_reachedness[i]
+             && VG_(eq_ExeContext) ( MAC_(clo_leak_resolution),
+                                     p->allocated_at, 
+                                     where) ) {
+            break;
+        }
+      }
+      if (p != NULL) {
+         p->num_blocks  ++;
+         p->total_bytes += VG_(get_sc_size)(vglc_shadows[i]);
+      } else {
+         n_lossrecords ++;
+         p = VG_(malloc)(sizeof(LossRecord));
+         p->loss_mode    = vglc_reachedness[i];
+         p->allocated_at = where;
+         p->total_bytes  = VG_(get_sc_size)(vglc_shadows[i]);
+         p->num_blocks   = 1;
+         p->next         = errlist;
+         errlist         = p;
+      }
+   }
+
+   /* Print out the commoned-up blocks and collect summary stats. */
+   blocks_leaked     = bytes_leaked     = 0;
+   blocks_dubious    = bytes_dubious    = 0;
+   blocks_reachable  = bytes_reachable  = 0;
+   blocks_suppressed = bytes_suppressed = 0;
+
+   for (i = 0; i < n_lossrecords; i++) {
+      Bool        print_record;
+      LossRecord* p_min = NULL;
+      UInt        n_min = 0xFFFFFFFF;
+      for (p = errlist; p != NULL; p = p->next) {
+         if (p->num_blocks > 0 && p->total_bytes < n_min) {
+            n_min = p->total_bytes;
+            p_min = p;
+         }
+      }
+      sk_assert(p_min != NULL);
+
+      /* Ok to have tst==NULL;  it's only used if --gdb-attach=yes, and
+         we disallow that when --leak-check=yes.  
+         
+         Prints the error if not suppressed, unless it's reachable (Proper)
+         and --show-reachable=no */
+
+      print_record = ( MAC_(clo_show_reachable) || Proper != p_min->loss_mode );
+      is_suppressed = 
+         VG_(unique_error) ( /*tst*/NULL, LeakErr, (UInt)i+1,
+                             (Char*)n_lossrecords, (void*) p_min,
+                             p_min->allocated_at, print_record );
+
+      if (is_suppressed) {
+         blocks_suppressed += p_min->num_blocks;
+         bytes_suppressed  += p_min->total_bytes;
+
+      } else if (Unreached == p_min->loss_mode) {
+         blocks_leaked     += p_min->num_blocks;
+         bytes_leaked      += p_min->total_bytes;
+
+      } else if (Interior  == p_min->loss_mode) {
+         blocks_dubious    += p_min->num_blocks;
+         bytes_dubious     += p_min->total_bytes;
+
+      } else if (Proper    == p_min->loss_mode) {
+         blocks_reachable  += p_min->num_blocks;
+         bytes_reachable   += p_min->total_bytes;
+
+      } else {
+         VG_(skin_panic)("generic_detect_memory_leaks: unknown loss mode");
+      }
+      p_min->num_blocks = 0;
+   }
+
+   VG_(message)(Vg_UserMsg, "");
+   VG_(message)(Vg_UserMsg, "LEAK SUMMARY:");
+   VG_(message)(Vg_UserMsg, "   definitely lost: %d bytes in %d blocks.", 
+                            bytes_leaked, blocks_leaked );
+   VG_(message)(Vg_UserMsg, "   possibly lost:   %d bytes in %d blocks.", 
+                            bytes_dubious, blocks_dubious );
+   VG_(message)(Vg_UserMsg, "   still reachable: %d bytes in %d blocks.", 
+                            bytes_reachable, blocks_reachable );
+   VG_(message)(Vg_UserMsg, "        suppressed: %d bytes in %d blocks.", 
+                            bytes_suppressed, blocks_suppressed );
+   if (!MAC_(clo_show_reachable)) {
+      VG_(message)(Vg_UserMsg, 
+        "Reachable blocks (those to which a pointer was found) are not shown.");
+      VG_(message)(Vg_UserMsg, 
+         "To see them, rerun with: --show-reachable=yes");
+   }
+   VG_(message)(Vg_UserMsg, "");
+
+   VG_(free) ( vglc_shadows );
+   VG_(free) ( vglc_reachedness );
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                          mac_leakcheck.c ---*/
+/*--------------------------------------------------------------------*/
+
similarity index 62%
rename from memcheck/mc_common.c
rename to memcheck/mac_needs.c
index deedf8e494f5319e95d041563d07c38b71e61774..ad6b2f66520da1215d1b69cff942c9e86bd6c59f 100644 (file)
@@ -1,7 +1,7 @@
 
 /*--------------------------------------------------------------------*/
 /*--- Code that is shared between MemCheck and AddrCheck.          ---*/
-/*---                                                  mc_common.c ---*/
+/*---                                                  mac_needs.c ---*/
 /*--------------------------------------------------------------------*/
 
 /*
@@ -31,7 +31,7 @@
 */
 
 
-#include "mc_common.h"
+#include "mac_shared.h"
 
 /*------------------------------------------------------------*/
 /*--- Defns                                                ---*/
 /*--- Command line options                                 ---*/
 /*------------------------------------------------------------*/
 
-Bool  MC_(clo_partial_loads_ok)       = True;
-Int   MC_(clo_freelist_vol)           = 1000000;
-Bool  MC_(clo_leak_check)             = False;
-VgRes MC_(clo_leak_resolution)        = Vg_LowRes;
-Bool  MC_(clo_show_reachable)         = False;
-Bool  MC_(clo_workaround_gcc296_bugs) = False;
-Bool  MC_(clo_cleanup)                = True;
-Bool  MC_(clo_avoid_strlen_errors)    = True;
+Bool  MAC_(clo_partial_loads_ok)       = True;
+Int   MAC_(clo_freelist_vol)           = 1000000;
+Bool  MAC_(clo_leak_check)             = False;
+VgRes MAC_(clo_leak_resolution)        = Vg_LowRes;
+Bool  MAC_(clo_show_reachable)         = False;
+Bool  MAC_(clo_workaround_gcc296_bugs) = False;
 
-Bool MC_(process_common_cmd_line_option)(Char* arg)
+Bool MAC_(process_common_cmd_line_option)(Char* arg)
 {
-#  define STREQ(s1,s2)     (0==VG_(strcmp_ws)((s1),(s2)))
-#  define STREQN(nn,s1,s2) (0==VG_(strncmp_ws)((s1),(s2),(nn)))
-
-   if      (STREQ(arg, "--partial-loads-ok=yes"))
-      MC_(clo_partial_loads_ok) = True;
-   else if (STREQ(arg, "--partial-loads-ok=no"))
-      MC_(clo_partial_loads_ok) = False;
-
-   else if (STREQN(15, arg, "--freelist-vol=")) {
-      MC_(clo_freelist_vol) = (Int)VG_(atoll)(&arg[15]);
-      if (MC_(clo_freelist_vol) < 0) MC_(clo_freelist_vol) = 0;
+   if      (VG_CLO_STREQ(arg, "--partial-loads-ok=yes"))
+      MAC_(clo_partial_loads_ok) = True;
+   else if (VG_CLO_STREQ(arg, "--partial-loads-ok=no"))
+      MAC_(clo_partial_loads_ok) = False;
+
+   else if (VG_CLO_STREQN(15, arg, "--freelist-vol=")) {
+      MAC_(clo_freelist_vol) = (Int)VG_(atoll)(&arg[15]);
+      if (MAC_(clo_freelist_vol) < 0) MAC_(clo_freelist_vol) = 0;
    }
 
-   else if (STREQ(arg, "--leak-check=yes"))
-      MC_(clo_leak_check) = True;
-   else if (STREQ(arg, "--leak-check=no"))
-      MC_(clo_leak_check) = False;
-
-   else if (STREQ(arg, "--leak-resolution=low"))
-      MC_(clo_leak_resolution) = Vg_LowRes;
-   else if (STREQ(arg, "--leak-resolution=med"))
-      MC_(clo_leak_resolution) = Vg_MedRes;
-   else if (STREQ(arg, "--leak-resolution=high"))
-      MC_(clo_leak_resolution) = Vg_HighRes;
+   else if (VG_CLO_STREQ(arg, "--leak-check=yes"))
+      MAC_(clo_leak_check) = True;
+   else if (VG_CLO_STREQ(arg, "--leak-check=no"))
+      MAC_(clo_leak_check) = False;
+
+   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 if (STREQ(arg, "--show-reachable=yes"))
-      MC_(clo_show_reachable) = True;
-   else if (STREQ(arg, "--show-reachable=no"))
-      MC_(clo_show_reachable) = False;
-
-   else if (STREQ(arg, "--workaround-gcc296-bugs=yes"))
-      MC_(clo_workaround_gcc296_bugs) = True;
-   else if (STREQ(arg, "--workaround-gcc296-bugs=no"))
-      MC_(clo_workaround_gcc296_bugs) = False;
+   else if (VG_CLO_STREQ(arg, "--show-reachable=yes"))
+      MAC_(clo_show_reachable) = True;
+   else if (VG_CLO_STREQ(arg, "--show-reachable=no"))
+      MAC_(clo_show_reachable) = False;
 
-   else if (STREQ(arg, "--cleanup=yes"))
-      MC_(clo_cleanup) = True;
-   else if (STREQ(arg, "--cleanup=no"))
-      MC_(clo_cleanup) = False;
+   else if (VG_CLO_STREQ(arg, "--workaround-gcc296-bugs=yes"))
+      MAC_(clo_workaround_gcc296_bugs) = True;
+   else if (VG_CLO_STREQ(arg, "--workaround-gcc296-bugs=no"))
+      MAC_(clo_workaround_gcc296_bugs) = False;
 
    else
       return False;
 
    return True;
+}
+
+/*------------------------------------------------------------*/
+/*--- Shadow chunks info                                   ---*/
+/*------------------------------------------------------------*/
+
+void MAC_(set_where)( ShadowChunk* sc, ExeContext* ec )
+{
+   VG_(set_sc_extra)( sc, 0, (UInt)ec );
+}
 
-#undef STREQ
-#undef STREQN
+ExeContext *MAC_(get_where)( ShadowChunk* sc )
+{
+   return (ExeContext*)VG_(get_sc_extra)(sc, 0);
+}
+
+void SK_(complete_shadow_chunk) ( ShadowChunk* sc, ThreadState* tst )
+{
+   VG_(set_sc_extra) ( sc, 0, (UInt)VG_(get_ExeContext)(tst) );
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Postponing free()ing                                 ---*/
+/*------------------------------------------------------------*/
+
+/* Holds blocks after freeing. */
+static ShadowChunk* freed_list_start  = NULL;
+static ShadowChunk* freed_list_end    = NULL;
+static Int          freed_list_volume = 0;
+
+__attribute__ ((unused))
+Int MAC_(count_freelist) ( void )
+{
+   ShadowChunk* sc;
+   Int n = 0;
+   for (sc = freed_list_start; sc != NULL; sc = VG_(get_sc_next)(sc))
+      n++;
+   return n;
+}
+
+__attribute__ ((unused))
+void MAC_(freelist_sanity) ( void )
+{
+   ShadowChunk* sc;
+   Int n = 0;
+   /* VG_(printf)("freelist sanity\n"); */
+   for (sc = freed_list_start; sc != NULL; sc = VG_(get_sc_next)(sc))
+      n += VG_(get_sc_size)(sc);
+   sk_assert(n == freed_list_volume);
+}
+
+/* Put a shadow chunk on the freed blocks queue, possibly freeing up
+   some of the oldest blocks in the queue at the same time. */
+static void add_to_freed_queue ( ShadowChunk* sc )
+{
+   ShadowChunk* sc1;
+
+   /* Put it at the end of the freed list */
+   if (freed_list_end == NULL) {
+      sk_assert(freed_list_start == NULL);
+      freed_list_end = freed_list_start = sc;
+      freed_list_volume = VG_(get_sc_size)(sc);
+   } else {    
+      sk_assert(VG_(get_sc_next)(freed_list_end) == NULL);
+      VG_(set_sc_next)(freed_list_end, sc);
+      freed_list_end = sc;
+      freed_list_volume += VG_(get_sc_size)(sc);
+   }
+   VG_(set_sc_next)(sc, NULL);
+
+   /* Release enough of the oldest blocks to bring the free queue
+      volume below vg_clo_freelist_vol. */
+   
+   while (freed_list_volume > MAC_(clo_freelist_vol)) {
+      /* freelist_sanity(); */
+      sk_assert(freed_list_start != NULL);
+      sk_assert(freed_list_end != NULL);
+
+      sc1 = freed_list_start;
+      freed_list_volume -= VG_(get_sc_size)(sc1);
+      /* VG_(printf)("volume now %d\n", freed_list_volume); */
+      sk_assert(freed_list_volume >= 0);
+
+      if (freed_list_start == freed_list_end) {
+         freed_list_start = freed_list_end = NULL;
+      } else {
+         freed_list_start = VG_(get_sc_next)(sc1);
+      }
+      VG_(set_sc_next)(sc1, NULL); /* just paranoia */
+      VG_(free_ShadowChunk) ( sc1 );
+   }
+}
+
+void SK_(alt_free) ( ShadowChunk* sc, ThreadState* tst )
+{
+   /* Record where freed */
+   MAC_(set_where)( sc, VG_(get_ExeContext) ( tst ) );
+
+   /* Put it out of harm's way for a while. */
+   add_to_freed_queue ( sc );
 }
 
 /*------------------------------------------------------------*/
@@ -120,7 +208,7 @@ void clear_AddrInfo ( AddrInfo* ai )
    ai->maybe_gcc  = False;
 }
 
-void MC_(clear_MemCheckError) ( MemCheckError* err_extra )
+void MAC_(clear_MAC_Error) ( MAC_Error* err_extra )
 {
    err_extra->axskind   = ReadAxs;
    err_extra->size      = 0;
@@ -150,8 +238,8 @@ static Bool eq_AddrInfo ( VgRes res, AddrInfo* ai1, AddrInfo* ai2 )
 
 Bool SK_(eq_SkinError) ( VgRes res, Error* e1, Error* e2 )
 {
-   MemCheckError* e1_extra = VG_(get_error_extra)(e1);
-   MemCheckError* e2_extra = VG_(get_error_extra)(e2);
+   MAC_Error* e1_extra = VG_(get_error_extra)(e1);
+   MAC_Error* e2_extra = VG_(get_error_extra)(e2);
 
    /* Guaranteed by calling function */
    sk_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
@@ -200,6 +288,10 @@ Bool SK_(eq_SkinError) ( VgRes res, Error* e1, Error* e2 )
          if (e1_extra->size != e2_extra->size) return False;
          return True;
 
+      case LeakErr:
+         VG_(skin_panic)("Shouldn't get LeakErr in SK_(eq_SkinError),\n"
+                         "since it's handled with VG_(unique_error)()!");
+
       default: 
          VG_(printf)("Error:\n  unknown error code %d\n",
                      VG_(get_error_kind)(e1));
@@ -207,7 +299,7 @@ Bool SK_(eq_SkinError) ( VgRes res, Error* e1, Error* e2 )
    }
 }
 
-void MC_(pp_AddrInfo) ( Addr a, AddrInfo* ai )
+void MAC_(pp_AddrInfo) ( Addr a, AddrInfo* ai )
 {
    switch (ai->akind) {
       case Stack: 
@@ -251,7 +343,41 @@ void MC_(pp_AddrInfo) ( Addr a, AddrInfo* ai )
          break;
       }
       default:
-         VG_(skin_panic)("MC_(pp_AddrInfo)");
+         VG_(skin_panic)("MAC_(pp_AddrInfo)");
+   }
+}
+
+/* This prints out the message for the error types where Memcheck and
+   Addrcheck have identical messages */
+void MAC_(pp_shared_SkinError) ( 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 LeakErr: {
+         /* Totally abusing the types of these spare fields... oh well. */
+         UInt n_this_record   = (UInt)VG_(get_error_address)(err);
+         UInt n_total_records = (UInt)VG_(get_error_string) (err);
+
+         MAC_(pp_LeakError)(err_extra, n_this_record, n_total_records);
+         break;
+      }
+
+      default: 
+         VG_(printf)("Error:\n  unknown Memcheck/Addrcheck error code %d\n",
+                     VG_(get_error_kind)(err));
+         VG_(skin_panic)("unknown error code in MAC_(pp_shared_SkinError)");
    }
 }
 
@@ -259,6 +385,81 @@ void MC_(pp_AddrInfo) ( Addr a, AddrInfo* ai )
 /*--- 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;
+   
+/* Return the first shadow chunk satisfying the predicate p. */
+static ShadowChunk* first_matching_freed_ShadowChunk ( Bool (*p)(ShadowChunk*) )
+{
+   ShadowChunk* sc;
+
+   /* No point looking through freed blocks if we're not keeping
+      them around for a while... */
+   for (sc = freed_list_start; sc != NULL; sc = VG_(get_sc_next)(sc))
+      if (p(sc))
+         return sc;
+
+   return NULL;
+}
+
+/* Describe an address as best you can, for error messages,
+   putting the result in ai. */
+static void describe_addr ( Addr a, AddrInfo* ai )
+{
+   ShadowChunk* sc;
+   ThreadId     tid;
+
+   /* Nested functions, yeah.  Need the lexical scoping of 'a'. */
+   
+   /* Closure for searching thread stacks */
+   Bool addr_is_in_bounds(Addr stack_min, Addr stack_max)
+   {
+      return (stack_min <= a && a <= stack_max);
+   }
+   /* Closure for searching malloc'd and free'd lists */
+   Bool addr_is_in_block(ShadowChunk *sh_ch)
+   {
+      return VG_(addr_is_in_block) ( a, VG_(get_sc_data)(sh_ch),
+                                        VG_(get_sc_size)(sh_ch) );
+   }
+
+   /* 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);
+   if (tid != VG_INVALID_THREADID) {
+      ai->akind     = Stack;
+      ai->stack_tid = tid;
+      return;
+   }
+   /* Search for a recently freed block which might bracket it. */
+   sc = first_matching_freed_ShadowChunk(addr_is_in_block);
+   if (NULL != sc) { 
+      ai->akind      = Freed;
+      ai->blksize    = VG_(get_sc_size)(sc);
+      ai->rwoffset   = (Int)a - (Int)VG_(get_sc_data)(sc);
+      ai->lastchange = MAC_(get_where)(sc);
+      return;
+   }
+   /* Search for a currently malloc'd block which might bracket it. */
+   sc = VG_(first_matching_mallocd_ShadowChunk)(addr_is_in_block);
+   if (NULL != sc) {
+      ai->akind      = Mallocd;
+      ai->blksize    = VG_(get_sc_size)(sc);
+      ai->rwoffset   = (Int)a - (Int)VG_(get_sc_data)(sc);
+      ai->lastchange = MAC_(get_where)(sc);
+      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 )
@@ -272,19 +473,19 @@ static Bool is_just_below_ESP( Addr esp, Addr aa )
 
 /* This one called from generated code. */
 
-void MC_(record_address_error) ( Addr a, Int size, Bool isWrite )
+void MAC_(record_address_error) ( Addr a, Int size, Bool isWrite )
 {
-   MemCheckError err_extra;
-   Bool          just_below_esp;
+   MAC_Error err_extra;
+   Bool      just_below_esp;
 
    just_below_esp = is_just_below_ESP( VG_(get_stack_pointer)(), a );
 
    /* If this is caused by an access immediately below %ESP, and the
       user asks nicely, we just ignore it. */
-   if (MC_(clo_workaround_gcc296_bugs) && just_below_esp)
+   if (MAC_(clo_workaround_gcc296_bugs) && just_below_esp)
       return;
 
-   MC_(clear_MemCheckError)( &err_extra );
+   MAC_(clear_MAC_Error)( &err_extra );
    err_extra.axskind = isWrite ? WriteAxs : ReadAxs;
    err_extra.size    = size;
    err_extra.addrinfo.akind     = Undescribed;
@@ -296,65 +497,104 @@ void MC_(record_address_error) ( Addr a, Int size, Bool isWrite )
 
 /* This is for memory errors in pthread functions, as opposed to pthread API
    errors which are found by the core. */
-void MC_(record_core_mem_error) ( ThreadState* tst, Bool isWrite, Char* msg )
+void MAC_(record_core_mem_error) ( ThreadState* tst, Bool isWrite, Char* msg )
 {
-   MemCheckError err_extra;
+   MAC_Error err_extra;
 
-   MC_(clear_MemCheckError)( &err_extra );
+   MAC_(clear_MAC_Error)( &err_extra );
    err_extra.isWrite = isWrite;
    VG_(maybe_record_error)( tst, CoreMemErr, /*addr*/0, msg, &err_extra );
 }
 
-void MC_(record_param_error) ( ThreadState* tst, Addr a, Bool isWrite, 
+void MAC_(record_param_error) ( ThreadState* tst, Addr a, Bool isWrite, 
                                Char* msg )
 {
-   MemCheckError err_extra;
+   MAC_Error err_extra;
 
    sk_assert(NULL != tst);
-   MC_(clear_MemCheckError)( &err_extra );
+   MAC_(clear_MAC_Error)( &err_extra );
    err_extra.addrinfo.akind = Undescribed;
    err_extra.isWrite = isWrite;
    VG_(maybe_record_error)( tst, ParamErr, a, msg, &err_extra );
 }
 
-void MC_(record_jump_error) ( ThreadState* tst, Addr a )
+void MAC_(record_jump_error) ( ThreadState* tst, Addr a )
 {
-   MemCheckError err_extra;
+   MAC_Error err_extra;
 
    sk_assert(NULL != tst);
 
-   MC_(clear_MemCheckError)( &err_extra );
+   MAC_(clear_MAC_Error)( &err_extra );
    err_extra.axskind = ExecAxs;
    err_extra.addrinfo.akind = Undescribed;
    VG_(maybe_record_error)( tst, AddrErr, a, /*s*/NULL, &err_extra );
 }
 
-void MC_(record_free_error) ( ThreadState* tst, Addr a ) 
+void MAC_(record_free_error) ( ThreadState* tst, Addr a ) 
 {
-   MemCheckError err_extra;
+   MAC_Error err_extra;
 
    sk_assert(NULL != tst);
 
-   MC_(clear_MemCheckError)( &err_extra );
+   MAC_(clear_MAC_Error)( &err_extra );
    err_extra.addrinfo.akind = Undescribed;
    VG_(maybe_record_error)( tst, FreeErr, a, /*s*/NULL, &err_extra );
 }
 
-void MC_(record_freemismatch_error) ( ThreadState* tst, Addr a )
+void MAC_(record_freemismatch_error) ( ThreadState* tst, Addr a )
 {
-   MemCheckError err_extra;
+   MAC_Error err_extra;
 
    sk_assert(NULL != tst);
 
-   MC_(clear_MemCheckError)( &err_extra );
+   MAC_(clear_MAC_Error)( &err_extra );
    err_extra.addrinfo.akind = Undescribed;
    VG_(maybe_record_error)( tst, FreeMismatchErr, a, /*s*/NULL, &err_extra );
 }
 
+/* Updates the copy with address info if necessary (but not for LeakErrs). */
+UInt SK_(update_extra)( Error* err )
+{
+   MAC_Error* extra;
+
+   /* Don't need to return the correct size -- LeakErrs are always shown with
+      VG_(unique_error)() so they're not copied anyway. */
+   if (LeakErr == VG_(get_error_kind)(err))
+      return 0;
+
+   extra = (MAC_Error*)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);
+}
+
+
 /*------------------------------------------------------------*/
 /*--- 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, "Free"))    skind = FreeSupp;
+   else if (VG_STREQ(name, "Leak"))    skind = LeakSupp;
+   else
+      return False;
+
+   VG_(set_supp_kind)(su, skind);
+   return True;
+}
+
 Bool SK_(read_extra_suppression_info) ( Int fd, Char* buf, Int nBuf, Supp *su )
 {
    Bool eof;
@@ -367,23 +607,22 @@ Bool SK_(read_extra_suppression_info) ( Int fd, Char* buf, Int nBuf, Supp *su )
    return True;
 }
 
-#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
-                      && VG_(strcmp)((s1),(s2))==0)
-
 Bool SK_(error_matches_suppression)(Error* err, Supp* su)
 {
-   UInt su_size;
-   MemCheckError* err_extra = VG_(get_error_extra)(err);
-   ErrorKind      ekind     = VG_(get_error_kind )(err);
+   UInt       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 
-              && STREQ(VG_(get_error_string)(err), VG_(get_supp_string)(su)));
+              && VG_STREQ(VG_(get_error_string)(err), 
+                          VG_(get_supp_string)(su)));
 
       case CoreMemSupp:
          return (ekind == CoreMemErr
-              && STREQ(VG_(get_error_string)(err), VG_(get_supp_string)(su)));
+              && 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;
@@ -404,7 +643,7 @@ Bool SK_(error_matches_suppression)(Error* err, Supp* su)
          return (ekind == FreeErr || ekind == FreeMismatchErr);
 
       case LeakSupp:
-         return False; /* Doesn't match any normal error */
+         return (ekind == LeakErr);
 
       default:
          VG_(printf)("Error:\n"
@@ -415,7 +654,45 @@ Bool SK_(error_matches_suppression)(Error* err, Supp* su)
    }
 }
 
-#  undef STREQ
+Char* SK_(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 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";
+      default:              VG_(skin_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";
+      default:              VG_(skin_panic)("unexpected size for Value");
+      }
+   case CoreMemErr:         return "CoreMem";
+   case LeakErr:            return "Leak";
+   default:                 VG_(skin_panic)("get_error_name: unexpected type");
+   }
+   VG_(printf)(s);
+}
+
+void SK_(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.                           ---*/
@@ -517,151 +794,36 @@ M  89   fpu_write 10/28/108
    125  die_mem_stack
 */
 
-#ifdef VG_PROFILE_MEMORY
+#ifdef MAC_PROFILE_MEMORY
 
-UInt MC_(event_ctr)[N_PROF_EVENTS];
+UInt MAC_(event_ctr)[N_PROF_EVENTS];
 
-void MC_(init_prof_mem) ( void )
+void MAC_(init_prof_mem) ( void )
 {
    Int i;
    for (i = 0; i < N_PROF_EVENTS; i++)
-      MC_(event_ctr)[i] = 0;
+      MAC_(event_ctr)[i] = 0;
 }
 
-void MC_(done_prof_mem) ( void )
+void MAC_(done_prof_mem) ( void )
 {
    Int i;
    for (i = 0; i < N_PROF_EVENTS; i++) {
       if ((i % 10) == 0) 
          VG_(printf)("\n");
-      if (MC_(event_ctr)[i] > 0)
-         VG_(printf)( "prof mem event %2d: %d\n", i, MC_(event_ctr)[i] );
+      if (MAC_(event_ctr)[i] > 0)
+         VG_(printf)( "prof mem event %2d: %d\n", i, MAC_(event_ctr)[i] );
    }
    VG_(printf)("\n");
 }
 
 #else
 
-void MC_(init_prof_mem) ( void ) { }
-void MC_(done_prof_mem) ( void ) { }
+void MAC_(init_prof_mem) ( void ) { }
+void MAC_(done_prof_mem) ( void ) { }
 
 #endif
 
-/*------------------------------------------------------------*/
-/*--- Shadow chunks info                                   ---*/
-/*------------------------------------------------------------*/
-
-void MC_(set_where)( ShadowChunk* sc, ExeContext* ec )
-{
-   VG_(set_sc_extra)( sc, 0, (UInt)ec );
-}
-
-ExeContext *MC_(get_where)( ShadowChunk* sc )
-{
-   return (ExeContext*)VG_(get_sc_extra)(sc, 0);
-}
-
-void SK_(complete_shadow_chunk) ( ShadowChunk* sc, ThreadState* tst )
-{
-   VG_(set_sc_extra) ( sc, 0, (UInt)VG_(get_ExeContext)(tst) );
-}
-
-
-/*------------------------------------------------------------*/
-/*--- Postponing free()ing                                 ---*/
-/*------------------------------------------------------------*/
-
-/* Holds blocks after freeing. */
-static ShadowChunk* freed_list_start  = NULL;
-static ShadowChunk* freed_list_end    = NULL;
-static Int          freed_list_volume = 0;
-
-__attribute__ ((unused))
-Int MC_(count_freelist) ( void )
-{
-   ShadowChunk* sc;
-   Int n = 0;
-   for (sc = freed_list_start; sc != NULL; sc = VG_(get_sc_next)(sc))
-      n++;
-   return n;
-}
-
-__attribute__ ((unused))
-void MC_(freelist_sanity) ( void )
-{
-   ShadowChunk* sc;
-   Int n = 0;
-   /* VG_(printf)("freelist sanity\n"); */
-   for (sc = freed_list_start; sc != NULL; sc = VG_(get_sc_next)(sc))
-      n += VG_(get_sc_size)(sc);
-   sk_assert(n == freed_list_volume);
-}
-
-/* Put a shadow chunk on the freed blocks queue, possibly freeing up
-   some of the oldest blocks in the queue at the same time. */
-static void add_to_freed_queue ( ShadowChunk* sc )
-{
-   ShadowChunk* sc1;
-
-   /* Put it at the end of the freed list */
-   if (freed_list_end == NULL) {
-      sk_assert(freed_list_start == NULL);
-      freed_list_end = freed_list_start = sc;
-      freed_list_volume = VG_(get_sc_size)(sc);
-   } else {    
-      sk_assert(VG_(get_sc_next)(freed_list_end) == NULL);
-      VG_(set_sc_next)(freed_list_end, sc);
-      freed_list_end = sc;
-      freed_list_volume += VG_(get_sc_size)(sc);
-   }
-   VG_(set_sc_next)(sc, NULL);
-
-   /* Release enough of the oldest blocks to bring the free queue
-      volume below vg_clo_freelist_vol. */
-   
-   while (freed_list_volume > MC_(clo_freelist_vol)) {
-      /* freelist_sanity(); */
-      sk_assert(freed_list_start != NULL);
-      sk_assert(freed_list_end != NULL);
-
-      sc1 = freed_list_start;
-      freed_list_volume -= VG_(get_sc_size)(sc1);
-      /* VG_(printf)("volume now %d\n", freed_list_volume); */
-      sk_assert(freed_list_volume >= 0);
-
-      if (freed_list_start == freed_list_end) {
-         freed_list_start = freed_list_end = NULL;
-      } else {
-         freed_list_start = VG_(get_sc_next)(sc1);
-      }
-      VG_(set_sc_next)(sc1, NULL); /* just paranoia */
-      VG_(free_ShadowChunk) ( sc1 );
-   }
-}
-
-/* Return the first shadow chunk satisfying the predicate p. */
-ShadowChunk* MC_(any_matching_freed_ShadowChunks) ( Bool (*p)(ShadowChunk*) )
-{
-   ShadowChunk* sc;
-
-   /* No point looking through freed blocks if we're not keeping
-      them around for a while... */
-   for (sc = freed_list_start; sc != NULL; sc = VG_(get_sc_next)(sc))
-      if (p(sc))
-         return sc;
-
-   return NULL;
-}
-
-void SK_(alt_free) ( ShadowChunk* sc, ThreadState* tst )
-{
-   /* Record where freed */
-   MC_(set_where)( sc, VG_(get_ExeContext) ( tst ) );
-
-   /* Put it out of harm's way for a while. */
-   add_to_freed_queue ( sc );
-}
-
 /*------------------------------------------------------------*/
 /*--- Syscall wrappers                                     ---*/
 /*------------------------------------------------------------*/
@@ -688,5 +850,5 @@ void  SK_(post_syscall) ( ThreadId tid, UInt syscallno,
 }
 
 /*--------------------------------------------------------------------*/
-/*--- end                                              mc_common.c ---*/
+/*--- end                                              mac_needs.c ---*/
 /*--------------------------------------------------------------------*/
similarity index 78%
rename from memcheck/mc_common.h
rename to memcheck/mac_shared.h
index 7a8d14b4bb8d706e862f5cc50c9683f847dfa46e..fc3d86bdf7164706a32bbedaa4c76545b5d97e7b 100644 (file)
@@ -1,7 +1,7 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Code that is shared between MemCheck and AddrCheck.          ---*/
-/*---                                                  mc_common.h ---*/
+/*--- Declarations shared between MemCheck and AddrCheck.          ---*/
+/*---                                                 mac_shared.h ---*/
 /*--------------------------------------------------------------------*/
 
 /*
    The GNU General Public License is contained in the file COPYING.
 */
 
-#ifndef __MC_COMMON_H
-#define __MC_COMMON_H
+/* Note: This header contains the declarations shared between
+   Addrcheck and Memcheck, and is #included by both. */
+
+#ifndef __MAC_SHARED_H
+#define __MAC_SHARED_H
 
 #include "vg_skin.h"
-#include "mc_constants.h"
+
+#define MAC_(str)    VGAPPEND(vgMAC_,str)
 
 /*------------------------------------------------------------*/
 /*--- Errors and suppressions                              ---*/
 
 /* The classification of a faulting address. */
 typedef 
-   enum { Undescribed,  /* as-yet unclassified */
-          Stack, 
-          Unknown,      /* classification yielded nothing useful */
-          Freed, Mallocd, 
-          UserG  /* in a user-defined block; Addrcheck & Memcheck only */
+   enum { 
+      Undescribed,  /* as-yet unclassified */
+      Stack, 
+      Unknown,      /* classification yielded nothing useful */
+      Freed, Mallocd, 
+      UserG  /* in a user-defined block; Addrcheck & Memcheck only */
    }
    AddrKind;
 
@@ -83,7 +88,7 @@ typedef
       /* Something to be suppressed in a leak check. */
       LeakSupp
    } 
-   MemCheckSuppKind;
+   MAC_SuppKind;
 
 /* What kind of error it is. */
 typedef 
@@ -91,9 +96,10 @@ typedef
           CoreMemErr,
           AddrErr, 
           ParamErr, UserErr,  /* behaves like an anonymous ParamErr */
-          FreeErr, FreeMismatchErr
+          FreeErr, FreeMismatchErr,
+          LeakErr
    }
-   MemCheckErrorKind;
+   MAC_ErrorKind;
 
 /* What kind of memory access is involved in the error? */
 typedef
@@ -112,7 +118,7 @@ typedef
       /* ParamErr, UserErr, CoreMemErr */
       Bool isWrite;
    }
-   MemCheckError;
+   MAC_Error;
 
 /*------------------------------------------------------------*/
 /*--- Profiling of skins and memory events                 ---*/
@@ -127,23 +133,23 @@ typedef
    VgpSkinCC;
 
 /* Define to collect detailed performance info. */
-/* #define VG_PROFILE_MEMORY */
+/* #define MAC_PROFILE_MEMORY */
 
-#ifdef VG_PROFILE_MEMORY
+#ifdef MAC_PROFILE_MEMORY
 #  define N_PROF_EVENTS 150
 
-extern UInt MC_(event_ctr)[N_PROF_EVENTS];
+extern UInt MAC_(event_ctr)[N_PROF_EVENTS];
 
-#  define PROF_EVENT(ev)                                  \
-   do { sk_assert((ev) >= 0 && (ev) < N_PROF_EVENTS);   \
-        MC_(event_ctr)[ev]++;                           \
+#  define PROF_EVENT(ev)                                 \
+   do { sk_assert((ev) >= 0 && (ev) < N_PROF_EVENTS);    \
+        MAC_(event_ctr)[ev]++;                           \
    } while (False);
 
 #else
 
 #  define PROF_EVENT(ev) /* */
 
-#endif   /* VG_PROFILE_MEMORY */
+#endif   /* MAC_PROFILE_MEMORY */
 
 /*------------------------------------------------------------*/
 /*--- V and A bits                                         ---*/
@@ -152,12 +158,12 @@ extern UInt MC_(event_ctr)[N_PROF_EVENTS];
 #define IS_DISTINGUISHED_SM(smap) \
    ((smap) == &distinguished_secondary_map)
 
-#define ENSURE_MAPPABLE(addr,caller)                                   \
-   do {                                                                \
+#define ENSURE_MAPPABLE(addr,caller)                              \
+   do {                                                           \
       if (IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) {       \
          primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
-         /* VG_(printf)("new 2map because of %p\n", addr); */          \
-      }                                                                \
+         /* VG_(printf)("new 2map because of %p\n", addr); */     \
+      }                                                           \
    } while(0)
 
 #define BITARR_SET(aaa_p,iii_p)                         \
@@ -198,78 +204,85 @@ extern UInt MC_(event_ctr)[N_PROF_EVENTS];
 /*--- Command line options + defaults                      ---*/
 /*------------------------------------------------------------*/
 
-/* Most are shared between MemCheck and AddrCheck, the last two are
-   MemCheck only (but here anyway for simplicity) */
+/* Memcheck defines a couple more. */
 
 /* Allow loads from partially-valid addresses?  default: YES */
-extern Bool MC_(clo_partial_loads_ok);
+extern Bool MAC_(clo_partial_loads_ok);
 
 /* Max volume of the freed blocks queue. */
-extern Int MC_(clo_freelist_vol);
+extern Int MAC_(clo_freelist_vol);
 
 /* Do leak check at exit?  default: NO */
-extern Bool MC_(clo_leak_check);
+extern Bool MAC_(clo_leak_check);
 
 /* How closely should we compare ExeContexts in leak records? default: 2 */
-extern VgRes MC_(clo_leak_resolution);
+extern VgRes MAC_(clo_leak_resolution);
 
 /* In leak check, show reachable-but-not-freed blocks?  default: NO */
-extern Bool MC_(clo_show_reachable);
+extern Bool MAC_(clo_show_reachable);
 
 /* Assume accesses immediately below %esp are due to gcc-2.96 bugs.
  * default: NO*/
-extern Bool MC_(clo_workaround_gcc296_bugs);
-
-/* DEBUG: clean up instrumented code?  default: YES */
-extern Bool MC_(clo_cleanup);
-
-/* When instrumenting, omit some checks if tell-tale literals for
-   inlined strlen() are visible in the basic block.  default: YES */
-extern Bool MC_(clo_avoid_strlen_errors);
+extern Bool MAC_(clo_workaround_gcc296_bugs);
 
-extern Bool MC_(process_common_cmd_line_option)(Char* arg);
+extern Bool MAC_(process_common_cmd_line_option)(Char* arg);
 
 
 /*------------------------------------------------------------*/
 /*--- Functions                                            ---*/
 /*------------------------------------------------------------*/
 
-extern void        MC_(set_where) ( ShadowChunk* sc, ExeContext* ec );
-extern ExeContext *MC_(get_where) ( ShadowChunk* sc );
+extern void        MAC_(set_where) ( ShadowChunk* sc, ExeContext* ec );
+extern ExeContext *MAC_(get_where) ( ShadowChunk* sc );
+
+extern void MAC_(pp_AddrInfo) ( Addr a, AddrInfo* ai );
+
+extern void MAC_(clear_MAC_Error)          ( MAC_Error* err_extra );
+
+extern Bool (*MAC_(describe_addr_supp))    ( Addr a, AddrInfo* ai );
+
+extern Bool MAC_(shared_recognised_suppression) ( Char* name, Supp* su );
 
-extern void MC_(pp_AddrInfo) ( Addr a, AddrInfo* ai );
+extern void MAC_(record_address_error)     ( Addr a, Int size, Bool isWrite );
+extern void MAC_(record_core_mem_error)    ( ThreadState* tst, Bool isWrite,
+                                             Char* s );
+extern void MAC_(record_param_error)       ( ThreadState* tst, Addr a,   
+                                             Bool isWriteLack, Char* msg );
+extern void MAC_(record_jump_error)        ( ThreadState* tst, Addr a );
+extern void MAC_(record_free_error)        ( ThreadState* tst, Addr a );
+extern void MAC_(record_freemismatch_error)( ThreadState* tst, Addr a );
 
-extern void MC_(clear_MemCheckError) ( MemCheckError* err_extra );
+extern void MAC_(pp_shared_SkinError)      ( Error* err);
 
-extern void MC_(record_address_error)     ( Addr a, Int size, Bool isWrite );
-extern void MC_(record_core_mem_error)    ( ThreadState* tst, Bool isWrite,
-                                            Char* s );
-extern void MC_(record_param_error)       ( ThreadState* tst, Addr a,   
-                                            Bool isWriteLack, Char* msg );
-extern void MC_(record_jump_error)        ( ThreadState* tst, Addr a );
-extern void MC_(record_free_error)        ( ThreadState* tst, Addr a );
-extern void MC_(record_freemismatch_error)( ThreadState* tst, Addr a );
+extern void MAC_(init_prof_mem) ( void );
+extern void MAC_(done_prof_mem) ( void );
 
-extern void MC_(init_prof_mem) ( void );
-extern void MC_(done_prof_mem) ( void );
+extern Int          MAC_(count_freelist)  ( void ) __attribute__ ((unused));
+extern void         MAC_(freelist_sanity) ( void ) __attribute__ ((unused));
+extern ShadowChunk* MAC_(any_matching_freed_ShadowChunks) 
+                            ( Bool (*p)(ShadowChunk*) );
 
-extern Int          MC_(count_freelist)  ( void ) __attribute__ ((unused));
-extern void         MC_(freelist_sanity) ( void ) __attribute__ ((unused));
-extern ShadowChunk* MC_(any_matching_freed_ShadowChunks) 
-                           ( Bool (*p)(ShadowChunk*) );
+/* For leak checking */
+extern void MAC_(pp_LeakError)(void* vl, UInt n_this_record, 
+                                         UInt n_total_records); 
+                           
+extern void MAC_(do_detect_memory_leaks) (
+          Bool is_valid_64k_chunk ( UInt ),
+          Bool is_valid_address   ( Addr )
+       );
 
-extern __attribute__((regparm(1))) void MC_(new_mem_stack_4)  ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(die_mem_stack_4)  ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(new_mem_stack_8)  ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(die_mem_stack_8)  ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(new_mem_stack_12) ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(die_mem_stack_12) ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(new_mem_stack_16) ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(die_mem_stack_16) ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(new_mem_stack_32) ( Addr old_ESP );
-extern __attribute__((regparm(1))) void MC_(die_mem_stack_32) ( Addr old_ESP );
-extern                             void MC_(die_mem_stack) ( Addr a, UInt len );
-extern                             void MC_(new_mem_stack) ( Addr a, UInt len );
+extern __attribute__((regparm(1))) void MAC_(new_mem_stack_4)  ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(die_mem_stack_4)  ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(new_mem_stack_8)  ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(die_mem_stack_8)  ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(new_mem_stack_12) ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(die_mem_stack_12) ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(new_mem_stack_16) ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(die_mem_stack_16) ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(new_mem_stack_32) ( Addr old_ESP );
+extern __attribute__((regparm(1))) void MAC_(die_mem_stack_32) ( Addr old_ESP );
+extern                             void MAC_(die_mem_stack) ( Addr a, UInt len );
+extern                             void MAC_(new_mem_stack) ( Addr a, UInt len );
 
 
 /*------------------------------------------------------------*/
@@ -288,7 +301,7 @@ extern                             void MC_(new_mem_stack) ( Addr a, UInt len );
                             ALIGNED8_NEW,  ALIGNED8_DIE,                      \
                             UNALIGNED_NEW, UNALIGNED_DIE)                     \
                                                                               \
-void __attribute__((regparm(1))) MC_(new_mem_stack_4)(Addr new_ESP)           \
+void __attribute__((regparm(1))) MAC_(new_mem_stack_4)(Addr new_ESP)          \
 {                                                                             \
    PROF_EVENT(110);                                                           \
    if (IS_ALIGNED4_ADDR(new_ESP)) {                                           \
@@ -298,7 +311,7 @@ void __attribute__((regparm(1))) MC_(new_mem_stack_4)(Addr new_ESP)           \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(die_mem_stack_4)(Addr new_ESP)           \
+void __attribute__((regparm(1))) MAC_(die_mem_stack_4)(Addr new_ESP)          \
 {                                                                             \
    PROF_EVENT(120);                                                           \
    if (IS_ALIGNED4_ADDR(new_ESP)) {                                           \
@@ -308,7 +321,7 @@ void __attribute__((regparm(1))) MC_(die_mem_stack_4)(Addr new_ESP)           \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(new_mem_stack_8)(Addr new_ESP)           \
+void __attribute__((regparm(1))) MAC_(new_mem_stack_8)(Addr new_ESP)          \
 {                                                                             \
    PROF_EVENT(111);                                                           \
    if (IS_ALIGNED8_ADDR(new_ESP)) {                                           \
@@ -321,7 +334,7 @@ void __attribute__((regparm(1))) MC_(new_mem_stack_8)(Addr new_ESP)           \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(die_mem_stack_8)(Addr new_ESP)           \
+void __attribute__((regparm(1))) MAC_(die_mem_stack_8)(Addr new_ESP)          \
 {                                                                             \
    PROF_EVENT(121);                                                           \
    if (IS_ALIGNED8_ADDR(new_ESP)) {                                           \
@@ -334,7 +347,7 @@ void __attribute__((regparm(1))) MC_(die_mem_stack_8)(Addr new_ESP)           \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(new_mem_stack_12)(Addr new_ESP)          \
+void __attribute__((regparm(1))) MAC_(new_mem_stack_12)(Addr new_ESP)         \
 {                                                                             \
    PROF_EVENT(112);                                                           \
    if (IS_ALIGNED8_ADDR(new_ESP)) {                                           \
@@ -348,7 +361,7 @@ void __attribute__((regparm(1))) MC_(new_mem_stack_12)(Addr new_ESP)          \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(die_mem_stack_12)(Addr new_ESP)          \
+void __attribute__((regparm(1))) MAC_(die_mem_stack_12)(Addr new_ESP)         \
 {                                                                             \
    PROF_EVENT(122);                                                           \
    /* Note the -12 in the test */                                             \
@@ -363,7 +376,7 @@ void __attribute__((regparm(1))) MC_(die_mem_stack_12)(Addr new_ESP)          \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(new_mem_stack_16)(Addr new_ESP)          \
+void __attribute__((regparm(1))) MAC_(new_mem_stack_16)(Addr new_ESP)         \
 {                                                                             \
    PROF_EVENT(113);                                                           \
    if (IS_ALIGNED8_ADDR(new_ESP)) {                                           \
@@ -378,7 +391,7 @@ void __attribute__((regparm(1))) MC_(new_mem_stack_16)(Addr new_ESP)          \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(die_mem_stack_16)(Addr new_ESP)          \
+void __attribute__((regparm(1))) MAC_(die_mem_stack_16)(Addr new_ESP)         \
 {                                                                             \
    PROF_EVENT(123);                                                           \
    if (IS_ALIGNED8_ADDR(new_ESP)) {                                           \
@@ -393,7 +406,7 @@ void __attribute__((regparm(1))) MC_(die_mem_stack_16)(Addr new_ESP)          \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(new_mem_stack_32)(Addr new_ESP)          \
+void __attribute__((regparm(1))) MAC_(new_mem_stack_32)(Addr new_ESP)         \
 {                                                                             \
    PROF_EVENT(114);                                                           \
    if (IS_ALIGNED8_ADDR(new_ESP)) {                                           \
@@ -412,7 +425,7 @@ void __attribute__((regparm(1))) MC_(new_mem_stack_32)(Addr new_ESP)          \
    }                                                                          \
 }                                                                             \
                                                                               \
-void __attribute__((regparm(1))) MC_(die_mem_stack_32)(Addr new_ESP)          \
+void __attribute__((regparm(1))) MAC_(die_mem_stack_32)(Addr new_ESP)         \
 {                                                                             \
    PROF_EVENT(124);                                                           \
    if (IS_ALIGNED8_ADDR(new_ESP)) {                                           \
@@ -431,20 +444,20 @@ void __attribute__((regparm(1))) MC_(die_mem_stack_32)(Addr new_ESP)          \
    }                                                                          \
 }                                                                             \
                                                                               \
-void MC_(new_mem_stack) ( Addr a, UInt len )                                  \
+void MAC_(new_mem_stack) ( Addr a, UInt len )                                 \
 {                                                                             \
    PROF_EVENT(115);                                                           \
    UNALIGNED_NEW ( a, len );                                                  \
 }                                                                             \
                                                                               \
-void MC_(die_mem_stack) ( Addr a, UInt len )                                  \
+void MAC_(die_mem_stack) ( Addr a, UInt len )                                 \
 {                                                                             \
    PROF_EVENT(125);                                                           \
    UNALIGNED_DIE ( a, len );                                                  \
 }
 
-#endif   /* __MC_COMMON_H */
+#endif   /* __MAC_SHARED_H */
 
 /*--------------------------------------------------------------------*/
-/*--- end                                              mc_common.h ---*/
+/*--- end                                             mac_shared.h ---*/
 /*--------------------------------------------------------------------*/
index cb757c7c81c07a51db1a9654228fecc5dd8aff97..eda5ca8d5c57edcd929c839340dfbe3f8e44b84f 100644 (file)
 #include "mc_include.h"
 
 /*------------------------------------------------------------*/
-/*--- Comparing and printing errors                        ---*/
+/*--- Printing errors                                      ---*/
 /*------------------------------------------------------------*/
 
-void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
+void SK_(pp_SkinError) ( Error* err )
 {
-   MemCheckError* err_extra = VG_(get_error_extra)(err);
+   MAC_Error* err_extra = VG_(get_error_extra)(err);
 
    switch (VG_(get_error_kind)(err)) {
       case CoreMemErr:
@@ -49,7 +49,7 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
                 "%s contains uninitialised or unaddressable byte(s)",
                 VG_(get_error_string)(err));
          }
-         pp_ExeContext();
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
          break;
       
       case ValueErr:
@@ -62,7 +62,7 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
                           "Use of uninitialised value of size %d",
                           err_extra->size);
          }
-         pp_ExeContext();
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
          break;
 
       case AddrErr:
@@ -82,19 +82,8 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
             default: 
                VG_(skin_panic)("SK_(pp_SkinError)(axskind)");
          }
-         pp_ExeContext();
-         MC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
-         break;
-
-      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 []");
-         pp_ExeContext();
-         MC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+         MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
          break;
 
       case ParamErr:
@@ -108,8 +97,8 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
                 "unaddressable byte(s)",
                 VG_(get_error_string)(err));
          }
-         pp_ExeContext();
-         MC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
+         MAC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
          break;
 
       case UserErr:
@@ -121,14 +110,13 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
                "Uninitialised or "
                "unaddressable byte(s) found during client check request");
          }
-         pp_ExeContext();
-         MC_(pp_AddrInfo)(VG_(get_error_address)(err), &err_extra->addrinfo);
+         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 error code %d\n",
-                     VG_(get_error_kind)(err));
-         VG_(skin_panic)("unknown error code in SK_(pp_SkinError)");
+         MAC_(pp_shared_SkinError)(err);
+         break;
    }
 }
 
@@ -136,89 +124,14 @@ void SK_(pp_SkinError) ( Error* err, void (*pp_ExeContext)(void) )
 /*--- Recording errors                                     ---*/
 /*------------------------------------------------------------*/
 
-/* Describe an address as best you can, for error messages,
-   putting the result in ai. */
-
-static void mc_describe_addr ( Addr a, AddrInfo* ai )
-{
-   ShadowChunk* sc;
-   Bool         ok;
-   ThreadId     tid;
-
-   /* Nested functions, yeah.  Need the lexical scoping of 'a'. */ 
-
-   /* Closure for searching thread stacks */
-   Bool addr_is_in_bounds(Addr stack_min, Addr stack_max)
-   {
-      return (stack_min <= a && a <= stack_max);
-   }
-   /* Closure for searching malloc'd and free'd lists */
-   Bool addr_is_in_block(ShadowChunk *sh_ch)
-   {
-      return VG_(addr_is_in_block) ( a, VG_(get_sc_data)(sh_ch),
-                                        VG_(get_sc_size)(sh_ch) );
-   }
-
-   /* Perhaps it's a user-def'd block ? */
-   ok = MC_(client_perm_maybe_describe)( a, ai );
-   if (ok)
-      return;
-   /* Perhaps it's on a thread's stack? */
-   tid = VG_(any_matching_thread_stack)(addr_is_in_bounds);
-   if (tid != VG_INVALID_THREADID) {
-      ai->akind     = Stack;
-      ai->stack_tid = tid;
-      return;
-   }
-   /* Search for a recently freed block which might bracket it. */
-   sc = MC_(any_matching_freed_ShadowChunks)(addr_is_in_block);
-   if (NULL != sc) {
-      ai->akind      = Freed;
-      ai->blksize    = VG_(get_sc_size)(sc);
-      ai->rwoffset   = (Int)(a) - (Int)(VG_(get_sc_data)(sc));
-      ai->lastchange = (ExeContext*)( VG_(get_sc_extra)(sc, 0) );
-      return;
-   }
-   /* Search for a currently malloc'd block which might bracket it. */
-   sc = VG_(any_matching_mallocd_ShadowChunks)(addr_is_in_block);
-   if (NULL != sc) {
-      ai->akind      = Mallocd;
-      ai->blksize    = VG_(get_sc_size)(sc);
-      ai->rwoffset   = (Int)(a) - (Int)(VG_(get_sc_data)(sc));
-      ai->lastchange = (ExeContext*)( VG_(get_sc_extra)(sc, 0) );
-      return;
-   } 
-   /* Clueless ... */
-   ai->akind = Unknown;
-   return;
-}
-
 /* Creates a copy of the `extra' part, updates the copy with address info if
    necessary, and returns the copy. */
-void* SK_(dup_extra_and_update)( Error* err )
-{
-   MemCheckError* extra;
-   MemCheckError* new_extra = NULL;
-
-   extra = ((MemCheckError*)VG_(get_error_extra)(err));
-   if (extra != NULL) {
-      new_extra  = VG_(malloc)(sizeof(MemCheckError));
-      *new_extra = *extra;
-      if (new_extra->addrinfo.akind == Undescribed)
-         mc_describe_addr ( VG_(get_error_address)(err),
-                            &(new_extra->addrinfo) );
-   }
-
-   return new_extra;
-}
-
-
 /* This one called from generated code. */
 void MC_(record_value_error) ( Int size )
 {
-   MemCheckError err_extra;
+   MAC_Error err_extra;
 
-   MC_(clear_MemCheckError)( &err_extra );
+   MAC_(clear_MAC_Error)( &err_extra );
    err_extra.size = size;
    VG_(maybe_record_error)( NULL, ValueErr, /*addr*/0, /*s*/NULL, &err_extra );
 }
@@ -226,11 +139,11 @@ void MC_(record_value_error) ( Int size )
 /* This one called from non-generated code */
 void MC_(record_user_error) ( ThreadState* tst, Addr a, Bool isWrite )
 {
-   MemCheckError err_extra;
+   MAC_Error err_extra;
 
    sk_assert(NULL != tst);
 
-   MC_(clear_MemCheckError)( &err_extra );
+   MAC_(clear_MAC_Error)( &err_extra );
    err_extra.addrinfo.akind = Undescribed;
    err_extra.isWrite        = isWrite;
    VG_(maybe_record_error)( tst, UserErr, a, /*s*/NULL, &err_extra );
@@ -240,27 +153,20 @@ void MC_(record_user_error) ( ThreadState* tst, Addr a, Bool isWrite )
 /*--- Suppressions                                         ---*/
 /*------------------------------------------------------------*/
 
-#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
-                      && VG_(strcmp)((s1),(s2))==0)
-
 Bool SK_(recognised_suppression) ( Char* name, Supp* su )
 {
    SuppKind skind;
 
-   if      (STREQ(name, "Param"))   skind = ParamSupp;
-   else if (STREQ(name, "CoreMem")) skind = CoreMemSupp;
-   else if (STREQ(name, "Value0"))  skind = Value0Supp; /* backwards compat */ 
-   else if (STREQ(name, "Cond"))    skind = Value0Supp;
-   else if (STREQ(name, "Value1"))  skind = Value1Supp;
-   else if (STREQ(name, "Value2"))  skind = Value2Supp;
-   else if (STREQ(name, "Value4"))  skind = Value4Supp;
-   else if (STREQ(name, "Value8"))  skind = Value8Supp;
-   else if (STREQ(name, "Addr1"))   skind = Addr1Supp;
-   else if (STREQ(name, "Addr2"))   skind = Addr2Supp;
-   else if (STREQ(name, "Addr4"))   skind = Addr4Supp;
-   else if (STREQ(name, "Addr8"))   skind = Addr8Supp;
-   else if (STREQ(name, "Free"))    skind = FreeSupp;
-   else if (STREQ(name, "Leak"))    skind = LeakSupp;
+   if (MAC_(shared_recognised_suppression)(name, su))
+      return True;
+
+   /* Extra suppressions not used by Addrcheck */
+   else if (VG_STREQ(name, "Cond"))   skind = Value0Supp;
+   else if (VG_STREQ(name, "Value0")) skind = Value0Supp; /* backwards compat */
+   else if (VG_STREQ(name, "Value1")) skind = Value1Supp;
+   else if (VG_STREQ(name, "Value2")) skind = Value2Supp;
+   else if (VG_STREQ(name, "Value4")) skind = Value4Supp;
+   else if (VG_STREQ(name, "Value8")) skind = Value8Supp;
    else 
       return False;
 
@@ -268,8 +174,6 @@ Bool SK_(recognised_suppression) ( Char* name, Supp* su )
    return True;
 }
 
-#  undef STREQ
-
 /*--------------------------------------------------------------------*/
 /*--- end                                          mc_errcontext.c ---*/
 /*--------------------------------------------------------------------*/
index af3e2ed3624020bbf51ea1a89c23297b9101d0a0..7d568e5b369f42088d47fa7ba49b39db1963b67f 100644 (file)
    The GNU General Public License is contained in the file COPYING.
 */
 
+/* Note: this header should contain declarations that are for use by
+   Memcheck only -- declarations shared with Addrcheck go in mac_shared.h.
+*/
+
 #ifndef __MC_INCLUDE_H
 #define __MC_INCLUDE_H
 
-#include "mc_common.h"
+#include "mac_shared.h"
+#include "mc_constants.h"
+
+/*------------------------------------------------------------*/
+/*--- Types                                                ---*/
+/*------------------------------------------------------------*/
 
 /* UCode extension for efficient memory checking operations */
 typedef
@@ -88,6 +97,18 @@ typedef
    TagOp;
 
 
+/*------------------------------------------------------------*/
+/*--- Command line options                                 ---*/
+/*------------------------------------------------------------*/
+
+/* DEBUG: clean up instrumented code?  default: YES */
+extern Bool MC_(clo_cleanup);
+
+/* When instrumenting, omit some checks if tell-tale literals for
+   inlined strlen() are visible in the basic block.  default: YES */
+extern Bool MC_(clo_avoid_strlen_errors);
+
+
 /*------------------------------------------------------------*/
 /*--- Functions                                            ---*/
 /*------------------------------------------------------------*/
index c5d9ef056c4165087aab9388119a8cf2811c7f35..46ae522cd24537f721df3666665a0869faad85f5 100644 (file)
@@ -586,12 +586,12 @@ void mc_check_is_writable ( CorePart part, ThreadState* tst,
    if (!ok) {
       switch (part) {
       case Vg_CoreSysCall:
-         MC_(record_param_error) ( tst, bad_addr, /*isWrite =*/True, s );
+         MAC_(record_param_error) ( tst, bad_addr, /*isWrite =*/True, s );
          break;
 
       case Vg_CorePThread:
       case Vg_CoreSignal:
-         MC_(record_core_mem_error)( tst, /*isWrite=*/True, s );
+         MAC_(record_core_mem_error)( tst, /*isWrite=*/True, s );
          break;
 
       default:
@@ -617,17 +617,17 @@ void mc_check_is_readable ( CorePart part, ThreadState* tst,
    if (!ok) {
       switch (part) {
       case Vg_CoreSysCall:
-         MC_(record_param_error) ( tst, bad_addr, /*isWrite =*/False, s );
+         MAC_(record_param_error) ( tst, bad_addr, /*isWrite =*/False, s );
          break;
       
       case Vg_CorePThread:
-         MC_(record_core_mem_error)( tst, /*isWrite=*/False, s );
+         MAC_(record_core_mem_error)( tst, /*isWrite=*/False, s );
          break;
 
       /* If we're being asked to jump to a silly address, record an error 
          message before potentially crashing the entire system. */
       case Vg_CoreTranslate:
-         MC_(record_jump_error)( tst, bad_addr );
+         MAC_(record_jump_error)( tst, bad_addr );
          break;
 
       default:
@@ -650,7 +650,7 @@ void mc_check_is_readable_asciiz ( CorePart part, ThreadState* tst,
    sk_assert(part == Vg_CoreSysCall);
    ok = mc_check_readable_asciiz ( (Addr)str, &bad_addr );
    if (!ok) {
-      MC_(record_param_error) ( tst, bad_addr, /*is_writable =*/False, s );
+      MAC_(record_param_error) ( tst, bad_addr, /*is_writable =*/False, s );
    }
 
    VGP_POPCC(VgpCheckMem);
@@ -897,10 +897,10 @@ static UInt mc_rd_V4_SLOWLY ( Addr a )
       error arose in the first place from an invalid address. 
    */
    /* VG_(printf)("%p (%d %d %d %d)\n", a, a0ok, a1ok, a2ok, a3ok); */
-   if (!MC_(clo_partial_loads_ok) 
+   if (!MAC_(clo_partial_loads_ok) 
        || ((a & 3) != 0)
        || (!a0ok && !a1ok && !a2ok && !a3ok)) {
-      MC_(record_address_error)( a, 4, False );
+      MAC_(record_address_error)( a, 4, False );
       return (VGM_BYTE_VALID << 24) | (VGM_BYTE_VALID << 16) 
              | (VGM_BYTE_VALID << 8) | VGM_BYTE_VALID;
    }
@@ -913,7 +913,7 @@ static UInt mc_rd_V4_SLOWLY ( Addr a )
       (which is the default), and the address is 4-aligned.  
       If not, Case 2 will have applied.
    */
-   sk_assert(MC_(clo_partial_loads_ok));
+   sk_assert(MAC_(clo_partial_loads_ok));
    {
       UInt vw = VGM_WORD_INVALID;
       vw <<= 8; vw |= (a3ok ? vb3 : VGM_BYTE_INVALID);
@@ -943,7 +943,7 @@ static void mc_wr_V4_SLOWLY ( Addr a, UInt vbytes )
 
    /* If an address error has happened, report it. */
    if (aerr)
-      MC_(record_address_error)( a, 4, True );
+      MAC_(record_address_error)( a, 4, True );
 }
 
 static UInt mc_rd_V2_SLOWLY ( Addr a )
@@ -962,7 +962,7 @@ static UInt mc_rd_V2_SLOWLY ( Addr a )
 
    /* If an address error has happened, report it. */
    if (aerr) {
-      MC_(record_address_error)( a, 2, False );
+      MAC_(record_address_error)( a, 2, False );
       vw = (VGM_BYTE_INVALID << 24) | (VGM_BYTE_INVALID << 16) 
            | (VGM_BYTE_VALID << 8) | (VGM_BYTE_VALID);
    }
@@ -984,7 +984,7 @@ static void mc_wr_V2_SLOWLY ( Addr a, UInt vbytes )
 
    /* If an address error has happened, report it. */
    if (aerr)
-      MC_(record_address_error)( a, 2, True );
+      MAC_(record_address_error)( a, 2, True );
 }
 
 static UInt mc_rd_V1_SLOWLY ( Addr a )
@@ -1001,7 +1001,7 @@ static UInt mc_rd_V1_SLOWLY ( Addr a )
 
    /* If an address error has happened, report it. */
    if (aerr) {
-      MC_(record_address_error)( a, 1, False );
+      MAC_(record_address_error)( a, 1, False );
       vw = (VGM_BYTE_INVALID << 24) | (VGM_BYTE_INVALID << 16) 
            | (VGM_BYTE_INVALID << 8) | (VGM_BYTE_VALID);
    }
@@ -1020,7 +1020,7 @@ static void mc_wr_V1_SLOWLY ( Addr a, UInt vbytes )
 
    /* If an address error has happened, report it. */
    if (aerr)
-      MC_(record_address_error)( a, 1, True );
+      MAC_(record_address_error)( a, 1, True );
 }
 
 
@@ -1250,7 +1250,7 @@ void mc_fpu_read_check_SLOWLY ( Addr addr, Int size )
    }
 
    if (aerr) {
-      MC_(record_address_error)( addr, size, False );
+      MAC_(record_address_error)( addr, size, False );
    } else {
      if (verr)
         MC_(record_value_error)( size );
@@ -1280,7 +1280,7 @@ void mc_fpu_write_check_SLOWLY ( Addr addr, Int size )
       }
    }
    if (aerr) {
-      MC_(record_address_error)( addr, size, True );
+      MAC_(record_address_error)( addr, size, True );
    }
 }
 
@@ -1329,14 +1329,7 @@ Bool mc_is_valid_address ( Addr a )
    skin. */
 void MC_(detect_memory_leaks) ( void )
 {
-   VG_(generic_detect_memory_leaks) ( 
-      mc_is_valid_64k_chunk,
-      mc_is_valid_address,
-      MC_(get_where),
-      MC_(clo_leak_resolution),
-      MC_(clo_show_reachable),
-      (UInt)LeakSupp
-   );
+   MAC_(do_detect_memory_leaks) ( mc_is_valid_64k_chunk, mc_is_valid_address );
 }
 
 
@@ -1489,23 +1482,25 @@ void SK_(written_shadow_regs_values)( UInt* gen_reg_value, UInt* eflags_value )
    *eflags_value  = VGM_EFLAGS_VALID;
 }
 
+Bool  MC_(clo_avoid_strlen_errors)    = True;
+Bool  MC_(clo_cleanup)                = True;
+
 Bool SK_(process_cmd_line_option)(Char* arg)
 {
-#  define STREQ(s1,s2)     (0==VG_(strcmp_ws)((s1),(s2)))
-#  define STREQN(nn,s1,s2) (0==VG_(strncmp_ws)((s1),(s2),(nn)))
-
-   if (STREQ(arg, "--avoid-strlen-errors=yes"))
+   if (VG_CLO_STREQ(arg, "--avoid-strlen-errors=yes"))
       MC_(clo_avoid_strlen_errors) = True;
-   else if (STREQ(arg, "--avoid-strlen-errors=no"))
+   else if (VG_CLO_STREQ(arg, "--avoid-strlen-errors=no"))
       MC_(clo_avoid_strlen_errors) = False;
 
+   else if (VG_CLO_STREQ(arg, "--cleanup=yes"))
+      MC_(clo_cleanup) = True;
+   else if (VG_CLO_STREQ(arg, "--cleanup=no"))
+      MC_(clo_cleanup) = False;
+
    else
-      return MC_(process_common_cmd_line_option)(arg);
+      return MAC_(process_common_cmd_line_option)(arg);
 
    return True;
-
-#undef STREQ
-#undef STREQN
 }
 
 Char* SK_(usage)(void)
@@ -1556,12 +1551,12 @@ void SK_(pre_clo_init)(void)
    VG_(track_new_mem_brk)          ( & MC_(make_writable) );
    VG_(track_new_mem_mmap)         ( & mc_set_perms );
    
-   VG_(track_new_mem_stack_4)      ( & MC_(new_mem_stack_4)  );
-   VG_(track_new_mem_stack_8)      ( & MC_(new_mem_stack_8)  );
-   VG_(track_new_mem_stack_12)     ( & MC_(new_mem_stack_12) );
-   VG_(track_new_mem_stack_16)     ( & MC_(new_mem_stack_16) );
-   VG_(track_new_mem_stack_32)     ( & MC_(new_mem_stack_32) );
-   VG_(track_new_mem_stack)        ( & MC_(new_mem_stack)    );
+   VG_(track_new_mem_stack_4)      ( & MAC_(new_mem_stack_4)  );
+   VG_(track_new_mem_stack_8)      ( & MAC_(new_mem_stack_8)  );
+   VG_(track_new_mem_stack_12)     ( & MAC_(new_mem_stack_12) );
+   VG_(track_new_mem_stack_16)     ( & MAC_(new_mem_stack_16) );
+   VG_(track_new_mem_stack_32)     ( & MAC_(new_mem_stack_32) );
+   VG_(track_new_mem_stack)        ( & MAC_(new_mem_stack)    );
 
    VG_(track_copy_mem_heap)        ( & mc_copy_address_range_state );
    VG_(track_copy_mem_remap)       ( & mc_copy_address_range_state );
@@ -1575,15 +1570,15 @@ void SK_(pre_clo_init)(void)
    VG_(track_die_mem_brk)          ( & MC_(make_noaccess) );
    VG_(track_die_mem_munmap)       ( & MC_(make_noaccess) ); 
 
-   VG_(track_die_mem_stack_4)      ( & MC_(die_mem_stack_4)  );
-   VG_(track_die_mem_stack_8)      ( & MC_(die_mem_stack_8)  );
-   VG_(track_die_mem_stack_12)     ( & MC_(die_mem_stack_12) );
-   VG_(track_die_mem_stack_16)     ( & MC_(die_mem_stack_16) );
-   VG_(track_die_mem_stack_32)     ( & MC_(die_mem_stack_32) );
-   VG_(track_die_mem_stack)        ( & MC_(die_mem_stack)    );
+   VG_(track_die_mem_stack_4)      ( & MAC_(die_mem_stack_4)  );
+   VG_(track_die_mem_stack_8)      ( & MAC_(die_mem_stack_8)  );
+   VG_(track_die_mem_stack_12)     ( & MAC_(die_mem_stack_12) );
+   VG_(track_die_mem_stack_16)     ( & MAC_(die_mem_stack_16) );
+   VG_(track_die_mem_stack_32)     ( & MAC_(die_mem_stack_32) );
+   VG_(track_die_mem_stack)        ( & MAC_(die_mem_stack)    );
    
-   VG_(track_bad_free)             ( & MC_(record_free_error) );
-   VG_(track_mismatched_free)      ( & MC_(record_freemismatch_error) );
+   VG_(track_bad_free)             ( & MAC_(record_free_error) );
+   VG_(track_mismatched_free)      ( & MAC_(record_freemismatch_error) );
 
    VG_(track_pre_mem_read)         ( & mc_check_is_readable );
    VG_(track_pre_mem_read_asciiz)  ( & mc_check_is_readable_asciiz );
@@ -1610,8 +1605,11 @@ void SK_(pre_clo_init)(void)
    VGP_(register_profile_event) ( VgpCheckMem, "check-mem-perms" );
    VGP_(register_profile_event) ( VgpESPAdj,   "adjust-ESP" );
 
+   /* Additional block description for VG_(describe_addr)() */
+   MAC_(describe_addr_supp) = MC_(client_perm_maybe_describe);
+
    init_shadow_memory();
-   MC_(init_prof_mem)();
+   MAC_(init_prof_mem)();
 }
 
 void SK_(post_clo_init) ( void )
@@ -1623,16 +1621,16 @@ void SK_(fini) ( void )
    VG_(print_malloc_stats)();
 
    if (VG_(clo_verbosity) == 1) {
-      if (!MC_(clo_leak_check))
+      if (!MAC_(clo_leak_check))
          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 (MC_(clo_leak_check)) MC_(detect_memory_leaks)();
+   if (MAC_(clo_leak_check)) MC_(detect_memory_leaks)();
 
-   MC_(done_prof_mem)();
+   MAC_(done_prof_mem)();
 
    if (0) {
       VG_(message)(Vg_DebugMsg,