blob: 4a028b8788ded7ee09fa0f07f8fa47a10dc91c63 [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00003/*--- Helgrind: checking for data races in threaded programs. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Helgrind, a Valgrind tool for detecting
njnc9539842002-10-02 13:26:35 +00009 data races in threaded programs.
njn25e49d8e72002-09-23 09:36:25 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2002-2005 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn25e49d8e72002-09-23 09:36:25 +000013
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
nethercote46063202004-09-02 08:51:43 +000032#include "tool.h"
njn717cde52005-05-10 02:47:21 +000033#include "pub_tool_mallocfree.h"
34#include "pub_tool_replacemalloc.h"
njn43b9a8a2005-05-10 04:37:01 +000035#include "pub_tool_tooliface.h"
njn717cde52005-05-10 02:47:21 +000036
sewardj7f3ad222002-11-13 22:11:53 +000037#include "helgrind.h"
njn25e49d8e72002-09-23 09:36:25 +000038
njnfbdcba92005-05-09 01:23:49 +000039static UInt n_hg_warnings = 0;
sewardjff2c9232002-11-13 21:44:39 +000040static UInt n_lockorder_warnings = 0;
njn25e49d8e72002-09-23 09:36:25 +000041
42/*------------------------------------------------------------*/
43/*--- Debug guff ---*/
44/*------------------------------------------------------------*/
45
sewardje11d6c82002-12-15 02:00:41 +000046#define DEBUG_LOCK_TABLE 0 /* Print lock table at end */
njn25e49d8e72002-09-23 09:36:25 +000047
48#define DEBUG_MAKE_ACCESSES 0 /* Print make_access() calls */
49#define DEBUG_LOCKS 0 /* Print lock()/unlock() calls and locksets */
50#define DEBUG_NEW_LOCKSETS 0 /* Print new locksets when created */
51#define DEBUG_ACCESSES 0 /* Print reads, writes */
52#define DEBUG_MEM_LOCKSET_CHANGES 0
53 /* Print when an address's lockset
54 changes; only useful with
55 DEBUG_ACCESSES */
sewardj8fac99a2002-11-13 22:31:26 +000056#define SLOW_ASSERTS 0 /* do expensive asserts */
njn25e49d8e72002-09-23 09:36:25 +000057#define DEBUG_VIRGIN_READS 0 /* Dump around address on VIRGIN reads */
58
sewardj8fac99a2002-11-13 22:31:26 +000059#if SLOW_ASSERTS
njn94065fd2004-11-22 19:26:27 +000060#define TL_ASSERT(x) tl_assert(x)
sewardj8fac99a2002-11-13 22:31:26 +000061#else
njn94065fd2004-11-22 19:26:27 +000062#define TL_ASSERT(x)
sewardj8fac99a2002-11-13 22:31:26 +000063#endif
64
njn25e49d8e72002-09-23 09:36:25 +000065/* heavyweight LockSet sanity checking:
66 0 == never
67 1 == after important ops
68 2 == As 1 and also after pthread_mutex_* ops (excessively slow)
69 */
70#define LOCKSET_SANITY 0
71
sewardj8fac99a2002-11-13 22:31:26 +000072/* Rotate an unsigned quantity left */
73#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x)*8)-(n))))
74
75/* round a up to the next multiple of N. N must be a power of 2 */
76#define ROUNDUP(a, N) ((a + N - 1) & ~(N-1))
77
78/* Round a down to the next multiple of N. N must be a power of 2 */
79#define ROUNDDN(a, N) ((a) & ~(N-1))
njn25e49d8e72002-09-23 09:36:25 +000080
81/*------------------------------------------------------------*/
sewardjf6374322002-11-13 22:35:55 +000082/*--- Command line options ---*/
83/*------------------------------------------------------------*/
84
85static enum {
86 EC_None,
87 EC_Some,
88 EC_All
89} clo_execontext = EC_None;
90
sewardje1a39f42002-12-15 01:56:17 +000091static Bool clo_priv_stacks = False;
sewardjf6374322002-11-13 22:35:55 +000092
93/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000094/*--- Crude profiling machinery. ---*/
95/*------------------------------------------------------------*/
96
97// PPP: work out if I want this
98
99#define PROF_EVENT(x)
100#if 0
101#ifdef VG_PROFILE_MEMORY
102
103#define N_PROF_EVENTS 150
104
105static UInt event_ctr[N_PROF_EVENTS];
106
107void VGE_(done_prof_mem) ( void )
108{
109 Int i;
110 for (i = 0; i < N_PROF_EVENTS; i++) {
111 if ((i % 10) == 0)
112 VG_(printf)("\n");
113 if (event_ctr[i] > 0)
114 VG_(printf)( "prof mem event %2d: %d\n", i, event_ctr[i] );
115 }
116 VG_(printf)("\n");
117}
118
119#define PROF_EVENT(ev) \
njnca82cc02004-11-22 17:18:48 +0000120 do { tl_assert((ev) >= 0 && (ev) < N_PROF_EVENTS); \
njn25e49d8e72002-09-23 09:36:25 +0000121 event_ctr[ev]++; \
122 } while (False);
123
124#else
125
126//static void init_prof_mem ( void ) { }
127// void VG_(done_prof_mem) ( void ) { }
128
129#define PROF_EVENT(ev) /* */
130
131#endif /* VG_PROFILE_MEMORY */
132
133/* Event index. If just the name of the fn is given, this means the
134 number of calls to the fn. Otherwise it is the specified event.
135
136 [PPP: snip event numbers...]
137*/
138#endif /* 0 */
139
140
141/*------------------------------------------------------------*/
142/*--- Data defns. ---*/
143/*------------------------------------------------------------*/
144
njn3e884182003-04-15 13:03:23 +0000145typedef
146 struct _HG_Chunk {
147 struct _HG_Chunk* next;
148 Addr data; /* ptr to actual block */
nethercote928a5f72004-11-03 18:10:37 +0000149 SizeT size; /* size requested */
njn3e884182003-04-15 13:03:23 +0000150 ExeContext* where; /* where it was allocated */
151 ThreadId tid; /* allocating thread */
152 }
153 HG_Chunk;
154
njn25e49d8e72002-09-23 09:36:25 +0000155typedef enum
sewardj7f3ad222002-11-13 22:11:53 +0000156 { Vge_VirginInit, Vge_NonVirginInit, Vge_SegmentInit, Vge_Error }
njn25e49d8e72002-09-23 09:36:25 +0000157 VgeInitStatus;
158
sewardjc808ef52002-11-13 22:43:26 +0000159
njnc6168192004-11-29 13:54:10 +0000160// XXX: not 64-bit clean!
njn25e49d8e72002-09-23 09:36:25 +0000161/* Should add up to 32 to fit in one word */
162#define OTHER_BITS 30
163#define STATE_BITS 2
164
165#define ESEC_MAP_WORDS 16384 /* Words per secondary map */
166
167/* This is for indicating that a memory block has been initialised but not
168 * really directly by a particular thread... (eg. text/data initialised
169 * automatically at startup).
170 * Must be different to virgin_word.other */
171#define TID_INDICATING_NONVIRGIN 1
172
sewardjc4a810d2002-11-13 22:25:51 +0000173/* Magic packed TLS used for error suppression; if word state is Excl
174 and tid is this, then it means all access are OK without changing
175 state and without raising any more errors */
176#define TLSP_INDICATING_ALL ((1 << OTHER_BITS) - 1)
sewardj16748af2002-10-22 04:55:54 +0000177
njn25e49d8e72002-09-23 09:36:25 +0000178/* Number of entries must fit in STATE_BITS bits */
179typedef enum { Vge_Virgin, Vge_Excl, Vge_Shar, Vge_SharMod } pth_state;
180
sewardjc808ef52002-11-13 22:43:26 +0000181static inline const Char *pp_state(pth_state st)
182{
183 const Char *ret;
184
185 switch(st) {
186 case Vge_Virgin: ret = "virgin"; break;
187 case Vge_Excl: ret = "exclusive"; break;
188 case Vge_Shar: ret = "shared RO"; break;
189 case Vge_SharMod: ret = "shared RW"; break;
190 default: ret = "???";
191 }
192 return ret;
193}
194
njn25e49d8e72002-09-23 09:36:25 +0000195typedef
196 struct {
sewardj8fac99a2002-11-13 22:31:26 +0000197 /* gcc arranges this bitfield with state in the 2LSB and other
198 in the 30MSB, which is what we want */
njn25e49d8e72002-09-23 09:36:25 +0000199 UInt state:STATE_BITS;
sewardj8fac99a2002-11-13 22:31:26 +0000200 UInt other:OTHER_BITS;
njn25e49d8e72002-09-23 09:36:25 +0000201 } shadow_word;
202
sewardj8fac99a2002-11-13 22:31:26 +0000203#define SW(st, other) ((shadow_word) { st, other })
204
njn25e49d8e72002-09-23 09:36:25 +0000205typedef
206 struct {
207 shadow_word swords[ESEC_MAP_WORDS];
208 }
209 ESecMap;
210
211static ESecMap* primary_map[ 65536 ];
212static ESecMap distinguished_secondary_map;
213
sewardj8fac99a2002-11-13 22:31:26 +0000214static const shadow_word virgin_sword = SW(Vge_Virgin, 0);
215static const shadow_word error_sword = SW(Vge_Excl, TLSP_INDICATING_ALL);
njn25e49d8e72002-09-23 09:36:25 +0000216
217#define VGE_IS_DISTINGUISHED_SM(smap) \
218 ((smap) == &distinguished_secondary_map)
219
220#define ENSURE_MAPPABLE(addr,caller) \
221 do { \
222 if (VGE_IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
223 primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
224 /*VG_(printf)("new 2map because of %p\n", addr);*/ \
225 } \
226 } while(0)
227
228
sewardjc808ef52002-11-13 22:43:26 +0000229/* Parallel map which contains execution contexts when words last
230 changed state (if required) */
sewardj499e3de2002-11-13 22:22:25 +0000231
nethercoteca788ff2004-10-20 10:58:09 +0000232typedef struct EC_IP {
233 union u_ec_ip {
234 Addr ip;
sewardjc808ef52002-11-13 22:43:26 +0000235 ExeContext *ec;
nethercoteca788ff2004-10-20 10:58:09 +0000236 } uu_ec_ip;
sewardjc808ef52002-11-13 22:43:26 +0000237 UInt state:STATE_BITS;
238 UInt tls:OTHER_BITS; /* packed TLS */
nethercoteca788ff2004-10-20 10:58:09 +0000239} EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000240
nethercoteca788ff2004-10-20 10:58:09 +0000241#define NULL_EC_IP ((EC_IP){ { 0 }, 0, 0})
sewardjc808ef52002-11-13 22:43:26 +0000242
nethercoteca788ff2004-10-20 10:58:09 +0000243#define IP(ip, prev, tls) ((EC_IP) { (union u_ec_ip)(ip), (prev).state, packTLS(tls) })
244#define EC(ec, prev, tls) ((EC_IP) { (union u_ec_ip)(ec), (prev).state, packTLS(tls) })
sewardjc808ef52002-11-13 22:43:26 +0000245
246static inline UInt packEC(ExeContext *ec)
247{
njn94065fd2004-11-22 19:26:27 +0000248 TL_ASSERT(((UWord)ec & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000249 return ((UWord)ec) >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000250}
251
nethercoteca788ff2004-10-20 10:58:09 +0000252/* Lose 2 LSB of IP */
253static inline UInt packIP(Addr ip)
sewardjc808ef52002-11-13 22:43:26 +0000254{
nethercote50397c22004-11-04 18:03:06 +0000255 return ip >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000256}
257
nethercoteca788ff2004-10-20 10:58:09 +0000258static inline Addr unpackIP(UInt i)
sewardjc808ef52002-11-13 22:43:26 +0000259{
260 return (Addr)(i << STATE_BITS);
261}
sewardj499e3de2002-11-13 22:22:25 +0000262
263typedef struct {
nethercoteca788ff2004-10-20 10:58:09 +0000264 EC_IP execontext[ESEC_MAP_WORDS];
sewardj499e3de2002-11-13 22:22:25 +0000265} ExeContextMap;
266
267static ExeContextMap** execontext_map;
268
nethercoteca788ff2004-10-20 10:58:09 +0000269static inline void setExeContext(Addr a, EC_IP ec)
sewardj499e3de2002-11-13 22:22:25 +0000270{
271 UInt idx = (a >> 16) & 0xffff;
272 UInt off = (a >> 2) & 0x3fff;
273
274 if (execontext_map[idx] == NULL) {
275 execontext_map[idx] = VG_(malloc)(sizeof(ExeContextMap));
276 VG_(memset)(execontext_map[idx], 0, sizeof(ExeContextMap));
277 }
278
279 execontext_map[idx]->execontext[off] = ec;
280}
281
nethercoteca788ff2004-10-20 10:58:09 +0000282static inline EC_IP getExeContext(Addr a)
sewardj499e3de2002-11-13 22:22:25 +0000283{
284 UInt idx = (a >> 16) & 0xffff;
285 UInt off = (a >> 2) & 0x3fff;
nethercoteca788ff2004-10-20 10:58:09 +0000286 EC_IP ec = NULL_EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000287
288 if (execontext_map[idx] != NULL)
289 ec = execontext_map[idx]->execontext[off];
290
291 return ec;
292}
293
njn25e49d8e72002-09-23 09:36:25 +0000294/*------------------------------------------------------------*/
sewardjc4a810d2002-11-13 22:25:51 +0000295/*--- Thread lifetime segments ---*/
296/*------------------------------------------------------------*/
297
298/*
299 * This mechanism deals with the common case of a parent thread
300 * creating a structure for a child thread, and then passing ownership
301 * of the structure to that thread. It similarly copes with a child
302 * thread passing information back to another thread waiting to join
303 * on it.
304 *
305 * Each thread's lifetime can be partitioned into segments. Those
306 * segments are arranged to form an interference graph which indicates
307 * whether two thread lifetime segments can possibly be concurrent.
308 * If not, then memory with is exclusively accessed by one TLS can be
daywalker7e73e5f2003-07-04 16:18:15 +0000309 * passed on to another TLS without an error occurring, and without
sewardjc4a810d2002-11-13 22:25:51 +0000310 * moving it from Excl state.
311 *
312 * At present this only considers thread creation and join as
313 * synchronisation events for creating new lifetime segments, but
314 * others may be possible (like mutex operations).
315 */
316
317typedef struct _ThreadLifeSeg ThreadLifeSeg;
318
319struct _ThreadLifeSeg {
320 ThreadId tid;
321 ThreadLifeSeg *prior[2]; /* Previous lifetime segments */
322 UInt refcount; /* Number of memory locations pointing here */
323 UInt mark; /* mark used for graph traversal */
324 ThreadLifeSeg *next; /* list of all TLS */
325};
326
327static ThreadLifeSeg *all_tls;
328static UInt tls_since_gc;
329#define TLS_SINCE_GC 10000
330
331/* current mark used for TLS graph traversal */
332static UInt tlsmark;
333
334static ThreadLifeSeg *thread_seg[VG_N_THREADS];
335
336
337static void tls_gc(void)
338{
339 /* XXX later. Walk through all TLSs and look for ones with 0
340 refcount and remove them from the structure and free them.
341 Could probably get rid of ThreadLifeSeg.refcount and simply use
342 mark-sweep from the shadow table. */
343 VG_(printf)("WRITEME: TLS GC\n");
344}
345
346static void newTLS(ThreadId tid)
347{
348 static const Bool debug = False;
349 ThreadLifeSeg *tls;
350
351 /* Initial NULL */
352 if (thread_seg[tid] == NULL) {
353 tls = VG_(malloc)(sizeof(*tls));
354 tls->tid = tid;
355 tls->prior[0] = tls->prior[1] = NULL;
356 tls->refcount = 0;
357 tls->mark = tlsmark-1;
358
359 tls->next = all_tls;
360 all_tls = tls;
361 tls_since_gc++;
362
363 thread_seg[tid] = tls;
364 return;
365 }
366
367 /* Previous TLS was unused, so just recycle */
368 if (thread_seg[tid]->refcount == 0) {
369 if (debug)
370 VG_(printf)("newTLS; recycling TLS %p for tid %u\n",
371 thread_seg[tid], tid);
372 return;
373 }
374
375 /* Use existing TLS for this tid as a prior for new TLS */
376 tls = VG_(malloc)(sizeof(*tls));
377 tls->tid = tid;
378 tls->prior[0] = thread_seg[tid];
379 tls->prior[1] = NULL;
380 tls->refcount = 0;
381 tls->mark = tlsmark-1;
382
383 tls->next = all_tls;
384 all_tls = tls;
385 if (++tls_since_gc > TLS_SINCE_GC) {
386 tls_gc();
387 tls_since_gc = 0;
388 }
389
390 if (debug)
391 VG_(printf)("newTLS: made new TLS %p for tid %u (prior %p(%u))\n",
392 tls, tid, tls->prior[0], tls->prior[0]->tid);
393
394 thread_seg[tid] = tls;
395}
396
397/* clear out a TLS for a thread that's died */
398static void clearTLS(ThreadId tid)
399{
400 newTLS(tid);
401
402 thread_seg[tid]->prior[0] = NULL;
403 thread_seg[tid]->prior[1] = NULL;
404}
405
406static void addPriorTLS(ThreadId tid, ThreadId prior)
407{
408 static const Bool debug = False;
409 ThreadLifeSeg *tls = thread_seg[tid];
410
411 if (debug)
412 VG_(printf)("making TLS %p(%u) prior to TLS %p(%u)\n",
413 thread_seg[prior], prior, tls, tid);
414
njnca82cc02004-11-22 17:18:48 +0000415 tl_assert(thread_seg[tid] != NULL);
416 tl_assert(thread_seg[prior] != NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000417
418 if (tls->prior[0] == NULL)
419 tls->prior[0] = thread_seg[prior];
420 else {
njnca82cc02004-11-22 17:18:48 +0000421 tl_assert(tls->prior[1] == NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000422 tls->prior[1] = thread_seg[prior];
423 }
424}
425
njnfbdcba92005-05-09 01:23:49 +0000426static Bool isPrior(const ThreadLifeSeg *t, const ThreadLifeSeg *prior)
427{
428 if (t == NULL || t->mark == tlsmark)
429 return False;
430
431 if (t == prior)
432 return True;
433
434 ((ThreadLifeSeg *)t)->mark = tlsmark;
435
436 return isPrior(t->prior[0], prior) || isPrior(t->prior[1], prior);
437}
438
sewardjc4a810d2002-11-13 22:25:51 +0000439/* Return True if prior is definitely not concurrent with tls */
440static Bool tlsIsDisjoint(const ThreadLifeSeg *tls,
441 const ThreadLifeSeg *prior)
442{
sewardjc4a810d2002-11-13 22:25:51 +0000443 tlsmark++; /* new traversal mark */
444
njnfbdcba92005-05-09 01:23:49 +0000445 return isPrior(tls, prior);
sewardjc4a810d2002-11-13 22:25:51 +0000446}
447
448static inline UInt packTLS(ThreadLifeSeg *tls)
449{
njn94065fd2004-11-22 19:26:27 +0000450 TL_ASSERT(((UWord)tls & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000451 return ((UWord)tls) >> STATE_BITS;
sewardjc4a810d2002-11-13 22:25:51 +0000452}
453
454static inline ThreadLifeSeg *unpackTLS(UInt i)
455{
456 return (ThreadLifeSeg *)(i << STATE_BITS);
457}
458
459/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000460/*--- Low-level support for memory tracking. ---*/
461/*------------------------------------------------------------*/
462
463/*
464 All reads and writes are recorded in the memory map, which
465 records the state of all memory in the process. The memory map is
466 organised like that for normal Valgrind, except each that everything
467 is done at word-level instead of byte-level, and each word has only
468 one word of shadow (instead of 36 bits).
469
470 As for normal Valgrind there is a distinguished secondary map. But we're
471 working at word-granularity, so it has 16k word entries instead of 64k byte
472 entries. Lookup is done as follows:
473
474 bits 31..16: primary map lookup
475 bits 15.. 2: secondary map lookup
476 bits 1.. 0: ignored
477*/
478
479
480/*------------------------------------------------------------*/
481/*--- Basic bitmap management, reading and writing. ---*/
482/*------------------------------------------------------------*/
483
484/* Allocate and initialise a secondary map, marking all words as virgin. */
485
486/* Just a value that isn't a real pointer */
487#define SEC_MAP_ACCESS (shadow_word*)0x99
488
489
490static
491ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
492{
493 ESecMap* map;
494 UInt i;
495 //PROF_EVENT(10); PPP
496
nethercote1420ab22004-08-18 22:26:01 +0000497 // Mark all words as virgin.
fitzhardinge98abfc72003-12-16 02:05:15 +0000498 map = (ESecMap *)VG_(shadow_alloc)(sizeof(ESecMap));
njn25e49d8e72002-09-23 09:36:25 +0000499 for (i = 0; i < ESEC_MAP_WORDS; i++)
500 map->swords[i] = virgin_sword;
501
502 return map;
503}
504
505
506/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
507 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000508static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000509void set_sword ( Addr a, shadow_word sword )
510{
511 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000512 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000513
514 //PROF_EVENT(23); PPP
515 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
516
517 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
518 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000519 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000520 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
521 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
522 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
523 tls->refcount--;
524 }
525
526 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
527 ThreadLifeSeg *tls = unpackTLS(sword.other);
528 tls->refcount++;
529 }
530
njn25e49d8e72002-09-23 09:36:25 +0000531 sm->swords[(a & 0xFFFC) >> 2] = sword;
532
533 if (VGE_IS_DISTINGUISHED_SM(sm)) {
534 VG_(printf)("wrote to distinguished 2ndary map! 0x%x\n", a);
535 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000536 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000537 }
538}
539
540
541static __inline__
542shadow_word* get_sword_addr ( Addr a )
543{
544 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
545 ESecMap* sm = primary_map[a >> 16];
546 UInt sm_off = (a & 0xFFFC) >> 2;
547
548 if (VGE_IS_DISTINGUISHED_SM(sm)) {
549 VG_(printf)("accessed distinguished 2ndary map! 0x%x\n", a);
550 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000551 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000552 return SEC_MAP_ACCESS;
553 }
554
555 //PROF_EVENT(21); PPP
556 return & (sm->swords[sm_off]);
557}
558
559
560// SSS: rename these so they're not so similar to memcheck, unless it's
561// appropriate of course
562
563static __inline__
564void init_virgin_sword(Addr a)
565{
sewardj499e3de2002-11-13 22:22:25 +0000566 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000567 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000568 set_sword(a, virgin_sword);
569}
570
sewardj7f3ad222002-11-13 22:11:53 +0000571static __inline__
572void init_error_sword(Addr a)
573{
574 set_sword(a, error_sword);
575}
njn25e49d8e72002-09-23 09:36:25 +0000576
njn25e49d8e72002-09-23 09:36:25 +0000577static __inline__
578void init_nonvirgin_sword(Addr a)
579{
580 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000581 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000582 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000583
njn14d01ce2004-11-26 11:30:14 +0000584 // The tid must be passed in here now; this requires more events to be
585 // given the tid in the first place.
586 //
587 //tid = VG_(get_current_or_recent_tid)();
588 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
589 VG_(exit)(1);
590
njnca82cc02004-11-22 17:18:48 +0000591 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000592 tls = thread_seg[tid];
593
sewardj8fac99a2002-11-13 22:31:26 +0000594 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000595 set_sword(a, sword);
596}
597
598
njnfbdcba92005-05-09 01:23:49 +0000599/* In this case, we treat it for Helgrind's sake like virgin (it hasn't
njn25e49d8e72002-09-23 09:36:25 +0000600 * been inited by a particular thread, it's just done automatically upon
601 * startup), but we mark its .state specially so it doesn't look like an
602 * uninited read. */
603static __inline__
604void init_magically_inited_sword(Addr a)
605{
606 shadow_word sword;
607
sewardj8fac99a2002-11-13 22:31:26 +0000608 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
609
njn25e49d8e72002-09-23 09:36:25 +0000610 set_sword(a, virgin_sword);
611}
612
sewardjc26cc252002-10-23 21:58:55 +0000613
sewardj274c6012002-10-22 04:54:55 +0000614/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000615/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000616/*------------------------------------------------------------*/
617
sewardj39a4d842002-11-13 22:14:30 +0000618typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000619typedef struct _LockSet LockSet;
620
sewardj16748af2002-10-22 04:55:54 +0000621typedef enum MutexState {
622 MxUnknown, /* don't know */
623 MxUnlocked, /* unlocked */
624 MxLocked, /* locked */
625 MxDead /* destroyed */
626} MutexState;
627
sewardj39a4d842002-11-13 22:14:30 +0000628struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000629 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000630 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000631
632 MutexState state; /* mutex state */
633 ThreadId tid; /* owner */
634 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000635
sewardj4bffb232002-11-13 21:46:34 +0000636 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000637 UInt mark; /* mark for graph traversal */
638};
sewardj16748af2002-10-22 04:55:54 +0000639
sewardj39a4d842002-11-13 22:14:30 +0000640static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000641{
sewardjdac0a442002-11-13 22:08:40 +0000642 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000643}
njn25e49d8e72002-09-23 09:36:25 +0000644
sewardj274c6012002-10-22 04:54:55 +0000645struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000646 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000647 UInt hash; /* hash code */
648 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000649 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000650};
sewardj4bffb232002-11-13 21:46:34 +0000651
652static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000653
654/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000655static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000656
sewardjdac0a442002-11-13 22:08:40 +0000657#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000658
sewardj4bffb232002-11-13 21:46:34 +0000659static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000660
sewardj4bffb232002-11-13 21:46:34 +0000661/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000662static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000663{
sewardj4bffb232002-11-13 21:46:34 +0000664 UInt id;
665
njn94065fd2004-11-22 19:26:27 +0000666 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000667 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000668
669 return id;
njn25e49d8e72002-09-23 09:36:25 +0000670}
671
sewardj8fac99a2002-11-13 22:31:26 +0000672static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000673{
sewardj4bffb232002-11-13 21:46:34 +0000674 return (LockSet *)(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000675}
676
njn25e49d8e72002-09-23 09:36:25 +0000677static
sewardj4bffb232002-11-13 21:46:34 +0000678void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000679{
sewardj05bcdcb2003-05-18 10:05:38 +0000680 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000681 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000682 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000683 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000684
685 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000686 }
687 VG_(printf)("}\n");
688}
689
690
sewardj4bffb232002-11-13 21:46:34 +0000691static void print_LockSet(const Char *s, const LockSet *ls)
692{
693 VG_(printf)("%s: ", s);
694 pp_LockSet(ls);
695}
696
697/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000698static UInt hash_LockSet_w_wo(const LockSet *ls,
699 const Mutex *with,
700 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000701{
sewardj05bcdcb2003-05-18 10:05:38 +0000702 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000703 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000704
njnca82cc02004-11-22 17:18:48 +0000705 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000706
707 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000708 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000709
710 if (without && mutex_cmp(without, mx) == 0)
711 continue;
712
713 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
714 mx = with;
715 with = NULL;
716 i--;
717 }
718
sewardj8fac99a2002-11-13 22:31:26 +0000719 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000720 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000721 }
722
723 return hash % LOCKSET_HASH_SZ;
724}
725
sewardj39a4d842002-11-13 22:14:30 +0000726static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000727{
728 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
729
730 if (0)
731 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
732
733 return hash;
734}
735
sewardj39a4d842002-11-13 22:14:30 +0000736static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000737{
738 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
739
740 if (0)
741 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
742
743 return hash;
744}
745
746static inline UInt hash_LockSet(const LockSet *ls)
747{
748 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
749
750 if (0)
751 VG_(printf)("hash %p -> %d\n", ls, hash);
752
753 return hash;
754}
755
756static
757Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000758{
759 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000760
sewardj4bffb232002-11-13 21:46:34 +0000761 if (a == b)
762 return True;
763 if (a->setsize != b->setsize)
764 return False;
njn25e49d8e72002-09-23 09:36:25 +0000765
sewardj4bffb232002-11-13 21:46:34 +0000766 for(i = 0; i < a->setsize; i++) {
767 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000768 return False;
njn25e49d8e72002-09-23 09:36:25 +0000769 }
770
sewardj4bffb232002-11-13 21:46:34 +0000771 return True;
njn25e49d8e72002-09-23 09:36:25 +0000772}
773
774
775/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
776 * doesn't do the insertion. Returns True if they match.
777 */
778static Bool
sewardj4bffb232002-11-13 21:46:34 +0000779weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000780 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000781{
sewardjc26cc252002-10-23 21:58:55 +0000782 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000783 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000784
njn25e49d8e72002-09-23 09:36:25 +0000785 /* Idea is to try and match each element of b against either an
786 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000787
788 if (debug) {
789 print_LockSet("weird_LockSet_equals a", a);
790 print_LockSet(" b", b);
791 VG_(printf)( " missing: %p%(y\n",
792 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000793 }
sewardjc26cc252002-10-23 21:58:55 +0000794
sewardj4bffb232002-11-13 21:46:34 +0000795 if ((a->setsize + 1) != b->setsize) {
796 if (debug)
797 VG_(printf)(" fastpath length mismatch -> 0\n");
798 return False;
799 }
800
sewardjc26cc252002-10-23 21:58:55 +0000801 /* There are three phases to this compare:
802 1 the section from the start of a up to missing_mutex
803 2 missing mutex itself
804 3 the section after missing_mutex to the end of a
805 */
806
sewardj4bffb232002-11-13 21:46:34 +0000807 ia = 0;
808 ib = 0;
809
sewardjc26cc252002-10-23 21:58:55 +0000810 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000811 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000812 if (debug) {
813 print_LockSet(" 1:a", a);
814 print_LockSet(" 1:b", b);
815 }
sewardj4bffb232002-11-13 21:46:34 +0000816 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000817 return False;
sewardjc26cc252002-10-23 21:58:55 +0000818 }
819
820 /* 2: missing_mutex itself */
821 if (debug) {
822 VG_(printf)( " 2:missing: %p%(y\n",
823 missing_mutex->mutexp, missing_mutex->mutexp);
824 print_LockSet(" 2: b", b);
825 }
826
njnca82cc02004-11-22 17:18:48 +0000827 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000828
sewardj4bffb232002-11-13 21:46:34 +0000829 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000830 return False;
831
sewardj4bffb232002-11-13 21:46:34 +0000832 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000833
834 /* 3: after missing_mutex to end */
835
sewardj4bffb232002-11-13 21:46:34 +0000836 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000837 if (debug) {
838 print_LockSet(" 3:a", a);
839 print_LockSet(" 3:b", b);
840 }
sewardj4bffb232002-11-13 21:46:34 +0000841 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000842 return False;
sewardjc26cc252002-10-23 21:58:55 +0000843 }
844
845 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000846 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000847
sewardj4bffb232002-11-13 21:46:34 +0000848 return ia == a->setsize && ib == b->setsize;
849}
850
851
852
853static const LockSet *lookup_LockSet(const LockSet *set)
854{
855 UInt bucket = set->hash;
856 LockSet *ret;
857
858 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
859 if (set == ret || structural_eq_LockSet(set, ret))
860 return ret;
861
862 return NULL;
863}
864
sewardj39a4d842002-11-13 22:14:30 +0000865static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000866{
867 UInt bucket = hash_LockSet_with(set, mutex);
868 const LockSet *ret;
869
870 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
871 if (weird_LockSet_equals(set, ret, mutex))
872 return ret;
873
874 return NULL;
875}
876
sewardj39a4d842002-11-13 22:14:30 +0000877static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000878{
879 UInt bucket = hash_LockSet_without(set, mutex);
880 const LockSet *ret;
881
882 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
883 if (weird_LockSet_equals(ret, set, mutex))
884 return ret;
885
886 return NULL;
887}
888
889static void insert_LockSet(LockSet *set)
890{
891 UInt hash = hash_LockSet(set);
892
893 set->hash = hash;
894
njnca82cc02004-11-22 17:18:48 +0000895 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000896
897 set->next = lockset_hash[hash];
898 lockset_hash[hash] = set;
899}
900
901static inline
902LockSet *alloc_LockSet(UInt setsize)
903{
sewardj39a4d842002-11-13 22:14:30 +0000904 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000905 ret->setsize = setsize;
906 return ret;
907}
908
909static inline
910void free_LockSet(LockSet *p)
911{
912 /* assert: not present in hash */
913 VG_(free)(p);
914}
915
njnb4aee052003-04-15 14:09:58 +0000916static
sewardj4bffb232002-11-13 21:46:34 +0000917void pp_all_LockSets ( void )
918{
919 Int i;
920 Int sets, buckets;
921
922 sets = buckets = 0;
923 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
924 const LockSet *ls = lockset_hash[i];
925 Bool first = True;
926
sewardj4bffb232002-11-13 21:46:34 +0000927 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000928 if (first) {
929 buckets++;
930 VG_(printf)("[%4d] = ", i);
931 } else
932 VG_(printf)(" ");
933
sewardj4bffb232002-11-13 21:46:34 +0000934 sets++;
935 first = False;
936 pp_LockSet(ls);
937 }
938 }
939
940 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
941}
942
943static inline Bool isempty(const LockSet *ls)
944{
945 return ls == NULL || ls->setsize == 0;
946}
947
sewardj39a4d842002-11-13 22:14:30 +0000948static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000949{
950 Int i;
951
952 /* XXX use binary search */
953 for(i = 0; i < ls->setsize; i++)
954 if (mutex_cmp(mx, ls->mutex[i]) == 0)
955 return True;
956
957 return False;
958}
959
960/* Check invariants:
961 - all locksets are unique
962 - each set is an array in strictly increasing order of mutex addr
963*/
964static
965void sanity_check_locksets ( const Char* caller )
966{
967 Int i;
968 const Char *badness;
969 LockSet *ls;
970
971 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
972
973 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000974 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000975 Int j;
976
977 if (hash_LockSet(ls) != ls->hash) {
978 badness = "mismatched hash";
979 goto bad;
980 }
sewardj05bcdcb2003-05-18 10:05:38 +0000981 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +0000982 badness = "wrong bucket";
983 goto bad;
984 }
985 if (lookup_LockSet(ls) != ls) {
986 badness = "non-unique set";
987 goto bad;
988 }
989
990 prev = ls->mutex[0];
991 for(j = 1; j < ls->setsize; j++) {
992 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
993 badness = "mutexes out of order";
994 goto bad;
995 }
996 }
997 }
998 }
999 return;
1000
1001 bad:
1002 VG_(printf)("sanity_check_locksets: "
1003 "i = %d, ls=%p badness = %s, caller = %s\n",
1004 i, ls, badness, caller);
1005 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001006 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001007}
1008
1009static
sewardj39a4d842002-11-13 22:14:30 +00001010LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001011{
1012 static const Bool debug = False;
1013 LockSet *ret = NULL;
1014 Int i, j;
1015
1016 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1017 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1018 print_LockSet("add-IN", ls);
1019 }
1020
1021 if (debug || LOCKSET_SANITY)
1022 sanity_check_locksets("add-IN");
1023
njnca82cc02004-11-22 17:18:48 +00001024 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001025
1026 ret = alloc_LockSet(ls->setsize+1);
1027
1028 for(i = j = 0; i < ls->setsize; i++) {
1029 if (debug)
1030 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1031 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1032 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1033 ret->mutex[j++] = mx;
1034 mx = NULL;
1035 }
1036 ret->mutex[j++] = ls->mutex[i];
1037 }
1038
1039 /* not added in loop - must be after */
1040 if (mx)
1041 ret->mutex[j++] = mx;
1042
njnca82cc02004-11-22 17:18:48 +00001043 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001044
1045 if (debug || LOCKSET_SANITY) {
1046 print_LockSet("add-OUT", ret);
1047 sanity_check_locksets("add-OUT");
1048 }
1049 return ret;
1050}
1051
1052/* Builds ls with mx removed. mx should actually be in ls!
1053 (a checked assertion). Resulting set should not already
1054 exist in the table (unchecked).
1055*/
1056static
sewardj39a4d842002-11-13 22:14:30 +00001057LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001058{
1059 static const Bool debug = False;
1060 LockSet *ret = NULL;
1061 Int i, j;
1062
1063 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1064 print_LockSet("remove-IN", ls);
1065 }
1066
1067 if (debug || LOCKSET_SANITY)
1068 sanity_check_locksets("remove-IN");
1069
njnca82cc02004-11-22 17:18:48 +00001070 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001071
1072 ret = alloc_LockSet(ls->setsize-1);
1073
1074 for(i = j = 0; i < ls->setsize; i++) {
1075 if (mutex_cmp(ls->mutex[i], mx) == 0)
1076 continue;
1077 ret->mutex[j++] = ls->mutex[i];
1078 }
1079
njnca82cc02004-11-22 17:18:48 +00001080 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001081
1082 if (debug || LOCKSET_SANITY) {
1083 print_LockSet("remove-OUT", ret);
1084 sanity_check_locksets("remove-OUT");
1085 }
1086 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001087}
1088
1089
1090/* Builds the intersection, and then unbuilds it if it's already in the table.
1091 */
sewardj4bffb232002-11-13 21:46:34 +00001092static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001093{
sewardj4bffb232002-11-13 21:46:34 +00001094 static const Bool debug = False;
1095 Int iret;
1096 Int ia, ib;
1097 Int size;
1098 LockSet *ret;
1099 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001100
sewardj4bffb232002-11-13 21:46:34 +00001101 if (debug || LOCKSET_SANITY)
1102 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001103
sewardj4bffb232002-11-13 21:46:34 +00001104 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1105 print_LockSet("intersect a", a);
1106 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001107 }
1108
sewardj4bffb232002-11-13 21:46:34 +00001109 /* count the size of the new set */
1110 size = 0;
1111 ia = ib = 0;
1112 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1113 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1114 size++;
1115 ia++;
1116 ib++;
1117 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1118 ia++;
1119 } else {
njnca82cc02004-11-22 17:18:48 +00001120 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001121 ib++;
1122 }
njn25e49d8e72002-09-23 09:36:25 +00001123 }
1124
sewardj4bffb232002-11-13 21:46:34 +00001125 /* Build the intersection of the two sets */
1126 ret = alloc_LockSet(size);
1127 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1128 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001129 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001130 ret->mutex[iret++] = a->mutex[ia];
1131 ia++;
1132 ib++;
1133 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1134 ia++;
1135 } else {
njnca82cc02004-11-22 17:18:48 +00001136 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001137 ib++;
1138 }
1139 }
1140
1141 ret->hash = hash_LockSet(ret);
1142
njn25e49d8e72002-09-23 09:36:25 +00001143 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001144 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001145
sewardj4bffb232002-11-13 21:46:34 +00001146 if (found != NULL) {
1147 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001148 } else {
sewardj4bffb232002-11-13 21:46:34 +00001149 insert_LockSet(ret);
1150 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001151 }
1152
sewardj4bffb232002-11-13 21:46:34 +00001153 if (debug || LOCKSET_SANITY) {
1154 print_LockSet("intersect-OUT", found);
1155 sanity_check_locksets("intersect-OUT");
1156 }
njn25e49d8e72002-09-23 09:36:25 +00001157
sewardj4bffb232002-11-13 21:46:34 +00001158 return found;
njn25e49d8e72002-09-23 09:36:25 +00001159}
1160
sewardj4bffb232002-11-13 21:46:34 +00001161/* inline the fastpath */
1162static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001163{
sewardj4bffb232002-11-13 21:46:34 +00001164 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001165
1166 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001167 if (a == b) {
1168 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1169 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001170 }
sewardj4bffb232002-11-13 21:46:34 +00001171 return a;
sewardjc26cc252002-10-23 21:58:55 +00001172 }
1173
sewardj4bffb232002-11-13 21:46:34 +00001174 if (isempty(a) || isempty(b)) {
1175 if (debug)
1176 VG_(printf)("intersect empty fastpath\n");
1177 return emptyset;
1178 }
1179
1180 return _intersect(a, b);
1181}
1182
1183
1184static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1185{
1186 static const Bool debug = False;
1187 Int iret;
1188 Int ia, ib;
1189 Int size;
1190 LockSet *ret;
1191 const LockSet *found;
1192
1193 if (debug || LOCKSET_SANITY)
1194 sanity_check_locksets("union-IN");
1195
1196 /* Fast case -- when the two are the same */
1197 if (a == b) {
1198 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1199 print_LockSet("union-same fastpath", a);
1200 }
1201 return a;
1202 }
1203
1204 if (isempty(a)) {
1205 if (debug)
1206 print_LockSet("union a=empty b", b);
1207 return b;
1208 }
1209 if (isempty(b)) {
1210 if (debug)
1211 print_LockSet("union b=empty a", a);
1212 return a;
1213 }
1214
1215 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001216 print_LockSet("union a", a);
1217 print_LockSet("union b", b);
1218 }
1219
sewardj4bffb232002-11-13 21:46:34 +00001220 /* count the size of the new set */
1221 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1222 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001223
sewardj4bffb232002-11-13 21:46:34 +00001224 if ((ia < a->setsize) && (ib < b->setsize))
1225 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1226 else if (ia == a->setsize)
1227 cmp = 1;
1228 else
1229 cmp = -1;
1230
1231 if (cmp == 0) {
1232 size++;
1233 ia++;
1234 ib++;
1235 } else if (cmp < 0) {
1236 size++;
1237 ia++;
1238 } else {
njnca82cc02004-11-22 17:18:48 +00001239 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001240 size++;
1241 ib++;
1242 }
sewardjc26cc252002-10-23 21:58:55 +00001243 }
1244
sewardj4bffb232002-11-13 21:46:34 +00001245 /* Build the intersection of the two sets */
1246 ret = alloc_LockSet(size);
1247 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1248 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001249 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001250
1251 if ((ia < a->setsize) && (ib < b->setsize))
1252 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1253 else if (ia == a->setsize)
1254 cmp = 1;
1255 else
1256 cmp = -1;
1257
1258 if (cmp == 0) {
1259 ret->mutex[iret++] = a->mutex[ia];
1260 ia++;
1261 ib++;
1262 } else if (cmp < 0) {
1263 ret->mutex[iret++] = a->mutex[ia];
1264 ia++;
1265 } else {
njnca82cc02004-11-22 17:18:48 +00001266 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001267 ret->mutex[iret++] = b->mutex[ib];
1268 ib++;
1269 }
1270 }
1271
njnca82cc02004-11-22 17:18:48 +00001272 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001273
1274 ret->hash = hash_LockSet(ret);
1275
sewardjc26cc252002-10-23 21:58:55 +00001276 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001277 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001278
sewardj4bffb232002-11-13 21:46:34 +00001279 if (found != NULL) {
1280 if (debug)
1281 print_LockSet("union found existing set", found);
1282 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001283 } else {
sewardj4bffb232002-11-13 21:46:34 +00001284 if (debug)
1285 print_LockSet("union inserting new set", ret);
1286 insert_LockSet(ret);
1287 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001288 }
1289
sewardj4bffb232002-11-13 21:46:34 +00001290 if (debug || LOCKSET_SANITY) {
1291 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001292 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001293 }
sewardjc26cc252002-10-23 21:58:55 +00001294
sewardj4bffb232002-11-13 21:46:34 +00001295 return found;
sewardjc26cc252002-10-23 21:58:55 +00001296}
1297
1298/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001299/*--- Implementation of mutex structure. ---*/
1300/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001301
1302static UInt graph_mark; /* current mark we're using for graph traversal */
1303
sewardj39a4d842002-11-13 22:14:30 +00001304static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001305 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001306static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001307 const LockSet *lockset_holding,
1308 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001309
njn72718642003-07-24 08:45:32 +00001310static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001311
1312#define M_MUTEX_HASHSZ 1021
1313
sewardj39a4d842002-11-13 22:14:30 +00001314static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001315static UInt total_mutexes;
1316
1317static const Char *pp_MutexState(MutexState st)
1318{
1319 switch(st) {
1320 case MxLocked: return "Locked";
1321 case MxUnlocked: return "Unlocked";
1322 case MxDead: return "Dead";
1323 case MxUnknown: return "Unknown";
1324 }
1325 return "???";
1326}
1327
1328static void pp_all_mutexes()
1329{
1330 Int i;
1331 Int locks, buckets;
1332
1333 locks = buckets = 0;
1334 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001335 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001336 Bool first = True;
1337
1338 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1339 if (first) {
1340 buckets++;
1341 VG_(printf)("[%4d] = ", i);
1342 } else
1343 VG_(printf)(" ");
1344 locks++;
1345 first = False;
1346 VG_(printf)("%p [%8s] -> %p%(y\n",
1347 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1348 }
1349 }
1350
1351 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1352 locks, buckets, total_mutexes);
1353}
sewardjc26cc252002-10-23 21:58:55 +00001354
sewardj39a4d842002-11-13 22:14:30 +00001355/* find or create a Mutex for a program's mutex use */
1356static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001357{
nethercote50397c22004-11-04 18:03:06 +00001358 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001359 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001360
1361 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1362 if (mp->mutexp == mutexp)
1363 return mp;
1364
sewardjdac0a442002-11-13 22:08:40 +00001365 total_mutexes++;
1366
sewardjc26cc252002-10-23 21:58:55 +00001367 mp = VG_(malloc)(sizeof(*mp));
1368 mp->mutexp = mutexp;
1369 mp->next = mutex_hash[bucket];
1370 mutex_hash[bucket] = mp;
1371
1372 mp->state = MxUnknown;
1373 mp->tid = VG_INVALID_THREADID;
1374 mp->location = NULL;
1375
sewardj4bffb232002-11-13 21:46:34 +00001376 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001377 mp->mark = graph_mark - 1;
1378
1379 return mp;
1380}
1381
sewardjdac0a442002-11-13 22:08:40 +00001382/* Find all mutexes in a range of memory, and call the callback.
1383 Remove the mutex from the hash if the callback returns True (mutex
1384 structure itself is not freed, because it may be pointed to by a
1385 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001386static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001387{
sewardjdac0a442002-11-13 22:08:40 +00001388 UInt first = start % M_MUTEX_HASHSZ;
1389 UInt last = (end+1) % M_MUTEX_HASHSZ;
1390 UInt i;
1391
1392 /* Single pass over the hash table, looking for likely hashes */
1393 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001394 Mutex *mx;
1395 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001396
1397 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1398 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1399 *prev = mx->next;
1400 }
1401
1402 if (++i == M_MUTEX_HASHSZ)
1403 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001404 }
sewardjc26cc252002-10-23 21:58:55 +00001405}
1406
1407#define MARK_LOOP (graph_mark+0)
1408#define MARK_DONE (graph_mark+1)
1409
thughes4ad52d02004-06-27 17:37:21 +00001410static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1411{
1412 static const Bool debug = False;
1413 Int i;
1414
1415 if (mutex->mark == MARK_LOOP)
1416 return True; /* found cycle */
1417 if (mutex->mark == MARK_DONE)
1418 return False; /* been here before, its OK */
1419
1420 ((Mutex*)mutex)->mark = MARK_LOOP;
1421
1422 if (debug)
1423 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1424 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1425 for(i = 0; i < ls->setsize; i++) {
1426 const Mutex *mx = ls->mutex[i];
1427
1428 if (debug)
1429 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1430 mutex->mutexp, ls,
1431 mx->mutexp, mx->mutexp);
1432 if (check_cycle_inner(mx, mx->lockdep))
1433 return True;
1434 }
1435 ((Mutex*)mutex)->mark = MARK_DONE;
1436
1437 return False;
1438}
1439
sewardj39a4d842002-11-13 22:14:30 +00001440static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001441{
sewardjff2c9232002-11-13 21:44:39 +00001442
sewardjc26cc252002-10-23 21:58:55 +00001443 graph_mark += 2; /* clear all marks */
1444
sewardj4bffb232002-11-13 21:46:34 +00001445 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001446}
1447
sewardjdca84112002-11-13 22:29:34 +00001448/* test to see if a mutex state change would be problematic; this
1449 makes no changes to the mutex state. This should be called before
1450 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001451static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001452{
1453 static const Bool debug = False;
1454
sewardjc26cc252002-10-23 21:58:55 +00001455 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001456 Char *str;
1457
1458 switch(state) {
1459 case MxLocked: str = "lock dead mutex"; break;
1460 case MxUnlocked: str = "unlock dead mutex"; break;
1461 default: str = "operate on dead mutex"; break;
1462 }
1463
sewardjc26cc252002-10-23 21:58:55 +00001464 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001465 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001466 return;
1467 }
1468
1469 switch(state) {
1470 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001471 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001472
1473 if (debug)
1474 print_LockSet("thread holding", thread_locks[tid]);
1475
1476 if (check_cycle(mutex, thread_locks[tid]))
1477 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1478 else {
1479 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1480
1481 if (debug) {
1482 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1483 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1484 print_LockSet("lockdep", mutex->lockdep);
1485 }
1486 }
1487 break;
1488
1489 case MxUnlocked:
1490 if (debug)
1491 print_LockSet("thread holding", thread_locks[tid]);
1492
1493 if (mutex->state != MxLocked) {
1494 record_mutex_error(tid, mutex,
1495 "unlock non-locked mutex", mutex->location);
1496 }
1497 if (mutex->tid != tid) {
1498 record_mutex_error(tid, mutex,
1499 "unlock someone else's mutex", mutex->location);
1500 }
1501 break;
1502
1503 case MxDead:
1504 break;
1505
1506 default:
1507 break;
1508 }
1509}
1510
1511/* Update a mutex state. Expects most error testing and reporting to
1512 have happened in test_mutex_state(). The assumption is that no
1513 client code is run by thread tid between test and set, either
1514 because it is blocked or test and set are called together
1515 atomically.
1516
1517 Setting state to MxDead is the exception, since that can happen as
1518 a result of any thread freeing memory; in this case set_mutex_state
1519 does all the error reporting as well.
1520*/
njn72718642003-07-24 08:45:32 +00001521static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001522{
1523 static const Bool debug = False;
1524
1525 if (debug)
1526 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1527 tid, mutex, mutex->mutexp, mutex->mutexp,
1528 pp_MutexState(mutex->state), pp_MutexState(state));
1529
1530 if (mutex->state == MxDead) {
1531 /* can't do anything legal to a destroyed mutex */
1532 return;
1533 }
1534
1535 switch(state) {
1536 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001537 if (mutex->state == MxLocked) {
1538 if (mutex->tid != tid)
1539 record_mutex_error(tid, mutex, "take lock held by someone else",
1540 mutex->location);
1541 else
1542 record_mutex_error(tid, mutex, "take lock we already hold",
1543 mutex->location);
1544
njn67993252004-11-22 18:02:32 +00001545 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001546 break;
1547 }
sewardjc26cc252002-10-23 21:58:55 +00001548
njnca82cc02004-11-22 17:18:48 +00001549 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001550
sewardjc26cc252002-10-23 21:58:55 +00001551 mutex->tid = tid;
1552 break;
1553
1554 case MxUnlocked:
1555 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001556 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001557
sewardjdca84112002-11-13 22:29:34 +00001558 if (mutex->state != MxLocked || mutex->tid != tid)
1559 break;
1560
sewardjc26cc252002-10-23 21:58:55 +00001561 mutex->tid = VG_INVALID_THREADID;
1562 break;
1563
sewardjdac0a442002-11-13 22:08:40 +00001564 case MxDead:
1565 if (mutex->state == MxLocked) {
1566 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001567 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001568 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1569 mutex->tid = VG_INVALID_THREADID;
1570
1571 record_mutex_error(tid, mutex,
1572 "free locked mutex", mutex->location);
1573 }
1574 break;
1575
sewardjc26cc252002-10-23 21:58:55 +00001576 default:
1577 break;
1578 }
1579
njnd01fef72005-03-25 23:35:48 +00001580 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001581 mutex->state = state;
1582}
njn25e49d8e72002-09-23 09:36:25 +00001583
1584/*------------------------------------------------------------*/
1585/*--- Setting and checking permissions. ---*/
1586/*------------------------------------------------------------*/
1587
thughes4ad52d02004-06-27 17:37:21 +00001588/* only clean up dead mutexes */
1589static
1590Bool cleanmx(Mutex *mx) {
1591 return mx->state == MxDead;
1592}
1593
njn25e49d8e72002-09-23 09:36:25 +00001594static
nethercote451eae92004-11-02 13:06:32 +00001595void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001596 VgeInitStatus status )
1597{
sewardj1806d7f2002-10-22 05:05:49 +00001598 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001599
1600# if DEBUG_MAKE_ACCESSES
1601 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1602# endif
1603 //PROF_EVENT(30); PPP
1604
1605 if (len == 0)
1606 return;
1607
1608 if (len > 100 * 1000 * 1000)
1609 VG_(message)(Vg_UserMsg,
1610 "Warning: set address range state: large range %d",
1611 len);
1612
1613 VGP_PUSHCC(VgpSARP);
1614
sewardjdac0a442002-11-13 22:08:40 +00001615 /* Remove mutexes in recycled memory range from hash */
1616 find_mutex_range(a, a+len, cleanmx);
1617
njn25e49d8e72002-09-23 09:36:25 +00001618 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1619 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1620 * len/4+1 words. This works out which it is by aligning the block and
1621 * seeing if the end byte is in the same word as it is for the unaligned
1622 * block; if not, it's the awkward case. */
sewardj8fac99a2002-11-13 22:31:26 +00001623 end = ROUNDUP(a + len, 4);
1624 a = ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001625
1626 /* Do it ... */
1627 switch (status) {
1628 case Vge_VirginInit:
1629 for ( ; a < end; a += 4) {
1630 //PROF_EVENT(31); PPP
1631 init_virgin_sword(a);
1632 }
1633 break;
1634
1635 case Vge_NonVirginInit:
1636 for ( ; a < end; a += 4) {
1637 //PROF_EVENT(31); PPP
1638 init_nonvirgin_sword(a);
1639 }
1640 break;
1641
1642 case Vge_SegmentInit:
1643 for ( ; a < end; a += 4) {
1644 //PROF_EVENT(31); PPP
1645 init_magically_inited_sword(a);
1646 }
1647 break;
sewardj7f3ad222002-11-13 22:11:53 +00001648
1649 case Vge_Error:
1650 for ( ; a < end; a += 4) {
1651 //PROF_EVENT(31); PPP
1652 init_error_sword(a);
1653 }
1654 break;
njn25e49d8e72002-09-23 09:36:25 +00001655
1656 default:
1657 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001658 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001659 }
1660
njn25e49d8e72002-09-23 09:36:25 +00001661 VGP_POPCC(VgpSARP);
1662}
1663
1664
nethercote451eae92004-11-02 13:06:32 +00001665static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001666{
1667 //PROF_EVENT(??); PPP
1668 set_address_range_state ( a, len, Vge_SegmentInit );
1669}
1670
nethercote451eae92004-11-02 13:06:32 +00001671static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001672{
1673 //PROF_EVENT(36); PPP
1674 set_address_range_state( a, len, Vge_VirginInit );
1675}
1676
nethercote451eae92004-11-02 13:06:32 +00001677static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001678{
1679 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001680 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001681}
1682
1683
njn25e49d8e72002-09-23 09:36:25 +00001684/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001685static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001686{
1687 UInt i;
1688
1689 //PROF_EVENT(40); PPP
1690 for (i = 0; i < len; i += 4) {
1691 shadow_word sword = *(get_sword_addr ( src+i ));
1692 //PROF_EVENT(41); PPP
1693 set_sword ( dst+i, sword );
1694 }
1695}
1696
1697// SSS: put these somewhere better
njnfbdcba92005-05-09 01:23:49 +00001698static void hg_mem_read (Addr a, SizeT data_size, ThreadId tid);
1699static void hg_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001700
njnfbdcba92005-05-09 01:23:49 +00001701static void hg_mem_help_read_1(Addr a) VGA_REGPARM(1);
1702static void hg_mem_help_read_2(Addr a) VGA_REGPARM(1);
1703static void hg_mem_help_read_4(Addr a) VGA_REGPARM(1);
1704static void hg_mem_help_read_N(Addr a, SizeT size) VGA_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001705
njnfbdcba92005-05-09 01:23:49 +00001706static void hg_mem_help_write_1(Addr a, UInt val) VGA_REGPARM(2);
1707static void hg_mem_help_write_2(Addr a, UInt val) VGA_REGPARM(2);
1708static void hg_mem_help_write_4(Addr a, UInt val) VGA_REGPARM(2);
1709static void hg_mem_help_write_N(Addr a, SizeT size) VGA_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001710
sewardj7a5ebcf2002-11-13 22:42:13 +00001711static void bus_lock(void);
1712static void bus_unlock(void);
1713
njn25e49d8e72002-09-23 09:36:25 +00001714static
njnfbdcba92005-05-09 01:23:49 +00001715void hg_pre_mem_read(CorePart part, ThreadId tid,
1716 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001717{
njn67993252004-11-22 18:02:32 +00001718 if (tid > 50) { VG_(printf)("pid = %d, s = `%s`, part = %d\n", tid, s, part); VG_(tool_panic)("a");}
njnfbdcba92005-05-09 01:23:49 +00001719 hg_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001720}
1721
1722static
njnfbdcba92005-05-09 01:23:49 +00001723void hg_pre_mem_read_asciiz(CorePart part, ThreadId tid,
1724 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001725{
njnfbdcba92005-05-09 01:23:49 +00001726 hg_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001727}
1728
1729static
njnfbdcba92005-05-09 01:23:49 +00001730void hg_pre_mem_write(CorePart part, ThreadId tid,
1731 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001732{
njnfbdcba92005-05-09 01:23:49 +00001733 hg_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001734}
1735
1736
1737
1738static
njnfbdcba92005-05-09 01:23:49 +00001739void hg_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001740{
njn1f3a9092002-10-04 09:22:30 +00001741 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001742 make_segment_readable(a, len);
1743}
1744
1745
1746static
njnfbdcba92005-05-09 01:23:49 +00001747void hg_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001748{
1749 if (is_inited) {
1750 make_readable(a, len);
1751 } else {
1752 make_writable(a, len);
1753 }
1754}
1755
1756static
njnfbdcba92005-05-09 01:23:49 +00001757void hg_set_perms (Addr a, SizeT len,
1758 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001759{
1760 if (rr) make_readable(a, len);
1761 else if (ww) make_writable(a, len);
1762 /* else do nothing */
1763}
1764
sewardjf6374322002-11-13 22:35:55 +00001765static
njnfbdcba92005-05-09 01:23:49 +00001766void hg_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001767{
1768 set_address_range_state(a, len, Vge_NonVirginInit);
1769}
1770
1771static
njnfbdcba92005-05-09 01:23:49 +00001772void hg_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001773{
1774 set_address_range_state(a, len, Vge_VirginInit);
1775}
njn25e49d8e72002-09-23 09:36:25 +00001776
1777/*--------------------------------------------------------------*/
1778/*--- Initialise the memory audit system on program startup. ---*/
1779/*--------------------------------------------------------------*/
1780
1781static
1782void init_shadow_memory(void)
1783{
1784 Int i;
1785
1786 for (i = 0; i < ESEC_MAP_WORDS; i++)
1787 distinguished_secondary_map.swords[i] = virgin_sword;
1788
1789 /* These entries gradually get overwritten as the used address
1790 space expands. */
1791 for (i = 0; i < 65536; i++)
1792 primary_map[i] = &distinguished_secondary_map;
1793}
1794
1795
njn3e884182003-04-15 13:03:23 +00001796/*------------------------------------------------------------*/
1797/*--- malloc() et al replacements ---*/
1798/*------------------------------------------------------------*/
1799
njnb4aee052003-04-15 14:09:58 +00001800static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001801
1802#define N_FREED_CHUNKS 2
1803static Int freechunkptr = 0;
1804static HG_Chunk *freechunks[N_FREED_CHUNKS];
1805
njn3e884182003-04-15 13:03:23 +00001806
1807/* Allocate a user-chunk of size bytes. Also allocate its shadow
1808 block, make the shadow block point at the user block. Put the
1809 shadow chunk on the appropriate list, and set all memory
1810 protections correctly. */
1811
nethercote7ac7f7b2004-11-02 12:36:02 +00001812static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001813{
1814 HG_Chunk* hc;
1815
1816 hc = VG_(malloc)(sizeof(HG_Chunk));
1817 hc->data = p;
1818 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001819 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001820 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001821
1822 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1823}
1824
1825/* Allocate memory and note change in memory available */
1826static __inline__
njn14d01ce2004-11-26 11:30:14 +00001827void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1828 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001829{
1830 Addr p;
1831
njn34ac0272003-09-30 14:20:00 +00001832 if (size < 0) return NULL;
1833
njn3e884182003-04-15 13:03:23 +00001834 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001835 if (!p) {
1836 return NULL;
1837 }
njn34ac0272003-09-30 14:20:00 +00001838 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001839 add_HG_Chunk ( tid, p, size );
njnfbdcba92005-05-09 01:23:49 +00001840 hg_new_mem_heap( p, size, is_zeroed );
njn3e884182003-04-15 13:03:23 +00001841
1842 return (void*)p;
1843}
1844
njn51d827b2005-05-09 01:02:08 +00001845static void* hg_malloc ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001846{
njn14d01ce2004-11-26 11:30:14 +00001847 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001848}
1849
njn51d827b2005-05-09 01:02:08 +00001850static void* hg___builtin_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001851{
njn14d01ce2004-11-26 11:30:14 +00001852 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001853}
1854
njn51d827b2005-05-09 01:02:08 +00001855static void* hg___builtin_vec_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001856{
njn14d01ce2004-11-26 11:30:14 +00001857 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001858}
1859
njn51d827b2005-05-09 01:02:08 +00001860static void* hg_memalign ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001861{
njn14d01ce2004-11-26 11:30:14 +00001862 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001863}
1864
njn51d827b2005-05-09 01:02:08 +00001865static void* hg_calloc ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001866{
njn14d01ce2004-11-26 11:30:14 +00001867 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001868 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001869}
1870
thughes4ad52d02004-06-27 17:37:21 +00001871static ThreadId deadmx_tid;
1872
1873static
1874Bool deadmx(Mutex *mx) {
1875 if (mx->state != MxDead)
1876 set_mutex_state(mx, MxDead, deadmx_tid);
1877
1878 return False;
1879}
1880
njn3e884182003-04-15 13:03:23 +00001881static
njn72718642003-07-24 08:45:32 +00001882void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001883 HG_Chunk** prev_chunks_next_ptr )
1884{
njn72718642003-07-24 08:45:32 +00001885 Addr start = hc->data;
1886 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001887
njn3e884182003-04-15 13:03:23 +00001888 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1889 avoid repeating the hash table lookup. Can't remove until at least
1890 after free and free_mismatch errors are done because they use
1891 describe_addr() which looks for it in malloclist. */
1892 *prev_chunks_next_ptr = hc->next;
1893
1894 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001895 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001896
1897 /* maintain a small window so that the error reporting machinery
1898 knows about this memory */
1899 if (freechunks[freechunkptr] != NULL) {
1900 /* free HG_Chunk */
1901 HG_Chunk* sc1 = freechunks[freechunkptr];
1902 VG_(cli_free) ( (void*)(sc1->data) );
1903 VG_(free) ( sc1 );
1904 }
1905
1906 freechunks[freechunkptr] = hc;
1907
1908 if (++freechunkptr == N_FREED_CHUNKS)
1909 freechunkptr = 0;
1910
1911 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001912 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001913 find_mutex_range(start, end, deadmx);
1914}
1915
1916
1917static __inline__
njn14d01ce2004-11-26 11:30:14 +00001918void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001919{
1920 HG_Chunk* hc;
1921 HG_Chunk** prev_chunks_next_ptr;
1922
nethercote3d6b6112004-11-04 16:39:43 +00001923 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001924 (VgHashNode***)&prev_chunks_next_ptr );
1925 if (hc == NULL) {
1926 return;
1927 }
njn14d01ce2004-11-26 11:30:14 +00001928 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001929}
1930
njn51d827b2005-05-09 01:02:08 +00001931static void hg_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001932{
njn14d01ce2004-11-26 11:30:14 +00001933 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001934}
1935
njn51d827b2005-05-09 01:02:08 +00001936static void hg___builtin_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001937{
njn14d01ce2004-11-26 11:30:14 +00001938 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001939}
1940
njn51d827b2005-05-09 01:02:08 +00001941static void hg___builtin_vec_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001942{
njn14d01ce2004-11-26 11:30:14 +00001943 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001944}
1945
njn51d827b2005-05-09 01:02:08 +00001946static void* hg_realloc ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001947{
1948 HG_Chunk *hc;
1949 HG_Chunk **prev_chunks_next_ptr;
sewardj05bcdcb2003-05-18 10:05:38 +00001950 Int i;
njn3e884182003-04-15 13:03:23 +00001951
1952 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001953 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001954 (VgHashNode***)&prev_chunks_next_ptr );
1955
1956 if (hc == NULL) {
1957 return NULL;
1958 }
1959
1960 if (hc->size == new_size) {
1961 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001962 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001963 return p;
1964
1965 } else if (hc->size > new_size) {
1966 /* new size is smaller */
1967 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001968 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001969 return p;
1970
1971 } else {
1972 /* new size is bigger */
1973 Addr p_new;
1974
1975 /* Get new memory */
1976 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
1977
1978 /* First half kept and copied, second half new */
1979 copy_address_range_state( (Addr)p, p_new, hc->size );
njnfbdcba92005-05-09 01:23:49 +00001980 hg_new_mem_heap ( p_new+hc->size, new_size-hc->size,
1981 /*inited*/False );
njn3e884182003-04-15 13:03:23 +00001982
1983 /* Copy from old to new */
1984 for (i = 0; i < hc->size; i++)
1985 ((UChar*)p_new)[i] = ((UChar*)p)[i];
1986
1987 /* Free old memory */
njn72718642003-07-24 08:45:32 +00001988 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001989
1990 /* this has to be after die_and_free_mem, otherwise the
1991 former succeeds in shorting out the new block, not the
1992 old, in the case when both are on the same list. */
njn72718642003-07-24 08:45:32 +00001993 add_HG_Chunk ( tid, p_new, new_size );
njn3e884182003-04-15 13:03:23 +00001994
1995 return (void*)p_new;
1996 }
1997}
1998
njn25e49d8e72002-09-23 09:36:25 +00001999/*--------------------------------------------------------------*/
2000/*--- Machinery to support sanity checking ---*/
2001/*--------------------------------------------------------------*/
2002
njn51d827b2005-05-09 01:02:08 +00002003static Bool hg_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00002004{
jseward9800fd32004-01-04 23:08:04 +00002005 /* nothing useful we can rapidly check */
2006 return True;
njn25e49d8e72002-09-23 09:36:25 +00002007}
2008
njn51d827b2005-05-09 01:02:08 +00002009static Bool hg_expensive_sanity_check(void)
njn25e49d8e72002-09-23 09:36:25 +00002010{
2011 Int i;
2012
2013 /* Make sure nobody changed the distinguished secondary. */
2014 for (i = 0; i < ESEC_MAP_WORDS; i++)
2015 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2016 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2017 return False;
2018
2019 return True;
2020}
2021
2022
2023/*--------------------------------------------------------------*/
2024/*--- Instrumentation ---*/
2025/*--------------------------------------------------------------*/
2026
sewardjf6374322002-11-13 22:35:55 +00002027static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2028
njn14d01ce2004-11-26 11:30:14 +00002029#if 0
njn25e49d8e72002-09-23 09:36:25 +00002030/* Create and return an instrumented version of cb_in. Free cb_in
2031 before returning. */
njn26f02512004-11-22 18:33:15 +00002032UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002033{
2034 UCodeBlock* cb;
2035 Int i;
2036 UInstr* u_in;
2037 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002038 Int ntemps;
2039 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002040 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002041
njn810086f2002-11-14 12:42:47 +00002042 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002043
sewardjf6374322002-11-13 22:35:55 +00002044 /* stackref[] is used for super-simple value tracking to keep note
2045 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002046 the stack pointer or frame pointer, and is therefore likely
2047 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002048 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002049 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2050 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2051
njn810086f2002-11-14 12:42:47 +00002052 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2053 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002054
njn25e49d8e72002-09-23 09:36:25 +00002055 switch (u_in->opcode) {
2056
2057 case NOP: case CALLM_S: case CALLM_E:
2058 break;
sewardjf6374322002-11-13 22:35:55 +00002059
sewardj7a5ebcf2002-11-13 22:42:13 +00002060 case LOCK:
2061 locked = True;
2062 uInstr0(cb, CCALL, 0);
2063 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2064 break;
2065
2066 case JMP: case INCEIP:
2067 if (locked) {
2068 uInstr0(cb, CCALL, 0);
2069 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2070 }
2071 locked = False;
2072 VG_(copy_UInstr)(cb, u_in);
2073 break;
2074
sewardjf6374322002-11-13 22:35:55 +00002075 case GET:
njnca82cc02004-11-22 17:18:48 +00002076 tl_assert(u_in->tag1 == ArchReg);
2077 tl_assert(u_in->tag2 == TempReg);
2078 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002079
2080 stackref[u_in->val2] = (u_in->size == 4 &&
njndb9b7732005-03-26 00:32:29 +00002081 (u_in->val1 == VGA_R_STACK_PTR ||
2082 u_in->val1 == VGA_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002083 VG_(copy_UInstr)(cb, u_in);
2084 break;
2085
2086 case MOV:
2087 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002088 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002089 stackref[u_in->val2] = stackref[u_in->val1];
2090 }
2091 VG_(copy_UInstr)(cb, u_in);
2092 break;
2093
2094 case LEA1:
2095 case ADD: case SUB:
2096 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002097 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002098 stackref[u_in->val2] |= stackref[u_in->val1];
2099 }
2100 VG_(copy_UInstr)(cb, u_in);
2101 break;
njn25e49d8e72002-09-23 09:36:25 +00002102
sewardja5b3aec2002-10-22 05:09:36 +00002103 case LOAD: {
2104 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002105 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2106 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002107
2108 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2109 nonstk_ld++;
2110
2111 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002112 case 1: help = hg_mem_help_read_1; break;
2113 case 2: help = hg_mem_help_read_2; break;
2114 case 4: help = hg_mem_help_read_4; break;
sewardjf6374322002-11-13 22:35:55 +00002115 default:
njn67993252004-11-22 18:02:32 +00002116 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002117 }
jsgfcb1d1c02003-10-14 21:55:10 +00002118
2119 /* XXX all registers should be flushed to baseblock
2120 here */
sewardjf6374322002-11-13 22:35:55 +00002121 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2122 uCCall(cb, (Addr)help, 1, 1, False);
2123 } else
2124 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002125
sewardja5b3aec2002-10-22 05:09:36 +00002126 VG_(copy_UInstr)(cb, u_in);
2127 t_size = INVALID_TEMPREG;
2128 break;
2129 }
2130
fitzhardinge111c6072004-03-09 02:45:07 +00002131 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002132 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002133 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002134 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002135
fitzhardinge111c6072004-03-09 02:45:07 +00002136 t_size = newTemp(cb);
2137 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2138 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002139
fitzhardinge111c6072004-03-09 02:45:07 +00002140 /* XXX all registers should be flushed to baseblock
2141 here */
2142 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002143 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002144
2145 VG_(copy_UInstr)(cb, u_in);
2146 t_size = INVALID_TEMPREG;
2147 break;
sewardja5b3aec2002-10-22 05:09:36 +00002148 }
2149
thughes96b466a2004-03-15 16:43:58 +00002150 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002151 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002152
2153 t_size = newTemp(cb);
2154 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2155 uLiteral(cb, (UInt)u_in->size);
2156
2157 /* XXX all registers should be flushed to baseblock
2158 here */
2159 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002160 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
thughes96b466a2004-03-15 16:43:58 +00002161
2162 VG_(copy_UInstr)(cb, u_in);
2163 t_size = INVALID_TEMPREG;
2164 break;
2165 }
2166
fitzhardinge111c6072004-03-09 02:45:07 +00002167 case SSE2a_MemRd:
2168 case SSE2a1_MemRd:
2169 case SSE3a_MemRd:
2170 case SSE3a1_MemRd:
2171 case SSE3ag_MemRd_RegWr: {
2172 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2173
njnca82cc02004-11-22 17:18:48 +00002174 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002175
2176 t_size = newTemp(cb);
2177 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2178 uLiteral(cb, (UInt)u_in->size);
2179
2180 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002181 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002182
2183 VG_(copy_UInstr)(cb, u_in);
2184 t_size = INVALID_TEMPREG;
2185 break;
2186 }
2187
sewardja5b3aec2002-10-22 05:09:36 +00002188 case STORE: {
2189 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002190 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2191 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002192
sewardjf6374322002-11-13 22:35:55 +00002193 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2194 nonstk_st++;
2195
2196 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002197 case 1: help = hg_mem_help_write_1; break;
2198 case 2: help = hg_mem_help_write_2; break;
2199 case 4: help = hg_mem_help_write_4; break;
sewardjf6374322002-11-13 22:35:55 +00002200 default:
njn67993252004-11-22 18:02:32 +00002201 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002202 }
2203
jsgfcb1d1c02003-10-14 21:55:10 +00002204 /* XXX all registers should be flushed to baseblock
2205 here */
sewardjf6374322002-11-13 22:35:55 +00002206 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2207 uCCall(cb, (Addr)help, 2, 2, False);
2208 } else
2209 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002210
2211 VG_(copy_UInstr)(cb, u_in);
2212 t_size = INVALID_TEMPREG;
2213 break;
2214 }
2215
fitzhardinge111c6072004-03-09 02:45:07 +00002216 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002217 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002218 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002219 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002220
2221 t_size = newTemp(cb);
2222 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2223 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002224 /* XXX all registers should be flushed to baseblock
2225 here */
sewardja5b3aec2002-10-22 05:09:36 +00002226 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002227 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
sewardja5b3aec2002-10-22 05:09:36 +00002228
2229 VG_(copy_UInstr)(cb, u_in);
2230 t_size = INVALID_TEMPREG;
2231 break;
2232 }
njn25e49d8e72002-09-23 09:36:25 +00002233
fitzhardinge111c6072004-03-09 02:45:07 +00002234 case SSE2a_MemWr:
2235 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002236 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002237 512 == u_in->size);
2238
2239 t_size = newTemp(cb);
2240 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2241 uLiteral(cb, (UInt)u_in->size);
2242 /* XXX all registers should be flushed to baseblock
2243 here */
2244 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002245 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002246
2247 VG_(copy_UInstr)(cb, u_in);
2248 t_size = INVALID_TEMPREG;
2249 break;
2250 }
sewardj3d7c9c82003-03-26 21:08:13 +00002251
njn25e49d8e72002-09-23 09:36:25 +00002252 default:
sewardjf6374322002-11-13 22:35:55 +00002253 /* conservative tromping */
2254 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2255 stackref[u_in->val1] = False;
2256 if (u_in->tag2 == TempReg)
2257 stackref[u_in->val2] = False;
2258 if (u_in->tag3 == TempReg)
2259 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002260 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002261 break;
2262 }
2263 }
2264
sewardjf6374322002-11-13 22:35:55 +00002265 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002266 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002267 return cb;
2268}
njn14d01ce2004-11-26 11:30:14 +00002269#endif
njn51d827b2005-05-09 01:02:08 +00002270static IRBB* hg_instrument ( IRBB* bb_in, VexGuestLayout* layout,
2271 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002272{
2273 VG_(message)(Vg_DebugMsg, "Helgrind is not yet ready to handle Vex IR");
2274 VG_(exit)(1);
2275}
njn25e49d8e72002-09-23 09:36:25 +00002276
2277/*--------------------------------------------------------------------*/
2278/*--- Error and suppression handling ---*/
2279/*--------------------------------------------------------------------*/
2280
2281typedef
2282 enum {
2283 /* Possible data race */
njnfbdcba92005-05-09 01:23:49 +00002284 RaceSupp
njn25e49d8e72002-09-23 09:36:25 +00002285 }
njnfbdcba92005-05-09 01:23:49 +00002286 RaceSuppKind;
njn25e49d8e72002-09-23 09:36:25 +00002287
2288/* What kind of error it is. */
2289typedef
2290 enum {
njnfbdcba92005-05-09 01:23:49 +00002291 RaceErr, /* data-race */
sewardj16748af2002-10-22 04:55:54 +00002292 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002293 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002294 }
njnfbdcba92005-05-09 01:23:49 +00002295 RaceErrorKind;
njn25e49d8e72002-09-23 09:36:25 +00002296
sewardj16748af2002-10-22 04:55:54 +00002297/* The classification of a faulting address. */
2298typedef
2299 enum { Undescribed, /* as-yet unclassified */
2300 Stack,
2301 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002302 Mallocd,
2303 Freed,
sewardj16748af2002-10-22 04:55:54 +00002304 Segment
2305 }
2306 AddrKind;
2307/* Records info about a faulting address. */
2308typedef
2309 struct {
2310 /* ALL */
2311 AddrKind akind;
2312 /* Freed, Mallocd */
2313 Int blksize;
2314 /* Freed, Mallocd */
2315 Int rwoffset;
2316 /* Freed, Mallocd */
2317 ExeContext* lastchange;
2318 ThreadId lasttid;
2319 /* Stack */
2320 ThreadId stack_tid;
2321 /* Segment */
2322 const Char* filename;
2323 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002324 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002325 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002326 /* symbolic address description */
2327 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002328 }
2329 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002330
sewardj16748af2002-10-22 04:55:54 +00002331/* What kind of memory access is involved in the error? */
2332typedef
2333 enum { ReadAxs, WriteAxs, ExecAxs }
2334 AxsKind;
2335
2336/* Extra context for memory errors */
2337typedef
2338 struct {
2339 AxsKind axskind;
2340 Int size;
2341 AddrInfo addrinfo;
2342 Bool isWrite;
2343 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002344 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002345 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002346 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002347 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002348 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002349 const LockSet *held_lockset;
2350 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002351 }
2352 HelgrindError;
2353
2354static __inline__
2355void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002356{
sewardj16748af2002-10-22 04:55:54 +00002357 ai->akind = Unknown;
2358 ai->blksize = 0;
2359 ai->rwoffset = 0;
2360 ai->lastchange = NULL;
2361 ai->lasttid = VG_INVALID_THREADID;
2362 ai->filename = NULL;
2363 ai->section = "???";
2364 ai->stack_tid = VG_INVALID_THREADID;
2365 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002366 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002367}
2368
sewardj16748af2002-10-22 04:55:54 +00002369static __inline__
2370void clear_HelgrindError ( HelgrindError* err_extra )
2371{
2372 err_extra->axskind = ReadAxs;
2373 err_extra->size = 0;
2374 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002375 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002376 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002377 err_extra->prev_lockset = 0;
2378 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002379 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002380 clear_AddrInfo ( &err_extra->addrinfo );
2381 err_extra->isWrite = False;
2382}
2383
2384
2385
2386/* Describe an address as best you can, for error messages,
2387 putting the result in ai. */
2388
thughes4ad52d02004-06-27 17:37:21 +00002389/* Callback for searching malloc'd and free'd lists */
2390static Bool addr_is_in_block(VgHashNode *node, void *ap)
2391{
2392 HG_Chunk* hc2 = (HG_Chunk*)node;
2393 Addr a = *(Addr *)ap;
2394
2395 return (hc2->data <= a && a < hc2->data + hc2->size);
2396}
2397
sewardj16748af2002-10-22 04:55:54 +00002398static void describe_addr ( Addr a, AddrInfo* ai )
2399{
njn3e884182003-04-15 13:03:23 +00002400 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002401 Int i;
sewardj16748af2002-10-22 04:55:54 +00002402
sewardj16748af2002-10-22 04:55:54 +00002403 /* Search for it in segments */
2404 {
2405 const SegInfo *seg;
2406
2407 for(seg = VG_(next_seginfo)(NULL);
2408 seg != NULL;
2409 seg = VG_(next_seginfo)(seg)) {
2410 Addr base = VG_(seg_start)(seg);
nethercote928a5f72004-11-03 18:10:37 +00002411 SizeT size = VG_(seg_size)(seg);
sewardj16748af2002-10-22 04:55:54 +00002412 const UChar *filename = VG_(seg_filename)(seg);
2413
2414 if (a >= base && a < base+size) {
2415 ai->akind = Segment;
2416 ai->blksize = size;
2417 ai->rwoffset = a - base;
2418 ai->filename = filename;
2419
2420 switch(VG_(seg_sect_kind)(a)) {
2421 case Vg_SectText: ai->section = "text"; break;
2422 case Vg_SectData: ai->section = "data"; break;
2423 case Vg_SectBSS: ai->section = "BSS"; break;
2424 case Vg_SectGOT: ai->section = "GOT"; break;
2425 case Vg_SectPLT: ai->section = "PLT"; break;
2426 case Vg_SectUnknown:
2427 default:
2428 ai->section = "???"; break;
2429 }
2430
2431 return;
2432 }
2433 }
2434 }
2435
2436 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002437 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002438 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002439 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002440 ai->blksize = hc->size;
2441 ai->rwoffset = (Int)a - (Int)(hc->data);
2442 ai->lastchange = hc->where;
2443 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002444 return;
2445 }
sewardjdac0a442002-11-13 22:08:40 +00002446
2447 /* Look in recently freed memory */
2448 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002449 hc = freechunks[i];
2450 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002451 continue;
2452
njn3e884182003-04-15 13:03:23 +00002453 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002454 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002455 ai->blksize = hc->size;
2456 ai->rwoffset = a - hc->data;
2457 ai->lastchange = hc->where;
2458 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002459 return;
2460 }
2461 }
2462
sewardj16748af2002-10-22 04:55:54 +00002463 /* Clueless ... */
2464 ai->akind = Unknown;
2465 return;
2466}
2467
2468
njn7e614812003-04-21 22:04:03 +00002469/* Updates the copy with address info if necessary. */
njn51d827b2005-05-09 01:02:08 +00002470static UInt hg_update_extra(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002471{
njn7e614812003-04-21 22:04:03 +00002472 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002473
njn7e614812003-04-21 22:04:03 +00002474 extra = (HelgrindError*)VG_(get_error_extra)(err);
2475 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2476 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2477 }
2478 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002479}
2480
njnfbdcba92005-05-09 01:23:49 +00002481static void record_race_error ( ThreadId tid, Addr a, Bool is_write,
2482 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002483{
sewardjc4a810d2002-11-13 22:25:51 +00002484 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002485 HelgrindError err_extra;
2486
njnfbdcba92005-05-09 01:23:49 +00002487 n_hg_warnings++;
sewardjff2c9232002-11-13 21:44:39 +00002488
sewardj16748af2002-10-22 04:55:54 +00002489 clear_HelgrindError(&err_extra);
2490 err_extra.isWrite = is_write;
2491 err_extra.addrinfo.akind = Undescribed;
2492 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002493 if (clo_execontext)
2494 err_extra.lasttouched = getExeContext(a);
jsgfcb1d1c02003-10-14 21:55:10 +00002495 err_extra.addrinfo.expr = VG_(describe_addr)(tid, a);
2496
njnfbdcba92005-05-09 01:23:49 +00002497 VG_(maybe_record_error)( tid, RaceErr, a,
sewardj16748af2002-10-22 04:55:54 +00002498 (is_write ? "writing" : "reading"),
2499 &err_extra);
2500
sewardjc4a810d2002-11-13 22:25:51 +00002501 sw = get_sword_addr(a);
2502 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2503 ThreadLifeSeg *tls = unpackTLS(sw->other);
2504 tls->refcount--;
2505 }
2506
sewardj7f3ad222002-11-13 22:11:53 +00002507 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002508}
2509
sewardj39a4d842002-11-13 22:14:30 +00002510static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002511 Char *str, ExeContext *ec)
2512{
2513 HelgrindError err_extra;
2514
2515 clear_HelgrindError(&err_extra);
2516 err_extra.addrinfo.akind = Undescribed;
2517 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002518 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002519 err_extra.lasttid = tid;
2520
njn72718642003-07-24 08:45:32 +00002521 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002522 (Addr)mutex->mutexp, str, &err_extra);
2523}
njn25e49d8e72002-09-23 09:36:25 +00002524
sewardj39a4d842002-11-13 22:14:30 +00002525static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002526 const LockSet *lockset_holding,
2527 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002528{
2529 HelgrindError err_extra;
2530
2531 n_lockorder_warnings++;
2532
2533 clear_HelgrindError(&err_extra);
2534 err_extra.addrinfo.akind = Undescribed;
2535 err_extra.mutex = mutex;
2536
sewardjc808ef52002-11-13 22:43:26 +00002537 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002538 err_extra.held_lockset = lockset_holding;
2539 err_extra.prev_lockset = lockset_prev;
2540
njn72718642003-07-24 08:45:32 +00002541 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002542}
2543
njn51d827b2005-05-09 01:02:08 +00002544static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002545{
njn810086f2002-11-14 12:42:47 +00002546 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002547
njnca82cc02004-11-22 17:18:48 +00002548 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002549
2550 switch (VG_(get_error_kind)(e1)) {
njnfbdcba92005-05-09 01:23:49 +00002551 case RaceErr:
njn810086f2002-11-14 12:42:47 +00002552 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002553
2554 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002555 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002556 }
2557
njn810086f2002-11-14 12:42:47 +00002558 e1s = VG_(get_error_string)(e1);
2559 e2s = VG_(get_error_string)(e2);
2560 if (e1s != e2s) return False;
2561 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002562 return True;
2563}
2564
sewardj16748af2002-10-22 04:55:54 +00002565static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002566{
jsgfcb1d1c02003-10-14 21:55:10 +00002567 if (ai->expr != NULL)
2568 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002569 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002570
sewardj16748af2002-10-22 04:55:54 +00002571 switch (ai->akind) {
2572 case Stack:
2573 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002574 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002575 a, ai->stack_tid);
2576 break;
2577 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002578 if (ai->expr != NULL)
2579 break;
2580
nethercote3b390c72003-11-13 17:53:43 +00002581 /* maybe_gcc is never set to True! This is a hangover from code
2582 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002583 if (ai->maybe_gcc) {
2584 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002585 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002586 a);
2587 VG_(message)(Vg_UserMsg,
2588 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2589 } else {
2590 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002591 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002592 }
2593 break;
2594 case Segment:
2595 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002596 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002597 a, ai->section, ai->filename);
2598 break;
sewardjdac0a442002-11-13 22:08:40 +00002599 case Mallocd:
2600 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002601 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002602 UChar* relative;
2603 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002604 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002605 relative = "before";
2606 } else if (ai->rwoffset >= ai->blksize) {
2607 delta = ai->rwoffset - ai->blksize;
2608 relative = "after";
2609 } else {
2610 delta = ai->rwoffset;
2611 relative = "inside";
2612 }
2613 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002614 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2615 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002616 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002617 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002618 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002619
sewardj16748af2002-10-22 04:55:54 +00002620 VG_(pp_ExeContext)(ai->lastchange);
2621 break;
2622 }
2623 default:
njn67993252004-11-22 18:02:32 +00002624 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002625 }
njn25e49d8e72002-09-23 09:36:25 +00002626}
2627
sewardj4bffb232002-11-13 21:46:34 +00002628static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002629{
sewardjff2c9232002-11-13 21:44:39 +00002630 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002631 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002632
sewardj4bffb232002-11-13 21:46:34 +00002633 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2634 lockset->setsize * 120 +
2635 1);
sewardjff2c9232002-11-13 21:44:39 +00002636
2637 cp = buf;
2638 if (prefix)
2639 cp += VG_(sprintf)(cp, "%s", prefix);
2640
sewardj4bffb232002-11-13 21:46:34 +00002641 for(i = 0; i < lockset->setsize; i++)
2642 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2643 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002644
sewardj4bffb232002-11-13 21:46:34 +00002645 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002646 cp[-2] = '\0';
2647 else
2648 *cp = '\0';
2649
2650 return buf;
2651}
njn25e49d8e72002-09-23 09:36:25 +00002652
njn51d827b2005-05-09 01:02:08 +00002653static void hg_pp_Error ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002654{
njn810086f2002-11-14 12:42:47 +00002655 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002656 Char buf[100];
2657 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002658 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002659
2660 *msg = '\0';
2661
njn810086f2002-11-14 12:42:47 +00002662 switch(VG_(get_error_kind)(err)) {
njnfbdcba92005-05-09 01:23:49 +00002663 case RaceErr: {
njn810086f2002-11-14 12:42:47 +00002664 Addr err_addr = VG_(get_error_address)(err);
2665
sewardj16748af2002-10-22 04:55:54 +00002666 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002667 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002668 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002669 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002670
2671 switch(extra->prevstate.state) {
2672 case Vge_Virgin:
2673 /* shouldn't be possible to go directly from virgin -> error */
2674 VG_(sprintf)(buf, "virgin!?");
2675 break;
2676
sewardjc4a810d2002-11-13 22:25:51 +00002677 case Vge_Excl: {
2678 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2679
njnca82cc02004-11-22 17:18:48 +00002680 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002681 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002682 break;
sewardjc4a810d2002-11-13 22:25:51 +00002683 }
sewardj16748af2002-10-22 04:55:54 +00002684
2685 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002686 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002687 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002688
2689 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002690 VG_(sprintf)(buf, "shared %s, no locks",
2691 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2692 break;
2693 }
2694
sewardjff2c9232002-11-13 21:44:39 +00002695 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2696 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002697 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002698
sewardj16748af2002-10-22 04:55:54 +00002699 break;
2700 }
sewardj16748af2002-10-22 04:55:54 +00002701
sewardj499e3de2002-11-13 22:22:25 +00002702 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002703 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002704
sewardj72baa7a2002-12-09 23:32:58 +00002705 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002706 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002707 Char file[100];
2708 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002709 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002710
nethercote3b390c72003-11-13 17:53:43 +00002711 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002712 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002713 pp_state(extra->lasttouched.state),
2714 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002715
nethercoteca788ff2004-10-20 10:58:09 +00002716 if (VG_(get_filename_linenum)(ip, file, sizeof(file), &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002717 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002718 ip, ip, file, line);
2719 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002720 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002721 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002722 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002723 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002724 }
sewardj72baa7a2002-12-09 23:32:58 +00002725 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002726 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002727 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002728 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002729 pp_state(extra->lasttouched.state),
2730 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002731 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002732 }
sewardj16748af2002-10-22 04:55:54 +00002733 break;
njn810086f2002-11-14 12:42:47 +00002734 }
sewardj16748af2002-10-22 04:55:54 +00002735
2736 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002737 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002738 VG_(get_error_address)(err),
2739 VG_(get_error_address)(err),
2740 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002741 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002742 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002743 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002744 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002745 }
njn810086f2002-11-14 12:42:47 +00002746 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002747 break;
sewardjff2c9232002-11-13 21:44:39 +00002748
2749 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002750 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002751 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002752 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002753
2754 msg = lockset_str(NULL, heldset);
2755
2756 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002757 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002758 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002759 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2760
sewardj4bffb232002-11-13 21:46:34 +00002761 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002762 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002763
sewardj542494b2002-11-13 22:46:13 +00002764 /* needs to be a recursive search+display */
2765 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002766 continue;
2767
nethercote3b390c72003-11-13 17:53:43 +00002768 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002769 lsmx->mutexp, lsmx->mutexp);
2770 VG_(pp_ExeContext)(lsmx->location);
2771 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002772 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002773 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002774 }
2775
2776 break;
sewardj16748af2002-10-22 04:55:54 +00002777 }
sewardjff2c9232002-11-13 21:44:39 +00002778 }
2779
2780 if (msg != buf)
2781 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002782}
2783
2784
njn51d827b2005-05-09 01:02:08 +00002785static Bool hg_recognised_suppression ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002786{
2787 if (0 == VG_(strcmp)(name, "Eraser")) {
njnfbdcba92005-05-09 01:23:49 +00002788 VG_(set_supp_kind)(su, RaceSupp);
njn25e49d8e72002-09-23 09:36:25 +00002789 return True;
2790 } else {
2791 return False;
2792 }
2793}
2794
2795
njn51d827b2005-05-09 01:02:08 +00002796static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002797{
2798 /* do nothing -- no extra suppression info present. Return True to
2799 indicate nothing bad happened. */
2800 return True;
2801}
2802
2803
njn51d827b2005-05-09 01:02:08 +00002804static Bool hg_error_matches_suppression(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002805{
njnfbdcba92005-05-09 01:23:49 +00002806 tl_assert(VG_(get_supp_kind)(su) == RaceSupp);
nethercote64366b42003-12-01 13:11:47 +00002807
njnfbdcba92005-05-09 01:23:49 +00002808 return (VG_(get_error_kind)(err) == RaceErr);
njn25e49d8e72002-09-23 09:36:25 +00002809}
2810
njn51d827b2005-05-09 01:02:08 +00002811static Char* hg_get_error_name ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002812{
njnfbdcba92005-05-09 01:23:49 +00002813 if (RaceErr == VG_(get_error_kind)(err)) {
2814 return "Eraser"; // old name, required for backwards compatibility
njn43c799e2003-04-08 00:08:52 +00002815 } else {
2816 return NULL; /* Other errors types can't be suppressed */
2817 }
2818}
2819
njn51d827b2005-05-09 01:02:08 +00002820static void hg_print_extra_suppression_info ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002821{
2822 /* Do nothing */
2823}
njn25e49d8e72002-09-23 09:36:25 +00002824
njnfbdcba92005-05-09 01:23:49 +00002825static void hg_pre_mutex_lock(ThreadId tid, void* void_mutex)
sewardjdca84112002-11-13 22:29:34 +00002826{
2827 Mutex *mutex = get_mutex((Addr)void_mutex);
2828
njn72718642003-07-24 08:45:32 +00002829 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002830}
2831
njnfbdcba92005-05-09 01:23:49 +00002832static void hg_post_mutex_lock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002833{
sewardj4bffb232002-11-13 21:46:34 +00002834 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002835 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002836 const LockSet* ls;
2837
njn72718642003-07-24 08:45:32 +00002838 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002839
njn25e49d8e72002-09-23 09:36:25 +00002840# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002841 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002842# endif
2843
njn25e49d8e72002-09-23 09:36:25 +00002844 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2845# if LOCKSET_SANITY > 1
njnfbdcba92005-05-09 01:23:49 +00002846 sanity_check_locksets("hg_post_mutex_lock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002847# endif
2848
sewardj4bffb232002-11-13 21:46:34 +00002849 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002850
sewardj4bffb232002-11-13 21:46:34 +00002851 if (ls == NULL) {
2852 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2853 insert_LockSet(newset);
2854 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002855 }
sewardj4bffb232002-11-13 21:46:34 +00002856 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002857
sewardj4bffb232002-11-13 21:46:34 +00002858 if (debug || DEBUG_LOCKS)
2859 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002860
sewardj4bffb232002-11-13 21:46:34 +00002861 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002862 sanity_check_locksets("hg_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002863}
2864
2865
njnfbdcba92005-05-09 01:23:49 +00002866static void hg_post_mutex_unlock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002867{
sewardjc26cc252002-10-23 21:58:55 +00002868 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002869 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002870 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002871 const LockSet *ls;
2872
njn72718642003-07-24 08:45:32 +00002873 test_mutex_state(mutex, MxUnlocked, tid);
2874 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002875
sewardjdac0a442002-11-13 22:08:40 +00002876 if (!ismember(thread_locks[tid], mutex))
2877 return;
2878
sewardjc26cc252002-10-23 21:58:55 +00002879 if (debug || DEBUG_LOCKS)
2880 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002881
sewardjc26cc252002-10-23 21:58:55 +00002882 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002883 sanity_check_locksets("hg_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002884
sewardj4bffb232002-11-13 21:46:34 +00002885 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002886
sewardj4bffb232002-11-13 21:46:34 +00002887 if (ls == NULL) {
2888 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2889 insert_LockSet(newset);
2890 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002891 }
2892
2893 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002894 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002895 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002896 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002897
sewardj4bffb232002-11-13 21:46:34 +00002898 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002899
sewardjc26cc252002-10-23 21:58:55 +00002900 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002901 sanity_check_locksets("hg_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002902}
2903
2904
2905/* ---------------------------------------------------------------------
2906 Checking memory reads and writes
2907 ------------------------------------------------------------------ */
2908
2909/* Behaviour on reads and writes:
2910 *
2911 * VIR EXCL SHAR SH_MOD
2912 * ----------------------------------------------------------------
2913 * rd/wr, 1st thread | - EXCL - -
2914 * rd, new thread | - SHAR - -
2915 * wr, new thread | - SH_MOD - -
2916 * rd | error! - SHAR SH_MOD
2917 * wr | EXCL - SH_MOD SH_MOD
2918 * ----------------------------------------------------------------
2919 */
2920
sewardj8fac99a2002-11-13 22:31:26 +00002921static inline
njn25e49d8e72002-09-23 09:36:25 +00002922void dump_around_a(Addr a)
2923{
2924 UInt i;
2925 shadow_word* sword;
2926 VG_(printf)("NEARBY:\n");
2927 for (i = a - 12; i <= a + 12; i += 4) {
2928 sword = get_sword_addr(i);
2929 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2930 }
2931}
njn25e49d8e72002-09-23 09:36:25 +00002932
2933#if DEBUG_ACCESSES
2934 #define DEBUG_STATE(args...) \
2935 VG_(printf)("(%u) ", size), \
2936 VG_(printf)(args)
2937#else
2938 #define DEBUG_STATE(args...)
2939#endif
2940
njnfbdcba92005-05-09 01:23:49 +00002941static void hg_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002942{
sewardj72baa7a2002-12-09 23:32:58 +00002943 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002944 shadow_word prevstate;
2945 ThreadLifeSeg *tls;
2946 const LockSet *ls;
2947 Bool statechange = False;
2948
2949 static const void *const states[4] = {
2950 [Vge_Virgin] &&st_virgin,
2951 [Vge_Excl] &&st_excl,
2952 [Vge_Shar] &&st_shar,
2953 [Vge_SharMod] &&st_sharmod,
2954 };
2955
2956 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002957 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002958
2959 sword = get_sword_addr(a);
2960 if (sword == SEC_MAP_ACCESS) {
2961 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2962 return;
2963 }
2964
2965 prevstate = *sword;
2966
2967 goto *states[sword->state];
2968
2969 /* This looks like reading of unitialised memory, may be legit. Eg.
2970 * calloc() zeroes its values, so untouched memory may actually be
2971 * initialised. Leave that stuff to Valgrind. */
2972 st_virgin:
2973 if (TID_INDICATING_NONVIRGIN == sword->other) {
2974 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
2975 if (DEBUG_VIRGIN_READS)
2976 dump_around_a(a);
2977 } else {
2978 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
2979 }
2980 statechange = True;
2981 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
2982 tls->refcount++;
2983 goto done;
2984
2985 st_excl: {
2986 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
2987
2988 if (tls == sw_tls) {
2989 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
2990 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
2991 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
2992 } else if (tlsIsDisjoint(tls, sw_tls)) {
2993 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
2994 statechange = True;
2995 sword->other = packTLS(tls);
2996 sw_tls->refcount--;
2997 tls->refcount++;
2998 } else {
2999 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3000 sw_tls->refcount--;
3001 statechange = True;
3002 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3003
3004 if (DEBUG_MEM_LOCKSET_CHANGES)
3005 print_LockSet("excl read locks", unpackLockSet(sword->other));
3006 }
3007 goto done;
3008 }
3009
3010 st_shar:
3011 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3012 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3013 thread_locks[tid]));
3014 statechange = sword->other != prevstate.other;
3015 goto done;
3016
3017 st_sharmod:
3018 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3019 ls = intersect(unpackLockSet(sword->other),
3020 thread_locks[tid]);
3021 sword->other = packLockSet(ls);
3022
3023 statechange = sword->other != prevstate.other;
3024
3025 if (isempty(ls)) {
njnfbdcba92005-05-09 01:23:49 +00003026 record_race_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003027 }
3028 goto done;
3029
3030 done:
3031 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003032 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003033
3034 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003035 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003036 else
njnd01fef72005-03-25 23:35:48 +00003037 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003038 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003039 }
3040}
njn25e49d8e72002-09-23 09:36:25 +00003041
njnfbdcba92005-05-09 01:23:49 +00003042static void hg_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003043{
njn72718642003-07-24 08:45:32 +00003044 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003045
sewardj8fac99a2002-11-13 22:31:26 +00003046 end = ROUNDUP(a+size, 4);
3047 a = ROUNDDN(a, 4);
3048
sewardj18cd4a52002-11-13 22:37:41 +00003049 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003050 hg_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003051}
3052
njnfbdcba92005-05-09 01:23:49 +00003053static void hg_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003054{
3055 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003056 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003057 shadow_word prevstate;
3058 Bool statechange = False;
3059 static const void *const states[4] = {
3060 [Vge_Virgin] &&st_virgin,
3061 [Vge_Excl] &&st_excl,
3062 [Vge_Shar] &&st_shar,
3063 [Vge_SharMod] &&st_sharmod,
3064 };
3065
sewardjc4a810d2002-11-13 22:25:51 +00003066 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003067 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003068
sewardj18cd4a52002-11-13 22:37:41 +00003069 sword = get_sword_addr(a);
3070 if (sword == SEC_MAP_ACCESS) {
3071 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3072 return;
3073 }
njn25e49d8e72002-09-23 09:36:25 +00003074
sewardj18cd4a52002-11-13 22:37:41 +00003075 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003076
sewardj18cd4a52002-11-13 22:37:41 +00003077 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003078
sewardj18cd4a52002-11-13 22:37:41 +00003079 st_virgin:
3080 if (TID_INDICATING_NONVIRGIN == sword->other)
3081 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3082 else
3083 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3084 statechange = True;
3085 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3086 tls->refcount++;
3087 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003088
sewardj18cd4a52002-11-13 22:37:41 +00003089 st_excl: {
3090 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3091
3092 if (tls == sw_tls) {
3093 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3094 goto done;
3095 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3096 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3097 goto done;
3098 } else if (tlsIsDisjoint(tls, sw_tls)) {
3099 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3100 sword->other = packTLS(tls);
3101 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003102 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003103 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003104 } else {
3105 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3106 statechange = True;
3107 sw_tls->refcount--;
3108 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3109 if(DEBUG_MEM_LOCKSET_CHANGES)
3110 print_LockSet("excl write locks", unpackLockSet(sword->other));
3111 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003112 }
sewardj18cd4a52002-11-13 22:37:41 +00003113 }
njn25e49d8e72002-09-23 09:36:25 +00003114
sewardj18cd4a52002-11-13 22:37:41 +00003115 st_shar:
3116 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3117 sword->state = Vge_SharMod;
3118 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3119 thread_locks[tid]));
3120 statechange = True;
3121 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003122
sewardj18cd4a52002-11-13 22:37:41 +00003123 st_sharmod:
3124 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3125 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3126 thread_locks[tid]));
3127 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003128
sewardj18cd4a52002-11-13 22:37:41 +00003129 SHARED_MODIFIED:
3130 if (isempty(unpackLockSet(sword->other))) {
njnfbdcba92005-05-09 01:23:49 +00003131 record_race_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003132 }
3133 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003134
sewardj18cd4a52002-11-13 22:37:41 +00003135 done:
3136 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003137 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003138
sewardj18cd4a52002-11-13 22:37:41 +00003139 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003140 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003141 else
njnd01fef72005-03-25 23:35:48 +00003142 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003143 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003144 }
3145}
3146
njnfbdcba92005-05-09 01:23:49 +00003147static void hg_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003148{
sewardj8fac99a2002-11-13 22:31:26 +00003149 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003150
sewardj8fac99a2002-11-13 22:31:26 +00003151 end = ROUNDUP(a+size, 4);
3152 a = ROUNDDN(a, 4);
3153
sewardj18cd4a52002-11-13 22:37:41 +00003154 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003155 hg_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003156}
3157
3158#undef DEBUG_STATE
3159
njnfbdcba92005-05-09 01:23:49 +00003160VGA_REGPARM(1) static void hg_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003161{
njnfbdcba92005-05-09 01:23:49 +00003162 hg_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003163}
3164
njnfbdcba92005-05-09 01:23:49 +00003165VGA_REGPARM(1) static void hg_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003166{
njnfbdcba92005-05-09 01:23:49 +00003167 hg_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003168}
3169
njnfbdcba92005-05-09 01:23:49 +00003170VGA_REGPARM(1) static void hg_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003171{
njnfbdcba92005-05-09 01:23:49 +00003172 hg_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003173}
3174
njnfbdcba92005-05-09 01:23:49 +00003175VGA_REGPARM(2) static void hg_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003176{
njnfbdcba92005-05-09 01:23:49 +00003177 hg_mem_read(a, size, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003178}
3179
njnfbdcba92005-05-09 01:23:49 +00003180VGA_REGPARM(2) static void hg_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003181{
3182 if (*(UChar *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003183 hg_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003184}
njnfbdcba92005-05-09 01:23:49 +00003185VGA_REGPARM(2) static void hg_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003186{
3187 if (*(UShort *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003188 hg_mem_write(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003189}
njnfbdcba92005-05-09 01:23:49 +00003190VGA_REGPARM(2) static void hg_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003191{
3192 if (*(UInt *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003193 hg_mem_write(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003194}
njnfbdcba92005-05-09 01:23:49 +00003195VGA_REGPARM(2) static void hg_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003196{
njnfbdcba92005-05-09 01:23:49 +00003197 hg_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003198}
njn25e49d8e72002-09-23 09:36:25 +00003199
sewardjc4a810d2002-11-13 22:25:51 +00003200static void hg_thread_create(ThreadId parent, ThreadId child)
3201{
3202 if (0)
3203 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3204
3205 newTLS(child);
3206 addPriorTLS(child, parent);
3207
3208 newTLS(parent);
3209}
3210
3211static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3212{
3213 if (0)
3214 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3215
3216 newTLS(joiner);
3217 addPriorTLS(joiner, joinee);
3218
3219 clearTLS(joinee);
3220}
3221
sewardj7a5ebcf2002-11-13 22:42:13 +00003222static Int __BUS_HARDWARE_LOCK__;
3223
3224static void bus_lock(void)
3225{
njn95e65f62005-03-30 04:13:56 +00003226 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003227 hg_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3228 hg_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003229}
3230
3231static void bus_unlock(void)
3232{
njn95e65f62005-03-30 04:13:56 +00003233 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003234 hg_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003235}
3236
njn25e49d8e72002-09-23 09:36:25 +00003237/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003238/*--- Client requests ---*/
3239/*--------------------------------------------------------------------*/
3240
njn51d827b2005-05-09 01:02:08 +00003241static Bool hg_handle_client_request(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003242{
njnfc26ff92004-11-22 19:12:49 +00003243 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003244 return False;
3245
3246 switch(args[0]) {
3247 case VG_USERREQ__HG_CLEAN_MEMORY:
3248 set_address_range_state(args[1], args[2], Vge_VirginInit);
3249 *ret = 0; /* meaningless */
3250 break;
3251
3252 case VG_USERREQ__HG_KNOWN_RACE:
3253 set_address_range_state(args[1], args[2], Vge_Error);
3254 *ret = 0; /* meaningless */
3255 break;
3256
3257 default:
3258 return False;
3259 }
3260
3261 return True;
3262}
3263
3264
3265/*--------------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00003266/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00003267/*--------------------------------------------------------------------*/
3268
njn51d827b2005-05-09 01:02:08 +00003269static Bool hg_process_cmd_line_option(Char* arg)
3270{
3271 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3272 clo_execontext = EC_None;
3273 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3274 clo_execontext = EC_Some;
3275 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3276 clo_execontext = EC_All;
3277
3278 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
3279
3280 else
3281 return VG_(replacement_malloc_process_cmd_line_option)(arg);
3282
3283 return True;
3284}
3285
3286static void hg_print_usage(void)
3287{
3288 VG_(printf)(
3289" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3290" --show-last-access=no|some|all\n"
3291" show location of last word access on error [no]\n"
3292 );
3293 VG_(replacement_malloc_print_usage)();
3294}
3295
3296static void hg_print_debug_usage(void)
3297{
3298 VG_(replacement_malloc_print_debug_usage)();
3299}
3300
3301static void hg_post_clo_init(void)
3302{
3303 void (*stack_tracker)(Addr a, SizeT len);
3304
3305 if (clo_execontext) {
3306 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3307 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3308 }
3309
3310 if (clo_priv_stacks)
njnfbdcba92005-05-09 01:23:49 +00003311 stack_tracker = & hg_new_mem_stack_private;
njn51d827b2005-05-09 01:02:08 +00003312 else
njnfbdcba92005-05-09 01:23:49 +00003313 stack_tracker = & hg_new_mem_stack;
njn51d827b2005-05-09 01:02:08 +00003314
3315 VG_(track_new_mem_stack) (stack_tracker);
3316 VG_(track_new_mem_stack_signal) (stack_tracker);
3317}
3318
3319
3320static void hg_fini(Int exitcode)
3321{
3322 if (DEBUG_LOCK_TABLE) {
3323 pp_all_LockSets();
3324 pp_all_mutexes();
3325 }
3326
3327 if (LOCKSET_SANITY)
3328 sanity_check_locksets("hg_fini");
3329
3330 if (VG_(clo_verbosity) > 0)
3331 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
njnfbdcba92005-05-09 01:23:49 +00003332 n_hg_warnings, n_lockorder_warnings);
njn51d827b2005-05-09 01:02:08 +00003333
3334 if (0)
3335 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3336 stk_ld, stk_st, stk_ld + stk_st,
3337 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3338 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
3339}
3340
3341static void hg_pre_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00003342{
3343 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003344 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003345
njn810086f2002-11-14 12:42:47 +00003346 VG_(details_name) ("Helgrind");
3347 VG_(details_version) (NULL);
3348 VG_(details_description) ("a data race detector");
3349 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +00003350 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003351 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003352 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003353
njn51d827b2005-05-09 01:02:08 +00003354 VG_(basic_tool_funcs) (hg_post_clo_init,
3355 hg_instrument,
3356 hg_fini);
tomc756a8e2005-03-31 07:59:35 +00003357
3358 VG_(needs_core_errors) ();
njn51d827b2005-05-09 01:02:08 +00003359 VG_(needs_tool_errors) (hg_eq_Error,
3360 hg_pp_Error,
3361 hg_update_extra,
3362 hg_recognised_suppression,
3363 hg_read_extra_suppression_info,
3364 hg_error_matches_suppression,
3365 hg_get_error_name,
3366 hg_print_extra_suppression_info);
tomc756a8e2005-03-31 07:59:35 +00003367 VG_(needs_data_syms) ();
njn51d827b2005-05-09 01:02:08 +00003368 VG_(needs_client_requests) (hg_handle_client_request);
3369 VG_(needs_sanity_checks) (hg_cheap_sanity_check,
3370 hg_expensive_sanity_check);
3371 VG_(needs_command_line_options)(hg_process_cmd_line_option,
3372 hg_print_usage,
3373 hg_print_debug_usage);
tomc756a8e2005-03-31 07:59:35 +00003374 VG_(needs_shadow_memory) ();
3375
njn51d827b2005-05-09 01:02:08 +00003376 VG_(malloc_funcs) (hg_malloc,
3377 hg___builtin_new,
3378 hg___builtin_vec_new,
3379 hg_memalign,
3380 hg_calloc,
3381 hg_free,
3382 hg___builtin_delete,
3383 hg___builtin_vec_delete,
3384 hg_realloc,
tomc756a8e2005-03-31 07:59:35 +00003385 8 );
njn25e49d8e72002-09-23 09:36:25 +00003386
njnfbdcba92005-05-09 01:23:49 +00003387 VG_(track_new_mem_startup) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003388
njn51d827b2005-05-09 01:02:08 +00003389 /* stack ones not decided until hg_post_clo_init() */
njn25e49d8e72002-09-23 09:36:25 +00003390
njn51d827b2005-05-09 01:02:08 +00003391 VG_(track_new_mem_brk) (& make_writable);
njnfbdcba92005-05-09 01:23:49 +00003392 VG_(track_new_mem_mmap) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003393
njnfbdcba92005-05-09 01:23:49 +00003394 VG_(track_change_mem_mprotect) (& hg_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003395
njn51d827b2005-05-09 01:02:08 +00003396 VG_(track_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003397
njn51d827b2005-05-09 01:02:08 +00003398 VG_(track_die_mem_stack) (NULL);
3399 VG_(track_die_mem_stack_signal)(NULL);
3400 VG_(track_die_mem_brk) (NULL);
3401 VG_(track_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003402
njnfbdcba92005-05-09 01:23:49 +00003403 VG_(track_pre_mem_read) (& hg_pre_mem_read);
3404 VG_(track_pre_mem_read_asciiz) (& hg_pre_mem_read_asciiz);
3405 VG_(track_pre_mem_write) (& hg_pre_mem_write);
njn51d827b2005-05-09 01:02:08 +00003406 VG_(track_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003407
njn51d827b2005-05-09 01:02:08 +00003408 VG_(track_post_thread_create) (& hg_thread_create);
3409 VG_(track_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003410
njnfbdcba92005-05-09 01:23:49 +00003411 VG_(track_pre_mutex_lock) (& hg_pre_mutex_lock);
3412 VG_(track_post_mutex_lock) (& hg_post_mutex_lock);
3413 VG_(track_post_mutex_unlock) (& hg_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003414
njn14d01ce2004-11-26 11:30:14 +00003415 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003416 lockset_hash[i] = NULL;
3417
3418 empty = alloc_LockSet(0);
3419 insert_LockSet(empty);
3420 emptyset = empty;
3421
sewardjc4a810d2002-11-13 22:25:51 +00003422 /* Init lock table and thread segments */
3423 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003424 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003425
sewardjc4a810d2002-11-13 22:25:51 +00003426 newTLS(i);
3427 }
3428
njn25e49d8e72002-09-23 09:36:25 +00003429 init_shadow_memory();
njn3e884182003-04-15 13:03:23 +00003430 hg_malloc_list = VG_(HT_construct)();
njn25e49d8e72002-09-23 09:36:25 +00003431}
3432
fitzhardinge98abfc72003-12-16 02:05:15 +00003433/* Uses a 1:1 mapping */
njn51d827b2005-05-09 01:02:08 +00003434VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init, 1.0)
fitzhardinge98abfc72003-12-16 02:05:15 +00003435
njn25e49d8e72002-09-23 09:36:25 +00003436/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003437/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003438/*--------------------------------------------------------------------*/