- 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/Makefile.am b/drd/Makefile.am
index 19e374d..18a8844 100644
--- a/drd/Makefile.am
+++ b/drd/Makefile.am
@@ -92,12 +92,13 @@
$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
-DRD_SOURCES = \
+DRD_SOURCES = \
drd_barrier.c \
drd_clientobj.c \
drd_clientreq.c \
drd_cond.c \
drd_error.c \
+ drd_load_store.c \
drd_main.c \
drd_malloc_wrappers.c \
drd_mutex.c \
@@ -111,12 +112,14 @@
noinst_HEADERS = \
drd_barrier.h \
+ drd_basics.h \
drd_bitmap.c \
drd_bitmap.h \
drd_clientobj.h \
drd_clientreq.h \
drd_cond.h \
drd_error.h \
+ drd_load_store.h \
drd_malloc_wrappers.h \
drd_mutex.h \
drd_rwlock.h \
@@ -127,7 +130,6 @@
drd_thread.c \
drd_thread.h \
drd_thread_bitmap.h \
- drd_track.h \
drd_vc.c \
drd_vc.h \
pub_drd_bitmap.h
diff --git a/drd/drd_clientreq.c b/drd/drd_clientreq.c
index 29ce30b..44c662e 100644
--- a/drd/drd_clientreq.c
+++ b/drd/drd_clientreq.c
@@ -1,8 +1,7 @@
/*
This file is part of drd, a data race detector.
- Copyright (C) 2006-2008 Bart Van Assche
- bart.vanassche@gmail.com
+ 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
@@ -23,14 +22,14 @@
*/
+#include "drd_barrier.h"
#include "drd_clientreq.h"
#include "drd_cond.h"
#include "drd_mutex.h"
+#include "drd_rwlock.h"
#include "drd_semaphore.h"
#include "drd_suppression.h" // drd_start_suppression()
#include "drd_thread.h"
-#include "drd_track.h"
-#include "drd_rwlock.h"
#include "pub_tool_basics.h" // Bool
#include "pub_tool_debuginfo.h" // VG_(describe_IP)()
#include "pub_tool_libcassert.h"
@@ -41,52 +40,22 @@
#include "pub_tool_tooliface.h" // VG_(needs_...)()
-static void drd_spin_init_or_unlock(const Addr spinlock)
-{
- struct mutex_info* mutex_p = mutex_get(spinlock);
- if (mutex_p)
- {
- mutex_unlock(spinlock, mutex_type_spinlock);
- }
- else
- {
- mutex_init(spinlock, mutex_type_spinlock);
- }
-}
+/* Local function declarations. */
-static void drd_pre_cond_wait(const Addr cond,
- const Addr mutex, const MutexT mutex_type)
-{
- mutex_unlock(mutex, mutex_type);
- cond_pre_wait(cond, mutex);
-}
+static
+Bool DRD_(handle_client_request)(ThreadId vg_tid, UWord* arg, UWord* ret);
+static Addr DRD_(highest_used_stack_address)(const ThreadId vg_tid);
-static void drd_post_cond_wait(const Addr cond,
- const Addr mutex,
- const Bool took_lock)
-{
- cond_post_wait(cond);
- mutex_post_lock(mutex, took_lock, True);
-}
-static void drd_pre_cond_signal(const Addr cond)
-{
- cond_pre_signal(cond);
-}
-
-static void drd_pre_cond_broadcast(const Addr cond)
-{
- cond_pre_broadcast(cond);
-}
-
-/** Walk the stack up to the highest stack frame, and return the stack pointer
- * of the highest stack frame. It is assumed that there are no more than
- * ten stack frames above the current frame. This should be no problem
- * since this function is either called indirectly from the _init() function
- * in vgpreload_exp-drd-*.so or from the thread wrapper for a newly created
- * thread. See also drd_pthread_intercepts.c.
+/**
+ * Walk the stack up to the highest stack frame, and return the stack pointer
+ * of the highest stack frame. It is assumed that there are no more than
+ * ten stack frames above the current frame. This should be no problem
+ * since this function is either called indirectly from the _init() function
+ * in vgpreload_exp-drd-*.so or from the thread wrapper for a newly created
+ * thread. See also drd_pthread_intercepts.c.
*/
-static Addr highest_used_stack_address(const ThreadId vg_tid)
+static Addr DRD_(highest_used_stack_address)(const ThreadId vg_tid)
{
UInt nframes;
const UInt n_ips = 10;
@@ -122,7 +91,12 @@
return husa;
}
-static Bool drd_handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret)
+/**
+ * DRD's handler for Valgrind client requests. The code below handles both
+ * DRD's public and tool-internal client requests.
+ */
+static
+Bool DRD_(handle_client_request)(ThreadId vg_tid, UWord* arg, UWord* ret)
{
UWord result = 0;
const DrdThreadId drd_tid = thread_get_running_tid();
@@ -150,7 +124,7 @@
case VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK:
{
- const Addr topmost_sp = highest_used_stack_address(vg_tid);
+ const Addr topmost_sp = DRD_(highest_used_stack_address)(vg_tid);
#if 0
UInt nframes;
const UInt n_ips = 20;
@@ -206,23 +180,21 @@
case VG_USERREQ__POST_THREAD_JOIN:
tl_assert(arg[1]);
- drd_post_thread_join(drd_tid,
- PtThreadIdToDrdThreadId(arg[1]));
+ DRD_(thread_post_join)(drd_tid, PtThreadIdToDrdThreadId(arg[1]));
break;
case VG_USERREQ__PRE_THREAD_CANCEL:
tl_assert(arg[1]);
- drd_pre_thread_cancel(drd_tid, PtThreadIdToDrdThreadId(arg[1]));
+ thread_pre_cancel(drd_tid);
break;
case VG_USERREQ__POST_THREAD_CANCEL:
tl_assert(arg[1]);
- drd_post_thread_cancel(drd_tid, PtThreadIdToDrdThreadId(arg[1]), arg[2]);
break;
case VG_USERREQ__PRE_MUTEX_INIT:
if (thread_enter_synchr(drd_tid) == 0)
- drd_pre_mutex_init(arg[1], arg[2]);
+ mutex_init(arg[1], arg[2]);
break;
case VG_USERREQ__POST_MUTEX_INIT:
@@ -235,22 +207,22 @@
case VG_USERREQ__POST_MUTEX_DESTROY:
if (thread_leave_synchr(drd_tid) == 0)
- drd_post_mutex_destroy(arg[1], arg[2]);
+ mutex_post_destroy(arg[1]);
break;
case VG_USERREQ__PRE_MUTEX_LOCK:
if (thread_enter_synchr(drd_tid) == 0)
- drd_pre_mutex_lock(arg[1], arg[2], arg[3]);
+ mutex_pre_lock(arg[1], arg[2], arg[3]);
break;
case VG_USERREQ__POST_MUTEX_LOCK:
if (thread_leave_synchr(drd_tid) == 0)
- drd_post_mutex_lock(arg[1], arg[2]);
+ mutex_post_lock(arg[1], arg[2], False/*post_cond_wait*/);
break;
case VG_USERREQ__PRE_MUTEX_UNLOCK:
if (thread_enter_synchr(drd_tid) == 0)
- drd_pre_mutex_unlock(arg[1], arg[2]);
+ mutex_unlock(arg[1], arg[2]);
break;
case VG_USERREQ__POST_MUTEX_UNLOCK:
@@ -259,7 +231,7 @@
case VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK:
if (thread_enter_synchr(drd_tid) == 0)
- drd_spin_init_or_unlock(arg[1]);
+ DRD_(spinlock_init_or_unlock)(arg[1]);
break;
case VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK:
@@ -268,7 +240,7 @@
case VG_USERREQ__PRE_COND_INIT:
if (thread_enter_synchr(drd_tid) == 0)
- drd_pre_cond_init(arg[1]);
+ cond_pre_init(arg[1]);
break;
case VG_USERREQ__POST_COND_INIT:
@@ -281,22 +253,34 @@
case VG_USERREQ__POST_COND_DESTROY:
if (thread_leave_synchr(drd_tid) == 0)
- drd_post_cond_destroy(arg[1]);
+ cond_post_destroy(arg[1]);
break;
case VG_USERREQ__PRE_COND_WAIT:
if (thread_enter_synchr(drd_tid) == 0)
- drd_pre_cond_wait(arg[1], arg[2], arg[3]);
+ {
+ const Addr cond = arg[1];
+ const Addr mutex = arg[2];
+ const MutexT mutex_type = arg[3];
+ mutex_unlock(mutex, mutex_type);
+ cond_pre_wait(cond, mutex);
+ }
break;
case VG_USERREQ__POST_COND_WAIT:
if (thread_leave_synchr(drd_tid) == 0)
- drd_post_cond_wait(arg[1], arg[2], arg[3]);
+ {
+ const Addr cond = arg[1];
+ const Addr mutex = arg[2];
+ const Bool took_lock = arg[3];
+ cond_post_wait(cond);
+ mutex_post_lock(mutex, took_lock, True);
+ }
break;
case VG_USERREQ__PRE_COND_SIGNAL:
if (thread_enter_synchr(drd_tid) == 0)
- drd_pre_cond_signal(arg[1]);
+ cond_pre_signal(arg[1]);
break;
case VG_USERREQ__POST_COND_SIGNAL:
@@ -305,7 +289,7 @@
case VG_USERREQ__PRE_COND_BROADCAST:
if (thread_enter_synchr(drd_tid) == 0)
- drd_pre_cond_broadcast(arg[1]);
+ cond_pre_broadcast(arg[1]);
break;
case VG_USERREQ__POST_COND_BROADCAST:
@@ -314,7 +298,7 @@
case VG_USERREQ__PRE_SEM_INIT:
if (thread_enter_synchr(drd_tid) == 0)
- drd_semaphore_init(arg[1], arg[2], arg[3]);
+ semaphore_init(arg[1], arg[2], arg[3]);
break;
case VG_USERREQ__POST_SEM_INIT:
@@ -327,32 +311,32 @@
case VG_USERREQ__POST_SEM_DESTROY:
if (thread_leave_synchr(drd_tid) == 0)
- drd_semaphore_destroy(arg[1]);
+ semaphore_destroy(arg[1]);
break;
case VG_USERREQ__PRE_SEM_WAIT:
if (thread_enter_synchr(drd_tid) == 0)
- drd_semaphore_pre_wait(drd_tid, arg[1]);
+ semaphore_pre_wait(arg[1]);
break;
case VG_USERREQ__POST_SEM_WAIT:
if (thread_leave_synchr(drd_tid) == 0)
- drd_semaphore_post_wait(drd_tid, arg[1], arg[2]);
+ semaphore_post_wait(drd_tid, arg[1], arg[2]);
break;
case VG_USERREQ__PRE_SEM_POST:
if (thread_enter_synchr(drd_tid) == 0)
- drd_semaphore_pre_post(drd_tid, arg[1]);
+ semaphore_pre_post(drd_tid, arg[1]);
break;
case VG_USERREQ__POST_SEM_POST:
if (thread_leave_synchr(drd_tid) == 0)
- drd_semaphore_post_post(drd_tid, arg[1], arg[2]);
+ semaphore_post_post(drd_tid, arg[1], arg[2]);
break;
case VG_USERREQ__PRE_BARRIER_INIT:
if (thread_enter_synchr(drd_tid) == 0)
- drd_barrier_init(arg[1], arg[2], arg[3], arg[4]);
+ barrier_init(arg[1], arg[2], arg[3], arg[4]);
break;
case VG_USERREQ__POST_BARRIER_INIT:
@@ -365,17 +349,17 @@
case VG_USERREQ__POST_BARRIER_DESTROY:
if (thread_leave_synchr(drd_tid) == 0)
- drd_barrier_destroy(arg[1], arg[2]);
+ barrier_destroy(arg[1], arg[2]);
break;
case VG_USERREQ__PRE_BARRIER_WAIT:
if (thread_enter_synchr(drd_tid) == 0)
- drd_barrier_pre_wait(drd_tid, arg[1], arg[2]);
+ barrier_pre_wait(drd_tid, arg[1], arg[2]);
break;
case VG_USERREQ__POST_BARRIER_WAIT:
if (thread_leave_synchr(drd_tid) == 0)
- drd_barrier_post_wait(drd_tid, arg[1], arg[2], arg[3]);
+ barrier_post_wait(drd_tid, arg[1], arg[2], arg[3]);
break;
case VG_USERREQ__PRE_RWLOCK_INIT:
@@ -426,7 +410,11 @@
return True;
}
-void drd_clientreq_init(void)
+/**
+ * Tell the Valgrind core the address of the DRD function that processes
+ * client requests. Must be called before any client code is run.
+ */
+void DRD_(clientreq_init)(void)
{
- VG_(needs_client_requests)(drd_handle_client_request);
+ VG_(needs_client_requests)(DRD_(handle_client_request));
}
diff --git a/drd/drd_clientreq.h b/drd/drd_clientreq.h
index 3d06e71..e43d845 100644
--- a/drd/drd_clientreq.h
+++ b/drd/drd_clientreq.h
@@ -22,14 +22,27 @@
The GNU General Public License is contained in the file COPYING.
*/
+/*
+ * This header file contains the tool-internal interface for the code that
+ * processes client requests.
+ */
+
#ifndef __DRD_CLIENTREQ_H
#define __DRD_CLIENTREQ_H
#include "drd.h"
+#include "drd_basics.h" /* DRD_() */
+/*
+ * While the client requests defined in the header file "drd.h" define a
+ * public interface between client programs and the DRD tool, the client
+ * requests defined below are a tool-internal interface. These last client
+ * requests must only be used by the source code in the various *_intercepts.c
+ * source files.
+ */
enum {
/* Ask drd to suppress data race reports on all currently allocated stack */
/* data of the current thread. */
@@ -194,6 +207,11 @@
};
+/*
+ * Error checking on POSIX recursive mutexes, POSIX error checking mutexes,
+ * POSIX default mutexes and POSIX spinlocks happens by the same code. The
+ * values defined below specify which of these types a mutex really is.
+ */
typedef enum
{
mutex_type_unknown = -1,
@@ -204,13 +222,19 @@
mutex_type_spinlock = 4
} MutexT;
+/*
+ * Error checking on POSIX barriers and GOMP barriers happens by the same
+ * code. The integer values defined below specify the type of a barrier with
+ * a given client address.
+ */
typedef enum
{
pthread_barrier = 1,
gomp_barrier = 2
} BarrierT;
-void drd_clientreq_init(void);
+
+void DRD_(clientreq_init)(void);
#endif // __DRD_CLIENTREQ_H
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;
+}
+
diff --git a/drd/drd_load_store.h b/drd/drd_load_store.h
new file mode 100644
index 0000000..f820555
--- /dev/null
+++ b/drd/drd_load_store.h
@@ -0,0 +1,52 @@
+/*
+ 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.
+*/
+
+
+/*
+ * Functions related to instrumentation of loads and stores.
+ */
+
+
+#ifndef __DRD_LOAD_STORE_H
+#define __DRD_LOAD_STORE_H
+
+
+#include <libvex.h> /* IRSB */
+#include <pub_tool_tooliface.h> /* VgCallbackClosure */
+
+
+Bool DRD_(get_check_stack_accesses)(void);
+void DRD_(set_check_stack_accesses)(const Bool c);
+IRSB* drd_instrument(VgCallbackClosure* const closure,
+ IRSB* const bb_in,
+ VexGuestLayout* const layout,
+ VexGuestExtents* const vge,
+ IRType const gWordTy,
+ IRType const hWordTy);
+void drd_trace_mem_access(const Addr addr, const SizeT size,
+ const BmAccessTypeT access_type);
+VG_REGPARM(2) void drd_trace_load(Addr addr, SizeT size);
+VG_REGPARM(2) void drd_trace_store(Addr addr, SizeT size);
+
+
+#endif // __DRD_LOAD_STORE_H
diff --git a/drd/drd_main.c b/drd/drd_main.c
index 4b8cdc2..a051711 100644
--- a/drd/drd_main.c
+++ b/drd/drd_main.c
@@ -1,8 +1,7 @@
/*
This file is part of drd, a data race detector.
- Copyright (C) 2006-2008 Bart Van Assche
- bart.vanassche@gmail.com
+ 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
@@ -24,10 +23,11 @@
#include "drd_barrier.h"
-#include "drd_clientreq.h"
#include "drd_clientobj.h"
+#include "drd_clientreq.h"
#include "drd_cond.h"
#include "drd_error.h"
+#include "drd_load_store.h"
#include "drd_malloc_wrappers.h"
#include "drd_mutex.h"
#include "drd_rwlock.h"
@@ -35,8 +35,6 @@
#include "drd_semaphore.h"
#include "drd_suppression.h"
#include "drd_thread.h"
-#include "drd_thread_bitmap.h"
-#include "drd_track.h"
#include "drd_vc.h"
#include "libvex_guest_offsets.h"
#include "pub_drd_bitmap.h"
@@ -55,15 +53,6 @@
#include "pub_tool_tooliface.h"
-/* Include several source files here in order to allow the compiler to */
-/* do more inlining. */
-#include "drd_bitmap.c"
-#include "drd_segment.c"
-#include "drd_thread.c"
-#include "drd_vc.c"
-
-
-
// Function declarations.
static void drd_start_client_code(const ThreadId tid, const ULong bbs_done);
@@ -71,9 +60,7 @@
// Local variables.
-static Bool s_drd_check_stack_accesses = False;
static Bool s_drd_print_stats = False;
-static Bool s_drd_trace_fork_join = False;
static Bool s_drd_var_info = False;
static Bool s_show_stack_usage = False;
@@ -84,6 +71,7 @@
static Bool drd_process_cmd_line_option(Char* arg)
{
+ int check_stack_accesses = -1;
int exclusive_threshold_ms = -1;
int segment_merging = -1;
int shared_threshold_ms = -1;
@@ -92,6 +80,7 @@
int trace_clientobj = -1;
int trace_cond = -1;
int trace_csw = -1;
+ int trace_fork_join = -1;
int trace_conflict_set = -1;
int trace_mutex = -1;
int trace_rwlock = -1;
@@ -100,7 +89,7 @@
int trace_suppression = -1;
Char* trace_address = 0;
- VG_BOOL_CLO (arg, "--check-stack-var", s_drd_check_stack_accesses)
+ VG_BOOL_CLO (arg, "--check-stack-var", check_stack_accesses)
else VG_BOOL_CLO(arg, "--drd-stats", s_drd_print_stats)
else VG_BOOL_CLO(arg,"--report-signal-unlocked",s_drd_report_signal_unlocked)
else VG_BOOL_CLO(arg, "--segment-merging", segment_merging)
@@ -111,7 +100,7 @@
else VG_BOOL_CLO(arg, "--trace-cond", trace_cond)
else VG_BOOL_CLO(arg, "--trace-conflict-set", trace_conflict_set)
else VG_BOOL_CLO(arg, "--trace-csw", trace_csw)
- else VG_BOOL_CLO(arg, "--trace-fork-join", s_drd_trace_fork_join)
+ else VG_BOOL_CLO(arg, "--trace-fork-join", trace_fork_join)
else VG_BOOL_CLO(arg, "--trace-mutex", trace_mutex)
else VG_BOOL_CLO(arg, "--trace-rwlock", trace_rwlock)
else VG_BOOL_CLO(arg, "--trace-segment", trace_segment)
@@ -124,6 +113,8 @@
else
return VG_(replacement_malloc_process_cmd_line_option)(arg);
+ if (check_stack_accesses != -1)
+ DRD_(set_check_stack_accesses)(check_stack_accesses);
if (exclusive_threshold_ms != -1)
{
mutex_set_lock_threshold(exclusive_threshold_ms);
@@ -150,6 +141,8 @@
cond_set_trace(trace_cond);
if (trace_csw != -1)
thread_trace_context_switches(trace_csw);
+ if (trace_fork_join != -1)
+ DRD_(thread_set_trace_fork_join)(trace_fork_join);
if (trace_conflict_set != -1)
thread_trace_conflict_set(trace_conflict_set);
if (trace_mutex != -1)
@@ -223,185 +216,6 @@
// Implements the thread-related core callbacks.
//
-static 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);
-}
-
-static 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);
- }
-}
-
-static
-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);
- }
-}
-
static void drd_pre_mem_read(const CorePart part,
const ThreadId tid,
Char* const s,
@@ -486,7 +300,7 @@
{
drd_trace_mem_access(a1, len, eEnd);
}
- if (! is_stack_mem || s_drd_check_stack_accesses)
+ if (! is_stack_mem || DRD_(get_check_stack_accesses)())
{
thread_stop_using_mem(a1, a2);
clientobj_stop_using_mem(a1, a2);
@@ -606,7 +420,7 @@
{
thread_new_segment(drd_creator);
}
- if (s_drd_trace_fork_join)
+ if (DRD_(thread_get_trace_fork_join)())
{
VG_(message)(Vg_DebugMsg,
"drd_pre_thread_create creator = %d/%d, created = %d",
@@ -625,13 +439,13 @@
tl_assert(vg_created != VG_INVALID_THREADID);
drd_created = thread_post_create(vg_created);
- if (s_drd_trace_fork_join)
+ if (DRD_(thread_get_trace_fork_join)())
{
VG_(message)(Vg_DebugMsg,
"drd_post_thread_create created = %d/%d",
vg_created, drd_created);
}
- if (! s_drd_check_stack_accesses)
+ if (! DRD_(get_check_stack_accesses)())
{
drd_start_suppression(thread_get_stack_max(drd_created)
- thread_get_stack_size(drd_created),
@@ -640,60 +454,6 @@
}
}
-/* Process VG_USERREQ__POST_THREAD_JOIN. This client request is invoked just */
-/* after thread drd_joiner joined thread drd_joinee. */
-void drd_post_thread_join(DrdThreadId drd_joiner, DrdThreadId drd_joinee)
-{
- tl_assert(IsValidDrdThreadId(drd_joiner));
- tl_assert(IsValidDrdThreadId(drd_joinee));
- thread_new_segment(drd_joinee);
- thread_combine_vc(drd_joiner, drd_joinee);
- thread_new_segment(drd_joiner);
-
- if (s_drd_trace_fork_join)
- {
- const ThreadId joiner = DrdThreadIdToVgThreadId(drd_joiner);
- const ThreadId joinee = DrdThreadIdToVgThreadId(drd_joinee);
- const unsigned msg_size = 256;
- char* msg;
-
- msg = VG_(malloc)("drd.main.dptj.1", msg_size);
- tl_assert(msg);
- VG_(snprintf)(msg, msg_size,
- "drd_post_thread_join joiner = %d/%d, joinee = %d/%d",
- joiner, drd_joiner, joinee, drd_joinee);
- if (joiner)
- {
- VG_(snprintf)(msg + VG_(strlen)(msg), msg_size - VG_(strlen)(msg),
- ", new vc: ");
- vc_snprint(msg + VG_(strlen)(msg), msg_size - VG_(strlen)(msg),
- thread_get_vc(drd_joiner));
- }
- VG_(message)(Vg_DebugMsg, "%s", msg);
- VG_(free)(msg);
- }
-
- if (! s_drd_check_stack_accesses)
- {
- drd_finish_suppression(thread_get_stack_max(drd_joinee)
- - thread_get_stack_size(drd_joinee),
- thread_get_stack_max(drd_joinee));
- }
- thread_delete(drd_joinee);
- mutex_thread_delete(drd_joinee);
- cond_thread_delete(drd_joinee);
- semaphore_thread_delete(drd_joinee);
- barrier_thread_delete(drd_joinee);
-}
-
-void drd_pre_thread_cancel(DrdThreadId canceling, DrdThreadId canceled)
-{
- thread_pre_cancel(canceled);
-}
-
-void drd_post_thread_cancel(DrdThreadId canceling, DrdThreadId canceled, Bool succeeded)
-{ }
-
/* Called after a thread has performed its last memory access. */
static void drd_thread_finished(ThreadId vg_tid)
{
@@ -702,7 +462,7 @@
tl_assert(VG_(get_running_tid)() == vg_tid);
drd_tid = VgThreadIdToDrdThreadId(vg_tid);
- if (s_drd_trace_fork_join)
+ if (DRD_(thread_get_trace_fork_join)())
{
VG_(message)(Vg_DebugMsg,
"drd_thread_finished tid = %d/%d%s",
@@ -738,101 +498,6 @@
thread_finished(drd_tid);
}
-void drd_pre_mutex_init(const Addr mutex, const MutexT mutex_type)
-{
- mutex_init(mutex, mutex_type);
-}
-
-void drd_post_mutex_destroy(const Addr mutex, const MutexT mutex_type)
-{
- mutex_post_destroy(mutex);
-}
-
-void drd_pre_mutex_lock(const Addr mutex, const MutexT mutex_type,
- const Bool trylock)
-{
- mutex_pre_lock(mutex, mutex_type, trylock);
-}
-
-void drd_post_mutex_lock(const Addr mutex, const Bool took_lock)
-{
- mutex_post_lock(mutex, took_lock, False);
-}
-
-void drd_pre_mutex_unlock(const Addr mutex, const MutexT mutex_type)
-{
- mutex_unlock(mutex, mutex_type);
-}
-
-void drd_pre_cond_init(Addr cond)
-{
- cond_pre_init(cond);
-}
-
-void drd_post_cond_destroy(Addr cond)
-{
- cond_post_destroy(cond);
-}
-
-void drd_semaphore_init(const Addr semaphore,
- const Word pshared, const Word value)
-{
- semaphore_init(semaphore, pshared, value);
-}
-
-void drd_semaphore_destroy(const Addr semaphore)
-{
- semaphore_destroy(semaphore);
-}
-
-void drd_semaphore_pre_wait(const DrdThreadId tid, const Addr semaphore)
-{
- semaphore_pre_wait(semaphore);
-}
-
-void drd_semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
- const Bool waited)
-{
- semaphore_post_wait(tid, semaphore, waited);
-}
-
-void drd_semaphore_pre_post(const DrdThreadId tid, const Addr semaphore)
-{
- semaphore_pre_post(tid, semaphore);
-}
-
-void drd_semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
- const Bool waited)
-{
- semaphore_post_post(tid, semaphore, waited);
-}
-
-
-void drd_barrier_init(const Addr barrier,
- const BarrierT barrier_type, const Word count,
- const Bool reinitialization)
-{
- barrier_init(barrier, barrier_type, count, reinitialization);
-}
-
-void drd_barrier_destroy(const Addr barrier, const BarrierT barrier_type)
-{
- barrier_destroy(barrier, barrier_type);
-}
-
-void drd_barrier_pre_wait(const DrdThreadId tid, const Addr barrier,
- const BarrierT barrier_type)
-{
- barrier_pre_wait(tid, barrier, barrier_type);
-}
-
-void drd_barrier_post_wait(const DrdThreadId tid, const Addr barrier,
- const BarrierT barrier_type, const Bool waited)
-{
- barrier_post_wait(tid, barrier, barrier_type, waited);
-}
-
-
//
// Implementation of the tool interface.
//
@@ -853,319 +518,6 @@
}
}
-#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
-
-
-/** 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));
-}
-
-static
-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;
-}
-
static void drd_start_client_code(const ThreadId tid, const ULong bbs_done)
{
tl_assert(tid == VG_(get_running_tid)());
@@ -1267,7 +619,7 @@
drd_register_malloc_wrappers(drd_start_using_mem_w_ecu,
drd_stop_using_nonstack_mem);
- drd_clientreq_init();
+ DRD_(clientreq_init)();
drd_suppression_init();
diff --git a/drd/drd_thread.c b/drd/drd_thread.c
index af137c5..8ca0547 100644
--- a/drd/drd_thread.c
+++ b/drd/drd_thread.c
@@ -24,7 +24,11 @@
#include "drd_error.h"
+#include "drd_barrier.h"
+#include "drd_cond.h"
+#include "drd_mutex.h"
#include "drd_segment.h"
+#include "drd_semaphore.h"
#include "drd_suppression.h"
#include "drd_thread.h"
#include "pub_tool_vki.h"
@@ -66,6 +70,7 @@
struct bitmap* s_conflict_set;
static Bool s_trace_context_switches = False;
static Bool s_trace_conflict_set = False;
+static Bool s_trace_fork_join = False;
static Bool s_segment_merging = True;
@@ -73,16 +78,30 @@
void thread_trace_context_switches(const Bool t)
{
+ tl_assert(t == False || t == True);
s_trace_context_switches = t;
}
void thread_trace_conflict_set(const Bool t)
{
+ tl_assert(t == False || t == True);
s_trace_conflict_set = t;
}
+Bool DRD_(thread_get_trace_fork_join)(void)
+{
+ return s_trace_fork_join;
+}
+
+void DRD_(thread_set_trace_fork_join)(const Bool t)
+{
+ tl_assert(t == False || t == True);
+ s_trace_fork_join = t;
+}
+
void thread_set_segment_merging(const Bool m)
{
+ tl_assert(m == False || m == True);
s_segment_merging = m;
}
@@ -211,6 +230,53 @@
return created;
}
+
+/* Process VG_USERREQ__POST_THREAD_JOIN. This client request is invoked just */
+/* after thread drd_joiner joined thread drd_joinee. */
+void DRD_(thread_post_join)(DrdThreadId drd_joiner, DrdThreadId drd_joinee)
+{
+ tl_assert(IsValidDrdThreadId(drd_joiner));
+ tl_assert(IsValidDrdThreadId(drd_joinee));
+ thread_new_segment(drd_joinee);
+ thread_combine_vc(drd_joiner, drd_joinee);
+ thread_new_segment(drd_joiner);
+
+ if (s_trace_fork_join)
+ {
+ const ThreadId joiner = DrdThreadIdToVgThreadId(drd_joiner);
+ const ThreadId joinee = DrdThreadIdToVgThreadId(drd_joinee);
+ const unsigned msg_size = 256;
+ char* msg;
+
+ msg = VG_(malloc)("drd.main.dptj.1", msg_size);
+ tl_assert(msg);
+ VG_(snprintf)(msg, msg_size,
+ "drd_post_thread_join joiner = %d/%d, joinee = %d/%d",
+ joiner, drd_joiner, joinee, drd_joinee);
+ if (joiner)
+ {
+ VG_(snprintf)(msg + VG_(strlen)(msg), msg_size - VG_(strlen)(msg),
+ ", new vc: ");
+ vc_snprint(msg + VG_(strlen)(msg), msg_size - VG_(strlen)(msg),
+ thread_get_vc(drd_joiner));
+ }
+ VG_(message)(Vg_DebugMsg, "%s", msg);
+ VG_(free)(msg);
+ }
+
+ if (! DRD_(get_check_stack_accesses)())
+ {
+ drd_finish_suppression(thread_get_stack_max(drd_joinee)
+ - thread_get_stack_size(drd_joinee),
+ thread_get_stack_max(drd_joinee));
+ }
+ thread_delete(drd_joinee);
+ mutex_thread_delete(drd_joinee);
+ cond_thread_delete(drd_joinee);
+ semaphore_thread_delete(drd_joinee);
+ barrier_thread_delete(drd_joinee);
+}
+
/** Allocate the first segment for a thread. Call this just after
* pthread_create().
*/
@@ -272,8 +338,9 @@
return s_threadinfo[tid].stack_size;
}
-/** Clean up thread-specific data structures. Call this just after
- * pthread_join().
+/**
+ * Clean up thread-specific data structures. Call this just after
+ * pthread_join().
*/
void thread_delete(const DrdThreadId tid)
{
diff --git a/drd/drd_thread.h b/drd/drd_thread.h
index 895502f..525c945 100644
--- a/drd/drd_thread.h
+++ b/drd/drd_thread.h
@@ -29,6 +29,7 @@
// Includes.
+#include "drd_basics.h"
#include "drd_segment.h"
#include "pub_drd_bitmap.h"
#include "pub_tool_libcassert.h" // tl_assert()
@@ -92,6 +93,8 @@
void thread_trace_context_switches(const Bool t);
void thread_trace_conflict_set(const Bool t);
+Bool DRD_(thread_get_trace_fork_join)(void);
+void DRD_(thread_set_trace_fork_join)(const Bool t);
void thread_set_segment_merging(const Bool m);
DrdThreadId VgThreadIdToDrdThreadId(const ThreadId tid);
@@ -101,6 +104,7 @@
DrdThreadId thread_pre_create(const DrdThreadId creator,
const ThreadId vg_created);
DrdThreadId thread_post_create(const ThreadId vg_created);
+void DRD_(thread_post_join)(DrdThreadId drd_joiner, DrdThreadId drd_joinee);
void thread_delete(const DrdThreadId tid);
void thread_finished(const DrdThreadId tid);
void thread_pre_cancel(const DrdThreadId tid);
diff --git a/drd/drd_thread_bitmap.h b/drd/drd_thread_bitmap.h
index 4fb098f..aa43e83 100644
--- a/drd/drd_thread_bitmap.h
+++ b/drd/drd_thread_bitmap.h
@@ -26,7 +26,11 @@
#ifndef __DRD_THREAD_BITMAP_H
#define __DRD_THREAD_BITMAP_H
+
#include "drd_bitmap.h"
+#include "drd_thread.h" /* running_thread_get_segment() */
+#include "pub_drd_bitmap.h"
+
static __inline__
Bool bm_access_load_1_triggers_conflict(const Addr a1)
diff --git a/drd/drd_track.h b/drd/drd_track.h
deleted file mode 100644
index 880e3f1..0000000
--- a/drd/drd_track.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- This file is part of drd, a data race detector.
-
- Copyright (C) 2006-2008 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.
-*/
-
-
-void drd_post_thread_join(DrdThreadId joiner, DrdThreadId joinee);
-
-void drd_pre_thread_cancel(DrdThreadId canceling, DrdThreadId canceled);
-void drd_post_thread_cancel(DrdThreadId canceling, DrdThreadId canceled, Bool succeeded);
-
-void drd_pre_mutex_init(Addr mutex, const MutexT mutex_type);
-void drd_post_mutex_destroy(Addr mutex, const MutexT mutex_type);
-void drd_pre_mutex_lock(const Addr mutex, const MutexT mutex_type,
- const Bool trylock);
-void drd_post_mutex_lock(Addr mutex, const Bool took_lock);
-void drd_pre_mutex_unlock(const Addr mutex, const MutexT mutex_type);
-
-void drd_pre_cond_init(Addr cond);
-void drd_post_cond_destroy(Addr cond);
-
-void drd_semaphore_init(const Addr semaphore,
- const Word pshared, const Word value);
-void drd_semaphore_destroy(const Addr semaphore);
-void drd_semaphore_pre_wait(const DrdThreadId tid, const Addr semaphore);
-void drd_semaphore_post_wait(const DrdThreadId tid, const Addr semaphore,
- const Bool waited);
-void drd_semaphore_pre_post(const DrdThreadId tid, const Addr semaphore);
-void drd_semaphore_post_post(const DrdThreadId tid, const Addr semaphore,
- const Bool waited);
-
-void drd_barrier_init(const Addr barrier,
- const BarrierT barrier_type, const Word count,
- const Bool reinitialization);
-void drd_barrier_destroy(const Addr barrier, const BarrierT barrier_type);
-void drd_barrier_pre_wait(const DrdThreadId tid, const Addr barrier,
- const BarrierT barrier_type);
-void drd_barrier_post_wait(const DrdThreadId tid, const Addr barrier,
- const BarrierT barrier_type, const Bool waited);