blob: 0b5056601ffa066a0998f7d660f027ae24e0c4c9 [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00003/*--- Helgrind: checking for data races in threaded programs. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Helgrind, a Valgrind tool for detecting
njnc9539842002-10-02 13:26:35 +00009 data races in threaded programs.
njn25e49d8e72002-09-23 09:36:25 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2002-2005 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn25e49d8e72002-09-23 09:36:25 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
nethercote46063202004-09-02 08:51:43 +000032#include "tool.h"
njn4802b382005-06-11 04:58:29 +000033#include "pub_tool_aspacemgr.h"
njnea27e462005-05-31 02:38:09 +000034#include "pub_tool_debuginfo.h"
njn81c00df2005-05-14 21:28:43 +000035#include "pub_tool_hashtable.h"
njn97405b22005-06-02 03:39:33 +000036#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000037#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000039#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000040#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000041#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000042#include "pub_tool_options.h"
njn31513b42005-06-01 03:09:59 +000043#include "pub_tool_profile.h"
njn717cde52005-05-10 02:47:21 +000044#include "pub_tool_replacemalloc.h"
njn43b9a8a2005-05-10 04:37:01 +000045#include "pub_tool_tooliface.h"
njn717cde52005-05-10 02:47:21 +000046
sewardj7f3ad222002-11-13 22:11:53 +000047#include "helgrind.h"
njn25e49d8e72002-09-23 09:36:25 +000048
njnfbdcba92005-05-09 01:23:49 +000049static UInt n_hg_warnings = 0;
sewardjff2c9232002-11-13 21:44:39 +000050static UInt n_lockorder_warnings = 0;
njn25e49d8e72002-09-23 09:36:25 +000051
52/*------------------------------------------------------------*/
53/*--- Debug guff ---*/
54/*------------------------------------------------------------*/
55
sewardje11d6c82002-12-15 02:00:41 +000056#define DEBUG_LOCK_TABLE 0 /* Print lock table at end */
njn25e49d8e72002-09-23 09:36:25 +000057
58#define DEBUG_MAKE_ACCESSES 0 /* Print make_access() calls */
59#define DEBUG_LOCKS 0 /* Print lock()/unlock() calls and locksets */
60#define DEBUG_NEW_LOCKSETS 0 /* Print new locksets when created */
61#define DEBUG_ACCESSES 0 /* Print reads, writes */
62#define DEBUG_MEM_LOCKSET_CHANGES 0
63 /* Print when an address's lockset
64 changes; only useful with
65 DEBUG_ACCESSES */
sewardj8fac99a2002-11-13 22:31:26 +000066#define SLOW_ASSERTS 0 /* do expensive asserts */
njn25e49d8e72002-09-23 09:36:25 +000067#define DEBUG_VIRGIN_READS 0 /* Dump around address on VIRGIN reads */
68
sewardj8fac99a2002-11-13 22:31:26 +000069#if SLOW_ASSERTS
njn94065fd2004-11-22 19:26:27 +000070#define TL_ASSERT(x) tl_assert(x)
sewardj8fac99a2002-11-13 22:31:26 +000071#else
njn94065fd2004-11-22 19:26:27 +000072#define TL_ASSERT(x)
sewardj8fac99a2002-11-13 22:31:26 +000073#endif
74
njn25e49d8e72002-09-23 09:36:25 +000075/* heavyweight LockSet sanity checking:
76 0 == never
77 1 == after important ops
78 2 == As 1 and also after pthread_mutex_* ops (excessively slow)
79 */
80#define LOCKSET_SANITY 0
81
sewardj8fac99a2002-11-13 22:31:26 +000082/* Rotate an unsigned quantity left */
83#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x)*8)-(n))))
84
njn25e49d8e72002-09-23 09:36:25 +000085/*------------------------------------------------------------*/
sewardjf6374322002-11-13 22:35:55 +000086/*--- Command line options ---*/
87/*------------------------------------------------------------*/
88
89static enum {
90 EC_None,
91 EC_Some,
92 EC_All
93} clo_execontext = EC_None;
94
sewardje1a39f42002-12-15 01:56:17 +000095static Bool clo_priv_stacks = False;
sewardjf6374322002-11-13 22:35:55 +000096
97/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000098/*--- Crude profiling machinery. ---*/
99/*------------------------------------------------------------*/
100
101// PPP: work out if I want this
102
103#define PROF_EVENT(x)
104#if 0
105#ifdef VG_PROFILE_MEMORY
106
107#define N_PROF_EVENTS 150
108
109static UInt event_ctr[N_PROF_EVENTS];
110
111void VGE_(done_prof_mem) ( void )
112{
113 Int i;
114 for (i = 0; i < N_PROF_EVENTS; i++) {
115 if ((i % 10) == 0)
116 VG_(printf)("\n");
117 if (event_ctr[i] > 0)
118 VG_(printf)( "prof mem event %2d: %d\n", i, event_ctr[i] );
119 }
120 VG_(printf)("\n");
121}
122
123#define PROF_EVENT(ev) \
njnca82cc02004-11-22 17:18:48 +0000124 do { tl_assert((ev) >= 0 && (ev) < N_PROF_EVENTS); \
njn25e49d8e72002-09-23 09:36:25 +0000125 event_ctr[ev]++; \
126 } while (False);
127
128#else
129
130//static void init_prof_mem ( void ) { }
131// void VG_(done_prof_mem) ( void ) { }
132
133#define PROF_EVENT(ev) /* */
134
135#endif /* VG_PROFILE_MEMORY */
136
137/* Event index. If just the name of the fn is given, this means the
138 number of calls to the fn. Otherwise it is the specified event.
139
140 [PPP: snip event numbers...]
141*/
142#endif /* 0 */
143
144
145/*------------------------------------------------------------*/
146/*--- Data defns. ---*/
147/*------------------------------------------------------------*/
148
njn3e884182003-04-15 13:03:23 +0000149typedef
150 struct _HG_Chunk {
151 struct _HG_Chunk* next;
152 Addr data; /* ptr to actual block */
nethercote928a5f72004-11-03 18:10:37 +0000153 SizeT size; /* size requested */
njn3e884182003-04-15 13:03:23 +0000154 ExeContext* where; /* where it was allocated */
155 ThreadId tid; /* allocating thread */
156 }
157 HG_Chunk;
158
njn25e49d8e72002-09-23 09:36:25 +0000159typedef enum
sewardj7f3ad222002-11-13 22:11:53 +0000160 { Vge_VirginInit, Vge_NonVirginInit, Vge_SegmentInit, Vge_Error }
njn25e49d8e72002-09-23 09:36:25 +0000161 VgeInitStatus;
162
sewardjc808ef52002-11-13 22:43:26 +0000163
njnc6168192004-11-29 13:54:10 +0000164// XXX: not 64-bit clean!
njn25e49d8e72002-09-23 09:36:25 +0000165/* Should add up to 32 to fit in one word */
166#define OTHER_BITS 30
167#define STATE_BITS 2
168
169#define ESEC_MAP_WORDS 16384 /* Words per secondary map */
170
171/* This is for indicating that a memory block has been initialised but not
172 * really directly by a particular thread... (eg. text/data initialised
173 * automatically at startup).
174 * Must be different to virgin_word.other */
175#define TID_INDICATING_NONVIRGIN 1
176
sewardjc4a810d2002-11-13 22:25:51 +0000177/* Magic packed TLS used for error suppression; if word state is Excl
178 and tid is this, then it means all access are OK without changing
179 state and without raising any more errors */
180#define TLSP_INDICATING_ALL ((1 << OTHER_BITS) - 1)
sewardj16748af2002-10-22 04:55:54 +0000181
njn25e49d8e72002-09-23 09:36:25 +0000182/* Number of entries must fit in STATE_BITS bits */
183typedef enum { Vge_Virgin, Vge_Excl, Vge_Shar, Vge_SharMod } pth_state;
184
sewardjc808ef52002-11-13 22:43:26 +0000185static inline const Char *pp_state(pth_state st)
186{
187 const Char *ret;
188
189 switch(st) {
190 case Vge_Virgin: ret = "virgin"; break;
191 case Vge_Excl: ret = "exclusive"; break;
192 case Vge_Shar: ret = "shared RO"; break;
193 case Vge_SharMod: ret = "shared RW"; break;
194 default: ret = "???";
195 }
196 return ret;
197}
198
njn25e49d8e72002-09-23 09:36:25 +0000199typedef
200 struct {
sewardj8fac99a2002-11-13 22:31:26 +0000201 /* gcc arranges this bitfield with state in the 2LSB and other
202 in the 30MSB, which is what we want */
njn25e49d8e72002-09-23 09:36:25 +0000203 UInt state:STATE_BITS;
sewardj8fac99a2002-11-13 22:31:26 +0000204 UInt other:OTHER_BITS;
njn25e49d8e72002-09-23 09:36:25 +0000205 } shadow_word;
206
sewardj8fac99a2002-11-13 22:31:26 +0000207#define SW(st, other) ((shadow_word) { st, other })
208
njn25e49d8e72002-09-23 09:36:25 +0000209typedef
210 struct {
211 shadow_word swords[ESEC_MAP_WORDS];
212 }
213 ESecMap;
214
215static ESecMap* primary_map[ 65536 ];
216static ESecMap distinguished_secondary_map;
217
sewardj8fac99a2002-11-13 22:31:26 +0000218static const shadow_word virgin_sword = SW(Vge_Virgin, 0);
219static const shadow_word error_sword = SW(Vge_Excl, TLSP_INDICATING_ALL);
njn25e49d8e72002-09-23 09:36:25 +0000220
221#define VGE_IS_DISTINGUISHED_SM(smap) \
222 ((smap) == &distinguished_secondary_map)
223
224#define ENSURE_MAPPABLE(addr,caller) \
225 do { \
226 if (VGE_IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
227 primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
228 /*VG_(printf)("new 2map because of %p\n", addr);*/ \
229 } \
230 } while(0)
231
232
sewardjc808ef52002-11-13 22:43:26 +0000233/* Parallel map which contains execution contexts when words last
234 changed state (if required) */
sewardj499e3de2002-11-13 22:22:25 +0000235
nethercoteca788ff2004-10-20 10:58:09 +0000236typedef struct EC_IP {
237 union u_ec_ip {
238 Addr ip;
sewardjc808ef52002-11-13 22:43:26 +0000239 ExeContext *ec;
nethercoteca788ff2004-10-20 10:58:09 +0000240 } uu_ec_ip;
sewardjc808ef52002-11-13 22:43:26 +0000241 UInt state:STATE_BITS;
242 UInt tls:OTHER_BITS; /* packed TLS */
nethercoteca788ff2004-10-20 10:58:09 +0000243} EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000244
nethercoteca788ff2004-10-20 10:58:09 +0000245#define NULL_EC_IP ((EC_IP){ { 0 }, 0, 0})
sewardjc808ef52002-11-13 22:43:26 +0000246
nethercoteca788ff2004-10-20 10:58:09 +0000247#define IP(ip, prev, tls) ((EC_IP) { (union u_ec_ip)(ip), (prev).state, packTLS(tls) })
248#define EC(ec, prev, tls) ((EC_IP) { (union u_ec_ip)(ec), (prev).state, packTLS(tls) })
sewardjc808ef52002-11-13 22:43:26 +0000249
250static inline UInt packEC(ExeContext *ec)
251{
njn94065fd2004-11-22 19:26:27 +0000252 TL_ASSERT(((UWord)ec & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000253 return ((UWord)ec) >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000254}
255
nethercoteca788ff2004-10-20 10:58:09 +0000256/* Lose 2 LSB of IP */
257static inline UInt packIP(Addr ip)
sewardjc808ef52002-11-13 22:43:26 +0000258{
nethercote50397c22004-11-04 18:03:06 +0000259 return ip >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000260}
261
nethercoteca788ff2004-10-20 10:58:09 +0000262static inline Addr unpackIP(UInt i)
sewardjc808ef52002-11-13 22:43:26 +0000263{
264 return (Addr)(i << STATE_BITS);
265}
sewardj499e3de2002-11-13 22:22:25 +0000266
267typedef struct {
nethercoteca788ff2004-10-20 10:58:09 +0000268 EC_IP execontext[ESEC_MAP_WORDS];
sewardj499e3de2002-11-13 22:22:25 +0000269} ExeContextMap;
270
271static ExeContextMap** execontext_map;
272
nethercoteca788ff2004-10-20 10:58:09 +0000273static inline void setExeContext(Addr a, EC_IP ec)
sewardj499e3de2002-11-13 22:22:25 +0000274{
275 UInt idx = (a >> 16) & 0xffff;
276 UInt off = (a >> 2) & 0x3fff;
277
278 if (execontext_map[idx] == NULL) {
279 execontext_map[idx] = VG_(malloc)(sizeof(ExeContextMap));
280 VG_(memset)(execontext_map[idx], 0, sizeof(ExeContextMap));
281 }
282
283 execontext_map[idx]->execontext[off] = ec;
284}
285
nethercoteca788ff2004-10-20 10:58:09 +0000286static inline EC_IP getExeContext(Addr a)
sewardj499e3de2002-11-13 22:22:25 +0000287{
288 UInt idx = (a >> 16) & 0xffff;
289 UInt off = (a >> 2) & 0x3fff;
nethercoteca788ff2004-10-20 10:58:09 +0000290 EC_IP ec = NULL_EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000291
292 if (execontext_map[idx] != NULL)
293 ec = execontext_map[idx]->execontext[off];
294
295 return ec;
296}
297
njn25e49d8e72002-09-23 09:36:25 +0000298/*------------------------------------------------------------*/
sewardjc4a810d2002-11-13 22:25:51 +0000299/*--- Thread lifetime segments ---*/
300/*------------------------------------------------------------*/
301
302/*
303 * This mechanism deals with the common case of a parent thread
304 * creating a structure for a child thread, and then passing ownership
305 * of the structure to that thread. It similarly copes with a child
306 * thread passing information back to another thread waiting to join
307 * on it.
308 *
309 * Each thread's lifetime can be partitioned into segments. Those
310 * segments are arranged to form an interference graph which indicates
311 * whether two thread lifetime segments can possibly be concurrent.
312 * If not, then memory with is exclusively accessed by one TLS can be
daywalker7e73e5f2003-07-04 16:18:15 +0000313 * passed on to another TLS without an error occurring, and without
sewardjc4a810d2002-11-13 22:25:51 +0000314 * moving it from Excl state.
315 *
316 * At present this only considers thread creation and join as
317 * synchronisation events for creating new lifetime segments, but
318 * others may be possible (like mutex operations).
319 */
320
321typedef struct _ThreadLifeSeg ThreadLifeSeg;
322
323struct _ThreadLifeSeg {
324 ThreadId tid;
325 ThreadLifeSeg *prior[2]; /* Previous lifetime segments */
326 UInt refcount; /* Number of memory locations pointing here */
327 UInt mark; /* mark used for graph traversal */
328 ThreadLifeSeg *next; /* list of all TLS */
329};
330
331static ThreadLifeSeg *all_tls;
332static UInt tls_since_gc;
333#define TLS_SINCE_GC 10000
334
335/* current mark used for TLS graph traversal */
336static UInt tlsmark;
337
338static ThreadLifeSeg *thread_seg[VG_N_THREADS];
339
340
341static void tls_gc(void)
342{
343 /* XXX later. Walk through all TLSs and look for ones with 0
344 refcount and remove them from the structure and free them.
345 Could probably get rid of ThreadLifeSeg.refcount and simply use
346 mark-sweep from the shadow table. */
347 VG_(printf)("WRITEME: TLS GC\n");
348}
349
350static void newTLS(ThreadId tid)
351{
352 static const Bool debug = False;
353 ThreadLifeSeg *tls;
354
355 /* Initial NULL */
356 if (thread_seg[tid] == NULL) {
357 tls = VG_(malloc)(sizeof(*tls));
358 tls->tid = tid;
359 tls->prior[0] = tls->prior[1] = NULL;
360 tls->refcount = 0;
361 tls->mark = tlsmark-1;
362
363 tls->next = all_tls;
364 all_tls = tls;
365 tls_since_gc++;
366
367 thread_seg[tid] = tls;
368 return;
369 }
370
371 /* Previous TLS was unused, so just recycle */
372 if (thread_seg[tid]->refcount == 0) {
373 if (debug)
374 VG_(printf)("newTLS; recycling TLS %p for tid %u\n",
375 thread_seg[tid], tid);
376 return;
377 }
378
379 /* Use existing TLS for this tid as a prior for new TLS */
380 tls = VG_(malloc)(sizeof(*tls));
381 tls->tid = tid;
382 tls->prior[0] = thread_seg[tid];
383 tls->prior[1] = NULL;
384 tls->refcount = 0;
385 tls->mark = tlsmark-1;
386
387 tls->next = all_tls;
388 all_tls = tls;
389 if (++tls_since_gc > TLS_SINCE_GC) {
390 tls_gc();
391 tls_since_gc = 0;
392 }
393
394 if (debug)
395 VG_(printf)("newTLS: made new TLS %p for tid %u (prior %p(%u))\n",
396 tls, tid, tls->prior[0], tls->prior[0]->tid);
397
398 thread_seg[tid] = tls;
399}
400
401/* clear out a TLS for a thread that's died */
402static void clearTLS(ThreadId tid)
403{
404 newTLS(tid);
405
406 thread_seg[tid]->prior[0] = NULL;
407 thread_seg[tid]->prior[1] = NULL;
408}
409
410static void addPriorTLS(ThreadId tid, ThreadId prior)
411{
412 static const Bool debug = False;
413 ThreadLifeSeg *tls = thread_seg[tid];
414
415 if (debug)
416 VG_(printf)("making TLS %p(%u) prior to TLS %p(%u)\n",
417 thread_seg[prior], prior, tls, tid);
418
njnca82cc02004-11-22 17:18:48 +0000419 tl_assert(thread_seg[tid] != NULL);
420 tl_assert(thread_seg[prior] != NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000421
422 if (tls->prior[0] == NULL)
423 tls->prior[0] = thread_seg[prior];
424 else {
njnca82cc02004-11-22 17:18:48 +0000425 tl_assert(tls->prior[1] == NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000426 tls->prior[1] = thread_seg[prior];
427 }
428}
429
njnfbdcba92005-05-09 01:23:49 +0000430static Bool isPrior(const ThreadLifeSeg *t, const ThreadLifeSeg *prior)
431{
432 if (t == NULL || t->mark == tlsmark)
433 return False;
434
435 if (t == prior)
436 return True;
437
438 ((ThreadLifeSeg *)t)->mark = tlsmark;
439
440 return isPrior(t->prior[0], prior) || isPrior(t->prior[1], prior);
441}
442
sewardjc4a810d2002-11-13 22:25:51 +0000443/* Return True if prior is definitely not concurrent with tls */
444static Bool tlsIsDisjoint(const ThreadLifeSeg *tls,
445 const ThreadLifeSeg *prior)
446{
sewardjc4a810d2002-11-13 22:25:51 +0000447 tlsmark++; /* new traversal mark */
448
njnfbdcba92005-05-09 01:23:49 +0000449 return isPrior(tls, prior);
sewardjc4a810d2002-11-13 22:25:51 +0000450}
451
452static inline UInt packTLS(ThreadLifeSeg *tls)
453{
njn94065fd2004-11-22 19:26:27 +0000454 TL_ASSERT(((UWord)tls & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000455 return ((UWord)tls) >> STATE_BITS;
sewardjc4a810d2002-11-13 22:25:51 +0000456}
457
458static inline ThreadLifeSeg *unpackTLS(UInt i)
459{
sewardj29ef1c82005-06-11 10:33:35 +0000460 /* HACK ALERT -- DUBIOUS CAST */
461 return (ThreadLifeSeg *)ULong_to_Ptr(i << STATE_BITS);
sewardjc4a810d2002-11-13 22:25:51 +0000462}
463
464/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000465/*--- Low-level support for memory tracking. ---*/
466/*------------------------------------------------------------*/
467
468/*
469 All reads and writes are recorded in the memory map, which
470 records the state of all memory in the process. The memory map is
471 organised like that for normal Valgrind, except each that everything
472 is done at word-level instead of byte-level, and each word has only
473 one word of shadow (instead of 36 bits).
474
475 As for normal Valgrind there is a distinguished secondary map. But we're
476 working at word-granularity, so it has 16k word entries instead of 64k byte
477 entries. Lookup is done as follows:
478
479 bits 31..16: primary map lookup
480 bits 15.. 2: secondary map lookup
481 bits 1.. 0: ignored
482*/
483
484
485/*------------------------------------------------------------*/
486/*--- Basic bitmap management, reading and writing. ---*/
487/*------------------------------------------------------------*/
488
489/* Allocate and initialise a secondary map, marking all words as virgin. */
490
491/* Just a value that isn't a real pointer */
492#define SEC_MAP_ACCESS (shadow_word*)0x99
493
494
495static
496ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
497{
498 ESecMap* map;
499 UInt i;
500 //PROF_EVENT(10); PPP
501
nethercote1420ab22004-08-18 22:26:01 +0000502 // Mark all words as virgin.
fitzhardinge98abfc72003-12-16 02:05:15 +0000503 map = (ESecMap *)VG_(shadow_alloc)(sizeof(ESecMap));
njn25e49d8e72002-09-23 09:36:25 +0000504 for (i = 0; i < ESEC_MAP_WORDS; i++)
505 map->swords[i] = virgin_sword;
506
507 return map;
508}
509
510
511/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
512 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000513static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000514void set_sword ( Addr a, shadow_word sword )
515{
516 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000517 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000518
519 //PROF_EVENT(23); PPP
520 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
521
522 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
523 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000524 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000525 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
526 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
527 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
528 tls->refcount--;
529 }
530
531 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
532 ThreadLifeSeg *tls = unpackTLS(sword.other);
533 tls->refcount++;
534 }
535
njn25e49d8e72002-09-23 09:36:25 +0000536 sm->swords[(a & 0xFFFC) >> 2] = sword;
537
538 if (VGE_IS_DISTINGUISHED_SM(sm)) {
539 VG_(printf)("wrote to distinguished 2ndary map! 0x%x\n", a);
540 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000541 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000542 }
543}
544
545
546static __inline__
547shadow_word* get_sword_addr ( Addr a )
548{
549 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
550 ESecMap* sm = primary_map[a >> 16];
551 UInt sm_off = (a & 0xFFFC) >> 2;
552
553 if (VGE_IS_DISTINGUISHED_SM(sm)) {
554 VG_(printf)("accessed distinguished 2ndary map! 0x%x\n", a);
555 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000556 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000557 return SEC_MAP_ACCESS;
558 }
559
560 //PROF_EVENT(21); PPP
561 return & (sm->swords[sm_off]);
562}
563
564
565// SSS: rename these so they're not so similar to memcheck, unless it's
566// appropriate of course
567
568static __inline__
569void init_virgin_sword(Addr a)
570{
sewardj499e3de2002-11-13 22:22:25 +0000571 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000572 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000573 set_sword(a, virgin_sword);
574}
575
sewardj7f3ad222002-11-13 22:11:53 +0000576static __inline__
577void init_error_sword(Addr a)
578{
579 set_sword(a, error_sword);
580}
njn25e49d8e72002-09-23 09:36:25 +0000581
njn25e49d8e72002-09-23 09:36:25 +0000582static __inline__
583void init_nonvirgin_sword(Addr a)
584{
585 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000586 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000587 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000588
njn14d01ce2004-11-26 11:30:14 +0000589 // The tid must be passed in here now; this requires more events to be
590 // given the tid in the first place.
591 //
592 //tid = VG_(get_current_or_recent_tid)();
593 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
594 VG_(exit)(1);
595
njnca82cc02004-11-22 17:18:48 +0000596 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000597 tls = thread_seg[tid];
598
sewardj8fac99a2002-11-13 22:31:26 +0000599 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000600 set_sword(a, sword);
601}
602
603
njnfbdcba92005-05-09 01:23:49 +0000604/* In this case, we treat it for Helgrind's sake like virgin (it hasn't
njn25e49d8e72002-09-23 09:36:25 +0000605 * been inited by a particular thread, it's just done automatically upon
606 * startup), but we mark its .state specially so it doesn't look like an
607 * uninited read. */
608static __inline__
609void init_magically_inited_sword(Addr a)
610{
611 shadow_word sword;
612
sewardj8fac99a2002-11-13 22:31:26 +0000613 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
614
njn25e49d8e72002-09-23 09:36:25 +0000615 set_sword(a, virgin_sword);
616}
617
sewardjc26cc252002-10-23 21:58:55 +0000618
sewardj274c6012002-10-22 04:54:55 +0000619/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000620/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000621/*------------------------------------------------------------*/
622
sewardj39a4d842002-11-13 22:14:30 +0000623typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000624typedef struct _LockSet LockSet;
625
sewardj16748af2002-10-22 04:55:54 +0000626typedef enum MutexState {
627 MxUnknown, /* don't know */
628 MxUnlocked, /* unlocked */
629 MxLocked, /* locked */
630 MxDead /* destroyed */
631} MutexState;
632
sewardj39a4d842002-11-13 22:14:30 +0000633struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000634 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000635 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000636
637 MutexState state; /* mutex state */
638 ThreadId tid; /* owner */
639 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000640
sewardj4bffb232002-11-13 21:46:34 +0000641 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000642 UInt mark; /* mark for graph traversal */
643};
sewardj16748af2002-10-22 04:55:54 +0000644
sewardj39a4d842002-11-13 22:14:30 +0000645static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000646{
sewardjdac0a442002-11-13 22:08:40 +0000647 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000648}
njn25e49d8e72002-09-23 09:36:25 +0000649
sewardj274c6012002-10-22 04:54:55 +0000650struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000651 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000652 UInt hash; /* hash code */
653 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000654 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000655};
sewardj4bffb232002-11-13 21:46:34 +0000656
657static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000658
659/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000660static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000661
sewardjdac0a442002-11-13 22:08:40 +0000662#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000663
sewardj4bffb232002-11-13 21:46:34 +0000664static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000665
sewardj4bffb232002-11-13 21:46:34 +0000666/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000667static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000668{
sewardj4bffb232002-11-13 21:46:34 +0000669 UInt id;
670
njn94065fd2004-11-22 19:26:27 +0000671 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000672 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000673
674 return id;
njn25e49d8e72002-09-23 09:36:25 +0000675}
676
sewardj8fac99a2002-11-13 22:31:26 +0000677static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000678{
sewardj29ef1c82005-06-11 10:33:35 +0000679 /* HACK ALERT -- DUBIOUS CAST */
680 return (LockSet *)ULong_to_Ptr(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000681}
682
njn25e49d8e72002-09-23 09:36:25 +0000683static
sewardj4bffb232002-11-13 21:46:34 +0000684void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000685{
sewardj05bcdcb2003-05-18 10:05:38 +0000686 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000687 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000688 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000689 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000690
691 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000692 }
693 VG_(printf)("}\n");
694}
695
696
sewardj4bffb232002-11-13 21:46:34 +0000697static void print_LockSet(const Char *s, const LockSet *ls)
698{
699 VG_(printf)("%s: ", s);
700 pp_LockSet(ls);
701}
702
703/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000704static UInt hash_LockSet_w_wo(const LockSet *ls,
705 const Mutex *with,
706 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000707{
sewardj05bcdcb2003-05-18 10:05:38 +0000708 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000709 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000710
njnca82cc02004-11-22 17:18:48 +0000711 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000712
713 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000714 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000715
716 if (without && mutex_cmp(without, mx) == 0)
717 continue;
718
719 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
720 mx = with;
721 with = NULL;
722 i--;
723 }
724
sewardj8fac99a2002-11-13 22:31:26 +0000725 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000726 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000727 }
728
729 return hash % LOCKSET_HASH_SZ;
730}
731
sewardj39a4d842002-11-13 22:14:30 +0000732static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000733{
734 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
735
736 if (0)
737 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
738
739 return hash;
740}
741
sewardj39a4d842002-11-13 22:14:30 +0000742static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000743{
744 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
745
746 if (0)
747 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
748
749 return hash;
750}
751
752static inline UInt hash_LockSet(const LockSet *ls)
753{
754 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
755
756 if (0)
757 VG_(printf)("hash %p -> %d\n", ls, hash);
758
759 return hash;
760}
761
762static
763Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000764{
765 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000766
sewardj4bffb232002-11-13 21:46:34 +0000767 if (a == b)
768 return True;
769 if (a->setsize != b->setsize)
770 return False;
njn25e49d8e72002-09-23 09:36:25 +0000771
sewardj4bffb232002-11-13 21:46:34 +0000772 for(i = 0; i < a->setsize; i++) {
773 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000774 return False;
njn25e49d8e72002-09-23 09:36:25 +0000775 }
776
sewardj4bffb232002-11-13 21:46:34 +0000777 return True;
njn25e49d8e72002-09-23 09:36:25 +0000778}
779
780
781/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
782 * doesn't do the insertion. Returns True if they match.
783 */
784static Bool
sewardj4bffb232002-11-13 21:46:34 +0000785weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000786 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000787{
sewardjc26cc252002-10-23 21:58:55 +0000788 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000789 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000790
njn25e49d8e72002-09-23 09:36:25 +0000791 /* Idea is to try and match each element of b against either an
792 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000793
794 if (debug) {
795 print_LockSet("weird_LockSet_equals a", a);
796 print_LockSet(" b", b);
797 VG_(printf)( " missing: %p%(y\n",
798 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000799 }
sewardjc26cc252002-10-23 21:58:55 +0000800
sewardj4bffb232002-11-13 21:46:34 +0000801 if ((a->setsize + 1) != b->setsize) {
802 if (debug)
803 VG_(printf)(" fastpath length mismatch -> 0\n");
804 return False;
805 }
806
sewardjc26cc252002-10-23 21:58:55 +0000807 /* There are three phases to this compare:
808 1 the section from the start of a up to missing_mutex
809 2 missing mutex itself
810 3 the section after missing_mutex to the end of a
811 */
812
sewardj4bffb232002-11-13 21:46:34 +0000813 ia = 0;
814 ib = 0;
815
sewardjc26cc252002-10-23 21:58:55 +0000816 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000817 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000818 if (debug) {
819 print_LockSet(" 1:a", a);
820 print_LockSet(" 1:b", b);
821 }
sewardj4bffb232002-11-13 21:46:34 +0000822 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000823 return False;
sewardjc26cc252002-10-23 21:58:55 +0000824 }
825
826 /* 2: missing_mutex itself */
827 if (debug) {
828 VG_(printf)( " 2:missing: %p%(y\n",
829 missing_mutex->mutexp, missing_mutex->mutexp);
830 print_LockSet(" 2: b", b);
831 }
832
njnca82cc02004-11-22 17:18:48 +0000833 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000834
sewardj4bffb232002-11-13 21:46:34 +0000835 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000836 return False;
837
sewardj4bffb232002-11-13 21:46:34 +0000838 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000839
840 /* 3: after missing_mutex to end */
841
sewardj4bffb232002-11-13 21:46:34 +0000842 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000843 if (debug) {
844 print_LockSet(" 3:a", a);
845 print_LockSet(" 3:b", b);
846 }
sewardj4bffb232002-11-13 21:46:34 +0000847 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000848 return False;
sewardjc26cc252002-10-23 21:58:55 +0000849 }
850
851 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000852 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000853
sewardj4bffb232002-11-13 21:46:34 +0000854 return ia == a->setsize && ib == b->setsize;
855}
856
857
858
859static const LockSet *lookup_LockSet(const LockSet *set)
860{
861 UInt bucket = set->hash;
862 LockSet *ret;
863
864 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
865 if (set == ret || structural_eq_LockSet(set, ret))
866 return ret;
867
868 return NULL;
869}
870
sewardj39a4d842002-11-13 22:14:30 +0000871static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000872{
873 UInt bucket = hash_LockSet_with(set, mutex);
874 const LockSet *ret;
875
876 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
877 if (weird_LockSet_equals(set, ret, mutex))
878 return ret;
879
880 return NULL;
881}
882
sewardj39a4d842002-11-13 22:14:30 +0000883static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000884{
885 UInt bucket = hash_LockSet_without(set, mutex);
886 const LockSet *ret;
887
888 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
889 if (weird_LockSet_equals(ret, set, mutex))
890 return ret;
891
892 return NULL;
893}
894
895static void insert_LockSet(LockSet *set)
896{
897 UInt hash = hash_LockSet(set);
898
899 set->hash = hash;
900
njnca82cc02004-11-22 17:18:48 +0000901 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000902
903 set->next = lockset_hash[hash];
904 lockset_hash[hash] = set;
905}
906
907static inline
908LockSet *alloc_LockSet(UInt setsize)
909{
sewardj39a4d842002-11-13 22:14:30 +0000910 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000911 ret->setsize = setsize;
912 return ret;
913}
914
915static inline
916void free_LockSet(LockSet *p)
917{
918 /* assert: not present in hash */
919 VG_(free)(p);
920}
921
njnb4aee052003-04-15 14:09:58 +0000922static
sewardj4bffb232002-11-13 21:46:34 +0000923void pp_all_LockSets ( void )
924{
925 Int i;
926 Int sets, buckets;
927
928 sets = buckets = 0;
929 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
930 const LockSet *ls = lockset_hash[i];
931 Bool first = True;
932
sewardj4bffb232002-11-13 21:46:34 +0000933 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000934 if (first) {
935 buckets++;
936 VG_(printf)("[%4d] = ", i);
937 } else
938 VG_(printf)(" ");
939
sewardj4bffb232002-11-13 21:46:34 +0000940 sets++;
941 first = False;
942 pp_LockSet(ls);
943 }
944 }
945
946 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
947}
948
949static inline Bool isempty(const LockSet *ls)
950{
951 return ls == NULL || ls->setsize == 0;
952}
953
sewardj39a4d842002-11-13 22:14:30 +0000954static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000955{
956 Int i;
957
958 /* XXX use binary search */
959 for(i = 0; i < ls->setsize; i++)
960 if (mutex_cmp(mx, ls->mutex[i]) == 0)
961 return True;
962
963 return False;
964}
965
966/* Check invariants:
967 - all locksets are unique
968 - each set is an array in strictly increasing order of mutex addr
969*/
970static
971void sanity_check_locksets ( const Char* caller )
972{
973 Int i;
974 const Char *badness;
975 LockSet *ls;
976
977 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
978
979 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000980 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000981 Int j;
982
983 if (hash_LockSet(ls) != ls->hash) {
984 badness = "mismatched hash";
985 goto bad;
986 }
sewardj05bcdcb2003-05-18 10:05:38 +0000987 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +0000988 badness = "wrong bucket";
989 goto bad;
990 }
991 if (lookup_LockSet(ls) != ls) {
992 badness = "non-unique set";
993 goto bad;
994 }
995
996 prev = ls->mutex[0];
997 for(j = 1; j < ls->setsize; j++) {
998 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
999 badness = "mutexes out of order";
1000 goto bad;
1001 }
1002 }
1003 }
1004 }
1005 return;
1006
1007 bad:
1008 VG_(printf)("sanity_check_locksets: "
1009 "i = %d, ls=%p badness = %s, caller = %s\n",
1010 i, ls, badness, caller);
1011 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001012 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001013}
1014
1015static
sewardj39a4d842002-11-13 22:14:30 +00001016LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001017{
1018 static const Bool debug = False;
1019 LockSet *ret = NULL;
1020 Int i, j;
1021
1022 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1023 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1024 print_LockSet("add-IN", ls);
1025 }
1026
1027 if (debug || LOCKSET_SANITY)
1028 sanity_check_locksets("add-IN");
1029
njnca82cc02004-11-22 17:18:48 +00001030 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001031
1032 ret = alloc_LockSet(ls->setsize+1);
1033
1034 for(i = j = 0; i < ls->setsize; i++) {
1035 if (debug)
1036 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1037 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1038 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1039 ret->mutex[j++] = mx;
1040 mx = NULL;
1041 }
1042 ret->mutex[j++] = ls->mutex[i];
1043 }
1044
1045 /* not added in loop - must be after */
1046 if (mx)
1047 ret->mutex[j++] = mx;
1048
njnca82cc02004-11-22 17:18:48 +00001049 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001050
1051 if (debug || LOCKSET_SANITY) {
1052 print_LockSet("add-OUT", ret);
1053 sanity_check_locksets("add-OUT");
1054 }
1055 return ret;
1056}
1057
1058/* Builds ls with mx removed. mx should actually be in ls!
1059 (a checked assertion). Resulting set should not already
1060 exist in the table (unchecked).
1061*/
1062static
sewardj39a4d842002-11-13 22:14:30 +00001063LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001064{
1065 static const Bool debug = False;
1066 LockSet *ret = NULL;
1067 Int i, j;
1068
1069 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1070 print_LockSet("remove-IN", ls);
1071 }
1072
1073 if (debug || LOCKSET_SANITY)
1074 sanity_check_locksets("remove-IN");
1075
njnca82cc02004-11-22 17:18:48 +00001076 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001077
1078 ret = alloc_LockSet(ls->setsize-1);
1079
1080 for(i = j = 0; i < ls->setsize; i++) {
1081 if (mutex_cmp(ls->mutex[i], mx) == 0)
1082 continue;
1083 ret->mutex[j++] = ls->mutex[i];
1084 }
1085
njnca82cc02004-11-22 17:18:48 +00001086 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001087
1088 if (debug || LOCKSET_SANITY) {
1089 print_LockSet("remove-OUT", ret);
1090 sanity_check_locksets("remove-OUT");
1091 }
1092 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001093}
1094
1095
1096/* Builds the intersection, and then unbuilds it if it's already in the table.
1097 */
sewardj4bffb232002-11-13 21:46:34 +00001098static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001099{
sewardj4bffb232002-11-13 21:46:34 +00001100 static const Bool debug = False;
1101 Int iret;
1102 Int ia, ib;
1103 Int size;
1104 LockSet *ret;
1105 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001106
sewardj4bffb232002-11-13 21:46:34 +00001107 if (debug || LOCKSET_SANITY)
1108 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001109
sewardj4bffb232002-11-13 21:46:34 +00001110 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1111 print_LockSet("intersect a", a);
1112 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001113 }
1114
sewardj4bffb232002-11-13 21:46:34 +00001115 /* count the size of the new set */
1116 size = 0;
1117 ia = ib = 0;
1118 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1119 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1120 size++;
1121 ia++;
1122 ib++;
1123 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1124 ia++;
1125 } else {
njnca82cc02004-11-22 17:18:48 +00001126 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001127 ib++;
1128 }
njn25e49d8e72002-09-23 09:36:25 +00001129 }
1130
sewardj4bffb232002-11-13 21:46:34 +00001131 /* Build the intersection of the two sets */
1132 ret = alloc_LockSet(size);
1133 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1134 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001135 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001136 ret->mutex[iret++] = a->mutex[ia];
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 }
1145 }
1146
1147 ret->hash = hash_LockSet(ret);
1148
njn25e49d8e72002-09-23 09:36:25 +00001149 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001150 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001151
sewardj4bffb232002-11-13 21:46:34 +00001152 if (found != NULL) {
1153 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001154 } else {
sewardj4bffb232002-11-13 21:46:34 +00001155 insert_LockSet(ret);
1156 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001157 }
1158
sewardj4bffb232002-11-13 21:46:34 +00001159 if (debug || LOCKSET_SANITY) {
1160 print_LockSet("intersect-OUT", found);
1161 sanity_check_locksets("intersect-OUT");
1162 }
njn25e49d8e72002-09-23 09:36:25 +00001163
sewardj4bffb232002-11-13 21:46:34 +00001164 return found;
njn25e49d8e72002-09-23 09:36:25 +00001165}
1166
sewardj4bffb232002-11-13 21:46:34 +00001167/* inline the fastpath */
1168static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001169{
sewardj4bffb232002-11-13 21:46:34 +00001170 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001171
1172 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001173 if (a == b) {
1174 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1175 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001176 }
sewardj4bffb232002-11-13 21:46:34 +00001177 return a;
sewardjc26cc252002-10-23 21:58:55 +00001178 }
1179
sewardj4bffb232002-11-13 21:46:34 +00001180 if (isempty(a) || isempty(b)) {
1181 if (debug)
1182 VG_(printf)("intersect empty fastpath\n");
1183 return emptyset;
1184 }
1185
1186 return _intersect(a, b);
1187}
1188
1189
1190static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1191{
1192 static const Bool debug = False;
1193 Int iret;
1194 Int ia, ib;
1195 Int size;
1196 LockSet *ret;
1197 const LockSet *found;
1198
1199 if (debug || LOCKSET_SANITY)
1200 sanity_check_locksets("union-IN");
1201
1202 /* Fast case -- when the two are the same */
1203 if (a == b) {
1204 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1205 print_LockSet("union-same fastpath", a);
1206 }
1207 return a;
1208 }
1209
1210 if (isempty(a)) {
1211 if (debug)
1212 print_LockSet("union a=empty b", b);
1213 return b;
1214 }
1215 if (isempty(b)) {
1216 if (debug)
1217 print_LockSet("union b=empty a", a);
1218 return a;
1219 }
1220
1221 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001222 print_LockSet("union a", a);
1223 print_LockSet("union b", b);
1224 }
1225
sewardj4bffb232002-11-13 21:46:34 +00001226 /* count the size of the new set */
1227 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1228 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001229
sewardj4bffb232002-11-13 21:46:34 +00001230 if ((ia < a->setsize) && (ib < b->setsize))
1231 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1232 else if (ia == a->setsize)
1233 cmp = 1;
1234 else
1235 cmp = -1;
1236
1237 if (cmp == 0) {
1238 size++;
1239 ia++;
1240 ib++;
1241 } else if (cmp < 0) {
1242 size++;
1243 ia++;
1244 } else {
njnca82cc02004-11-22 17:18:48 +00001245 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001246 size++;
1247 ib++;
1248 }
sewardjc26cc252002-10-23 21:58:55 +00001249 }
1250
sewardj4bffb232002-11-13 21:46:34 +00001251 /* Build the intersection of the two sets */
1252 ret = alloc_LockSet(size);
1253 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1254 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001255 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001256
1257 if ((ia < a->setsize) && (ib < b->setsize))
1258 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1259 else if (ia == a->setsize)
1260 cmp = 1;
1261 else
1262 cmp = -1;
1263
1264 if (cmp == 0) {
1265 ret->mutex[iret++] = a->mutex[ia];
1266 ia++;
1267 ib++;
1268 } else if (cmp < 0) {
1269 ret->mutex[iret++] = a->mutex[ia];
1270 ia++;
1271 } else {
njnca82cc02004-11-22 17:18:48 +00001272 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001273 ret->mutex[iret++] = b->mutex[ib];
1274 ib++;
1275 }
1276 }
1277
njnca82cc02004-11-22 17:18:48 +00001278 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001279
1280 ret->hash = hash_LockSet(ret);
1281
sewardjc26cc252002-10-23 21:58:55 +00001282 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001283 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001284
sewardj4bffb232002-11-13 21:46:34 +00001285 if (found != NULL) {
1286 if (debug)
1287 print_LockSet("union found existing set", found);
1288 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001289 } else {
sewardj4bffb232002-11-13 21:46:34 +00001290 if (debug)
1291 print_LockSet("union inserting new set", ret);
1292 insert_LockSet(ret);
1293 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001294 }
1295
sewardj4bffb232002-11-13 21:46:34 +00001296 if (debug || LOCKSET_SANITY) {
1297 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001298 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001299 }
sewardjc26cc252002-10-23 21:58:55 +00001300
sewardj4bffb232002-11-13 21:46:34 +00001301 return found;
sewardjc26cc252002-10-23 21:58:55 +00001302}
1303
1304/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001305/*--- Implementation of mutex structure. ---*/
1306/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001307
1308static UInt graph_mark; /* current mark we're using for graph traversal */
1309
sewardj39a4d842002-11-13 22:14:30 +00001310static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001311 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001312static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001313 const LockSet *lockset_holding,
1314 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001315
njn72718642003-07-24 08:45:32 +00001316static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001317
1318#define M_MUTEX_HASHSZ 1021
1319
sewardj39a4d842002-11-13 22:14:30 +00001320static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001321static UInt total_mutexes;
1322
1323static const Char *pp_MutexState(MutexState st)
1324{
1325 switch(st) {
1326 case MxLocked: return "Locked";
1327 case MxUnlocked: return "Unlocked";
1328 case MxDead: return "Dead";
1329 case MxUnknown: return "Unknown";
1330 }
1331 return "???";
1332}
1333
1334static void pp_all_mutexes()
1335{
1336 Int i;
1337 Int locks, buckets;
1338
1339 locks = buckets = 0;
1340 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001341 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001342 Bool first = True;
1343
1344 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1345 if (first) {
1346 buckets++;
1347 VG_(printf)("[%4d] = ", i);
1348 } else
1349 VG_(printf)(" ");
1350 locks++;
1351 first = False;
1352 VG_(printf)("%p [%8s] -> %p%(y\n",
1353 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1354 }
1355 }
1356
1357 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1358 locks, buckets, total_mutexes);
1359}
sewardjc26cc252002-10-23 21:58:55 +00001360
sewardj39a4d842002-11-13 22:14:30 +00001361/* find or create a Mutex for a program's mutex use */
1362static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001363{
nethercote50397c22004-11-04 18:03:06 +00001364 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001365 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001366
1367 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1368 if (mp->mutexp == mutexp)
1369 return mp;
1370
sewardjdac0a442002-11-13 22:08:40 +00001371 total_mutexes++;
1372
sewardjc26cc252002-10-23 21:58:55 +00001373 mp = VG_(malloc)(sizeof(*mp));
1374 mp->mutexp = mutexp;
1375 mp->next = mutex_hash[bucket];
1376 mutex_hash[bucket] = mp;
1377
1378 mp->state = MxUnknown;
1379 mp->tid = VG_INVALID_THREADID;
1380 mp->location = NULL;
1381
sewardj4bffb232002-11-13 21:46:34 +00001382 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001383 mp->mark = graph_mark - 1;
1384
1385 return mp;
1386}
1387
sewardjdac0a442002-11-13 22:08:40 +00001388/* Find all mutexes in a range of memory, and call the callback.
1389 Remove the mutex from the hash if the callback returns True (mutex
1390 structure itself is not freed, because it may be pointed to by a
1391 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001392static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001393{
sewardjdac0a442002-11-13 22:08:40 +00001394 UInt first = start % M_MUTEX_HASHSZ;
1395 UInt last = (end+1) % M_MUTEX_HASHSZ;
1396 UInt i;
1397
1398 /* Single pass over the hash table, looking for likely hashes */
1399 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001400 Mutex *mx;
1401 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001402
1403 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1404 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1405 *prev = mx->next;
1406 }
1407
1408 if (++i == M_MUTEX_HASHSZ)
1409 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001410 }
sewardjc26cc252002-10-23 21:58:55 +00001411}
1412
1413#define MARK_LOOP (graph_mark+0)
1414#define MARK_DONE (graph_mark+1)
1415
thughes4ad52d02004-06-27 17:37:21 +00001416static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1417{
1418 static const Bool debug = False;
1419 Int i;
1420
1421 if (mutex->mark == MARK_LOOP)
1422 return True; /* found cycle */
1423 if (mutex->mark == MARK_DONE)
1424 return False; /* been here before, its OK */
1425
1426 ((Mutex*)mutex)->mark = MARK_LOOP;
1427
1428 if (debug)
1429 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1430 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1431 for(i = 0; i < ls->setsize; i++) {
1432 const Mutex *mx = ls->mutex[i];
1433
1434 if (debug)
1435 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1436 mutex->mutexp, ls,
1437 mx->mutexp, mx->mutexp);
1438 if (check_cycle_inner(mx, mx->lockdep))
1439 return True;
1440 }
1441 ((Mutex*)mutex)->mark = MARK_DONE;
1442
1443 return False;
1444}
1445
sewardj39a4d842002-11-13 22:14:30 +00001446static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001447{
sewardjff2c9232002-11-13 21:44:39 +00001448
sewardjc26cc252002-10-23 21:58:55 +00001449 graph_mark += 2; /* clear all marks */
1450
sewardj4bffb232002-11-13 21:46:34 +00001451 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001452}
1453
sewardjdca84112002-11-13 22:29:34 +00001454/* test to see if a mutex state change would be problematic; this
1455 makes no changes to the mutex state. This should be called before
1456 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001457static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001458{
1459 static const Bool debug = False;
1460
sewardjc26cc252002-10-23 21:58:55 +00001461 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001462 Char *str;
1463
1464 switch(state) {
1465 case MxLocked: str = "lock dead mutex"; break;
1466 case MxUnlocked: str = "unlock dead mutex"; break;
1467 default: str = "operate on dead mutex"; break;
1468 }
1469
sewardjc26cc252002-10-23 21:58:55 +00001470 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001471 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001472 return;
1473 }
1474
1475 switch(state) {
1476 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001477 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001478
1479 if (debug)
1480 print_LockSet("thread holding", thread_locks[tid]);
1481
1482 if (check_cycle(mutex, thread_locks[tid]))
1483 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1484 else {
1485 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1486
1487 if (debug) {
1488 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1489 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1490 print_LockSet("lockdep", mutex->lockdep);
1491 }
1492 }
1493 break;
1494
1495 case MxUnlocked:
1496 if (debug)
1497 print_LockSet("thread holding", thread_locks[tid]);
1498
1499 if (mutex->state != MxLocked) {
1500 record_mutex_error(tid, mutex,
1501 "unlock non-locked mutex", mutex->location);
1502 }
1503 if (mutex->tid != tid) {
1504 record_mutex_error(tid, mutex,
1505 "unlock someone else's mutex", mutex->location);
1506 }
1507 break;
1508
1509 case MxDead:
1510 break;
1511
1512 default:
1513 break;
1514 }
1515}
1516
1517/* Update a mutex state. Expects most error testing and reporting to
1518 have happened in test_mutex_state(). The assumption is that no
1519 client code is run by thread tid between test and set, either
1520 because it is blocked or test and set are called together
1521 atomically.
1522
1523 Setting state to MxDead is the exception, since that can happen as
1524 a result of any thread freeing memory; in this case set_mutex_state
1525 does all the error reporting as well.
1526*/
njn72718642003-07-24 08:45:32 +00001527static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001528{
1529 static const Bool debug = False;
1530
1531 if (debug)
1532 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1533 tid, mutex, mutex->mutexp, mutex->mutexp,
1534 pp_MutexState(mutex->state), pp_MutexState(state));
1535
1536 if (mutex->state == MxDead) {
1537 /* can't do anything legal to a destroyed mutex */
1538 return;
1539 }
1540
1541 switch(state) {
1542 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001543 if (mutex->state == MxLocked) {
1544 if (mutex->tid != tid)
1545 record_mutex_error(tid, mutex, "take lock held by someone else",
1546 mutex->location);
1547 else
1548 record_mutex_error(tid, mutex, "take lock we already hold",
1549 mutex->location);
1550
njn67993252004-11-22 18:02:32 +00001551 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001552 break;
1553 }
sewardjc26cc252002-10-23 21:58:55 +00001554
njnca82cc02004-11-22 17:18:48 +00001555 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001556
sewardjc26cc252002-10-23 21:58:55 +00001557 mutex->tid = tid;
1558 break;
1559
1560 case MxUnlocked:
1561 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001562 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001563
sewardjdca84112002-11-13 22:29:34 +00001564 if (mutex->state != MxLocked || mutex->tid != tid)
1565 break;
1566
sewardjc26cc252002-10-23 21:58:55 +00001567 mutex->tid = VG_INVALID_THREADID;
1568 break;
1569
sewardjdac0a442002-11-13 22:08:40 +00001570 case MxDead:
1571 if (mutex->state == MxLocked) {
1572 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001573 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001574 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1575 mutex->tid = VG_INVALID_THREADID;
1576
1577 record_mutex_error(tid, mutex,
1578 "free locked mutex", mutex->location);
1579 }
1580 break;
1581
sewardjc26cc252002-10-23 21:58:55 +00001582 default:
1583 break;
1584 }
1585
njnd01fef72005-03-25 23:35:48 +00001586 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001587 mutex->state = state;
1588}
njn25e49d8e72002-09-23 09:36:25 +00001589
1590/*------------------------------------------------------------*/
1591/*--- Setting and checking permissions. ---*/
1592/*------------------------------------------------------------*/
1593
thughes4ad52d02004-06-27 17:37:21 +00001594/* only clean up dead mutexes */
1595static
1596Bool cleanmx(Mutex *mx) {
1597 return mx->state == MxDead;
1598}
1599
njn25e49d8e72002-09-23 09:36:25 +00001600static
nethercote451eae92004-11-02 13:06:32 +00001601void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001602 VgeInitStatus status )
1603{
sewardj1806d7f2002-10-22 05:05:49 +00001604 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001605
1606# if DEBUG_MAKE_ACCESSES
1607 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1608# endif
1609 //PROF_EVENT(30); PPP
1610
1611 if (len == 0)
1612 return;
1613
1614 if (len > 100 * 1000 * 1000)
1615 VG_(message)(Vg_UserMsg,
1616 "Warning: set address range state: large range %d",
1617 len);
1618
njn31513b42005-06-01 03:09:59 +00001619 //VGP_PUSHCC(VgpSARP);
njn25e49d8e72002-09-23 09:36:25 +00001620
sewardjdac0a442002-11-13 22:08:40 +00001621 /* Remove mutexes in recycled memory range from hash */
1622 find_mutex_range(a, a+len, cleanmx);
1623
njn25e49d8e72002-09-23 09:36:25 +00001624 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1625 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1626 * len/4+1 words. This works out which it is by aligning the block and
1627 * seeing if the end byte is in the same word as it is for the unaligned
1628 * block; if not, it's the awkward case. */
njn13bfd852005-06-02 03:52:53 +00001629 end = VG_ROUNDUP(a + len, 4);
1630 a = VG_ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001631
1632 /* Do it ... */
1633 switch (status) {
1634 case Vge_VirginInit:
1635 for ( ; a < end; a += 4) {
1636 //PROF_EVENT(31); PPP
1637 init_virgin_sword(a);
1638 }
1639 break;
1640
1641 case Vge_NonVirginInit:
1642 for ( ; a < end; a += 4) {
1643 //PROF_EVENT(31); PPP
1644 init_nonvirgin_sword(a);
1645 }
1646 break;
1647
1648 case Vge_SegmentInit:
1649 for ( ; a < end; a += 4) {
1650 //PROF_EVENT(31); PPP
1651 init_magically_inited_sword(a);
1652 }
1653 break;
sewardj7f3ad222002-11-13 22:11:53 +00001654
1655 case Vge_Error:
1656 for ( ; a < end; a += 4) {
1657 //PROF_EVENT(31); PPP
1658 init_error_sword(a);
1659 }
1660 break;
njn25e49d8e72002-09-23 09:36:25 +00001661
1662 default:
1663 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001664 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001665 }
1666
njn31513b42005-06-01 03:09:59 +00001667 //VGP_POPCC(VgpSARP);
njn25e49d8e72002-09-23 09:36:25 +00001668}
1669
1670
nethercote451eae92004-11-02 13:06:32 +00001671static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001672{
1673 //PROF_EVENT(??); PPP
1674 set_address_range_state ( a, len, Vge_SegmentInit );
1675}
1676
nethercote451eae92004-11-02 13:06:32 +00001677static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001678{
1679 //PROF_EVENT(36); PPP
1680 set_address_range_state( a, len, Vge_VirginInit );
1681}
1682
nethercote451eae92004-11-02 13:06:32 +00001683static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001684{
1685 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001686 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001687}
1688
1689
njn25e49d8e72002-09-23 09:36:25 +00001690/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001691static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001692{
1693 UInt i;
1694
1695 //PROF_EVENT(40); PPP
1696 for (i = 0; i < len; i += 4) {
1697 shadow_word sword = *(get_sword_addr ( src+i ));
1698 //PROF_EVENT(41); PPP
1699 set_sword ( dst+i, sword );
1700 }
1701}
1702
1703// SSS: put these somewhere better
njnfbdcba92005-05-09 01:23:49 +00001704static void hg_mem_read (Addr a, SizeT data_size, ThreadId tid);
1705static void hg_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001706
njnadb7a752005-06-11 01:30:57 +00001707__attribute__((unused))
njnfbdcba92005-05-09 01:23:49 +00001708static void hg_mem_help_read_1(Addr a) VGA_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001709__attribute__((unused))
njnfbdcba92005-05-09 01:23:49 +00001710static void hg_mem_help_read_2(Addr a) VGA_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001711__attribute__((unused))
njnfbdcba92005-05-09 01:23:49 +00001712static void hg_mem_help_read_4(Addr a) VGA_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001713__attribute__((unused))
njnfbdcba92005-05-09 01:23:49 +00001714static void hg_mem_help_read_N(Addr a, SizeT size) VGA_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001715
njnadb7a752005-06-11 01:30:57 +00001716__attribute__((unused))
njnfbdcba92005-05-09 01:23:49 +00001717static void hg_mem_help_write_1(Addr a, UInt val) VGA_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001718__attribute__((unused))
njnfbdcba92005-05-09 01:23:49 +00001719static void hg_mem_help_write_2(Addr a, UInt val) VGA_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001720__attribute__((unused))
njnfbdcba92005-05-09 01:23:49 +00001721static void hg_mem_help_write_4(Addr a, UInt val) VGA_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001722__attribute__((unused))
njnfbdcba92005-05-09 01:23:49 +00001723static void hg_mem_help_write_N(Addr a, SizeT size) VGA_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001724
njnadb7a752005-06-11 01:30:57 +00001725__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001726static void bus_lock(void);
njnadb7a752005-06-11 01:30:57 +00001727__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001728static void bus_unlock(void);
1729
njn25e49d8e72002-09-23 09:36:25 +00001730static
njnfbdcba92005-05-09 01:23:49 +00001731void hg_pre_mem_read(CorePart part, ThreadId tid,
1732 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001733{
njn02bc4b82005-05-15 17:28:26 +00001734 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 +00001735 hg_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001736}
1737
1738static
njnfbdcba92005-05-09 01:23:49 +00001739void hg_pre_mem_read_asciiz(CorePart part, ThreadId tid,
1740 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001741{
njnfbdcba92005-05-09 01:23:49 +00001742 hg_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001743}
1744
1745static
njnfbdcba92005-05-09 01:23:49 +00001746void hg_pre_mem_write(CorePart part, ThreadId tid,
1747 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001748{
njnfbdcba92005-05-09 01:23:49 +00001749 hg_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001750}
1751
1752
1753
1754static
njnfbdcba92005-05-09 01:23:49 +00001755void hg_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001756{
njn1f3a9092002-10-04 09:22:30 +00001757 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001758 make_segment_readable(a, len);
1759}
1760
1761
1762static
njnfbdcba92005-05-09 01:23:49 +00001763void hg_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001764{
1765 if (is_inited) {
1766 make_readable(a, len);
1767 } else {
1768 make_writable(a, len);
1769 }
1770}
1771
1772static
njnfbdcba92005-05-09 01:23:49 +00001773void hg_set_perms (Addr a, SizeT len,
1774 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001775{
1776 if (rr) make_readable(a, len);
1777 else if (ww) make_writable(a, len);
1778 /* else do nothing */
1779}
1780
sewardjf6374322002-11-13 22:35:55 +00001781static
njnfbdcba92005-05-09 01:23:49 +00001782void hg_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001783{
1784 set_address_range_state(a, len, Vge_NonVirginInit);
1785}
1786
1787static
njnfbdcba92005-05-09 01:23:49 +00001788void hg_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001789{
1790 set_address_range_state(a, len, Vge_VirginInit);
1791}
njn25e49d8e72002-09-23 09:36:25 +00001792
1793/*--------------------------------------------------------------*/
1794/*--- Initialise the memory audit system on program startup. ---*/
1795/*--------------------------------------------------------------*/
1796
1797static
1798void init_shadow_memory(void)
1799{
1800 Int i;
1801
1802 for (i = 0; i < ESEC_MAP_WORDS; i++)
1803 distinguished_secondary_map.swords[i] = virgin_sword;
1804
1805 /* These entries gradually get overwritten as the used address
1806 space expands. */
1807 for (i = 0; i < 65536; i++)
1808 primary_map[i] = &distinguished_secondary_map;
1809}
1810
1811
njn3e884182003-04-15 13:03:23 +00001812/*------------------------------------------------------------*/
1813/*--- malloc() et al replacements ---*/
1814/*------------------------------------------------------------*/
1815
njnb4aee052003-04-15 14:09:58 +00001816static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001817
1818#define N_FREED_CHUNKS 2
1819static Int freechunkptr = 0;
1820static HG_Chunk *freechunks[N_FREED_CHUNKS];
1821
njn3e884182003-04-15 13:03:23 +00001822
1823/* Allocate a user-chunk of size bytes. Also allocate its shadow
1824 block, make the shadow block point at the user block. Put the
1825 shadow chunk on the appropriate list, and set all memory
1826 protections correctly. */
1827
nethercote7ac7f7b2004-11-02 12:36:02 +00001828static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001829{
1830 HG_Chunk* hc;
1831
1832 hc = VG_(malloc)(sizeof(HG_Chunk));
1833 hc->data = p;
1834 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001835 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001836 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001837
1838 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1839}
1840
1841/* Allocate memory and note change in memory available */
1842static __inline__
njn14d01ce2004-11-26 11:30:14 +00001843void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1844 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001845{
1846 Addr p;
1847
njn34ac0272003-09-30 14:20:00 +00001848 if (size < 0) return NULL;
1849
njn3e884182003-04-15 13:03:23 +00001850 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001851 if (!p) {
1852 return NULL;
1853 }
njn34ac0272003-09-30 14:20:00 +00001854 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001855 add_HG_Chunk ( tid, p, size );
njnfbdcba92005-05-09 01:23:49 +00001856 hg_new_mem_heap( p, size, is_zeroed );
njn3e884182003-04-15 13:03:23 +00001857
1858 return (void*)p;
1859}
1860
njn51d827b2005-05-09 01:02:08 +00001861static void* hg_malloc ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001862{
njn14d01ce2004-11-26 11:30:14 +00001863 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001864}
1865
njn51d827b2005-05-09 01:02:08 +00001866static void* hg___builtin_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001867{
njn14d01ce2004-11-26 11:30:14 +00001868 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001869}
1870
njn51d827b2005-05-09 01:02:08 +00001871static void* hg___builtin_vec_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001872{
njn14d01ce2004-11-26 11:30:14 +00001873 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001874}
1875
njn51d827b2005-05-09 01:02:08 +00001876static void* hg_memalign ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001877{
njn14d01ce2004-11-26 11:30:14 +00001878 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001879}
1880
njn51d827b2005-05-09 01:02:08 +00001881static void* hg_calloc ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001882{
njn14d01ce2004-11-26 11:30:14 +00001883 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001884 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001885}
1886
thughes4ad52d02004-06-27 17:37:21 +00001887static ThreadId deadmx_tid;
1888
1889static
1890Bool deadmx(Mutex *mx) {
1891 if (mx->state != MxDead)
1892 set_mutex_state(mx, MxDead, deadmx_tid);
1893
1894 return False;
1895}
1896
njn3e884182003-04-15 13:03:23 +00001897static
njn72718642003-07-24 08:45:32 +00001898void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001899 HG_Chunk** prev_chunks_next_ptr )
1900{
njn72718642003-07-24 08:45:32 +00001901 Addr start = hc->data;
1902 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001903
njn3e884182003-04-15 13:03:23 +00001904 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1905 avoid repeating the hash table lookup. Can't remove until at least
1906 after free and free_mismatch errors are done because they use
1907 describe_addr() which looks for it in malloclist. */
1908 *prev_chunks_next_ptr = hc->next;
1909
1910 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001911 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001912
1913 /* maintain a small window so that the error reporting machinery
1914 knows about this memory */
1915 if (freechunks[freechunkptr] != NULL) {
1916 /* free HG_Chunk */
1917 HG_Chunk* sc1 = freechunks[freechunkptr];
1918 VG_(cli_free) ( (void*)(sc1->data) );
1919 VG_(free) ( sc1 );
1920 }
1921
1922 freechunks[freechunkptr] = hc;
1923
1924 if (++freechunkptr == N_FREED_CHUNKS)
1925 freechunkptr = 0;
1926
1927 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001928 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001929 find_mutex_range(start, end, deadmx);
1930}
1931
1932
1933static __inline__
njn14d01ce2004-11-26 11:30:14 +00001934void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001935{
1936 HG_Chunk* hc;
1937 HG_Chunk** prev_chunks_next_ptr;
1938
nethercote3d6b6112004-11-04 16:39:43 +00001939 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001940 (VgHashNode***)&prev_chunks_next_ptr );
1941 if (hc == NULL) {
1942 return;
1943 }
njn14d01ce2004-11-26 11:30:14 +00001944 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001945}
1946
njn51d827b2005-05-09 01:02:08 +00001947static void hg_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001948{
njn14d01ce2004-11-26 11:30:14 +00001949 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001950}
1951
njn51d827b2005-05-09 01:02:08 +00001952static void hg___builtin_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001953{
njn14d01ce2004-11-26 11:30:14 +00001954 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001955}
1956
njn51d827b2005-05-09 01:02:08 +00001957static void hg___builtin_vec_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001958{
njn14d01ce2004-11-26 11:30:14 +00001959 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001960}
1961
njn51d827b2005-05-09 01:02:08 +00001962static void* hg_realloc ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001963{
1964 HG_Chunk *hc;
1965 HG_Chunk **prev_chunks_next_ptr;
sewardj05bcdcb2003-05-18 10:05:38 +00001966 Int i;
njn3e884182003-04-15 13:03:23 +00001967
1968 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001969 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001970 (VgHashNode***)&prev_chunks_next_ptr );
1971
1972 if (hc == NULL) {
1973 return NULL;
1974 }
1975
1976 if (hc->size == new_size) {
1977 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001978 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001979 return p;
1980
1981 } else if (hc->size > new_size) {
1982 /* new size is smaller */
1983 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001984 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001985 return p;
1986
1987 } else {
1988 /* new size is bigger */
1989 Addr p_new;
1990
1991 /* Get new memory */
1992 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
1993
1994 /* First half kept and copied, second half new */
1995 copy_address_range_state( (Addr)p, p_new, hc->size );
njnfbdcba92005-05-09 01:23:49 +00001996 hg_new_mem_heap ( p_new+hc->size, new_size-hc->size,
1997 /*inited*/False );
njn3e884182003-04-15 13:03:23 +00001998
1999 /* Copy from old to new */
2000 for (i = 0; i < hc->size; i++)
2001 ((UChar*)p_new)[i] = ((UChar*)p)[i];
2002
2003 /* Free old memory */
njn72718642003-07-24 08:45:32 +00002004 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00002005
2006 /* this has to be after die_and_free_mem, otherwise the
2007 former succeeds in shorting out the new block, not the
2008 old, in the case when both are on the same list. */
njn72718642003-07-24 08:45:32 +00002009 add_HG_Chunk ( tid, p_new, new_size );
njn3e884182003-04-15 13:03:23 +00002010
2011 return (void*)p_new;
2012 }
2013}
2014
njn25e49d8e72002-09-23 09:36:25 +00002015/*--------------------------------------------------------------*/
2016/*--- Machinery to support sanity checking ---*/
2017/*--------------------------------------------------------------*/
2018
njn51d827b2005-05-09 01:02:08 +00002019static Bool hg_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00002020{
jseward9800fd32004-01-04 23:08:04 +00002021 /* nothing useful we can rapidly check */
2022 return True;
njn25e49d8e72002-09-23 09:36:25 +00002023}
2024
njn51d827b2005-05-09 01:02:08 +00002025static Bool hg_expensive_sanity_check(void)
njn25e49d8e72002-09-23 09:36:25 +00002026{
2027 Int i;
2028
2029 /* Make sure nobody changed the distinguished secondary. */
2030 for (i = 0; i < ESEC_MAP_WORDS; i++)
2031 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2032 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2033 return False;
2034
2035 return True;
2036}
2037
2038
2039/*--------------------------------------------------------------*/
2040/*--- Instrumentation ---*/
2041/*--------------------------------------------------------------*/
2042
sewardjf6374322002-11-13 22:35:55 +00002043static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2044
njn14d01ce2004-11-26 11:30:14 +00002045#if 0
njn25e49d8e72002-09-23 09:36:25 +00002046/* Create and return an instrumented version of cb_in. Free cb_in
2047 before returning. */
njn26f02512004-11-22 18:33:15 +00002048UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002049{
2050 UCodeBlock* cb;
2051 Int i;
2052 UInstr* u_in;
2053 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002054 Int ntemps;
2055 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002056 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002057
njn810086f2002-11-14 12:42:47 +00002058 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002059
sewardjf6374322002-11-13 22:35:55 +00002060 /* stackref[] is used for super-simple value tracking to keep note
2061 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002062 the stack pointer or frame pointer, and is therefore likely
2063 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002064 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002065 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2066 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2067
njn810086f2002-11-14 12:42:47 +00002068 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2069 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002070
njn25e49d8e72002-09-23 09:36:25 +00002071 switch (u_in->opcode) {
2072
2073 case NOP: case CALLM_S: case CALLM_E:
2074 break;
sewardjf6374322002-11-13 22:35:55 +00002075
sewardj7a5ebcf2002-11-13 22:42:13 +00002076 case LOCK:
2077 locked = True;
2078 uInstr0(cb, CCALL, 0);
2079 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2080 break;
2081
2082 case JMP: case INCEIP:
2083 if (locked) {
2084 uInstr0(cb, CCALL, 0);
2085 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2086 }
2087 locked = False;
2088 VG_(copy_UInstr)(cb, u_in);
2089 break;
2090
sewardjf6374322002-11-13 22:35:55 +00002091 case GET:
njnca82cc02004-11-22 17:18:48 +00002092 tl_assert(u_in->tag1 == ArchReg);
2093 tl_assert(u_in->tag2 == TempReg);
2094 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002095
2096 stackref[u_in->val2] = (u_in->size == 4 &&
njndb9b7732005-03-26 00:32:29 +00002097 (u_in->val1 == VGA_R_STACK_PTR ||
2098 u_in->val1 == VGA_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002099 VG_(copy_UInstr)(cb, u_in);
2100 break;
2101
2102 case MOV:
2103 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002104 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002105 stackref[u_in->val2] = stackref[u_in->val1];
2106 }
2107 VG_(copy_UInstr)(cb, u_in);
2108 break;
2109
2110 case LEA1:
2111 case ADD: case SUB:
2112 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002113 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002114 stackref[u_in->val2] |= stackref[u_in->val1];
2115 }
2116 VG_(copy_UInstr)(cb, u_in);
2117 break;
njn25e49d8e72002-09-23 09:36:25 +00002118
sewardja5b3aec2002-10-22 05:09:36 +00002119 case LOAD: {
2120 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002121 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2122 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002123
2124 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2125 nonstk_ld++;
2126
2127 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002128 case 1: help = hg_mem_help_read_1; break;
2129 case 2: help = hg_mem_help_read_2; break;
2130 case 4: help = hg_mem_help_read_4; break;
sewardjf6374322002-11-13 22:35:55 +00002131 default:
njn67993252004-11-22 18:02:32 +00002132 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002133 }
jsgfcb1d1c02003-10-14 21:55:10 +00002134
2135 /* XXX all registers should be flushed to baseblock
2136 here */
sewardjf6374322002-11-13 22:35:55 +00002137 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2138 uCCall(cb, (Addr)help, 1, 1, False);
2139 } else
2140 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002141
sewardja5b3aec2002-10-22 05:09:36 +00002142 VG_(copy_UInstr)(cb, u_in);
2143 t_size = INVALID_TEMPREG;
2144 break;
2145 }
2146
fitzhardinge111c6072004-03-09 02:45:07 +00002147 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002148 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002149 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002150 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002151
fitzhardinge111c6072004-03-09 02:45:07 +00002152 t_size = newTemp(cb);
2153 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2154 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002155
fitzhardinge111c6072004-03-09 02:45:07 +00002156 /* XXX all registers should be flushed to baseblock
2157 here */
2158 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002159 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002160
2161 VG_(copy_UInstr)(cb, u_in);
2162 t_size = INVALID_TEMPREG;
2163 break;
sewardja5b3aec2002-10-22 05:09:36 +00002164 }
2165
thughes96b466a2004-03-15 16:43:58 +00002166 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002167 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002168
2169 t_size = newTemp(cb);
2170 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2171 uLiteral(cb, (UInt)u_in->size);
2172
2173 /* XXX all registers should be flushed to baseblock
2174 here */
2175 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002176 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
thughes96b466a2004-03-15 16:43:58 +00002177
2178 VG_(copy_UInstr)(cb, u_in);
2179 t_size = INVALID_TEMPREG;
2180 break;
2181 }
2182
fitzhardinge111c6072004-03-09 02:45:07 +00002183 case SSE2a_MemRd:
2184 case SSE2a1_MemRd:
2185 case SSE3a_MemRd:
2186 case SSE3a1_MemRd:
2187 case SSE3ag_MemRd_RegWr: {
2188 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2189
njnca82cc02004-11-22 17:18:48 +00002190 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002191
2192 t_size = newTemp(cb);
2193 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2194 uLiteral(cb, (UInt)u_in->size);
2195
2196 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002197 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002198
2199 VG_(copy_UInstr)(cb, u_in);
2200 t_size = INVALID_TEMPREG;
2201 break;
2202 }
2203
sewardja5b3aec2002-10-22 05:09:36 +00002204 case STORE: {
2205 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002206 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2207 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002208
sewardjf6374322002-11-13 22:35:55 +00002209 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2210 nonstk_st++;
2211
2212 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002213 case 1: help = hg_mem_help_write_1; break;
2214 case 2: help = hg_mem_help_write_2; break;
2215 case 4: help = hg_mem_help_write_4; break;
sewardjf6374322002-11-13 22:35:55 +00002216 default:
njn67993252004-11-22 18:02:32 +00002217 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002218 }
2219
jsgfcb1d1c02003-10-14 21:55:10 +00002220 /* XXX all registers should be flushed to baseblock
2221 here */
sewardjf6374322002-11-13 22:35:55 +00002222 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2223 uCCall(cb, (Addr)help, 2, 2, False);
2224 } else
2225 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002226
2227 VG_(copy_UInstr)(cb, u_in);
2228 t_size = INVALID_TEMPREG;
2229 break;
2230 }
2231
fitzhardinge111c6072004-03-09 02:45:07 +00002232 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002233 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002234 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002235 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002236
2237 t_size = newTemp(cb);
2238 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2239 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002240 /* XXX all registers should be flushed to baseblock
2241 here */
sewardja5b3aec2002-10-22 05:09:36 +00002242 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002243 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
sewardja5b3aec2002-10-22 05:09:36 +00002244
2245 VG_(copy_UInstr)(cb, u_in);
2246 t_size = INVALID_TEMPREG;
2247 break;
2248 }
njn25e49d8e72002-09-23 09:36:25 +00002249
fitzhardinge111c6072004-03-09 02:45:07 +00002250 case SSE2a_MemWr:
2251 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002252 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002253 512 == u_in->size);
2254
2255 t_size = newTemp(cb);
2256 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2257 uLiteral(cb, (UInt)u_in->size);
2258 /* XXX all registers should be flushed to baseblock
2259 here */
2260 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002261 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002262
2263 VG_(copy_UInstr)(cb, u_in);
2264 t_size = INVALID_TEMPREG;
2265 break;
2266 }
sewardj3d7c9c82003-03-26 21:08:13 +00002267
njn25e49d8e72002-09-23 09:36:25 +00002268 default:
sewardjf6374322002-11-13 22:35:55 +00002269 /* conservative tromping */
2270 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2271 stackref[u_in->val1] = False;
2272 if (u_in->tag2 == TempReg)
2273 stackref[u_in->val2] = False;
2274 if (u_in->tag3 == TempReg)
2275 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002276 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002277 break;
2278 }
2279 }
2280
sewardjf6374322002-11-13 22:35:55 +00002281 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002282 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002283 return cb;
2284}
njn14d01ce2004-11-26 11:30:14 +00002285#endif
njn51d827b2005-05-09 01:02:08 +00002286static IRBB* hg_instrument ( IRBB* bb_in, VexGuestLayout* layout,
2287 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002288{
2289 VG_(message)(Vg_DebugMsg, "Helgrind is not yet ready to handle Vex IR");
2290 VG_(exit)(1);
2291}
njn25e49d8e72002-09-23 09:36:25 +00002292
2293/*--------------------------------------------------------------------*/
2294/*--- Error and suppression handling ---*/
2295/*--------------------------------------------------------------------*/
2296
2297typedef
2298 enum {
2299 /* Possible data race */
njnfbdcba92005-05-09 01:23:49 +00002300 RaceSupp
njn25e49d8e72002-09-23 09:36:25 +00002301 }
njnfbdcba92005-05-09 01:23:49 +00002302 RaceSuppKind;
njn25e49d8e72002-09-23 09:36:25 +00002303
2304/* What kind of error it is. */
2305typedef
2306 enum {
njnfbdcba92005-05-09 01:23:49 +00002307 RaceErr, /* data-race */
sewardj16748af2002-10-22 04:55:54 +00002308 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002309 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002310 }
njnfbdcba92005-05-09 01:23:49 +00002311 RaceErrorKind;
njn25e49d8e72002-09-23 09:36:25 +00002312
sewardj16748af2002-10-22 04:55:54 +00002313/* The classification of a faulting address. */
2314typedef
2315 enum { Undescribed, /* as-yet unclassified */
2316 Stack,
2317 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002318 Mallocd,
2319 Freed,
sewardj16748af2002-10-22 04:55:54 +00002320 Segment
2321 }
2322 AddrKind;
2323/* Records info about a faulting address. */
2324typedef
2325 struct {
2326 /* ALL */
2327 AddrKind akind;
2328 /* Freed, Mallocd */
2329 Int blksize;
2330 /* Freed, Mallocd */
2331 Int rwoffset;
2332 /* Freed, Mallocd */
2333 ExeContext* lastchange;
2334 ThreadId lasttid;
2335 /* Stack */
2336 ThreadId stack_tid;
2337 /* Segment */
2338 const Char* filename;
2339 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002340 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002341 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002342 /* symbolic address description */
2343 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002344 }
2345 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002346
sewardj16748af2002-10-22 04:55:54 +00002347/* What kind of memory access is involved in the error? */
2348typedef
2349 enum { ReadAxs, WriteAxs, ExecAxs }
2350 AxsKind;
2351
2352/* Extra context for memory errors */
2353typedef
2354 struct {
2355 AxsKind axskind;
2356 Int size;
2357 AddrInfo addrinfo;
2358 Bool isWrite;
2359 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002360 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002361 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002362 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002363 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002364 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002365 const LockSet *held_lockset;
2366 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002367 }
2368 HelgrindError;
2369
2370static __inline__
2371void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002372{
sewardj16748af2002-10-22 04:55:54 +00002373 ai->akind = Unknown;
2374 ai->blksize = 0;
2375 ai->rwoffset = 0;
2376 ai->lastchange = NULL;
2377 ai->lasttid = VG_INVALID_THREADID;
2378 ai->filename = NULL;
2379 ai->section = "???";
2380 ai->stack_tid = VG_INVALID_THREADID;
2381 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002382 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002383}
2384
sewardj16748af2002-10-22 04:55:54 +00002385static __inline__
2386void clear_HelgrindError ( HelgrindError* err_extra )
2387{
2388 err_extra->axskind = ReadAxs;
2389 err_extra->size = 0;
2390 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002391 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002392 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002393 err_extra->prev_lockset = 0;
2394 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002395 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002396 clear_AddrInfo ( &err_extra->addrinfo );
2397 err_extra->isWrite = False;
2398}
2399
2400
2401
2402/* Describe an address as best you can, for error messages,
2403 putting the result in ai. */
2404
thughes4ad52d02004-06-27 17:37:21 +00002405/* Callback for searching malloc'd and free'd lists */
2406static Bool addr_is_in_block(VgHashNode *node, void *ap)
2407{
2408 HG_Chunk* hc2 = (HG_Chunk*)node;
2409 Addr a = *(Addr *)ap;
2410
2411 return (hc2->data <= a && a < hc2->data + hc2->size);
2412}
2413
sewardj16748af2002-10-22 04:55:54 +00002414static void describe_addr ( Addr a, AddrInfo* ai )
2415{
njn3e884182003-04-15 13:03:23 +00002416 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002417 Int i;
sewardj16748af2002-10-22 04:55:54 +00002418
sewardj16748af2002-10-22 04:55:54 +00002419 /* Search for it in segments */
2420 {
njn36ef6ba2005-05-14 18:42:26 +00002421 const SegInfo *si;
sewardj16748af2002-10-22 04:55:54 +00002422
njn36ef6ba2005-05-14 18:42:26 +00002423 for (si = VG_(next_seginfo)(NULL);
2424 si != NULL;
2425 si = VG_(next_seginfo)(si))
2426 {
2427 Addr base = VG_(seg_start)(si);
2428 SizeT size = VG_(seg_size)(si);
2429 const UChar *filename = VG_(seg_filename)(si);
sewardj16748af2002-10-22 04:55:54 +00002430
2431 if (a >= base && a < base+size) {
2432 ai->akind = Segment;
2433 ai->blksize = size;
2434 ai->rwoffset = a - base;
2435 ai->filename = filename;
2436
2437 switch(VG_(seg_sect_kind)(a)) {
2438 case Vg_SectText: ai->section = "text"; break;
2439 case Vg_SectData: ai->section = "data"; break;
2440 case Vg_SectBSS: ai->section = "BSS"; break;
2441 case Vg_SectGOT: ai->section = "GOT"; break;
2442 case Vg_SectPLT: ai->section = "PLT"; break;
2443 case Vg_SectUnknown:
2444 default:
2445 ai->section = "???"; break;
2446 }
2447
2448 return;
2449 }
2450 }
2451 }
2452
2453 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002454 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002455 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002456 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002457 ai->blksize = hc->size;
2458 ai->rwoffset = (Int)a - (Int)(hc->data);
2459 ai->lastchange = hc->where;
2460 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002461 return;
2462 }
sewardjdac0a442002-11-13 22:08:40 +00002463
2464 /* Look in recently freed memory */
2465 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002466 hc = freechunks[i];
2467 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002468 continue;
2469
njn3e884182003-04-15 13:03:23 +00002470 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002471 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002472 ai->blksize = hc->size;
2473 ai->rwoffset = a - hc->data;
2474 ai->lastchange = hc->where;
2475 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002476 return;
2477 }
2478 }
2479
sewardj16748af2002-10-22 04:55:54 +00002480 /* Clueless ... */
2481 ai->akind = Unknown;
2482 return;
2483}
2484
2485
njn7e614812003-04-21 22:04:03 +00002486/* Updates the copy with address info if necessary. */
njn51d827b2005-05-09 01:02:08 +00002487static UInt hg_update_extra(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002488{
njn7e614812003-04-21 22:04:03 +00002489 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002490
njn7e614812003-04-21 22:04:03 +00002491 extra = (HelgrindError*)VG_(get_error_extra)(err);
2492 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2493 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2494 }
2495 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002496}
2497
njnfbdcba92005-05-09 01:23:49 +00002498static void record_race_error ( ThreadId tid, Addr a, Bool is_write,
2499 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002500{
sewardjc4a810d2002-11-13 22:25:51 +00002501 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002502 HelgrindError err_extra;
2503
njnfbdcba92005-05-09 01:23:49 +00002504 n_hg_warnings++;
sewardjff2c9232002-11-13 21:44:39 +00002505
sewardj16748af2002-10-22 04:55:54 +00002506 clear_HelgrindError(&err_extra);
2507 err_extra.isWrite = is_write;
2508 err_extra.addrinfo.akind = Undescribed;
2509 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002510 if (clo_execontext)
2511 err_extra.lasttouched = getExeContext(a);
jsgfcb1d1c02003-10-14 21:55:10 +00002512 err_extra.addrinfo.expr = VG_(describe_addr)(tid, a);
2513
njnfbdcba92005-05-09 01:23:49 +00002514 VG_(maybe_record_error)( tid, RaceErr, a,
sewardj16748af2002-10-22 04:55:54 +00002515 (is_write ? "writing" : "reading"),
2516 &err_extra);
2517
sewardjc4a810d2002-11-13 22:25:51 +00002518 sw = get_sword_addr(a);
2519 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2520 ThreadLifeSeg *tls = unpackTLS(sw->other);
2521 tls->refcount--;
2522 }
2523
sewardj7f3ad222002-11-13 22:11:53 +00002524 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002525}
2526
sewardj39a4d842002-11-13 22:14:30 +00002527static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002528 Char *str, ExeContext *ec)
2529{
2530 HelgrindError err_extra;
2531
2532 clear_HelgrindError(&err_extra);
2533 err_extra.addrinfo.akind = Undescribed;
2534 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002535 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002536 err_extra.lasttid = tid;
2537
njn72718642003-07-24 08:45:32 +00002538 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002539 (Addr)mutex->mutexp, str, &err_extra);
2540}
njn25e49d8e72002-09-23 09:36:25 +00002541
sewardj39a4d842002-11-13 22:14:30 +00002542static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002543 const LockSet *lockset_holding,
2544 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002545{
2546 HelgrindError err_extra;
2547
2548 n_lockorder_warnings++;
2549
2550 clear_HelgrindError(&err_extra);
2551 err_extra.addrinfo.akind = Undescribed;
2552 err_extra.mutex = mutex;
2553
sewardjc808ef52002-11-13 22:43:26 +00002554 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002555 err_extra.held_lockset = lockset_holding;
2556 err_extra.prev_lockset = lockset_prev;
2557
njn72718642003-07-24 08:45:32 +00002558 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002559}
2560
njn51d827b2005-05-09 01:02:08 +00002561static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002562{
njn810086f2002-11-14 12:42:47 +00002563 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002564
njnca82cc02004-11-22 17:18:48 +00002565 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002566
2567 switch (VG_(get_error_kind)(e1)) {
njnfbdcba92005-05-09 01:23:49 +00002568 case RaceErr:
njn810086f2002-11-14 12:42:47 +00002569 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002570
2571 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002572 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002573 }
2574
njn810086f2002-11-14 12:42:47 +00002575 e1s = VG_(get_error_string)(e1);
2576 e2s = VG_(get_error_string)(e2);
2577 if (e1s != e2s) return False;
2578 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002579 return True;
2580}
2581
sewardj16748af2002-10-22 04:55:54 +00002582static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002583{
jsgfcb1d1c02003-10-14 21:55:10 +00002584 if (ai->expr != NULL)
2585 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002586 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002587
sewardj16748af2002-10-22 04:55:54 +00002588 switch (ai->akind) {
2589 case Stack:
2590 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002591 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002592 a, ai->stack_tid);
2593 break;
2594 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002595 if (ai->expr != NULL)
2596 break;
2597
nethercote3b390c72003-11-13 17:53:43 +00002598 /* maybe_gcc is never set to True! This is a hangover from code
2599 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002600 if (ai->maybe_gcc) {
2601 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002602 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002603 a);
2604 VG_(message)(Vg_UserMsg,
2605 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2606 } else {
2607 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002608 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002609 }
2610 break;
2611 case Segment:
2612 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002613 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002614 a, ai->section, ai->filename);
2615 break;
sewardjdac0a442002-11-13 22:08:40 +00002616 case Mallocd:
2617 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002618 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002619 UChar* relative;
2620 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002621 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002622 relative = "before";
2623 } else if (ai->rwoffset >= ai->blksize) {
2624 delta = ai->rwoffset - ai->blksize;
2625 relative = "after";
2626 } else {
2627 delta = ai->rwoffset;
2628 relative = "inside";
2629 }
2630 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002631 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2632 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002633 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002634 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002635 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002636
sewardj16748af2002-10-22 04:55:54 +00002637 VG_(pp_ExeContext)(ai->lastchange);
2638 break;
2639 }
2640 default:
njn67993252004-11-22 18:02:32 +00002641 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002642 }
njn25e49d8e72002-09-23 09:36:25 +00002643}
2644
sewardj4bffb232002-11-13 21:46:34 +00002645static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002646{
sewardjff2c9232002-11-13 21:44:39 +00002647 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002648 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002649
sewardj4bffb232002-11-13 21:46:34 +00002650 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2651 lockset->setsize * 120 +
2652 1);
sewardjff2c9232002-11-13 21:44:39 +00002653
2654 cp = buf;
2655 if (prefix)
2656 cp += VG_(sprintf)(cp, "%s", prefix);
2657
sewardj4bffb232002-11-13 21:46:34 +00002658 for(i = 0; i < lockset->setsize; i++)
2659 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2660 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002661
sewardj4bffb232002-11-13 21:46:34 +00002662 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002663 cp[-2] = '\0';
2664 else
2665 *cp = '\0';
2666
2667 return buf;
2668}
njn25e49d8e72002-09-23 09:36:25 +00002669
njn51d827b2005-05-09 01:02:08 +00002670static void hg_pp_Error ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002671{
njn810086f2002-11-14 12:42:47 +00002672 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002673 Char buf[100];
2674 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002675 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002676
2677 *msg = '\0';
2678
njn810086f2002-11-14 12:42:47 +00002679 switch(VG_(get_error_kind)(err)) {
njnfbdcba92005-05-09 01:23:49 +00002680 case RaceErr: {
njn810086f2002-11-14 12:42:47 +00002681 Addr err_addr = VG_(get_error_address)(err);
2682
sewardj16748af2002-10-22 04:55:54 +00002683 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002684 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002685 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002686 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002687
2688 switch(extra->prevstate.state) {
2689 case Vge_Virgin:
2690 /* shouldn't be possible to go directly from virgin -> error */
2691 VG_(sprintf)(buf, "virgin!?");
2692 break;
2693
sewardjc4a810d2002-11-13 22:25:51 +00002694 case Vge_Excl: {
2695 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2696
njnca82cc02004-11-22 17:18:48 +00002697 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002698 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002699 break;
sewardjc4a810d2002-11-13 22:25:51 +00002700 }
sewardj16748af2002-10-22 04:55:54 +00002701
2702 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002703 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002704 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002705
2706 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002707 VG_(sprintf)(buf, "shared %s, no locks",
2708 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2709 break;
2710 }
2711
sewardjff2c9232002-11-13 21:44:39 +00002712 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2713 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002714 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002715
sewardj16748af2002-10-22 04:55:54 +00002716 break;
2717 }
sewardj16748af2002-10-22 04:55:54 +00002718
sewardj499e3de2002-11-13 22:22:25 +00002719 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002720 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002721
sewardj72baa7a2002-12-09 23:32:58 +00002722 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002723 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002724 Char file[100];
2725 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002726 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002727
nethercote3b390c72003-11-13 17:53:43 +00002728 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002729 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002730 pp_state(extra->lasttouched.state),
2731 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002732
nethercoteca788ff2004-10-20 10:58:09 +00002733 if (VG_(get_filename_linenum)(ip, file, sizeof(file), &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002734 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002735 ip, ip, file, line);
2736 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002737 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002738 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002739 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002740 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002741 }
sewardj72baa7a2002-12-09 23:32:58 +00002742 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002743 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002744 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002745 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002746 pp_state(extra->lasttouched.state),
2747 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002748 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002749 }
sewardj16748af2002-10-22 04:55:54 +00002750 break;
njn810086f2002-11-14 12:42:47 +00002751 }
sewardj16748af2002-10-22 04:55:54 +00002752
2753 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002754 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002755 VG_(get_error_address)(err),
2756 VG_(get_error_address)(err),
2757 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002758 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002759 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002760 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002761 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002762 }
njn810086f2002-11-14 12:42:47 +00002763 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002764 break;
sewardjff2c9232002-11-13 21:44:39 +00002765
2766 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002767 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002768 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002769 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002770
2771 msg = lockset_str(NULL, heldset);
2772
2773 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002774 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002775 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002776 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2777
sewardj4bffb232002-11-13 21:46:34 +00002778 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002779 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002780
sewardj542494b2002-11-13 22:46:13 +00002781 /* needs to be a recursive search+display */
2782 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002783 continue;
2784
nethercote3b390c72003-11-13 17:53:43 +00002785 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002786 lsmx->mutexp, lsmx->mutexp);
2787 VG_(pp_ExeContext)(lsmx->location);
2788 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002789 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002790 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002791 }
2792
2793 break;
sewardj16748af2002-10-22 04:55:54 +00002794 }
sewardjff2c9232002-11-13 21:44:39 +00002795 }
2796
2797 if (msg != buf)
2798 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002799}
2800
2801
njn51d827b2005-05-09 01:02:08 +00002802static Bool hg_recognised_suppression ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002803{
2804 if (0 == VG_(strcmp)(name, "Eraser")) {
njnfbdcba92005-05-09 01:23:49 +00002805 VG_(set_supp_kind)(su, RaceSupp);
njn25e49d8e72002-09-23 09:36:25 +00002806 return True;
2807 } else {
2808 return False;
2809 }
2810}
2811
2812
njn51d827b2005-05-09 01:02:08 +00002813static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002814{
2815 /* do nothing -- no extra suppression info present. Return True to
2816 indicate nothing bad happened. */
2817 return True;
2818}
2819
2820
njn51d827b2005-05-09 01:02:08 +00002821static Bool hg_error_matches_suppression(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002822{
njnfbdcba92005-05-09 01:23:49 +00002823 tl_assert(VG_(get_supp_kind)(su) == RaceSupp);
nethercote64366b42003-12-01 13:11:47 +00002824
njnfbdcba92005-05-09 01:23:49 +00002825 return (VG_(get_error_kind)(err) == RaceErr);
njn25e49d8e72002-09-23 09:36:25 +00002826}
2827
njn51d827b2005-05-09 01:02:08 +00002828static Char* hg_get_error_name ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002829{
njnfbdcba92005-05-09 01:23:49 +00002830 if (RaceErr == VG_(get_error_kind)(err)) {
2831 return "Eraser"; // old name, required for backwards compatibility
njn43c799e2003-04-08 00:08:52 +00002832 } else {
2833 return NULL; /* Other errors types can't be suppressed */
2834 }
2835}
2836
njn51d827b2005-05-09 01:02:08 +00002837static void hg_print_extra_suppression_info ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002838{
2839 /* Do nothing */
2840}
njn25e49d8e72002-09-23 09:36:25 +00002841
njnfbdcba92005-05-09 01:23:49 +00002842static void hg_pre_mutex_lock(ThreadId tid, void* void_mutex)
sewardjdca84112002-11-13 22:29:34 +00002843{
2844 Mutex *mutex = get_mutex((Addr)void_mutex);
2845
njn72718642003-07-24 08:45:32 +00002846 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002847}
2848
njnfbdcba92005-05-09 01:23:49 +00002849static void hg_post_mutex_lock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002850{
sewardj4bffb232002-11-13 21:46:34 +00002851 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002852 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002853 const LockSet* ls;
2854
njn72718642003-07-24 08:45:32 +00002855 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002856
njn25e49d8e72002-09-23 09:36:25 +00002857# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002858 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002859# endif
2860
njn25e49d8e72002-09-23 09:36:25 +00002861 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2862# if LOCKSET_SANITY > 1
njnfbdcba92005-05-09 01:23:49 +00002863 sanity_check_locksets("hg_post_mutex_lock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002864# endif
2865
sewardj4bffb232002-11-13 21:46:34 +00002866 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002867
sewardj4bffb232002-11-13 21:46:34 +00002868 if (ls == NULL) {
2869 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2870 insert_LockSet(newset);
2871 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002872 }
sewardj4bffb232002-11-13 21:46:34 +00002873 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002874
sewardj4bffb232002-11-13 21:46:34 +00002875 if (debug || DEBUG_LOCKS)
2876 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002877
sewardj4bffb232002-11-13 21:46:34 +00002878 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002879 sanity_check_locksets("hg_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002880}
2881
2882
njnfbdcba92005-05-09 01:23:49 +00002883static void hg_post_mutex_unlock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002884{
sewardjc26cc252002-10-23 21:58:55 +00002885 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002886 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002887 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002888 const LockSet *ls;
2889
njn72718642003-07-24 08:45:32 +00002890 test_mutex_state(mutex, MxUnlocked, tid);
2891 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002892
sewardjdac0a442002-11-13 22:08:40 +00002893 if (!ismember(thread_locks[tid], mutex))
2894 return;
2895
sewardjc26cc252002-10-23 21:58:55 +00002896 if (debug || DEBUG_LOCKS)
2897 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002898
sewardjc26cc252002-10-23 21:58:55 +00002899 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002900 sanity_check_locksets("hg_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002901
sewardj4bffb232002-11-13 21:46:34 +00002902 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002903
sewardj4bffb232002-11-13 21:46:34 +00002904 if (ls == NULL) {
2905 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2906 insert_LockSet(newset);
2907 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002908 }
2909
2910 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002911 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002912 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002913 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002914
sewardj4bffb232002-11-13 21:46:34 +00002915 thread_locks[tid] = ls;
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-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002919}
2920
2921
2922/* ---------------------------------------------------------------------
2923 Checking memory reads and writes
2924 ------------------------------------------------------------------ */
2925
2926/* Behaviour on reads and writes:
2927 *
2928 * VIR EXCL SHAR SH_MOD
2929 * ----------------------------------------------------------------
2930 * rd/wr, 1st thread | - EXCL - -
2931 * rd, new thread | - SHAR - -
2932 * wr, new thread | - SH_MOD - -
2933 * rd | error! - SHAR SH_MOD
2934 * wr | EXCL - SH_MOD SH_MOD
2935 * ----------------------------------------------------------------
2936 */
2937
sewardj8fac99a2002-11-13 22:31:26 +00002938static inline
njn25e49d8e72002-09-23 09:36:25 +00002939void dump_around_a(Addr a)
2940{
2941 UInt i;
2942 shadow_word* sword;
2943 VG_(printf)("NEARBY:\n");
2944 for (i = a - 12; i <= a + 12; i += 4) {
2945 sword = get_sword_addr(i);
2946 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2947 }
2948}
njn25e49d8e72002-09-23 09:36:25 +00002949
2950#if DEBUG_ACCESSES
2951 #define DEBUG_STATE(args...) \
2952 VG_(printf)("(%u) ", size), \
2953 VG_(printf)(args)
2954#else
2955 #define DEBUG_STATE(args...)
2956#endif
2957
njnfbdcba92005-05-09 01:23:49 +00002958static void hg_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002959{
sewardj72baa7a2002-12-09 23:32:58 +00002960 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002961 shadow_word prevstate;
2962 ThreadLifeSeg *tls;
2963 const LockSet *ls;
2964 Bool statechange = False;
2965
2966 static const void *const states[4] = {
2967 [Vge_Virgin] &&st_virgin,
2968 [Vge_Excl] &&st_excl,
2969 [Vge_Shar] &&st_shar,
2970 [Vge_SharMod] &&st_sharmod,
2971 };
2972
2973 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002974 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002975
2976 sword = get_sword_addr(a);
2977 if (sword == SEC_MAP_ACCESS) {
2978 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2979 return;
2980 }
2981
2982 prevstate = *sword;
2983
2984 goto *states[sword->state];
2985
2986 /* This looks like reading of unitialised memory, may be legit. Eg.
2987 * calloc() zeroes its values, so untouched memory may actually be
2988 * initialised. Leave that stuff to Valgrind. */
2989 st_virgin:
2990 if (TID_INDICATING_NONVIRGIN == sword->other) {
2991 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
2992 if (DEBUG_VIRGIN_READS)
2993 dump_around_a(a);
2994 } else {
2995 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
2996 }
2997 statechange = True;
2998 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
2999 tls->refcount++;
3000 goto done;
3001
3002 st_excl: {
3003 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3004
3005 if (tls == sw_tls) {
3006 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
3007 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3008 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
3009 } else if (tlsIsDisjoint(tls, sw_tls)) {
3010 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3011 statechange = True;
3012 sword->other = packTLS(tls);
3013 sw_tls->refcount--;
3014 tls->refcount++;
3015 } else {
3016 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3017 sw_tls->refcount--;
3018 statechange = True;
3019 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3020
3021 if (DEBUG_MEM_LOCKSET_CHANGES)
3022 print_LockSet("excl read locks", unpackLockSet(sword->other));
3023 }
3024 goto done;
3025 }
3026
3027 st_shar:
3028 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3029 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3030 thread_locks[tid]));
3031 statechange = sword->other != prevstate.other;
3032 goto done;
3033
3034 st_sharmod:
3035 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3036 ls = intersect(unpackLockSet(sword->other),
3037 thread_locks[tid]);
3038 sword->other = packLockSet(ls);
3039
3040 statechange = sword->other != prevstate.other;
3041
3042 if (isempty(ls)) {
njnfbdcba92005-05-09 01:23:49 +00003043 record_race_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003044 }
3045 goto done;
3046
3047 done:
3048 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003049 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003050
3051 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003052 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003053 else
njnd01fef72005-03-25 23:35:48 +00003054 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003055 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003056 }
3057}
njn25e49d8e72002-09-23 09:36:25 +00003058
njnfbdcba92005-05-09 01:23:49 +00003059static void hg_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003060{
njn72718642003-07-24 08:45:32 +00003061 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003062
njn13bfd852005-06-02 03:52:53 +00003063 end = VG_ROUNDUP(a+size, 4);
3064 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003065
sewardj18cd4a52002-11-13 22:37:41 +00003066 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003067 hg_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003068}
3069
njnfbdcba92005-05-09 01:23:49 +00003070static void hg_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003071{
3072 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003073 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003074 shadow_word prevstate;
3075 Bool statechange = False;
3076 static const void *const states[4] = {
3077 [Vge_Virgin] &&st_virgin,
3078 [Vge_Excl] &&st_excl,
3079 [Vge_Shar] &&st_shar,
3080 [Vge_SharMod] &&st_sharmod,
3081 };
3082
sewardjc4a810d2002-11-13 22:25:51 +00003083 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003084 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003085
sewardj18cd4a52002-11-13 22:37:41 +00003086 sword = get_sword_addr(a);
3087 if (sword == SEC_MAP_ACCESS) {
3088 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3089 return;
3090 }
njn25e49d8e72002-09-23 09:36:25 +00003091
sewardj18cd4a52002-11-13 22:37:41 +00003092 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003093
sewardj18cd4a52002-11-13 22:37:41 +00003094 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003095
sewardj18cd4a52002-11-13 22:37:41 +00003096 st_virgin:
3097 if (TID_INDICATING_NONVIRGIN == sword->other)
3098 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3099 else
3100 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3101 statechange = True;
3102 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3103 tls->refcount++;
3104 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003105
sewardj18cd4a52002-11-13 22:37:41 +00003106 st_excl: {
3107 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3108
3109 if (tls == sw_tls) {
3110 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3111 goto done;
3112 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3113 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3114 goto done;
3115 } else if (tlsIsDisjoint(tls, sw_tls)) {
3116 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3117 sword->other = packTLS(tls);
3118 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003119 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003120 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003121 } else {
3122 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3123 statechange = True;
3124 sw_tls->refcount--;
3125 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3126 if(DEBUG_MEM_LOCKSET_CHANGES)
3127 print_LockSet("excl write locks", unpackLockSet(sword->other));
3128 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003129 }
sewardj18cd4a52002-11-13 22:37:41 +00003130 }
njn25e49d8e72002-09-23 09:36:25 +00003131
sewardj18cd4a52002-11-13 22:37:41 +00003132 st_shar:
3133 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3134 sword->state = Vge_SharMod;
3135 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3136 thread_locks[tid]));
3137 statechange = True;
3138 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003139
sewardj18cd4a52002-11-13 22:37:41 +00003140 st_sharmod:
3141 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3142 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3143 thread_locks[tid]));
3144 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003145
sewardj18cd4a52002-11-13 22:37:41 +00003146 SHARED_MODIFIED:
3147 if (isempty(unpackLockSet(sword->other))) {
njnfbdcba92005-05-09 01:23:49 +00003148 record_race_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003149 }
3150 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003151
sewardj18cd4a52002-11-13 22:37:41 +00003152 done:
3153 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003154 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003155
sewardj18cd4a52002-11-13 22:37:41 +00003156 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003157 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003158 else
njnd01fef72005-03-25 23:35:48 +00003159 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003160 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003161 }
3162}
3163
njnfbdcba92005-05-09 01:23:49 +00003164static void hg_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003165{
sewardj8fac99a2002-11-13 22:31:26 +00003166 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003167
njn13bfd852005-06-02 03:52:53 +00003168 end = VG_ROUNDUP(a+size, 4);
3169 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003170
sewardj18cd4a52002-11-13 22:37:41 +00003171 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003172 hg_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003173}
3174
3175#undef DEBUG_STATE
3176
njnfbdcba92005-05-09 01:23:49 +00003177VGA_REGPARM(1) static void hg_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003178{
njnfbdcba92005-05-09 01:23:49 +00003179 hg_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003180}
3181
njnfbdcba92005-05-09 01:23:49 +00003182VGA_REGPARM(1) static void hg_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003183{
njnfbdcba92005-05-09 01:23:49 +00003184 hg_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003185}
3186
njnfbdcba92005-05-09 01:23:49 +00003187VGA_REGPARM(1) static void hg_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003188{
njnfbdcba92005-05-09 01:23:49 +00003189 hg_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003190}
3191
njnfbdcba92005-05-09 01:23:49 +00003192VGA_REGPARM(2) static void hg_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003193{
njnfbdcba92005-05-09 01:23:49 +00003194 hg_mem_read(a, size, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003195}
3196
njnfbdcba92005-05-09 01:23:49 +00003197VGA_REGPARM(2) static void hg_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003198{
3199 if (*(UChar *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003200 hg_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003201}
njnfbdcba92005-05-09 01:23:49 +00003202VGA_REGPARM(2) static void hg_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003203{
3204 if (*(UShort *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003205 hg_mem_write(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003206}
njnfbdcba92005-05-09 01:23:49 +00003207VGA_REGPARM(2) static void hg_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003208{
3209 if (*(UInt *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003210 hg_mem_write(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003211}
njnfbdcba92005-05-09 01:23:49 +00003212VGA_REGPARM(2) static void hg_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003213{
njnfbdcba92005-05-09 01:23:49 +00003214 hg_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003215}
njn25e49d8e72002-09-23 09:36:25 +00003216
sewardjc4a810d2002-11-13 22:25:51 +00003217static void hg_thread_create(ThreadId parent, ThreadId child)
3218{
3219 if (0)
3220 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3221
3222 newTLS(child);
3223 addPriorTLS(child, parent);
3224
3225 newTLS(parent);
3226}
3227
3228static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3229{
3230 if (0)
3231 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3232
3233 newTLS(joiner);
3234 addPriorTLS(joiner, joinee);
3235
3236 clearTLS(joinee);
3237}
3238
sewardj7a5ebcf2002-11-13 22:42:13 +00003239static Int __BUS_HARDWARE_LOCK__;
3240
3241static void bus_lock(void)
3242{
njn95e65f62005-03-30 04:13:56 +00003243 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003244 hg_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3245 hg_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003246}
3247
3248static void bus_unlock(void)
3249{
njn95e65f62005-03-30 04:13:56 +00003250 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003251 hg_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003252}
3253
njn25e49d8e72002-09-23 09:36:25 +00003254/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003255/*--- Client requests ---*/
3256/*--------------------------------------------------------------------*/
3257
njn51d827b2005-05-09 01:02:08 +00003258static Bool hg_handle_client_request(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003259{
njnfc26ff92004-11-22 19:12:49 +00003260 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003261 return False;
3262
3263 switch(args[0]) {
3264 case VG_USERREQ__HG_CLEAN_MEMORY:
3265 set_address_range_state(args[1], args[2], Vge_VirginInit);
3266 *ret = 0; /* meaningless */
3267 break;
3268
3269 case VG_USERREQ__HG_KNOWN_RACE:
3270 set_address_range_state(args[1], args[2], Vge_Error);
3271 *ret = 0; /* meaningless */
3272 break;
3273
3274 default:
3275 return False;
3276 }
3277
3278 return True;
3279}
3280
3281
3282/*--------------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00003283/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00003284/*--------------------------------------------------------------------*/
3285
njn51d827b2005-05-09 01:02:08 +00003286static Bool hg_process_cmd_line_option(Char* arg)
3287{
3288 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3289 clo_execontext = EC_None;
3290 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3291 clo_execontext = EC_Some;
3292 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3293 clo_execontext = EC_All;
3294
3295 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
3296
3297 else
3298 return VG_(replacement_malloc_process_cmd_line_option)(arg);
3299
3300 return True;
3301}
3302
3303static void hg_print_usage(void)
3304{
3305 VG_(printf)(
3306" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3307" --show-last-access=no|some|all\n"
3308" show location of last word access on error [no]\n"
3309 );
3310 VG_(replacement_malloc_print_usage)();
3311}
3312
3313static void hg_print_debug_usage(void)
3314{
3315 VG_(replacement_malloc_print_debug_usage)();
3316}
3317
3318static void hg_post_clo_init(void)
3319{
3320 void (*stack_tracker)(Addr a, SizeT len);
3321
3322 if (clo_execontext) {
3323 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3324 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3325 }
3326
3327 if (clo_priv_stacks)
njnfbdcba92005-05-09 01:23:49 +00003328 stack_tracker = & hg_new_mem_stack_private;
njn51d827b2005-05-09 01:02:08 +00003329 else
njnfbdcba92005-05-09 01:23:49 +00003330 stack_tracker = & hg_new_mem_stack;
njn51d827b2005-05-09 01:02:08 +00003331
3332 VG_(track_new_mem_stack) (stack_tracker);
3333 VG_(track_new_mem_stack_signal) (stack_tracker);
3334}
3335
3336
3337static void hg_fini(Int exitcode)
3338{
3339 if (DEBUG_LOCK_TABLE) {
3340 pp_all_LockSets();
3341 pp_all_mutexes();
3342 }
3343
3344 if (LOCKSET_SANITY)
3345 sanity_check_locksets("hg_fini");
3346
3347 if (VG_(clo_verbosity) > 0)
3348 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
njnfbdcba92005-05-09 01:23:49 +00003349 n_hg_warnings, n_lockorder_warnings);
njn51d827b2005-05-09 01:02:08 +00003350
3351 if (0)
3352 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3353 stk_ld, stk_st, stk_ld + stk_st,
3354 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3355 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
3356}
3357
3358static void hg_pre_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00003359{
3360 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003361 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003362
njn810086f2002-11-14 12:42:47 +00003363 VG_(details_name) ("Helgrind");
3364 VG_(details_version) (NULL);
3365 VG_(details_description) ("a data race detector");
3366 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +00003367 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003368 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003369 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003370
njn51d827b2005-05-09 01:02:08 +00003371 VG_(basic_tool_funcs) (hg_post_clo_init,
3372 hg_instrument,
3373 hg_fini);
tomc756a8e2005-03-31 07:59:35 +00003374
3375 VG_(needs_core_errors) ();
njn51d827b2005-05-09 01:02:08 +00003376 VG_(needs_tool_errors) (hg_eq_Error,
3377 hg_pp_Error,
3378 hg_update_extra,
3379 hg_recognised_suppression,
3380 hg_read_extra_suppression_info,
3381 hg_error_matches_suppression,
3382 hg_get_error_name,
3383 hg_print_extra_suppression_info);
tomc756a8e2005-03-31 07:59:35 +00003384 VG_(needs_data_syms) ();
njn51d827b2005-05-09 01:02:08 +00003385 VG_(needs_client_requests) (hg_handle_client_request);
3386 VG_(needs_sanity_checks) (hg_cheap_sanity_check,
3387 hg_expensive_sanity_check);
3388 VG_(needs_command_line_options)(hg_process_cmd_line_option,
3389 hg_print_usage,
3390 hg_print_debug_usage);
tomc756a8e2005-03-31 07:59:35 +00003391 VG_(needs_shadow_memory) ();
3392
njn51d827b2005-05-09 01:02:08 +00003393 VG_(malloc_funcs) (hg_malloc,
3394 hg___builtin_new,
3395 hg___builtin_vec_new,
3396 hg_memalign,
3397 hg_calloc,
3398 hg_free,
3399 hg___builtin_delete,
3400 hg___builtin_vec_delete,
3401 hg_realloc,
tomc756a8e2005-03-31 07:59:35 +00003402 8 );
njn25e49d8e72002-09-23 09:36:25 +00003403
njnfbdcba92005-05-09 01:23:49 +00003404 VG_(track_new_mem_startup) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003405
njn51d827b2005-05-09 01:02:08 +00003406 /* stack ones not decided until hg_post_clo_init() */
njn25e49d8e72002-09-23 09:36:25 +00003407
njn51d827b2005-05-09 01:02:08 +00003408 VG_(track_new_mem_brk) (& make_writable);
njnfbdcba92005-05-09 01:23:49 +00003409 VG_(track_new_mem_mmap) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003410
njnfbdcba92005-05-09 01:23:49 +00003411 VG_(track_change_mem_mprotect) (& hg_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003412
njn51d827b2005-05-09 01:02:08 +00003413 VG_(track_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003414
njn51d827b2005-05-09 01:02:08 +00003415 VG_(track_die_mem_stack) (NULL);
3416 VG_(track_die_mem_stack_signal)(NULL);
3417 VG_(track_die_mem_brk) (NULL);
3418 VG_(track_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003419
njnfbdcba92005-05-09 01:23:49 +00003420 VG_(track_pre_mem_read) (& hg_pre_mem_read);
3421 VG_(track_pre_mem_read_asciiz) (& hg_pre_mem_read_asciiz);
3422 VG_(track_pre_mem_write) (& hg_pre_mem_write);
njn51d827b2005-05-09 01:02:08 +00003423 VG_(track_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003424
njn51d827b2005-05-09 01:02:08 +00003425 VG_(track_post_thread_create) (& hg_thread_create);
3426 VG_(track_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003427
njnfbdcba92005-05-09 01:23:49 +00003428 VG_(track_pre_mutex_lock) (& hg_pre_mutex_lock);
3429 VG_(track_post_mutex_lock) (& hg_post_mutex_lock);
3430 VG_(track_post_mutex_unlock) (& hg_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003431
njn14d01ce2004-11-26 11:30:14 +00003432 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003433 lockset_hash[i] = NULL;
3434
3435 empty = alloc_LockSet(0);
3436 insert_LockSet(empty);
3437 emptyset = empty;
3438
sewardjc4a810d2002-11-13 22:25:51 +00003439 /* Init lock table and thread segments */
3440 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003441 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003442
sewardjc4a810d2002-11-13 22:25:51 +00003443 newTLS(i);
3444 }
3445
njn25e49d8e72002-09-23 09:36:25 +00003446 init_shadow_memory();
njn3e884182003-04-15 13:03:23 +00003447 hg_malloc_list = VG_(HT_construct)();
njn25e49d8e72002-09-23 09:36:25 +00003448}
3449
fitzhardinge98abfc72003-12-16 02:05:15 +00003450/* Uses a 1:1 mapping */
njn51d827b2005-05-09 01:02:08 +00003451VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init, 1.0)
fitzhardinge98abfc72003-12-16 02:05:15 +00003452
njn25e49d8e72002-09-23 09:36:25 +00003453/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003454/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003455/*--------------------------------------------------------------------*/