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