- Moved several functions and variables from one source file to another.
- Created two new source files: drd_load_store.h and .c.
- Removed the header file drd_track.h.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@9153 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/drd/drd_load_store.c b/drd/drd_load_store.c
new file mode 100644
index 0000000..160b356
--- /dev/null
+++ b/drd/drd_load_store.c
@@ -0,0 +1,547 @@
+/*
+  This file is part of drd, a data race detector.
+
+  Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
+
+  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 "drd_bitmap.h"
+#include "drd_thread_bitmap.h"
+
+/* Include several source files here in order to allow the compiler to */
+/* do more inlining.                                                   */
+#include "drd_bitmap.c"
+#include "drd_load_store.h"
+#include "drd_segment.c"
+#include "drd_thread.c"
+#include "drd_vc.c"
+#include "libvex_guest_offsets.h"
+
+
+/* STACK_POINTER_OFFSET: VEX register offset for the stack pointer register. */
+#if defined(VGA_x86)
+#define STACK_POINTER_OFFSET OFFSET_x86_ESP
+#elif defined(VGA_amd64)
+#define STACK_POINTER_OFFSET OFFSET_amd64_RSP
+#elif defined(VGA_ppc32)
+#define STACK_POINTER_OFFSET ((OFFSET_ppc32_GPR0 + OFFSET_ppc32_GPR2) / 2)
+#elif defined(VGA_ppc64)
+#define STACK_POINTER_OFFSET ((OFFSET_ppc64_GPR0 + OFFSET_ppc64_GPR2) / 2)
+#else
+#error Unknown architecture.
+#endif
+
+
+/* Local variables. */
+
+static Bool s_drd_check_stack_accesses = False;
+
+
+/* Function definitions. */
+
+Bool DRD_(get_check_stack_accesses)()
+{
+  return s_drd_check_stack_accesses;
+}
+
+void DRD_(set_check_stack_accesses)(const Bool c)
+{
+  tl_assert(c == False || c == True);
+  s_drd_check_stack_accesses = c;
+}
+
+void drd_trace_mem_access(const Addr addr, const SizeT size,
+                          const BmAccessTypeT access_type)
+{
+  if (drd_is_any_traced(addr, addr + size))
+  {
+    char vc[80];
+    vc_snprint(vc, sizeof(vc), thread_get_vc(thread_get_running_tid()));
+    VG_(message)(Vg_UserMsg,
+                 "%s 0x%lx size %ld (vg %d / drd %d / vc %s)",
+                 access_type == eLoad
+                 ? "load "
+                 : access_type == eStore
+                 ? "store"
+                 : access_type == eStart
+                 ? "start"
+                 : access_type == eEnd
+                 ? "end  "
+                 : "????",
+                 addr,
+                 size,
+                 VG_(get_running_tid)(),
+                 thread_get_running_tid(),
+                 vc);
+    VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
+                               VG_(clo_backtrace_size));
+    tl_assert(DrdThreadIdToVgThreadId(thread_get_running_tid())
+              == VG_(get_running_tid)());
+  }
+}
+
+static VG_REGPARM(2) void drd_trace_mem_load(const Addr addr, const SizeT size)
+{
+  return drd_trace_mem_access(addr, size, eLoad);
+}
+
+static VG_REGPARM(2) void drd_trace_mem_store(const Addr addr,const SizeT size)
+{
+  return drd_trace_mem_access(addr, size, eStore);
+}
+
+static void drd_report_race(const Addr addr, const SizeT size,
+                            const BmAccessTypeT access_type)
+{
+  DataRaceErrInfo drei;
+
+  drei.tid  = thread_get_running_tid();
+  drei.addr = addr;
+  drei.size = size;
+  drei.access_type = access_type;
+  VG_(maybe_record_error)(VG_(get_running_tid)(),
+                          DataRaceErr,
+                          VG_(get_IP)(VG_(get_running_tid)()),
+                          "Conflicting accesses",
+                          &drei);
+}
+
+VG_REGPARM(2) void drd_trace_load(Addr addr, SizeT size)
+{
+#ifdef ENABLE_DRD_CONSISTENCY_CHECKS
+  /* The assert below has been commented out because of performance reasons.*/
+  tl_assert(thread_get_running_tid()
+            == VgThreadIdToDrdThreadId(VG_(get_running_tid())));
+#endif
+
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_load_triggers_conflict(addr, addr + size)
+      && ! drd_is_suppressed(addr, addr + size))
+  {
+    drd_report_race(addr, size, eLoad);
+  }
+}
+
+static VG_REGPARM(1) void drd_trace_load_1(Addr addr)
+{
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_load_1_triggers_conflict(addr)
+      && ! drd_is_suppressed(addr, addr + 1))
+  {
+    drd_report_race(addr, 1, eLoad);
+  }
+}
+
+static VG_REGPARM(1) void drd_trace_load_2(Addr addr)
+{
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_load_2_triggers_conflict(addr)
+      && ! drd_is_suppressed(addr, addr + 2))
+  {
+    drd_report_race(addr, 2, eLoad);
+  }
+}
+
+static VG_REGPARM(1) void drd_trace_load_4(Addr addr)
+{
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_load_4_triggers_conflict(addr)
+      && ! drd_is_suppressed(addr, addr + 4))
+  {
+    drd_report_race(addr, 4, eLoad);
+  }
+}
+
+static VG_REGPARM(1) void drd_trace_load_8(Addr addr)
+{
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_load_8_triggers_conflict(addr)
+      && ! drd_is_suppressed(addr, addr + 8))
+  {
+    drd_report_race(addr, 8, eLoad);
+  }
+}
+
+VG_REGPARM(2) void drd_trace_store(Addr addr, SizeT size)
+{
+#ifdef ENABLE_DRD_CONSISTENCY_CHECKS
+  /* The assert below has been commented out because of performance reasons.*/
+  tl_assert(thread_get_running_tid()
+            == VgThreadIdToDrdThreadId(VG_(get_running_tid())));
+#endif
+
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_store_triggers_conflict(addr, addr + size)
+      && ! drd_is_suppressed(addr, addr + size))
+  {
+    drd_report_race(addr, size, eStore);
+  }
+}
+
+static VG_REGPARM(1) void drd_trace_store_1(Addr addr)
+{
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_store_1_triggers_conflict(addr)
+      && ! drd_is_suppressed(addr, addr + 1))
+  {
+    drd_report_race(addr, 1, eStore);
+  }
+}
+
+static VG_REGPARM(1) void drd_trace_store_2(Addr addr)
+{
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_store_2_triggers_conflict(addr)
+      && ! drd_is_suppressed(addr, addr + 2))
+  {
+    drd_report_race(addr, 2, eStore);
+  }
+}
+
+static VG_REGPARM(1) void drd_trace_store_4(Addr addr)
+{
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_store_4_triggers_conflict(addr)
+      && ! drd_is_suppressed(addr, addr + 4))
+  {
+    drd_report_race(addr, 4, eStore);
+  }
+}
+
+static VG_REGPARM(1) void drd_trace_store_8(Addr addr)
+{
+  if (running_thread_is_recording()
+      && (s_drd_check_stack_accesses || ! thread_address_on_stack(addr))
+      && bm_access_store_8_triggers_conflict(addr)
+      && ! drd_is_suppressed(addr, addr + 8))
+  {
+    drd_report_race(addr, 8, eStore);
+  }
+}
+
+/**
+ * Return true if and only if addr_expr matches the pattern (SP) or
+ * <offset>(SP).
+ */
+static Bool is_stack_access(IRSB* const bb, IRExpr* const addr_expr)
+{
+  Bool result = False;
+
+  if (addr_expr->tag == Iex_RdTmp)
+  {
+    int i;
+    for (i = 0; i < bb->stmts_size; i++)
+    {
+      if (bb->stmts[i]
+          && bb->stmts[i]->tag == Ist_WrTmp
+          && bb->stmts[i]->Ist.WrTmp.tmp == addr_expr->Iex.RdTmp.tmp)
+      {
+        IRExpr* e = bb->stmts[i]->Ist.WrTmp.data;
+        if (e->tag == Iex_Get && e->Iex.Get.offset == STACK_POINTER_OFFSET)
+        {
+          result = True;
+        }
+
+        //ppIRExpr(e);
+        //VG_(printf)(" (%s)\n", result ? "True" : "False");
+        break;
+      }
+    }
+  }
+  return result;
+}
+
+static void instrument_load(IRSB* const bb,
+                            IRExpr* const addr_expr,
+                            const HWord size)
+{
+  IRExpr* size_expr;
+  IRExpr** argv;
+  IRDirty* di;
+
+  if (UNLIKELY(drd_any_address_is_traced()))
+  {
+    addStmtToIRSB(bb,
+		  IRStmt_Dirty(
+		    unsafeIRDirty_0_N(/*regparms*/2,
+				      "drd_trace_load",
+				      VG_(fnptr_to_fnentry)
+				      (drd_trace_mem_load),
+				      mkIRExprVec_2(addr_expr,
+						    mkIRExpr_HWord(size)))));
+  }
+
+  if (! s_drd_check_stack_accesses && is_stack_access(bb, addr_expr))
+    return;
+
+  switch (size)
+  {
+  case 1:
+    argv = mkIRExprVec_1(addr_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/1,
+                           "drd_trace_load_1",
+                           VG_(fnptr_to_fnentry)(drd_trace_load_1),
+                           argv);
+    break;
+  case 2:
+    argv = mkIRExprVec_1(addr_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/1,
+                           "drd_trace_load_2",
+                           VG_(fnptr_to_fnentry)(drd_trace_load_2),
+                           argv);
+    break;
+  case 4:
+    argv = mkIRExprVec_1(addr_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/1,
+                           "drd_trace_load_4",
+                           VG_(fnptr_to_fnentry)(drd_trace_load_4),
+                           argv);
+    break;
+  case 8:
+    argv = mkIRExprVec_1(addr_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/1,
+                           "drd_trace_load_8",
+                           VG_(fnptr_to_fnentry)(drd_trace_load_8),
+                           argv);
+    break;
+  default:
+    size_expr = mkIRExpr_HWord(size);
+    argv = mkIRExprVec_2(addr_expr, size_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/2,
+                           "drd_trace_load",
+                           VG_(fnptr_to_fnentry)(drd_trace_load),
+                           argv);
+    break;
+  }
+  addStmtToIRSB(bb, IRStmt_Dirty(di));
+}
+
+static void instrument_store(IRSB* const bb,
+                             IRExpr* const addr_expr,
+                             const HWord size)
+{
+  IRExpr* size_expr;
+  IRExpr** argv;
+  IRDirty* di;
+
+  if (UNLIKELY(drd_any_address_is_traced()))
+  {
+    addStmtToIRSB(bb,
+		  IRStmt_Dirty(
+		    unsafeIRDirty_0_N(/*regparms*/2,
+				      "drd_trace_store",
+				      VG_(fnptr_to_fnentry)
+				      (drd_trace_mem_store),
+				      mkIRExprVec_2(addr_expr,
+						    mkIRExpr_HWord(size)))));
+  }
+
+  if (! s_drd_check_stack_accesses && is_stack_access(bb, addr_expr))
+    return;
+
+  switch (size)
+  {
+  case 1:
+    argv = mkIRExprVec_1(addr_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/1,
+                           "drd_trace_store_1",
+                           VG_(fnptr_to_fnentry)(drd_trace_store_1),
+                           argv);
+    break;
+  case 2:
+    argv = mkIRExprVec_1(addr_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/1,
+                           "drd_trace_store_2",
+                           VG_(fnptr_to_fnentry)(drd_trace_store_2),
+                           argv);
+    break;
+  case 4:
+    argv = mkIRExprVec_1(addr_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/1,
+                           "drd_trace_store_4",
+                           VG_(fnptr_to_fnentry)(drd_trace_store_4),
+                           argv);
+    break;
+  case 8:
+    argv = mkIRExprVec_1(addr_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/1,
+                           "drd_trace_store_8",
+                           VG_(fnptr_to_fnentry)(drd_trace_store_8),
+                           argv);
+    break;
+  default:
+    size_expr = mkIRExpr_HWord(size);
+    argv = mkIRExprVec_2(addr_expr, size_expr);
+    di = unsafeIRDirty_0_N(/*regparms*/2,
+                           "drd_trace_store",
+                           VG_(fnptr_to_fnentry)(drd_trace_store),
+                           argv);
+    break;
+  }
+  addStmtToIRSB(bb, IRStmt_Dirty(di));
+}
+
+IRSB* drd_instrument(VgCallbackClosure* const closure,
+                     IRSB* const bb_in,
+                     VexGuestLayout* const layout,
+                     VexGuestExtents* const vge, 
+                     IRType const gWordTy,
+                     IRType const hWordTy)
+{
+  IRDirty* di;
+  Int      i;
+  IRSB*    bb;
+  IRExpr** argv;
+  Bool     instrument = True;
+  Bool     bus_locked = False;
+
+  /* Set up BB */
+  bb           = emptyIRSB();
+  bb->tyenv    = deepCopyIRTypeEnv(bb_in->tyenv);
+  bb->next     = deepCopyIRExpr(bb_in->next);
+  bb->jumpkind = bb_in->jumpkind;
+
+  for (i = 0; i < bb_in->stmts_used; i++)
+  {
+    IRStmt* const st = bb_in->stmts[i];
+    tl_assert(st);
+    if (st->tag == Ist_NoOp)
+      continue;
+
+    switch (st->tag)
+    {
+    /* Note: the code for not instrumenting the code in .plt          */
+    /* sections is only necessary on CentOS 3.0 x86 (kernel 2.4.21    */
+    /* + glibc 2.3.2 + NPTL 0.60 + binutils 2.14.90.0.4).             */
+    /* This is because on this platform dynamic library symbols are   */
+    /* relocated in another way than by later binutils versions. The  */
+    /* linker e.g. does not generate .got.plt sections on CentOS 3.0. */
+    case Ist_IMark:
+      instrument = VG_(seginfo_sect_kind)(NULL, 0, st->Ist.IMark.addr)
+        != Vg_SectPLT;
+      addStmtToIRSB(bb, st);
+      break;
+
+    case Ist_MBE:
+      switch (st->Ist.MBE.event)
+      {
+      case Imbe_Fence:
+        break; /* not interesting */
+      case Imbe_BusLock:
+      case Imbe_SnoopedStoreBegin:
+        tl_assert(! bus_locked);
+        bus_locked = True;
+        break;
+      case Imbe_BusUnlock:
+      case Imbe_SnoopedStoreEnd:
+        tl_assert(bus_locked);
+        bus_locked = False;
+        break;
+      default:
+        tl_assert(0);
+      }
+      addStmtToIRSB(bb, st);
+      break;
+
+    case Ist_Store:
+      if (instrument && ! bus_locked)
+      {
+        instrument_store(bb,
+                         st->Ist.Store.addr,
+                         sizeofIRType(typeOfIRExpr(bb->tyenv,
+                                                   st->Ist.Store.data)));
+      }
+      addStmtToIRSB(bb, st);
+      break;
+
+    case Ist_WrTmp:
+      if (instrument)
+      {
+        const IRExpr* const data = st->Ist.WrTmp.data;
+        if (data->tag == Iex_Load)
+        {
+          instrument_load(bb,
+                          data->Iex.Load.addr,
+                          sizeofIRType(data->Iex.Load.ty));
+        }
+      }
+      addStmtToIRSB(bb, st);
+      break;
+
+    case Ist_Dirty:
+      if (instrument)
+      {
+        IRDirty* d = st->Ist.Dirty.details;
+        IREffect const mFx = d->mFx;
+        switch (mFx) {
+        case Ifx_None:
+          break;
+        case Ifx_Read:
+        case Ifx_Write:
+        case Ifx_Modify:
+          tl_assert(d->mAddr);
+          tl_assert(d->mSize > 0);
+          argv = mkIRExprVec_2(d->mAddr, mkIRExpr_HWord(d->mSize));
+          if (mFx == Ifx_Read || mFx == Ifx_Modify) {
+            di = unsafeIRDirty_0_N(
+                                   /*regparms*/2,
+                                   "drd_trace_load",
+                                   VG_(fnptr_to_fnentry)(drd_trace_load),
+                                   argv);
+            addStmtToIRSB(bb, IRStmt_Dirty(di));
+          }
+          if ((mFx == Ifx_Write || mFx == Ifx_Modify)
+              && ! bus_locked)
+          {
+            di = unsafeIRDirty_0_N(
+                                   /*regparms*/2,
+                                   "drd_trace_store",
+                                   VG_(fnptr_to_fnentry)(drd_trace_store),
+                                   argv);
+            addStmtToIRSB(bb, IRStmt_Dirty(di));
+          }
+          break;
+        default:
+          tl_assert(0);
+        }
+      }
+      addStmtToIRSB(bb, st);
+      break;
+
+    default:
+      addStmtToIRSB(bb, st);
+      break;
+    }
+  }
+
+  tl_assert(! bus_locked);
+
+  return bb;
+}
+