blob: 0a97571247b130d5d3345060931886ea3e0ea189 [file] [log] [blame]
sewardjb4112022007-11-09 22:49:28 +00001
2/*--------------------------------------------------------------------*/
3/*--- Helgrind: a Valgrind tool for detecting errors ---*/
4/*--- in threaded programs. hg_main.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
10
11 Copyright (C) 2007-2007 OpenWorks LLP
12 info@open-works.co.uk
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30
31 Neither the names of the U.S. Department of Energy nor the
32 University of California nor the names of its contributors may be
33 used to endorse or promote products derived from this software
34 without prior written permission.
35*/
36
37#include "pub_tool_basics.h"
38#include "pub_tool_aspacemgr.h"
39#include "pub_tool_libcassert.h"
40#include "pub_tool_libcbase.h"
41#include "pub_tool_libcprint.h"
42#include "pub_tool_mallocfree.h"
43#include "pub_tool_threadstate.h"
44#include "pub_tool_tooliface.h"
45#include "pub_tool_hashtable.h"
46#include "pub_tool_replacemalloc.h"
47#include "pub_tool_machine.h"
48#include "pub_tool_options.h"
49#include "pub_tool_xarray.h"
50#include "pub_tool_stacktrace.h"
51
52#include "helgrind.h"
53
54#define HG_(str) VGAPPEND(vgHelgrind_,str)
55#include "hg_wordfm.h"
56#include "hg_wordset.h"
57
58/*----------------------------------------------------------------*/
59/*--- ---*/
60/*----------------------------------------------------------------*/
61
62/* Note there are a whole bunch of ugly double casts of the form
63 (Word*)(void*)&p. These placate gcc at -O2. The obvious form
64 (Word*)&p causes gcc to complain that 'dereferencing a type-punned
65 pointer ill break strict-aliasing rules'. It stops complaining
66 when the intermediate void* type is inserted. Is this a reasonable
67 "fix"? I don't know. */
68
69// FIXME what is supposed to happen to locks in memory which
70// is relocated as a result of client realloc?
71
72// FIXME some kind of ownership recycling problem in
73// init_thread_specific_state() for programs which use the same thread
74// slot more than once?
75
76// FIXME put referencing ThreadId into Thread and get
77// rid of the slow reverse mapping function.
78
79// FIXME accesses to NoAccess areas: change state to Excl?
80
81// FIXME report errors for accesses of NoAccess memory?
82
83// FIXME pth_cond_wait/timedwait wrappers. Even if these fail,
84// the thread still holds the lock.
85
86/* ------------ Debug/trace options ------------ */
87
88// this is:
89// shadow_mem_make_NoAccess: 29156 SMs, 1728 scanned
90// happens_before_wrk: 1000
91// ev__post_thread_join: 3360 SMs, 29 scanned, 252 re-Excls
92#define SHOW_EXPENSIVE_STUFF 0
93
94// 0 for silent, 1 for some stuff, 2 for lots of stuff
95#define SHOW_EVENTS 0
96
97// Flags for controlling for which events sanity checking is done
98#define SCE_THREADS (1<<0) // Sanity check at thread create/join
99#define SCE_LOCKS (1<<1) // Sanity check at lock events
100#define SCE_BIGRANGE (1<<2) // Sanity check at big mem range events
101#define SCE_ACCESS (1<<3) // Sanity check at mem accesses
102#define SCE_LAOG (1<<4) // Sanity check at significant LAOG events
103
104#define SCE_BIGRANGE_T 256 // big mem range minimum size
105
106
107/* For the shadow mem cache stuff we may want more intrusive
108 checks. Unfortunately there's no almost-zero-cost way to make them
109 selectable at run time. Hence set the #if 0 to #if 1 and
110 rebuild if you want them. */
111#if 0
112# define SCE_CACHELINE 1 /* do sanity-check CacheLine stuff */
113# define inline __attribute__((noinline))
114 /* probably want to ditch -fomit-frame-pointer too */
115#else
116# define SCE_CACHELINE 0 /* don't sanity-check CacheLine stuff */
117#endif
118
119static void all__sanity_check ( Char* who ); /* fwds */
120
121#define HG_CLI__MALLOC_REDZONE_SZB 16 /* let's say */
122
123// 0 for none, 1 for dump at end of run
124#define SHOW_DATA_STRUCTURES 0
125
126
127/* ------------ Command line options ------------ */
128
129// 0 = no segments at all
130// 1 = segments at thread create/join
131// 2 = as 1 + segments at condition variable signal/broadcast/wait too
132static Int clo_happens_before = 2; /* default setting */
133
134/* Generate .vcg output of the happens-before graph?
135 0: no 1: yes, without VTSs 2: yes, with VTSs */
136static Int clo_gen_vcg = 0;
137
138/* When comparing race errors for equality, should the race address be
139 taken into account? For users, no, but for verification purposes
140 (regtesting) this is sometimes important. */
141static Bool clo_cmp_race_err_addrs = False;
142
143/* Tracing memory accesses, so we can see what's going on.
144 clo_trace_addr is the address to monitor. clo_trace_level = 0 for
145 no tracing, 1 for summary, 2 for detailed. */
146static Addr clo_trace_addr = 0;
147static Int clo_trace_level = 0;
148
149/* Sanity check level. This is an or-ing of
150 SCE_{THREADS,LOCKS,BIGRANGE,ACCESS,LAOG}. */
151static Int clo_sanity_flags = 0;
152
153/* This has to do with printing error messages. See comments on
154 announce_threadset() and summarise_threadset(). Perhaps it
155 should be a command line option. */
156#define N_THREADS_TO_ANNOUNCE 5
157
158
159/* ------------ Misc comments ------------ */
160
161// FIXME: don't hardwire initial entries for root thread.
162// Instead, let the pre_thread_ll_create handler do this.
163
164// FIXME: when a SecMap is completely set via and address range
165// setting operation to a non-ShR/M state, clear its .mbHasShared
166// bit
167
168/* FIXME: figure out what the real rules are for Excl->ShR/M
169 transitions w.r.t locksets.
170
171 Muelenfeld thesis Sec 2.2.1 p 8/9 says that
172
173 When another thread accesses the memory location, the lock-set
174 is initialized with all active locks and the algorithm reports
175 the next access that results in an empty lock-set.
176
177 What does "all active locks" mean? All locks held by the accessing
178 thread, or all locks held by the system as a whole?
179
180 However: Muelenfeld's enhanced Helgrind (eraser_mem_read_word)
181 seems to use simply the set of locks held by the thread causing the
182 transition into a shared state at the time of the transition:
183
184 *sword = SW(Vge_Shar, packLockSet(thread_locks_rd[tid]));
185
186 Original Eraser paper also says "all active locks".
187*/
188
189// Major stuff to fix:
190// - reader-writer locks
191
192/* Thread async exit:
193
194 remove the map_threads entry
195 leave the Thread object in place
196 complain if holds any locks
197
198 unlike with Join, do not change any memory states
199
200 I _think_ this is correctly handled now.
201*/
202
203/*----------------------------------------------------------------*/
204/*--- Some very basic stuff ---*/
205/*----------------------------------------------------------------*/
206
207static void* hg_zalloc ( SizeT n ) {
208 void* p;
209 tl_assert(n > 0);
210 p = VG_(malloc)( n );
211 tl_assert(p);
212 VG_(memset)(p, 0, n);
213 return p;
214}
215static void hg_free ( void* p ) {
216 tl_assert(p);
217 VG_(free)(p);
218}
219
220/* Round a up to the next multiple of N. N must be a power of 2 */
221#define ROUNDUP(a, N) ((a + N - 1) & ~(N-1))
222/* Round a down to the next multiple of N. N must be a power of 2 */
223#define ROUNDDN(a, N) ((a) & ~(N-1))
224
225#ifdef HAVE_BUILTIN_EXPECT
226#define LIKELY(cond) __builtin_expect((cond),1)
227#define UNLIKELY(cond) __builtin_expect((cond),0)
228#else
229#define LIKELY(cond) (cond)
230#define UNLIKELY(cond) (cond)
231#endif
232
233
234/*----------------------------------------------------------------*/
235/*--- Primary data definitions ---*/
236/*----------------------------------------------------------------*/
237
238/* These are handles for thread segments. CONSTRAINTS: Must be small
239 ints numbered from zero, since 30-bit versions of them must are
240 used to represent Exclusive shadow states. Are used as keys in
241 WordFMs so must be castable to Words at the appropriate points. */
242typedef UInt SegmentID;
243
244
245/* These are handles for Word sets. CONSTRAINTS: must be (very) small
246 ints numbered from zero, since < 30-bit versions of them are used to
247 encode thread-sets and lock-sets in 32-bit shadow words. */
248typedef WordSet WordSetID;
249
250
251/* Stores information about a thread. Addresses of these also serve
252 as unique thread identifiers and so are never freed, so they should
253 be as small as possible. */
254typedef
255 struct _Thread {
256 /* ADMIN */
257 struct _Thread* admin;
258 UInt magic;
259 /* USEFUL */
260 WordSetID locksetA; /* WordSet of Lock* currently held by thread */
261 WordSetID locksetW; /* subset of locksetA held in w-mode */
262 SegmentID csegid; /* current thread segment for thread */
263 /* EXPOSITION */
264 /* Place where parent was when this thread was created. */
265 ExeContext* created_at;
266 Bool announced;
267 /* Index for generating references in error messages. */
268 Int errmsg_index;
269 }
270 Thread;
271
272
273/* Stores information about a lock's current state. These are
274 allocated and later freed (when the containing memory becomes
275 NoAccess). This gives a problem for the XError type, which
276 contains Lock*s. Solution is to copy any Lock which is to be
277 incorporated into an XErrors, so as to make it independent from the
278 'normal' collection of Locks, which can come and go. When the lock
279 is copied, its .magic is changed from LockN_Magic to
280 LockP_Magic. */
281
282/* Lock kinds. */
283typedef
284 enum {
285 LK_mbRec=1001, /* normal mutex, possibly recursive */
286 LK_nonRec, /* normal mutex, definitely non recursive */
287 LK_rdwr /* reader-writer lock */
288 }
289 LockKind;
290
291typedef
292 struct _Lock {
293 /* ADMIN */
294 struct _Lock* admin;
295 ULong unique; /* used for persistence-hashing */
296 UInt magic; /* LockN_MAGIC or LockP_MAGIC */
297 /* EXPOSITION */
298 /* Place where lock first came to the attention of Helgrind. */
299 ExeContext* appeared_at;
300 /* Place where the lock most recently made an unlocked->locked
301 transition. */
302 ExeContext* acquired_at;
303 /* USEFUL-STATIC */
304 Addr guestaddr; /* Guest address of lock */
305 LockKind kind; /* what kind of lock this is */
306 /* USEFUL-DYNAMIC */
307 Bool heldW;
308 WordBag* heldBy; /* bag of threads that hold this lock */
309 /* .heldBy is NULL: lock is unheld, and .heldW is meaningless
310 but arbitrarily set to False
311 .heldBy is non-NULL:
312 .heldW is True: lock is w-held by threads in heldBy
313 .heldW is False: lock is r-held by threads in heldBy
314 Either way, heldBy may not validly be an empty Bag.
315
316 for LK_nonRec, r-holdings are not allowed, and w-holdings may
317 only have sizeTotal(heldBy) == 1
318
319 for LK_mbRec, r-holdings are not allowed, and w-holdings may
320 only have sizeUnique(heldBy) == 1
321
322 for LK_rdwr, w-holdings may only have sizeTotal(heldBy) == 1 */
323 }
324 Lock;
325
326
327/* Stores information about thread segments. .prev can be NULL only
328 when this is the first segment for the thread. .other is NULL
329 unless this segment depends on a message (create, join, signal)
330 from some other thread. Segments are never freed (!) */
331typedef
332 struct _Segment {
333 /* ADMIN */
334 struct _Segment* admin;
335 UInt magic;
336 /* USEFUL */
337 UInt dfsver; /* Version # for depth-first searches */
338 Thread* thr; /* The thread that I am part of */
339 struct _Segment* prev; /* The previous segment in this thread */
340 struct _Segment* other; /* Possibly a segment from some other
341 thread, which happened-before me */
342 XArray* vts; /* XArray of ScalarTS */
343 /* DEBUGGING ONLY: what does 'other' arise from?
344 c=thread creation, j=join, s=cvsignal, S=semaphore */
345 Char other_hint;
346 }
347 Segment;
348
349
350/* ------ CacheLine ------ */
351
352#define N_LINE_BITS 5 /* must be >= 3 */
353#define N_LINE_ARANGE (1 << N_LINE_BITS)
354#define N_LINE_TREES (N_LINE_ARANGE >> 3)
355
356typedef
357 struct {
358 UShort descrs[N_LINE_TREES];
359 UInt svals[N_LINE_ARANGE]; // == N_LINE_TREES * 8
360 }
361 CacheLine;
362
363#define TREE_DESCR_16_0 (1<<0)
364#define TREE_DESCR_32_0 (1<<1)
365#define TREE_DESCR_16_1 (1<<2)
366#define TREE_DESCR_64 (1<<3)
367#define TREE_DESCR_16_2 (1<<4)
368#define TREE_DESCR_32_1 (1<<5)
369#define TREE_DESCR_16_3 (1<<6)
370#define TREE_DESCR_8_0 (1<<7)
371#define TREE_DESCR_8_1 (1<<8)
372#define TREE_DESCR_8_2 (1<<9)
373#define TREE_DESCR_8_3 (1<<10)
374#define TREE_DESCR_8_4 (1<<11)
375#define TREE_DESCR_8_5 (1<<12)
376#define TREE_DESCR_8_6 (1<<13)
377#define TREE_DESCR_8_7 (1<<14)
378#define TREE_DESCR_DTY (1<<15)
379
380typedef
381 struct {
382 UInt dict[4]; /* can represent up to 4 diff values in the line */
383 UChar ix2s[N_LINE_ARANGE/4]; /* array of N_LINE_ARANGE 2-bit
384 dict indexes */
385 /* if dict[0] == 0 then dict[1] is the index of the CacheLineF
386 to use */
387 }
388 CacheLineZ; /* compressed rep for a cache line */
389
390typedef
391 struct {
392 Bool inUse;
393 UInt w32s[N_LINE_ARANGE];
394 }
395 CacheLineF; /* full rep for a cache line */
396
397
398/* Shadow memory.
399 Primary map is a WordFM Addr SecMap*.
400 SecMaps cover some page-size-ish section of address space and hold
401 a compressed representation.
402 CacheLine-sized chunks of SecMaps are copied into a Cache, being
403 decompressed when moved into the cache and recompressed on the
404 way out. Because of this, the cache must operate as a writeback
405 cache, not a writethrough one.
406*/
407/* See comments below on shadow_mem_make_NoAccess re performance
408 effects of N_SECMAP_BITS settings. On a 2.4GHz Core2,
409 starting/quitting OOo (32-bit), I have these rough numbers:
410 N_SECMAP_BITS = 11 2m23
411 N_SECMAP_BITS = 12 1m58
412 N_SECMAP_BITS = 13 1m53
413
414 Each SecMap must hold a power-of-2 number of CacheLines. Hence
415 N_SECMAP_BITS must >= N_LINE_BITS.
416*/
417#define N_SECMAP_BITS 13
418#define N_SECMAP_ARANGE (1 << N_SECMAP_BITS)
419
420// # CacheLines held by a SecMap
421#define N_SECMAP_ZLINES (N_SECMAP_ARANGE / N_LINE_ARANGE)
422typedef
423 struct {
424 UInt magic;
425 Bool mbHasLocks; /* hint: any locks in range? safe: True */
426 Bool mbHasShared; /* hint: any ShM/ShR states in range? safe: True */
427 CacheLineZ linesZ[N_SECMAP_ZLINES];
428 CacheLineF* linesF;
429 Int linesF_size;
430 }
431 SecMap;
432
433typedef
434 struct {
435 Int line_no; /* which Z-line are we in? */
436 Int word_no; /* inside the line, which word is current? */
437 }
438 SecMapIter;
439
440static void initSecMapIter ( SecMapIter* itr ) {
441 itr->line_no = 0;
442 itr->word_no = 0;
443}
444
445/* Get the current val, and move to the next position. This is called
446 a huge amount in some programs (eg OpenOffice). Hence the
447 'inline'. */
448static UWord stats__secmap_iterator_steppings; /* fwds */
449
450inline
451static Bool stepSecMapIter ( /*OUT*/UInt** pVal,
452 /*MOD*/SecMapIter* itr, SecMap* sm )
453{
454 CacheLineZ* lineZ = NULL;
455 CacheLineF* lineF = NULL;
456 /* Either it points to a valid place, or to (-1,-1) */
457 stats__secmap_iterator_steppings++;
458 if (UNLIKELY(itr->line_no == -1)) {
459 tl_assert(itr->word_no == -1);
460 return False;
461 }
462 /* so now it must be a valid place in the SecMap. */
463 if (0) VG_(printf)("%p %d %d\n", sm, (Int)itr->line_no, (Int)itr->word_no);
464 tl_assert(itr->line_no >= 0 && itr->line_no < N_SECMAP_ZLINES);
465 lineZ = &sm->linesZ[itr->line_no];
466 if (UNLIKELY(lineZ->dict[0] == 0)) {
467 tl_assert(sm->linesF);
468 tl_assert(sm->linesF_size > 0);
469 tl_assert(lineZ->dict[1] >= 0);
470 tl_assert(lineZ->dict[1] < sm->linesF_size);
471 lineF = &sm->linesF[ lineZ->dict[1] ];
472 tl_assert(lineF->inUse);
473 tl_assert(itr->word_no >= 0 && itr->word_no < N_LINE_ARANGE);
474 *pVal = &lineF->w32s[itr->word_no];
475 itr->word_no++;
476 if (itr->word_no == N_LINE_ARANGE)
477 itr->word_no = 0;
478 } else {
479 tl_assert(itr->word_no >= 0 && itr->word_no <= 3);
480 tl_assert(lineZ->dict[itr->word_no] != 0);
481 *pVal = &lineZ->dict[itr->word_no];
482 itr->word_no++;
483 if (itr->word_no == 4 || lineZ->dict[itr->word_no] == 0)
484 itr->word_no = 0;
485 }
486
487 if (itr->word_no == 0) {
488 itr->line_no++;
489 if (itr->line_no == N_SECMAP_ZLINES) {
490 itr->line_no = -1;
491 itr->word_no = -1;
492 }
493 }
494
495 return True;
496}
497
498/* ------ Cache ------ */
499
500#define N_WAY_BITS 16
501#define N_WAY_NENT (1 << N_WAY_BITS)
502
503/* Each tag is the address of the associated CacheLine, rounded down
504 to a CacheLine address boundary. A CacheLine size must be a power
505 of 2 and must be 8 or more. Hence an easy way to initialise the
506 cache so it is empty is to set all the tag values to any value % 8
507 != 0, eg 1. This means all queries in the cache initially miss.
508 It does however require us to detect and not writeback, any line
509 with a bogus tag. */
510typedef
511 struct {
512 CacheLine lyns0[N_WAY_NENT];
513 Addr tags0[N_WAY_NENT];
514 }
515 Cache;
516
517
518/* --------- Primary data structures --------- */
519
520/* Admin linked list of Threads */
521static Thread* admin_threads = NULL;
522
523/* Admin linked list of Locks */
524static Lock* admin_locks = NULL;
525
526/* Admin linked list of Segments */
527static Segment* admin_segments = NULL;
528
529/* Shadow memory primary map */
530static WordFM* map_shmem = NULL; /* WordFM Addr SecMap* */
531static Cache cache_shmem;
532
533/* Mapping table for core ThreadIds to Thread* */
534static Thread** map_threads = NULL; /* Array[VG_N_THREADS] of Thread* */
535
536/* Mapping table for thread segments IDs to Segment* */
537static WordFM* map_segments = NULL; /* WordFM SegmentID Segment* */
538
539/* Mapping table for lock guest addresses to Lock* */
540static WordFM* map_locks = NULL; /* WordFM LockAddr Lock* */
541
542/* The word-set universes for thread sets and lock sets. */
543static WordSetU* univ_tsets = NULL; /* sets of Thread* */
544static WordSetU* univ_lsets = NULL; /* sets of Lock* */
545static WordSetU* univ_laog = NULL; /* sets of Lock*, for LAOG */
546
547/* never changed; we only care about its address. Is treated as if it
548 was a standard userspace lock. Also we have a Lock* describing it
549 so it can participate in lock sets in the usual way. */
550static Int __bus_lock = 0;
551static Lock* __bus_lock_Lock = NULL;
552
553
554/*----------------------------------------------------------------*/
555/*--- Simple helpers for the data structures ---*/
556/*----------------------------------------------------------------*/
557
558static UWord stats__lockN_acquires = 0;
559static UWord stats__lockN_releases = 0;
560
561static ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* ); /*fwds*/
562
563#define Thread_MAGIC 0x504fc5e5
564#define LockN_MAGIC 0x6545b557 /* normal nonpersistent locks */
565#define LockP_MAGIC 0x755b5456 /* persistent (copied) locks */
566#define Segment_MAGIC 0x49e94d81
567#define SecMap_MAGIC 0x571e58cb
568
569static UWord stats__mk_Segment = 0;
570
571/* --------- Constructors --------- */
572
573static inline Bool is_sane_LockN ( Lock* lock ); /* fwds */
574
575static Thread* mk_Thread ( SegmentID csegid ) {
576 static Int indx = 1;
577 Thread* thread = hg_zalloc( sizeof(Lock) );
578 thread->locksetA = HG_(emptyWS)( univ_lsets );
579 thread->locksetW = HG_(emptyWS)( univ_lsets );
580 thread->csegid = csegid;
581 thread->magic = Thread_MAGIC;
582 thread->created_at = NULL;
583 thread->announced = False;
584 thread->errmsg_index = indx++;
585 thread->admin = admin_threads;
586 admin_threads = thread;
587 return thread;
588}
589// Make a new lock which is unlocked (hence ownerless)
590static Lock* mk_LockN ( LockKind kind, Addr guestaddr ) {
591 static ULong unique = 0;
592 Lock* lock = hg_zalloc( sizeof(Lock) );
593 lock->admin = admin_locks;
594 lock->unique = unique++;
595 lock->magic = LockN_MAGIC;
596 lock->appeared_at = NULL;
597 lock->acquired_at = NULL;
598 lock->guestaddr = guestaddr;
599 lock->kind = kind;
600 lock->heldW = False;
601 lock->heldBy = NULL;
602 tl_assert(is_sane_LockN(lock));
603 admin_locks = lock;
604 return lock;
605}
606static Segment* mk_Segment ( Thread* thr, Segment* prev, Segment* other ) {
607 Segment* seg = hg_zalloc( sizeof(Segment) );
608 seg->dfsver = 0;
609 seg->thr = thr;
610 seg->prev = prev;
611 seg->other = other;
612 seg->vts = NULL;
613 seg->other_hint = ' ';
614 seg->magic = Segment_MAGIC;
615 seg->admin = admin_segments;
616 admin_segments = seg;
617 stats__mk_Segment++;
618 return seg;
619}
620
621static inline Bool is_sane_Segment ( Segment* seg ) {
622 return seg != NULL && seg->magic == Segment_MAGIC;
623}
624static inline Bool is_sane_Thread ( Thread* thr ) {
625 return thr != NULL && thr->magic == Thread_MAGIC;
626}
627
628static Bool is_sane_Bag_of_Threads ( WordBag* bag )
629{
630 Thread* thr;
631 Word count;
632 HG_(initIterBag)( bag );
633 while (HG_(nextIterBag)( bag, (Word*)(void*)&thr, &count )) {
634 if (count < 1) return False;
635 if (!is_sane_Thread(thr)) return False;
636 }
637 HG_(doneIterBag)( bag );
638 return True;
639}
640static Bool is_sane_Lock_BASE ( Lock* lock )
641{
642 if (lock == NULL
643 || (lock->magic != LockN_MAGIC && lock->magic != LockP_MAGIC))
644 return False;
645 switch (lock->kind) {
646 case LK_mbRec: case LK_nonRec: case LK_rdwr: break;
647 default: return False;
648 }
649 if (lock->heldBy == NULL) {
650 if (lock->acquired_at != NULL) return False;
651 /* Unheld. We arbitrarily require heldW to be False. */
652 return !lock->heldW;
653 } else {
654 if (lock->acquired_at == NULL) return False;
655 }
656
657 /* If heldBy is non-NULL, we require it to contain at least one
658 thread. */
659 if (HG_(isEmptyBag)(lock->heldBy))
660 return False;
661
662 /* Lock is either r- or w-held. */
663 if (!is_sane_Bag_of_Threads(lock->heldBy))
664 return False;
665 if (lock->heldW) {
666 /* Held in write-mode */
667 if ((lock->kind == LK_nonRec || lock->kind == LK_rdwr)
668 && !HG_(isSingletonTotalBag)(lock->heldBy))
669 return False;
670 } else {
671 /* Held in read-mode */
672 if (lock->kind != LK_rdwr) return False;
673 }
674 return True;
675}
676static inline Bool is_sane_LockP ( Lock* lock ) {
677 return lock != NULL
678 && lock->magic == LockP_MAGIC
679 && is_sane_Lock_BASE(lock);
680}
681static inline Bool is_sane_LockN ( Lock* lock ) {
682 return lock != NULL
683 && lock->magic == LockN_MAGIC
684 && is_sane_Lock_BASE(lock);
685}
686static inline Bool is_sane_LockNorP ( Lock* lock ) {
687 return is_sane_Lock_BASE(lock);
688}
689
690/* Release storage for a Lock. Also release storage in .heldBy, if
691 any. */
692static void del_LockN ( Lock* lk )
693{
694 tl_assert(is_sane_LockN(lk));
695 if (lk->heldBy)
696 HG_(deleteBag)( lk->heldBy );
697 VG_(memset)(lk, 0xAA, sizeof(*lk));
698 hg_free(lk);
699}
700
701/* Update 'lk' to reflect that 'thr' now has a write-acquisition of
702 it. This is done strictly: only combinations resulting from
703 correct program and libpthread behaviour are allowed. */
704static void lockN_acquire_writer ( Lock* lk, Thread* thr )
705{
706 tl_assert(is_sane_LockN(lk));
707 tl_assert(is_sane_Thread(thr));
708
709 stats__lockN_acquires++;
710
711 /* EXPOSITION only */
712 /* We need to keep recording snapshots of where the lock was
713 acquired, so as to produce better lock-order error messages. */
714 if (lk->acquired_at == NULL) {
715 ThreadId tid;
716 tl_assert(lk->heldBy == NULL);
717 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
718 lk->acquired_at
719 = VG_(record_ExeContext(tid, 0/*first_ip_delta*/));
720 } else {
721 tl_assert(lk->heldBy != NULL);
722 }
723 /* end EXPOSITION only */
724
725 switch (lk->kind) {
726 case LK_nonRec:
727 case_LK_nonRec:
728 tl_assert(lk->heldBy == NULL); /* can't w-lock recursively */
729 tl_assert(!lk->heldW);
730 lk->heldW = True;
731 lk->heldBy = HG_(newBag)( hg_zalloc, hg_free );
732 HG_(addToBag)( lk->heldBy, (Word)thr );
733 break;
734 case LK_mbRec:
735 if (lk->heldBy == NULL)
736 goto case_LK_nonRec;
737 /* 2nd and subsequent locking of a lock by its owner */
738 tl_assert(lk->heldW);
739 /* assert: lk is only held by one thread .. */
740 tl_assert(HG_(sizeUniqueBag(lk->heldBy)) == 1);
741 /* assert: .. and that thread is 'thr'. */
742 tl_assert(HG_(elemBag)(lk->heldBy, (Word)thr)
743 == HG_(sizeTotalBag)(lk->heldBy));
744 HG_(addToBag)(lk->heldBy, (Word)thr);
745 break;
746 case LK_rdwr:
747 tl_assert(lk->heldBy == NULL && !lk->heldW); /* must be unheld */
748 goto case_LK_nonRec;
749 default:
750 tl_assert(0);
751 }
752 tl_assert(is_sane_LockN(lk));
753}
754
755static void lockN_acquire_reader ( Lock* lk, Thread* thr )
756{
757 tl_assert(is_sane_LockN(lk));
758 tl_assert(is_sane_Thread(thr));
759 /* can only add reader to a reader-writer lock. */
760 tl_assert(lk->kind == LK_rdwr);
761 /* lk must be free or already r-held. */
762 tl_assert(lk->heldBy == NULL
763 || (lk->heldBy != NULL && !lk->heldW));
764
765 stats__lockN_acquires++;
766
767 /* EXPOSITION only */
768 /* We need to keep recording snapshots of where the lock was
769 acquired, so as to produce better lock-order error messages. */
770 if (lk->acquired_at == NULL) {
771 ThreadId tid;
772 tl_assert(lk->heldBy == NULL);
773 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
774 lk->acquired_at
775 = VG_(record_ExeContext(tid, 0/*first_ip_delta*/));
776 } else {
777 tl_assert(lk->heldBy != NULL);
778 }
779 /* end EXPOSITION only */
780
781 if (lk->heldBy) {
782 HG_(addToBag)(lk->heldBy, (Word)thr);
783 } else {
784 lk->heldW = False;
785 lk->heldBy = HG_(newBag)( hg_zalloc, hg_free );
786 HG_(addToBag)( lk->heldBy, (Word)thr );
787 }
788 tl_assert(!lk->heldW);
789 tl_assert(is_sane_LockN(lk));
790}
791
792/* Update 'lk' to reflect a release of it by 'thr'. This is done
793 strictly: only combinations resulting from correct program and
794 libpthread behaviour are allowed. */
795
796static void lockN_release ( Lock* lk, Thread* thr )
797{
798 Bool b;
799 tl_assert(is_sane_LockN(lk));
800 tl_assert(is_sane_Thread(thr));
801 /* lock must be held by someone */
802 tl_assert(lk->heldBy);
803 stats__lockN_releases++;
804 /* Remove it from the holder set */
805 b = HG_(delFromBag)(lk->heldBy, (Word)thr);
806 /* thr must actually have been a holder of lk */
807 tl_assert(b);
808 /* normalise */
809 tl_assert(lk->acquired_at);
810 if (HG_(isEmptyBag)(lk->heldBy)) {
811 HG_(deleteBag)(lk->heldBy);
812 lk->heldBy = NULL;
813 lk->heldW = False;
814 lk->acquired_at = NULL;
815 }
816 tl_assert(is_sane_LockN(lk));
817}
818
819static void remove_Lock_from_locksets_of_all_owning_Threads( Lock* lk )
820{
821 Thread* thr;
822 if (!lk->heldBy) {
823 tl_assert(!lk->heldW);
824 return;
825 }
826 /* for each thread that holds this lock do ... */
827 HG_(initIterBag)( lk->heldBy );
828 while (HG_(nextIterBag)( lk->heldBy, (Word*)(void*)&thr, NULL )) {
829 tl_assert(is_sane_Thread(thr));
830 tl_assert(HG_(elemWS)( univ_lsets,
831 thr->locksetA, (Word)lk ));
832 thr->locksetA
833 = HG_(delFromWS)( univ_lsets, thr->locksetA, (Word)lk );
834
835 if (lk->heldW) {
836 tl_assert(HG_(elemWS)( univ_lsets,
837 thr->locksetW, (Word)lk ));
838 thr->locksetW
839 = HG_(delFromWS)( univ_lsets, thr->locksetW, (Word)lk );
840 }
841 }
842 HG_(doneIterBag)( lk->heldBy );
843}
844
845/* --------- xxxID functions --------- */
846
847/* Proposal (for debugging sanity):
848
849 SegmentIDs from 0x1000000 .. 0x1FFFFFF (16777216)
850
851 All other xxxID handles are invalid.
852*/
853static inline Bool is_sane_SegmentID ( SegmentID tseg ) {
854 return tseg >= 0x1000000 && tseg <= 0x1FFFFFF;
855}
856static inline Bool is_sane_ThreadId ( ThreadId coretid ) {
857 return coretid >= 0 && coretid < VG_N_THREADS;
858}
859static SegmentID alloc_SegmentID ( void ) {
860 static SegmentID next = 0x1000000;
861 tl_assert(is_sane_SegmentID(next));
862 return next++;
863}
864
865/* --------- Shadow memory --------- */
866
867static inline Bool is_valid_scache_tag ( Addr tag ) {
868 /* a valid tag should be naturally aligned to the start of
869 a CacheLine. */
870 return 0 == (tag & (N_LINE_ARANGE - 1));
871}
872
873static inline Bool is_sane_SecMap ( SecMap* sm ) {
874 return sm != NULL && sm->magic == SecMap_MAGIC;
875}
876
877/* Shadow value encodings:
878
879 11 WordSetID:TSID_BITS WordSetID:LSID_BITS ShM thread-set lock-set
880 10 WordSetID:TSID_BITS WordSetID:LSID_BITS ShR thread-set lock-set
881 01 TSegmentID:30 Excl thread-segment
882 00 0--(20)--0 10 0000 0000 New
883 00 0--(20)--0 01 0000 0000 NoAccess
884 00 0--(20)--0 00 0000 0000 Invalid
885
886 TSID_BITS + LSID_BITS must equal 30.
887 The elements in thread sets are Thread*, casted to Word.
888 The elements in lock sets are Lock*, casted to Word.
889*/
890
891#define N_LSID_BITS 17
892#define N_LSID_MASK ((1 << (N_LSID_BITS)) - 1)
893#define N_LSID_SHIFT 0
894
895#define N_TSID_BITS (30 - (N_LSID_BITS))
896#define N_TSID_MASK ((1 << (N_TSID_BITS)) - 1)
897#define N_TSID_SHIFT (N_LSID_BITS)
898
899static inline Bool is_sane_WordSetID_LSet ( WordSetID wset ) {
900 return wset >= 0 && wset <= N_LSID_MASK;
901}
902static inline Bool is_sane_WordSetID_TSet ( WordSetID wset ) {
903 return wset >= 0 && wset <= N_TSID_MASK;
904}
905
906
907__attribute__((noinline))
908__attribute__((noreturn))
909static void mk_SHVAL_fail ( WordSetID tset, WordSetID lset, HChar* who ) {
910 VG_(printf)("\n");
911 VG_(printf)("Helgrind: Fatal internal error -- cannot continue.\n");
912 VG_(printf)("Helgrind: mk_SHVAL_ShR(tset=%d,lset=%d): FAILED\n",
913 (Int)tset, (Int)lset);
914 VG_(printf)("Helgrind: max allowed tset=%d, lset=%d\n",
915 (Int)N_TSID_MASK, (Int)N_LSID_MASK);
916 VG_(printf)("Helgrind: program has too many thread "
917 "sets or lock sets to track.\n");
918 tl_assert(0);
919}
920
921static inline UInt mk_SHVAL_ShM ( WordSetID tset, WordSetID lset ) {
922 if (LIKELY(is_sane_WordSetID_TSet(tset)
923 && is_sane_WordSetID_LSet(lset))) {
924 return (UInt)( (3<<30) | (tset << N_TSID_SHIFT)
925 | (lset << N_LSID_SHIFT));
926 } else {
927 mk_SHVAL_fail(tset, lset, "mk_SHVAL_ShM");
928 }
929}
930static inline UInt mk_SHVAL_ShR ( WordSetID tset, WordSetID lset ) {
931 if (LIKELY(is_sane_WordSetID_TSet(tset)
932 && is_sane_WordSetID_LSet(lset))) {
933 return (UInt)( (2<<30) | (tset << N_TSID_SHIFT)
934 | (lset << N_LSID_SHIFT) );
935 } else {
936 mk_SHVAL_fail(tset, lset, "mk_SHVAL_ShR");
937 }
938}
939static inline UInt mk_SHVAL_Excl ( SegmentID tseg ) {
940 tl_assert(is_sane_SegmentID(tseg));
941 return (UInt)( (1<<30) | tseg );
942}
943#define SHVAL_New ((UInt)(2<<8))
944#define SHVAL_NoAccess ((UInt)(1<<8))
945#define SHVAL_Invalid ((UInt)(0<<8))
946
947static inline Bool is_SHVAL_ShM ( UInt w32 ) {
948 return (w32 >> 30) == 3;
949}
950static inline Bool is_SHVAL_ShR ( UInt w32 ) {
951 return (w32 >> 30) == 2;
952}
953static inline Bool is_SHVAL_Sh ( UInt w32 ) {
954 return (w32 >> 31) == 1;
955}
956static inline Bool is_SHVAL_Excl ( UInt w32 ) {
957 return (w32 >> 30) == 1;
958}
959static inline Bool is_SHVAL_New ( UInt w32 ) {
960 return w32 == SHVAL_New;
961}
962static inline Bool is_SHVAL_NoAccess ( UInt w32 ) {
963 return w32 == SHVAL_NoAccess;
964}
965static inline Bool is_SHVAL_valid ( UInt w32 ) {
966 return is_SHVAL_Excl(w32) || is_SHVAL_NoAccess(w32)
967 || is_SHVAL_Sh(w32) || is_SHVAL_New(w32);
968}
969
970static inline SegmentID un_SHVAL_Excl ( UInt w32 ) {
971 tl_assert(is_SHVAL_Excl(w32));
972 return w32 & ~(3<<30);
973}
974static inline WordSetID un_SHVAL_ShR_tset ( UInt w32 ) {
975 tl_assert(is_SHVAL_ShR(w32));
976 return (w32 >> N_TSID_SHIFT) & N_TSID_MASK;
977}
978static inline WordSetID un_SHVAL_ShR_lset ( UInt w32 ) {
979 tl_assert(is_SHVAL_ShR(w32));
980 return (w32 >> N_LSID_SHIFT) & N_LSID_MASK;
981}
982static inline WordSetID un_SHVAL_ShM_tset ( UInt w32 ) {
983 tl_assert(is_SHVAL_ShM(w32));
984 return (w32 >> N_TSID_SHIFT) & N_TSID_MASK;
985}
986static inline WordSetID un_SHVAL_ShM_lset ( UInt w32 ) {
987 tl_assert(is_SHVAL_ShM(w32));
988 return (w32 >> N_LSID_SHIFT) & N_LSID_MASK;
989}
990static inline WordSetID un_SHVAL_Sh_tset ( UInt w32 ) {
991 tl_assert(is_SHVAL_Sh(w32));
992 return (w32 >> N_TSID_SHIFT) & N_TSID_MASK;
993}
994static inline WordSetID un_SHVAL_Sh_lset ( UInt w32 ) {
995 tl_assert(is_SHVAL_Sh(w32));
996 return (w32 >> N_LSID_SHIFT) & N_LSID_MASK;
997}
998
999
1000/*----------------------------------------------------------------*/
1001/*--- Print out the primary data structures ---*/
1002/*----------------------------------------------------------------*/
1003
1004static WordSetID del_BHL ( WordSetID lockset ); /* fwds */
1005static
1006void get_ZF_by_index ( /*OUT*/CacheLineZ** zp, /*OUT*/CacheLineF** fp,
1007 SecMap* sm, Int zix ); /* fwds */
1008static
1009Segment* map_segments_maybe_lookup ( SegmentID segid ); /* fwds */
1010
1011#define PP_THREADS (1<<1)
1012#define PP_LOCKS (1<<2)
1013#define PP_SEGMENTS (1<<3)
1014#define PP_SHMEM_SHARED (1<<4)
1015#define PP_ALL (PP_THREADS | PP_LOCKS | PP_SEGMENTS | PP_SHMEM_SHARED)
1016
1017
1018static const Int sHOW_ADMIN = 0;
1019
1020static void space ( Int n )
1021{
1022 Int i;
1023 Char spaces[128+1];
1024 tl_assert(n >= 0 && n < 128);
1025 if (n == 0)
1026 return;
1027 for (i = 0; i < n; i++)
1028 spaces[i] = ' ';
1029 spaces[i] = 0;
1030 tl_assert(i < 128+1);
1031 VG_(printf)("%s", spaces);
1032}
1033
1034static void pp_Thread ( Int d, Thread* t )
1035{
1036 space(d+0); VG_(printf)("Thread %p {\n", t);
1037 if (sHOW_ADMIN) {
1038 space(d+3); VG_(printf)("admin %p\n", t->admin);
1039 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)t->magic);
1040 }
1041 space(d+3); VG_(printf)("locksetA %d\n", (Int)t->locksetA);
1042 space(d+3); VG_(printf)("locksetW %d\n", (Int)t->locksetW);
1043 space(d+3); VG_(printf)("csegid 0x%x\n", (UInt)t->csegid);
1044 space(d+0); VG_(printf)("}\n");
1045}
1046
1047static void pp_admin_threads ( Int d )
1048{
1049 Int i, n;
1050 Thread* t;
1051 for (n = 0, t = admin_threads; t; n++, t = t->admin) {
1052 /* nothing */
1053 }
1054 space(d); VG_(printf)("admin_threads (%d records) {\n", n);
1055 for (i = 0, t = admin_threads; t; i++, t = t->admin) {
1056 if (0) {
1057 space(n);
1058 VG_(printf)("admin_threads record %d of %d:\n", i, n);
1059 }
1060 pp_Thread(d+3, t);
1061 }
1062 space(d); VG_(printf)("}\n", n);
1063}
1064
1065static void pp_map_threads ( Int d )
1066{
1067 Int i, n;
1068 n = 0;
1069 space(d); VG_(printf)("map_threads ");
1070 n = 0;
1071 for (i = 0; i < VG_N_THREADS; i++) {
1072 if (map_threads[i] != NULL)
1073 n++;
1074 }
1075 VG_(printf)("(%d entries) {\n", n);
1076 for (i = 0; i < VG_N_THREADS; i++) {
1077 if (map_threads[i] == NULL)
1078 continue;
1079 space(d+3);
1080 VG_(printf)("coretid %d -> Thread %p\n", i, map_threads[i]);
1081 }
1082 space(d); VG_(printf)("}\n");
1083}
1084
1085static const HChar* show_LockKind ( LockKind lkk ) {
1086 switch (lkk) {
1087 case LK_mbRec: return "mbRec";
1088 case LK_nonRec: return "nonRec";
1089 case LK_rdwr: return "rdwr";
1090 default: tl_assert(0);
1091 }
1092}
1093
1094static void pp_Lock ( Int d, Lock* lk )
1095{
1096 space(d+0); VG_(printf)("Lock %p (ga %p) {\n", lk, lk->guestaddr);
1097 if (sHOW_ADMIN) {
1098 space(d+3); VG_(printf)("admin %p\n", lk->admin);
1099 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)lk->magic);
1100 }
1101 space(d+3); VG_(printf)("unique %llu\n", lk->unique);
1102 space(d+3); VG_(printf)("kind %s\n", show_LockKind(lk->kind));
1103 space(d+3); VG_(printf)("heldW %s\n", lk->heldW ? "yes" : "no");
1104 space(d+3); VG_(printf)("heldBy %p", lk->heldBy);
1105 if (lk->heldBy) {
1106 Thread* thr;
1107 Word count;
1108 VG_(printf)(" { ");
1109 HG_(initIterBag)( lk->heldBy );
1110 while (HG_(nextIterBag)( lk->heldBy, (Word*)(void*)&thr, &count ))
1111 VG_(printf)("%lu:%p ", count, thr);
1112 HG_(doneIterBag)( lk->heldBy );
1113 VG_(printf)("}");
1114 }
1115 VG_(printf)("\n");
1116 space(d+0); VG_(printf)("}\n");
1117}
1118
1119static void pp_admin_locks ( Int d )
1120{
1121 Int i, n;
1122 Lock* lk;
1123 for (n = 0, lk = admin_locks; lk; n++, lk = lk->admin) {
1124 /* nothing */
1125 }
1126 space(d); VG_(printf)("admin_locks (%d records) {\n", n);
1127 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin) {
1128 if (0) {
1129 space(n);
1130 VG_(printf)("admin_locks record %d of %d:\n", i, n);
1131 }
1132 pp_Lock(d+3, lk);
1133 }
1134 space(d); VG_(printf)("}\n", n);
1135}
1136
1137static void pp_map_locks ( Int d )
1138{
1139 void* gla;
1140 Lock* lk;
1141 space(d); VG_(printf)("map_locks (%d entries) {\n",
1142 (Int)HG_(sizeFM)( map_locks ));
1143 HG_(initIterFM)( map_locks );
1144 while (HG_(nextIterFM)( map_locks, (Word*)(void*)&gla,
1145 (Word*)(void*)&lk )) {
1146 space(d+3);
1147 VG_(printf)("guest %p -> Lock %p\n", gla, lk);
1148 }
1149 HG_(doneIterFM)( map_locks );
1150 space(d); VG_(printf)("}\n");
1151}
1152
1153static void pp_Segment ( Int d, Segment* s )
1154{
1155 space(d+0); VG_(printf)("Segment %p {\n", s);
1156 if (sHOW_ADMIN) {
1157 space(d+3); VG_(printf)("admin %p\n", s->admin);
1158 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)s->magic);
1159 }
1160 space(d+3); VG_(printf)("dfsver %u\n", s->dfsver);
1161 space(d+3); VG_(printf)("thr %p\n", s->thr);
1162 space(d+3); VG_(printf)("prev %p\n", s->prev);
1163 space(d+3); VG_(printf)("other[%c] %p\n", s->other_hint, s->other);
1164 space(d+0); VG_(printf)("}\n");
1165}
1166
1167static void pp_admin_segments ( Int d )
1168{
1169 Int i, n;
1170 Segment* s;
1171 for (n = 0, s = admin_segments; s; n++, s = s->admin) {
1172 /* nothing */
1173 }
1174 space(d); VG_(printf)("admin_segments (%d records) {\n", n);
1175 for (i = 0, s = admin_segments; s; i++, s = s->admin) {
1176 if (0) {
1177 space(n);
1178 VG_(printf)("admin_segments record %d of %d:\n", i, n);
1179 }
1180 pp_Segment(d+3, s);
1181 }
1182 space(d); VG_(printf)("}\n", n);
1183}
1184
1185static void pp_map_segments ( Int d )
1186{
1187 SegmentID segid;
1188 Segment* seg;
1189 space(d); VG_(printf)("map_segments (%d entries) {\n",
1190 (Int)HG_(sizeFM)( map_segments ));
1191 HG_(initIterFM)( map_segments );
1192 while (HG_(nextIterFM)( map_segments, (Word*)(void*)&segid,
1193 (Word*)(void*)&seg )) {
1194 space(d+3);
1195 VG_(printf)("segid 0x%x -> Segment %p\n", (UInt)segid, seg);
1196 }
1197 HG_(doneIterFM)( map_segments );
1198 space(d); VG_(printf)("}\n");
1199}
1200
1201static void show_shadow_w32 ( /*OUT*/Char* buf, Int nBuf, UInt w32 )
1202{
1203 tl_assert(nBuf-1 >= 99);
1204 VG_(memset)(buf, 0, nBuf);
1205 if (is_SHVAL_ShM(w32)) {
1206 VG_(sprintf)(buf, "ShM(%u,%u)",
1207 un_SHVAL_ShM_tset(w32), un_SHVAL_ShM_lset(w32));
1208 }
1209 else
1210 if (is_SHVAL_ShR(w32)) {
1211 VG_(sprintf)(buf, "ShR(%u,%u)",
1212 un_SHVAL_ShR_tset(w32), un_SHVAL_ShR_lset(w32));
1213 }
1214 else
1215 if (is_SHVAL_Excl(w32)) {
1216 VG_(sprintf)(buf, "Excl(%u)", un_SHVAL_Excl(w32));
1217 }
1218 else
1219 if (is_SHVAL_New(w32)) {
1220 VG_(sprintf)(buf, "%s", "New");
1221 }
1222 else
1223 if (is_SHVAL_NoAccess(w32)) {
1224 VG_(sprintf)(buf, "%s", "NoAccess");
1225 }
1226 else {
1227 VG_(sprintf)(buf, "Invalid-shadow-word(%u)", w32);
1228 }
1229}
1230
1231static
1232void show_shadow_w32_for_user ( /*OUT*/Char* buf, Int nBuf, UInt w32 )
1233{
1234 tl_assert(nBuf-1 >= 99);
1235 VG_(memset)(buf, 0, nBuf);
1236 if (is_SHVAL_ShM(w32)) {
1237 WordSetID tset = un_SHVAL_ShM_tset(w32);
1238 WordSetID lset = del_BHL( un_SHVAL_ShM_lset(w32) );
1239 VG_(sprintf)(buf, "ShMod(#Tset=%d,#Lset=%d)",
1240 HG_(cardinalityWS)(univ_tsets, tset),
1241 HG_(cardinalityWS)(univ_lsets, lset));
1242 }
1243 else
1244 if (is_SHVAL_ShR(w32)) {
1245 WordSetID tset = un_SHVAL_ShR_tset(w32);
1246 WordSetID lset = del_BHL( un_SHVAL_ShR_lset(w32) );
1247 VG_(sprintf)(buf, "ShRO(#Tset=%d,#Lset=%d)",
1248 HG_(cardinalityWS)(univ_tsets, tset),
1249 HG_(cardinalityWS)(univ_lsets, lset));
1250 }
1251 else
1252 if (is_SHVAL_Excl(w32)) {
1253 SegmentID segid = un_SHVAL_Excl(w32);
1254 Segment* mb_seg = map_segments_maybe_lookup(segid);
1255 if (mb_seg && mb_seg->thr && is_sane_Thread(mb_seg->thr)) {
1256 VG_(sprintf)(buf, "Exclusive(thr#%d)", mb_seg->thr->errmsg_index);
1257 } else {
1258 VG_(sprintf)(buf, "Exclusive(segid=%u)", un_SHVAL_Excl(w32));
1259 }
1260 }
1261 else
1262 if (is_SHVAL_New(w32)) {
1263 VG_(sprintf)(buf, "%s", "New");
1264 }
1265 else
1266 if (is_SHVAL_NoAccess(w32)) {
1267 VG_(sprintf)(buf, "%s", "NoAccess");
1268 }
1269 else {
1270 VG_(sprintf)(buf, "Invalid-shadow-word(%u)", w32);
1271 }
1272}
1273
1274static void pp_SecMap_shared ( Int d, SecMap* sm, Addr ga )
1275{
1276 Int i;
1277#if 0
1278 Addr a;
1279 UInt w32;
1280 Char buf[100];
1281#endif
1282 CacheLineZ* lineZ;
1283 CacheLineF* lineF;
1284 space(d+0); VG_(printf)("SecMap %p (ga %p) {\n", sm, (void*)ga);
1285
1286 for (i = 0; i < N_SECMAP_ZLINES; i++) {
1287 get_ZF_by_index( &lineZ, &lineF, sm, i );
1288 space(d+3); VG_(printf)("// pp_SecMap_shared: not implemented\n");
1289 }
1290
1291#if 0
1292 for (i = 0; i < N_SECMAP_ARANGE; i++) {
1293 w32 = sm->w32s[i];
1294 a = ga + 1 * i;
1295 if (! (is_SHVAL_ShM(w32) || is_SHVAL_ShR(w32)))
1296 continue;
1297 space(d+3); VG_(printf)("%p -> 0x%08x ", (void*)a, w32);
1298 show_shadow_w32(buf, sizeof(buf), w32);
1299 VG_(printf)("%s\n", buf);
1300 }
1301#endif
1302
1303 space(d+0); VG_(printf)("}\n");
1304}
1305
1306static void pp_map_shmem_shared ( Int d )
1307{
1308 Addr ga;
1309 SecMap* sm;
1310 space(d); VG_(printf)("map_shmem_ShR_and_ShM_only {\n");
1311 HG_(initIterFM)( map_shmem );
1312 while (HG_(nextIterFM)( map_shmem, (Word*)(void*)&ga,
1313 (Word*)(void*)&sm )) {
1314 pp_SecMap_shared( d+3, sm, ga );
1315 }
1316 HG_(doneIterFM) ( map_shmem );
1317 space(d); VG_(printf)("}\n");
1318}
1319
1320static void pp_everything ( Int flags, Char* caller )
1321{
1322 Int d = 0;
1323 VG_(printf)("\n");
1324 VG_(printf)("All_Data_Structures (caller = \"%s\") {\n", caller);
1325 if (flags & PP_THREADS) {
1326 VG_(printf)("\n");
1327 pp_admin_threads(d+3);
1328 VG_(printf)("\n");
1329 pp_map_threads(d+3);
1330 }
1331 if (flags & PP_LOCKS) {
1332 VG_(printf)("\n");
1333 pp_admin_locks(d+3);
1334 VG_(printf)("\n");
1335 pp_map_locks(d+3);
1336 }
1337 if (flags & PP_SEGMENTS) {
1338 VG_(printf)("\n");
1339 pp_admin_segments(d+3);
1340 VG_(printf)("\n");
1341 pp_map_segments(d+3);
1342 }
1343 if (flags & PP_SHMEM_SHARED) {
1344 VG_(printf)("\n");
1345 pp_map_shmem_shared( d+3 );
1346 }
1347
1348 VG_(printf)("\n");
1349 VG_(printf)("}\n");
1350 VG_(printf)("\n");
1351}
1352
1353#undef SHOW_ADMIN
1354
1355
1356/*----------------------------------------------------------------*/
1357/*--- Initialise the primary data structures ---*/
1358/*----------------------------------------------------------------*/
1359
1360/* fwds */
1361static void map_segments_add ( SegmentID segid, Segment* seg );
1362static void shmem__invalidate_scache ( void );
1363static void hbefore__invalidate_cache ( void );
1364static void shmem__set_mbHasLocks ( Addr a, Bool b );
1365static Bool shmem__get_mbHasLocks ( Addr a );
1366static void shadow_mem_set8 ( Thread* uu_thr_acc, Addr a, UInt svNew );
1367static XArray* singleton_VTS ( Thread* thr, UWord tym );
1368
1369static void initialise_data_structures ( void )
1370{
1371 SegmentID segid;
1372 Segment* seg;
1373 Thread* thr;
1374
1375 /* Get everything initialised and zeroed. */
1376 tl_assert(admin_threads == NULL);
1377 tl_assert(admin_locks == NULL);
1378 tl_assert(admin_segments == NULL);
1379
1380 tl_assert(sizeof(Addr) == sizeof(Word));
1381 tl_assert(map_shmem == NULL);
1382 map_shmem = HG_(newFM)( hg_zalloc, hg_free, NULL/*unboxed Word cmp*/);
1383 tl_assert(map_shmem != NULL);
1384 shmem__invalidate_scache();
1385
1386 tl_assert(map_threads == NULL);
1387 map_threads = hg_zalloc( VG_N_THREADS * sizeof(Thread*) );
1388 tl_assert(map_threads != NULL);
1389
1390 /* re <=: < on 64-bit platforms, == on 32-bit ones */
1391 tl_assert(sizeof(SegmentID) <= sizeof(Word));
1392 tl_assert(sizeof(Segment*) == sizeof(Word));
1393 tl_assert(map_segments == NULL);
1394 map_segments = HG_(newFM)( hg_zalloc, hg_free, NULL/*unboxed Word cmp*/);
1395 tl_assert(map_segments != NULL);
1396 hbefore__invalidate_cache();
1397
1398 tl_assert(sizeof(Addr) == sizeof(Word));
1399 tl_assert(map_locks == NULL);
1400 map_locks = HG_(newFM)( hg_zalloc, hg_free, NULL/*unboxed Word cmp*/);
1401 tl_assert(map_locks != NULL);
1402
1403 __bus_lock_Lock = mk_LockN( LK_nonRec, (Addr)&__bus_lock );
1404 tl_assert(is_sane_LockN(__bus_lock_Lock));
1405 HG_(addToFM)( map_locks, (Word)&__bus_lock, (Word)__bus_lock_Lock );
1406
1407 tl_assert(univ_tsets == NULL);
1408 univ_tsets = HG_(newWordSetU)( hg_zalloc, hg_free, 8/*cacheSize*/ );
1409 tl_assert(univ_tsets != NULL);
1410
1411 tl_assert(univ_lsets == NULL);
1412 univ_lsets = HG_(newWordSetU)( hg_zalloc, hg_free, 8/*cacheSize*/ );
1413 tl_assert(univ_lsets != NULL);
1414
1415 tl_assert(univ_laog == NULL);
1416 univ_laog = HG_(newWordSetU)( hg_zalloc, hg_free, 24/*cacheSize*/ );
1417 tl_assert(univ_laog != NULL);
1418
1419 /* Set up entries for the root thread */
1420 // FIXME: this assumes that the first real ThreadId is 1
1421
1422 /* a segment for the new thread ... */
1423 // FIXME: code duplication in ev__post_thread_create
1424 segid = alloc_SegmentID();
1425 seg = mk_Segment( NULL, NULL, NULL );
1426 map_segments_add( segid, seg );
1427
1428 /* a Thread for the new thread ... */
1429 thr = mk_Thread( segid );
1430 seg->thr = thr;
1431
1432 /* Give the thread a starting-off vector timestamp. */
1433 seg->vts = singleton_VTS( seg->thr, 1 );
1434
1435 /* and bind it in the thread-map table.
1436 FIXME: assumes root ThreadId == 1. */
1437 map_threads[1] = thr;
1438
1439 tl_assert(VG_INVALID_THREADID == 0);
1440
1441 /* Mark the new bus lock correctly (to stop the sanity checks
1442 complaining) */
1443 tl_assert( sizeof(__bus_lock) == 4 );
1444 shadow_mem_set8( NULL/*unused*/, __bus_lock_Lock->guestaddr,
1445 mk_SHVAL_Excl(segid) );
1446 shmem__set_mbHasLocks( __bus_lock_Lock->guestaddr, True );
1447
1448 all__sanity_check("initialise_data_structures");
1449}
1450
1451
1452/*----------------------------------------------------------------*/
1453/*--- map_threads :: WordFM core-ThreadId Thread* ---*/
1454/*----------------------------------------------------------------*/
1455
1456/* Doesn't assert if the relevant map_threads entry is NULL. */
1457static Thread* map_threads_maybe_lookup ( ThreadId coretid )
1458{
1459 Thread* thr;
1460 tl_assert( is_sane_ThreadId(coretid) );
1461 thr = map_threads[coretid];
1462 return thr;
1463}
1464
1465/* Asserts if the relevant map_threads entry is NULL. */
1466static inline Thread* map_threads_lookup ( ThreadId coretid )
1467{
1468 Thread* thr;
1469 tl_assert( is_sane_ThreadId(coretid) );
1470 thr = map_threads[coretid];
1471 tl_assert(thr);
1472 return thr;
1473}
1474
1475/* Do a reverse lookup. Warning: POTENTIALLY SLOW. Does not assert
1476 if 'thr' is not found in map_threads. */
1477static ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr )
1478{
1479 Int i;
1480 tl_assert(is_sane_Thread(thr));
1481 /* Check nobody used the invalid-threadid slot */
1482 tl_assert(VG_INVALID_THREADID >= 0 && VG_INVALID_THREADID < VG_N_THREADS);
1483 tl_assert(map_threads[VG_INVALID_THREADID] == NULL);
1484 for (i = 0; i < VG_N_THREADS; i++) {
1485 if (i != VG_INVALID_THREADID && map_threads[i] == thr)
1486 return (ThreadId)i;
1487 }
1488 return VG_INVALID_THREADID;
1489}
1490
1491/* Do a reverse lookup. Warning: POTENTIALLY SLOW. Asserts if 'thr'
1492 is not found in map_threads. */
1493static ThreadId map_threads_reverse_lookup_SLOW ( Thread* thr )
1494{
1495 ThreadId tid = map_threads_maybe_reverse_lookup_SLOW( thr );
1496 tl_assert(tid != VG_INVALID_THREADID);
1497 return tid;
1498}
1499
1500static void map_threads_delete ( ThreadId coretid )
1501{
1502 Thread* thr;
1503 tl_assert(coretid != 0);
1504 tl_assert( is_sane_ThreadId(coretid) );
1505 thr = map_threads[coretid];
1506 tl_assert(thr);
1507 map_threads[coretid] = NULL;
1508}
1509
1510
1511/*----------------------------------------------------------------*/
1512/*--- map_locks :: WordFM guest-Addr-of-lock Lock* ---*/
1513/*----------------------------------------------------------------*/
1514
1515/* Make sure there is a lock table entry for the given (lock) guest
1516 address. If not, create one of the stated 'kind' in unheld state.
1517 In any case, return the address of the existing or new Lock. */
1518static
1519Lock* map_locks_lookup_or_create ( LockKind lkk, Addr ga, ThreadId tid )
1520{
1521 Bool found;
1522 Lock* oldlock = NULL;
1523 tl_assert(is_sane_ThreadId(tid));
1524 found = HG_(lookupFM)( map_locks,
1525 NULL, (Word*)(void*)&oldlock, (Word)ga );
1526 if (!found) {
1527 Lock* lock = mk_LockN(lkk, ga);
1528 lock->appeared_at = VG_(record_ExeContext)( tid, 0 );
1529 tl_assert(is_sane_LockN(lock));
1530 HG_(addToFM)( map_locks, (Word)ga, (Word)lock );
1531 tl_assert(oldlock == NULL);
1532 // mark the relevant secondary map has .mbHasLocks
1533 shmem__set_mbHasLocks( ga, True );
1534 return lock;
1535 } else {
1536 tl_assert(oldlock != NULL);
1537 tl_assert(is_sane_LockN(oldlock));
1538 tl_assert(oldlock->guestaddr == ga);
1539 // check the relevant secondary map has .mbHasLocks?
1540 tl_assert(shmem__get_mbHasLocks(ga) == True);
1541 return oldlock;
1542 }
1543}
1544
1545static Lock* map_locks_maybe_lookup ( Addr ga )
1546{
1547 Bool found;
1548 Lock* lk = NULL;
1549 found = HG_(lookupFM)( map_locks, NULL, (Word*)(void*)&lk, (Word)ga );
1550 tl_assert(found ? lk != NULL : lk == NULL);
1551 if (found) {
1552 // check the relevant secondary map has .mbHasLocks?
1553 tl_assert(shmem__get_mbHasLocks(ga) == True);
1554 }
1555 return lk;
1556}
1557
1558static void map_locks_delete ( Addr ga )
1559{
1560 Addr ga2 = 0;
1561 Lock* lk = NULL;
1562 HG_(delFromFM)( map_locks,
1563 (Word*)(void*)&ga2, (Word*)(void*)&lk, (Word)ga );
1564 /* delFromFM produces the val which is being deleted, if it is
1565 found. So assert it is non-null; that in effect asserts that we
1566 are deleting a (ga, Lock) pair which actually exists. */
1567 tl_assert(lk != NULL);
1568 tl_assert(ga2 == ga);
1569}
1570
1571
1572/*----------------------------------------------------------------*/
1573/*--- map_segments :: WordFM SegmentID Segment* ---*/
1574/*--- the DAG of thread segments ---*/
1575/*----------------------------------------------------------------*/
1576
1577static void segments__generate_vcg ( void ); /* fwds */
1578
1579/*--------------- SegmentID to Segment* maps ---------------*/
1580
1581static Segment* map_segments_lookup ( SegmentID segid )
1582{
1583 Bool found;
1584 Segment* seg = NULL;
1585 tl_assert( is_sane_SegmentID(segid) );
1586 found = HG_(lookupFM)( map_segments,
1587 NULL, (Word*)(void*)&seg, (Word)segid );
1588 tl_assert(found);
1589 tl_assert(seg != NULL);
1590 return seg;
1591}
1592
1593static Segment* map_segments_maybe_lookup ( SegmentID segid )
1594{
1595 Bool found;
1596 Segment* seg = NULL;
1597 tl_assert( is_sane_SegmentID(segid) );
1598 found = HG_(lookupFM)( map_segments,
1599 NULL, (Word*)(void*)&seg, (Word)segid );
1600 if (!found) tl_assert(seg == NULL);
1601 return seg;
1602}
1603
1604static void map_segments_add ( SegmentID segid, Segment* seg )
1605{
1606 /* This is a bit inefficient. Oh well. */
1607 tl_assert( !HG_(lookupFM)( map_segments, NULL, NULL, segid ));
1608 HG_(addToFM)( map_segments, (Word)segid, (Word)seg );
1609}
1610
1611/*--------------- to do with Vector Timestamps ---------------*/
1612
1613/* Scalar Timestamp */
1614typedef
1615 struct {
1616 Thread* thr;
1617 UWord tym;
1618 }
1619 ScalarTS;
1620
1621/* Vector Timestamp = XArray* ScalarTS */
1622
1623static Bool is_sane_VTS ( XArray* vts )
1624{
1625 UWord i, n;
1626 ScalarTS *st1, *st2;
1627 n = VG_(sizeXA)( vts );
1628 if (n >= 2) {
1629 for (i = 0; i < n-1; i++) {
1630 st1 = VG_(indexXA)( vts, i );
1631 st2 = VG_(indexXA)( vts, i+1 );
1632 if (st1->thr >= st2->thr)
1633 return False;
1634 if (st1->tym == 0 || st2->tym == 0)
1635 return False;
1636 }
1637 }
1638 return True;
1639}
1640
1641static XArray* new_VTS ( void ) {
1642 return VG_(newXA)( hg_zalloc, hg_free, sizeof(ScalarTS) );
1643}
1644static XArray* singleton_VTS ( Thread* thr, UWord tym ) {
1645 ScalarTS st;
1646 XArray* vts;
1647 tl_assert(thr);
1648 tl_assert(tym >= 1);
1649 vts = new_VTS();
1650 tl_assert(vts);
1651 st.thr = thr;
1652 st.tym = tym;
1653 VG_(addToXA)( vts, &st );
1654 return vts;
1655}
1656
1657
1658static Bool cmpGEQ_VTS ( XArray* a, XArray* b )
1659{
1660 Word ia, ib, useda, usedb;
1661 UWord tyma, tymb;
1662 Thread* thr;
1663 ScalarTS *tmpa, *tmpb;
1664
1665 Bool all_leq = True;
1666 Bool all_geq = True;
1667
1668 tl_assert(a);
1669 tl_assert(b);
1670 useda = VG_(sizeXA)( a );
1671 usedb = VG_(sizeXA)( b );
1672
1673 ia = ib = 0;
1674
1675 while (1) {
1676
1677 /* This logic is to enumerate triples (thr, tyma, tymb) drawn
1678 from a and b in order, where thr is the next Thread*
1679 occurring in either a or b, and tyma/b are the relevant
1680 scalar timestamps, taking into account implicit zeroes. */
1681 tl_assert(ia >= 0 && ia <= useda);
1682 tl_assert(ib >= 0 && ib <= usedb);
1683 tmpa = tmpb = NULL;
1684
1685 if (ia == useda && ib == usedb) {
1686 /* both empty - done */
1687 break;
1688 }
1689 else
1690 if (ia == useda && ib != usedb) {
1691 /* a empty, use up b */
1692 tmpb = VG_(indexXA)( b, ib );
1693 thr = tmpb->thr;
1694 tyma = 0;
1695 tymb = tmpb->tym;
1696 ib++;
1697 }
1698 else
1699 if (ia != useda && ib == usedb) {
1700 /* b empty, use up a */
1701 tmpa = VG_(indexXA)( a, ia );
1702 thr = tmpa->thr;
1703 tyma = tmpa->tym;
1704 tymb = 0;
1705 ia++;
1706 }
1707 else {
1708 /* both not empty; extract lowest-Thread*'d triple */
1709 tmpa = VG_(indexXA)( a, ia );
1710 tmpb = VG_(indexXA)( b, ib );
1711 if (tmpa->thr < tmpb->thr) {
1712 /* a has the lowest unconsidered Thread* */
1713 thr = tmpa->thr;
1714 tyma = tmpa->tym;
1715 tymb = 0;
1716 ia++;
1717 }
1718 else
1719 if (tmpa->thr > tmpb->thr) {
1720 /* b has the lowest unconsidered Thread* */
1721 thr = tmpb->thr;
1722 tyma = 0;
1723 tymb = tmpb->tym;
1724 ib++;
1725 } else {
1726 /* they both next mention the same Thread* */
1727 tl_assert(tmpa->thr == tmpb->thr);
1728 thr = tmpa->thr; /* == tmpb->thr */
1729 tyma = tmpa->tym;
1730 tymb = tmpb->tym;
1731 ia++;
1732 ib++;
1733 }
1734 }
1735
1736 /* having laboriously determined (thr, tyma, tymb), do something
1737 useful with it. */
1738 if (tyma < tymb)
1739 all_geq = False;
1740 if (tyma > tymb)
1741 all_leq = False;
1742 }
1743
1744 if (all_leq && all_geq)
1745 return True; /* PordEQ */
1746 /* now we know they aren't equal, so either all_leq or all_geq or
1747 both are false. */
1748 if (all_leq)
1749 return False; /* PordLT */
1750 if (all_geq)
1751 return True; /* PordGT */
1752 /* hmm, neither all_geq or all_leq. This means unordered. */
1753 return False; /* PordUN */
1754}
1755
1756
1757/* Compute max((tick(thra,a),b) into a new XArray. a and b are
1758 unchanged. If neither a nor b supply a value for 'thra',
1759 assert. */
1760static
1761XArray* tickL_and_joinR_VTS ( Thread* thra, XArray* a, XArray* b )
1762{
1763 Word ia, ib, useda, usedb, ticks_found;
1764 UWord tyma, tymb, tymMax;
1765 Thread* thr;
1766 XArray* res;
1767 ScalarTS *tmpa, *tmpb;
1768
1769 tl_assert(a);
1770 tl_assert(b);
1771 tl_assert(thra);
1772 useda = VG_(sizeXA)( a );
1773 usedb = VG_(sizeXA)( b );
1774
1775 res = new_VTS();
1776 ia = ib = ticks_found = 0;
1777
1778 while (1) {
1779
1780 /* This logic is to enumerate triples (thr, tyma, tymb) drawn
1781 from a and b in order, where thr is the next Thread*
1782 occurring in either a or b, and tyma/b are the relevant
1783 scalar timestamps, taking into account implicit zeroes. */
1784 tl_assert(ia >= 0 && ia <= useda);
1785 tl_assert(ib >= 0 && ib <= usedb);
1786 tmpa = tmpb = NULL;
1787
1788 if (ia == useda && ib == usedb) {
1789 /* both empty - done */
1790 break;
1791 }
1792 else
1793 if (ia == useda && ib != usedb) {
1794 /* a empty, use up b */
1795 tmpb = VG_(indexXA)( b, ib );
1796 thr = tmpb->thr;
1797 tyma = 0;
1798 tymb = tmpb->tym;
1799 ib++;
1800 }
1801 else
1802 if (ia != useda && ib == usedb) {
1803 /* b empty, use up a */
1804 tmpa = VG_(indexXA)( a, ia );
1805 thr = tmpa->thr;
1806 tyma = tmpa->tym;
1807 tymb = 0;
1808 ia++;
1809 }
1810 else {
1811 /* both not empty; extract lowest-Thread*'d triple */
1812 tmpa = VG_(indexXA)( a, ia );
1813 tmpb = VG_(indexXA)( b, ib );
1814 if (tmpa->thr < tmpb->thr) {
1815 /* a has the lowest unconsidered Thread* */
1816 thr = tmpa->thr;
1817 tyma = tmpa->tym;
1818 tymb = 0;
1819 ia++;
1820 }
1821 else
1822 if (tmpa->thr > tmpb->thr) {
1823 /* b has the lowest unconsidered Thread* */
1824 thr = tmpb->thr;
1825 tyma = 0;
1826 tymb = tmpb->tym;
1827 ib++;
1828 } else {
1829 /* they both next mention the same Thread* */
1830 tl_assert(tmpa->thr == tmpb->thr);
1831 thr = tmpa->thr; /* == tmpb->thr */
1832 tyma = tmpa->tym;
1833 tymb = tmpb->tym;
1834 ia++;
1835 ib++;
1836 }
1837 }
1838
1839 /* having laboriously determined (thr, tyma, tymb), do something
1840 useful with it. */
1841 if (thr == thra) {
1842 if (tyma > 0) {
1843 /* VTS 'a' actually supplied this value; it is not a
1844 default zero. Do the required 'tick' action. */
1845 tyma++;
1846 ticks_found++;
1847 } else {
1848 /* 'a' didn't supply this value, so 'b' must have. */
1849 tl_assert(tymb > 0);
1850 }
1851 }
1852 tymMax = tyma > tymb ? tyma : tymb;
1853 if (tymMax > 0) {
1854 ScalarTS st;
1855 st.thr = thr;
1856 st.tym = tymMax;
1857 VG_(addToXA)( res, &st );
1858 }
1859
1860 }
1861
1862 tl_assert(is_sane_VTS( res ));
1863
1864 if (thra != NULL) {
1865 tl_assert(ticks_found == 1);
1866 } else {
1867 tl_assert(ticks_found == 0);
1868 }
1869
1870 return res;
1871}
1872
1873
1874/* Do 'vts[me]++', so to speak. If 'me' does not have an entry in
1875 'vts', set it to 1 in the returned VTS. */
1876
1877static XArray* tick_VTS ( Thread* me, XArray* vts ) {
1878 ScalarTS* here = NULL;
1879 ScalarTS tmp;
1880 XArray* res;
1881 Word i, n;
1882 tl_assert(me);
1883 tl_assert(is_sane_VTS(vts));
1884 if (0) VG_(printf)("tick vts thrno %ld szin %d\n",
1885 (Word)me->errmsg_index, (Int)VG_(sizeXA)(vts) );
1886 res = new_VTS();
1887 n = VG_(sizeXA)( vts );
1888 for (i = 0; i < n; i++) {
1889 here = VG_(indexXA)( vts, i );
1890 if (me < here->thr) {
1891 /* We just went past 'me', without seeing it. */
1892 tmp.thr = me;
1893 tmp.tym = 1;
1894 VG_(addToXA)( res, &tmp );
1895 tmp = *here;
1896 VG_(addToXA)( res, &tmp );
1897 i++;
1898 break;
1899 }
1900 else if (me == here->thr) {
1901 tmp = *here;
1902 tmp.tym++;
1903 VG_(addToXA)( res, &tmp );
1904 i++;
1905 break;
1906 }
1907 else /* me > here->thr */ {
1908 tmp = *here;
1909 VG_(addToXA)( res, &tmp );
1910 }
1911 }
1912 tl_assert(i >= 0 && i <= n);
1913 if (i == n && here && here->thr < me) {
1914 tmp.thr = me;
1915 tmp.tym = 1;
1916 VG_(addToXA)( res, &tmp );
1917 } else {
1918 for (/*keepgoing*/; i < n; i++) {
1919 here = VG_(indexXA)( vts, i );
1920 tmp = *here;
1921 VG_(addToXA)( res, &tmp );
1922 }
1923 }
1924 tl_assert(is_sane_VTS(res));
1925 if (0) VG_(printf)("tick vts thrno %ld szou %d\n",
1926 (Word)me->errmsg_index, (Int)VG_(sizeXA)(res) );
1927 return res;
1928}
1929
1930static void show_VTS ( HChar* buf, Int nBuf, XArray* vts ) {
1931 ScalarTS* st;
1932 HChar unit[64];
1933 Word i, n;
1934 Int avail = nBuf;
1935 tl_assert(avail > 16);
1936 buf[0] = '[';
1937 buf[1] = 0;
1938 n = VG_(sizeXA)( vts );
1939 for (i = 0; i < n; i++) {
1940 tl_assert(avail >= 10);
1941 st = VG_(indexXA)( vts, i );
1942 VG_(memset)(unit, 0, sizeof(unit));
1943 VG_(sprintf)(unit, i < n-1 ? "%ld:%ld " : "%ld:%ld",
1944 (Word)st->thr->errmsg_index, st->tym);
1945 if (avail < VG_(strlen)(unit) + 10/*let's say*/) {
1946 VG_(strcat)(buf, " ...]");
1947 return;
1948 }
1949 VG_(strcat)(buf, unit);
1950 avail -= VG_(strlen)(unit);
1951 }
1952 VG_(strcat)(buf, "]");
1953}
1954
1955
1956/*------------ searching the happens-before graph ------------*/
1957
1958static UWord stats__hbefore_queries = 0; // total # queries
1959static UWord stats__hbefore_cache0s = 0; // hits at cache[0]
1960static UWord stats__hbefore_cacheNs = 0; // hits at cache[> 0]
1961static UWord stats__hbefore_probes = 0; // # checks in cache
1962static UWord stats__hbefore_gsearches = 0; // # searches in graph
1963static UWord stats__hbefore_gsearchFs = 0; // # fast searches in graph
1964static UWord stats__hbefore_invals = 0; // # cache invals
1965static UWord stats__hbefore_stk_hwm = 0; // stack high water mark
1966
1967/* Running marker for depth-first searches */
1968/* NOTE: global variable */
1969static UInt dfsver_current = 0;
1970
1971/* A stack of possibly-unexplored nodes used in the depth first search */
1972/* NOTE: global variable */
1973static XArray* dfsver_stack = NULL;
1974
1975// FIXME: check this - is it really correct?
1976__attribute__((noinline))
1977static Bool happens_before_do_dfs_from_to ( Segment* src, Segment* dst )
1978{
1979 Segment* here;
1980 Word ssz;
1981
1982 /* begin SPEEDUP HACK -- the following can safely be omitted */
1983 /* fast track common case, without favouring either the
1984 ->prev or ->other links */
1985 tl_assert(src);
1986 tl_assert(dst);
1987 if ((src->prev && src->prev == dst)
1988 || (src->other && src->other == dst)) {
1989 stats__hbefore_gsearchFs++;
1990 return True;
1991 }
1992 /* end SPEEDUP HACK */
1993
1994 /* empty out the stack */
1995 tl_assert(dfsver_stack);
1996 VG_(dropTailXA)( dfsver_stack, VG_(sizeXA)( dfsver_stack ));
1997 tl_assert(VG_(sizeXA)( dfsver_stack ) == 0);
1998
1999 /* push starting point */
2000 (void) VG_(addToXA)( dfsver_stack, &src );
2001
2002 while (True) {
2003 /* While the stack is not empty, pop the next node off it and
2004 consider. */
2005 ssz = VG_(sizeXA)( dfsver_stack );
2006 tl_assert(ssz >= 0);
2007 if (ssz == 0)
2008 return False; /* stack empty ==> no path from src to dst */
2009
2010 if (UNLIKELY( ((UWord)ssz) > stats__hbefore_stk_hwm ))
2011 stats__hbefore_stk_hwm = (UWord)ssz;
2012
2013 /* here = pop(stack) */
2014 here = *(Segment**) VG_(indexXA)( dfsver_stack, ssz-1 );
2015 VG_(dropTailXA)( dfsver_stack, 1 );
2016
2017 again:
2018 /* consider the node 'here' */
2019 if (here == dst)
2020 return True; /* found a path from src and dst */
2021
2022 /* have we been to 'here' before? */
2023 tl_assert(here->dfsver <= dfsver_current);
2024 if (here->dfsver == dfsver_current)
2025 continue; /* We've been 'here' before - node is not interesting*/
2026
2027 /* Mark that we've been here */
2028 here->dfsver = dfsver_current;
2029
2030 /* Now push both children on the stack */
2031
2032 /* begin SPEEDUP hack -- the following can safely be omitted */
2033 /* idea is, if there is exactly one child, avoid the overhead of
2034 pushing it on the stack and immediately popping it off again.
2035 Kinda like doing a tail-call. */
2036 if (here->prev && !here->other) {
2037 here = here->prev;
2038 goto again;
2039 }
2040 if (here->other && !here->prev) {
2041 here = here->other;
2042 goto again;
2043 }
2044 /* end of SPEEDUP HACK */
2045
2046 /* Push all available children on stack. From some quick
2047 experimentation it seems like exploring ->other first leads
2048 to lower maximum stack use, although getting repeatable
2049 results is difficult. */
2050 if (here->prev)
2051 (void) VG_(addToXA)( dfsver_stack, &(here->prev) );
2052 if (here->other)
2053 (void) VG_(addToXA)( dfsver_stack, &(here->other) );
2054 }
2055}
2056
2057__attribute__((noinline))
2058static Bool happens_before_wrk ( Segment* seg1, Segment* seg2 )
2059{
2060 Bool reachable;
2061
2062 { static Int nnn = 0;
2063 if (SHOW_EXPENSIVE_STUFF && (nnn++ % 1000) == 0)
2064 VG_(printf)("happens_before_wrk: %d\n", nnn);
2065 }
2066
2067 /* Now the question is, is there a chain of pointers through the
2068 .prev and .other fields, that leads from seg2 back to seg1 ? */
2069 tl_assert(dfsver_current < 0xFFFFFFFF);
2070 dfsver_current++;
2071
2072 if (dfsver_stack == NULL) {
2073 dfsver_stack = VG_(newXA)( hg_zalloc, hg_free, sizeof(Segment*) );
2074 tl_assert(dfsver_stack);
2075 }
2076
2077 reachable = happens_before_do_dfs_from_to( seg2, seg1 );
2078
2079 return reachable;
2080}
2081
2082/*--------------- the happens_before cache ---------------*/
2083
2084#define HBEFORE__N_CACHE 64
2085typedef
2086 struct { SegmentID segid1; SegmentID segid2; Bool result; }
2087 HBeforeCacheEnt;
2088
2089static HBeforeCacheEnt hbefore__cache[HBEFORE__N_CACHE];
2090
2091static void hbefore__invalidate_cache ( void )
2092{
2093 Int i;
2094 SegmentID bogus = 0;
2095 tl_assert(!is_sane_SegmentID(bogus));
2096 stats__hbefore_invals++;
2097 for (i = 0; i < HBEFORE__N_CACHE; i++) {
2098 hbefore__cache[i].segid1 = bogus;
2099 hbefore__cache[i].segid2 = bogus;
2100 hbefore__cache[i].result = False;
2101 }
2102}
2103
2104static Bool happens_before ( SegmentID segid1, SegmentID segid2 )
2105{
2106 Bool hbG, hbV;
2107 Int i, j, iNSERT_POINT;
2108 Segment *seg1, *seg2;
2109 tl_assert(is_sane_SegmentID(segid1));
2110 tl_assert(is_sane_SegmentID(segid2));
2111 tl_assert(segid1 != segid2);
2112 stats__hbefore_queries++;
2113 stats__hbefore_probes++;
2114 if (segid1 == hbefore__cache[0].segid1
2115 && segid2 == hbefore__cache[0].segid2) {
2116 stats__hbefore_cache0s++;
2117 return hbefore__cache[0].result;
2118 }
2119 for (i = 1; i < HBEFORE__N_CACHE; i++) {
2120 stats__hbefore_probes++;
2121 if (segid1 == hbefore__cache[i].segid1
2122 && segid2 == hbefore__cache[i].segid2) {
2123 /* Found it. Move it 1 step closer to the front. */
2124 HBeforeCacheEnt tmp = hbefore__cache[i];
2125 hbefore__cache[i] = hbefore__cache[i-1];
2126 hbefore__cache[i-1] = tmp;
2127 stats__hbefore_cacheNs++;
2128 return tmp.result;
2129 }
2130 }
2131 /* Not found. Search the graph and add an entry to the cache. */
2132 stats__hbefore_gsearches++;
2133
2134 seg1 = map_segments_lookup(segid1);
2135 seg2 = map_segments_lookup(segid2);
2136 tl_assert(is_sane_Segment(seg1));
2137 tl_assert(is_sane_Segment(seg2));
2138 tl_assert(seg1 != seg2);
2139 tl_assert(seg1->vts);
2140 tl_assert(seg2->vts);
2141
2142 hbV = cmpGEQ_VTS( seg2->vts, seg1->vts );
2143 if (0) {
2144 /* Crosscheck the vector-timestamp comparison result against that
2145 obtained from the explicit graph approach. Can be very
2146 slow. */
2147 hbG = happens_before_wrk( seg1, seg2 );
2148 } else {
2149 /* Assume the vector-timestamp comparison result is correct, and
2150 use it as-is. */
2151 hbG = hbV;
2152 }
2153
2154 if (hbV != hbG) {
2155 VG_(printf)("seg1 %p seg2 %p hbV %d hbG %d\n",
2156 seg1,seg2,(Int)hbV,(Int)hbG);
2157 segments__generate_vcg();
2158 }
2159 tl_assert(hbV == hbG);
2160
2161 iNSERT_POINT = (1*HBEFORE__N_CACHE)/4 - 1;
2162 /* if (iNSERT_POINT > 4) iNSERT_POINT = 4; */
2163
2164 for (j = HBEFORE__N_CACHE-1; j > iNSERT_POINT; j--) {
2165 hbefore__cache[j] = hbefore__cache[j-1];
2166 }
2167 hbefore__cache[iNSERT_POINT].segid1 = segid1;
2168 hbefore__cache[iNSERT_POINT].segid2 = segid2;
2169 hbefore__cache[iNSERT_POINT].result = hbG;
2170
2171 if (0)
2172 VG_(printf)("hb %d %d\n", (Int)segid1-(1<<24), (Int)segid2-(1<<24));
2173 return hbG;
2174}
2175
2176/*--------------- generating .vcg output ---------------*/
2177
2178static void segments__generate_vcg ( void )
2179{
2180#define PFX "xxxxxx"
2181 /* Edge colours:
2182 Black -- the chain of .prev links
2183 Green -- thread creation, link to parent
2184 Red -- thread exit, link to exiting thread
2185 Yellow -- signal edge
2186 Pink -- semaphore-up edge
2187 */
2188 Segment* seg;
2189 HChar vtsstr[128];
2190 VG_(printf)(PFX "graph: { title: \"Segments\"\n");
2191 VG_(printf)(PFX "orientation: top_to_bottom\n");
2192 VG_(printf)(PFX "height: 900\n");
2193 VG_(printf)(PFX "width: 500\n");
2194 VG_(printf)(PFX "x: 20\n");
2195 VG_(printf)(PFX "y: 20\n");
2196 VG_(printf)(PFX "color: lightgrey\n");
2197 for (seg = admin_segments; seg; seg=seg->admin) {
2198
2199 VG_(printf)(PFX "node: { title: \"%p\" color: lightcyan "
2200 "textcolor: darkgreen label: \"Seg %p\\n",
2201 seg, seg);
2202 if (seg->thr->errmsg_index == 1) {
2203 VG_(printf)("ROOT_THREAD");
2204 } else {
2205 VG_(printf)("Thr# %d", seg->thr->errmsg_index);
2206 }
2207
2208 if (clo_gen_vcg >= 2) {
2209 show_VTS( vtsstr, sizeof(vtsstr)-1, seg->vts );
2210 vtsstr[sizeof(vtsstr)-1] = 0;
2211 VG_(printf)("\\n%s", vtsstr);
2212 }
2213
2214 VG_(printf)("\" }\n", vtsstr);
2215
2216 if (seg->prev)
2217 VG_(printf)(PFX "edge: { sourcename: \"%p\" targetname: \"%p\""
2218 "color: black }\n", seg->prev, seg );
2219 if (seg->other) {
2220 HChar* colour = "orange";
2221 switch (seg->other_hint) {
2222 case 'c': colour = "darkgreen"; break; /* creation */
2223 case 'j': colour = "red"; break; /* join (exit) */
2224 case 's': colour = "orange"; break; /* signal */
2225 case 'S': colour = "pink"; break; /* sem_post->wait */
2226 case 'u': colour = "cyan"; break; /* unlock */
2227 default: tl_assert(0);
2228 }
2229 VG_(printf)(PFX "edge: { sourcename: \"%p\" targetname: \"%p\""
2230 " color: %s }\n", seg->other, seg, colour );
2231 }
2232 }
2233 VG_(printf)(PFX "}\n");
2234#undef PFX
2235}
2236
2237
2238/*----------------------------------------------------------------*/
2239/*--- map_shmem :: WordFM Addr SecMap ---*/
2240/*--- shadow memory (low level handlers) (shmem__* fns) ---*/
2241/*----------------------------------------------------------------*/
2242
2243
2244static UWord stats__secmaps_allocd = 0; // # SecMaps issued
2245static UWord stats__secmap_ga_space_covered = 0; // # ga bytes covered
2246static UWord stats__secmap_linesZ_allocd = 0; // # CacheLineZ's issued
2247static UWord stats__secmap_linesZ_bytes = 0; // .. using this much storage
2248static UWord stats__secmap_linesF_allocd = 0; // # CacheLineF's issued
2249static UWord stats__secmap_linesF_bytes = 0; // .. using this much storage
2250static UWord stats__secmap_iterator_steppings = 0; // # calls to stepSMIter
2251static UWord stats__cache_Z_fetches = 0; // # Z lines fetched
2252static UWord stats__cache_Z_wbacks = 0; // # Z lines written back
2253static UWord stats__cache_F_fetches = 0; // # F lines fetched
2254static UWord stats__cache_F_wbacks = 0; // # F lines written back
2255static UWord stats__cache_invals = 0; // # cache invals
2256static UWord stats__cache_flushes = 0; // # cache flushes
2257static UWord stats__cache_totrefs = 0; // # total accesses
2258static UWord stats__cache_totmisses = 0; // # misses
2259static UWord stats__cline_normalises = 0; // # calls to cacheline_normalise
2260static UWord stats__cline_read64s = 0; // # calls to s_m_read64
2261static UWord stats__cline_read32s = 0; // # calls to s_m_read32
2262static UWord stats__cline_read16s = 0; // # calls to s_m_read16
2263static UWord stats__cline_read8s = 0; // # calls to s_m_read8
2264static UWord stats__cline_write64s = 0; // # calls to s_m_write64
2265static UWord stats__cline_write32s = 0; // # calls to s_m_write32
2266static UWord stats__cline_write16s = 0; // # calls to s_m_write16
2267static UWord stats__cline_write8s = 0; // # calls to s_m_write8
2268static UWord stats__cline_set64s = 0; // # calls to s_m_set64
2269static UWord stats__cline_set32s = 0; // # calls to s_m_set32
2270static UWord stats__cline_set16s = 0; // # calls to s_m_set16
2271static UWord stats__cline_set8s = 0; // # calls to s_m_set8
2272static UWord stats__cline_get8s = 0; // # calls to s_m_get8
2273static UWord stats__cline_copy8s = 0; // # calls to s_m_copy8
2274static UWord stats__cline_64to32splits = 0; // # 64-bit accesses split
2275static UWord stats__cline_32to16splits = 0; // # 32-bit accesses split
2276static UWord stats__cline_16to8splits = 0; // # 16-bit accesses split
2277static UWord stats__cline_64to32pulldown = 0; // # calls to pulldown_to_32
2278static UWord stats__cline_32to16pulldown = 0; // # calls to pulldown_to_16
2279static UWord stats__cline_16to8pulldown = 0; // # calls to pulldown_to_8
2280
2281
2282static UInt shadow_mem_get8 ( Addr a ); /* fwds */
2283
2284static inline Addr shmem__round_to_SecMap_base ( Addr a ) {
2285 return a & ~(N_SECMAP_ARANGE - 1);
2286}
2287static inline UWord shmem__get_SecMap_offset ( Addr a ) {
2288 return a & (N_SECMAP_ARANGE - 1);
2289}
2290
2291/*--------------- SecMap allocation --------------- */
2292
2293static HChar* shmem__bigchunk_next = NULL;
2294static HChar* shmem__bigchunk_end1 = NULL;
2295
2296static void* shmem__bigchunk_alloc ( SizeT n )
2297{
2298 const SizeT sHMEM__BIGCHUNK_SIZE = 4096 * 256;
2299 tl_assert(n > 0);
2300 n = ROUNDUP(n, 16);
2301 tl_assert(shmem__bigchunk_next <= shmem__bigchunk_end1);
2302 tl_assert(shmem__bigchunk_end1 - shmem__bigchunk_next
2303 <= (SSizeT)sHMEM__BIGCHUNK_SIZE);
2304 if (shmem__bigchunk_next + n > shmem__bigchunk_end1) {
2305 if (0)
2306 VG_(printf)("XXXXX bigchunk: abandoning %d bytes\n",
2307 (Int)(shmem__bigchunk_end1 - shmem__bigchunk_next));
2308 shmem__bigchunk_next = VG_(am_shadow_alloc)( sHMEM__BIGCHUNK_SIZE );
2309 shmem__bigchunk_end1 = shmem__bigchunk_next + sHMEM__BIGCHUNK_SIZE;
2310 }
2311 tl_assert(shmem__bigchunk_next);
2312 tl_assert( 0 == (((Addr)shmem__bigchunk_next) & (16-1)) );
2313 tl_assert(shmem__bigchunk_next + n <= shmem__bigchunk_end1);
2314 shmem__bigchunk_next += n;
2315 return shmem__bigchunk_next - n;
2316}
2317
2318static SecMap* shmem__alloc_SecMap ( void )
2319{
2320 Word i, j;
2321 SecMap* sm = shmem__bigchunk_alloc( sizeof(SecMap) );
2322 if (0) VG_(printf)("alloc_SecMap %p\n",sm);
2323 tl_assert(sm);
2324 sm->magic = SecMap_MAGIC;
2325 sm->mbHasLocks = False; /* dangerous */
2326 sm->mbHasShared = False; /* dangerous */
2327 for (i = 0; i < N_SECMAP_ZLINES; i++) {
2328 sm->linesZ[i].dict[0] = SHVAL_NoAccess;
2329 sm->linesZ[i].dict[1] = 0; /* completely invalid SHVAL */
2330 sm->linesZ[i].dict[2] = 0;
2331 sm->linesZ[i].dict[3] = 0;
2332 for (j = 0; j < N_LINE_ARANGE/4; j++)
2333 sm->linesZ[i].ix2s[j] = 0; /* all reference dict[0] */
2334 }
2335 sm->linesF = NULL;
2336 sm->linesF_size = 0;
2337 stats__secmaps_allocd++;
2338 stats__secmap_ga_space_covered += N_SECMAP_ARANGE;
2339 stats__secmap_linesZ_allocd += N_SECMAP_ZLINES;
2340 stats__secmap_linesZ_bytes += N_SECMAP_ZLINES * sizeof(CacheLineZ);
2341 return sm;
2342}
2343
2344static SecMap* shmem__find_or_alloc_SecMap ( Addr ga )
2345{
2346 SecMap* sm = NULL;
2347 Addr gaKey = shmem__round_to_SecMap_base(ga);
2348 if (HG_(lookupFM)( map_shmem,
2349 NULL/*keyP*/, (Word*)(void*)&sm, (Word)gaKey )) {
2350 /* Found; address of SecMap is in sm */
2351 tl_assert(sm);
2352 } else {
2353 /* create a new one */
2354 sm = shmem__alloc_SecMap();
2355 tl_assert(sm);
2356 HG_(addToFM)( map_shmem, (Word)gaKey, (Word)sm );
2357 }
2358 return sm;
2359}
2360
2361
2362/*--------------- cache management/lookup --------------- */
2363
2364/*--------------- misc --------------- */
2365
2366static Bool shmem__get_mbHasLocks ( Addr a )
2367{
2368 SecMap* sm;
2369 Addr aKey = shmem__round_to_SecMap_base(a);
2370 if (HG_(lookupFM)( map_shmem,
2371 NULL/*keyP*/, (Word*)(void*)&sm, (Word)aKey )) {
2372 /* Found */
2373 return sm->mbHasLocks;
2374 } else {
2375 return False;
2376 }
2377}
2378
2379static void shmem__set_mbHasLocks ( Addr a, Bool b )
2380{
2381 SecMap* sm;
2382 Addr aKey = shmem__round_to_SecMap_base(a);
2383 tl_assert(b == False || b == True);
2384 if (HG_(lookupFM)( map_shmem,
2385 NULL/*keyP*/, (Word*)(void*)&sm, (Word)aKey )) {
2386 /* Found; address of SecMap is in sm */
2387 } else {
2388 /* create a new one */
2389 sm = shmem__alloc_SecMap();
2390 tl_assert(sm);
2391 HG_(addToFM)( map_shmem, (Word)aKey, (Word)sm );
2392 }
2393 sm->mbHasLocks = b;
2394}
2395
2396static void shmem__set_mbHasShared ( Addr a, Bool b )
2397{
2398 SecMap* sm;
2399 Addr aKey = shmem__round_to_SecMap_base(a);
2400 tl_assert(b == False || b == True);
2401 if (HG_(lookupFM)( map_shmem,
2402 NULL/*keyP*/, (Word*)(void*)&sm, (Word)aKey )) {
2403 /* Found; address of SecMap is in sm */
2404 } else {
2405 /* create a new one */
2406 sm = shmem__alloc_SecMap();
2407 tl_assert(sm);
2408 HG_(addToFM)( map_shmem, (Word)aKey, (Word)sm );
2409 }
2410 sm->mbHasShared = b;
2411}
2412
2413
2414/*----------------------------------------------------------------*/
2415/*--- Sanity checking the data structures ---*/
2416/*----------------------------------------------------------------*/
2417
2418static UWord stats__sanity_checks = 0;
2419
2420static Bool is_sane_CacheLine ( CacheLine* cl ); /* fwds */
2421static Bool cmpGEQ_VTS ( XArray* a, XArray* b ); /* fwds */
2422static void laog__sanity_check ( Char* who ); /* fwds */
2423
2424/* REQUIRED INVARIANTS:
2425
2426 Thread vs Segment/Lock/SecMaps
2427
2428 for each t in Threads {
2429
2430 // Thread.lockset: each element is really a valid Lock
2431
2432 // Thread.lockset: each Lock in set is actually held by that thread
2433 for lk in Thread.lockset
2434 lk == LockedBy(t)
2435
2436 // Thread.csegid is a valid SegmentID
2437 // and the associated Segment has .thr == t
2438
2439 }
2440
2441 all thread Locksets are pairwise empty under intersection
2442 (that is, no lock is claimed to be held by more than one thread)
2443 -- this is guaranteed if all locks in locksets point back to their
2444 owner threads
2445
2446 Lock vs Thread/Segment/SecMaps
2447
2448 for each entry (gla, la) in map_locks
2449 gla == la->guest_addr
2450
2451 for each lk in Locks {
2452
2453 lk->tag is valid
2454 lk->guest_addr does not have shadow state NoAccess
2455 if lk == LockedBy(t), then t->lockset contains lk
2456 if lk == UnlockedBy(segid) then segid is valid SegmentID
2457 and can be mapped to a valid Segment(seg)
2458 and seg->thr->lockset does not contain lk
2459 if lk == UnlockedNew then (no lockset contains lk)
2460
2461 secmaps for lk has .mbHasLocks == True
2462
2463 }
2464
2465 Segment vs Thread/Lock/SecMaps
2466
2467 the Segment graph is a dag (no cycles)
2468 all of the Segment graph must be reachable from the segids
2469 mentioned in the Threads
2470
2471 for seg in Segments {
2472
2473 seg->thr is a sane Thread
2474
2475 }
2476
2477 SecMaps vs Segment/Thread/Lock
2478
2479 for sm in SecMaps {
2480
2481 sm properly aligned
2482 if any shadow word is ShR or ShM then .mbHasShared == True
2483
2484 for each Excl(segid) state
2485 map_segments_lookup maps to a sane Segment(seg)
2486 for each ShM/ShR(tsetid,lsetid) state
2487 each lk in lset is a valid Lock
2488 each thr in tset is a valid thread, which is non-dead
2489
2490 }
2491*/
2492
2493
2494/* Return True iff 'thr' holds 'lk' in some mode. */
2495static Bool thread_is_a_holder_of_Lock ( Thread* thr, Lock* lk )
2496{
2497 if (lk->heldBy)
2498 return HG_(elemBag)( lk->heldBy, (Word)thr ) > 0;
2499 else
2500 return False;
2501}
2502
2503/* Sanity check Threads, as far as possible */
2504__attribute__((noinline))
2505static void threads__sanity_check ( Char* who )
2506{
2507#define BAD(_str) do { how = (_str); goto bad; } while (0)
2508 Char* how = "no error";
2509 Thread* thr;
2510 WordSetID wsA, wsW;
2511 Word* ls_words;
2512 Word ls_size, i;
2513 Lock* lk;
2514 Segment* seg;
2515 for (thr = admin_threads; thr; thr = thr->admin) {
2516 if (!is_sane_Thread(thr)) BAD("1");
2517 wsA = thr->locksetA;
2518 wsW = thr->locksetW;
2519 // locks held in W mode are a subset of all locks held
2520 if (!HG_(isSubsetOf)( univ_lsets, wsW, wsA )) BAD("7");
2521 HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, wsA );
2522 for (i = 0; i < ls_size; i++) {
2523 lk = (Lock*)ls_words[i];
2524 // Thread.lockset: each element is really a valid Lock
2525 if (!is_sane_LockN(lk)) BAD("2");
2526 // Thread.lockset: each Lock in set is actually held by that
2527 // thread
2528 if (!thread_is_a_holder_of_Lock(thr,lk)) BAD("3");
2529 // Thread.csegid is a valid SegmentID
2530 if (!is_sane_SegmentID(thr->csegid)) BAD("4");
2531 // and the associated Segment has .thr == t
2532 seg = map_segments_maybe_lookup(thr->csegid);
2533 if (!is_sane_Segment(seg)) BAD("5");
2534 if (seg->thr != thr) BAD("6");
2535 }
2536 }
2537 return;
2538 bad:
2539 VG_(printf)("threads__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
2540 tl_assert(0);
2541#undef BAD
2542}
2543
2544
2545/* Sanity check Locks, as far as possible */
2546__attribute__((noinline))
2547static void locks__sanity_check ( Char* who )
2548{
2549#define BAD(_str) do { how = (_str); goto bad; } while (0)
2550 Char* how = "no error";
2551 Addr gla;
2552 Lock* lk;
2553 Int i;
2554 // # entries in admin_locks == # entries in map_locks
2555 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin)
2556 ;
2557 if (i != HG_(sizeFM)(map_locks)) BAD("1");
2558 // for each entry (gla, lk) in map_locks
2559 // gla == lk->guest_addr
2560 HG_(initIterFM)( map_locks );
2561 while (HG_(nextIterFM)( map_locks,
2562 (Word*)(void*)&gla, (Word*)(void*)&lk )) {
2563 if (lk->guestaddr != gla) BAD("2");
2564 }
2565 HG_(doneIterFM)( map_locks );
2566 // scan through admin_locks ...
2567 for (lk = admin_locks; lk; lk = lk->admin) {
2568 // lock is sane. Quite comprehensive, also checks that
2569 // referenced (holder) threads are sane.
2570 if (!is_sane_LockN(lk)) BAD("3");
2571 // map_locks binds guest address back to this lock
2572 if (lk != map_locks_maybe_lookup(lk->guestaddr)) BAD("4");
2573 // lk->guest_addr does not have shadow state NoAccess
2574 // FIXME: this could legitimately arise from a buggy guest
2575 // that attempts to lock in (eg) freed memory. Detect this
2576 // and warn about it in the pre/post-mutex-lock event handler.
2577 if (is_SHVAL_NoAccess(shadow_mem_get8(lk->guestaddr))) BAD("5");
2578 // look at all threads mentioned as holders of this lock. Ensure
2579 // this lock is mentioned in their locksets.
2580 if (lk->heldBy) {
2581 Thread* thr;
2582 Word count;
2583 HG_(initIterBag)( lk->heldBy );
2584 while (HG_(nextIterBag)( lk->heldBy,
2585 (Word*)(void*)&thr, &count )) {
2586 // is_sane_LockN above ensures these
2587 tl_assert(count >= 1);
2588 tl_assert(is_sane_Thread(thr));
2589 if (!HG_(elemWS)(univ_lsets, thr->locksetA, (Word)lk))
2590 BAD("6");
2591 // also check the w-only lockset
2592 if (lk->heldW
2593 && !HG_(elemWS)(univ_lsets, thr->locksetW, (Word)lk))
2594 BAD("7");
2595 if ((!lk->heldW)
2596 && HG_(elemWS)(univ_lsets, thr->locksetW, (Word)lk))
2597 BAD("8");
2598 }
2599 HG_(doneIterBag)( lk->heldBy );
2600 } else {
2601 /* lock not held by anybody */
2602 if (lk->heldW) BAD("9"); /* should be False if !heldBy */
2603 // since lk is unheld, then (no lockset contains lk)
2604 // hmm, this is really too expensive to check. Hmm.
2605 }
2606 // secmaps for lk has .mbHasLocks == True
2607 if (!shmem__get_mbHasLocks(lk->guestaddr)) BAD("10");
2608 }
2609
2610 return;
2611 bad:
2612 VG_(printf)("locks__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
2613 tl_assert(0);
2614#undef BAD
2615}
2616
2617
2618/* Sanity check Segments, as far as possible */
2619__attribute__((noinline))
2620static void segments__sanity_check ( Char* who )
2621{
2622#define BAD(_str) do { how = (_str); goto bad; } while (0)
2623 Char* how = "no error";
2624 Int i;
2625 Segment* seg;
2626 // FIXME
2627 // the Segment graph is a dag (no cycles)
2628 // all of the Segment graph must be reachable from the segids
2629 // mentioned in the Threads
2630 // # entries in admin_segments == # entries in map_segments
2631 for (i = 0, seg = admin_segments; seg; i++, seg = seg->admin)
2632 ;
2633 if (i != HG_(sizeFM)(map_segments)) BAD("1");
2634 // for seg in Segments {
2635 for (seg = admin_segments; seg; seg = seg->admin) {
2636 if (!is_sane_Segment(seg)) BAD("2");
2637 if (!is_sane_Thread(seg->thr)) BAD("3");
2638 if (!seg->vts) BAD("4");
2639 if (seg->prev && seg->prev->vts
2640 && !cmpGEQ_VTS(seg->vts, seg->prev->vts))
2641 BAD("5");
2642 if (seg->other && seg->other->vts
2643 && !cmpGEQ_VTS(seg->vts, seg->other->vts))
2644 BAD("6");
2645 }
2646 return;
2647 bad:
2648 VG_(printf)("segments__sanity_check: who=\"%s\", bad=\"%s\"\n",
2649 who, how);
2650 tl_assert(0);
2651#undef BAD
2652}
2653
2654
2655/* Sanity check shadow memory, as far as possible */
2656static Int cmp_Addr_for_ssort ( void* p1, void* p2 ) {
2657 Addr a1 = *(Addr*)p1;
2658 Addr a2 = *(Addr*)p2;
2659 if (a1 < a2) return -1;
2660 if (a1 > a2) return 1;
2661 return 0;
2662}
2663__attribute__((noinline))
2664static void shmem__sanity_check ( Char* who )
2665{
2666#define BAD(_str) do { how = (_str); goto bad; } while (0)
2667 Char* how = "no error";
2668 Word smga;
2669 SecMap* sm;
2670 Word i, j, ws_size, n_valid_tags;
2671 Word* ws_words;
2672 Addr* valid_tags;
2673 HG_(initIterFM)( map_shmem );
2674 // for sm in SecMaps {
2675 while (HG_(nextIterFM)( map_shmem,
2676 (Word*)(void*)&smga, (Word*)(void*)&sm )) {
2677 SecMapIter itr;
2678 UInt* w32p;
2679 Bool mbHasShared = False;
2680 Bool allNoAccess = True;
2681 if (!is_sane_SecMap(sm)) BAD("1");
2682 // sm properly aligned
2683 if (smga != shmem__round_to_SecMap_base(smga)) BAD("2");
2684 // if any shadow word is ShR or ShM then .mbHasShared == True
2685 initSecMapIter( &itr );
2686 while (stepSecMapIter( &w32p, &itr, sm )) {
2687 UInt w32 = *w32p;
2688 if (is_SHVAL_Sh(w32))
2689 mbHasShared = True;
2690 if (!is_SHVAL_NoAccess(w32))
2691 allNoAccess = False;
2692 if (is_SHVAL_Excl(w32)) {
2693 // for each Excl(segid) state
2694 // map_segments_lookup maps to a sane Segment(seg)
2695 Segment* seg;
2696 SegmentID segid = un_SHVAL_Excl(w32);
2697 if (!is_sane_SegmentID(segid)) BAD("3");
2698 seg = map_segments_maybe_lookup(segid);
2699 if (!is_sane_Segment(seg)) BAD("4");
2700 }
2701 else if (is_SHVAL_Sh(w32)) {
2702 WordSetID tset = un_SHVAL_Sh_tset(w32);
2703 WordSetID lset = un_SHVAL_Sh_lset(w32);
2704 if (!HG_(plausibleWS)( univ_tsets, tset )) BAD("5");
2705 if (!HG_(saneWS_SLOW)( univ_tsets, tset )) BAD("6");
2706 if (HG_(cardinalityWS)( univ_tsets, tset ) < 2) BAD("7");
2707 if (!HG_(plausibleWS)( univ_lsets, lset )) BAD("8");
2708 if (!HG_(saneWS_SLOW)( univ_lsets, lset )) BAD("9");
2709 HG_(getPayloadWS)( &ws_words, &ws_size, univ_lsets, lset );
2710 for (j = 0; j < ws_size; j++) {
2711 Lock* lk = (Lock*)ws_words[j];
2712 // for each ShM/ShR(tsetid,lsetid) state
2713 // each lk in lset is a valid Lock
2714 if (!is_sane_LockN(lk)) BAD("10");
2715 }
2716 HG_(getPayloadWS)( &ws_words, &ws_size, univ_tsets, tset );
2717 for (j = 0; j < ws_size; j++) {
2718 Thread* thr = (Thread*)ws_words[j];
2719 //for each ShM/ShR(tsetid,lsetid) state
2720 // each thr in tset is a valid thread, which is non-dead
2721 if (!is_sane_Thread(thr)) BAD("11");
2722 }
2723 }
2724 else if (is_SHVAL_NoAccess(w32) || is_SHVAL_New(w32)) {
2725 /* nothing to check */
2726 }
2727 else {
2728 /* bogus shadow mem value */
2729 BAD("12");
2730 }
2731 } /* iterating over a SecMap */
2732 // Check essential safety property
2733 if (mbHasShared && !sm->mbHasShared) BAD("13");
2734 // This is optional - check that destroyed memory has its hint
2735 // bits cleared. NB won't work properly unless full, eager
2736 // GCing of SecMaps is implemented
2737 //if (allNoAccess && sm->mbHasLocks) BAD("13a");
2738 }
2739 HG_(doneIterFM)( map_shmem );
2740
2741 // check the cache
2742 valid_tags = hg_zalloc(N_WAY_NENT * sizeof(Addr));
2743 n_valid_tags = 0;
2744 tl_assert(valid_tags);
2745 for (i = 0; i < N_WAY_NENT; i++) {
2746 CacheLine* cl;
2747 Addr tag;
2748 /* way0, dude */
2749 cl = &cache_shmem.lyns0[i];
2750 tag = cache_shmem.tags0[i];
2751 if (tag != 1) {
2752 if (!is_valid_scache_tag(tag)) BAD("14-0");
2753 if (!is_sane_CacheLine(cl)) BAD("15-0");
2754 /* A valid tag should be of the form
2755 X---X line_number:N_WAY_BITS 0:N_LINE_BITS */
2756 if (tag & (N_LINE_ARANGE-1)) BAD("16-0");
2757 if ( i != ((tag >> N_LINE_BITS) & (N_WAY_NENT-1)) ) BAD("16-1");
2758 valid_tags[n_valid_tags++] = tag;
2759 }
2760 }
2761 tl_assert(n_valid_tags <= N_WAY_NENT);
2762 if (n_valid_tags > 1) {
2763 /* Check that the valid tags are unique */
2764 VG_(ssort)( valid_tags, n_valid_tags, sizeof(Addr), cmp_Addr_for_ssort );
2765 for (i = 0; i < n_valid_tags-1; i++) {
2766 if (valid_tags[i] >= valid_tags[i+1])
2767 BAD("16-2");
2768 }
2769 }
2770 hg_free(valid_tags);
2771 return;
2772 bad:
2773 VG_(printf)("shmem__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
2774 tl_assert(0);
2775#undef BAD
2776}
2777
2778static void all_except_Locks__sanity_check ( Char* who ) {
2779 stats__sanity_checks++;
2780 if (0) VG_(printf)("all_except_Locks__sanity_check(%s)\n", who);
2781 threads__sanity_check(who);
2782 segments__sanity_check(who);
2783 shmem__sanity_check(who);
2784 laog__sanity_check(who);
2785}
2786static void all__sanity_check ( Char* who ) {
2787 all_except_Locks__sanity_check(who);
2788 locks__sanity_check(who);
2789}
2790
2791
2792/*----------------------------------------------------------------*/
2793/*--- the core memory state machine (msm__* functions) ---*/
2794/*----------------------------------------------------------------*/
2795
2796static UWord stats__msm_read_Excl_nochange = 0;
2797static UWord stats__msm_read_Excl_transfer = 0;
2798static UWord stats__msm_read_Excl_to_ShR = 0;
2799static UWord stats__msm_read_ShR_to_ShR = 0;
2800static UWord stats__msm_read_ShM_to_ShM = 0;
2801static UWord stats__msm_read_New_to_Excl = 0;
2802static UWord stats__msm_read_NoAccess = 0;
2803
2804static UWord stats__msm_write_Excl_nochange = 0;
2805static UWord stats__msm_write_Excl_transfer = 0;
2806static UWord stats__msm_write_Excl_to_ShM = 0;
2807static UWord stats__msm_write_ShR_to_ShM = 0;
2808static UWord stats__msm_write_ShM_to_ShM = 0;
2809static UWord stats__msm_write_New_to_Excl = 0;
2810static UWord stats__msm_write_NoAccess = 0;
2811
2812/* fwds */
2813static void record_error_Race ( Thread* thr,
2814 Addr data_addr, Bool isWrite, Int szB,
2815 UInt old_sv, UInt new_sv,
2816 ExeContext* mb_lastlock );
2817
2818static void record_error_FreeMemLock ( Thread* thr, Lock* lk );
2819
2820static void record_error_UnlockUnlocked ( Thread*, Lock* );
2821static void record_error_UnlockForeign ( Thread*, Thread*, Lock* );
2822static void record_error_UnlockBogus ( Thread*, Addr );
2823static void record_error_PthAPIerror ( Thread*, HChar*, Word, HChar* );
2824static void record_error_LockOrder ( Thread*, Addr, Addr,
2825 ExeContext*, ExeContext* );
2826
2827static void record_error_Misc ( Thread*, HChar* );
2828static void announce_one_thread ( Thread* thr ); /* fwds */
2829
2830static WordSetID add_BHL ( WordSetID lockset ) {
2831 return HG_(addToWS)( univ_lsets, lockset, (Word)__bus_lock_Lock );
2832}
2833static WordSetID del_BHL ( WordSetID lockset ) {
2834 return HG_(delFromWS)( univ_lsets, lockset, (Word)__bus_lock_Lock );
2835}
2836
2837
2838/* Last-lock-lossage records. This mechanism exists to help explain
2839 to programmers why we are complaining about a race. The idea is to
2840 monitor all lockset transitions. When a previously nonempty
2841 lockset becomes empty, the lock(s) that just disappeared (the
2842 "lossage") are the locks that have consistently protected the
2843 location (ga_of_access) in question for the longest time. Most of
2844 the time the lossage-set is a single lock. Because the
2845 lossage-lock is the one that has survived longest, there is there
2846 is a good chance that it is indeed the lock that the programmer
2847 intended to use to protect the location.
2848
2849 Note that we cannot in general just look at the lossage set when we
2850 see a transition to ShM(...,empty-set), because a transition to an
2851 empty lockset can happen arbitrarily far before the point where we
2852 want to report an error. This is in the case where there are many
2853 transitions ShR -> ShR, all with an empty lockset, and only later
2854 is there a transition to ShM. So what we want to do is note the
2855 lossage lock at the point where a ShR -> ShR transition empties out
2856 the lockset, so we can present it later if there should be a
2857 transition to ShM.
2858
2859 So this function finds such transitions. For each, it associates
2860 in ga_to_lastlock, the guest address and the lossage lock. In fact
2861 we do not record the Lock* directly as that may disappear later,
2862 but instead the ExeContext inside the Lock which says where it was
2863 initialised or first locked. ExeContexts are permanent so keeping
2864 them indefinitely is safe.
2865
2866 A boring detail: the hardware bus lock is not interesting in this
2867 respect, so we first remove that from the pre/post locksets.
2868*/
2869
2870static UWord stats__ga_LL_adds = 0;
2871
2872static WordFM* ga_to_lastlock = NULL; /* GuestAddr -> ExeContext* */
2873
2874static
2875void record_last_lock_lossage ( Addr ga_of_access,
2876 WordSetID lset_old, WordSetID lset_new )
2877{
2878 Lock* lk;
2879 Int card_old, card_new;
2880
2881 tl_assert(lset_old != lset_new);
2882
2883 if (0) VG_(printf)("XX1: %d (card %d) -> %d (card %d) %p\n",
2884 (Int)lset_old,
2885 HG_(cardinalityWS)(univ_lsets,lset_old),
2886 (Int)lset_new,
2887 HG_(cardinalityWS)(univ_lsets,lset_new),
2888 ga_of_access );
2889
2890 /* This is slow, but at least it's simple. The bus hardware lock
2891 just confuses the logic, so remove it from the locksets we're
2892 considering before doing anything else. */
2893 lset_new = del_BHL( lset_new );
2894
2895 if (!HG_(isEmptyWS)( univ_lsets, lset_new )) {
2896 /* The post-transition lock set is not empty. So we are not
2897 interested. We're only interested in spotting transitions
2898 that make locksets become empty. */
2899 return;
2900 }
2901
2902 /* lset_new is now empty */
2903 card_new = HG_(cardinalityWS)( univ_lsets, lset_new );
2904 tl_assert(card_new == 0);
2905
2906 lset_old = del_BHL( lset_old );
2907 card_old = HG_(cardinalityWS)( univ_lsets, lset_old );
2908
2909 if (0) VG_(printf)(" X2: %d (card %d) -> %d (card %d)\n",
2910 (Int)lset_old, card_old, (Int)lset_new, card_new );
2911
2912 if (card_old == 0) {
2913 /* The old lockset was also empty. Not interesting. */
2914 return;
2915 }
2916
2917 tl_assert(card_old > 0);
2918 tl_assert(!HG_(isEmptyWS)( univ_lsets, lset_old ));
2919
2920 /* Now we know we've got a transition from a nonempty lockset to an
2921 empty one. So lset_old must be the set of locks lost. Record
2922 some details. If there is more than one element in the lossage
2923 set, just choose one arbitrarily -- not the best, but at least
2924 it's simple. */
2925
2926 lk = (Lock*)HG_(anyElementOfWS)( univ_lsets, lset_old );
2927 if (0) VG_(printf)("lossage %d %p\n",
2928 HG_(cardinalityWS)( univ_lsets, lset_old), lk );
2929 if (lk->appeared_at) {
2930 if (ga_to_lastlock == NULL)
2931 ga_to_lastlock = HG_(newFM)( hg_zalloc, hg_free, NULL );
2932 HG_(addToFM)( ga_to_lastlock, ga_of_access, (Word)lk->appeared_at );
2933 stats__ga_LL_adds++;
2934 }
2935}
2936
2937/* This queries the table (ga_to_lastlock) made by
2938 record_last_lock_lossage, when constructing error messages. It
2939 attempts to find the ExeContext of the allocation or initialisation
2940 point for the lossage lock associated with 'ga'. */
2941
2942static ExeContext* maybe_get_lastlock_initpoint ( Addr ga )
2943{
2944 ExeContext* ec_hint = NULL;
2945 if (ga_to_lastlock != NULL
2946 && HG_(lookupFM)(ga_to_lastlock,
2947 NULL, (Word*)(void*)&ec_hint, ga)) {
2948 tl_assert(ec_hint != NULL);
2949 return ec_hint;
2950 } else {
2951 return NULL;
2952 }
2953}
2954
2955
2956static void msm__show_state_change ( Thread* thr_acc, Addr a, Int szB,
2957 Char howC,
2958 UInt sv_old, UInt sv_new )
2959{
2960 ThreadId tid;
2961 UChar txt_old[100], txt_new[100];
2962 Char* how = "";
2963 tl_assert(is_sane_Thread(thr_acc));
2964 tl_assert(clo_trace_level == 1 || clo_trace_level == 2);
2965 switch (howC) {
2966 case 'r': how = "rd"; break;
2967 case 'w': how = "wr"; break;
2968 case 'p': how = "pa"; break;
2969 default: tl_assert(0);
2970 }
2971 show_shadow_w32_for_user(txt_old, sizeof(txt_old), sv_old);
2972 show_shadow_w32_for_user(txt_new, sizeof(txt_new), sv_new);
2973 txt_old[sizeof(txt_old)-1] = 0;
2974 txt_new[sizeof(txt_new)-1] = 0;
2975 if (clo_trace_level == 2) {
2976 /* show everything */
2977 VG_(message)(Vg_UserMsg, "");
2978 announce_one_thread( thr_acc );
2979 VG_(message)(Vg_UserMsg,
2980 "TRACE: %p %s %d thr#%d :: %s --> %s",
2981 a, how, szB, thr_acc->errmsg_index, txt_old, txt_new );
2982 tid = map_threads_maybe_reverse_lookup_SLOW(thr_acc);
2983 if (tid != VG_INVALID_THREADID) {
2984 VG_(get_and_pp_StackTrace)( tid, 8 );
2985 }
2986 } else {
2987 /* Just print one line */
2988 VG_(message)(Vg_UserMsg,
2989 "TRACE: %p %s %d thr#%d :: %22s --> %22s",
2990 a, how, szB, thr_acc->errmsg_index, txt_old, txt_new );
2991 }
2992}
2993
2994
2995/* Here are some MSM stats from startup/shutdown of OpenOffice.
2996
2997 msm: 489,734,723 80,278,862 rd/wr_Excl_nochange
2998 msm: 3,171,542 93,738 rd/wr_Excl_transfer
2999 msm: 45,036 167 rd/wr_Excl_to_ShR/ShM
3000 msm: 13,352,594 285 rd/wr_ShR_to_ShR/ShM
3001 msm: 1,125,879 815,779 rd/wr_ShM_to_ShM
3002 msm: 7,561,842 250,629,935 rd/wr_New_to_Excl
3003 msm: 17,778 0 rd/wr_NoAccess
3004
3005 This says how the clauses should be ordered for greatest speed:
3006
3007 * the vast majority of memory reads (490 million out of a total of
3008 515 million) are of memory in an exclusive state, and the state
3009 is unchanged. All other read accesses are insignificant by
3010 comparison.
3011
3012 * 75% (251 million out of a total of 332 million) writes are 'first
3013 time' writes, which take New memory into exclusive ownership.
3014 Almost all the rest (80 million) are accesses to exclusive state,
3015 which remains unchanged. All other write accesses are
3016 insignificant. */
3017
3018/* The core MSM. If 'wold' is the old 32-bit shadow word for a
3019 location, return the new shadow word that would result for a read
3020 of the location, and report any errors necessary on the way. This
3021 does not update shadow memory - it merely produces new shadow words
3022 from old. 'thr_acc' and 'a' are supplied only so it can produce
3023 coherent error messages if necessary. */
3024static
3025UInt msm__handle_read ( Thread* thr_acc, Addr a, UInt wold, Int szB )
3026{
3027 UInt wnew = SHVAL_Invalid;
3028
3029 tl_assert(is_sane_Thread(thr_acc));
3030
3031 if (0) VG_(printf)("read thr=%p %p\n", thr_acc, a);
3032
3033 /* Exclusive */
3034 if (LIKELY(is_SHVAL_Excl(wold))) {
3035 /* read Excl(segid)
3036 | segid_old == segid-of-thread
3037 -> no change
3038 | segid_old `happens_before` segid-of-this-thread
3039 -> Excl(segid-of-this-thread)
3040 | otherwise
3041 -> ShR
3042 */
3043 SegmentID segid_old = un_SHVAL_Excl(wold);
3044 tl_assert(is_sane_SegmentID(segid_old));
3045 if (LIKELY(segid_old == thr_acc->csegid)) {
3046 /* no change */
3047 stats__msm_read_Excl_nochange++;
3048 /*NOCHANGE*/return wold;
3049 }
3050 if (happens_before(segid_old, thr_acc->csegid)) {
3051 /* -> Excl(segid-of-this-thread) */
3052 wnew = mk_SHVAL_Excl(thr_acc->csegid);
3053 stats__msm_read_Excl_transfer++;
3054 goto changed;
3055 }
3056 /* else */ {
3057 /* Enter the shared-readonly (ShR) state. */
3058 WordSetID tset, lset;
3059 /* This location has been accessed by precisely two threads.
3060 Make an appropriate tset. */
3061 // FIXME: performance: duplicate map_segments_lookup(segid_old)
3062 // since must also be done in happens_before()
3063 Segment* seg_old = map_segments_lookup( segid_old );
3064 Thread* thr_old = seg_old->thr;
3065 tset = HG_(doubletonWS)( univ_tsets, (Word)thr_old, (Word)thr_acc );
3066 lset = add_BHL( thr_acc->locksetA ); /* read ==> use all locks */
3067 wnew = mk_SHVAL_ShR( tset, lset );
3068 stats__msm_read_Excl_to_ShR++;
3069 goto changed;
3070 }
3071 /*NOTREACHED*/
3072 }
3073
3074 /* Shared-Readonly */
3075 if (is_SHVAL_ShR(wold)) {
3076 /* read Shared-Readonly(threadset, lockset)
3077 We remain in ShR state, but add this thread to the
3078 threadset and refine the lockset accordingly. Do not
3079 complain if the lockset becomes empty -- that's ok. */
3080 WordSetID tset_old = un_SHVAL_ShR_tset(wold);
3081 WordSetID lset_old = un_SHVAL_ShR_lset(wold);
3082 WordSetID tset_new = HG_(addToWS)( univ_tsets,
3083 tset_old, (Word)thr_acc );
3084 WordSetID lset_new = HG_(intersectWS)( univ_lsets,
3085 lset_old,
3086 add_BHL(thr_acc->locksetA)
3087 /* read ==> use all locks */ );
3088 /*UInt*/ wnew = mk_SHVAL_ShR( tset_new, lset_new );
3089 if (lset_old != lset_new)
3090 record_last_lock_lossage(a,lset_old,lset_new);
3091 stats__msm_read_ShR_to_ShR++;
3092 goto changed;
3093 }
3094
3095 /* Shared-Modified */
3096 if (is_SHVAL_ShM(wold)) {
3097 /* read Shared-Modified(threadset, lockset)
3098 We remain in ShM state, but add this thread to the
3099 threadset and refine the lockset accordingly.
3100 If the lockset becomes empty, complain. */
3101 WordSetID tset_old = un_SHVAL_ShM_tset(wold);
3102 WordSetID lset_old = un_SHVAL_ShM_lset(wold);
3103 WordSetID tset_new = HG_(addToWS)( univ_tsets,
3104 tset_old, (Word)thr_acc );
3105 WordSetID lset_new = HG_(intersectWS)( univ_lsets,
3106 lset_old,
3107 add_BHL(thr_acc->locksetA)
3108 /* read ==> use all locks */ );
3109 /*UInt*/ wnew = mk_SHVAL_ShM( tset_new, lset_new );
3110 if (lset_old != lset_new)
3111 record_last_lock_lossage(a,lset_old,lset_new);
3112 if (HG_(isEmptyWS)(univ_lsets, lset_new)
3113 && !HG_(isEmptyWS)(univ_lsets, lset_old)) {
3114 record_error_Race( thr_acc, a,
3115 False/*isWrite*/, szB, wold, wnew,
3116 maybe_get_lastlock_initpoint(a) );
3117 }
3118 stats__msm_read_ShM_to_ShM++;
3119 goto changed;
3120 }
3121
3122 /* New */
3123 if (is_SHVAL_New(wold)) {
3124 /* read New -> Excl(segid) */
3125 wnew = mk_SHVAL_Excl( thr_acc->csegid );
3126 stats__msm_read_New_to_Excl++;
3127 goto changed;
3128 }
3129
3130 /* NoAccess */
3131 if (is_SHVAL_NoAccess(wold)) {
3132 // FIXME: complain if accessing here
3133 // FIXME: transition to Excl?
3134 if (0)
3135 VG_(printf)(
3136 "msm__handle_read_aligned_32(thr=%p, addr=%p): NoAccess\n",
3137 thr_acc, (void*)a );
3138 stats__msm_read_NoAccess++;
3139 /*NOCHANGE*/return wold; /* no change */
3140 }
3141
3142 /* hmm, bogus state */
3143 tl_assert(0);
3144
3145 changed:
3146 if (UNLIKELY(clo_trace_level > 0)) {
3147 if (a <= clo_trace_addr && clo_trace_addr < a+szB
3148 && wold != wnew) {
3149 msm__show_state_change( thr_acc, a, szB, 'r', wold, wnew );
3150 }
3151 }
3152 return wnew;
3153}
3154
3155/* Similar to msm__handle_read, compute a new 32-bit shadow word
3156 resulting from a write to a location, and report any errors
3157 necessary on the way. */
3158static
3159UInt msm__handle_write ( Thread* thr_acc, Addr a, UInt wold, Int szB )
3160{
3161 UInt wnew = SHVAL_Invalid;
3162
3163 tl_assert(is_sane_Thread(thr_acc));
3164
3165 if (0) VG_(printf)("write32 thr=%p %p\n", thr_acc, a);
3166
3167 /* New */
3168 if (LIKELY(is_SHVAL_New(wold))) {
3169 /* write New -> Excl(segid) */
3170 wnew = mk_SHVAL_Excl( thr_acc->csegid );
3171 stats__msm_write_New_to_Excl++;
3172 goto changed;
3173 }
3174
3175 /* Exclusive */
3176 if (is_SHVAL_Excl(wold)) {
3177 // I believe is identical to case for read Excl
3178 // apart from enters ShM rather than ShR
3179 /* read Excl(segid)
3180 | segid_old == segid-of-thread
3181 -> no change
3182 | segid_old `happens_before` segid-of-this-thread
3183 -> Excl(segid-of-this-thread)
3184 | otherwise
3185 -> ShM
3186 */
3187 SegmentID segid_old = un_SHVAL_Excl(wold);
3188 tl_assert(is_sane_SegmentID(segid_old));
3189 if (segid_old == thr_acc->csegid) {
3190 /* no change */
3191 stats__msm_write_Excl_nochange++;
3192 /*NOCHANGE*/return wold;
3193 }
3194 if (happens_before(segid_old, thr_acc->csegid)) {
3195 /* -> Excl(segid-of-this-thread) */
3196 wnew = mk_SHVAL_Excl(thr_acc->csegid);
3197 stats__msm_write_Excl_transfer++;
3198 goto changed;
3199 }
3200 /* else */ {
3201 /* Enter the shared-modified (ShM) state. */
3202 WordSetID tset, lset;
3203 /* This location has been accessed by precisely two threads.
3204 Make an appropriate tset. */
3205 // FIXME: performance: duplicate map_segments_lookup(segid_old)
3206 // since must also be done in happens_before()
3207 Segment* seg_old = map_segments_lookup( segid_old );
3208 Thread* thr_old = seg_old->thr;
3209 tset = HG_(doubletonWS)( univ_tsets, (Word)thr_old, (Word)thr_acc );
3210 lset = thr_acc->locksetW; /* write ==> use only w-held locks */
3211 wnew = mk_SHVAL_ShM( tset, lset );
3212 if (HG_(isEmptyWS)(univ_lsets, lset)) {
3213 record_error_Race( thr_acc,
3214 a, True/*isWrite*/, szB, wold, wnew,
3215 maybe_get_lastlock_initpoint(a) );
3216 }
3217 stats__msm_write_Excl_to_ShM++;
3218 goto changed;
3219 }
3220 /*NOTREACHED*/
3221 }
3222
3223 /* Shared-Readonly */
3224 if (is_SHVAL_ShR(wold)) {
3225 /* write Shared-Readonly(threadset, lockset)
3226 We move to ShM state, add this thread to the
3227 threadset and refine the lockset accordingly.
3228 If the lockset becomes empty, complain. */
3229 WordSetID tset_old = un_SHVAL_ShR_tset(wold);
3230 WordSetID lset_old = un_SHVAL_ShR_lset(wold);
3231 WordSetID tset_new = HG_(addToWS)( univ_tsets,
3232 tset_old, (Word)thr_acc );
3233 WordSetID lset_new = HG_(intersectWS)(
3234 univ_lsets,
3235 lset_old,
3236 thr_acc->locksetW
3237 /* write ==> use only w-held locks */
3238 );
3239 /*UInt*/ wnew = mk_SHVAL_ShM( tset_new, lset_new );
3240 if (lset_old != lset_new)
3241 record_last_lock_lossage(a,lset_old,lset_new);
3242 if (HG_(isEmptyWS)(univ_lsets, lset_new)) {
3243 record_error_Race( thr_acc, a,
3244 True/*isWrite*/, szB, wold, wnew,
3245 maybe_get_lastlock_initpoint(a) );
3246 }
3247 stats__msm_write_ShR_to_ShM++;
3248 goto changed;
3249 }
3250
3251 /* Shared-Modified */
3252 else if (is_SHVAL_ShM(wold)) {
3253 /* write Shared-Modified(threadset, lockset)
3254 We remain in ShM state, but add this thread to the
3255 threadset and refine the lockset accordingly.
3256 If the lockset becomes empty, complain. */
3257 WordSetID tset_old = un_SHVAL_ShM_tset(wold);
3258 WordSetID lset_old = un_SHVAL_ShM_lset(wold);
3259 WordSetID tset_new = HG_(addToWS)( univ_tsets,
3260 tset_old, (Word)thr_acc );
3261 WordSetID lset_new = HG_(intersectWS)(
3262 univ_lsets,
3263 lset_old,
3264 thr_acc->locksetW
3265 /* write ==> use only w-held locks */
3266 );
3267 /*UInt*/ wnew = mk_SHVAL_ShM( tset_new, lset_new );
3268 if (lset_old != lset_new)
3269 record_last_lock_lossage(a,lset_old,lset_new);
3270 if (HG_(isEmptyWS)(univ_lsets, lset_new)
3271 && !HG_(isEmptyWS)(univ_lsets, lset_old)) {
3272 record_error_Race( thr_acc, a,
3273 True/*isWrite*/, szB, wold, wnew,
3274 maybe_get_lastlock_initpoint(a) );
3275 }
3276 stats__msm_write_ShM_to_ShM++;
3277 goto changed;
3278 }
3279
3280 /* NoAccess */
3281 if (is_SHVAL_NoAccess(wold)) {
3282 // FIXME: complain if accessing here
3283 // FIXME: transition to Excl?
3284 if (0)
3285 VG_(printf)(
3286 "msm__handle_write_aligned_32(thr=%p, addr=%p): NoAccess\n",
3287 thr_acc, (void*)a );
3288 stats__msm_write_NoAccess++;
3289 /*NOCHANGE*/return wold;
3290 }
3291
3292 /* hmm, bogus state */
3293 VG_(printf)("msm__handle_write_aligned_32: bogus old state 0x%x\n",
3294 wold);
3295 tl_assert(0);
3296
3297 changed:
3298 if (UNLIKELY(clo_trace_level > 0)) {
3299 if (a <= clo_trace_addr && clo_trace_addr < a+szB
3300 && wold != wnew) {
3301 msm__show_state_change( thr_acc, a, szB, 'w', wold, wnew );
3302 }
3303 }
3304 return wnew;
3305}
3306
3307
3308/*----------------------------------------------------------------*/
3309/*--- Shadow value and address range handlers ---*/
3310/*----------------------------------------------------------------*/
3311
3312static void laog__pre_thread_acquires_lock ( Thread*, Lock* ); /* fwds */
3313static void laog__handle_lock_deletions ( WordSetID ); /* fwds */
3314static inline Thread* get_current_Thread ( void ); /* fwds */
3315
3316/* ------------ CacheLineF and CacheLineZ related ------------ */
3317
3318static void write_twobit_array ( UChar* arr, UWord ix, UWord b2 ) {
3319 Word bix, shft, mask, prep;
3320 tl_assert((b2 & ~3) == 0);
3321 tl_assert(ix >= 0);
3322 bix = ix >> 2;
3323 shft = 2 * (ix & 3); /* 0, 2, 4 or 6 */
3324 mask = 3 << shft;
3325 prep = b2 << shft;
3326 arr[bix] = (arr[bix] & ~mask) | prep;
3327}
3328
3329static UWord read_twobit_array ( UChar* arr, UWord ix ) {
3330 Word bix, shft;
3331 tl_assert(ix >= 0);
3332 bix = ix >> 2;
3333 shft = 2 * (ix & 3); /* 0, 2, 4 or 6 */
3334 return (arr[bix] >> shft) & 3;
3335}
3336
3337/* Given a lineZ index and a SecMap, return the CacheLineZ* and CacheLineF*
3338 for that index. */
3339static void get_ZF_by_index ( /*OUT*/CacheLineZ** zp,
3340 /*OUT*/CacheLineF** fp,
3341 SecMap* sm, Int zix ) {
3342 CacheLineZ* lineZ;
3343 tl_assert(zp);
3344 tl_assert(fp);
3345 tl_assert(zix >= 0 && zix < N_SECMAP_ZLINES);
3346 tl_assert(is_sane_SecMap(sm));
3347 lineZ = &sm->linesZ[zix];
3348 if (lineZ->dict[0] == 0) {
3349 Int fix = lineZ->dict[1];
3350 tl_assert(sm->linesF);
3351 tl_assert(sm->linesF_size > 0);
3352 tl_assert(fix >= 0 && fix < sm->linesF_size);
3353 *zp = NULL;
3354 *fp = &sm->linesF[fix];
3355 tl_assert(sm->linesF[fix].inUse);
3356 } else {
3357 *zp = lineZ;
3358 *fp = NULL;
3359 }
3360}
3361
3362static void find_ZF_for_reading ( /*OUT*/CacheLineZ** zp,
3363 /*OUT*/CacheLineF** fp, Addr tag ) {
3364 CacheLineZ* lineZ;
3365 CacheLineF* lineF;
3366 UWord zix;
3367 SecMap* sm = shmem__find_or_alloc_SecMap(tag);
3368 UWord smoff = shmem__get_SecMap_offset(tag);
3369 /* since smoff is derived from a valid tag, it should be
3370 cacheline-aligned. */
3371 tl_assert(0 == (smoff & (N_LINE_ARANGE - 1)));
3372 zix = smoff >> N_LINE_BITS;
3373 tl_assert(zix < N_SECMAP_ZLINES);
3374 lineZ = &sm->linesZ[zix];
3375 lineF = NULL;
3376 if (lineZ->dict[0] == 0) {
3377 Word fix = lineZ->dict[1];
3378 tl_assert(sm->linesF);
3379 tl_assert(sm->linesF_size > 0);
3380 tl_assert(fix >= 0 && fix < sm->linesF_size);
3381 lineF = &sm->linesF[fix];
3382 tl_assert(lineF->inUse);
3383 lineZ = NULL;
3384 }
3385 *zp = lineZ;
3386 *fp = lineF;
3387}
3388
3389static void find_Z_for_writing ( /*OUT*/SecMap** smp,
3390 /*OUT*/Word* zixp,
3391 Addr tag ) {
3392 CacheLineZ* lineZ;
3393 CacheLineF* lineF;
3394 UWord zix;
3395 SecMap* sm = shmem__find_or_alloc_SecMap(tag);
3396 UWord smoff = shmem__get_SecMap_offset(tag);
3397 /* since smoff is derived from a valid tag, it should be
3398 cacheline-aligned. */
3399 tl_assert(0 == (smoff & (N_LINE_ARANGE - 1)));
3400 zix = smoff >> N_LINE_BITS;
3401 tl_assert(zix < N_SECMAP_ZLINES);
3402 lineZ = &sm->linesZ[zix];
3403 lineF = NULL;
3404 /* If lineZ has an associated lineF, free it up. */
3405 if (lineZ->dict[0] == 0) {
3406 Word fix = lineZ->dict[1];
3407 tl_assert(sm->linesF);
3408 tl_assert(sm->linesF_size > 0);
3409 tl_assert(fix >= 0 && fix < sm->linesF_size);
3410 lineF = &sm->linesF[fix];
3411 tl_assert(lineF->inUse);
3412 lineF->inUse = False;
3413 }
3414 *smp = sm;
3415 *zixp = zix;
3416}
3417
3418static
3419void alloc_F_for_writing ( /*MOD*/SecMap* sm, /*OUT*/Word* fixp ) {
3420 Word i, new_size;
3421 CacheLineF* nyu;
3422
3423 if (sm->linesF) {
3424 tl_assert(sm->linesF_size > 0);
3425 } else {
3426 tl_assert(sm->linesF_size == 0);
3427 }
3428
3429 if (sm->linesF) {
3430 for (i = 0; i < sm->linesF_size; i++) {
3431 if (!sm->linesF[i].inUse) {
3432 *fixp = (Word)i;
3433 return;
3434 }
3435 }
3436 }
3437
3438 /* No free F line found. Expand existing array and try again. */
3439 new_size = sm->linesF_size==0 ? 1 : 2 * sm->linesF_size;
3440 nyu = hg_zalloc( new_size * sizeof(CacheLineF) );
3441 tl_assert(nyu);
3442
3443 stats__secmap_linesF_allocd += (new_size - sm->linesF_size);
3444 stats__secmap_linesF_bytes += (new_size - sm->linesF_size)
3445 * sizeof(CacheLineF);
3446
3447 if (0)
3448 VG_(printf)("SM %p: expand F array from %d to %d\n",
3449 sm, (Int)sm->linesF_size, new_size);
3450
3451 for (i = 0; i < new_size; i++)
3452 nyu[i].inUse = False;
3453
3454 if (sm->linesF) {
3455 for (i = 0; i < sm->linesF_size; i++) {
3456 tl_assert(sm->linesF[i].inUse);
3457 nyu[i] = sm->linesF[i];
3458 }
3459 VG_(memset)(sm->linesF, 0, sm->linesF_size * sizeof(CacheLineF) );
3460 hg_free(sm->linesF);
3461 }
3462
3463 sm->linesF = nyu;
3464 sm->linesF_size = new_size;
3465
3466 for (i = 0; i < sm->linesF_size; i++) {
3467 if (!sm->linesF[i].inUse) {
3468 *fixp = (Word)i;
3469 return;
3470 }
3471 }
3472
3473 /*NOTREACHED*/
3474 tl_assert(0);
3475}
3476
3477
3478/* ------------ CacheLine and implicit-tree related ------------ */
3479
3480__attribute__((unused))
3481static void pp_CacheLine ( CacheLine* cl ) {
3482 Word i;
3483 if (!cl) {
3484 VG_(printf)("pp_CacheLine(NULL)\n");
3485 return;
3486 }
3487 for (i = 0; i < N_LINE_TREES; i++)
3488 VG_(printf)(" descr: %04lx\n", (UWord)cl->descrs[i]);
3489 for (i = 0; i < N_LINE_ARANGE; i++)
3490 VG_(printf)(" sval: %08lx\n", (UWord)cl->svals[i]);
3491}
3492
3493static UChar descr_to_validbits ( UShort descr )
3494{
3495 /* a.k.a Party Time for gcc's constant folder */
3496# define DESCR(b8_7, b8_6, b8_5, b8_4, b8_3, b8_2, b8_1, b8_0, \
3497 b16_3, b32_1, b16_2, b64, b16_1, b32_0, b16_0) \
3498 ( (UShort) ( ( (b8_7) << 14) | ( (b8_6) << 13) | \
3499 ( (b8_5) << 12) | ( (b8_4) << 11) | \
3500 ( (b8_3) << 10) | ( (b8_2) << 9) | \
3501 ( (b8_1) << 8) | ( (b8_0) << 7) | \
3502 ( (b16_3) << 6) | ( (b32_1) << 5) | \
3503 ( (b16_2) << 4) | ( (b64) << 3) | \
3504 ( (b16_1) << 2) | ( (b32_0) << 1) | \
3505 ( (b16_0) << 0) ) )
3506
3507# define BYTE(bit7, bit6, bit5, bit4, bit3, bit2, bit1, bit0) \
3508 ( (UChar) ( ( (bit7) << 7) | ( (bit6) << 6) | \
3509 ( (bit5) << 5) | ( (bit4) << 4) | \
3510 ( (bit3) << 3) | ( (bit2) << 2) | \
3511 ( (bit1) << 1) | ( (bit0) << 0) ) )
3512
3513 /* these should all get folded out at compile time */
3514 tl_assert(DESCR(1,0,0,0,0,0,0,0, 0,0,0, 0, 0,0,0) == TREE_DESCR_8_7);
3515 tl_assert(DESCR(0,0,0,0,0,0,0,1, 0,0,0, 0, 0,0,0) == TREE_DESCR_8_0);
3516 tl_assert(DESCR(0,0,0,0,0,0,0,0, 1,0,0, 0, 0,0,0) == TREE_DESCR_16_3);
3517 tl_assert(DESCR(0,0,0,0,0,0,0,0, 0,1,0, 0, 0,0,0) == TREE_DESCR_32_1);
3518 tl_assert(DESCR(0,0,0,0,0,0,0,0, 0,0,1, 0, 0,0,0) == TREE_DESCR_16_2);
3519 tl_assert(DESCR(0,0,0,0,0,0,0,0, 0,0,0, 1, 0,0,0) == TREE_DESCR_64);
3520 tl_assert(DESCR(0,0,0,0,0,0,0,0, 0,0,0, 0, 1,0,0) == TREE_DESCR_16_1);
3521 tl_assert(DESCR(0,0,0,0,0,0,0,0, 0,0,0, 0, 0,1,0) == TREE_DESCR_32_0);
3522 tl_assert(DESCR(0,0,0,0,0,0,0,0, 0,0,0, 0, 0,0,1) == TREE_DESCR_16_0);
3523
3524 switch (descr) {
3525 /*
3526 +--------------------------------- TREE_DESCR_8_7
3527 | +------------------- TREE_DESCR_8_0
3528 | | +---------------- TREE_DESCR_16_3
3529 | | | +-------------- TREE_DESCR_32_1
3530 | | | | +------------ TREE_DESCR_16_2
3531 | | | | | +--------- TREE_DESCR_64
3532 | | | | | | +------ TREE_DESCR_16_1
3533 | | | | | | | +---- TREE_DESCR_32_0
3534 | | | | | | | | +-- TREE_DESCR_16_0
3535 | | | | | | | | |
3536 | | | | | | | | | GRANULARITY, 7 -> 0 */
3537 case DESCR(1,1,1,1,1,1,1,1, 0,0,0, 0, 0,0,0): /* 8 8 8 8 8 8 8 8 */
3538 return BYTE(1,1,1,1,1,1,1,1);
3539 case DESCR(1,1,0,0,1,1,1,1, 0,0,1, 0, 0,0,0): /* 8 8 16 8 8 8 8 */
3540 return BYTE(1,1,0,1,1,1,1,1);
3541 case DESCR(0,0,1,1,1,1,1,1, 1,0,0, 0, 0,0,0): /* 16 8 8 8 8 8 8 */
3542 return BYTE(0,1,1,1,1,1,1,1);
3543 case DESCR(0,0,0,0,1,1,1,1, 1,0,1, 0, 0,0,0): /* 16 16 8 8 8 8 */
3544 return BYTE(0,1,0,1,1,1,1,1);
3545
3546 case DESCR(1,1,1,1,1,1,0,0, 0,0,0, 0, 0,0,1): /* 8 8 8 8 8 8 16 */
3547 return BYTE(1,1,1,1,1,1,0,1);
3548 case DESCR(1,1,0,0,1,1,0,0, 0,0,1, 0, 0,0,1): /* 8 8 16 8 8 16 */
3549 return BYTE(1,1,0,1,1,1,0,1);
3550 case DESCR(0,0,1,1,1,1,0,0, 1,0,0, 0, 0,0,1): /* 16 8 8 8 8 16 */
3551 return BYTE(0,1,1,1,1,1,0,1);
3552 case DESCR(0,0,0,0,1,1,0,0, 1,0,1, 0, 0,0,1): /* 16 16 8 8 16 */
3553 return BYTE(0,1,0,1,1,1,0,1);
3554
3555 case DESCR(1,1,1,1,0,0,1,1, 0,0,0, 0, 1,0,0): /* 8 8 8 8 16 8 8 */
3556 return BYTE(1,1,1,1,0,1,1,1);
3557 case DESCR(1,1,0,0,0,0,1,1, 0,0,1, 0, 1,0,0): /* 8 8 16 16 8 8 */
3558 return BYTE(1,1,0,1,0,1,1,1);
3559 case DESCR(0,0,1,1,0,0,1,1, 1,0,0, 0, 1,0,0): /* 16 8 8 16 8 8 */
3560 return BYTE(0,1,1,1,0,1,1,1);
3561 case DESCR(0,0,0,0,0,0,1,1, 1,0,1, 0, 1,0,0): /* 16 16 16 8 8 */
3562 return BYTE(0,1,0,1,0,1,1,1);
3563
3564 case DESCR(1,1,1,1,0,0,0,0, 0,0,0, 0, 1,0,1): /* 8 8 8 8 16 16 */
3565 return BYTE(1,1,1,1,0,1,0,1);
3566 case DESCR(1,1,0,0,0,0,0,0, 0,0,1, 0, 1,0,1): /* 8 8 16 16 16 */
3567 return BYTE(1,1,0,1,0,1,0,1);
3568 case DESCR(0,0,1,1,0,0,0,0, 1,0,0, 0, 1,0,1): /* 16 8 8 16 16 */
3569 return BYTE(0,1,1,1,0,1,0,1);
3570 case DESCR(0,0,0,0,0,0,0,0, 1,0,1, 0, 1,0,1): /* 16 16 16 16 */
3571 return BYTE(0,1,0,1,0,1,0,1);
3572
3573 case DESCR(0,0,0,0,1,1,1,1, 0,1,0, 0, 0,0,0): /* 32 8 8 8 8 */
3574 return BYTE(0,0,0,1,1,1,1,1);
3575 case DESCR(0,0,0,0,1,1,0,0, 0,1,0, 0, 0,0,1): /* 32 8 8 16 */
3576 return BYTE(0,0,0,1,1,1,0,1);
3577 case DESCR(0,0,0,0,0,0,1,1, 0,1,0, 0, 1,0,0): /* 32 16 8 8 */
3578 return BYTE(0,0,0,1,0,1,1,1);
3579 case DESCR(0,0,0,0,0,0,0,0, 0,1,0, 0, 1,0,1): /* 32 16 16 */
3580 return BYTE(0,0,0,1,0,1,0,1);
3581
3582 case DESCR(1,1,1,1,0,0,0,0, 0,0,0, 0, 0,1,0): /* 8 8 8 8 32 */
3583 return BYTE(1,1,1,1,0,0,0,1);
3584 case DESCR(1,1,0,0,0,0,0,0, 0,0,1, 0, 0,1,0): /* 8 8 16 32 */
3585 return BYTE(1,1,0,1,0,0,0,1);
3586 case DESCR(0,0,1,1,0,0,0,0, 1,0,0, 0, 0,1,0): /* 16 8 8 32 */
3587 return BYTE(0,1,1,1,0,0,0,1);
3588 case DESCR(0,0,0,0,0,0,0,0, 1,0,1, 0, 0,1,0): /* 16 16 32 */
3589 return BYTE(0,1,0,1,0,0,0,1);
3590
3591 case DESCR(0,0,0,0,0,0,0,0, 0,1,0, 0, 0,1,0): /* 32 32 */
3592 return BYTE(0,0,0,1,0,0,0,1);
3593
3594 case DESCR(0,0,0,0,0,0,0,0, 0,0,0, 1, 0,0,0): /* 64 */
3595 return BYTE(0,0,0,0,0,0,0,1);
3596
3597 default: return BYTE(0,0,0,0,0,0,0,0);
3598 /* INVALID - any valid descr produces at least one
3599 valid bit in tree[0..7]*/
3600 }
3601 /* NOTREACHED*/
3602 tl_assert(0);
3603
3604# undef DESCR
3605# undef BYTE
3606}
3607
3608__attribute__((unused))
3609static Bool is_sane_Descr ( UShort descr ) {
3610 return descr_to_validbits(descr) != 0;
3611}
3612
3613static void sprintf_Descr ( /*OUT*/UChar* dst, UShort descr ) {
3614 VG_(sprintf)(dst,
3615 "%d%d%d%d%d%d%d%d %d%d%d %d %d%d%d",
3616 (Int)((descr & TREE_DESCR_8_7) ? 1 : 0),
3617 (Int)((descr & TREE_DESCR_8_6) ? 1 : 0),
3618 (Int)((descr & TREE_DESCR_8_5) ? 1 : 0),
3619 (Int)((descr & TREE_DESCR_8_4) ? 1 : 0),
3620 (Int)((descr & TREE_DESCR_8_3) ? 1 : 0),
3621 (Int)((descr & TREE_DESCR_8_2) ? 1 : 0),
3622 (Int)((descr & TREE_DESCR_8_1) ? 1 : 0),
3623 (Int)((descr & TREE_DESCR_8_0) ? 1 : 0),
3624 (Int)((descr & TREE_DESCR_16_3) ? 1 : 0),
3625 (Int)((descr & TREE_DESCR_32_1) ? 1 : 0),
3626 (Int)((descr & TREE_DESCR_16_2) ? 1 : 0),
3627 (Int)((descr & TREE_DESCR_64) ? 1 : 0),
3628 (Int)((descr & TREE_DESCR_16_1) ? 1 : 0),
3629 (Int)((descr & TREE_DESCR_32_0) ? 1 : 0),
3630 (Int)((descr & TREE_DESCR_16_0) ? 1 : 0)
3631 );
3632}
3633static void sprintf_Byte ( /*OUT*/UChar* dst, UChar byte ) {
3634 VG_(sprintf)(dst, "%d%d%d%d%d%d%d%d",
3635 (Int)((byte & 128) ? 1 : 0),
3636 (Int)((byte & 64) ? 1 : 0),
3637 (Int)((byte & 32) ? 1 : 0),
3638 (Int)((byte & 16) ? 1 : 0),
3639 (Int)((byte & 8) ? 1 : 0),
3640 (Int)((byte & 4) ? 1 : 0),
3641 (Int)((byte & 2) ? 1 : 0),
3642 (Int)((byte & 1) ? 1 : 0)
3643 );
3644}
3645
3646static Bool is_sane_Descr_and_Tree ( UShort descr, UInt* tree ) {
3647 Word i;
3648 UChar validbits = descr_to_validbits(descr);
3649 UChar buf[128], buf2[128];
3650 if (validbits == 0)
3651 goto bad;
3652 for (i = 0; i < 8; i++) {
3653 if (validbits & (1<<i)) {
3654 if (!is_SHVAL_valid(tree[i]))
3655 goto bad;
3656 } else {
3657 if (tree[i] != 0)
3658 goto bad;
3659 }
3660 }
3661 return True;
3662 bad:
3663 sprintf_Descr( buf, descr );
3664 sprintf_Byte( buf2, validbits );
3665 VG_(printf)("is_sane_Descr_and_Tree: bad tree {\n");
3666 VG_(printf)(" validbits 0x%02lx %s\n", (UWord)validbits, buf2);
3667 VG_(printf)(" descr 0x%04lx %s\n", (UWord)descr, buf);
3668 for (i = 0; i < 8; i++)
3669 VG_(printf)(" [%ld] 0x%08x\n", i, tree[i]);
3670 VG_(printf)("}\n");
3671 return 0;
3672}
3673
3674
3675static Bool is_sane_CacheLine ( CacheLine* cl )
3676{
3677 Word tno, cloff;
3678
3679 if (!cl) goto bad;
3680
3681 for (tno = 0, cloff = 0; tno < N_LINE_TREES; tno++, cloff += 8) {
3682 UShort descr = cl->descrs[tno];
3683 UInt* tree = &cl->svals[cloff];
3684 if (!is_sane_Descr_and_Tree(descr, tree))
3685 goto bad;
3686 }
3687 tl_assert(cloff == N_LINE_ARANGE);
3688 return True;
3689 bad:
3690 pp_CacheLine(cl);
3691 return False;
3692}
3693
3694
3695static UShort normalise_tree ( /*MOD*/UInt* tree ) {
3696 Word i;
3697 UShort descr;
3698 /* pre: incoming tree[0..7] does not have any invalid shvals, in
3699 particular no zeroes. */
3700 for (i = 0; i < 8; i++)
3701 tl_assert(tree[i] != 0);
3702
3703 descr = TREE_DESCR_8_7 | TREE_DESCR_8_6 | TREE_DESCR_8_5
3704 | TREE_DESCR_8_4 | TREE_DESCR_8_3 | TREE_DESCR_8_2
3705 | TREE_DESCR_8_1 | TREE_DESCR_8_0;
3706 /* build 16-bit layer */
3707 if (tree[1] == tree[0]) {
3708 tree[1] = 0/*INVALID*/;
3709 descr &= ~(TREE_DESCR_8_1 | TREE_DESCR_8_0);
3710 descr |= TREE_DESCR_16_0;
3711 }
3712 if (tree[3] == tree[2]) {
3713 tree[3] = 0/*INVALID*/;
3714 descr &= ~(TREE_DESCR_8_3 | TREE_DESCR_8_2);
3715 descr |= TREE_DESCR_16_1;
3716 }
3717 if (tree[5] == tree[4]) {
3718 tree[5] = 0/*INVALID*/;
3719 descr &= ~(TREE_DESCR_8_5 | TREE_DESCR_8_4);
3720 descr |= TREE_DESCR_16_2;
3721 }
3722 if (tree[7] == tree[6]) {
3723 tree[7] = 0/*INVALID*/;
3724 descr &= ~(TREE_DESCR_8_7 | TREE_DESCR_8_6);
3725 descr |= TREE_DESCR_16_3;
3726 }
3727 /* build 32-bit layer */
3728 if (tree[2] == tree[0]
3729 && (descr & TREE_DESCR_16_1) && (descr & TREE_DESCR_16_0)) {
3730 tree[2] = 0; /* [3,1] must already be 0 */
3731 descr &= ~(TREE_DESCR_16_1 | TREE_DESCR_16_0);
3732 descr |= TREE_DESCR_32_0;
3733 }
3734 if (tree[6] == tree[4]
3735 && (descr & TREE_DESCR_16_3) && (descr & TREE_DESCR_16_2)) {
3736 tree[6] = 0; /* [7,5] must already be 0 */
3737 descr &= ~(TREE_DESCR_16_3 | TREE_DESCR_16_2);
3738 descr |= TREE_DESCR_32_1;
3739 }
3740 /* build 64-bit layer */
3741 if (tree[4] == tree[0]
3742 && (descr & TREE_DESCR_32_1) && (descr & TREE_DESCR_32_0)) {
3743 tree[4] = 0; /* [7,6,5,3,2,1] must already be 0 */
3744 descr &= ~(TREE_DESCR_32_1 | TREE_DESCR_32_0);
3745 descr |= TREE_DESCR_64;
3746 }
3747 return descr;
3748}
3749
3750/* This takes a cacheline where all the data is at the leaves
3751 (w8[..]) and builds a correctly normalised tree. */
3752static void normalise_CacheLine ( /*MOD*/CacheLine* cl )
3753{
3754 Word tno, cloff;
3755 for (tno = 0, cloff = 0; tno < N_LINE_TREES; tno++, cloff += 8) {
3756 UInt* tree = &cl->svals[cloff];
3757 cl->descrs[tno] = normalise_tree( tree );
3758 }
3759 tl_assert(cloff == N_LINE_ARANGE);
3760 if (SCE_CACHELINE)
3761 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
3762 stats__cline_normalises++;
3763}
3764
3765
3766static
3767UInt* sequentialise_tree ( /*MOD*/UInt* dst, /*OUT*/Bool* anyShared,
3768 UShort descr, UInt* tree ) {
3769 UInt* dst0 = dst;
3770 *anyShared = False;
3771
3772# define PUT(_n,_v) \
3773 do { Word i; \
3774 if (is_SHVAL_Sh(_v)) \
3775 *anyShared = True; \
3776 for (i = 0; i < (_n); i++) \
3777 *dst++ = (_v); \
3778 } while (0)
3779
3780 /* byte 0 */
3781 if (descr & TREE_DESCR_64) PUT(8, tree[0]); else
3782 if (descr & TREE_DESCR_32_0) PUT(4, tree[0]); else
3783 if (descr & TREE_DESCR_16_0) PUT(2, tree[0]); else
3784 if (descr & TREE_DESCR_8_0) PUT(1, tree[0]);
3785 /* byte 1 */
3786 if (descr & TREE_DESCR_8_1) PUT(1, tree[1]);
3787 /* byte 2 */
3788 if (descr & TREE_DESCR_16_1) PUT(2, tree[2]); else
3789 if (descr & TREE_DESCR_8_2) PUT(1, tree[2]);
3790 /* byte 3 */
3791 if (descr & TREE_DESCR_8_3) PUT(1, tree[3]);
3792 /* byte 4 */
3793 if (descr & TREE_DESCR_32_1) PUT(4, tree[4]); else
3794 if (descr & TREE_DESCR_16_2) PUT(2, tree[4]); else
3795 if (descr & TREE_DESCR_8_4) PUT(1, tree[4]);
3796 /* byte 5 */
3797 if (descr & TREE_DESCR_8_5) PUT(1, tree[5]);
3798 /* byte 6 */
3799 if (descr & TREE_DESCR_16_3) PUT(2, tree[6]); else
3800 if (descr & TREE_DESCR_8_6) PUT(1, tree[6]);
3801 /* byte 7 */
3802 if (descr & TREE_DESCR_8_7) PUT(1, tree[7]);
3803
3804# undef PUT
3805
3806 tl_assert( (((Char*)dst) - ((Char*)dst0)) == 8 * sizeof(UInt) );
3807 return dst;
3808}
3809
3810/* Write the cacheline 'wix' to backing store. Where it ends up
3811 is determined by its tag field. */
3812static
3813Bool sequentialise_CacheLine ( /*OUT*/UInt* dst, Word nDst, CacheLine* src )
3814{
3815 Word tno, cloff;
3816 Bool anyShared = False;
3817 UInt* dst0 = dst;
3818
3819 for (tno = 0, cloff = 0; tno < N_LINE_TREES; tno++, cloff += 8) {
3820 UShort descr = src->descrs[tno];
3821 UInt* tree = &src->svals[cloff];
3822 Bool bTmp = False;
3823 dst = sequentialise_tree ( dst, &bTmp, descr, tree );
3824 anyShared |= bTmp;
3825 }
3826 tl_assert(cloff == N_LINE_ARANGE);
3827
3828 /* Assert we wrote N_LINE_ARANGE shadow values. */
3829 tl_assert( ((HChar*)dst) - ((HChar*)dst0)
3830 == nDst * sizeof(UInt) );
3831
3832 return anyShared;
3833}
3834
3835
3836static __attribute__((noinline)) void cacheline_wback ( UWord wix )
3837{
3838 Word i, j;
3839 Bool anyShared = False;
3840 Addr tag;
3841 SecMap* sm;
3842 CacheLine* cl;
3843 CacheLineZ* lineZ;
3844 CacheLineF* lineF;
3845 Word zix, fix;
3846 UInt shvals[N_LINE_ARANGE];
3847 UInt sv;
3848
3849 if (0)
3850 VG_(printf)("scache wback line %d\n", (Int)wix);
3851
3852 tl_assert(wix >= 0 && wix < N_WAY_NENT);
3853
3854 tag = cache_shmem.tags0[wix];
3855 cl = &cache_shmem.lyns0[wix];
3856
3857 /* The cache line may have been invalidated; if so, ignore it. */
3858 if (!is_valid_scache_tag(tag))
3859 return;
3860
3861 /* Where are we going to put it? */
3862 sm = NULL;
3863 lineZ = NULL;
3864 lineF = NULL;
3865 zix = fix = -1;
3866
3867 find_Z_for_writing( &sm, &zix, tag );
3868 tl_assert(sm);
3869 tl_assert(zix >= 0 && zix < N_SECMAP_ZLINES);
3870 lineZ = &sm->linesZ[zix];
3871
3872 /* Generate the data to be stored */
3873 if (SCE_CACHELINE)
3874 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
3875 anyShared = sequentialise_CacheLine( shvals, N_LINE_ARANGE, cl );
3876
3877 lineZ->dict[0] = lineZ->dict[1]
3878 = lineZ->dict[2] = lineZ->dict[3] = 0;
3879
3880 for (i = 0; i < N_LINE_ARANGE; i++) {
3881
3882 sv = shvals[i];
3883 for (j = 0; j < 4; j++) {
3884 if (sv == lineZ->dict[j])
3885 goto dict_ok;
3886 }
3887 for (j = 0; j < 4; j++) {
3888 if (lineZ->dict[j] == 0)
3889 break;
3890 }
3891 tl_assert(j >= 0 && j <= 4);
3892 if (j == 4) break; /* we'll have to use the f rep */
3893 tl_assert(is_SHVAL_valid(sv));
3894 lineZ->dict[j] = sv;
3895 dict_ok:
3896 write_twobit_array( lineZ->ix2s, i, j );
3897
3898 }
3899
3900 tl_assert(i >= 0 && i <= N_LINE_ARANGE);
3901
3902 if (i < N_LINE_ARANGE) {
3903 /* cannot use the compressed rep. Use f rep instead. */
3904 alloc_F_for_writing( sm, &fix );
3905 tl_assert(sm->linesF);
3906 tl_assert(sm->linesF_size > 0);
3907 tl_assert(fix >= 0 && fix < sm->linesF_size);
3908 lineF = &sm->linesF[fix];
3909 tl_assert(!lineF->inUse);
3910 lineZ->dict[0] = lineZ->dict[2] = lineZ->dict[3] = 0;
3911 lineZ->dict[1] = (UInt)fix;
3912 lineF->inUse = True;
3913 for (i = 0; i < N_LINE_ARANGE; i++) {
3914 sv = shvals[i];
3915 tl_assert(is_SHVAL_valid(sv));
3916 lineF->w32s[i] = sv;
3917 }
3918 stats__cache_F_wbacks++;
3919 } else {
3920 stats__cache_Z_wbacks++;
3921 }
3922
3923 if (anyShared)
3924 sm->mbHasShared = True;
3925
3926 /* mb_tidy_one_cacheline(); */
3927}
3928
3929/* Fetch the cacheline 'wix' from the backing store. The tag
3930 associated with 'wix' is assumed to have already been filled in;
3931 hence that is used to determine where in the backing store to read
3932 from. */
3933static __attribute__((noinline)) void cacheline_fetch ( UWord wix )
3934{
3935 Word i;
3936 Addr tag;
3937 CacheLine* cl;
3938 CacheLineZ* lineZ;
3939 CacheLineF* lineF;
3940
3941 if (0)
3942 VG_(printf)("scache fetch line %d\n", (Int)wix);
3943
3944 tl_assert(wix >= 0 && wix < N_WAY_NENT);
3945
3946 tag = cache_shmem.tags0[wix];
3947 cl = &cache_shmem.lyns0[wix];
3948
3949 /* reject nonsense requests */
3950 tl_assert(is_valid_scache_tag(tag));
3951
3952 lineZ = NULL;
3953 lineF = NULL;
3954 find_ZF_for_reading( &lineZ, &lineF, tag );
3955 tl_assert( (lineZ && !lineF) || (!lineZ && lineF) );
3956
3957 /* expand the data into the bottom layer of the tree, then get
3958 cacheline_normalise to build the descriptor array. */
3959 if (lineF) {
3960 tl_assert(lineF->inUse);
3961 for (i = 0; i < N_LINE_ARANGE; i++) {
3962 cl->svals[i] = lineF->w32s[i];
3963 }
3964 stats__cache_F_fetches++;
3965 } else {
3966 for (i = 0; i < N_LINE_ARANGE; i++) {
3967 UInt sv;
3968 UWord ix = read_twobit_array( lineZ->ix2s, i );
3969 tl_assert(ix >= 0 && ix <= 3);
3970 sv = lineZ->dict[ix];
3971 tl_assert(sv != 0);
3972 cl->svals[i] = sv;
3973 }
3974 stats__cache_Z_fetches++;
3975 }
3976 normalise_CacheLine( cl );
3977}
3978
3979static void shmem__invalidate_scache ( void ) {
3980 Word wix;
3981 if (0) VG_(printf)("scache inval\n");
3982 tl_assert(!is_valid_scache_tag(1));
3983 for (wix = 0; wix < N_WAY_NENT; wix++) {
3984 cache_shmem.tags0[wix] = 1/*INVALID*/;
3985 }
3986 stats__cache_invals++;
3987}
3988
3989static void shmem__flush_and_invalidate_scache ( void ) {
3990 Word wix;
3991 Addr tag;
3992 if (0) VG_(printf)("scache flush and invalidate\n");
3993 tl_assert(!is_valid_scache_tag(1));
3994 for (wix = 0; wix < N_WAY_NENT; wix++) {
3995 tag = cache_shmem.tags0[wix];
3996 if (tag == 1/*INVALID*/) {
3997 /* already invalid; nothing to do */
3998 } else {
3999 tl_assert(is_valid_scache_tag(tag));
4000 cacheline_wback( wix );
4001 }
4002 cache_shmem.tags0[wix] = 1/*INVALID*/;
4003 }
4004 stats__cache_flushes++;
4005 stats__cache_invals++;
4006}
4007
4008
4009/* ------------ Basic shadow memory read/write ops ------------ */
4010
4011static inline Bool aligned16 ( Addr a ) {
4012 return 0 == (a & 1);
4013}
4014static inline Bool aligned32 ( Addr a ) {
4015 return 0 == (a & 3);
4016}
4017static inline Bool aligned64 ( Addr a ) {
4018 return 0 == (a & 7);
4019}
4020static inline UWord get_cacheline_offset ( Addr a ) {
4021 return (UWord)(a & (N_LINE_ARANGE - 1));
4022}
4023static inline UWord get_treeno ( Addr a ) {
4024 return get_cacheline_offset(a) >> 3;
4025}
4026static inline UWord get_tree_offset ( Addr a ) {
4027 return a & 7;
4028}
4029
4030static __attribute__((noinline))
4031 CacheLine* get_cacheline_MISS ( Addr a ); /* fwds */
4032static inline CacheLine* get_cacheline ( Addr a )
4033{
4034 /* tag is 'a' with the in-line offset masked out,
4035 eg a[31]..a[4] 0000 */
4036 Addr tag = a & ~(N_LINE_ARANGE - 1);
4037 UWord wix = (a >> N_LINE_BITS) & (N_WAY_NENT - 1);
4038 stats__cache_totrefs++;
4039 if (LIKELY(tag == cache_shmem.tags0[wix])) {
4040 return &cache_shmem.lyns0[wix];
4041 } else {
4042 return get_cacheline_MISS( a );
4043 }
4044}
4045
4046static __attribute__((noinline))
4047 CacheLine* get_cacheline_MISS ( Addr a )
4048{
4049 /* tag is 'a' with the in-line offset masked out,
4050 eg a[31]..a[4] 0000 */
4051
4052 CacheLine* cl;
4053 Addr* tag_old_p;
4054 Addr tag = a & ~(N_LINE_ARANGE - 1);
4055 UWord wix = (a >> N_LINE_BITS) & (N_WAY_NENT - 1);
4056
4057 tl_assert(tag != cache_shmem.tags0[wix]);
4058
4059 /* Dump the old line into the backing store. */
4060 stats__cache_totmisses++;
4061
4062 cl = &cache_shmem.lyns0[wix];
4063 tag_old_p = &cache_shmem.tags0[wix];
4064
4065 if (is_valid_scache_tag( *tag_old_p )) {
4066 /* EXPENSIVE and REDUNDANT: callee does it */
4067 if (SCE_CACHELINE)
4068 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4069 cacheline_wback( wix );
4070 }
4071 /* and reload the new one */
4072 *tag_old_p = tag;
4073 cacheline_fetch( wix );
4074 if (SCE_CACHELINE)
4075 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4076 return cl;
4077}
4078
4079static UShort pulldown_to_32 ( /*MOD*/UInt* tree, UWord toff, UShort descr ) {
4080 stats__cline_64to32pulldown++;
4081 switch (toff) {
4082 case 0: case 4:
4083 tl_assert(descr & TREE_DESCR_64);
4084 tree[4] = tree[0];
4085 descr &= ~TREE_DESCR_64;
4086 descr |= (TREE_DESCR_32_1 | TREE_DESCR_32_0);
4087 break;
4088 default:
4089 tl_assert(0);
4090 }
4091 return descr;
4092}
4093
4094static UShort pulldown_to_16 ( /*MOD*/UInt* tree, UWord toff, UShort descr ) {
4095 stats__cline_32to16pulldown++;
4096 switch (toff) {
4097 case 0: case 2:
4098 if (!(descr & TREE_DESCR_32_0)) {
4099 descr = pulldown_to_32(tree, 0, descr);
4100 }
4101 tl_assert(descr & TREE_DESCR_32_0);
4102 tree[2] = tree[0];
4103 descr &= ~TREE_DESCR_32_0;
4104 descr |= (TREE_DESCR_16_1 | TREE_DESCR_16_0);
4105 break;
4106 case 4: case 6:
4107 if (!(descr & TREE_DESCR_32_1)) {
4108 descr = pulldown_to_32(tree, 4, descr);
4109 }
4110 tl_assert(descr & TREE_DESCR_32_1);
4111 tree[6] = tree[4];
4112 descr &= ~TREE_DESCR_32_1;
4113 descr |= (TREE_DESCR_16_3 | TREE_DESCR_16_2);
4114 break;
4115 default:
4116 tl_assert(0);
4117 }
4118 return descr;
4119}
4120
4121static UShort pulldown_to_8 ( /*MOD*/UInt* tree, UWord toff, UShort descr ) {
4122 stats__cline_16to8pulldown++;
4123 switch (toff) {
4124 case 0: case 1:
4125 if (!(descr & TREE_DESCR_16_0)) {
4126 descr = pulldown_to_16(tree, 0, descr);
4127 }
4128 tl_assert(descr & TREE_DESCR_16_0);
4129 tree[1] = tree[0];
4130 descr &= ~TREE_DESCR_16_0;
4131 descr |= (TREE_DESCR_8_1 | TREE_DESCR_8_0);
4132 break;
4133 case 2: case 3:
4134 if (!(descr & TREE_DESCR_16_1)) {
4135 descr = pulldown_to_16(tree, 2, descr);
4136 }
4137 tl_assert(descr & TREE_DESCR_16_1);
4138 tree[3] = tree[2];
4139 descr &= ~TREE_DESCR_16_1;
4140 descr |= (TREE_DESCR_8_3 | TREE_DESCR_8_2);
4141 break;
4142 case 4: case 5:
4143 if (!(descr & TREE_DESCR_16_2)) {
4144 descr = pulldown_to_16(tree, 4, descr);
4145 }
4146 tl_assert(descr & TREE_DESCR_16_2);
4147 tree[5] = tree[4];
4148 descr &= ~TREE_DESCR_16_2;
4149 descr |= (TREE_DESCR_8_5 | TREE_DESCR_8_4);
4150 break;
4151 case 6: case 7:
4152 if (!(descr & TREE_DESCR_16_3)) {
4153 descr = pulldown_to_16(tree, 6, descr);
4154 }
4155 tl_assert(descr & TREE_DESCR_16_3);
4156 tree[7] = tree[6];
4157 descr &= ~TREE_DESCR_16_3;
4158 descr |= (TREE_DESCR_8_7 | TREE_DESCR_8_6);
4159 break;
4160 default:
4161 tl_assert(0);
4162 }
4163 return descr;
4164}
4165
4166
4167static UShort pullup_descr_to_16 ( UShort descr, UWord toff ) {
4168 UShort mask;
4169 switch (toff) {
4170 case 0:
4171 mask = TREE_DESCR_8_1 | TREE_DESCR_8_0;
4172 tl_assert( (descr & mask) == mask );
4173 descr &= ~mask;
4174 descr |= TREE_DESCR_16_0;
4175 break;
4176 case 2:
4177 mask = TREE_DESCR_8_3 | TREE_DESCR_8_2;
4178 tl_assert( (descr & mask) == mask );
4179 descr &= ~mask;
4180 descr |= TREE_DESCR_16_1;
4181 break;
4182 case 4:
4183 mask = TREE_DESCR_8_5 | TREE_DESCR_8_4;
4184 tl_assert( (descr & mask) == mask );
4185 descr &= ~mask;
4186 descr |= TREE_DESCR_16_2;
4187 break;
4188 case 6:
4189 mask = TREE_DESCR_8_7 | TREE_DESCR_8_6;
4190 tl_assert( (descr & mask) == mask );
4191 descr &= ~mask;
4192 descr |= TREE_DESCR_16_3;
4193 break;
4194 default:
4195 tl_assert(0);
4196 }
4197 return descr;
4198}
4199
4200static UShort pullup_descr_to_32 ( UShort descr, UWord toff ) {
4201 UShort mask;
4202 switch (toff) {
4203 case 0:
4204 if (!(descr & TREE_DESCR_16_0))
4205 descr = pullup_descr_to_16(descr, 0);
4206 if (!(descr & TREE_DESCR_16_1))
4207 descr = pullup_descr_to_16(descr, 2);
4208 mask = TREE_DESCR_16_1 | TREE_DESCR_16_0;
4209 tl_assert( (descr & mask) == mask );
4210 descr &= ~mask;
4211 descr |= TREE_DESCR_32_0;
4212 break;
4213 case 4:
4214 if (!(descr & TREE_DESCR_16_2))
4215 descr = pullup_descr_to_16(descr, 4);
4216 if (!(descr & TREE_DESCR_16_3))
4217 descr = pullup_descr_to_16(descr, 6);
4218 mask = TREE_DESCR_16_3 | TREE_DESCR_16_2;
4219 tl_assert( (descr & mask) == mask );
4220 descr &= ~mask;
4221 descr |= TREE_DESCR_32_1;
4222 break;
4223 default:
4224 tl_assert(0);
4225 }
4226 return descr;
4227}
4228
4229static Bool valid_value_is_above_me_32 ( UShort descr, UWord toff ) {
4230 switch (toff) {
4231 case 0: case 4:
4232 return 0 != (descr & TREE_DESCR_64);
4233 default:
4234 tl_assert(0);
4235 }
4236}
4237
4238static Bool valid_value_is_below_me_16 ( UShort descr, UWord toff ) {
4239 switch (toff) {
4240 case 0:
4241 return 0 != (descr & (TREE_DESCR_8_1 | TREE_DESCR_8_0));
4242 case 2:
4243 return 0 != (descr & (TREE_DESCR_8_3 | TREE_DESCR_8_2));
4244 case 4:
4245 return 0 != (descr & (TREE_DESCR_8_5 | TREE_DESCR_8_4));
4246 case 6:
4247 return 0 != (descr & (TREE_DESCR_8_7 | TREE_DESCR_8_6));
4248 default:
4249 tl_assert(0);
4250 }
4251}
4252
4253static void shadow_mem_read8 ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4254 CacheLine* cl;
4255 UWord cloff, tno, toff;
4256 UInt svOld, svNew;
4257 UShort descr;
4258 stats__cline_read8s++;
4259 cl = get_cacheline(a);
4260 cloff = get_cacheline_offset(a);
4261 tno = get_treeno(a);
4262 toff = get_tree_offset(a); /* == 0 .. 7 */
4263 descr = cl->descrs[tno];
4264 if (UNLIKELY( !(descr & (TREE_DESCR_8_0 << toff)) )) {
4265 UInt* tree = &cl->svals[tno << 3];
4266 cl->descrs[tno] = pulldown_to_8(tree, toff, descr);
4267 if (SCE_CACHELINE)
4268 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4269 }
4270 svOld = cl->svals[cloff];
4271 svNew = msm__handle_read( thr_acc, a, svOld, 1 );
4272 cl->svals[cloff] = svNew;
4273}
4274static void shadow_mem_read16 ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4275 CacheLine* cl;
4276 UWord cloff, tno, toff;
4277 UInt svOld, svNew;
4278 UShort descr;
4279 stats__cline_read16s++;
4280 if (UNLIKELY(!aligned16(a))) goto slowcase;
4281 cl = get_cacheline(a);
4282 cloff = get_cacheline_offset(a);
4283 tno = get_treeno(a);
4284 toff = get_tree_offset(a); /* == 0, 2, 4 or 6 */
4285 descr = cl->descrs[tno];
4286 if (UNLIKELY( !(descr & (TREE_DESCR_16_0 << toff)) )) {
4287 if (valid_value_is_below_me_16(descr, toff)) {
4288 goto slowcase;
4289 } else {
4290 UInt* tree = &cl->svals[tno << 3];
4291 cl->descrs[tno] = pulldown_to_16(tree, toff, descr);
4292 }
4293 if (SCE_CACHELINE)
4294 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4295 }
4296 svOld = cl->svals[cloff];
4297 svNew = msm__handle_read( thr_acc, a, svOld, 2 );
4298 cl->svals[cloff] = svNew;
4299 return;
4300 slowcase: /* misaligned, or must go further down the tree */
4301 stats__cline_16to8splits++;
4302 shadow_mem_read8( thr_acc, a + 0, 0/*unused*/ );
4303 shadow_mem_read8( thr_acc, a + 1, 0/*unused*/ );
4304}
4305
4306__attribute__((noinline))
4307static void shadow_mem_read32_SLOW ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4308 CacheLine* cl;
4309 UWord cloff, tno, toff;
4310 UInt svOld, svNew;
4311 UShort descr;
4312 if (UNLIKELY(!aligned32(a))) goto slowcase;
4313 cl = get_cacheline(a);
4314 cloff = get_cacheline_offset(a);
4315 tno = get_treeno(a);
4316 toff = get_tree_offset(a); /* == 0 or 4 */
4317 descr = cl->descrs[tno];
4318 if (UNLIKELY( !(descr & (TREE_DESCR_32_0 << toff)) )) {
4319 if (valid_value_is_above_me_32(descr, toff)) {
4320 UInt* tree = &cl->svals[tno << 3];
4321 cl->descrs[tno] = pulldown_to_32(tree, toff, descr);
4322 } else {
4323 goto slowcase;
4324 }
4325 if (SCE_CACHELINE)
4326 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4327 }
4328 svOld = cl->svals[cloff];
4329 svNew = msm__handle_read( thr_acc, a, svOld, 4 );
4330 cl->svals[cloff] = svNew;
4331 return;
4332 slowcase: /* misaligned, or must go further down the tree */
4333 stats__cline_32to16splits++;
4334 shadow_mem_read16( thr_acc, a + 0, 0/*unused*/ );
4335 shadow_mem_read16( thr_acc, a + 2, 0/*unused*/ );
4336}
4337inline
4338static void shadow_mem_read32 ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4339 CacheLine* cl;
4340 UWord cloff, tno, toff;
4341 UShort descr;
4342 stats__cline_read32s++;
4343 if (UNLIKELY(!aligned32(a))) goto slowcase;
4344 cl = get_cacheline(a);
4345 cloff = get_cacheline_offset(a);
4346 tno = get_treeno(a);
4347 toff = get_tree_offset(a); /* == 0 or 4 */
4348 descr = cl->descrs[tno];
4349 if (UNLIKELY( !(descr & (TREE_DESCR_32_0 << toff)) )) goto slowcase;
4350 { UInt* p = &cl->svals[cloff];
4351 *p = msm__handle_read( thr_acc, a, *p, 4 );
4352 }
4353 return;
4354 slowcase: /* misaligned, or not at this level in the tree */
4355 shadow_mem_read32_SLOW( thr_acc, a, uuOpaque );
4356}
4357
4358inline
4359static void shadow_mem_read64 ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4360 CacheLine* cl;
4361 UWord cloff, tno, toff;
4362 UInt svOld, svNew;
4363 UShort descr;
4364 stats__cline_read64s++;
4365 if (UNLIKELY(!aligned64(a))) goto slowcase;
4366 cl = get_cacheline(a);
4367 cloff = get_cacheline_offset(a);
4368 tno = get_treeno(a);
4369 toff = get_tree_offset(a); /* == 0, unused */
4370 descr = cl->descrs[tno];
4371 if (UNLIKELY( !(descr & TREE_DESCR_64) )) {
4372 goto slowcase;
4373 }
4374 svOld = cl->svals[cloff];
4375 svNew = msm__handle_read( thr_acc, a, svOld, 8 );
4376 cl->svals[cloff] = svNew;
4377 return;
4378 slowcase: /* misaligned, or must go further down the tree */
4379 stats__cline_64to32splits++;
4380 shadow_mem_read32( thr_acc, a + 0, 0/*unused*/ );
4381 shadow_mem_read32( thr_acc, a + 4, 0/*unused*/ );
4382}
4383
4384static void shadow_mem_write8 ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4385 CacheLine* cl;
4386 UWord cloff, tno, toff;
4387 UInt svOld, svNew;
4388 UShort descr;
4389 stats__cline_write8s++;
4390 cl = get_cacheline(a);
4391 cloff = get_cacheline_offset(a);
4392 tno = get_treeno(a);
4393 toff = get_tree_offset(a); /* == 0 .. 7 */
4394 descr = cl->descrs[tno];
4395 if (UNLIKELY( !(descr & (TREE_DESCR_8_0 << toff)) )) {
4396 UInt* tree = &cl->svals[tno << 3];
4397 cl->descrs[tno] = pulldown_to_8(tree, toff, descr);
4398 if (SCE_CACHELINE)
4399 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4400 }
4401 svOld = cl->svals[cloff];
4402 svNew = msm__handle_write( thr_acc, a, svOld, 1 );
4403 cl->svals[cloff] = svNew;
4404}
4405static void shadow_mem_write16 ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4406 CacheLine* cl;
4407 UWord cloff, tno, toff;
4408 UInt svOld, svNew;
4409 UShort descr;
4410 stats__cline_write16s++;
4411 if (UNLIKELY(!aligned16(a))) goto slowcase;
4412 cl = get_cacheline(a);
4413 cloff = get_cacheline_offset(a);
4414 tno = get_treeno(a);
4415 toff = get_tree_offset(a); /* == 0, 2, 4 or 6 */
4416 descr = cl->descrs[tno];
4417 if (UNLIKELY( !(descr & (TREE_DESCR_16_0 << toff)) )) {
4418 if (valid_value_is_below_me_16(descr, toff)) {
4419 goto slowcase;
4420 } else {
4421 UInt* tree = &cl->svals[tno << 3];
4422 cl->descrs[tno] = pulldown_to_16(tree, toff, descr);
4423 }
4424 if (SCE_CACHELINE)
4425 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4426 }
4427 svOld = cl->svals[cloff];
4428 svNew = msm__handle_write( thr_acc, a, svOld, 2 );
4429 cl->svals[cloff] = svNew;
4430 return;
4431 slowcase: /* misaligned, or must go further down the tree */
4432 stats__cline_16to8splits++;
4433 shadow_mem_write8( thr_acc, a + 0, 0/*unused*/ );
4434 shadow_mem_write8( thr_acc, a + 1, 0/*unused*/ );
4435}
4436
4437__attribute__((noinline))
4438static void shadow_mem_write32_SLOW ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4439 CacheLine* cl;
4440 UWord cloff, tno, toff;
4441 UInt svOld, svNew;
4442 UShort descr;
4443 if (UNLIKELY(!aligned32(a))) goto slowcase;
4444 cl = get_cacheline(a);
4445 cloff = get_cacheline_offset(a);
4446 tno = get_treeno(a);
4447 toff = get_tree_offset(a); /* == 0 or 4 */
4448 descr = cl->descrs[tno];
4449 if (UNLIKELY( !(descr & (TREE_DESCR_32_0 << toff)) )) {
4450 if (valid_value_is_above_me_32(descr, toff)) {
4451 UInt* tree = &cl->svals[tno << 3];
4452 cl->descrs[tno] = pulldown_to_32(tree, toff, descr);
4453 } else {
4454 goto slowcase;
4455 }
4456 if (SCE_CACHELINE)
4457 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4458 }
4459 svOld = cl->svals[cloff];
4460 svNew = msm__handle_write( thr_acc, a, svOld, 4 );
4461 cl->svals[cloff] = svNew;
4462 return;
4463 slowcase: /* misaligned, or must go further down the tree */
4464 stats__cline_32to16splits++;
4465 shadow_mem_write16( thr_acc, a + 0, 0/*unused*/ );
4466 shadow_mem_write16( thr_acc, a + 2, 0/*unused*/ );
4467}
4468inline
4469static void shadow_mem_write32 ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4470 CacheLine* cl;
4471 UWord cloff, tno, toff;
4472 UShort descr;
4473 stats__cline_write32s++;
4474 if (UNLIKELY(!aligned32(a))) goto slowcase;
4475 cl = get_cacheline(a);
4476 cloff = get_cacheline_offset(a);
4477 tno = get_treeno(a);
4478 toff = get_tree_offset(a); /* == 0 or 4 */
4479 descr = cl->descrs[tno];
4480 if (UNLIKELY( !(descr & (TREE_DESCR_32_0 << toff)) )) goto slowcase;
4481 { UInt* p = &cl->svals[cloff];
4482 *p = msm__handle_write( thr_acc, a, *p, 4 );
4483 }
4484 return;
4485 slowcase: /* misaligned, or must go further down the tree */
4486 shadow_mem_write32_SLOW( thr_acc, a, uuOpaque );
4487}
4488
4489inline
4490static void shadow_mem_write64 ( Thread* thr_acc, Addr a, UInt uuOpaque ) {
4491 CacheLine* cl;
4492 UWord cloff, tno, toff;
4493 UInt svOld, svNew;
4494 UShort descr;
4495 stats__cline_write64s++;
4496 if (UNLIKELY(!aligned64(a))) goto slowcase;
4497 cl = get_cacheline(a);
4498 cloff = get_cacheline_offset(a);
4499 tno = get_treeno(a);
4500 toff = get_tree_offset(a); /* == 0, unused */
4501 descr = cl->descrs[tno];
4502 if (UNLIKELY( !(descr & TREE_DESCR_64) )) {
4503 goto slowcase;
4504 }
4505 svOld = cl->svals[cloff];
4506 svNew = msm__handle_write( thr_acc, a, svOld, 8 );
4507 cl->svals[cloff] = svNew;
4508 return;
4509 slowcase: /* misaligned, or must go further down the tree */
4510 stats__cline_64to32splits++;
4511 shadow_mem_write32( thr_acc, a + 0, 0/*unused*/ );
4512 shadow_mem_write32( thr_acc, a + 4, 0/*unused*/ );
4513}
4514
4515static void shadow_mem_set8 ( Thread* uu_thr_acc, Addr a, UInt svNew ) {
4516 CacheLine* cl;
4517 UWord cloff, tno, toff;
4518 UShort descr;
4519 stats__cline_set8s++;
4520 cl = get_cacheline(a);
4521 cloff = get_cacheline_offset(a);
4522 tno = get_treeno(a);
4523 toff = get_tree_offset(a); /* == 0 .. 7 */
4524 descr = cl->descrs[tno];
4525 if (UNLIKELY( !(descr & (TREE_DESCR_8_0 << toff)) )) {
4526 UInt* tree = &cl->svals[tno << 3];
4527 cl->descrs[tno] = pulldown_to_8(tree, toff, descr);
4528 if (SCE_CACHELINE)
4529 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4530 }
4531 cl->svals[cloff] = svNew;
4532}
4533static void shadow_mem_set16 ( Thread* uu_thr_acc, Addr a, UInt svNew ) {
4534 CacheLine* cl;
4535 UWord cloff, tno, toff;
4536 UShort descr;
4537 stats__cline_set16s++;
4538 if (UNLIKELY(!aligned16(a))) goto slowcase;
4539 cl = get_cacheline(a);
4540 cloff = get_cacheline_offset(a);
4541 tno = get_treeno(a);
4542 toff = get_tree_offset(a); /* == 0, 2, 4 or 6 */
4543 descr = cl->descrs[tno];
4544 if (UNLIKELY( !(descr & (TREE_DESCR_16_0 << toff)) )) {
4545 if (valid_value_is_below_me_16(descr, toff)) {
4546 /* Writing at this level. Need to fix up 'descr'. */
4547 cl->descrs[tno] = pullup_descr_to_16(descr, toff);
4548 /* At this point, the tree does not match cl->descr[tno] any
4549 more. The assignments below will fix it up. */
4550 } else {
4551 /* We can't indiscriminately write on the w16 node as in the
4552 w64 case, as that might make the node inconsistent with
4553 its parent. So first, pull down to this level. */
4554 UInt* tree = &cl->svals[tno << 3];
4555 cl->descrs[tno] = pulldown_to_16(tree, toff, descr);
4556 if (SCE_CACHELINE)
4557 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4558 }
4559 }
4560 cl->svals[cloff + 0] = svNew;
4561 cl->svals[cloff + 1] = 0;
4562 return;
4563 slowcase: /* misaligned */
4564 stats__cline_16to8splits++;
4565 shadow_mem_set8( uu_thr_acc, a + 0, svNew );
4566 shadow_mem_set8( uu_thr_acc, a + 1, svNew );
4567}
4568static void shadow_mem_set32 ( Thread* uu_thr_acc, Addr a, UInt svNew ) {
4569 CacheLine* cl;
4570 UWord cloff, tno, toff;
4571 UShort descr;
4572 stats__cline_set32s++;
4573 if (UNLIKELY(!aligned32(a))) goto slowcase;
4574 cl = get_cacheline(a);
4575 cloff = get_cacheline_offset(a);
4576 tno = get_treeno(a);
4577 toff = get_tree_offset(a); /* == 0 or 4 */
4578 descr = cl->descrs[tno];
4579 if (UNLIKELY( !(descr & (TREE_DESCR_32_0 << toff)) )) {
4580 if (valid_value_is_above_me_32(descr, toff)) {
4581 /* We can't indiscriminately write on the w32 node as in the
4582 w64 case, as that might make the node inconsistent with
4583 its parent. So first, pull down to this level. */
4584 UInt* tree = &cl->svals[tno << 3];
4585 cl->descrs[tno] = pulldown_to_32(tree, toff, descr);
4586 if (SCE_CACHELINE)
4587 tl_assert(is_sane_CacheLine(cl)); /* EXPENSIVE */
4588 } else {
4589 /* Writing at this level. Need to fix up 'descr'. */
4590 cl->descrs[tno] = pullup_descr_to_32(descr, toff);
4591 /* At this point, the tree does not match cl->descr[tno] any
4592 more. The assignments below will fix it up. */
4593 }
4594 }
4595 cl->svals[cloff + 0] = svNew;
4596 cl->svals[cloff + 1] = 0;
4597 cl->svals[cloff + 2] = 0;
4598 cl->svals[cloff + 3] = 0;
4599 return;
4600 slowcase: /* misaligned */
4601 stats__cline_32to16splits++;
4602 shadow_mem_set16( uu_thr_acc, a + 0, svNew );
4603 shadow_mem_set16( uu_thr_acc, a + 2, svNew );
4604}
4605inline
4606static void shadow_mem_set64 ( Thread* uu_thr_acc, Addr a, UInt svNew ) {
4607 CacheLine* cl;
4608 UWord cloff, tno, toff;
4609 stats__cline_set64s++;
4610 if (UNLIKELY(!aligned64(a))) goto slowcase;
4611 cl = get_cacheline(a);
4612 cloff = get_cacheline_offset(a);
4613 tno = get_treeno(a);
4614 toff = get_tree_offset(a); /* == 0 */
4615 cl->descrs[tno] = TREE_DESCR_64;
4616 cl->svals[cloff + 0] = svNew;
4617 cl->svals[cloff + 1] = 0;
4618 cl->svals[cloff + 2] = 0;
4619 cl->svals[cloff + 3] = 0;
4620 cl->svals[cloff + 4] = 0;
4621 cl->svals[cloff + 5] = 0;
4622 cl->svals[cloff + 6] = 0;
4623 cl->svals[cloff + 7] = 0;
4624 return;
4625 slowcase: /* misaligned */
4626 stats__cline_64to32splits++;
4627 shadow_mem_set32( uu_thr_acc, a + 0, svNew );
4628 shadow_mem_set32( uu_thr_acc, a + 4, svNew );
4629}
4630
4631static UInt shadow_mem_get8 ( Addr a ) {
4632 CacheLine* cl;
4633 UWord cloff, tno, toff;
4634 UShort descr;
4635 stats__cline_get8s++;
4636 cl = get_cacheline(a);
4637 cloff = get_cacheline_offset(a);
4638 tno = get_treeno(a);
4639 toff = get_tree_offset(a); /* == 0 .. 7 */
4640 descr = cl->descrs[tno];
4641 if (UNLIKELY( !(descr & (TREE_DESCR_8_0 << toff)) )) {
4642 UInt* tree = &cl->svals[tno << 3];
4643 cl->descrs[tno] = pulldown_to_8(tree, toff, descr);
4644 }
4645 return cl->svals[cloff];
4646}
4647
4648static void shadow_mem_copy8 ( Addr src, Addr dst, Bool normalise ) {
4649 UInt sv;
4650 stats__cline_copy8s++;
4651 sv = shadow_mem_get8( src );
4652
4653 if (UNLIKELY(clo_trace_level > 0)) {
4654 if (dst == clo_trace_addr) {
4655 Thread* thr = get_current_Thread();
4656 UInt sv_old = shadow_mem_get8( dst );
4657 msm__show_state_change( thr, dst, 1, 'w', sv_old, sv );
4658 }
4659 }
4660
4661 shadow_mem_set8( NULL/*unused*/, dst, sv );
4662}
4663
4664
4665/* ------------ Shadow memory range setting ops ------------ */
4666
4667static void shadow_mem_modify_range(
4668 Thread* thr,
4669 Addr a,
4670 SizeT len,
4671 void (*fn8) (Thread*,Addr,UInt),
4672 void (*fn16)(Thread*,Addr,UInt),
4673 void (*fn32)(Thread*,Addr,UInt),
4674 void (*fn64)(Thread*,Addr,UInt),
4675 UInt opaque
4676 )
4677{
4678 /* fast track a couple of common cases */
4679 if (len == 4 && aligned32(a)) {
4680 fn32( thr, a, opaque );
4681 return;
4682 }
4683 if (len == 8 && aligned64(a)) {
4684 fn64( thr, a, opaque );
4685 return;
4686 }
4687
4688 /* be completely general (but as efficient as possible) */
4689 if (len == 0) return;
4690
4691 if (!aligned16(a) && len >= 1) {
4692 fn8( thr, a, opaque );
4693 a += 1;
4694 len -= 1;
4695 tl_assert(aligned16(a));
4696 }
4697 if (len == 0) return;
4698
4699 if (!aligned32(a) && len >= 2) {
4700 fn16( thr, a, opaque );
4701 a += 2;
4702 len -= 2;
4703 tl_assert(aligned32(a));
4704 }
4705 if (len == 0) return;
4706
4707 if (!aligned64(a) && len >= 4) {
4708 fn32( thr, a, opaque );
4709 a += 4;
4710 len -= 4;
4711 tl_assert(aligned64(a));
4712 }
4713 if (len == 0) return;
4714
4715 if (len >= 8) {
4716 tl_assert(aligned64(a));
4717 while (len >= 8) {
4718 fn64( thr, a, opaque );
4719 a += 8;
4720 len -= 8;
4721 }
4722 tl_assert(aligned64(a));
4723 }
4724 if (len == 0) return;
4725
4726 if (len >= 4)
4727 tl_assert(aligned32(a));
4728 if (len >= 4) {
4729 fn32( thr, a, opaque );
4730 a += 4;
4731 len -= 4;
4732 }
4733 if (len == 0) return;
4734
4735 if (len >= 2)
4736 tl_assert(aligned16(a));
4737 if (len >= 2) {
4738 fn16( thr, a, opaque );
4739 a += 2;
4740 len -= 2;
4741 }
4742 if (len == 0) return;
4743
4744 if (len >= 1) {
4745 fn8( thr, a, opaque );
4746 a += 1;
4747 len -= 1;
4748 }
4749 tl_assert(len == 0);
4750}
4751
4752/* Block-copy states (needed for implementing realloc()). */
4753static void shadow_mem_copy_range ( Addr src, Addr dst, SizeT len )
4754{
4755 SizeT i;
4756 if (len == 0)
4757 return;
4758 /* To be simple, just copy byte by byte. But so as not to wreck
4759 performance for later accesses to dst[0 .. len-1], normalise
4760 destination lines as we finish with them, and also normalise the
4761 line containing the first and last address. */
4762 for (i = 0; i < len; i++) {
4763 Bool normalise
4764 = get_cacheline_offset( dst+i+1 ) == 0 /* last in line */
4765 || i == 0 /* first in range */
4766 || i == len-1; /* last in range */
4767 shadow_mem_copy8( src+i, dst+i, normalise );
4768 }
4769}
4770
4771static void shadow_mem_read_range ( Thread* thr, Addr a, SizeT len ) {
4772 shadow_mem_modify_range( thr, a, len,
4773 shadow_mem_read8,
4774 shadow_mem_read16,
4775 shadow_mem_read32,
4776 shadow_mem_read64,
4777 0/*opaque,ignored*/ );
4778}
4779
4780static void shadow_mem_write_range ( Thread* thr, Addr a, SizeT len ) {
4781 shadow_mem_modify_range( thr, a, len,
4782 shadow_mem_write8,
4783 shadow_mem_write16,
4784 shadow_mem_write32,
4785 shadow_mem_write64,
4786 0/*opaque,ignored*/ );
4787}
4788
4789static void shadow_mem_make_New ( Thread* thr, Addr a, SizeT len )
4790{
4791 if (UNLIKELY(clo_trace_level > 0)) {
4792 if (len > 0 && a <= clo_trace_addr && clo_trace_addr < a+len) {
4793 UInt sv_old = shadow_mem_get8( clo_trace_addr );
4794 msm__show_state_change( thr, a, (Int)len, 'p', sv_old, SHVAL_New );
4795 }
4796 }
4797 shadow_mem_modify_range( thr, a, len,
4798 shadow_mem_set8,
4799 shadow_mem_set16,
4800 shadow_mem_set32,
4801 shadow_mem_set64,
4802 SHVAL_New/*opaque*/ );
4803}
4804
4805
4806/* Putting memory into the NoAccess state. This is hugely complicated
4807 by the problem of memory that contains locks.
4808
4809 1. Examine the .mbHasLocks fields in all SecMaps in the range to be
4810 deleted. This quickly indicates if there are or might be any
4811 locks in the range to be deleted. Note that .mbHasLocks fields on
4812 SecMaps are not subject to scaching, so it safe to look at them
4813 without flushing the scache.
4814
4815 2. Set the range to NoAccess. Clear the .mbHasShared and
4816 .mbHasLocks hint bits for any completely vacated SecMaps.
4817 Clearing the hint bits isn't necessary for correctness, but it
4818 is important to avoid ending up with hint bits being permanently
4819 set, which would render them pointless.
4820
4821 3. If (1) indicated "definitely no locks", we're done. This is
4822 the fast and hopefully common case.
4823
4824 Otherwise, the range contains some locks (or may do), so we have to
4825 go to considerable effort to tidy up.
4826
4827 4. Make up a set containing the locks which are deleted:
4828
4829 ToDelete = NULL
4830
4831 for each lk in map_locks {
4832 if lk's guest addr falls in the range to memory be deleted
4833 add lk to ToDelete
4834
4835 if lk is held, issue an error message - freeing memory
4836 containing a held lock
4837 }
4838
4839 5. If ToDelete is empty, there were in fact no locks in the range,
4840 despite what the .mbHasLocks hint bits indicated. We're done.
4841
4842 6. Flush the scache. This is necessary both to bring the SecMap
4843 .mbHasShared fields up to date, and to bring the actual shadow
4844 values up to date. We will need to examine both of these.
4845
4846 Invalidate the scache. This is necessary because we will be
4847 modifying values in the backing store (SecMaps) and need
4848 subsequent shmem accesses to get the new values.
4849
4850 7. Modify all shadow words, by removing ToDelete from the lockset
4851 of all ShM and ShR states. Note this involves a complete scan
4852 over map_shmem, which is very expensive according to OProfile.
4853 Hence it depends critically on the size of each entry in
4854 map_shmem. See comments on definition of N_SECMAP_BITS above.
4855
4856 Why is it safe to do (7) after (2) ? Because we're not
4857 interested in messing with ShR/M states which are going to be
4858 set to NoAccess anyway.
4859
4860 Optimisation 1 (implemented): skip this step for SecMaps which
4861 do not have .mbHasShared set
4862
4863 Optimisation 2 (not implemented): for each SecMap, have a
4864 summary lock set which is the union of all locks mentioned in
4865 locksets on this page (or any superset of it). Then skip step
4866 (2) if the summary lockset does not intersect with ToDelete.
4867
4868 That's potentially cheap, since the usual lockset refinement
4869 only shrinks locksets; hence there is no point in updating the
4870 summary lockset for ShM/R -> ShM/R transitions. Therefore only
4871 need to do this for Excl->ShM/R transitions.
4872
4873 8. Tell laog that these locks have disappeared.
4874*/
4875static void shadow_mem_make_NoAccess ( Thread* thr, Addr aIN, SizeT len )
4876{
4877 Lock* lk;
4878 Addr gla, sma, firstSM, lastSM, firstA, lastA;
4879 WordSetID locksToDelete;
4880 Bool mbHasLocks;
4881
4882 if (0 && len > 500)
4883 VG_(printf)("make NoAccess ( %p, %d )\n", aIN, len );
4884
4885 if (len == 0)
4886 return;
4887
4888 /* --- Step 1 --- */
4889
4890 firstA = aIN;
4891 lastA = aIN + len - 1;
4892
4893 firstSM = shmem__round_to_SecMap_base( firstA );
4894 lastSM = shmem__round_to_SecMap_base( lastA );
4895 tl_assert(firstSM <= lastSM);
4896
4897 mbHasLocks = False;
4898 for (sma = firstSM; sma <= lastSM; sma += N_SECMAP_ARANGE) {
4899 if (shmem__get_mbHasLocks(sma)) {
4900 mbHasLocks = True;
4901 break;
4902 }
4903 }
4904
4905 /* --- Step 2 --- */
4906
4907 if (UNLIKELY(clo_trace_level > 0)) {
4908 if (len > 0 && firstA <= clo_trace_addr && clo_trace_addr <= lastA) {
4909 UInt sv_old = shadow_mem_get8( clo_trace_addr );
4910 msm__show_state_change( thr, firstA, (Int)len, 'p',
4911 sv_old, SHVAL_NoAccess );
4912 }
4913 }
4914 shadow_mem_modify_range( thr, firstA, len,
4915 shadow_mem_set8,
4916 shadow_mem_set16,
4917 shadow_mem_set32,
4918 shadow_mem_set64,
4919 SHVAL_NoAccess/*opaque*/ );
4920
4921 for (sma = firstSM; sma <= lastSM; sma += N_SECMAP_ARANGE) {
4922 /* Is this sm entirely within the deleted range? */
4923 if (firstA <= sma && sma + N_SECMAP_ARANGE - 1 <= lastA) {
4924 /* Yes. Clear the hint bits. */
4925 shmem__set_mbHasLocks( sma, False );
4926 shmem__set_mbHasShared( sma, False );
4927 }
4928 }
4929
4930 /* --- Step 3 --- */
4931
4932 if (!mbHasLocks)
4933 return;
4934
4935 /* --- Step 4 --- */
4936
4937 if (0)
4938 VG_(printf)("shadow_mem_make_NoAccess(%p, %u, %p): maybe slow case\n",
4939 (void*)firstA, (UWord)len, (void*)lastA);
4940 locksToDelete = HG_(emptyWS)( univ_lsets );
4941
4942 /* FIXME: don't iterate over the complete lock set */
4943 HG_(initIterFM)( map_locks );
4944 while (HG_(nextIterFM)( map_locks,
4945 (Word*)(void*)&gla, (Word*)(void*)&lk )) {
4946 tl_assert(is_sane_LockN(lk));
4947 if (gla < firstA || gla > lastA)
4948 continue;
4949 locksToDelete = HG_(addToWS)( univ_lsets, locksToDelete, (Word)lk );
4950 /* If the lock is held, we must remove it from the currlock sets
4951 of all threads that hold it. Also take the opportunity to
4952 report an error. To report an error we need to know at least
4953 one of the threads that holds it; really we should mention
4954 them all, but that's too much hassle. So choose one
4955 arbitrarily. */
4956 if (lk->heldBy) {
4957 tl_assert(!HG_(isEmptyBag)(lk->heldBy));
4958 record_error_FreeMemLock( (Thread*)HG_(anyElementOfBag)(lk->heldBy),
4959 lk );
4960 /* remove lock from locksets of all owning threads */
4961 remove_Lock_from_locksets_of_all_owning_Threads( lk );
4962 /* Leave lk->heldBy in place; del_Lock below will free it up. */
4963 }
4964 }
4965 HG_(doneIterFM)( map_locks );
4966
4967 /* --- Step 5 --- */
4968
4969 if (HG_(isEmptyWS)( univ_lsets, locksToDelete ))
4970 return;
4971
4972 /* --- Step 6 --- */
4973
4974 shmem__flush_and_invalidate_scache();
4975
4976 /* --- Step 7 --- */
4977
4978 if (0)
4979 VG_(printf)("shadow_mem_make_NoAccess(%p, %u, %p): definitely slow case\n",
4980 (void*)firstA, (UWord)len, (void*)lastA);
4981
4982 /* Modify all shadow words, by removing locksToDelete from the lockset
4983 of all ShM and ShR states.
4984 Optimisation 1: skip SecMaps which do not have .mbHasShared set
4985 */
4986 { Int stats_SMs = 0, stats_SMs_scanned = 0;
4987 Addr ga;
4988 SecMap* sm;
4989 SecMapIter itr;
4990 UInt* w32p;
4991
4992 HG_(initIterFM)( map_shmem );
4993 while (HG_(nextIterFM)( map_shmem,
4994 (Word*)(void*)&ga, (Word*)(void*)&sm )) {
4995 tl_assert(sm);
4996 stats_SMs++;
4997 /* Skip this SecMap if the summary bit indicates it is safe to
4998 do so. */
4999 if (!sm->mbHasShared)
5000 continue;
5001 stats_SMs_scanned++;
5002 initSecMapIter( &itr );
5003 while (stepSecMapIter( &w32p, &itr, sm )) {
5004 Bool isM;
5005 UInt wold, wnew, lset_old, tset_old, lset_new;
5006 wold = *w32p;
5007 if (LIKELY( !is_SHVAL_Sh(wold) ))
5008 continue;
5009 isM = is_SHVAL_ShM(wold);
5010 lset_old = un_SHVAL_Sh_lset(wold);
5011 tset_old = un_SHVAL_Sh_tset(wold);
5012 lset_new = HG_(minusWS)( univ_lsets, lset_old, locksToDelete );
5013 wnew = isM ? mk_SHVAL_ShM(tset_old, lset_new)
5014 : mk_SHVAL_ShR(tset_old, lset_new);
5015 if (wnew != wold)
5016 *w32p = wnew;
5017 }
5018 }
5019 HG_(doneIterFM)( map_shmem );
5020 if (SHOW_EXPENSIVE_STUFF)
5021 VG_(printf)("shadow_mem_make_NoAccess: %d SMs, %d scanned\n",
5022 stats_SMs, stats_SMs_scanned);
5023 }
5024
5025 /* Now we have to free up the Locks in locksToDelete and remove
5026 any mention of them from admin_locks and map_locks. This is
5027 inefficient. */
5028 { Lock* lkprev = NULL;
5029 lk = admin_locks;
5030 while (True) {
5031 if (lk == NULL) break;
5032 if (lkprev) tl_assert(lkprev->admin == lk);
5033
5034 if (!HG_(elemWS)(univ_lsets, locksToDelete, (Word)lk)) {
5035 lkprev = lk;
5036 lk = lk->admin;
5037 continue;
5038 }
5039 /* Need to delete 'lk' */
5040 if (lkprev == NULL) {
5041 admin_locks = lk->admin;
5042 } else {
5043 lkprev->admin = lk->admin;
5044 }
5045 /* and get it out of map_locks */
5046 map_locks_delete(lk->guestaddr);
5047 /* release storage (incl. associated .heldBy Bag) */
5048 { Lock* tmp = lk->admin;
5049 del_LockN(lk);
5050 lk = tmp;
5051 }
5052 }
5053 }
5054
5055 /* --- Step 8 --- */
5056
5057 /* update lock order acquisition graph */
5058 laog__handle_lock_deletions( locksToDelete );
5059
5060 if (0) all__sanity_check("Make NoAccess");
5061}
5062
5063
5064/*----------------------------------------------------------------*/
5065/*--- Event handlers (evh__* functions) ---*/
5066/*--- plus helpers (evhH__* functions) ---*/
5067/*----------------------------------------------------------------*/
5068
5069/*--------- Event handler helpers (evhH__* functions) ---------*/
5070
5071/* Create a new segment for 'thr', making it depend (.prev) on its
5072 existing segment, bind together the SegmentID and Segment, and
5073 return both of them. Also update 'thr' so it references the new
5074 Segment. */
5075static
5076void evhH__start_new_segment_for_thread ( /*OUT*/SegmentID* new_segidP,
5077 /*OUT*/Segment** new_segP,
5078 Thread* thr )
5079{
5080 Segment* cur_seg;
5081 tl_assert(new_segP);
5082 tl_assert(new_segidP);
5083 tl_assert(is_sane_Thread(thr));
5084 cur_seg = map_segments_lookup( thr->csegid );
5085 tl_assert(cur_seg);
5086 tl_assert(cur_seg->thr == thr); /* all sane segs should point back
5087 at their owner thread. */
5088 *new_segP = mk_Segment( thr, cur_seg, NULL/*other*/ );
5089 *new_segidP = alloc_SegmentID();
5090 map_segments_add( *new_segidP, *new_segP );
5091 thr->csegid = *new_segidP;
5092}
5093
5094
5095/* The lock at 'lock_ga' has acquired a writer. Make all necessary
5096 updates, and also do all possible error checks. */
5097static
5098void evhH__post_thread_w_acquires_lock ( Thread* thr,
5099 LockKind lkk, Addr lock_ga )
5100{
5101 Lock* lk;
5102
5103 /* Basically what we need to do is call lockN_acquire_writer.
5104 However, that will barf if any 'invalid' lock states would
5105 result. Therefore check before calling. Side effect is that
5106 'is_sane_LockN(lk)' is both a pre- and post-condition of this
5107 routine.
5108
5109 Because this routine is only called after successful lock
5110 acquisition, we should not be asked to move the lock into any
5111 invalid states. Requests to do so are bugs in libpthread, since
5112 that should have rejected any such requests. */
5113
5114 /* be paranoid w.r.t hint bits, even if lock_ga is complete
5115 nonsense */
5116 shmem__set_mbHasLocks( lock_ga, True );
5117
5118 tl_assert(is_sane_Thread(thr));
5119 /* Try to find the lock. If we can't, then create a new one with
5120 kind 'lkk'. */
5121 lk = map_locks_lookup_or_create(
5122 lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
5123 tl_assert( is_sane_LockN(lk) );
5124 shmem__set_mbHasLocks( lock_ga, True );
5125
5126 if (lk->heldBy == NULL) {
5127 /* the lock isn't held. Simple. */
5128 tl_assert(!lk->heldW);
5129 lockN_acquire_writer( lk, thr );
5130 goto noerror;
5131 }
5132
5133 /* So the lock is already held. If held as a r-lock then
5134 libpthread must be buggy. */
5135 tl_assert(lk->heldBy);
5136 if (!lk->heldW) {
5137 record_error_Misc( thr, "Bug in libpthread: write lock "
5138 "granted on rwlock which is currently rd-held");
5139 goto error;
5140 }
5141
5142 /* So the lock is held in w-mode. If it's held by some other
5143 thread, then libpthread must be buggy. */
5144 tl_assert(HG_(sizeUniqueBag)(lk->heldBy) == 1); /* from precondition */
5145
5146 if (thr != (Thread*)HG_(anyElementOfBag)(lk->heldBy)) {
5147 record_error_Misc( thr, "Bug in libpthread: write lock "
5148 "granted on mutex/rwlock which is currently "
5149 "wr-held by a different thread");
5150 goto error;
5151 }
5152
5153 /* So the lock is already held in w-mode by 'thr'. That means this
5154 is an attempt to lock it recursively, which is only allowable
5155 for LK_mbRec kinded locks. Since this routine is called only
5156 once the lock has been acquired, this must also be a libpthread
5157 bug. */
5158 if (lk->kind != LK_mbRec) {
5159 record_error_Misc( thr, "Bug in libpthread: recursive write lock "
5160 "granted on mutex/wrlock which does not "
5161 "support recursion");
5162 goto error;
5163 }
5164
5165 /* So we are recursively re-locking a lock we already w-hold. */
5166 lockN_acquire_writer( lk, thr );
5167 goto noerror;
5168
5169 noerror:
5170 /* check lock order acquisition graph, and update. This has to
5171 happen before the lock is added to the thread's locksetA/W. */
5172 laog__pre_thread_acquires_lock( thr, lk );
5173 /* update the thread's held-locks set */
5174 thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (Word)lk );
5175 thr->locksetW = HG_(addToWS)( univ_lsets, thr->locksetW, (Word)lk );
5176 /* fall through */
5177
5178 error:
5179 tl_assert(is_sane_LockN(lk));
5180}
5181
5182
5183/* The lock at 'lock_ga' has acquired a reader. Make all necessary
5184 updates, and also do all possible error checks. */
5185static
5186void evhH__post_thread_r_acquires_lock ( Thread* thr,
5187 LockKind lkk, Addr lock_ga )
5188{
5189 Lock* lk;
5190
5191 /* Basically what we need to do is call lockN_acquire_reader.
5192 However, that will barf if any 'invalid' lock states would
5193 result. Therefore check before calling. Side effect is that
5194 'is_sane_LockN(lk)' is both a pre- and post-condition of this
5195 routine.
5196
5197 Because this routine is only called after successful lock
5198 acquisition, we should not be asked to move the lock into any
5199 invalid states. Requests to do so are bugs in libpthread, since
5200 that should have rejected any such requests. */
5201
5202 /* be paranoid w.r.t hint bits, even if lock_ga is complete
5203 nonsense */
5204 shmem__set_mbHasLocks( lock_ga, True );
5205
5206 tl_assert(is_sane_Thread(thr));
5207 /* Try to find the lock. If we can't, then create a new one with
5208 kind 'lkk'. Only a reader-writer lock can be read-locked,
5209 hence the first assertion. */
5210 tl_assert(lkk == LK_rdwr);
5211 lk = map_locks_lookup_or_create(
5212 lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
5213 tl_assert( is_sane_LockN(lk) );
5214 shmem__set_mbHasLocks( lock_ga, True );
5215
5216 if (lk->heldBy == NULL) {
5217 /* the lock isn't held. Simple. */
5218 tl_assert(!lk->heldW);
5219 lockN_acquire_reader( lk, thr );
5220 goto noerror;
5221 }
5222
5223 /* So the lock is already held. If held as a w-lock then
5224 libpthread must be buggy. */
5225 tl_assert(lk->heldBy);
5226 if (lk->heldW) {
5227 record_error_Misc( thr, "Bug in libpthread: read lock "
5228 "granted on rwlock which is "
5229 "currently wr-held");
5230 goto error;
5231 }
5232
5233 /* Easy enough. In short anybody can get a read-lock on a rwlock
5234 provided it is either unlocked or already in rd-held. */
5235 lockN_acquire_reader( lk, thr );
5236 goto noerror;
5237
5238 noerror:
5239 /* check lock order acquisition graph, and update. This has to
5240 happen before the lock is added to the thread's locksetA/W. */
5241 laog__pre_thread_acquires_lock( thr, lk );
5242 /* update the thread's held-locks set */
5243 thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (Word)lk );
5244 /* but don't update thr->locksetW, since lk is only rd-held */
5245 /* fall through */
5246
5247 error:
5248 tl_assert(is_sane_LockN(lk));
5249}
5250
5251
5252/* The lock at 'lock_ga' is just about to be unlocked. Make all
5253 necessary updates, and also do all possible error checks. */
5254static
5255void evhH__pre_thread_releases_lock ( Thread* thr,
5256 Addr lock_ga, Bool isRDWR )
5257{
5258 Lock* lock;
5259 Word n;
5260
5261 /* This routine is called prior to a lock release, before
5262 libpthread has had a chance to validate the call. Hence we need
5263 to detect and reject any attempts to move the lock into an
5264 invalid state. Such attempts are bugs in the client.
5265
5266 isRDWR is True if we know from the wrapper context that lock_ga
5267 should refer to a reader-writer lock, and is False if [ditto]
5268 lock_ga should refer to a standard mutex. */
5269
5270 /* be paranoid w.r.t hint bits, even if lock_ga is complete
5271 nonsense */
5272 shmem__set_mbHasLocks( lock_ga, True );
5273
5274 tl_assert(is_sane_Thread(thr));
5275 lock = map_locks_maybe_lookup( lock_ga );
5276
5277 if (!lock) {
5278 /* We know nothing about a lock at 'lock_ga'. Nevertheless
5279 the client is trying to unlock it. So complain, then ignore
5280 the attempt. */
5281 record_error_UnlockBogus( thr, lock_ga );
5282 return;
5283 }
5284
5285 tl_assert(lock->guestaddr == lock_ga);
5286 tl_assert(is_sane_LockN(lock));
5287
5288 if (isRDWR && lock->kind != LK_rdwr) {
5289 record_error_Misc( thr, "pthread_rwlock_unlock with a "
5290 "pthread_mutex_t* argument " );
5291 }
5292 if ((!isRDWR) && lock->kind == LK_rdwr) {
5293 record_error_Misc( thr, "pthread_mutex_unlock with a "
5294 "pthread_rwlock_t* argument " );
5295 }
5296
5297 if (!lock->heldBy) {
5298 /* The lock is not held. This indicates a serious bug in the
5299 client. */
5300 tl_assert(!lock->heldW);
5301 record_error_UnlockUnlocked( thr, lock );
5302 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
5303 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
5304 goto error;
5305 }
5306
5307 /* The lock is held. Is this thread one of the holders? If not,
5308 report a bug in the client. */
5309 n = HG_(elemBag)( lock->heldBy, (Word)thr );
5310 tl_assert(n >= 0);
5311 if (n == 0) {
5312 /* We are not a current holder of the lock. This is a bug in
5313 the guest, and (per POSIX pthread rules) the unlock
5314 attempt will fail. So just complain and do nothing
5315 else. */
5316 Thread* realOwner = (Thread*)HG_(anyElementOfBag)( lock->heldBy );
5317 tl_assert(is_sane_Thread(realOwner));
5318 tl_assert(realOwner != thr);
5319 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
5320 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
5321 record_error_UnlockForeign( thr, realOwner, lock );
5322 goto error;
5323 }
5324
5325 /* Ok, we hold the lock 'n' times. */
5326 tl_assert(n >= 1);
5327
5328 lockN_release( lock, thr );
5329
5330 n--;
5331 tl_assert(n >= 0);
5332
5333 if (n > 0) {
5334 tl_assert(lock->heldBy);
5335 tl_assert(n == HG_(elemBag)( lock->heldBy, (Word)thr ));
5336 /* We still hold the lock. So either it's a recursive lock
5337 or a rwlock which is currently r-held. */
5338 tl_assert(lock->kind == LK_mbRec
5339 || (lock->kind == LK_rdwr && !lock->heldW));
5340 tl_assert(HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
5341 if (lock->heldW)
5342 tl_assert(HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
5343 else
5344 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
5345 } else {
5346 /* We no longer hold the lock. */
5347 if (lock->heldBy) {
5348 tl_assert(0 == HG_(elemBag)( lock->heldBy, (Word)thr ));
5349 }
5350 /* update this thread's lockset accordingly. */
5351 thr->locksetA
5352 = HG_(delFromWS)( univ_lsets, thr->locksetA, (Word)lock );
5353 thr->locksetW
5354 = HG_(delFromWS)( univ_lsets, thr->locksetW, (Word)lock );
5355 }
5356 /* fall through */
5357
5358 error:
5359 tl_assert(is_sane_LockN(lock));
5360}
5361
5362
5363/*--------- Event handlers proper (evh__* functions) ---------*/
5364
5365/* What is the Thread* for the currently running thread? This is
5366 absolutely performance critical. We receive notifications from the
5367 core for client code starts/stops, and cache the looked-up result
5368 in 'current_Thread'. Hence, for the vast majority of requests,
5369 finding the current thread reduces to a read of a global variable,
5370 provided get_current_Thread_in_C_C is inlined.
5371
5372 Outside of client code, current_Thread is NULL, and presumably
5373 any uses of it will cause a segfault. Hence:
5374
5375 - for uses definitely within client code, use
5376 get_current_Thread_in_C_C.
5377
5378 - for all other uses, use get_current_Thread.
5379*/
5380
5381static Thread* current_Thread = NULL;
5382
5383static void evh__start_client_code ( ThreadId tid, ULong nDisp ) {
5384 if (0) VG_(printf)("start %d %llu\n", (Int)tid, nDisp);
5385 tl_assert(current_Thread == NULL);
5386 current_Thread = map_threads_lookup( tid );
5387 tl_assert(current_Thread != NULL);
5388}
5389static void evh__stop_client_code ( ThreadId tid, ULong nDisp ) {
5390 if (0) VG_(printf)(" stop %d %llu\n", (Int)tid, nDisp);
5391 tl_assert(current_Thread != NULL);
5392 current_Thread = NULL;
5393}
5394static inline Thread* get_current_Thread_in_C_C ( void ) {
5395 return current_Thread;
5396}
5397static inline Thread* get_current_Thread ( void ) {
5398 ThreadId coretid;
5399 Thread* thr;
5400 thr = get_current_Thread_in_C_C();
5401 if (LIKELY(thr))
5402 return thr;
5403 /* evidently not in client code. Do it the slow way. */
5404 coretid = VG_(get_running_tid)();
5405 /* FIXME: get rid of the following kludge. It exists because
5406 evim__new_mem is called during initialisation (as notification
5407 of initial memory layout) and VG_(get_running_tid)() returns
5408 VG_INVALID_THREADID at that point. */
5409 if (coretid == VG_INVALID_THREADID)
5410 coretid = 1; /* KLUDGE */
5411 thr = map_threads_lookup( coretid );
5412 return thr;
5413}
5414
5415static
5416void evh__new_mem ( Addr a, SizeT len ) {
5417 if (SHOW_EVENTS >= 2)
5418 VG_(printf)("evh__new_mem(%p, %lu)\n", (void*)a, len );
5419 shadow_mem_make_New( get_current_Thread(), a, len );
5420 if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5421 all__sanity_check("evh__new_mem-post");
5422}
5423
5424static
5425void evh__new_mem_w_perms ( Addr a, SizeT len,
5426 Bool rr, Bool ww, Bool xx ) {
5427 if (SHOW_EVENTS >= 1)
5428 VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n",
5429 (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
5430 if (rr || ww || xx)
5431 shadow_mem_make_New( get_current_Thread(), a, len );
5432 if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5433 all__sanity_check("evh__new_mem_w_perms-post");
5434}
5435
5436static
5437void evh__set_perms ( Addr a, SizeT len,
5438 Bool rr, Bool ww, Bool xx ) {
5439 if (SHOW_EVENTS >= 1)
5440 VG_(printf)("evh__set_perms(%p, %lu, %d,%d,%d)\n",
5441 (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
5442 /* Hmm. What should we do here, that actually makes any sense?
5443 Let's say: if neither readable nor writable, then declare it
5444 NoAccess, else leave it alone. */
5445 if (!(rr || ww))
5446 shadow_mem_make_NoAccess( get_current_Thread(), a, len );
5447 if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5448 all__sanity_check("evh__set_perms-post");
5449}
5450
5451static
5452void evh__die_mem ( Addr a, SizeT len ) {
5453 if (SHOW_EVENTS >= 2)
5454 VG_(printf)("evh__die_mem(%p, %lu)\n", (void*)a, len );
5455 shadow_mem_make_NoAccess( get_current_Thread(), a, len );
5456 if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5457 all__sanity_check("evh__die_mem-post");
5458}
5459
5460static
5461void evh__pre_thread_ll_create ( ThreadId parent, ThreadId child )
5462{
5463 if (SHOW_EVENTS >= 1)
5464 VG_(printf)("evh__pre_thread_ll_create(p=%d, c=%d)\n",
5465 (Int)parent, (Int)child );
5466
5467 if (parent != VG_INVALID_THREADID) {
5468 Thread* thr_p;
5469 Thread* thr_c;
5470 SegmentID segid_c;
5471 Segment* seg_c;
5472
5473 tl_assert(is_sane_ThreadId(parent));
5474 tl_assert(is_sane_ThreadId(child));
5475 tl_assert(parent != child);
5476
5477 thr_p = map_threads_maybe_lookup( parent );
5478 thr_c = map_threads_maybe_lookup( child );
5479
5480 tl_assert(thr_p != NULL);
5481 tl_assert(thr_c == NULL);
5482
5483 /* Create a new thread record for the child. */
5484 // FIXME: code duplication from init_data_structures
5485 segid_c = alloc_SegmentID();
5486 seg_c = mk_Segment( NULL/*thr*/, NULL/*prev*/, NULL/*other*/ );
5487 map_segments_add( segid_c, seg_c );
5488
5489 /* a Thread for the new thread ... */
5490 thr_c = mk_Thread( segid_c );
5491 seg_c->thr = thr_c;
5492
5493 /* and bind it in the thread-map table */
5494 map_threads[child] = thr_c;
5495
5496 /* Record where the parent is so we can later refer to this in
5497 error messages.
5498
5499 On amd64-linux, this entails a nasty glibc-2.5 specific hack.
5500 The stack snapshot is taken immediately after the parent has
5501 returned from its sys_clone call. Unfortunately there is no
5502 unwind info for the insn following "syscall" - reading the
5503 glibc sources confirms this. So we ask for a snapshot to be
5504 taken as if RIP was 3 bytes earlier, in a place where there
5505 is unwind info. Sigh.
5506 */
5507 { Word first_ip_delta = 0;
5508# if defined(VGP_amd64_linux)
5509 first_ip_delta = -3;
5510# endif
5511 thr_c->created_at = VG_(record_ExeContext)(parent, first_ip_delta);
5512 }
5513
5514 /* Now, mess with segments. */
5515 if (clo_happens_before >= 1) {
5516 /* Make the child's new segment depend on the parent */
5517 seg_c->other = map_segments_lookup( thr_p->csegid );
5518 seg_c->other_hint = 'c';
5519 seg_c->vts = tick_VTS( thr_c, seg_c->other->vts );
5520 tl_assert(seg_c->prev == NULL);
5521 /* and start a new segment for the parent. */
5522 { SegmentID new_segid = 0; /* bogus */
5523 Segment* new_seg = NULL;
5524 evhH__start_new_segment_for_thread( &new_segid, &new_seg,
5525 thr_p );
5526 tl_assert(is_sane_SegmentID(new_segid));
5527 tl_assert(is_sane_Segment(new_seg));
5528 new_seg->vts = tick_VTS( thr_p, new_seg->prev->vts );
5529 tl_assert(new_seg->other == NULL);
5530 }
5531 }
5532 }
5533
5534 if (clo_sanity_flags & SCE_THREADS)
5535 all__sanity_check("evh__pre_thread_create-post");
5536}
5537
5538static
5539void evh__pre_thread_ll_exit ( ThreadId quit_tid )
5540{
5541 Int nHeld;
5542 Thread* thr_q;
5543 if (SHOW_EVENTS >= 1)
5544 VG_(printf)("evh__pre_thread_ll_exit(thr=%d)\n",
5545 (Int)quit_tid );
5546
5547 /* quit_tid has disappeared without joining to any other thread.
5548 Therefore there is no synchronisation event associated with its
5549 exit and so we have to pretty much treat it as if it was still
5550 alive but mysteriously making no progress. That is because, if
5551 we don't know when it really exited, then we can never say there
5552 is a point in time when we're sure the thread really has
5553 finished, and so we need to consider the possibility that it
5554 lingers indefinitely and continues to interact with other
5555 threads. */
5556 /* However, it might have rendezvous'd with a thread that called
5557 pthread_join with this one as arg, prior to this point (that's
5558 how NPTL works). In which case there has already been a prior
5559 sync event. So in any case, just let the thread exit. On NPTL,
5560 all thread exits go through here. */
5561 tl_assert(is_sane_ThreadId(quit_tid));
5562 thr_q = map_threads_maybe_lookup( quit_tid );
5563 tl_assert(thr_q != NULL);
5564
5565 /* Complain if this thread holds any locks. */
5566 nHeld = HG_(cardinalityWS)( univ_lsets, thr_q->locksetA );
5567 tl_assert(nHeld >= 0);
5568 if (nHeld > 0) {
5569 HChar buf[80];
5570 VG_(sprintf)(buf, "Exiting thread still holds %d lock%s",
5571 nHeld, nHeld > 1 ? "s" : "");
5572 record_error_Misc( thr_q, buf );
5573 }
5574
5575 /* About the only thing we do need to do is clear the map_threads
5576 entry, in order that the Valgrind core can re-use it. */
5577 map_threads_delete( quit_tid );
5578
5579 if (clo_sanity_flags & SCE_THREADS)
5580 all__sanity_check("evh__pre_thread_ll_exit-post");
5581}
5582
5583static
5584void evh__HG_PTHREAD_JOIN_POST ( ThreadId stay_tid, Thread* quit_thr )
5585{
5586 Int stats_SMs, stats_SMs_scanned, stats_reExcls;
5587 Addr ga;
5588 SecMap* sm;
5589 Thread* thr_s;
5590 Thread* thr_q;
5591
5592 if (SHOW_EVENTS >= 1)
5593 VG_(printf)("evh__post_thread_join(stayer=%d, quitter=%p)\n",
5594 (Int)stay_tid, quit_thr );
5595
5596 tl_assert(is_sane_ThreadId(stay_tid));
5597
5598 thr_s = map_threads_maybe_lookup( stay_tid );
5599 thr_q = quit_thr;
5600 tl_assert(thr_s != NULL);
5601 tl_assert(thr_q != NULL);
5602 tl_assert(thr_s != thr_q);
5603
5604 if (clo_happens_before >= 1) {
5605 /* Start a new segment for the stayer */
5606 SegmentID new_segid = 0; /* bogus */
5607 Segment* new_seg = NULL;
5608 evhH__start_new_segment_for_thread( &new_segid, &new_seg, thr_s );
5609 tl_assert(is_sane_SegmentID(new_segid));
5610 tl_assert(is_sane_Segment(new_seg));
5611 /* and make it depend on the quitter's last segment */
5612 tl_assert(new_seg->other == NULL);
5613 new_seg->other = map_segments_lookup( thr_q->csegid );
5614 new_seg->other_hint = 'j';
5615 tl_assert(new_seg->thr == thr_s);
5616 new_seg->vts = tickL_and_joinR_VTS( thr_s, new_seg->prev->vts,
5617 new_seg->other->vts );
5618 }
5619
5620 // FIXME: error-if: exiting thread holds any locks
5621 // or should evh__pre_thread_ll_exit do that?
5622
5623 /* Delete thread from ShM/ShR thread sets and restore Excl states
5624 where appropriate */
5625
5626 /* When Thread(t) joins to Thread(u):
5627
5628 scan all shadow memory. For each ShM/ShR thread set, replace
5629 't' in each set with 'u'. If this results in a singleton 'u',
5630 change the state to Excl(u->csegid).
5631
5632 Optimisation: tag each SecMap with a superset of the union of
5633 the thread sets in the SecMap. Then if the tag set does not
5634 include 't' then the SecMap can be skipped, because there is no
5635 't' to change to anything else.
5636
5637 Problem is that the tag set needs to be updated often, after
5638 every ShR/ShM store. (that increases the thread set of the
5639 shadow value.)
5640
5641 --> Compromise. Tag each SecMap with a .mbHasShared bit which
5642 must be set true if any ShR/ShM on the page. Set this for
5643 any transitions into ShR/ShM on the page. Then skip page if
5644 not set.
5645
5646 .mbHasShared bits are (effectively) cached in cache_shmem.
5647 Hence that must be flushed before we can safely consult them.
5648
5649 Since we're modifying the backing store, we also need to
5650 invalidate cache_shmem, so that subsequent memory references get
5651 up to date shadow values.
5652 */
5653 shmem__flush_and_invalidate_scache();
5654
5655 stats_SMs = stats_SMs_scanned = stats_reExcls = 0;
5656 HG_(initIterFM)( map_shmem );
5657 while (HG_(nextIterFM)( map_shmem,
5658 (Word*)(void*)&ga, (Word*)(void*)&sm )) {
5659 SecMapIter itr;
5660 UInt* w32p;
5661 tl_assert(sm);
5662 stats_SMs++;
5663 /* Skip this SecMap if the summary bit indicates it is safe to
5664 do so. */
5665 if (!sm->mbHasShared)
5666 continue;
5667 stats_SMs_scanned++;
5668 initSecMapIter( &itr );
5669 while (stepSecMapIter( &w32p, &itr, sm )) {
5670 Bool isM;
5671 UInt wnew, wold, lset_old, tset_old, tset_new;
5672 wold = *w32p;
5673 if (!is_SHVAL_Sh(wold))
5674 continue;
5675 isM = is_SHVAL_ShM(wold);
5676 lset_old = un_SHVAL_Sh_lset(wold);
5677 tset_old = un_SHVAL_Sh_tset(wold);
5678 /* Subst thr_q -> thr_s in the thread set. Longwindedly, if
5679 thr_q is in the set, delete it and add thr_s; else leave
5680 it alone. FIXME: is inefficient - make a special
5681 substInWS method for this. */
5682 tset_new
5683 = HG_(elemWS)( univ_tsets, tset_old, (Word)thr_q )
5684 ? HG_(addToWS)(
5685 univ_tsets,
5686 HG_(delFromWS)( univ_tsets, tset_old, (Word)thr_q ),
5687 (Word)thr_s
5688 )
5689 : tset_old;
5690
5691 tl_assert(HG_(cardinalityWS)(univ_tsets, tset_new)
5692 <= HG_(cardinalityWS)(univ_tsets, tset_old));
5693
5694 if (0) {
5695 VG_(printf)("smga %p: old 0x%x new 0x%x ",
5696 ga, tset_old, tset_new);
5697 HG_(ppWS)( univ_tsets, tset_old );
5698 VG_(printf)(" --> ");
5699 HG_(ppWS)( univ_tsets, tset_new );
5700 VG_(printf)("\n");
5701 }
5702 if (HG_(isSingletonWS)( univ_tsets, tset_new, (Word)thr_s )) {
5703 /* This word returns to Excl state */
5704 wnew = mk_SHVAL_Excl(thr_s->csegid);
5705 stats_reExcls++;
5706 } else {
5707 wnew = isM ? mk_SHVAL_ShM(tset_new, lset_old)
5708 : mk_SHVAL_ShR(tset_new, lset_old);
5709 }
5710 *w32p = wnew;
5711 }
5712 }
5713 HG_(doneIterFM)( map_shmem );
5714
5715 if (SHOW_EXPENSIVE_STUFF)
5716 VG_(printf)("evh__post_thread_join: %d SMs, "
5717 "%d scanned, %d re-Excls\n",
5718 stats_SMs, stats_SMs_scanned, stats_reExcls);
5719
5720 /* This holds because, at least when using NPTL as the thread
5721 library, we should be notified the low level thread exit before
5722 we hear of any join event on it. The low level exit
5723 notification feeds through into evh__pre_thread_ll_exit,
5724 which should clear the map_threads entry for it. Hence we
5725 expect there to be no map_threads entry at this point. */
5726 tl_assert( map_threads_maybe_reverse_lookup_SLOW(thr_q)
5727 == VG_INVALID_THREADID);
5728
5729 if (clo_sanity_flags & SCE_THREADS)
5730 all__sanity_check("evh__post_thread_join-post");
5731}
5732
5733static
5734void evh__pre_mem_read ( CorePart part, ThreadId tid, Char* s,
5735 Addr a, SizeT size) {
5736 if (SHOW_EVENTS >= 2
5737 || (SHOW_EVENTS >= 1 && size != 1))
5738 VG_(printf)("evh__pre_mem_read(ctid=%d, \"%s\", %p, %lu)\n",
5739 (Int)tid, s, (void*)a, size );
5740 shadow_mem_read_range( map_threads_lookup(tid), a, size);
5741 if (size >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5742 all__sanity_check("evh__pre_mem_read-post");
5743}
5744
5745static
5746void evh__pre_mem_read_asciiz ( CorePart part, ThreadId tid,
5747 Char* s, Addr a ) {
5748 Int len;
5749 if (SHOW_EVENTS >= 1)
5750 VG_(printf)("evh__pre_mem_asciiz(ctid=%d, \"%s\", %p)\n",
5751 (Int)tid, s, (void*)a );
5752 // FIXME: think of a less ugly hack
5753 len = VG_(strlen)( (Char*) a );
5754 shadow_mem_read_range( map_threads_lookup(tid), a, len+1 );
5755 if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5756 all__sanity_check("evh__pre_mem_read_asciiz-post");
5757}
5758
5759static
5760void evh__pre_mem_write ( CorePart part, ThreadId tid, Char* s,
5761 Addr a, SizeT size ) {
5762 if (SHOW_EVENTS >= 1)
5763 VG_(printf)("evh__pre_mem_write(ctid=%d, \"%s\", %p, %lu)\n",
5764 (Int)tid, s, (void*)a, size );
5765 shadow_mem_write_range( map_threads_lookup(tid), a, size);
5766 if (size >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5767 all__sanity_check("evh__pre_mem_write-post");
5768}
5769
5770static
5771void evh__new_mem_heap ( Addr a, SizeT len, Bool is_inited ) {
5772 if (SHOW_EVENTS >= 1)
5773 VG_(printf)("evh__new_mem_heap(%p, %lu, inited=%d)\n",
5774 (void*)a, len, (Int)is_inited );
5775 // FIXME: this is kinda stupid
5776 if (is_inited) {
5777 shadow_mem_make_New(get_current_Thread(), a, len);
5778 } else {
5779 shadow_mem_make_New(get_current_Thread(), a, len);
5780 }
5781 if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5782 all__sanity_check("evh__pre_mem_read-post");
5783}
5784
5785static
5786void evh__die_mem_heap ( Addr a, SizeT len ) {
5787 if (SHOW_EVENTS >= 1)
5788 VG_(printf)("evh__die_mem_heap(%p, %lu)\n", (void*)a, len );
5789 shadow_mem_make_NoAccess( get_current_Thread(), a, len );
5790 if (len >= SCE_BIGRANGE_T && (clo_sanity_flags & SCE_BIGRANGE))
5791 all__sanity_check("evh__pre_mem_read-post");
5792}
5793
5794// thread async exit?
5795
5796static VG_REGPARM(1)
5797void evh__mem_help_read_1(Addr a) {
5798 shadow_mem_read8( get_current_Thread_in_C_C(), a, 0/*unused*/ );
5799}
5800static VG_REGPARM(1)
5801void evh__mem_help_read_2(Addr a) {
5802 shadow_mem_read16( get_current_Thread_in_C_C(), a, 0/*unused*/ );
5803}
5804static VG_REGPARM(1)
5805void evh__mem_help_read_4(Addr a) {
5806 shadow_mem_read32( get_current_Thread_in_C_C(), a, 0/*unused*/ );
5807}
5808static VG_REGPARM(1)
5809void evh__mem_help_read_8(Addr a) {
5810 shadow_mem_read64( get_current_Thread_in_C_C(), a, 0/*unused*/ );
5811}
5812static VG_REGPARM(2)
5813void evh__mem_help_read_N(Addr a, SizeT size) {
5814 shadow_mem_read_range( get_current_Thread_in_C_C(), a, size );
5815}
5816
5817static VG_REGPARM(1)
5818void evh__mem_help_write_1(Addr a) {
5819 shadow_mem_write8( get_current_Thread_in_C_C(), a, 0/*unused*/ );
5820}
5821static VG_REGPARM(1)
5822void evh__mem_help_write_2(Addr a) {
5823 shadow_mem_write16( get_current_Thread_in_C_C(), a, 0/*unused*/ );
5824}
5825static VG_REGPARM(1)
5826void evh__mem_help_write_4(Addr a) {
5827 shadow_mem_write32( get_current_Thread_in_C_C(), a, 0/*unused*/ );
5828}
5829static VG_REGPARM(1)
5830void evh__mem_help_write_8(Addr a) {
5831 shadow_mem_write64( get_current_Thread_in_C_C(), a, 0/*unused*/ );
5832}
5833static VG_REGPARM(2)
5834void evh__mem_help_write_N(Addr a, SizeT size) {
5835 shadow_mem_write_range( get_current_Thread_in_C_C(), a, size );
5836}
5837
5838static void evh__bus_lock(void) {
5839 Thread* thr;
5840 if (0) VG_(printf)("evh__bus_lock()\n");
5841 thr = get_current_Thread();
5842 tl_assert(thr); /* cannot fail - Thread* must already exist */
5843 evhH__post_thread_w_acquires_lock( thr, LK_nonRec, (Addr)&__bus_lock );
5844}
5845static void evh__bus_unlock(void) {
5846 Thread* thr;
5847 if (0) VG_(printf)("evh__bus_unlock()\n");
5848 thr = get_current_Thread();
5849 tl_assert(thr); /* cannot fail - Thread* must already exist */
5850 evhH__pre_thread_releases_lock( thr, (Addr)&__bus_lock, False/*!isRDWR*/ );
5851}
5852
5853
5854/* -------------- events to do with mutexes -------------- */
5855
5856/* EXPOSITION only: by intercepting lock init events we can show the
5857 user where the lock was initialised, rather than only being able to
5858 show where it was first locked. Intercepting lock initialisations
5859 is not necessary for the basic operation of the race checker. */
5860static
5861void evh__HG_PTHREAD_MUTEX_INIT_POST( ThreadId tid,
5862 void* mutex, Word mbRec )
5863{
5864 if (SHOW_EVENTS >= 1)
5865 VG_(printf)("evh__hg_PTHREAD_MUTEX_INIT_POST(ctid=%d, mbRec=%ld, %p)\n",
5866 (Int)tid, mbRec, (void*)mutex );
5867 tl_assert(mbRec == 0 || mbRec == 1);
5868 map_locks_lookup_or_create( mbRec ? LK_mbRec : LK_nonRec,
5869 (Addr)mutex, tid );
5870 if (clo_sanity_flags & SCE_LOCKS)
5871 all__sanity_check("evh__hg_PTHREAD_MUTEX_INIT_POST");
5872}
5873
5874static
5875void evh__HG_PTHREAD_MUTEX_DESTROY_PRE( ThreadId tid, void* mutex )
5876{
5877 Thread* thr;
5878 Lock* lk;
5879 if (SHOW_EVENTS >= 1)
5880 VG_(printf)("evh__hg_PTHREAD_MUTEX_DESTROY_PRE(ctid=%d, %p)\n",
5881 (Int)tid, (void*)mutex );
5882
5883 thr = map_threads_maybe_lookup( tid );
5884 /* cannot fail - Thread* must already exist */
5885 tl_assert( is_sane_Thread(thr) );
5886
5887 lk = map_locks_maybe_lookup( (Addr)mutex );
5888
5889 if (lk == NULL || (lk->kind != LK_nonRec && lk->kind != LK_mbRec)) {
5890 record_error_Misc( thr,
5891 "pthread_mutex_destroy with invalid argument" );
5892 }
5893
5894 if (lk) {
5895 tl_assert( is_sane_LockN(lk) );
5896 tl_assert( lk->guestaddr == (Addr)mutex );
5897 if (lk->heldBy) {
5898 /* Basically act like we unlocked the lock */
5899 record_error_Misc( thr, "pthread_mutex_destroy of a locked mutex" );
5900 /* remove lock from locksets of all owning threads */
5901 remove_Lock_from_locksets_of_all_owning_Threads( lk );
5902 HG_(deleteBag)( lk->heldBy );
5903 lk->heldBy = NULL;
5904 lk->heldW = False;
5905 lk->acquired_at = NULL;
5906 }
5907 tl_assert( !lk->heldBy );
5908 tl_assert( is_sane_LockN(lk) );
5909 }
5910
5911 if (clo_sanity_flags & SCE_LOCKS)
5912 all__sanity_check("evh__hg_PTHREAD_MUTEX_DESTROY_PRE");
5913}
5914
5915static void evh__HG_PTHREAD_MUTEX_LOCK_PRE ( ThreadId tid,
5916 void* mutex, Word isTryLock )
5917{
5918 /* Just check the mutex is sane; nothing else to do. */
5919 // 'mutex' may be invalid - not checked by wrapper
5920 Thread* thr;
5921 Lock* lk;
5922 if (SHOW_EVENTS >= 1)
5923 VG_(printf)("evh__hg_PTHREAD_MUTEX_LOCK_PRE(ctid=%d, mutex=%p)\n",
5924 (Int)tid, (void*)mutex );
5925
5926 tl_assert(isTryLock == 0 || isTryLock == 1);
5927 thr = map_threads_maybe_lookup( tid );
5928 tl_assert(thr); /* cannot fail - Thread* must already exist */
5929
5930 lk = map_locks_maybe_lookup( (Addr)mutex );
5931
5932 if (lk && (lk->kind == LK_rdwr)) {
5933 record_error_Misc( thr, "pthread_mutex_lock with a "
5934 "pthread_rwlock_t* argument " );
5935 }
5936
5937 if ( lk
5938 && isTryLock == 0
5939 && (lk->kind == LK_nonRec || lk->kind == LK_rdwr)
5940 && lk->heldBy
5941 && lk->heldW
5942 && HG_(elemBag)( lk->heldBy, (Word)thr ) > 0 ) {
5943 /* uh, it's a non-recursive lock and we already w-hold it, and
5944 this is a real lock operation (not a speculative "tryLock"
5945 kind of thing). Duh. Deadlock coming up; but at least
5946 produce an error message. */
5947 record_error_Misc( thr, "Attempt to re-lock a "
5948 "non-recursive lock I already hold" );
5949 }
5950}
5951
5952static void evh__HG_PTHREAD_MUTEX_LOCK_POST ( ThreadId tid, void* mutex )
5953{
5954 // only called if the real library call succeeded - so mutex is sane
5955 Thread* thr;
5956 if (SHOW_EVENTS >= 1)
5957 VG_(printf)("evh__HG_PTHREAD_MUTEX_LOCK_POST(ctid=%d, mutex=%p)\n",
5958 (Int)tid, (void*)mutex );
5959
5960 thr = map_threads_maybe_lookup( tid );
5961 tl_assert(thr); /* cannot fail - Thread* must already exist */
5962
5963 evhH__post_thread_w_acquires_lock(
5964 thr,
5965 LK_mbRec, /* if not known, create new lock with this LockKind */
5966 (Addr)mutex
5967 );
5968}
5969
5970static void evh__HG_PTHREAD_MUTEX_UNLOCK_PRE ( ThreadId tid, void* mutex )
5971{
5972 // 'mutex' may be invalid - not checked by wrapper
5973 Thread* thr;
5974 if (SHOW_EVENTS >= 1)
5975 VG_(printf)("evh__HG_PTHREAD_MUTEX_UNLOCK_PRE(ctid=%d, mutex=%p)\n",
5976 (Int)tid, (void*)mutex );
5977
5978 thr = map_threads_maybe_lookup( tid );
5979 tl_assert(thr); /* cannot fail - Thread* must already exist */
5980
5981 evhH__pre_thread_releases_lock( thr, (Addr)mutex, False/*!isRDWR*/ );
5982}
5983
5984static void evh__HG_PTHREAD_MUTEX_UNLOCK_POST ( ThreadId tid, void* mutex )
5985{
5986 // only called if the real library call succeeded - so mutex is sane
5987 Thread* thr;
5988 if (SHOW_EVENTS >= 1)
5989 VG_(printf)("evh__hg_PTHREAD_MUTEX_UNLOCK_POST(ctid=%d, mutex=%p)\n",
5990 (Int)tid, (void*)mutex );
5991 thr = map_threads_maybe_lookup( tid );
5992 tl_assert(thr); /* cannot fail - Thread* must already exist */
5993
5994 // anything we should do here?
5995}
5996
5997
5998/* --------------- events to do with CVs --------------- */
5999
6000/* A mapping from CV to the thread segment which has most recently
6001 signalled/broadcasted on it. This makes it possible to create
6002 thread segments to model happens-before events arising from CV
6003 signallings/broadcasts.
6004*/
6005
6006/* pthread_mutex_cond* -> Segment* */
6007static WordFM* map_cond_to_Segment = NULL;
6008
6009static void map_cond_to_Segment_INIT ( void ) {
6010 if (UNLIKELY(map_cond_to_Segment == NULL)) {
6011 map_cond_to_Segment = HG_(newFM)( hg_zalloc, hg_free, NULL );
6012 tl_assert(map_cond_to_Segment != NULL);
6013 }
6014}
6015
6016static void evh__HG_PTHREAD_COND_SIGNAL_PRE ( ThreadId tid, void* cond )
6017{
6018 /* 'tid' has signalled on 'cond'. Start a new segment for this
6019 thread, and make a binding from 'cond' to our old segment in the
6020 mapping. This is later used by other thread(s) which
6021 successfully exit from a pthread_cond_wait on the same cv; then
6022 they know what the signalling segment was, so a dependency edge
6023 back to it can be constructed. */
6024
6025 Thread* thr;
6026 SegmentID new_segid;
6027 Segment* new_seg;
6028
6029 if (SHOW_EVENTS >= 1)
6030 VG_(printf)("evh__HG_PTHREAD_COND_SIGNAL_PRE(ctid=%d, cond=%p)\n",
6031 (Int)tid, (void*)cond );
6032
6033 map_cond_to_Segment_INIT();
6034 thr = map_threads_maybe_lookup( tid );
6035 tl_assert(thr); /* cannot fail - Thread* must already exist */
6036
6037 // error-if: mutex is bogus
6038 // error-if: mutex is not locked
6039
6040 if (clo_happens_before >= 2) {
6041 /* create a new segment ... */
6042 new_segid = 0; /* bogus */
6043 new_seg = NULL;
6044 evhH__start_new_segment_for_thread( &new_segid, &new_seg, thr );
6045 tl_assert( is_sane_SegmentID(new_segid) );
6046 tl_assert( is_sane_Segment(new_seg) );
6047 tl_assert( new_seg->thr == thr );
6048 tl_assert( is_sane_Segment(new_seg->prev) );
6049 tl_assert( new_seg->prev->vts );
6050 new_seg->vts = tick_VTS( new_seg->thr, new_seg->prev->vts );
6051
6052 /* ... and add the binding. */
6053 HG_(addToFM)( map_cond_to_Segment, (Word)cond,
6054 (Word)(new_seg->prev) );
6055 }
6056}
6057
6058/* returns True if it reckons 'mutex' is valid and held by this
6059 thread, else False */
6060static Bool evh__HG_PTHREAD_COND_WAIT_PRE ( ThreadId tid,
6061 void* cond, void* mutex )
6062{
6063 Thread* thr;
6064 Lock* lk;
6065 Bool lk_valid = True;
6066
6067 if (SHOW_EVENTS >= 1)
6068 VG_(printf)("evh__hg_PTHREAD_COND_WAIT_PRE"
6069 "(ctid=%d, cond=%p, mutex=%p)\n",
6070 (Int)tid, (void*)cond, (void*)mutex );
6071
6072 map_cond_to_Segment_INIT();
6073 thr = map_threads_maybe_lookup( tid );
6074 tl_assert(thr); /* cannot fail - Thread* must already exist */
6075
6076 lk = map_locks_maybe_lookup( (Addr)mutex );
6077
6078 /* Check for stupid mutex arguments. There are various ways to be
6079 a bozo. Only complain once, though, even if more than one thing
6080 is wrong. */
6081 if (lk == NULL) {
6082 lk_valid = False;
6083 record_error_Misc(
6084 thr,
6085 "pthread_cond_{timed}wait called with invalid mutex" );
6086 } else {
6087 tl_assert( is_sane_LockN(lk) );
6088 if (lk->kind == LK_rdwr) {
6089 lk_valid = False;
6090 record_error_Misc(
6091 thr, "pthread_cond_{timed}wait called with mutex "
6092 "of type pthread_rwlock_t*" );
6093 } else
6094 if (lk->heldBy == NULL) {
6095 lk_valid = False;
6096 record_error_Misc(
6097 thr, "pthread_cond_{timed}wait called with un-held mutex");
6098 } else
6099 if (lk->heldBy != NULL
6100 && HG_(elemBag)( lk->heldBy, (Word)thr ) == 0) {
6101 lk_valid = False;
6102 record_error_Misc(
6103 thr, "pthread_cond_{timed}wait called with mutex "
6104 "held by a different thread" );
6105 }
6106 }
6107
6108 // error-if: cond is also associated with a different mutex
6109
6110 return lk_valid;
6111}
6112
6113static void evh__HG_PTHREAD_COND_WAIT_POST ( ThreadId tid,
6114 void* cond, void* mutex )
6115{
6116 /* A pthread_cond_wait(cond, mutex) completed successfully. Start
6117 a new segment for this thread. Look up the signalling-segment
6118 for the 'cond' in the mapping, and add a dependency edge from
6119 the new segment back to it. */
6120
6121 Thread* thr;
6122 SegmentID new_segid;
6123 Segment* new_seg;
6124 Segment* signalling_seg;
6125 Bool found;
6126
6127 if (SHOW_EVENTS >= 1)
6128 VG_(printf)("evh__HG_PTHREAD_COND_WAIT_POST"
6129 "(ctid=%d, cond=%p, mutex=%p)\n",
6130 (Int)tid, (void*)cond, (void*)mutex );
6131
6132 map_cond_to_Segment_INIT();
6133 thr = map_threads_maybe_lookup( tid );
6134 tl_assert(thr); /* cannot fail - Thread* must already exist */
6135
6136 // error-if: cond is also associated with a different mutex
6137
6138 if (clo_happens_before >= 2) {
6139 /* create a new segment ... */
6140 new_segid = 0; /* bogus */
6141 new_seg = NULL;
6142 evhH__start_new_segment_for_thread( &new_segid, &new_seg, thr );
6143 tl_assert( is_sane_SegmentID(new_segid) );
6144 tl_assert( is_sane_Segment(new_seg) );
6145 tl_assert( new_seg->thr == thr );
6146 tl_assert( is_sane_Segment(new_seg->prev) );
6147 tl_assert( new_seg->other == NULL);
6148
6149 /* and find out which thread signalled us; then add a dependency
6150 edge back to it. */
6151 signalling_seg = NULL;
6152 found = HG_(lookupFM)( map_cond_to_Segment,
6153 NULL, (Word*)(void*)&signalling_seg,
6154 (Word)cond );
6155 if (found) {
6156 tl_assert(is_sane_Segment(signalling_seg));
6157 tl_assert(new_seg->prev);
6158 tl_assert(new_seg->prev->vts);
6159 new_seg->other = signalling_seg;
6160 new_seg->other_hint = 's';
6161 tl_assert(new_seg->other->vts);
6162 new_seg->vts = tickL_and_joinR_VTS(
6163 new_seg->thr,
6164 new_seg->prev->vts,
6165 new_seg->other->vts );
6166 } else {
6167 /* Hmm. How can a wait on 'cond' succeed if nobody signalled
6168 it? If this happened it would surely be a bug in the
6169 threads library. Or one of those fabled "spurious
6170 wakeups". */
6171 record_error_Misc( thr, "Bug in libpthread: pthread_cond_wait "
6172 "succeeded on"
6173 " without prior pthread_cond_post");
6174 tl_assert(new_seg->prev->vts);
6175 new_seg->vts = tick_VTS( new_seg->thr, new_seg->prev->vts );
6176 }
6177 }
6178}
6179
6180
6181/* -------------- events to do with rwlocks -------------- */
6182
6183/* EXPOSITION only */
6184static
6185void evh__HG_PTHREAD_RWLOCK_INIT_POST( ThreadId tid, void* rwl )
6186{
6187 if (SHOW_EVENTS >= 1)
6188 VG_(printf)("evh__hg_PTHREAD_RWLOCK_INIT_POST(ctid=%d, %p)\n",
6189 (Int)tid, (void*)rwl );
6190 map_locks_lookup_or_create( LK_rdwr, (Addr)rwl, tid );
6191 if (clo_sanity_flags & SCE_LOCKS)
6192 all__sanity_check("evh__hg_PTHREAD_RWLOCK_INIT_POST");
6193}
6194
6195static
6196void evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( ThreadId tid, void* rwl )
6197{
6198 Thread* thr;
6199 Lock* lk;
6200 if (SHOW_EVENTS >= 1)
6201 VG_(printf)("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE(ctid=%d, %p)\n",
6202 (Int)tid, (void*)rwl );
6203
6204 thr = map_threads_maybe_lookup( tid );
6205 /* cannot fail - Thread* must already exist */
6206 tl_assert( is_sane_Thread(thr) );
6207
6208 lk = map_locks_maybe_lookup( (Addr)rwl );
6209
6210 if (lk == NULL || lk->kind != LK_rdwr) {
6211 record_error_Misc( thr,
6212 "pthread_rwlock_destroy with invalid argument" );
6213 }
6214
6215 if (lk) {
6216 tl_assert( is_sane_LockN(lk) );
6217 tl_assert( lk->guestaddr == (Addr)rwl );
6218 if (lk->heldBy) {
6219 /* Basically act like we unlocked the lock */
6220 record_error_Misc( thr, "pthread_rwlock_destroy of a locked mutex" );
6221 /* remove lock from locksets of all owning threads */
6222 remove_Lock_from_locksets_of_all_owning_Threads( lk );
6223 HG_(deleteBag)( lk->heldBy );
6224 lk->heldBy = NULL;
6225 lk->heldW = False;
6226 }
6227 tl_assert( !lk->heldBy );
6228 tl_assert( is_sane_LockN(lk) );
6229 }
6230
6231 if (clo_sanity_flags & SCE_LOCKS)
6232 all__sanity_check("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE");
6233}
6234
6235static
6236void evh__HG_PTHREAD_RWLOCK_LOCK_PRE ( ThreadId tid, void* rwl, Word isW )
6237{
6238 /* Just check the rwl is sane; nothing else to do. */
6239 // 'rwl' may be invalid - not checked by wrapper
6240 Thread* thr;
6241 Lock* lk;
6242 if (SHOW_EVENTS >= 1)
6243 VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_PRE(ctid=%d, isW=%d, %p)\n",
6244 (Int)tid, (Int)isW, (void*)rwl );
6245
6246 tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
6247 thr = map_threads_maybe_lookup( tid );
6248 tl_assert(thr); /* cannot fail - Thread* must already exist */
6249
6250 lk = map_locks_maybe_lookup( (Addr)rwl );
6251 if ( lk
6252 && (lk->kind == LK_nonRec || lk->kind == LK_mbRec) ) {
6253 /* Wrong kind of lock. Duh. */
6254 record_error_Misc( thr, "pthread_rwlock_{rd,rw}lock with a "
6255 "pthread_mutex_t* argument " );
6256 }
6257}
6258
6259static
6260void evh__HG_PTHREAD_RWLOCK_LOCK_POST ( ThreadId tid, void* rwl, Word isW )
6261{
6262 // only called if the real library call succeeded - so mutex is sane
6263 Thread* thr;
6264 if (SHOW_EVENTS >= 1)
6265 VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_POST(ctid=%d, isW=%d, %p)\n",
6266 (Int)tid, (Int)isW, (void*)rwl );
6267
6268 tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
6269 thr = map_threads_maybe_lookup( tid );
6270 tl_assert(thr); /* cannot fail - Thread* must already exist */
6271
6272 (isW ? evhH__post_thread_w_acquires_lock
6273 : evhH__post_thread_r_acquires_lock)(
6274 thr,
6275 LK_rdwr, /* if not known, create new lock with this LockKind */
6276 (Addr)rwl
6277 );
6278}
6279
6280static void evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE ( ThreadId tid, void* rwl )
6281{
6282 // 'rwl' may be invalid - not checked by wrapper
6283 Thread* thr;
6284 if (SHOW_EVENTS >= 1)
6285 VG_(printf)("evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE(ctid=%d, rwl=%p)\n",
6286 (Int)tid, (void*)rwl );
6287
6288 thr = map_threads_maybe_lookup( tid );
6289 tl_assert(thr); /* cannot fail - Thread* must already exist */
6290
6291 evhH__pre_thread_releases_lock( thr, (Addr)rwl, True/*isRDWR*/ );
6292}
6293
6294static void evh__HG_PTHREAD_RWLOCK_UNLOCK_POST ( ThreadId tid, void* rwl )
6295{
6296 // only called if the real library call succeeded - so mutex is sane
6297 Thread* thr;
6298 if (SHOW_EVENTS >= 1)
6299 VG_(printf)("evh__hg_PTHREAD_RWLOCK_UNLOCK_POST(ctid=%d, rwl=%p)\n",
6300 (Int)tid, (void*)rwl );
6301 thr = map_threads_maybe_lookup( tid );
6302 tl_assert(thr); /* cannot fail - Thread* must already exist */
6303
6304 // anything we should do here?
6305}
6306
6307
6308/* --------------- events to do with semaphores --------------- */
6309
6310/* This is similar but not identical the handling for condition
6311 variables. */
6312
6313/* For each semaphore, we maintain a stack of Segments. When a 'post'
6314 operation is done on a semaphore (unlocking, essentially), a new
6315 segment is created for the posting thread, and the old segment is
6316 pushed on the semaphore's stack.
6317
6318 Later, when a (probably different) thread completes 'wait' on the
6319 semaphore, we pop a Segment off the semaphore's stack (which should
6320 be nonempty). We start a new segment for the thread and make it
6321 also depend on the just-popped segment. This mechanism creates
6322 dependencies between posters and waiters of the semaphore.
6323
6324 It may not be necessary to use a stack - perhaps a bag of Segments
6325 would do. But we do need to keep track of how many unused-up posts
6326 have happened for the semaphore.
6327
6328 Imagine T1 and T2 both post once on a semphore S, and T3 waits
6329 twice on S. T3 cannot complete its waits without both T1 and T2
6330 posting. The above mechanism will ensure that T3 acquires
6331 dependencies on both T1 and T2.
6332*/
6333
6334/* sem_t* -> XArray* Segment* */
6335static WordFM* map_sem_to_Segment_stack = NULL;
6336
6337static void map_sem_to_Segment_stack_INIT ( void ) {
6338 if (map_sem_to_Segment_stack == NULL) {
6339 map_sem_to_Segment_stack = HG_(newFM)( hg_zalloc, hg_free, NULL );
6340 tl_assert(map_sem_to_Segment_stack != NULL);
6341 }
6342}
6343
6344static void push_Segment_for_sem ( void* sem, Segment* seg ) {
6345 XArray* xa;
6346 tl_assert(seg);
6347 map_sem_to_Segment_stack_INIT();
6348 if (HG_(lookupFM)( map_sem_to_Segment_stack,
6349 NULL, (Word*)(void*)&xa, (Word)sem )) {
6350 tl_assert(xa);
6351 VG_(addToXA)( xa, &seg );
6352 } else {
6353 xa = VG_(newXA)( hg_zalloc, hg_free, sizeof(Segment*) );
6354 VG_(addToXA)( xa, &seg );
6355 HG_(addToFM)( map_sem_to_Segment_stack, (Word)sem, (Word)xa );
6356 }
6357}
6358
6359static Segment* mb_pop_Segment_for_sem ( void* sem ) {
6360 XArray* xa;
6361 Segment* seg;
6362 map_sem_to_Segment_stack_INIT();
6363 if (HG_(lookupFM)( map_sem_to_Segment_stack,
6364 NULL, (Word*)(void*)&xa, (Word)sem )) {
6365 /* xa is the stack for this semaphore. */
6366 Word sz = VG_(sizeXA)( xa );
6367 tl_assert(sz >= 0);
6368 if (sz == 0)
6369 return NULL; /* odd, the stack is empty */
6370 seg = *(Segment**)VG_(indexXA)( xa, sz-1 );
6371 tl_assert(seg);
6372 VG_(dropTailXA)( xa, 1 );
6373 return seg;
6374 } else {
6375 /* hmm, that's odd. No stack for this semaphore. */
6376 return NULL;
6377 }
6378}
6379
6380static void evh__HG_POSIX_SEM_ZAPSTACK ( ThreadId tid, void* sem )
6381{
6382 Segment* seg;
6383
6384 /* Empty out the semaphore's segment stack. Occurs at
6385 sem_init and sem_destroy time. */
6386 if (SHOW_EVENTS >= 1)
6387 VG_(printf)("evh__HG_POSIX_SEM_ZAPSTACK(ctid=%d, sem=%p)\n",
6388 (Int)tid, (void*)sem );
6389
6390 /* This is stupid, but at least it's easy. */
6391 do {
6392 seg = mb_pop_Segment_for_sem( sem );
6393 } while (seg);
6394
6395 tl_assert(!seg);
6396}
6397
6398static void evh__HG_POSIX_SEMPOST_PRE ( ThreadId tid, void* sem )
6399{
6400 /* 'tid' has posted on 'sem'. Start a new segment for this thread,
6401 and push the old segment on a stack of segments associated with
6402 'sem'. This is later used by other thread(s) which successfully
6403 exit from a sem_wait on the same sem; then they know what the
6404 posting segment was, so a dependency edge back to it can be
6405 constructed. */
6406
6407 Thread* thr;
6408 SegmentID new_segid;
6409 Segment* new_seg;
6410
6411 if (SHOW_EVENTS >= 1)
6412 VG_(printf)("evh__HG_POSIX_SEMPOST_PRE(ctid=%d, sem=%p)\n",
6413 (Int)tid, (void*)sem );
6414
6415 thr = map_threads_maybe_lookup( tid );
6416 tl_assert(thr); /* cannot fail - Thread* must already exist */
6417
6418 // error-if: sem is bogus
6419
6420 if (clo_happens_before >= 2) {
6421 /* create a new segment ... */
6422 new_segid = 0; /* bogus */
6423 new_seg = NULL;
6424 evhH__start_new_segment_for_thread( &new_segid, &new_seg, thr );
6425 tl_assert( is_sane_SegmentID(new_segid) );
6426 tl_assert( is_sane_Segment(new_seg) );
6427 tl_assert( new_seg->thr == thr );
6428 tl_assert( is_sane_Segment(new_seg->prev) );
6429 tl_assert( new_seg->prev->vts );
6430 new_seg->vts = tick_VTS( new_seg->thr, new_seg->prev->vts );
6431
6432 /* ... and add the binding. */
6433 push_Segment_for_sem( sem, new_seg->prev );
6434 }
6435}
6436
6437static void evh__HG_POSIX_SEMWAIT_POST ( ThreadId tid, void* sem )
6438{
6439 /* A sem_wait(sem) completed successfully. Start a new segment for
6440 this thread. Pop the posting-segment for the 'sem' in the
6441 mapping, and add a dependency edge from the new segment back to
6442 it. */
6443
6444 Thread* thr;
6445 SegmentID new_segid;
6446 Segment* new_seg;
6447 Segment* posting_seg;
6448
6449 if (SHOW_EVENTS >= 1)
6450 VG_(printf)("evh__HG_POSIX_SEMWAIT_POST(ctid=%d, sem=%p)\n",
6451 (Int)tid, (void*)sem );
6452
6453 thr = map_threads_maybe_lookup( tid );
6454 tl_assert(thr); /* cannot fail - Thread* must already exist */
6455
6456 // error-if: sem is bogus
6457
6458 if (clo_happens_before >= 2) {
6459 /* create a new segment ... */
6460 new_segid = 0; /* bogus */
6461 new_seg = NULL;
6462 evhH__start_new_segment_for_thread( &new_segid, &new_seg, thr );
6463 tl_assert( is_sane_SegmentID(new_segid) );
6464 tl_assert( is_sane_Segment(new_seg) );
6465 tl_assert( new_seg->thr == thr );
6466 tl_assert( is_sane_Segment(new_seg->prev) );
6467 tl_assert( new_seg->other == NULL);
6468
6469 /* and find out which thread posted last on sem; then add a
6470 dependency edge back to it. */
6471 posting_seg = mb_pop_Segment_for_sem( sem );
6472 if (posting_seg) {
6473 tl_assert(is_sane_Segment(posting_seg));
6474 tl_assert(new_seg->prev);
6475 tl_assert(new_seg->prev->vts);
6476 new_seg->other = posting_seg;
6477 new_seg->other_hint = 'S';
6478 tl_assert(new_seg->other->vts);
6479 new_seg->vts = tickL_and_joinR_VTS(
6480 new_seg->thr,
6481 new_seg->prev->vts,
6482 new_seg->other->vts );
6483 } else {
6484 /* Hmm. How can a wait on 'sem' succeed if nobody posted to
6485 it? If this happened it would surely be a bug in the
6486 threads library. */
6487 record_error_Misc( thr, "Bug in libpthread: sem_wait succeeded on"
6488 " semaphore without prior sem_post");
6489 tl_assert(new_seg->prev->vts);
6490 new_seg->vts = tick_VTS( new_seg->thr, new_seg->prev->vts );
6491 }
6492 }
6493}
6494
6495
6496/*--------------------------------------------------------------*/
6497/*--- Lock acquisition order monitoring ---*/
6498/*--------------------------------------------------------------*/
6499
6500/* FIXME: here are some optimisations still to do in
6501 laog__pre_thread_acquires_lock.
6502
6503 The graph is structured so that if L1 --*--> L2 then L1 must be
6504 acquired before L2.
6505
6506 The common case is that some thread T holds (eg) L1 L2 and L3 and
6507 is repeatedly acquiring and releasing Ln, and there is no ordering
6508 error in what it is doing. Hence it repeatly:
6509
6510 (1) searches laog to see if Ln --*--> {L1,L2,L3}, which always
6511 produces the answer No (because there is no error).
6512
6513 (2) adds edges {L1,L2,L3} --> Ln to laog, which are already present
6514 (because they already got added the first time T acquired Ln).
6515
6516 Hence cache these two events:
6517
6518 (1) Cache result of the query from last time. Invalidate the cache
6519 any time any edges are added to or deleted from laog.
6520
6521 (2) Cache these add-edge requests and ignore them if said edges
6522 have already been added to laog. Invalidate the cache any time
6523 any edges are deleted from laog.
6524*/
6525
6526typedef
6527 struct {
6528 WordSetID inns; /* in univ_laog */
6529 WordSetID outs; /* in univ_laog */
6530 }
6531 LAOGLinks;
6532
6533/* lock order acquisition graph */
6534static WordFM* laog = NULL; /* WordFM Lock* LAOGLinks* */
6535
6536/* EXPOSITION ONLY: for each edge in 'laog', record the two places
6537 where that edge was created, so that we can show the user later if
6538 we need to. */
6539typedef
6540 struct {
6541 Addr src_ga; /* Lock guest addresses for */
6542 Addr dst_ga; /* src/dst of the edge */
6543 ExeContext* src_ec; /* And corresponding places where that */
6544 ExeContext* dst_ec; /* ordering was established */
6545 }
6546 LAOGLinkExposition;
6547
6548static Word cmp_LAOGLinkExposition ( Word llx1W, Word llx2W ) {
6549 /* Compare LAOGLinkExposition*s by (src_ga,dst_ga) field pair. */
6550 LAOGLinkExposition* llx1 = (LAOGLinkExposition*)llx1W;
6551 LAOGLinkExposition* llx2 = (LAOGLinkExposition*)llx2W;
6552 if (llx1->src_ga < llx2->src_ga) return -1;
6553 if (llx1->src_ga > llx2->src_ga) return 1;
6554 if (llx1->dst_ga < llx2->dst_ga) return -1;
6555 if (llx1->dst_ga > llx2->dst_ga) return 1;
6556 return 0;
6557}
6558
6559static WordFM* laog_exposition = NULL; /* WordFM LAOGLinkExposition* NULL */
6560/* end EXPOSITION ONLY */
6561
6562
6563static void laog__show ( Char* who ) {
6564 Word i, ws_size;
6565 Word* ws_words;
6566 Lock* me;
6567 LAOGLinks* links;
6568 VG_(printf)("laog (requested by %s) {\n", who);
6569 HG_(initIterFM)( laog );
6570 me = NULL;
6571 links = NULL;
6572 while (HG_(nextIterFM)( laog, (Word*)(void*)&me,
6573 (Word*)(void*)&links )) {
6574 tl_assert(me);
6575 tl_assert(links);
6576 VG_(printf)(" node %p:\n", me);
6577 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
6578 for (i = 0; i < ws_size; i++)
6579 VG_(printf)(" inn %p\n", ws_words[i] );
6580 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
6581 for (i = 0; i < ws_size; i++)
6582 VG_(printf)(" out %p\n", ws_words[i] );
6583 me = NULL;
6584 links = NULL;
6585 }
6586 HG_(doneIterFM)( laog );
6587 VG_(printf)("}\n");
6588}
6589
6590__attribute__((noinline))
6591static void laog__add_edge ( Lock* src, Lock* dst ) {
6592 Word keyW;
6593 LAOGLinks* links;
6594 Bool presentF, presentR;
6595 if (0) VG_(printf)("laog__add_edge %p %p\n", src, dst);
6596
6597 /* Take the opportunity to sanity check the graph. Record in
6598 presentF if there is already a src->dst mapping in this node's
6599 forwards links, and presentR if there is already a src->dst
6600 mapping in this node's backwards links. They should agree!
6601 Also, we need to know whether the edge was already present so as
6602 to decide whether or not to update the link details mapping. We
6603 can compute presentF and presentR essentially for free, so may
6604 as well do this always. */
6605 presentF = presentR = False;
6606
6607 /* Update the out edges for src */
6608 keyW = 0;
6609 links = NULL;
6610 if (HG_(lookupFM)( laog, &keyW, (Word*)(void*)&links, (Word)src )) {
6611 WordSetID outs_new;
6612 tl_assert(links);
6613 tl_assert(keyW == (Word)src);
6614 outs_new = HG_(addToWS)( univ_laog, links->outs, (Word)dst );
6615 presentF = outs_new == links->outs;
6616 links->outs = outs_new;
6617 } else {
6618 links = hg_zalloc(sizeof(LAOGLinks));
6619 links->inns = HG_(emptyWS)( univ_laog );
6620 links->outs = HG_(singletonWS)( univ_laog, (Word)dst );
6621 HG_(addToFM)( laog, (Word)src, (Word)links );
6622 }
6623 /* Update the in edges for dst */
6624 keyW = 0;
6625 links = NULL;
6626 if (HG_(lookupFM)( laog, &keyW, (Word*)(void*)&links, (Word)dst )) {
6627 WordSetID inns_new;
6628 tl_assert(links);
6629 tl_assert(keyW == (Word)dst);
6630 inns_new = HG_(addToWS)( univ_laog, links->inns, (Word)src );
6631 presentR = inns_new == links->inns;
6632 links->inns = inns_new;
6633 } else {
6634 links = hg_zalloc(sizeof(LAOGLinks));
6635 links->inns = HG_(singletonWS)( univ_laog, (Word)src );
6636 links->outs = HG_(emptyWS)( univ_laog );
6637 HG_(addToFM)( laog, (Word)dst, (Word)links );
6638 }
6639
6640 tl_assert( (presentF && presentR) || (!presentF && !presentR) );
6641
6642 if (!presentF && src->acquired_at && dst->acquired_at) {
6643 LAOGLinkExposition expo;
6644 /* If this edge is entering the graph, and we have acquired_at
6645 information for both src and dst, record those acquisition
6646 points. Hence, if there is later a violation of this
6647 ordering, we can show the user the two places in which the
6648 required src-dst ordering was previously established. */
6649 if (0) VG_(printf)("acquire edge %p %p\n",
6650 src->guestaddr, dst->guestaddr);
6651 expo.src_ga = src->guestaddr;
6652 expo.dst_ga = dst->guestaddr;
6653 expo.src_ec = NULL;
6654 expo.dst_ec = NULL;
6655 tl_assert(laog_exposition);
6656 if (HG_(lookupFM)( laog_exposition, NULL, NULL, (Word)&expo )) {
6657 /* we already have it; do nothing */
6658 } else {
6659 LAOGLinkExposition* expo2 = hg_zalloc(sizeof(LAOGLinkExposition));
6660 expo2->src_ga = src->guestaddr;
6661 expo2->dst_ga = dst->guestaddr;
6662 expo2->src_ec = src->acquired_at;
6663 expo2->dst_ec = dst->acquired_at;
6664 HG_(addToFM)( laog_exposition, (Word)expo2, (Word)NULL );
6665 }
6666 }
6667}
6668
6669__attribute__((noinline))
6670static void laog__del_edge ( Lock* src, Lock* dst ) {
6671 Word keyW;
6672 LAOGLinks* links;
6673 if (0) VG_(printf)("laog__del_edge %p %p\n", src, dst);
6674 /* Update the out edges for src */
6675 keyW = 0;
6676 links = NULL;
6677 if (HG_(lookupFM)( laog, &keyW, (Word*)(void*)&links, (Word)src )) {
6678 tl_assert(links);
6679 tl_assert(keyW == (Word)src);
6680 links->outs = HG_(delFromWS)( univ_laog, links->outs, (Word)dst );
6681 }
6682 /* Update the in edges for dst */
6683 keyW = 0;
6684 links = NULL;
6685 if (HG_(lookupFM)( laog, &keyW, (Word*)(void*)&links, (Word)dst )) {
6686 tl_assert(links);
6687 tl_assert(keyW == (Word)dst);
6688 links->inns = HG_(delFromWS)( univ_laog, links->inns, (Word)src );
6689 }
6690}
6691
6692__attribute__((noinline))
6693static WordSetID /* in univ_laog */ laog__succs ( Lock* lk ) {
6694 Word keyW;
6695 LAOGLinks* links;
6696 keyW = 0;
6697 links = NULL;
6698 if (HG_(lookupFM)( laog, &keyW, (Word*)(void*)&links, (Word)lk )) {
6699 tl_assert(links);
6700 tl_assert(keyW == (Word)lk);
6701 return links->outs;
6702 } else {
6703 return HG_(emptyWS)( univ_laog );
6704 }
6705}
6706
6707__attribute__((noinline))
6708static WordSetID /* in univ_laog */ laog__preds ( Lock* lk ) {
6709 Word keyW;
6710 LAOGLinks* links;
6711 keyW = 0;
6712 links = NULL;
6713 if (HG_(lookupFM)( laog, &keyW, (Word*)(void*)&links, (Word)lk )) {
6714 tl_assert(links);
6715 tl_assert(keyW == (Word)lk);
6716 return links->inns;
6717 } else {
6718 return HG_(emptyWS)( univ_laog );
6719 }
6720}
6721
6722__attribute__((noinline))
6723static void laog__sanity_check ( Char* who ) {
6724 Word i, ws_size;
6725 Word* ws_words;
6726 Lock* me;
6727 LAOGLinks* links;
6728 if ( !laog )
6729 return; /* nothing much we can do */
6730 HG_(initIterFM)( laog );
6731 me = NULL;
6732 links = NULL;
6733 if (0) VG_(printf)("laog sanity check\n");
6734 while (HG_(nextIterFM)( laog, (Word*)(void*)&me,
6735 (Word*)(void*)&links )) {
6736 tl_assert(me);
6737 tl_assert(links);
6738 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
6739 for (i = 0; i < ws_size; i++) {
6740 if ( ! HG_(elemWS)( univ_laog,
6741 laog__succs( (Lock*)ws_words[i] ),
6742 (Word)me ))
6743 goto bad;
6744 }
6745 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
6746 for (i = 0; i < ws_size; i++) {
6747 if ( ! HG_(elemWS)( univ_laog,
6748 laog__preds( (Lock*)ws_words[i] ),
6749 (Word)me ))
6750 goto bad;
6751 }
6752 me = NULL;
6753 links = NULL;
6754 }
6755 HG_(doneIterFM)( laog );
6756 return;
6757
6758 bad:
6759 VG_(printf)("laog__sanity_check(%s) FAILED\n", who);
6760 laog__show(who);
6761 tl_assert(0);
6762}
6763
6764/* If there is a path in laog from 'src' to any of the elements in
6765 'dst', return an arbitrarily chosen element of 'dst' reachable from
6766 'src'. If no path exist from 'src' to any element in 'dst', return
6767 NULL. */
6768__attribute__((noinline))
6769static
6770Lock* laog__do_dfs_from_to ( Lock* src, WordSetID dsts /* univ_lsets */ )
6771{
6772 Lock* ret;
6773 Word i, ssz;
6774 XArray* stack; /* of Lock* */
6775 WordFM* visited; /* Lock* -> void, iow, Set(Lock*) */
6776 Lock* here;
6777 WordSetID succs;
6778 Word succs_size;
6779 Word* succs_words;
6780 //laog__sanity_check();
6781
6782 /* If the destination set is empty, we can never get there from
6783 'src' :-), so don't bother to try */
6784 if (HG_(isEmptyWS)( univ_lsets, dsts ))
6785 return NULL;
6786
6787 ret = NULL;
6788 stack = VG_(newXA)( hg_zalloc, hg_free, sizeof(Lock*) );
6789 visited = HG_(newFM)( hg_zalloc, hg_free, NULL/*unboxedcmp*/ );
6790
6791 (void) VG_(addToXA)( stack, &src );
6792
6793 while (True) {
6794
6795 ssz = VG_(sizeXA)( stack );
6796
6797 if (ssz == 0) { ret = NULL; break; }
6798
6799 here = *(Lock**) VG_(indexXA)( stack, ssz-1 );
6800 VG_(dropTailXA)( stack, 1 );
6801
6802 if (HG_(elemWS)( univ_lsets, dsts, (Word)here )) { ret = here; break; }
6803
6804 if (HG_(lookupFM)( visited, NULL, NULL, (Word)here ))
6805 continue;
6806
6807 HG_(addToFM)( visited, (Word)here, 0 );
6808
6809 succs = laog__succs( here );
6810 HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
6811 for (i = 0; i < succs_size; i++)
6812 (void) VG_(addToXA)( stack, &succs_words[i] );
6813 }
6814
6815 HG_(deleteFM)( visited, NULL, NULL );
6816 VG_(deleteXA)( stack );
6817 return ret;
6818}
6819
6820
6821/* Thread 'thr' is acquiring 'lk'. Check for inconsistent ordering
6822 between 'lk' and the locks already held by 'thr' and issue a
6823 complaint if so. Also, update the ordering graph appropriately.
6824*/
6825__attribute__((noinline))
6826static void laog__pre_thread_acquires_lock (
6827 Thread* thr, /* NB: BEFORE lock is added */
6828 Lock* lk
6829 )
6830{
6831 Word* ls_words;
6832 Word ls_size, i;
6833 Lock* other;
6834
6835 /* It may be that 'thr' already holds 'lk' and is recursively
6836 relocking in. In this case we just ignore the call. */
6837 /* NB: univ_lsets really is correct here */
6838 if (HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lk ))
6839 return;
6840
6841 if (!laog)
6842 laog = HG_(newFM)( hg_zalloc, hg_free, NULL/*unboxedcmp*/ );
6843 if (!laog_exposition)
6844 laog_exposition = HG_(newFM)( hg_zalloc, hg_free,
6845 cmp_LAOGLinkExposition );
6846
6847 /* First, the check. Complain if there is any path in laog from lk
6848 to any of the locks already held by thr, since if any such path
6849 existed, it would mean that previously lk was acquired before
6850 (rather than after, as we are doing here) at least one of those
6851 locks.
6852 */
6853 other = laog__do_dfs_from_to(lk, thr->locksetA);
6854 if (other) {
6855 LAOGLinkExposition key, *found;
6856 /* So we managed to find a path lk --*--> other in the graph,
6857 which implies that 'lk' should have been acquired before
6858 'other' but is in fact being acquired afterwards. We present
6859 the lk/other arguments to record_error_LockOrder in the order
6860 in which they should have been acquired. */
6861 /* Go look in the laog_exposition mapping, to find the allocation
6862 points for this edge, so we can show the user. */
6863 key.src_ga = lk->guestaddr;
6864 key.dst_ga = other->guestaddr;
6865 key.src_ec = NULL;
6866 key.dst_ec = NULL;
6867 found = NULL;
6868 if (HG_(lookupFM)( laog_exposition,
6869 (Word*)(void*)&found, NULL, (Word)&key )) {
6870 tl_assert(found != &key);
6871 tl_assert(found->src_ga == key.src_ga);
6872 tl_assert(found->dst_ga == key.dst_ga);
6873 tl_assert(found->src_ec);
6874 tl_assert(found->dst_ec);
6875 record_error_LockOrder( thr,
6876 lk->guestaddr, other->guestaddr,
6877 found->src_ec, found->dst_ec );
6878 } else {
6879 /* Hmm. This can't happen (can it?) */
6880 record_error_LockOrder( thr,
6881 lk->guestaddr, other->guestaddr,
6882 NULL, NULL );
6883 }
6884 }
6885
6886 /* Second, add to laog the pairs
6887 (old, lk) | old <- locks already held by thr
6888 Since both old and lk are currently held by thr, their acquired_at
6889 fields must be non-NULL.
6890 */
6891 tl_assert(lk->acquired_at);
6892 HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, thr->locksetA );
6893 for (i = 0; i < ls_size; i++) {
6894 Lock* old = (Lock*)ls_words[i];
6895 tl_assert(old->acquired_at);
6896 laog__add_edge( old, lk );
6897 }
6898
6899 /* Why "except_Locks" ? We're here because a lock is being
6900 acquired by a thread, and we're in an inconsistent state here.
6901 See the call points in evhH__post_thread_{r,w}_acquires_lock.
6902 When called in this inconsistent state, locks__sanity_check duly
6903 barfs. */
6904 if (clo_sanity_flags & SCE_LAOG)
6905 all_except_Locks__sanity_check("laog__pre_thread_acquires_lock-post");
6906}
6907
6908
6909/* Delete from 'laog' any pair mentioning a lock in locksToDelete */
6910
6911__attribute__((noinline))
6912static void laog__handle_one_lock_deletion ( Lock* lk )
6913{
6914 WordSetID preds, succs;
6915 Word preds_size, succs_size, i, j;
6916 Word *preds_words, *succs_words;
6917
6918 preds = laog__preds( lk );
6919 succs = laog__succs( lk );
6920
6921 HG_(getPayloadWS)( &preds_words, &preds_size, univ_laog, preds );
6922 for (i = 0; i < preds_size; i++)
6923 laog__del_edge( (Lock*)preds_words[i], lk );
6924
6925 HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
6926 for (j = 0; j < succs_size; j++)
6927 laog__del_edge( lk, (Lock*)succs_words[j] );
6928
6929 for (i = 0; i < preds_size; i++) {
6930 for (j = 0; j < succs_size; j++) {
6931 if (preds_words[i] != succs_words[j]) {
6932 /* This can pass unlocked locks to laog__add_edge, since
6933 we're deleting stuff. So their acquired_at fields may
6934 be NULL. */
6935 laog__add_edge( (Lock*)preds_words[i], (Lock*)succs_words[j] );
6936 }
6937 }
6938 }
6939}
6940
6941__attribute__((noinline))
6942static void laog__handle_lock_deletions (
6943 WordSetID /* in univ_laog */ locksToDelete
6944 )
6945{
6946 Word i, ws_size;
6947 Word* ws_words;
6948
6949 if (!laog)
6950 laog = HG_(newFM)( hg_zalloc, hg_free, NULL/*unboxedcmp*/ );
6951 if (!laog_exposition)
6952 laog_exposition = HG_(newFM)( hg_zalloc, hg_free,
6953 cmp_LAOGLinkExposition );
6954
6955 HG_(getPayloadWS)( &ws_words, &ws_size, univ_lsets, locksToDelete );
6956 for (i = 0; i < ws_size; i++)
6957 laog__handle_one_lock_deletion( (Lock*)ws_words[i] );
6958
6959 if (clo_sanity_flags & SCE_LAOG)
6960 all__sanity_check("laog__handle_lock_deletions-post");
6961}
6962
6963
6964/*--------------------------------------------------------------*/
6965/*--- Malloc/free replacements ---*/
6966/*--------------------------------------------------------------*/
6967
6968typedef
6969 struct {
6970 void* next; /* required by m_hashtable */
6971 Addr payload; /* ptr to actual block */
6972 SizeT szB; /* size requested */
6973 ExeContext* where; /* where it was allocated */
6974 Thread* thr; /* allocating thread */
6975 }
6976 MallocMeta;
6977
6978/* A hash table of MallocMetas, used to track malloc'd blocks
6979 (obviously). */
6980static VgHashTable hg_mallocmeta_table = NULL;
6981
6982
6983static MallocMeta* new_MallocMeta ( void ) {
6984 MallocMeta* md = hg_zalloc( sizeof(MallocMeta) );
6985 tl_assert(md);
6986 return md;
6987}
6988static void delete_MallocMeta ( MallocMeta* md ) {
6989 hg_free(md);
6990}
6991
6992
6993/* Allocate a client block and set up the metadata for it. */
6994
6995static
6996void* handle_alloc ( ThreadId tid,
6997 SizeT szB, SizeT alignB, Bool is_zeroed )
6998{
6999 Addr p;
7000 MallocMeta* md;
7001
7002 tl_assert( ((SSizeT)szB) >= 0 );
7003 p = (Addr)VG_(cli_malloc)(alignB, szB);
7004 if (!p) {
7005 return NULL;
7006 }
7007 if (is_zeroed)
7008 VG_(memset)((void*)p, 0, szB);
7009
7010 /* Note that map_threads_lookup must succeed (cannot assert), since
7011 memory can only be allocated by currently alive threads, hence
7012 they must have an entry in map_threads. */
7013 md = new_MallocMeta();
7014 md->payload = p;
7015 md->szB = szB;
7016 md->where = VG_(record_ExeContext)( tid, 0 );
7017 md->thr = map_threads_lookup( tid );
7018
7019 VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md );
7020
7021 /* Tell the lower level memory wranglers. */
7022 evh__new_mem_heap( p, szB, is_zeroed );
7023
7024 return (void*)p;
7025}
7026
7027/* Re the checks for less-than-zero (also in hg_cli__realloc below):
7028 Cast to a signed type to catch any unexpectedly negative args.
7029 We're assuming here that the size asked for is not greater than
7030 2^31 bytes (for 32-bit platforms) or 2^63 bytes (for 64-bit
7031 platforms). */
7032static void* hg_cli__malloc ( ThreadId tid, SizeT n ) {
7033 if (((SSizeT)n) < 0) return NULL;
7034 return handle_alloc ( tid, n, VG_(clo_alignment),
7035 /*is_zeroed*/False );
7036}
7037static void* hg_cli____builtin_new ( ThreadId tid, SizeT n ) {
7038 if (((SSizeT)n) < 0) return NULL;
7039 return handle_alloc ( tid, n, VG_(clo_alignment),
7040 /*is_zeroed*/False );
7041}
7042static void* hg_cli____builtin_vec_new ( ThreadId tid, SizeT n ) {
7043 if (((SSizeT)n) < 0) return NULL;
7044 return handle_alloc ( tid, n, VG_(clo_alignment),
7045 /*is_zeroed*/False );
7046}
7047static void* hg_cli__memalign ( ThreadId tid, SizeT align, SizeT n ) {
7048 if (((SSizeT)n) < 0) return NULL;
7049 return handle_alloc ( tid, n, align,
7050 /*is_zeroed*/False );
7051}
7052static void* hg_cli__calloc ( ThreadId tid, SizeT nmemb, SizeT size1 ) {
7053 if ( ((SSizeT)nmemb) < 0 || ((SSizeT)size1) < 0 ) return NULL;
7054 return handle_alloc ( tid, nmemb*size1, VG_(clo_alignment),
7055 /*is_zeroed*/True );
7056}
7057
7058
7059/* Free a client block, including getting rid of the relevant
7060 metadata. */
7061
7062static void handle_free ( ThreadId tid, void* p )
7063{
7064 MallocMeta *md, *old_md;
7065 SizeT szB;
7066
7067 /* First see if we can find the metadata for 'p'. */
7068 md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
7069 if (!md)
7070 return; /* apparently freeing a bogus address. Oh well. */
7071
7072 tl_assert(md->payload == (Addr)p);
7073 szB = md->szB;
7074
7075 /* Nuke the metadata block */
7076 old_md = (MallocMeta*)
7077 VG_(HT_remove)( hg_mallocmeta_table, (UWord)p );
7078 tl_assert(old_md); /* it must be present - we just found it */
7079 tl_assert(old_md == md);
7080 tl_assert(old_md->payload == (Addr)p);
7081
7082 VG_(cli_free)((void*)old_md->payload);
7083 delete_MallocMeta(old_md);
7084
7085 /* Tell the lower level memory wranglers. */
7086 evh__die_mem_heap( (Addr)p, szB );
7087}
7088
7089static void hg_cli__free ( ThreadId tid, void* p ) {
7090 handle_free(tid, p);
7091}
7092static void hg_cli____builtin_delete ( ThreadId tid, void* p ) {
7093 handle_free(tid, p);
7094}
7095static void hg_cli____builtin_vec_delete ( ThreadId tid, void* p ) {
7096 handle_free(tid, p);
7097}
7098
7099
7100static void* hg_cli__realloc ( ThreadId tid, void* payloadV, SizeT new_size )
7101{
7102 MallocMeta *md, *md_new, *md_tmp;
7103 SizeT i;
7104
7105 Addr payload = (Addr)payloadV;
7106
7107 if (((SSizeT)new_size) < 0) return NULL;
7108
7109 md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)payload );
7110 if (!md)
7111 return NULL; /* apparently realloc-ing a bogus address. Oh well. */
7112
7113 tl_assert(md->payload == payload);
7114
7115 if (md->szB == new_size) {
7116 /* size unchanged */
7117 md->where = VG_(record_ExeContext)(tid, 0);
7118 return payloadV;
7119 }
7120
7121 if (md->szB > new_size) {
7122 /* new size is smaller */
7123 md->szB = new_size;
7124 md->where = VG_(record_ExeContext)(tid, 0);
7125 evh__die_mem_heap( md->payload + new_size, md->szB - new_size );
7126 return payloadV;
7127 }
7128
7129 /* else */ {
7130 /* new size is bigger */
7131 Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
7132
7133 /* First half kept and copied, second half new */
7134 // FIXME: shouldn't we use a copier which implements the
7135 // memory state machine?
7136 shadow_mem_copy_range( payload, p_new, md->szB );
7137 evh__new_mem_heap ( p_new + md->szB, new_size - md->szB,
7138 /*inited*/False );
7139 /* FIXME: can anything funny happen here? specifically, if the
7140 old range contained a lock, then die_mem_heap will complain.
7141 Is that the correct behaviour? Not sure. */
7142 evh__die_mem_heap( payload, md->szB );
7143
7144 /* Copy from old to new */
7145 for (i = 0; i < md->szB; i++)
7146 ((UChar*)p_new)[i] = ((UChar*)payload)[i];
7147
7148 /* Because the metadata hash table is index by payload address,
7149 we have to get rid of the old hash table entry and make a new
7150 one. We can't just modify the existing metadata in place,
7151 because then it would (almost certainly) be in the wrong hash
7152 chain. */
7153 md_new = new_MallocMeta();
7154 *md_new = *md;
7155
7156 md_tmp = VG_(HT_remove)( hg_mallocmeta_table, payload );
7157 tl_assert(md_tmp);
7158 tl_assert(md_tmp == md);
7159
7160 VG_(cli_free)((void*)md->payload);
7161 delete_MallocMeta(md);
7162
7163 /* Update fields */
7164 md_new->where = VG_(record_ExeContext)( tid, 0 );
7165 md_new->szB = new_size;
7166 md_new->payload = p_new;
7167 md_new->thr = map_threads_lookup( tid );
7168
7169 /* and add */
7170 VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md_new );
7171
7172 return (void*)p_new;
7173 }
7174}
7175
7176
7177/*--------------------------------------------------------------*/
7178/*--- Instrumentation ---*/
7179/*--------------------------------------------------------------*/
7180
7181static void instrument_mem_access ( IRSB* bbOut,
7182 IRExpr* addr,
7183 Int szB,
7184 Bool isStore,
7185 Int hWordTy_szB )
7186{
7187 IRType tyAddr = Ity_INVALID;
7188 HChar* hName = NULL;
7189 void* hAddr = NULL;
7190 Int regparms = 0;
7191 IRExpr** argv = NULL;
7192 IRDirty* di = NULL;
7193
7194 tl_assert(isIRAtom(addr));
7195 tl_assert(hWordTy_szB == 4 || hWordTy_szB == 8);
7196
7197 tyAddr = typeOfIRExpr( bbOut->tyenv, addr );
7198 tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64);
7199
7200 /* So the effective address is in 'addr' now. */
7201 regparms = 1; // unless stated otherwise
7202 if (isStore) {
7203 switch (szB) {
7204 case 1:
7205 hName = "evh__mem_help_write_1";
7206 hAddr = &evh__mem_help_write_1;
7207 argv = mkIRExprVec_1( addr );
7208 break;
7209 case 2:
7210 hName = "evh__mem_help_write_2";
7211 hAddr = &evh__mem_help_write_2;
7212 argv = mkIRExprVec_1( addr );
7213 break;
7214 case 4:
7215 hName = "evh__mem_help_write_4";
7216 hAddr = &evh__mem_help_write_4;
7217 argv = mkIRExprVec_1( addr );
7218 break;
7219 case 8:
7220 hName = "evh__mem_help_write_8";
7221 hAddr = &evh__mem_help_write_8;
7222 argv = mkIRExprVec_1( addr );
7223 break;
7224 default:
7225 tl_assert(szB > 8 && szB <= 512); /* stay sane */
7226 regparms = 2;
7227 hName = "evh__mem_help_write_N";
7228 hAddr = &evh__mem_help_write_N;
7229 argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
7230 break;
7231 }
7232 } else {
7233 switch (szB) {
7234 case 1:
7235 hName = "evh__mem_help_read_1";
7236 hAddr = &evh__mem_help_read_1;
7237 argv = mkIRExprVec_1( addr );
7238 break;
7239 case 2:
7240 hName = "evh__mem_help_read_2";
7241 hAddr = &evh__mem_help_read_2;
7242 argv = mkIRExprVec_1( addr );
7243 break;
7244 case 4:
7245 hName = "evh__mem_help_read_4";
7246 hAddr = &evh__mem_help_read_4;
7247 argv = mkIRExprVec_1( addr );
7248 break;
7249 case 8:
7250 hName = "evh__mem_help_read_8";
7251 hAddr = &evh__mem_help_read_8;
7252 argv = mkIRExprVec_1( addr );
7253 break;
7254 default:
7255 tl_assert(szB > 8 && szB <= 512); /* stay sane */
7256 regparms = 2;
7257 hName = "evh__mem_help_read_N";
7258 hAddr = &evh__mem_help_read_N;
7259 argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
7260 break;
7261 }
7262 }
7263
7264 /* Add the helper. */
7265 tl_assert(hName);
7266 tl_assert(hAddr);
7267 tl_assert(argv);
7268 di = unsafeIRDirty_0_N( regparms,
7269 hName, VG_(fnptr_to_fnentry)( hAddr ),
7270 argv );
7271 addStmtToIRSB( bbOut, IRStmt_Dirty(di) );
7272}
7273
7274
7275static void instrument_memory_bus_event ( IRSB* bbOut, IRMBusEvent event )
7276{
7277 switch (event) {
7278 case Imbe_Fence:
7279 break; /* not interesting */
7280 case Imbe_BusLock:
7281 case Imbe_BusUnlock:
7282 addStmtToIRSB(
7283 bbOut,
7284 IRStmt_Dirty(
7285 unsafeIRDirty_0_N(
7286 0/*regparms*/,
7287 event == Imbe_BusLock ? "evh__bus_lock"
7288 : "evh__bus_unlock",
7289 VG_(fnptr_to_fnentry)(
7290 event == Imbe_BusLock ? &evh__bus_lock
7291 : &evh__bus_unlock
7292 ),
7293 mkIRExprVec_0()
7294 )
7295 )
7296 );
7297 break;
7298 default:
7299 tl_assert(0);
7300 }
7301}
7302
7303
7304static
7305IRSB* hg_instrument ( VgCallbackClosure* closure,
7306 IRSB* bbIn,
7307 VexGuestLayout* layout,
7308 VexGuestExtents* vge,
7309 IRType gWordTy, IRType hWordTy )
7310{
7311 Int i;
7312 IRSB* bbOut;
7313
7314 if (gWordTy != hWordTy) {
7315 /* We don't currently support this case. */
7316 VG_(tool_panic)("host/guest word size mismatch");
7317 }
7318
7319 /* Set up BB */
7320 bbOut = emptyIRSB();
7321 bbOut->tyenv = deepCopyIRTypeEnv(bbIn->tyenv);
7322 bbOut->next = deepCopyIRExpr(bbIn->next);
7323 bbOut->jumpkind = bbIn->jumpkind;
7324
7325 // Copy verbatim any IR preamble preceding the first IMark
7326 i = 0;
7327 while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
7328 addStmtToIRSB( bbOut, bbIn->stmts[i] );
7329 i++;
7330 }
7331
7332 for (/*use current i*/; i < bbIn->stmts_used; i++) {
7333 IRStmt* st = bbIn->stmts[i];
7334 tl_assert(st);
7335 tl_assert(isFlatIRStmt(st));
7336 switch (st->tag) {
7337 case Ist_NoOp:
7338 case Ist_AbiHint:
7339 case Ist_Put:
7340 case Ist_PutI:
7341 case Ist_IMark:
7342 case Ist_Exit:
7343 /* None of these can contain any memory references. */
7344 break;
7345
7346 case Ist_MBE:
7347 instrument_memory_bus_event( bbOut, st->Ist.MBE.event );
7348 break;
7349
7350 case Ist_Store:
7351 instrument_mem_access(
7352 bbOut,
7353 st->Ist.Store.addr,
7354 sizeofIRType(typeOfIRExpr(bbIn->tyenv, st->Ist.Store.data)),
7355 True/*isStore*/,
7356 sizeofIRType(hWordTy)
7357 );
7358 break;
7359
7360 case Ist_WrTmp: {
7361 IRExpr* data = st->Ist.WrTmp.data;
7362 if (data->tag == Iex_Load) {
7363 instrument_mem_access(
7364 bbOut,
7365 data->Iex.Load.addr,
7366 sizeofIRType(data->Iex.Load.ty),
7367 False/*!isStore*/,
7368 sizeofIRType(hWordTy)
7369 );
7370 }
7371 break;
7372 }
7373
7374 case Ist_Dirty: {
7375 Int dataSize;
7376 IRDirty* d = st->Ist.Dirty.details;
7377 if (d->mFx != Ifx_None) {
7378 /* This dirty helper accesses memory. Collect the
7379 details. */
7380 tl_assert(d->mAddr != NULL);
7381 tl_assert(d->mSize != 0);
7382 dataSize = d->mSize;
7383 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) {
7384 instrument_mem_access(
7385 bbOut, d->mAddr, dataSize, False/*!isStore*/,
7386 sizeofIRType(hWordTy)
7387 );
7388 }
7389 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) {
7390 instrument_mem_access(
7391 bbOut, d->mAddr, dataSize, True/*isStore*/,
7392 sizeofIRType(hWordTy)
7393 );
7394 }
7395 } else {
7396 tl_assert(d->mAddr == NULL);
7397 tl_assert(d->mSize == 0);
7398 }
7399 break;
7400 }
7401
7402 default:
7403 tl_assert(0);
7404
7405 } /* switch (st->tag) */
7406
7407 addStmtToIRSB( bbOut, st );
7408 } /* iterate over bbIn->stmts */
7409
7410 return bbOut;
7411}
7412
7413
7414/*----------------------------------------------------------------*/
7415/*--- Client requests ---*/
7416/*----------------------------------------------------------------*/
7417
7418/* Sheesh. Yet another goddam finite map. */
7419static WordFM* map_pthread_t_to_Thread = NULL; /* pthread_t -> Thread* */
7420
7421static void map_pthread_t_to_Thread_INIT ( void ) {
7422 if (UNLIKELY(map_pthread_t_to_Thread == NULL)) {
7423 map_pthread_t_to_Thread = HG_(newFM)( hg_zalloc, hg_free, NULL );
7424 tl_assert(map_pthread_t_to_Thread != NULL);
7425 }
7426}
7427
7428
7429static
7430Bool hg_handle_client_request ( ThreadId tid, UWord* args, UWord* ret)
7431{
7432 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
7433 return False;
7434
7435 /* Anything that gets past the above check is one of ours, so we
7436 should be able to handle it. */
7437
7438 /* default, meaningless return value, unless otherwise set */
7439 *ret = 0;
7440
7441 switch (args[0]) {
7442
7443 /* --- --- User-visible client requests --- --- */
7444
7445 case VG_USERREQ__HG_CLEAN_MEMORY:
7446 if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY(%p,%d)\n",
7447 args[1], args[2]);
7448 /* Call die_mem to (expensively) tidy up properly, if there
7449 are any held locks etc in the area */
7450 if (args[2] > 0) { /* length */
7451 evh__die_mem(args[1], args[2]);
7452 /* and then set it to New */
7453 evh__new_mem(args[1], args[2]);
7454 }
7455 break;
7456
7457 /* --- --- Client requests for Helgrind's use only --- --- */
7458
7459 /* Some thread is telling us its pthread_t value. Record the
7460 binding between that and the associated Thread*, so we can
7461 later find the Thread* again when notified of a join by the
7462 thread. */
7463 case _VG_USERREQ__HG_SET_MY_PTHREAD_T: {
7464 Thread* my_thr = NULL;
7465 if (0)
7466 VG_(printf)("SET_MY_PTHREAD_T (tid %d): pthread_t = %p\n", (Int)tid,
7467 (void*)args[1]);
7468 map_pthread_t_to_Thread_INIT();
7469 my_thr = map_threads_maybe_lookup( tid );
7470 /* This assertion should hold because the map_threads (tid to
7471 Thread*) binding should have been made at the point of
7472 low-level creation of this thread, which should have
7473 happened prior to us getting this client request for it.
7474 That's because this client request is sent from
7475 client-world from the 'thread_wrapper' function, which
7476 only runs once the thread has been low-level created. */
7477 tl_assert(my_thr != NULL);
7478 /* So now we know that (pthread_t)args[1] is associated with
7479 (Thread*)my_thr. Note that down. */
7480 if (0)
7481 VG_(printf)("XXXX: bind pthread_t %p to Thread* %p\n",
7482 (void*)args[1], (void*)my_thr );
7483 HG_(addToFM)( map_pthread_t_to_Thread, (Word)args[1], (Word)my_thr );
7484 break;
7485 }
7486
7487 case _VG_USERREQ__HG_PTH_API_ERROR: {
7488 Thread* my_thr = NULL;
7489 map_pthread_t_to_Thread_INIT();
7490 my_thr = map_threads_maybe_lookup( tid );
7491 tl_assert(my_thr); /* See justification above in SET_MY_PTHREAD_T */
7492 record_error_PthAPIerror( my_thr, (HChar*)args[1],
7493 (Word)args[2], (HChar*)args[3] );
7494 break;
7495 }
7496
7497 /* This thread (tid) has completed a join with the quitting
7498 thread whose pthread_t is in args[1]. */
7499 case _VG_USERREQ__HG_PTHREAD_JOIN_POST: {
7500 Thread* thr_q = NULL; /* quitter Thread* */
7501 Bool found = False;
7502 if (0)
7503 VG_(printf)("NOTIFY_JOIN_COMPLETE (tid %d): quitter = %p\n", (Int)tid,
7504 (void*)args[1]);
7505 map_pthread_t_to_Thread_INIT();
7506 found = HG_(lookupFM)( map_pthread_t_to_Thread,
7507 NULL, (Word*)(void*)&thr_q, (Word)args[1] );
7508 /* Can this fail? It would mean that our pthread_join
7509 wrapper observed a successful join on args[1] yet that
7510 thread never existed (or at least, it never lodged an
7511 entry in the mapping (via SET_MY_PTHREAD_T)). Which
7512 sounds like a bug in the threads library. */
7513 // FIXME: get rid of this assertion; handle properly
7514 tl_assert(found);
7515 if (found) {
7516 if (0)
7517 VG_(printf)(".................... quitter Thread* = %p\n",
7518 thr_q);
7519 evh__HG_PTHREAD_JOIN_POST( tid, thr_q );
7520 }
7521 break;
7522 }
7523
7524 /* EXPOSITION only: by intercepting lock init events we can show
7525 the user where the lock was initialised, rather than only
7526 being able to show where it was first locked. Intercepting
7527 lock initialisations is not necessary for the basic operation
7528 of the race checker. */
7529 case _VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST:
7530 evh__HG_PTHREAD_MUTEX_INIT_POST( tid, (void*)args[1], args[2] );
7531 break;
7532
7533 case _VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE:
7534 evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, (void*)args[1] );
7535 break;
7536
7537 case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE: // pth_mx_t*
7538 evh__HG_PTHREAD_MUTEX_UNLOCK_PRE( tid, (void*)args[1] );
7539 break;
7540
7541 case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST: // pth_mx_t*
7542 evh__HG_PTHREAD_MUTEX_UNLOCK_POST( tid, (void*)args[1] );
7543 break;
7544
7545 case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE: // pth_mx_t*, Word
7546 evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, (void*)args[1], args[2] );
7547 break;
7548
7549 case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST: // pth_mx_t*
7550 evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, (void*)args[1] );
7551 break;
7552
7553 /* This thread is about to do pthread_cond_signal on the
7554 pthread_cond_t* in arg[1]. Ditto pthread_cond_broadcast. */
7555 case _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE:
7556 case _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE:
7557 evh__HG_PTHREAD_COND_SIGNAL_PRE( tid, (void*)args[1] );
7558 break;
7559
7560 /* Entry into pthread_cond_wait, cond=arg[1], mutex=arg[2].
7561 Returns a flag indicating whether or not the mutex is believed to be
7562 valid for this operation. */
7563 case _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE: {
7564 Bool mutex_is_valid
7565 = evh__HG_PTHREAD_COND_WAIT_PRE( tid, (void*)args[1],
7566 (void*)args[2] );
7567 *ret = mutex_is_valid ? 1 : 0;
7568 break;
7569 }
7570
7571 /* Thread successfully completed pthread_cond_wait, cond=arg[1],
7572 mutex=arg[2] */
7573 case _VG_USERREQ__HG_PTHREAD_COND_WAIT_POST:
7574 evh__HG_PTHREAD_COND_WAIT_POST( tid,
7575 (void*)args[1], (void*)args[2] );
7576 break;
7577
7578 case _VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST:
7579 evh__HG_PTHREAD_RWLOCK_INIT_POST( tid, (void*)args[1] );
7580 break;
7581
7582 case _VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE:
7583 evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( tid, (void*)args[1] );
7584 break;
7585
7586 /* rwlock=arg[1], isW=arg[2] */
7587 case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE:
7588 evh__HG_PTHREAD_RWLOCK_LOCK_PRE( tid, (void*)args[1], args[2] );
7589 break;
7590
7591 /* rwlock=arg[1], isW=arg[2] */
7592 case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST:
7593 evh__HG_PTHREAD_RWLOCK_LOCK_POST( tid, (void*)args[1], args[2] );
7594 break;
7595
7596 case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE:
7597 evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE( tid, (void*)args[1] );
7598 break;
7599
7600 case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST:
7601 evh__HG_PTHREAD_RWLOCK_UNLOCK_POST( tid, (void*)args[1] );
7602 break;
7603
7604 case _VG_USERREQ__HG_POSIX_SEMPOST_PRE: /* sem_t* */
7605 evh__HG_POSIX_SEMPOST_PRE( tid, (void*)args[1] );
7606 break;
7607
7608 case _VG_USERREQ__HG_POSIX_SEMWAIT_POST: /* sem_t* */
7609 evh__HG_POSIX_SEMWAIT_POST( tid, (void*)args[1] );
7610 break;
7611
7612 case _VG_USERREQ__HG_POSIX_SEM_ZAPSTACK: /* sem_t* */
7613 evh__HG_POSIX_SEM_ZAPSTACK( tid, (void*)args[1] );
7614 break;
7615
7616 case _VG_USERREQ__HG_GET_MY_SEGMENT: { // -> Segment*
7617 Thread* thr;
7618 SegmentID segid;
7619 Segment* seg;
7620 thr = map_threads_maybe_lookup( tid );
7621 tl_assert(thr); /* cannot fail */
7622 segid = thr->csegid;
7623 tl_assert(is_sane_SegmentID(segid));
7624 seg = map_segments_lookup( segid );
7625 tl_assert(seg);
7626 *ret = (UWord)seg;
7627 break;
7628 }
7629
7630 default:
7631 /* Unhandled Helgrind client request! */
7632 tl_assert2(0, "unhandled Helgrind client request!");
7633 }
7634
7635 return True;
7636}
7637
7638
7639/*----------------------------------------------------------------*/
7640/*--- Error management ---*/
7641/*----------------------------------------------------------------*/
7642
7643/* maps (by value) strings to a copy of them in ARENA_TOOL */
7644static UWord stats__string_table_queries = 0;
7645static WordFM* string_table = NULL;
7646static Word string_table_cmp ( Word s1, Word s2 ) {
7647 return (Word)VG_(strcmp)( (HChar*)s1, (HChar*)s2 );
7648}
7649static HChar* string_table_strdup ( HChar* str ) {
7650 HChar* copy = NULL;
7651 stats__string_table_queries++;
7652 if (!str)
7653 str = "(null)";
7654 if (!string_table) {
7655 string_table = HG_(newFM)( hg_zalloc, hg_free, string_table_cmp );
7656 tl_assert(string_table);
7657 }
7658 if (HG_(lookupFM)( string_table,
7659 NULL, (Word*)(void*)&copy, (Word)str )) {
7660 tl_assert(copy);
7661 if (0) VG_(printf)("string_table_strdup: %p -> %p\n", str, copy );
7662 return copy;
7663 } else {
7664 copy = VG_(strdup)(str);
7665 tl_assert(copy);
7666 HG_(addToFM)( string_table, (Word)copy, (Word)copy );
7667 return copy;
7668 }
7669}
7670
7671/* maps from Lock .unique fields to LockP*s */
7672static UWord stats__ga_LockN_to_P_queries = 0;
7673static WordFM* yaWFM = NULL;
7674static Word lock_unique_cmp ( Word lk1W, Word lk2W )
7675{
7676 Lock* lk1 = (Lock*)lk1W;
7677 Lock* lk2 = (Lock*)lk2W;
7678 tl_assert( is_sane_LockNorP(lk1) );
7679 tl_assert( is_sane_LockNorP(lk2) );
7680 if (lk1->unique < lk2->unique) return -1;
7681 if (lk1->unique > lk2->unique) return 1;
7682 return 0;
7683}
7684static Lock* mk_LockP_from_LockN ( Lock* lkn )
7685{
7686 Lock* lkp = NULL;
7687 stats__ga_LockN_to_P_queries++;
7688 tl_assert( is_sane_LockN(lkn) );
7689 if (!yaWFM) {
7690 yaWFM = HG_(newFM)( hg_zalloc, hg_free, lock_unique_cmp );
7691 tl_assert(yaWFM);
7692 }
7693 if (!HG_(lookupFM)( yaWFM, NULL, (Word*)(void*)&lkp, (Word)lkn)) {
7694 lkp = hg_zalloc( sizeof(Lock) );
7695 *lkp = *lkn;
7696 lkp->admin = NULL;
7697 lkp->magic = LockP_MAGIC;
7698 /* Forget about the bag of lock holders - don't copy that.
7699 Also, acquired_at should be NULL whenever heldBy is, and vice
7700 versa. */
7701 lkp->heldW = False;
7702 lkp->heldBy = NULL;
7703 lkp->acquired_at = NULL;
7704 HG_(addToFM)( yaWFM, (Word)lkp, (Word)lkp );
7705 }
7706 tl_assert( is_sane_LockP(lkp) );
7707 return lkp;
7708}
7709
7710/* Errors:
7711
7712 race: program counter
7713 read or write
7714 data size
7715 previous state
7716 current state
7717
7718 FIXME: how does state printing interact with lockset gc?
7719 Are the locksets in prev/curr state always valid?
7720 Ditto question for the threadsets
7721 ThreadSets - probably are always valid if Threads
7722 are never thrown away.
7723 LockSets - could at least print the lockset elements that
7724 correspond to actual locks at the time of printing. Hmm.
7725*/
7726
7727/* Error kinds */
7728typedef
7729 enum {
7730 XE_Race=1101, // race
7731 XE_FreeMemLock, // freeing memory containing a locked lock
7732 XE_UnlockUnlocked, // unlocking a not-locked lock
7733 XE_UnlockForeign, // unlocking a lock held by some other thread
7734 XE_UnlockBogus, // unlocking an address not known to be a lock
7735 XE_PthAPIerror, // error from the POSIX pthreads API
7736 XE_LockOrder, // lock order error
7737 XE_Misc // misc other error (w/ string to describe it)
7738 }
7739 XErrorTag;
7740
7741/* Extra contexts for kinds */
7742typedef
7743 struct {
7744 XErrorTag tag;
7745 union {
7746 struct {
7747 Addr data_addr;
7748 Int szB;
7749 Bool isWrite;
7750 UInt new_state;
7751 UInt old_state;
7752 ExeContext* mb_lastlock;
7753 Thread* thr;
7754 } Race;
7755 struct {
7756 Thread* thr; /* doing the freeing */
7757 Lock* lock; /* lock which is locked */
7758 } FreeMemLock;
7759 struct {
7760 Thread* thr; /* doing the unlocking */
7761 Lock* lock; /* lock (that is already unlocked) */
7762 } UnlockUnlocked;
7763 struct {
7764 Thread* thr; /* doing the unlocking */
7765 Thread* owner; /* thread that actually holds the lock */
7766 Lock* lock; /* lock (that is held by 'owner') */
7767 } UnlockForeign;
7768 struct {
7769 Thread* thr; /* doing the unlocking */
7770 Addr lock_ga; /* purported address of the lock */
7771 } UnlockBogus;
7772 struct {
7773 Thread* thr;
7774 HChar* fnname; /* persistent, in tool-arena */
7775 Word err; /* pth error code */
7776 HChar* errstr; /* persistent, in tool-arena */
7777 } PthAPIerror;
7778 struct {
7779 Thread* thr;
7780 Addr before_ga; /* always locked first in prog. history */
7781 Addr after_ga;
7782 ExeContext* before_ec;
7783 ExeContext* after_ec;
7784 } LockOrder;
7785 struct {
7786 Thread* thr;
7787 HChar* errstr; /* persistent, in tool-arena */
7788 } Misc;
7789 } XE;
7790 }
7791 XError;
7792
7793static void init_XError ( XError* xe ) {
7794 VG_(memset)(xe, 0, sizeof(*xe) );
7795 xe->tag = XE_Race-1; /* bogus */
7796}
7797
7798
7799/* Extensions of suppressions */
7800typedef
7801 enum {
7802 XS_Race=1201, /* race */
7803 XS_FreeMemLock,
7804 XS_UnlockUnlocked,
7805 XS_UnlockForeign,
7806 XS_UnlockBogus,
7807 XS_PthAPIerror,
7808 XS_LockOrder,
7809 XS_Misc
7810 }
7811 XSuppTag;
7812
7813
7814/* Updates the copy with address info if necessary. */
7815static UInt hg_update_extra ( Error* err )
7816{
7817 XError* extra = (XError*)VG_(get_error_extra)(err);
7818 tl_assert(extra);
7819 //if (extra != NULL && Undescribed == extra->addrinfo.akind) {
7820 // describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
7821 //}
7822 return sizeof(XError);
7823}
7824
7825static void record_error_Race ( Thread* thr,
7826 Addr data_addr, Bool isWrite, Int szB,
7827 UInt old_sv, UInt new_sv,
7828 ExeContext* mb_lastlock ) {
7829 XError xe;
7830 tl_assert( is_sane_Thread(thr) );
7831 init_XError(&xe);
7832 xe.tag = XE_Race;
7833 xe.XE.Race.data_addr = data_addr;
7834 xe.XE.Race.szB = szB;
7835 xe.XE.Race.isWrite = isWrite;
7836 xe.XE.Race.new_state = new_sv;
7837 xe.XE.Race.old_state = old_sv;
7838 xe.XE.Race.mb_lastlock = mb_lastlock;
7839 xe.XE.Race.thr = thr;
7840 // FIXME: tid vs thr
7841 tl_assert(isWrite == False || isWrite == True);
7842 tl_assert(szB == 8 || szB == 4 || szB == 2 || szB == 1);
7843 VG_(maybe_record_error)( map_threads_reverse_lookup_SLOW(thr),
7844 XE_Race, data_addr, NULL, &xe );
7845}
7846
7847static void record_error_FreeMemLock ( Thread* thr, Lock* lk ) {
7848 XError xe;
7849 tl_assert( is_sane_Thread(thr) );
7850 tl_assert( is_sane_LockN(lk) );
7851 init_XError(&xe);
7852 xe.tag = XE_FreeMemLock;
7853 xe.XE.FreeMemLock.thr = thr;
7854 xe.XE.FreeMemLock.lock = mk_LockP_from_LockN(lk);
7855 // FIXME: tid vs thr
7856 VG_(maybe_record_error)( map_threads_reverse_lookup_SLOW(thr),
7857 XE_FreeMemLock, 0, NULL, &xe );
7858}
7859
7860static void record_error_UnlockUnlocked ( Thread* thr, Lock* lk ) {
7861 XError xe;
7862 tl_assert( is_sane_Thread(thr) );
7863 tl_assert( is_sane_LockN(lk) );
7864 init_XError(&xe);
7865 xe.tag = XE_UnlockUnlocked;
7866 xe.XE.UnlockUnlocked.thr = thr;
7867 xe.XE.UnlockUnlocked.lock = mk_LockP_from_LockN(lk);
7868 // FIXME: tid vs thr
7869 VG_(maybe_record_error)( map_threads_reverse_lookup_SLOW(thr),
7870 XE_UnlockUnlocked, 0, NULL, &xe );
7871}
7872
7873static void record_error_UnlockForeign ( Thread* thr,
7874 Thread* owner, Lock* lk ) {
7875 XError xe;
7876 tl_assert( is_sane_Thread(thr) );
7877 tl_assert( is_sane_Thread(owner) );
7878 tl_assert( is_sane_LockN(lk) );
7879 init_XError(&xe);
7880 xe.tag = XE_UnlockForeign;
7881 xe.XE.UnlockForeign.thr = thr;
7882 xe.XE.UnlockForeign.owner = owner;
7883 xe.XE.UnlockForeign.lock = mk_LockP_from_LockN(lk);
7884 // FIXME: tid vs thr
7885 VG_(maybe_record_error)( map_threads_reverse_lookup_SLOW(thr),
7886 XE_UnlockForeign, 0, NULL, &xe );
7887}
7888
7889static void record_error_UnlockBogus ( Thread* thr, Addr lock_ga ) {
7890 XError xe;
7891 tl_assert( is_sane_Thread(thr) );
7892 init_XError(&xe);
7893 xe.tag = XE_UnlockBogus;
7894 xe.XE.UnlockBogus.thr = thr;
7895 xe.XE.UnlockBogus.lock_ga = lock_ga;
7896 // FIXME: tid vs thr
7897 VG_(maybe_record_error)( map_threads_reverse_lookup_SLOW(thr),
7898 XE_UnlockBogus, 0, NULL, &xe );
7899}
7900
7901static
7902void record_error_LockOrder ( Thread* thr, Addr before_ga, Addr after_ga,
7903 ExeContext* before_ec, ExeContext* after_ec ) {
7904 XError xe;
7905 tl_assert( is_sane_Thread(thr) );
7906 init_XError(&xe);
7907 xe.tag = XE_LockOrder;
7908 xe.XE.LockOrder.thr = thr;
7909 xe.XE.LockOrder.before_ga = before_ga;
7910 xe.XE.LockOrder.before_ec = before_ec;
7911 xe.XE.LockOrder.after_ga = after_ga;
7912 xe.XE.LockOrder.after_ec = after_ec;
7913 // FIXME: tid vs thr
7914 VG_(maybe_record_error)( map_threads_reverse_lookup_SLOW(thr),
7915 XE_LockOrder, 0, NULL, &xe );
7916}
7917
7918static
7919void record_error_PthAPIerror ( Thread* thr, HChar* fnname,
7920 Word err, HChar* errstr ) {
7921 XError xe;
7922 tl_assert( is_sane_Thread(thr) );
7923 tl_assert(fnname);
7924 tl_assert(errstr);
7925 init_XError(&xe);
7926 xe.tag = XE_PthAPIerror;
7927 xe.XE.PthAPIerror.thr = thr;
7928 xe.XE.PthAPIerror.fnname = string_table_strdup(fnname);
7929 xe.XE.PthAPIerror.err = err;
7930 xe.XE.PthAPIerror.errstr = string_table_strdup(errstr);
7931 // FIXME: tid vs thr
7932 VG_(maybe_record_error)( map_threads_reverse_lookup_SLOW(thr),
7933 XE_PthAPIerror, 0, NULL, &xe );
7934}
7935
7936static void record_error_Misc ( Thread* thr, HChar* errstr ) {
7937 XError xe;
7938 tl_assert( is_sane_Thread(thr) );
7939 tl_assert(errstr);
7940 init_XError(&xe);
7941 xe.tag = XE_Misc;
7942 xe.XE.Misc.thr = thr;
7943 xe.XE.Misc.errstr = string_table_strdup(errstr);
7944 // FIXME: tid vs thr
7945 VG_(maybe_record_error)( map_threads_reverse_lookup_SLOW(thr),
7946 XE_Misc, 0, NULL, &xe );
7947}
7948
7949static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
7950{
7951 XError *xe1, *xe2;
7952
7953 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
7954
7955 xe1 = (XError*)VG_(get_error_extra)(e1);
7956 xe2 = (XError*)VG_(get_error_extra)(e2);
7957 tl_assert(xe1);
7958 tl_assert(xe2);
7959
7960 switch (VG_(get_error_kind)(e1)) {
7961 case XE_Race:
7962 return xe1->XE.Race.szB == xe2->XE.Race.szB
7963 && xe1->XE.Race.isWrite == xe2->XE.Race.isWrite
7964 && (clo_cmp_race_err_addrs
7965 ? xe1->XE.Race.data_addr == xe2->XE.Race.data_addr
7966 : True);
7967 case XE_FreeMemLock:
7968 return xe1->XE.FreeMemLock.thr == xe2->XE.FreeMemLock.thr
7969 && xe1->XE.FreeMemLock.lock == xe2->XE.FreeMemLock.lock;
7970 case XE_UnlockUnlocked:
7971 return xe1->XE.UnlockUnlocked.thr == xe2->XE.UnlockUnlocked.thr
7972 && xe1->XE.UnlockUnlocked.lock == xe2->XE.UnlockUnlocked.lock;
7973 case XE_UnlockForeign:
7974 return xe1->XE.UnlockForeign.thr == xe2->XE.UnlockForeign.thr
7975 && xe1->XE.UnlockForeign.owner == xe2->XE.UnlockForeign.owner
7976 && xe1->XE.UnlockForeign.lock == xe2->XE.UnlockForeign.lock;
7977 case XE_UnlockBogus:
7978 return xe1->XE.UnlockBogus.thr == xe2->XE.UnlockBogus.thr
7979 && xe1->XE.UnlockBogus.lock_ga == xe2->XE.UnlockBogus.lock_ga;
7980 case XE_PthAPIerror:
7981 return xe1->XE.PthAPIerror.thr == xe2->XE.PthAPIerror.thr
7982 && 0==VG_(strcmp)(xe1->XE.PthAPIerror.fnname,
7983 xe2->XE.PthAPIerror.fnname)
7984 && xe1->XE.PthAPIerror.err == xe2->XE.PthAPIerror.err;
7985 case XE_LockOrder:
7986 return xe1->XE.LockOrder.thr == xe2->XE.LockOrder.thr;
7987 case XE_Misc:
7988 return xe1->XE.Misc.thr == xe2->XE.Misc.thr
7989 && 0==VG_(strcmp)(xe1->XE.Misc.errstr, xe2->XE.Misc.errstr);
7990 default:
7991 tl_assert(0);
7992 }
7993
7994 /*NOTREACHED*/
7995 tl_assert(0);
7996}
7997
7998/* Given a WordSetID in univ_tsets (that is, a Thread set ID), produce
7999 an XArray* with the corresponding Thread*'s sorted by their
8000 errmsg_index fields. This is for printing out thread sets in
8001 repeatable orders, which is important for for repeatable regression
8002 testing. The returned XArray* is dynamically allocated (of course)
8003 and so must be hg_freed by the caller. */
8004static Int cmp_Thread_by_errmsg_index ( void* thr1V, void* thr2V ) {
8005 Thread* thr1 = *(Thread**)thr1V;
8006 Thread* thr2 = *(Thread**)thr2V;
8007 if (thr1->errmsg_index < thr2->errmsg_index) return -1;
8008 if (thr1->errmsg_index > thr2->errmsg_index) return 1;
8009 return 0;
8010}
8011static XArray* /* of Thread* */ get_sorted_thread_set ( WordSetID tset )
8012{
8013 XArray* xa;
8014 Word* ts_words;
8015 Word ts_size, i;
8016 xa = VG_(newXA)( hg_zalloc, hg_free, sizeof(Thread*) );
8017 tl_assert(xa);
8018 HG_(getPayloadWS)( &ts_words, &ts_size, univ_tsets, tset );
8019 tl_assert(ts_words);
8020 tl_assert(ts_size >= 0);
8021 /* This isn't a very clever scheme, but we don't expect this to be
8022 called very often. */
8023 for (i = 0; i < ts_size; i++) {
8024 Thread* thr = (Thread*)ts_words[i];
8025 tl_assert(is_sane_Thread(thr));
8026 VG_(addToXA)( xa, (void*)&thr );
8027 }
8028 tl_assert(ts_size == VG_(sizeXA)( xa ));
8029 VG_(setCmpFnXA)( xa, cmp_Thread_by_errmsg_index );
8030 VG_(sortXA)( xa );
8031 return xa;
8032}
8033
8034
8035/* Announce (that is, print the point-of-creation) of the threads in
8036 'tset'. Only do this once, as we only want to see these
8037 announcements once each. Also, first sort the threads by their
8038 errmsg_index fields, and show only the first N_THREADS_TO_ANNOUNCE.
8039 That's because we only want to bother to announce threads
8040 enumerated by summarise_threadset() below, and that in turn does
8041 the same: it sorts them and then only shows the first
8042 N_THREADS_TO_ANNOUNCE. */
8043
8044static void announce_threadset ( WordSetID tset )
8045{
8046 const Word limit = N_THREADS_TO_ANNOUNCE;
8047 Thread* thr;
8048 XArray* sorted;
8049 Word ts_size, i, loopmax;
8050 sorted = get_sorted_thread_set( tset );
8051 ts_size = VG_(sizeXA)( sorted );
8052 tl_assert(ts_size >= 0);
8053 loopmax = limit < ts_size ? limit : ts_size; /* min(limit, ts_size) */
8054 tl_assert(loopmax >= 0 && loopmax <= limit);
8055 for (i = 0; i < loopmax; i++) {
8056 thr = *(Thread**)VG_(indexXA)( sorted, i );
8057 tl_assert(is_sane_Thread(thr));
8058 tl_assert(thr->errmsg_index >= 1);
8059 if (thr->announced)
8060 continue;
8061 if (thr->errmsg_index == 1/*FIXME: this hardwires an assumption
8062 about the identity of the root
8063 thread*/) {
8064 tl_assert(thr->created_at == NULL);
8065 VG_(message)(Vg_UserMsg, "Thread #%d is the program's root thread",
8066 thr->errmsg_index);
8067 } else {
8068 tl_assert(thr->created_at != NULL);
8069 VG_(message)(Vg_UserMsg, "Thread #%d was created",
8070 thr->errmsg_index);
8071 VG_(pp_ExeContext)( thr->created_at );
8072 }
8073 VG_(message)(Vg_UserMsg, "");
8074 thr->announced = True;
8075 }
8076 VG_(deleteXA)( sorted );
8077}
8078static void announce_one_thread ( Thread* thr ) {
8079 announce_threadset( HG_(singletonWS)(univ_tsets, (Word)thr ));
8080}
8081
8082/* Generate into buf[0 .. nBuf-1] a 1-line summary of a thread set, of
8083 the form "#1, #3, #77, #78, #79 and 42 others". The first
8084 N_THREADS_TO_ANNOUNCE are listed explicitly (as '#n') and the
8085 leftovers lumped into the 'and n others' bit. */
8086
8087static void summarise_threadset ( WordSetID tset, Char* buf, UInt nBuf )
8088{
8089 const Word limit = N_THREADS_TO_ANNOUNCE;
8090 Thread* thr;
8091 XArray* sorted;
8092 Word ts_size, i, loopmax;
8093 UInt off = 0;
8094 tl_assert(nBuf > 0);
8095 tl_assert(nBuf >= 40 + 20*limit);
8096 tl_assert(buf);
8097 sorted = get_sorted_thread_set( tset );
8098 ts_size = VG_(sizeXA)( sorted );
8099 tl_assert(ts_size >= 0);
8100 loopmax = limit < ts_size ? limit : ts_size; /* min(limit, ts_size) */
8101 tl_assert(loopmax >= 0 && loopmax <= limit);
8102 VG_(memset)(buf, 0, nBuf);
8103 for (i = 0; i < loopmax; i++) {
8104 thr = *(Thread**)VG_(indexXA)( sorted, i );
8105 tl_assert(is_sane_Thread(thr));
8106 tl_assert(thr->errmsg_index >= 1);
8107 off += VG_(sprintf)(&buf[off], "#%d", (Int)thr->errmsg_index);
8108 if (i < loopmax-1)
8109 off += VG_(sprintf)(&buf[off], ", ");
8110 }
8111 if (limit < ts_size) {
8112 Word others = ts_size - limit;
8113 off += VG_(sprintf)(&buf[off], " and %d other%s",
8114 (Int)others, others > 1 ? "s" : "");
8115 }
8116 tl_assert(off < nBuf);
8117 tl_assert(buf[nBuf-1] == 0);
8118 VG_(deleteXA)( sorted );
8119}
8120
8121static void hg_pp_Error ( Error* err )
8122{
8123 const Bool show_raw_states = False;
8124 XError *xe = (XError*)VG_(get_error_extra)(err);
8125
8126 switch (VG_(get_error_kind)(err)) {
8127
8128 case XE_Misc: {
8129 tl_assert(xe);
8130 tl_assert( is_sane_Thread( xe->XE.Misc.thr ) );
8131 announce_one_thread( xe->XE.Misc.thr );
8132 VG_(message)(Vg_UserMsg,
8133 "Thread #%d: %s",
8134 (Int)xe->XE.Misc.thr->errmsg_index,
8135 xe->XE.Misc.errstr);
8136 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8137 break;
8138 }
8139
8140 case XE_LockOrder: {
8141 tl_assert(xe);
8142 tl_assert( is_sane_Thread( xe->XE.LockOrder.thr ) );
8143 announce_one_thread( xe->XE.LockOrder.thr );
8144 VG_(message)(Vg_UserMsg,
8145 "Thread #%d: lock order \"%p before %p\" violated",
8146 (Int)xe->XE.LockOrder.thr->errmsg_index,
8147 (void*)xe->XE.LockOrder.before_ga,
8148 (void*)xe->XE.LockOrder.after_ga);
8149 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8150 if (xe->XE.LockOrder.before_ec && xe->XE.LockOrder.after_ec) {
8151 VG_(message)(Vg_UserMsg,
8152 " Required order was established by acquisition of lock at %p",
8153 (void*)xe->XE.LockOrder.before_ga);
8154 VG_(pp_ExeContext)( xe->XE.LockOrder.before_ec );
8155 VG_(message)(Vg_UserMsg,
8156 " followed by a later acquisition of lock at %p",
8157 (void*)xe->XE.LockOrder.after_ga);
8158 VG_(pp_ExeContext)( xe->XE.LockOrder.after_ec );
8159 }
8160 break;
8161 }
8162
8163 case XE_PthAPIerror: {
8164 tl_assert(xe);
8165 tl_assert( is_sane_Thread( xe->XE.PthAPIerror.thr ) );
8166 announce_one_thread( xe->XE.PthAPIerror.thr );
8167 VG_(message)(Vg_UserMsg,
8168 "Thread #%d's call to %s failed",
8169 (Int)xe->XE.PthAPIerror.thr->errmsg_index,
8170 xe->XE.PthAPIerror.fnname);
8171 VG_(message)(Vg_UserMsg,
8172 " with error code %ld (%s)",
8173 xe->XE.PthAPIerror.err,
8174 xe->XE.PthAPIerror.errstr);
8175 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8176 break;
8177 }
8178
8179 case XE_UnlockBogus: {
8180 tl_assert(xe);
8181 tl_assert( is_sane_Thread( xe->XE.UnlockBogus.thr ) );
8182 announce_one_thread( xe->XE.UnlockBogus.thr );
8183 VG_(message)(Vg_UserMsg,
8184 "Thread #%d unlocked an invalid lock at %p ",
8185 (Int)xe->XE.UnlockBogus.thr->errmsg_index,
8186 (void*)xe->XE.UnlockBogus.lock_ga);
8187 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8188 break;
8189 }
8190
8191 case XE_UnlockForeign: {
8192 tl_assert(xe);
8193 tl_assert( is_sane_LockP( xe->XE.UnlockForeign.lock ) );
8194 tl_assert( is_sane_Thread( xe->XE.UnlockForeign.owner ) );
8195 tl_assert( is_sane_Thread( xe->XE.UnlockForeign.thr ) );
8196 announce_one_thread( xe->XE.UnlockForeign.thr );
8197 announce_one_thread( xe->XE.UnlockForeign.owner );
8198 VG_(message)(Vg_UserMsg,
8199 "Thread #%d unlocked lock at %p "
8200 "currently held by thread #%d",
8201 (Int)xe->XE.UnlockForeign.thr->errmsg_index,
8202 (void*)xe->XE.UnlockForeign.lock->guestaddr,
8203 (Int)xe->XE.UnlockForeign.owner->errmsg_index );
8204 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8205 if (xe->XE.UnlockForeign.lock->appeared_at) {
8206 VG_(message)(Vg_UserMsg,
8207 " Lock at %p was first observed",
8208 (void*)xe->XE.UnlockForeign.lock->guestaddr);
8209 VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at );
8210 }
8211 break;
8212 }
8213
8214 case XE_UnlockUnlocked: {
8215 tl_assert(xe);
8216 tl_assert( is_sane_LockP( xe->XE.UnlockUnlocked.lock ) );
8217 tl_assert( is_sane_Thread( xe->XE.UnlockUnlocked.thr ) );
8218 announce_one_thread( xe->XE.UnlockUnlocked.thr );
8219 VG_(message)(Vg_UserMsg,
8220 "Thread #%d unlocked a not-locked lock at %p ",
8221 (Int)xe->XE.UnlockUnlocked.thr->errmsg_index,
8222 (void*)xe->XE.UnlockUnlocked.lock->guestaddr);
8223 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8224 if (xe->XE.UnlockUnlocked.lock->appeared_at) {
8225 VG_(message)(Vg_UserMsg,
8226 " Lock at %p was first observed",
8227 (void*)xe->XE.UnlockUnlocked.lock->guestaddr);
8228 VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at );
8229 }
8230 break;
8231 }
8232
8233 case XE_FreeMemLock: {
8234 tl_assert(xe);
8235 tl_assert( is_sane_LockP( xe->XE.FreeMemLock.lock ) );
8236 tl_assert( is_sane_Thread( xe->XE.FreeMemLock.thr ) );
8237 announce_one_thread( xe->XE.FreeMemLock.thr );
8238 VG_(message)(Vg_UserMsg,
8239 "Thread #%d deallocated location %p "
8240 "containing a locked lock",
8241 (Int)xe->XE.FreeMemLock.thr->errmsg_index,
8242 (void*)xe->XE.FreeMemLock.lock->guestaddr);
8243 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8244 if (xe->XE.FreeMemLock.lock->appeared_at) {
8245 VG_(message)(Vg_UserMsg,
8246 " Lock at %p was first observed",
8247 (void*)xe->XE.FreeMemLock.lock->guestaddr);
8248 VG_(pp_ExeContext)( xe->XE.FreeMemLock.lock->appeared_at );
8249 }
8250 break;
8251 }
8252
8253 case XE_Race: {
8254 Addr err_ga;
8255 Char old_buf[100], new_buf[100];
8256 Char old_tset_buf[140], new_tset_buf[140];
8257 UInt old_state, new_state;
8258 Thread* thr_acc;
8259 HChar* what;
8260 Int szB;
8261 WordSetID tset_to_announce = HG_(emptyWS)( univ_tsets );
8262
8263 /* First extract some essential info */
8264 tl_assert(xe);
8265 old_state = xe->XE.Race.old_state;
8266 new_state = xe->XE.Race.new_state;
8267 thr_acc = xe->XE.Race.thr;
8268 what = xe->XE.Race.isWrite ? "write" : "read";
8269 szB = xe->XE.Race.szB;
8270 tl_assert(is_sane_Thread(thr_acc));
8271 err_ga = VG_(get_error_address)(err);
8272
8273 /* Format the low level state print descriptions */
8274 show_shadow_w32(old_buf, sizeof(old_buf), old_state);
8275 show_shadow_w32(new_buf, sizeof(new_buf), new_state);
8276
8277 /* Now we have to 'announce' the threadset mentioned in the
8278 error message, if it hasn't already been announced.
8279 Unfortunately the precise threadset and error message text
8280 depends on the nature of the transition involved. So now
8281 fall into a case analysis of the error state transitions. */
8282
8283 /* CASE of Excl -> ShM */
8284 if (is_SHVAL_Excl(old_state) && is_SHVAL_ShM(new_state)) {
8285 SegmentID old_segid;
8286 Segment* old_seg;
8287 Thread* old_thr;
8288 WordSetID new_tset;
8289 old_segid = un_SHVAL_Excl( old_state );
8290 tl_assert(is_sane_SegmentID(old_segid));
8291 old_seg = map_segments_lookup( old_segid );
8292 tl_assert(is_sane_Segment(old_seg));
8293 tl_assert(old_seg->thr);
8294 old_thr = old_seg->thr;
8295 tl_assert(is_sane_Thread(old_thr));
8296
8297 new_tset = un_SHVAL_ShM_tset(new_state);
8298 tset_to_announce = HG_(addToWS)( univ_tsets,
8299 new_tset, (Word)old_thr );
8300 announce_threadset( tset_to_announce );
8301
8302 VG_(message)(Vg_UserMsg,
8303 "Possible data race during %s of size %d at %p",
8304 what, szB, err_ga);
8305 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8306 /* pp_AddrInfo(err_addr, &extra->addrinfo); */
8307 if (show_raw_states)
8308 VG_(message)(Vg_UserMsg,
8309 " Old state 0x%08x=%s, new state 0x%08x=%s",
8310 old_state, old_buf, new_state, new_buf);
8311 VG_(message)(Vg_UserMsg,
8312 " Old state: owned exclusively by thread #%d",
8313 old_thr->errmsg_index);
8314 // This should always show exactly 2 threads
8315 summarise_threadset( new_tset, new_tset_buf, sizeof(new_tset_buf) );
8316 VG_(message)(Vg_UserMsg,
8317 " New state: shared-modified by threads %s",
8318 new_tset_buf );
8319 VG_(message)(Vg_UserMsg,
8320 " Reason: this thread, #%d, holds no locks at all",
8321 thr_acc->errmsg_index);
8322 }
8323 else
8324 /* Case of ShR/M -> ShM */
8325 if (is_SHVAL_Sh(old_state) && is_SHVAL_ShM(new_state)) {
8326 WordSetID old_tset = un_SHVAL_Sh_tset(old_state);
8327 WordSetID new_tset = un_SHVAL_Sh_tset(new_state);
8328
8329 tset_to_announce = HG_(unionWS)( univ_tsets, old_tset, new_tset );
8330 announce_threadset( tset_to_announce );
8331
8332 VG_(message)(Vg_UserMsg,
8333 "Possible data race during %s of size %d at %p",
8334 what, szB, err_ga);
8335 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8336 /* pp_AddrInfo(err_addr, &extra->addrinfo); */
8337 if (show_raw_states)
8338 VG_(message)(Vg_UserMsg,
8339 " Old state 0x%08x=%s, new state 0x%08x=%s",
8340 old_state, old_buf, new_state, new_buf);
8341
8342 summarise_threadset( old_tset, old_tset_buf, sizeof(old_tset_buf) );
8343 summarise_threadset( new_tset, new_tset_buf, sizeof(new_tset_buf) );
8344
8345 VG_(message)(Vg_UserMsg,
8346 " Old state: shared-%s by threads %s",
8347 is_SHVAL_ShM(old_state) ? "modified" : "readonly",
8348 old_tset_buf);
8349 VG_(message)(Vg_UserMsg,
8350 " New state: shared-modified by threads %s",
8351 new_tset_buf);
8352 VG_(message)(Vg_UserMsg,
8353 " Reason: this thread, #%d, holds no "
8354 "consistent locks",
8355 thr_acc->errmsg_index);
8356 if (xe->XE.Race.mb_lastlock) {
8357 VG_(message)(Vg_UserMsg, " Last consistently used lock for %p was "
8358 "first observed", err_ga);
8359 VG_(pp_ExeContext)(xe->XE.Race.mb_lastlock);
8360 } else {
8361 VG_(message)(Vg_UserMsg, " Location %p has never been protected "
8362 "by any lock", err_ga);
8363 }
8364 }
8365 /* Hmm, unknown transition. Just print what we do know. */
8366 else {
8367 VG_(message)(Vg_UserMsg,
8368 "Possible data race during %s of size %d at %p",
8369 what, szB, err_ga);
8370 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
8371
8372 //pp_AddrInfo(err_addr, &extra->addrinfo);
8373 VG_(message)(Vg_UserMsg,
8374 " Old state 0x%08x=%s, new state 0x%08x=%s",
8375 old_state, old_buf, new_state, new_buf);
8376 }
8377
8378 break; /* case XE_Race */
8379 } /* case XE_Race */
8380
8381 default:
8382 tl_assert(0);
8383 } /* switch (VG_(get_error_kind)(err)) */
8384}
8385
8386static Char* hg_get_error_name ( Error* err )
8387{
8388 switch (VG_(get_error_kind)(err)) {
8389 case XE_Race: return "Race";
8390 case XE_FreeMemLock: return "FreeMemLock";
8391 case XE_UnlockUnlocked: return "UnlockUnlocked";
8392 case XE_UnlockForeign: return "UnlockForeign";
8393 case XE_UnlockBogus: return "UnlockBogus";
8394 case XE_PthAPIerror: return "PthAPIerror";
8395 case XE_LockOrder: return "LockOrder";
8396 case XE_Misc: return "Misc";
8397 default: tl_assert(0); /* fill in missing case */
8398 }
8399}
8400
8401static Bool hg_recognised_suppression ( Char* name, Supp *su )
8402{
8403# define TRY(_name,_xskind) \
8404 if (0 == VG_(strcmp)(name, (_name))) { \
8405 VG_(set_supp_kind)(su, (_xskind)); \
8406 return True; \
8407 }
8408 TRY("Race", XS_Race);
8409 TRY("FreeMemLock", XS_FreeMemLock);
8410 TRY("UnlockUnlocked", XS_UnlockUnlocked);
8411 TRY("UnlockForeign", XS_UnlockForeign);
8412 TRY("UnlockBogus", XS_UnlockBogus);
8413 TRY("PthAPIerror", XS_PthAPIerror);
8414 TRY("LockOrder", XS_LockOrder);
8415 TRY("Misc", XS_Misc);
8416 return False;
8417# undef TRY
8418}
8419
8420static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf,
8421 Supp* su )
8422{
8423 /* do nothing -- no extra suppression info present. Return True to
8424 indicate nothing bad happened. */
8425 return True;
8426}
8427
8428static Bool hg_error_matches_suppression ( Error* err, Supp* su )
8429{
8430 switch (VG_(get_supp_kind)(su)) {
8431 case XS_Race: return VG_(get_error_kind)(err) == XE_Race;
8432 case XS_FreeMemLock: return VG_(get_error_kind)(err) == XE_FreeMemLock;
8433 case XS_UnlockUnlocked: return VG_(get_error_kind)(err) == XE_UnlockUnlocked;
8434 case XS_UnlockForeign: return VG_(get_error_kind)(err) == XE_UnlockForeign;
8435 case XS_UnlockBogus: return VG_(get_error_kind)(err) == XE_UnlockBogus;
8436 case XS_PthAPIerror: return VG_(get_error_kind)(err) == XE_PthAPIerror;
8437 case XS_LockOrder: return VG_(get_error_kind)(err) == XE_LockOrder;
8438 case XS_Misc: return VG_(get_error_kind)(err) == XE_Misc;
8439 //case XS_: return VG_(get_error_kind)(err) == XE_;
8440 default: tl_assert(0); /* fill in missing cases */
8441 }
8442}
8443
8444static void hg_print_extra_suppression_info ( Error* err )
8445{
8446 /* Do nothing */
8447}
8448
8449
8450/*----------------------------------------------------------------*/
8451/*--- Setup ---*/
8452/*----------------------------------------------------------------*/
8453
8454static Bool hg_process_cmd_line_option ( Char* arg )
8455{
8456 if (VG_CLO_STREQ(arg, "--happens-before=none"))
8457 clo_happens_before = 0;
8458 else if (VG_CLO_STREQ(arg, "--happens-before=threads"))
8459 clo_happens_before = 1;
8460 else if (VG_CLO_STREQ(arg, "--happens-before=all"))
8461 clo_happens_before = 2;
8462
8463 else if (VG_CLO_STREQ(arg, "--gen-vcg=no"))
8464 clo_gen_vcg = 0;
8465 else if (VG_CLO_STREQ(arg, "--gen-vcg=yes"))
8466 clo_gen_vcg = 1;
8467 else if (VG_CLO_STREQ(arg, "--gen-vcg=yes-w-vts"))
8468 clo_gen_vcg = 2;
8469
8470 else if (VG_CLO_STREQ(arg, "--cmp-race-err-addrs=no"))
8471 clo_cmp_race_err_addrs = False;
8472 else if (VG_CLO_STREQ(arg, "--cmp-race-err-addrs=yes"))
8473 clo_cmp_race_err_addrs = True;
8474
8475 else if (VG_CLO_STREQN(13, arg, "--trace-addr=")) {
8476 clo_trace_addr = VG_(atoll16)(&arg[13]);
8477 if (clo_trace_level == 0)
8478 clo_trace_level = 1;
8479 }
8480 else VG_BNUM_CLO(arg, "--trace-level", clo_trace_level, 0, 2)
8481
8482 /* "stuvw" --> stuvw (binary) */
8483 else if (VG_CLO_STREQN(18, arg, "--tc-sanity-flags=")) {
8484 Int j;
8485 char* opt = & arg[18];
8486
8487 if (5 != VG_(strlen)(opt)) {
8488 VG_(message)(Vg_UserMsg,
8489 "--tc-sanity-flags argument must have 5 digits");
8490 return False;
8491 }
8492 for (j = 0; j < 5; j++) {
8493 if ('0' == opt[j]) { /* do nothing */ }
8494 else if ('1' == opt[j]) clo_sanity_flags |= (1 << (5-1-j));
8495 else {
8496 VG_(message)(Vg_UserMsg, "--tc-sanity-flags argument can "
8497 "only contain 0s and 1s");
8498 return False;
8499 }
8500 }
8501 if (0) VG_(printf)("XXX sanity flags: 0x%x\n", clo_sanity_flags);
8502 }
8503
8504 else
8505 return VG_(replacement_malloc_process_cmd_line_option)(arg);
8506
8507 return True;
8508}
8509
8510static void hg_print_usage ( void )
8511{
8512 VG_(printf)(
8513" --happens-before=none|threads|all [all] consider no events, thread\n"
8514" create/join, create/join/cvsignal/cvwait/semwait/post as sync points\n"
8515" --trace-addr=0xXXYYZZ show all state changes for address 0xXXYYZZ\n"
8516" --trace-level=0|1|2 verbosity level of --trace-addr [1]\n"
8517 );
8518 VG_(replacement_malloc_print_usage)();
8519}
8520
8521static void hg_print_debug_usage ( void )
8522{
8523 VG_(replacement_malloc_print_debug_usage)();
8524 VG_(printf)(" --gen-vcg=no|yes|yes-w-vts show happens-before graph "
8525 "in .vcg format [no]\n");
8526 VG_(printf)(" --cmp-race-err-addrs=no|yes are data addresses in "
8527 "race errors significant? [no]\n");
8528 VG_(printf)(" --tc-sanity-flags=<XXXXX> sanity check "
8529 " at events (X = 0|1) [00000]\n");
8530 VG_(printf)(" --tc-sanity-flags values:\n");
8531 VG_(printf)(" 10000 after changes to "
8532 "lock-order-acquisition-graph\n");
8533 VG_(printf)(" 01000 at memory accesses (NB: not curently used)\n");
8534 VG_(printf)(" 00100 at mem permission setting for "
8535 "ranges >= %d bytes\n", SCE_BIGRANGE_T);
8536 VG_(printf)(" 00010 at lock/unlock events\n");
8537 VG_(printf)(" 00001 at thread create/join events\n");
8538}
8539
8540static void hg_post_clo_init ( void )
8541{
8542}
8543
8544static void hg_fini ( Int exitcode )
8545{
8546 if (SHOW_DATA_STRUCTURES)
8547 pp_everything( PP_ALL, "SK_(fini)" );
8548 if (clo_sanity_flags)
8549 all__sanity_check("SK_(fini)");
8550
8551 if (clo_gen_vcg > 0)
8552 segments__generate_vcg();
8553
8554 if (VG_(clo_verbosity) >= 2) {
8555
8556 if (1) {
8557 VG_(printf)("\n");
8558 HG_(ppWSUstats)( univ_tsets, "univ_tsets" );
8559 VG_(printf)("\n");
8560 HG_(ppWSUstats)( univ_lsets, "univ_lsets" );
8561 VG_(printf)("\n");
8562 HG_(ppWSUstats)( univ_laog, "univ_laog" );
8563 }
8564
8565 VG_(printf)("\n");
8566 VG_(printf)(" hbefore: %,10lu queries\n", stats__hbefore_queries);
8567 VG_(printf)(" hbefore: %,10lu cache 0 hits\n", stats__hbefore_cache0s);
8568 VG_(printf)(" hbefore: %,10lu cache > 0 hits\n", stats__hbefore_cacheNs);
8569 VG_(printf)(" hbefore: %,10lu graph searches\n", stats__hbefore_gsearches);
8570 VG_(printf)(" hbefore: %,10lu of which slow\n",
8571 stats__hbefore_gsearches - stats__hbefore_gsearchFs);
8572 VG_(printf)(" hbefore: %,10lu stack high water mark\n",
8573 stats__hbefore_stk_hwm);
8574 VG_(printf)(" hbefore: %,10lu cache invals\n", stats__hbefore_invals);
8575 VG_(printf)(" hbefore: %,10lu probes\n", stats__hbefore_probes);
8576
8577 VG_(printf)("\n");
8578 VG_(printf)(" segments: %,8lu Segment objects allocated\n",
8579 stats__mk_Segment);
8580 VG_(printf)(" locksets: %,8d unique lock sets\n",
8581 (Int)HG_(cardinalityWSU)( univ_lsets ));
8582 VG_(printf)(" threadsets: %,8d unique thread sets\n",
8583 (Int)HG_(cardinalityWSU)( univ_tsets ));
8584 VG_(printf)(" univ_laog: %,8d unique lock sets\n",
8585 (Int)HG_(cardinalityWSU)( univ_laog ));
8586
8587 VG_(printf)("L(ast)L(ock) map: %,8lu inserts (%d map size)\n",
8588 stats__ga_LL_adds,
8589 (Int)(ga_to_lastlock ? HG_(sizeFM)( ga_to_lastlock ) : 0) );
8590
8591 VG_(printf)(" LockN-to-P map: %,8lu queries (%d map size)\n",
8592 stats__ga_LockN_to_P_queries,
8593 (Int)(yaWFM ? HG_(sizeFM)( yaWFM ) : 0) );
8594
8595 VG_(printf)("string table map: %,8lu queries (%d map size)\n",
8596 stats__string_table_queries,
8597 (Int)(string_table ? HG_(sizeFM)( string_table ) : 0) );
8598 VG_(printf)(" LAOG: %,8d map size\n",
8599 (Int)(laog ? HG_(sizeFM)( laog ) : 0));
8600 VG_(printf)(" LAOG exposition: %,8d map size\n",
8601 (Int)(laog_exposition ? HG_(sizeFM)( laog_exposition ) : 0));
8602 VG_(printf)(" locks: %,8lu acquires, "
8603 "%,lu releases\n",
8604 stats__lockN_acquires,
8605 stats__lockN_releases
8606 );
8607 VG_(printf)(" sanity checks: %,8lu\n", stats__sanity_checks);
8608
8609 VG_(printf)("\n");
8610 VG_(printf)(" msm: %,12lu %,12lu rd/wr_Excl_nochange\n",
8611 stats__msm_read_Excl_nochange, stats__msm_write_Excl_nochange);
8612 VG_(printf)(" msm: %,12lu %,12lu rd/wr_Excl_transfer\n",
8613 stats__msm_read_Excl_transfer, stats__msm_write_Excl_transfer);
8614 VG_(printf)(" msm: %,12lu %,12lu rd/wr_Excl_to_ShR/ShM\n",
8615 stats__msm_read_Excl_to_ShR, stats__msm_write_Excl_to_ShM);
8616 VG_(printf)(" msm: %,12lu %,12lu rd/wr_ShR_to_ShR/ShM\n",
8617 stats__msm_read_ShR_to_ShR, stats__msm_write_ShR_to_ShM);
8618 VG_(printf)(" msm: %,12lu %,12lu rd/wr_ShM_to_ShM\n",
8619 stats__msm_read_ShM_to_ShM, stats__msm_write_ShM_to_ShM);
8620 VG_(printf)(" msm: %,12lu %,12lu rd/wr_New_to_Excl\n",
8621 stats__msm_read_New_to_Excl, stats__msm_write_New_to_Excl);
8622 VG_(printf)(" msm: %,12lu %,12lu rd/wr_NoAccess\n",
8623 stats__msm_read_NoAccess, stats__msm_write_NoAccess);
8624
8625 VG_(printf)("\n");
8626 VG_(printf)(" secmaps: %,10lu allocd (%,12lu g-a-range)\n",
8627 stats__secmaps_allocd,
8628 stats__secmap_ga_space_covered);
8629 VG_(printf)(" linesZ: %,10lu allocd (%,12lu bytes occupied)\n",
8630 stats__secmap_linesZ_allocd,
8631 stats__secmap_linesZ_bytes);
8632 VG_(printf)(" linesF: %,10lu allocd (%,12lu bytes occupied)\n",
8633 stats__secmap_linesF_allocd,
8634 stats__secmap_linesF_bytes);
8635 VG_(printf)(" secmaps: %,10lu iterator steppings\n",
8636 stats__secmap_iterator_steppings);
8637
8638 VG_(printf)("\n");
8639 VG_(printf)(" cache: %,lu totrefs (%,lu misses)\n",
8640 stats__cache_totrefs, stats__cache_totmisses );
8641 VG_(printf)(" cache: %,12lu Z-fetch, %,12lu F-fetch\n",
8642 stats__cache_Z_fetches, stats__cache_F_fetches );
8643 VG_(printf)(" cache: %,12lu Z-wback, %,12lu F-wback\n",
8644 stats__cache_Z_wbacks, stats__cache_F_wbacks );
8645 VG_(printf)(" cache: %,12lu invals, %,12lu flushes\n",
8646 stats__cache_invals, stats__cache_flushes );
8647
8648 VG_(printf)("\n");
8649 VG_(printf)(" cline: %,10lu normalises\n",
8650 stats__cline_normalises );
8651 VG_(printf)(" cline: reads 8/4/2/1: %,12lu %,12lu %,12lu %,12lu\n",
8652 stats__cline_read64s,
8653 stats__cline_read32s,
8654 stats__cline_read16s,
8655 stats__cline_read8s );
8656 VG_(printf)(" cline: writes 8/4/2/1: %,12lu %,12lu %,12lu %,12lu\n",
8657 stats__cline_write64s,
8658 stats__cline_write32s,
8659 stats__cline_write16s,
8660 stats__cline_write8s );
8661 VG_(printf)(" cline: sets 8/4/2/1: %,12lu %,12lu %,12lu %,12lu\n",
8662 stats__cline_set64s,
8663 stats__cline_set32s,
8664 stats__cline_set16s,
8665 stats__cline_set8s );
8666 VG_(printf)(" cline: get1s %,lu, copy1s %,lu\n",
8667 stats__cline_get8s, stats__cline_copy8s );
8668 VG_(printf)(" cline: splits: 8to4 %,12lu 4to2 %,12lu 2to1 %,12lu\n",
8669 stats__cline_64to32splits,
8670 stats__cline_32to16splits,
8671 stats__cline_16to8splits );
8672 VG_(printf)(" cline: pulldowns: 8to4 %,12lu 4to2 %,12lu 2to1 %,12lu\n",
8673 stats__cline_64to32pulldown,
8674 stats__cline_32to16pulldown,
8675 stats__cline_16to8pulldown );
8676
8677 VG_(printf)("\n");
8678 }
8679}
8680
8681static void hg_pre_clo_init ( void )
8682{
8683 VG_(details_name) ("Helgrind");
8684 VG_(details_version) (NULL);
8685 VG_(details_description) ("a thread error detector");
8686 VG_(details_copyright_author)(
8687 "Copyright (C) 2007-2007, and GNU GPL'd, by OpenWorks LLP et al.");
8688 VG_(details_bug_reports_to) (VG_BUGS_TO);
8689 VG_(details_avg_translation_sizeB) ( 200 );
8690
8691 VG_(basic_tool_funcs) (hg_post_clo_init,
8692 hg_instrument,
8693 hg_fini);
8694
8695 VG_(needs_core_errors) ();
8696 VG_(needs_tool_errors) (hg_eq_Error,
8697 hg_pp_Error,
8698 False,/*show TIDs for errors*/
8699 hg_update_extra,
8700 hg_recognised_suppression,
8701 hg_read_extra_suppression_info,
8702 hg_error_matches_suppression,
8703 hg_get_error_name,
8704 hg_print_extra_suppression_info);
8705
8706 VG_(needs_command_line_options)(hg_process_cmd_line_option,
8707 hg_print_usage,
8708 hg_print_debug_usage);
8709 VG_(needs_client_requests) (hg_handle_client_request);
8710
8711 // FIXME?
8712 //VG_(needs_sanity_checks) (hg_cheap_sanity_check,
8713 // hg_expensive_sanity_check);
8714
8715 VG_(needs_malloc_replacement) (hg_cli__malloc,
8716 hg_cli____builtin_new,
8717 hg_cli____builtin_vec_new,
8718 hg_cli__memalign,
8719 hg_cli__calloc,
8720 hg_cli__free,
8721 hg_cli____builtin_delete,
8722 hg_cli____builtin_vec_delete,
8723 hg_cli__realloc,
8724 HG_CLI__MALLOC_REDZONE_SZB );
8725
8726 VG_(needs_data_syms)();
8727
8728 //VG_(needs_xml_output) ();
8729
8730 VG_(track_new_mem_startup) ( evh__new_mem_w_perms );
8731 VG_(track_new_mem_stack_signal)( evh__die_mem );
8732 VG_(track_new_mem_brk) ( evh__new_mem );
8733 VG_(track_new_mem_mmap) ( evh__new_mem_w_perms );
8734 VG_(track_new_mem_stack) ( evh__new_mem );
8735
8736 // FIXME: surely this isn't thread-aware
8737 VG_(track_copy_mem_remap) ( shadow_mem_copy_range );
8738
8739 VG_(track_change_mem_mprotect) ( evh__set_perms );
8740
8741 VG_(track_die_mem_stack_signal)( evh__die_mem );
8742 VG_(track_die_mem_brk) ( evh__die_mem );
8743 VG_(track_die_mem_munmap) ( evh__die_mem );
8744 VG_(track_die_mem_stack) ( evh__die_mem );
8745
8746 // FIXME: what is this for?
8747 VG_(track_ban_mem_stack) (NULL);
8748
8749 VG_(track_pre_mem_read) ( evh__pre_mem_read );
8750 VG_(track_pre_mem_read_asciiz) ( evh__pre_mem_read_asciiz );
8751 VG_(track_pre_mem_write) ( evh__pre_mem_write );
8752 VG_(track_post_mem_write) (NULL);
8753
8754 /////////////////
8755
8756 VG_(track_pre_thread_ll_create)( evh__pre_thread_ll_create );
8757 VG_(track_pre_thread_ll_exit) ( evh__pre_thread_ll_exit );
8758
8759 VG_(track_start_client_code)( evh__start_client_code );
8760 VG_(track_stop_client_code)( evh__stop_client_code );
8761
8762 initialise_data_structures();
8763
8764 /* Ensure that requirements for "dodgy C-as-C++ style inheritance"
8765 as described in comments at the top of pub_tool_hashtable.h, are
8766 met. Blargh. */
8767 tl_assert( sizeof(void*) == sizeof(struct _MallocMeta*) );
8768 tl_assert( sizeof(UWord) == sizeof(Addr) );
8769 hg_mallocmeta_table
8770 = VG_(HT_construct)( "hg_malloc_metadata_table" );
8771
8772 /* a SecMap must contain an integral number of CacheLines */
8773 tl_assert(0 == (N_SECMAP_ARANGE % N_LINE_ARANGE));
8774 /* also ... a CacheLine holds an integral number of trees */
8775 tl_assert(0 == (N_LINE_ARANGE % 8));
8776}
8777
8778VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
8779
8780/*--------------------------------------------------------------------*/
8781/*--- end hg_main.c ---*/
8782/*--------------------------------------------------------------------*/