blob: 897b2adc683ea178751993805179e0953371baf0 [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
sewardje4b0bf02006-06-05 23:21:15 +000011 Copyright (C) 2002-2006 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn25e49d8e72002-09-23 09:36:25 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
njnb1489202006-04-23 10:51:48 +000032// *** WARNING ***
33// Helgrind is not 64-bit clean.
34
njn8cdd1852005-08-30 19:47:32 +000035// For anyone wanting to understand race conditions better, this paper might
36// be instructive:
37//
38// S. Carr, J. Mayo and C.-K. Shene. Race Conditions: A Case Study, The
39// Journal of Computing in Small Colleges 17(1), September 2001.
40// http://www.cs.mtu.edu/~carr/papers/jcsc02.pdf
41//
42// It nicely describes several example race conditions, emphasising the
43// fundamentals in each case.
44
njnc7561b92005-06-19 01:24:32 +000045#include "pub_tool_basics.h"
46#include "pub_tool_threadstate.h"
njn4802b382005-06-11 04:58:29 +000047#include "pub_tool_aspacemgr.h"
njnea27e462005-05-31 02:38:09 +000048#include "pub_tool_debuginfo.h"
njn81c00df2005-05-14 21:28:43 +000049#include "pub_tool_hashtable.h"
njn97405b22005-06-02 03:39:33 +000050#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000051#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000052#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000053#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000054#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000055#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000056#include "pub_tool_options.h"
njn717cde52005-05-10 02:47:21 +000057#include "pub_tool_replacemalloc.h"
njn43b9a8a2005-05-10 04:37:01 +000058#include "pub_tool_tooliface.h"
njn717cde52005-05-10 02:47:21 +000059
sewardj7f3ad222002-11-13 22:11:53 +000060#include "helgrind.h"
njn25e49d8e72002-09-23 09:36:25 +000061
njnfbdcba92005-05-09 01:23:49 +000062static UInt n_hg_warnings = 0;
sewardjff2c9232002-11-13 21:44:39 +000063static UInt n_lockorder_warnings = 0;
njn25e49d8e72002-09-23 09:36:25 +000064
65/*------------------------------------------------------------*/
66/*--- Debug guff ---*/
67/*------------------------------------------------------------*/
68
sewardje11d6c82002-12-15 02:00:41 +000069#define DEBUG_LOCK_TABLE 0 /* Print lock table at end */
njn25e49d8e72002-09-23 09:36:25 +000070
71#define DEBUG_MAKE_ACCESSES 0 /* Print make_access() calls */
72#define DEBUG_LOCKS 0 /* Print lock()/unlock() calls and locksets */
73#define DEBUG_NEW_LOCKSETS 0 /* Print new locksets when created */
74#define DEBUG_ACCESSES 0 /* Print reads, writes */
75#define DEBUG_MEM_LOCKSET_CHANGES 0
76 /* Print when an address's lockset
77 changes; only useful with
78 DEBUG_ACCESSES */
sewardj8fac99a2002-11-13 22:31:26 +000079#define SLOW_ASSERTS 0 /* do expensive asserts */
njn25e49d8e72002-09-23 09:36:25 +000080#define DEBUG_VIRGIN_READS 0 /* Dump around address on VIRGIN reads */
81
sewardj8fac99a2002-11-13 22:31:26 +000082#if SLOW_ASSERTS
njn94065fd2004-11-22 19:26:27 +000083#define TL_ASSERT(x) tl_assert(x)
sewardj8fac99a2002-11-13 22:31:26 +000084#else
njn94065fd2004-11-22 19:26:27 +000085#define TL_ASSERT(x)
sewardj8fac99a2002-11-13 22:31:26 +000086#endif
87
njn25e49d8e72002-09-23 09:36:25 +000088/* heavyweight LockSet sanity checking:
89 0 == never
90 1 == after important ops
91 2 == As 1 and also after pthread_mutex_* ops (excessively slow)
92 */
93#define LOCKSET_SANITY 0
94
sewardj8fac99a2002-11-13 22:31:26 +000095/* Rotate an unsigned quantity left */
96#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x)*8)-(n))))
97
njn25e49d8e72002-09-23 09:36:25 +000098/*------------------------------------------------------------*/
sewardjf6374322002-11-13 22:35:55 +000099/*--- Command line options ---*/
100/*------------------------------------------------------------*/
101
102static enum {
103 EC_None,
104 EC_Some,
105 EC_All
106} clo_execontext = EC_None;
107
sewardje1a39f42002-12-15 01:56:17 +0000108static Bool clo_priv_stacks = False;
sewardjf6374322002-11-13 22:35:55 +0000109
110/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000111/*--- Crude profiling machinery. ---*/
112/*------------------------------------------------------------*/
113
114// PPP: work out if I want this
115
116#define PROF_EVENT(x)
117#if 0
118#ifdef VG_PROFILE_MEMORY
119
120#define N_PROF_EVENTS 150
121
122static UInt event_ctr[N_PROF_EVENTS];
123
124void VGE_(done_prof_mem) ( void )
125{
126 Int i;
127 for (i = 0; i < N_PROF_EVENTS; i++) {
128 if ((i % 10) == 0)
129 VG_(printf)("\n");
130 if (event_ctr[i] > 0)
131 VG_(printf)( "prof mem event %2d: %d\n", i, event_ctr[i] );
132 }
133 VG_(printf)("\n");
134}
135
136#define PROF_EVENT(ev) \
njnca82cc02004-11-22 17:18:48 +0000137 do { tl_assert((ev) >= 0 && (ev) < N_PROF_EVENTS); \
njn25e49d8e72002-09-23 09:36:25 +0000138 event_ctr[ev]++; \
139 } while (False);
140
141#else
142
143//static void init_prof_mem ( void ) { }
144// void VG_(done_prof_mem) ( void ) { }
145
146#define PROF_EVENT(ev) /* */
147
148#endif /* VG_PROFILE_MEMORY */
149
150/* Event index. If just the name of the fn is given, this means the
151 number of calls to the fn. Otherwise it is the specified event.
152
153 [PPP: snip event numbers...]
154*/
155#endif /* 0 */
156
157
158/*------------------------------------------------------------*/
159/*--- Data defns. ---*/
160/*------------------------------------------------------------*/
161
njn3e884182003-04-15 13:03:23 +0000162typedef
163 struct _HG_Chunk {
164 struct _HG_Chunk* next;
165 Addr data; /* ptr to actual block */
nethercote928a5f72004-11-03 18:10:37 +0000166 SizeT size; /* size requested */
njn3e884182003-04-15 13:03:23 +0000167 ExeContext* where; /* where it was allocated */
168 ThreadId tid; /* allocating thread */
169 }
170 HG_Chunk;
171
njn25e49d8e72002-09-23 09:36:25 +0000172typedef enum
sewardj7f3ad222002-11-13 22:11:53 +0000173 { Vge_VirginInit, Vge_NonVirginInit, Vge_SegmentInit, Vge_Error }
njn25e49d8e72002-09-23 09:36:25 +0000174 VgeInitStatus;
175
sewardjc808ef52002-11-13 22:43:26 +0000176
njnc6168192004-11-29 13:54:10 +0000177// XXX: not 64-bit clean!
njn25e49d8e72002-09-23 09:36:25 +0000178/* Should add up to 32 to fit in one word */
179#define OTHER_BITS 30
180#define STATE_BITS 2
181
182#define ESEC_MAP_WORDS 16384 /* Words per secondary map */
183
184/* This is for indicating that a memory block has been initialised but not
185 * really directly by a particular thread... (eg. text/data initialised
186 * automatically at startup).
187 * Must be different to virgin_word.other */
188#define TID_INDICATING_NONVIRGIN 1
189
sewardjc4a810d2002-11-13 22:25:51 +0000190/* Magic packed TLS used for error suppression; if word state is Excl
191 and tid is this, then it means all access are OK without changing
192 state and without raising any more errors */
193#define TLSP_INDICATING_ALL ((1 << OTHER_BITS) - 1)
sewardj16748af2002-10-22 04:55:54 +0000194
njn25e49d8e72002-09-23 09:36:25 +0000195/* Number of entries must fit in STATE_BITS bits */
196typedef enum { Vge_Virgin, Vge_Excl, Vge_Shar, Vge_SharMod } pth_state;
197
sewardjc808ef52002-11-13 22:43:26 +0000198static inline const Char *pp_state(pth_state st)
199{
200 const Char *ret;
201
202 switch(st) {
203 case Vge_Virgin: ret = "virgin"; break;
204 case Vge_Excl: ret = "exclusive"; break;
205 case Vge_Shar: ret = "shared RO"; break;
206 case Vge_SharMod: ret = "shared RW"; break;
207 default: ret = "???";
208 }
209 return ret;
210}
211
njn25e49d8e72002-09-23 09:36:25 +0000212typedef
213 struct {
sewardj8fac99a2002-11-13 22:31:26 +0000214 /* gcc arranges this bitfield with state in the 2LSB and other
215 in the 30MSB, which is what we want */
njn25e49d8e72002-09-23 09:36:25 +0000216 UInt state:STATE_BITS;
sewardj8fac99a2002-11-13 22:31:26 +0000217 UInt other:OTHER_BITS;
njn25e49d8e72002-09-23 09:36:25 +0000218 } shadow_word;
219
sewardj8fac99a2002-11-13 22:31:26 +0000220#define SW(st, other) ((shadow_word) { st, other })
221
njn25e49d8e72002-09-23 09:36:25 +0000222typedef
223 struct {
224 shadow_word swords[ESEC_MAP_WORDS];
225 }
226 ESecMap;
227
228static ESecMap* primary_map[ 65536 ];
229static ESecMap distinguished_secondary_map;
230
sewardj8fac99a2002-11-13 22:31:26 +0000231static const shadow_word virgin_sword = SW(Vge_Virgin, 0);
232static const shadow_word error_sword = SW(Vge_Excl, TLSP_INDICATING_ALL);
njn25e49d8e72002-09-23 09:36:25 +0000233
234#define VGE_IS_DISTINGUISHED_SM(smap) \
235 ((smap) == &distinguished_secondary_map)
236
237#define ENSURE_MAPPABLE(addr,caller) \
238 do { \
239 if (VGE_IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
240 primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
241 /*VG_(printf)("new 2map because of %p\n", addr);*/ \
242 } \
243 } while(0)
244
245
sewardjc808ef52002-11-13 22:43:26 +0000246/* Parallel map which contains execution contexts when words last
247 changed state (if required) */
sewardj499e3de2002-11-13 22:22:25 +0000248
nethercoteca788ff2004-10-20 10:58:09 +0000249typedef struct EC_IP {
250 union u_ec_ip {
251 Addr ip;
sewardjc808ef52002-11-13 22:43:26 +0000252 ExeContext *ec;
nethercoteca788ff2004-10-20 10:58:09 +0000253 } uu_ec_ip;
sewardjc808ef52002-11-13 22:43:26 +0000254 UInt state:STATE_BITS;
255 UInt tls:OTHER_BITS; /* packed TLS */
nethercoteca788ff2004-10-20 10:58:09 +0000256} EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000257
nethercoteca788ff2004-10-20 10:58:09 +0000258#define NULL_EC_IP ((EC_IP){ { 0 }, 0, 0})
sewardjc808ef52002-11-13 22:43:26 +0000259
nethercoteca788ff2004-10-20 10:58:09 +0000260#define IP(ip, prev, tls) ((EC_IP) { (union u_ec_ip)(ip), (prev).state, packTLS(tls) })
261#define EC(ec, prev, tls) ((EC_IP) { (union u_ec_ip)(ec), (prev).state, packTLS(tls) })
sewardjc808ef52002-11-13 22:43:26 +0000262
263static inline UInt packEC(ExeContext *ec)
264{
njn94065fd2004-11-22 19:26:27 +0000265 TL_ASSERT(((UWord)ec & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000266 return ((UWord)ec) >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000267}
268
nethercoteca788ff2004-10-20 10:58:09 +0000269/* Lose 2 LSB of IP */
270static inline UInt packIP(Addr ip)
sewardjc808ef52002-11-13 22:43:26 +0000271{
nethercote50397c22004-11-04 18:03:06 +0000272 return ip >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000273}
274
nethercoteca788ff2004-10-20 10:58:09 +0000275static inline Addr unpackIP(UInt i)
sewardjc808ef52002-11-13 22:43:26 +0000276{
277 return (Addr)(i << STATE_BITS);
278}
sewardj499e3de2002-11-13 22:22:25 +0000279
280typedef struct {
nethercoteca788ff2004-10-20 10:58:09 +0000281 EC_IP execontext[ESEC_MAP_WORDS];
sewardj499e3de2002-11-13 22:22:25 +0000282} ExeContextMap;
283
284static ExeContextMap** execontext_map;
285
nethercoteca788ff2004-10-20 10:58:09 +0000286static inline void setExeContext(Addr a, EC_IP ec)
sewardj499e3de2002-11-13 22:22:25 +0000287{
288 UInt idx = (a >> 16) & 0xffff;
289 UInt off = (a >> 2) & 0x3fff;
290
291 if (execontext_map[idx] == NULL) {
292 execontext_map[idx] = VG_(malloc)(sizeof(ExeContextMap));
293 VG_(memset)(execontext_map[idx], 0, sizeof(ExeContextMap));
294 }
295
296 execontext_map[idx]->execontext[off] = ec;
297}
298
nethercoteca788ff2004-10-20 10:58:09 +0000299static inline EC_IP getExeContext(Addr a)
sewardj499e3de2002-11-13 22:22:25 +0000300{
301 UInt idx = (a >> 16) & 0xffff;
302 UInt off = (a >> 2) & 0x3fff;
nethercoteca788ff2004-10-20 10:58:09 +0000303 EC_IP ec = NULL_EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000304
305 if (execontext_map[idx] != NULL)
306 ec = execontext_map[idx]->execontext[off];
307
308 return ec;
309}
310
njn25e49d8e72002-09-23 09:36:25 +0000311/*------------------------------------------------------------*/
sewardjc4a810d2002-11-13 22:25:51 +0000312/*--- Thread lifetime segments ---*/
313/*------------------------------------------------------------*/
314
315/*
316 * This mechanism deals with the common case of a parent thread
317 * creating a structure for a child thread, and then passing ownership
318 * of the structure to that thread. It similarly copes with a child
319 * thread passing information back to another thread waiting to join
320 * on it.
321 *
322 * Each thread's lifetime can be partitioned into segments. Those
323 * segments are arranged to form an interference graph which indicates
324 * whether two thread lifetime segments can possibly be concurrent.
325 * If not, then memory with is exclusively accessed by one TLS can be
daywalker7e73e5f2003-07-04 16:18:15 +0000326 * passed on to another TLS without an error occurring, and without
sewardjc4a810d2002-11-13 22:25:51 +0000327 * moving it from Excl state.
328 *
329 * At present this only considers thread creation and join as
330 * synchronisation events for creating new lifetime segments, but
331 * others may be possible (like mutex operations).
332 */
333
334typedef struct _ThreadLifeSeg ThreadLifeSeg;
335
336struct _ThreadLifeSeg {
337 ThreadId tid;
338 ThreadLifeSeg *prior[2]; /* Previous lifetime segments */
339 UInt refcount; /* Number of memory locations pointing here */
340 UInt mark; /* mark used for graph traversal */
341 ThreadLifeSeg *next; /* list of all TLS */
342};
343
344static ThreadLifeSeg *all_tls;
345static UInt tls_since_gc;
346#define TLS_SINCE_GC 10000
347
348/* current mark used for TLS graph traversal */
349static UInt tlsmark;
350
351static ThreadLifeSeg *thread_seg[VG_N_THREADS];
352
353
354static void tls_gc(void)
355{
356 /* XXX later. Walk through all TLSs and look for ones with 0
357 refcount and remove them from the structure and free them.
358 Could probably get rid of ThreadLifeSeg.refcount and simply use
359 mark-sweep from the shadow table. */
360 VG_(printf)("WRITEME: TLS GC\n");
361}
362
363static void newTLS(ThreadId tid)
364{
365 static const Bool debug = False;
366 ThreadLifeSeg *tls;
367
368 /* Initial NULL */
369 if (thread_seg[tid] == NULL) {
370 tls = VG_(malloc)(sizeof(*tls));
371 tls->tid = tid;
372 tls->prior[0] = tls->prior[1] = NULL;
373 tls->refcount = 0;
374 tls->mark = tlsmark-1;
375
376 tls->next = all_tls;
377 all_tls = tls;
378 tls_since_gc++;
379
380 thread_seg[tid] = tls;
381 return;
382 }
383
384 /* Previous TLS was unused, so just recycle */
385 if (thread_seg[tid]->refcount == 0) {
386 if (debug)
387 VG_(printf)("newTLS; recycling TLS %p for tid %u\n",
388 thread_seg[tid], tid);
389 return;
390 }
391
392 /* Use existing TLS for this tid as a prior for new TLS */
393 tls = VG_(malloc)(sizeof(*tls));
394 tls->tid = tid;
395 tls->prior[0] = thread_seg[tid];
396 tls->prior[1] = NULL;
397 tls->refcount = 0;
398 tls->mark = tlsmark-1;
399
400 tls->next = all_tls;
401 all_tls = tls;
402 if (++tls_since_gc > TLS_SINCE_GC) {
403 tls_gc();
404 tls_since_gc = 0;
405 }
406
407 if (debug)
408 VG_(printf)("newTLS: made new TLS %p for tid %u (prior %p(%u))\n",
409 tls, tid, tls->prior[0], tls->prior[0]->tid);
410
411 thread_seg[tid] = tls;
412}
413
414/* clear out a TLS for a thread that's died */
415static void clearTLS(ThreadId tid)
416{
417 newTLS(tid);
418
419 thread_seg[tid]->prior[0] = NULL;
420 thread_seg[tid]->prior[1] = NULL;
421}
422
423static void addPriorTLS(ThreadId tid, ThreadId prior)
424{
425 static const Bool debug = False;
426 ThreadLifeSeg *tls = thread_seg[tid];
427
428 if (debug)
429 VG_(printf)("making TLS %p(%u) prior to TLS %p(%u)\n",
430 thread_seg[prior], prior, tls, tid);
431
njnca82cc02004-11-22 17:18:48 +0000432 tl_assert(thread_seg[tid] != NULL);
433 tl_assert(thread_seg[prior] != NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000434
435 if (tls->prior[0] == NULL)
436 tls->prior[0] = thread_seg[prior];
437 else {
njnca82cc02004-11-22 17:18:48 +0000438 tl_assert(tls->prior[1] == NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000439 tls->prior[1] = thread_seg[prior];
440 }
441}
442
njnfbdcba92005-05-09 01:23:49 +0000443static Bool isPrior(const ThreadLifeSeg *t, const ThreadLifeSeg *prior)
444{
445 if (t == NULL || t->mark == tlsmark)
446 return False;
447
448 if (t == prior)
449 return True;
450
451 ((ThreadLifeSeg *)t)->mark = tlsmark;
452
453 return isPrior(t->prior[0], prior) || isPrior(t->prior[1], prior);
454}
455
sewardjc4a810d2002-11-13 22:25:51 +0000456/* Return True if prior is definitely not concurrent with tls */
457static Bool tlsIsDisjoint(const ThreadLifeSeg *tls,
458 const ThreadLifeSeg *prior)
459{
sewardjc4a810d2002-11-13 22:25:51 +0000460 tlsmark++; /* new traversal mark */
461
njnfbdcba92005-05-09 01:23:49 +0000462 return isPrior(tls, prior);
sewardjc4a810d2002-11-13 22:25:51 +0000463}
464
465static inline UInt packTLS(ThreadLifeSeg *tls)
466{
njn94065fd2004-11-22 19:26:27 +0000467 TL_ASSERT(((UWord)tls & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000468 return ((UWord)tls) >> STATE_BITS;
sewardjc4a810d2002-11-13 22:25:51 +0000469}
470
471static inline ThreadLifeSeg *unpackTLS(UInt i)
472{
sewardj29ef1c82005-06-11 10:33:35 +0000473 /* HACK ALERT -- DUBIOUS CAST */
474 return (ThreadLifeSeg *)ULong_to_Ptr(i << STATE_BITS);
sewardjc4a810d2002-11-13 22:25:51 +0000475}
476
477/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000478/*--- Low-level support for memory tracking. ---*/
479/*------------------------------------------------------------*/
480
481/*
482 All reads and writes are recorded in the memory map, which
483 records the state of all memory in the process. The memory map is
484 organised like that for normal Valgrind, except each that everything
485 is done at word-level instead of byte-level, and each word has only
486 one word of shadow (instead of 36 bits).
487
488 As for normal Valgrind there is a distinguished secondary map. But we're
489 working at word-granularity, so it has 16k word entries instead of 64k byte
490 entries. Lookup is done as follows:
491
492 bits 31..16: primary map lookup
493 bits 15.. 2: secondary map lookup
494 bits 1.. 0: ignored
495*/
496
497
498/*------------------------------------------------------------*/
499/*--- Basic bitmap management, reading and writing. ---*/
500/*------------------------------------------------------------*/
501
502/* Allocate and initialise a secondary map, marking all words as virgin. */
503
504/* Just a value that isn't a real pointer */
505#define SEC_MAP_ACCESS (shadow_word*)0x99
506
507
508static
509ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
510{
511 ESecMap* map;
512 UInt i;
513 //PROF_EVENT(10); PPP
514
nethercote1420ab22004-08-18 22:26:01 +0000515 // Mark all words as virgin.
sewardj45f4e7c2005-09-27 19:20:21 +0000516 map = (ESecMap *)VG_(am_shadow_alloc)(sizeof(ESecMap));
517 if (map == NULL)
518 VG_(out_of_memory_NORETURN)( "helgrind:allocate new ESecMap",
519 sizeof(ESecMap) );
njn25e49d8e72002-09-23 09:36:25 +0000520 for (i = 0; i < ESEC_MAP_WORDS; i++)
521 map->swords[i] = virgin_sword;
522
523 return map;
524}
525
526
527/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
528 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000529static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000530void set_sword ( Addr a, shadow_word sword )
531{
532 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000533 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000534
535 //PROF_EVENT(23); PPP
536 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
537
538 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
539 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000540 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000541 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
542 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
543 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
544 tls->refcount--;
545 }
546
547 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
548 ThreadLifeSeg *tls = unpackTLS(sword.other);
549 tls->refcount++;
550 }
551
njn25e49d8e72002-09-23 09:36:25 +0000552 sm->swords[(a & 0xFFFC) >> 2] = sword;
553
554 if (VGE_IS_DISTINGUISHED_SM(sm)) {
555 VG_(printf)("wrote to distinguished 2ndary map! 0x%x\n", a);
556 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000557 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000558 }
559}
560
561
562static __inline__
563shadow_word* get_sword_addr ( Addr a )
564{
565 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
566 ESecMap* sm = primary_map[a >> 16];
567 UInt sm_off = (a & 0xFFFC) >> 2;
568
569 if (VGE_IS_DISTINGUISHED_SM(sm)) {
570 VG_(printf)("accessed distinguished 2ndary map! 0x%x\n", a);
571 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000572 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000573 return SEC_MAP_ACCESS;
574 }
575
576 //PROF_EVENT(21); PPP
577 return & (sm->swords[sm_off]);
578}
579
580
581// SSS: rename these so they're not so similar to memcheck, unless it's
582// appropriate of course
583
584static __inline__
585void init_virgin_sword(Addr a)
586{
sewardj499e3de2002-11-13 22:22:25 +0000587 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000588 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000589 set_sword(a, virgin_sword);
590}
591
sewardj7f3ad222002-11-13 22:11:53 +0000592static __inline__
593void init_error_sword(Addr a)
594{
595 set_sword(a, error_sword);
596}
njn25e49d8e72002-09-23 09:36:25 +0000597
njn25e49d8e72002-09-23 09:36:25 +0000598static __inline__
599void init_nonvirgin_sword(Addr a)
600{
601 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000602 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000603 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000604
njn14d01ce2004-11-26 11:30:14 +0000605 // The tid must be passed in here now; this requires more events to be
606 // given the tid in the first place.
607 //
608 //tid = VG_(get_current_or_recent_tid)();
609 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
610 VG_(exit)(1);
611
njnca82cc02004-11-22 17:18:48 +0000612 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000613 tls = thread_seg[tid];
614
sewardj8fac99a2002-11-13 22:31:26 +0000615 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000616 set_sword(a, sword);
617}
618
619
njnfbdcba92005-05-09 01:23:49 +0000620/* In this case, we treat it for Helgrind's sake like virgin (it hasn't
njn25e49d8e72002-09-23 09:36:25 +0000621 * been inited by a particular thread, it's just done automatically upon
622 * startup), but we mark its .state specially so it doesn't look like an
623 * uninited read. */
624static __inline__
625void init_magically_inited_sword(Addr a)
626{
627 shadow_word sword;
628
sewardj8fac99a2002-11-13 22:31:26 +0000629 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
630
njn25e49d8e72002-09-23 09:36:25 +0000631 set_sword(a, virgin_sword);
632}
633
sewardjc26cc252002-10-23 21:58:55 +0000634
sewardj274c6012002-10-22 04:54:55 +0000635/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000636/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000637/*------------------------------------------------------------*/
638
sewardj39a4d842002-11-13 22:14:30 +0000639typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000640typedef struct _LockSet LockSet;
641
sewardj16748af2002-10-22 04:55:54 +0000642typedef enum MutexState {
643 MxUnknown, /* don't know */
644 MxUnlocked, /* unlocked */
645 MxLocked, /* locked */
646 MxDead /* destroyed */
647} MutexState;
648
sewardj39a4d842002-11-13 22:14:30 +0000649struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000650 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000651 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000652
653 MutexState state; /* mutex state */
654 ThreadId tid; /* owner */
655 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000656
sewardj4bffb232002-11-13 21:46:34 +0000657 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000658 UInt mark; /* mark for graph traversal */
659};
sewardj16748af2002-10-22 04:55:54 +0000660
sewardj39a4d842002-11-13 22:14:30 +0000661static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000662{
sewardjdac0a442002-11-13 22:08:40 +0000663 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000664}
njn25e49d8e72002-09-23 09:36:25 +0000665
sewardj274c6012002-10-22 04:54:55 +0000666struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000667 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000668 UInt hash; /* hash code */
669 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000670 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000671};
sewardj4bffb232002-11-13 21:46:34 +0000672
673static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000674
675/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000676static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000677
sewardjdac0a442002-11-13 22:08:40 +0000678#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000679
sewardj4bffb232002-11-13 21:46:34 +0000680static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000681
sewardj4bffb232002-11-13 21:46:34 +0000682/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000683static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000684{
sewardj4bffb232002-11-13 21:46:34 +0000685 UInt id;
686
njn94065fd2004-11-22 19:26:27 +0000687 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000688 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000689
690 return id;
njn25e49d8e72002-09-23 09:36:25 +0000691}
692
sewardj8fac99a2002-11-13 22:31:26 +0000693static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000694{
sewardj29ef1c82005-06-11 10:33:35 +0000695 /* HACK ALERT -- DUBIOUS CAST */
696 return (LockSet *)ULong_to_Ptr(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000697}
698
njn25e49d8e72002-09-23 09:36:25 +0000699static
sewardj4bffb232002-11-13 21:46:34 +0000700void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000701{
sewardj05bcdcb2003-05-18 10:05:38 +0000702 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000703 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000704 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000705 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000706
707 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000708 }
709 VG_(printf)("}\n");
710}
711
712
sewardj4bffb232002-11-13 21:46:34 +0000713static void print_LockSet(const Char *s, const LockSet *ls)
714{
715 VG_(printf)("%s: ", s);
716 pp_LockSet(ls);
717}
718
719/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000720static UInt hash_LockSet_w_wo(const LockSet *ls,
721 const Mutex *with,
722 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000723{
sewardj05bcdcb2003-05-18 10:05:38 +0000724 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000725 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000726
njnca82cc02004-11-22 17:18:48 +0000727 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000728
729 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000730 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000731
732 if (without && mutex_cmp(without, mx) == 0)
733 continue;
734
735 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
736 mx = with;
737 with = NULL;
738 i--;
739 }
740
sewardj8fac99a2002-11-13 22:31:26 +0000741 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000742 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000743 }
744
745 return hash % LOCKSET_HASH_SZ;
746}
747
sewardj39a4d842002-11-13 22:14:30 +0000748static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000749{
750 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
751
752 if (0)
753 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
754
755 return hash;
756}
757
sewardj39a4d842002-11-13 22:14:30 +0000758static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000759{
760 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
761
762 if (0)
763 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
764
765 return hash;
766}
767
768static inline UInt hash_LockSet(const LockSet *ls)
769{
770 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
771
772 if (0)
773 VG_(printf)("hash %p -> %d\n", ls, hash);
774
775 return hash;
776}
777
778static
779Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000780{
781 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000782
sewardj4bffb232002-11-13 21:46:34 +0000783 if (a == b)
784 return True;
785 if (a->setsize != b->setsize)
786 return False;
njn25e49d8e72002-09-23 09:36:25 +0000787
sewardj4bffb232002-11-13 21:46:34 +0000788 for(i = 0; i < a->setsize; i++) {
789 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000790 return False;
njn25e49d8e72002-09-23 09:36:25 +0000791 }
792
sewardj4bffb232002-11-13 21:46:34 +0000793 return True;
njn25e49d8e72002-09-23 09:36:25 +0000794}
795
796
797/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
798 * doesn't do the insertion. Returns True if they match.
799 */
800static Bool
sewardj4bffb232002-11-13 21:46:34 +0000801weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000802 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000803{
sewardjc26cc252002-10-23 21:58:55 +0000804 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000805 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000806
njn25e49d8e72002-09-23 09:36:25 +0000807 /* Idea is to try and match each element of b against either an
808 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000809
810 if (debug) {
811 print_LockSet("weird_LockSet_equals a", a);
812 print_LockSet(" b", b);
813 VG_(printf)( " missing: %p%(y\n",
814 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000815 }
sewardjc26cc252002-10-23 21:58:55 +0000816
sewardj4bffb232002-11-13 21:46:34 +0000817 if ((a->setsize + 1) != b->setsize) {
818 if (debug)
819 VG_(printf)(" fastpath length mismatch -> 0\n");
820 return False;
821 }
822
sewardjc26cc252002-10-23 21:58:55 +0000823 /* There are three phases to this compare:
824 1 the section from the start of a up to missing_mutex
825 2 missing mutex itself
826 3 the section after missing_mutex to the end of a
827 */
828
sewardj4bffb232002-11-13 21:46:34 +0000829 ia = 0;
830 ib = 0;
831
sewardjc26cc252002-10-23 21:58:55 +0000832 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000833 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000834 if (debug) {
835 print_LockSet(" 1:a", a);
836 print_LockSet(" 1:b", b);
837 }
sewardj4bffb232002-11-13 21:46:34 +0000838 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000839 return False;
sewardjc26cc252002-10-23 21:58:55 +0000840 }
841
842 /* 2: missing_mutex itself */
843 if (debug) {
844 VG_(printf)( " 2:missing: %p%(y\n",
845 missing_mutex->mutexp, missing_mutex->mutexp);
846 print_LockSet(" 2: b", b);
847 }
848
njnca82cc02004-11-22 17:18:48 +0000849 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000850
sewardj4bffb232002-11-13 21:46:34 +0000851 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000852 return False;
853
sewardj4bffb232002-11-13 21:46:34 +0000854 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000855
856 /* 3: after missing_mutex to end */
857
sewardj4bffb232002-11-13 21:46:34 +0000858 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000859 if (debug) {
860 print_LockSet(" 3:a", a);
861 print_LockSet(" 3:b", b);
862 }
sewardj4bffb232002-11-13 21:46:34 +0000863 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000864 return False;
sewardjc26cc252002-10-23 21:58:55 +0000865 }
866
867 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000868 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000869
sewardj4bffb232002-11-13 21:46:34 +0000870 return ia == a->setsize && ib == b->setsize;
871}
872
873
874
875static const LockSet *lookup_LockSet(const LockSet *set)
876{
877 UInt bucket = set->hash;
878 LockSet *ret;
879
880 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
881 if (set == ret || structural_eq_LockSet(set, ret))
882 return ret;
883
884 return NULL;
885}
886
sewardj39a4d842002-11-13 22:14:30 +0000887static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000888{
889 UInt bucket = hash_LockSet_with(set, mutex);
890 const LockSet *ret;
891
892 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
893 if (weird_LockSet_equals(set, ret, mutex))
894 return ret;
895
896 return NULL;
897}
898
sewardj39a4d842002-11-13 22:14:30 +0000899static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000900{
901 UInt bucket = hash_LockSet_without(set, mutex);
902 const LockSet *ret;
903
904 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
905 if (weird_LockSet_equals(ret, set, mutex))
906 return ret;
907
908 return NULL;
909}
910
911static void insert_LockSet(LockSet *set)
912{
913 UInt hash = hash_LockSet(set);
914
915 set->hash = hash;
916
njnca82cc02004-11-22 17:18:48 +0000917 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000918
919 set->next = lockset_hash[hash];
920 lockset_hash[hash] = set;
921}
922
923static inline
924LockSet *alloc_LockSet(UInt setsize)
925{
sewardj39a4d842002-11-13 22:14:30 +0000926 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000927 ret->setsize = setsize;
928 return ret;
929}
930
931static inline
932void free_LockSet(LockSet *p)
933{
934 /* assert: not present in hash */
935 VG_(free)(p);
936}
937
njnb4aee052003-04-15 14:09:58 +0000938static
sewardj4bffb232002-11-13 21:46:34 +0000939void pp_all_LockSets ( void )
940{
941 Int i;
942 Int sets, buckets;
943
944 sets = buckets = 0;
945 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
946 const LockSet *ls = lockset_hash[i];
947 Bool first = True;
948
sewardj4bffb232002-11-13 21:46:34 +0000949 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000950 if (first) {
951 buckets++;
952 VG_(printf)("[%4d] = ", i);
953 } else
954 VG_(printf)(" ");
955
sewardj4bffb232002-11-13 21:46:34 +0000956 sets++;
957 first = False;
958 pp_LockSet(ls);
959 }
960 }
961
962 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
963}
964
965static inline Bool isempty(const LockSet *ls)
966{
967 return ls == NULL || ls->setsize == 0;
968}
969
sewardj39a4d842002-11-13 22:14:30 +0000970static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000971{
972 Int i;
973
974 /* XXX use binary search */
975 for(i = 0; i < ls->setsize; i++)
976 if (mutex_cmp(mx, ls->mutex[i]) == 0)
977 return True;
978
979 return False;
980}
981
982/* Check invariants:
983 - all locksets are unique
984 - each set is an array in strictly increasing order of mutex addr
985*/
986static
987void sanity_check_locksets ( const Char* caller )
988{
989 Int i;
990 const Char *badness;
991 LockSet *ls;
992
993 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
994
995 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000996 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000997 Int j;
998
999 if (hash_LockSet(ls) != ls->hash) {
1000 badness = "mismatched hash";
1001 goto bad;
1002 }
sewardj05bcdcb2003-05-18 10:05:38 +00001003 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +00001004 badness = "wrong bucket";
1005 goto bad;
1006 }
1007 if (lookup_LockSet(ls) != ls) {
1008 badness = "non-unique set";
1009 goto bad;
1010 }
1011
1012 prev = ls->mutex[0];
1013 for(j = 1; j < ls->setsize; j++) {
1014 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
1015 badness = "mutexes out of order";
1016 goto bad;
1017 }
1018 }
1019 }
1020 }
1021 return;
1022
1023 bad:
1024 VG_(printf)("sanity_check_locksets: "
1025 "i = %d, ls=%p badness = %s, caller = %s\n",
1026 i, ls, badness, caller);
1027 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001028 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001029}
1030
1031static
sewardj39a4d842002-11-13 22:14:30 +00001032LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001033{
1034 static const Bool debug = False;
1035 LockSet *ret = NULL;
1036 Int i, j;
1037
1038 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1039 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1040 print_LockSet("add-IN", ls);
1041 }
1042
1043 if (debug || LOCKSET_SANITY)
1044 sanity_check_locksets("add-IN");
1045
njnca82cc02004-11-22 17:18:48 +00001046 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001047
1048 ret = alloc_LockSet(ls->setsize+1);
1049
1050 for(i = j = 0; i < ls->setsize; i++) {
1051 if (debug)
1052 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1053 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1054 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1055 ret->mutex[j++] = mx;
1056 mx = NULL;
1057 }
1058 ret->mutex[j++] = ls->mutex[i];
1059 }
1060
1061 /* not added in loop - must be after */
1062 if (mx)
1063 ret->mutex[j++] = mx;
1064
njnca82cc02004-11-22 17:18:48 +00001065 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001066
1067 if (debug || LOCKSET_SANITY) {
1068 print_LockSet("add-OUT", ret);
1069 sanity_check_locksets("add-OUT");
1070 }
1071 return ret;
1072}
1073
1074/* Builds ls with mx removed. mx should actually be in ls!
1075 (a checked assertion). Resulting set should not already
1076 exist in the table (unchecked).
1077*/
1078static
sewardj39a4d842002-11-13 22:14:30 +00001079LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001080{
1081 static const Bool debug = False;
1082 LockSet *ret = NULL;
1083 Int i, j;
1084
1085 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1086 print_LockSet("remove-IN", ls);
1087 }
1088
1089 if (debug || LOCKSET_SANITY)
1090 sanity_check_locksets("remove-IN");
1091
njnca82cc02004-11-22 17:18:48 +00001092 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001093
1094 ret = alloc_LockSet(ls->setsize-1);
1095
1096 for(i = j = 0; i < ls->setsize; i++) {
1097 if (mutex_cmp(ls->mutex[i], mx) == 0)
1098 continue;
1099 ret->mutex[j++] = ls->mutex[i];
1100 }
1101
njnca82cc02004-11-22 17:18:48 +00001102 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001103
1104 if (debug || LOCKSET_SANITY) {
1105 print_LockSet("remove-OUT", ret);
1106 sanity_check_locksets("remove-OUT");
1107 }
1108 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001109}
1110
1111
1112/* Builds the intersection, and then unbuilds it if it's already in the table.
1113 */
sewardj4bffb232002-11-13 21:46:34 +00001114static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001115{
sewardj4bffb232002-11-13 21:46:34 +00001116 static const Bool debug = False;
1117 Int iret;
1118 Int ia, ib;
1119 Int size;
1120 LockSet *ret;
1121 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001122
sewardj4bffb232002-11-13 21:46:34 +00001123 if (debug || LOCKSET_SANITY)
1124 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001125
sewardj4bffb232002-11-13 21:46:34 +00001126 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1127 print_LockSet("intersect a", a);
1128 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001129 }
1130
sewardj4bffb232002-11-13 21:46:34 +00001131 /* count the size of the new set */
1132 size = 0;
1133 ia = ib = 0;
1134 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1135 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1136 size++;
1137 ia++;
1138 ib++;
1139 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1140 ia++;
1141 } else {
njnca82cc02004-11-22 17:18:48 +00001142 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001143 ib++;
1144 }
njn25e49d8e72002-09-23 09:36:25 +00001145 }
1146
sewardj4bffb232002-11-13 21:46:34 +00001147 /* Build the intersection of the two sets */
1148 ret = alloc_LockSet(size);
1149 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1150 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001151 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001152 ret->mutex[iret++] = a->mutex[ia];
1153 ia++;
1154 ib++;
1155 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1156 ia++;
1157 } else {
njnca82cc02004-11-22 17:18:48 +00001158 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001159 ib++;
1160 }
1161 }
1162
1163 ret->hash = hash_LockSet(ret);
1164
njn25e49d8e72002-09-23 09:36:25 +00001165 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001166 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001167
sewardj4bffb232002-11-13 21:46:34 +00001168 if (found != NULL) {
1169 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001170 } else {
sewardj4bffb232002-11-13 21:46:34 +00001171 insert_LockSet(ret);
1172 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001173 }
1174
sewardj4bffb232002-11-13 21:46:34 +00001175 if (debug || LOCKSET_SANITY) {
1176 print_LockSet("intersect-OUT", found);
1177 sanity_check_locksets("intersect-OUT");
1178 }
njn25e49d8e72002-09-23 09:36:25 +00001179
sewardj4bffb232002-11-13 21:46:34 +00001180 return found;
njn25e49d8e72002-09-23 09:36:25 +00001181}
1182
sewardj4bffb232002-11-13 21:46:34 +00001183/* inline the fastpath */
1184static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001185{
sewardj4bffb232002-11-13 21:46:34 +00001186 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001187
1188 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001189 if (a == b) {
1190 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1191 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001192 }
sewardj4bffb232002-11-13 21:46:34 +00001193 return a;
sewardjc26cc252002-10-23 21:58:55 +00001194 }
1195
sewardj4bffb232002-11-13 21:46:34 +00001196 if (isempty(a) || isempty(b)) {
1197 if (debug)
1198 VG_(printf)("intersect empty fastpath\n");
1199 return emptyset;
1200 }
1201
1202 return _intersect(a, b);
1203}
1204
1205
1206static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1207{
1208 static const Bool debug = False;
1209 Int iret;
1210 Int ia, ib;
1211 Int size;
1212 LockSet *ret;
1213 const LockSet *found;
1214
1215 if (debug || LOCKSET_SANITY)
1216 sanity_check_locksets("union-IN");
1217
1218 /* Fast case -- when the two are the same */
1219 if (a == b) {
1220 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1221 print_LockSet("union-same fastpath", a);
1222 }
1223 return a;
1224 }
1225
1226 if (isempty(a)) {
1227 if (debug)
1228 print_LockSet("union a=empty b", b);
1229 return b;
1230 }
1231 if (isempty(b)) {
1232 if (debug)
1233 print_LockSet("union b=empty a", a);
1234 return a;
1235 }
1236
1237 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001238 print_LockSet("union a", a);
1239 print_LockSet("union b", b);
1240 }
1241
sewardj4bffb232002-11-13 21:46:34 +00001242 /* count the size of the new set */
1243 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1244 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001245
sewardj4bffb232002-11-13 21:46:34 +00001246 if ((ia < a->setsize) && (ib < b->setsize))
1247 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1248 else if (ia == a->setsize)
1249 cmp = 1;
1250 else
1251 cmp = -1;
1252
1253 if (cmp == 0) {
1254 size++;
1255 ia++;
1256 ib++;
1257 } else if (cmp < 0) {
1258 size++;
1259 ia++;
1260 } else {
njnca82cc02004-11-22 17:18:48 +00001261 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001262 size++;
1263 ib++;
1264 }
sewardjc26cc252002-10-23 21:58:55 +00001265 }
1266
sewardj4bffb232002-11-13 21:46:34 +00001267 /* Build the intersection of the two sets */
1268 ret = alloc_LockSet(size);
1269 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1270 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001271 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001272
1273 if ((ia < a->setsize) && (ib < b->setsize))
1274 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1275 else if (ia == a->setsize)
1276 cmp = 1;
1277 else
1278 cmp = -1;
1279
1280 if (cmp == 0) {
1281 ret->mutex[iret++] = a->mutex[ia];
1282 ia++;
1283 ib++;
1284 } else if (cmp < 0) {
1285 ret->mutex[iret++] = a->mutex[ia];
1286 ia++;
1287 } else {
njnca82cc02004-11-22 17:18:48 +00001288 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001289 ret->mutex[iret++] = b->mutex[ib];
1290 ib++;
1291 }
1292 }
1293
njnca82cc02004-11-22 17:18:48 +00001294 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001295
1296 ret->hash = hash_LockSet(ret);
1297
sewardjc26cc252002-10-23 21:58:55 +00001298 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001299 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001300
sewardj4bffb232002-11-13 21:46:34 +00001301 if (found != NULL) {
1302 if (debug)
1303 print_LockSet("union found existing set", found);
1304 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001305 } else {
sewardj4bffb232002-11-13 21:46:34 +00001306 if (debug)
1307 print_LockSet("union inserting new set", ret);
1308 insert_LockSet(ret);
1309 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001310 }
1311
sewardj4bffb232002-11-13 21:46:34 +00001312 if (debug || LOCKSET_SANITY) {
1313 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001314 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001315 }
sewardjc26cc252002-10-23 21:58:55 +00001316
sewardj4bffb232002-11-13 21:46:34 +00001317 return found;
sewardjc26cc252002-10-23 21:58:55 +00001318}
1319
1320/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001321/*--- Implementation of mutex structure. ---*/
1322/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001323
1324static UInt graph_mark; /* current mark we're using for graph traversal */
1325
sewardj39a4d842002-11-13 22:14:30 +00001326static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001327 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001328static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001329 const LockSet *lockset_holding,
1330 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001331
njn72718642003-07-24 08:45:32 +00001332static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001333
1334#define M_MUTEX_HASHSZ 1021
1335
sewardj39a4d842002-11-13 22:14:30 +00001336static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001337static UInt total_mutexes;
1338
1339static const Char *pp_MutexState(MutexState st)
1340{
1341 switch(st) {
1342 case MxLocked: return "Locked";
1343 case MxUnlocked: return "Unlocked";
1344 case MxDead: return "Dead";
1345 case MxUnknown: return "Unknown";
1346 }
1347 return "???";
1348}
1349
tom151a6392005-11-11 12:30:36 +00001350static void pp_all_mutexes(void)
sewardjdac0a442002-11-13 22:08:40 +00001351{
1352 Int i;
1353 Int locks, buckets;
1354
1355 locks = buckets = 0;
1356 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001357 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001358 Bool first = True;
1359
1360 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1361 if (first) {
1362 buckets++;
1363 VG_(printf)("[%4d] = ", i);
1364 } else
1365 VG_(printf)(" ");
1366 locks++;
1367 first = False;
1368 VG_(printf)("%p [%8s] -> %p%(y\n",
1369 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1370 }
1371 }
1372
1373 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1374 locks, buckets, total_mutexes);
1375}
sewardjc26cc252002-10-23 21:58:55 +00001376
sewardj39a4d842002-11-13 22:14:30 +00001377/* find or create a Mutex for a program's mutex use */
1378static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001379{
nethercote50397c22004-11-04 18:03:06 +00001380 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001381 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001382
1383 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1384 if (mp->mutexp == mutexp)
1385 return mp;
1386
sewardjdac0a442002-11-13 22:08:40 +00001387 total_mutexes++;
1388
sewardjc26cc252002-10-23 21:58:55 +00001389 mp = VG_(malloc)(sizeof(*mp));
1390 mp->mutexp = mutexp;
1391 mp->next = mutex_hash[bucket];
1392 mutex_hash[bucket] = mp;
1393
1394 mp->state = MxUnknown;
1395 mp->tid = VG_INVALID_THREADID;
1396 mp->location = NULL;
1397
sewardj4bffb232002-11-13 21:46:34 +00001398 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001399 mp->mark = graph_mark - 1;
1400
1401 return mp;
1402}
1403
sewardjdac0a442002-11-13 22:08:40 +00001404/* Find all mutexes in a range of memory, and call the callback.
1405 Remove the mutex from the hash if the callback returns True (mutex
1406 structure itself is not freed, because it may be pointed to by a
1407 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001408static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001409{
sewardjdac0a442002-11-13 22:08:40 +00001410 UInt first = start % M_MUTEX_HASHSZ;
1411 UInt last = (end+1) % M_MUTEX_HASHSZ;
1412 UInt i;
1413
1414 /* Single pass over the hash table, looking for likely hashes */
1415 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001416 Mutex *mx;
1417 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001418
1419 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1420 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1421 *prev = mx->next;
1422 }
1423
1424 if (++i == M_MUTEX_HASHSZ)
1425 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001426 }
sewardjc26cc252002-10-23 21:58:55 +00001427}
1428
1429#define MARK_LOOP (graph_mark+0)
1430#define MARK_DONE (graph_mark+1)
1431
thughes4ad52d02004-06-27 17:37:21 +00001432static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1433{
1434 static const Bool debug = False;
1435 Int i;
1436
1437 if (mutex->mark == MARK_LOOP)
1438 return True; /* found cycle */
1439 if (mutex->mark == MARK_DONE)
1440 return False; /* been here before, its OK */
1441
1442 ((Mutex*)mutex)->mark = MARK_LOOP;
1443
1444 if (debug)
1445 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1446 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1447 for(i = 0; i < ls->setsize; i++) {
1448 const Mutex *mx = ls->mutex[i];
1449
1450 if (debug)
1451 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1452 mutex->mutexp, ls,
1453 mx->mutexp, mx->mutexp);
1454 if (check_cycle_inner(mx, mx->lockdep))
1455 return True;
1456 }
1457 ((Mutex*)mutex)->mark = MARK_DONE;
1458
1459 return False;
1460}
1461
sewardj39a4d842002-11-13 22:14:30 +00001462static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001463{
sewardjff2c9232002-11-13 21:44:39 +00001464
sewardjc26cc252002-10-23 21:58:55 +00001465 graph_mark += 2; /* clear all marks */
1466
sewardj4bffb232002-11-13 21:46:34 +00001467 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001468}
1469
sewardjdca84112002-11-13 22:29:34 +00001470/* test to see if a mutex state change would be problematic; this
1471 makes no changes to the mutex state. This should be called before
1472 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001473static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001474{
1475 static const Bool debug = False;
1476
sewardjc26cc252002-10-23 21:58:55 +00001477 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001478 Char *str;
1479
1480 switch(state) {
1481 case MxLocked: str = "lock dead mutex"; break;
1482 case MxUnlocked: str = "unlock dead mutex"; break;
1483 default: str = "operate on dead mutex"; break;
1484 }
1485
sewardjc26cc252002-10-23 21:58:55 +00001486 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001487 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001488 return;
1489 }
1490
1491 switch(state) {
1492 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001493 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001494
1495 if (debug)
1496 print_LockSet("thread holding", thread_locks[tid]);
1497
1498 if (check_cycle(mutex, thread_locks[tid]))
1499 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1500 else {
1501 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1502
1503 if (debug) {
1504 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1505 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1506 print_LockSet("lockdep", mutex->lockdep);
1507 }
1508 }
1509 break;
1510
1511 case MxUnlocked:
1512 if (debug)
1513 print_LockSet("thread holding", thread_locks[tid]);
1514
1515 if (mutex->state != MxLocked) {
1516 record_mutex_error(tid, mutex,
1517 "unlock non-locked mutex", mutex->location);
1518 }
1519 if (mutex->tid != tid) {
1520 record_mutex_error(tid, mutex,
1521 "unlock someone else's mutex", mutex->location);
1522 }
1523 break;
1524
1525 case MxDead:
1526 break;
1527
1528 default:
1529 break;
1530 }
1531}
1532
1533/* Update a mutex state. Expects most error testing and reporting to
1534 have happened in test_mutex_state(). The assumption is that no
1535 client code is run by thread tid between test and set, either
1536 because it is blocked or test and set are called together
1537 atomically.
1538
1539 Setting state to MxDead is the exception, since that can happen as
1540 a result of any thread freeing memory; in this case set_mutex_state
1541 does all the error reporting as well.
1542*/
njn72718642003-07-24 08:45:32 +00001543static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001544{
1545 static const Bool debug = False;
1546
1547 if (debug)
1548 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1549 tid, mutex, mutex->mutexp, mutex->mutexp,
1550 pp_MutexState(mutex->state), pp_MutexState(state));
1551
1552 if (mutex->state == MxDead) {
1553 /* can't do anything legal to a destroyed mutex */
1554 return;
1555 }
1556
1557 switch(state) {
1558 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001559 if (mutex->state == MxLocked) {
1560 if (mutex->tid != tid)
1561 record_mutex_error(tid, mutex, "take lock held by someone else",
1562 mutex->location);
1563 else
1564 record_mutex_error(tid, mutex, "take lock we already hold",
1565 mutex->location);
1566
njn67993252004-11-22 18:02:32 +00001567 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001568 break;
1569 }
sewardjc26cc252002-10-23 21:58:55 +00001570
njnca82cc02004-11-22 17:18:48 +00001571 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001572
sewardjc26cc252002-10-23 21:58:55 +00001573 mutex->tid = tid;
1574 break;
1575
1576 case MxUnlocked:
1577 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001578 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001579
sewardjdca84112002-11-13 22:29:34 +00001580 if (mutex->state != MxLocked || mutex->tid != tid)
1581 break;
1582
sewardjc26cc252002-10-23 21:58:55 +00001583 mutex->tid = VG_INVALID_THREADID;
1584 break;
1585
sewardjdac0a442002-11-13 22:08:40 +00001586 case MxDead:
1587 if (mutex->state == MxLocked) {
1588 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001589 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001590 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1591 mutex->tid = VG_INVALID_THREADID;
1592
1593 record_mutex_error(tid, mutex,
1594 "free locked mutex", mutex->location);
1595 }
1596 break;
1597
sewardjc26cc252002-10-23 21:58:55 +00001598 default:
1599 break;
1600 }
1601
njnd01fef72005-03-25 23:35:48 +00001602 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001603 mutex->state = state;
1604}
njn25e49d8e72002-09-23 09:36:25 +00001605
1606/*------------------------------------------------------------*/
1607/*--- Setting and checking permissions. ---*/
1608/*------------------------------------------------------------*/
1609
thughes4ad52d02004-06-27 17:37:21 +00001610/* only clean up dead mutexes */
1611static
1612Bool cleanmx(Mutex *mx) {
1613 return mx->state == MxDead;
1614}
1615
njn25e49d8e72002-09-23 09:36:25 +00001616static
nethercote451eae92004-11-02 13:06:32 +00001617void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001618 VgeInitStatus status )
1619{
sewardj1806d7f2002-10-22 05:05:49 +00001620 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001621
1622# if DEBUG_MAKE_ACCESSES
1623 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1624# endif
1625 //PROF_EVENT(30); PPP
1626
1627 if (len == 0)
1628 return;
1629
1630 if (len > 100 * 1000 * 1000)
1631 VG_(message)(Vg_UserMsg,
1632 "Warning: set address range state: large range %d",
1633 len);
1634
sewardjdac0a442002-11-13 22:08:40 +00001635 /* Remove mutexes in recycled memory range from hash */
1636 find_mutex_range(a, a+len, cleanmx);
1637
njn25e49d8e72002-09-23 09:36:25 +00001638 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1639 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1640 * len/4+1 words. This works out which it is by aligning the block and
1641 * seeing if the end byte is in the same word as it is for the unaligned
1642 * block; if not, it's the awkward case. */
njn13bfd852005-06-02 03:52:53 +00001643 end = VG_ROUNDUP(a + len, 4);
1644 a = VG_ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001645
1646 /* Do it ... */
1647 switch (status) {
1648 case Vge_VirginInit:
1649 for ( ; a < end; a += 4) {
1650 //PROF_EVENT(31); PPP
1651 init_virgin_sword(a);
1652 }
1653 break;
1654
1655 case Vge_NonVirginInit:
1656 for ( ; a < end; a += 4) {
1657 //PROF_EVENT(31); PPP
1658 init_nonvirgin_sword(a);
1659 }
1660 break;
1661
1662 case Vge_SegmentInit:
1663 for ( ; a < end; a += 4) {
1664 //PROF_EVENT(31); PPP
1665 init_magically_inited_sword(a);
1666 }
1667 break;
sewardj7f3ad222002-11-13 22:11:53 +00001668
1669 case Vge_Error:
1670 for ( ; a < end; a += 4) {
1671 //PROF_EVENT(31); PPP
1672 init_error_sword(a);
1673 }
1674 break;
njn25e49d8e72002-09-23 09:36:25 +00001675
1676 default:
1677 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001678 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001679 }
njn25e49d8e72002-09-23 09:36:25 +00001680}
1681
1682
nethercote451eae92004-11-02 13:06:32 +00001683static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001684{
1685 //PROF_EVENT(??); PPP
1686 set_address_range_state ( a, len, Vge_SegmentInit );
1687}
1688
nethercote451eae92004-11-02 13:06:32 +00001689static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001690{
1691 //PROF_EVENT(36); PPP
1692 set_address_range_state( a, len, Vge_VirginInit );
1693}
1694
nethercote451eae92004-11-02 13:06:32 +00001695static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001696{
1697 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001698 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001699}
1700
1701
njn25e49d8e72002-09-23 09:36:25 +00001702/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001703static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001704{
1705 UInt i;
1706
1707 //PROF_EVENT(40); PPP
1708 for (i = 0; i < len; i += 4) {
1709 shadow_word sword = *(get_sword_addr ( src+i ));
1710 //PROF_EVENT(41); PPP
1711 set_sword ( dst+i, sword );
1712 }
1713}
1714
1715// SSS: put these somewhere better
njnfbdcba92005-05-09 01:23:49 +00001716static void hg_mem_read (Addr a, SizeT data_size, ThreadId tid);
1717static void hg_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001718
njnadb7a752005-06-11 01:30:57 +00001719__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001720static void hg_mem_help_read_1(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001721__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001722static void hg_mem_help_read_2(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001723__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001724static void hg_mem_help_read_4(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001725__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001726static void hg_mem_help_read_N(Addr a, SizeT size) VG_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001727
njnadb7a752005-06-11 01:30:57 +00001728__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001729static void hg_mem_help_write_1(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001730__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001731static void hg_mem_help_write_2(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001732__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001733static void hg_mem_help_write_4(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001734__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001735static void hg_mem_help_write_N(Addr a, SizeT size) VG_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001736
njnadb7a752005-06-11 01:30:57 +00001737__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001738static void bus_lock(void);
njnadb7a752005-06-11 01:30:57 +00001739__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001740static void bus_unlock(void);
1741
njn25e49d8e72002-09-23 09:36:25 +00001742static
njnfbdcba92005-05-09 01:23:49 +00001743void hg_pre_mem_read(CorePart part, ThreadId tid,
1744 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001745{
njn02bc4b82005-05-15 17:28:26 +00001746 if (tid > 50) { VG_(printf)("pid = %d, s = '%s', part = %d\n", tid, s, part); VG_(tool_panic)("a");}
njnfbdcba92005-05-09 01:23:49 +00001747 hg_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001748}
1749
1750static
njnfbdcba92005-05-09 01:23:49 +00001751void hg_pre_mem_read_asciiz(CorePart part, ThreadId tid,
1752 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001753{
njnfbdcba92005-05-09 01:23:49 +00001754 hg_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001755}
1756
1757static
njnfbdcba92005-05-09 01:23:49 +00001758void hg_pre_mem_write(CorePart part, ThreadId tid,
1759 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001760{
njnfbdcba92005-05-09 01:23:49 +00001761 hg_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001762}
1763
1764
1765
1766static
njnfbdcba92005-05-09 01:23:49 +00001767void hg_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001768{
njn1f3a9092002-10-04 09:22:30 +00001769 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001770 make_segment_readable(a, len);
1771}
1772
1773
1774static
njnfbdcba92005-05-09 01:23:49 +00001775void hg_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001776{
1777 if (is_inited) {
1778 make_readable(a, len);
1779 } else {
1780 make_writable(a, len);
1781 }
1782}
1783
1784static
njnfbdcba92005-05-09 01:23:49 +00001785void hg_set_perms (Addr a, SizeT len,
1786 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001787{
1788 if (rr) make_readable(a, len);
1789 else if (ww) make_writable(a, len);
1790 /* else do nothing */
1791}
1792
sewardjf6374322002-11-13 22:35:55 +00001793static
njnfbdcba92005-05-09 01:23:49 +00001794void hg_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001795{
1796 set_address_range_state(a, len, Vge_NonVirginInit);
1797}
1798
1799static
njnfbdcba92005-05-09 01:23:49 +00001800void hg_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001801{
1802 set_address_range_state(a, len, Vge_VirginInit);
1803}
njn25e49d8e72002-09-23 09:36:25 +00001804
1805/*--------------------------------------------------------------*/
1806/*--- Initialise the memory audit system on program startup. ---*/
1807/*--------------------------------------------------------------*/
1808
1809static
1810void init_shadow_memory(void)
1811{
1812 Int i;
1813
1814 for (i = 0; i < ESEC_MAP_WORDS; i++)
1815 distinguished_secondary_map.swords[i] = virgin_sword;
1816
1817 /* These entries gradually get overwritten as the used address
1818 space expands. */
1819 for (i = 0; i < 65536; i++)
1820 primary_map[i] = &distinguished_secondary_map;
1821}
1822
1823
njn3e884182003-04-15 13:03:23 +00001824/*------------------------------------------------------------*/
1825/*--- malloc() et al replacements ---*/
1826/*------------------------------------------------------------*/
1827
njnb4aee052003-04-15 14:09:58 +00001828static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001829
1830#define N_FREED_CHUNKS 2
1831static Int freechunkptr = 0;
1832static HG_Chunk *freechunks[N_FREED_CHUNKS];
1833
njn3e884182003-04-15 13:03:23 +00001834
1835/* Allocate a user-chunk of size bytes. Also allocate its shadow
1836 block, make the shadow block point at the user block. Put the
1837 shadow chunk on the appropriate list, and set all memory
1838 protections correctly. */
1839
nethercote7ac7f7b2004-11-02 12:36:02 +00001840static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001841{
1842 HG_Chunk* hc;
1843
1844 hc = VG_(malloc)(sizeof(HG_Chunk));
1845 hc->data = p;
1846 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001847 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001848 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001849
1850 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1851}
1852
1853/* Allocate memory and note change in memory available */
1854static __inline__
njn14d01ce2004-11-26 11:30:14 +00001855void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1856 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001857{
1858 Addr p;
1859
njn34ac0272003-09-30 14:20:00 +00001860 if (size < 0) return NULL;
1861
njn3e884182003-04-15 13:03:23 +00001862 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001863 if (!p) {
1864 return NULL;
1865 }
njn34ac0272003-09-30 14:20:00 +00001866 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001867 add_HG_Chunk ( tid, p, size );
njnfbdcba92005-05-09 01:23:49 +00001868 hg_new_mem_heap( p, size, is_zeroed );
njn3e884182003-04-15 13:03:23 +00001869
1870 return (void*)p;
1871}
1872
njn51d827b2005-05-09 01:02:08 +00001873static void* hg_malloc ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001874{
njn14d01ce2004-11-26 11:30:14 +00001875 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001876}
1877
njn51d827b2005-05-09 01:02:08 +00001878static void* hg___builtin_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001879{
njn14d01ce2004-11-26 11:30:14 +00001880 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001881}
1882
njn51d827b2005-05-09 01:02:08 +00001883static void* hg___builtin_vec_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001884{
njn14d01ce2004-11-26 11:30:14 +00001885 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001886}
1887
njn51d827b2005-05-09 01:02:08 +00001888static void* hg_memalign ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001889{
njn14d01ce2004-11-26 11:30:14 +00001890 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001891}
1892
njn51d827b2005-05-09 01:02:08 +00001893static void* hg_calloc ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001894{
njn14d01ce2004-11-26 11:30:14 +00001895 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001896 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001897}
1898
thughes4ad52d02004-06-27 17:37:21 +00001899static ThreadId deadmx_tid;
1900
1901static
1902Bool deadmx(Mutex *mx) {
1903 if (mx->state != MxDead)
1904 set_mutex_state(mx, MxDead, deadmx_tid);
1905
1906 return False;
1907}
1908
njn3e884182003-04-15 13:03:23 +00001909static
njn72718642003-07-24 08:45:32 +00001910void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001911 HG_Chunk** prev_chunks_next_ptr )
1912{
njn72718642003-07-24 08:45:32 +00001913 Addr start = hc->data;
1914 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001915
njn3e884182003-04-15 13:03:23 +00001916 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1917 avoid repeating the hash table lookup. Can't remove until at least
1918 after free and free_mismatch errors are done because they use
1919 describe_addr() which looks for it in malloclist. */
1920 *prev_chunks_next_ptr = hc->next;
1921
1922 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001923 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001924
1925 /* maintain a small window so that the error reporting machinery
1926 knows about this memory */
1927 if (freechunks[freechunkptr] != NULL) {
1928 /* free HG_Chunk */
1929 HG_Chunk* sc1 = freechunks[freechunkptr];
1930 VG_(cli_free) ( (void*)(sc1->data) );
1931 VG_(free) ( sc1 );
1932 }
1933
1934 freechunks[freechunkptr] = hc;
1935
1936 if (++freechunkptr == N_FREED_CHUNKS)
1937 freechunkptr = 0;
1938
1939 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001940 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001941 find_mutex_range(start, end, deadmx);
1942}
1943
1944
1945static __inline__
njn14d01ce2004-11-26 11:30:14 +00001946void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001947{
1948 HG_Chunk* hc;
1949 HG_Chunk** prev_chunks_next_ptr;
1950
nethercote3d6b6112004-11-04 16:39:43 +00001951 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001952 (VgHashNode***)&prev_chunks_next_ptr );
1953 if (hc == NULL) {
1954 return;
1955 }
njn14d01ce2004-11-26 11:30:14 +00001956 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001957}
1958
njn51d827b2005-05-09 01:02:08 +00001959static void hg_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001960{
njn14d01ce2004-11-26 11:30:14 +00001961 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001962}
1963
njn51d827b2005-05-09 01:02:08 +00001964static void hg___builtin_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001965{
njn14d01ce2004-11-26 11:30:14 +00001966 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001967}
1968
njn51d827b2005-05-09 01:02:08 +00001969static void hg___builtin_vec_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001970{
njn14d01ce2004-11-26 11:30:14 +00001971 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001972}
1973
njn51d827b2005-05-09 01:02:08 +00001974static void* hg_realloc ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001975{
1976 HG_Chunk *hc;
1977 HG_Chunk **prev_chunks_next_ptr;
njn3e884182003-04-15 13:03:23 +00001978
1979 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001980 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001981 (VgHashNode***)&prev_chunks_next_ptr );
1982
1983 if (hc == NULL) {
1984 return NULL;
1985 }
1986
1987 if (hc->size == new_size) {
1988 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001989 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001990 return p;
1991
1992 } else if (hc->size > new_size) {
1993 /* new size is smaller */
1994 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001995 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001996 return p;
1997
1998 } else {
1999 /* new size is bigger */
2000 Addr p_new;
2001
2002 /* Get new memory */
2003 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
2004
tom0cd42f02005-10-06 09:00:17 +00002005 if (p_new) {
2006 /* First half kept and copied, second half new */
2007 copy_address_range_state( (Addr)p, p_new, hc->size );
2008 hg_new_mem_heap ( p_new+hc->size, new_size-hc->size,
2009 /*inited*/False );
njn3e884182003-04-15 13:03:23 +00002010
tom0cd42f02005-10-06 09:00:17 +00002011 /* Copy from old to new */
2012 VG_(memcpy)((void *)p_new, p, hc->size);
njn3e884182003-04-15 13:03:23 +00002013
tom0cd42f02005-10-06 09:00:17 +00002014 /* Free old memory */
2015 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00002016
tom0cd42f02005-10-06 09:00:17 +00002017 /* this has to be after die_and_free_mem, otherwise the
2018 former succeeds in shorting out the new block, not the
2019 old, in the case when both are on the same list. */
2020 add_HG_Chunk ( tid, p_new, new_size );
2021 }
njn3e884182003-04-15 13:03:23 +00002022
2023 return (void*)p_new;
2024 }
2025}
2026
njn25e49d8e72002-09-23 09:36:25 +00002027/*--------------------------------------------------------------*/
2028/*--- Machinery to support sanity checking ---*/
2029/*--------------------------------------------------------------*/
2030
njn51d827b2005-05-09 01:02:08 +00002031static Bool hg_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00002032{
jseward9800fd32004-01-04 23:08:04 +00002033 /* nothing useful we can rapidly check */
2034 return True;
njn25e49d8e72002-09-23 09:36:25 +00002035}
2036
njn51d827b2005-05-09 01:02:08 +00002037static Bool hg_expensive_sanity_check(void)
njn25e49d8e72002-09-23 09:36:25 +00002038{
2039 Int i;
2040
2041 /* Make sure nobody changed the distinguished secondary. */
2042 for (i = 0; i < ESEC_MAP_WORDS; i++)
2043 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2044 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2045 return False;
2046
2047 return True;
2048}
2049
2050
2051/*--------------------------------------------------------------*/
2052/*--- Instrumentation ---*/
2053/*--------------------------------------------------------------*/
2054
sewardjf6374322002-11-13 22:35:55 +00002055static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2056
njn14d01ce2004-11-26 11:30:14 +00002057#if 0
njn25e49d8e72002-09-23 09:36:25 +00002058/* Create and return an instrumented version of cb_in. Free cb_in
2059 before returning. */
njn26f02512004-11-22 18:33:15 +00002060UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002061{
2062 UCodeBlock* cb;
2063 Int i;
2064 UInstr* u_in;
2065 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002066 Int ntemps;
2067 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002068 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002069
njn810086f2002-11-14 12:42:47 +00002070 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002071
sewardjf6374322002-11-13 22:35:55 +00002072 /* stackref[] is used for super-simple value tracking to keep note
2073 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002074 the stack pointer or frame pointer, and is therefore likely
2075 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002076 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002077 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2078 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2079
njn810086f2002-11-14 12:42:47 +00002080 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2081 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002082
njn25e49d8e72002-09-23 09:36:25 +00002083 switch (u_in->opcode) {
2084
2085 case NOP: case CALLM_S: case CALLM_E:
2086 break;
sewardjf6374322002-11-13 22:35:55 +00002087
sewardj7a5ebcf2002-11-13 22:42:13 +00002088 case LOCK:
2089 locked = True;
2090 uInstr0(cb, CCALL, 0);
2091 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2092 break;
2093
2094 case JMP: case INCEIP:
2095 if (locked) {
2096 uInstr0(cb, CCALL, 0);
2097 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2098 }
2099 locked = False;
2100 VG_(copy_UInstr)(cb, u_in);
2101 break;
2102
sewardjf6374322002-11-13 22:35:55 +00002103 case GET:
njnca82cc02004-11-22 17:18:48 +00002104 tl_assert(u_in->tag1 == ArchReg);
2105 tl_assert(u_in->tag2 == TempReg);
2106 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002107
2108 stackref[u_in->val2] = (u_in->size == 4 &&
njnaf839f52005-06-23 03:27:57 +00002109 (u_in->val1 == VG_R_STACK_PTR ||
2110 u_in->val1 == VG_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002111 VG_(copy_UInstr)(cb, u_in);
2112 break;
2113
2114 case MOV:
2115 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002116 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002117 stackref[u_in->val2] = stackref[u_in->val1];
2118 }
2119 VG_(copy_UInstr)(cb, u_in);
2120 break;
2121
2122 case LEA1:
2123 case ADD: case SUB:
2124 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002125 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002126 stackref[u_in->val2] |= stackref[u_in->val1];
2127 }
2128 VG_(copy_UInstr)(cb, u_in);
2129 break;
njn25e49d8e72002-09-23 09:36:25 +00002130
sewardja5b3aec2002-10-22 05:09:36 +00002131 case LOAD: {
2132 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002133 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2134 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002135
2136 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2137 nonstk_ld++;
2138
2139 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002140 case 1: help = hg_mem_help_read_1; break;
2141 case 2: help = hg_mem_help_read_2; break;
2142 case 4: help = hg_mem_help_read_4; break;
sewardjf6374322002-11-13 22:35:55 +00002143 default:
njn67993252004-11-22 18:02:32 +00002144 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002145 }
jsgfcb1d1c02003-10-14 21:55:10 +00002146
2147 /* XXX all registers should be flushed to baseblock
2148 here */
sewardjf6374322002-11-13 22:35:55 +00002149 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2150 uCCall(cb, (Addr)help, 1, 1, False);
2151 } else
2152 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002153
sewardja5b3aec2002-10-22 05:09:36 +00002154 VG_(copy_UInstr)(cb, u_in);
2155 t_size = INVALID_TEMPREG;
2156 break;
2157 }
2158
fitzhardinge111c6072004-03-09 02:45:07 +00002159 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002160 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002161 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002162 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002163
fitzhardinge111c6072004-03-09 02:45:07 +00002164 t_size = newTemp(cb);
2165 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2166 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002167
fitzhardinge111c6072004-03-09 02:45:07 +00002168 /* XXX all registers should be flushed to baseblock
2169 here */
2170 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002171 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002172
2173 VG_(copy_UInstr)(cb, u_in);
2174 t_size = INVALID_TEMPREG;
2175 break;
sewardja5b3aec2002-10-22 05:09:36 +00002176 }
2177
thughes96b466a2004-03-15 16:43:58 +00002178 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002179 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002180
2181 t_size = newTemp(cb);
2182 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2183 uLiteral(cb, (UInt)u_in->size);
2184
2185 /* XXX all registers should be flushed to baseblock
2186 here */
2187 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002188 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
thughes96b466a2004-03-15 16:43:58 +00002189
2190 VG_(copy_UInstr)(cb, u_in);
2191 t_size = INVALID_TEMPREG;
2192 break;
2193 }
2194
fitzhardinge111c6072004-03-09 02:45:07 +00002195 case SSE2a_MemRd:
2196 case SSE2a1_MemRd:
2197 case SSE3a_MemRd:
2198 case SSE3a1_MemRd:
2199 case SSE3ag_MemRd_RegWr: {
2200 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2201
njnca82cc02004-11-22 17:18:48 +00002202 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002203
2204 t_size = newTemp(cb);
2205 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2206 uLiteral(cb, (UInt)u_in->size);
2207
2208 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002209 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002210
2211 VG_(copy_UInstr)(cb, u_in);
2212 t_size = INVALID_TEMPREG;
2213 break;
2214 }
2215
sewardja5b3aec2002-10-22 05:09:36 +00002216 case STORE: {
2217 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002218 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2219 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002220
sewardjf6374322002-11-13 22:35:55 +00002221 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2222 nonstk_st++;
2223
2224 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002225 case 1: help = hg_mem_help_write_1; break;
2226 case 2: help = hg_mem_help_write_2; break;
2227 case 4: help = hg_mem_help_write_4; break;
sewardjf6374322002-11-13 22:35:55 +00002228 default:
njn67993252004-11-22 18:02:32 +00002229 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002230 }
2231
jsgfcb1d1c02003-10-14 21:55:10 +00002232 /* XXX all registers should be flushed to baseblock
2233 here */
sewardjf6374322002-11-13 22:35:55 +00002234 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2235 uCCall(cb, (Addr)help, 2, 2, False);
2236 } else
2237 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002238
2239 VG_(copy_UInstr)(cb, u_in);
2240 t_size = INVALID_TEMPREG;
2241 break;
2242 }
2243
fitzhardinge111c6072004-03-09 02:45:07 +00002244 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002245 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002246 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002247 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002248
2249 t_size = newTemp(cb);
2250 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2251 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002252 /* XXX all registers should be flushed to baseblock
2253 here */
sewardja5b3aec2002-10-22 05:09:36 +00002254 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002255 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
sewardja5b3aec2002-10-22 05:09:36 +00002256
2257 VG_(copy_UInstr)(cb, u_in);
2258 t_size = INVALID_TEMPREG;
2259 break;
2260 }
njn25e49d8e72002-09-23 09:36:25 +00002261
fitzhardinge111c6072004-03-09 02:45:07 +00002262 case SSE2a_MemWr:
2263 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002264 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002265 512 == u_in->size);
2266
2267 t_size = newTemp(cb);
2268 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2269 uLiteral(cb, (UInt)u_in->size);
2270 /* XXX all registers should be flushed to baseblock
2271 here */
2272 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002273 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002274
2275 VG_(copy_UInstr)(cb, u_in);
2276 t_size = INVALID_TEMPREG;
2277 break;
2278 }
sewardj3d7c9c82003-03-26 21:08:13 +00002279
njn25e49d8e72002-09-23 09:36:25 +00002280 default:
sewardjf6374322002-11-13 22:35:55 +00002281 /* conservative tromping */
2282 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2283 stackref[u_in->val1] = False;
2284 if (u_in->tag2 == TempReg)
2285 stackref[u_in->val2] = False;
2286 if (u_in->tag3 == TempReg)
2287 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002288 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002289 break;
2290 }
2291 }
2292
sewardjf6374322002-11-13 22:35:55 +00002293 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002294 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002295 return cb;
2296}
njn14d01ce2004-11-26 11:30:14 +00002297#endif
sewardj4ba057c2005-10-18 12:04:18 +00002298static
sewardj461df9c2006-01-17 02:06:39 +00002299IRBB* hg_instrument ( VgCallbackClosure* closure,
2300 IRBB* bb,
2301 VexGuestLayout* layout,
2302 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +00002303 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002304{
njn5db32122005-08-12 15:23:57 +00002305 tl_assert(0); // Need to convert to Vex
njn14d01ce2004-11-26 11:30:14 +00002306}
njn25e49d8e72002-09-23 09:36:25 +00002307
2308/*--------------------------------------------------------------------*/
2309/*--- Error and suppression handling ---*/
2310/*--------------------------------------------------------------------*/
2311
2312typedef
2313 enum {
2314 /* Possible data race */
njnfbdcba92005-05-09 01:23:49 +00002315 RaceSupp
njn25e49d8e72002-09-23 09:36:25 +00002316 }
njnfbdcba92005-05-09 01:23:49 +00002317 RaceSuppKind;
njn25e49d8e72002-09-23 09:36:25 +00002318
2319/* What kind of error it is. */
2320typedef
2321 enum {
njnfbdcba92005-05-09 01:23:49 +00002322 RaceErr, /* data-race */
sewardj16748af2002-10-22 04:55:54 +00002323 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002324 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002325 }
njnfbdcba92005-05-09 01:23:49 +00002326 RaceErrorKind;
njn25e49d8e72002-09-23 09:36:25 +00002327
sewardj16748af2002-10-22 04:55:54 +00002328/* The classification of a faulting address. */
2329typedef
2330 enum { Undescribed, /* as-yet unclassified */
2331 Stack,
2332 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002333 Mallocd,
2334 Freed,
sewardj16748af2002-10-22 04:55:54 +00002335 Segment
2336 }
2337 AddrKind;
2338/* Records info about a faulting address. */
2339typedef
2340 struct {
2341 /* ALL */
2342 AddrKind akind;
2343 /* Freed, Mallocd */
2344 Int blksize;
2345 /* Freed, Mallocd */
2346 Int rwoffset;
2347 /* Freed, Mallocd */
2348 ExeContext* lastchange;
2349 ThreadId lasttid;
2350 /* Stack */
2351 ThreadId stack_tid;
2352 /* Segment */
2353 const Char* filename;
2354 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002355 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002356 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002357 /* symbolic address description */
2358 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002359 }
2360 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002361
sewardj16748af2002-10-22 04:55:54 +00002362/* What kind of memory access is involved in the error? */
2363typedef
2364 enum { ReadAxs, WriteAxs, ExecAxs }
2365 AxsKind;
2366
2367/* Extra context for memory errors */
2368typedef
2369 struct {
2370 AxsKind axskind;
2371 Int size;
2372 AddrInfo addrinfo;
2373 Bool isWrite;
2374 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002375 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002376 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002377 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002378 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002379 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002380 const LockSet *held_lockset;
2381 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002382 }
2383 HelgrindError;
2384
2385static __inline__
2386void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002387{
sewardj16748af2002-10-22 04:55:54 +00002388 ai->akind = Unknown;
2389 ai->blksize = 0;
2390 ai->rwoffset = 0;
2391 ai->lastchange = NULL;
2392 ai->lasttid = VG_INVALID_THREADID;
2393 ai->filename = NULL;
2394 ai->section = "???";
2395 ai->stack_tid = VG_INVALID_THREADID;
2396 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002397 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002398}
2399
sewardj16748af2002-10-22 04:55:54 +00002400static __inline__
2401void clear_HelgrindError ( HelgrindError* err_extra )
2402{
2403 err_extra->axskind = ReadAxs;
2404 err_extra->size = 0;
2405 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002406 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002407 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002408 err_extra->prev_lockset = 0;
2409 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002410 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002411 clear_AddrInfo ( &err_extra->addrinfo );
2412 err_extra->isWrite = False;
2413}
2414
2415
2416
2417/* Describe an address as best you can, for error messages,
2418 putting the result in ai. */
2419
thughes4ad52d02004-06-27 17:37:21 +00002420/* Callback for searching malloc'd and free'd lists */
2421static Bool addr_is_in_block(VgHashNode *node, void *ap)
2422{
2423 HG_Chunk* hc2 = (HG_Chunk*)node;
2424 Addr a = *(Addr *)ap;
2425
2426 return (hc2->data <= a && a < hc2->data + hc2->size);
2427}
2428
sewardj16748af2002-10-22 04:55:54 +00002429static void describe_addr ( Addr a, AddrInfo* ai )
2430{
njn3e884182003-04-15 13:03:23 +00002431 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002432 Int i;
sewardj16748af2002-10-22 04:55:54 +00002433
sewardj16748af2002-10-22 04:55:54 +00002434 /* Search for it in segments */
2435 {
njn36ef6ba2005-05-14 18:42:26 +00002436 const SegInfo *si;
sewardj16748af2002-10-22 04:55:54 +00002437
njn36ef6ba2005-05-14 18:42:26 +00002438 for (si = VG_(next_seginfo)(NULL);
2439 si != NULL;
2440 si = VG_(next_seginfo)(si))
2441 {
njnd9e5fd72005-06-25 19:51:33 +00002442 Addr base = VG_(seginfo_start)(si);
2443 SizeT size = VG_(seginfo_size)(si);
2444 const UChar *filename = VG_(seginfo_filename)(si);
sewardj16748af2002-10-22 04:55:54 +00002445
2446 if (a >= base && a < base+size) {
2447 ai->akind = Segment;
2448 ai->blksize = size;
2449 ai->rwoffset = a - base;
2450 ai->filename = filename;
2451
njnd9e5fd72005-06-25 19:51:33 +00002452 switch(VG_(seginfo_sect_kind)(a)) {
sewardj16748af2002-10-22 04:55:54 +00002453 case Vg_SectText: ai->section = "text"; break;
2454 case Vg_SectData: ai->section = "data"; break;
2455 case Vg_SectBSS: ai->section = "BSS"; break;
2456 case Vg_SectGOT: ai->section = "GOT"; break;
2457 case Vg_SectPLT: ai->section = "PLT"; break;
2458 case Vg_SectUnknown:
2459 default:
2460 ai->section = "???"; break;
2461 }
2462
2463 return;
2464 }
2465 }
2466 }
2467
2468 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002469 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002470 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002471 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002472 ai->blksize = hc->size;
2473 ai->rwoffset = (Int)a - (Int)(hc->data);
2474 ai->lastchange = hc->where;
2475 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002476 return;
2477 }
sewardjdac0a442002-11-13 22:08:40 +00002478
2479 /* Look in recently freed memory */
2480 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002481 hc = freechunks[i];
2482 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002483 continue;
2484
njn3e884182003-04-15 13:03:23 +00002485 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002486 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002487 ai->blksize = hc->size;
2488 ai->rwoffset = a - hc->data;
2489 ai->lastchange = hc->where;
2490 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002491 return;
2492 }
2493 }
2494
sewardj16748af2002-10-22 04:55:54 +00002495 /* Clueless ... */
2496 ai->akind = Unknown;
2497 return;
2498}
2499
2500
njn7e614812003-04-21 22:04:03 +00002501/* Updates the copy with address info if necessary. */
njn51d827b2005-05-09 01:02:08 +00002502static UInt hg_update_extra(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002503{
njn7e614812003-04-21 22:04:03 +00002504 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002505
njn7e614812003-04-21 22:04:03 +00002506 extra = (HelgrindError*)VG_(get_error_extra)(err);
2507 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2508 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2509 }
2510 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002511}
2512
njnfbdcba92005-05-09 01:23:49 +00002513static void record_race_error ( ThreadId tid, Addr a, Bool is_write,
2514 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002515{
sewardjc4a810d2002-11-13 22:25:51 +00002516 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002517 HelgrindError err_extra;
2518
njnfbdcba92005-05-09 01:23:49 +00002519 n_hg_warnings++;
sewardjff2c9232002-11-13 21:44:39 +00002520
sewardj16748af2002-10-22 04:55:54 +00002521 clear_HelgrindError(&err_extra);
2522 err_extra.isWrite = is_write;
2523 err_extra.addrinfo.akind = Undescribed;
2524 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002525 if (clo_execontext)
2526 err_extra.lasttouched = getExeContext(a);
sewardjeadcd862006-04-04 15:12:44 +00002527 /* JRS 4 Apr 06: VG_(describe_addr) disappeared from m_debuginfo,
2528 at least for the time being. */
2529 err_extra.addrinfo.expr = "???"; /* VG_(describe_addr)(tid, a); */
jsgfcb1d1c02003-10-14 21:55:10 +00002530
njnfbdcba92005-05-09 01:23:49 +00002531 VG_(maybe_record_error)( tid, RaceErr, a,
sewardj16748af2002-10-22 04:55:54 +00002532 (is_write ? "writing" : "reading"),
2533 &err_extra);
2534
sewardjc4a810d2002-11-13 22:25:51 +00002535 sw = get_sword_addr(a);
2536 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2537 ThreadLifeSeg *tls = unpackTLS(sw->other);
2538 tls->refcount--;
2539 }
2540
sewardj7f3ad222002-11-13 22:11:53 +00002541 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002542}
2543
sewardj39a4d842002-11-13 22:14:30 +00002544static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002545 Char *str, ExeContext *ec)
2546{
2547 HelgrindError err_extra;
2548
2549 clear_HelgrindError(&err_extra);
2550 err_extra.addrinfo.akind = Undescribed;
2551 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002552 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002553 err_extra.lasttid = tid;
2554
njn72718642003-07-24 08:45:32 +00002555 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002556 (Addr)mutex->mutexp, str, &err_extra);
2557}
njn25e49d8e72002-09-23 09:36:25 +00002558
sewardj39a4d842002-11-13 22:14:30 +00002559static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002560 const LockSet *lockset_holding,
2561 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002562{
2563 HelgrindError err_extra;
2564
2565 n_lockorder_warnings++;
2566
2567 clear_HelgrindError(&err_extra);
2568 err_extra.addrinfo.akind = Undescribed;
2569 err_extra.mutex = mutex;
2570
sewardjc808ef52002-11-13 22:43:26 +00002571 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002572 err_extra.held_lockset = lockset_holding;
2573 err_extra.prev_lockset = lockset_prev;
2574
njn72718642003-07-24 08:45:32 +00002575 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002576}
2577
njn51d827b2005-05-09 01:02:08 +00002578static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002579{
njn810086f2002-11-14 12:42:47 +00002580 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002581
njnca82cc02004-11-22 17:18:48 +00002582 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002583
2584 switch (VG_(get_error_kind)(e1)) {
njnfbdcba92005-05-09 01:23:49 +00002585 case RaceErr:
njn810086f2002-11-14 12:42:47 +00002586 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002587
2588 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002589 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002590 }
2591
njn810086f2002-11-14 12:42:47 +00002592 e1s = VG_(get_error_string)(e1);
2593 e2s = VG_(get_error_string)(e2);
2594 if (e1s != e2s) return False;
2595 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002596 return True;
2597}
2598
sewardj16748af2002-10-22 04:55:54 +00002599static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002600{
jsgfcb1d1c02003-10-14 21:55:10 +00002601 if (ai->expr != NULL)
2602 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002603 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002604
sewardj16748af2002-10-22 04:55:54 +00002605 switch (ai->akind) {
2606 case Stack:
2607 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002608 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002609 a, ai->stack_tid);
2610 break;
2611 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002612 if (ai->expr != NULL)
2613 break;
2614
nethercote3b390c72003-11-13 17:53:43 +00002615 /* maybe_gcc is never set to True! This is a hangover from code
2616 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002617 if (ai->maybe_gcc) {
2618 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002619 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002620 a);
2621 VG_(message)(Vg_UserMsg,
2622 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2623 } else {
2624 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002625 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002626 }
2627 break;
2628 case Segment:
2629 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002630 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002631 a, ai->section, ai->filename);
2632 break;
sewardjdac0a442002-11-13 22:08:40 +00002633 case Mallocd:
2634 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002635 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002636 UChar* relative;
2637 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002638 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002639 relative = "before";
2640 } else if (ai->rwoffset >= ai->blksize) {
2641 delta = ai->rwoffset - ai->blksize;
2642 relative = "after";
2643 } else {
2644 delta = ai->rwoffset;
2645 relative = "inside";
2646 }
2647 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002648 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2649 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002650 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002651 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002652 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002653
sewardj16748af2002-10-22 04:55:54 +00002654 VG_(pp_ExeContext)(ai->lastchange);
2655 break;
2656 }
2657 default:
njn67993252004-11-22 18:02:32 +00002658 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002659 }
njn25e49d8e72002-09-23 09:36:25 +00002660}
2661
sewardj4bffb232002-11-13 21:46:34 +00002662static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002663{
sewardjff2c9232002-11-13 21:44:39 +00002664 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002665 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002666
sewardj4bffb232002-11-13 21:46:34 +00002667 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2668 lockset->setsize * 120 +
2669 1);
sewardjff2c9232002-11-13 21:44:39 +00002670
2671 cp = buf;
2672 if (prefix)
2673 cp += VG_(sprintf)(cp, "%s", prefix);
2674
sewardj4bffb232002-11-13 21:46:34 +00002675 for(i = 0; i < lockset->setsize; i++)
2676 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2677 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002678
sewardj4bffb232002-11-13 21:46:34 +00002679 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002680 cp[-2] = '\0';
2681 else
2682 *cp = '\0';
2683
2684 return buf;
2685}
njn25e49d8e72002-09-23 09:36:25 +00002686
njn51d827b2005-05-09 01:02:08 +00002687static void hg_pp_Error ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002688{
njn810086f2002-11-14 12:42:47 +00002689 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002690 Char buf[100];
2691 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002692 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002693
2694 *msg = '\0';
2695
njn810086f2002-11-14 12:42:47 +00002696 switch(VG_(get_error_kind)(err)) {
njnfbdcba92005-05-09 01:23:49 +00002697 case RaceErr: {
njn810086f2002-11-14 12:42:47 +00002698 Addr err_addr = VG_(get_error_address)(err);
2699
sewardj16748af2002-10-22 04:55:54 +00002700 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002701 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002702 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002703 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002704
2705 switch(extra->prevstate.state) {
2706 case Vge_Virgin:
2707 /* shouldn't be possible to go directly from virgin -> error */
2708 VG_(sprintf)(buf, "virgin!?");
2709 break;
2710
sewardjc4a810d2002-11-13 22:25:51 +00002711 case Vge_Excl: {
2712 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2713
njnca82cc02004-11-22 17:18:48 +00002714 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002715 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002716 break;
sewardjc4a810d2002-11-13 22:25:51 +00002717 }
sewardj16748af2002-10-22 04:55:54 +00002718
2719 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002720 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002721 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002722
2723 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002724 VG_(sprintf)(buf, "shared %s, no locks",
2725 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2726 break;
2727 }
2728
sewardjff2c9232002-11-13 21:44:39 +00002729 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2730 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002731 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002732
sewardj16748af2002-10-22 04:55:54 +00002733 break;
2734 }
sewardj16748af2002-10-22 04:55:54 +00002735
sewardj499e3de2002-11-13 22:22:25 +00002736 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002737 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002738
sewardj72baa7a2002-12-09 23:32:58 +00002739 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002740 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002741 Char file[100];
2742 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002743 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002744
nethercote3b390c72003-11-13 17:53:43 +00002745 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002746 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002747 pp_state(extra->lasttouched.state),
2748 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002749
sewardj7cee6f92005-06-13 17:39:06 +00002750 if (VG_(get_filename_linenum)(ip, file, sizeof(file),
2751 NULL, 0, NULL, &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002752 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002753 ip, ip, file, line);
2754 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002755 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002756 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002757 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002758 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002759 }
sewardj72baa7a2002-12-09 23:32:58 +00002760 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002761 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002762 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002763 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002764 pp_state(extra->lasttouched.state),
2765 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002766 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002767 }
sewardj16748af2002-10-22 04:55:54 +00002768 break;
njn810086f2002-11-14 12:42:47 +00002769 }
sewardj16748af2002-10-22 04:55:54 +00002770
2771 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002772 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002773 VG_(get_error_address)(err),
2774 VG_(get_error_address)(err),
2775 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002776 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002777 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002778 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002779 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002780 }
njn810086f2002-11-14 12:42:47 +00002781 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002782 break;
sewardjff2c9232002-11-13 21:44:39 +00002783
2784 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002785 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002786 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002787 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002788
2789 msg = lockset_str(NULL, heldset);
2790
2791 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002792 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002793 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002794 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2795
sewardj4bffb232002-11-13 21:46:34 +00002796 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002797 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002798
sewardj542494b2002-11-13 22:46:13 +00002799 /* needs to be a recursive search+display */
2800 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002801 continue;
2802
nethercote3b390c72003-11-13 17:53:43 +00002803 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002804 lsmx->mutexp, lsmx->mutexp);
2805 VG_(pp_ExeContext)(lsmx->location);
2806 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002807 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002808 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002809 }
2810
2811 break;
sewardj16748af2002-10-22 04:55:54 +00002812 }
sewardjff2c9232002-11-13 21:44:39 +00002813 }
2814
2815 if (msg != buf)
2816 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002817}
2818
2819
njn51d827b2005-05-09 01:02:08 +00002820static Bool hg_recognised_suppression ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002821{
2822 if (0 == VG_(strcmp)(name, "Eraser")) {
njnfbdcba92005-05-09 01:23:49 +00002823 VG_(set_supp_kind)(su, RaceSupp);
njn25e49d8e72002-09-23 09:36:25 +00002824 return True;
2825 } else {
2826 return False;
2827 }
2828}
2829
2830
njn51d827b2005-05-09 01:02:08 +00002831static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002832{
2833 /* do nothing -- no extra suppression info present. Return True to
2834 indicate nothing bad happened. */
2835 return True;
2836}
2837
2838
njn51d827b2005-05-09 01:02:08 +00002839static Bool hg_error_matches_suppression(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002840{
njnfbdcba92005-05-09 01:23:49 +00002841 tl_assert(VG_(get_supp_kind)(su) == RaceSupp);
nethercote64366b42003-12-01 13:11:47 +00002842
njnfbdcba92005-05-09 01:23:49 +00002843 return (VG_(get_error_kind)(err) == RaceErr);
njn25e49d8e72002-09-23 09:36:25 +00002844}
2845
njn51d827b2005-05-09 01:02:08 +00002846static Char* hg_get_error_name ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002847{
njnfbdcba92005-05-09 01:23:49 +00002848 if (RaceErr == VG_(get_error_kind)(err)) {
2849 return "Eraser"; // old name, required for backwards compatibility
njn43c799e2003-04-08 00:08:52 +00002850 } else {
2851 return NULL; /* Other errors types can't be suppressed */
2852 }
2853}
2854
njn51d827b2005-05-09 01:02:08 +00002855static void hg_print_extra_suppression_info ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002856{
2857 /* Do nothing */
2858}
njn25e49d8e72002-09-23 09:36:25 +00002859
njnfbdcba92005-05-09 01:23:49 +00002860static void hg_pre_mutex_lock(ThreadId tid, void* void_mutex)
sewardjdca84112002-11-13 22:29:34 +00002861{
2862 Mutex *mutex = get_mutex((Addr)void_mutex);
2863
njn72718642003-07-24 08:45:32 +00002864 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002865}
2866
njnfbdcba92005-05-09 01:23:49 +00002867static void hg_post_mutex_lock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002868{
sewardj4bffb232002-11-13 21:46:34 +00002869 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002870 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002871 const LockSet* ls;
2872
njn72718642003-07-24 08:45:32 +00002873 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002874
njn25e49d8e72002-09-23 09:36:25 +00002875# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002876 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002877# endif
2878
njn25e49d8e72002-09-23 09:36:25 +00002879 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2880# if LOCKSET_SANITY > 1
njnfbdcba92005-05-09 01:23:49 +00002881 sanity_check_locksets("hg_post_mutex_lock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002882# endif
2883
sewardj4bffb232002-11-13 21:46:34 +00002884 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002885
sewardj4bffb232002-11-13 21:46:34 +00002886 if (ls == NULL) {
2887 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2888 insert_LockSet(newset);
2889 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002890 }
sewardj4bffb232002-11-13 21:46:34 +00002891 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002892
sewardj4bffb232002-11-13 21:46:34 +00002893 if (debug || DEBUG_LOCKS)
2894 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002895
sewardj4bffb232002-11-13 21:46:34 +00002896 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002897 sanity_check_locksets("hg_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002898}
2899
2900
njnfbdcba92005-05-09 01:23:49 +00002901static void hg_post_mutex_unlock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002902{
sewardjc26cc252002-10-23 21:58:55 +00002903 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002904 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002905 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002906 const LockSet *ls;
2907
njn72718642003-07-24 08:45:32 +00002908 test_mutex_state(mutex, MxUnlocked, tid);
2909 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002910
sewardjdac0a442002-11-13 22:08:40 +00002911 if (!ismember(thread_locks[tid], mutex))
2912 return;
2913
sewardjc26cc252002-10-23 21:58:55 +00002914 if (debug || DEBUG_LOCKS)
2915 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002916
sewardjc26cc252002-10-23 21:58:55 +00002917 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002918 sanity_check_locksets("hg_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002919
sewardj4bffb232002-11-13 21:46:34 +00002920 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002921
sewardj4bffb232002-11-13 21:46:34 +00002922 if (ls == NULL) {
2923 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2924 insert_LockSet(newset);
2925 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002926 }
2927
2928 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002929 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002930 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002931 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002932
sewardj4bffb232002-11-13 21:46:34 +00002933 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002934
sewardjc26cc252002-10-23 21:58:55 +00002935 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002936 sanity_check_locksets("hg_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002937}
2938
2939
2940/* ---------------------------------------------------------------------
2941 Checking memory reads and writes
2942 ------------------------------------------------------------------ */
2943
2944/* Behaviour on reads and writes:
2945 *
2946 * VIR EXCL SHAR SH_MOD
2947 * ----------------------------------------------------------------
2948 * rd/wr, 1st thread | - EXCL - -
2949 * rd, new thread | - SHAR - -
2950 * wr, new thread | - SH_MOD - -
2951 * rd | error! - SHAR SH_MOD
2952 * wr | EXCL - SH_MOD SH_MOD
2953 * ----------------------------------------------------------------
2954 */
2955
sewardj8fac99a2002-11-13 22:31:26 +00002956static inline
njn25e49d8e72002-09-23 09:36:25 +00002957void dump_around_a(Addr a)
2958{
2959 UInt i;
2960 shadow_word* sword;
2961 VG_(printf)("NEARBY:\n");
2962 for (i = a - 12; i <= a + 12; i += 4) {
2963 sword = get_sword_addr(i);
2964 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2965 }
2966}
njn25e49d8e72002-09-23 09:36:25 +00002967
2968#if DEBUG_ACCESSES
2969 #define DEBUG_STATE(args...) \
2970 VG_(printf)("(%u) ", size), \
2971 VG_(printf)(args)
2972#else
2973 #define DEBUG_STATE(args...)
2974#endif
2975
njnfbdcba92005-05-09 01:23:49 +00002976static void hg_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002977{
sewardj72baa7a2002-12-09 23:32:58 +00002978 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002979 shadow_word prevstate;
2980 ThreadLifeSeg *tls;
2981 const LockSet *ls;
2982 Bool statechange = False;
2983
2984 static const void *const states[4] = {
2985 [Vge_Virgin] &&st_virgin,
2986 [Vge_Excl] &&st_excl,
2987 [Vge_Shar] &&st_shar,
2988 [Vge_SharMod] &&st_sharmod,
2989 };
2990
2991 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002992 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002993
2994 sword = get_sword_addr(a);
2995 if (sword == SEC_MAP_ACCESS) {
2996 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2997 return;
2998 }
2999
3000 prevstate = *sword;
3001
3002 goto *states[sword->state];
3003
3004 /* This looks like reading of unitialised memory, may be legit. Eg.
3005 * calloc() zeroes its values, so untouched memory may actually be
3006 * initialised. Leave that stuff to Valgrind. */
3007 st_virgin:
3008 if (TID_INDICATING_NONVIRGIN == sword->other) {
3009 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
3010 if (DEBUG_VIRGIN_READS)
3011 dump_around_a(a);
3012 } else {
3013 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
3014 }
3015 statechange = True;
3016 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
3017 tls->refcount++;
3018 goto done;
3019
3020 st_excl: {
3021 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3022
3023 if (tls == sw_tls) {
3024 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
3025 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3026 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
3027 } else if (tlsIsDisjoint(tls, sw_tls)) {
3028 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3029 statechange = True;
3030 sword->other = packTLS(tls);
3031 sw_tls->refcount--;
3032 tls->refcount++;
3033 } else {
3034 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3035 sw_tls->refcount--;
3036 statechange = True;
3037 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3038
3039 if (DEBUG_MEM_LOCKSET_CHANGES)
3040 print_LockSet("excl read locks", unpackLockSet(sword->other));
3041 }
3042 goto done;
3043 }
3044
3045 st_shar:
3046 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3047 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3048 thread_locks[tid]));
3049 statechange = sword->other != prevstate.other;
3050 goto done;
3051
3052 st_sharmod:
3053 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3054 ls = intersect(unpackLockSet(sword->other),
3055 thread_locks[tid]);
3056 sword->other = packLockSet(ls);
3057
3058 statechange = sword->other != prevstate.other;
3059
3060 if (isempty(ls)) {
njnfbdcba92005-05-09 01:23:49 +00003061 record_race_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003062 }
3063 goto done;
3064
3065 done:
3066 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003067 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003068
3069 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003070 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003071 else
njnd01fef72005-03-25 23:35:48 +00003072 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003073 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003074 }
3075}
njn25e49d8e72002-09-23 09:36:25 +00003076
njnfbdcba92005-05-09 01:23:49 +00003077static void hg_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003078{
njn72718642003-07-24 08:45:32 +00003079 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003080
njn13bfd852005-06-02 03:52:53 +00003081 end = VG_ROUNDUP(a+size, 4);
3082 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003083
sewardj18cd4a52002-11-13 22:37:41 +00003084 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003085 hg_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003086}
3087
njnfbdcba92005-05-09 01:23:49 +00003088static void hg_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003089{
3090 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003091 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003092 shadow_word prevstate;
3093 Bool statechange = False;
3094 static const void *const states[4] = {
3095 [Vge_Virgin] &&st_virgin,
3096 [Vge_Excl] &&st_excl,
3097 [Vge_Shar] &&st_shar,
3098 [Vge_SharMod] &&st_sharmod,
3099 };
3100
sewardjc4a810d2002-11-13 22:25:51 +00003101 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003102 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003103
sewardj18cd4a52002-11-13 22:37:41 +00003104 sword = get_sword_addr(a);
3105 if (sword == SEC_MAP_ACCESS) {
3106 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3107 return;
3108 }
njn25e49d8e72002-09-23 09:36:25 +00003109
sewardj18cd4a52002-11-13 22:37:41 +00003110 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003111
sewardj18cd4a52002-11-13 22:37:41 +00003112 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003113
sewardj18cd4a52002-11-13 22:37:41 +00003114 st_virgin:
3115 if (TID_INDICATING_NONVIRGIN == sword->other)
3116 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3117 else
3118 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3119 statechange = True;
3120 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3121 tls->refcount++;
3122 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003123
sewardj18cd4a52002-11-13 22:37:41 +00003124 st_excl: {
3125 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3126
3127 if (tls == sw_tls) {
3128 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3129 goto done;
3130 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3131 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3132 goto done;
3133 } else if (tlsIsDisjoint(tls, sw_tls)) {
3134 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3135 sword->other = packTLS(tls);
3136 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003137 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003138 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003139 } else {
3140 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3141 statechange = True;
3142 sw_tls->refcount--;
3143 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3144 if(DEBUG_MEM_LOCKSET_CHANGES)
3145 print_LockSet("excl write locks", unpackLockSet(sword->other));
3146 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003147 }
sewardj18cd4a52002-11-13 22:37:41 +00003148 }
njn25e49d8e72002-09-23 09:36:25 +00003149
sewardj18cd4a52002-11-13 22:37:41 +00003150 st_shar:
3151 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3152 sword->state = Vge_SharMod;
3153 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3154 thread_locks[tid]));
3155 statechange = True;
3156 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003157
sewardj18cd4a52002-11-13 22:37:41 +00003158 st_sharmod:
3159 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3160 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3161 thread_locks[tid]));
3162 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003163
sewardj18cd4a52002-11-13 22:37:41 +00003164 SHARED_MODIFIED:
3165 if (isempty(unpackLockSet(sword->other))) {
njnfbdcba92005-05-09 01:23:49 +00003166 record_race_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003167 }
3168 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003169
sewardj18cd4a52002-11-13 22:37:41 +00003170 done:
3171 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003172 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003173
sewardj18cd4a52002-11-13 22:37:41 +00003174 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003175 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003176 else
njnd01fef72005-03-25 23:35:48 +00003177 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003178 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003179 }
3180}
3181
njnfbdcba92005-05-09 01:23:49 +00003182static void hg_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003183{
sewardj8fac99a2002-11-13 22:31:26 +00003184 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003185
njn13bfd852005-06-02 03:52:53 +00003186 end = VG_ROUNDUP(a+size, 4);
3187 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003188
sewardj18cd4a52002-11-13 22:37:41 +00003189 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003190 hg_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003191}
3192
3193#undef DEBUG_STATE
3194
njnaf839f52005-06-23 03:27:57 +00003195VG_REGPARM(1) static void hg_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003196{
njnfbdcba92005-05-09 01:23:49 +00003197 hg_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003198}
3199
njnaf839f52005-06-23 03:27:57 +00003200VG_REGPARM(1) static void hg_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003201{
njnfbdcba92005-05-09 01:23:49 +00003202 hg_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003203}
3204
njnaf839f52005-06-23 03:27:57 +00003205VG_REGPARM(1) static void hg_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003206{
njnfbdcba92005-05-09 01:23:49 +00003207 hg_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003208}
3209
njnaf839f52005-06-23 03:27:57 +00003210VG_REGPARM(2) static void hg_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003211{
njnfbdcba92005-05-09 01:23:49 +00003212 hg_mem_read(a, size, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003213}
3214
njnaf839f52005-06-23 03:27:57 +00003215VG_REGPARM(2) static void hg_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003216{
3217 if (*(UChar *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003218 hg_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003219}
njnaf839f52005-06-23 03:27:57 +00003220VG_REGPARM(2) static void hg_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003221{
3222 if (*(UShort *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003223 hg_mem_write(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003224}
njnaf839f52005-06-23 03:27:57 +00003225VG_REGPARM(2) static void hg_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003226{
3227 if (*(UInt *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003228 hg_mem_write(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003229}
njnaf839f52005-06-23 03:27:57 +00003230VG_REGPARM(2) static void hg_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003231{
njnfbdcba92005-05-09 01:23:49 +00003232 hg_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003233}
njn25e49d8e72002-09-23 09:36:25 +00003234
sewardjc4a810d2002-11-13 22:25:51 +00003235static void hg_thread_create(ThreadId parent, ThreadId child)
3236{
3237 if (0)
3238 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3239
3240 newTLS(child);
3241 addPriorTLS(child, parent);
3242
3243 newTLS(parent);
3244}
3245
3246static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3247{
3248 if (0)
3249 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3250
3251 newTLS(joiner);
3252 addPriorTLS(joiner, joinee);
3253
3254 clearTLS(joinee);
3255}
3256
sewardj7a5ebcf2002-11-13 22:42:13 +00003257static Int __BUS_HARDWARE_LOCK__;
3258
3259static void bus_lock(void)
3260{
njn95e65f62005-03-30 04:13:56 +00003261 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003262 hg_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3263 hg_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003264}
3265
3266static void bus_unlock(void)
3267{
njn95e65f62005-03-30 04:13:56 +00003268 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003269 hg_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003270}
3271
njn25e49d8e72002-09-23 09:36:25 +00003272/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003273/*--- Client requests ---*/
3274/*--------------------------------------------------------------------*/
3275
njn51d827b2005-05-09 01:02:08 +00003276static Bool hg_handle_client_request(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003277{
njnfc26ff92004-11-22 19:12:49 +00003278 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003279 return False;
3280
3281 switch(args[0]) {
3282 case VG_USERREQ__HG_CLEAN_MEMORY:
3283 set_address_range_state(args[1], args[2], Vge_VirginInit);
3284 *ret = 0; /* meaningless */
3285 break;
3286
3287 case VG_USERREQ__HG_KNOWN_RACE:
3288 set_address_range_state(args[1], args[2], Vge_Error);
3289 *ret = 0; /* meaningless */
3290 break;
3291
3292 default:
3293 return False;
3294 }
3295
3296 return True;
3297}
3298
3299
3300/*--------------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00003301/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00003302/*--------------------------------------------------------------------*/
3303
njn51d827b2005-05-09 01:02:08 +00003304static Bool hg_process_cmd_line_option(Char* arg)
3305{
3306 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3307 clo_execontext = EC_None;
3308 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3309 clo_execontext = EC_Some;
3310 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3311 clo_execontext = EC_All;
3312
3313 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
3314
3315 else
3316 return VG_(replacement_malloc_process_cmd_line_option)(arg);
3317
3318 return True;
3319}
3320
3321static void hg_print_usage(void)
3322{
3323 VG_(printf)(
3324" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3325" --show-last-access=no|some|all\n"
3326" show location of last word access on error [no]\n"
3327 );
3328 VG_(replacement_malloc_print_usage)();
3329}
3330
3331static void hg_print_debug_usage(void)
3332{
3333 VG_(replacement_malloc_print_debug_usage)();
3334}
3335
3336static void hg_post_clo_init(void)
3337{
3338 void (*stack_tracker)(Addr a, SizeT len);
3339
3340 if (clo_execontext) {
3341 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3342 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3343 }
3344
3345 if (clo_priv_stacks)
njnfbdcba92005-05-09 01:23:49 +00003346 stack_tracker = & hg_new_mem_stack_private;
njn51d827b2005-05-09 01:02:08 +00003347 else
njnfbdcba92005-05-09 01:23:49 +00003348 stack_tracker = & hg_new_mem_stack;
njn51d827b2005-05-09 01:02:08 +00003349
3350 VG_(track_new_mem_stack) (stack_tracker);
3351 VG_(track_new_mem_stack_signal) (stack_tracker);
3352}
3353
3354
3355static void hg_fini(Int exitcode)
3356{
3357 if (DEBUG_LOCK_TABLE) {
3358 pp_all_LockSets();
3359 pp_all_mutexes();
3360 }
3361
3362 if (LOCKSET_SANITY)
3363 sanity_check_locksets("hg_fini");
3364
3365 if (VG_(clo_verbosity) > 0)
3366 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
njnfbdcba92005-05-09 01:23:49 +00003367 n_hg_warnings, n_lockorder_warnings);
njn51d827b2005-05-09 01:02:08 +00003368
3369 if (0)
3370 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3371 stk_ld, stk_st, stk_ld + stk_st,
3372 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3373 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
3374}
3375
3376static void hg_pre_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00003377{
3378 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003379 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003380
njn810086f2002-11-14 12:42:47 +00003381 VG_(details_name) ("Helgrind");
3382 VG_(details_version) (NULL);
3383 VG_(details_description) ("a data race detector");
3384 VG_(details_copyright_author)(
sewardje4b0bf02006-06-05 23:21:15 +00003385 "Copyright (C) 2002-2006, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003386 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003387 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003388
njn51d827b2005-05-09 01:02:08 +00003389 VG_(basic_tool_funcs) (hg_post_clo_init,
3390 hg_instrument,
3391 hg_fini);
tomc756a8e2005-03-31 07:59:35 +00003392
njn5db32122005-08-12 15:23:57 +00003393 VG_(printf)(
3394"\n"
3395"Helgrind is currently not working, because:\n"
3396" (a) it is not yet ready to handle the Vex IR and the use with 64-bit\n"
3397" platforms introduced in Valgrind 3.0.0\n"
3398" (b) we need to get thread operation tracking working again after\n"
3399" the changes added in Valgrind 2.4.0\n"
njn5e0e9222006-04-12 22:53:23 +00003400" If you want to use Helgrind, you'll have to use Valgrind 2.2.0, which is\n"
3401" the most recent Valgrind release that contains a working Helgrind.\n"
njn5db32122005-08-12 15:23:57 +00003402"\n"
3403"Sorry for the inconvenience. Let us know if this is a problem for you.\n");
3404 VG_(exit)(1);
3405
tomc756a8e2005-03-31 07:59:35 +00003406 VG_(needs_core_errors) ();
njn51d827b2005-05-09 01:02:08 +00003407 VG_(needs_tool_errors) (hg_eq_Error,
3408 hg_pp_Error,
3409 hg_update_extra,
3410 hg_recognised_suppression,
3411 hg_read_extra_suppression_info,
3412 hg_error_matches_suppression,
3413 hg_get_error_name,
3414 hg_print_extra_suppression_info);
tomc756a8e2005-03-31 07:59:35 +00003415 VG_(needs_data_syms) ();
njn51d827b2005-05-09 01:02:08 +00003416 VG_(needs_client_requests) (hg_handle_client_request);
3417 VG_(needs_sanity_checks) (hg_cheap_sanity_check,
3418 hg_expensive_sanity_check);
3419 VG_(needs_command_line_options)(hg_process_cmd_line_option,
3420 hg_print_usage,
3421 hg_print_debug_usage);
tomc756a8e2005-03-31 07:59:35 +00003422
njnfc51f8d2005-06-21 03:20:17 +00003423 VG_(needs_malloc_replacement) (hg_malloc,
njn51d827b2005-05-09 01:02:08 +00003424 hg___builtin_new,
3425 hg___builtin_vec_new,
3426 hg_memalign,
3427 hg_calloc,
3428 hg_free,
3429 hg___builtin_delete,
3430 hg___builtin_vec_delete,
3431 hg_realloc,
tomc756a8e2005-03-31 07:59:35 +00003432 8 );
njn25e49d8e72002-09-23 09:36:25 +00003433
njnfbdcba92005-05-09 01:23:49 +00003434 VG_(track_new_mem_startup) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003435
njn51d827b2005-05-09 01:02:08 +00003436 /* stack ones not decided until hg_post_clo_init() */
njn25e49d8e72002-09-23 09:36:25 +00003437
njn51d827b2005-05-09 01:02:08 +00003438 VG_(track_new_mem_brk) (& make_writable);
njnfbdcba92005-05-09 01:23:49 +00003439 VG_(track_new_mem_mmap) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003440
njnfbdcba92005-05-09 01:23:49 +00003441 VG_(track_change_mem_mprotect) (& hg_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003442
njn51d827b2005-05-09 01:02:08 +00003443 VG_(track_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003444
njn51d827b2005-05-09 01:02:08 +00003445 VG_(track_die_mem_stack) (NULL);
3446 VG_(track_die_mem_stack_signal)(NULL);
3447 VG_(track_die_mem_brk) (NULL);
3448 VG_(track_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003449
njnfbdcba92005-05-09 01:23:49 +00003450 VG_(track_pre_mem_read) (& hg_pre_mem_read);
3451 VG_(track_pre_mem_read_asciiz) (& hg_pre_mem_read_asciiz);
3452 VG_(track_pre_mem_write) (& hg_pre_mem_write);
njn51d827b2005-05-09 01:02:08 +00003453 VG_(track_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003454
njn51d827b2005-05-09 01:02:08 +00003455 VG_(track_post_thread_create) (& hg_thread_create);
3456 VG_(track_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003457
njnfbdcba92005-05-09 01:23:49 +00003458 VG_(track_pre_mutex_lock) (& hg_pre_mutex_lock);
3459 VG_(track_post_mutex_lock) (& hg_post_mutex_lock);
3460 VG_(track_post_mutex_unlock) (& hg_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003461
njn14d01ce2004-11-26 11:30:14 +00003462 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003463 lockset_hash[i] = NULL;
3464
3465 empty = alloc_LockSet(0);
3466 insert_LockSet(empty);
3467 emptyset = empty;
3468
sewardjc4a810d2002-11-13 22:25:51 +00003469 /* Init lock table and thread segments */
3470 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003471 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003472
sewardjc4a810d2002-11-13 22:25:51 +00003473 newTLS(i);
3474 }
3475
njn25e49d8e72002-09-23 09:36:25 +00003476 init_shadow_memory();
njnf69f9452005-07-03 17:53:11 +00003477 hg_malloc_list = VG_(HT_construct)( 80021 ); // prime, big
njn25e49d8e72002-09-23 09:36:25 +00003478}
3479
sewardj45f4e7c2005-09-27 19:20:21 +00003480VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00003481
njn25e49d8e72002-09-23 09:36:25 +00003482/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003483/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003484/*--------------------------------------------------------------------*/