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