|
From: <sv...@va...> - 2007-10-31 13:53:33
|
Author: sewardj
Date: 2007-10-31 13:53:35 +0000 (Wed, 31 Oct 2007)
New Revision: 7063
Log:
Make sanity checking controllable from the command line, and tidy up
the top of tc_main.c a bit.
Modified:
branches/THRCHECK/thrcheck/tc_main.c
Modified: branches/THRCHECK/thrcheck/tc_main.c
===================================================================
--- branches/THRCHECK/thrcheck/tc_main.c 2007-10-31 01:01:02 UTC (rev 7062)
+++ branches/THRCHECK/thrcheck/tc_main.c 2007-10-31 13:53:35 UTC (rev 7063)
@@ -76,6 +76,8 @@
// FIXME pth_cond_wait/timedwait wrappers. Even if these fail,
// the thread still holds the lock.
+/* ------------ Debug/trace options ------------ */
+
// this is:
// shadow_mem_make_NoAccess: 29156 SMs, 1728 scanned
// happens_before_wrk: 1000
@@ -90,34 +92,33 @@
#define SCE_LOCKS (1<<1) // Sanity check at lock events
#define SCE_BIGRANGE (1<<2) // Sanity check at big mem range events
#define SCE_ACCESS (1<<3) // Sanity check at mem accesses
+#define SCE_LAOG (1<<4) // Sanity check at significant LAOG events
#define SCE_BIGRANGE_T 256 // big mem range minimum size
-static const Int sanity_flags
-//= SCE_THREADS | SCE_LOCKS | SCE_BIGRANGE | SCE_ACCESS;
-= 0;
-#define SCE_CACHELINE 0 /* don't sanity-check CacheLine stuff */
-//#define SCE_CACHELINE 1 /* do sanity-check CacheLine stuff */
-//#define inline __attribute__((noinline))
+/* For the shadow mem cache stuff we may want more intrusive
+ checks. Unfortunately there's no almost-zero-cost way to make them
+ selectable at run time. Hence set the #if 0 to #if 1 and
+ rebuild if you want them. */
+#if 0
+# define SCE_CACHELINE 1 /* do sanity-check CacheLine stuff */
+# define inline __attribute__((noinline))
+ /* probably want to ditch -fomit-frame-pointer too */
+#else
+# define SCE_CACHELINE 0 /* don't sanity-check CacheLine stuff */
+#endif
static void all__sanity_check ( char* who ); /* fwds */
#define TC_CLI__MALLOC_REDZONE_SZB 16 /* let's say */
+// 0 for none, 1 for dump at end of run
+#define SHOW_DATA_STRUCTURES 0
-/* This has to do with printing error messages. See comments on
- announce_threadset() and summarise_threadset(). */
-#define N_THREADS_TO_ANNOUNCE 5
+/* ------------ Command line options ------------ */
-// FIXME: don't hardwire initial entries for root thread.
-// Instead, let the pre_thread_ll_create handler do this.
-
-// 0 for none, 1 for dump at end of run
-#define SHOW_DATA_STRUCTURES 0
-
-// FIXME move this somewhere sane
// 0 = no segments at all
// 1 = segments at thread create/join
// 2 = as 1 + segments at condition variable signal/broadcast/wait too
@@ -138,6 +139,21 @@
static Addr clo_trace_addr = 0;
static Int clo_trace_level = 0;
+/* Sanity check level. This is an or-ing of
+ SCE_{THREADS,LOCKS,BIGRANGE,ACCESS,LAOG}. */
+static Int clo_sanity_flags = 0;
+
+/* This has to do with printing error messages. See comments on
+ announce_threadset() and summarise_threadset(). Perhaps it
+ should be a command line option. */
+#define N_THREADS_TO_ANNOUNCE 5
+
+
+/* ------------ Misc comments ------------ */
+
+// FIXME: don't hardwire initial entries for root thread.
+// Instead, let the pre_thread_ll_create handler do this.
+
// FIXME: when a SecMap is completely set via and address range
// setting operation to a non-ShR/M state, clear its .mbHasShared
// bit
@@ -534,7 +550,6 @@
static UWord stats__lockN_acquires = 0;
static UWord stats__lockN_releases = 0;
-static UWord stats__lockN_acquires_w_ExeContext = 0;
static ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* ); /*fwds*/
@@ -2383,8 +2398,11 @@
/*--- Sanity checking the data structures ---*/
/*----------------------------------------------------------------*/
+static UWord stats__sanity_checks = 0;
+
static Bool is_sane_CacheLine ( CacheLine* cl ); /* fwds */
static Bool cmpGEQ_VTS ( XArray* a, XArray* b ); /* fwds */
+static void laog__sanity_check ( Char* who ); /* fwds */
/* REQUIRED INVARIANTS:
@@ -2466,6 +2484,7 @@
}
/* Sanity check Threads, as far as possible */
+__attribute__((noinline))
static void threads__sanity_check ( Char* who )
{
#define BAD(_str) do { how = (_str); goto bad; } while (0)
@@ -2507,6 +2526,7 @@
/* Sanity check Locks, as far as possible */
+__attribute__((noinline))
static void locks__sanity_check ( Char* who )
{
#define BAD(_str) do { how = (_str); goto bad; } while (0)
@@ -2577,6 +2597,7 @@
/* Sanity check Segments, as far as possible */
+__attribute__((noinline))
static void segments__sanity_check ( Char* who )
{
#define BAD(_str) do { how = (_str); goto bad; } while (0)
@@ -2613,14 +2634,23 @@
/* Sanity check shadow memory, as far as possible */
+static Int cmp_Addr_for_ssort ( void* p1, void* p2 ) {
+ Addr a1 = *(Addr*)p1;
+ Addr a2 = *(Addr*)p2;
+ if (a1 < a2) return -1;
+ if (a1 > a2) return 1;
+ return 0;
+}
+__attribute__((noinline))
static void shmem__sanity_check ( Char* who )
{
#define BAD(_str) do { how = (_str); goto bad; } while (0)
Char* how = "no error";
Word smga;
SecMap* sm;
- Word i, j, ws_size;
+ Word i, j, ws_size, n_valid_tags;
Word* ws_words;
+ Addr* valid_tags;
TC_(initIterFM)( map_shmem );
// for sm in SecMaps {
while (TC_(nextIterFM)( map_shmem, (Word*)&smga, (Word*)&sm )) {
@@ -2653,7 +2683,7 @@
WordSetID lset = un_SHVAL_Sh_lset(w32);
if (!TC_(plausibleWS)( univ_tsets, tset )) BAD("5");
if (!TC_(saneWS_SLOW)( univ_tsets, tset )) BAD("6");
- if (TC_(isEmptyWS)( univ_tsets, tset )) BAD("7");
+ if (TC_(cardinalityWS)( univ_tsets, tset ) < 2) BAD("7");
if (!TC_(plausibleWS)( univ_lsets, lset )) BAD("8");
if (!TC_(saneWS_SLOW)( univ_lsets, lset )) BAD("9");
TC_(getPayloadWS)( &ws_words, &ws_size, univ_lsets, lset );
@@ -2689,6 +2719,9 @@
TC_(doneIterFM)( map_shmem );
// check the cache
+ valid_tags = tc_zalloc(N_WAY_NENT * sizeof(Addr));
+ n_valid_tags = 0;
+ tl_assert(valid_tags);
for (i = 0; i < N_WAY_NENT; i++) {
CacheLine* cl;
Addr tag;
@@ -2698,12 +2731,23 @@
if (tag != 1) {
if (!is_valid_scache_tag(tag)) BAD("14-0");
if (!is_sane_CacheLine(cl)) BAD("15-0");
+ /* A valid tag should be of the form
+ X---X line_number:N_WAY_BITS 0:N_LINE_BITS */
if (tag & (N_LINE_ARANGE-1)) BAD("16-0");
- for (j = i+1; j < N_WAY_NENT; j++)
- if (cache_shmem.tags0[j] == tag) BAD("17-0");
+ if ( i != ((tag >> N_LINE_BITS) & (N_WAY_NENT-1)) ) BAD("16-1");
+ valid_tags[n_valid_tags++] = tag;
}
}
-
+ tl_assert(n_valid_tags <= N_WAY_NENT);
+ if (n_valid_tags > 1) {
+ /* Check that the valid tags are unique */
+ VG_(ssort)( valid_tags, n_valid_tags, sizeof(Addr), cmp_Addr_for_ssort );
+ for (i = 0; i < n_valid_tags-1; i++) {
+ if (valid_tags[i] >= valid_tags[i+1])
+ BAD("16-2");
+ }
+ }
+ tc_free(valid_tags);
return;
bad:
VG_(printf)("shmem__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
@@ -2713,11 +2757,13 @@
static void all__sanity_check ( char* who )
{
+ stats__sanity_checks++;
if (0) VG_(printf)("all__sanity_check(%s)\n", who);
threads__sanity_check(who);
locks__sanity_check(who);
segments__sanity_check(who);
shmem__sanity_check(who);
+ laog__sanity_check(who);
}
@@ -5344,7 +5390,7 @@
if (SHOW_EVENTS >= 2)
VG_(printf)("evh__new_mem(%p, %lu)\n", (void*)a, len );
shadow_mem_make_New( get_current_Thread(), a, len );
- if (len >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__new_mem-post");
}
@@ -5356,7 +5402,7 @@
(void*)a, len, (Int)rr, (Int)ww, (Int)xx );
if (rr || ww || xx)
shadow_mem_make_New( get_current_Thread(), a, len );
- if (len >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__new_mem_w_perms-post");
}
@@ -5371,7 +5417,7 @@
NoAccess, else leave it alone. */
if (!(rr || ww))
shadow_mem_make_NoAccess( get_current_Thread(), a, len );
- if (len >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__set_perms-post");
}
@@ -5380,7 +5426,7 @@
if (SHOW_EVENTS >= 2)
VG_(printf)("evh__die_mem(%p, %lu)\n", (void*)a, len );
shadow_mem_make_NoAccess( get_current_Thread(), a, len );
- if (len >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__die_mem-post");
}
@@ -5458,7 +5504,7 @@
}
}
- if (sanity_flags & SCE_THREADS)
+ if (clo_sanity_flags & SCE_THREADS)
all__sanity_check("evh__pre_thread_create-post");
}
@@ -5487,7 +5533,7 @@
entry, in order that the Valgrind core can re-use it. */
map_threads_delete( quit_tid );
- if (sanity_flags & SCE_THREADS)
+ if (clo_sanity_flags & SCE_THREADS)
all__sanity_check("evh__pre_thread_ll_exit-post");
}
@@ -5636,7 +5682,7 @@
tl_assert( map_threads_maybe_reverse_lookup_SLOW(thr_q)
== VG_INVALID_THREADID);
- if (sanity_flags & SCE_THREADS)
+ if (clo_sanity_flags & SCE_THREADS)
all__sanity_check("evh__post_thread_join-post");
}
@@ -5648,7 +5694,7 @@
VG_(printf)("evh__pre_mem_read(ctid=%d, \"%s\", %p, %lu)\n",
(Int)tid, s, (void*)a, size );
shadow_mem_read_range( map_threads_lookup(tid), a, size);
- if (size >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (size >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__pre_mem_read-post");
}
@@ -5662,7 +5708,7 @@
// FIXME: think of a less ugly hack
len = VG_(strlen)( (Char*) a );
shadow_mem_read_range( map_threads_lookup(tid), a, len+1 );
- if (len >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__pre_mem_read_asciiz-post");
}
@@ -5673,7 +5719,7 @@
VG_(printf)("evh__pre_mem_write(ctid=%d, \"%s\", %p, %lu)\n",
(Int)tid, s, (void*)a, size );
shadow_mem_write_range( map_threads_lookup(tid), a, size);
- if (size >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (size >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__pre_mem_write-post");
}
@@ -5688,7 +5734,7 @@
} else {
shadow_mem_make_New(get_current_Thread(), a, len);
}
- if (len >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__pre_mem_read-post");
}
@@ -5697,7 +5743,7 @@
if (SHOW_EVENTS >= 1)
VG_(printf)("evh__die_mem_heap(%p, %lu)\n", (void*)a, len );
shadow_mem_make_NoAccess( get_current_Thread(), a, len );
- if (len >= SCE_BIGRANGE_T && (sanity_flags & SCE_BIGRANGE))
+ if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
all__sanity_check("evh__pre_mem_read-post");
}
@@ -5777,7 +5823,7 @@
tl_assert(mbRec == 0 || mbRec == 1);
map_locks_lookup_or_create( mbRec ? LK_mbRec : LK_nonRec,
(Addr)mutex, tid );
- if (sanity_flags & SCE_LOCKS)
+ if (clo_sanity_flags & SCE_LOCKS)
all__sanity_check("evh__tc_PTHREAD_MUTEX_INIT_POST");
}
@@ -5818,7 +5864,7 @@
tl_assert( is_sane_LockN(lk) );
}
- if (sanity_flags & SCE_LOCKS)
+ if (clo_sanity_flags & SCE_LOCKS)
all__sanity_check("evh__tc_PTHREAD_MUTEX_DESTROY_PRE");
}
@@ -6058,7 +6104,7 @@
VG_(printf)("evh__tc_PTHREAD_RWLOCK_INIT_POST(ctid=%d, %p)\n",
(Int)tid, (void*)rwl );
map_locks_lookup_or_create( LK_rdwr, (Addr)rwl, tid );
- if (sanity_flags & SCE_LOCKS)
+ if (clo_sanity_flags & SCE_LOCKS)
all__sanity_check("evh__tc_PTHREAD_RWLOCK_INIT_POST");
}
@@ -6098,7 +6144,7 @@
tl_assert( is_sane_LockN(lk) );
}
- if (sanity_flags & SCE_LOCKS)
+ if (clo_sanity_flags & SCE_LOCKS)
all__sanity_check("evh__tc_PTHREAD_RWLOCK_DESTROY_PRE");
}
@@ -6430,12 +6476,12 @@
/* end EXPOSITION ONLY */
-static void laog__show ( void ) {
+static void laog__show ( Char* who ) {
Word i, ws_size;
Word* ws_words;
Lock* me;
LAOGLinks* links;
- VG_(printf)("laog {\n");
+ VG_(printf)("laog (requested by %s) {\n", who);
TC_(initIterFM)( laog );
me = NULL;
links = NULL;
@@ -6588,12 +6634,14 @@
}
}
-__attribute__((unused))
-static void laog__sanity_check ( void ) {
+__attribute__((noinline))
+static void laog__sanity_check ( Char* who ) {
Word i, ws_size;
Word* ws_words;
Lock* me;
LAOGLinks* links;
+ if ( !laog )
+ return; /* nothing much we can do */
TC_(initIterFM)( laog );
me = NULL;
links = NULL;
@@ -6622,7 +6670,8 @@
return;
bad:
- laog__show();
+ VG_(printf)("laog__sanity_check(%s) FAILED\n", who);
+ laog__show(who);
tl_assert(0);
}
@@ -6759,6 +6808,9 @@
tl_assert(old->acquired_at);
laog__add_edge( old, lk );
}
+
+ if (clo_sanity_flags & SCE_LAOG)
+ all__sanity_check("laog__pre_thread_acquires_lock-post");
}
@@ -6811,6 +6863,9 @@
TC_(getPayloadWS)( &ws_words, &ws_size, univ_lsets, locksToDelete );
for (i = 0; i < ws_size; i++)
laog__handle_one_lock_deletion( (Lock*)ws_words[i] );
+
+ if (clo_sanity_flags & SCE_LAOG)
+ all__sanity_check("laog__handle_lock_deletions-post");
}
@@ -8313,6 +8368,28 @@
}
else VG_BNUM_CLO(arg, "--trace-level", clo_trace_level, 0, 2)
+ /* "stuvw" --> stuvw (binary) */
+ else if (VG_CLO_STREQN(18, arg, "--tc-sanity-flags=")) {
+ Int j;
+ char* opt = & arg[18];
+
+ if (5 != VG_(strlen)(opt)) {
+ VG_(message)(Vg_UserMsg,
+ "--tc-sanity-flags argument must have 5 digits");
+ return False;
+ }
+ for (j = 0; j < 5; j++) {
+ if ('0' == opt[j]) { /* do nothing */ }
+ else if ('1' == opt[j]) clo_sanity_flags |= (1 << (5-1-j));
+ else {
+ VG_(message)(Vg_UserMsg, "--tc-sanity-flags argument can "
+ "only contain 0s and 1s");
+ return False;
+ }
+ }
+ VG_(printf)("XXX sanity flags: 0x%x\n", clo_sanity_flags);
+ }
+
else
return VG_(replacement_malloc_process_cmd_line_option)(arg);
@@ -8337,6 +8414,16 @@
"in .vcg format [no]\n");
VG_(printf)(" --cmp-race-err-addrs=no|yes are data addresses in "
"race errors significant? [no]\n");
+ VG_(printf)(" --tc-sanity-flags=<XXXXX> sanity check "
+ " at events (X = 0|1) [00000]\n");
+ VG_(printf)(" --tc-sanity-flags values:\n");
+ VG_(printf)(" 10000 after changes to "
+ "lock-order-acquisition-graph\n");
+ VG_(printf)(" 01000 at memory accesses (NB: not curently used)\n");
+ VG_(printf)(" 00100 at mem permission setting for "
+ "ranges >= %d bytes\n", SCE_BIGRANGE_T);
+ VG_(printf)(" 00010 at lock/unlock events\n");
+ VG_(printf)(" 00001 at thread create/join events\n");
}
static void tc_post_clo_init ( void )
@@ -8347,7 +8434,7 @@
{
if (SHOW_DATA_STRUCTURES)
pp_everything( PP_ALL, "SK_(fini)" );
- if (sanity_flags)
+ if (clo_sanity_flags)
all__sanity_check("SK_(fini)");
if (clo_gen_vcg > 0)
@@ -8377,33 +8464,36 @@
VG_(printf)(" hbefore: %,10lu probes\n", stats__hbefore_probes);
VG_(printf)("\n");
- VG_(printf)("segments: %,10lu Segment objects allocated\n",
+ VG_(printf)(" segments: %,8lu Segment objects allocated\n",
stats__mk_Segment);
- VG_(printf)("locksets: %8d unique lock sets\n",
+ VG_(printf)(" locksets: %,8d unique lock sets\n",
(Int)TC_(cardinalityWSU)( univ_lsets ));
- VG_(printf)("threadsets: %8d unique thread sets\n",
+ VG_(printf)(" threadsets: %,8d unique thread sets\n",
(Int)TC_(cardinalityWSU)( univ_tsets ));
- VG_(printf)("univ_laog: %8d unique lock sets\n",
+ VG_(printf)(" univ_laog: %,8d unique lock sets\n",
(Int)TC_(cardinalityWSU)( univ_laog ));
- VG_(printf)("L(ast)L(ock) map: %8lu inserts (%d map size)\n",
+ VG_(printf)("L(ast)L(ock) map: %,8lu inserts (%d map size)\n",
stats__ga_LL_adds,
(Int)(ga_to_lastlock ? TC_(sizeFM)( ga_to_lastlock ) : 0) );
- VG_(printf)("LockN-to-P map: %8lu queries (%d map size)\n",
+ VG_(printf)(" LockN-to-P map: %,8lu queries (%d map size)\n",
stats__ga_LockN_to_P_queries,
(Int)(yaWFM ? TC_(sizeFM)( yaWFM ) : 0) );
- VG_(printf)("string table map: %8lu queries (%d map size)\n",
+ VG_(printf)("string table map: %,8lu queries (%d map size)\n",
stats__string_table_queries,
(Int)(string_table ? TC_(sizeFM)( string_table ) : 0) );
-
- VG_(printf)(" locks: %,lu acquires (%,lu w/ExeContext), "
+ VG_(printf)(" LAOG: %,8d map size\n",
+ (Int)(laog ? TC_(sizeFM)( laog ) : 0));
+ VG_(printf)(" LAOG exposition: %,8d map size\n",
+ (Int)(laog_exposition ? TC_(sizeFM)( laog_exposition ) : 0));
+ VG_(printf)(" locks: %,8lu acquires, "
"%,lu releases\n",
stats__lockN_acquires,
- stats__lockN_acquires_w_ExeContext,
stats__lockN_releases
);
+ VG_(printf)(" sanity checks: %,8lu\n", stats__sanity_checks);
VG_(printf)("\n");
VG_(printf)(" msm: %,12lu %,12lu rd/wr_Excl_nochange\n",
|