Add DRD as an experimental tool. Bart Van Assche is the maintainer.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7211 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/drd_malloc_wrappers.c b/exp-drd/drd_malloc_wrappers.c
new file mode 100644
index 0000000..205f473
--- /dev/null
+++ b/exp-drd/drd_malloc_wrappers.c
@@ -0,0 +1,347 @@
+/*
+ This file is part of drd, a data race detector.
+
+ Copyright (C) 2006-2007 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_malloc_wrappers.h"
+#include "drd_thread.h"
+#include "pub_tool_basics.h"
+#include "pub_tool_execontext.h"
+#include "pub_tool_hashtable.h"
+#include "pub_tool_libcassert.h"
+#include "pub_tool_libcbase.h"
+#include "pub_tool_libcprint.h"
+#include "pub_tool_mallocfree.h"
+#include "pub_tool_options.h"
+#include "pub_tool_replacemalloc.h"
+#include "pub_tool_threadstate.h"
+#include "pub_tool_tooliface.h"
+
+
+/*------------------------------------------------------------*/
+/*--- Defns ---*/
+/*------------------------------------------------------------*/
+
+
+typedef struct _DRD_Chunk {
+ struct _DRD_Chunk* next;
+ Addr data; // ptr to actual block
+ SizeT size : (sizeof(UWord)*8)-2; //size requested; 30 or 62 bits
+ ExeContext* where; // where it was allocated
+} DRD_Chunk;
+
+static StartUsingMem s_start_using_mem_callback;
+static StopUsingMem s_stop_using_mem_callback;
+/* Stats ... */
+static SizeT cmalloc_n_mallocs = 0;
+static SizeT cmalloc_n_frees = 0;
+static SizeT cmalloc_bs_mallocd = 0;
+
+
+/*------------------------------------------------------------*/
+/*--- Tracking malloc'd and free'd blocks ---*/
+/*------------------------------------------------------------*/
+
+/* Record malloc'd blocks. */
+static VgHashTable drd_malloc_list = NULL;
+
+
+/* Allocate its shadow chunk, put it on the appropriate list. */
+static
+DRD_Chunk* create_DRD_Chunk(ThreadId tid, Addr p, SizeT size)
+{
+ DRD_Chunk* mc = VG_(malloc)(sizeof(DRD_Chunk));
+ mc->data = p;
+ mc->size = size;
+ mc->where = VG_(record_ExeContext)(tid, 0);
+
+ return mc;
+}
+
+/*------------------------------------------------------------*/
+/*--- client_malloc(), etc ---*/
+/*------------------------------------------------------------*/
+
+/* Allocate memory and note change in memory available */
+static
+__inline__
+void* drd_new_block(ThreadId tid,
+ SizeT size, SizeT align,
+ Bool is_zeroed)
+{
+ Addr p;
+
+ cmalloc_n_mallocs ++;
+
+ // Allocate and zero
+ p = (Addr)VG_(cli_malloc)(align, size);
+ if (!p) {
+ return NULL;
+ }
+ if (is_zeroed) VG_(memset)((void*)p, 0, size);
+ s_start_using_mem_callback(p, p + size);
+
+ // Only update this stat if allocation succeeded.
+ cmalloc_bs_mallocd += size;
+
+ VG_(HT_add_node)(drd_malloc_list, create_DRD_Chunk(tid, p, size));
+
+ return (void*)p;
+}
+
+static
+void* drd_malloc(ThreadId tid, SizeT n)
+{
+ return drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
+}
+
+static
+void* drd_memalign(ThreadId tid, SizeT align, SizeT n)
+{
+ return drd_new_block(tid, n, align, /*is_zeroed*/False);
+}
+
+static
+void* drd_calloc(ThreadId tid, SizeT nmemb, SizeT size1)
+{
+ return drd_new_block(tid, nmemb*size1, VG_(clo_alignment),
+ /*is_zeroed*/True);
+}
+
+static
+__inline__
+void drd_handle_free(ThreadId tid, Addr p)
+{
+ DRD_Chunk* mc;
+
+ cmalloc_n_frees++;
+
+ mc = VG_(HT_remove)(drd_malloc_list, (UWord)p);
+ if (mc == NULL)
+ {
+ tl_assert(0);
+ }
+ else
+ {
+ s_stop_using_mem_callback(mc->data, mc->data + mc->size);
+ VG_(free)(mc);
+ }
+}
+
+static
+void drd_free(ThreadId tid, void* p)
+{
+ drd_handle_free(tid, (Addr)p);
+}
+
+static
+void* drd_realloc(ThreadId tid, void* p_old, SizeT new_size)
+{
+ DRD_Chunk* mc;
+ void* p_new;
+ SizeT old_size;
+
+ cmalloc_n_frees ++;
+ cmalloc_n_mallocs ++;
+ cmalloc_bs_mallocd += new_size;
+
+ /* Remove the old block */
+ mc = VG_(HT_remove)(drd_malloc_list, (UWord)p_old);
+ if (mc == NULL) {
+ tl_assert(0);
+ return NULL;
+ }
+
+ old_size = mc->size;
+
+ if (old_size == new_size)
+ {
+ /* size unchanged */
+ mc->where = VG_(record_ExeContext)(tid, 0);
+ p_new = p_old;
+
+ }
+ else if (old_size > new_size)
+ {
+ /* new size is smaller */
+ s_stop_using_mem_callback(mc->data + new_size, mc->data + old_size);
+ mc->size = new_size;
+ mc->where = VG_(record_ExeContext)(tid, 0);
+ p_new = p_old;
+
+ }
+ else
+ {
+ /* new size is bigger */
+ /* Get new memory */
+ const Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
+
+ if (a_new)
+ {
+ /* Copy from old to new */
+ VG_(memcpy)((void*)a_new, p_old, mc->size);
+
+ /* Free old memory */
+ s_stop_using_mem_callback(mc->data, mc->data + mc->size);
+ VG_(free)(mc);
+
+ // Allocate a new chunk.
+ mc = create_DRD_Chunk(tid, a_new, new_size);
+ s_start_using_mem_callback(a_new, a_new + new_size);
+ }
+ else
+ {
+ /* Allocation failed -- leave original block untouched. */
+ }
+
+ p_new = (void*)a_new;
+ }
+
+ // Now insert the new mc (with a possibly new 'data' field) into
+ // malloc_list. If this realloc() did not increase the memory size, we
+ // will have removed and then re-added mc unnecessarily. But that's ok
+ // because shrinking a block with realloc() is (presumably) much rarer
+ // than growing it, and this way simplifies the growing case.
+ VG_(HT_add_node)(drd_malloc_list, mc);
+
+ return p_new;
+}
+
+static
+void* drd___builtin_new(ThreadId tid, SizeT n)
+{
+ void* const result = drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
+ //VG_(message)(Vg_DebugMsg, "__builtin_new(%d, %d) = %p", tid, n, result);
+ return result;
+}
+
+static
+void drd___builtin_delete(ThreadId tid, void* p)
+{
+ //VG_(message)(Vg_DebugMsg, "__builtin_delete(%d, %p)", tid, p);
+ drd_handle_free(tid, (Addr)p);
+}
+
+static
+void* drd___builtin_vec_new(ThreadId tid, SizeT n)
+{
+ return drd_new_block(tid, n, VG_(clo_alignment), /*is_zeroed*/False);
+}
+
+static
+void drd___builtin_vec_delete(ThreadId tid, void* p)
+{
+ drd_handle_free(tid, (Addr)p);
+}
+
+void drd_register_malloc_wrappers(const StartUsingMem start_using_mem_callback,
+ const StopUsingMem stop_using_mem_callback)
+{
+ tl_assert(drd_malloc_list == 0);
+ drd_malloc_list = VG_(HT_construct)("drd_malloc_list"); // a big prime
+ tl_assert(drd_malloc_list != 0);
+ tl_assert(stop_using_mem_callback);
+
+ s_start_using_mem_callback = start_using_mem_callback;
+ s_stop_using_mem_callback = stop_using_mem_callback;
+
+ VG_(needs_malloc_replacement)(drd_malloc,
+ drd___builtin_new,
+ drd___builtin_vec_new,
+ drd_memalign,
+ drd_calloc,
+ drd_free,
+ drd___builtin_delete,
+ drd___builtin_vec_delete,
+ drd_realloc,
+ 0);
+}
+
+Bool drd_heap_addrinfo(Addr const a,
+ Addr* const data,
+ SizeT* const size,
+ ExeContext** const where)
+{
+ DRD_Chunk* mc;
+
+ tl_assert(data);
+ tl_assert(size);
+ tl_assert(where);
+
+ VG_(HT_ResetIter)(drd_malloc_list);
+ while ((mc = VG_(HT_Next)(drd_malloc_list)))
+ {
+ if (mc->data <= a && a < mc->data + mc->size)
+ {
+ *data = mc->data;
+ *size = mc->size;
+ *where = mc->where;
+ return True;
+ }
+ }
+ return False;
+}
+
+/*------------------------------------------------------------*/
+/*--- Statistics printing ---*/
+/*------------------------------------------------------------*/
+
+void drd_print_malloc_stats(void)
+{
+ DRD_Chunk* mc;
+ SizeT nblocks = 0;
+ SizeT nbytes = 0;
+
+ if (VG_(clo_verbosity) == 0)
+ return;
+ if (VG_(clo_xml))
+ return;
+
+ /* Count memory still in use. */
+ VG_(HT_ResetIter)(drd_malloc_list);
+ while ((mc = VG_(HT_Next)(drd_malloc_list)))
+ {
+ nblocks++;
+ nbytes += mc->size;
+ }
+
+ VG_(message)(Vg_DebugMsg,
+ "malloc/free: in use at exit: %lu bytes in %lu blocks.",
+ nbytes, nblocks);
+ VG_(message)(Vg_DebugMsg,
+ "malloc/free: %lu allocs, %lu frees, %lu bytes allocated.",
+ cmalloc_n_mallocs,
+ cmalloc_n_frees, cmalloc_bs_mallocd);
+ if (VG_(clo_verbosity) > 1)
+ VG_(message)(Vg_DebugMsg, " ");
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ * Local variables:
+ * c-basic-offset: 3
+ * End:
+ */