Made Addrcheck distinguish between invalid reads and invalid writes (previously
was just saying "invalid memory access").

Added a regression test for this, for memcheck and addrcheck.  Also made
Addrcheck use Memcheck's fprw regtest.  Was able to remove the not-very-useful
'true' test for Addrcheck now that it has a couple of real tests.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1815 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/addrcheck/ac_main.c b/addrcheck/ac_main.c
index 2efaa3a..760e219 100644
--- a/addrcheck/ac_main.c
+++ b/addrcheck/ac_main.c
@@ -55,9 +55,11 @@
       case AddrErr:
          switch (err_extra->axskind) {
             case ReadAxs:
+               VG_(message)(Vg_UserMsg, "Invalid read of size %d", 
+                                        err_extra->size ); 
+               break;
             case WriteAxs:
-               /* These two aren't actually differentiated ever. */
-               VG_(message)(Vg_UserMsg, "Invalid memory access of size %d", 
+               VG_(message)(Vg_UserMsg, "Invalid write of size %d", 
                                         err_extra->size ); 
                break;
             case ExecAxs:
@@ -156,10 +158,10 @@
 /*--- Function declarations.                               ---*/
 /*------------------------------------------------------------*/
 
-static void ac_ACCESS4_SLOWLY ( Addr a );
-static void ac_ACCESS2_SLOWLY ( Addr a );
-static void ac_ACCESS1_SLOWLY ( Addr a );
-static void ac_fpu_ACCESS_check_SLOWLY ( Addr addr, Int size );
+static void ac_ACCESS4_SLOWLY ( Addr a, Bool isWrite );
+static void ac_ACCESS2_SLOWLY ( Addr a, Bool isWrite );
+static void ac_ACCESS1_SLOWLY ( Addr a, Bool isWrite );
+static void ac_fpu_ACCESS_check_SLOWLY ( Addr addr, Int size, Bool isWrite );
 
 /*------------------------------------------------------------*/
 /*--- Data defns.                                          ---*/
@@ -682,11 +684,10 @@
    Under all other circumstances, it defers to the relevant _SLOWLY
    function, which can handle all situations.
 */
-__attribute__ ((regparm(1)))
-static void ac_helperc_ACCESS4 ( Addr a )
+static __inline__ void ac_helperc_ACCESS4 ( Addr a, Bool isWrite )
 {
 #  ifdef VG_DEBUG_MEMORY
-   return ac_ACCESS4_SLOWLY(a);
+   return ac_ACCESS4_SLOWLY(a, isWrite);
 #  else
    UInt    sec_no = rotateRight16(a) & 0x3FFFF;
    AcSecMap* sm     = primary_map[sec_no];
@@ -701,16 +702,15 @@
       return;
    } else {
       /* Slow but general case. */
-      ac_ACCESS4_SLOWLY(a);
+      ac_ACCESS4_SLOWLY(a, isWrite);
    }
 #  endif
 }
 
-__attribute__ ((regparm(1)))
-static void ac_helperc_ACCESS2 ( Addr a )
+static __inline__ void ac_helperc_ACCESS2 ( Addr a, Bool isWrite )
 {
 #  ifdef VG_DEBUG_MEMORY
-   return ac_ACCESS2_SLOWLY(a);
+   return ac_ACCESS2_SLOWLY(a, isWrite);
 #  else
    UInt    sec_no = rotateRight16(a) & 0x1FFFF;
    AcSecMap* sm     = primary_map[sec_no];
@@ -721,16 +721,15 @@
       return;
    } else {
       /* Slow but general case. */
-      ac_ACCESS2_SLOWLY(a);
+      ac_ACCESS2_SLOWLY(a, isWrite);
    }
 #  endif
 }
 
-__attribute__ ((regparm(1)))
-static void ac_helperc_ACCESS1 ( Addr a )
+static __inline__ void ac_helperc_ACCESS1 ( Addr a, Bool isWrite )
 {
 #  ifdef VG_DEBUG_MEMORY
-   return ac_ACCESS1_SLOWLY(a);
+   return ac_ACCESS1_SLOWLY(a, isWrite);
 #  else
    UInt    sec_no = shiftRight16(a);
    AcSecMap* sm   = primary_map[sec_no];
@@ -741,18 +740,51 @@
       return;
    } else {
       /* Slow but general case. */
-      ac_ACCESS1_SLOWLY(a);
+      ac_ACCESS1_SLOWLY(a, isWrite);
    }
 #  endif
 }
 
+__attribute__ ((regparm(1)))
+static void ac_helperc_LOAD4 ( Addr a )
+{
+   ac_helperc_ACCESS4 ( a, /*isWrite*/False );
+}
+__attribute__ ((regparm(1)))
+static void ac_helperc_STORE4 ( Addr a )
+{
+   ac_helperc_ACCESS4 ( a, /*isWrite*/True );
+}
+
+__attribute__ ((regparm(1)))
+static void ac_helperc_LOAD2 ( Addr a )
+{
+   ac_helperc_ACCESS2 ( a, /*isWrite*/False );
+}
+__attribute__ ((regparm(1)))
+static void ac_helperc_STORE2 ( Addr a )
+{
+   ac_helperc_ACCESS2 ( a, /*isWrite*/True );
+}
+
+__attribute__ ((regparm(1)))
+static void ac_helperc_LOAD1 ( Addr a )
+{
+   ac_helperc_ACCESS1 ( a, /*isWrite*/False );
+}
+__attribute__ ((regparm(1)))
+static void ac_helperc_STORE1 ( Addr a )
+{
+   ac_helperc_ACCESS1 ( a, /*isWrite*/True );
+}
+
 
 /*------------------------------------------------------------*/
 /*--- Fallback functions to handle cases that the above    ---*/
-/*--- VG_(helperc_ACCESS{1,2,4}) can't manage.             ---*/
+/*--- ac_helperc_ACCESS{1,2,4} can't manage.               ---*/
 /*------------------------------------------------------------*/
 
-static void ac_ACCESS4_SLOWLY ( Addr a )
+static void ac_ACCESS4_SLOWLY ( Addr a, Bool isWrite )
 {
    Bool a0ok, a1ok, a2ok, a3ok;
 
@@ -781,7 +813,7 @@
    if (!MAC_(clo_partial_loads_ok) 
        || ((a & 3) != 0)
        || (!a0ok && !a1ok && !a2ok && !a3ok)) {
-      MAC_(record_address_error)( VG_(get_current_tid)(), a, 4, False );
+      MAC_(record_address_error)( VG_(get_current_tid)(), a, 4, isWrite );
       return;
    }
 
@@ -797,7 +829,7 @@
    }
 }
 
-static void ac_ACCESS2_SLOWLY ( Addr a )
+static void ac_ACCESS2_SLOWLY ( Addr a, Bool isWrite )
 {
    /* Check the address for validity. */
    Bool aerr = False;
@@ -808,11 +840,11 @@
 
    /* If an address error has happened, report it. */
    if (aerr) {
-      MAC_(record_address_error)( VG_(get_current_tid)(), a, 2, False );
+      MAC_(record_address_error)( VG_(get_current_tid)(), a, 2, isWrite );
    }
 }
 
-static void ac_ACCESS1_SLOWLY ( Addr a )
+static void ac_ACCESS1_SLOWLY ( Addr a, Bool isWrite)
 {
    /* Check the address for validity. */
    Bool aerr = False;
@@ -822,7 +854,7 @@
 
    /* If an address error has happened, report it. */
    if (aerr) {
-      MAC_(record_address_error)( VG_(get_current_tid)(), a, 1, False );
+      MAC_(record_address_error)( VG_(get_current_tid)(), a, 1, isWrite );
    }
 }
 
@@ -831,8 +863,8 @@
    FPU load and store checks, called from generated code.
    ------------------------------------------------------------------ */
 
-__attribute__ ((regparm(2)))
-static void ac_fpu_ACCESS_check ( Addr addr, Int size )
+static __inline__ 
+void ac_fpu_ACCESS_check ( Addr addr, Int size, Bool isWrite )
 {
    /* Ensure the read area is both addressible and valid (ie,
       readable).  If there's an address error, don't report a value
@@ -849,7 +881,7 @@
    PROF_EVENT(90);
 
 #  ifdef VG_DEBUG_MEMORY
-   ac_fpu_ACCESS_check_SLOWLY ( addr, size );
+   ac_fpu_ACCESS_check_SLOWLY ( addr, size, isWrite );
 #  else
 
    if (size == 4) {
@@ -863,7 +895,7 @@
       /* Properly aligned and addressible. */
       return;
      slow4:
-      ac_fpu_ACCESS_check_SLOWLY ( addr, 4 );
+      ac_fpu_ACCESS_check_SLOWLY ( addr, 4, isWrite );
       return;
    }
 
@@ -887,7 +919,7 @@
       /* Both halves properly aligned and addressible. */
       return;
      slow8:
-      ac_fpu_ACCESS_check_SLOWLY ( addr, 8 );
+      ac_fpu_ACCESS_check_SLOWLY ( addr, 8, isWrite );
       return;
    }
 
@@ -895,13 +927,13 @@
       cases go quickly.  */
    if (size == 2) {
       PROF_EVENT(93);
-      ac_fpu_ACCESS_check_SLOWLY ( addr, 2 );
+      ac_fpu_ACCESS_check_SLOWLY ( addr, 2, isWrite );
       return;
    }
 
    if (size == 16 || size == 10 || size == 28 || size == 108) {
       PROF_EVENT(94);
-      ac_fpu_ACCESS_check_SLOWLY ( addr, size );
+      ac_fpu_ACCESS_check_SLOWLY ( addr, size, isWrite );
       return;
    }
 
@@ -910,12 +942,23 @@
 #  endif
 }
 
+__attribute__ ((regparm(2)))
+static void ac_fpu_READ_check ( Addr addr, Int size )
+{
+   ac_fpu_ACCESS_check ( addr, size, /*isWrite*/False );
+}
+
+__attribute__ ((regparm(2)))
+static void ac_fpu_WRITE_check ( Addr addr, Int size )
+{
+   ac_fpu_ACCESS_check ( addr, size, /*isWrite*/True );
+}
 
 /* ---------------------------------------------------------------------
    Slow, general cases for FPU access checks.
    ------------------------------------------------------------------ */
 
-void ac_fpu_ACCESS_check_SLOWLY ( Addr addr, Int size )
+void ac_fpu_ACCESS_check_SLOWLY ( Addr addr, Int size, Bool isWrite )
 {
    Int  i;
    Bool aerr = False;
@@ -927,7 +970,7 @@
    }
 
    if (aerr) {
-      MAC_(record_address_error)( VG_(get_current_tid)(), addr, size, False );
+      MAC_(record_address_error)( VG_(get_current_tid)(), addr, size, isWrite );
    }
 }
 
@@ -945,6 +988,7 @@
    Int         i;
    UInstr*     u_in;
    Int         t_addr, t_size;
+   Addr        helper;
 
    cb = VG_(setup_UCodeBlock)(cb_in);
 
@@ -960,28 +1004,33 @@
          /* For memory-ref instrs, copy the data_addr into a temporary to be
           * passed to the helper at the end of the instruction.
           */
-         case LOAD: 
-            t_addr = u_in->val1; 
-            goto do_LOAD_or_STORE;
-         case STORE: t_addr = u_in->val2;
-            goto do_LOAD_or_STORE;
-           do_LOAD_or_STORE:
-            uInstr1(cb, CCALL, 0, TempReg, t_addr);
+         case LOAD:
             switch (u_in->size) {
-               case 4: uCCall(cb, (Addr) & ac_helperc_ACCESS4, 1, 1, False );
-                  break;
-               case 2: uCCall(cb, (Addr) & ac_helperc_ACCESS2, 1, 1, False );
-                  break;
-               case 1: uCCall(cb, (Addr) & ac_helperc_ACCESS1, 1, 1, False );
-                  break;
-               default: 
-                  VG_(skin_panic)("addrcheck::SK_(instrument):LOAD/STORE");
+               case 4:  helper = (Addr)ac_helperc_LOAD4; break;
+               case 2:  helper = (Addr)ac_helperc_LOAD2; break;
+               case 1:  helper = (Addr)ac_helperc_LOAD1; break;
+               default: VG_(skin_panic)("addrcheck::SK_(instrument):LOAD");
             }
+            uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
+            uCCall (cb, helper, 1, 1, False );
+            VG_(copy_UInstr)(cb, u_in);
+            break;
+
+         case STORE:
+            switch (u_in->size) {
+               case 4:  helper = (Addr)ac_helperc_STORE4; break;
+               case 2:  helper = (Addr)ac_helperc_STORE2; break;
+               case 1:  helper = (Addr)ac_helperc_STORE1; break;
+               default: VG_(skin_panic)("addrcheck::SK_(instrument):STORE");
+            }
+            uInstr1(cb, CCALL, 0, TempReg, u_in->val2);
+            uCCall (cb, helper, 1, 1, False );
             VG_(copy_UInstr)(cb, u_in);
             break;
 
 	 case SSE3ag_MemRd_RegWr:
             sk_assert(u_in->size == 4 || u_in->size == 8);
+            helper = (Addr)ac_fpu_READ_check;
 	    goto do_Access_ARG1;
          do_Access_ARG1:
 	    sk_assert(u_in->tag1 == TempReg);
@@ -990,16 +1039,23 @@
 	    uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
 	    uLiteral(cb, u_in->size);
             uInstr2(cb, CCALL, 0, TempReg, t_addr, TempReg, t_size);
-            uCCall(cb, (Addr) & ac_fpu_ACCESS_check, 2, 2, False );
+            uCCall(cb, helper, 2, 2, False );
             VG_(copy_UInstr)(cb, u_in);
             break;
 
          case MMX2_MemRd:
+            sk_assert(u_in->size == 4 || u_in->size == 8);
+            helper = (Addr)ac_fpu_READ_check;
+	    goto do_Access_ARG2;
          case MMX2_MemWr:
             sk_assert(u_in->size == 4 || u_in->size == 8);
+            helper = (Addr)ac_fpu_WRITE_check;
 	    goto do_Access_ARG2;
          case FPU_R:
+            helper = (Addr)ac_fpu_READ_check;
+            goto do_Access_ARG2;
          case FPU_W:
+            helper = (Addr)ac_fpu_WRITE_check;
             goto do_Access_ARG2;
          do_Access_ARG2:
 	    sk_assert(u_in->tag2 == TempReg);
@@ -1008,25 +1064,27 @@
 	    uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
 	    uLiteral(cb, u_in->size);
             uInstr2(cb, CCALL, 0, TempReg, t_addr, TempReg, t_size);
-            uCCall(cb, (Addr) & ac_fpu_ACCESS_check, 2, 2, False );
+            uCCall(cb, helper, 2, 2, False );
             VG_(copy_UInstr)(cb, u_in);
             break;
 
          case SSE3a_MemRd: // this one causes trouble
          case SSE2a_MemRd:
+            helper = (Addr)ac_fpu_READ_check;
+	    goto do_Access_ARG3;
          case SSE2a_MemWr:
 	 case SSE3a_MemWr:
-	    sk_assert(u_in->size == 4 || u_in->size == 8 
-                      || u_in->size == 16);
+            helper = (Addr)ac_fpu_WRITE_check;
 	    goto do_Access_ARG3;
          do_Access_ARG3:
+	    sk_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16);
             sk_assert(u_in->tag3 == TempReg);
             t_addr = u_in->val3;
             t_size = newTemp(cb);
 	    uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
 	    uLiteral(cb, u_in->size);
             uInstr2(cb, CCALL, 0, TempReg, t_addr, TempReg, t_size);
-            uCCall(cb, (Addr) & ac_fpu_ACCESS_check, 2, 2, False );
+            uCCall(cb, helper, 2, 2, False );
             VG_(copy_UInstr)(cb, u_in);
             break;
 
@@ -1288,10 +1346,14 @@
    VG_(track_pre_mem_write)        ( & ac_check_is_writable );
    VG_(track_post_mem_write)       ( & ac_make_accessible );
 
-   VG_(register_compact_helper)((Addr) & ac_helperc_ACCESS4);
-   VG_(register_compact_helper)((Addr) & ac_helperc_ACCESS2);
-   VG_(register_compact_helper)((Addr) & ac_helperc_ACCESS1);
-   VG_(register_compact_helper)((Addr) & ac_fpu_ACCESS_check);
+   VG_(register_compact_helper)((Addr) & ac_helperc_LOAD4);
+   VG_(register_compact_helper)((Addr) & ac_helperc_LOAD2);
+   VG_(register_compact_helper)((Addr) & ac_helperc_LOAD1);
+   VG_(register_compact_helper)((Addr) & ac_helperc_STORE4);
+   VG_(register_compact_helper)((Addr) & ac_helperc_STORE2);
+   VG_(register_compact_helper)((Addr) & ac_helperc_STORE1);
+   VG_(register_noncompact_helper)((Addr) & ac_fpu_READ_check);
+   VG_(register_noncompact_helper)((Addr) & ac_fpu_WRITE_check);
 
    VGP_(register_profile_event) ( VgpSetMem,   "set-mem-perms" );
    VGP_(register_profile_event) ( VgpCheckMem, "check-mem-perms" );