blob: b45d13d3465c763b8deba7b4418ca63750896ce8 [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00003/*--- Helgrind: checking for data races in threaded programs. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Helgrind, a Valgrind tool for detecting
njnc9539842002-10-02 13:26:35 +00009 data races in threaded programs.
njn25e49d8e72002-09-23 09:36:25 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2002-2005 Nicholas Nethercote
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
sewardj8fac99a2002-11-13 22:31:26 +0000602 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
603
njn25e49d8e72002-09-23 09:36:25 +0000604 set_sword(a, virgin_sword);
605}
606
sewardjc26cc252002-10-23 21:58:55 +0000607
sewardj274c6012002-10-22 04:54:55 +0000608/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000609/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000610/*------------------------------------------------------------*/
611
sewardj39a4d842002-11-13 22:14:30 +0000612typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000613typedef struct _LockSet LockSet;
614
sewardj16748af2002-10-22 04:55:54 +0000615typedef enum MutexState {
616 MxUnknown, /* don't know */
617 MxUnlocked, /* unlocked */
618 MxLocked, /* locked */
619 MxDead /* destroyed */
620} MutexState;
621
sewardj39a4d842002-11-13 22:14:30 +0000622struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000623 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000624 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000625
626 MutexState state; /* mutex state */
627 ThreadId tid; /* owner */
628 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000629
sewardj4bffb232002-11-13 21:46:34 +0000630 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000631 UInt mark; /* mark for graph traversal */
632};
sewardj16748af2002-10-22 04:55:54 +0000633
sewardj39a4d842002-11-13 22:14:30 +0000634static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000635{
sewardjdac0a442002-11-13 22:08:40 +0000636 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000637}
njn25e49d8e72002-09-23 09:36:25 +0000638
sewardj274c6012002-10-22 04:54:55 +0000639struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000640 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000641 UInt hash; /* hash code */
642 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000643 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000644};
sewardj4bffb232002-11-13 21:46:34 +0000645
646static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000647
648/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000649static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000650
sewardjdac0a442002-11-13 22:08:40 +0000651#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000652
sewardj4bffb232002-11-13 21:46:34 +0000653static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000654
sewardj4bffb232002-11-13 21:46:34 +0000655/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000656static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000657{
sewardj4bffb232002-11-13 21:46:34 +0000658 UInt id;
659
njn94065fd2004-11-22 19:26:27 +0000660 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000661 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000662
663 return id;
njn25e49d8e72002-09-23 09:36:25 +0000664}
665
sewardj8fac99a2002-11-13 22:31:26 +0000666static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000667{
sewardj4bffb232002-11-13 21:46:34 +0000668 return (LockSet *)(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000669}
670
njn25e49d8e72002-09-23 09:36:25 +0000671static
sewardj4bffb232002-11-13 21:46:34 +0000672void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000673{
sewardj05bcdcb2003-05-18 10:05:38 +0000674 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000675 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000676 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000677 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000678
679 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000680 }
681 VG_(printf)("}\n");
682}
683
684
sewardj4bffb232002-11-13 21:46:34 +0000685static void print_LockSet(const Char *s, const LockSet *ls)
686{
687 VG_(printf)("%s: ", s);
688 pp_LockSet(ls);
689}
690
691/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000692static UInt hash_LockSet_w_wo(const LockSet *ls,
693 const Mutex *with,
694 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000695{
sewardj05bcdcb2003-05-18 10:05:38 +0000696 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000697 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000698
njnca82cc02004-11-22 17:18:48 +0000699 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000700
701 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000702 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000703
704 if (without && mutex_cmp(without, mx) == 0)
705 continue;
706
707 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
708 mx = with;
709 with = NULL;
710 i--;
711 }
712
sewardj8fac99a2002-11-13 22:31:26 +0000713 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000714 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000715 }
716
717 return hash % LOCKSET_HASH_SZ;
718}
719
sewardj39a4d842002-11-13 22:14:30 +0000720static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000721{
722 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
723
724 if (0)
725 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
726
727 return hash;
728}
729
sewardj39a4d842002-11-13 22:14:30 +0000730static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000731{
732 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
733
734 if (0)
735 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
736
737 return hash;
738}
739
740static inline UInt hash_LockSet(const LockSet *ls)
741{
742 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
743
744 if (0)
745 VG_(printf)("hash %p -> %d\n", ls, hash);
746
747 return hash;
748}
749
750static
751Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000752{
753 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000754
sewardj4bffb232002-11-13 21:46:34 +0000755 if (a == b)
756 return True;
757 if (a->setsize != b->setsize)
758 return False;
njn25e49d8e72002-09-23 09:36:25 +0000759
sewardj4bffb232002-11-13 21:46:34 +0000760 for(i = 0; i < a->setsize; i++) {
761 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000762 return False;
njn25e49d8e72002-09-23 09:36:25 +0000763 }
764
sewardj4bffb232002-11-13 21:46:34 +0000765 return True;
njn25e49d8e72002-09-23 09:36:25 +0000766}
767
768
769/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
770 * doesn't do the insertion. Returns True if they match.
771 */
772static Bool
sewardj4bffb232002-11-13 21:46:34 +0000773weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000774 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000775{
sewardjc26cc252002-10-23 21:58:55 +0000776 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000777 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000778
njn25e49d8e72002-09-23 09:36:25 +0000779 /* Idea is to try and match each element of b against either an
780 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000781
782 if (debug) {
783 print_LockSet("weird_LockSet_equals a", a);
784 print_LockSet(" b", b);
785 VG_(printf)( " missing: %p%(y\n",
786 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000787 }
sewardjc26cc252002-10-23 21:58:55 +0000788
sewardj4bffb232002-11-13 21:46:34 +0000789 if ((a->setsize + 1) != b->setsize) {
790 if (debug)
791 VG_(printf)(" fastpath length mismatch -> 0\n");
792 return False;
793 }
794
sewardjc26cc252002-10-23 21:58:55 +0000795 /* There are three phases to this compare:
796 1 the section from the start of a up to missing_mutex
797 2 missing mutex itself
798 3 the section after missing_mutex to the end of a
799 */
800
sewardj4bffb232002-11-13 21:46:34 +0000801 ia = 0;
802 ib = 0;
803
sewardjc26cc252002-10-23 21:58:55 +0000804 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000805 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000806 if (debug) {
807 print_LockSet(" 1:a", a);
808 print_LockSet(" 1:b", b);
809 }
sewardj4bffb232002-11-13 21:46:34 +0000810 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000811 return False;
sewardjc26cc252002-10-23 21:58:55 +0000812 }
813
814 /* 2: missing_mutex itself */
815 if (debug) {
816 VG_(printf)( " 2:missing: %p%(y\n",
817 missing_mutex->mutexp, missing_mutex->mutexp);
818 print_LockSet(" 2: b", b);
819 }
820
njnca82cc02004-11-22 17:18:48 +0000821 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000822
sewardj4bffb232002-11-13 21:46:34 +0000823 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000824 return False;
825
sewardj4bffb232002-11-13 21:46:34 +0000826 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000827
828 /* 3: after missing_mutex to end */
829
sewardj4bffb232002-11-13 21:46:34 +0000830 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000831 if (debug) {
832 print_LockSet(" 3:a", a);
833 print_LockSet(" 3:b", b);
834 }
sewardj4bffb232002-11-13 21:46:34 +0000835 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000836 return False;
sewardjc26cc252002-10-23 21:58:55 +0000837 }
838
839 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000840 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000841
sewardj4bffb232002-11-13 21:46:34 +0000842 return ia == a->setsize && ib == b->setsize;
843}
844
845
846
847static const LockSet *lookup_LockSet(const LockSet *set)
848{
849 UInt bucket = set->hash;
850 LockSet *ret;
851
852 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
853 if (set == ret || structural_eq_LockSet(set, ret))
854 return ret;
855
856 return NULL;
857}
858
sewardj39a4d842002-11-13 22:14:30 +0000859static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000860{
861 UInt bucket = hash_LockSet_with(set, mutex);
862 const LockSet *ret;
863
864 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
865 if (weird_LockSet_equals(set, ret, mutex))
866 return ret;
867
868 return NULL;
869}
870
sewardj39a4d842002-11-13 22:14:30 +0000871static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000872{
873 UInt bucket = hash_LockSet_without(set, mutex);
874 const LockSet *ret;
875
876 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
877 if (weird_LockSet_equals(ret, set, mutex))
878 return ret;
879
880 return NULL;
881}
882
883static void insert_LockSet(LockSet *set)
884{
885 UInt hash = hash_LockSet(set);
886
887 set->hash = hash;
888
njnca82cc02004-11-22 17:18:48 +0000889 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000890
891 set->next = lockset_hash[hash];
892 lockset_hash[hash] = set;
893}
894
895static inline
896LockSet *alloc_LockSet(UInt setsize)
897{
sewardj39a4d842002-11-13 22:14:30 +0000898 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000899 ret->setsize = setsize;
900 return ret;
901}
902
903static inline
904void free_LockSet(LockSet *p)
905{
906 /* assert: not present in hash */
907 VG_(free)(p);
908}
909
njnb4aee052003-04-15 14:09:58 +0000910static
sewardj4bffb232002-11-13 21:46:34 +0000911void pp_all_LockSets ( void )
912{
913 Int i;
914 Int sets, buckets;
915
916 sets = buckets = 0;
917 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
918 const LockSet *ls = lockset_hash[i];
919 Bool first = True;
920
sewardj4bffb232002-11-13 21:46:34 +0000921 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000922 if (first) {
923 buckets++;
924 VG_(printf)("[%4d] = ", i);
925 } else
926 VG_(printf)(" ");
927
sewardj4bffb232002-11-13 21:46:34 +0000928 sets++;
929 first = False;
930 pp_LockSet(ls);
931 }
932 }
933
934 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
935}
936
937static inline Bool isempty(const LockSet *ls)
938{
939 return ls == NULL || ls->setsize == 0;
940}
941
sewardj39a4d842002-11-13 22:14:30 +0000942static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000943{
944 Int i;
945
946 /* XXX use binary search */
947 for(i = 0; i < ls->setsize; i++)
948 if (mutex_cmp(mx, ls->mutex[i]) == 0)
949 return True;
950
951 return False;
952}
953
954/* Check invariants:
955 - all locksets are unique
956 - each set is an array in strictly increasing order of mutex addr
957*/
958static
959void sanity_check_locksets ( const Char* caller )
960{
961 Int i;
962 const Char *badness;
963 LockSet *ls;
964
965 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
966
967 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000968 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000969 Int j;
970
971 if (hash_LockSet(ls) != ls->hash) {
972 badness = "mismatched hash";
973 goto bad;
974 }
sewardj05bcdcb2003-05-18 10:05:38 +0000975 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +0000976 badness = "wrong bucket";
977 goto bad;
978 }
979 if (lookup_LockSet(ls) != ls) {
980 badness = "non-unique set";
981 goto bad;
982 }
983
984 prev = ls->mutex[0];
985 for(j = 1; j < ls->setsize; j++) {
986 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
987 badness = "mutexes out of order";
988 goto bad;
989 }
990 }
991 }
992 }
993 return;
994
995 bad:
996 VG_(printf)("sanity_check_locksets: "
997 "i = %d, ls=%p badness = %s, caller = %s\n",
998 i, ls, badness, caller);
999 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001000 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001001}
1002
1003static
sewardj39a4d842002-11-13 22:14:30 +00001004LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001005{
1006 static const Bool debug = False;
1007 LockSet *ret = NULL;
1008 Int i, j;
1009
1010 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1011 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1012 print_LockSet("add-IN", ls);
1013 }
1014
1015 if (debug || LOCKSET_SANITY)
1016 sanity_check_locksets("add-IN");
1017
njnca82cc02004-11-22 17:18:48 +00001018 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001019
1020 ret = alloc_LockSet(ls->setsize+1);
1021
1022 for(i = j = 0; i < ls->setsize; i++) {
1023 if (debug)
1024 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1025 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1026 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1027 ret->mutex[j++] = mx;
1028 mx = NULL;
1029 }
1030 ret->mutex[j++] = ls->mutex[i];
1031 }
1032
1033 /* not added in loop - must be after */
1034 if (mx)
1035 ret->mutex[j++] = mx;
1036
njnca82cc02004-11-22 17:18:48 +00001037 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001038
1039 if (debug || LOCKSET_SANITY) {
1040 print_LockSet("add-OUT", ret);
1041 sanity_check_locksets("add-OUT");
1042 }
1043 return ret;
1044}
1045
1046/* Builds ls with mx removed. mx should actually be in ls!
1047 (a checked assertion). Resulting set should not already
1048 exist in the table (unchecked).
1049*/
1050static
sewardj39a4d842002-11-13 22:14:30 +00001051LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001052{
1053 static const Bool debug = False;
1054 LockSet *ret = NULL;
1055 Int i, j;
1056
1057 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1058 print_LockSet("remove-IN", ls);
1059 }
1060
1061 if (debug || LOCKSET_SANITY)
1062 sanity_check_locksets("remove-IN");
1063
njnca82cc02004-11-22 17:18:48 +00001064 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001065
1066 ret = alloc_LockSet(ls->setsize-1);
1067
1068 for(i = j = 0; i < ls->setsize; i++) {
1069 if (mutex_cmp(ls->mutex[i], mx) == 0)
1070 continue;
1071 ret->mutex[j++] = ls->mutex[i];
1072 }
1073
njnca82cc02004-11-22 17:18:48 +00001074 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001075
1076 if (debug || LOCKSET_SANITY) {
1077 print_LockSet("remove-OUT", ret);
1078 sanity_check_locksets("remove-OUT");
1079 }
1080 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001081}
1082
1083
1084/* Builds the intersection, and then unbuilds it if it's already in the table.
1085 */
sewardj4bffb232002-11-13 21:46:34 +00001086static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001087{
sewardj4bffb232002-11-13 21:46:34 +00001088 static const Bool debug = False;
1089 Int iret;
1090 Int ia, ib;
1091 Int size;
1092 LockSet *ret;
1093 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001094
sewardj4bffb232002-11-13 21:46:34 +00001095 if (debug || LOCKSET_SANITY)
1096 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001097
sewardj4bffb232002-11-13 21:46:34 +00001098 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1099 print_LockSet("intersect a", a);
1100 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001101 }
1102
sewardj4bffb232002-11-13 21:46:34 +00001103 /* count the size of the new set */
1104 size = 0;
1105 ia = ib = 0;
1106 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1107 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1108 size++;
1109 ia++;
1110 ib++;
1111 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1112 ia++;
1113 } else {
njnca82cc02004-11-22 17:18:48 +00001114 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001115 ib++;
1116 }
njn25e49d8e72002-09-23 09:36:25 +00001117 }
1118
sewardj4bffb232002-11-13 21:46:34 +00001119 /* Build the intersection of the two sets */
1120 ret = alloc_LockSet(size);
1121 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1122 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001123 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001124 ret->mutex[iret++] = a->mutex[ia];
1125 ia++;
1126 ib++;
1127 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1128 ia++;
1129 } else {
njnca82cc02004-11-22 17:18:48 +00001130 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001131 ib++;
1132 }
1133 }
1134
1135 ret->hash = hash_LockSet(ret);
1136
njn25e49d8e72002-09-23 09:36:25 +00001137 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001138 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001139
sewardj4bffb232002-11-13 21:46:34 +00001140 if (found != NULL) {
1141 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001142 } else {
sewardj4bffb232002-11-13 21:46:34 +00001143 insert_LockSet(ret);
1144 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001145 }
1146
sewardj4bffb232002-11-13 21:46:34 +00001147 if (debug || LOCKSET_SANITY) {
1148 print_LockSet("intersect-OUT", found);
1149 sanity_check_locksets("intersect-OUT");
1150 }
njn25e49d8e72002-09-23 09:36:25 +00001151
sewardj4bffb232002-11-13 21:46:34 +00001152 return found;
njn25e49d8e72002-09-23 09:36:25 +00001153}
1154
sewardj4bffb232002-11-13 21:46:34 +00001155/* inline the fastpath */
1156static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001157{
sewardj4bffb232002-11-13 21:46:34 +00001158 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001159
1160 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001161 if (a == b) {
1162 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1163 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001164 }
sewardj4bffb232002-11-13 21:46:34 +00001165 return a;
sewardjc26cc252002-10-23 21:58:55 +00001166 }
1167
sewardj4bffb232002-11-13 21:46:34 +00001168 if (isempty(a) || isempty(b)) {
1169 if (debug)
1170 VG_(printf)("intersect empty fastpath\n");
1171 return emptyset;
1172 }
1173
1174 return _intersect(a, b);
1175}
1176
1177
1178static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1179{
1180 static const Bool debug = False;
1181 Int iret;
1182 Int ia, ib;
1183 Int size;
1184 LockSet *ret;
1185 const LockSet *found;
1186
1187 if (debug || LOCKSET_SANITY)
1188 sanity_check_locksets("union-IN");
1189
1190 /* Fast case -- when the two are the same */
1191 if (a == b) {
1192 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1193 print_LockSet("union-same fastpath", a);
1194 }
1195 return a;
1196 }
1197
1198 if (isempty(a)) {
1199 if (debug)
1200 print_LockSet("union a=empty b", b);
1201 return b;
1202 }
1203 if (isempty(b)) {
1204 if (debug)
1205 print_LockSet("union b=empty a", a);
1206 return a;
1207 }
1208
1209 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001210 print_LockSet("union a", a);
1211 print_LockSet("union b", b);
1212 }
1213
sewardj4bffb232002-11-13 21:46:34 +00001214 /* count the size of the new set */
1215 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1216 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001217
sewardj4bffb232002-11-13 21:46:34 +00001218 if ((ia < a->setsize) && (ib < b->setsize))
1219 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1220 else if (ia == a->setsize)
1221 cmp = 1;
1222 else
1223 cmp = -1;
1224
1225 if (cmp == 0) {
1226 size++;
1227 ia++;
1228 ib++;
1229 } else if (cmp < 0) {
1230 size++;
1231 ia++;
1232 } else {
njnca82cc02004-11-22 17:18:48 +00001233 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001234 size++;
1235 ib++;
1236 }
sewardjc26cc252002-10-23 21:58:55 +00001237 }
1238
sewardj4bffb232002-11-13 21:46:34 +00001239 /* Build the intersection of the two sets */
1240 ret = alloc_LockSet(size);
1241 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1242 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001243 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001244
1245 if ((ia < a->setsize) && (ib < b->setsize))
1246 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1247 else if (ia == a->setsize)
1248 cmp = 1;
1249 else
1250 cmp = -1;
1251
1252 if (cmp == 0) {
1253 ret->mutex[iret++] = a->mutex[ia];
1254 ia++;
1255 ib++;
1256 } else if (cmp < 0) {
1257 ret->mutex[iret++] = a->mutex[ia];
1258 ia++;
1259 } else {
njnca82cc02004-11-22 17:18:48 +00001260 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001261 ret->mutex[iret++] = b->mutex[ib];
1262 ib++;
1263 }
1264 }
1265
njnca82cc02004-11-22 17:18:48 +00001266 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001267
1268 ret->hash = hash_LockSet(ret);
1269
sewardjc26cc252002-10-23 21:58:55 +00001270 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001271 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001272
sewardj4bffb232002-11-13 21:46:34 +00001273 if (found != NULL) {
1274 if (debug)
1275 print_LockSet("union found existing set", found);
1276 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001277 } else {
sewardj4bffb232002-11-13 21:46:34 +00001278 if (debug)
1279 print_LockSet("union inserting new set", ret);
1280 insert_LockSet(ret);
1281 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001282 }
1283
sewardj4bffb232002-11-13 21:46:34 +00001284 if (debug || LOCKSET_SANITY) {
1285 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001286 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001287 }
sewardjc26cc252002-10-23 21:58:55 +00001288
sewardj4bffb232002-11-13 21:46:34 +00001289 return found;
sewardjc26cc252002-10-23 21:58:55 +00001290}
1291
1292/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001293/*--- Implementation of mutex structure. ---*/
1294/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001295
1296static UInt graph_mark; /* current mark we're using for graph traversal */
1297
sewardj39a4d842002-11-13 22:14:30 +00001298static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001299 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001300static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001301 const LockSet *lockset_holding,
1302 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001303
njn72718642003-07-24 08:45:32 +00001304static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001305
1306#define M_MUTEX_HASHSZ 1021
1307
sewardj39a4d842002-11-13 22:14:30 +00001308static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001309static UInt total_mutexes;
1310
1311static const Char *pp_MutexState(MutexState st)
1312{
1313 switch(st) {
1314 case MxLocked: return "Locked";
1315 case MxUnlocked: return "Unlocked";
1316 case MxDead: return "Dead";
1317 case MxUnknown: return "Unknown";
1318 }
1319 return "???";
1320}
1321
1322static void pp_all_mutexes()
1323{
1324 Int i;
1325 Int locks, buckets;
1326
1327 locks = buckets = 0;
1328 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001329 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001330 Bool first = True;
1331
1332 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1333 if (first) {
1334 buckets++;
1335 VG_(printf)("[%4d] = ", i);
1336 } else
1337 VG_(printf)(" ");
1338 locks++;
1339 first = False;
1340 VG_(printf)("%p [%8s] -> %p%(y\n",
1341 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1342 }
1343 }
1344
1345 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1346 locks, buckets, total_mutexes);
1347}
sewardjc26cc252002-10-23 21:58:55 +00001348
sewardj39a4d842002-11-13 22:14:30 +00001349/* find or create a Mutex for a program's mutex use */
1350static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001351{
nethercote50397c22004-11-04 18:03:06 +00001352 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001353 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001354
1355 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1356 if (mp->mutexp == mutexp)
1357 return mp;
1358
sewardjdac0a442002-11-13 22:08:40 +00001359 total_mutexes++;
1360
sewardjc26cc252002-10-23 21:58:55 +00001361 mp = VG_(malloc)(sizeof(*mp));
1362 mp->mutexp = mutexp;
1363 mp->next = mutex_hash[bucket];
1364 mutex_hash[bucket] = mp;
1365
1366 mp->state = MxUnknown;
1367 mp->tid = VG_INVALID_THREADID;
1368 mp->location = NULL;
1369
sewardj4bffb232002-11-13 21:46:34 +00001370 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001371 mp->mark = graph_mark - 1;
1372
1373 return mp;
1374}
1375
sewardjdac0a442002-11-13 22:08:40 +00001376/* Find all mutexes in a range of memory, and call the callback.
1377 Remove the mutex from the hash if the callback returns True (mutex
1378 structure itself is not freed, because it may be pointed to by a
1379 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001380static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001381{
sewardjdac0a442002-11-13 22:08:40 +00001382 UInt first = start % M_MUTEX_HASHSZ;
1383 UInt last = (end+1) % M_MUTEX_HASHSZ;
1384 UInt i;
1385
1386 /* Single pass over the hash table, looking for likely hashes */
1387 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001388 Mutex *mx;
1389 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001390
1391 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1392 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1393 *prev = mx->next;
1394 }
1395
1396 if (++i == M_MUTEX_HASHSZ)
1397 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001398 }
sewardjc26cc252002-10-23 21:58:55 +00001399}
1400
1401#define MARK_LOOP (graph_mark+0)
1402#define MARK_DONE (graph_mark+1)
1403
thughes4ad52d02004-06-27 17:37:21 +00001404static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1405{
1406 static const Bool debug = False;
1407 Int i;
1408
1409 if (mutex->mark == MARK_LOOP)
1410 return True; /* found cycle */
1411 if (mutex->mark == MARK_DONE)
1412 return False; /* been here before, its OK */
1413
1414 ((Mutex*)mutex)->mark = MARK_LOOP;
1415
1416 if (debug)
1417 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1418 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1419 for(i = 0; i < ls->setsize; i++) {
1420 const Mutex *mx = ls->mutex[i];
1421
1422 if (debug)
1423 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1424 mutex->mutexp, ls,
1425 mx->mutexp, mx->mutexp);
1426 if (check_cycle_inner(mx, mx->lockdep))
1427 return True;
1428 }
1429 ((Mutex*)mutex)->mark = MARK_DONE;
1430
1431 return False;
1432}
1433
sewardj39a4d842002-11-13 22:14:30 +00001434static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001435{
sewardjff2c9232002-11-13 21:44:39 +00001436
sewardjc26cc252002-10-23 21:58:55 +00001437 graph_mark += 2; /* clear all marks */
1438
sewardj4bffb232002-11-13 21:46:34 +00001439 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001440}
1441
sewardjdca84112002-11-13 22:29:34 +00001442/* test to see if a mutex state change would be problematic; this
1443 makes no changes to the mutex state. This should be called before
1444 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001445static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001446{
1447 static const Bool debug = False;
1448
sewardjc26cc252002-10-23 21:58:55 +00001449 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001450 Char *str;
1451
1452 switch(state) {
1453 case MxLocked: str = "lock dead mutex"; break;
1454 case MxUnlocked: str = "unlock dead mutex"; break;
1455 default: str = "operate on dead mutex"; break;
1456 }
1457
sewardjc26cc252002-10-23 21:58:55 +00001458 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001459 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001460 return;
1461 }
1462
1463 switch(state) {
1464 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001465 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001466
1467 if (debug)
1468 print_LockSet("thread holding", thread_locks[tid]);
1469
1470 if (check_cycle(mutex, thread_locks[tid]))
1471 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1472 else {
1473 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1474
1475 if (debug) {
1476 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1477 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1478 print_LockSet("lockdep", mutex->lockdep);
1479 }
1480 }
1481 break;
1482
1483 case MxUnlocked:
1484 if (debug)
1485 print_LockSet("thread holding", thread_locks[tid]);
1486
1487 if (mutex->state != MxLocked) {
1488 record_mutex_error(tid, mutex,
1489 "unlock non-locked mutex", mutex->location);
1490 }
1491 if (mutex->tid != tid) {
1492 record_mutex_error(tid, mutex,
1493 "unlock someone else's mutex", mutex->location);
1494 }
1495 break;
1496
1497 case MxDead:
1498 break;
1499
1500 default:
1501 break;
1502 }
1503}
1504
1505/* Update a mutex state. Expects most error testing and reporting to
1506 have happened in test_mutex_state(). The assumption is that no
1507 client code is run by thread tid between test and set, either
1508 because it is blocked or test and set are called together
1509 atomically.
1510
1511 Setting state to MxDead is the exception, since that can happen as
1512 a result of any thread freeing memory; in this case set_mutex_state
1513 does all the error reporting as well.
1514*/
njn72718642003-07-24 08:45:32 +00001515static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001516{
1517 static const Bool debug = False;
1518
1519 if (debug)
1520 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1521 tid, mutex, mutex->mutexp, mutex->mutexp,
1522 pp_MutexState(mutex->state), pp_MutexState(state));
1523
1524 if (mutex->state == MxDead) {
1525 /* can't do anything legal to a destroyed mutex */
1526 return;
1527 }
1528
1529 switch(state) {
1530 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001531 if (mutex->state == MxLocked) {
1532 if (mutex->tid != tid)
1533 record_mutex_error(tid, mutex, "take lock held by someone else",
1534 mutex->location);
1535 else
1536 record_mutex_error(tid, mutex, "take lock we already hold",
1537 mutex->location);
1538
njn67993252004-11-22 18:02:32 +00001539 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001540 break;
1541 }
sewardjc26cc252002-10-23 21:58:55 +00001542
njnca82cc02004-11-22 17:18:48 +00001543 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001544
sewardjc26cc252002-10-23 21:58:55 +00001545 mutex->tid = tid;
1546 break;
1547
1548 case MxUnlocked:
1549 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001550 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001551
sewardjdca84112002-11-13 22:29:34 +00001552 if (mutex->state != MxLocked || mutex->tid != tid)
1553 break;
1554
sewardjc26cc252002-10-23 21:58:55 +00001555 mutex->tid = VG_INVALID_THREADID;
1556 break;
1557
sewardjdac0a442002-11-13 22:08:40 +00001558 case MxDead:
1559 if (mutex->state == MxLocked) {
1560 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001561 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001562 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1563 mutex->tid = VG_INVALID_THREADID;
1564
1565 record_mutex_error(tid, mutex,
1566 "free locked mutex", mutex->location);
1567 }
1568 break;
1569
sewardjc26cc252002-10-23 21:58:55 +00001570 default:
1571 break;
1572 }
1573
njnd01fef72005-03-25 23:35:48 +00001574 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001575 mutex->state = state;
1576}
njn25e49d8e72002-09-23 09:36:25 +00001577
1578/*------------------------------------------------------------*/
1579/*--- Setting and checking permissions. ---*/
1580/*------------------------------------------------------------*/
1581
thughes4ad52d02004-06-27 17:37:21 +00001582/* only clean up dead mutexes */
1583static
1584Bool cleanmx(Mutex *mx) {
1585 return mx->state == MxDead;
1586}
1587
njn25e49d8e72002-09-23 09:36:25 +00001588static
nethercote451eae92004-11-02 13:06:32 +00001589void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001590 VgeInitStatus status )
1591{
sewardj1806d7f2002-10-22 05:05:49 +00001592 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001593
1594# if DEBUG_MAKE_ACCESSES
1595 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1596# endif
1597 //PROF_EVENT(30); PPP
1598
1599 if (len == 0)
1600 return;
1601
1602 if (len > 100 * 1000 * 1000)
1603 VG_(message)(Vg_UserMsg,
1604 "Warning: set address range state: large range %d",
1605 len);
1606
1607 VGP_PUSHCC(VgpSARP);
1608
sewardjdac0a442002-11-13 22:08:40 +00001609 /* Remove mutexes in recycled memory range from hash */
1610 find_mutex_range(a, a+len, cleanmx);
1611
njn25e49d8e72002-09-23 09:36:25 +00001612 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1613 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1614 * len/4+1 words. This works out which it is by aligning the block and
1615 * seeing if the end byte is in the same word as it is for the unaligned
1616 * block; if not, it's the awkward case. */
sewardj8fac99a2002-11-13 22:31:26 +00001617 end = ROUNDUP(a + len, 4);
1618 a = ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001619
1620 /* Do it ... */
1621 switch (status) {
1622 case Vge_VirginInit:
1623 for ( ; a < end; a += 4) {
1624 //PROF_EVENT(31); PPP
1625 init_virgin_sword(a);
1626 }
1627 break;
1628
1629 case Vge_NonVirginInit:
1630 for ( ; a < end; a += 4) {
1631 //PROF_EVENT(31); PPP
1632 init_nonvirgin_sword(a);
1633 }
1634 break;
1635
1636 case Vge_SegmentInit:
1637 for ( ; a < end; a += 4) {
1638 //PROF_EVENT(31); PPP
1639 init_magically_inited_sword(a);
1640 }
1641 break;
sewardj7f3ad222002-11-13 22:11:53 +00001642
1643 case Vge_Error:
1644 for ( ; a < end; a += 4) {
1645 //PROF_EVENT(31); PPP
1646 init_error_sword(a);
1647 }
1648 break;
njn25e49d8e72002-09-23 09:36:25 +00001649
1650 default:
1651 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001652 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001653 }
1654
1655 /* Check that zero page and highest page have not been written to
1656 -- this could happen with buggy syscall wrappers. Today
1657 (2001-04-26) had precisely such a problem with
1658 __NR_setitimer. */
njn26f02512004-11-22 18:33:15 +00001659 tl_assert(TL_(cheap_sanity_check)());
njn25e49d8e72002-09-23 09:36:25 +00001660 VGP_POPCC(VgpSARP);
1661}
1662
1663
nethercote451eae92004-11-02 13:06:32 +00001664static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001665{
1666 //PROF_EVENT(??); PPP
1667 set_address_range_state ( a, len, Vge_SegmentInit );
1668}
1669
nethercote451eae92004-11-02 13:06:32 +00001670static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001671{
1672 //PROF_EVENT(36); PPP
1673 set_address_range_state( a, len, Vge_VirginInit );
1674}
1675
nethercote451eae92004-11-02 13:06:32 +00001676static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001677{
1678 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001679 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001680}
1681
1682
njn25e49d8e72002-09-23 09:36:25 +00001683/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001684static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001685{
1686 UInt i;
1687
1688 //PROF_EVENT(40); PPP
1689 for (i = 0; i < len; i += 4) {
1690 shadow_word sword = *(get_sword_addr ( src+i ));
1691 //PROF_EVENT(41); PPP
1692 set_sword ( dst+i, sword );
1693 }
1694}
1695
1696// SSS: put these somewhere better
nethercote451eae92004-11-02 13:06:32 +00001697static void eraser_mem_read (Addr a, SizeT data_size, ThreadId tid);
1698static void eraser_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001699
njn9fb73db2005-03-27 01:55:21 +00001700static void eraser_mem_help_read_1(Addr a) VGA_REGPARM(1);
1701static void eraser_mem_help_read_2(Addr a) VGA_REGPARM(1);
1702static void eraser_mem_help_read_4(Addr a) VGA_REGPARM(1);
1703static void eraser_mem_help_read_N(Addr a, SizeT size) VGA_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001704
njn9fb73db2005-03-27 01:55:21 +00001705static void eraser_mem_help_write_1(Addr a, UInt val) VGA_REGPARM(2);
1706static void eraser_mem_help_write_2(Addr a, UInt val) VGA_REGPARM(2);
1707static void eraser_mem_help_write_4(Addr a, UInt val) VGA_REGPARM(2);
1708static void eraser_mem_help_write_N(Addr a, SizeT size) VGA_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001709
sewardj7a5ebcf2002-11-13 22:42:13 +00001710static void bus_lock(void);
1711static void bus_unlock(void);
1712
njn25e49d8e72002-09-23 09:36:25 +00001713static
njn72718642003-07-24 08:45:32 +00001714void eraser_pre_mem_read(CorePart part, ThreadId tid,
nethercote451eae92004-11-02 13:06:32 +00001715 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001716{
njn67993252004-11-22 18:02:32 +00001717 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 +00001718 eraser_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001719}
1720
1721static
njn72718642003-07-24 08:45:32 +00001722void eraser_pre_mem_read_asciiz(CorePart part, ThreadId tid,
nethercote6a27d832004-09-07 10:17:02 +00001723 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001724{
njn72718642003-07-24 08:45:32 +00001725 eraser_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001726}
1727
1728static
njn72718642003-07-24 08:45:32 +00001729void eraser_pre_mem_write(CorePart part, ThreadId tid,
nethercote451eae92004-11-02 13:06:32 +00001730 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001731{
njn72718642003-07-24 08:45:32 +00001732 eraser_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001733}
1734
1735
1736
1737static
nethercote451eae92004-11-02 13:06:32 +00001738void eraser_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001739{
njn1f3a9092002-10-04 09:22:30 +00001740 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001741 make_segment_readable(a, len);
1742}
1743
1744
1745static
nethercote451eae92004-11-02 13:06:32 +00001746void eraser_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001747{
1748 if (is_inited) {
1749 make_readable(a, len);
1750 } else {
1751 make_writable(a, len);
1752 }
1753}
1754
1755static
nethercote451eae92004-11-02 13:06:32 +00001756void eraser_set_perms (Addr a, SizeT len,
sewardj40f8ebe2002-10-23 21:46:13 +00001757 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001758{
1759 if (rr) make_readable(a, len);
1760 else if (ww) make_writable(a, len);
1761 /* else do nothing */
1762}
1763
sewardjf6374322002-11-13 22:35:55 +00001764static
nethercote451eae92004-11-02 13:06:32 +00001765void eraser_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001766{
1767 set_address_range_state(a, len, Vge_NonVirginInit);
1768}
1769
1770static
nethercote451eae92004-11-02 13:06:32 +00001771void eraser_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001772{
1773 set_address_range_state(a, len, Vge_VirginInit);
1774}
njn25e49d8e72002-09-23 09:36:25 +00001775
1776/*--------------------------------------------------------------*/
1777/*--- Initialise the memory audit system on program startup. ---*/
1778/*--------------------------------------------------------------*/
1779
1780static
1781void init_shadow_memory(void)
1782{
1783 Int i;
1784
1785 for (i = 0; i < ESEC_MAP_WORDS; i++)
1786 distinguished_secondary_map.swords[i] = virgin_sword;
1787
1788 /* These entries gradually get overwritten as the used address
1789 space expands. */
1790 for (i = 0; i < 65536; i++)
1791 primary_map[i] = &distinguished_secondary_map;
1792}
1793
1794
njn3e884182003-04-15 13:03:23 +00001795/*------------------------------------------------------------*/
1796/*--- malloc() et al replacements ---*/
1797/*------------------------------------------------------------*/
1798
njnb4aee052003-04-15 14:09:58 +00001799static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001800
1801#define N_FREED_CHUNKS 2
1802static Int freechunkptr = 0;
1803static HG_Chunk *freechunks[N_FREED_CHUNKS];
1804
njn3e884182003-04-15 13:03:23 +00001805
1806/* Allocate a user-chunk of size bytes. Also allocate its shadow
1807 block, make the shadow block point at the user block. Put the
1808 shadow chunk on the appropriate list, and set all memory
1809 protections correctly. */
1810
nethercote7ac7f7b2004-11-02 12:36:02 +00001811static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001812{
1813 HG_Chunk* hc;
1814
1815 hc = VG_(malloc)(sizeof(HG_Chunk));
1816 hc->data = p;
1817 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001818 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001819 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001820
1821 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1822}
1823
1824/* Allocate memory and note change in memory available */
1825static __inline__
njn14d01ce2004-11-26 11:30:14 +00001826void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1827 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001828{
1829 Addr p;
1830
njn34ac0272003-09-30 14:20:00 +00001831 if (size < 0) return NULL;
1832
njn3e884182003-04-15 13:03:23 +00001833 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001834 if (!p) {
1835 return NULL;
1836 }
njn34ac0272003-09-30 14:20:00 +00001837 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001838 add_HG_Chunk ( tid, p, size );
njn3e884182003-04-15 13:03:23 +00001839 eraser_new_mem_heap( p, size, is_zeroed );
1840
1841 return (void*)p;
1842}
1843
njn14d01ce2004-11-26 11:30:14 +00001844void* TL_(malloc) ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001845{
njn14d01ce2004-11-26 11:30:14 +00001846 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001847}
1848
njn14d01ce2004-11-26 11:30:14 +00001849void* TL_(__builtin_new) ( 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_vec_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_(memalign) ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001860{
njn14d01ce2004-11-26 11:30:14 +00001861 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001862}
1863
njn14d01ce2004-11-26 11:30:14 +00001864void* TL_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001865{
njn14d01ce2004-11-26 11:30:14 +00001866 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001867 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001868}
1869
thughes4ad52d02004-06-27 17:37:21 +00001870static ThreadId deadmx_tid;
1871
1872static
1873Bool deadmx(Mutex *mx) {
1874 if (mx->state != MxDead)
1875 set_mutex_state(mx, MxDead, deadmx_tid);
1876
1877 return False;
1878}
1879
njn3e884182003-04-15 13:03:23 +00001880static
njn72718642003-07-24 08:45:32 +00001881void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001882 HG_Chunk** prev_chunks_next_ptr )
1883{
njn72718642003-07-24 08:45:32 +00001884 Addr start = hc->data;
1885 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001886
njn3e884182003-04-15 13:03:23 +00001887 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1888 avoid repeating the hash table lookup. Can't remove until at least
1889 after free and free_mismatch errors are done because they use
1890 describe_addr() which looks for it in malloclist. */
1891 *prev_chunks_next_ptr = hc->next;
1892
1893 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001894 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001895
1896 /* maintain a small window so that the error reporting machinery
1897 knows about this memory */
1898 if (freechunks[freechunkptr] != NULL) {
1899 /* free HG_Chunk */
1900 HG_Chunk* sc1 = freechunks[freechunkptr];
1901 VG_(cli_free) ( (void*)(sc1->data) );
1902 VG_(free) ( sc1 );
1903 }
1904
1905 freechunks[freechunkptr] = hc;
1906
1907 if (++freechunkptr == N_FREED_CHUNKS)
1908 freechunkptr = 0;
1909
1910 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001911 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001912 find_mutex_range(start, end, deadmx);
1913}
1914
1915
1916static __inline__
njn14d01ce2004-11-26 11:30:14 +00001917void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001918{
1919 HG_Chunk* hc;
1920 HG_Chunk** prev_chunks_next_ptr;
1921
nethercote3d6b6112004-11-04 16:39:43 +00001922 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001923 (VgHashNode***)&prev_chunks_next_ptr );
1924 if (hc == NULL) {
1925 return;
1926 }
njn14d01ce2004-11-26 11:30:14 +00001927 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001928}
1929
njn14d01ce2004-11-26 11:30:14 +00001930void TL_(free) ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001931{
njn14d01ce2004-11-26 11:30:14 +00001932 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001933}
1934
njn14d01ce2004-11-26 11:30:14 +00001935void TL_(__builtin_delete) ( 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_vec_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_(realloc) ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001946{
1947 HG_Chunk *hc;
1948 HG_Chunk **prev_chunks_next_ptr;
sewardj05bcdcb2003-05-18 10:05:38 +00001949 Int i;
njn3e884182003-04-15 13:03:23 +00001950
1951 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001952 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001953 (VgHashNode***)&prev_chunks_next_ptr );
1954
1955 if (hc == NULL) {
1956 return NULL;
1957 }
1958
1959 if (hc->size == new_size) {
1960 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001961 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001962 return p;
1963
1964 } else if (hc->size > new_size) {
1965 /* new size is smaller */
1966 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001967 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001968 return p;
1969
1970 } else {
1971 /* new size is bigger */
1972 Addr p_new;
1973
1974 /* Get new memory */
1975 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
1976
1977 /* First half kept and copied, second half new */
1978 copy_address_range_state( (Addr)p, p_new, hc->size );
1979 eraser_new_mem_heap ( p_new+hc->size, new_size-hc->size,
1980 /*inited*/False );
1981
1982 /* Copy from old to new */
1983 for (i = 0; i < hc->size; i++)
1984 ((UChar*)p_new)[i] = ((UChar*)p)[i];
1985
1986 /* Free old memory */
njn72718642003-07-24 08:45:32 +00001987 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001988
1989 /* this has to be after die_and_free_mem, otherwise the
1990 former succeeds in shorting out the new block, not the
1991 old, in the case when both are on the same list. */
njn72718642003-07-24 08:45:32 +00001992 add_HG_Chunk ( tid, p_new, new_size );
njn3e884182003-04-15 13:03:23 +00001993
1994 return (void*)p_new;
1995 }
1996}
1997
njn25e49d8e72002-09-23 09:36:25 +00001998/*--------------------------------------------------------------*/
1999/*--- Machinery to support sanity checking ---*/
2000/*--------------------------------------------------------------*/
2001
njn26f02512004-11-22 18:33:15 +00002002Bool TL_(cheap_sanity_check) ( void )
njn25e49d8e72002-09-23 09:36:25 +00002003{
jseward9800fd32004-01-04 23:08:04 +00002004 /* nothing useful we can rapidly check */
2005 return True;
njn25e49d8e72002-09-23 09:36:25 +00002006}
2007
njn26f02512004-11-22 18:33:15 +00002008Bool TL_(expensive_sanity_check)(void)
njn25e49d8e72002-09-23 09:36:25 +00002009{
2010 Int i;
2011
2012 /* Make sure nobody changed the distinguished secondary. */
2013 for (i = 0; i < ESEC_MAP_WORDS; i++)
2014 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2015 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2016 return False;
2017
2018 return True;
2019}
2020
2021
2022/*--------------------------------------------------------------*/
2023/*--- Instrumentation ---*/
2024/*--------------------------------------------------------------*/
2025
sewardjf6374322002-11-13 22:35:55 +00002026static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2027
njn14d01ce2004-11-26 11:30:14 +00002028#if 0
njn25e49d8e72002-09-23 09:36:25 +00002029/* Create and return an instrumented version of cb_in. Free cb_in
2030 before returning. */
njn26f02512004-11-22 18:33:15 +00002031UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002032{
2033 UCodeBlock* cb;
2034 Int i;
2035 UInstr* u_in;
2036 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002037 Int ntemps;
2038 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002039 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002040
njn810086f2002-11-14 12:42:47 +00002041 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002042
sewardjf6374322002-11-13 22:35:55 +00002043 /* stackref[] is used for super-simple value tracking to keep note
2044 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002045 the stack pointer or frame pointer, and is therefore likely
2046 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002047 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002048 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2049 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2050
njn810086f2002-11-14 12:42:47 +00002051 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2052 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002053
njn25e49d8e72002-09-23 09:36:25 +00002054 switch (u_in->opcode) {
2055
2056 case NOP: case CALLM_S: case CALLM_E:
2057 break;
sewardjf6374322002-11-13 22:35:55 +00002058
sewardj7a5ebcf2002-11-13 22:42:13 +00002059 case LOCK:
2060 locked = True;
2061 uInstr0(cb, CCALL, 0);
2062 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2063 break;
2064
2065 case JMP: case INCEIP:
2066 if (locked) {
2067 uInstr0(cb, CCALL, 0);
2068 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2069 }
2070 locked = False;
2071 VG_(copy_UInstr)(cb, u_in);
2072 break;
2073
sewardjf6374322002-11-13 22:35:55 +00002074 case GET:
njnca82cc02004-11-22 17:18:48 +00002075 tl_assert(u_in->tag1 == ArchReg);
2076 tl_assert(u_in->tag2 == TempReg);
2077 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002078
2079 stackref[u_in->val2] = (u_in->size == 4 &&
njndb9b7732005-03-26 00:32:29 +00002080 (u_in->val1 == VGA_R_STACK_PTR ||
2081 u_in->val1 == VGA_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002082 VG_(copy_UInstr)(cb, u_in);
2083 break;
2084
2085 case MOV:
2086 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002087 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002088 stackref[u_in->val2] = stackref[u_in->val1];
2089 }
2090 VG_(copy_UInstr)(cb, u_in);
2091 break;
2092
2093 case LEA1:
2094 case ADD: case SUB:
2095 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002096 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002097 stackref[u_in->val2] |= stackref[u_in->val1];
2098 }
2099 VG_(copy_UInstr)(cb, u_in);
2100 break;
njn25e49d8e72002-09-23 09:36:25 +00002101
sewardja5b3aec2002-10-22 05:09:36 +00002102 case LOAD: {
2103 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002104 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2105 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002106
2107 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2108 nonstk_ld++;
2109
2110 switch(u_in->size) {
2111 case 1: help = eraser_mem_help_read_1; break;
2112 case 2: help = eraser_mem_help_read_2; break;
2113 case 4: help = eraser_mem_help_read_4; break;
2114 default:
njn67993252004-11-22 18:02:32 +00002115 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002116 }
jsgfcb1d1c02003-10-14 21:55:10 +00002117
2118 /* XXX all registers should be flushed to baseblock
2119 here */
sewardjf6374322002-11-13 22:35:55 +00002120 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2121 uCCall(cb, (Addr)help, 1, 1, False);
2122 } else
2123 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002124
sewardja5b3aec2002-10-22 05:09:36 +00002125 VG_(copy_UInstr)(cb, u_in);
2126 t_size = INVALID_TEMPREG;
2127 break;
2128 }
2129
fitzhardinge111c6072004-03-09 02:45:07 +00002130 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002131 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002132 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002133 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002134
fitzhardinge111c6072004-03-09 02:45:07 +00002135 t_size = newTemp(cb);
2136 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2137 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002138
fitzhardinge111c6072004-03-09 02:45:07 +00002139 /* XXX all registers should be flushed to baseblock
2140 here */
2141 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
2142 uCCall(cb, (Addr) & eraser_mem_help_read_N, 2, 2, False);
2143
2144 VG_(copy_UInstr)(cb, u_in);
2145 t_size = INVALID_TEMPREG;
2146 break;
sewardja5b3aec2002-10-22 05:09:36 +00002147 }
2148
thughes96b466a2004-03-15 16:43:58 +00002149 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002150 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002151
2152 t_size = newTemp(cb);
2153 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2154 uLiteral(cb, (UInt)u_in->size);
2155
2156 /* XXX all registers should be flushed to baseblock
2157 here */
2158 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
2159 uCCall(cb, (Addr) & eraser_mem_help_read_N, 2, 2, False);
2160
2161 VG_(copy_UInstr)(cb, u_in);
2162 t_size = INVALID_TEMPREG;
2163 break;
2164 }
2165
fitzhardinge111c6072004-03-09 02:45:07 +00002166 case SSE2a_MemRd:
2167 case SSE2a1_MemRd:
2168 case SSE3a_MemRd:
2169 case SSE3a1_MemRd:
2170 case SSE3ag_MemRd_RegWr: {
2171 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2172
njnca82cc02004-11-22 17:18:48 +00002173 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002174
2175 t_size = newTemp(cb);
2176 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2177 uLiteral(cb, (UInt)u_in->size);
2178
2179 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
2180 uCCall(cb, (Addr) & eraser_mem_help_read_N, 2, 2, False);
2181
2182 VG_(copy_UInstr)(cb, u_in);
2183 t_size = INVALID_TEMPREG;
2184 break;
2185 }
2186
sewardja5b3aec2002-10-22 05:09:36 +00002187 case STORE: {
2188 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002189 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2190 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002191
sewardjf6374322002-11-13 22:35:55 +00002192 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2193 nonstk_st++;
2194
2195 switch(u_in->size) {
2196 case 1: help = eraser_mem_help_write_1; break;
2197 case 2: help = eraser_mem_help_write_2; break;
2198 case 4: help = eraser_mem_help_write_4; break;
2199 default:
njn67993252004-11-22 18:02:32 +00002200 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002201 }
2202
jsgfcb1d1c02003-10-14 21:55:10 +00002203 /* XXX all registers should be flushed to baseblock
2204 here */
sewardjf6374322002-11-13 22:35:55 +00002205 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2206 uCCall(cb, (Addr)help, 2, 2, False);
2207 } else
2208 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002209
2210 VG_(copy_UInstr)(cb, u_in);
2211 t_size = INVALID_TEMPREG;
2212 break;
2213 }
2214
fitzhardinge111c6072004-03-09 02:45:07 +00002215 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002216 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002217 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002218 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002219
2220 t_size = newTemp(cb);
2221 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2222 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002223 /* XXX all registers should be flushed to baseblock
2224 here */
sewardja5b3aec2002-10-22 05:09:36 +00002225 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
2226 uCCall(cb, (Addr) & eraser_mem_help_write_N, 2, 2, False);
2227
2228 VG_(copy_UInstr)(cb, u_in);
2229 t_size = INVALID_TEMPREG;
2230 break;
2231 }
njn25e49d8e72002-09-23 09:36:25 +00002232
fitzhardinge111c6072004-03-09 02:45:07 +00002233 case SSE2a_MemWr:
2234 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002235 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002236 512 == u_in->size);
2237
2238 t_size = newTemp(cb);
2239 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2240 uLiteral(cb, (UInt)u_in->size);
2241 /* XXX all registers should be flushed to baseblock
2242 here */
2243 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
2244 uCCall(cb, (Addr) & eraser_mem_help_write_N, 2, 2, False);
2245
2246 VG_(copy_UInstr)(cb, u_in);
2247 t_size = INVALID_TEMPREG;
2248 break;
2249 }
sewardj3d7c9c82003-03-26 21:08:13 +00002250
njn25e49d8e72002-09-23 09:36:25 +00002251 default:
sewardjf6374322002-11-13 22:35:55 +00002252 /* conservative tromping */
2253 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2254 stackref[u_in->val1] = False;
2255 if (u_in->tag2 == TempReg)
2256 stackref[u_in->val2] = False;
2257 if (u_in->tag3 == TempReg)
2258 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002259 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002260 break;
2261 }
2262 }
2263
sewardjf6374322002-11-13 22:35:55 +00002264 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002265 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002266 return cb;
2267}
njn14d01ce2004-11-26 11:30:14 +00002268#endif
njn95e65f62005-03-30 04:13:56 +00002269IRBB* TL_(instrument) ( IRBB* bb_in, VexGuestLayout* layout,
2270 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002271{
2272 VG_(message)(Vg_DebugMsg, "Helgrind is not yet ready to handle Vex IR");
2273 VG_(exit)(1);
2274}
njn25e49d8e72002-09-23 09:36:25 +00002275
2276/*--------------------------------------------------------------------*/
2277/*--- Error and suppression handling ---*/
2278/*--------------------------------------------------------------------*/
2279
2280typedef
2281 enum {
2282 /* Possible data race */
2283 EraserSupp
2284 }
2285 EraserSuppKind;
2286
2287/* What kind of error it is. */
2288typedef
2289 enum {
sewardj16748af2002-10-22 04:55:54 +00002290 EraserErr, /* data-race */
2291 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002292 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002293 }
2294 EraserErrorKind;
2295
sewardj16748af2002-10-22 04:55:54 +00002296/* The classification of a faulting address. */
2297typedef
2298 enum { Undescribed, /* as-yet unclassified */
2299 Stack,
2300 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002301 Mallocd,
2302 Freed,
sewardj16748af2002-10-22 04:55:54 +00002303 Segment
2304 }
2305 AddrKind;
2306/* Records info about a faulting address. */
2307typedef
2308 struct {
2309 /* ALL */
2310 AddrKind akind;
2311 /* Freed, Mallocd */
2312 Int blksize;
2313 /* Freed, Mallocd */
2314 Int rwoffset;
2315 /* Freed, Mallocd */
2316 ExeContext* lastchange;
2317 ThreadId lasttid;
2318 /* Stack */
2319 ThreadId stack_tid;
2320 /* Segment */
2321 const Char* filename;
2322 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002323 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002324 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002325 /* symbolic address description */
2326 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002327 }
2328 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002329
sewardj16748af2002-10-22 04:55:54 +00002330/* What kind of memory access is involved in the error? */
2331typedef
2332 enum { ReadAxs, WriteAxs, ExecAxs }
2333 AxsKind;
2334
2335/* Extra context for memory errors */
2336typedef
2337 struct {
2338 AxsKind axskind;
2339 Int size;
2340 AddrInfo addrinfo;
2341 Bool isWrite;
2342 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002343 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002344 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002345 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002346 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002347 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002348 const LockSet *held_lockset;
2349 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002350 }
2351 HelgrindError;
2352
2353static __inline__
2354void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002355{
sewardj16748af2002-10-22 04:55:54 +00002356 ai->akind = Unknown;
2357 ai->blksize = 0;
2358 ai->rwoffset = 0;
2359 ai->lastchange = NULL;
2360 ai->lasttid = VG_INVALID_THREADID;
2361 ai->filename = NULL;
2362 ai->section = "???";
2363 ai->stack_tid = VG_INVALID_THREADID;
2364 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002365 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002366}
2367
sewardj16748af2002-10-22 04:55:54 +00002368static __inline__
2369void clear_HelgrindError ( HelgrindError* err_extra )
2370{
2371 err_extra->axskind = ReadAxs;
2372 err_extra->size = 0;
2373 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002374 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002375 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002376 err_extra->prev_lockset = 0;
2377 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002378 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002379 clear_AddrInfo ( &err_extra->addrinfo );
2380 err_extra->isWrite = False;
2381}
2382
2383
2384
2385/* Describe an address as best you can, for error messages,
2386 putting the result in ai. */
2387
thughes4ad52d02004-06-27 17:37:21 +00002388/* Callback for searching malloc'd and free'd lists */
2389static Bool addr_is_in_block(VgHashNode *node, void *ap)
2390{
2391 HG_Chunk* hc2 = (HG_Chunk*)node;
2392 Addr a = *(Addr *)ap;
2393
2394 return (hc2->data <= a && a < hc2->data + hc2->size);
2395}
2396
sewardj16748af2002-10-22 04:55:54 +00002397static void describe_addr ( Addr a, AddrInfo* ai )
2398{
njn3e884182003-04-15 13:03:23 +00002399 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002400 Int i;
sewardj16748af2002-10-22 04:55:54 +00002401
sewardj16748af2002-10-22 04:55:54 +00002402 /* Search for it in segments */
2403 {
2404 const SegInfo *seg;
2405
2406 for(seg = VG_(next_seginfo)(NULL);
2407 seg != NULL;
2408 seg = VG_(next_seginfo)(seg)) {
2409 Addr base = VG_(seg_start)(seg);
nethercote928a5f72004-11-03 18:10:37 +00002410 SizeT size = VG_(seg_size)(seg);
sewardj16748af2002-10-22 04:55:54 +00002411 const UChar *filename = VG_(seg_filename)(seg);
2412
2413 if (a >= base && a < base+size) {
2414 ai->akind = Segment;
2415 ai->blksize = size;
2416 ai->rwoffset = a - base;
2417 ai->filename = filename;
2418
2419 switch(VG_(seg_sect_kind)(a)) {
2420 case Vg_SectText: ai->section = "text"; break;
2421 case Vg_SectData: ai->section = "data"; break;
2422 case Vg_SectBSS: ai->section = "BSS"; break;
2423 case Vg_SectGOT: ai->section = "GOT"; break;
2424 case Vg_SectPLT: ai->section = "PLT"; break;
2425 case Vg_SectUnknown:
2426 default:
2427 ai->section = "???"; break;
2428 }
2429
2430 return;
2431 }
2432 }
2433 }
2434
2435 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002436 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002437 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002438 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002439 ai->blksize = hc->size;
2440 ai->rwoffset = (Int)a - (Int)(hc->data);
2441 ai->lastchange = hc->where;
2442 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002443 return;
2444 }
sewardjdac0a442002-11-13 22:08:40 +00002445
2446 /* Look in recently freed memory */
2447 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002448 hc = freechunks[i];
2449 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002450 continue;
2451
njn3e884182003-04-15 13:03:23 +00002452 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002453 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002454 ai->blksize = hc->size;
2455 ai->rwoffset = a - hc->data;
2456 ai->lastchange = hc->where;
2457 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002458 return;
2459 }
2460 }
2461
sewardj16748af2002-10-22 04:55:54 +00002462 /* Clueless ... */
2463 ai->akind = Unknown;
2464 return;
2465}
2466
2467
njn7e614812003-04-21 22:04:03 +00002468/* Updates the copy with address info if necessary. */
njn26f02512004-11-22 18:33:15 +00002469UInt TL_(update_extra)(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002470{
njn7e614812003-04-21 22:04:03 +00002471 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002472
njn7e614812003-04-21 22:04:03 +00002473 extra = (HelgrindError*)VG_(get_error_extra)(err);
2474 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2475 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2476 }
2477 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002478}
2479
njn72718642003-07-24 08:45:32 +00002480static void record_eraser_error ( ThreadId tid, Addr a, Bool is_write,
sewardj0f811692002-10-22 04:59:26 +00002481 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002482{
sewardjc4a810d2002-11-13 22:25:51 +00002483 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002484 HelgrindError err_extra;
2485
sewardjff2c9232002-11-13 21:44:39 +00002486 n_eraser_warnings++;
2487
sewardj16748af2002-10-22 04:55:54 +00002488 clear_HelgrindError(&err_extra);
2489 err_extra.isWrite = is_write;
2490 err_extra.addrinfo.akind = Undescribed;
2491 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002492 if (clo_execontext)
2493 err_extra.lasttouched = getExeContext(a);
jsgfcb1d1c02003-10-14 21:55:10 +00002494 err_extra.addrinfo.expr = VG_(describe_addr)(tid, a);
2495
njn72718642003-07-24 08:45:32 +00002496 VG_(maybe_record_error)( tid, EraserErr, a,
sewardj16748af2002-10-22 04:55:54 +00002497 (is_write ? "writing" : "reading"),
2498 &err_extra);
2499
sewardjc4a810d2002-11-13 22:25:51 +00002500 sw = get_sword_addr(a);
2501 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2502 ThreadLifeSeg *tls = unpackTLS(sw->other);
2503 tls->refcount--;
2504 }
2505
sewardj7f3ad222002-11-13 22:11:53 +00002506 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002507}
2508
sewardj39a4d842002-11-13 22:14:30 +00002509static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002510 Char *str, ExeContext *ec)
2511{
2512 HelgrindError err_extra;
2513
2514 clear_HelgrindError(&err_extra);
2515 err_extra.addrinfo.akind = Undescribed;
2516 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002517 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002518 err_extra.lasttid = tid;
2519
njn72718642003-07-24 08:45:32 +00002520 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002521 (Addr)mutex->mutexp, str, &err_extra);
2522}
njn25e49d8e72002-09-23 09:36:25 +00002523
sewardj39a4d842002-11-13 22:14:30 +00002524static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002525 const LockSet *lockset_holding,
2526 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002527{
2528 HelgrindError err_extra;
2529
2530 n_lockorder_warnings++;
2531
2532 clear_HelgrindError(&err_extra);
2533 err_extra.addrinfo.akind = Undescribed;
2534 err_extra.mutex = mutex;
2535
sewardjc808ef52002-11-13 22:43:26 +00002536 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002537 err_extra.held_lockset = lockset_holding;
2538 err_extra.prev_lockset = lockset_prev;
2539
njn72718642003-07-24 08:45:32 +00002540 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002541}
2542
njn26f02512004-11-22 18:33:15 +00002543Bool TL_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002544{
njn810086f2002-11-14 12:42:47 +00002545 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002546
njnca82cc02004-11-22 17:18:48 +00002547 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002548
2549 switch (VG_(get_error_kind)(e1)) {
sewardj16748af2002-10-22 04:55:54 +00002550 case EraserErr:
njn810086f2002-11-14 12:42:47 +00002551 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002552
2553 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002554 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002555 }
2556
njn810086f2002-11-14 12:42:47 +00002557 e1s = VG_(get_error_string)(e1);
2558 e2s = VG_(get_error_string)(e2);
2559 if (e1s != e2s) return False;
2560 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002561 return True;
2562}
2563
sewardj16748af2002-10-22 04:55:54 +00002564static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002565{
jsgfcb1d1c02003-10-14 21:55:10 +00002566 if (ai->expr != NULL)
2567 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002568 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002569
sewardj16748af2002-10-22 04:55:54 +00002570 switch (ai->akind) {
2571 case Stack:
2572 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002573 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002574 a, ai->stack_tid);
2575 break;
2576 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002577 if (ai->expr != NULL)
2578 break;
2579
nethercote3b390c72003-11-13 17:53:43 +00002580 /* maybe_gcc is never set to True! This is a hangover from code
2581 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002582 if (ai->maybe_gcc) {
2583 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002584 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002585 a);
2586 VG_(message)(Vg_UserMsg,
2587 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2588 } else {
2589 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002590 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002591 }
2592 break;
2593 case Segment:
2594 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002595 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002596 a, ai->section, ai->filename);
2597 break;
sewardjdac0a442002-11-13 22:08:40 +00002598 case Mallocd:
2599 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002600 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002601 UChar* relative;
2602 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002603 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002604 relative = "before";
2605 } else if (ai->rwoffset >= ai->blksize) {
2606 delta = ai->rwoffset - ai->blksize;
2607 relative = "after";
2608 } else {
2609 delta = ai->rwoffset;
2610 relative = "inside";
2611 }
2612 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002613 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2614 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002615 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002616 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002617 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002618
sewardj16748af2002-10-22 04:55:54 +00002619 VG_(pp_ExeContext)(ai->lastchange);
2620 break;
2621 }
2622 default:
njn67993252004-11-22 18:02:32 +00002623 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002624 }
njn25e49d8e72002-09-23 09:36:25 +00002625}
2626
sewardj4bffb232002-11-13 21:46:34 +00002627static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002628{
sewardjff2c9232002-11-13 21:44:39 +00002629 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002630 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002631
sewardj4bffb232002-11-13 21:46:34 +00002632 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2633 lockset->setsize * 120 +
2634 1);
sewardjff2c9232002-11-13 21:44:39 +00002635
2636 cp = buf;
2637 if (prefix)
2638 cp += VG_(sprintf)(cp, "%s", prefix);
2639
sewardj4bffb232002-11-13 21:46:34 +00002640 for(i = 0; i < lockset->setsize; i++)
2641 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2642 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002643
sewardj4bffb232002-11-13 21:46:34 +00002644 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002645 cp[-2] = '\0';
2646 else
2647 *cp = '\0';
2648
2649 return buf;
2650}
njn25e49d8e72002-09-23 09:36:25 +00002651
njn26f02512004-11-22 18:33:15 +00002652void TL_(pp_Error) ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002653{
njn810086f2002-11-14 12:42:47 +00002654 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002655 Char buf[100];
2656 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002657 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002658
2659 *msg = '\0';
2660
njn810086f2002-11-14 12:42:47 +00002661 switch(VG_(get_error_kind)(err)) {
2662 case EraserErr: {
2663 Addr err_addr = VG_(get_error_address)(err);
2664
sewardj16748af2002-10-22 04:55:54 +00002665 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002666 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002667 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002668 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002669
2670 switch(extra->prevstate.state) {
2671 case Vge_Virgin:
2672 /* shouldn't be possible to go directly from virgin -> error */
2673 VG_(sprintf)(buf, "virgin!?");
2674 break;
2675
sewardjc4a810d2002-11-13 22:25:51 +00002676 case Vge_Excl: {
2677 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2678
njnca82cc02004-11-22 17:18:48 +00002679 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002680 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002681 break;
sewardjc4a810d2002-11-13 22:25:51 +00002682 }
sewardj16748af2002-10-22 04:55:54 +00002683
2684 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002685 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002686 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002687
2688 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002689 VG_(sprintf)(buf, "shared %s, no locks",
2690 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2691 break;
2692 }
2693
sewardjff2c9232002-11-13 21:44:39 +00002694 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2695 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002696 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002697
sewardj16748af2002-10-22 04:55:54 +00002698 break;
2699 }
sewardj16748af2002-10-22 04:55:54 +00002700
sewardj499e3de2002-11-13 22:22:25 +00002701 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002702 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002703
sewardj72baa7a2002-12-09 23:32:58 +00002704 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002705 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002706 Char file[100];
2707 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002708 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002709
nethercote3b390c72003-11-13 17:53:43 +00002710 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002711 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002712 pp_state(extra->lasttouched.state),
2713 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002714
nethercoteca788ff2004-10-20 10:58:09 +00002715 if (VG_(get_filename_linenum)(ip, file, sizeof(file), &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002716 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002717 ip, ip, file, line);
2718 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002719 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002720 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002721 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002722 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002723 }
sewardj72baa7a2002-12-09 23:32:58 +00002724 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002725 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002726 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002727 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002728 pp_state(extra->lasttouched.state),
2729 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002730 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002731 }
sewardj16748af2002-10-22 04:55:54 +00002732 break;
njn810086f2002-11-14 12:42:47 +00002733 }
sewardj16748af2002-10-22 04:55:54 +00002734
2735 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002736 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002737 VG_(get_error_address)(err),
2738 VG_(get_error_address)(err),
2739 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002740 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002741 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002742 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002743 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002744 }
njn810086f2002-11-14 12:42:47 +00002745 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002746 break;
sewardjff2c9232002-11-13 21:44:39 +00002747
2748 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002749 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002750 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002751 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002752
2753 msg = lockset_str(NULL, heldset);
2754
2755 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002756 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002757 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002758 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2759
sewardj4bffb232002-11-13 21:46:34 +00002760 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002761 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002762
sewardj542494b2002-11-13 22:46:13 +00002763 /* needs to be a recursive search+display */
2764 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002765 continue;
2766
nethercote3b390c72003-11-13 17:53:43 +00002767 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002768 lsmx->mutexp, lsmx->mutexp);
2769 VG_(pp_ExeContext)(lsmx->location);
2770 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002771 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002772 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002773 }
2774
2775 break;
sewardj16748af2002-10-22 04:55:54 +00002776 }
sewardjff2c9232002-11-13 21:44:39 +00002777 }
2778
2779 if (msg != buf)
2780 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002781}
2782
2783
njn26f02512004-11-22 18:33:15 +00002784Bool TL_(recognised_suppression) ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002785{
2786 if (0 == VG_(strcmp)(name, "Eraser")) {
njn810086f2002-11-14 12:42:47 +00002787 VG_(set_supp_kind)(su, EraserSupp);
njn25e49d8e72002-09-23 09:36:25 +00002788 return True;
2789 } else {
2790 return False;
2791 }
2792}
2793
2794
njn26f02512004-11-22 18:33:15 +00002795Bool TL_(read_extra_suppression_info) ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002796{
2797 /* do nothing -- no extra suppression info present. Return True to
2798 indicate nothing bad happened. */
2799 return True;
2800}
2801
2802
njn26f02512004-11-22 18:33:15 +00002803Bool TL_(error_matches_suppression)(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002804{
njnca82cc02004-11-22 17:18:48 +00002805 tl_assert(VG_(get_supp_kind)(su) == EraserSupp);
nethercote64366b42003-12-01 13:11:47 +00002806
2807 return (VG_(get_error_kind)(err) == EraserErr);
njn25e49d8e72002-09-23 09:36:25 +00002808}
2809
njn26f02512004-11-22 18:33:15 +00002810extern Char* TL_(get_error_name) ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002811{
2812 if (EraserErr == VG_(get_error_kind)(err)) {
2813 return "Eraser";
2814 } else {
2815 return NULL; /* Other errors types can't be suppressed */
2816 }
2817}
2818
njn26f02512004-11-22 18:33:15 +00002819extern void TL_(print_extra_suppression_info) ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002820{
2821 /* Do nothing */
2822}
njn25e49d8e72002-09-23 09:36:25 +00002823
sewardjdca84112002-11-13 22:29:34 +00002824static void eraser_pre_mutex_lock(ThreadId tid, void* void_mutex)
2825{
2826 Mutex *mutex = get_mutex((Addr)void_mutex);
2827
njn72718642003-07-24 08:45:32 +00002828 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002829}
2830
njn25e49d8e72002-09-23 09:36:25 +00002831static void eraser_post_mutex_lock(ThreadId tid, void* void_mutex)
2832{
sewardj4bffb232002-11-13 21:46:34 +00002833 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002834 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002835 const LockSet* ls;
2836
njn72718642003-07-24 08:45:32 +00002837 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002838
njn25e49d8e72002-09-23 09:36:25 +00002839# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002840 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002841# endif
2842
njn25e49d8e72002-09-23 09:36:25 +00002843 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2844# if LOCKSET_SANITY > 1
2845 sanity_check_locksets("eraser_post_mutex_lock-IN");
2846# endif
2847
sewardj4bffb232002-11-13 21:46:34 +00002848 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002849
sewardj4bffb232002-11-13 21:46:34 +00002850 if (ls == NULL) {
2851 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2852 insert_LockSet(newset);
2853 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002854 }
sewardj4bffb232002-11-13 21:46:34 +00002855 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002856
sewardj4bffb232002-11-13 21:46:34 +00002857 if (debug || DEBUG_LOCKS)
2858 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002859
sewardj4bffb232002-11-13 21:46:34 +00002860 if (debug || LOCKSET_SANITY > 1)
2861 sanity_check_locksets("eraser_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002862}
2863
2864
2865static void eraser_post_mutex_unlock(ThreadId tid, void* void_mutex)
2866{
sewardjc26cc252002-10-23 21:58:55 +00002867 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002868 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002869 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002870 const LockSet *ls;
2871
njn72718642003-07-24 08:45:32 +00002872 test_mutex_state(mutex, MxUnlocked, tid);
2873 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002874
sewardjdac0a442002-11-13 22:08:40 +00002875 if (!ismember(thread_locks[tid], mutex))
2876 return;
2877
sewardjc26cc252002-10-23 21:58:55 +00002878 if (debug || DEBUG_LOCKS)
2879 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002880
sewardjc26cc252002-10-23 21:58:55 +00002881 if (debug || LOCKSET_SANITY > 1)
2882 sanity_check_locksets("eraser_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002883
sewardj4bffb232002-11-13 21:46:34 +00002884 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002885
sewardj4bffb232002-11-13 21:46:34 +00002886 if (ls == NULL) {
2887 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2888 insert_LockSet(newset);
2889 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002890 }
2891
2892 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002893 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002894 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002895 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002896
sewardj4bffb232002-11-13 21:46:34 +00002897 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002898
sewardjc26cc252002-10-23 21:58:55 +00002899 if (debug || LOCKSET_SANITY > 1)
2900 sanity_check_locksets("eraser_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002901}
2902
2903
2904/* ---------------------------------------------------------------------
2905 Checking memory reads and writes
2906 ------------------------------------------------------------------ */
2907
2908/* Behaviour on reads and writes:
2909 *
2910 * VIR EXCL SHAR SH_MOD
2911 * ----------------------------------------------------------------
2912 * rd/wr, 1st thread | - EXCL - -
2913 * rd, new thread | - SHAR - -
2914 * wr, new thread | - SH_MOD - -
2915 * rd | error! - SHAR SH_MOD
2916 * wr | EXCL - SH_MOD SH_MOD
2917 * ----------------------------------------------------------------
2918 */
2919
sewardj8fac99a2002-11-13 22:31:26 +00002920static inline
njn25e49d8e72002-09-23 09:36:25 +00002921void dump_around_a(Addr a)
2922{
2923 UInt i;
2924 shadow_word* sword;
2925 VG_(printf)("NEARBY:\n");
2926 for (i = a - 12; i <= a + 12; i += 4) {
2927 sword = get_sword_addr(i);
2928 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2929 }
2930}
njn25e49d8e72002-09-23 09:36:25 +00002931
2932#if DEBUG_ACCESSES
2933 #define DEBUG_STATE(args...) \
2934 VG_(printf)("(%u) ", size), \
2935 VG_(printf)(args)
2936#else
2937 #define DEBUG_STATE(args...)
2938#endif
2939
njn72718642003-07-24 08:45:32 +00002940static void eraser_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002941{
sewardj72baa7a2002-12-09 23:32:58 +00002942 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002943 shadow_word prevstate;
2944 ThreadLifeSeg *tls;
2945 const LockSet *ls;
2946 Bool statechange = False;
2947
2948 static const void *const states[4] = {
2949 [Vge_Virgin] &&st_virgin,
2950 [Vge_Excl] &&st_excl,
2951 [Vge_Shar] &&st_shar,
2952 [Vge_SharMod] &&st_sharmod,
2953 };
2954
2955 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002956 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002957
2958 sword = get_sword_addr(a);
2959 if (sword == SEC_MAP_ACCESS) {
2960 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2961 return;
2962 }
2963
2964 prevstate = *sword;
2965
2966 goto *states[sword->state];
2967
2968 /* This looks like reading of unitialised memory, may be legit. Eg.
2969 * calloc() zeroes its values, so untouched memory may actually be
2970 * initialised. Leave that stuff to Valgrind. */
2971 st_virgin:
2972 if (TID_INDICATING_NONVIRGIN == sword->other) {
2973 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
2974 if (DEBUG_VIRGIN_READS)
2975 dump_around_a(a);
2976 } else {
2977 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
2978 }
2979 statechange = True;
2980 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
2981 tls->refcount++;
2982 goto done;
2983
2984 st_excl: {
2985 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
2986
2987 if (tls == sw_tls) {
2988 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
2989 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
2990 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
2991 } else if (tlsIsDisjoint(tls, sw_tls)) {
2992 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
2993 statechange = True;
2994 sword->other = packTLS(tls);
2995 sw_tls->refcount--;
2996 tls->refcount++;
2997 } else {
2998 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
2999 sw_tls->refcount--;
3000 statechange = True;
3001 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3002
3003 if (DEBUG_MEM_LOCKSET_CHANGES)
3004 print_LockSet("excl read locks", unpackLockSet(sword->other));
3005 }
3006 goto done;
3007 }
3008
3009 st_shar:
3010 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3011 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3012 thread_locks[tid]));
3013 statechange = sword->other != prevstate.other;
3014 goto done;
3015
3016 st_sharmod:
3017 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3018 ls = intersect(unpackLockSet(sword->other),
3019 thread_locks[tid]);
3020 sword->other = packLockSet(ls);
3021
3022 statechange = sword->other != prevstate.other;
3023
3024 if (isempty(ls)) {
njn72718642003-07-24 08:45:32 +00003025 record_eraser_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003026 }
3027 goto done;
3028
3029 done:
3030 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003031 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003032
3033 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003034 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003035 else
njnd01fef72005-03-25 23:35:48 +00003036 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003037 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003038 }
3039}
njn25e49d8e72002-09-23 09:36:25 +00003040
nethercote451eae92004-11-02 13:06:32 +00003041static void eraser_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003042{
njn72718642003-07-24 08:45:32 +00003043 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003044
sewardj8fac99a2002-11-13 22:31:26 +00003045 end = ROUNDUP(a+size, 4);
3046 a = ROUNDDN(a, 4);
3047
sewardj18cd4a52002-11-13 22:37:41 +00003048 for ( ; a < end; a += 4)
njn72718642003-07-24 08:45:32 +00003049 eraser_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003050}
3051
njn72718642003-07-24 08:45:32 +00003052static void eraser_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003053{
3054 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003055 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003056 shadow_word prevstate;
3057 Bool statechange = False;
3058 static const void *const states[4] = {
3059 [Vge_Virgin] &&st_virgin,
3060 [Vge_Excl] &&st_excl,
3061 [Vge_Shar] &&st_shar,
3062 [Vge_SharMod] &&st_sharmod,
3063 };
3064
sewardjc4a810d2002-11-13 22:25:51 +00003065 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003066 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003067
sewardj18cd4a52002-11-13 22:37:41 +00003068 sword = get_sword_addr(a);
3069 if (sword == SEC_MAP_ACCESS) {
3070 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3071 return;
3072 }
njn25e49d8e72002-09-23 09:36:25 +00003073
sewardj18cd4a52002-11-13 22:37:41 +00003074 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003075
sewardj18cd4a52002-11-13 22:37:41 +00003076 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003077
sewardj18cd4a52002-11-13 22:37:41 +00003078 st_virgin:
3079 if (TID_INDICATING_NONVIRGIN == sword->other)
3080 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3081 else
3082 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3083 statechange = True;
3084 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3085 tls->refcount++;
3086 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003087
sewardj18cd4a52002-11-13 22:37:41 +00003088 st_excl: {
3089 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3090
3091 if (tls == sw_tls) {
3092 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3093 goto done;
3094 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3095 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3096 goto done;
3097 } else if (tlsIsDisjoint(tls, sw_tls)) {
3098 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3099 sword->other = packTLS(tls);
3100 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003101 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003102 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003103 } else {
3104 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3105 statechange = True;
3106 sw_tls->refcount--;
3107 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3108 if(DEBUG_MEM_LOCKSET_CHANGES)
3109 print_LockSet("excl write locks", unpackLockSet(sword->other));
3110 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003111 }
sewardj18cd4a52002-11-13 22:37:41 +00003112 }
njn25e49d8e72002-09-23 09:36:25 +00003113
sewardj18cd4a52002-11-13 22:37:41 +00003114 st_shar:
3115 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3116 sword->state = Vge_SharMod;
3117 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3118 thread_locks[tid]));
3119 statechange = True;
3120 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003121
sewardj18cd4a52002-11-13 22:37:41 +00003122 st_sharmod:
3123 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3124 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3125 thread_locks[tid]));
3126 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003127
sewardj18cd4a52002-11-13 22:37:41 +00003128 SHARED_MODIFIED:
3129 if (isempty(unpackLockSet(sword->other))) {
njn72718642003-07-24 08:45:32 +00003130 record_eraser_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003131 }
3132 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003133
sewardj18cd4a52002-11-13 22:37:41 +00003134 done:
3135 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003136 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003137
sewardj18cd4a52002-11-13 22:37:41 +00003138 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003139 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003140 else
njnd01fef72005-03-25 23:35:48 +00003141 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003142 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003143 }
3144}
3145
nethercote451eae92004-11-02 13:06:32 +00003146static void eraser_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003147{
sewardj8fac99a2002-11-13 22:31:26 +00003148 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003149
sewardj8fac99a2002-11-13 22:31:26 +00003150 end = ROUNDUP(a+size, 4);
3151 a = ROUNDDN(a, 4);
3152
sewardj18cd4a52002-11-13 22:37:41 +00003153 for ( ; a < end; a += 4)
njn72718642003-07-24 08:45:32 +00003154 eraser_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003155}
3156
3157#undef DEBUG_STATE
3158
njn9fb73db2005-03-27 01:55:21 +00003159VGA_REGPARM(1) static void eraser_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003160{
njn95e65f62005-03-30 04:13:56 +00003161 eraser_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003162}
3163
njn9fb73db2005-03-27 01:55:21 +00003164VGA_REGPARM(1) static void eraser_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003165{
njn95e65f62005-03-30 04:13:56 +00003166 eraser_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003167}
3168
njn9fb73db2005-03-27 01:55:21 +00003169VGA_REGPARM(1) static void eraser_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003170{
njn95e65f62005-03-30 04:13:56 +00003171 eraser_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003172}
3173
njn9fb73db2005-03-27 01:55:21 +00003174VGA_REGPARM(2) static void eraser_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003175{
njn95e65f62005-03-30 04:13:56 +00003176 eraser_mem_read(a, size, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003177}
3178
njn9fb73db2005-03-27 01:55:21 +00003179VGA_REGPARM(2) static void eraser_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003180{
3181 if (*(UChar *)a != val)
njn95e65f62005-03-30 04:13:56 +00003182 eraser_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003183}
njn9fb73db2005-03-27 01:55:21 +00003184VGA_REGPARM(2) static void eraser_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003185{
3186 if (*(UShort *)a != val)
njn95e65f62005-03-30 04:13:56 +00003187 eraser_mem_write(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003188}
njn9fb73db2005-03-27 01:55:21 +00003189VGA_REGPARM(2) static void eraser_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003190{
3191 if (*(UInt *)a != val)
njn95e65f62005-03-30 04:13:56 +00003192 eraser_mem_write(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003193}
njn9fb73db2005-03-27 01:55:21 +00003194VGA_REGPARM(2) static void eraser_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003195{
njn95e65f62005-03-30 04:13:56 +00003196 eraser_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003197}
njn25e49d8e72002-09-23 09:36:25 +00003198
sewardjc4a810d2002-11-13 22:25:51 +00003199static void hg_thread_create(ThreadId parent, ThreadId child)
3200{
3201 if (0)
3202 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3203
3204 newTLS(child);
3205 addPriorTLS(child, parent);
3206
3207 newTLS(parent);
3208}
3209
3210static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3211{
3212 if (0)
3213 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3214
3215 newTLS(joiner);
3216 addPriorTLS(joiner, joinee);
3217
3218 clearTLS(joinee);
3219}
3220
sewardj7a5ebcf2002-11-13 22:42:13 +00003221static Int __BUS_HARDWARE_LOCK__;
3222
3223static void bus_lock(void)
3224{
njn95e65f62005-03-30 04:13:56 +00003225 ThreadId tid = VG_(get_running_tid)();
sewardj7a5ebcf2002-11-13 22:42:13 +00003226 eraser_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3227 eraser_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3228}
3229
3230static void bus_unlock(void)
3231{
njn95e65f62005-03-30 04:13:56 +00003232 ThreadId tid = VG_(get_running_tid)();
sewardj7a5ebcf2002-11-13 22:42:13 +00003233 eraser_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
3234}
3235
njn25e49d8e72002-09-23 09:36:25 +00003236/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003237/*--- Client requests ---*/
3238/*--------------------------------------------------------------------*/
3239
njn26f02512004-11-22 18:33:15 +00003240Bool TL_(handle_client_request)(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003241{
njnfc26ff92004-11-22 19:12:49 +00003242 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003243 return False;
3244
3245 switch(args[0]) {
3246 case VG_USERREQ__HG_CLEAN_MEMORY:
3247 set_address_range_state(args[1], args[2], Vge_VirginInit);
3248 *ret = 0; /* meaningless */
3249 break;
3250
3251 case VG_USERREQ__HG_KNOWN_RACE:
3252 set_address_range_state(args[1], args[2], Vge_Error);
3253 *ret = 0; /* meaningless */
3254 break;
3255
3256 default:
3257 return False;
3258 }
3259
3260 return True;
3261}
3262
3263
3264/*--------------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00003265/*--- Setup ---*/
3266/*--------------------------------------------------------------------*/
3267
njn26f02512004-11-22 18:33:15 +00003268void TL_(pre_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +00003269{
3270 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003271 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003272
njn810086f2002-11-14 12:42:47 +00003273 VG_(details_name) ("Helgrind");
3274 VG_(details_version) (NULL);
3275 VG_(details_description) ("a data race detector");
3276 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +00003277 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003278 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003279 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003280
tomc756a8e2005-03-31 07:59:35 +00003281 VG_(basic_tool_funcs) (TL_(post_clo_init),
3282 TL_(instrument),
3283 TL_(fini));
3284
3285 VG_(needs_core_errors) ();
3286 VG_(needs_tool_errors) (TL_(eq_Error),
3287 TL_(pp_Error),
3288 TL_(update_extra),
3289 TL_(recognised_suppression),
3290 TL_(read_extra_suppression_info),
3291 TL_(error_matches_suppression),
3292 TL_(get_error_name),
3293 TL_(print_extra_suppression_info));
3294 VG_(needs_data_syms) ();
3295 VG_(needs_client_requests) (TL_(handle_client_request));
3296 VG_(needs_command_line_options)(TL_(process_cmd_line_option),
3297 TL_(print_usage),
3298 TL_(print_debug_usage));
3299 VG_(needs_shadow_memory) ();
3300
3301 VG_(malloc_funcs) (TL_(malloc),
3302 TL_(__builtin_new),
3303 TL_(__builtin_vec_new),
3304 TL_(memalign),
3305 TL_(calloc),
3306 TL_(free),
3307 TL_(__builtin_delete),
3308 TL_(__builtin_vec_delete),
3309 TL_(realloc),
3310 8 );
njn25e49d8e72002-09-23 09:36:25 +00003311
fitzhardinge98abfc72003-12-16 02:05:15 +00003312 VG_(init_new_mem_startup) (& eraser_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003313
njn810086f2002-11-14 12:42:47 +00003314 /* stack ones not decided until VG_(post_clo_init)() */
njn25e49d8e72002-09-23 09:36:25 +00003315
fitzhardinge98abfc72003-12-16 02:05:15 +00003316 VG_(init_new_mem_brk) (& make_writable);
3317 VG_(init_new_mem_mmap) (& eraser_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003318
fitzhardinge98abfc72003-12-16 02:05:15 +00003319 VG_(init_change_mem_mprotect) (& eraser_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003320
fitzhardinge98abfc72003-12-16 02:05:15 +00003321 VG_(init_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003322
fitzhardinge98abfc72003-12-16 02:05:15 +00003323 VG_(init_die_mem_stack) (NULL);
3324 VG_(init_die_mem_stack_signal) (NULL);
3325 VG_(init_die_mem_brk) (NULL);
3326 VG_(init_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003327
fitzhardinge98abfc72003-12-16 02:05:15 +00003328 VG_(init_pre_mem_read) (& eraser_pre_mem_read);
3329 VG_(init_pre_mem_read_asciiz) (& eraser_pre_mem_read_asciiz);
3330 VG_(init_pre_mem_write) (& eraser_pre_mem_write);
3331 VG_(init_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003332
fitzhardinge98abfc72003-12-16 02:05:15 +00003333 VG_(init_post_thread_create) (& hg_thread_create);
3334 VG_(init_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003335
fitzhardinge98abfc72003-12-16 02:05:15 +00003336 VG_(init_pre_mutex_lock) (& eraser_pre_mutex_lock);
3337 VG_(init_post_mutex_lock) (& eraser_post_mutex_lock);
3338 VG_(init_post_mutex_unlock) (& eraser_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003339
njn14d01ce2004-11-26 11:30:14 +00003340 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003341 lockset_hash[i] = NULL;
3342
3343 empty = alloc_LockSet(0);
3344 insert_LockSet(empty);
3345 emptyset = empty;
3346
sewardjc4a810d2002-11-13 22:25:51 +00003347 /* Init lock table and thread segments */
3348 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003349 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003350
sewardjc4a810d2002-11-13 22:25:51 +00003351 newTLS(i);
3352 }
3353
njn25e49d8e72002-09-23 09:36:25 +00003354 init_shadow_memory();
njn3e884182003-04-15 13:03:23 +00003355 hg_malloc_list = VG_(HT_construct)();
njn25e49d8e72002-09-23 09:36:25 +00003356}
3357
njn26f02512004-11-22 18:33:15 +00003358Bool TL_(process_cmd_line_option)(Char* arg)
sewardj406270b2002-11-13 22:18:09 +00003359{
nethercote27fec902004-06-16 21:26:32 +00003360 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3361 clo_execontext = EC_None;
3362 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3363 clo_execontext = EC_Some;
3364 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3365 clo_execontext = EC_All;
sewardj499e3de2002-11-13 22:22:25 +00003366
njn95e65f62005-03-30 04:13:56 +00003367 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
sewardj499e3de2002-11-13 22:22:25 +00003368
nethercote27fec902004-06-16 21:26:32 +00003369 else
3370 return VG_(replacement_malloc_process_cmd_line_option)(arg);
sewardj499e3de2002-11-13 22:22:25 +00003371
nethercote27fec902004-06-16 21:26:32 +00003372 return True;
sewardj406270b2002-11-13 22:18:09 +00003373}
3374
njn26f02512004-11-22 18:33:15 +00003375void TL_(print_usage)(void)
sewardj406270b2002-11-13 22:18:09 +00003376{
njn3e884182003-04-15 13:03:23 +00003377 VG_(printf)(
sewardje11d6c82002-12-15 02:00:41 +00003378" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3379" --show-last-access=no|some|all\n"
3380" show location of last word access on error [no]\n"
njn3e884182003-04-15 13:03:23 +00003381 );
3382 VG_(replacement_malloc_print_usage)();
sewardj406270b2002-11-13 22:18:09 +00003383}
3384
njn26f02512004-11-22 18:33:15 +00003385void TL_(print_debug_usage)(void)
njn3e884182003-04-15 13:03:23 +00003386{
3387 VG_(replacement_malloc_print_debug_usage)();
3388}
njn25e49d8e72002-09-23 09:36:25 +00003389
njn26f02512004-11-22 18:33:15 +00003390void TL_(post_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +00003391{
nethercote451eae92004-11-02 13:06:32 +00003392 void (*stack_tracker)(Addr a, SizeT len);
njn810086f2002-11-14 12:42:47 +00003393
sewardj499e3de2002-11-13 22:22:25 +00003394 if (clo_execontext) {
3395 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3396 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3397 }
sewardjf6374322002-11-13 22:35:55 +00003398
njn810086f2002-11-14 12:42:47 +00003399 if (clo_priv_stacks)
3400 stack_tracker = & eraser_new_mem_stack_private;
3401 else
3402 stack_tracker = & eraser_new_mem_stack;
sewardjf6374322002-11-13 22:35:55 +00003403
fitzhardinge98abfc72003-12-16 02:05:15 +00003404 VG_(init_new_mem_stack) (stack_tracker);
3405 VG_(init_new_mem_stack_signal) (stack_tracker);
njn25e49d8e72002-09-23 09:36:25 +00003406}
3407
3408
njn26f02512004-11-22 18:33:15 +00003409void TL_(fini)(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +00003410{
sewardjdac0a442002-11-13 22:08:40 +00003411 if (DEBUG_LOCK_TABLE) {
sewardj4bffb232002-11-13 21:46:34 +00003412 pp_all_LockSets();
sewardjdac0a442002-11-13 22:08:40 +00003413 pp_all_mutexes();
3414 }
sewardj4bffb232002-11-13 21:46:34 +00003415
3416 if (LOCKSET_SANITY)
njn26f02512004-11-22 18:33:15 +00003417 sanity_check_locksets("TL_(fini)");
sewardj4bffb232002-11-13 21:46:34 +00003418
fitzhardinge111c6072004-03-09 02:45:07 +00003419 if (VG_(clo_verbosity) > 0)
3420 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
3421 n_eraser_warnings, n_lockorder_warnings);
sewardjf6374322002-11-13 22:35:55 +00003422
3423 if (0)
3424 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3425 stk_ld, stk_st, stk_ld + stk_st,
3426 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3427 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
njn25e49d8e72002-09-23 09:36:25 +00003428}
3429
fitzhardinge98abfc72003-12-16 02:05:15 +00003430/* Uses a 1:1 mapping */
njn26f02512004-11-22 18:33:15 +00003431VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 1.0)
fitzhardinge98abfc72003-12-16 02:05:15 +00003432
njn25e49d8e72002-09-23 09:36:25 +00003433/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003434/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003435/*--------------------------------------------------------------------*/