All pastes #1059964 Raw Edit

valgrind 3.3.1 mmt

public text v1 · immutable
#1059964 ·published 2008-07-01 22:01 UTC
rendered paste body
diff --git a/Makefile.am b/Makefile.am
index ccdf027..c4142a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,7 +9,8 @@ TOOLS =		memcheck \
 		massif \
 		lackey \
 		none \
-		helgrind
+		helgrind \
+		mmt
 
 EXP_TOOLS = 	exp-omega \
 		exp-drd
diff --git a/configure b/configure
index 1f13ea0..be8d6ec 100755
--- a/configure
+++ b/configure
@@ -721,13 +721,13 @@ echo X"$0" |
   	  /^X\(\/\).*/{ s//\1/; q; }
   	  s/.*/./; q'`
   srcdir=$ac_confdir
-  if test ! -r $srcdir/$ac_unique_file; then
+  if test ! -r "$srcdir/$ac_unique_file"; then
     srcdir=..
   fi
 else
   ac_srcdir_defaulted=no
 fi
-if test ! -r $srcdir/$ac_unique_file; then
+if test ! -r "$srcdir/$ac_unique_file"; then
   if test "$ac_srcdir_defaulted" = yes; then
     { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
    { (exit 1); exit 1; }; }
@@ -736,7 +736,7 @@ if test ! -r $srcdir/$ac_unique_file; then
    { (exit 1); exit 1; }; }
   fi
 fi
-(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+(cd $srcdir && test -r "./$ac_unique_file") 2>/dev/null ||
   { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
    { (exit 1); exit 1; }; }
 srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
@@ -7518,7 +7518,7 @@ fi
 
 # -------------------- ok.  We're done. --------------------
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        ac_config_files="$ac_config_files Makefile valgrind.spec valgrind.pc docs/Makefile docs/lib/Makefile docs/images/Makefile docs/internals/Makefile docs/xml/Makefile tests/Makefile tests/vg_regtest perf/Makefile perf/vg_perf include/Makefile include/vki/Makefile auxprogs/Makefile coregrind/Makefile memcheck/Makefile memcheck/tests/Makefile memcheck/tests/amd64/Makefile memcheck/tests/ppc32/Makefile memcheck/tests/ppc64/Makefile memcheck/tests/x86/Makefile memcheck/docs/Makefile cachegrind/Makefile cachegrind/tests/Makefile cachegrind/tests/amd64/Makefile cachegrind/tests/ppc32/Makefile cachegrind/tests/ppc64/Makefile cachegrind/tests/x86/Makefile cachegrind/docs/Makefile cachegrind/cg_annotate callgrind/Makefile callgrind/callgrind_annotate callgrind/callgrind_control callgrind/tests/Makefile callgrind/docs/Makefile helgrind/Makefile helgrind/tests/Makefile helgrind/docs/Makefile massif/Makefile massif/tests/Makefile massif/perf/Makefile massif/docs/Makefile massif/ms_print lackey/Makefile lackey/tests/Makefile lackey/docs/Makefile none/Makefile none/tests/Makefile none/tests/amd64/Makefile none/tests/ppc32/Makefile none/tests/ppc64/Makefile none/tests/x86/Makefile none/docs/Makefile exp-omega/Makefile exp-omega/tests/Makefile exp-omega/docs/Makefile exp-drd/Makefile exp-drd/docs/Makefile exp-drd/tests/Makefile"
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      ac_config_files="$ac_config_files Makefile valgrind.spec valgrind.pc docs/Makefile docs/lib/Makefile docs/images/Makefile docs/internals/Makefile docs/xml/Makefile tests/Makefile tests/vg_regtest perf/Makefile perf/vg_perf include/Makefile include/vki/Makefile auxprogs/Makefile coregrind/Makefile memcheck/Makefile memcheck/tests/Makefile memcheck/tests/amd64/Makefile memcheck/tests/ppc32/Makefile memcheck/tests/ppc64/Makefile memcheck/tests/x86/Makefile memcheck/docs/Makefile cachegrind/Makefile cachegrind/tests/Makefile cachegrind/tests/amd64/Makefile cachegrind/tests/ppc32/Makefile cachegrind/tests/ppc64/Makefile cachegrind/tests/x86/Makefile cachegrind/docs/Makefile cachegrind/cg_annotate callgrind/Makefile callgrind/callgrind_annotate callgrind/callgrind_control callgrind/tests/Makefile callgrind/docs/Makefile helgrind/Makefile helgrind/tests/Makefile helgrind/docs/Makefile massif/Makefile massif/tests/Makefile massif/perf/Makefile massif/docs/Makefile massif/ms_print lackey/Makefile lackey/tests/Makefile lackey/docs/Makefile mmt/Makefile mmt/tests/Makefile mmt/docs/Makefile none/Makefile none/tests/Makefile none/tests/amd64/Makefile none/tests/ppc32/Makefile none/tests/ppc64/Makefile none/tests/x86/Makefile none/docs/Makefile exp-omega/Makefile exp-omega/tests/Makefile exp-omega/docs/Makefile exp-drd/Makefile exp-drd/docs/Makefile exp-drd/tests/Makefile"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -8213,6 +8213,9 @@ do
   "lackey/Makefile" ) CONFIG_FILES="$CONFIG_FILES lackey/Makefile" ;;
   "lackey/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES lackey/tests/Makefile" ;;
   "lackey/docs/Makefile" ) CONFIG_FILES="$CONFIG_FILES lackey/docs/Makefile" ;;
+  "mmt/Makefile" ) CONFIG_FILES="$CONFIG_FILES mmt/Makefile" ;;
+  "mmt/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES mmt/tests/Makefile" ;;
+  "mmt/docs/Makefile" ) CONFIG_FILES="$CONFIG_FILES mmt/docs/Makefile" ;;
   "none/Makefile" ) CONFIG_FILES="$CONFIG_FILES none/Makefile" ;;
   "none/tests/Makefile" ) CONFIG_FILES="$CONFIG_FILES none/tests/Makefile" ;;
   "none/tests/amd64/Makefile" ) CONFIG_FILES="$CONFIG_FILES none/tests/amd64/Makefile" ;;
diff --git a/configure.in b/configure.in
index 75cc768..2ebec75 100644
--- a/configure.in
+++ b/configure.in
@@ -1024,6 +1024,9 @@ AC_OUTPUT(
    lackey/Makefile
    lackey/tests/Makefile
    lackey/docs/Makefile
+   mmt/Makefile
+   mmt/tests/Makefile
+   mmt/docs/Makefile
    none/Makefile
    none/tests/Makefile
    none/tests/amd64/Makefile
diff --git a/coregrind/m_libcbase.c b/coregrind/m_libcbase.c
index d895bd3..673a7f1 100644
--- a/coregrind/m_libcbase.c
+++ b/coregrind/m_libcbase.c
@@ -217,6 +217,26 @@ Long VG_(atoll16) ( Char* str )
    return VG_(strtoll16)(str, NULL);
 }
 
+Long VG_(strtoll) ( Char* str, Char **endptr, Int base )
+{
+   Bool neg = False;
+   Long n = 0;
+   if (*str == '-') { str++; neg = True; };
+   if (base == 16 && *str == '0' && *(str + 1) == 'x') { str += 2; }
+   while ((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f')) {
+      n = base * n;
+      if (*str <= '9')
+        n += (*str - '0');
+      else
+        n += (*str - 'a' + 10);
+      str++;
+   }
+   if (neg) n = -n;
+   if (endptr)
+      *endptr = str;
+   return n;
+}
+
 Long VG_(atoll36) ( Char* str )
 {
    return VG_(strtoll36)(str, NULL);
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 95a6d3f..9d8f1aa 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -160,7 +160,7 @@ ML_(notify_aspacem_and_tool_of_mmap) ( Addr a, SizeT len, UInt prot,
    ww = toBool(prot & VKI_PROT_WRITE);
    xx = toBool(prot & VKI_PROT_EXEC);
 
-   VG_TRACK( new_mem_mmap, a, len, rr, ww, xx );
+   VG_TRACK( new_mem_mmap, a, len, offset, rr, ww, xx );
 
    if (d)
       VG_(discard_translations)( (Addr64)a, (ULong)len,
@@ -303,7 +303,7 @@ SysRes do_mremap( Addr old_addr, SizeT old_len,
          VG_TRACK( copy_mem_remap, old_addr, new_addr, 
                                    MIN_SIZET(old_len,new_len) );
          if (new_len > old_len)
-            VG_TRACK( new_mem_mmap, new_addr+old_len, new_len-old_len,
+            VG_TRACK( new_mem_mmap, new_addr+old_len, new_len-old_len, 0,
                       old_seg->hasR, old_seg->hasW, old_seg->hasX );
          VG_TRACK(die_mem_munmap, old_addr, old_len);
          if (d) {
@@ -345,7 +345,7 @@ SysRes do_mremap( Addr old_addr, SizeT old_len,
    if (ok && advised == needA) {
       ok = VG_(am_extend_map_client)( &d, (NSegment*)old_seg, needL );
       if (ok) {
-         VG_TRACK( new_mem_mmap, needA, needL, 
+         VG_TRACK( new_mem_mmap, needA, needL, 0,
                                  old_seg->hasR, 
                                  old_seg->hasW, old_seg->hasX );
          if (d) 
@@ -366,7 +366,7 @@ SysRes do_mremap( Addr old_addr, SizeT old_len,
          VG_TRACK( copy_mem_remap, old_addr, advised, 
                                    MIN_SIZET(old_len,new_len) );
          if (new_len > old_len)
-            VG_TRACK( new_mem_mmap, advised+old_len, new_len-old_len,
+            VG_TRACK( new_mem_mmap, advised+old_len, new_len-old_len, 0,
                       old_seg->hasR, old_seg->hasW, old_seg->hasX );
          VG_TRACK(die_mem_munmap, old_addr, old_len);
          if (d) {
@@ -405,7 +405,7 @@ SysRes do_mremap( Addr old_addr, SizeT old_len,
    ok = VG_(am_extend_map_client)( &d, (NSegment*)old_seg, needL );
    if (!ok)
       goto eNOMEM;
-   VG_TRACK( new_mem_mmap, needA, needL, 
+   VG_TRACK( new_mem_mmap, needA, needL, 0,
                            old_seg->hasR, old_seg->hasW, old_seg->hasX );
    if (d)
       VG_(discard_translations)( needA, needL, "do_remap(6)" );
@@ -1694,7 +1694,7 @@ ML_(generic_POST_sys_shmat) ( ThreadId tid,
 
       /* we don't distinguish whether it's read-only or
        * read-write -- it doesn't matter really. */
-      VG_TRACK( new_mem_mmap, res, segmentSize, True, True, False );
+      VG_TRACK( new_mem_mmap, res, segmentSize, 0, True, True, False );
       if (d)
          VG_(discard_translations)( (Addr64)res, 
                                     (ULong)VG_PGROUNDUP(segmentSize),
diff --git a/coregrind/m_tooliface.c b/coregrind/m_tooliface.c
index 2aa74e9..ee2ca24 100644
--- a/coregrind/m_tooliface.c
+++ b/coregrind/m_tooliface.c
@@ -289,7 +289,7 @@ void VG_(fn)(VG_REGPARM(1) void(*f)(args)) \
 DEF(track_new_mem_startup,       Addr, SizeT, Bool, Bool, Bool)
 DEF(track_new_mem_stack_signal,  Addr, SizeT)
 DEF(track_new_mem_brk,           Addr, SizeT)
-DEF(track_new_mem_mmap,          Addr, SizeT, Bool, Bool, Bool)
+DEF(track_new_mem_mmap,          Addr, SizeT, Off64T, Bool, Bool, Bool)
 
 DEF(track_copy_mem_remap,        Addr, Addr, SizeT)
 DEF(track_change_mem_mprotect,   Addr, SizeT, Bool, Bool, Bool)
diff --git a/coregrind/pub_core_tooliface.h b/coregrind/pub_core_tooliface.h
index 7f77fed..13cb96b 100644
--- a/coregrind/pub_core_tooliface.h
+++ b/coregrind/pub_core_tooliface.h
@@ -164,7 +164,7 @@ typedef struct {
    void (*track_new_mem_startup)     (Addr, SizeT, Bool, Bool, Bool);
    void (*track_new_mem_stack_signal)(Addr, SizeT);
    void (*track_new_mem_brk)         (Addr, SizeT);
-   void (*track_new_mem_mmap)        (Addr, SizeT, Bool, Bool, Bool);
+   void (*track_new_mem_mmap)        (Addr, SizeT, Off64T, Bool, Bool, Bool);
 
    void (*track_copy_mem_remap)      (Addr src, Addr dst, SizeT);
    void (*track_change_mem_mprotect) (Addr, SizeT, Bool, Bool, Bool);
diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c
index f246e66..884e0ce 100644
--- a/helgrind/hg_main.c
+++ b/helgrind/hg_main.c
@@ -5432,7 +5432,7 @@ void evh__new_mem ( Addr a, SizeT len ) {
 
 static
 void evh__new_mem_w_perms ( Addr a, SizeT len, 
-                            Bool rr, Bool ww, Bool xx ) {
+			    Bool rr, Bool ww, Bool xx ) {
    if (SHOW_EVENTS >= 1)
       VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n",
                   (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
@@ -5443,6 +5443,18 @@ void evh__new_mem_w_perms ( Addr a, SizeT len,
 }
 
 static
+void evh__new_mem_w_perms_mmap ( Addr a, SizeT len, 
+				 Off64T offset, Bool rr, Bool ww, Bool xx ) {
+   if (SHOW_EVENTS >= 1)
+      VG_(printf)("evh__new_mem_w_perms_mmap(%p, %lu, %d,%d,%d)\n",
+                  (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
+   if (rr || ww || xx)
+      shadow_mem_make_New( get_current_Thread(), a, len );
+   if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
+      all__sanity_check("evh__new_mem_w_perms_mmap-post");
+}
+
+static
 void evh__set_perms ( Addr a, SizeT len,
                       Bool rr, Bool ww, Bool xx ) {
    if (SHOW_EVENTS >= 1)
@@ -8807,7 +8819,7 @@ static void hg_pre_clo_init ( void )
    VG_(track_new_mem_startup)     ( evh__new_mem_w_perms );
    VG_(track_new_mem_stack_signal)( evh__die_mem );
    VG_(track_new_mem_brk)         ( evh__new_mem );
-   VG_(track_new_mem_mmap)        ( evh__new_mem_w_perms );
+   VG_(track_new_mem_mmap)        ( evh__new_mem_w_perms_mmap );
    VG_(track_new_mem_stack)       ( evh__new_mem );
 
    // FIXME: surely this isn't thread-aware
diff --git a/include/pub_tool_libcbase.h b/include/pub_tool_libcbase.h
index f262377..dcfa011 100644
--- a/include/pub_tool_libcbase.h
+++ b/include/pub_tool_libcbase.h
@@ -65,6 +65,7 @@ extern double VG_(strtod)  ( Char* str, Char** endptr );
 
 extern Long  VG_(atoll)   ( Char* str ); // base 10
 extern Long  VG_(atoll16) ( Char* str ); // base 16; leading 0x accepted
+extern Long  VG_(strtoll) ( Char* str, Char** endptr, Int base );
 extern Long  VG_(atoll36) ( Char* str ); // base 36
 
 /* ---------------------------------------------------------------------
diff --git a/include/pub_tool_options.h b/include/pub_tool_options.h
index ed5c37e..338d97d 100644
--- a/include/pub_tool_options.h
+++ b/include/pub_tool_options.h
@@ -60,6 +60,11 @@
       if ('\0' != s[0] || (qq_var) != n) VG_(err_bad_option)(qq_arg); \
    }
 
+#define VG_HEX_CLO(qq_arg, qq_option, qq_var) \
+   if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
+      (qq_var) = (Int)VG_(strtoll)( &qq_arg[ VG_(strlen)(qq_option)+1 ], NULL, 16 ); \
+   }
+
 /* Bounded integer arg */
 #define VG_BNUM_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \
    if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
@@ -94,6 +99,14 @@
       if ('\0' != s[0]) VG_(err_bad_option)(qq_arg); \
    }
 
+/* Bounded integer arg, given in hex */
+#define VG_BHEX_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \
+   if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
+      (qq_var) = (Int)VG_(strtoll)( &qq_arg[ VG_(strlen)(qq_option)+1 ], NULL, 16 ); \
+      if ((qq_var) < (qq_lo)) (qq_var) = (qq_lo); \
+      if ((qq_var) > (qq_hi)) (qq_var) = (qq_hi); \
+   }
+
 /* Bool arg whose value is denoted by the exact presence of the given string. */
 #define VG_XACT_CLO(qq_arg, qq_option, qq_var) \
    if (VG_CLO_STREQ(qq_arg, qq_option)) { \
diff --git a/include/pub_tool_tooliface.h b/include/pub_tool_tooliface.h
index cfc57d7..7564025 100644
--- a/include/pub_tool_tooliface.h
+++ b/include/pub_tool_tooliface.h
@@ -475,7 +475,7 @@ void VG_(track_new_mem_startup)     (void(*f)(Addr a, SizeT len,
                                               Bool rr, Bool ww, Bool xx));
 void VG_(track_new_mem_stack_signal)(void(*f)(Addr a, SizeT len));
 void VG_(track_new_mem_brk)         (void(*f)(Addr a, SizeT len));
-void VG_(track_new_mem_mmap)        (void(*f)(Addr a, SizeT len,
+void VG_(track_new_mem_mmap)        (void(*f)(Addr a, SizeT len, Off64T offset,
                                               Bool rr, Bool ww, Bool xx));
 
 void VG_(track_copy_mem_remap)      (void(*f)(Addr from, Addr to, SizeT len));
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index b7e7006..78daaed 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -2539,7 +2539,7 @@ void mc_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
 }
 
 static
-void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
+void mc_new_mem_mmap ( Addr a, SizeT len, Off64T o, Bool rr, Bool ww, Bool xx )
 {
    MC_(make_mem_defined)(a, len);
 }
diff --git a/mmt/Makefile.am b/mmt/Makefile.am
new file mode 100644
index 0000000..e8f7101
--- /dev/null
+++ b/mmt/Makefile.am
@@ -0,0 +1,47 @@
+include $(top_srcdir)/Makefile.tool.am
+
+noinst_PROGRAMS = 
+if VGP_X86_LINUX
+noinst_PROGRAMS += mmt-x86-linux
+endif
+if VGP_AMD64_LINUX
+noinst_PROGRAMS += mmt-amd64-linux
+endif
+if VGP_PPC32_LINUX
+noinst_PROGRAMS += mmt-ppc32-linux
+endif
+if VGP_PPC64_LINUX
+noinst_PROGRAMS += mmt-ppc64-linux
+endif
+
+MMT_SOURCES_COMMON = mmt_main.c
+
+mmt_x86_linux_SOURCES      = $(MMT_SOURCES_COMMON)
+mmt_x86_linux_CPPFLAGS     = $(AM_CPPFLAGS_X86_LINUX)
+mmt_x86_linux_CFLAGS       = $(AM_CFLAGS_X86_LINUX)
+mmt_x86_linux_DEPENDENCIES = $(COREGRIND_LIBS_X86_LINUX)
+mmt_x86_linux_LDADD        = $(TOOL_LDADD_X86_LINUX)
+mmt_x86_linux_LDFLAGS      = $(TOOL_LDFLAGS_X86_LINUX)
+
+mmt_amd64_linux_SOURCES      = $(MMT_SOURCES_COMMON)
+mmt_amd64_linux_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_LINUX)
+mmt_amd64_linux_CFLAGS       = $(AM_CFLAGS_AMD64_LINUX)
+mmt_amd64_linux_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_LINUX)
+mmt_amd64_linux_LDADD        = $(TOOL_LDADD_AMD64_LINUX)
+mmt_amd64_linux_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_LINUX)
+
+mmt_ppc32_linux_SOURCES      = $(MMT_SOURCES_COMMON)
+mmt_ppc32_linux_CPPFLAGS     = $(AM_CPPFLAGS_PPC32_LINUX)
+mmt_ppc32_linux_CFLAGS       = $(AM_CFLAGS_PPC32_LINUX)
+mmt_ppc32_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC32_LINUX)
+mmt_ppc32_linux_LDADD        = $(TOOL_LDADD_PPC32_LINUX)
+mmt_ppc32_linux_LDFLAGS      = $(TOOL_LDFLAGS_PPC32_LINUX)
+
+mmt_ppc64_linux_SOURCES      = $(MMT_SOURCES_COMMON)
+mmt_ppc64_linux_CPPFLAGS     = $(AM_CPPFLAGS_PPC64_LINUX)
+mmt_ppc64_linux_CFLAGS       = $(AM_CFLAGS_PPC64_LINUX)
+mmt_ppc64_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_LINUX)
+mmt_ppc64_linux_LDADD        = $(TOOL_LDADD_PPC64_LINUX)
+mmt_ppc64_linux_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_LINUX)
+
+mmtincludedir = $(includedir)/valgrind
diff --git a/mmt/mmt_main.c b/mmt/mmt_main.c
new file mode 100644
index 0000000..32bfb7a
--- /dev/null
+++ b/mmt/mmt_main.c
@@ -0,0 +1,385 @@
+/*
+ * vim:sw=3 ts=3 sts=3 noexpandtab
+ */
+
+/*--------------------------------------------------------------------*/
+/*--- mmaptrace: The mmaptracer tool.                   mmt_main.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   Copyright (C) 2006 Dave Airlie
+
+   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 "pub_tool_basics.h"
+#include "pub_tool_libcprint.h"
+#include "pub_tool_libcassert.h"
+#include "pub_tool_tooliface.h"
+#include "pub_tool_debuginfo.h"
+#include "pub_tool_libcbase.h"
+#include "pub_tool_options.h"
+#include "pub_tool_machine.h"     // VG_(fnptr_to_fnentry)
+
+#define MAX_ITEMS 100
+
+static struct mmt_memmap {
+	 Bool initialized;
+	 Addr offset;
+	 Addr addr;
+	 SizeT len;
+} mmt_gpu_reg[MAX_ITEMS];
+
+static UInt current_item;
+
+static struct mmt_op {
+	Addr offset;
+	SizeT size;
+	UInt value;
+	ULong reps;
+	UInt store;
+} last_op;
+
+
+/* Command line options */
+UInt mmt_clo_offset = (UInt) -1;
+
+static struct mmt_memmap *find_mmap(Addr addr)
+{
+	struct mmt_memmap *ptr = NULL;
+	UInt i;
+
+	for (i = 0; i < MAX_ITEMS; i++) {
+		 ptr = &mmt_gpu_reg[i];
+
+		 if (!ptr->initialized) {
+			 /* since we cannot un-init entries in the array,
+			  * we can return once we hit the first uninitialized
+			  * item -- there can't be initialized items following it.
+			  */
+			 return NULL;
+		 }
+
+		 if ((addr > ptr->addr) && (addr < ptr->addr + ptr->len))
+			return ptr;
+	}
+
+	return NULL;
+}
+
+static void
+print_op(void)
+{
+	int i;
+
+	if (last_op.reps > 5) {
+		VG_(printf)(" ... repeated %lu times total\n", last_op.reps);
+	}
+	else {
+		for (i = 0; i < last_op.reps; i++) {
+			VG_(printf)("%s: %p, %d, %p\n", last_op.store ? "store" : "load",
+			            last_op.offset, last_op.size, last_op.value);
+		}
+	}
+}
+
+static VG_REGPARM(2) void
+trace_store(Addr addr, SizeT size, UInt value)
+{
+	struct mmt_memmap *ptr;
+
+	ptr = find_mmap(addr);
+	if (!ptr)
+		return;
+
+	if (last_op.offset != (addr - ptr->addr) || last_op.size != size ||
+       last_op.value != value || !last_op.store) {
+		print_op();
+
+		last_op.offset = addr - ptr->addr;
+		last_op.size = size;
+		last_op.value = value;
+		last_op.store = 1;
+		last_op.reps = 1;
+	}
+	else {
+		last_op.reps++;
+
+		if (last_op.reps % 1000 == 0)
+			VG_(printf)(" ... repeating: %d times\n", last_op.reps);
+		if (last_op.reps == ~0UL)
+			VG_(printf)(" ... overflow!\n");
+	}
+}
+
+static VG_REGPARM(2) void
+trace_load(Addr addr, SizeT size)
+{
+	struct mmt_memmap *ptr;
+	UInt value;
+
+	ptr = find_mmap(addr);
+	if (!ptr)
+		return;
+
+	switch (size) {
+		case 1:
+			value = *(UChar*) addr;
+			break;
+		case 2:
+			value = *(UShort*) addr;
+			break;
+		case 4:
+			value = *(UInt*) addr;
+			break;
+		case 8:
+			value = *(ULong*) addr;
+		default:
+			return;
+	}
+
+	if (last_op.offset != (addr - ptr->addr) || last_op.size != size ||
+       last_op.value != value || last_op.store) {
+		print_op();
+
+		last_op.offset = addr - ptr->addr;
+		last_op.size = size;
+		last_op.value = value;
+		last_op.store = 0;
+		last_op.reps = 1;
+	}
+	else {
+		last_op.reps++;
+
+		if (last_op.reps % 1000 == 0)
+			VG_(printf)(" ... repeating: %d times\n", last_op.reps);
+		if (last_op.reps == ~0UL)
+			VG_(printf)(" ... overflow!\n");
+	}
+}
+
+static void
+handle_load(IRSB* bb, IRExpr* addr, Int size)
+{
+	IRExpr** argv = mkIRExprVec_2(addr, mkIRExpr_HWord(size));
+	IRDirty* di = unsafeIRDirty_0_N(2,
+	                                "trace_load",
+	                               VG_(fnptr_to_fnentry)(trace_load),
+	                               argv);
+	addStmtToIRSB(bb, IRStmt_Dirty(di));
+}
+
+static void
+handle_store(IRSB*bb, IRExpr* addr, Int size, IRExpr* data)
+{
+	IRExpr** argv = mkIRExprVec_3(addr, mkIRExpr_HWord(size), data);
+	IRDirty* di = unsafeIRDirty_0_N(2,
+	                                "trace_store",
+	                               VG_(fnptr_to_fnentry)(trace_store),
+	                               argv);
+	addStmtToIRSB(bb, IRStmt_Dirty(di));
+}
+
+static IRSB*
+mmt_instrument(VgCallbackClosure* closure,
+               IRSB* bbIn,
+               VexGuestLayout* layout,
+               VexGuestExtents* vge,
+               IRType gWordTy, IRType hWordTy)
+{
+	IRSB* bbOut;
+	int i = 0;
+
+	if (gWordTy != hWordTy) {
+		/* We don't currently support this case. */
+		VG_(tool_panic)("host/guest word size mismatch");
+	}
+	if (gWordTy != Ity_I32 && gWordTy != Ity_I64) {
+		VG_(tool_panic)("word size must be 32 or 64 bits");
+	}
+
+	/* Set up BB */
+	bbOut = deepCopyIRSBExceptStmts(bbIn);
+
+	/* Copy verbatim any IR preamble preceding the first IMark */
+	while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
+		addStmtToIRSB(bbOut, bbIn->stmts[i]);
+		i++;
+	}
+
+	for (; i < bbIn->stmts_used; i++) {
+		IRStmt* st = bbIn->stmts[i];
+		IRExpr* data_expr;
+		IRType arg_ty;
+		IRTemp t = IRTemp_INVALID;
+		IRStmt* cast = NULL;
+
+		if (!st)
+			continue;
+
+		if (st->tag == Ist_Store) {
+			arg_ty = typeOfIRExpr(bbIn->tyenv, st->Ist.Store.data);
+
+			data_expr = st->Ist.Store.data;
+
+			/* convert data_expr into a 64 bit value */
+			switch (arg_ty) {
+				case Ity_I8:
+					if (gWordTy == Ity_I32) {
+						t = newIRTemp(bbOut->tyenv, Ity_I32);
+						cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_8Uto32, data_expr));
+					}
+					else {
+						t = newIRTemp(bbOut->tyenv, Ity_I64);
+						cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_8Uto64, data_expr));
+					}
+					break;
+				case Ity_I16:
+					if (gWordTy == Ity_I32) {
+						t = newIRTemp(bbOut->tyenv, Ity_I32);
+						cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_16Uto32, data_expr));
+					}
+					else {
+						t = newIRTemp(bbOut->tyenv, Ity_I64);
+						cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_16Uto64, data_expr));
+					}
+					break;
+				case Ity_I32:
+					if (gWordTy == Ity_I64) {
+						t = newIRTemp(bbOut->tyenv, Ity_I64);
+						cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_32Uto64, data_expr));
+					}
+					break;
+				case Ity_I64:
+					if (gWordTy == Ity_I64) {
+						break;
+					}
+				default:
+					/* since we only support stores up to the guest word size, we
+                * will never have to evaluate the data_expr that this case
+					 * generates.
+					 */
+					if (gWordTy == Ity_I32) {
+						t = newIRTemp(bbOut->tyenv, Ity_I32);
+						cast = IRStmt_WrTmp(t, IRExpr_Const (IRConst_U32 (0)));
+					}
+					else {
+						t = newIRTemp(bbOut->tyenv, Ity_I64);
+						cast = IRStmt_WrTmp(t, IRExpr_Const (IRConst_U64 (0)));
+					}
+					break;
+			}
+
+			if (cast) {
+				addStmtToIRSB(bbOut, cast);
+				data_expr = IRExpr_RdTmp(t);
+			}
+
+			handle_store(bbOut, st->Ist.Store.addr,
+			             sizeofIRType(arg_ty), data_expr);
+		} else if (st->tag == Ist_WrTmp) {
+			data_expr = st->Ist.WrTmp.data;
+
+			if (data_expr->tag == Iex_Load) {
+				handle_load(bbOut, data_expr->Iex.Load.addr,
+				            sizeofIRType (data_expr->Iex.Load.ty));
+			}
+		}
+
+		addStmtToIRSB(bbOut, st);
+	}
+
+	return bbOut;
+}
+
+static Bool
+mmt_process_cmd_line_option(Char* arg)
+{
+	/* FIXME: make this argument mandatory */
+	VG_BHEX_CLO(arg, "--offset", mmt_clo_offset, 0, 0xffffffff)
+	else
+		return False;
+
+	VG_(message)(Vg_UserMsg, "set offset to %lx\n", mmt_clo_offset);
+
+	return True;
+}
+
+static void
+mmt_print_usage(void)
+{
+	VG_(printf)("    --offset=<number> (number must be in decimal!)\n");
+}
+
+static void
+mmt_print_debug_usage(void)
+{
+}
+
+static void
+mmt_new_mem_mmap(Addr a, SizeT len, Off64T offset, Bool rr, Bool ww, Bool xx)
+{
+	if (offset != mmt_clo_offset)
+		return;
+
+	mmt_gpu_reg[current_item].offset = offset;
+	mmt_gpu_reg[current_item].addr = a;
+	mmt_gpu_reg[current_item].len = len;
+	mmt_gpu_reg[current_item].initialized = True;
+	current_item++;
+
+	VG_(message)(Vg_UserMsg, "got new mmap for %p, len %d, offset %p\n", a, len, offset);
+}
+
+static void
+mmt_fini(Int exitcode)
+{
+}
+
+static void mmt_post_clo_init(void)
+{
+}
+
+static void
+mmt_pre_clo_init(void)
+{
+   VG_(details_name)            ("mmaptrace");
+   VG_(details_version)         (NULL);
+   VG_(details_description)     ("an MMAP tracer");
+   VG_(details_copyright_author)(
+      "Copyright (C) 2006, and GNU GPL'd, by Dave Airlie.");
+   VG_(details_bug_reports_to)  (VG_BUGS_TO);
+
+   VG_(basic_tool_funcs)        (mmt_post_clo_init,
+                                 mmt_instrument,
+                                 mmt_fini);
+
+   VG_(needs_command_line_options)(mmt_process_cmd_line_option,
+                                   mmt_print_usage,
+                                   mmt_print_debug_usage);
+
+   VG_(track_new_mem_mmap)        (mmt_new_mem_mmap);
+
+	last_op.offset = 0;
+	last_op.size = 0;
+	last_op.value = 0;
+	last_op.store = 0;
+	last_op.reps = 0;
+}
+
+VG_DETERMINE_INTERFACE_VERSION(mmt_pre_clo_init)
diff --git a/valgrind.sh b/valgrind.sh
new file mode 100755
index 0000000..fcd0b72
--- /dev/null
+++ b/valgrind.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+valgrind --tool=mmt --offset=$1 /usr/bin/Xorg :0 -ac