blob: e93bdea44bb0ac5602d33329b275cbfdd84e2369 [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
nethercotebb1c9912004-01-04 16:43:23 +000011 Copyright (C) 2002-2004 Nicholas Nethercote
njn25e49d8e72002-09-23 09:36:25 +000012 njn25@cam.ac.uk
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
nethercote46063202004-09-02 08:51:43 +000032#include "tool.h"
sewardj7f3ad222002-11-13 22:11:53 +000033#include "helgrind.h"
njn25e49d8e72002-09-23 09:36:25 +000034
njn25e49d8e72002-09-23 09:36:25 +000035static UInt n_eraser_warnings = 0;
sewardjff2c9232002-11-13 21:44:39 +000036static UInt n_lockorder_warnings = 0;
njn25e49d8e72002-09-23 09:36:25 +000037
38/*------------------------------------------------------------*/
39/*--- Debug guff ---*/
40/*------------------------------------------------------------*/
41
sewardje11d6c82002-12-15 02:00:41 +000042#define DEBUG_LOCK_TABLE 0 /* Print lock table at end */
njn25e49d8e72002-09-23 09:36:25 +000043
44#define DEBUG_MAKE_ACCESSES 0 /* Print make_access() calls */
45#define DEBUG_LOCKS 0 /* Print lock()/unlock() calls and locksets */
46#define DEBUG_NEW_LOCKSETS 0 /* Print new locksets when created */
47#define DEBUG_ACCESSES 0 /* Print reads, writes */
48#define DEBUG_MEM_LOCKSET_CHANGES 0
49 /* Print when an address's lockset
50 changes; only useful with
51 DEBUG_ACCESSES */
sewardj8fac99a2002-11-13 22:31:26 +000052#define SLOW_ASSERTS 0 /* do expensive asserts */
njn25e49d8e72002-09-23 09:36:25 +000053#define DEBUG_VIRGIN_READS 0 /* Dump around address on VIRGIN reads */
54
sewardj8fac99a2002-11-13 22:31:26 +000055#if SLOW_ASSERTS
njn94065fd2004-11-22 19:26:27 +000056#define TL_ASSERT(x) tl_assert(x)
sewardj8fac99a2002-11-13 22:31:26 +000057#else
njn94065fd2004-11-22 19:26:27 +000058#define TL_ASSERT(x)
sewardj8fac99a2002-11-13 22:31:26 +000059#endif
60
njn25e49d8e72002-09-23 09:36:25 +000061/* heavyweight LockSet sanity checking:
62 0 == never
63 1 == after important ops
64 2 == As 1 and also after pthread_mutex_* ops (excessively slow)
65 */
66#define LOCKSET_SANITY 0
67
sewardj8fac99a2002-11-13 22:31:26 +000068/* Rotate an unsigned quantity left */
69#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x)*8)-(n))))
70
71/* round a up to the next multiple of N. N must be a power of 2 */
72#define ROUNDUP(a, N) ((a + N - 1) & ~(N-1))
73
74/* Round a down to the next multiple of N. N must be a power of 2 */
75#define ROUNDDN(a, N) ((a) & ~(N-1))
njn25e49d8e72002-09-23 09:36:25 +000076
77/*------------------------------------------------------------*/
sewardjf6374322002-11-13 22:35:55 +000078/*--- Command line options ---*/
79/*------------------------------------------------------------*/
80
81static enum {
82 EC_None,
83 EC_Some,
84 EC_All
85} clo_execontext = EC_None;
86
sewardje1a39f42002-12-15 01:56:17 +000087static Bool clo_priv_stacks = False;
sewardjf6374322002-11-13 22:35:55 +000088
89/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000090/*--- Crude profiling machinery. ---*/
91/*------------------------------------------------------------*/
92
93// PPP: work out if I want this
94
95#define PROF_EVENT(x)
96#if 0
97#ifdef VG_PROFILE_MEMORY
98
99#define N_PROF_EVENTS 150
100
101static UInt event_ctr[N_PROF_EVENTS];
102
103void VGE_(done_prof_mem) ( void )
104{
105 Int i;
106 for (i = 0; i < N_PROF_EVENTS; i++) {
107 if ((i % 10) == 0)
108 VG_(printf)("\n");
109 if (event_ctr[i] > 0)
110 VG_(printf)( "prof mem event %2d: %d\n", i, event_ctr[i] );
111 }
112 VG_(printf)("\n");
113}
114
115#define PROF_EVENT(ev) \
njnca82cc02004-11-22 17:18:48 +0000116 do { tl_assert((ev) >= 0 && (ev) < N_PROF_EVENTS); \
njn25e49d8e72002-09-23 09:36:25 +0000117 event_ctr[ev]++; \
118 } while (False);
119
120#else
121
122//static void init_prof_mem ( void ) { }
123// void VG_(done_prof_mem) ( void ) { }
124
125#define PROF_EVENT(ev) /* */
126
127#endif /* VG_PROFILE_MEMORY */
128
129/* Event index. If just the name of the fn is given, this means the
130 number of calls to the fn. Otherwise it is the specified event.
131
132 [PPP: snip event numbers...]
133*/
134#endif /* 0 */
135
136
137/*------------------------------------------------------------*/
138/*--- Data defns. ---*/
139/*------------------------------------------------------------*/
140
njn3e884182003-04-15 13:03:23 +0000141typedef
142 struct _HG_Chunk {
143 struct _HG_Chunk* next;
144 Addr data; /* ptr to actual block */
nethercote928a5f72004-11-03 18:10:37 +0000145 SizeT size; /* size requested */
njn3e884182003-04-15 13:03:23 +0000146 ExeContext* where; /* where it was allocated */
147 ThreadId tid; /* allocating thread */
148 }
149 HG_Chunk;
150
njn25e49d8e72002-09-23 09:36:25 +0000151typedef enum
sewardj7f3ad222002-11-13 22:11:53 +0000152 { Vge_VirginInit, Vge_NonVirginInit, Vge_SegmentInit, Vge_Error }
njn25e49d8e72002-09-23 09:36:25 +0000153 VgeInitStatus;
154
sewardjc808ef52002-11-13 22:43:26 +0000155
njnc6168192004-11-29 13:54:10 +0000156// XXX: not 64-bit clean!
njn25e49d8e72002-09-23 09:36:25 +0000157/* Should add up to 32 to fit in one word */
158#define OTHER_BITS 30
159#define STATE_BITS 2
160
161#define ESEC_MAP_WORDS 16384 /* Words per secondary map */
162
163/* This is for indicating that a memory block has been initialised but not
164 * really directly by a particular thread... (eg. text/data initialised
165 * automatically at startup).
166 * Must be different to virgin_word.other */
167#define TID_INDICATING_NONVIRGIN 1
168
sewardjc4a810d2002-11-13 22:25:51 +0000169/* Magic packed TLS used for error suppression; if word state is Excl
170 and tid is this, then it means all access are OK without changing
171 state and without raising any more errors */
172#define TLSP_INDICATING_ALL ((1 << OTHER_BITS) - 1)
sewardj16748af2002-10-22 04:55:54 +0000173
njn25e49d8e72002-09-23 09:36:25 +0000174/* Number of entries must fit in STATE_BITS bits */
175typedef enum { Vge_Virgin, Vge_Excl, Vge_Shar, Vge_SharMod } pth_state;
176
sewardjc808ef52002-11-13 22:43:26 +0000177static inline const Char *pp_state(pth_state st)
178{
179 const Char *ret;
180
181 switch(st) {
182 case Vge_Virgin: ret = "virgin"; break;
183 case Vge_Excl: ret = "exclusive"; break;
184 case Vge_Shar: ret = "shared RO"; break;
185 case Vge_SharMod: ret = "shared RW"; break;
186 default: ret = "???";
187 }
188 return ret;
189}
190
njn25e49d8e72002-09-23 09:36:25 +0000191typedef
192 struct {
sewardj8fac99a2002-11-13 22:31:26 +0000193 /* gcc arranges this bitfield with state in the 2LSB and other
194 in the 30MSB, which is what we want */
njn25e49d8e72002-09-23 09:36:25 +0000195 UInt state:STATE_BITS;
sewardj8fac99a2002-11-13 22:31:26 +0000196 UInt other:OTHER_BITS;
njn25e49d8e72002-09-23 09:36:25 +0000197 } shadow_word;
198
sewardj8fac99a2002-11-13 22:31:26 +0000199#define SW(st, other) ((shadow_word) { st, other })
200
njn25e49d8e72002-09-23 09:36:25 +0000201typedef
202 struct {
203 shadow_word swords[ESEC_MAP_WORDS];
204 }
205 ESecMap;
206
207static ESecMap* primary_map[ 65536 ];
208static ESecMap distinguished_secondary_map;
209
sewardj8fac99a2002-11-13 22:31:26 +0000210static const shadow_word virgin_sword = SW(Vge_Virgin, 0);
211static const shadow_word error_sword = SW(Vge_Excl, TLSP_INDICATING_ALL);
njn25e49d8e72002-09-23 09:36:25 +0000212
213#define VGE_IS_DISTINGUISHED_SM(smap) \
214 ((smap) == &distinguished_secondary_map)
215
216#define ENSURE_MAPPABLE(addr,caller) \
217 do { \
218 if (VGE_IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
219 primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
220 /*VG_(printf)("new 2map because of %p\n", addr);*/ \
221 } \
222 } while(0)
223
224
sewardjc808ef52002-11-13 22:43:26 +0000225/* Parallel map which contains execution contexts when words last
226 changed state (if required) */
sewardj499e3de2002-11-13 22:22:25 +0000227
nethercoteca788ff2004-10-20 10:58:09 +0000228typedef struct EC_IP {
229 union u_ec_ip {
230 Addr ip;
sewardjc808ef52002-11-13 22:43:26 +0000231 ExeContext *ec;
nethercoteca788ff2004-10-20 10:58:09 +0000232 } uu_ec_ip;
sewardjc808ef52002-11-13 22:43:26 +0000233 UInt state:STATE_BITS;
234 UInt tls:OTHER_BITS; /* packed TLS */
nethercoteca788ff2004-10-20 10:58:09 +0000235} EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000236
nethercoteca788ff2004-10-20 10:58:09 +0000237#define NULL_EC_IP ((EC_IP){ { 0 }, 0, 0})
sewardjc808ef52002-11-13 22:43:26 +0000238
nethercoteca788ff2004-10-20 10:58:09 +0000239#define IP(ip, prev, tls) ((EC_IP) { (union u_ec_ip)(ip), (prev).state, packTLS(tls) })
240#define EC(ec, prev, tls) ((EC_IP) { (union u_ec_ip)(ec), (prev).state, packTLS(tls) })
sewardjc808ef52002-11-13 22:43:26 +0000241
242static inline UInt packEC(ExeContext *ec)
243{
njn94065fd2004-11-22 19:26:27 +0000244 TL_ASSERT(((UWord)ec & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000245 return ((UWord)ec) >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000246}
247
nethercoteca788ff2004-10-20 10:58:09 +0000248/* Lose 2 LSB of IP */
249static inline UInt packIP(Addr ip)
sewardjc808ef52002-11-13 22:43:26 +0000250{
nethercote50397c22004-11-04 18:03:06 +0000251 return ip >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000252}
253
nethercoteca788ff2004-10-20 10:58:09 +0000254static inline Addr unpackIP(UInt i)
sewardjc808ef52002-11-13 22:43:26 +0000255{
256 return (Addr)(i << STATE_BITS);
257}
sewardj499e3de2002-11-13 22:22:25 +0000258
259typedef struct {
nethercoteca788ff2004-10-20 10:58:09 +0000260 EC_IP execontext[ESEC_MAP_WORDS];
sewardj499e3de2002-11-13 22:22:25 +0000261} ExeContextMap;
262
263static ExeContextMap** execontext_map;
264
nethercoteca788ff2004-10-20 10:58:09 +0000265static inline void setExeContext(Addr a, EC_IP ec)
sewardj499e3de2002-11-13 22:22:25 +0000266{
267 UInt idx = (a >> 16) & 0xffff;
268 UInt off = (a >> 2) & 0x3fff;
269
270 if (execontext_map[idx] == NULL) {
271 execontext_map[idx] = VG_(malloc)(sizeof(ExeContextMap));
272 VG_(memset)(execontext_map[idx], 0, sizeof(ExeContextMap));
273 }
274
275 execontext_map[idx]->execontext[off] = ec;
276}
277
nethercoteca788ff2004-10-20 10:58:09 +0000278static inline EC_IP getExeContext(Addr a)
sewardj499e3de2002-11-13 22:22:25 +0000279{
280 UInt idx = (a >> 16) & 0xffff;
281 UInt off = (a >> 2) & 0x3fff;
nethercoteca788ff2004-10-20 10:58:09 +0000282 EC_IP ec = NULL_EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000283
284 if (execontext_map[idx] != NULL)
285 ec = execontext_map[idx]->execontext[off];
286
287 return ec;
288}
289
njn25e49d8e72002-09-23 09:36:25 +0000290/*------------------------------------------------------------*/
sewardjc4a810d2002-11-13 22:25:51 +0000291/*--- Thread lifetime segments ---*/
292/*------------------------------------------------------------*/
293
294/*
295 * This mechanism deals with the common case of a parent thread
296 * creating a structure for a child thread, and then passing ownership
297 * of the structure to that thread. It similarly copes with a child
298 * thread passing information back to another thread waiting to join
299 * on it.
300 *
301 * Each thread's lifetime can be partitioned into segments. Those
302 * segments are arranged to form an interference graph which indicates
303 * whether two thread lifetime segments can possibly be concurrent.
304 * If not, then memory with is exclusively accessed by one TLS can be
daywalker7e73e5f2003-07-04 16:18:15 +0000305 * passed on to another TLS without an error occurring, and without
sewardjc4a810d2002-11-13 22:25:51 +0000306 * moving it from Excl state.
307 *
308 * At present this only considers thread creation and join as
309 * synchronisation events for creating new lifetime segments, but
310 * others may be possible (like mutex operations).
311 */
312
313typedef struct _ThreadLifeSeg ThreadLifeSeg;
314
315struct _ThreadLifeSeg {
316 ThreadId tid;
317 ThreadLifeSeg *prior[2]; /* Previous lifetime segments */
318 UInt refcount; /* Number of memory locations pointing here */
319 UInt mark; /* mark used for graph traversal */
320 ThreadLifeSeg *next; /* list of all TLS */
321};
322
323static ThreadLifeSeg *all_tls;
324static UInt tls_since_gc;
325#define TLS_SINCE_GC 10000
326
327/* current mark used for TLS graph traversal */
328static UInt tlsmark;
329
330static ThreadLifeSeg *thread_seg[VG_N_THREADS];
331
332
333static void tls_gc(void)
334{
335 /* XXX later. Walk through all TLSs and look for ones with 0
336 refcount and remove them from the structure and free them.
337 Could probably get rid of ThreadLifeSeg.refcount and simply use
338 mark-sweep from the shadow table. */
339 VG_(printf)("WRITEME: TLS GC\n");
340}
341
342static void newTLS(ThreadId tid)
343{
344 static const Bool debug = False;
345 ThreadLifeSeg *tls;
346
347 /* Initial NULL */
348 if (thread_seg[tid] == NULL) {
349 tls = VG_(malloc)(sizeof(*tls));
350 tls->tid = tid;
351 tls->prior[0] = tls->prior[1] = NULL;
352 tls->refcount = 0;
353 tls->mark = tlsmark-1;
354
355 tls->next = all_tls;
356 all_tls = tls;
357 tls_since_gc++;
358
359 thread_seg[tid] = tls;
360 return;
361 }
362
363 /* Previous TLS was unused, so just recycle */
364 if (thread_seg[tid]->refcount == 0) {
365 if (debug)
366 VG_(printf)("newTLS; recycling TLS %p for tid %u\n",
367 thread_seg[tid], tid);
368 return;
369 }
370
371 /* Use existing TLS for this tid as a prior for new TLS */
372 tls = VG_(malloc)(sizeof(*tls));
373 tls->tid = tid;
374 tls->prior[0] = thread_seg[tid];
375 tls->prior[1] = NULL;
376 tls->refcount = 0;
377 tls->mark = tlsmark-1;
378
379 tls->next = all_tls;
380 all_tls = tls;
381 if (++tls_since_gc > TLS_SINCE_GC) {
382 tls_gc();
383 tls_since_gc = 0;
384 }
385
386 if (debug)
387 VG_(printf)("newTLS: made new TLS %p for tid %u (prior %p(%u))\n",
388 tls, tid, tls->prior[0], tls->prior[0]->tid);
389
390 thread_seg[tid] = tls;
391}
392
393/* clear out a TLS for a thread that's died */
394static void clearTLS(ThreadId tid)
395{
396 newTLS(tid);
397
398 thread_seg[tid]->prior[0] = NULL;
399 thread_seg[tid]->prior[1] = NULL;
400}
401
402static void addPriorTLS(ThreadId tid, ThreadId prior)
403{
404 static const Bool debug = False;
405 ThreadLifeSeg *tls = thread_seg[tid];
406
407 if (debug)
408 VG_(printf)("making TLS %p(%u) prior to TLS %p(%u)\n",
409 thread_seg[prior], prior, tls, tid);
410
njnca82cc02004-11-22 17:18:48 +0000411 tl_assert(thread_seg[tid] != NULL);
412 tl_assert(thread_seg[prior] != NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000413
414 if (tls->prior[0] == NULL)
415 tls->prior[0] = thread_seg[prior];
416 else {
njnca82cc02004-11-22 17:18:48 +0000417 tl_assert(tls->prior[1] == NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000418 tls->prior[1] = thread_seg[prior];
419 }
420}
421
422/* Return True if prior is definitely not concurrent with tls */
423static Bool tlsIsDisjoint(const ThreadLifeSeg *tls,
424 const ThreadLifeSeg *prior)
425{
426 Bool isPrior(const ThreadLifeSeg *t) {
427 if (t == NULL || t->mark == tlsmark)
428 return False;
429
430 if (t == prior)
431 return True;
432
433 ((ThreadLifeSeg *)t)->mark = tlsmark;
434
435 return isPrior(t->prior[0]) || isPrior(t->prior[1]);
436 }
437 tlsmark++; /* new traversal mark */
438
439 return isPrior(tls);
440}
441
442static inline UInt packTLS(ThreadLifeSeg *tls)
443{
njn94065fd2004-11-22 19:26:27 +0000444 TL_ASSERT(((UWord)tls & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000445 return ((UWord)tls) >> STATE_BITS;
sewardjc4a810d2002-11-13 22:25:51 +0000446}
447
448static inline ThreadLifeSeg *unpackTLS(UInt i)
449{
450 return (ThreadLifeSeg *)(i << STATE_BITS);
451}
452
453/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000454/*--- Low-level support for memory tracking. ---*/
455/*------------------------------------------------------------*/
456
457/*
458 All reads and writes are recorded in the memory map, which
459 records the state of all memory in the process. The memory map is
460 organised like that for normal Valgrind, except each that everything
461 is done at word-level instead of byte-level, and each word has only
462 one word of shadow (instead of 36 bits).
463
464 As for normal Valgrind there is a distinguished secondary map. But we're
465 working at word-granularity, so it has 16k word entries instead of 64k byte
466 entries. Lookup is done as follows:
467
468 bits 31..16: primary map lookup
469 bits 15.. 2: secondary map lookup
470 bits 1.. 0: ignored
471*/
472
473
474/*------------------------------------------------------------*/
475/*--- Basic bitmap management, reading and writing. ---*/
476/*------------------------------------------------------------*/
477
478/* Allocate and initialise a secondary map, marking all words as virgin. */
479
480/* Just a value that isn't a real pointer */
481#define SEC_MAP_ACCESS (shadow_word*)0x99
482
483
484static
485ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
486{
487 ESecMap* map;
488 UInt i;
489 //PROF_EVENT(10); PPP
490
nethercote1420ab22004-08-18 22:26:01 +0000491 // Mark all words as virgin.
fitzhardinge98abfc72003-12-16 02:05:15 +0000492 map = (ESecMap *)VG_(shadow_alloc)(sizeof(ESecMap));
njn25e49d8e72002-09-23 09:36:25 +0000493 for (i = 0; i < ESEC_MAP_WORDS; i++)
494 map->swords[i] = virgin_sword;
495
496 return map;
497}
498
499
500/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
501 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000502static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000503void set_sword ( Addr a, shadow_word sword )
504{
505 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000506 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000507
508 //PROF_EVENT(23); PPP
509 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
510
511 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
512 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000513 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000514 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
515 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
516 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
517 tls->refcount--;
518 }
519
520 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
521 ThreadLifeSeg *tls = unpackTLS(sword.other);
522 tls->refcount++;
523 }
524
njn25e49d8e72002-09-23 09:36:25 +0000525 sm->swords[(a & 0xFFFC) >> 2] = sword;
526
527 if (VGE_IS_DISTINGUISHED_SM(sm)) {
528 VG_(printf)("wrote to distinguished 2ndary map! 0x%x\n", a);
529 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000530 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000531 }
532}
533
534
535static __inline__
536shadow_word* get_sword_addr ( Addr a )
537{
538 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
539 ESecMap* sm = primary_map[a >> 16];
540 UInt sm_off = (a & 0xFFFC) >> 2;
541
542 if (VGE_IS_DISTINGUISHED_SM(sm)) {
543 VG_(printf)("accessed distinguished 2ndary map! 0x%x\n", a);
544 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000545 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000546 return SEC_MAP_ACCESS;
547 }
548
549 //PROF_EVENT(21); PPP
550 return & (sm->swords[sm_off]);
551}
552
553
554// SSS: rename these so they're not so similar to memcheck, unless it's
555// appropriate of course
556
557static __inline__
558void init_virgin_sword(Addr a)
559{
sewardj499e3de2002-11-13 22:22:25 +0000560 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000561 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000562 set_sword(a, virgin_sword);
563}
564
sewardj7f3ad222002-11-13 22:11:53 +0000565static __inline__
566void init_error_sword(Addr a)
567{
568 set_sword(a, error_sword);
569}
njn25e49d8e72002-09-23 09:36:25 +0000570
njn25e49d8e72002-09-23 09:36:25 +0000571static __inline__
572void init_nonvirgin_sword(Addr a)
573{
574 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000575 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000576 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000577
njn14d01ce2004-11-26 11:30:14 +0000578 // The tid must be passed in here now; this requires more events to be
579 // given the tid in the first place.
580 //
581 //tid = VG_(get_current_or_recent_tid)();
582 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
583 VG_(exit)(1);
584
njnca82cc02004-11-22 17:18:48 +0000585 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000586 tls = thread_seg[tid];
587
sewardj8fac99a2002-11-13 22:31:26 +0000588 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000589 set_sword(a, sword);
590}
591
592
593/* In this case, we treat it for Eraser's sake like virgin (it hasn't
594 * been inited by a particular thread, it's just done automatically upon
595 * startup), but we mark its .state specially so it doesn't look like an
596 * uninited read. */
597static __inline__
598void init_magically_inited_sword(Addr a)
599{
600 shadow_word sword;
601
njnca82cc02004-11-22 17:18:48 +0000602 tl_assert(VG_INVALID_THREADID == VG_(get_current_tid)());
sewardj8fac99a2002-11-13 22:31:26 +0000603
604 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
605
njn25e49d8e72002-09-23 09:36:25 +0000606 set_sword(a, virgin_sword);
607}
608
sewardjc26cc252002-10-23 21:58:55 +0000609
sewardj274c6012002-10-22 04:54:55 +0000610/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000611/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000612/*------------------------------------------------------------*/
613
sewardj39a4d842002-11-13 22:14:30 +0000614typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000615typedef struct _LockSet LockSet;
616
sewardj16748af2002-10-22 04:55:54 +0000617typedef enum MutexState {
618 MxUnknown, /* don't know */
619 MxUnlocked, /* unlocked */
620 MxLocked, /* locked */
621 MxDead /* destroyed */
622} MutexState;
623
sewardj39a4d842002-11-13 22:14:30 +0000624struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000625 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000626 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000627
628 MutexState state; /* mutex state */
629 ThreadId tid; /* owner */
630 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000631
sewardj4bffb232002-11-13 21:46:34 +0000632 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000633 UInt mark; /* mark for graph traversal */
634};
sewardj16748af2002-10-22 04:55:54 +0000635
sewardj39a4d842002-11-13 22:14:30 +0000636static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000637{
sewardjdac0a442002-11-13 22:08:40 +0000638 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000639}
njn25e49d8e72002-09-23 09:36:25 +0000640
sewardj274c6012002-10-22 04:54:55 +0000641struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000642 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000643 UInt hash; /* hash code */
644 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000645 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000646};
sewardj4bffb232002-11-13 21:46:34 +0000647
648static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000649
650/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000651static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000652
sewardjdac0a442002-11-13 22:08:40 +0000653#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000654
sewardj4bffb232002-11-13 21:46:34 +0000655static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000656
sewardj4bffb232002-11-13 21:46:34 +0000657/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000658static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000659{
sewardj4bffb232002-11-13 21:46:34 +0000660 UInt id;
661
njn94065fd2004-11-22 19:26:27 +0000662 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000663 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000664
665 return id;
njn25e49d8e72002-09-23 09:36:25 +0000666}
667
sewardj8fac99a2002-11-13 22:31:26 +0000668static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000669{
sewardj4bffb232002-11-13 21:46:34 +0000670 return (LockSet *)(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000671}
672
njn25e49d8e72002-09-23 09:36:25 +0000673static
sewardj4bffb232002-11-13 21:46:34 +0000674void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000675{
sewardj05bcdcb2003-05-18 10:05:38 +0000676 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000677 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000678 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000679 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000680
681 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000682 }
683 VG_(printf)("}\n");
684}
685
686
sewardj4bffb232002-11-13 21:46:34 +0000687static void print_LockSet(const Char *s, const LockSet *ls)
688{
689 VG_(printf)("%s: ", s);
690 pp_LockSet(ls);
691}
692
693/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000694static UInt hash_LockSet_w_wo(const LockSet *ls,
695 const Mutex *with,
696 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000697{
sewardj05bcdcb2003-05-18 10:05:38 +0000698 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000699 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000700
njnca82cc02004-11-22 17:18:48 +0000701 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000702
703 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000704 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000705
706 if (without && mutex_cmp(without, mx) == 0)
707 continue;
708
709 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
710 mx = with;
711 with = NULL;
712 i--;
713 }
714
sewardj8fac99a2002-11-13 22:31:26 +0000715 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000716 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000717 }
718
719 return hash % LOCKSET_HASH_SZ;
720}
721
sewardj39a4d842002-11-13 22:14:30 +0000722static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000723{
724 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
725
726 if (0)
727 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
728
729 return hash;
730}
731
sewardj39a4d842002-11-13 22:14:30 +0000732static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000733{
734 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
735
736 if (0)
737 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
738
739 return hash;
740}
741
742static inline UInt hash_LockSet(const LockSet *ls)
743{
744 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
745
746 if (0)
747 VG_(printf)("hash %p -> %d\n", ls, hash);
748
749 return hash;
750}
751
752static
753Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000754{
755 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000756
sewardj4bffb232002-11-13 21:46:34 +0000757 if (a == b)
758 return True;
759 if (a->setsize != b->setsize)
760 return False;
njn25e49d8e72002-09-23 09:36:25 +0000761
sewardj4bffb232002-11-13 21:46:34 +0000762 for(i = 0; i < a->setsize; i++) {
763 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000764 return False;
njn25e49d8e72002-09-23 09:36:25 +0000765 }
766
sewardj4bffb232002-11-13 21:46:34 +0000767 return True;
njn25e49d8e72002-09-23 09:36:25 +0000768}
769
770
771/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
772 * doesn't do the insertion. Returns True if they match.
773 */
774static Bool
sewardj4bffb232002-11-13 21:46:34 +0000775weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000776 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000777{
sewardjc26cc252002-10-23 21:58:55 +0000778 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000779 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000780
njn25e49d8e72002-09-23 09:36:25 +0000781 /* Idea is to try and match each element of b against either an
782 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000783
784 if (debug) {
785 print_LockSet("weird_LockSet_equals a", a);
786 print_LockSet(" b", b);
787 VG_(printf)( " missing: %p%(y\n",
788 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000789 }
sewardjc26cc252002-10-23 21:58:55 +0000790
sewardj4bffb232002-11-13 21:46:34 +0000791 if ((a->setsize + 1) != b->setsize) {
792 if (debug)
793 VG_(printf)(" fastpath length mismatch -> 0\n");
794 return False;
795 }
796
sewardjc26cc252002-10-23 21:58:55 +0000797 /* There are three phases to this compare:
798 1 the section from the start of a up to missing_mutex
799 2 missing mutex itself
800 3 the section after missing_mutex to the end of a
801 */
802
sewardj4bffb232002-11-13 21:46:34 +0000803 ia = 0;
804 ib = 0;
805
sewardjc26cc252002-10-23 21:58:55 +0000806 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000807 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000808 if (debug) {
809 print_LockSet(" 1:a", a);
810 print_LockSet(" 1:b", b);
811 }
sewardj4bffb232002-11-13 21:46:34 +0000812 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000813 return False;
sewardjc26cc252002-10-23 21:58:55 +0000814 }
815
816 /* 2: missing_mutex itself */
817 if (debug) {
818 VG_(printf)( " 2:missing: %p%(y\n",
819 missing_mutex->mutexp, missing_mutex->mutexp);
820 print_LockSet(" 2: b", b);
821 }
822
njnca82cc02004-11-22 17:18:48 +0000823 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000824
sewardj4bffb232002-11-13 21:46:34 +0000825 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000826 return False;
827
sewardj4bffb232002-11-13 21:46:34 +0000828 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000829
830 /* 3: after missing_mutex to end */
831
sewardj4bffb232002-11-13 21:46:34 +0000832 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000833 if (debug) {
834 print_LockSet(" 3:a", a);
835 print_LockSet(" 3:b", b);
836 }
sewardj4bffb232002-11-13 21:46:34 +0000837 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000838 return False;
sewardjc26cc252002-10-23 21:58:55 +0000839 }
840
841 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000842 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000843
sewardj4bffb232002-11-13 21:46:34 +0000844 return ia == a->setsize && ib == b->setsize;
845}
846
847
848
849static const LockSet *lookup_LockSet(const LockSet *set)
850{
851 UInt bucket = set->hash;
852 LockSet *ret;
853
854 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
855 if (set == ret || structural_eq_LockSet(set, ret))
856 return ret;
857
858 return NULL;
859}
860
sewardj39a4d842002-11-13 22:14:30 +0000861static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000862{
863 UInt bucket = hash_LockSet_with(set, mutex);
864 const LockSet *ret;
865
866 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
867 if (weird_LockSet_equals(set, ret, mutex))
868 return ret;
869
870 return NULL;
871}
872
sewardj39a4d842002-11-13 22:14:30 +0000873static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000874{
875 UInt bucket = hash_LockSet_without(set, mutex);
876 const LockSet *ret;
877
878 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
879 if (weird_LockSet_equals(ret, set, mutex))
880 return ret;
881
882 return NULL;
883}
884
885static void insert_LockSet(LockSet *set)
886{
887 UInt hash = hash_LockSet(set);
888
889 set->hash = hash;
890
njnca82cc02004-11-22 17:18:48 +0000891 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000892
893 set->next = lockset_hash[hash];
894 lockset_hash[hash] = set;
895}
896
897static inline
898LockSet *alloc_LockSet(UInt setsize)
899{
sewardj39a4d842002-11-13 22:14:30 +0000900 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000901 ret->setsize = setsize;
902 return ret;
903}
904
905static inline
906void free_LockSet(LockSet *p)
907{
908 /* assert: not present in hash */
909 VG_(free)(p);
910}
911
njnb4aee052003-04-15 14:09:58 +0000912static
sewardj4bffb232002-11-13 21:46:34 +0000913void pp_all_LockSets ( void )
914{
915 Int i;
916 Int sets, buckets;
917
918 sets = buckets = 0;
919 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
920 const LockSet *ls = lockset_hash[i];
921 Bool first = True;
922
sewardj4bffb232002-11-13 21:46:34 +0000923 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000924 if (first) {
925 buckets++;
926 VG_(printf)("[%4d] = ", i);
927 } else
928 VG_(printf)(" ");
929
sewardj4bffb232002-11-13 21:46:34 +0000930 sets++;
931 first = False;
932 pp_LockSet(ls);
933 }
934 }
935
936 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
937}
938
939static inline Bool isempty(const LockSet *ls)
940{
941 return ls == NULL || ls->setsize == 0;
942}
943
sewardj39a4d842002-11-13 22:14:30 +0000944static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000945{
946 Int i;
947
948 /* XXX use binary search */
949 for(i = 0; i < ls->setsize; i++)
950 if (mutex_cmp(mx, ls->mutex[i]) == 0)
951 return True;
952
953 return False;
954}
955
956/* Check invariants:
957 - all locksets are unique
958 - each set is an array in strictly increasing order of mutex addr
959*/
960static
961void sanity_check_locksets ( const Char* caller )
962{
963 Int i;
964 const Char *badness;
965 LockSet *ls;
966
967 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
968
969 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000970 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000971 Int j;
972
973 if (hash_LockSet(ls) != ls->hash) {
974 badness = "mismatched hash";
975 goto bad;
976 }
sewardj05bcdcb2003-05-18 10:05:38 +0000977 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +0000978 badness = "wrong bucket";
979 goto bad;
980 }
981 if (lookup_LockSet(ls) != ls) {
982 badness = "non-unique set";
983 goto bad;
984 }
985
986 prev = ls->mutex[0];
987 for(j = 1; j < ls->setsize; j++) {
988 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
989 badness = "mutexes out of order";
990 goto bad;
991 }
992 }
993 }
994 }
995 return;
996
997 bad:
998 VG_(printf)("sanity_check_locksets: "
999 "i = %d, ls=%p badness = %s, caller = %s\n",
1000 i, ls, badness, caller);
1001 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001002 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001003}
1004
1005static
sewardj39a4d842002-11-13 22:14:30 +00001006LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001007{
1008 static const Bool debug = False;
1009 LockSet *ret = NULL;
1010 Int i, j;
1011
1012 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1013 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1014 print_LockSet("add-IN", ls);
1015 }
1016
1017 if (debug || LOCKSET_SANITY)
1018 sanity_check_locksets("add-IN");
1019
njnca82cc02004-11-22 17:18:48 +00001020 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001021
1022 ret = alloc_LockSet(ls->setsize+1);
1023
1024 for(i = j = 0; i < ls->setsize; i++) {
1025 if (debug)
1026 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1027 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1028 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1029 ret->mutex[j++] = mx;
1030 mx = NULL;
1031 }
1032 ret->mutex[j++] = ls->mutex[i];
1033 }
1034
1035 /* not added in loop - must be after */
1036 if (mx)
1037 ret->mutex[j++] = mx;
1038
njnca82cc02004-11-22 17:18:48 +00001039 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001040
1041 if (debug || LOCKSET_SANITY) {
1042 print_LockSet("add-OUT", ret);
1043 sanity_check_locksets("add-OUT");
1044 }
1045 return ret;
1046}
1047
1048/* Builds ls with mx removed. mx should actually be in ls!
1049 (a checked assertion). Resulting set should not already
1050 exist in the table (unchecked).
1051*/
1052static
sewardj39a4d842002-11-13 22:14:30 +00001053LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001054{
1055 static const Bool debug = False;
1056 LockSet *ret = NULL;
1057 Int i, j;
1058
1059 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1060 print_LockSet("remove-IN", ls);
1061 }
1062
1063 if (debug || LOCKSET_SANITY)
1064 sanity_check_locksets("remove-IN");
1065
njnca82cc02004-11-22 17:18:48 +00001066 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001067
1068 ret = alloc_LockSet(ls->setsize-1);
1069
1070 for(i = j = 0; i < ls->setsize; i++) {
1071 if (mutex_cmp(ls->mutex[i], mx) == 0)
1072 continue;
1073 ret->mutex[j++] = ls->mutex[i];
1074 }
1075
njnca82cc02004-11-22 17:18:48 +00001076 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001077
1078 if (debug || LOCKSET_SANITY) {
1079 print_LockSet("remove-OUT", ret);
1080 sanity_check_locksets("remove-OUT");
1081 }
1082 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001083}
1084
1085
1086/* Builds the intersection, and then unbuilds it if it's already in the table.
1087 */
sewardj4bffb232002-11-13 21:46:34 +00001088static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001089{
sewardj4bffb232002-11-13 21:46:34 +00001090 static const Bool debug = False;
1091 Int iret;
1092 Int ia, ib;
1093 Int size;
1094 LockSet *ret;
1095 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001096
sewardj4bffb232002-11-13 21:46:34 +00001097 if (debug || LOCKSET_SANITY)
1098 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001099
sewardj4bffb232002-11-13 21:46:34 +00001100 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1101 print_LockSet("intersect a", a);
1102 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001103 }
1104
sewardj4bffb232002-11-13 21:46:34 +00001105 /* count the size of the new set */
1106 size = 0;
1107 ia = ib = 0;
1108 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1109 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1110 size++;
1111 ia++;
1112 ib++;
1113 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1114 ia++;
1115 } else {
njnca82cc02004-11-22 17:18:48 +00001116 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001117 ib++;
1118 }
njn25e49d8e72002-09-23 09:36:25 +00001119 }
1120
sewardj4bffb232002-11-13 21:46:34 +00001121 /* Build the intersection of the two sets */
1122 ret = alloc_LockSet(size);
1123 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1124 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001125 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001126 ret->mutex[iret++] = a->mutex[ia];
1127 ia++;
1128 ib++;
1129 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1130 ia++;
1131 } else {
njnca82cc02004-11-22 17:18:48 +00001132 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001133 ib++;
1134 }
1135 }
1136
1137 ret->hash = hash_LockSet(ret);
1138
njn25e49d8e72002-09-23 09:36:25 +00001139 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001140 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001141
sewardj4bffb232002-11-13 21:46:34 +00001142 if (found != NULL) {
1143 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001144 } else {
sewardj4bffb232002-11-13 21:46:34 +00001145 insert_LockSet(ret);
1146 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001147 }
1148
sewardj4bffb232002-11-13 21:46:34 +00001149 if (debug || LOCKSET_SANITY) {
1150 print_LockSet("intersect-OUT", found);
1151 sanity_check_locksets("intersect-OUT");
1152 }
njn25e49d8e72002-09-23 09:36:25 +00001153
sewardj4bffb232002-11-13 21:46:34 +00001154 return found;
njn25e49d8e72002-09-23 09:36:25 +00001155}
1156
sewardj4bffb232002-11-13 21:46:34 +00001157/* inline the fastpath */
1158static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001159{
sewardj4bffb232002-11-13 21:46:34 +00001160 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001161
1162 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001163 if (a == b) {
1164 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1165 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001166 }
sewardj4bffb232002-11-13 21:46:34 +00001167 return a;
sewardjc26cc252002-10-23 21:58:55 +00001168 }
1169
sewardj4bffb232002-11-13 21:46:34 +00001170 if (isempty(a) || isempty(b)) {
1171 if (debug)
1172 VG_(printf)("intersect empty fastpath\n");
1173 return emptyset;
1174 }
1175
1176 return _intersect(a, b);
1177}
1178
1179
1180static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1181{
1182 static const Bool debug = False;
1183 Int iret;
1184 Int ia, ib;
1185 Int size;
1186 LockSet *ret;
1187 const LockSet *found;
1188
1189 if (debug || LOCKSET_SANITY)
1190 sanity_check_locksets("union-IN");
1191
1192 /* Fast case -- when the two are the same */
1193 if (a == b) {
1194 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1195 print_LockSet("union-same fastpath", a);
1196 }
1197 return a;
1198 }
1199
1200 if (isempty(a)) {
1201 if (debug)
1202 print_LockSet("union a=empty b", b);
1203 return b;
1204 }
1205 if (isempty(b)) {
1206 if (debug)
1207 print_LockSet("union b=empty a", a);
1208 return a;
1209 }
1210
1211 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001212 print_LockSet("union a", a);
1213 print_LockSet("union b", b);
1214 }
1215
sewardj4bffb232002-11-13 21:46:34 +00001216 /* count the size of the new set */
1217 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1218 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001219
sewardj4bffb232002-11-13 21:46:34 +00001220 if ((ia < a->setsize) && (ib < b->setsize))
1221 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1222 else if (ia == a->setsize)
1223 cmp = 1;
1224 else
1225 cmp = -1;
1226
1227 if (cmp == 0) {
1228 size++;
1229 ia++;
1230 ib++;
1231 } else if (cmp < 0) {
1232 size++;
1233 ia++;
1234 } else {
njnca82cc02004-11-22 17:18:48 +00001235 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001236 size++;
1237 ib++;
1238 }
sewardjc26cc252002-10-23 21:58:55 +00001239 }
1240
sewardj4bffb232002-11-13 21:46:34 +00001241 /* Build the intersection of the two sets */
1242 ret = alloc_LockSet(size);
1243 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1244 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001245 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001246
1247 if ((ia < a->setsize) && (ib < b->setsize))
1248 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1249 else if (ia == a->setsize)
1250 cmp = 1;
1251 else
1252 cmp = -1;
1253
1254 if (cmp == 0) {
1255 ret->mutex[iret++] = a->mutex[ia];
1256 ia++;
1257 ib++;
1258 } else if (cmp < 0) {
1259 ret->mutex[iret++] = a->mutex[ia];
1260 ia++;
1261 } else {
njnca82cc02004-11-22 17:18:48 +00001262 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001263 ret->mutex[iret++] = b->mutex[ib];
1264 ib++;
1265 }
1266 }
1267
njnca82cc02004-11-22 17:18:48 +00001268 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001269
1270 ret->hash = hash_LockSet(ret);
1271
sewardjc26cc252002-10-23 21:58:55 +00001272 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001273 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001274
sewardj4bffb232002-11-13 21:46:34 +00001275 if (found != NULL) {
1276 if (debug)
1277 print_LockSet("union found existing set", found);
1278 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001279 } else {
sewardj4bffb232002-11-13 21:46:34 +00001280 if (debug)
1281 print_LockSet("union inserting new set", ret);
1282 insert_LockSet(ret);
1283 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001284 }
1285
sewardj4bffb232002-11-13 21:46:34 +00001286 if (debug || LOCKSET_SANITY) {
1287 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001288 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001289 }
sewardjc26cc252002-10-23 21:58:55 +00001290
sewardj4bffb232002-11-13 21:46:34 +00001291 return found;
sewardjc26cc252002-10-23 21:58:55 +00001292}
1293
1294/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001295/*--- Implementation of mutex structure. ---*/
1296/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001297
1298static UInt graph_mark; /* current mark we're using for graph traversal */
1299
sewardj39a4d842002-11-13 22:14:30 +00001300static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001301 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001302static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001303 const LockSet *lockset_holding,
1304 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001305
njn72718642003-07-24 08:45:32 +00001306static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001307
1308#define M_MUTEX_HASHSZ 1021
1309
sewardj39a4d842002-11-13 22:14:30 +00001310static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001311static UInt total_mutexes;
1312
1313static const Char *pp_MutexState(MutexState st)
1314{
1315 switch(st) {
1316 case MxLocked: return "Locked";
1317 case MxUnlocked: return "Unlocked";
1318 case MxDead: return "Dead";
1319 case MxUnknown: return "Unknown";
1320 }
1321 return "???";
1322}
1323
1324static void pp_all_mutexes()
1325{
1326 Int i;
1327 Int locks, buckets;
1328
1329 locks = buckets = 0;
1330 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001331 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001332 Bool first = True;
1333
1334 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1335 if (first) {
1336 buckets++;
1337 VG_(printf)("[%4d] = ", i);
1338 } else
1339 VG_(printf)(" ");
1340 locks++;
1341 first = False;
1342 VG_(printf)("%p [%8s] -> %p%(y\n",
1343 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1344 }
1345 }
1346
1347 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1348 locks, buckets, total_mutexes);
1349}
sewardjc26cc252002-10-23 21:58:55 +00001350
sewardj39a4d842002-11-13 22:14:30 +00001351/* find or create a Mutex for a program's mutex use */
1352static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001353{
nethercote50397c22004-11-04 18:03:06 +00001354 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001355 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001356
1357 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1358 if (mp->mutexp == mutexp)
1359 return mp;
1360
sewardjdac0a442002-11-13 22:08:40 +00001361 total_mutexes++;
1362
sewardjc26cc252002-10-23 21:58:55 +00001363 mp = VG_(malloc)(sizeof(*mp));
1364 mp->mutexp = mutexp;
1365 mp->next = mutex_hash[bucket];
1366 mutex_hash[bucket] = mp;
1367
1368 mp->state = MxUnknown;
1369 mp->tid = VG_INVALID_THREADID;
1370 mp->location = NULL;
1371
sewardj4bffb232002-11-13 21:46:34 +00001372 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001373 mp->mark = graph_mark - 1;
1374
1375 return mp;
1376}
1377
sewardjdac0a442002-11-13 22:08:40 +00001378/* Find all mutexes in a range of memory, and call the callback.
1379 Remove the mutex from the hash if the callback returns True (mutex
1380 structure itself is not freed, because it may be pointed to by a
1381 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001382static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001383{
sewardjdac0a442002-11-13 22:08:40 +00001384 UInt first = start % M_MUTEX_HASHSZ;
1385 UInt last = (end+1) % M_MUTEX_HASHSZ;
1386 UInt i;
1387
1388 /* Single pass over the hash table, looking for likely hashes */
1389 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001390 Mutex *mx;
1391 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001392
1393 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1394 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1395 *prev = mx->next;
1396 }
1397
1398 if (++i == M_MUTEX_HASHSZ)
1399 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001400 }
sewardjc26cc252002-10-23 21:58:55 +00001401}
1402
1403#define MARK_LOOP (graph_mark+0)
1404#define MARK_DONE (graph_mark+1)
1405
thughes4ad52d02004-06-27 17:37:21 +00001406static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1407{
1408 static const Bool debug = False;
1409 Int i;
1410
1411 if (mutex->mark == MARK_LOOP)
1412 return True; /* found cycle */
1413 if (mutex->mark == MARK_DONE)
1414 return False; /* been here before, its OK */
1415
1416 ((Mutex*)mutex)->mark = MARK_LOOP;
1417
1418 if (debug)
1419 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1420 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1421 for(i = 0; i < ls->setsize; i++) {
1422 const Mutex *mx = ls->mutex[i];
1423
1424 if (debug)
1425 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1426 mutex->mutexp, ls,
1427 mx->mutexp, mx->mutexp);
1428 if (check_cycle_inner(mx, mx->lockdep))
1429 return True;
1430 }
1431 ((Mutex*)mutex)->mark = MARK_DONE;
1432
1433 return False;
1434}
1435
sewardj39a4d842002-11-13 22:14:30 +00001436static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001437{
sewardjff2c9232002-11-13 21:44:39 +00001438
sewardjc26cc252002-10-23 21:58:55 +00001439 graph_mark += 2; /* clear all marks */
1440
sewardj4bffb232002-11-13 21:46:34 +00001441 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001442}
1443
sewardjdca84112002-11-13 22:29:34 +00001444/* test to see if a mutex state change would be problematic; this
1445 makes no changes to the mutex state. This should be called before
1446 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001447static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001448{
1449 static const Bool debug = False;
1450
sewardjc26cc252002-10-23 21:58:55 +00001451 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001452 Char *str;
1453
1454 switch(state) {
1455 case MxLocked: str = "lock dead mutex"; break;
1456 case MxUnlocked: str = "unlock dead mutex"; break;
1457 default: str = "operate on dead mutex"; break;
1458 }
1459
sewardjc26cc252002-10-23 21:58:55 +00001460 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001461 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001462 return;
1463 }
1464
1465 switch(state) {
1466 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001467 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001468
1469 if (debug)
1470 print_LockSet("thread holding", thread_locks[tid]);
1471
1472 if (check_cycle(mutex, thread_locks[tid]))
1473 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1474 else {
1475 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1476
1477 if (debug) {
1478 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1479 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1480 print_LockSet("lockdep", mutex->lockdep);
1481 }
1482 }
1483 break;
1484
1485 case MxUnlocked:
1486 if (debug)
1487 print_LockSet("thread holding", thread_locks[tid]);
1488
1489 if (mutex->state != MxLocked) {
1490 record_mutex_error(tid, mutex,
1491 "unlock non-locked mutex", mutex->location);
1492 }
1493 if (mutex->tid != tid) {
1494 record_mutex_error(tid, mutex,
1495 "unlock someone else's mutex", mutex->location);
1496 }
1497 break;
1498
1499 case MxDead:
1500 break;
1501
1502 default:
1503 break;
1504 }
1505}
1506
1507/* Update a mutex state. Expects most error testing and reporting to
1508 have happened in test_mutex_state(). The assumption is that no
1509 client code is run by thread tid between test and set, either
1510 because it is blocked or test and set are called together
1511 atomically.
1512
1513 Setting state to MxDead is the exception, since that can happen as
1514 a result of any thread freeing memory; in this case set_mutex_state
1515 does all the error reporting as well.
1516*/
njn72718642003-07-24 08:45:32 +00001517static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001518{
1519 static const Bool debug = False;
1520
1521 if (debug)
1522 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1523 tid, mutex, mutex->mutexp, mutex->mutexp,
1524 pp_MutexState(mutex->state), pp_MutexState(state));
1525
1526 if (mutex->state == MxDead) {
1527 /* can't do anything legal to a destroyed mutex */
1528 return;
1529 }
1530
1531 switch(state) {
1532 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001533 if (mutex->state == MxLocked) {
1534 if (mutex->tid != tid)
1535 record_mutex_error(tid, mutex, "take lock held by someone else",
1536 mutex->location);
1537 else
1538 record_mutex_error(tid, mutex, "take lock we already hold",
1539 mutex->location);
1540
njn67993252004-11-22 18:02:32 +00001541 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001542 break;
1543 }
sewardjc26cc252002-10-23 21:58:55 +00001544
njnca82cc02004-11-22 17:18:48 +00001545 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001546
sewardjc26cc252002-10-23 21:58:55 +00001547 mutex->tid = tid;
1548 break;
1549
1550 case MxUnlocked:
1551 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001552 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001553
sewardjdca84112002-11-13 22:29:34 +00001554 if (mutex->state != MxLocked || mutex->tid != tid)
1555 break;
1556
sewardjc26cc252002-10-23 21:58:55 +00001557 mutex->tid = VG_INVALID_THREADID;
1558 break;
1559
sewardjdac0a442002-11-13 22:08:40 +00001560 case MxDead:
1561 if (mutex->state == MxLocked) {
1562 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001563 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001564 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1565 mutex->tid = VG_INVALID_THREADID;
1566
1567 record_mutex_error(tid, mutex,
1568 "free locked mutex", mutex->location);
1569 }
1570 break;
1571
sewardjc26cc252002-10-23 21:58:55 +00001572 default:
1573 break;
1574 }
1575
njn72718642003-07-24 08:45:32 +00001576 mutex->location = VG_(get_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001577 mutex->state = state;
1578}
njn25e49d8e72002-09-23 09:36:25 +00001579
1580/*------------------------------------------------------------*/
1581/*--- Setting and checking permissions. ---*/
1582/*------------------------------------------------------------*/
1583
thughes4ad52d02004-06-27 17:37:21 +00001584/* only clean up dead mutexes */
1585static
1586Bool cleanmx(Mutex *mx) {
1587 return mx->state == MxDead;
1588}
1589
njn25e49d8e72002-09-23 09:36:25 +00001590static
nethercote451eae92004-11-02 13:06:32 +00001591void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001592 VgeInitStatus status )
1593{
sewardj1806d7f2002-10-22 05:05:49 +00001594 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001595
1596# if DEBUG_MAKE_ACCESSES
1597 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1598# endif
1599 //PROF_EVENT(30); PPP
1600
1601 if (len == 0)
1602 return;
1603
1604 if (len > 100 * 1000 * 1000)
1605 VG_(message)(Vg_UserMsg,
1606 "Warning: set address range state: large range %d",
1607 len);
1608
1609 VGP_PUSHCC(VgpSARP);
1610
sewardjdac0a442002-11-13 22:08:40 +00001611 /* Remove mutexes in recycled memory range from hash */
1612 find_mutex_range(a, a+len, cleanmx);
1613
njn25e49d8e72002-09-23 09:36:25 +00001614 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1615 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1616 * len/4+1 words. This works out which it is by aligning the block and
1617 * seeing if the end byte is in the same word as it is for the unaligned
1618 * block; if not, it's the awkward case. */
sewardj8fac99a2002-11-13 22:31:26 +00001619 end = ROUNDUP(a + len, 4);
1620 a = ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001621
1622 /* Do it ... */
1623 switch (status) {
1624 case Vge_VirginInit:
1625 for ( ; a < end; a += 4) {
1626 //PROF_EVENT(31); PPP
1627 init_virgin_sword(a);
1628 }
1629 break;
1630
1631 case Vge_NonVirginInit:
1632 for ( ; a < end; a += 4) {
1633 //PROF_EVENT(31); PPP
1634 init_nonvirgin_sword(a);
1635 }
1636 break;
1637
1638 case Vge_SegmentInit:
1639 for ( ; a < end; a += 4) {
1640 //PROF_EVENT(31); PPP
1641 init_magically_inited_sword(a);
1642 }
1643 break;
sewardj7f3ad222002-11-13 22:11:53 +00001644
1645 case Vge_Error:
1646 for ( ; a < end; a += 4) {
1647 //PROF_EVENT(31); PPP
1648 init_error_sword(a);
1649 }
1650 break;
njn25e49d8e72002-09-23 09:36:25 +00001651
1652 default:
1653 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001654 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001655 }
1656
1657 /* Check that zero page and highest page have not been written to
1658 -- this could happen with buggy syscall wrappers. Today
1659 (2001-04-26) had precisely such a problem with
1660 __NR_setitimer. */
njn26f02512004-11-22 18:33:15 +00001661 tl_assert(TL_(cheap_sanity_check)());
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
nethercote451eae92004-11-02 13:06:32 +00001699static void eraser_mem_read (Addr a, SizeT data_size, ThreadId tid);
1700static void eraser_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001701
sewardja5b3aec2002-10-22 05:09:36 +00001702static void eraser_mem_help_read_1(Addr a) REGPARM(1);
1703static void eraser_mem_help_read_2(Addr a) REGPARM(1);
1704static void eraser_mem_help_read_4(Addr a) REGPARM(1);
nethercote451eae92004-11-02 13:06:32 +00001705static void eraser_mem_help_read_N(Addr a, SizeT size) REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001706
1707static void eraser_mem_help_write_1(Addr a, UInt val) REGPARM(2);
1708static void eraser_mem_help_write_2(Addr a, UInt val) REGPARM(2);
1709static void eraser_mem_help_write_4(Addr a, UInt val) REGPARM(2);
nethercote451eae92004-11-02 13:06:32 +00001710static void eraser_mem_help_write_N(Addr a, SizeT size) 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
njn72718642003-07-24 08:45:32 +00001716void eraser_pre_mem_read(CorePart part, ThreadId tid,
nethercote451eae92004-11-02 13:06:32 +00001717 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001718{
njn67993252004-11-22 18:02:32 +00001719 if (tid > 50) { VG_(printf)("pid = %d, s = `%s`, part = %d\n", tid, s, part); VG_(tool_panic)("a");}
njn72718642003-07-24 08:45:32 +00001720 eraser_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001721}
1722
1723static
njn72718642003-07-24 08:45:32 +00001724void eraser_pre_mem_read_asciiz(CorePart part, ThreadId tid,
nethercote6a27d832004-09-07 10:17:02 +00001725 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001726{
njn72718642003-07-24 08:45:32 +00001727 eraser_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001728}
1729
1730static
njn72718642003-07-24 08:45:32 +00001731void eraser_pre_mem_write(CorePart part, ThreadId tid,
nethercote451eae92004-11-02 13:06:32 +00001732 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001733{
njn72718642003-07-24 08:45:32 +00001734 eraser_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001735}
1736
1737
1738
1739static
nethercote451eae92004-11-02 13:06:32 +00001740void eraser_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
nethercote451eae92004-11-02 13:06:32 +00001748void eraser_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
nethercote451eae92004-11-02 13:06:32 +00001758void eraser_set_perms (Addr a, SizeT len,
sewardj40f8ebe2002-10-23 21:46:13 +00001759 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
nethercote451eae92004-11-02 13:06:32 +00001767void eraser_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
nethercote451eae92004-11-02 13:06:32 +00001773void eraser_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
1807/* Use a small redzone (paranoia) */
nethercotee1efb922004-07-10 16:01:52 +00001808UInt VG_(vg_malloc_redzone_szB) = 8;
njn3e884182003-04-15 13:03:23 +00001809
1810
1811/* Allocate a user-chunk of size bytes. Also allocate its shadow
1812 block, make the shadow block point at the user block. Put the
1813 shadow chunk on the appropriate list, and set all memory
1814 protections correctly. */
1815
nethercote7ac7f7b2004-11-02 12:36:02 +00001816static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001817{
1818 HG_Chunk* hc;
1819
1820 hc = VG_(malloc)(sizeof(HG_Chunk));
1821 hc->data = p;
1822 hc->size = size;
njn72718642003-07-24 08:45:32 +00001823 hc->where = VG_(get_ExeContext)(tid);
1824 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001825
1826 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1827}
1828
1829/* Allocate memory and note change in memory available */
1830static __inline__
njn14d01ce2004-11-26 11:30:14 +00001831void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1832 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001833{
1834 Addr p;
1835
njn34ac0272003-09-30 14:20:00 +00001836 if (size < 0) return NULL;
1837
njn3e884182003-04-15 13:03:23 +00001838 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001839 if (!p) {
1840 return NULL;
1841 }
njn34ac0272003-09-30 14:20:00 +00001842 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001843 add_HG_Chunk ( tid, p, size );
njn3e884182003-04-15 13:03:23 +00001844 eraser_new_mem_heap( p, size, is_zeroed );
1845
1846 return (void*)p;
1847}
1848
njn14d01ce2004-11-26 11:30:14 +00001849void* TL_(malloc) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001850{
njn14d01ce2004-11-26 11:30:14 +00001851 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001852}
1853
njn14d01ce2004-11-26 11:30:14 +00001854void* TL_(__builtin_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001855{
njn14d01ce2004-11-26 11:30:14 +00001856 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001857}
1858
njn14d01ce2004-11-26 11:30:14 +00001859void* TL_(__builtin_vec_new) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001860{
njn14d01ce2004-11-26 11:30:14 +00001861 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001862}
1863
njn14d01ce2004-11-26 11:30:14 +00001864void* TL_(memalign) ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001865{
njn14d01ce2004-11-26 11:30:14 +00001866 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001867}
1868
njn14d01ce2004-11-26 11:30:14 +00001869void* TL_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001870{
njn14d01ce2004-11-26 11:30:14 +00001871 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001872 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001873}
1874
thughes4ad52d02004-06-27 17:37:21 +00001875static ThreadId deadmx_tid;
1876
1877static
1878Bool deadmx(Mutex *mx) {
1879 if (mx->state != MxDead)
1880 set_mutex_state(mx, MxDead, deadmx_tid);
1881
1882 return False;
1883}
1884
njn3e884182003-04-15 13:03:23 +00001885static
njn72718642003-07-24 08:45:32 +00001886void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001887 HG_Chunk** prev_chunks_next_ptr )
1888{
njn72718642003-07-24 08:45:32 +00001889 Addr start = hc->data;
1890 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001891
njn3e884182003-04-15 13:03:23 +00001892 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1893 avoid repeating the hash table lookup. Can't remove until at least
1894 after free and free_mismatch errors are done because they use
1895 describe_addr() which looks for it in malloclist. */
1896 *prev_chunks_next_ptr = hc->next;
1897
1898 /* Record where freed */
njn72718642003-07-24 08:45:32 +00001899 hc->where = VG_(get_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001900
1901 /* maintain a small window so that the error reporting machinery
1902 knows about this memory */
1903 if (freechunks[freechunkptr] != NULL) {
1904 /* free HG_Chunk */
1905 HG_Chunk* sc1 = freechunks[freechunkptr];
1906 VG_(cli_free) ( (void*)(sc1->data) );
1907 VG_(free) ( sc1 );
1908 }
1909
1910 freechunks[freechunkptr] = hc;
1911
1912 if (++freechunkptr == N_FREED_CHUNKS)
1913 freechunkptr = 0;
1914
1915 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001916 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001917 find_mutex_range(start, end, deadmx);
1918}
1919
1920
1921static __inline__
njn14d01ce2004-11-26 11:30:14 +00001922void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001923{
1924 HG_Chunk* hc;
1925 HG_Chunk** prev_chunks_next_ptr;
1926
nethercote3d6b6112004-11-04 16:39:43 +00001927 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001928 (VgHashNode***)&prev_chunks_next_ptr );
1929 if (hc == NULL) {
1930 return;
1931 }
njn14d01ce2004-11-26 11:30:14 +00001932 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001933}
1934
njn14d01ce2004-11-26 11:30:14 +00001935void TL_(free) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001936{
njn14d01ce2004-11-26 11:30:14 +00001937 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001938}
1939
njn14d01ce2004-11-26 11:30:14 +00001940void TL_(__builtin_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001941{
njn14d01ce2004-11-26 11:30:14 +00001942 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001943}
1944
njn14d01ce2004-11-26 11:30:14 +00001945void TL_(__builtin_vec_delete) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001946{
njn14d01ce2004-11-26 11:30:14 +00001947 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001948}
1949
njn14d01ce2004-11-26 11:30:14 +00001950void* TL_(realloc) ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001951{
1952 HG_Chunk *hc;
1953 HG_Chunk **prev_chunks_next_ptr;
sewardj05bcdcb2003-05-18 10:05:38 +00001954 Int i;
njn3e884182003-04-15 13:03:23 +00001955
1956 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001957 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001958 (VgHashNode***)&prev_chunks_next_ptr );
1959
1960 if (hc == NULL) {
1961 return NULL;
1962 }
1963
1964 if (hc->size == new_size) {
1965 /* size unchanged */
njn398044f2003-07-24 17:39:59 +00001966 hc->where = VG_(get_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001967 return p;
1968
1969 } else if (hc->size > new_size) {
1970 /* new size is smaller */
1971 hc->size = new_size;
njn398044f2003-07-24 17:39:59 +00001972 hc->where = VG_(get_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001973 return p;
1974
1975 } else {
1976 /* new size is bigger */
1977 Addr p_new;
1978
1979 /* Get new memory */
1980 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
1981
1982 /* First half kept and copied, second half new */
1983 copy_address_range_state( (Addr)p, p_new, hc->size );
1984 eraser_new_mem_heap ( p_new+hc->size, new_size-hc->size,
1985 /*inited*/False );
1986
1987 /* Copy from old to new */
1988 for (i = 0; i < hc->size; i++)
1989 ((UChar*)p_new)[i] = ((UChar*)p)[i];
1990
1991 /* Free old memory */
njn72718642003-07-24 08:45:32 +00001992 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001993
1994 /* this has to be after die_and_free_mem, otherwise the
1995 former succeeds in shorting out the new block, not the
1996 old, in the case when both are on the same list. */
njn72718642003-07-24 08:45:32 +00001997 add_HG_Chunk ( tid, p_new, new_size );
njn3e884182003-04-15 13:03:23 +00001998
1999 return (void*)p_new;
2000 }
2001}
2002
njn25e49d8e72002-09-23 09:36:25 +00002003/*--------------------------------------------------------------*/
2004/*--- Machinery to support sanity checking ---*/
2005/*--------------------------------------------------------------*/
2006
njn26f02512004-11-22 18:33:15 +00002007Bool TL_(cheap_sanity_check) ( void )
njn25e49d8e72002-09-23 09:36:25 +00002008{
jseward9800fd32004-01-04 23:08:04 +00002009 /* nothing useful we can rapidly check */
2010 return True;
njn25e49d8e72002-09-23 09:36:25 +00002011}
2012
njn26f02512004-11-22 18:33:15 +00002013Bool TL_(expensive_sanity_check)(void)
njn25e49d8e72002-09-23 09:36:25 +00002014{
2015 Int i;
2016
2017 /* Make sure nobody changed the distinguished secondary. */
2018 for (i = 0; i < ESEC_MAP_WORDS; i++)
2019 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2020 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2021 return False;
2022
2023 return True;
2024}
2025
2026
2027/*--------------------------------------------------------------*/
2028/*--- Instrumentation ---*/
2029/*--------------------------------------------------------------*/
2030
sewardjf6374322002-11-13 22:35:55 +00002031static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2032
njn14d01ce2004-11-26 11:30:14 +00002033#if 0
njn25e49d8e72002-09-23 09:36:25 +00002034/* Create and return an instrumented version of cb_in. Free cb_in
2035 before returning. */
njn26f02512004-11-22 18:33:15 +00002036UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002037{
2038 UCodeBlock* cb;
2039 Int i;
2040 UInstr* u_in;
2041 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002042 Int ntemps;
2043 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002044 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002045
njn810086f2002-11-14 12:42:47 +00002046 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002047
sewardjf6374322002-11-13 22:35:55 +00002048 /* stackref[] is used for super-simple value tracking to keep note
2049 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002050 the stack pointer or frame pointer, and is therefore likely
2051 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002052 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002053 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2054 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2055
njn810086f2002-11-14 12:42:47 +00002056 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2057 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002058
njn25e49d8e72002-09-23 09:36:25 +00002059 switch (u_in->opcode) {
2060
2061 case NOP: case CALLM_S: case CALLM_E:
2062 break;
sewardjf6374322002-11-13 22:35:55 +00002063
sewardj7a5ebcf2002-11-13 22:42:13 +00002064 case LOCK:
2065 locked = True;
2066 uInstr0(cb, CCALL, 0);
2067 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2068 break;
2069
2070 case JMP: case INCEIP:
2071 if (locked) {
2072 uInstr0(cb, CCALL, 0);
2073 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2074 }
2075 locked = False;
2076 VG_(copy_UInstr)(cb, u_in);
2077 break;
2078
sewardjf6374322002-11-13 22:35:55 +00002079 case GET:
njnca82cc02004-11-22 17:18:48 +00002080 tl_assert(u_in->tag1 == ArchReg);
2081 tl_assert(u_in->tag2 == TempReg);
2082 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002083
2084 stackref[u_in->val2] = (u_in->size == 4 &&
nethercoteca788ff2004-10-20 10:58:09 +00002085 (u_in->val1 == R_STACK_PTR ||
2086 u_in->val1 == R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002087 VG_(copy_UInstr)(cb, u_in);
2088 break;
2089
2090 case MOV:
2091 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002092 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002093 stackref[u_in->val2] = stackref[u_in->val1];
2094 }
2095 VG_(copy_UInstr)(cb, u_in);
2096 break;
2097
2098 case LEA1:
2099 case ADD: case SUB:
2100 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002101 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002102 stackref[u_in->val2] |= stackref[u_in->val1];
2103 }
2104 VG_(copy_UInstr)(cb, u_in);
2105 break;
njn25e49d8e72002-09-23 09:36:25 +00002106
sewardja5b3aec2002-10-22 05:09:36 +00002107 case LOAD: {
2108 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002109 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2110 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002111
2112 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2113 nonstk_ld++;
2114
2115 switch(u_in->size) {
2116 case 1: help = eraser_mem_help_read_1; break;
2117 case 2: help = eraser_mem_help_read_2; break;
2118 case 4: help = eraser_mem_help_read_4; break;
2119 default:
njn67993252004-11-22 18:02:32 +00002120 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002121 }
jsgfcb1d1c02003-10-14 21:55:10 +00002122
2123 /* XXX all registers should be flushed to baseblock
2124 here */
sewardjf6374322002-11-13 22:35:55 +00002125 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2126 uCCall(cb, (Addr)help, 1, 1, False);
2127 } else
2128 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002129
sewardja5b3aec2002-10-22 05:09:36 +00002130 VG_(copy_UInstr)(cb, u_in);
2131 t_size = INVALID_TEMPREG;
2132 break;
2133 }
2134
fitzhardinge111c6072004-03-09 02:45:07 +00002135 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002136 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002137 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002138 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002139
fitzhardinge111c6072004-03-09 02:45:07 +00002140 t_size = newTemp(cb);
2141 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2142 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002143
fitzhardinge111c6072004-03-09 02:45:07 +00002144 /* XXX all registers should be flushed to baseblock
2145 here */
2146 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
2147 uCCall(cb, (Addr) & eraser_mem_help_read_N, 2, 2, False);
2148
2149 VG_(copy_UInstr)(cb, u_in);
2150 t_size = INVALID_TEMPREG;
2151 break;
sewardja5b3aec2002-10-22 05:09:36 +00002152 }
2153
thughes96b466a2004-03-15 16:43:58 +00002154 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002155 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002156
2157 t_size = newTemp(cb);
2158 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2159 uLiteral(cb, (UInt)u_in->size);
2160
2161 /* XXX all registers should be flushed to baseblock
2162 here */
2163 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
2164 uCCall(cb, (Addr) & eraser_mem_help_read_N, 2, 2, False);
2165
2166 VG_(copy_UInstr)(cb, u_in);
2167 t_size = INVALID_TEMPREG;
2168 break;
2169 }
2170
fitzhardinge111c6072004-03-09 02:45:07 +00002171 case SSE2a_MemRd:
2172 case SSE2a1_MemRd:
2173 case SSE3a_MemRd:
2174 case SSE3a1_MemRd:
2175 case SSE3ag_MemRd_RegWr: {
2176 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2177
njnca82cc02004-11-22 17:18:48 +00002178 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002179
2180 t_size = newTemp(cb);
2181 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2182 uLiteral(cb, (UInt)u_in->size);
2183
2184 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
2185 uCCall(cb, (Addr) & eraser_mem_help_read_N, 2, 2, False);
2186
2187 VG_(copy_UInstr)(cb, u_in);
2188 t_size = INVALID_TEMPREG;
2189 break;
2190 }
2191
sewardja5b3aec2002-10-22 05:09:36 +00002192 case STORE: {
2193 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002194 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2195 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002196
sewardjf6374322002-11-13 22:35:55 +00002197 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2198 nonstk_st++;
2199
2200 switch(u_in->size) {
2201 case 1: help = eraser_mem_help_write_1; break;
2202 case 2: help = eraser_mem_help_write_2; break;
2203 case 4: help = eraser_mem_help_write_4; break;
2204 default:
njn67993252004-11-22 18:02:32 +00002205 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002206 }
2207
jsgfcb1d1c02003-10-14 21:55:10 +00002208 /* XXX all registers should be flushed to baseblock
2209 here */
sewardjf6374322002-11-13 22:35:55 +00002210 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2211 uCCall(cb, (Addr)help, 2, 2, False);
2212 } else
2213 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002214
2215 VG_(copy_UInstr)(cb, u_in);
2216 t_size = INVALID_TEMPREG;
2217 break;
2218 }
2219
fitzhardinge111c6072004-03-09 02:45:07 +00002220 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002221 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002222 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002223 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002224
2225 t_size = newTemp(cb);
2226 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2227 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002228 /* XXX all registers should be flushed to baseblock
2229 here */
sewardja5b3aec2002-10-22 05:09:36 +00002230 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
2231 uCCall(cb, (Addr) & eraser_mem_help_write_N, 2, 2, False);
2232
2233 VG_(copy_UInstr)(cb, u_in);
2234 t_size = INVALID_TEMPREG;
2235 break;
2236 }
njn25e49d8e72002-09-23 09:36:25 +00002237
fitzhardinge111c6072004-03-09 02:45:07 +00002238 case SSE2a_MemWr:
2239 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002240 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002241 512 == u_in->size);
2242
2243 t_size = newTemp(cb);
2244 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2245 uLiteral(cb, (UInt)u_in->size);
2246 /* XXX all registers should be flushed to baseblock
2247 here */
2248 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
2249 uCCall(cb, (Addr) & eraser_mem_help_write_N, 2, 2, False);
2250
2251 VG_(copy_UInstr)(cb, u_in);
2252 t_size = INVALID_TEMPREG;
2253 break;
2254 }
sewardj3d7c9c82003-03-26 21:08:13 +00002255
njn25e49d8e72002-09-23 09:36:25 +00002256 default:
sewardjf6374322002-11-13 22:35:55 +00002257 /* conservative tromping */
2258 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2259 stackref[u_in->val1] = False;
2260 if (u_in->tag2 == TempReg)
2261 stackref[u_in->val2] = False;
2262 if (u_in->tag3 == TempReg)
2263 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002264 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002265 break;
2266 }
2267 }
2268
sewardjf6374322002-11-13 22:35:55 +00002269 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002270 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002271 return cb;
2272}
njn14d01ce2004-11-26 11:30:14 +00002273#endif
2274IRBB* TL_(instrument) ( IRBB* bb_in, VexGuestLayout* layout, IRType hWordTy )
2275{
2276 VG_(message)(Vg_DebugMsg, "Helgrind is not yet ready to handle Vex IR");
2277 VG_(exit)(1);
2278}
njn25e49d8e72002-09-23 09:36:25 +00002279
2280/*--------------------------------------------------------------------*/
2281/*--- Error and suppression handling ---*/
2282/*--------------------------------------------------------------------*/
2283
2284typedef
2285 enum {
2286 /* Possible data race */
2287 EraserSupp
2288 }
2289 EraserSuppKind;
2290
2291/* What kind of error it is. */
2292typedef
2293 enum {
sewardj16748af2002-10-22 04:55:54 +00002294 EraserErr, /* data-race */
2295 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002296 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002297 }
2298 EraserErrorKind;
2299
sewardj16748af2002-10-22 04:55:54 +00002300/* The classification of a faulting address. */
2301typedef
2302 enum { Undescribed, /* as-yet unclassified */
2303 Stack,
2304 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002305 Mallocd,
2306 Freed,
sewardj16748af2002-10-22 04:55:54 +00002307 Segment
2308 }
2309 AddrKind;
2310/* Records info about a faulting address. */
2311typedef
2312 struct {
2313 /* ALL */
2314 AddrKind akind;
2315 /* Freed, Mallocd */
2316 Int blksize;
2317 /* Freed, Mallocd */
2318 Int rwoffset;
2319 /* Freed, Mallocd */
2320 ExeContext* lastchange;
2321 ThreadId lasttid;
2322 /* Stack */
2323 ThreadId stack_tid;
2324 /* Segment */
2325 const Char* filename;
2326 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002327 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002328 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002329 /* symbolic address description */
2330 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002331 }
2332 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002333
sewardj16748af2002-10-22 04:55:54 +00002334/* What kind of memory access is involved in the error? */
2335typedef
2336 enum { ReadAxs, WriteAxs, ExecAxs }
2337 AxsKind;
2338
2339/* Extra context for memory errors */
2340typedef
2341 struct {
2342 AxsKind axskind;
2343 Int size;
2344 AddrInfo addrinfo;
2345 Bool isWrite;
2346 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002347 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002348 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002349 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002350 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002351 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002352 const LockSet *held_lockset;
2353 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002354 }
2355 HelgrindError;
2356
2357static __inline__
2358void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002359{
sewardj16748af2002-10-22 04:55:54 +00002360 ai->akind = Unknown;
2361 ai->blksize = 0;
2362 ai->rwoffset = 0;
2363 ai->lastchange = NULL;
2364 ai->lasttid = VG_INVALID_THREADID;
2365 ai->filename = NULL;
2366 ai->section = "???";
2367 ai->stack_tid = VG_INVALID_THREADID;
2368 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002369 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002370}
2371
sewardj16748af2002-10-22 04:55:54 +00002372static __inline__
2373void clear_HelgrindError ( HelgrindError* err_extra )
2374{
2375 err_extra->axskind = ReadAxs;
2376 err_extra->size = 0;
2377 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002378 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002379 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002380 err_extra->prev_lockset = 0;
2381 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002382 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002383 clear_AddrInfo ( &err_extra->addrinfo );
2384 err_extra->isWrite = False;
2385}
2386
2387
2388
2389/* Describe an address as best you can, for error messages,
2390 putting the result in ai. */
2391
thughes4ad52d02004-06-27 17:37:21 +00002392/* Callback for searching malloc'd and free'd lists */
2393static Bool addr_is_in_block(VgHashNode *node, void *ap)
2394{
2395 HG_Chunk* hc2 = (HG_Chunk*)node;
2396 Addr a = *(Addr *)ap;
2397
2398 return (hc2->data <= a && a < hc2->data + hc2->size);
2399}
2400
sewardj16748af2002-10-22 04:55:54 +00002401static void describe_addr ( Addr a, AddrInfo* ai )
2402{
njn3e884182003-04-15 13:03:23 +00002403 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002404 Int i;
sewardj16748af2002-10-22 04:55:54 +00002405
sewardj16748af2002-10-22 04:55:54 +00002406 /* Search for it in segments */
2407 {
2408 const SegInfo *seg;
2409
2410 for(seg = VG_(next_seginfo)(NULL);
2411 seg != NULL;
2412 seg = VG_(next_seginfo)(seg)) {
2413 Addr base = VG_(seg_start)(seg);
nethercote928a5f72004-11-03 18:10:37 +00002414 SizeT size = VG_(seg_size)(seg);
sewardj16748af2002-10-22 04:55:54 +00002415 const UChar *filename = VG_(seg_filename)(seg);
2416
2417 if (a >= base && a < base+size) {
2418 ai->akind = Segment;
2419 ai->blksize = size;
2420 ai->rwoffset = a - base;
2421 ai->filename = filename;
2422
2423 switch(VG_(seg_sect_kind)(a)) {
2424 case Vg_SectText: ai->section = "text"; break;
2425 case Vg_SectData: ai->section = "data"; break;
2426 case Vg_SectBSS: ai->section = "BSS"; break;
2427 case Vg_SectGOT: ai->section = "GOT"; break;
2428 case Vg_SectPLT: ai->section = "PLT"; break;
2429 case Vg_SectUnknown:
2430 default:
2431 ai->section = "???"; break;
2432 }
2433
2434 return;
2435 }
2436 }
2437 }
2438
2439 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002440 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002441 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002442 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002443 ai->blksize = hc->size;
2444 ai->rwoffset = (Int)a - (Int)(hc->data);
2445 ai->lastchange = hc->where;
2446 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002447 return;
2448 }
sewardjdac0a442002-11-13 22:08:40 +00002449
2450 /* Look in recently freed memory */
2451 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002452 hc = freechunks[i];
2453 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002454 continue;
2455
njn3e884182003-04-15 13:03:23 +00002456 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002457 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002458 ai->blksize = hc->size;
2459 ai->rwoffset = a - hc->data;
2460 ai->lastchange = hc->where;
2461 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002462 return;
2463 }
2464 }
2465
sewardj16748af2002-10-22 04:55:54 +00002466 /* Clueless ... */
2467 ai->akind = Unknown;
2468 return;
2469}
2470
2471
njn7e614812003-04-21 22:04:03 +00002472/* Updates the copy with address info if necessary. */
njn26f02512004-11-22 18:33:15 +00002473UInt TL_(update_extra)(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002474{
njn7e614812003-04-21 22:04:03 +00002475 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002476
njn7e614812003-04-21 22:04:03 +00002477 extra = (HelgrindError*)VG_(get_error_extra)(err);
2478 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2479 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2480 }
2481 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002482}
2483
njn72718642003-07-24 08:45:32 +00002484static void record_eraser_error ( ThreadId tid, Addr a, Bool is_write,
sewardj0f811692002-10-22 04:59:26 +00002485 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002486{
sewardjc4a810d2002-11-13 22:25:51 +00002487 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002488 HelgrindError err_extra;
2489
sewardjff2c9232002-11-13 21:44:39 +00002490 n_eraser_warnings++;
2491
sewardj16748af2002-10-22 04:55:54 +00002492 clear_HelgrindError(&err_extra);
2493 err_extra.isWrite = is_write;
2494 err_extra.addrinfo.akind = Undescribed;
2495 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002496 if (clo_execontext)
2497 err_extra.lasttouched = getExeContext(a);
jsgfcb1d1c02003-10-14 21:55:10 +00002498 err_extra.addrinfo.expr = VG_(describe_addr)(tid, a);
2499
njn72718642003-07-24 08:45:32 +00002500 VG_(maybe_record_error)( tid, EraserErr, a,
sewardj16748af2002-10-22 04:55:54 +00002501 (is_write ? "writing" : "reading"),
2502 &err_extra);
2503
sewardjc4a810d2002-11-13 22:25:51 +00002504 sw = get_sword_addr(a);
2505 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2506 ThreadLifeSeg *tls = unpackTLS(sw->other);
2507 tls->refcount--;
2508 }
2509
sewardj7f3ad222002-11-13 22:11:53 +00002510 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002511}
2512
sewardj39a4d842002-11-13 22:14:30 +00002513static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002514 Char *str, ExeContext *ec)
2515{
2516 HelgrindError err_extra;
2517
2518 clear_HelgrindError(&err_extra);
2519 err_extra.addrinfo.akind = Undescribed;
2520 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002521 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002522 err_extra.lasttid = tid;
2523
njn72718642003-07-24 08:45:32 +00002524 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002525 (Addr)mutex->mutexp, str, &err_extra);
2526}
njn25e49d8e72002-09-23 09:36:25 +00002527
sewardj39a4d842002-11-13 22:14:30 +00002528static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002529 const LockSet *lockset_holding,
2530 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002531{
2532 HelgrindError err_extra;
2533
2534 n_lockorder_warnings++;
2535
2536 clear_HelgrindError(&err_extra);
2537 err_extra.addrinfo.akind = Undescribed;
2538 err_extra.mutex = mutex;
2539
sewardjc808ef52002-11-13 22:43:26 +00002540 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002541 err_extra.held_lockset = lockset_holding;
2542 err_extra.prev_lockset = lockset_prev;
2543
njn72718642003-07-24 08:45:32 +00002544 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002545}
2546
njn26f02512004-11-22 18:33:15 +00002547Bool TL_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002548{
njn810086f2002-11-14 12:42:47 +00002549 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002550
njnca82cc02004-11-22 17:18:48 +00002551 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002552
2553 switch (VG_(get_error_kind)(e1)) {
sewardj16748af2002-10-22 04:55:54 +00002554 case EraserErr:
njn810086f2002-11-14 12:42:47 +00002555 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002556
2557 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002558 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002559 }
2560
njn810086f2002-11-14 12:42:47 +00002561 e1s = VG_(get_error_string)(e1);
2562 e2s = VG_(get_error_string)(e2);
2563 if (e1s != e2s) return False;
2564 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002565 return True;
2566}
2567
sewardj16748af2002-10-22 04:55:54 +00002568static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002569{
jsgfcb1d1c02003-10-14 21:55:10 +00002570 if (ai->expr != NULL)
2571 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002572 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002573
sewardj16748af2002-10-22 04:55:54 +00002574 switch (ai->akind) {
2575 case Stack:
2576 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002577 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002578 a, ai->stack_tid);
2579 break;
2580 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002581 if (ai->expr != NULL)
2582 break;
2583
nethercote3b390c72003-11-13 17:53:43 +00002584 /* maybe_gcc is never set to True! This is a hangover from code
2585 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002586 if (ai->maybe_gcc) {
2587 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002588 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002589 a);
2590 VG_(message)(Vg_UserMsg,
2591 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2592 } else {
2593 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002594 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002595 }
2596 break;
2597 case Segment:
2598 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002599 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002600 a, ai->section, ai->filename);
2601 break;
sewardjdac0a442002-11-13 22:08:40 +00002602 case Mallocd:
2603 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002604 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002605 UChar* relative;
2606 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002607 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002608 relative = "before";
2609 } else if (ai->rwoffset >= ai->blksize) {
2610 delta = ai->rwoffset - ai->blksize;
2611 relative = "after";
2612 } else {
2613 delta = ai->rwoffset;
2614 relative = "inside";
2615 }
2616 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002617 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2618 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002619 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002620 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002621 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002622
sewardj16748af2002-10-22 04:55:54 +00002623 VG_(pp_ExeContext)(ai->lastchange);
2624 break;
2625 }
2626 default:
njn67993252004-11-22 18:02:32 +00002627 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002628 }
njn25e49d8e72002-09-23 09:36:25 +00002629}
2630
sewardj4bffb232002-11-13 21:46:34 +00002631static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002632{
sewardjff2c9232002-11-13 21:44:39 +00002633 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002634 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002635
sewardj4bffb232002-11-13 21:46:34 +00002636 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2637 lockset->setsize * 120 +
2638 1);
sewardjff2c9232002-11-13 21:44:39 +00002639
2640 cp = buf;
2641 if (prefix)
2642 cp += VG_(sprintf)(cp, "%s", prefix);
2643
sewardj4bffb232002-11-13 21:46:34 +00002644 for(i = 0; i < lockset->setsize; i++)
2645 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2646 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002647
sewardj4bffb232002-11-13 21:46:34 +00002648 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002649 cp[-2] = '\0';
2650 else
2651 *cp = '\0';
2652
2653 return buf;
2654}
njn25e49d8e72002-09-23 09:36:25 +00002655
njn26f02512004-11-22 18:33:15 +00002656void TL_(pp_Error) ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002657{
njn810086f2002-11-14 12:42:47 +00002658 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002659 Char buf[100];
2660 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002661 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002662
2663 *msg = '\0';
2664
njn810086f2002-11-14 12:42:47 +00002665 switch(VG_(get_error_kind)(err)) {
2666 case EraserErr: {
2667 Addr err_addr = VG_(get_error_address)(err);
2668
sewardj16748af2002-10-22 04:55:54 +00002669 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002670 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002671 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002672 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002673
2674 switch(extra->prevstate.state) {
2675 case Vge_Virgin:
2676 /* shouldn't be possible to go directly from virgin -> error */
2677 VG_(sprintf)(buf, "virgin!?");
2678 break;
2679
sewardjc4a810d2002-11-13 22:25:51 +00002680 case Vge_Excl: {
2681 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2682
njnca82cc02004-11-22 17:18:48 +00002683 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002684 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002685 break;
sewardjc4a810d2002-11-13 22:25:51 +00002686 }
sewardj16748af2002-10-22 04:55:54 +00002687
2688 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002689 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002690 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002691
2692 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002693 VG_(sprintf)(buf, "shared %s, no locks",
2694 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2695 break;
2696 }
2697
sewardjff2c9232002-11-13 21:44:39 +00002698 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2699 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002700 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002701
sewardj16748af2002-10-22 04:55:54 +00002702 break;
2703 }
sewardj16748af2002-10-22 04:55:54 +00002704
sewardj499e3de2002-11-13 22:22:25 +00002705 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002706 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002707
sewardj72baa7a2002-12-09 23:32:58 +00002708 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002709 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002710 Char file[100];
2711 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002712 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002713
nethercote3b390c72003-11-13 17:53:43 +00002714 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002715 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002716 pp_state(extra->lasttouched.state),
2717 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002718
nethercoteca788ff2004-10-20 10:58:09 +00002719 if (VG_(get_filename_linenum)(ip, file, sizeof(file), &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002720 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002721 ip, ip, file, line);
2722 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002723 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002724 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002725 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002726 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002727 }
sewardj72baa7a2002-12-09 23:32:58 +00002728 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002729 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002730 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002731 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002732 pp_state(extra->lasttouched.state),
2733 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002734 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002735 }
sewardj16748af2002-10-22 04:55:54 +00002736 break;
njn810086f2002-11-14 12:42:47 +00002737 }
sewardj16748af2002-10-22 04:55:54 +00002738
2739 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002740 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002741 VG_(get_error_address)(err),
2742 VG_(get_error_address)(err),
2743 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002744 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002745 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002746 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002747 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002748 }
njn810086f2002-11-14 12:42:47 +00002749 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002750 break;
sewardjff2c9232002-11-13 21:44:39 +00002751
2752 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002753 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002754 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002755 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002756
2757 msg = lockset_str(NULL, heldset);
2758
2759 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002760 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002761 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002762 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2763
sewardj4bffb232002-11-13 21:46:34 +00002764 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002765 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002766
sewardj542494b2002-11-13 22:46:13 +00002767 /* needs to be a recursive search+display */
2768 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002769 continue;
2770
nethercote3b390c72003-11-13 17:53:43 +00002771 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002772 lsmx->mutexp, lsmx->mutexp);
2773 VG_(pp_ExeContext)(lsmx->location);
2774 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002775 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002776 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002777 }
2778
2779 break;
sewardj16748af2002-10-22 04:55:54 +00002780 }
sewardjff2c9232002-11-13 21:44:39 +00002781 }
2782
2783 if (msg != buf)
2784 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002785}
2786
2787
njn26f02512004-11-22 18:33:15 +00002788Bool TL_(recognised_suppression) ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002789{
2790 if (0 == VG_(strcmp)(name, "Eraser")) {
njn810086f2002-11-14 12:42:47 +00002791 VG_(set_supp_kind)(su, EraserSupp);
njn25e49d8e72002-09-23 09:36:25 +00002792 return True;
2793 } else {
2794 return False;
2795 }
2796}
2797
2798
njn26f02512004-11-22 18:33:15 +00002799Bool TL_(read_extra_suppression_info) ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002800{
2801 /* do nothing -- no extra suppression info present. Return True to
2802 indicate nothing bad happened. */
2803 return True;
2804}
2805
2806
njn26f02512004-11-22 18:33:15 +00002807Bool TL_(error_matches_suppression)(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002808{
njnca82cc02004-11-22 17:18:48 +00002809 tl_assert(VG_(get_supp_kind)(su) == EraserSupp);
nethercote64366b42003-12-01 13:11:47 +00002810
2811 return (VG_(get_error_kind)(err) == EraserErr);
njn25e49d8e72002-09-23 09:36:25 +00002812}
2813
njn26f02512004-11-22 18:33:15 +00002814extern Char* TL_(get_error_name) ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002815{
2816 if (EraserErr == VG_(get_error_kind)(err)) {
2817 return "Eraser";
2818 } else {
2819 return NULL; /* Other errors types can't be suppressed */
2820 }
2821}
2822
njn26f02512004-11-22 18:33:15 +00002823extern void TL_(print_extra_suppression_info) ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002824{
2825 /* Do nothing */
2826}
njn25e49d8e72002-09-23 09:36:25 +00002827
sewardjdca84112002-11-13 22:29:34 +00002828static void eraser_pre_mutex_lock(ThreadId tid, void* void_mutex)
2829{
2830 Mutex *mutex = get_mutex((Addr)void_mutex);
2831
njn72718642003-07-24 08:45:32 +00002832 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002833}
2834
njn25e49d8e72002-09-23 09:36:25 +00002835static void eraser_post_mutex_lock(ThreadId tid, void* void_mutex)
2836{
sewardj4bffb232002-11-13 21:46:34 +00002837 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002838 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002839 const LockSet* ls;
2840
njn72718642003-07-24 08:45:32 +00002841 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002842
njn25e49d8e72002-09-23 09:36:25 +00002843# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002844 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002845# endif
2846
njn25e49d8e72002-09-23 09:36:25 +00002847 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2848# if LOCKSET_SANITY > 1
2849 sanity_check_locksets("eraser_post_mutex_lock-IN");
2850# endif
2851
sewardj4bffb232002-11-13 21:46:34 +00002852 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002853
sewardj4bffb232002-11-13 21:46:34 +00002854 if (ls == NULL) {
2855 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2856 insert_LockSet(newset);
2857 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002858 }
sewardj4bffb232002-11-13 21:46:34 +00002859 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002860
sewardj4bffb232002-11-13 21:46:34 +00002861 if (debug || DEBUG_LOCKS)
2862 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002863
sewardj4bffb232002-11-13 21:46:34 +00002864 if (debug || LOCKSET_SANITY > 1)
2865 sanity_check_locksets("eraser_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002866}
2867
2868
2869static void eraser_post_mutex_unlock(ThreadId tid, void* void_mutex)
2870{
sewardjc26cc252002-10-23 21:58:55 +00002871 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002872 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002873 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002874 const LockSet *ls;
2875
njn72718642003-07-24 08:45:32 +00002876 test_mutex_state(mutex, MxUnlocked, tid);
2877 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002878
sewardjdac0a442002-11-13 22:08:40 +00002879 if (!ismember(thread_locks[tid], mutex))
2880 return;
2881
sewardjc26cc252002-10-23 21:58:55 +00002882 if (debug || DEBUG_LOCKS)
2883 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002884
sewardjc26cc252002-10-23 21:58:55 +00002885 if (debug || LOCKSET_SANITY > 1)
2886 sanity_check_locksets("eraser_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002887
sewardj4bffb232002-11-13 21:46:34 +00002888 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002889
sewardj4bffb232002-11-13 21:46:34 +00002890 if (ls == NULL) {
2891 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2892 insert_LockSet(newset);
2893 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002894 }
2895
2896 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002897 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002898 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002899 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002900
sewardj4bffb232002-11-13 21:46:34 +00002901 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002902
sewardjc26cc252002-10-23 21:58:55 +00002903 if (debug || LOCKSET_SANITY > 1)
2904 sanity_check_locksets("eraser_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002905}
2906
2907
2908/* ---------------------------------------------------------------------
2909 Checking memory reads and writes
2910 ------------------------------------------------------------------ */
2911
2912/* Behaviour on reads and writes:
2913 *
2914 * VIR EXCL SHAR SH_MOD
2915 * ----------------------------------------------------------------
2916 * rd/wr, 1st thread | - EXCL - -
2917 * rd, new thread | - SHAR - -
2918 * wr, new thread | - SH_MOD - -
2919 * rd | error! - SHAR SH_MOD
2920 * wr | EXCL - SH_MOD SH_MOD
2921 * ----------------------------------------------------------------
2922 */
2923
sewardj8fac99a2002-11-13 22:31:26 +00002924static inline
njn25e49d8e72002-09-23 09:36:25 +00002925void dump_around_a(Addr a)
2926{
2927 UInt i;
2928 shadow_word* sword;
2929 VG_(printf)("NEARBY:\n");
2930 for (i = a - 12; i <= a + 12; i += 4) {
2931 sword = get_sword_addr(i);
2932 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2933 }
2934}
njn25e49d8e72002-09-23 09:36:25 +00002935
2936#if DEBUG_ACCESSES
2937 #define DEBUG_STATE(args...) \
2938 VG_(printf)("(%u) ", size), \
2939 VG_(printf)(args)
2940#else
2941 #define DEBUG_STATE(args...)
2942#endif
2943
njn72718642003-07-24 08:45:32 +00002944static void eraser_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002945{
sewardj72baa7a2002-12-09 23:32:58 +00002946 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002947 shadow_word prevstate;
2948 ThreadLifeSeg *tls;
2949 const LockSet *ls;
2950 Bool statechange = False;
2951
2952 static const void *const states[4] = {
2953 [Vge_Virgin] &&st_virgin,
2954 [Vge_Excl] &&st_excl,
2955 [Vge_Shar] &&st_shar,
2956 [Vge_SharMod] &&st_sharmod,
2957 };
2958
2959 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002960 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002961
2962 sword = get_sword_addr(a);
2963 if (sword == SEC_MAP_ACCESS) {
2964 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2965 return;
2966 }
2967
2968 prevstate = *sword;
2969
2970 goto *states[sword->state];
2971
2972 /* This looks like reading of unitialised memory, may be legit. Eg.
2973 * calloc() zeroes its values, so untouched memory may actually be
2974 * initialised. Leave that stuff to Valgrind. */
2975 st_virgin:
2976 if (TID_INDICATING_NONVIRGIN == sword->other) {
2977 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
2978 if (DEBUG_VIRGIN_READS)
2979 dump_around_a(a);
2980 } else {
2981 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
2982 }
2983 statechange = True;
2984 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
2985 tls->refcount++;
2986 goto done;
2987
2988 st_excl: {
2989 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
2990
2991 if (tls == sw_tls) {
2992 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
2993 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
2994 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
2995 } else if (tlsIsDisjoint(tls, sw_tls)) {
2996 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
2997 statechange = True;
2998 sword->other = packTLS(tls);
2999 sw_tls->refcount--;
3000 tls->refcount++;
3001 } else {
3002 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3003 sw_tls->refcount--;
3004 statechange = True;
3005 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3006
3007 if (DEBUG_MEM_LOCKSET_CHANGES)
3008 print_LockSet("excl read locks", unpackLockSet(sword->other));
3009 }
3010 goto done;
3011 }
3012
3013 st_shar:
3014 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3015 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3016 thread_locks[tid]));
3017 statechange = sword->other != prevstate.other;
3018 goto done;
3019
3020 st_sharmod:
3021 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3022 ls = intersect(unpackLockSet(sword->other),
3023 thread_locks[tid]);
3024 sword->other = packLockSet(ls);
3025
3026 statechange = sword->other != prevstate.other;
3027
3028 if (isempty(ls)) {
njn72718642003-07-24 08:45:32 +00003029 record_eraser_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003030 }
3031 goto done;
3032
3033 done:
3034 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003035 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003036
3037 if (clo_execontext == EC_Some)
nethercoteca788ff2004-10-20 10:58:09 +00003038 ecip = IP(VG_(get_EIP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003039 else
nethercoteca788ff2004-10-20 10:58:09 +00003040 ecip = EC(VG_(get_ExeContext)(tid), prevstate, tls);
3041 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003042 }
3043}
njn25e49d8e72002-09-23 09:36:25 +00003044
nethercote451eae92004-11-02 13:06:32 +00003045static void eraser_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003046{
njn72718642003-07-24 08:45:32 +00003047 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003048
sewardj8fac99a2002-11-13 22:31:26 +00003049 end = ROUNDUP(a+size, 4);
3050 a = ROUNDDN(a, 4);
3051
sewardj18cd4a52002-11-13 22:37:41 +00003052 for ( ; a < end; a += 4)
njn72718642003-07-24 08:45:32 +00003053 eraser_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003054}
3055
njn72718642003-07-24 08:45:32 +00003056static void eraser_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003057{
3058 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003059 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003060 shadow_word prevstate;
3061 Bool statechange = False;
3062 static const void *const states[4] = {
3063 [Vge_Virgin] &&st_virgin,
3064 [Vge_Excl] &&st_excl,
3065 [Vge_Shar] &&st_shar,
3066 [Vge_SharMod] &&st_sharmod,
3067 };
3068
sewardjc4a810d2002-11-13 22:25:51 +00003069 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003070 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003071
sewardj18cd4a52002-11-13 22:37:41 +00003072 sword = get_sword_addr(a);
3073 if (sword == SEC_MAP_ACCESS) {
3074 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3075 return;
3076 }
njn25e49d8e72002-09-23 09:36:25 +00003077
sewardj18cd4a52002-11-13 22:37:41 +00003078 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003079
sewardj18cd4a52002-11-13 22:37:41 +00003080 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003081
sewardj18cd4a52002-11-13 22:37:41 +00003082 st_virgin:
3083 if (TID_INDICATING_NONVIRGIN == sword->other)
3084 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3085 else
3086 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3087 statechange = True;
3088 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3089 tls->refcount++;
3090 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003091
sewardj18cd4a52002-11-13 22:37:41 +00003092 st_excl: {
3093 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3094
3095 if (tls == sw_tls) {
3096 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3097 goto done;
3098 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3099 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3100 goto done;
3101 } else if (tlsIsDisjoint(tls, sw_tls)) {
3102 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3103 sword->other = packTLS(tls);
3104 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003105 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003106 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003107 } else {
3108 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3109 statechange = True;
3110 sw_tls->refcount--;
3111 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3112 if(DEBUG_MEM_LOCKSET_CHANGES)
3113 print_LockSet("excl write locks", unpackLockSet(sword->other));
3114 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003115 }
sewardj18cd4a52002-11-13 22:37:41 +00003116 }
njn25e49d8e72002-09-23 09:36:25 +00003117
sewardj18cd4a52002-11-13 22:37:41 +00003118 st_shar:
3119 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3120 sword->state = Vge_SharMod;
3121 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3122 thread_locks[tid]));
3123 statechange = True;
3124 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003125
sewardj18cd4a52002-11-13 22:37:41 +00003126 st_sharmod:
3127 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3128 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3129 thread_locks[tid]));
3130 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003131
sewardj18cd4a52002-11-13 22:37:41 +00003132 SHARED_MODIFIED:
3133 if (isempty(unpackLockSet(sword->other))) {
njn72718642003-07-24 08:45:32 +00003134 record_eraser_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003135 }
3136 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003137
sewardj18cd4a52002-11-13 22:37:41 +00003138 done:
3139 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003140 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003141
sewardj18cd4a52002-11-13 22:37:41 +00003142 if (clo_execontext == EC_Some)
nethercoteca788ff2004-10-20 10:58:09 +00003143 ecip = IP(VG_(get_EIP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003144 else
nethercoteca788ff2004-10-20 10:58:09 +00003145 ecip = EC(VG_(get_ExeContext)(tid), prevstate, tls);
3146 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003147 }
3148}
3149
nethercote451eae92004-11-02 13:06:32 +00003150static void eraser_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003151{
sewardj8fac99a2002-11-13 22:31:26 +00003152 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003153
sewardj8fac99a2002-11-13 22:31:26 +00003154 end = ROUNDUP(a+size, 4);
3155 a = ROUNDDN(a, 4);
3156
sewardj18cd4a52002-11-13 22:37:41 +00003157 for ( ; a < end; a += 4)
njn72718642003-07-24 08:45:32 +00003158 eraser_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003159}
3160
3161#undef DEBUG_STATE
3162
nethercote31212bc2004-02-29 15:50:04 +00003163REGPARM(1) static void eraser_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003164{
njn72718642003-07-24 08:45:32 +00003165 eraser_mem_read(a, 1, VG_(get_current_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003166}
3167
nethercote31212bc2004-02-29 15:50:04 +00003168REGPARM(1) static void eraser_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003169{
njn72718642003-07-24 08:45:32 +00003170 eraser_mem_read(a, 2, VG_(get_current_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003171}
3172
nethercote31212bc2004-02-29 15:50:04 +00003173REGPARM(1) static void eraser_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003174{
njn72718642003-07-24 08:45:32 +00003175 eraser_mem_read(a, 4, VG_(get_current_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003176}
3177
nethercote451eae92004-11-02 13:06:32 +00003178REGPARM(2) static void eraser_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003179{
njn72718642003-07-24 08:45:32 +00003180 eraser_mem_read(a, size, VG_(get_current_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003181}
3182
nethercote31212bc2004-02-29 15:50:04 +00003183REGPARM(2) static void eraser_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003184{
3185 if (*(UChar *)a != val)
njn72718642003-07-24 08:45:32 +00003186 eraser_mem_write(a, 1, VG_(get_current_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003187}
nethercote31212bc2004-02-29 15:50:04 +00003188REGPARM(2) static void eraser_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003189{
3190 if (*(UShort *)a != val)
njn72718642003-07-24 08:45:32 +00003191 eraser_mem_write(a, 2, VG_(get_current_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003192}
nethercote31212bc2004-02-29 15:50:04 +00003193REGPARM(2) static void eraser_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003194{
3195 if (*(UInt *)a != val)
njn72718642003-07-24 08:45:32 +00003196 eraser_mem_write(a, 4, VG_(get_current_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003197}
nethercote451eae92004-11-02 13:06:32 +00003198REGPARM(2) static void eraser_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003199{
njn72718642003-07-24 08:45:32 +00003200 eraser_mem_write(a, size, VG_(get_current_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003201}
njn25e49d8e72002-09-23 09:36:25 +00003202
sewardjc4a810d2002-11-13 22:25:51 +00003203static void hg_thread_create(ThreadId parent, ThreadId child)
3204{
3205 if (0)
3206 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3207
3208 newTLS(child);
3209 addPriorTLS(child, parent);
3210
3211 newTLS(parent);
3212}
3213
3214static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3215{
3216 if (0)
3217 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3218
3219 newTLS(joiner);
3220 addPriorTLS(joiner, joinee);
3221
3222 clearTLS(joinee);
3223}
3224
sewardj7a5ebcf2002-11-13 22:42:13 +00003225static Int __BUS_HARDWARE_LOCK__;
3226
3227static void bus_lock(void)
3228{
3229 ThreadId tid = VG_(get_current_tid)();
3230 eraser_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3231 eraser_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3232}
3233
3234static void bus_unlock(void)
3235{
3236 ThreadId tid = VG_(get_current_tid)();
3237 eraser_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
3238}
3239
njn25e49d8e72002-09-23 09:36:25 +00003240/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003241/*--- Client requests ---*/
3242/*--------------------------------------------------------------------*/
3243
njn26f02512004-11-22 18:33:15 +00003244Bool TL_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003245{
njnfc26ff92004-11-22 19:12:49 +00003246 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003247 return False;
3248
3249 switch(args[0]) {
3250 case VG_USERREQ__HG_CLEAN_MEMORY:
3251 set_address_range_state(args[1], args[2], Vge_VirginInit);
3252 *ret = 0; /* meaningless */
3253 break;
3254
3255 case VG_USERREQ__HG_KNOWN_RACE:
3256 set_address_range_state(args[1], args[2], Vge_Error);
3257 *ret = 0; /* meaningless */
3258 break;
3259
3260 default:
3261 return False;
3262 }
3263
3264 return True;
3265}
3266
3267
3268/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00003269/*--- Setup ---*/
3270/*--------------------------------------------------------------------*/
3271
njn26f02512004-11-22 18:33:15 +00003272void TL_(pre_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +00003273{
3274 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003275 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003276
njn810086f2002-11-14 12:42:47 +00003277 VG_(details_name) ("Helgrind");
3278 VG_(details_version) (NULL);
3279 VG_(details_description) ("a data race detector");
3280 VG_(details_copyright_author)(
nethercote08fa9a72004-07-16 17:44:00 +00003281 "Copyright (C) 2002-2004, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003282 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003283 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003284
njn810086f2002-11-14 12:42:47 +00003285 VG_(needs_core_errors)();
njn95ec8702004-11-22 16:46:13 +00003286 VG_(needs_tool_errors)();
njn810086f2002-11-14 12:42:47 +00003287 VG_(needs_data_syms)();
njn810086f2002-11-14 12:42:47 +00003288 VG_(needs_client_requests)();
3289 VG_(needs_command_line_options)();
fitzhardinge98abfc72003-12-16 02:05:15 +00003290 VG_(needs_shadow_memory)();
njn25e49d8e72002-09-23 09:36:25 +00003291
fitzhardinge98abfc72003-12-16 02:05:15 +00003292 VG_(init_new_mem_startup) (& eraser_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003293
njn810086f2002-11-14 12:42:47 +00003294 /* stack ones not decided until VG_(post_clo_init)() */
njn25e49d8e72002-09-23 09:36:25 +00003295
fitzhardinge98abfc72003-12-16 02:05:15 +00003296 VG_(init_new_mem_brk) (& make_writable);
3297 VG_(init_new_mem_mmap) (& eraser_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003298
fitzhardinge98abfc72003-12-16 02:05:15 +00003299 VG_(init_change_mem_mprotect) (& eraser_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003300
fitzhardinge98abfc72003-12-16 02:05:15 +00003301 VG_(init_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003302
fitzhardinge98abfc72003-12-16 02:05:15 +00003303 VG_(init_die_mem_stack) (NULL);
3304 VG_(init_die_mem_stack_signal) (NULL);
3305 VG_(init_die_mem_brk) (NULL);
3306 VG_(init_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003307
fitzhardinge98abfc72003-12-16 02:05:15 +00003308 VG_(init_pre_mem_read) (& eraser_pre_mem_read);
3309 VG_(init_pre_mem_read_asciiz) (& eraser_pre_mem_read_asciiz);
3310 VG_(init_pre_mem_write) (& eraser_pre_mem_write);
3311 VG_(init_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003312
fitzhardinge98abfc72003-12-16 02:05:15 +00003313 VG_(init_post_thread_create) (& hg_thread_create);
3314 VG_(init_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003315
fitzhardinge98abfc72003-12-16 02:05:15 +00003316 VG_(init_pre_mutex_lock) (& eraser_pre_mutex_lock);
3317 VG_(init_post_mutex_lock) (& eraser_post_mutex_lock);
3318 VG_(init_post_mutex_unlock) (& eraser_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003319
njn14d01ce2004-11-26 11:30:14 +00003320 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003321 lockset_hash[i] = NULL;
3322
3323 empty = alloc_LockSet(0);
3324 insert_LockSet(empty);
3325 emptyset = empty;
3326
sewardjc4a810d2002-11-13 22:25:51 +00003327 /* Init lock table and thread segments */
3328 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003329 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003330
sewardjc4a810d2002-11-13 22:25:51 +00003331 newTLS(i);
3332 }
3333
njn25e49d8e72002-09-23 09:36:25 +00003334 init_shadow_memory();
njn3e884182003-04-15 13:03:23 +00003335 hg_malloc_list = VG_(HT_construct)();
njn25e49d8e72002-09-23 09:36:25 +00003336}
3337
njn26f02512004-11-22 18:33:15 +00003338Bool TL_(process_cmd_line_option)(Char* arg)
sewardj406270b2002-11-13 22:18:09 +00003339{
nethercote27fec902004-06-16 21:26:32 +00003340 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3341 clo_execontext = EC_None;
3342 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3343 clo_execontext = EC_Some;
3344 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3345 clo_execontext = EC_All;
sewardj499e3de2002-11-13 22:22:25 +00003346
nethercote27fec902004-06-16 21:26:32 +00003347 else VG_BOOL_CLO("--private-stacks", clo_priv_stacks)
sewardj499e3de2002-11-13 22:22:25 +00003348
nethercote27fec902004-06-16 21:26:32 +00003349 else
3350 return VG_(replacement_malloc_process_cmd_line_option)(arg);
sewardj499e3de2002-11-13 22:22:25 +00003351
nethercote27fec902004-06-16 21:26:32 +00003352 return True;
sewardj406270b2002-11-13 22:18:09 +00003353}
3354
njn26f02512004-11-22 18:33:15 +00003355void TL_(print_usage)(void)
sewardj406270b2002-11-13 22:18:09 +00003356{
njn3e884182003-04-15 13:03:23 +00003357 VG_(printf)(
sewardje11d6c82002-12-15 02:00:41 +00003358" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3359" --show-last-access=no|some|all\n"
3360" show location of last word access on error [no]\n"
njn3e884182003-04-15 13:03:23 +00003361 );
3362 VG_(replacement_malloc_print_usage)();
sewardj406270b2002-11-13 22:18:09 +00003363}
3364
njn26f02512004-11-22 18:33:15 +00003365void TL_(print_debug_usage)(void)
njn3e884182003-04-15 13:03:23 +00003366{
3367 VG_(replacement_malloc_print_debug_usage)();
3368}
njn25e49d8e72002-09-23 09:36:25 +00003369
njn26f02512004-11-22 18:33:15 +00003370void TL_(post_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +00003371{
nethercote451eae92004-11-02 13:06:32 +00003372 void (*stack_tracker)(Addr a, SizeT len);
njn810086f2002-11-14 12:42:47 +00003373
sewardj499e3de2002-11-13 22:22:25 +00003374 if (clo_execontext) {
3375 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3376 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3377 }
sewardjf6374322002-11-13 22:35:55 +00003378
njn810086f2002-11-14 12:42:47 +00003379 if (clo_priv_stacks)
3380 stack_tracker = & eraser_new_mem_stack_private;
3381 else
3382 stack_tracker = & eraser_new_mem_stack;
sewardjf6374322002-11-13 22:35:55 +00003383
fitzhardinge98abfc72003-12-16 02:05:15 +00003384 VG_(init_new_mem_stack) (stack_tracker);
3385 VG_(init_new_mem_stack_signal) (stack_tracker);
njn25e49d8e72002-09-23 09:36:25 +00003386}
3387
3388
njn26f02512004-11-22 18:33:15 +00003389void TL_(fini)(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +00003390{
sewardjdac0a442002-11-13 22:08:40 +00003391 if (DEBUG_LOCK_TABLE) {
sewardj4bffb232002-11-13 21:46:34 +00003392 pp_all_LockSets();
sewardjdac0a442002-11-13 22:08:40 +00003393 pp_all_mutexes();
3394 }
sewardj4bffb232002-11-13 21:46:34 +00003395
3396 if (LOCKSET_SANITY)
njn26f02512004-11-22 18:33:15 +00003397 sanity_check_locksets("TL_(fini)");
sewardj4bffb232002-11-13 21:46:34 +00003398
fitzhardinge111c6072004-03-09 02:45:07 +00003399 if (VG_(clo_verbosity) > 0)
3400 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
3401 n_eraser_warnings, n_lockorder_warnings);
sewardjf6374322002-11-13 22:35:55 +00003402
3403 if (0)
3404 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3405 stk_ld, stk_st, stk_ld + stk_st,
3406 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3407 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
njn25e49d8e72002-09-23 09:36:25 +00003408}
3409
fitzhardinge98abfc72003-12-16 02:05:15 +00003410/* Uses a 1:1 mapping */
njn26f02512004-11-22 18:33:15 +00003411VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 1.0)
fitzhardinge98abfc72003-12-16 02:05:15 +00003412
njn25e49d8e72002-09-23 09:36:25 +00003413/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003414/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003415/*--------------------------------------------------------------------*/