blob: 09f22527bc41bfdd09a59463dba513c6195e9030 [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"
njn81c00df2005-05-14 21:28:43 +000033#include "pub_tool_hashtable.h"
njn717cde52005-05-10 02:47:21 +000034#include "pub_tool_mallocfree.h"
35#include "pub_tool_replacemalloc.h"
njn43b9a8a2005-05-10 04:37:01 +000036#include "pub_tool_tooliface.h"
njn717cde52005-05-10 02:47:21 +000037
sewardj7f3ad222002-11-13 22:11:53 +000038#include "helgrind.h"
njn25e49d8e72002-09-23 09:36:25 +000039
njnfbdcba92005-05-09 01:23:49 +000040static UInt n_hg_warnings = 0;
sewardjff2c9232002-11-13 21:44:39 +000041static UInt n_lockorder_warnings = 0;
njn25e49d8e72002-09-23 09:36:25 +000042
43/*------------------------------------------------------------*/
44/*--- Debug guff ---*/
45/*------------------------------------------------------------*/
46
sewardje11d6c82002-12-15 02:00:41 +000047#define DEBUG_LOCK_TABLE 0 /* Print lock table at end */
njn25e49d8e72002-09-23 09:36:25 +000048
49#define DEBUG_MAKE_ACCESSES 0 /* Print make_access() calls */
50#define DEBUG_LOCKS 0 /* Print lock()/unlock() calls and locksets */
51#define DEBUG_NEW_LOCKSETS 0 /* Print new locksets when created */
52#define DEBUG_ACCESSES 0 /* Print reads, writes */
53#define DEBUG_MEM_LOCKSET_CHANGES 0
54 /* Print when an address's lockset
55 changes; only useful with
56 DEBUG_ACCESSES */
sewardj8fac99a2002-11-13 22:31:26 +000057#define SLOW_ASSERTS 0 /* do expensive asserts */
njn25e49d8e72002-09-23 09:36:25 +000058#define DEBUG_VIRGIN_READS 0 /* Dump around address on VIRGIN reads */
59
sewardj8fac99a2002-11-13 22:31:26 +000060#if SLOW_ASSERTS
njn94065fd2004-11-22 19:26:27 +000061#define TL_ASSERT(x) tl_assert(x)
sewardj8fac99a2002-11-13 22:31:26 +000062#else
njn94065fd2004-11-22 19:26:27 +000063#define TL_ASSERT(x)
sewardj8fac99a2002-11-13 22:31:26 +000064#endif
65
njn25e49d8e72002-09-23 09:36:25 +000066/* heavyweight LockSet sanity checking:
67 0 == never
68 1 == after important ops
69 2 == As 1 and also after pthread_mutex_* ops (excessively slow)
70 */
71#define LOCKSET_SANITY 0
72
sewardj8fac99a2002-11-13 22:31:26 +000073/* Rotate an unsigned quantity left */
74#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x)*8)-(n))))
75
76/* round a up to the next multiple of N. N must be a power of 2 */
77#define ROUNDUP(a, N) ((a + N - 1) & ~(N-1))
78
79/* Round a down to the next multiple of N. N must be a power of 2 */
80#define ROUNDDN(a, N) ((a) & ~(N-1))
njn25e49d8e72002-09-23 09:36:25 +000081
82/*------------------------------------------------------------*/
sewardjf6374322002-11-13 22:35:55 +000083/*--- Command line options ---*/
84/*------------------------------------------------------------*/
85
86static enum {
87 EC_None,
88 EC_Some,
89 EC_All
90} clo_execontext = EC_None;
91
sewardje1a39f42002-12-15 01:56:17 +000092static Bool clo_priv_stacks = False;
sewardjf6374322002-11-13 22:35:55 +000093
94/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000095/*--- Crude profiling machinery. ---*/
96/*------------------------------------------------------------*/
97
98// PPP: work out if I want this
99
100#define PROF_EVENT(x)
101#if 0
102#ifdef VG_PROFILE_MEMORY
103
104#define N_PROF_EVENTS 150
105
106static UInt event_ctr[N_PROF_EVENTS];
107
108void VGE_(done_prof_mem) ( void )
109{
110 Int i;
111 for (i = 0; i < N_PROF_EVENTS; i++) {
112 if ((i % 10) == 0)
113 VG_(printf)("\n");
114 if (event_ctr[i] > 0)
115 VG_(printf)( "prof mem event %2d: %d\n", i, event_ctr[i] );
116 }
117 VG_(printf)("\n");
118}
119
120#define PROF_EVENT(ev) \
njnca82cc02004-11-22 17:18:48 +0000121 do { tl_assert((ev) >= 0 && (ev) < N_PROF_EVENTS); \
njn25e49d8e72002-09-23 09:36:25 +0000122 event_ctr[ev]++; \
123 } while (False);
124
125#else
126
127//static void init_prof_mem ( void ) { }
128// void VG_(done_prof_mem) ( void ) { }
129
130#define PROF_EVENT(ev) /* */
131
132#endif /* VG_PROFILE_MEMORY */
133
134/* Event index. If just the name of the fn is given, this means the
135 number of calls to the fn. Otherwise it is the specified event.
136
137 [PPP: snip event numbers...]
138*/
139#endif /* 0 */
140
141
142/*------------------------------------------------------------*/
143/*--- Data defns. ---*/
144/*------------------------------------------------------------*/
145
njn3e884182003-04-15 13:03:23 +0000146typedef
147 struct _HG_Chunk {
148 struct _HG_Chunk* next;
149 Addr data; /* ptr to actual block */
nethercote928a5f72004-11-03 18:10:37 +0000150 SizeT size; /* size requested */
njn3e884182003-04-15 13:03:23 +0000151 ExeContext* where; /* where it was allocated */
152 ThreadId tid; /* allocating thread */
153 }
154 HG_Chunk;
155
njn25e49d8e72002-09-23 09:36:25 +0000156typedef enum
sewardj7f3ad222002-11-13 22:11:53 +0000157 { Vge_VirginInit, Vge_NonVirginInit, Vge_SegmentInit, Vge_Error }
njn25e49d8e72002-09-23 09:36:25 +0000158 VgeInitStatus;
159
sewardjc808ef52002-11-13 22:43:26 +0000160
njnc6168192004-11-29 13:54:10 +0000161// XXX: not 64-bit clean!
njn25e49d8e72002-09-23 09:36:25 +0000162/* Should add up to 32 to fit in one word */
163#define OTHER_BITS 30
164#define STATE_BITS 2
165
166#define ESEC_MAP_WORDS 16384 /* Words per secondary map */
167
168/* This is for indicating that a memory block has been initialised but not
169 * really directly by a particular thread... (eg. text/data initialised
170 * automatically at startup).
171 * Must be different to virgin_word.other */
172#define TID_INDICATING_NONVIRGIN 1
173
sewardjc4a810d2002-11-13 22:25:51 +0000174/* Magic packed TLS used for error suppression; if word state is Excl
175 and tid is this, then it means all access are OK without changing
176 state and without raising any more errors */
177#define TLSP_INDICATING_ALL ((1 << OTHER_BITS) - 1)
sewardj16748af2002-10-22 04:55:54 +0000178
njn25e49d8e72002-09-23 09:36:25 +0000179/* Number of entries must fit in STATE_BITS bits */
180typedef enum { Vge_Virgin, Vge_Excl, Vge_Shar, Vge_SharMod } pth_state;
181
sewardjc808ef52002-11-13 22:43:26 +0000182static inline const Char *pp_state(pth_state st)
183{
184 const Char *ret;
185
186 switch(st) {
187 case Vge_Virgin: ret = "virgin"; break;
188 case Vge_Excl: ret = "exclusive"; break;
189 case Vge_Shar: ret = "shared RO"; break;
190 case Vge_SharMod: ret = "shared RW"; break;
191 default: ret = "???";
192 }
193 return ret;
194}
195
njn25e49d8e72002-09-23 09:36:25 +0000196typedef
197 struct {
sewardj8fac99a2002-11-13 22:31:26 +0000198 /* gcc arranges this bitfield with state in the 2LSB and other
199 in the 30MSB, which is what we want */
njn25e49d8e72002-09-23 09:36:25 +0000200 UInt state:STATE_BITS;
sewardj8fac99a2002-11-13 22:31:26 +0000201 UInt other:OTHER_BITS;
njn25e49d8e72002-09-23 09:36:25 +0000202 } shadow_word;
203
sewardj8fac99a2002-11-13 22:31:26 +0000204#define SW(st, other) ((shadow_word) { st, other })
205
njn25e49d8e72002-09-23 09:36:25 +0000206typedef
207 struct {
208 shadow_word swords[ESEC_MAP_WORDS];
209 }
210 ESecMap;
211
212static ESecMap* primary_map[ 65536 ];
213static ESecMap distinguished_secondary_map;
214
sewardj8fac99a2002-11-13 22:31:26 +0000215static const shadow_word virgin_sword = SW(Vge_Virgin, 0);
216static const shadow_word error_sword = SW(Vge_Excl, TLSP_INDICATING_ALL);
njn25e49d8e72002-09-23 09:36:25 +0000217
218#define VGE_IS_DISTINGUISHED_SM(smap) \
219 ((smap) == &distinguished_secondary_map)
220
221#define ENSURE_MAPPABLE(addr,caller) \
222 do { \
223 if (VGE_IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
224 primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
225 /*VG_(printf)("new 2map because of %p\n", addr);*/ \
226 } \
227 } while(0)
228
229
sewardjc808ef52002-11-13 22:43:26 +0000230/* Parallel map which contains execution contexts when words last
231 changed state (if required) */
sewardj499e3de2002-11-13 22:22:25 +0000232
nethercoteca788ff2004-10-20 10:58:09 +0000233typedef struct EC_IP {
234 union u_ec_ip {
235 Addr ip;
sewardjc808ef52002-11-13 22:43:26 +0000236 ExeContext *ec;
nethercoteca788ff2004-10-20 10:58:09 +0000237 } uu_ec_ip;
sewardjc808ef52002-11-13 22:43:26 +0000238 UInt state:STATE_BITS;
239 UInt tls:OTHER_BITS; /* packed TLS */
nethercoteca788ff2004-10-20 10:58:09 +0000240} EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000241
nethercoteca788ff2004-10-20 10:58:09 +0000242#define NULL_EC_IP ((EC_IP){ { 0 }, 0, 0})
sewardjc808ef52002-11-13 22:43:26 +0000243
nethercoteca788ff2004-10-20 10:58:09 +0000244#define IP(ip, prev, tls) ((EC_IP) { (union u_ec_ip)(ip), (prev).state, packTLS(tls) })
245#define EC(ec, prev, tls) ((EC_IP) { (union u_ec_ip)(ec), (prev).state, packTLS(tls) })
sewardjc808ef52002-11-13 22:43:26 +0000246
247static inline UInt packEC(ExeContext *ec)
248{
njn94065fd2004-11-22 19:26:27 +0000249 TL_ASSERT(((UWord)ec & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000250 return ((UWord)ec) >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000251}
252
nethercoteca788ff2004-10-20 10:58:09 +0000253/* Lose 2 LSB of IP */
254static inline UInt packIP(Addr ip)
sewardjc808ef52002-11-13 22:43:26 +0000255{
nethercote50397c22004-11-04 18:03:06 +0000256 return ip >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000257}
258
nethercoteca788ff2004-10-20 10:58:09 +0000259static inline Addr unpackIP(UInt i)
sewardjc808ef52002-11-13 22:43:26 +0000260{
261 return (Addr)(i << STATE_BITS);
262}
sewardj499e3de2002-11-13 22:22:25 +0000263
264typedef struct {
nethercoteca788ff2004-10-20 10:58:09 +0000265 EC_IP execontext[ESEC_MAP_WORDS];
sewardj499e3de2002-11-13 22:22:25 +0000266} ExeContextMap;
267
268static ExeContextMap** execontext_map;
269
nethercoteca788ff2004-10-20 10:58:09 +0000270static inline void setExeContext(Addr a, EC_IP ec)
sewardj499e3de2002-11-13 22:22:25 +0000271{
272 UInt idx = (a >> 16) & 0xffff;
273 UInt off = (a >> 2) & 0x3fff;
274
275 if (execontext_map[idx] == NULL) {
276 execontext_map[idx] = VG_(malloc)(sizeof(ExeContextMap));
277 VG_(memset)(execontext_map[idx], 0, sizeof(ExeContextMap));
278 }
279
280 execontext_map[idx]->execontext[off] = ec;
281}
282
nethercoteca788ff2004-10-20 10:58:09 +0000283static inline EC_IP getExeContext(Addr a)
sewardj499e3de2002-11-13 22:22:25 +0000284{
285 UInt idx = (a >> 16) & 0xffff;
286 UInt off = (a >> 2) & 0x3fff;
nethercoteca788ff2004-10-20 10:58:09 +0000287 EC_IP ec = NULL_EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000288
289 if (execontext_map[idx] != NULL)
290 ec = execontext_map[idx]->execontext[off];
291
292 return ec;
293}
294
njn25e49d8e72002-09-23 09:36:25 +0000295/*------------------------------------------------------------*/
sewardjc4a810d2002-11-13 22:25:51 +0000296/*--- Thread lifetime segments ---*/
297/*------------------------------------------------------------*/
298
299/*
300 * This mechanism deals with the common case of a parent thread
301 * creating a structure for a child thread, and then passing ownership
302 * of the structure to that thread. It similarly copes with a child
303 * thread passing information back to another thread waiting to join
304 * on it.
305 *
306 * Each thread's lifetime can be partitioned into segments. Those
307 * segments are arranged to form an interference graph which indicates
308 * whether two thread lifetime segments can possibly be concurrent.
309 * If not, then memory with is exclusively accessed by one TLS can be
daywalker7e73e5f2003-07-04 16:18:15 +0000310 * passed on to another TLS without an error occurring, and without
sewardjc4a810d2002-11-13 22:25:51 +0000311 * moving it from Excl state.
312 *
313 * At present this only considers thread creation and join as
314 * synchronisation events for creating new lifetime segments, but
315 * others may be possible (like mutex operations).
316 */
317
318typedef struct _ThreadLifeSeg ThreadLifeSeg;
319
320struct _ThreadLifeSeg {
321 ThreadId tid;
322 ThreadLifeSeg *prior[2]; /* Previous lifetime segments */
323 UInt refcount; /* Number of memory locations pointing here */
324 UInt mark; /* mark used for graph traversal */
325 ThreadLifeSeg *next; /* list of all TLS */
326};
327
328static ThreadLifeSeg *all_tls;
329static UInt tls_since_gc;
330#define TLS_SINCE_GC 10000
331
332/* current mark used for TLS graph traversal */
333static UInt tlsmark;
334
335static ThreadLifeSeg *thread_seg[VG_N_THREADS];
336
337
338static void tls_gc(void)
339{
340 /* XXX later. Walk through all TLSs and look for ones with 0
341 refcount and remove them from the structure and free them.
342 Could probably get rid of ThreadLifeSeg.refcount and simply use
343 mark-sweep from the shadow table. */
344 VG_(printf)("WRITEME: TLS GC\n");
345}
346
347static void newTLS(ThreadId tid)
348{
349 static const Bool debug = False;
350 ThreadLifeSeg *tls;
351
352 /* Initial NULL */
353 if (thread_seg[tid] == NULL) {
354 tls = VG_(malloc)(sizeof(*tls));
355 tls->tid = tid;
356 tls->prior[0] = tls->prior[1] = NULL;
357 tls->refcount = 0;
358 tls->mark = tlsmark-1;
359
360 tls->next = all_tls;
361 all_tls = tls;
362 tls_since_gc++;
363
364 thread_seg[tid] = tls;
365 return;
366 }
367
368 /* Previous TLS was unused, so just recycle */
369 if (thread_seg[tid]->refcount == 0) {
370 if (debug)
371 VG_(printf)("newTLS; recycling TLS %p for tid %u\n",
372 thread_seg[tid], tid);
373 return;
374 }
375
376 /* Use existing TLS for this tid as a prior for new TLS */
377 tls = VG_(malloc)(sizeof(*tls));
378 tls->tid = tid;
379 tls->prior[0] = thread_seg[tid];
380 tls->prior[1] = NULL;
381 tls->refcount = 0;
382 tls->mark = tlsmark-1;
383
384 tls->next = all_tls;
385 all_tls = tls;
386 if (++tls_since_gc > TLS_SINCE_GC) {
387 tls_gc();
388 tls_since_gc = 0;
389 }
390
391 if (debug)
392 VG_(printf)("newTLS: made new TLS %p for tid %u (prior %p(%u))\n",
393 tls, tid, tls->prior[0], tls->prior[0]->tid);
394
395 thread_seg[tid] = tls;
396}
397
398/* clear out a TLS for a thread that's died */
399static void clearTLS(ThreadId tid)
400{
401 newTLS(tid);
402
403 thread_seg[tid]->prior[0] = NULL;
404 thread_seg[tid]->prior[1] = NULL;
405}
406
407static void addPriorTLS(ThreadId tid, ThreadId prior)
408{
409 static const Bool debug = False;
410 ThreadLifeSeg *tls = thread_seg[tid];
411
412 if (debug)
413 VG_(printf)("making TLS %p(%u) prior to TLS %p(%u)\n",
414 thread_seg[prior], prior, tls, tid);
415
njnca82cc02004-11-22 17:18:48 +0000416 tl_assert(thread_seg[tid] != NULL);
417 tl_assert(thread_seg[prior] != NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000418
419 if (tls->prior[0] == NULL)
420 tls->prior[0] = thread_seg[prior];
421 else {
njnca82cc02004-11-22 17:18:48 +0000422 tl_assert(tls->prior[1] == NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000423 tls->prior[1] = thread_seg[prior];
424 }
425}
426
njnfbdcba92005-05-09 01:23:49 +0000427static Bool isPrior(const ThreadLifeSeg *t, const ThreadLifeSeg *prior)
428{
429 if (t == NULL || t->mark == tlsmark)
430 return False;
431
432 if (t == prior)
433 return True;
434
435 ((ThreadLifeSeg *)t)->mark = tlsmark;
436
437 return isPrior(t->prior[0], prior) || isPrior(t->prior[1], prior);
438}
439
sewardjc4a810d2002-11-13 22:25:51 +0000440/* Return True if prior is definitely not concurrent with tls */
441static Bool tlsIsDisjoint(const ThreadLifeSeg *tls,
442 const ThreadLifeSeg *prior)
443{
sewardjc4a810d2002-11-13 22:25:51 +0000444 tlsmark++; /* new traversal mark */
445
njnfbdcba92005-05-09 01:23:49 +0000446 return isPrior(tls, prior);
sewardjc4a810d2002-11-13 22:25:51 +0000447}
448
449static inline UInt packTLS(ThreadLifeSeg *tls)
450{
njn94065fd2004-11-22 19:26:27 +0000451 TL_ASSERT(((UWord)tls & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000452 return ((UWord)tls) >> STATE_BITS;
sewardjc4a810d2002-11-13 22:25:51 +0000453}
454
455static inline ThreadLifeSeg *unpackTLS(UInt i)
456{
457 return (ThreadLifeSeg *)(i << STATE_BITS);
458}
459
460/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000461/*--- Low-level support for memory tracking. ---*/
462/*------------------------------------------------------------*/
463
464/*
465 All reads and writes are recorded in the memory map, which
466 records the state of all memory in the process. The memory map is
467 organised like that for normal Valgrind, except each that everything
468 is done at word-level instead of byte-level, and each word has only
469 one word of shadow (instead of 36 bits).
470
471 As for normal Valgrind there is a distinguished secondary map. But we're
472 working at word-granularity, so it has 16k word entries instead of 64k byte
473 entries. Lookup is done as follows:
474
475 bits 31..16: primary map lookup
476 bits 15.. 2: secondary map lookup
477 bits 1.. 0: ignored
478*/
479
480
481/*------------------------------------------------------------*/
482/*--- Basic bitmap management, reading and writing. ---*/
483/*------------------------------------------------------------*/
484
485/* Allocate and initialise a secondary map, marking all words as virgin. */
486
487/* Just a value that isn't a real pointer */
488#define SEC_MAP_ACCESS (shadow_word*)0x99
489
490
491static
492ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
493{
494 ESecMap* map;
495 UInt i;
496 //PROF_EVENT(10); PPP
497
nethercote1420ab22004-08-18 22:26:01 +0000498 // Mark all words as virgin.
fitzhardinge98abfc72003-12-16 02:05:15 +0000499 map = (ESecMap *)VG_(shadow_alloc)(sizeof(ESecMap));
njn25e49d8e72002-09-23 09:36:25 +0000500 for (i = 0; i < ESEC_MAP_WORDS; i++)
501 map->swords[i] = virgin_sword;
502
503 return map;
504}
505
506
507/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
508 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000509static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000510void set_sword ( Addr a, shadow_word sword )
511{
512 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000513 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000514
515 //PROF_EVENT(23); PPP
516 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
517
518 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
519 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000520 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000521 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
522 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
523 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
524 tls->refcount--;
525 }
526
527 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
528 ThreadLifeSeg *tls = unpackTLS(sword.other);
529 tls->refcount++;
530 }
531
njn25e49d8e72002-09-23 09:36:25 +0000532 sm->swords[(a & 0xFFFC) >> 2] = sword;
533
534 if (VGE_IS_DISTINGUISHED_SM(sm)) {
535 VG_(printf)("wrote to distinguished 2ndary map! 0x%x\n", a);
536 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000537 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000538 }
539}
540
541
542static __inline__
543shadow_word* get_sword_addr ( Addr a )
544{
545 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
546 ESecMap* sm = primary_map[a >> 16];
547 UInt sm_off = (a & 0xFFFC) >> 2;
548
549 if (VGE_IS_DISTINGUISHED_SM(sm)) {
550 VG_(printf)("accessed distinguished 2ndary map! 0x%x\n", a);
551 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000552 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000553 return SEC_MAP_ACCESS;
554 }
555
556 //PROF_EVENT(21); PPP
557 return & (sm->swords[sm_off]);
558}
559
560
561// SSS: rename these so they're not so similar to memcheck, unless it's
562// appropriate of course
563
564static __inline__
565void init_virgin_sword(Addr a)
566{
sewardj499e3de2002-11-13 22:22:25 +0000567 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000568 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000569 set_sword(a, virgin_sword);
570}
571
sewardj7f3ad222002-11-13 22:11:53 +0000572static __inline__
573void init_error_sword(Addr a)
574{
575 set_sword(a, error_sword);
576}
njn25e49d8e72002-09-23 09:36:25 +0000577
njn25e49d8e72002-09-23 09:36:25 +0000578static __inline__
579void init_nonvirgin_sword(Addr a)
580{
581 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000582 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000583 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000584
njn14d01ce2004-11-26 11:30:14 +0000585 // The tid must be passed in here now; this requires more events to be
586 // given the tid in the first place.
587 //
588 //tid = VG_(get_current_or_recent_tid)();
589 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
590 VG_(exit)(1);
591
njnca82cc02004-11-22 17:18:48 +0000592 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000593 tls = thread_seg[tid];
594
sewardj8fac99a2002-11-13 22:31:26 +0000595 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000596 set_sword(a, sword);
597}
598
599
njnfbdcba92005-05-09 01:23:49 +0000600/* In this case, we treat it for Helgrind's sake like virgin (it hasn't
njn25e49d8e72002-09-23 09:36:25 +0000601 * been inited by a particular thread, it's just done automatically upon
602 * startup), but we mark its .state specially so it doesn't look like an
603 * uninited read. */
604static __inline__
605void init_magically_inited_sword(Addr a)
606{
607 shadow_word sword;
608
sewardj8fac99a2002-11-13 22:31:26 +0000609 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
610
njn25e49d8e72002-09-23 09:36:25 +0000611 set_sword(a, virgin_sword);
612}
613
sewardjc26cc252002-10-23 21:58:55 +0000614
sewardj274c6012002-10-22 04:54:55 +0000615/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000616/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000617/*------------------------------------------------------------*/
618
sewardj39a4d842002-11-13 22:14:30 +0000619typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000620typedef struct _LockSet LockSet;
621
sewardj16748af2002-10-22 04:55:54 +0000622typedef enum MutexState {
623 MxUnknown, /* don't know */
624 MxUnlocked, /* unlocked */
625 MxLocked, /* locked */
626 MxDead /* destroyed */
627} MutexState;
628
sewardj39a4d842002-11-13 22:14:30 +0000629struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000630 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000631 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000632
633 MutexState state; /* mutex state */
634 ThreadId tid; /* owner */
635 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000636
sewardj4bffb232002-11-13 21:46:34 +0000637 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000638 UInt mark; /* mark for graph traversal */
639};
sewardj16748af2002-10-22 04:55:54 +0000640
sewardj39a4d842002-11-13 22:14:30 +0000641static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000642{
sewardjdac0a442002-11-13 22:08:40 +0000643 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000644}
njn25e49d8e72002-09-23 09:36:25 +0000645
sewardj274c6012002-10-22 04:54:55 +0000646struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000647 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000648 UInt hash; /* hash code */
649 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000650 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000651};
sewardj4bffb232002-11-13 21:46:34 +0000652
653static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000654
655/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000656static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000657
sewardjdac0a442002-11-13 22:08:40 +0000658#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000659
sewardj4bffb232002-11-13 21:46:34 +0000660static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000661
sewardj4bffb232002-11-13 21:46:34 +0000662/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000663static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000664{
sewardj4bffb232002-11-13 21:46:34 +0000665 UInt id;
666
njn94065fd2004-11-22 19:26:27 +0000667 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000668 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000669
670 return id;
njn25e49d8e72002-09-23 09:36:25 +0000671}
672
sewardj8fac99a2002-11-13 22:31:26 +0000673static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000674{
sewardj4bffb232002-11-13 21:46:34 +0000675 return (LockSet *)(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000676}
677
njn25e49d8e72002-09-23 09:36:25 +0000678static
sewardj4bffb232002-11-13 21:46:34 +0000679void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000680{
sewardj05bcdcb2003-05-18 10:05:38 +0000681 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000682 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000683 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000684 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000685
686 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000687 }
688 VG_(printf)("}\n");
689}
690
691
sewardj4bffb232002-11-13 21:46:34 +0000692static void print_LockSet(const Char *s, const LockSet *ls)
693{
694 VG_(printf)("%s: ", s);
695 pp_LockSet(ls);
696}
697
698/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000699static UInt hash_LockSet_w_wo(const LockSet *ls,
700 const Mutex *with,
701 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000702{
sewardj05bcdcb2003-05-18 10:05:38 +0000703 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000704 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000705
njnca82cc02004-11-22 17:18:48 +0000706 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000707
708 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000709 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000710
711 if (without && mutex_cmp(without, mx) == 0)
712 continue;
713
714 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
715 mx = with;
716 with = NULL;
717 i--;
718 }
719
sewardj8fac99a2002-11-13 22:31:26 +0000720 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000721 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000722 }
723
724 return hash % LOCKSET_HASH_SZ;
725}
726
sewardj39a4d842002-11-13 22:14:30 +0000727static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000728{
729 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
730
731 if (0)
732 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
733
734 return hash;
735}
736
sewardj39a4d842002-11-13 22:14:30 +0000737static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000738{
739 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
740
741 if (0)
742 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
743
744 return hash;
745}
746
747static inline UInt hash_LockSet(const LockSet *ls)
748{
749 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
750
751 if (0)
752 VG_(printf)("hash %p -> %d\n", ls, hash);
753
754 return hash;
755}
756
757static
758Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000759{
760 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000761
sewardj4bffb232002-11-13 21:46:34 +0000762 if (a == b)
763 return True;
764 if (a->setsize != b->setsize)
765 return False;
njn25e49d8e72002-09-23 09:36:25 +0000766
sewardj4bffb232002-11-13 21:46:34 +0000767 for(i = 0; i < a->setsize; i++) {
768 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000769 return False;
njn25e49d8e72002-09-23 09:36:25 +0000770 }
771
sewardj4bffb232002-11-13 21:46:34 +0000772 return True;
njn25e49d8e72002-09-23 09:36:25 +0000773}
774
775
776/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
777 * doesn't do the insertion. Returns True if they match.
778 */
779static Bool
sewardj4bffb232002-11-13 21:46:34 +0000780weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000781 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000782{
sewardjc26cc252002-10-23 21:58:55 +0000783 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000784 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000785
njn25e49d8e72002-09-23 09:36:25 +0000786 /* Idea is to try and match each element of b against either an
787 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000788
789 if (debug) {
790 print_LockSet("weird_LockSet_equals a", a);
791 print_LockSet(" b", b);
792 VG_(printf)( " missing: %p%(y\n",
793 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000794 }
sewardjc26cc252002-10-23 21:58:55 +0000795
sewardj4bffb232002-11-13 21:46:34 +0000796 if ((a->setsize + 1) != b->setsize) {
797 if (debug)
798 VG_(printf)(" fastpath length mismatch -> 0\n");
799 return False;
800 }
801
sewardjc26cc252002-10-23 21:58:55 +0000802 /* There are three phases to this compare:
803 1 the section from the start of a up to missing_mutex
804 2 missing mutex itself
805 3 the section after missing_mutex to the end of a
806 */
807
sewardj4bffb232002-11-13 21:46:34 +0000808 ia = 0;
809 ib = 0;
810
sewardjc26cc252002-10-23 21:58:55 +0000811 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000812 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000813 if (debug) {
814 print_LockSet(" 1:a", a);
815 print_LockSet(" 1:b", b);
816 }
sewardj4bffb232002-11-13 21:46:34 +0000817 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000818 return False;
sewardjc26cc252002-10-23 21:58:55 +0000819 }
820
821 /* 2: missing_mutex itself */
822 if (debug) {
823 VG_(printf)( " 2:missing: %p%(y\n",
824 missing_mutex->mutexp, missing_mutex->mutexp);
825 print_LockSet(" 2: b", b);
826 }
827
njnca82cc02004-11-22 17:18:48 +0000828 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000829
sewardj4bffb232002-11-13 21:46:34 +0000830 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000831 return False;
832
sewardj4bffb232002-11-13 21:46:34 +0000833 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000834
835 /* 3: after missing_mutex to end */
836
sewardj4bffb232002-11-13 21:46:34 +0000837 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000838 if (debug) {
839 print_LockSet(" 3:a", a);
840 print_LockSet(" 3:b", b);
841 }
sewardj4bffb232002-11-13 21:46:34 +0000842 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000843 return False;
sewardjc26cc252002-10-23 21:58:55 +0000844 }
845
846 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000847 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000848
sewardj4bffb232002-11-13 21:46:34 +0000849 return ia == a->setsize && ib == b->setsize;
850}
851
852
853
854static const LockSet *lookup_LockSet(const LockSet *set)
855{
856 UInt bucket = set->hash;
857 LockSet *ret;
858
859 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
860 if (set == ret || structural_eq_LockSet(set, ret))
861 return ret;
862
863 return NULL;
864}
865
sewardj39a4d842002-11-13 22:14:30 +0000866static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000867{
868 UInt bucket = hash_LockSet_with(set, mutex);
869 const LockSet *ret;
870
871 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
872 if (weird_LockSet_equals(set, ret, mutex))
873 return ret;
874
875 return NULL;
876}
877
sewardj39a4d842002-11-13 22:14:30 +0000878static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000879{
880 UInt bucket = hash_LockSet_without(set, mutex);
881 const LockSet *ret;
882
883 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
884 if (weird_LockSet_equals(ret, set, mutex))
885 return ret;
886
887 return NULL;
888}
889
890static void insert_LockSet(LockSet *set)
891{
892 UInt hash = hash_LockSet(set);
893
894 set->hash = hash;
895
njnca82cc02004-11-22 17:18:48 +0000896 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000897
898 set->next = lockset_hash[hash];
899 lockset_hash[hash] = set;
900}
901
902static inline
903LockSet *alloc_LockSet(UInt setsize)
904{
sewardj39a4d842002-11-13 22:14:30 +0000905 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000906 ret->setsize = setsize;
907 return ret;
908}
909
910static inline
911void free_LockSet(LockSet *p)
912{
913 /* assert: not present in hash */
914 VG_(free)(p);
915}
916
njnb4aee052003-04-15 14:09:58 +0000917static
sewardj4bffb232002-11-13 21:46:34 +0000918void pp_all_LockSets ( void )
919{
920 Int i;
921 Int sets, buckets;
922
923 sets = buckets = 0;
924 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
925 const LockSet *ls = lockset_hash[i];
926 Bool first = True;
927
sewardj4bffb232002-11-13 21:46:34 +0000928 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000929 if (first) {
930 buckets++;
931 VG_(printf)("[%4d] = ", i);
932 } else
933 VG_(printf)(" ");
934
sewardj4bffb232002-11-13 21:46:34 +0000935 sets++;
936 first = False;
937 pp_LockSet(ls);
938 }
939 }
940
941 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
942}
943
944static inline Bool isempty(const LockSet *ls)
945{
946 return ls == NULL || ls->setsize == 0;
947}
948
sewardj39a4d842002-11-13 22:14:30 +0000949static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000950{
951 Int i;
952
953 /* XXX use binary search */
954 for(i = 0; i < ls->setsize; i++)
955 if (mutex_cmp(mx, ls->mutex[i]) == 0)
956 return True;
957
958 return False;
959}
960
961/* Check invariants:
962 - all locksets are unique
963 - each set is an array in strictly increasing order of mutex addr
964*/
965static
966void sanity_check_locksets ( const Char* caller )
967{
968 Int i;
969 const Char *badness;
970 LockSet *ls;
971
972 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
973
974 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000975 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000976 Int j;
977
978 if (hash_LockSet(ls) != ls->hash) {
979 badness = "mismatched hash";
980 goto bad;
981 }
sewardj05bcdcb2003-05-18 10:05:38 +0000982 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +0000983 badness = "wrong bucket";
984 goto bad;
985 }
986 if (lookup_LockSet(ls) != ls) {
987 badness = "non-unique set";
988 goto bad;
989 }
990
991 prev = ls->mutex[0];
992 for(j = 1; j < ls->setsize; j++) {
993 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
994 badness = "mutexes out of order";
995 goto bad;
996 }
997 }
998 }
999 }
1000 return;
1001
1002 bad:
1003 VG_(printf)("sanity_check_locksets: "
1004 "i = %d, ls=%p badness = %s, caller = %s\n",
1005 i, ls, badness, caller);
1006 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001007 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001008}
1009
1010static
sewardj39a4d842002-11-13 22:14:30 +00001011LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001012{
1013 static const Bool debug = False;
1014 LockSet *ret = NULL;
1015 Int i, j;
1016
1017 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1018 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1019 print_LockSet("add-IN", ls);
1020 }
1021
1022 if (debug || LOCKSET_SANITY)
1023 sanity_check_locksets("add-IN");
1024
njnca82cc02004-11-22 17:18:48 +00001025 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001026
1027 ret = alloc_LockSet(ls->setsize+1);
1028
1029 for(i = j = 0; i < ls->setsize; i++) {
1030 if (debug)
1031 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1032 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1033 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1034 ret->mutex[j++] = mx;
1035 mx = NULL;
1036 }
1037 ret->mutex[j++] = ls->mutex[i];
1038 }
1039
1040 /* not added in loop - must be after */
1041 if (mx)
1042 ret->mutex[j++] = mx;
1043
njnca82cc02004-11-22 17:18:48 +00001044 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001045
1046 if (debug || LOCKSET_SANITY) {
1047 print_LockSet("add-OUT", ret);
1048 sanity_check_locksets("add-OUT");
1049 }
1050 return ret;
1051}
1052
1053/* Builds ls with mx removed. mx should actually be in ls!
1054 (a checked assertion). Resulting set should not already
1055 exist in the table (unchecked).
1056*/
1057static
sewardj39a4d842002-11-13 22:14:30 +00001058LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001059{
1060 static const Bool debug = False;
1061 LockSet *ret = NULL;
1062 Int i, j;
1063
1064 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1065 print_LockSet("remove-IN", ls);
1066 }
1067
1068 if (debug || LOCKSET_SANITY)
1069 sanity_check_locksets("remove-IN");
1070
njnca82cc02004-11-22 17:18:48 +00001071 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001072
1073 ret = alloc_LockSet(ls->setsize-1);
1074
1075 for(i = j = 0; i < ls->setsize; i++) {
1076 if (mutex_cmp(ls->mutex[i], mx) == 0)
1077 continue;
1078 ret->mutex[j++] = ls->mutex[i];
1079 }
1080
njnca82cc02004-11-22 17:18:48 +00001081 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001082
1083 if (debug || LOCKSET_SANITY) {
1084 print_LockSet("remove-OUT", ret);
1085 sanity_check_locksets("remove-OUT");
1086 }
1087 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001088}
1089
1090
1091/* Builds the intersection, and then unbuilds it if it's already in the table.
1092 */
sewardj4bffb232002-11-13 21:46:34 +00001093static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001094{
sewardj4bffb232002-11-13 21:46:34 +00001095 static const Bool debug = False;
1096 Int iret;
1097 Int ia, ib;
1098 Int size;
1099 LockSet *ret;
1100 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001101
sewardj4bffb232002-11-13 21:46:34 +00001102 if (debug || LOCKSET_SANITY)
1103 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001104
sewardj4bffb232002-11-13 21:46:34 +00001105 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1106 print_LockSet("intersect a", a);
1107 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001108 }
1109
sewardj4bffb232002-11-13 21:46:34 +00001110 /* count the size of the new set */
1111 size = 0;
1112 ia = ib = 0;
1113 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1114 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1115 size++;
1116 ia++;
1117 ib++;
1118 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1119 ia++;
1120 } else {
njnca82cc02004-11-22 17:18:48 +00001121 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001122 ib++;
1123 }
njn25e49d8e72002-09-23 09:36:25 +00001124 }
1125
sewardj4bffb232002-11-13 21:46:34 +00001126 /* Build the intersection of the two sets */
1127 ret = alloc_LockSet(size);
1128 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1129 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001130 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001131 ret->mutex[iret++] = a->mutex[ia];
1132 ia++;
1133 ib++;
1134 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1135 ia++;
1136 } else {
njnca82cc02004-11-22 17:18:48 +00001137 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001138 ib++;
1139 }
1140 }
1141
1142 ret->hash = hash_LockSet(ret);
1143
njn25e49d8e72002-09-23 09:36:25 +00001144 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001145 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001146
sewardj4bffb232002-11-13 21:46:34 +00001147 if (found != NULL) {
1148 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001149 } else {
sewardj4bffb232002-11-13 21:46:34 +00001150 insert_LockSet(ret);
1151 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001152 }
1153
sewardj4bffb232002-11-13 21:46:34 +00001154 if (debug || LOCKSET_SANITY) {
1155 print_LockSet("intersect-OUT", found);
1156 sanity_check_locksets("intersect-OUT");
1157 }
njn25e49d8e72002-09-23 09:36:25 +00001158
sewardj4bffb232002-11-13 21:46:34 +00001159 return found;
njn25e49d8e72002-09-23 09:36:25 +00001160}
1161
sewardj4bffb232002-11-13 21:46:34 +00001162/* inline the fastpath */
1163static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001164{
sewardj4bffb232002-11-13 21:46:34 +00001165 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001166
1167 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001168 if (a == b) {
1169 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1170 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001171 }
sewardj4bffb232002-11-13 21:46:34 +00001172 return a;
sewardjc26cc252002-10-23 21:58:55 +00001173 }
1174
sewardj4bffb232002-11-13 21:46:34 +00001175 if (isempty(a) || isempty(b)) {
1176 if (debug)
1177 VG_(printf)("intersect empty fastpath\n");
1178 return emptyset;
1179 }
1180
1181 return _intersect(a, b);
1182}
1183
1184
1185static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1186{
1187 static const Bool debug = False;
1188 Int iret;
1189 Int ia, ib;
1190 Int size;
1191 LockSet *ret;
1192 const LockSet *found;
1193
1194 if (debug || LOCKSET_SANITY)
1195 sanity_check_locksets("union-IN");
1196
1197 /* Fast case -- when the two are the same */
1198 if (a == b) {
1199 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1200 print_LockSet("union-same fastpath", a);
1201 }
1202 return a;
1203 }
1204
1205 if (isempty(a)) {
1206 if (debug)
1207 print_LockSet("union a=empty b", b);
1208 return b;
1209 }
1210 if (isempty(b)) {
1211 if (debug)
1212 print_LockSet("union b=empty a", a);
1213 return a;
1214 }
1215
1216 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001217 print_LockSet("union a", a);
1218 print_LockSet("union b", b);
1219 }
1220
sewardj4bffb232002-11-13 21:46:34 +00001221 /* count the size of the new set */
1222 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1223 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001224
sewardj4bffb232002-11-13 21:46:34 +00001225 if ((ia < a->setsize) && (ib < b->setsize))
1226 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1227 else if (ia == a->setsize)
1228 cmp = 1;
1229 else
1230 cmp = -1;
1231
1232 if (cmp == 0) {
1233 size++;
1234 ia++;
1235 ib++;
1236 } else if (cmp < 0) {
1237 size++;
1238 ia++;
1239 } else {
njnca82cc02004-11-22 17:18:48 +00001240 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001241 size++;
1242 ib++;
1243 }
sewardjc26cc252002-10-23 21:58:55 +00001244 }
1245
sewardj4bffb232002-11-13 21:46:34 +00001246 /* Build the intersection of the two sets */
1247 ret = alloc_LockSet(size);
1248 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1249 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001250 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001251
1252 if ((ia < a->setsize) && (ib < b->setsize))
1253 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1254 else if (ia == a->setsize)
1255 cmp = 1;
1256 else
1257 cmp = -1;
1258
1259 if (cmp == 0) {
1260 ret->mutex[iret++] = a->mutex[ia];
1261 ia++;
1262 ib++;
1263 } else if (cmp < 0) {
1264 ret->mutex[iret++] = a->mutex[ia];
1265 ia++;
1266 } else {
njnca82cc02004-11-22 17:18:48 +00001267 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001268 ret->mutex[iret++] = b->mutex[ib];
1269 ib++;
1270 }
1271 }
1272
njnca82cc02004-11-22 17:18:48 +00001273 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001274
1275 ret->hash = hash_LockSet(ret);
1276
sewardjc26cc252002-10-23 21:58:55 +00001277 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001278 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001279
sewardj4bffb232002-11-13 21:46:34 +00001280 if (found != NULL) {
1281 if (debug)
1282 print_LockSet("union found existing set", found);
1283 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001284 } else {
sewardj4bffb232002-11-13 21:46:34 +00001285 if (debug)
1286 print_LockSet("union inserting new set", ret);
1287 insert_LockSet(ret);
1288 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001289 }
1290
sewardj4bffb232002-11-13 21:46:34 +00001291 if (debug || LOCKSET_SANITY) {
1292 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001293 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001294 }
sewardjc26cc252002-10-23 21:58:55 +00001295
sewardj4bffb232002-11-13 21:46:34 +00001296 return found;
sewardjc26cc252002-10-23 21:58:55 +00001297}
1298
1299/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001300/*--- Implementation of mutex structure. ---*/
1301/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001302
1303static UInt graph_mark; /* current mark we're using for graph traversal */
1304
sewardj39a4d842002-11-13 22:14:30 +00001305static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001306 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001307static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001308 const LockSet *lockset_holding,
1309 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001310
njn72718642003-07-24 08:45:32 +00001311static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001312
1313#define M_MUTEX_HASHSZ 1021
1314
sewardj39a4d842002-11-13 22:14:30 +00001315static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001316static UInt total_mutexes;
1317
1318static const Char *pp_MutexState(MutexState st)
1319{
1320 switch(st) {
1321 case MxLocked: return "Locked";
1322 case MxUnlocked: return "Unlocked";
1323 case MxDead: return "Dead";
1324 case MxUnknown: return "Unknown";
1325 }
1326 return "???";
1327}
1328
1329static void pp_all_mutexes()
1330{
1331 Int i;
1332 Int locks, buckets;
1333
1334 locks = buckets = 0;
1335 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001336 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001337 Bool first = True;
1338
1339 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1340 if (first) {
1341 buckets++;
1342 VG_(printf)("[%4d] = ", i);
1343 } else
1344 VG_(printf)(" ");
1345 locks++;
1346 first = False;
1347 VG_(printf)("%p [%8s] -> %p%(y\n",
1348 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1349 }
1350 }
1351
1352 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1353 locks, buckets, total_mutexes);
1354}
sewardjc26cc252002-10-23 21:58:55 +00001355
sewardj39a4d842002-11-13 22:14:30 +00001356/* find or create a Mutex for a program's mutex use */
1357static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001358{
nethercote50397c22004-11-04 18:03:06 +00001359 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001360 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001361
1362 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1363 if (mp->mutexp == mutexp)
1364 return mp;
1365
sewardjdac0a442002-11-13 22:08:40 +00001366 total_mutexes++;
1367
sewardjc26cc252002-10-23 21:58:55 +00001368 mp = VG_(malloc)(sizeof(*mp));
1369 mp->mutexp = mutexp;
1370 mp->next = mutex_hash[bucket];
1371 mutex_hash[bucket] = mp;
1372
1373 mp->state = MxUnknown;
1374 mp->tid = VG_INVALID_THREADID;
1375 mp->location = NULL;
1376
sewardj4bffb232002-11-13 21:46:34 +00001377 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001378 mp->mark = graph_mark - 1;
1379
1380 return mp;
1381}
1382
sewardjdac0a442002-11-13 22:08:40 +00001383/* Find all mutexes in a range of memory, and call the callback.
1384 Remove the mutex from the hash if the callback returns True (mutex
1385 structure itself is not freed, because it may be pointed to by a
1386 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001387static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001388{
sewardjdac0a442002-11-13 22:08:40 +00001389 UInt first = start % M_MUTEX_HASHSZ;
1390 UInt last = (end+1) % M_MUTEX_HASHSZ;
1391 UInt i;
1392
1393 /* Single pass over the hash table, looking for likely hashes */
1394 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001395 Mutex *mx;
1396 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001397
1398 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1399 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1400 *prev = mx->next;
1401 }
1402
1403 if (++i == M_MUTEX_HASHSZ)
1404 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001405 }
sewardjc26cc252002-10-23 21:58:55 +00001406}
1407
1408#define MARK_LOOP (graph_mark+0)
1409#define MARK_DONE (graph_mark+1)
1410
thughes4ad52d02004-06-27 17:37:21 +00001411static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1412{
1413 static const Bool debug = False;
1414 Int i;
1415
1416 if (mutex->mark == MARK_LOOP)
1417 return True; /* found cycle */
1418 if (mutex->mark == MARK_DONE)
1419 return False; /* been here before, its OK */
1420
1421 ((Mutex*)mutex)->mark = MARK_LOOP;
1422
1423 if (debug)
1424 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1425 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1426 for(i = 0; i < ls->setsize; i++) {
1427 const Mutex *mx = ls->mutex[i];
1428
1429 if (debug)
1430 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1431 mutex->mutexp, ls,
1432 mx->mutexp, mx->mutexp);
1433 if (check_cycle_inner(mx, mx->lockdep))
1434 return True;
1435 }
1436 ((Mutex*)mutex)->mark = MARK_DONE;
1437
1438 return False;
1439}
1440
sewardj39a4d842002-11-13 22:14:30 +00001441static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001442{
sewardjff2c9232002-11-13 21:44:39 +00001443
sewardjc26cc252002-10-23 21:58:55 +00001444 graph_mark += 2; /* clear all marks */
1445
sewardj4bffb232002-11-13 21:46:34 +00001446 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001447}
1448
sewardjdca84112002-11-13 22:29:34 +00001449/* test to see if a mutex state change would be problematic; this
1450 makes no changes to the mutex state. This should be called before
1451 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001452static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001453{
1454 static const Bool debug = False;
1455
sewardjc26cc252002-10-23 21:58:55 +00001456 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001457 Char *str;
1458
1459 switch(state) {
1460 case MxLocked: str = "lock dead mutex"; break;
1461 case MxUnlocked: str = "unlock dead mutex"; break;
1462 default: str = "operate on dead mutex"; break;
1463 }
1464
sewardjc26cc252002-10-23 21:58:55 +00001465 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001466 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001467 return;
1468 }
1469
1470 switch(state) {
1471 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001472 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001473
1474 if (debug)
1475 print_LockSet("thread holding", thread_locks[tid]);
1476
1477 if (check_cycle(mutex, thread_locks[tid]))
1478 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1479 else {
1480 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1481
1482 if (debug) {
1483 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1484 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1485 print_LockSet("lockdep", mutex->lockdep);
1486 }
1487 }
1488 break;
1489
1490 case MxUnlocked:
1491 if (debug)
1492 print_LockSet("thread holding", thread_locks[tid]);
1493
1494 if (mutex->state != MxLocked) {
1495 record_mutex_error(tid, mutex,
1496 "unlock non-locked mutex", mutex->location);
1497 }
1498 if (mutex->tid != tid) {
1499 record_mutex_error(tid, mutex,
1500 "unlock someone else's mutex", mutex->location);
1501 }
1502 break;
1503
1504 case MxDead:
1505 break;
1506
1507 default:
1508 break;
1509 }
1510}
1511
1512/* Update a mutex state. Expects most error testing and reporting to
1513 have happened in test_mutex_state(). The assumption is that no
1514 client code is run by thread tid between test and set, either
1515 because it is blocked or test and set are called together
1516 atomically.
1517
1518 Setting state to MxDead is the exception, since that can happen as
1519 a result of any thread freeing memory; in this case set_mutex_state
1520 does all the error reporting as well.
1521*/
njn72718642003-07-24 08:45:32 +00001522static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001523{
1524 static const Bool debug = False;
1525
1526 if (debug)
1527 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1528 tid, mutex, mutex->mutexp, mutex->mutexp,
1529 pp_MutexState(mutex->state), pp_MutexState(state));
1530
1531 if (mutex->state == MxDead) {
1532 /* can't do anything legal to a destroyed mutex */
1533 return;
1534 }
1535
1536 switch(state) {
1537 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001538 if (mutex->state == MxLocked) {
1539 if (mutex->tid != tid)
1540 record_mutex_error(tid, mutex, "take lock held by someone else",
1541 mutex->location);
1542 else
1543 record_mutex_error(tid, mutex, "take lock we already hold",
1544 mutex->location);
1545
njn67993252004-11-22 18:02:32 +00001546 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001547 break;
1548 }
sewardjc26cc252002-10-23 21:58:55 +00001549
njnca82cc02004-11-22 17:18:48 +00001550 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001551
sewardjc26cc252002-10-23 21:58:55 +00001552 mutex->tid = tid;
1553 break;
1554
1555 case MxUnlocked:
1556 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001557 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001558
sewardjdca84112002-11-13 22:29:34 +00001559 if (mutex->state != MxLocked || mutex->tid != tid)
1560 break;
1561
sewardjc26cc252002-10-23 21:58:55 +00001562 mutex->tid = VG_INVALID_THREADID;
1563 break;
1564
sewardjdac0a442002-11-13 22:08:40 +00001565 case MxDead:
1566 if (mutex->state == MxLocked) {
1567 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001568 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001569 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1570 mutex->tid = VG_INVALID_THREADID;
1571
1572 record_mutex_error(tid, mutex,
1573 "free locked mutex", mutex->location);
1574 }
1575 break;
1576
sewardjc26cc252002-10-23 21:58:55 +00001577 default:
1578 break;
1579 }
1580
njnd01fef72005-03-25 23:35:48 +00001581 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001582 mutex->state = state;
1583}
njn25e49d8e72002-09-23 09:36:25 +00001584
1585/*------------------------------------------------------------*/
1586/*--- Setting and checking permissions. ---*/
1587/*------------------------------------------------------------*/
1588
thughes4ad52d02004-06-27 17:37:21 +00001589/* only clean up dead mutexes */
1590static
1591Bool cleanmx(Mutex *mx) {
1592 return mx->state == MxDead;
1593}
1594
njn25e49d8e72002-09-23 09:36:25 +00001595static
nethercote451eae92004-11-02 13:06:32 +00001596void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001597 VgeInitStatus status )
1598{
sewardj1806d7f2002-10-22 05:05:49 +00001599 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001600
1601# if DEBUG_MAKE_ACCESSES
1602 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1603# endif
1604 //PROF_EVENT(30); PPP
1605
1606 if (len == 0)
1607 return;
1608
1609 if (len > 100 * 1000 * 1000)
1610 VG_(message)(Vg_UserMsg,
1611 "Warning: set address range state: large range %d",
1612 len);
1613
1614 VGP_PUSHCC(VgpSARP);
1615
sewardjdac0a442002-11-13 22:08:40 +00001616 /* Remove mutexes in recycled memory range from hash */
1617 find_mutex_range(a, a+len, cleanmx);
1618
njn25e49d8e72002-09-23 09:36:25 +00001619 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1620 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1621 * len/4+1 words. This works out which it is by aligning the block and
1622 * seeing if the end byte is in the same word as it is for the unaligned
1623 * block; if not, it's the awkward case. */
sewardj8fac99a2002-11-13 22:31:26 +00001624 end = ROUNDUP(a + len, 4);
1625 a = ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001626
1627 /* Do it ... */
1628 switch (status) {
1629 case Vge_VirginInit:
1630 for ( ; a < end; a += 4) {
1631 //PROF_EVENT(31); PPP
1632 init_virgin_sword(a);
1633 }
1634 break;
1635
1636 case Vge_NonVirginInit:
1637 for ( ; a < end; a += 4) {
1638 //PROF_EVENT(31); PPP
1639 init_nonvirgin_sword(a);
1640 }
1641 break;
1642
1643 case Vge_SegmentInit:
1644 for ( ; a < end; a += 4) {
1645 //PROF_EVENT(31); PPP
1646 init_magically_inited_sword(a);
1647 }
1648 break;
sewardj7f3ad222002-11-13 22:11:53 +00001649
1650 case Vge_Error:
1651 for ( ; a < end; a += 4) {
1652 //PROF_EVENT(31); PPP
1653 init_error_sword(a);
1654 }
1655 break;
njn25e49d8e72002-09-23 09:36:25 +00001656
1657 default:
1658 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001659 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001660 }
1661
njn25e49d8e72002-09-23 09:36:25 +00001662 VGP_POPCC(VgpSARP);
1663}
1664
1665
nethercote451eae92004-11-02 13:06:32 +00001666static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001667{
1668 //PROF_EVENT(??); PPP
1669 set_address_range_state ( a, len, Vge_SegmentInit );
1670}
1671
nethercote451eae92004-11-02 13:06:32 +00001672static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001673{
1674 //PROF_EVENT(36); PPP
1675 set_address_range_state( a, len, Vge_VirginInit );
1676}
1677
nethercote451eae92004-11-02 13:06:32 +00001678static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001679{
1680 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001681 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001682}
1683
1684
njn25e49d8e72002-09-23 09:36:25 +00001685/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001686static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001687{
1688 UInt i;
1689
1690 //PROF_EVENT(40); PPP
1691 for (i = 0; i < len; i += 4) {
1692 shadow_word sword = *(get_sword_addr ( src+i ));
1693 //PROF_EVENT(41); PPP
1694 set_sword ( dst+i, sword );
1695 }
1696}
1697
1698// SSS: put these somewhere better
njnfbdcba92005-05-09 01:23:49 +00001699static void hg_mem_read (Addr a, SizeT data_size, ThreadId tid);
1700static void hg_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001701
njnfbdcba92005-05-09 01:23:49 +00001702static void hg_mem_help_read_1(Addr a) VGA_REGPARM(1);
1703static void hg_mem_help_read_2(Addr a) VGA_REGPARM(1);
1704static void hg_mem_help_read_4(Addr a) VGA_REGPARM(1);
1705static void hg_mem_help_read_N(Addr a, SizeT size) VGA_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001706
njnfbdcba92005-05-09 01:23:49 +00001707static void hg_mem_help_write_1(Addr a, UInt val) VGA_REGPARM(2);
1708static void hg_mem_help_write_2(Addr a, UInt val) VGA_REGPARM(2);
1709static void hg_mem_help_write_4(Addr a, UInt val) VGA_REGPARM(2);
1710static void hg_mem_help_write_N(Addr a, SizeT size) VGA_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001711
sewardj7a5ebcf2002-11-13 22:42:13 +00001712static void bus_lock(void);
1713static void bus_unlock(void);
1714
njn25e49d8e72002-09-23 09:36:25 +00001715static
njnfbdcba92005-05-09 01:23:49 +00001716void hg_pre_mem_read(CorePart part, ThreadId tid,
1717 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001718{
njn02bc4b82005-05-15 17:28:26 +00001719 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 +00001720 hg_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001721}
1722
1723static
njnfbdcba92005-05-09 01:23:49 +00001724void hg_pre_mem_read_asciiz(CorePart part, ThreadId tid,
1725 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001726{
njnfbdcba92005-05-09 01:23:49 +00001727 hg_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001728}
1729
1730static
njnfbdcba92005-05-09 01:23:49 +00001731void hg_pre_mem_write(CorePart part, ThreadId tid,
1732 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001733{
njnfbdcba92005-05-09 01:23:49 +00001734 hg_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001735}
1736
1737
1738
1739static
njnfbdcba92005-05-09 01:23:49 +00001740void hg_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001741{
njn1f3a9092002-10-04 09:22:30 +00001742 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001743 make_segment_readable(a, len);
1744}
1745
1746
1747static
njnfbdcba92005-05-09 01:23:49 +00001748void hg_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001749{
1750 if (is_inited) {
1751 make_readable(a, len);
1752 } else {
1753 make_writable(a, len);
1754 }
1755}
1756
1757static
njnfbdcba92005-05-09 01:23:49 +00001758void hg_set_perms (Addr a, SizeT len,
1759 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001760{
1761 if (rr) make_readable(a, len);
1762 else if (ww) make_writable(a, len);
1763 /* else do nothing */
1764}
1765
sewardjf6374322002-11-13 22:35:55 +00001766static
njnfbdcba92005-05-09 01:23:49 +00001767void hg_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001768{
1769 set_address_range_state(a, len, Vge_NonVirginInit);
1770}
1771
1772static
njnfbdcba92005-05-09 01:23:49 +00001773void hg_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001774{
1775 set_address_range_state(a, len, Vge_VirginInit);
1776}
njn25e49d8e72002-09-23 09:36:25 +00001777
1778/*--------------------------------------------------------------*/
1779/*--- Initialise the memory audit system on program startup. ---*/
1780/*--------------------------------------------------------------*/
1781
1782static
1783void init_shadow_memory(void)
1784{
1785 Int i;
1786
1787 for (i = 0; i < ESEC_MAP_WORDS; i++)
1788 distinguished_secondary_map.swords[i] = virgin_sword;
1789
1790 /* These entries gradually get overwritten as the used address
1791 space expands. */
1792 for (i = 0; i < 65536; i++)
1793 primary_map[i] = &distinguished_secondary_map;
1794}
1795
1796
njn3e884182003-04-15 13:03:23 +00001797/*------------------------------------------------------------*/
1798/*--- malloc() et al replacements ---*/
1799/*------------------------------------------------------------*/
1800
njnb4aee052003-04-15 14:09:58 +00001801static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001802
1803#define N_FREED_CHUNKS 2
1804static Int freechunkptr = 0;
1805static HG_Chunk *freechunks[N_FREED_CHUNKS];
1806
njn3e884182003-04-15 13:03:23 +00001807
1808/* Allocate a user-chunk of size bytes. Also allocate its shadow
1809 block, make the shadow block point at the user block. Put the
1810 shadow chunk on the appropriate list, and set all memory
1811 protections correctly. */
1812
nethercote7ac7f7b2004-11-02 12:36:02 +00001813static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001814{
1815 HG_Chunk* hc;
1816
1817 hc = VG_(malloc)(sizeof(HG_Chunk));
1818 hc->data = p;
1819 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001820 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001821 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001822
1823 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1824}
1825
1826/* Allocate memory and note change in memory available */
1827static __inline__
njn14d01ce2004-11-26 11:30:14 +00001828void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1829 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001830{
1831 Addr p;
1832
njn34ac0272003-09-30 14:20:00 +00001833 if (size < 0) return NULL;
1834
njn3e884182003-04-15 13:03:23 +00001835 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001836 if (!p) {
1837 return NULL;
1838 }
njn34ac0272003-09-30 14:20:00 +00001839 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001840 add_HG_Chunk ( tid, p, size );
njnfbdcba92005-05-09 01:23:49 +00001841 hg_new_mem_heap( p, size, is_zeroed );
njn3e884182003-04-15 13:03:23 +00001842
1843 return (void*)p;
1844}
1845
njn51d827b2005-05-09 01:02:08 +00001846static void* hg_malloc ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001847{
njn14d01ce2004-11-26 11:30:14 +00001848 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001849}
1850
njn51d827b2005-05-09 01:02:08 +00001851static void* hg___builtin_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001852{
njn14d01ce2004-11-26 11:30:14 +00001853 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001854}
1855
njn51d827b2005-05-09 01:02:08 +00001856static void* hg___builtin_vec_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001857{
njn14d01ce2004-11-26 11:30:14 +00001858 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001859}
1860
njn51d827b2005-05-09 01:02:08 +00001861static void* hg_memalign ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001862{
njn14d01ce2004-11-26 11:30:14 +00001863 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001864}
1865
njn51d827b2005-05-09 01:02:08 +00001866static void* hg_calloc ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001867{
njn14d01ce2004-11-26 11:30:14 +00001868 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001869 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001870}
1871
thughes4ad52d02004-06-27 17:37:21 +00001872static ThreadId deadmx_tid;
1873
1874static
1875Bool deadmx(Mutex *mx) {
1876 if (mx->state != MxDead)
1877 set_mutex_state(mx, MxDead, deadmx_tid);
1878
1879 return False;
1880}
1881
njn3e884182003-04-15 13:03:23 +00001882static
njn72718642003-07-24 08:45:32 +00001883void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001884 HG_Chunk** prev_chunks_next_ptr )
1885{
njn72718642003-07-24 08:45:32 +00001886 Addr start = hc->data;
1887 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001888
njn3e884182003-04-15 13:03:23 +00001889 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1890 avoid repeating the hash table lookup. Can't remove until at least
1891 after free and free_mismatch errors are done because they use
1892 describe_addr() which looks for it in malloclist. */
1893 *prev_chunks_next_ptr = hc->next;
1894
1895 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001896 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001897
1898 /* maintain a small window so that the error reporting machinery
1899 knows about this memory */
1900 if (freechunks[freechunkptr] != NULL) {
1901 /* free HG_Chunk */
1902 HG_Chunk* sc1 = freechunks[freechunkptr];
1903 VG_(cli_free) ( (void*)(sc1->data) );
1904 VG_(free) ( sc1 );
1905 }
1906
1907 freechunks[freechunkptr] = hc;
1908
1909 if (++freechunkptr == N_FREED_CHUNKS)
1910 freechunkptr = 0;
1911
1912 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001913 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001914 find_mutex_range(start, end, deadmx);
1915}
1916
1917
1918static __inline__
njn14d01ce2004-11-26 11:30:14 +00001919void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001920{
1921 HG_Chunk* hc;
1922 HG_Chunk** prev_chunks_next_ptr;
1923
nethercote3d6b6112004-11-04 16:39:43 +00001924 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001925 (VgHashNode***)&prev_chunks_next_ptr );
1926 if (hc == NULL) {
1927 return;
1928 }
njn14d01ce2004-11-26 11:30:14 +00001929 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001930}
1931
njn51d827b2005-05-09 01:02:08 +00001932static void hg_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001933{
njn14d01ce2004-11-26 11:30:14 +00001934 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001935}
1936
njn51d827b2005-05-09 01:02:08 +00001937static void hg___builtin_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001938{
njn14d01ce2004-11-26 11:30:14 +00001939 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001940}
1941
njn51d827b2005-05-09 01:02:08 +00001942static void hg___builtin_vec_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001943{
njn14d01ce2004-11-26 11:30:14 +00001944 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001945}
1946
njn51d827b2005-05-09 01:02:08 +00001947static void* hg_realloc ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001948{
1949 HG_Chunk *hc;
1950 HG_Chunk **prev_chunks_next_ptr;
sewardj05bcdcb2003-05-18 10:05:38 +00001951 Int i;
njn3e884182003-04-15 13:03:23 +00001952
1953 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001954 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001955 (VgHashNode***)&prev_chunks_next_ptr );
1956
1957 if (hc == NULL) {
1958 return NULL;
1959 }
1960
1961 if (hc->size == new_size) {
1962 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001963 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001964 return p;
1965
1966 } else if (hc->size > new_size) {
1967 /* new size is smaller */
1968 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001969 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001970 return p;
1971
1972 } else {
1973 /* new size is bigger */
1974 Addr p_new;
1975
1976 /* Get new memory */
1977 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
1978
1979 /* First half kept and copied, second half new */
1980 copy_address_range_state( (Addr)p, p_new, hc->size );
njnfbdcba92005-05-09 01:23:49 +00001981 hg_new_mem_heap ( p_new+hc->size, new_size-hc->size,
1982 /*inited*/False );
njn3e884182003-04-15 13:03:23 +00001983
1984 /* Copy from old to new */
1985 for (i = 0; i < hc->size; i++)
1986 ((UChar*)p_new)[i] = ((UChar*)p)[i];
1987
1988 /* Free old memory */
njn72718642003-07-24 08:45:32 +00001989 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001990
1991 /* this has to be after die_and_free_mem, otherwise the
1992 former succeeds in shorting out the new block, not the
1993 old, in the case when both are on the same list. */
njn72718642003-07-24 08:45:32 +00001994 add_HG_Chunk ( tid, p_new, new_size );
njn3e884182003-04-15 13:03:23 +00001995
1996 return (void*)p_new;
1997 }
1998}
1999
njn25e49d8e72002-09-23 09:36:25 +00002000/*--------------------------------------------------------------*/
2001/*--- Machinery to support sanity checking ---*/
2002/*--------------------------------------------------------------*/
2003
njn51d827b2005-05-09 01:02:08 +00002004static Bool hg_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00002005{
jseward9800fd32004-01-04 23:08:04 +00002006 /* nothing useful we can rapidly check */
2007 return True;
njn25e49d8e72002-09-23 09:36:25 +00002008}
2009
njn51d827b2005-05-09 01:02:08 +00002010static Bool hg_expensive_sanity_check(void)
njn25e49d8e72002-09-23 09:36:25 +00002011{
2012 Int i;
2013
2014 /* Make sure nobody changed the distinguished secondary. */
2015 for (i = 0; i < ESEC_MAP_WORDS; i++)
2016 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2017 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2018 return False;
2019
2020 return True;
2021}
2022
2023
2024/*--------------------------------------------------------------*/
2025/*--- Instrumentation ---*/
2026/*--------------------------------------------------------------*/
2027
sewardjf6374322002-11-13 22:35:55 +00002028static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2029
njn14d01ce2004-11-26 11:30:14 +00002030#if 0
njn25e49d8e72002-09-23 09:36:25 +00002031/* Create and return an instrumented version of cb_in. Free cb_in
2032 before returning. */
njn26f02512004-11-22 18:33:15 +00002033UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002034{
2035 UCodeBlock* cb;
2036 Int i;
2037 UInstr* u_in;
2038 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002039 Int ntemps;
2040 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002041 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002042
njn810086f2002-11-14 12:42:47 +00002043 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002044
sewardjf6374322002-11-13 22:35:55 +00002045 /* stackref[] is used for super-simple value tracking to keep note
2046 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002047 the stack pointer or frame pointer, and is therefore likely
2048 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002049 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002050 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2051 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2052
njn810086f2002-11-14 12:42:47 +00002053 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2054 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002055
njn25e49d8e72002-09-23 09:36:25 +00002056 switch (u_in->opcode) {
2057
2058 case NOP: case CALLM_S: case CALLM_E:
2059 break;
sewardjf6374322002-11-13 22:35:55 +00002060
sewardj7a5ebcf2002-11-13 22:42:13 +00002061 case LOCK:
2062 locked = True;
2063 uInstr0(cb, CCALL, 0);
2064 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2065 break;
2066
2067 case JMP: case INCEIP:
2068 if (locked) {
2069 uInstr0(cb, CCALL, 0);
2070 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2071 }
2072 locked = False;
2073 VG_(copy_UInstr)(cb, u_in);
2074 break;
2075
sewardjf6374322002-11-13 22:35:55 +00002076 case GET:
njnca82cc02004-11-22 17:18:48 +00002077 tl_assert(u_in->tag1 == ArchReg);
2078 tl_assert(u_in->tag2 == TempReg);
2079 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002080
2081 stackref[u_in->val2] = (u_in->size == 4 &&
njndb9b7732005-03-26 00:32:29 +00002082 (u_in->val1 == VGA_R_STACK_PTR ||
2083 u_in->val1 == VGA_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002084 VG_(copy_UInstr)(cb, u_in);
2085 break;
2086
2087 case MOV:
2088 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002089 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002090 stackref[u_in->val2] = stackref[u_in->val1];
2091 }
2092 VG_(copy_UInstr)(cb, u_in);
2093 break;
2094
2095 case LEA1:
2096 case ADD: case SUB:
2097 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002098 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002099 stackref[u_in->val2] |= stackref[u_in->val1];
2100 }
2101 VG_(copy_UInstr)(cb, u_in);
2102 break;
njn25e49d8e72002-09-23 09:36:25 +00002103
sewardja5b3aec2002-10-22 05:09:36 +00002104 case LOAD: {
2105 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002106 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2107 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002108
2109 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2110 nonstk_ld++;
2111
2112 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002113 case 1: help = hg_mem_help_read_1; break;
2114 case 2: help = hg_mem_help_read_2; break;
2115 case 4: help = hg_mem_help_read_4; break;
sewardjf6374322002-11-13 22:35:55 +00002116 default:
njn67993252004-11-22 18:02:32 +00002117 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002118 }
jsgfcb1d1c02003-10-14 21:55:10 +00002119
2120 /* XXX all registers should be flushed to baseblock
2121 here */
sewardjf6374322002-11-13 22:35:55 +00002122 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2123 uCCall(cb, (Addr)help, 1, 1, False);
2124 } else
2125 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002126
sewardja5b3aec2002-10-22 05:09:36 +00002127 VG_(copy_UInstr)(cb, u_in);
2128 t_size = INVALID_TEMPREG;
2129 break;
2130 }
2131
fitzhardinge111c6072004-03-09 02:45:07 +00002132 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002133 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002134 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002135 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002136
fitzhardinge111c6072004-03-09 02:45:07 +00002137 t_size = newTemp(cb);
2138 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2139 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002140
fitzhardinge111c6072004-03-09 02:45:07 +00002141 /* XXX all registers should be flushed to baseblock
2142 here */
2143 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002144 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002145
2146 VG_(copy_UInstr)(cb, u_in);
2147 t_size = INVALID_TEMPREG;
2148 break;
sewardja5b3aec2002-10-22 05:09:36 +00002149 }
2150
thughes96b466a2004-03-15 16:43:58 +00002151 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002152 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002153
2154 t_size = newTemp(cb);
2155 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2156 uLiteral(cb, (UInt)u_in->size);
2157
2158 /* XXX all registers should be flushed to baseblock
2159 here */
2160 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002161 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
thughes96b466a2004-03-15 16:43:58 +00002162
2163 VG_(copy_UInstr)(cb, u_in);
2164 t_size = INVALID_TEMPREG;
2165 break;
2166 }
2167
fitzhardinge111c6072004-03-09 02:45:07 +00002168 case SSE2a_MemRd:
2169 case SSE2a1_MemRd:
2170 case SSE3a_MemRd:
2171 case SSE3a1_MemRd:
2172 case SSE3ag_MemRd_RegWr: {
2173 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2174
njnca82cc02004-11-22 17:18:48 +00002175 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002176
2177 t_size = newTemp(cb);
2178 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2179 uLiteral(cb, (UInt)u_in->size);
2180
2181 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002182 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002183
2184 VG_(copy_UInstr)(cb, u_in);
2185 t_size = INVALID_TEMPREG;
2186 break;
2187 }
2188
sewardja5b3aec2002-10-22 05:09:36 +00002189 case STORE: {
2190 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002191 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2192 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002193
sewardjf6374322002-11-13 22:35:55 +00002194 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2195 nonstk_st++;
2196
2197 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002198 case 1: help = hg_mem_help_write_1; break;
2199 case 2: help = hg_mem_help_write_2; break;
2200 case 4: help = hg_mem_help_write_4; break;
sewardjf6374322002-11-13 22:35:55 +00002201 default:
njn67993252004-11-22 18:02:32 +00002202 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002203 }
2204
jsgfcb1d1c02003-10-14 21:55:10 +00002205 /* XXX all registers should be flushed to baseblock
2206 here */
sewardjf6374322002-11-13 22:35:55 +00002207 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2208 uCCall(cb, (Addr)help, 2, 2, False);
2209 } else
2210 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002211
2212 VG_(copy_UInstr)(cb, u_in);
2213 t_size = INVALID_TEMPREG;
2214 break;
2215 }
2216
fitzhardinge111c6072004-03-09 02:45:07 +00002217 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002218 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002219 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002220 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002221
2222 t_size = newTemp(cb);
2223 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2224 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002225 /* XXX all registers should be flushed to baseblock
2226 here */
sewardja5b3aec2002-10-22 05:09:36 +00002227 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002228 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
sewardja5b3aec2002-10-22 05:09:36 +00002229
2230 VG_(copy_UInstr)(cb, u_in);
2231 t_size = INVALID_TEMPREG;
2232 break;
2233 }
njn25e49d8e72002-09-23 09:36:25 +00002234
fitzhardinge111c6072004-03-09 02:45:07 +00002235 case SSE2a_MemWr:
2236 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002237 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002238 512 == u_in->size);
2239
2240 t_size = newTemp(cb);
2241 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2242 uLiteral(cb, (UInt)u_in->size);
2243 /* XXX all registers should be flushed to baseblock
2244 here */
2245 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002246 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002247
2248 VG_(copy_UInstr)(cb, u_in);
2249 t_size = INVALID_TEMPREG;
2250 break;
2251 }
sewardj3d7c9c82003-03-26 21:08:13 +00002252
njn25e49d8e72002-09-23 09:36:25 +00002253 default:
sewardjf6374322002-11-13 22:35:55 +00002254 /* conservative tromping */
2255 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2256 stackref[u_in->val1] = False;
2257 if (u_in->tag2 == TempReg)
2258 stackref[u_in->val2] = False;
2259 if (u_in->tag3 == TempReg)
2260 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002261 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002262 break;
2263 }
2264 }
2265
sewardjf6374322002-11-13 22:35:55 +00002266 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002267 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002268 return cb;
2269}
njn14d01ce2004-11-26 11:30:14 +00002270#endif
njn51d827b2005-05-09 01:02:08 +00002271static IRBB* hg_instrument ( IRBB* bb_in, VexGuestLayout* layout,
2272 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002273{
2274 VG_(message)(Vg_DebugMsg, "Helgrind is not yet ready to handle Vex IR");
2275 VG_(exit)(1);
2276}
njn25e49d8e72002-09-23 09:36:25 +00002277
2278/*--------------------------------------------------------------------*/
2279/*--- Error and suppression handling ---*/
2280/*--------------------------------------------------------------------*/
2281
2282typedef
2283 enum {
2284 /* Possible data race */
njnfbdcba92005-05-09 01:23:49 +00002285 RaceSupp
njn25e49d8e72002-09-23 09:36:25 +00002286 }
njnfbdcba92005-05-09 01:23:49 +00002287 RaceSuppKind;
njn25e49d8e72002-09-23 09:36:25 +00002288
2289/* What kind of error it is. */
2290typedef
2291 enum {
njnfbdcba92005-05-09 01:23:49 +00002292 RaceErr, /* data-race */
sewardj16748af2002-10-22 04:55:54 +00002293 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002294 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002295 }
njnfbdcba92005-05-09 01:23:49 +00002296 RaceErrorKind;
njn25e49d8e72002-09-23 09:36:25 +00002297
sewardj16748af2002-10-22 04:55:54 +00002298/* The classification of a faulting address. */
2299typedef
2300 enum { Undescribed, /* as-yet unclassified */
2301 Stack,
2302 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002303 Mallocd,
2304 Freed,
sewardj16748af2002-10-22 04:55:54 +00002305 Segment
2306 }
2307 AddrKind;
2308/* Records info about a faulting address. */
2309typedef
2310 struct {
2311 /* ALL */
2312 AddrKind akind;
2313 /* Freed, Mallocd */
2314 Int blksize;
2315 /* Freed, Mallocd */
2316 Int rwoffset;
2317 /* Freed, Mallocd */
2318 ExeContext* lastchange;
2319 ThreadId lasttid;
2320 /* Stack */
2321 ThreadId stack_tid;
2322 /* Segment */
2323 const Char* filename;
2324 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002325 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002326 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002327 /* symbolic address description */
2328 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002329 }
2330 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002331
sewardj16748af2002-10-22 04:55:54 +00002332/* What kind of memory access is involved in the error? */
2333typedef
2334 enum { ReadAxs, WriteAxs, ExecAxs }
2335 AxsKind;
2336
2337/* Extra context for memory errors */
2338typedef
2339 struct {
2340 AxsKind axskind;
2341 Int size;
2342 AddrInfo addrinfo;
2343 Bool isWrite;
2344 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002345 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002346 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002347 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002348 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002349 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002350 const LockSet *held_lockset;
2351 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002352 }
2353 HelgrindError;
2354
2355static __inline__
2356void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002357{
sewardj16748af2002-10-22 04:55:54 +00002358 ai->akind = Unknown;
2359 ai->blksize = 0;
2360 ai->rwoffset = 0;
2361 ai->lastchange = NULL;
2362 ai->lasttid = VG_INVALID_THREADID;
2363 ai->filename = NULL;
2364 ai->section = "???";
2365 ai->stack_tid = VG_INVALID_THREADID;
2366 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002367 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002368}
2369
sewardj16748af2002-10-22 04:55:54 +00002370static __inline__
2371void clear_HelgrindError ( HelgrindError* err_extra )
2372{
2373 err_extra->axskind = ReadAxs;
2374 err_extra->size = 0;
2375 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002376 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002377 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002378 err_extra->prev_lockset = 0;
2379 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002380 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002381 clear_AddrInfo ( &err_extra->addrinfo );
2382 err_extra->isWrite = False;
2383}
2384
2385
2386
2387/* Describe an address as best you can, for error messages,
2388 putting the result in ai. */
2389
thughes4ad52d02004-06-27 17:37:21 +00002390/* Callback for searching malloc'd and free'd lists */
2391static Bool addr_is_in_block(VgHashNode *node, void *ap)
2392{
2393 HG_Chunk* hc2 = (HG_Chunk*)node;
2394 Addr a = *(Addr *)ap;
2395
2396 return (hc2->data <= a && a < hc2->data + hc2->size);
2397}
2398
sewardj16748af2002-10-22 04:55:54 +00002399static void describe_addr ( Addr a, AddrInfo* ai )
2400{
njn3e884182003-04-15 13:03:23 +00002401 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002402 Int i;
sewardj16748af2002-10-22 04:55:54 +00002403
sewardj16748af2002-10-22 04:55:54 +00002404 /* Search for it in segments */
2405 {
njn36ef6ba2005-05-14 18:42:26 +00002406 const SegInfo *si;
sewardj16748af2002-10-22 04:55:54 +00002407
njn36ef6ba2005-05-14 18:42:26 +00002408 for (si = VG_(next_seginfo)(NULL);
2409 si != NULL;
2410 si = VG_(next_seginfo)(si))
2411 {
2412 Addr base = VG_(seg_start)(si);
2413 SizeT size = VG_(seg_size)(si);
2414 const UChar *filename = VG_(seg_filename)(si);
sewardj16748af2002-10-22 04:55:54 +00002415
2416 if (a >= base && a < base+size) {
2417 ai->akind = Segment;
2418 ai->blksize = size;
2419 ai->rwoffset = a - base;
2420 ai->filename = filename;
2421
2422 switch(VG_(seg_sect_kind)(a)) {
2423 case Vg_SectText: ai->section = "text"; break;
2424 case Vg_SectData: ai->section = "data"; break;
2425 case Vg_SectBSS: ai->section = "BSS"; break;
2426 case Vg_SectGOT: ai->section = "GOT"; break;
2427 case Vg_SectPLT: ai->section = "PLT"; break;
2428 case Vg_SectUnknown:
2429 default:
2430 ai->section = "???"; break;
2431 }
2432
2433 return;
2434 }
2435 }
2436 }
2437
2438 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002439 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002440 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002441 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002442 ai->blksize = hc->size;
2443 ai->rwoffset = (Int)a - (Int)(hc->data);
2444 ai->lastchange = hc->where;
2445 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002446 return;
2447 }
sewardjdac0a442002-11-13 22:08:40 +00002448
2449 /* Look in recently freed memory */
2450 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002451 hc = freechunks[i];
2452 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002453 continue;
2454
njn3e884182003-04-15 13:03:23 +00002455 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002456 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002457 ai->blksize = hc->size;
2458 ai->rwoffset = a - hc->data;
2459 ai->lastchange = hc->where;
2460 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002461 return;
2462 }
2463 }
2464
sewardj16748af2002-10-22 04:55:54 +00002465 /* Clueless ... */
2466 ai->akind = Unknown;
2467 return;
2468}
2469
2470
njn7e614812003-04-21 22:04:03 +00002471/* Updates the copy with address info if necessary. */
njn51d827b2005-05-09 01:02:08 +00002472static UInt hg_update_extra(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002473{
njn7e614812003-04-21 22:04:03 +00002474 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002475
njn7e614812003-04-21 22:04:03 +00002476 extra = (HelgrindError*)VG_(get_error_extra)(err);
2477 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2478 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2479 }
2480 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002481}
2482
njnfbdcba92005-05-09 01:23:49 +00002483static void record_race_error ( ThreadId tid, Addr a, Bool is_write,
2484 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002485{
sewardjc4a810d2002-11-13 22:25:51 +00002486 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002487 HelgrindError err_extra;
2488
njnfbdcba92005-05-09 01:23:49 +00002489 n_hg_warnings++;
sewardjff2c9232002-11-13 21:44:39 +00002490
sewardj16748af2002-10-22 04:55:54 +00002491 clear_HelgrindError(&err_extra);
2492 err_extra.isWrite = is_write;
2493 err_extra.addrinfo.akind = Undescribed;
2494 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002495 if (clo_execontext)
2496 err_extra.lasttouched = getExeContext(a);
jsgfcb1d1c02003-10-14 21:55:10 +00002497 err_extra.addrinfo.expr = VG_(describe_addr)(tid, a);
2498
njnfbdcba92005-05-09 01:23:49 +00002499 VG_(maybe_record_error)( tid, RaceErr, a,
sewardj16748af2002-10-22 04:55:54 +00002500 (is_write ? "writing" : "reading"),
2501 &err_extra);
2502
sewardjc4a810d2002-11-13 22:25:51 +00002503 sw = get_sword_addr(a);
2504 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2505 ThreadLifeSeg *tls = unpackTLS(sw->other);
2506 tls->refcount--;
2507 }
2508
sewardj7f3ad222002-11-13 22:11:53 +00002509 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002510}
2511
sewardj39a4d842002-11-13 22:14:30 +00002512static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002513 Char *str, ExeContext *ec)
2514{
2515 HelgrindError err_extra;
2516
2517 clear_HelgrindError(&err_extra);
2518 err_extra.addrinfo.akind = Undescribed;
2519 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002520 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002521 err_extra.lasttid = tid;
2522
njn72718642003-07-24 08:45:32 +00002523 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002524 (Addr)mutex->mutexp, str, &err_extra);
2525}
njn25e49d8e72002-09-23 09:36:25 +00002526
sewardj39a4d842002-11-13 22:14:30 +00002527static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002528 const LockSet *lockset_holding,
2529 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002530{
2531 HelgrindError err_extra;
2532
2533 n_lockorder_warnings++;
2534
2535 clear_HelgrindError(&err_extra);
2536 err_extra.addrinfo.akind = Undescribed;
2537 err_extra.mutex = mutex;
2538
sewardjc808ef52002-11-13 22:43:26 +00002539 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002540 err_extra.held_lockset = lockset_holding;
2541 err_extra.prev_lockset = lockset_prev;
2542
njn72718642003-07-24 08:45:32 +00002543 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002544}
2545
njn51d827b2005-05-09 01:02:08 +00002546static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002547{
njn810086f2002-11-14 12:42:47 +00002548 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002549
njnca82cc02004-11-22 17:18:48 +00002550 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002551
2552 switch (VG_(get_error_kind)(e1)) {
njnfbdcba92005-05-09 01:23:49 +00002553 case RaceErr:
njn810086f2002-11-14 12:42:47 +00002554 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002555
2556 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002557 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002558 }
2559
njn810086f2002-11-14 12:42:47 +00002560 e1s = VG_(get_error_string)(e1);
2561 e2s = VG_(get_error_string)(e2);
2562 if (e1s != e2s) return False;
2563 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002564 return True;
2565}
2566
sewardj16748af2002-10-22 04:55:54 +00002567static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002568{
jsgfcb1d1c02003-10-14 21:55:10 +00002569 if (ai->expr != NULL)
2570 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002571 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002572
sewardj16748af2002-10-22 04:55:54 +00002573 switch (ai->akind) {
2574 case Stack:
2575 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002576 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002577 a, ai->stack_tid);
2578 break;
2579 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002580 if (ai->expr != NULL)
2581 break;
2582
nethercote3b390c72003-11-13 17:53:43 +00002583 /* maybe_gcc is never set to True! This is a hangover from code
2584 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002585 if (ai->maybe_gcc) {
2586 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002587 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002588 a);
2589 VG_(message)(Vg_UserMsg,
2590 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2591 } else {
2592 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002593 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002594 }
2595 break;
2596 case Segment:
2597 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002598 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002599 a, ai->section, ai->filename);
2600 break;
sewardjdac0a442002-11-13 22:08:40 +00002601 case Mallocd:
2602 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002603 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002604 UChar* relative;
2605 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002606 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002607 relative = "before";
2608 } else if (ai->rwoffset >= ai->blksize) {
2609 delta = ai->rwoffset - ai->blksize;
2610 relative = "after";
2611 } else {
2612 delta = ai->rwoffset;
2613 relative = "inside";
2614 }
2615 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002616 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2617 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002618 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002619 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002620 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002621
sewardj16748af2002-10-22 04:55:54 +00002622 VG_(pp_ExeContext)(ai->lastchange);
2623 break;
2624 }
2625 default:
njn67993252004-11-22 18:02:32 +00002626 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002627 }
njn25e49d8e72002-09-23 09:36:25 +00002628}
2629
sewardj4bffb232002-11-13 21:46:34 +00002630static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002631{
sewardjff2c9232002-11-13 21:44:39 +00002632 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002633 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002634
sewardj4bffb232002-11-13 21:46:34 +00002635 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2636 lockset->setsize * 120 +
2637 1);
sewardjff2c9232002-11-13 21:44:39 +00002638
2639 cp = buf;
2640 if (prefix)
2641 cp += VG_(sprintf)(cp, "%s", prefix);
2642
sewardj4bffb232002-11-13 21:46:34 +00002643 for(i = 0; i < lockset->setsize; i++)
2644 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2645 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002646
sewardj4bffb232002-11-13 21:46:34 +00002647 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002648 cp[-2] = '\0';
2649 else
2650 *cp = '\0';
2651
2652 return buf;
2653}
njn25e49d8e72002-09-23 09:36:25 +00002654
njn51d827b2005-05-09 01:02:08 +00002655static void hg_pp_Error ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002656{
njn810086f2002-11-14 12:42:47 +00002657 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002658 Char buf[100];
2659 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002660 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002661
2662 *msg = '\0';
2663
njn810086f2002-11-14 12:42:47 +00002664 switch(VG_(get_error_kind)(err)) {
njnfbdcba92005-05-09 01:23:49 +00002665 case RaceErr: {
njn810086f2002-11-14 12:42:47 +00002666 Addr err_addr = VG_(get_error_address)(err);
2667
sewardj16748af2002-10-22 04:55:54 +00002668 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002669 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002670 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002671 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002672
2673 switch(extra->prevstate.state) {
2674 case Vge_Virgin:
2675 /* shouldn't be possible to go directly from virgin -> error */
2676 VG_(sprintf)(buf, "virgin!?");
2677 break;
2678
sewardjc4a810d2002-11-13 22:25:51 +00002679 case Vge_Excl: {
2680 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2681
njnca82cc02004-11-22 17:18:48 +00002682 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002683 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002684 break;
sewardjc4a810d2002-11-13 22:25:51 +00002685 }
sewardj16748af2002-10-22 04:55:54 +00002686
2687 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002688 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002689 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002690
2691 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002692 VG_(sprintf)(buf, "shared %s, no locks",
2693 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2694 break;
2695 }
2696
sewardjff2c9232002-11-13 21:44:39 +00002697 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2698 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002699 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002700
sewardj16748af2002-10-22 04:55:54 +00002701 break;
2702 }
sewardj16748af2002-10-22 04:55:54 +00002703
sewardj499e3de2002-11-13 22:22:25 +00002704 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002705 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002706
sewardj72baa7a2002-12-09 23:32:58 +00002707 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002708 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002709 Char file[100];
2710 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002711 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002712
nethercote3b390c72003-11-13 17:53:43 +00002713 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002714 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002715 pp_state(extra->lasttouched.state),
2716 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002717
nethercoteca788ff2004-10-20 10:58:09 +00002718 if (VG_(get_filename_linenum)(ip, file, sizeof(file), &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002719 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002720 ip, ip, file, line);
2721 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002722 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002723 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002724 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002725 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002726 }
sewardj72baa7a2002-12-09 23:32:58 +00002727 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002728 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002729 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002730 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002731 pp_state(extra->lasttouched.state),
2732 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002733 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002734 }
sewardj16748af2002-10-22 04:55:54 +00002735 break;
njn810086f2002-11-14 12:42:47 +00002736 }
sewardj16748af2002-10-22 04:55:54 +00002737
2738 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002739 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002740 VG_(get_error_address)(err),
2741 VG_(get_error_address)(err),
2742 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002743 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002744 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002745 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002746 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002747 }
njn810086f2002-11-14 12:42:47 +00002748 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002749 break;
sewardjff2c9232002-11-13 21:44:39 +00002750
2751 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002752 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002753 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002754 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002755
2756 msg = lockset_str(NULL, heldset);
2757
2758 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002759 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002760 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002761 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2762
sewardj4bffb232002-11-13 21:46:34 +00002763 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002764 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002765
sewardj542494b2002-11-13 22:46:13 +00002766 /* needs to be a recursive search+display */
2767 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002768 continue;
2769
nethercote3b390c72003-11-13 17:53:43 +00002770 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002771 lsmx->mutexp, lsmx->mutexp);
2772 VG_(pp_ExeContext)(lsmx->location);
2773 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002774 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002775 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002776 }
2777
2778 break;
sewardj16748af2002-10-22 04:55:54 +00002779 }
sewardjff2c9232002-11-13 21:44:39 +00002780 }
2781
2782 if (msg != buf)
2783 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002784}
2785
2786
njn51d827b2005-05-09 01:02:08 +00002787static Bool hg_recognised_suppression ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002788{
2789 if (0 == VG_(strcmp)(name, "Eraser")) {
njnfbdcba92005-05-09 01:23:49 +00002790 VG_(set_supp_kind)(su, RaceSupp);
njn25e49d8e72002-09-23 09:36:25 +00002791 return True;
2792 } else {
2793 return False;
2794 }
2795}
2796
2797
njn51d827b2005-05-09 01:02:08 +00002798static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002799{
2800 /* do nothing -- no extra suppression info present. Return True to
2801 indicate nothing bad happened. */
2802 return True;
2803}
2804
2805
njn51d827b2005-05-09 01:02:08 +00002806static Bool hg_error_matches_suppression(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002807{
njnfbdcba92005-05-09 01:23:49 +00002808 tl_assert(VG_(get_supp_kind)(su) == RaceSupp);
nethercote64366b42003-12-01 13:11:47 +00002809
njnfbdcba92005-05-09 01:23:49 +00002810 return (VG_(get_error_kind)(err) == RaceErr);
njn25e49d8e72002-09-23 09:36:25 +00002811}
2812
njn51d827b2005-05-09 01:02:08 +00002813static Char* hg_get_error_name ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002814{
njnfbdcba92005-05-09 01:23:49 +00002815 if (RaceErr == VG_(get_error_kind)(err)) {
2816 return "Eraser"; // old name, required for backwards compatibility
njn43c799e2003-04-08 00:08:52 +00002817 } else {
2818 return NULL; /* Other errors types can't be suppressed */
2819 }
2820}
2821
njn51d827b2005-05-09 01:02:08 +00002822static void hg_print_extra_suppression_info ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002823{
2824 /* Do nothing */
2825}
njn25e49d8e72002-09-23 09:36:25 +00002826
njnfbdcba92005-05-09 01:23:49 +00002827static void hg_pre_mutex_lock(ThreadId tid, void* void_mutex)
sewardjdca84112002-11-13 22:29:34 +00002828{
2829 Mutex *mutex = get_mutex((Addr)void_mutex);
2830
njn72718642003-07-24 08:45:32 +00002831 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002832}
2833
njnfbdcba92005-05-09 01:23:49 +00002834static void hg_post_mutex_lock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002835{
sewardj4bffb232002-11-13 21:46:34 +00002836 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002837 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002838 const LockSet* ls;
2839
njn72718642003-07-24 08:45:32 +00002840 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002841
njn25e49d8e72002-09-23 09:36:25 +00002842# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002843 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002844# endif
2845
njn25e49d8e72002-09-23 09:36:25 +00002846 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2847# if LOCKSET_SANITY > 1
njnfbdcba92005-05-09 01:23:49 +00002848 sanity_check_locksets("hg_post_mutex_lock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002849# endif
2850
sewardj4bffb232002-11-13 21:46:34 +00002851 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002852
sewardj4bffb232002-11-13 21:46:34 +00002853 if (ls == NULL) {
2854 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2855 insert_LockSet(newset);
2856 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002857 }
sewardj4bffb232002-11-13 21:46:34 +00002858 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002859
sewardj4bffb232002-11-13 21:46:34 +00002860 if (debug || DEBUG_LOCKS)
2861 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002862
sewardj4bffb232002-11-13 21:46:34 +00002863 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002864 sanity_check_locksets("hg_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002865}
2866
2867
njnfbdcba92005-05-09 01:23:49 +00002868static void hg_post_mutex_unlock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002869{
sewardjc26cc252002-10-23 21:58:55 +00002870 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002871 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002872 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002873 const LockSet *ls;
2874
njn72718642003-07-24 08:45:32 +00002875 test_mutex_state(mutex, MxUnlocked, tid);
2876 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002877
sewardjdac0a442002-11-13 22:08:40 +00002878 if (!ismember(thread_locks[tid], mutex))
2879 return;
2880
sewardjc26cc252002-10-23 21:58:55 +00002881 if (debug || DEBUG_LOCKS)
2882 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002883
sewardjc26cc252002-10-23 21:58:55 +00002884 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002885 sanity_check_locksets("hg_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002886
sewardj4bffb232002-11-13 21:46:34 +00002887 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002888
sewardj4bffb232002-11-13 21:46:34 +00002889 if (ls == NULL) {
2890 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2891 insert_LockSet(newset);
2892 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002893 }
2894
2895 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002896 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002897 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002898 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002899
sewardj4bffb232002-11-13 21:46:34 +00002900 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002901
sewardjc26cc252002-10-23 21:58:55 +00002902 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002903 sanity_check_locksets("hg_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002904}
2905
2906
2907/* ---------------------------------------------------------------------
2908 Checking memory reads and writes
2909 ------------------------------------------------------------------ */
2910
2911/* Behaviour on reads and writes:
2912 *
2913 * VIR EXCL SHAR SH_MOD
2914 * ----------------------------------------------------------------
2915 * rd/wr, 1st thread | - EXCL - -
2916 * rd, new thread | - SHAR - -
2917 * wr, new thread | - SH_MOD - -
2918 * rd | error! - SHAR SH_MOD
2919 * wr | EXCL - SH_MOD SH_MOD
2920 * ----------------------------------------------------------------
2921 */
2922
sewardj8fac99a2002-11-13 22:31:26 +00002923static inline
njn25e49d8e72002-09-23 09:36:25 +00002924void dump_around_a(Addr a)
2925{
2926 UInt i;
2927 shadow_word* sword;
2928 VG_(printf)("NEARBY:\n");
2929 for (i = a - 12; i <= a + 12; i += 4) {
2930 sword = get_sword_addr(i);
2931 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2932 }
2933}
njn25e49d8e72002-09-23 09:36:25 +00002934
2935#if DEBUG_ACCESSES
2936 #define DEBUG_STATE(args...) \
2937 VG_(printf)("(%u) ", size), \
2938 VG_(printf)(args)
2939#else
2940 #define DEBUG_STATE(args...)
2941#endif
2942
njnfbdcba92005-05-09 01:23:49 +00002943static void hg_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002944{
sewardj72baa7a2002-12-09 23:32:58 +00002945 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002946 shadow_word prevstate;
2947 ThreadLifeSeg *tls;
2948 const LockSet *ls;
2949 Bool statechange = False;
2950
2951 static const void *const states[4] = {
2952 [Vge_Virgin] &&st_virgin,
2953 [Vge_Excl] &&st_excl,
2954 [Vge_Shar] &&st_shar,
2955 [Vge_SharMod] &&st_sharmod,
2956 };
2957
2958 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002959 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002960
2961 sword = get_sword_addr(a);
2962 if (sword == SEC_MAP_ACCESS) {
2963 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2964 return;
2965 }
2966
2967 prevstate = *sword;
2968
2969 goto *states[sword->state];
2970
2971 /* This looks like reading of unitialised memory, may be legit. Eg.
2972 * calloc() zeroes its values, so untouched memory may actually be
2973 * initialised. Leave that stuff to Valgrind. */
2974 st_virgin:
2975 if (TID_INDICATING_NONVIRGIN == sword->other) {
2976 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
2977 if (DEBUG_VIRGIN_READS)
2978 dump_around_a(a);
2979 } else {
2980 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
2981 }
2982 statechange = True;
2983 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
2984 tls->refcount++;
2985 goto done;
2986
2987 st_excl: {
2988 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
2989
2990 if (tls == sw_tls) {
2991 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
2992 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
2993 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
2994 } else if (tlsIsDisjoint(tls, sw_tls)) {
2995 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
2996 statechange = True;
2997 sword->other = packTLS(tls);
2998 sw_tls->refcount--;
2999 tls->refcount++;
3000 } else {
3001 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3002 sw_tls->refcount--;
3003 statechange = True;
3004 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3005
3006 if (DEBUG_MEM_LOCKSET_CHANGES)
3007 print_LockSet("excl read locks", unpackLockSet(sword->other));
3008 }
3009 goto done;
3010 }
3011
3012 st_shar:
3013 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3014 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3015 thread_locks[tid]));
3016 statechange = sword->other != prevstate.other;
3017 goto done;
3018
3019 st_sharmod:
3020 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3021 ls = intersect(unpackLockSet(sword->other),
3022 thread_locks[tid]);
3023 sword->other = packLockSet(ls);
3024
3025 statechange = sword->other != prevstate.other;
3026
3027 if (isempty(ls)) {
njnfbdcba92005-05-09 01:23:49 +00003028 record_race_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003029 }
3030 goto done;
3031
3032 done:
3033 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003034 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003035
3036 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003037 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003038 else
njnd01fef72005-03-25 23:35:48 +00003039 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003040 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003041 }
3042}
njn25e49d8e72002-09-23 09:36:25 +00003043
njnfbdcba92005-05-09 01:23:49 +00003044static void hg_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003045{
njn72718642003-07-24 08:45:32 +00003046 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003047
sewardj8fac99a2002-11-13 22:31:26 +00003048 end = ROUNDUP(a+size, 4);
3049 a = ROUNDDN(a, 4);
3050
sewardj18cd4a52002-11-13 22:37:41 +00003051 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003052 hg_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003053}
3054
njnfbdcba92005-05-09 01:23:49 +00003055static void hg_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003056{
3057 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003058 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003059 shadow_word prevstate;
3060 Bool statechange = False;
3061 static const void *const states[4] = {
3062 [Vge_Virgin] &&st_virgin,
3063 [Vge_Excl] &&st_excl,
3064 [Vge_Shar] &&st_shar,
3065 [Vge_SharMod] &&st_sharmod,
3066 };
3067
sewardjc4a810d2002-11-13 22:25:51 +00003068 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003069 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003070
sewardj18cd4a52002-11-13 22:37:41 +00003071 sword = get_sword_addr(a);
3072 if (sword == SEC_MAP_ACCESS) {
3073 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3074 return;
3075 }
njn25e49d8e72002-09-23 09:36:25 +00003076
sewardj18cd4a52002-11-13 22:37:41 +00003077 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003078
sewardj18cd4a52002-11-13 22:37:41 +00003079 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003080
sewardj18cd4a52002-11-13 22:37:41 +00003081 st_virgin:
3082 if (TID_INDICATING_NONVIRGIN == sword->other)
3083 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3084 else
3085 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3086 statechange = True;
3087 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3088 tls->refcount++;
3089 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003090
sewardj18cd4a52002-11-13 22:37:41 +00003091 st_excl: {
3092 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3093
3094 if (tls == sw_tls) {
3095 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3096 goto done;
3097 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3098 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3099 goto done;
3100 } else if (tlsIsDisjoint(tls, sw_tls)) {
3101 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3102 sword->other = packTLS(tls);
3103 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003104 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003105 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003106 } else {
3107 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3108 statechange = True;
3109 sw_tls->refcount--;
3110 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3111 if(DEBUG_MEM_LOCKSET_CHANGES)
3112 print_LockSet("excl write locks", unpackLockSet(sword->other));
3113 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003114 }
sewardj18cd4a52002-11-13 22:37:41 +00003115 }
njn25e49d8e72002-09-23 09:36:25 +00003116
sewardj18cd4a52002-11-13 22:37:41 +00003117 st_shar:
3118 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3119 sword->state = Vge_SharMod;
3120 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3121 thread_locks[tid]));
3122 statechange = True;
3123 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003124
sewardj18cd4a52002-11-13 22:37:41 +00003125 st_sharmod:
3126 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3127 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3128 thread_locks[tid]));
3129 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003130
sewardj18cd4a52002-11-13 22:37:41 +00003131 SHARED_MODIFIED:
3132 if (isempty(unpackLockSet(sword->other))) {
njnfbdcba92005-05-09 01:23:49 +00003133 record_race_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003134 }
3135 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003136
sewardj18cd4a52002-11-13 22:37:41 +00003137 done:
3138 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003139 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003140
sewardj18cd4a52002-11-13 22:37:41 +00003141 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003142 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003143 else
njnd01fef72005-03-25 23:35:48 +00003144 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003145 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003146 }
3147}
3148
njnfbdcba92005-05-09 01:23:49 +00003149static void hg_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003150{
sewardj8fac99a2002-11-13 22:31:26 +00003151 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003152
sewardj8fac99a2002-11-13 22:31:26 +00003153 end = ROUNDUP(a+size, 4);
3154 a = ROUNDDN(a, 4);
3155
sewardj18cd4a52002-11-13 22:37:41 +00003156 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003157 hg_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003158}
3159
3160#undef DEBUG_STATE
3161
njnfbdcba92005-05-09 01:23:49 +00003162VGA_REGPARM(1) static void hg_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003163{
njnfbdcba92005-05-09 01:23:49 +00003164 hg_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003165}
3166
njnfbdcba92005-05-09 01:23:49 +00003167VGA_REGPARM(1) static void hg_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003168{
njnfbdcba92005-05-09 01:23:49 +00003169 hg_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003170}
3171
njnfbdcba92005-05-09 01:23:49 +00003172VGA_REGPARM(1) static void hg_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003173{
njnfbdcba92005-05-09 01:23:49 +00003174 hg_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003175}
3176
njnfbdcba92005-05-09 01:23:49 +00003177VGA_REGPARM(2) static void hg_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003178{
njnfbdcba92005-05-09 01:23:49 +00003179 hg_mem_read(a, size, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003180}
3181
njnfbdcba92005-05-09 01:23:49 +00003182VGA_REGPARM(2) static void hg_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003183{
3184 if (*(UChar *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003185 hg_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003186}
njnfbdcba92005-05-09 01:23:49 +00003187VGA_REGPARM(2) static void hg_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003188{
3189 if (*(UShort *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003190 hg_mem_write(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003191}
njnfbdcba92005-05-09 01:23:49 +00003192VGA_REGPARM(2) static void hg_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003193{
3194 if (*(UInt *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003195 hg_mem_write(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003196}
njnfbdcba92005-05-09 01:23:49 +00003197VGA_REGPARM(2) static void hg_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003198{
njnfbdcba92005-05-09 01:23:49 +00003199 hg_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003200}
njn25e49d8e72002-09-23 09:36:25 +00003201
sewardjc4a810d2002-11-13 22:25:51 +00003202static void hg_thread_create(ThreadId parent, ThreadId child)
3203{
3204 if (0)
3205 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3206
3207 newTLS(child);
3208 addPriorTLS(child, parent);
3209
3210 newTLS(parent);
3211}
3212
3213static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3214{
3215 if (0)
3216 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3217
3218 newTLS(joiner);
3219 addPriorTLS(joiner, joinee);
3220
3221 clearTLS(joinee);
3222}
3223
sewardj7a5ebcf2002-11-13 22:42:13 +00003224static Int __BUS_HARDWARE_LOCK__;
3225
3226static void bus_lock(void)
3227{
njn95e65f62005-03-30 04:13:56 +00003228 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003229 hg_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3230 hg_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003231}
3232
3233static void bus_unlock(void)
3234{
njn95e65f62005-03-30 04:13:56 +00003235 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003236 hg_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003237}
3238
njn25e49d8e72002-09-23 09:36:25 +00003239/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003240/*--- Client requests ---*/
3241/*--------------------------------------------------------------------*/
3242
njn51d827b2005-05-09 01:02:08 +00003243static Bool hg_handle_client_request(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003244{
njnfc26ff92004-11-22 19:12:49 +00003245 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003246 return False;
3247
3248 switch(args[0]) {
3249 case VG_USERREQ__HG_CLEAN_MEMORY:
3250 set_address_range_state(args[1], args[2], Vge_VirginInit);
3251 *ret = 0; /* meaningless */
3252 break;
3253
3254 case VG_USERREQ__HG_KNOWN_RACE:
3255 set_address_range_state(args[1], args[2], Vge_Error);
3256 *ret = 0; /* meaningless */
3257 break;
3258
3259 default:
3260 return False;
3261 }
3262
3263 return True;
3264}
3265
3266
3267/*--------------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00003268/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00003269/*--------------------------------------------------------------------*/
3270
njn51d827b2005-05-09 01:02:08 +00003271static Bool hg_process_cmd_line_option(Char* arg)
3272{
3273 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3274 clo_execontext = EC_None;
3275 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3276 clo_execontext = EC_Some;
3277 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3278 clo_execontext = EC_All;
3279
3280 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
3281
3282 else
3283 return VG_(replacement_malloc_process_cmd_line_option)(arg);
3284
3285 return True;
3286}
3287
3288static void hg_print_usage(void)
3289{
3290 VG_(printf)(
3291" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3292" --show-last-access=no|some|all\n"
3293" show location of last word access on error [no]\n"
3294 );
3295 VG_(replacement_malloc_print_usage)();
3296}
3297
3298static void hg_print_debug_usage(void)
3299{
3300 VG_(replacement_malloc_print_debug_usage)();
3301}
3302
3303static void hg_post_clo_init(void)
3304{
3305 void (*stack_tracker)(Addr a, SizeT len);
3306
3307 if (clo_execontext) {
3308 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3309 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3310 }
3311
3312 if (clo_priv_stacks)
njnfbdcba92005-05-09 01:23:49 +00003313 stack_tracker = & hg_new_mem_stack_private;
njn51d827b2005-05-09 01:02:08 +00003314 else
njnfbdcba92005-05-09 01:23:49 +00003315 stack_tracker = & hg_new_mem_stack;
njn51d827b2005-05-09 01:02:08 +00003316
3317 VG_(track_new_mem_stack) (stack_tracker);
3318 VG_(track_new_mem_stack_signal) (stack_tracker);
3319}
3320
3321
3322static void hg_fini(Int exitcode)
3323{
3324 if (DEBUG_LOCK_TABLE) {
3325 pp_all_LockSets();
3326 pp_all_mutexes();
3327 }
3328
3329 if (LOCKSET_SANITY)
3330 sanity_check_locksets("hg_fini");
3331
3332 if (VG_(clo_verbosity) > 0)
3333 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
njnfbdcba92005-05-09 01:23:49 +00003334 n_hg_warnings, n_lockorder_warnings);
njn51d827b2005-05-09 01:02:08 +00003335
3336 if (0)
3337 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3338 stk_ld, stk_st, stk_ld + stk_st,
3339 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3340 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
3341}
3342
3343static void hg_pre_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00003344{
3345 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003346 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003347
njn810086f2002-11-14 12:42:47 +00003348 VG_(details_name) ("Helgrind");
3349 VG_(details_version) (NULL);
3350 VG_(details_description) ("a data race detector");
3351 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +00003352 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003353 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003354 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003355
njn51d827b2005-05-09 01:02:08 +00003356 VG_(basic_tool_funcs) (hg_post_clo_init,
3357 hg_instrument,
3358 hg_fini);
tomc756a8e2005-03-31 07:59:35 +00003359
3360 VG_(needs_core_errors) ();
njn51d827b2005-05-09 01:02:08 +00003361 VG_(needs_tool_errors) (hg_eq_Error,
3362 hg_pp_Error,
3363 hg_update_extra,
3364 hg_recognised_suppression,
3365 hg_read_extra_suppression_info,
3366 hg_error_matches_suppression,
3367 hg_get_error_name,
3368 hg_print_extra_suppression_info);
tomc756a8e2005-03-31 07:59:35 +00003369 VG_(needs_data_syms) ();
njn51d827b2005-05-09 01:02:08 +00003370 VG_(needs_client_requests) (hg_handle_client_request);
3371 VG_(needs_sanity_checks) (hg_cheap_sanity_check,
3372 hg_expensive_sanity_check);
3373 VG_(needs_command_line_options)(hg_process_cmd_line_option,
3374 hg_print_usage,
3375 hg_print_debug_usage);
tomc756a8e2005-03-31 07:59:35 +00003376 VG_(needs_shadow_memory) ();
3377
njn51d827b2005-05-09 01:02:08 +00003378 VG_(malloc_funcs) (hg_malloc,
3379 hg___builtin_new,
3380 hg___builtin_vec_new,
3381 hg_memalign,
3382 hg_calloc,
3383 hg_free,
3384 hg___builtin_delete,
3385 hg___builtin_vec_delete,
3386 hg_realloc,
tomc756a8e2005-03-31 07:59:35 +00003387 8 );
njn25e49d8e72002-09-23 09:36:25 +00003388
njnfbdcba92005-05-09 01:23:49 +00003389 VG_(track_new_mem_startup) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003390
njn51d827b2005-05-09 01:02:08 +00003391 /* stack ones not decided until hg_post_clo_init() */
njn25e49d8e72002-09-23 09:36:25 +00003392
njn51d827b2005-05-09 01:02:08 +00003393 VG_(track_new_mem_brk) (& make_writable);
njnfbdcba92005-05-09 01:23:49 +00003394 VG_(track_new_mem_mmap) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003395
njnfbdcba92005-05-09 01:23:49 +00003396 VG_(track_change_mem_mprotect) (& hg_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003397
njn51d827b2005-05-09 01:02:08 +00003398 VG_(track_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003399
njn51d827b2005-05-09 01:02:08 +00003400 VG_(track_die_mem_stack) (NULL);
3401 VG_(track_die_mem_stack_signal)(NULL);
3402 VG_(track_die_mem_brk) (NULL);
3403 VG_(track_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003404
njnfbdcba92005-05-09 01:23:49 +00003405 VG_(track_pre_mem_read) (& hg_pre_mem_read);
3406 VG_(track_pre_mem_read_asciiz) (& hg_pre_mem_read_asciiz);
3407 VG_(track_pre_mem_write) (& hg_pre_mem_write);
njn51d827b2005-05-09 01:02:08 +00003408 VG_(track_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003409
njn51d827b2005-05-09 01:02:08 +00003410 VG_(track_post_thread_create) (& hg_thread_create);
3411 VG_(track_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003412
njnfbdcba92005-05-09 01:23:49 +00003413 VG_(track_pre_mutex_lock) (& hg_pre_mutex_lock);
3414 VG_(track_post_mutex_lock) (& hg_post_mutex_lock);
3415 VG_(track_post_mutex_unlock) (& hg_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003416
njn14d01ce2004-11-26 11:30:14 +00003417 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003418 lockset_hash[i] = NULL;
3419
3420 empty = alloc_LockSet(0);
3421 insert_LockSet(empty);
3422 emptyset = empty;
3423
sewardjc4a810d2002-11-13 22:25:51 +00003424 /* Init lock table and thread segments */
3425 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003426 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003427
sewardjc4a810d2002-11-13 22:25:51 +00003428 newTLS(i);
3429 }
3430
njn25e49d8e72002-09-23 09:36:25 +00003431 init_shadow_memory();
njn3e884182003-04-15 13:03:23 +00003432 hg_malloc_list = VG_(HT_construct)();
njn25e49d8e72002-09-23 09:36:25 +00003433}
3434
fitzhardinge98abfc72003-12-16 02:05:15 +00003435/* Uses a 1:1 mapping */
njn51d827b2005-05-09 01:02:08 +00003436VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init, 1.0)
fitzhardinge98abfc72003-12-16 02:05:15 +00003437
njn25e49d8e72002-09-23 09:36:25 +00003438/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003439/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003440/*--------------------------------------------------------------------*/