mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 05:35:31 +00:00
3ee916ea11
--HG-- rename : xpcom/base/dmd.h => tools/dmdv/dmdv.h
2033 lines
65 KiB
Diff
2033 lines
65 KiB
Diff
Index: exp-dmdv.supp
|
|
===================================================================
|
|
--- exp-dmdv.supp (revision 0)
|
|
+++ exp-dmdv.supp (revision 0)
|
|
@@ -0,0 +1,17 @@
|
|
+##----------------------------------------------------------------------##
|
|
+# For DMDV and Firefox. SQLite has its own memory reporting infrastructure
|
|
+# which we can't tie into mallocSizeOf. So just suppress those ones.
|
|
+{
|
|
+ SQLite-malloc
|
|
+ DMDV:Unreported
|
|
+ fun:malloc
|
|
+ fun:sqlite3MemMalloc
|
|
+}
|
|
+
|
|
+{
|
|
+ SQLite-realloc
|
|
+ DMDV:Unreported
|
|
+ fun:realloc
|
|
+ fun:sqlite3MemRealloc
|
|
+}
|
|
+
|
|
Index: exp-dmdv/dmdv_main.c
|
|
===================================================================
|
|
--- exp-dmdv/dmdv_main.c (revision 0)
|
|
+++ exp-dmdv/dmdv_main.c (revision 0)
|
|
@@ -0,0 +1,1099 @@
|
|
+
|
|
+/*--------------------------------------------------------------------*/
|
|
+/*--- DMDV: A dark matter detector. dmdv_main.c ---*/
|
|
+/*--------------------------------------------------------------------*/
|
|
+
|
|
+/*
|
|
+ This file is part of DMDV, a dark matter detector.
|
|
+
|
|
+ Copyright (C) 2011-2011 Nicholas Nethercote
|
|
+ njn@valgrind.org
|
|
+
|
|
+ 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_aspacemgr.h"
|
|
+#include "pub_tool_execontext.h"
|
|
+#include "pub_tool_hashtable.h"
|
|
+#include "pub_tool_libcbase.h"
|
|
+#include "pub_tool_libcassert.h"
|
|
+#include "pub_tool_libcprint.h"
|
|
+#include "pub_tool_mallocfree.h"
|
|
+#include "pub_tool_options.h"
|
|
+#include "pub_tool_oset.h"
|
|
+#include "pub_tool_replacemalloc.h"
|
|
+#include "pub_tool_stacktrace.h" // XXX: temp? just for printing stacks
|
|
+#include "pub_tool_threadstate.h" // XXX: temp? just for printing stacks
|
|
+#include "pub_tool_tooliface.h"
|
|
+#include "pub_tool_vki.h"
|
|
+
|
|
+#include "dmdv.h" /* for client requests */
|
|
+
|
|
+// Todo:
|
|
+//
|
|
+// - Use a Massif-style allocation tree for unreported blocks -- makes it more
|
|
+// obvious if lots of small almost-the-same records add up to significant
|
|
+// amounts, and saves the hassle of trying different --num-callers values.
|
|
+// Compute it from the stack traces only at CHECK_REPORTING time. Should be
|
|
+// able to avoid looking up the debug info until the very end?
|
|
+//
|
|
+// - Would be good to track mmap'd blocks in such a way that any breakage
|
|
+// (e.g. regexp-code wasn't working for a while) is detected. Probably
|
|
+// would need suppressions for the common cases like dl_load and pthread
|
|
+// stacks.
|
|
+//
|
|
+// - Insert a sanity-check that REPORT isn't called outside of a
|
|
+// CHECK_REPORTING context (need to mark the end of such a context). [Would
|
|
+// need to distinguish between traverse-REPORT and counter-REPORT].
|
|
+//
|
|
+// - Probably should split DMDV_REPORT into two, one for each kind of reporter,
|
|
+// and store maintain-a-counter counts in a separate table.
|
|
+//
|
|
+
|
|
+// A note about reporter styles:
|
|
+// - Traverse-based reporters are easy to handle. They just call DMDV_REPORT
|
|
+// on each heap block. If we only had that style of reporter then all R
|
|
+// bits would be clear before about:memory is loaded, and we could clear all
|
|
+// R bits after CHECK_REPORTING is finished.
|
|
+//
|
|
+// - Counter-based reporters are more difficult. We could suppress
|
|
+// them, but that's inaccurate -- e.g. we could be missing some slop bytes
|
|
+// and not know. It's better to call DMDV_REPORT and DMDV_UNREPORT on the
|
|
+// relevant heap blocks as they are counted/uncounted. But that means that
|
|
+// some hb->isReported flags are set even before about:memory is loaded;
|
|
+// and those bits should still be set afterwards. Could introduce a second
|
|
+// flag to handle this, but for now we just restrict CHECK_REPORTING to only
|
|
+// be called once.
|
|
+
|
|
+// A note about terminology:
|
|
+// - A block that isn't fully reported is "under-reported". (But all heap
|
|
+// blocks are now either fully-reported or not reported at all.)
|
|
+// - Bytes within that block that aren't reported are "unreported".
|
|
+// - So "under-reported" refers to blocks, "unreported" refers to bytes.
|
|
+
|
|
+//------------------------------------------------------------//
|
|
+//--- Command line args ---//
|
|
+//------------------------------------------------------------//
|
|
+
|
|
+//static Bool cloMmap = False;
|
|
+
|
|
+static Bool dmdv_process_cmd_line_option(Char* arg)
|
|
+{
|
|
+ VG_(clo_backtrace_size) = 8; // re-define for DMDV
|
|
+
|
|
+ // njn: disabled for now
|
|
+ //if VG_BOOL_CLO(arg, "--mmap", cloMmap) {}
|
|
+ //else
|
|
+ // return False;
|
|
+
|
|
+ return True;
|
|
+}
|
|
+
|
|
+static void dmdv_print_usage(void)
|
|
+{
|
|
+ VG_(printf)(
|
|
+" --mmap=no|yes track mmap blocks [no]\n"
|
|
+ );
|
|
+}
|
|
+
|
|
+static void dmdv_print_debug_usage(void)
|
|
+{
|
|
+ VG_(printf)(
|
|
+" (none)\n"
|
|
+ );
|
|
+}
|
|
+
|
|
+//------------------------------------------------------------//
|
|
+//--- Heap management ---//
|
|
+//------------------------------------------------------------//
|
|
+
|
|
+// This is used by both HeapBlocks and Records.
|
|
+typedef
|
|
+ struct {
|
|
+ ExeContext* allocPt; // Where allocated
|
|
+ ExeContext* reportPt; // Where reported; NULL if unreported
|
|
+ const Char* reporter; // Reporter name; NULL if unreported
|
|
+ }
|
|
+ HeapKey;
|
|
+
|
|
+// Nb: first two fields must match core's VgHashNode.
|
|
+typedef
|
|
+ struct _HeapBlock {
|
|
+ struct _HeapBlock* next;
|
|
+ Addr data; // Ptr to actual block
|
|
+ SizeT reqSzB; // Size requested
|
|
+ SizeT usableSzB; // Size allocated
|
|
+ HeapKey key;
|
|
+ }
|
|
+ HeapBlock;
|
|
+
|
|
+static VgHashTable heapBlocks = NULL;
|
|
+
|
|
+// Compute the size of the block that would be allocated by jemalloc.
|
|
+static
|
|
+SizeT getJemallocSize(SizeT n)
|
|
+{
|
|
+ // Small/Tiny: 2, 4, 8 (bytes)
|
|
+ if (n <= 2) n = 2;
|
|
+ else if (n <= 4) n = 4;
|
|
+ else if (n <= 8) n = 8;
|
|
+
|
|
+ // Small/Quantum-spaced: 16, 32, 48, ..., 480, 496, 512 (bytes)
|
|
+ else if (n <= 512) n = VG_ROUNDUP(n, 16);
|
|
+
|
|
+ // Small/Sub-page: 1, 2 (KiB)
|
|
+ else if (n <= 2*1024) n = VG_ROUNDUP(n, 1024);
|
|
+
|
|
+ // Large: 4, 8, 12, ..., 1012, 1016, 1020 (KiB)
|
|
+ // Huge: 1 MiB + 4 KiB, 1 MiB + 8 KiB, ...
|
|
+ else n = VG_ROUNDUP(n, 4*1024);
|
|
+
|
|
+ return n;
|
|
+}
|
|
+
|
|
+static __inline__
|
|
+void* allocAndRecordBlock(ThreadId tid, SizeT reqSzB, SizeT reqAlignB,
|
|
+ Bool isZeroed)
|
|
+{
|
|
+ SizeT usableSzB;
|
|
+ void* p;
|
|
+
|
|
+ if ((SSizeT)reqSzB < 0)
|
|
+ return NULL;
|
|
+
|
|
+ // Round up the request size so that we allocate the amount of memory that
|
|
+ // jemalloc would allocate. And determine the amount of slop jemalloc
|
|
+ // would produce. In some cases Valgrind's allocator produces extra slop
|
|
+ // on top; we don't count that.
|
|
+ usableSzB = getJemallocSize(reqSzB);
|
|
+ p = VG_(cli_malloc)(reqAlignB, usableSzB);
|
|
+ if (!p) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ // Zero if necessary.
|
|
+ if (isZeroed) {
|
|
+ VG_(memset)(p, 0, usableSzB);
|
|
+ }
|
|
+
|
|
+ // Record block.
|
|
+ HeapBlock* hb = VG_(malloc)("dmdv.main.rb.1", sizeof(HeapBlock));
|
|
+ hb->reqSzB = reqSzB;
|
|
+ hb->usableSzB = usableSzB;
|
|
+ hb->data = (Addr)p;
|
|
+ hb->key.allocPt = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
|
|
+ hb->key.reportPt = NULL;
|
|
+ hb->key.reporter = NULL;
|
|
+ VG_(HT_add_node)(heapBlocks, hb);
|
|
+
|
|
+ return p;
|
|
+}
|
|
+
|
|
+static __inline__
|
|
+void unrecordAndFreeBlock(void* p)
|
|
+{
|
|
+ HeapBlock* hb = VG_(HT_remove)(heapBlocks, (UWord)p);
|
|
+ if (NULL == hb) {
|
|
+ return; // must have been a bogus free()
|
|
+ }
|
|
+
|
|
+ // Free the block and its metadata.
|
|
+ VG_(free)(hb);
|
|
+ VG_(cli_free)(p);
|
|
+}
|
|
+
|
|
+static __inline__
|
|
+void* reallocAndRecordBlock(ThreadId tid, void* pOld, SizeT newReqSzB)
|
|
+{
|
|
+ HeapBlock* hb;
|
|
+ void* pNew;
|
|
+ SizeT oldUsableSzB, newUsableSzB;
|
|
+
|
|
+ // Remove the old block
|
|
+ hb = VG_(HT_remove)(heapBlocks, (UWord)pOld);
|
|
+ if (hb == NULL) {
|
|
+ return NULL; // must have been a bogus realloc()
|
|
+ }
|
|
+
|
|
+ oldUsableSzB = hb->usableSzB;
|
|
+
|
|
+ if (newReqSzB <= oldUsableSzB) {
|
|
+ // New size is smaller or same; block not moved.
|
|
+ pNew = pOld;
|
|
+ newUsableSzB = oldUsableSzB;
|
|
+
|
|
+ } else {
|
|
+ newUsableSzB = getJemallocSize(newReqSzB);
|
|
+
|
|
+ // New size is bigger; make new block, copy shared contents, free old.
|
|
+ pNew = VG_(cli_malloc)(VG_(clo_alignment), newUsableSzB);
|
|
+ if (!pNew) {
|
|
+ // Nb: if realloc fails, NULL is returned but the old block is not
|
|
+ // touched. What an awful function.
|
|
+ return NULL;
|
|
+ }
|
|
+ VG_(memcpy)(pNew, pOld, oldUsableSzB);
|
|
+ VG_(cli_free)(pOld);
|
|
+ }
|
|
+
|
|
+ if (pNew) {
|
|
+ // Update HeapBlock.
|
|
+ hb->data = (Addr)pNew;
|
|
+ hb->reqSzB = newReqSzB;
|
|
+ hb->usableSzB = newUsableSzB;
|
|
+ hb->key.allocPt = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
|
|
+ }
|
|
+
|
|
+ // Now insert the new hb (with a possibly new 'data' field) into
|
|
+ // heapBlocks. If this realloc() did not increase the memory size, we
|
|
+ // will have removed and then re-added hb 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)(heapBlocks, hb);
|
|
+
|
|
+ return pNew;
|
|
+}
|
|
+
|
|
+//------------------------------------------------------------//
|
|
+//--- Mapping management ---//
|
|
+//------------------------------------------------------------//
|
|
+
|
|
+#if 0
|
|
+static __inline__
|
|
+void recordMapBlock(ThreadId tid, Addr a, SizeT szB)
|
|
+{
|
|
+ // Record block.
|
|
+ HeapBlock* hb = VG_(malloc)("dmdv.main.rmb.1", sizeof(HeapBlock));
|
|
+ hb->data = a;
|
|
+ hb->reqSzB = szB;
|
|
+ tl_assert(VG_IS_PAGE_ALIGNED(szB));
|
|
+ hb->slopSzB = 0;
|
|
+ hb->where = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
|
|
+ hb->isHeap = False;
|
|
+ VG_(HT_add_node)(blocks, hb);
|
|
+}
|
|
+
|
|
+static __inline__
|
|
+void unrecordMapBlock(Addr a, SizeT szB)
|
|
+{
|
|
+ HeapBlock* hb = VG_(HT_remove)(blocks, a);
|
|
+ if (NULL == hb) {
|
|
+ tl_assert(0); // njn
|
|
+ VG_(printf)("WARNING: removing unknown mapBlock: 0x%lx, %lu\n", a, szB);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ // Clear R bits; if the block has been reported and is recycled after it's
|
|
+ // freed, we don't want it to be bogusly considered reported.
|
|
+ Addr limit = a + szB;
|
|
+ while (a < limit) {
|
|
+ clearRbit(a);
|
|
+ a++;
|
|
+ }
|
|
+
|
|
+ // Free the mapping's metadata.
|
|
+ VG_(free)(hb); hb = NULL;
|
|
+}
|
|
+#endif
|
|
+
|
|
+//------------------------------------------------------------//
|
|
+//--- malloc() et al replacement wrappers ---//
|
|
+//------------------------------------------------------------//
|
|
+
|
|
+static void* dmdv_malloc(ThreadId tid, SizeT szB)
|
|
+{
|
|
+ return allocAndRecordBlock(tid, szB, VG_(clo_alignment), /*isZeroed*/False);
|
|
+}
|
|
+
|
|
+static void* dmdv___builtin_new(ThreadId tid, SizeT szB)
|
|
+{
|
|
+ return allocAndRecordBlock(tid, szB, VG_(clo_alignment), /*isZeroed*/False);
|
|
+}
|
|
+
|
|
+static void* dmdv___builtin_vec_new(ThreadId tid, SizeT szB)
|
|
+{
|
|
+ return allocAndRecordBlock(tid, szB, VG_(clo_alignment), /*isZeroed*/False);
|
|
+}
|
|
+
|
|
+static void* dmdv_calloc(ThreadId tid, SizeT m, SizeT szB)
|
|
+{
|
|
+ return allocAndRecordBlock(tid, m*szB, VG_(clo_alignment), /*isZeroed*/True);
|
|
+}
|
|
+
|
|
+static void *dmdv_memalign(ThreadId tid, SizeT alignB, SizeT szB)
|
|
+{
|
|
+ return allocAndRecordBlock(tid, szB, alignB, /*isZeroed*/False);
|
|
+}
|
|
+
|
|
+static void dmdv_free(ThreadId tid __attribute__((unused)), void* p)
|
|
+{
|
|
+ unrecordAndFreeBlock(p);
|
|
+}
|
|
+
|
|
+static void dmdv___builtin_delete(ThreadId tid, void* p)
|
|
+{
|
|
+ unrecordAndFreeBlock(p);
|
|
+}
|
|
+
|
|
+static void dmdv___builtin_vec_delete(ThreadId tid, void* p)
|
|
+{
|
|
+ unrecordAndFreeBlock(p);
|
|
+}
|
|
+
|
|
+static void* dmdv_realloc(ThreadId tid, void* pOld, SizeT new_szB)
|
|
+{
|
|
+ return reallocAndRecordBlock(tid, pOld, new_szB);
|
|
+}
|
|
+
|
|
+static SizeT dmdv_malloc_usable_size(ThreadId tid, void* p)
|
|
+{
|
|
+ HeapBlock* hb = VG_(HT_lookup)(heapBlocks, (UWord)p);
|
|
+ return hb ? hb->usableSzB : 0;
|
|
+}
|
|
+
|
|
+//------------------------------------------------------------//
|
|
+//--- mmap() et al tracers ---//
|
|
+//------------------------------------------------------------//
|
|
+
|
|
+#if 0
|
|
+static
|
|
+void dmdv_new_mem_startup(Addr a, SizeT len,
|
|
+ Bool rr, Bool ww, Bool xx, ULong di_handle)
|
|
+{
|
|
+ // Ignore.
|
|
+}
|
|
+
|
|
+static
|
|
+void dmdv_new_mem_mmap(Addr a, SizeT len,
|
|
+ Bool rr, Bool ww, Bool xx, ULong di_handle)
|
|
+{
|
|
+ if (cloMmap) {
|
|
+ tl_assert(VG_IS_PAGE_ALIGNED(len));
|
|
+ recordMapBlock(VG_(get_running_tid)(), a, len);
|
|
+ //VG_(printf)("foo: mmap: 0x%lx, %lu\n", a, len);
|
|
+ //VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 8);
|
|
+ }
|
|
+}
|
|
+
|
|
+static
|
|
+void dmdv_die_mem_munmap(Addr a, SizeT len)
|
|
+{
|
|
+ if (cloMmap) {
|
|
+ tl_assert(VG_IS_PAGE_ALIGNED(len));
|
|
+ unrecordMapBlock(a, len);
|
|
+ //VG_(printf)("foo: munmap: 0x%lx, %lu\n", a, len);
|
|
+ //VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 8);
|
|
+ }
|
|
+}
|
|
+
|
|
+static
|
|
+void dmdv_copy_mem_remap(Addr from, Addr to, SizeT len)
|
|
+{
|
|
+ if (cloMmap) {
|
|
+ tl_assert(0); // njn
|
|
+ tl_assert(VG_IS_PAGE_ALIGNED(len));
|
|
+ //dmdv_unrecord_page_mem(from, len);
|
|
+ //dmdv_record_page_mem(to, len);
|
|
+ VG_(printf)("foo: mremap: 0x%lx, 0x%lx, %lu\n", from, to, len);
|
|
+ VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 8);
|
|
+ }
|
|
+}
|
|
+
|
|
+static
|
|
+void dmdv_new_mem_brk ( Addr a, SizeT len, ThreadId tid )
|
|
+{
|
|
+ if (cloMmap) {
|
|
+ tl_assert(0); // njn
|
|
+ tl_assert(VG_IS_PAGE_ALIGNED(len));
|
|
+ //dmdv_record_page_mem(a, len);
|
|
+ VG_(printf)("foo: brk: 0x%lx, %lu\n", a, len);
|
|
+ VG_(get_and_pp_StackTrace)(tid, 8);
|
|
+ }
|
|
+}
|
|
+
|
|
+static
|
|
+void dmdv_die_mem_brk( Addr a, SizeT len )
|
|
+{
|
|
+ if (cloMmap) {
|
|
+ tl_assert(0); // njn
|
|
+ tl_assert(VG_IS_PAGE_ALIGNED(len));
|
|
+ //dmdv_unrecord_page_mem(a, len);
|
|
+ VG_(printf)("foo: unbrk: 0x%lx, %lu\n", a, len);
|
|
+ VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), 8);
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
+//------------------------------------------------------------//
|
|
+//--- Errors ---//
|
|
+//------------------------------------------------------------//
|
|
+
|
|
+// An record about one or more heap blocks with a common HeapKey, used for
|
|
+// generating err msgs. All reported blocks with a common HeapKey get
|
|
+// aggregated into one Record, and all unreported blocks with the same HeapKey
|
|
+// trace get aggregated into a different record.
|
|
+typedef
|
|
+ struct _Record {
|
|
+ HeapKey key;
|
|
+ SizeT nBlocks; // Num. of blocks of this kind with this ExeContext
|
|
+ SizeT reqSzB; // Requested bytes that are (un)reported
|
|
+ SizeT usableSzB; // Usable (requested+slop) bytes that are (un)reported
|
|
+ }
|
|
+ Record;
|
|
+
|
|
+typedef
|
|
+ enum {
|
|
+ Err_DoubleReported,
|
|
+ Err_Unreported,
|
|
+ Err_Reported
|
|
+ }
|
|
+ DMDV_ErrorTag;
|
|
+
|
|
+typedef struct _DMDV_Error DMDV_Error;
|
|
+
|
|
+struct _DMDV_Error {
|
|
+ // Nb: we don't need the tag here, as it's stored in the Error type! Yuk.
|
|
+ //ErrorTag tag;
|
|
+
|
|
+ union {
|
|
+ // Double-reported block.
|
|
+ struct {
|
|
+ HeapBlock* hb;
|
|
+ const Char* newReporter;
|
|
+ } DoubleReported;
|
|
+
|
|
+ // Unreported heap block. Storing aSumB in every block is inefficient,
|
|
+ // but it hardly matters.
|
|
+ struct {
|
|
+ Record* r;
|
|
+ Int nThisRecord;
|
|
+ Int nTotalRecords;
|
|
+ SizeT cSumB;
|
|
+ SizeT aSumB;
|
|
+ } Unreported;
|
|
+
|
|
+ // Reported heap block. Storing aSumB in every block is inefficient,
|
|
+ // but it hardly matters.
|
|
+ // njn: same as Unreported
|
|
+ struct {
|
|
+ Record* r;
|
|
+ Int nThisRecord;
|
|
+ Int nTotalRecords;
|
|
+ SizeT cSumB;
|
|
+ SizeT aSumB;
|
|
+ } Reported;
|
|
+
|
|
+ } Err;
|
|
+};
|
|
+
|
|
+static void dmdv_record_doubleReported_error(ThreadId tid, Addr a, HeapBlock* hb,
|
|
+ const Char* newReporter)
|
|
+{
|
|
+ DMDV_Error extra;
|
|
+ extra.Err.DoubleReported.hb = hb;
|
|
+ extra.Err.DoubleReported.newReporter = newReporter;
|
|
+ VG_(maybe_record_error)(tid, Err_DoubleReported, a, /*s*/NULL, &extra);
|
|
+}
|
|
+
|
|
+static Bool dmdv_record_unreported_error(ThreadId tid, Int n, Int nRecords,
|
|
+ Record* r, SizeT cSumB, SizeT aSumB)
|
|
+{
|
|
+ DMDV_Error extra;
|
|
+ extra.Err.Unreported.r = r;
|
|
+ extra.Err.Unreported.nThisRecord = n;
|
|
+ extra.Err.Unreported.nTotalRecords = nRecords;
|
|
+ extra.Err.Unreported.cSumB = cSumB;
|
|
+ extra.Err.Unreported.aSumB = aSumB;
|
|
+ return
|
|
+ VG_(unique_error)(tid, Err_Unreported, /*Addr*/0, /*s*/NULL, &extra,
|
|
+ r->key.allocPt, /*print_record*/True,
|
|
+ /*allow_GDB_attach*/False, /*count_error*/True);
|
|
+}
|
|
+
|
|
+static Bool dmdv_record_reported_error(ThreadId tid, Int n, Int nRecords,
|
|
+ Record* r, SizeT cSumB, SizeT aSumB)
|
|
+{
|
|
+ DMDV_Error extra;
|
|
+ extra.Err.Reported.r = r;
|
|
+ extra.Err.Reported.nThisRecord = n;
|
|
+ extra.Err.Reported.nTotalRecords = nRecords;
|
|
+ extra.Err.Reported.cSumB = cSumB;
|
|
+ extra.Err.Reported.aSumB = aSumB;
|
|
+ return
|
|
+ VG_(unique_error)(tid, Err_Reported, /*Addr*/0, /*s*/NULL, &extra,
|
|
+ r->key.allocPt, /*print_record*/True,
|
|
+ /*allow_GDB_attach*/False, /*count_error*/True);
|
|
+}
|
|
+
|
|
+static Bool dmdv_eq_Error(VgRes res, Error* e1, Error* e2)
|
|
+{
|
|
+ /* Guaranteed by calling function */
|
|
+ tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
|
|
+
|
|
+ switch (VG_(get_error_kind)(e1)) {
|
|
+ case Err_DoubleReported: {
|
|
+ DMDV_Error* extra1 = (DMDV_Error*)VG_(get_error_extra)(e1);
|
|
+ DMDV_Error* extra2 = (DMDV_Error*)VG_(get_error_extra)(e2);
|
|
+ // We could check if the hb->key.allocPt fields match, but it doesn't
|
|
+ // seem like it would matter much.
|
|
+ const Char* oldReporter1 = extra1->Err.DoubleReported.hb->key.reporter;
|
|
+ const Char* oldReporter2 = extra2->Err.DoubleReported.hb->key.reporter;
|
|
+ const Char* newReporter1 = extra1->Err.DoubleReported.newReporter;
|
|
+ const Char* newReporter2 = extra2->Err.DoubleReported.newReporter;
|
|
+
|
|
+ // njn: oldReporter1 here can be 0xDDDDDDDDDDDDDDDD, which indicates
|
|
+ // it's in memory that's been freed. That's odd, because AFAICT
|
|
+ // oldReporter1 will always comes from the 3rd arg to DMDV_REPORT,
|
|
+ // which should always be a static string in Firefox. Hmm.
|
|
+ if (VG_STREQ(oldReporter1, oldReporter2) &&
|
|
+ VG_STREQ(newReporter1, newReporter2))
|
|
+ {
|
|
+ return True;
|
|
+ }
|
|
+ return False;
|
|
+ }
|
|
+
|
|
+ case Err_Unreported:
|
|
+ case Err_Reported:
|
|
+ tl_assert(0); // should never be called for unique errors
|
|
+ return True;
|
|
+
|
|
+ default:
|
|
+ VG_(printf)("Error:\n unknown error code %d\n",
|
|
+ VG_(get_error_kind)(e1));
|
|
+ VG_(tool_panic)("unknown error code in mc_eq_Error");
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dmdv_before_pp_Error(Error* err) { /* Do nothing. */ }
|
|
+
|
|
+static void dmdv_pp_Error(Error* err)
|
|
+{
|
|
+ DMDV_Error* extra = VG_(get_error_extra)(err);
|
|
+ #define BUFLEN 32
|
|
+ char buf1[BUFLEN];
|
|
+ char buf2[BUFLEN];
|
|
+
|
|
+ switch (VG_(get_error_kind)(err)) {
|
|
+ case Err_DoubleReported:
|
|
+ VG_(umsg)("Double report of heap block %p:\n",
|
|
+ (void*)VG_(get_error_address)(err));
|
|
+
|
|
+ VG_(umsg)(" Allocated\n");
|
|
+ VG_(pp_ExeContext)(extra->Err.DoubleReported.hb->key.allocPt);
|
|
+
|
|
+ VG_(umsg)(" Previously reported by '%s'\n",
|
|
+ extra->Err.DoubleReported.hb->key.reporter);
|
|
+ VG_(pp_ExeContext)(extra->Err.DoubleReported.hb->key.reportPt);
|
|
+
|
|
+ VG_(umsg)(" Now reported by '%s'\n",
|
|
+ extra->Err.DoubleReported.newReporter);
|
|
+ VG_(pp_ExeContext)(VG_(get_error_where)(err));
|
|
+ break;
|
|
+
|
|
+ case Err_Unreported: {
|
|
+ Record* r = extra->Err.Unreported.r;
|
|
+ SizeT aSumB = extra->Err.Unreported.aSumB;
|
|
+ SizeT cSumB = extra->Err.Unreported.cSumB + r->usableSzB;
|
|
+ VG_(umsg)("Unreported: %'lu block(s) in record %d of %d\n",
|
|
+ r->nBlocks,
|
|
+ extra->Err.Unreported.nThisRecord,
|
|
+ extra->Err.Unreported.nTotalRecords);
|
|
+ VG_(umsg)(" %'lu bytes (%'lu requested / %'lu slop)\n",
|
|
+ r->usableSzB, r->reqSzB, r->usableSzB - r->reqSzB);
|
|
+ VG_(percentify)(r->usableSzB, aSumB, 2, 0, buf1);
|
|
+ VG_(percentify)(cSumB, aSumB, 2, 0, buf2);
|
|
+ VG_(umsg)(" %s of the heap (%s cumulative unreported)\n", buf1, buf2);
|
|
+ VG_(pp_ExeContext)(VG_(get_error_where)(err));
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case Err_Reported: {
|
|
+ Record* r = extra->Err.Reported.r;
|
|
+ SizeT aSumB = extra->Err.Reported.aSumB;
|
|
+ SizeT cSumB = extra->Err.Reported.cSumB + r->usableSzB;
|
|
+ VG_(umsg)("Reported(%s): %'lu block(s) in record %d of %d\n",
|
|
+ r->key.reporter, r->nBlocks,
|
|
+ extra->Err.Reported.nThisRecord,
|
|
+ extra->Err.Reported.nTotalRecords);
|
|
+ VG_(umsg)(" %'lu bytes (%'lu requested / %'lu slop)\n",
|
|
+ r->usableSzB, r->reqSzB, r->usableSzB - r->reqSzB);
|
|
+ VG_(percentify)(r->usableSzB, aSumB, 2, 0, buf1);
|
|
+ VG_(percentify)(cSumB, aSumB, 2, 0, buf2);
|
|
+ VG_(umsg)(" %s of the heap (%s cumulative reported)\n", buf1, buf2);
|
|
+
|
|
+ VG_(umsg)(" Allocated\n");
|
|
+ VG_(pp_ExeContext)(VG_(get_error_where)(err)); // the allocPt
|
|
+
|
|
+ VG_(umsg)(" Reported\n");
|
|
+ VG_(pp_ExeContext)(r->key.reportPt);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ default:
|
|
+ VG_(printf)("Error:\n unknown DMDV error code %d\n",
|
|
+ VG_(get_error_kind)(err));
|
|
+ VG_(tool_panic)("unknown error code in dmdv_pp_Error)");
|
|
+ }
|
|
+}
|
|
+
|
|
+static UInt dmdv_update_extra(Error* err)
|
|
+{
|
|
+ return sizeof(DMDV_Error);
|
|
+}
|
|
+
|
|
+static Char* dmdv_get_error_name(Error* err)
|
|
+{
|
|
+ switch (VG_(get_error_kind)(err)) {
|
|
+ case Err_DoubleReported: return "DoubleReported";
|
|
+ case Err_Unreported: return "Unreported";
|
|
+ case Err_Reported: return "Reported";
|
|
+ default: VG_(tool_panic)("dmdv_get_error_name: unexpected type");
|
|
+ }
|
|
+}
|
|
+
|
|
+/*------------------------------------------------------------*/
|
|
+/*--- Suppressions ---*/
|
|
+/*------------------------------------------------------------*/
|
|
+
|
|
+typedef
|
|
+ enum {
|
|
+ DoubleReportedSupp,
|
|
+ UnreportedSupp,
|
|
+ ReportedSupp,
|
|
+ }
|
|
+ DMDV_SuppKind;
|
|
+
|
|
+static Bool dmdv_is_recognised_suppression(Char* name, Supp* su)
|
|
+{
|
|
+ SuppKind skind;
|
|
+
|
|
+ if (VG_STREQ(name, "DoubleReported")) skind = DoubleReportedSupp;
|
|
+ else if (VG_STREQ(name, "Unreported")) skind = UnreportedSupp;
|
|
+ else if (VG_STREQ(name, "Reported")) skind = ReportedSupp;
|
|
+ else
|
|
+ return False;
|
|
+
|
|
+ VG_(set_supp_kind)(su, skind);
|
|
+ return True;
|
|
+}
|
|
+
|
|
+static Bool dmdv_read_extra_suppression_info(Int fd, Char** bufpp,
|
|
+ SizeT* nBufp, Supp *su )
|
|
+{
|
|
+ return True;
|
|
+}
|
|
+
|
|
+static Bool dmdv_error_matches_suppression(Error* err, Supp* su)
|
|
+{
|
|
+ ErrorKind ekind = VG_(get_error_kind )(err);
|
|
+
|
|
+ switch (VG_(get_supp_kind)(su)) {
|
|
+ case DoubleReportedSupp:
|
|
+ return (ekind == Err_DoubleReported);
|
|
+
|
|
+ case UnreportedSupp:
|
|
+ return (ekind == Err_Unreported);
|
|
+
|
|
+ case ReportedSupp:
|
|
+ return (ekind == Err_Reported);
|
|
+
|
|
+ default:
|
|
+ VG_(printf)("Error:\n unknown suppression type %d\n",
|
|
+ VG_(get_supp_kind)(su));
|
|
+ VG_(tool_panic)("unknown suppression type in "
|
|
+ "dmdv_error_matches_suppression");
|
|
+ }
|
|
+}
|
|
+
|
|
+static Bool dmdv_get_extra_suppression_info(Error* err, /*OUT*/Char* buf,
|
|
+ Int nBuf)
|
|
+{
|
|
+ return False;
|
|
+}
|
|
+
|
|
+/*------------------------------------------------------------*/
|
|
+/*--- Checking ---*/
|
|
+/*------------------------------------------------------------*/
|
|
+
|
|
+static Word cmpRecordByHeapKey(const void* key, const void* elem)
|
|
+{
|
|
+ HeapKey* a = (HeapKey*)key;
|
|
+ HeapKey* b = &((Record*)elem)->key;
|
|
+
|
|
+ // Always use Vg_HighRes -- the lower values don't make that much sense,
|
|
+ // because then the lower entries shown for the record aren't
|
|
+ // representative. Better to control this via --num-callers.
|
|
+ VgRes res = Vg_HighRes;
|
|
+
|
|
+ // Check the allocation point.
|
|
+ if (!VG_(eq_ExeContext)(res, a->allocPt, b->allocPt)) {
|
|
+ if (a->allocPt < b->allocPt) return -1;
|
|
+ if (a->allocPt > b->allocPt) return 1;
|
|
+ VG_(tool_panic)("bad Record comparison");
|
|
+ }
|
|
+
|
|
+ // Same allocation point, now check the reporter.
|
|
+ if (!a->reporter && !b->reporter) return 0;
|
|
+ if ( a->reporter && !b->reporter) return -1;
|
|
+ if (!a->reporter && b->reporter) return 1;
|
|
+ Int cmp = VG_(strcmp)(a->reporter, b->reporter);
|
|
+ if (cmp != 0) return cmp;
|
|
+
|
|
+ // Same reporter, now check the report point.
|
|
+ tl_assert(a->reportPt && b->reportPt);
|
|
+ if (!VG_(eq_ExeContext)(res, a->reportPt, b->reportPt)) {
|
|
+ if (a->reportPt < b->reportPt) return -1;
|
|
+ if (a->reportPt > b->reportPt) return 1;
|
|
+ VG_(tool_panic)("bad HeapKey comparison");
|
|
+ }
|
|
+
|
|
+ // They're equal.
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static Int cmpRecordBySize(void* va, void* vb)
|
|
+{
|
|
+ Record* a = *(Record**)va;
|
|
+ Record* b = *(Record**)vb;
|
|
+
|
|
+ // Compare by sizes.
|
|
+ if (a->usableSzB < b->usableSzB) return 1;
|
|
+ if (a->usableSzB > b->usableSzB) return -1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void reportHeapBlock(ThreadId tid, Addr a, SizeT len, const Char* name)
|
|
+{
|
|
+ if (!a && !len)
|
|
+ return;
|
|
+
|
|
+ // Get HeapBlock, check it matches the report, and mark it as reported.
|
|
+ HeapBlock* hb = VG_(HT_lookup)(heapBlocks, a);
|
|
+ if (!hb) {
|
|
+ VG_(umsg)("REPORT WARNING(%s): no such heap block %p (length %'lu):\n",
|
|
+ name, (void*)a, len);
|
|
+ VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
|
|
+ VG_(umsg)("\n");
|
|
+ return;
|
|
+ }
|
|
+ if (hb->usableSzB != len) {
|
|
+ VG_(umsg)("REPORT WARNING(%s): size mismatch: reported=%'lu, actual=%'lu (using actual)\n",
|
|
+ name, len, hb->usableSzB);
|
|
+ }
|
|
+ if (hb->key.reporter) {
|
|
+ tl_assert(hb->key.reportPt);
|
|
+ dmdv_record_doubleReported_error(tid, a, hb, name);
|
|
+ } else {
|
|
+ tl_assert(!hb->key.reportPt);
|
|
+ hb->key.reportPt = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
|
|
+ hb->key.reporter = name;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void unreportHeapBlock(ThreadId tid, Addr a)
|
|
+{
|
|
+ if (!a)
|
|
+ return;
|
|
+
|
|
+ // Get HeapBlock, check it matches the report, and mark it as unreported.
|
|
+ HeapBlock* hb = VG_(HT_lookup)(heapBlocks, a);
|
|
+ if (!hb) {
|
|
+ VG_(umsg)("UNREPORT WARNING: no such heap block\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!hb->key.reporter) {
|
|
+ VG_(umsg)("UNREPORT WARNING: block is not already reported\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ hb->key.reporter = NULL;
|
|
+ hb->key.reportPt = NULL;
|
|
+}
|
|
+
|
|
+static Record** createSortedRecordsArray(OSet *records, Int *nRecords)
|
|
+{
|
|
+ Record* r;
|
|
+ Record** recordsArray;
|
|
+ Int i = 0;
|
|
+
|
|
+ *nRecords = VG_(OSetGen_Size)(records);
|
|
+
|
|
+ // Create an array of pointers to the records.
|
|
+ recordsArray = VG_(malloc)("mc.cSRA", *nRecords * sizeof(Record*));
|
|
+ VG_(OSetGen_ResetIter)(records);
|
|
+ while ( (r = VG_(OSetGen_Next)(records)) ) {
|
|
+ recordsArray[i++] = r;
|
|
+ }
|
|
+ tl_assert(i == *nRecords);
|
|
+
|
|
+ // Sort the array by record size.
|
|
+ VG_(ssort)(recordsArray, *nRecords, sizeof(Record*), cmpRecordBySize);
|
|
+
|
|
+ return recordsArray;
|
|
+}
|
|
+
|
|
+static void checkReporting(ThreadId tid)
|
|
+{
|
|
+ Int i;
|
|
+ HeapBlock *hb;
|
|
+ OSet *uRecords =
|
|
+ VG_(OSetGen_Create)(offsetof(Record, key),
|
|
+ cmpRecordByHeapKey,
|
|
+ VG_(malloc), "dmdv.cr.1",
|
|
+ VG_(free));
|
|
+ OSet *rRecords =
|
|
+ VG_(OSetGen_Create)(offsetof(Record, key),
|
|
+ cmpRecordByHeapKey,
|
|
+ VG_(malloc), "dmdv.cr.2",
|
|
+ VG_(free));
|
|
+ Int nRecords;
|
|
+ Record** recordsArray;
|
|
+ Record* r;
|
|
+ SizeT aSumB = 0; // all == rSumB + uSumB + sSumB
|
|
+ SizeT rSumB = 0; // reported
|
|
+ SizeT uSumB = 0; // unreported
|
|
+ SizeT sSumB = 0; // suppressed
|
|
+ SizeT cSumB = 0; // cumulative
|
|
+ #define BUFLEN 32
|
|
+ char buf[BUFLEN];
|
|
+
|
|
+ static Bool hasChecked = False;
|
|
+ if (hasChecked) {
|
|
+ VG_(umsg)("Sorry, CHECK_REPORTING will only work once.\n");
|
|
+ VG_(umsg)("DMDV will ignore this request.\n\n");
|
|
+ return;
|
|
+ }
|
|
+ hasChecked = True;
|
|
+
|
|
+ // Create Records from heapBlocks.
|
|
+ VG_(HT_ResetIter)(heapBlocks);
|
|
+ while ( (hb = VG_(HT_Next)(heapBlocks)) ) {
|
|
+ OSet *records;
|
|
+
|
|
+ if (hb->key.reporter) {
|
|
+ records = rRecords;
|
|
+ } else {
|
|
+ records = uRecords;
|
|
+ }
|
|
+ r = VG_(OSetGen_Lookup)(records, &hb->key);
|
|
+ if (!r) {
|
|
+ // No existing record matches this chunk. Create a new record,
|
|
+ // zero it, and insert it into records.
|
|
+ r = VG_(OSetGen_AllocNode)(records, sizeof(Record));
|
|
+ r->key = hb->key;
|
|
+ r->nBlocks = 0;
|
|
+ r->reqSzB = 0;
|
|
+ r->usableSzB = 0;
|
|
+ VG_(OSetGen_Insert)(records, r);
|
|
+ } else {
|
|
+ // If we matched an existing Record, ensure the names match.
|
|
+ tl_assert((!r->key.reporter && !hb->key.reporter) ||
|
|
+ VG_STREQ(r->key.reporter, hb->key.reporter));
|
|
+ }
|
|
+ // Update the Record's details in-situ. This is safe because we
|
|
+ // don't change the elements used as the OSet key.
|
|
+ r->nBlocks++;
|
|
+ r->reqSzB += hb->reqSzB;
|
|
+ r->usableSzB += hb->usableSzB;
|
|
+
|
|
+ aSumB += hb->usableSzB;
|
|
+ }
|
|
+
|
|
+ // Print the unreported records in size order and gather stats.
|
|
+ VG_(umsg)("UNREPORTED BLOCKS:\n\n");
|
|
+ recordsArray = createSortedRecordsArray(uRecords, &nRecords);
|
|
+ if (nRecords > 0) {
|
|
+ for (i = 0; i < nRecords; i++) {
|
|
+ Bool isSuppressed;
|
|
+ r = recordsArray[i];
|
|
+ isSuppressed = dmdv_record_unreported_error(tid, i+1, nRecords, r, cSumB,
|
|
+ aSumB);
|
|
+ if (isSuppressed) {
|
|
+ sSumB += r->usableSzB;
|
|
+ } else {
|
|
+ uSumB += r->usableSzB;
|
|
+ cSumB += r->usableSzB;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ VG_(umsg)("(none)\n");
|
|
+ }
|
|
+
|
|
+ // Print the reported records in size order and gather stats.
|
|
+ VG_(umsg)("REPORTED BLOCKS:\n\n");
|
|
+ cSumB = 0;
|
|
+ recordsArray = createSortedRecordsArray(rRecords, &nRecords);
|
|
+ if (nRecords > 0) {
|
|
+ for (i = 0; i < nRecords; i++) {
|
|
+ Bool isSuppressed;
|
|
+ r = recordsArray[i];
|
|
+ isSuppressed = dmdv_record_reported_error(tid, i+1, nRecords, r, cSumB,
|
|
+ aSumB);
|
|
+ tl_assert(!isSuppressed);
|
|
+ rSumB += r->usableSzB;
|
|
+ cSumB += r->usableSzB;
|
|
+ }
|
|
+ } else {
|
|
+ VG_(umsg)("(none)\n\n");
|
|
+ }
|
|
+
|
|
+ VG_(umsg)("SUMMARY:\n");
|
|
+ tl_assert(aSumB == rSumB + uSumB + sSumB);
|
|
+ VG_(umsg)(" Total: %'13lu bytes\n", aSumB);
|
|
+
|
|
+ VG_(percentify)(rSumB, aSumB, 2, 7, buf);
|
|
+ VG_(umsg)(" Reported: %'13lu bytes (%s)\n", rSumB, buf);
|
|
+
|
|
+ VG_(percentify)(uSumB, aSumB, 2, 7, buf);
|
|
+ VG_(umsg)(" Unreported: %'13lu bytes (%s)\n", uSumB, buf);
|
|
+
|
|
+ VG_(percentify)(sSumB, aSumB, 2, 7, buf);
|
|
+ VG_(umsg)(" Suppressed: %'13lu bytes (%s)\n", sSumB, buf);
|
|
+}
|
|
+
|
|
+/*------------------------------------------------------------*/
|
|
+/*--- Client requests ---*/
|
|
+/*------------------------------------------------------------*/
|
|
+
|
|
+static Bool dmdv_handle_client_request(ThreadId tid, UWord* arg, UWord* ret)
|
|
+{
|
|
+ if (!VG_IS_TOOL_USERREQ('D','M',arg[0])
|
|
+ && VG_USERREQ__DMDV_REPORT != arg[0]
|
|
+ && VG_USERREQ__DMDV_UNREPORT != arg[0]
|
|
+ && VG_USERREQ__DMDV_CHECK_REPORTING != arg[0])
|
|
+ return False;
|
|
+
|
|
+ switch (arg[0]) {
|
|
+ case VG_USERREQ__DMDV_REPORT: {
|
|
+ reportHeapBlock(tid, arg[1], arg[2], (const char*)arg[3]);
|
|
+ *ret = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case VG_USERREQ__DMDV_UNREPORT: {
|
|
+ unreportHeapBlock(tid, arg[1]);
|
|
+ *ret = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case VG_USERREQ__DMDV_CHECK_REPORTING: {
|
|
+ checkReporting(tid);
|
|
+ *ret = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ default:
|
|
+ VG_(message)(
|
|
+ Vg_UserMsg,
|
|
+ "Warning: unknown DMDV client request code %llx\n",
|
|
+ (ULong)arg[0]
|
|
+ );
|
|
+ return False;
|
|
+ }
|
|
+ return True;
|
|
+}
|
|
+
|
|
+//------------------------------------------------------------//
|
|
+//--- Basic functions ---//
|
|
+//------------------------------------------------------------//
|
|
+
|
|
+static void dmdv_post_clo_init(void)
|
|
+{
|
|
+}
|
|
+
|
|
+static
|
|
+IRSB* dmdv_instrument(VgCallbackClosure* closure,
|
|
+ IRSB* sb,
|
|
+ VexGuestLayout* layout,
|
|
+ VexGuestExtents* vge,
|
|
+ VexArchInfo* archinfo_host,
|
|
+ IRType gWordTy,
|
|
+ IRType hWordTy)
|
|
+{
|
|
+ return sb;
|
|
+}
|
|
+
|
|
+static void dmdv_fini(Int exitcode)
|
|
+{
|
|
+}
|
|
+
|
|
+static void dmdv_pre_clo_init(void)
|
|
+{
|
|
+ VG_(details_name) ("DMDV");
|
|
+ VG_(details_version) (NULL);
|
|
+ VG_(details_description) ("a dark matter detector");
|
|
+ VG_(details_copyright_author)(
|
|
+ "Copyright (C) 2011-2011, and GNU GPL'd, by Nicholas Nethercote.");
|
|
+ VG_(details_bug_reports_to) (VG_BUGS_TO);
|
|
+
|
|
+ VG_(details_avg_translation_sizeB)(275);
|
|
+
|
|
+ VG_(basic_tool_funcs) (dmdv_post_clo_init,
|
|
+ dmdv_instrument,
|
|
+ dmdv_fini);
|
|
+
|
|
+ // Needs.
|
|
+ VG_(needs_command_line_options)(dmdv_process_cmd_line_option,
|
|
+ dmdv_print_usage,
|
|
+ dmdv_print_debug_usage);
|
|
+ VG_(needs_tool_errors) (dmdv_eq_Error,
|
|
+ dmdv_before_pp_Error,
|
|
+ dmdv_pp_Error,
|
|
+ True,/*show TIDs for errors*/
|
|
+ dmdv_update_extra,
|
|
+ dmdv_is_recognised_suppression,
|
|
+ dmdv_read_extra_suppression_info,
|
|
+ dmdv_error_matches_suppression,
|
|
+ dmdv_get_error_name,
|
|
+ dmdv_get_extra_suppression_info);
|
|
+ VG_(needs_client_requests) (dmdv_handle_client_request);
|
|
+ VG_(needs_malloc_replacement)(dmdv_malloc,
|
|
+ dmdv___builtin_new,
|
|
+ dmdv___builtin_vec_new,
|
|
+ dmdv_memalign,
|
|
+ dmdv_calloc,
|
|
+ dmdv_free,
|
|
+ dmdv___builtin_delete,
|
|
+ dmdv___builtin_vec_delete,
|
|
+ dmdv_realloc,
|
|
+ dmdv_malloc_usable_size,
|
|
+ 0);
|
|
+
|
|
+#if 0
|
|
+ // Tracked events.
|
|
+ VG_(track_new_mem_startup) ( dmdv_new_mem_startup );
|
|
+ VG_(track_new_mem_brk) ( dmdv_new_mem_brk );
|
|
+ VG_(track_new_mem_mmap) ( dmdv_new_mem_mmap );
|
|
+
|
|
+ VG_(track_copy_mem_remap) ( dmdv_copy_mem_remap );
|
|
+
|
|
+ VG_(track_die_mem_brk) ( dmdv_die_mem_brk );
|
|
+ VG_(track_die_mem_munmap) ( dmdv_die_mem_munmap );
|
|
+#endif
|
|
+
|
|
+ heapBlocks = VG_(HT_construct)("DMDV's heapBlocks");
|
|
+}
|
|
+
|
|
+VG_DETERMINE_INTERFACE_VERSION(dmdv_pre_clo_init)
|
|
+
|
|
+/*--------------------------------------------------------------------*/
|
|
+/*--- end ---*/
|
|
+/*--------------------------------------------------------------------*/
|
|
Index: exp-dmdv/dmdv.h
|
|
===================================================================
|
|
--- exp-dmdv/dmdv.h (revision 0)
|
|
+++ exp-dmdv/dmdv.h (revision 0)
|
|
@@ -0,0 +1,83 @@
|
|
+/*
|
|
+ ----------------------------------------------------------------
|
|
+ The following BSD-style license applies to this one file (dmdv.h) only.
|
|
+ ----------------------------------------------------------------
|
|
+
|
|
+ The Initial Developer of the Original Code is
|
|
+ the Mozilla Foundation.
|
|
+ Portions created by the Initial Developer are Copyright (C) 2011
|
|
+ the Initial Developer. All Rights Reserved.
|
|
+
|
|
+ Contributor(s):
|
|
+ Nicholas Nethercote <nnethercote@mozilla.com>
|
|
+
|
|
+ Redistribution and use in source and binary forms, with or without
|
|
+ modification, are permitted provided that the following conditions
|
|
+ are met:
|
|
+
|
|
+ 1. Redistributions of source code must retain the above copyright
|
|
+ notice, this list of conditions and the following disclaimer.
|
|
+
|
|
+ 2. The origin of this software must not be misrepresented; you must
|
|
+ not claim that you wrote the original software. If you use this
|
|
+ software in a product, an acknowledgment in the product
|
|
+ documentation would be appreciated but is not required.
|
|
+
|
|
+ 3. Altered source versions must be plainly marked as such, and must
|
|
+ not be misrepresented as being the original software.
|
|
+
|
|
+ 4. The name of the author may not be used to endorse or promote
|
|
+ products derived from this software without specific prior written
|
|
+ permission.
|
|
+
|
|
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
+*/
|
|
+
|
|
+#ifndef __DMDV_H
|
|
+#define __DMDV_H
|
|
+
|
|
+#include "valgrind/valgrind.h"
|
|
+
|
|
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
|
|
+ This enum comprises an ABI exported by Valgrind to programs
|
|
+ which use client requests. DO NOT CHANGE THE ORDER OF THESE
|
|
+ ENTRIES, NOR DELETE ANY -- add new ones at the end. */
|
|
+typedef
|
|
+ enum {
|
|
+ VG_USERREQ__DMDV_REPORT = VG_USERREQ_TOOL_BASE('D','M'),
|
|
+ VG_USERREQ__DMDV_UNREPORT,
|
|
+ VG_USERREQ__DMDV_CHECK_REPORTING
|
|
+ } Vg_DMDVClientRequest;
|
|
+
|
|
+
|
|
+/* Mark heap block at _qzz_addr as reported for _qzz_len bytes.
|
|
+ * _qzz_name is the name of the reporter. */
|
|
+#define VALGRIND_DMDV_REPORT(_qzz_addr,_qzz_len,_qzz_name) \
|
|
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
|
|
+ VG_USERREQ__DMDV_REPORT, \
|
|
+ (_qzz_addr), (_qzz_len), (_qzz_name), 0, 0)
|
|
+
|
|
+/* Mark heap block at _qzz_addr as not reported. */
|
|
+#define VALGRIND_DMDV_UNREPORT(_qzz_addr) \
|
|
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
|
|
+ VG_USERREQ__DMDV_UNREPORT, \
|
|
+ (_qzz_addr), 0, 0, 0, 0)
|
|
+
|
|
+/* Do a reporting check. */
|
|
+#define VALGRIND_DMDV_CHECK_REPORTING \
|
|
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
|
|
+ VG_USERREQ__DMDV_CHECK_REPORTING, \
|
|
+ 0, 0, 0, 0, 0)
|
|
+
|
|
+#endif
|
|
+
|
|
Index: exp-dmdv/tests/basics.c
|
|
===================================================================
|
|
--- exp-dmdv/tests/basics.c (revision 0)
|
|
+++ exp-dmdv/tests/basics.c (revision 0)
|
|
@@ -0,0 +1,55 @@
|
|
+#include <stdlib.h>
|
|
+#include <malloc.h>
|
|
+#include "exp-dmdv/dmdv.h"
|
|
+
|
|
+int main(void)
|
|
+{
|
|
+ int i;
|
|
+ char *a;
|
|
+ for (i = 0; i < 10; i++) {
|
|
+ a = malloc(100);
|
|
+ }
|
|
+ free(a); // 1 freed, 9 out of 10 unreported
|
|
+
|
|
+ char *b = malloc(10);
|
|
+ size_t bUsable = malloc_usable_size(b);
|
|
+ VALGRIND_DMDV_REPORT(b, bUsable, "b"); // reported
|
|
+
|
|
+ char *c = malloc(10);
|
|
+ size_t cUsable = malloc_usable_size(c);
|
|
+ VALGRIND_DMDV_REPORT(c, cUsable, "c");
|
|
+ VALGRIND_DMDV_REPORT(c, cUsable, "c"); // double-reported
|
|
+
|
|
+ VALGRIND_DMDV_REPORT(i, 10, "d"); // no such heap block warning
|
|
+
|
|
+ char *e = malloc(4096);
|
|
+ e = realloc(e, 4097); // jemalloc rounds this up to 8192
|
|
+ VALGRIND_DMDV_REPORT(e, 4097, "e"); // size mismatch warning
|
|
+
|
|
+ // jemalloc would leave this as size 2. Valgrind's heap allocator actually
|
|
+ // rounds it up to 8 (or 16?). Make sure that malloc_usable_size() returns
|
|
+ // 2 like jemalloc's would.
|
|
+ char *f = malloc(2);
|
|
+ fprintf(stderr, "mus: %ld\n", malloc_usable_size(f));
|
|
+
|
|
+ // Ensure that realloc copies the slop bytes! If it doesn't, we only get
|
|
+ // 10 'a's printed instead of 15.
|
|
+ char *g = malloc(10); // rounds up to 16
|
|
+ for (i = 0; i < malloc_usable_size(g); i++)
|
|
+ g[i] = 'a';
|
|
+ g[i-1] = '\0';
|
|
+ g = realloc(g, 32);
|
|
+ fprintf(stderr, "g = %s\n", g);
|
|
+
|
|
+ // Check that a freed block isn't considered by the checking.
|
|
+ char *h = malloc(10);
|
|
+ free(h);
|
|
+
|
|
+ VALGRIND_DMDV_CHECK_REPORTING; // ok
|
|
+ VALGRIND_DMDV_CHECK_REPORTING; // warning, ignored
|
|
+
|
|
+ // These should be ignored.
|
|
+ VALGRIND_DMDV_REPORT((void*)0x0, 0, "zero");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
Index: exp-dmdv/tests/heapkeys.stderr.exp
|
|
===================================================================
|
|
--- exp-dmdv/tests/heapkeys.stderr.exp (revision 0)
|
|
+++ exp-dmdv/tests/heapkeys.stderr.exp (revision 0)
|
|
@@ -0,0 +1,133 @@
|
|
+Copyright (C) 2011-2011, and GNU GPL'd, by Nicholas Nethercote.
|
|
+
|
|
+UNREPORTED BLOCKS:
|
|
+
|
|
+Unreported: 2 block(s) in record 1 of 3
|
|
+ 112 bytes (112 requested / 0 slop)
|
|
+ 7.07% of the heap (7.07% cumulative unreported)
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:25)
|
|
+
|
|
+Unreported: 2 block(s) in record 2 of 3
|
|
+ 112 bytes (112 requested / 0 slop)
|
|
+ 7.07% of the heap (14.14% cumulative unreported)
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:26)
|
|
+
|
|
+Unreported: 2 block(s) in record 3 of 3
|
|
+ 112 bytes (112 requested / 0 slop)
|
|
+ 7.07% of the heap (21.21% cumulative unreported)
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:27)
|
|
+
|
|
+REPORTED BLOCKS:
|
|
+
|
|
+Reported(a01): 2 block(s) in record 1 of 9
|
|
+ 240 bytes (240 requested / 0 slop)
|
|
+ 15.15% of the heap (15.15% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:26)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:17)
|
|
+ by 0x........: main (heapkeys.c:26)
|
|
+
|
|
+Reported(a01): 2 block(s) in record 2 of 9
|
|
+ 240 bytes (240 requested / 0 slop)
|
|
+ 15.15% of the heap (30.30% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:25)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:17)
|
|
+ by 0x........: main (heapkeys.c:25)
|
|
+
|
|
+Reported(a01): 2 block(s) in record 3 of 9
|
|
+ 240 bytes (240 requested / 0 slop)
|
|
+ 15.15% of the heap (45.45% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:27)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:17)
|
|
+ by 0x........: main (heapkeys.c:27)
|
|
+
|
|
+Reported(a23): 1 block(s) in record 4 of 9
|
|
+ 96 bytes (96 requested / 0 slop)
|
|
+ 6.06% of the heap (51.51% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:25)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:18)
|
|
+ by 0x........: main (heapkeys.c:25)
|
|
+
|
|
+Reported(a23): 1 block(s) in record 5 of 9
|
|
+ 96 bytes (96 requested / 0 slop)
|
|
+ 6.06% of the heap (57.57% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:26)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:18)
|
|
+ by 0x........: main (heapkeys.c:26)
|
|
+
|
|
+Reported(a23): 1 block(s) in record 6 of 9
|
|
+ 96 bytes (96 requested / 0 slop)
|
|
+ 6.06% of the heap (63.63% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:27)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:18)
|
|
+ by 0x........: main (heapkeys.c:27)
|
|
+
|
|
+Reported(a23): 1 block(s) in record 7 of 9
|
|
+ 80 bytes (80 requested / 0 slop)
|
|
+ 5.05% of the heap (68.68% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:25)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:19)
|
|
+ by 0x........: main (heapkeys.c:25)
|
|
+
|
|
+Reported(a23): 1 block(s) in record 8 of 9
|
|
+ 80 bytes (80 requested / 0 slop)
|
|
+ 5.05% of the heap (73.73% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:27)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:19)
|
|
+ by 0x........: main (heapkeys.c:27)
|
|
+
|
|
+Reported(a23): 1 block(s) in record 9 of 9
|
|
+ 80 bytes (80 requested / 0 slop)
|
|
+ 5.05% of the heap (78.78% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: f (heapkeys.c:13)
|
|
+ by 0x........: main (heapkeys.c:26)
|
|
+ Reported
|
|
+ at 0x........: f (heapkeys.c:19)
|
|
+ by 0x........: main (heapkeys.c:26)
|
|
+
|
|
+SUMMARY:
|
|
+ Total: 1,584 bytes
|
|
+ Reported: 1,248 bytes ( 78.78%)
|
|
+ Unreported: 336 bytes ( 21.21%)
|
|
+ Suppressed: 0 bytes ( 0.00%)
|
|
+
|
|
+ERROR SUMMARY: 12 errors from 12 contexts (suppressed: 0 from 0)
|
|
Index: exp-dmdv/tests/jesizes.vgtest
|
|
===================================================================
|
|
--- exp-dmdv/tests/jesizes.vgtest (revision 0)
|
|
+++ exp-dmdv/tests/jesizes.vgtest (revision 0)
|
|
@@ -0,0 +1 @@
|
|
+prog: jesizes
|
|
Index: exp-dmdv/tests/filter_stderr
|
|
===================================================================
|
|
--- exp-dmdv/tests/filter_stderr (revision 0)
|
|
+++ exp-dmdv/tests/filter_stderr (revision 0)
|
|
@@ -0,0 +1,12 @@
|
|
+#! /bin/sh
|
|
+
|
|
+dir=`dirname $0`
|
|
+
|
|
+$dir/../../tests/filter_stderr_basic |
|
|
+
|
|
+# Anonymise addresses
|
|
+$dir/../../tests/filter_addresses |
|
|
+
|
|
+# Remove "DMDV, ..." line and the following copyright line.
|
|
+sed "/^DMDV, a dark matter detector/ , /./ d"
|
|
+
|
|
Index: exp-dmdv/tests/unreport.vgtest
|
|
===================================================================
|
|
--- exp-dmdv/tests/unreport.vgtest (revision 0)
|
|
+++ exp-dmdv/tests/unreport.vgtest (revision 0)
|
|
@@ -0,0 +1 @@
|
|
+prog: unreport
|
|
Index: exp-dmdv/tests/Makefile.am
|
|
===================================================================
|
|
--- exp-dmdv/tests/Makefile.am (revision 0)
|
|
+++ exp-dmdv/tests/Makefile.am (revision 0)
|
|
@@ -0,0 +1,20 @@
|
|
+
|
|
+include $(top_srcdir)/Makefile.tool-tests.am
|
|
+
|
|
+dist_noinst_SCRIPTS = filter_stderr
|
|
+
|
|
+EXTRA_DIST = \
|
|
+ basics.stderr.exp basics.vgtest \
|
|
+ heapkeys.stderr.exp heapkeys.vgtest \
|
|
+ jesizes.stderr.exp jesizes.vgtest \
|
|
+ unreport.stderr.exp unreport.vgtest
|
|
+
|
|
+check_PROGRAMS = \
|
|
+ basics \
|
|
+ heapkeys \
|
|
+ jesizes \
|
|
+ unreport
|
|
+
|
|
+AM_CFLAGS += $(AM_FLAG_M3264_PRI)
|
|
+AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
|
|
+
|
|
Index: exp-dmdv/tests/jesizes.stderr.exp
|
|
===================================================================
|
|
--- exp-dmdv/tests/jesizes.stderr.exp (revision 0)
|
|
+++ exp-dmdv/tests/jesizes.stderr.exp (revision 0)
|
|
@@ -0,0 +1,129 @@
|
|
+Copyright (C) 2011-2011, and GNU GPL'd, by Nicholas Nethercote.
|
|
+
|
|
+0 -> 2 (2)
|
|
+1 -> 2 (1)
|
|
+2 -> 2 (0)
|
|
+3 -> 4 (1)
|
|
+4 -> 4 (0)
|
|
+5 -> 8 (3)
|
|
+7 -> 8 (1)
|
|
+8 -> 8 (0)
|
|
+9 -> 16 (7)
|
|
+15 -> 16 (1)
|
|
+16 -> 16 (0)
|
|
+17 -> 32 (15)
|
|
+31 -> 32 (1)
|
|
+32 -> 32 (0)
|
|
+33 -> 48 (15)
|
|
+47 -> 48 (1)
|
|
+48 -> 48 (0)
|
|
+49 -> 64 (15)
|
|
+63 -> 64 (1)
|
|
+64 -> 64 (0)
|
|
+65 -> 80 (15)
|
|
+79 -> 80 (1)
|
|
+80 -> 80 (0)
|
|
+113 -> 128 (15)
|
|
+127 -> 128 (1)
|
|
+128 -> 128 (0)
|
|
+129 -> 144 (15)
|
|
+143 -> 144 (1)
|
|
+144 -> 144 (0)
|
|
+241 -> 256 (15)
|
|
+255 -> 256 (1)
|
|
+256 -> 256 (0)
|
|
+257 -> 272 (15)
|
|
+271 -> 272 (1)
|
|
+272 -> 272 (0)
|
|
+481 -> 496 (15)
|
|
+495 -> 496 (1)
|
|
+496 -> 496 (0)
|
|
+497 -> 512 (15)
|
|
+511 -> 512 (1)
|
|
+512 -> 512 (0)
|
|
+513 -> 1024 (511)
|
|
+1023 -> 1024 (1)
|
|
+1024 -> 1024 (0)
|
|
+1025 -> 2048 (1023)
|
|
+2047 -> 2048 (1)
|
|
+2048 -> 2048 (0)
|
|
+2049 -> 4096 (2047)
|
|
+4095 -> 4096 (1)
|
|
+4096 -> 4096 (0)
|
|
+4097 -> 8192 (4095)
|
|
+8191 -> 8192 (1)
|
|
+8192 -> 8192 (0)
|
|
+12289 -> 16384 (4095)
|
|
+16383 -> 16384 (1)
|
|
+16384 -> 16384 (0)
|
|
+28673 -> 32768 (4095)
|
|
+32767 -> 32768 (1)
|
|
+32768 -> 32768 (0)
|
|
+61441 -> 65536 (4095)
|
|
+65535 -> 65536 (1)
|
|
+65536 -> 65536 (0)
|
|
+126977 -> 131072 (4095)
|
|
+131071 -> 131072 (1)
|
|
+131072 -> 131072 (0)
|
|
+258049 -> 262144 (4095)
|
|
+262143 -> 262144 (1)
|
|
+262144 -> 262144 (0)
|
|
+520193 -> 524288 (4095)
|
|
+524287 -> 524288 (1)
|
|
+524288 -> 524288 (0)
|
|
+1044481 -> 1048576 (4095)
|
|
+1048575 -> 1048576 (1)
|
|
+1048576 -> 1048576 (0)
|
|
+1048577 -> 1052672 (4095)
|
|
+2097151 -> 2097152 (1)
|
|
+2097152 -> 2097152 (0)
|
|
+2097153 -> 2101248 (4095)
|
|
+3145727 -> 3145728 (1)
|
|
+3145728 -> 3145728 (0)
|
|
+3145729 -> 3149824 (4095)
|
|
+4194303 -> 4194304 (1)
|
|
+4194304 -> 4194304 (0)
|
|
+4194305 -> 4198400 (4095)
|
|
+5242879 -> 5242880 (1)
|
|
+5242880 -> 5242880 (0)
|
|
+5242881 -> 5246976 (4095)
|
|
+6291455 -> 6291456 (1)
|
|
+6291456 -> 6291456 (0)
|
|
+6291457 -> 6295552 (4095)
|
|
+7340031 -> 7340032 (1)
|
|
+7340032 -> 7340032 (0)
|
|
+7340033 -> 7344128 (4095)
|
|
+8388607 -> 8388608 (1)
|
|
+8388608 -> 8388608 (0)
|
|
+8388609 -> 8392704 (4095)
|
|
+9437183 -> 9437184 (1)
|
|
+9437184 -> 9437184 (0)
|
|
+15728641 -> 15732736 (4095)
|
|
+16777215 -> 16777216 (1)
|
|
+16777216 -> 16777216 (0)
|
|
+32505857 -> 32509952 (4095)
|
|
+33554431 -> 33554432 (1)
|
|
+33554432 -> 33554432 (0)
|
|
+33554433 -> 33558528 (4095)
|
|
+34603007 -> 34603008 (1)
|
|
+34603008 -> 34603008 (0)
|
|
+totals: 387939702 -> 388021286 (81584)
|
|
+UNREPORTED BLOCKS:
|
|
+
|
|
+Unreported: 107 block(s) in record 1 of 1
|
|
+ 388,021,286 bytes (387,939,702 requested / 81,584 slop)
|
|
+ 100.00% of the heap (100.00% cumulative unreported)
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (jesizes.c:75)
|
|
+
|
|
+REPORTED BLOCKS:
|
|
+
|
|
+(none)
|
|
+
|
|
+SUMMARY:
|
|
+ Total: 388,021,286 bytes
|
|
+ Reported: 0 bytes ( 0.00%)
|
|
+ Unreported: 388,021,286 bytes (100.00%)
|
|
+ Suppressed: 0 bytes ( 0.00%)
|
|
+
|
|
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
|
Index: exp-dmdv/tests/heapkeys.c
|
|
===================================================================
|
|
--- exp-dmdv/tests/heapkeys.c (revision 0)
|
|
+++ exp-dmdv/tests/heapkeys.c (revision 0)
|
|
@@ -0,0 +1,32 @@
|
|
+#include <stdlib.h>
|
|
+#include <malloc.h>
|
|
+#include "exp-dmdv/dmdv.h"
|
|
+
|
|
+// This test checks that heap blocks that have the same stack trace but
|
|
+// different (or no) reporters get handled separately.
|
|
+
|
|
+void f(void)
|
|
+{
|
|
+ int i;
|
|
+ char *a[6];
|
|
+ for (i = 0; i < 6; i++) {
|
|
+ a[i] = malloc(128 - 16*i);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i <= 1; i++)
|
|
+ VALGRIND_DMDV_REPORT(a[i], 128 - 16*i, "a01"); // reported
|
|
+ VALGRIND_DMDV_REPORT(a[2], 128 - 16*2, "a23"); // reported
|
|
+ VALGRIND_DMDV_REPORT(a[3], 128 - 16*3, "a23"); // reported
|
|
+ // a[4], a[5] unreported
|
|
+}
|
|
+
|
|
+int main(void)
|
|
+{
|
|
+ f();
|
|
+ f();
|
|
+ f();
|
|
+
|
|
+ VALGRIND_DMDV_CHECK_REPORTING; // ok
|
|
+
|
|
+ return 0;
|
|
+}
|
|
Index: exp-dmdv/tests/unreport.stderr.exp
|
|
===================================================================
|
|
--- exp-dmdv/tests/unreport.stderr.exp (revision 0)
|
|
+++ exp-dmdv/tests/unreport.stderr.exp (revision 0)
|
|
@@ -0,0 +1,29 @@
|
|
+Copyright (C) 2011-2011, and GNU GPL'd, by Nicholas Nethercote.
|
|
+
|
|
+UNREPORT WARNING: block is not already reported
|
|
+UNREPORT WARNING: block is not already reported
|
|
+UNREPORTED BLOCKS:
|
|
+
|
|
+Unreported: 1 block(s) in record 1 of 2
|
|
+ 16 bytes (10 requested / 6 slop)
|
|
+ 50.00% of the heap (50.00% cumulative unreported)
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (unreport.c:11)
|
|
+
|
|
+Unreported: 1 block(s) in record 2 of 2
|
|
+ 16 bytes (10 requested / 6 slop)
|
|
+ 50.00% of the heap (100.00% cumulative unreported)
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (unreport.c:16)
|
|
+
|
|
+REPORTED BLOCKS:
|
|
+
|
|
+(none)
|
|
+
|
|
+SUMMARY:
|
|
+ Total: 32 bytes
|
|
+ Reported: 0 bytes ( 0.00%)
|
|
+ Unreported: 32 bytes (100.00%)
|
|
+ Suppressed: 0 bytes ( 0.00%)
|
|
+
|
|
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
|
Index: exp-dmdv/tests/jesizes.c
|
|
===================================================================
|
|
--- exp-dmdv/tests/jesizes.c (revision 0)
|
|
+++ exp-dmdv/tests/jesizes.c (revision 0)
|
|
@@ -0,0 +1,88 @@
|
|
+#include <stdlib.h>
|
|
+#include <malloc.h>
|
|
+#include "exp-dmdv/dmdv.h"
|
|
+
|
|
+int main(void)
|
|
+{
|
|
+ #define K * 1024
|
|
+ #define M * 1024 * 1024
|
|
+
|
|
+ size_t sizes[] = {
|
|
+ // Small/Tiny: 2, 4, 8 (bytes)
|
|
+ 0, 1, 2, // 2
|
|
+ 3, 4, // 4
|
|
+ 5, 7, 8, // 8
|
|
+
|
|
+ // Small/Quantum-spaced: 16, 32, 48, ..., 480, 496, 512 (bytes)
|
|
+ 9, 15, 16, // 16
|
|
+ 17, 31, 32, // 32
|
|
+ 33, 47, 48, // 48
|
|
+ 49, 63, 64, // 64
|
|
+ 65, 79, 80, // 80
|
|
+ // ...
|
|
+ 113, 127, 128, // 128
|
|
+ 129, 143, 144, // 144
|
|
+ // ...
|
|
+ 241, 255, 256, // 256
|
|
+ 257, 271, 272, // 272
|
|
+ // ...
|
|
+ 481, 495, 496, // 496
|
|
+ 497, 511, 512, // 512
|
|
+
|
|
+ // Small/Sub-page: 1, 2 (KiB)
|
|
+ 513, 1023, 1024, // 1024
|
|
+ 1025, 2047, 2048, // 2048
|
|
+
|
|
+ // Large: 4, 8, 12, ..., 1012, 1016, 1020 (KiB)
|
|
+ 2049, 4 K - 1, 4 K, // 4 K
|
|
+ 4 K + 1, 8 K -1, 8 K, // 8 K
|
|
+ // ...
|
|
+ 12 K + 1, 16 K - 1, 16 K, // 16 K
|
|
+ // ...
|
|
+ 28 K + 1, 32 K - 1, 32 K, // 32 K
|
|
+ // ...
|
|
+ 60 K + 1, 64 K - 1, 64 K, // 64 K
|
|
+ // ...
|
|
+ 124 K + 1, 128 K - 1, 128 K, // 128 K
|
|
+ // ...
|
|
+ 252 K + 1, 256 K - 1, 256 K, // 256 K
|
|
+ // ...
|
|
+ 508 K + 1, 512 K - 1, 512 K, // 512 K
|
|
+ // ...
|
|
+ 1020 K + 1, 1024 K - 1, 1024 K, // 1024 K
|
|
+
|
|
+ // Huge: 1, 2, 3, ... (MiB)
|
|
+ 1 M + 1, 2 M - 1, 2 M, // 2 M
|
|
+ 2 M + 1, 3 M - 1, 3 M, // 3 M
|
|
+ 3 M + 1, 4 M - 1, 4 M, // 4 M
|
|
+ 4 M + 1, 5 M - 1, 5 M, // 5 M
|
|
+ 5 M + 1, 6 M - 1, 6 M, // 6 M
|
|
+ 6 M + 1, 7 M - 1, 7 M, // 7 M
|
|
+ 7 M + 1, 8 M - 1, 8 M, // 8 M
|
|
+ 8 M + 1, 9 M - 1, 9 M, // 9 M
|
|
+ // ...
|
|
+ 15 M + 1, 16 M - 1, 16 M, // 16 M
|
|
+ // ...
|
|
+ 31 M + 1, 32 M - 1, 32 M, // 32 M
|
|
+ 32 M + 1, 33 M - 1, 33 M // 33 M
|
|
+ };
|
|
+ size_t n = sizeof(sizes) / sizeof(sizes[0]);
|
|
+ size_t i;
|
|
+ size_t totalReqSzB = 0;
|
|
+ size_t totalSlopSzB = 0;
|
|
+
|
|
+ for (i = 0; i < n; i++) {
|
|
+ char* x = malloc(sizes[i]);
|
|
+ size_t req = sizes[i];
|
|
+ size_t usable = malloc_usable_size(x);
|
|
+ size_t slop = usable - req;
|
|
+ fprintf(stderr, "%ld -> %ld (%ld)\n", req, usable, slop);
|
|
+ totalReqSzB += req;
|
|
+ totalSlopSzB += slop;
|
|
+ }
|
|
+ fprintf(stderr, "totals: %ld -> %ld (%ld)\n",
|
|
+ totalReqSzB, totalReqSzB + totalSlopSzB, totalSlopSzB);
|
|
+ VALGRIND_DMDV_CHECK_REPORTING;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
Index: exp-dmdv/tests/basics.vgtest
|
|
===================================================================
|
|
--- exp-dmdv/tests/basics.vgtest (revision 0)
|
|
+++ exp-dmdv/tests/basics.vgtest (revision 0)
|
|
@@ -0,0 +1 @@
|
|
+prog: basics
|
|
Index: exp-dmdv/tests/unreport.c
|
|
===================================================================
|
|
--- exp-dmdv/tests/unreport.c (revision 0)
|
|
+++ exp-dmdv/tests/unreport.c (revision 0)
|
|
@@ -0,0 +1,26 @@
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <malloc.h>
|
|
+#include "exp-dmdv/dmdv.h"
|
|
+
|
|
+int main(void)
|
|
+{
|
|
+
|
|
+ VALGRIND_DMDV_UNREPORT(NULL); // ignored
|
|
+
|
|
+ char *b = malloc(10);
|
|
+ size_t usable = malloc_usable_size(b);
|
|
+ VALGRIND_DMDV_REPORT(b, usable, "b"); // ok
|
|
+ VALGRIND_DMDV_UNREPORT(b); // ok
|
|
+
|
|
+ char *c = malloc(10);
|
|
+ usable = malloc_usable_size(c);
|
|
+ VALGRIND_DMDV_UNREPORT(c); // block not reported warning
|
|
+ VALGRIND_DMDV_REPORT(c, usable, "c");
|
|
+ VALGRIND_DMDV_UNREPORT(c);
|
|
+ VALGRIND_DMDV_UNREPORT(c); // block not reported warning
|
|
+
|
|
+ VALGRIND_DMDV_CHECK_REPORTING;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
Index: exp-dmdv/tests/basics.stderr.exp
|
|
===================================================================
|
|
--- exp-dmdv/tests/basics.stderr.exp (revision 0)
|
|
+++ exp-dmdv/tests/basics.stderr.exp (revision 0)
|
|
@@ -0,0 +1,76 @@
|
|
+Copyright (C) 2011-2011, and GNU GPL'd, by Nicholas Nethercote.
|
|
+
|
|
+Double report of heap block 0x........:
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (basics.c:18)
|
|
+ Previously reported by 'c'
|
|
+ at 0x........: main (basics.c:20)
|
|
+ Now reported by 'c'
|
|
+ at 0x........: main (basics.c:21)
|
|
+
|
|
+REPORT WARNING(d): no such heap block 0x........ (length 10):
|
|
+ at 0x........: main (basics.c:23)
|
|
+
|
|
+REPORT WARNING(e): size mismatch: reported=4,097, actual=8,192 (using actual)
|
|
+mus: 2
|
|
+g = aaaaaaaaaaaaaaa
|
|
+UNREPORTED BLOCKS:
|
|
+
|
|
+Unreported: 9 block(s) in record 1 of 3
|
|
+ 1,008 bytes (900 requested / 108 slop)
|
|
+ 10.87% of the heap (10.87% cumulative unreported)
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (basics.c:10)
|
|
+
|
|
+Unreported: 1 block(s) in record 2 of 3
|
|
+ 32 bytes (32 requested / 0 slop)
|
|
+ 0.34% of the heap (11.22% cumulative unreported)
|
|
+ at 0x........: realloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (basics.c:41)
|
|
+
|
|
+Unreported: 1 block(s) in record 3 of 3
|
|
+ 2 bytes (2 requested / 0 slop)
|
|
+ 0.02% of the heap (11.24% cumulative unreported)
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (basics.c:32)
|
|
+
|
|
+REPORTED BLOCKS:
|
|
+
|
|
+Reported(e): 1 block(s) in record 1 of 3
|
|
+ 8,192 bytes (4,097 requested / 4,095 slop)
|
|
+ 88.40% of the heap (88.40% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: realloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (basics.c:26)
|
|
+ Reported
|
|
+ at 0x........: main (basics.c:27)
|
|
+
|
|
+Reported(b): 1 block(s) in record 2 of 3
|
|
+ 16 bytes (10 requested / 6 slop)
|
|
+ 0.17% of the heap (88.58% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (basics.c:14)
|
|
+ Reported
|
|
+ at 0x........: main (basics.c:16)
|
|
+
|
|
+Reported(c): 1 block(s) in record 3 of 3
|
|
+ 16 bytes (10 requested / 6 slop)
|
|
+ 0.17% of the heap (88.75% cumulative reported)
|
|
+ Allocated
|
|
+ at 0x........: malloc (vg_replace_malloc.c:...)
|
|
+ by 0x........: main (basics.c:18)
|
|
+ Reported
|
|
+ at 0x........: main (basics.c:20)
|
|
+
|
|
+SUMMARY:
|
|
+ Total: 9,266 bytes
|
|
+ Reported: 8,224 bytes ( 88.75%)
|
|
+ Unreported: 1,042 bytes ( 11.24%)
|
|
+ Suppressed: 0 bytes ( 0.00%)
|
|
+Sorry, CHECK_REPORTING will only work once.
|
|
+DMDV will ignore this request.
|
|
+
|
|
+
|
|
+ERROR SUMMARY: 7 errors from 7 contexts (suppressed: 0 from 0)
|
|
Index: exp-dmdv/tests/heapkeys.vgtest
|
|
===================================================================
|
|
--- exp-dmdv/tests/heapkeys.vgtest (revision 0)
|
|
+++ exp-dmdv/tests/heapkeys.vgtest (revision 0)
|
|
@@ -0,0 +1 @@
|
|
+prog: heapkeys
|
|
Index: exp-dmdv/Makefile.am
|
|
===================================================================
|
|
--- exp-dmdv/Makefile.am (revision 0)
|
|
+++ exp-dmdv/Makefile.am (revision 0)
|
|
@@ -0,0 +1,93 @@
|
|
+include $(top_srcdir)/Makefile.tool.am
|
|
+
|
|
+EXTRA_DIST = docs/dmdv-manual.xml
|
|
+
|
|
+#----------------------------------------------------------------------------
|
|
+# dmdv-<platform>
|
|
+#----------------------------------------------------------------------------
|
|
+
|
|
+noinst_PROGRAMS = exp-dmdv-@VGCONF_ARCH_PRI@-@VGCONF_OS@
|
|
+if VGCONF_HAVE_PLATFORM_SEC
|
|
+noinst_PROGRAMS += exp-dmdv-@VGCONF_ARCH_SEC@-@VGCONF_OS@
|
|
+endif
|
|
+
|
|
+NONE_SOURCES_COMMON = dmdv_main.c
|
|
+
|
|
+exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_SOURCES = \
|
|
+ $(NONE_SOURCES_COMMON)
|
|
+exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CPPFLAGS = \
|
|
+ $(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS = \
|
|
+ $(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_DEPENDENCIES = \
|
|
+ $(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_PRI_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDADD = \
|
|
+ $(TOOL_LDADD_@VGCONF_PLATFORM_PRI_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS = \
|
|
+ $(TOOL_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LINK = \
|
|
+ $(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
|
|
+ @VALT_LOAD_ADDRESS_PRI@ \
|
|
+ $(LINK) \
|
|
+ $(exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS) \
|
|
+ $(exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS)
|
|
+
|
|
+if VGCONF_HAVE_PLATFORM_SEC
|
|
+exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_SOURCES = \
|
|
+ $(NONE_SOURCES_COMMON)
|
|
+exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CPPFLAGS = \
|
|
+ $(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS = \
|
|
+ $(AM_CFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_DEPENDENCIES = \
|
|
+ $(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_SEC_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDADD = \
|
|
+ $(TOOL_LDADD_@VGCONF_PLATFORM_SEC_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS = \
|
|
+ $(TOOL_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
|
+exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LINK = \
|
|
+ $(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
|
|
+ @VALT_LOAD_ADDRESS_SEC@ \
|
|
+ $(LINK) \
|
|
+ $(exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS) \
|
|
+ $(exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS)
|
|
+endif
|
|
+
|
|
+#----------------------------------------------------------------------------
|
|
+# vgpreload_exp_dmdv-<platform>.so
|
|
+#----------------------------------------------------------------------------
|
|
+
|
|
+noinst_PROGRAMS += vgpreload_exp-dmdv-@VGCONF_ARCH_PRI@-@VGCONF_OS@.so
|
|
+if VGCONF_HAVE_PLATFORM_SEC
|
|
+noinst_PROGRAMS += vgpreload_exp-dmdv-@VGCONF_ARCH_SEC@-@VGCONF_OS@.so
|
|
+endif
|
|
+
|
|
+if VGCONF_OS_IS_DARWIN
|
|
+noinst_DSYMS = $(noinst_PROGRAMS)
|
|
+endif
|
|
+
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_SOURCES =
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CPPFLAGS = \
|
|
+ $(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CFLAGS = \
|
|
+ $(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) $(AM_CFLAGS_PIC)
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_DEPENDENCIES = \
|
|
+ $(LIBREPLACEMALLOC_@VGCONF_PLATFORM_PRI_CAPS@)
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_LDFLAGS = \
|
|
+ $(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) \
|
|
+ $(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
|
+
|
|
+if VGCONF_HAVE_PLATFORM_SEC
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_SOURCES =
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CPPFLAGS = \
|
|
+ $(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CFLAGS = \
|
|
+ $(AM_CFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) $(AM_CFLAGS_PIC)
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_DEPENDENCIES = \
|
|
+ $(LIBREPLACEMALLOC_@VGCONF_PLATFORM_SEC_CAPS@)
|
|
+vgpreload_exp_dmdv_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_LDFLAGS = \
|
|
+ $(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) \
|
|
+ $(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
|
+endif
|
|
+
|
|
+
|
|
Index: Makefile.am
|
|
===================================================================
|
|
--- Makefile.am (revision 13036)
|
|
+++ Makefile.am (working copy)
|
|
@@ -14,7 +14,8 @@
|
|
|
|
EXP_TOOLS = exp-sgcheck \
|
|
exp-bbv \
|
|
- exp-dhat
|
|
+ exp-dhat \
|
|
+ exp-dmdv
|
|
|
|
# Put docs last because building the HTML is slow and we want to get
|
|
# everything else working before we try it.
|
|
@@ -42,6 +43,7 @@
|
|
glibc-2.2-LinuxThreads-helgrind.supp \
|
|
glibc-2.X-drd.supp \
|
|
exp-sgcheck.supp \
|
|
+ exp-dmdv.supp \
|
|
darwin9.supp darwin9-drd.supp \
|
|
darwin10.supp darwin10-drd.supp \
|
|
darwin11.supp darwin12.supp \
|
|
Index: configure.in
|
|
===================================================================
|
|
--- configure.in (revision 13036)
|
|
+++ configure.in (working copy)
|
|
@@ -937,7 +937,10 @@
|
|
# Add glibc and X11 suppressions for exp-sgcheck
|
|
DEFAULT_SUPP="exp-sgcheck.supp ${DEFAULT_SUPP}"
|
|
|
|
+# Add suppressions for DMDV
|
|
+DEFAULT_SUPP="exp-dmdv.supp ${DEFAULT_SUPP}"
|
|
|
|
+
|
|
#----------------------------------------------------------------------------
|
|
# Platform variants?
|
|
#----------------------------------------------------------------------------
|
|
@@ -2468,6 +2471,8 @@
|
|
exp-bbv/tests/arm-linux/Makefile
|
|
exp-dhat/Makefile
|
|
exp-dhat/tests/Makefile
|
|
+ exp-dmdv/Makefile
|
|
+ exp-dmdv/tests/Makefile
|
|
])
|
|
AC_CONFIG_FILES([coregrind/link_tool_exe_linux],
|
|
[chmod +x coregrind/link_tool_exe_linux])
|