blob: 56e95fb992e8203b94a76a24b9550f5f8368a848 [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
njnc7561b92005-06-19 01:24:32 +000032#include "pub_tool_basics.h"
33#include "pub_tool_threadstate.h"
njn4802b382005-06-11 04:58:29 +000034#include "pub_tool_aspacemgr.h"
njnea27e462005-05-31 02:38:09 +000035#include "pub_tool_debuginfo.h"
njn81c00df2005-05-14 21:28:43 +000036#include "pub_tool_hashtable.h"
njn97405b22005-06-02 03:39:33 +000037#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000038#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000039#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000040#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000041#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000042#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000043#include "pub_tool_options.h"
njn31513b42005-06-01 03:09:59 +000044#include "pub_tool_profile.h"
njn717cde52005-05-10 02:47:21 +000045#include "pub_tool_replacemalloc.h"
njn43b9a8a2005-05-10 04:37:01 +000046#include "pub_tool_tooliface.h"
njn717cde52005-05-10 02:47:21 +000047
sewardj7f3ad222002-11-13 22:11:53 +000048#include "helgrind.h"
njn25e49d8e72002-09-23 09:36:25 +000049
njnfbdcba92005-05-09 01:23:49 +000050static UInt n_hg_warnings = 0;
sewardjff2c9232002-11-13 21:44:39 +000051static UInt n_lockorder_warnings = 0;
njn25e49d8e72002-09-23 09:36:25 +000052
53/*------------------------------------------------------------*/
54/*--- Debug guff ---*/
55/*------------------------------------------------------------*/
56
sewardje11d6c82002-12-15 02:00:41 +000057#define DEBUG_LOCK_TABLE 0 /* Print lock table at end */
njn25e49d8e72002-09-23 09:36:25 +000058
59#define DEBUG_MAKE_ACCESSES 0 /* Print make_access() calls */
60#define DEBUG_LOCKS 0 /* Print lock()/unlock() calls and locksets */
61#define DEBUG_NEW_LOCKSETS 0 /* Print new locksets when created */
62#define DEBUG_ACCESSES 0 /* Print reads, writes */
63#define DEBUG_MEM_LOCKSET_CHANGES 0
64 /* Print when an address's lockset
65 changes; only useful with
66 DEBUG_ACCESSES */
sewardj8fac99a2002-11-13 22:31:26 +000067#define SLOW_ASSERTS 0 /* do expensive asserts */
njn25e49d8e72002-09-23 09:36:25 +000068#define DEBUG_VIRGIN_READS 0 /* Dump around address on VIRGIN reads */
69
sewardj8fac99a2002-11-13 22:31:26 +000070#if SLOW_ASSERTS
njn94065fd2004-11-22 19:26:27 +000071#define TL_ASSERT(x) tl_assert(x)
sewardj8fac99a2002-11-13 22:31:26 +000072#else
njn94065fd2004-11-22 19:26:27 +000073#define TL_ASSERT(x)
sewardj8fac99a2002-11-13 22:31:26 +000074#endif
75
njn25e49d8e72002-09-23 09:36:25 +000076/* heavyweight LockSet sanity checking:
77 0 == never
78 1 == after important ops
79 2 == As 1 and also after pthread_mutex_* ops (excessively slow)
80 */
81#define LOCKSET_SANITY 0
82
sewardj8fac99a2002-11-13 22:31:26 +000083/* Rotate an unsigned quantity left */
84#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x)*8)-(n))))
85
njn25e49d8e72002-09-23 09:36:25 +000086/*------------------------------------------------------------*/
sewardjf6374322002-11-13 22:35:55 +000087/*--- Command line options ---*/
88/*------------------------------------------------------------*/
89
90static enum {
91 EC_None,
92 EC_Some,
93 EC_All
94} clo_execontext = EC_None;
95
sewardje1a39f42002-12-15 01:56:17 +000096static Bool clo_priv_stacks = False;
sewardjf6374322002-11-13 22:35:55 +000097
98/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000099/*--- Crude profiling machinery. ---*/
100/*------------------------------------------------------------*/
101
102// PPP: work out if I want this
103
104#define PROF_EVENT(x)
105#if 0
106#ifdef VG_PROFILE_MEMORY
107
108#define N_PROF_EVENTS 150
109
110static UInt event_ctr[N_PROF_EVENTS];
111
112void VGE_(done_prof_mem) ( void )
113{
114 Int i;
115 for (i = 0; i < N_PROF_EVENTS; i++) {
116 if ((i % 10) == 0)
117 VG_(printf)("\n");
118 if (event_ctr[i] > 0)
119 VG_(printf)( "prof mem event %2d: %d\n", i, event_ctr[i] );
120 }
121 VG_(printf)("\n");
122}
123
124#define PROF_EVENT(ev) \
njnca82cc02004-11-22 17:18:48 +0000125 do { tl_assert((ev) >= 0 && (ev) < N_PROF_EVENTS); \
njn25e49d8e72002-09-23 09:36:25 +0000126 event_ctr[ev]++; \
127 } while (False);
128
129#else
130
131//static void init_prof_mem ( void ) { }
132// void VG_(done_prof_mem) ( void ) { }
133
134#define PROF_EVENT(ev) /* */
135
136#endif /* VG_PROFILE_MEMORY */
137
138/* Event index. If just the name of the fn is given, this means the
139 number of calls to the fn. Otherwise it is the specified event.
140
141 [PPP: snip event numbers...]
142*/
143#endif /* 0 */
144
145
146/*------------------------------------------------------------*/
147/*--- Data defns. ---*/
148/*------------------------------------------------------------*/
149
njn3e884182003-04-15 13:03:23 +0000150typedef
151 struct _HG_Chunk {
152 struct _HG_Chunk* next;
153 Addr data; /* ptr to actual block */
nethercote928a5f72004-11-03 18:10:37 +0000154 SizeT size; /* size requested */
njn3e884182003-04-15 13:03:23 +0000155 ExeContext* where; /* where it was allocated */
156 ThreadId tid; /* allocating thread */
157 }
158 HG_Chunk;
159
njn25e49d8e72002-09-23 09:36:25 +0000160typedef enum
sewardj7f3ad222002-11-13 22:11:53 +0000161 { Vge_VirginInit, Vge_NonVirginInit, Vge_SegmentInit, Vge_Error }
njn25e49d8e72002-09-23 09:36:25 +0000162 VgeInitStatus;
163
sewardjc808ef52002-11-13 22:43:26 +0000164
njnc6168192004-11-29 13:54:10 +0000165// XXX: not 64-bit clean!
njn25e49d8e72002-09-23 09:36:25 +0000166/* Should add up to 32 to fit in one word */
167#define OTHER_BITS 30
168#define STATE_BITS 2
169
170#define ESEC_MAP_WORDS 16384 /* Words per secondary map */
171
172/* This is for indicating that a memory block has been initialised but not
173 * really directly by a particular thread... (eg. text/data initialised
174 * automatically at startup).
175 * Must be different to virgin_word.other */
176#define TID_INDICATING_NONVIRGIN 1
177
sewardjc4a810d2002-11-13 22:25:51 +0000178/* Magic packed TLS used for error suppression; if word state is Excl
179 and tid is this, then it means all access are OK without changing
180 state and without raising any more errors */
181#define TLSP_INDICATING_ALL ((1 << OTHER_BITS) - 1)
sewardj16748af2002-10-22 04:55:54 +0000182
njn25e49d8e72002-09-23 09:36:25 +0000183/* Number of entries must fit in STATE_BITS bits */
184typedef enum { Vge_Virgin, Vge_Excl, Vge_Shar, Vge_SharMod } pth_state;
185
sewardjc808ef52002-11-13 22:43:26 +0000186static inline const Char *pp_state(pth_state st)
187{
188 const Char *ret;
189
190 switch(st) {
191 case Vge_Virgin: ret = "virgin"; break;
192 case Vge_Excl: ret = "exclusive"; break;
193 case Vge_Shar: ret = "shared RO"; break;
194 case Vge_SharMod: ret = "shared RW"; break;
195 default: ret = "???";
196 }
197 return ret;
198}
199
njn25e49d8e72002-09-23 09:36:25 +0000200typedef
201 struct {
sewardj8fac99a2002-11-13 22:31:26 +0000202 /* gcc arranges this bitfield with state in the 2LSB and other
203 in the 30MSB, which is what we want */
njn25e49d8e72002-09-23 09:36:25 +0000204 UInt state:STATE_BITS;
sewardj8fac99a2002-11-13 22:31:26 +0000205 UInt other:OTHER_BITS;
njn25e49d8e72002-09-23 09:36:25 +0000206 } shadow_word;
207
sewardj8fac99a2002-11-13 22:31:26 +0000208#define SW(st, other) ((shadow_word) { st, other })
209
njn25e49d8e72002-09-23 09:36:25 +0000210typedef
211 struct {
212 shadow_word swords[ESEC_MAP_WORDS];
213 }
214 ESecMap;
215
216static ESecMap* primary_map[ 65536 ];
217static ESecMap distinguished_secondary_map;
218
sewardj8fac99a2002-11-13 22:31:26 +0000219static const shadow_word virgin_sword = SW(Vge_Virgin, 0);
220static const shadow_word error_sword = SW(Vge_Excl, TLSP_INDICATING_ALL);
njn25e49d8e72002-09-23 09:36:25 +0000221
222#define VGE_IS_DISTINGUISHED_SM(smap) \
223 ((smap) == &distinguished_secondary_map)
224
225#define ENSURE_MAPPABLE(addr,caller) \
226 do { \
227 if (VGE_IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
228 primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
229 /*VG_(printf)("new 2map because of %p\n", addr);*/ \
230 } \
231 } while(0)
232
233
sewardjc808ef52002-11-13 22:43:26 +0000234/* Parallel map which contains execution contexts when words last
235 changed state (if required) */
sewardj499e3de2002-11-13 22:22:25 +0000236
nethercoteca788ff2004-10-20 10:58:09 +0000237typedef struct EC_IP {
238 union u_ec_ip {
239 Addr ip;
sewardjc808ef52002-11-13 22:43:26 +0000240 ExeContext *ec;
nethercoteca788ff2004-10-20 10:58:09 +0000241 } uu_ec_ip;
sewardjc808ef52002-11-13 22:43:26 +0000242 UInt state:STATE_BITS;
243 UInt tls:OTHER_BITS; /* packed TLS */
nethercoteca788ff2004-10-20 10:58:09 +0000244} EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000245
nethercoteca788ff2004-10-20 10:58:09 +0000246#define NULL_EC_IP ((EC_IP){ { 0 }, 0, 0})
sewardjc808ef52002-11-13 22:43:26 +0000247
nethercoteca788ff2004-10-20 10:58:09 +0000248#define IP(ip, prev, tls) ((EC_IP) { (union u_ec_ip)(ip), (prev).state, packTLS(tls) })
249#define EC(ec, prev, tls) ((EC_IP) { (union u_ec_ip)(ec), (prev).state, packTLS(tls) })
sewardjc808ef52002-11-13 22:43:26 +0000250
251static inline UInt packEC(ExeContext *ec)
252{
njn94065fd2004-11-22 19:26:27 +0000253 TL_ASSERT(((UWord)ec & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000254 return ((UWord)ec) >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000255}
256
nethercoteca788ff2004-10-20 10:58:09 +0000257/* Lose 2 LSB of IP */
258static inline UInt packIP(Addr ip)
sewardjc808ef52002-11-13 22:43:26 +0000259{
nethercote50397c22004-11-04 18:03:06 +0000260 return ip >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000261}
262
nethercoteca788ff2004-10-20 10:58:09 +0000263static inline Addr unpackIP(UInt i)
sewardjc808ef52002-11-13 22:43:26 +0000264{
265 return (Addr)(i << STATE_BITS);
266}
sewardj499e3de2002-11-13 22:22:25 +0000267
268typedef struct {
nethercoteca788ff2004-10-20 10:58:09 +0000269 EC_IP execontext[ESEC_MAP_WORDS];
sewardj499e3de2002-11-13 22:22:25 +0000270} ExeContextMap;
271
272static ExeContextMap** execontext_map;
273
nethercoteca788ff2004-10-20 10:58:09 +0000274static inline void setExeContext(Addr a, EC_IP ec)
sewardj499e3de2002-11-13 22:22:25 +0000275{
276 UInt idx = (a >> 16) & 0xffff;
277 UInt off = (a >> 2) & 0x3fff;
278
279 if (execontext_map[idx] == NULL) {
280 execontext_map[idx] = VG_(malloc)(sizeof(ExeContextMap));
281 VG_(memset)(execontext_map[idx], 0, sizeof(ExeContextMap));
282 }
283
284 execontext_map[idx]->execontext[off] = ec;
285}
286
nethercoteca788ff2004-10-20 10:58:09 +0000287static inline EC_IP getExeContext(Addr a)
sewardj499e3de2002-11-13 22:22:25 +0000288{
289 UInt idx = (a >> 16) & 0xffff;
290 UInt off = (a >> 2) & 0x3fff;
nethercoteca788ff2004-10-20 10:58:09 +0000291 EC_IP ec = NULL_EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000292
293 if (execontext_map[idx] != NULL)
294 ec = execontext_map[idx]->execontext[off];
295
296 return ec;
297}
298
njn25e49d8e72002-09-23 09:36:25 +0000299/*------------------------------------------------------------*/
sewardjc4a810d2002-11-13 22:25:51 +0000300/*--- Thread lifetime segments ---*/
301/*------------------------------------------------------------*/
302
303/*
304 * This mechanism deals with the common case of a parent thread
305 * creating a structure for a child thread, and then passing ownership
306 * of the structure to that thread. It similarly copes with a child
307 * thread passing information back to another thread waiting to join
308 * on it.
309 *
310 * Each thread's lifetime can be partitioned into segments. Those
311 * segments are arranged to form an interference graph which indicates
312 * whether two thread lifetime segments can possibly be concurrent.
313 * If not, then memory with is exclusively accessed by one TLS can be
daywalker7e73e5f2003-07-04 16:18:15 +0000314 * passed on to another TLS without an error occurring, and without
sewardjc4a810d2002-11-13 22:25:51 +0000315 * moving it from Excl state.
316 *
317 * At present this only considers thread creation and join as
318 * synchronisation events for creating new lifetime segments, but
319 * others may be possible (like mutex operations).
320 */
321
322typedef struct _ThreadLifeSeg ThreadLifeSeg;
323
324struct _ThreadLifeSeg {
325 ThreadId tid;
326 ThreadLifeSeg *prior[2]; /* Previous lifetime segments */
327 UInt refcount; /* Number of memory locations pointing here */
328 UInt mark; /* mark used for graph traversal */
329 ThreadLifeSeg *next; /* list of all TLS */
330};
331
332static ThreadLifeSeg *all_tls;
333static UInt tls_since_gc;
334#define TLS_SINCE_GC 10000
335
336/* current mark used for TLS graph traversal */
337static UInt tlsmark;
338
339static ThreadLifeSeg *thread_seg[VG_N_THREADS];
340
341
342static void tls_gc(void)
343{
344 /* XXX later. Walk through all TLSs and look for ones with 0
345 refcount and remove them from the structure and free them.
346 Could probably get rid of ThreadLifeSeg.refcount and simply use
347 mark-sweep from the shadow table. */
348 VG_(printf)("WRITEME: TLS GC\n");
349}
350
351static void newTLS(ThreadId tid)
352{
353 static const Bool debug = False;
354 ThreadLifeSeg *tls;
355
356 /* Initial NULL */
357 if (thread_seg[tid] == NULL) {
358 tls = VG_(malloc)(sizeof(*tls));
359 tls->tid = tid;
360 tls->prior[0] = tls->prior[1] = NULL;
361 tls->refcount = 0;
362 tls->mark = tlsmark-1;
363
364 tls->next = all_tls;
365 all_tls = tls;
366 tls_since_gc++;
367
368 thread_seg[tid] = tls;
369 return;
370 }
371
372 /* Previous TLS was unused, so just recycle */
373 if (thread_seg[tid]->refcount == 0) {
374 if (debug)
375 VG_(printf)("newTLS; recycling TLS %p for tid %u\n",
376 thread_seg[tid], tid);
377 return;
378 }
379
380 /* Use existing TLS for this tid as a prior for new TLS */
381 tls = VG_(malloc)(sizeof(*tls));
382 tls->tid = tid;
383 tls->prior[0] = thread_seg[tid];
384 tls->prior[1] = NULL;
385 tls->refcount = 0;
386 tls->mark = tlsmark-1;
387
388 tls->next = all_tls;
389 all_tls = tls;
390 if (++tls_since_gc > TLS_SINCE_GC) {
391 tls_gc();
392 tls_since_gc = 0;
393 }
394
395 if (debug)
396 VG_(printf)("newTLS: made new TLS %p for tid %u (prior %p(%u))\n",
397 tls, tid, tls->prior[0], tls->prior[0]->tid);
398
399 thread_seg[tid] = tls;
400}
401
402/* clear out a TLS for a thread that's died */
403static void clearTLS(ThreadId tid)
404{
405 newTLS(tid);
406
407 thread_seg[tid]->prior[0] = NULL;
408 thread_seg[tid]->prior[1] = NULL;
409}
410
411static void addPriorTLS(ThreadId tid, ThreadId prior)
412{
413 static const Bool debug = False;
414 ThreadLifeSeg *tls = thread_seg[tid];
415
416 if (debug)
417 VG_(printf)("making TLS %p(%u) prior to TLS %p(%u)\n",
418 thread_seg[prior], prior, tls, tid);
419
njnca82cc02004-11-22 17:18:48 +0000420 tl_assert(thread_seg[tid] != NULL);
421 tl_assert(thread_seg[prior] != NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000422
423 if (tls->prior[0] == NULL)
424 tls->prior[0] = thread_seg[prior];
425 else {
njnca82cc02004-11-22 17:18:48 +0000426 tl_assert(tls->prior[1] == NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000427 tls->prior[1] = thread_seg[prior];
428 }
429}
430
njnfbdcba92005-05-09 01:23:49 +0000431static Bool isPrior(const ThreadLifeSeg *t, const ThreadLifeSeg *prior)
432{
433 if (t == NULL || t->mark == tlsmark)
434 return False;
435
436 if (t == prior)
437 return True;
438
439 ((ThreadLifeSeg *)t)->mark = tlsmark;
440
441 return isPrior(t->prior[0], prior) || isPrior(t->prior[1], prior);
442}
443
sewardjc4a810d2002-11-13 22:25:51 +0000444/* Return True if prior is definitely not concurrent with tls */
445static Bool tlsIsDisjoint(const ThreadLifeSeg *tls,
446 const ThreadLifeSeg *prior)
447{
sewardjc4a810d2002-11-13 22:25:51 +0000448 tlsmark++; /* new traversal mark */
449
njnfbdcba92005-05-09 01:23:49 +0000450 return isPrior(tls, prior);
sewardjc4a810d2002-11-13 22:25:51 +0000451}
452
453static inline UInt packTLS(ThreadLifeSeg *tls)
454{
njn94065fd2004-11-22 19:26:27 +0000455 TL_ASSERT(((UWord)tls & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000456 return ((UWord)tls) >> STATE_BITS;
sewardjc4a810d2002-11-13 22:25:51 +0000457}
458
459static inline ThreadLifeSeg *unpackTLS(UInt i)
460{
sewardj29ef1c82005-06-11 10:33:35 +0000461 /* HACK ALERT -- DUBIOUS CAST */
462 return (ThreadLifeSeg *)ULong_to_Ptr(i << STATE_BITS);
sewardjc4a810d2002-11-13 22:25:51 +0000463}
464
465/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000466/*--- Low-level support for memory tracking. ---*/
467/*------------------------------------------------------------*/
468
469/*
470 All reads and writes are recorded in the memory map, which
471 records the state of all memory in the process. The memory map is
472 organised like that for normal Valgrind, except each that everything
473 is done at word-level instead of byte-level, and each word has only
474 one word of shadow (instead of 36 bits).
475
476 As for normal Valgrind there is a distinguished secondary map. But we're
477 working at word-granularity, so it has 16k word entries instead of 64k byte
478 entries. Lookup is done as follows:
479
480 bits 31..16: primary map lookup
481 bits 15.. 2: secondary map lookup
482 bits 1.. 0: ignored
483*/
484
485
486/*------------------------------------------------------------*/
487/*--- Basic bitmap management, reading and writing. ---*/
488/*------------------------------------------------------------*/
489
490/* Allocate and initialise a secondary map, marking all words as virgin. */
491
492/* Just a value that isn't a real pointer */
493#define SEC_MAP_ACCESS (shadow_word*)0x99
494
495
496static
497ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
498{
499 ESecMap* map;
500 UInt i;
501 //PROF_EVENT(10); PPP
502
nethercote1420ab22004-08-18 22:26:01 +0000503 // Mark all words as virgin.
fitzhardinge98abfc72003-12-16 02:05:15 +0000504 map = (ESecMap *)VG_(shadow_alloc)(sizeof(ESecMap));
njn25e49d8e72002-09-23 09:36:25 +0000505 for (i = 0; i < ESEC_MAP_WORDS; i++)
506 map->swords[i] = virgin_sword;
507
508 return map;
509}
510
511
512/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
513 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000514static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000515void set_sword ( Addr a, shadow_word sword )
516{
517 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000518 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000519
520 //PROF_EVENT(23); PPP
521 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
522
523 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
524 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000525 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000526 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
527 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
528 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
529 tls->refcount--;
530 }
531
532 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
533 ThreadLifeSeg *tls = unpackTLS(sword.other);
534 tls->refcount++;
535 }
536
njn25e49d8e72002-09-23 09:36:25 +0000537 sm->swords[(a & 0xFFFC) >> 2] = sword;
538
539 if (VGE_IS_DISTINGUISHED_SM(sm)) {
540 VG_(printf)("wrote to distinguished 2ndary map! 0x%x\n", a);
541 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000542 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000543 }
544}
545
546
547static __inline__
548shadow_word* get_sword_addr ( Addr a )
549{
550 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
551 ESecMap* sm = primary_map[a >> 16];
552 UInt sm_off = (a & 0xFFFC) >> 2;
553
554 if (VGE_IS_DISTINGUISHED_SM(sm)) {
555 VG_(printf)("accessed distinguished 2ndary map! 0x%x\n", a);
556 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000557 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000558 return SEC_MAP_ACCESS;
559 }
560
561 //PROF_EVENT(21); PPP
562 return & (sm->swords[sm_off]);
563}
564
565
566// SSS: rename these so they're not so similar to memcheck, unless it's
567// appropriate of course
568
569static __inline__
570void init_virgin_sword(Addr a)
571{
sewardj499e3de2002-11-13 22:22:25 +0000572 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000573 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000574 set_sword(a, virgin_sword);
575}
576
sewardj7f3ad222002-11-13 22:11:53 +0000577static __inline__
578void init_error_sword(Addr a)
579{
580 set_sword(a, error_sword);
581}
njn25e49d8e72002-09-23 09:36:25 +0000582
njn25e49d8e72002-09-23 09:36:25 +0000583static __inline__
584void init_nonvirgin_sword(Addr a)
585{
586 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000587 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000588 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000589
njn14d01ce2004-11-26 11:30:14 +0000590 // The tid must be passed in here now; this requires more events to be
591 // given the tid in the first place.
592 //
593 //tid = VG_(get_current_or_recent_tid)();
594 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
595 VG_(exit)(1);
596
njnca82cc02004-11-22 17:18:48 +0000597 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000598 tls = thread_seg[tid];
599
sewardj8fac99a2002-11-13 22:31:26 +0000600 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000601 set_sword(a, sword);
602}
603
604
njnfbdcba92005-05-09 01:23:49 +0000605/* In this case, we treat it for Helgrind's sake like virgin (it hasn't
njn25e49d8e72002-09-23 09:36:25 +0000606 * been inited by a particular thread, it's just done automatically upon
607 * startup), but we mark its .state specially so it doesn't look like an
608 * uninited read. */
609static __inline__
610void init_magically_inited_sword(Addr a)
611{
612 shadow_word sword;
613
sewardj8fac99a2002-11-13 22:31:26 +0000614 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
615
njn25e49d8e72002-09-23 09:36:25 +0000616 set_sword(a, virgin_sword);
617}
618
sewardjc26cc252002-10-23 21:58:55 +0000619
sewardj274c6012002-10-22 04:54:55 +0000620/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000621/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000622/*------------------------------------------------------------*/
623
sewardj39a4d842002-11-13 22:14:30 +0000624typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000625typedef struct _LockSet LockSet;
626
sewardj16748af2002-10-22 04:55:54 +0000627typedef enum MutexState {
628 MxUnknown, /* don't know */
629 MxUnlocked, /* unlocked */
630 MxLocked, /* locked */
631 MxDead /* destroyed */
632} MutexState;
633
sewardj39a4d842002-11-13 22:14:30 +0000634struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000635 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000636 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000637
638 MutexState state; /* mutex state */
639 ThreadId tid; /* owner */
640 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000641
sewardj4bffb232002-11-13 21:46:34 +0000642 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000643 UInt mark; /* mark for graph traversal */
644};
sewardj16748af2002-10-22 04:55:54 +0000645
sewardj39a4d842002-11-13 22:14:30 +0000646static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000647{
sewardjdac0a442002-11-13 22:08:40 +0000648 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000649}
njn25e49d8e72002-09-23 09:36:25 +0000650
sewardj274c6012002-10-22 04:54:55 +0000651struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000652 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000653 UInt hash; /* hash code */
654 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000655 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000656};
sewardj4bffb232002-11-13 21:46:34 +0000657
658static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000659
660/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000661static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000662
sewardjdac0a442002-11-13 22:08:40 +0000663#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000664
sewardj4bffb232002-11-13 21:46:34 +0000665static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000666
sewardj4bffb232002-11-13 21:46:34 +0000667/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000668static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000669{
sewardj4bffb232002-11-13 21:46:34 +0000670 UInt id;
671
njn94065fd2004-11-22 19:26:27 +0000672 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000673 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000674
675 return id;
njn25e49d8e72002-09-23 09:36:25 +0000676}
677
sewardj8fac99a2002-11-13 22:31:26 +0000678static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000679{
sewardj29ef1c82005-06-11 10:33:35 +0000680 /* HACK ALERT -- DUBIOUS CAST */
681 return (LockSet *)ULong_to_Ptr(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000682}
683
njn25e49d8e72002-09-23 09:36:25 +0000684static
sewardj4bffb232002-11-13 21:46:34 +0000685void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000686{
sewardj05bcdcb2003-05-18 10:05:38 +0000687 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000688 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000689 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000690 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000691
692 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000693 }
694 VG_(printf)("}\n");
695}
696
697
sewardj4bffb232002-11-13 21:46:34 +0000698static void print_LockSet(const Char *s, const LockSet *ls)
699{
700 VG_(printf)("%s: ", s);
701 pp_LockSet(ls);
702}
703
704/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000705static UInt hash_LockSet_w_wo(const LockSet *ls,
706 const Mutex *with,
707 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000708{
sewardj05bcdcb2003-05-18 10:05:38 +0000709 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000710 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000711
njnca82cc02004-11-22 17:18:48 +0000712 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000713
714 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000715 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000716
717 if (without && mutex_cmp(without, mx) == 0)
718 continue;
719
720 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
721 mx = with;
722 with = NULL;
723 i--;
724 }
725
sewardj8fac99a2002-11-13 22:31:26 +0000726 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000727 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000728 }
729
730 return hash % LOCKSET_HASH_SZ;
731}
732
sewardj39a4d842002-11-13 22:14:30 +0000733static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000734{
735 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
736
737 if (0)
738 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
739
740 return hash;
741}
742
sewardj39a4d842002-11-13 22:14:30 +0000743static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000744{
745 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
746
747 if (0)
748 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
749
750 return hash;
751}
752
753static inline UInt hash_LockSet(const LockSet *ls)
754{
755 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
756
757 if (0)
758 VG_(printf)("hash %p -> %d\n", ls, hash);
759
760 return hash;
761}
762
763static
764Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000765{
766 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000767
sewardj4bffb232002-11-13 21:46:34 +0000768 if (a == b)
769 return True;
770 if (a->setsize != b->setsize)
771 return False;
njn25e49d8e72002-09-23 09:36:25 +0000772
sewardj4bffb232002-11-13 21:46:34 +0000773 for(i = 0; i < a->setsize; i++) {
774 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000775 return False;
njn25e49d8e72002-09-23 09:36:25 +0000776 }
777
sewardj4bffb232002-11-13 21:46:34 +0000778 return True;
njn25e49d8e72002-09-23 09:36:25 +0000779}
780
781
782/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
783 * doesn't do the insertion. Returns True if they match.
784 */
785static Bool
sewardj4bffb232002-11-13 21:46:34 +0000786weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000787 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000788{
sewardjc26cc252002-10-23 21:58:55 +0000789 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000790 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000791
njn25e49d8e72002-09-23 09:36:25 +0000792 /* Idea is to try and match each element of b against either an
793 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000794
795 if (debug) {
796 print_LockSet("weird_LockSet_equals a", a);
797 print_LockSet(" b", b);
798 VG_(printf)( " missing: %p%(y\n",
799 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000800 }
sewardjc26cc252002-10-23 21:58:55 +0000801
sewardj4bffb232002-11-13 21:46:34 +0000802 if ((a->setsize + 1) != b->setsize) {
803 if (debug)
804 VG_(printf)(" fastpath length mismatch -> 0\n");
805 return False;
806 }
807
sewardjc26cc252002-10-23 21:58:55 +0000808 /* There are three phases to this compare:
809 1 the section from the start of a up to missing_mutex
810 2 missing mutex itself
811 3 the section after missing_mutex to the end of a
812 */
813
sewardj4bffb232002-11-13 21:46:34 +0000814 ia = 0;
815 ib = 0;
816
sewardjc26cc252002-10-23 21:58:55 +0000817 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000818 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000819 if (debug) {
820 print_LockSet(" 1:a", a);
821 print_LockSet(" 1:b", b);
822 }
sewardj4bffb232002-11-13 21:46:34 +0000823 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000824 return False;
sewardjc26cc252002-10-23 21:58:55 +0000825 }
826
827 /* 2: missing_mutex itself */
828 if (debug) {
829 VG_(printf)( " 2:missing: %p%(y\n",
830 missing_mutex->mutexp, missing_mutex->mutexp);
831 print_LockSet(" 2: b", b);
832 }
833
njnca82cc02004-11-22 17:18:48 +0000834 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000835
sewardj4bffb232002-11-13 21:46:34 +0000836 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000837 return False;
838
sewardj4bffb232002-11-13 21:46:34 +0000839 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000840
841 /* 3: after missing_mutex to end */
842
sewardj4bffb232002-11-13 21:46:34 +0000843 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000844 if (debug) {
845 print_LockSet(" 3:a", a);
846 print_LockSet(" 3:b", b);
847 }
sewardj4bffb232002-11-13 21:46:34 +0000848 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000849 return False;
sewardjc26cc252002-10-23 21:58:55 +0000850 }
851
852 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000853 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000854
sewardj4bffb232002-11-13 21:46:34 +0000855 return ia == a->setsize && ib == b->setsize;
856}
857
858
859
860static const LockSet *lookup_LockSet(const LockSet *set)
861{
862 UInt bucket = set->hash;
863 LockSet *ret;
864
865 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
866 if (set == ret || structural_eq_LockSet(set, ret))
867 return ret;
868
869 return NULL;
870}
871
sewardj39a4d842002-11-13 22:14:30 +0000872static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000873{
874 UInt bucket = hash_LockSet_with(set, mutex);
875 const LockSet *ret;
876
877 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
878 if (weird_LockSet_equals(set, ret, mutex))
879 return ret;
880
881 return NULL;
882}
883
sewardj39a4d842002-11-13 22:14:30 +0000884static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000885{
886 UInt bucket = hash_LockSet_without(set, mutex);
887 const LockSet *ret;
888
889 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
890 if (weird_LockSet_equals(ret, set, mutex))
891 return ret;
892
893 return NULL;
894}
895
896static void insert_LockSet(LockSet *set)
897{
898 UInt hash = hash_LockSet(set);
899
900 set->hash = hash;
901
njnca82cc02004-11-22 17:18:48 +0000902 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000903
904 set->next = lockset_hash[hash];
905 lockset_hash[hash] = set;
906}
907
908static inline
909LockSet *alloc_LockSet(UInt setsize)
910{
sewardj39a4d842002-11-13 22:14:30 +0000911 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000912 ret->setsize = setsize;
913 return ret;
914}
915
916static inline
917void free_LockSet(LockSet *p)
918{
919 /* assert: not present in hash */
920 VG_(free)(p);
921}
922
njnb4aee052003-04-15 14:09:58 +0000923static
sewardj4bffb232002-11-13 21:46:34 +0000924void pp_all_LockSets ( void )
925{
926 Int i;
927 Int sets, buckets;
928
929 sets = buckets = 0;
930 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
931 const LockSet *ls = lockset_hash[i];
932 Bool first = True;
933
sewardj4bffb232002-11-13 21:46:34 +0000934 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000935 if (first) {
936 buckets++;
937 VG_(printf)("[%4d] = ", i);
938 } else
939 VG_(printf)(" ");
940
sewardj4bffb232002-11-13 21:46:34 +0000941 sets++;
942 first = False;
943 pp_LockSet(ls);
944 }
945 }
946
947 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
948}
949
950static inline Bool isempty(const LockSet *ls)
951{
952 return ls == NULL || ls->setsize == 0;
953}
954
sewardj39a4d842002-11-13 22:14:30 +0000955static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000956{
957 Int i;
958
959 /* XXX use binary search */
960 for(i = 0; i < ls->setsize; i++)
961 if (mutex_cmp(mx, ls->mutex[i]) == 0)
962 return True;
963
964 return False;
965}
966
967/* Check invariants:
968 - all locksets are unique
969 - each set is an array in strictly increasing order of mutex addr
970*/
971static
972void sanity_check_locksets ( const Char* caller )
973{
974 Int i;
975 const Char *badness;
976 LockSet *ls;
977
978 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
979
980 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000981 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000982 Int j;
983
984 if (hash_LockSet(ls) != ls->hash) {
985 badness = "mismatched hash";
986 goto bad;
987 }
sewardj05bcdcb2003-05-18 10:05:38 +0000988 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +0000989 badness = "wrong bucket";
990 goto bad;
991 }
992 if (lookup_LockSet(ls) != ls) {
993 badness = "non-unique set";
994 goto bad;
995 }
996
997 prev = ls->mutex[0];
998 for(j = 1; j < ls->setsize; j++) {
999 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
1000 badness = "mutexes out of order";
1001 goto bad;
1002 }
1003 }
1004 }
1005 }
1006 return;
1007
1008 bad:
1009 VG_(printf)("sanity_check_locksets: "
1010 "i = %d, ls=%p badness = %s, caller = %s\n",
1011 i, ls, badness, caller);
1012 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001013 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001014}
1015
1016static
sewardj39a4d842002-11-13 22:14:30 +00001017LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001018{
1019 static const Bool debug = False;
1020 LockSet *ret = NULL;
1021 Int i, j;
1022
1023 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1024 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1025 print_LockSet("add-IN", ls);
1026 }
1027
1028 if (debug || LOCKSET_SANITY)
1029 sanity_check_locksets("add-IN");
1030
njnca82cc02004-11-22 17:18:48 +00001031 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001032
1033 ret = alloc_LockSet(ls->setsize+1);
1034
1035 for(i = j = 0; i < ls->setsize; i++) {
1036 if (debug)
1037 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1038 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1039 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1040 ret->mutex[j++] = mx;
1041 mx = NULL;
1042 }
1043 ret->mutex[j++] = ls->mutex[i];
1044 }
1045
1046 /* not added in loop - must be after */
1047 if (mx)
1048 ret->mutex[j++] = mx;
1049
njnca82cc02004-11-22 17:18:48 +00001050 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001051
1052 if (debug || LOCKSET_SANITY) {
1053 print_LockSet("add-OUT", ret);
1054 sanity_check_locksets("add-OUT");
1055 }
1056 return ret;
1057}
1058
1059/* Builds ls with mx removed. mx should actually be in ls!
1060 (a checked assertion). Resulting set should not already
1061 exist in the table (unchecked).
1062*/
1063static
sewardj39a4d842002-11-13 22:14:30 +00001064LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001065{
1066 static const Bool debug = False;
1067 LockSet *ret = NULL;
1068 Int i, j;
1069
1070 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1071 print_LockSet("remove-IN", ls);
1072 }
1073
1074 if (debug || LOCKSET_SANITY)
1075 sanity_check_locksets("remove-IN");
1076
njnca82cc02004-11-22 17:18:48 +00001077 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001078
1079 ret = alloc_LockSet(ls->setsize-1);
1080
1081 for(i = j = 0; i < ls->setsize; i++) {
1082 if (mutex_cmp(ls->mutex[i], mx) == 0)
1083 continue;
1084 ret->mutex[j++] = ls->mutex[i];
1085 }
1086
njnca82cc02004-11-22 17:18:48 +00001087 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001088
1089 if (debug || LOCKSET_SANITY) {
1090 print_LockSet("remove-OUT", ret);
1091 sanity_check_locksets("remove-OUT");
1092 }
1093 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001094}
1095
1096
1097/* Builds the intersection, and then unbuilds it if it's already in the table.
1098 */
sewardj4bffb232002-11-13 21:46:34 +00001099static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001100{
sewardj4bffb232002-11-13 21:46:34 +00001101 static const Bool debug = False;
1102 Int iret;
1103 Int ia, ib;
1104 Int size;
1105 LockSet *ret;
1106 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001107
sewardj4bffb232002-11-13 21:46:34 +00001108 if (debug || LOCKSET_SANITY)
1109 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001110
sewardj4bffb232002-11-13 21:46:34 +00001111 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1112 print_LockSet("intersect a", a);
1113 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001114 }
1115
sewardj4bffb232002-11-13 21:46:34 +00001116 /* count the size of the new set */
1117 size = 0;
1118 ia = ib = 0;
1119 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1120 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1121 size++;
1122 ia++;
1123 ib++;
1124 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1125 ia++;
1126 } else {
njnca82cc02004-11-22 17:18:48 +00001127 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001128 ib++;
1129 }
njn25e49d8e72002-09-23 09:36:25 +00001130 }
1131
sewardj4bffb232002-11-13 21:46:34 +00001132 /* Build the intersection of the two sets */
1133 ret = alloc_LockSet(size);
1134 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1135 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001136 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001137 ret->mutex[iret++] = a->mutex[ia];
1138 ia++;
1139 ib++;
1140 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1141 ia++;
1142 } else {
njnca82cc02004-11-22 17:18:48 +00001143 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001144 ib++;
1145 }
1146 }
1147
1148 ret->hash = hash_LockSet(ret);
1149
njn25e49d8e72002-09-23 09:36:25 +00001150 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001151 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001152
sewardj4bffb232002-11-13 21:46:34 +00001153 if (found != NULL) {
1154 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001155 } else {
sewardj4bffb232002-11-13 21:46:34 +00001156 insert_LockSet(ret);
1157 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001158 }
1159
sewardj4bffb232002-11-13 21:46:34 +00001160 if (debug || LOCKSET_SANITY) {
1161 print_LockSet("intersect-OUT", found);
1162 sanity_check_locksets("intersect-OUT");
1163 }
njn25e49d8e72002-09-23 09:36:25 +00001164
sewardj4bffb232002-11-13 21:46:34 +00001165 return found;
njn25e49d8e72002-09-23 09:36:25 +00001166}
1167
sewardj4bffb232002-11-13 21:46:34 +00001168/* inline the fastpath */
1169static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001170{
sewardj4bffb232002-11-13 21:46:34 +00001171 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001172
1173 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001174 if (a == b) {
1175 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1176 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001177 }
sewardj4bffb232002-11-13 21:46:34 +00001178 return a;
sewardjc26cc252002-10-23 21:58:55 +00001179 }
1180
sewardj4bffb232002-11-13 21:46:34 +00001181 if (isempty(a) || isempty(b)) {
1182 if (debug)
1183 VG_(printf)("intersect empty fastpath\n");
1184 return emptyset;
1185 }
1186
1187 return _intersect(a, b);
1188}
1189
1190
1191static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1192{
1193 static const Bool debug = False;
1194 Int iret;
1195 Int ia, ib;
1196 Int size;
1197 LockSet *ret;
1198 const LockSet *found;
1199
1200 if (debug || LOCKSET_SANITY)
1201 sanity_check_locksets("union-IN");
1202
1203 /* Fast case -- when the two are the same */
1204 if (a == b) {
1205 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1206 print_LockSet("union-same fastpath", a);
1207 }
1208 return a;
1209 }
1210
1211 if (isempty(a)) {
1212 if (debug)
1213 print_LockSet("union a=empty b", b);
1214 return b;
1215 }
1216 if (isempty(b)) {
1217 if (debug)
1218 print_LockSet("union b=empty a", a);
1219 return a;
1220 }
1221
1222 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001223 print_LockSet("union a", a);
1224 print_LockSet("union b", b);
1225 }
1226
sewardj4bffb232002-11-13 21:46:34 +00001227 /* count the size of the new set */
1228 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1229 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001230
sewardj4bffb232002-11-13 21:46:34 +00001231 if ((ia < a->setsize) && (ib < b->setsize))
1232 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1233 else if (ia == a->setsize)
1234 cmp = 1;
1235 else
1236 cmp = -1;
1237
1238 if (cmp == 0) {
1239 size++;
1240 ia++;
1241 ib++;
1242 } else if (cmp < 0) {
1243 size++;
1244 ia++;
1245 } else {
njnca82cc02004-11-22 17:18:48 +00001246 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001247 size++;
1248 ib++;
1249 }
sewardjc26cc252002-10-23 21:58:55 +00001250 }
1251
sewardj4bffb232002-11-13 21:46:34 +00001252 /* Build the intersection of the two sets */
1253 ret = alloc_LockSet(size);
1254 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1255 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001256 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001257
1258 if ((ia < a->setsize) && (ib < b->setsize))
1259 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1260 else if (ia == a->setsize)
1261 cmp = 1;
1262 else
1263 cmp = -1;
1264
1265 if (cmp == 0) {
1266 ret->mutex[iret++] = a->mutex[ia];
1267 ia++;
1268 ib++;
1269 } else if (cmp < 0) {
1270 ret->mutex[iret++] = a->mutex[ia];
1271 ia++;
1272 } else {
njnca82cc02004-11-22 17:18:48 +00001273 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001274 ret->mutex[iret++] = b->mutex[ib];
1275 ib++;
1276 }
1277 }
1278
njnca82cc02004-11-22 17:18:48 +00001279 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001280
1281 ret->hash = hash_LockSet(ret);
1282
sewardjc26cc252002-10-23 21:58:55 +00001283 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001284 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001285
sewardj4bffb232002-11-13 21:46:34 +00001286 if (found != NULL) {
1287 if (debug)
1288 print_LockSet("union found existing set", found);
1289 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001290 } else {
sewardj4bffb232002-11-13 21:46:34 +00001291 if (debug)
1292 print_LockSet("union inserting new set", ret);
1293 insert_LockSet(ret);
1294 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001295 }
1296
sewardj4bffb232002-11-13 21:46:34 +00001297 if (debug || LOCKSET_SANITY) {
1298 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001299 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001300 }
sewardjc26cc252002-10-23 21:58:55 +00001301
sewardj4bffb232002-11-13 21:46:34 +00001302 return found;
sewardjc26cc252002-10-23 21:58:55 +00001303}
1304
1305/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001306/*--- Implementation of mutex structure. ---*/
1307/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001308
1309static UInt graph_mark; /* current mark we're using for graph traversal */
1310
sewardj39a4d842002-11-13 22:14:30 +00001311static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001312 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001313static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001314 const LockSet *lockset_holding,
1315 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001316
njn72718642003-07-24 08:45:32 +00001317static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001318
1319#define M_MUTEX_HASHSZ 1021
1320
sewardj39a4d842002-11-13 22:14:30 +00001321static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001322static UInt total_mutexes;
1323
1324static const Char *pp_MutexState(MutexState st)
1325{
1326 switch(st) {
1327 case MxLocked: return "Locked";
1328 case MxUnlocked: return "Unlocked";
1329 case MxDead: return "Dead";
1330 case MxUnknown: return "Unknown";
1331 }
1332 return "???";
1333}
1334
1335static void pp_all_mutexes()
1336{
1337 Int i;
1338 Int locks, buckets;
1339
1340 locks = buckets = 0;
1341 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001342 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001343 Bool first = True;
1344
1345 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1346 if (first) {
1347 buckets++;
1348 VG_(printf)("[%4d] = ", i);
1349 } else
1350 VG_(printf)(" ");
1351 locks++;
1352 first = False;
1353 VG_(printf)("%p [%8s] -> %p%(y\n",
1354 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1355 }
1356 }
1357
1358 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1359 locks, buckets, total_mutexes);
1360}
sewardjc26cc252002-10-23 21:58:55 +00001361
sewardj39a4d842002-11-13 22:14:30 +00001362/* find or create a Mutex for a program's mutex use */
1363static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001364{
nethercote50397c22004-11-04 18:03:06 +00001365 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001366 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001367
1368 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1369 if (mp->mutexp == mutexp)
1370 return mp;
1371
sewardjdac0a442002-11-13 22:08:40 +00001372 total_mutexes++;
1373
sewardjc26cc252002-10-23 21:58:55 +00001374 mp = VG_(malloc)(sizeof(*mp));
1375 mp->mutexp = mutexp;
1376 mp->next = mutex_hash[bucket];
1377 mutex_hash[bucket] = mp;
1378
1379 mp->state = MxUnknown;
1380 mp->tid = VG_INVALID_THREADID;
1381 mp->location = NULL;
1382
sewardj4bffb232002-11-13 21:46:34 +00001383 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001384 mp->mark = graph_mark - 1;
1385
1386 return mp;
1387}
1388
sewardjdac0a442002-11-13 22:08:40 +00001389/* Find all mutexes in a range of memory, and call the callback.
1390 Remove the mutex from the hash if the callback returns True (mutex
1391 structure itself is not freed, because it may be pointed to by a
1392 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001393static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001394{
sewardjdac0a442002-11-13 22:08:40 +00001395 UInt first = start % M_MUTEX_HASHSZ;
1396 UInt last = (end+1) % M_MUTEX_HASHSZ;
1397 UInt i;
1398
1399 /* Single pass over the hash table, looking for likely hashes */
1400 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001401 Mutex *mx;
1402 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001403
1404 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1405 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1406 *prev = mx->next;
1407 }
1408
1409 if (++i == M_MUTEX_HASHSZ)
1410 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001411 }
sewardjc26cc252002-10-23 21:58:55 +00001412}
1413
1414#define MARK_LOOP (graph_mark+0)
1415#define MARK_DONE (graph_mark+1)
1416
thughes4ad52d02004-06-27 17:37:21 +00001417static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1418{
1419 static const Bool debug = False;
1420 Int i;
1421
1422 if (mutex->mark == MARK_LOOP)
1423 return True; /* found cycle */
1424 if (mutex->mark == MARK_DONE)
1425 return False; /* been here before, its OK */
1426
1427 ((Mutex*)mutex)->mark = MARK_LOOP;
1428
1429 if (debug)
1430 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1431 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1432 for(i = 0; i < ls->setsize; i++) {
1433 const Mutex *mx = ls->mutex[i];
1434
1435 if (debug)
1436 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1437 mutex->mutexp, ls,
1438 mx->mutexp, mx->mutexp);
1439 if (check_cycle_inner(mx, mx->lockdep))
1440 return True;
1441 }
1442 ((Mutex*)mutex)->mark = MARK_DONE;
1443
1444 return False;
1445}
1446
sewardj39a4d842002-11-13 22:14:30 +00001447static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001448{
sewardjff2c9232002-11-13 21:44:39 +00001449
sewardjc26cc252002-10-23 21:58:55 +00001450 graph_mark += 2; /* clear all marks */
1451
sewardj4bffb232002-11-13 21:46:34 +00001452 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001453}
1454
sewardjdca84112002-11-13 22:29:34 +00001455/* test to see if a mutex state change would be problematic; this
1456 makes no changes to the mutex state. This should be called before
1457 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001458static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001459{
1460 static const Bool debug = False;
1461
sewardjc26cc252002-10-23 21:58:55 +00001462 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001463 Char *str;
1464
1465 switch(state) {
1466 case MxLocked: str = "lock dead mutex"; break;
1467 case MxUnlocked: str = "unlock dead mutex"; break;
1468 default: str = "operate on dead mutex"; break;
1469 }
1470
sewardjc26cc252002-10-23 21:58:55 +00001471 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001472 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001473 return;
1474 }
1475
1476 switch(state) {
1477 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001478 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001479
1480 if (debug)
1481 print_LockSet("thread holding", thread_locks[tid]);
1482
1483 if (check_cycle(mutex, thread_locks[tid]))
1484 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1485 else {
1486 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1487
1488 if (debug) {
1489 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1490 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1491 print_LockSet("lockdep", mutex->lockdep);
1492 }
1493 }
1494 break;
1495
1496 case MxUnlocked:
1497 if (debug)
1498 print_LockSet("thread holding", thread_locks[tid]);
1499
1500 if (mutex->state != MxLocked) {
1501 record_mutex_error(tid, mutex,
1502 "unlock non-locked mutex", mutex->location);
1503 }
1504 if (mutex->tid != tid) {
1505 record_mutex_error(tid, mutex,
1506 "unlock someone else's mutex", mutex->location);
1507 }
1508 break;
1509
1510 case MxDead:
1511 break;
1512
1513 default:
1514 break;
1515 }
1516}
1517
1518/* Update a mutex state. Expects most error testing and reporting to
1519 have happened in test_mutex_state(). The assumption is that no
1520 client code is run by thread tid between test and set, either
1521 because it is blocked or test and set are called together
1522 atomically.
1523
1524 Setting state to MxDead is the exception, since that can happen as
1525 a result of any thread freeing memory; in this case set_mutex_state
1526 does all the error reporting as well.
1527*/
njn72718642003-07-24 08:45:32 +00001528static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001529{
1530 static const Bool debug = False;
1531
1532 if (debug)
1533 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1534 tid, mutex, mutex->mutexp, mutex->mutexp,
1535 pp_MutexState(mutex->state), pp_MutexState(state));
1536
1537 if (mutex->state == MxDead) {
1538 /* can't do anything legal to a destroyed mutex */
1539 return;
1540 }
1541
1542 switch(state) {
1543 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001544 if (mutex->state == MxLocked) {
1545 if (mutex->tid != tid)
1546 record_mutex_error(tid, mutex, "take lock held by someone else",
1547 mutex->location);
1548 else
1549 record_mutex_error(tid, mutex, "take lock we already hold",
1550 mutex->location);
1551
njn67993252004-11-22 18:02:32 +00001552 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001553 break;
1554 }
sewardjc26cc252002-10-23 21:58:55 +00001555
njnca82cc02004-11-22 17:18:48 +00001556 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001557
sewardjc26cc252002-10-23 21:58:55 +00001558 mutex->tid = tid;
1559 break;
1560
1561 case MxUnlocked:
1562 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001563 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001564
sewardjdca84112002-11-13 22:29:34 +00001565 if (mutex->state != MxLocked || mutex->tid != tid)
1566 break;
1567
sewardjc26cc252002-10-23 21:58:55 +00001568 mutex->tid = VG_INVALID_THREADID;
1569 break;
1570
sewardjdac0a442002-11-13 22:08:40 +00001571 case MxDead:
1572 if (mutex->state == MxLocked) {
1573 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001574 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001575 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1576 mutex->tid = VG_INVALID_THREADID;
1577
1578 record_mutex_error(tid, mutex,
1579 "free locked mutex", mutex->location);
1580 }
1581 break;
1582
sewardjc26cc252002-10-23 21:58:55 +00001583 default:
1584 break;
1585 }
1586
njnd01fef72005-03-25 23:35:48 +00001587 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001588 mutex->state = state;
1589}
njn25e49d8e72002-09-23 09:36:25 +00001590
1591/*------------------------------------------------------------*/
1592/*--- Setting and checking permissions. ---*/
1593/*------------------------------------------------------------*/
1594
thughes4ad52d02004-06-27 17:37:21 +00001595/* only clean up dead mutexes */
1596static
1597Bool cleanmx(Mutex *mx) {
1598 return mx->state == MxDead;
1599}
1600
njn25e49d8e72002-09-23 09:36:25 +00001601static
nethercote451eae92004-11-02 13:06:32 +00001602void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001603 VgeInitStatus status )
1604{
sewardj1806d7f2002-10-22 05:05:49 +00001605 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001606
1607# if DEBUG_MAKE_ACCESSES
1608 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1609# endif
1610 //PROF_EVENT(30); PPP
1611
1612 if (len == 0)
1613 return;
1614
1615 if (len > 100 * 1000 * 1000)
1616 VG_(message)(Vg_UserMsg,
1617 "Warning: set address range state: large range %d",
1618 len);
1619
njn31513b42005-06-01 03:09:59 +00001620 //VGP_PUSHCC(VgpSARP);
njn25e49d8e72002-09-23 09:36:25 +00001621
sewardjdac0a442002-11-13 22:08:40 +00001622 /* Remove mutexes in recycled memory range from hash */
1623 find_mutex_range(a, a+len, cleanmx);
1624
njn25e49d8e72002-09-23 09:36:25 +00001625 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1626 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1627 * len/4+1 words. This works out which it is by aligning the block and
1628 * seeing if the end byte is in the same word as it is for the unaligned
1629 * block; if not, it's the awkward case. */
njn13bfd852005-06-02 03:52:53 +00001630 end = VG_ROUNDUP(a + len, 4);
1631 a = VG_ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001632
1633 /* Do it ... */
1634 switch (status) {
1635 case Vge_VirginInit:
1636 for ( ; a < end; a += 4) {
1637 //PROF_EVENT(31); PPP
1638 init_virgin_sword(a);
1639 }
1640 break;
1641
1642 case Vge_NonVirginInit:
1643 for ( ; a < end; a += 4) {
1644 //PROF_EVENT(31); PPP
1645 init_nonvirgin_sword(a);
1646 }
1647 break;
1648
1649 case Vge_SegmentInit:
1650 for ( ; a < end; a += 4) {
1651 //PROF_EVENT(31); PPP
1652 init_magically_inited_sword(a);
1653 }
1654 break;
sewardj7f3ad222002-11-13 22:11:53 +00001655
1656 case Vge_Error:
1657 for ( ; a < end; a += 4) {
1658 //PROF_EVENT(31); PPP
1659 init_error_sword(a);
1660 }
1661 break;
njn25e49d8e72002-09-23 09:36:25 +00001662
1663 default:
1664 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001665 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001666 }
1667
njn31513b42005-06-01 03:09:59 +00001668 //VGP_POPCC(VgpSARP);
njn25e49d8e72002-09-23 09:36:25 +00001669}
1670
1671
nethercote451eae92004-11-02 13:06:32 +00001672static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001673{
1674 //PROF_EVENT(??); PPP
1675 set_address_range_state ( a, len, Vge_SegmentInit );
1676}
1677
nethercote451eae92004-11-02 13:06:32 +00001678static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001679{
1680 //PROF_EVENT(36); PPP
1681 set_address_range_state( a, len, Vge_VirginInit );
1682}
1683
nethercote451eae92004-11-02 13:06:32 +00001684static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001685{
1686 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001687 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001688}
1689
1690
njn25e49d8e72002-09-23 09:36:25 +00001691/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001692static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001693{
1694 UInt i;
1695
1696 //PROF_EVENT(40); PPP
1697 for (i = 0; i < len; i += 4) {
1698 shadow_word sword = *(get_sword_addr ( src+i ));
1699 //PROF_EVENT(41); PPP
1700 set_sword ( dst+i, sword );
1701 }
1702}
1703
1704// SSS: put these somewhere better
njnfbdcba92005-05-09 01:23:49 +00001705static void hg_mem_read (Addr a, SizeT data_size, ThreadId tid);
1706static void hg_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001707
njnadb7a752005-06-11 01:30:57 +00001708__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001709static void hg_mem_help_read_1(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001710__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001711static void hg_mem_help_read_2(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001712__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001713static void hg_mem_help_read_4(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001714__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001715static void hg_mem_help_read_N(Addr a, SizeT size) VG_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001716
njnadb7a752005-06-11 01:30:57 +00001717__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001718static void hg_mem_help_write_1(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001719__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001720static void hg_mem_help_write_2(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001721__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001722static void hg_mem_help_write_4(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001723__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001724static void hg_mem_help_write_N(Addr a, SizeT size) VG_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001725
njnadb7a752005-06-11 01:30:57 +00001726__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001727static void bus_lock(void);
njnadb7a752005-06-11 01:30:57 +00001728__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001729static void bus_unlock(void);
1730
njn25e49d8e72002-09-23 09:36:25 +00001731static
njnfbdcba92005-05-09 01:23:49 +00001732void hg_pre_mem_read(CorePart part, ThreadId tid,
1733 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001734{
njn02bc4b82005-05-15 17:28:26 +00001735 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 +00001736 hg_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001737}
1738
1739static
njnfbdcba92005-05-09 01:23:49 +00001740void hg_pre_mem_read_asciiz(CorePart part, ThreadId tid,
1741 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001742{
njnfbdcba92005-05-09 01:23:49 +00001743 hg_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001744}
1745
1746static
njnfbdcba92005-05-09 01:23:49 +00001747void hg_pre_mem_write(CorePart part, ThreadId tid,
1748 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001749{
njnfbdcba92005-05-09 01:23:49 +00001750 hg_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001751}
1752
1753
1754
1755static
njnfbdcba92005-05-09 01:23:49 +00001756void hg_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001757{
njn1f3a9092002-10-04 09:22:30 +00001758 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001759 make_segment_readable(a, len);
1760}
1761
1762
1763static
njnfbdcba92005-05-09 01:23:49 +00001764void hg_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001765{
1766 if (is_inited) {
1767 make_readable(a, len);
1768 } else {
1769 make_writable(a, len);
1770 }
1771}
1772
1773static
njnfbdcba92005-05-09 01:23:49 +00001774void hg_set_perms (Addr a, SizeT len,
1775 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001776{
1777 if (rr) make_readable(a, len);
1778 else if (ww) make_writable(a, len);
1779 /* else do nothing */
1780}
1781
sewardjf6374322002-11-13 22:35:55 +00001782static
njnfbdcba92005-05-09 01:23:49 +00001783void hg_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001784{
1785 set_address_range_state(a, len, Vge_NonVirginInit);
1786}
1787
1788static
njnfbdcba92005-05-09 01:23:49 +00001789void hg_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001790{
1791 set_address_range_state(a, len, Vge_VirginInit);
1792}
njn25e49d8e72002-09-23 09:36:25 +00001793
1794/*--------------------------------------------------------------*/
1795/*--- Initialise the memory audit system on program startup. ---*/
1796/*--------------------------------------------------------------*/
1797
1798static
1799void init_shadow_memory(void)
1800{
1801 Int i;
1802
1803 for (i = 0; i < ESEC_MAP_WORDS; i++)
1804 distinguished_secondary_map.swords[i] = virgin_sword;
1805
1806 /* These entries gradually get overwritten as the used address
1807 space expands. */
1808 for (i = 0; i < 65536; i++)
1809 primary_map[i] = &distinguished_secondary_map;
1810}
1811
1812
njn3e884182003-04-15 13:03:23 +00001813/*------------------------------------------------------------*/
1814/*--- malloc() et al replacements ---*/
1815/*------------------------------------------------------------*/
1816
njnb4aee052003-04-15 14:09:58 +00001817static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001818
1819#define N_FREED_CHUNKS 2
1820static Int freechunkptr = 0;
1821static HG_Chunk *freechunks[N_FREED_CHUNKS];
1822
njn3e884182003-04-15 13:03:23 +00001823
1824/* Allocate a user-chunk of size bytes. Also allocate its shadow
1825 block, make the shadow block point at the user block. Put the
1826 shadow chunk on the appropriate list, and set all memory
1827 protections correctly. */
1828
nethercote7ac7f7b2004-11-02 12:36:02 +00001829static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001830{
1831 HG_Chunk* hc;
1832
1833 hc = VG_(malloc)(sizeof(HG_Chunk));
1834 hc->data = p;
1835 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001836 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001837 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001838
1839 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1840}
1841
1842/* Allocate memory and note change in memory available */
1843static __inline__
njn14d01ce2004-11-26 11:30:14 +00001844void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1845 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001846{
1847 Addr p;
1848
njn34ac0272003-09-30 14:20:00 +00001849 if (size < 0) return NULL;
1850
njn3e884182003-04-15 13:03:23 +00001851 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001852 if (!p) {
1853 return NULL;
1854 }
njn34ac0272003-09-30 14:20:00 +00001855 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001856 add_HG_Chunk ( tid, p, size );
njnfbdcba92005-05-09 01:23:49 +00001857 hg_new_mem_heap( p, size, is_zeroed );
njn3e884182003-04-15 13:03:23 +00001858
1859 return (void*)p;
1860}
1861
njn51d827b2005-05-09 01:02:08 +00001862static void* hg_malloc ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001863{
njn14d01ce2004-11-26 11:30:14 +00001864 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001865}
1866
njn51d827b2005-05-09 01:02:08 +00001867static void* hg___builtin_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001868{
njn14d01ce2004-11-26 11:30:14 +00001869 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001870}
1871
njn51d827b2005-05-09 01:02:08 +00001872static void* hg___builtin_vec_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001873{
njn14d01ce2004-11-26 11:30:14 +00001874 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001875}
1876
njn51d827b2005-05-09 01:02:08 +00001877static void* hg_memalign ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001878{
njn14d01ce2004-11-26 11:30:14 +00001879 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001880}
1881
njn51d827b2005-05-09 01:02:08 +00001882static void* hg_calloc ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001883{
njn14d01ce2004-11-26 11:30:14 +00001884 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001885 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001886}
1887
thughes4ad52d02004-06-27 17:37:21 +00001888static ThreadId deadmx_tid;
1889
1890static
1891Bool deadmx(Mutex *mx) {
1892 if (mx->state != MxDead)
1893 set_mutex_state(mx, MxDead, deadmx_tid);
1894
1895 return False;
1896}
1897
njn3e884182003-04-15 13:03:23 +00001898static
njn72718642003-07-24 08:45:32 +00001899void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001900 HG_Chunk** prev_chunks_next_ptr )
1901{
njn72718642003-07-24 08:45:32 +00001902 Addr start = hc->data;
1903 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001904
njn3e884182003-04-15 13:03:23 +00001905 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1906 avoid repeating the hash table lookup. Can't remove until at least
1907 after free and free_mismatch errors are done because they use
1908 describe_addr() which looks for it in malloclist. */
1909 *prev_chunks_next_ptr = hc->next;
1910
1911 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001912 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001913
1914 /* maintain a small window so that the error reporting machinery
1915 knows about this memory */
1916 if (freechunks[freechunkptr] != NULL) {
1917 /* free HG_Chunk */
1918 HG_Chunk* sc1 = freechunks[freechunkptr];
1919 VG_(cli_free) ( (void*)(sc1->data) );
1920 VG_(free) ( sc1 );
1921 }
1922
1923 freechunks[freechunkptr] = hc;
1924
1925 if (++freechunkptr == N_FREED_CHUNKS)
1926 freechunkptr = 0;
1927
1928 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001929 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001930 find_mutex_range(start, end, deadmx);
1931}
1932
1933
1934static __inline__
njn14d01ce2004-11-26 11:30:14 +00001935void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001936{
1937 HG_Chunk* hc;
1938 HG_Chunk** prev_chunks_next_ptr;
1939
nethercote3d6b6112004-11-04 16:39:43 +00001940 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001941 (VgHashNode***)&prev_chunks_next_ptr );
1942 if (hc == NULL) {
1943 return;
1944 }
njn14d01ce2004-11-26 11:30:14 +00001945 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001946}
1947
njn51d827b2005-05-09 01:02:08 +00001948static void hg_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001949{
njn14d01ce2004-11-26 11:30:14 +00001950 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001951}
1952
njn51d827b2005-05-09 01:02:08 +00001953static void hg___builtin_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001954{
njn14d01ce2004-11-26 11:30:14 +00001955 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001956}
1957
njn51d827b2005-05-09 01:02:08 +00001958static void hg___builtin_vec_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001959{
njn14d01ce2004-11-26 11:30:14 +00001960 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001961}
1962
njn51d827b2005-05-09 01:02:08 +00001963static void* hg_realloc ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001964{
1965 HG_Chunk *hc;
1966 HG_Chunk **prev_chunks_next_ptr;
sewardj05bcdcb2003-05-18 10:05:38 +00001967 Int i;
njn3e884182003-04-15 13:03:23 +00001968
1969 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001970 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001971 (VgHashNode***)&prev_chunks_next_ptr );
1972
1973 if (hc == NULL) {
1974 return NULL;
1975 }
1976
1977 if (hc->size == new_size) {
1978 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001979 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001980 return p;
1981
1982 } else if (hc->size > new_size) {
1983 /* new size is smaller */
1984 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001985 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001986 return p;
1987
1988 } else {
1989 /* new size is bigger */
1990 Addr p_new;
1991
1992 /* Get new memory */
1993 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
1994
1995 /* First half kept and copied, second half new */
1996 copy_address_range_state( (Addr)p, p_new, hc->size );
njnfbdcba92005-05-09 01:23:49 +00001997 hg_new_mem_heap ( p_new+hc->size, new_size-hc->size,
1998 /*inited*/False );
njn3e884182003-04-15 13:03:23 +00001999
2000 /* Copy from old to new */
2001 for (i = 0; i < hc->size; i++)
2002 ((UChar*)p_new)[i] = ((UChar*)p)[i];
2003
2004 /* Free old memory */
njn72718642003-07-24 08:45:32 +00002005 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00002006
2007 /* this has to be after die_and_free_mem, otherwise the
2008 former succeeds in shorting out the new block, not the
2009 old, in the case when both are on the same list. */
njn72718642003-07-24 08:45:32 +00002010 add_HG_Chunk ( tid, p_new, new_size );
njn3e884182003-04-15 13:03:23 +00002011
2012 return (void*)p_new;
2013 }
2014}
2015
njn25e49d8e72002-09-23 09:36:25 +00002016/*--------------------------------------------------------------*/
2017/*--- Machinery to support sanity checking ---*/
2018/*--------------------------------------------------------------*/
2019
njn51d827b2005-05-09 01:02:08 +00002020static Bool hg_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00002021{
jseward9800fd32004-01-04 23:08:04 +00002022 /* nothing useful we can rapidly check */
2023 return True;
njn25e49d8e72002-09-23 09:36:25 +00002024}
2025
njn51d827b2005-05-09 01:02:08 +00002026static Bool hg_expensive_sanity_check(void)
njn25e49d8e72002-09-23 09:36:25 +00002027{
2028 Int i;
2029
2030 /* Make sure nobody changed the distinguished secondary. */
2031 for (i = 0; i < ESEC_MAP_WORDS; i++)
2032 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2033 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2034 return False;
2035
2036 return True;
2037}
2038
2039
2040/*--------------------------------------------------------------*/
2041/*--- Instrumentation ---*/
2042/*--------------------------------------------------------------*/
2043
sewardjf6374322002-11-13 22:35:55 +00002044static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2045
njn14d01ce2004-11-26 11:30:14 +00002046#if 0
njn25e49d8e72002-09-23 09:36:25 +00002047/* Create and return an instrumented version of cb_in. Free cb_in
2048 before returning. */
njn26f02512004-11-22 18:33:15 +00002049UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002050{
2051 UCodeBlock* cb;
2052 Int i;
2053 UInstr* u_in;
2054 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002055 Int ntemps;
2056 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002057 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002058
njn810086f2002-11-14 12:42:47 +00002059 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002060
sewardjf6374322002-11-13 22:35:55 +00002061 /* stackref[] is used for super-simple value tracking to keep note
2062 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002063 the stack pointer or frame pointer, and is therefore likely
2064 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002065 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002066 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2067 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2068
njn810086f2002-11-14 12:42:47 +00002069 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2070 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002071
njn25e49d8e72002-09-23 09:36:25 +00002072 switch (u_in->opcode) {
2073
2074 case NOP: case CALLM_S: case CALLM_E:
2075 break;
sewardjf6374322002-11-13 22:35:55 +00002076
sewardj7a5ebcf2002-11-13 22:42:13 +00002077 case LOCK:
2078 locked = True;
2079 uInstr0(cb, CCALL, 0);
2080 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2081 break;
2082
2083 case JMP: case INCEIP:
2084 if (locked) {
2085 uInstr0(cb, CCALL, 0);
2086 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2087 }
2088 locked = False;
2089 VG_(copy_UInstr)(cb, u_in);
2090 break;
2091
sewardjf6374322002-11-13 22:35:55 +00002092 case GET:
njnca82cc02004-11-22 17:18:48 +00002093 tl_assert(u_in->tag1 == ArchReg);
2094 tl_assert(u_in->tag2 == TempReg);
2095 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002096
2097 stackref[u_in->val2] = (u_in->size == 4 &&
njnaf839f52005-06-23 03:27:57 +00002098 (u_in->val1 == VG_R_STACK_PTR ||
2099 u_in->val1 == VG_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002100 VG_(copy_UInstr)(cb, u_in);
2101 break;
2102
2103 case MOV:
2104 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002105 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002106 stackref[u_in->val2] = stackref[u_in->val1];
2107 }
2108 VG_(copy_UInstr)(cb, u_in);
2109 break;
2110
2111 case LEA1:
2112 case ADD: case SUB:
2113 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002114 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002115 stackref[u_in->val2] |= stackref[u_in->val1];
2116 }
2117 VG_(copy_UInstr)(cb, u_in);
2118 break;
njn25e49d8e72002-09-23 09:36:25 +00002119
sewardja5b3aec2002-10-22 05:09:36 +00002120 case LOAD: {
2121 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002122 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2123 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002124
2125 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2126 nonstk_ld++;
2127
2128 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002129 case 1: help = hg_mem_help_read_1; break;
2130 case 2: help = hg_mem_help_read_2; break;
2131 case 4: help = hg_mem_help_read_4; break;
sewardjf6374322002-11-13 22:35:55 +00002132 default:
njn67993252004-11-22 18:02:32 +00002133 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002134 }
jsgfcb1d1c02003-10-14 21:55:10 +00002135
2136 /* XXX all registers should be flushed to baseblock
2137 here */
sewardjf6374322002-11-13 22:35:55 +00002138 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2139 uCCall(cb, (Addr)help, 1, 1, False);
2140 } else
2141 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002142
sewardja5b3aec2002-10-22 05:09:36 +00002143 VG_(copy_UInstr)(cb, u_in);
2144 t_size = INVALID_TEMPREG;
2145 break;
2146 }
2147
fitzhardinge111c6072004-03-09 02:45:07 +00002148 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002149 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002150 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002151 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002152
fitzhardinge111c6072004-03-09 02:45:07 +00002153 t_size = newTemp(cb);
2154 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2155 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002156
fitzhardinge111c6072004-03-09 02:45:07 +00002157 /* XXX all registers should be flushed to baseblock
2158 here */
2159 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002160 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002161
2162 VG_(copy_UInstr)(cb, u_in);
2163 t_size = INVALID_TEMPREG;
2164 break;
sewardja5b3aec2002-10-22 05:09:36 +00002165 }
2166
thughes96b466a2004-03-15 16:43:58 +00002167 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002168 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002169
2170 t_size = newTemp(cb);
2171 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2172 uLiteral(cb, (UInt)u_in->size);
2173
2174 /* XXX all registers should be flushed to baseblock
2175 here */
2176 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002177 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
thughes96b466a2004-03-15 16:43:58 +00002178
2179 VG_(copy_UInstr)(cb, u_in);
2180 t_size = INVALID_TEMPREG;
2181 break;
2182 }
2183
fitzhardinge111c6072004-03-09 02:45:07 +00002184 case SSE2a_MemRd:
2185 case SSE2a1_MemRd:
2186 case SSE3a_MemRd:
2187 case SSE3a1_MemRd:
2188 case SSE3ag_MemRd_RegWr: {
2189 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2190
njnca82cc02004-11-22 17:18:48 +00002191 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002192
2193 t_size = newTemp(cb);
2194 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2195 uLiteral(cb, (UInt)u_in->size);
2196
2197 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002198 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002199
2200 VG_(copy_UInstr)(cb, u_in);
2201 t_size = INVALID_TEMPREG;
2202 break;
2203 }
2204
sewardja5b3aec2002-10-22 05:09:36 +00002205 case STORE: {
2206 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002207 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2208 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002209
sewardjf6374322002-11-13 22:35:55 +00002210 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2211 nonstk_st++;
2212
2213 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002214 case 1: help = hg_mem_help_write_1; break;
2215 case 2: help = hg_mem_help_write_2; break;
2216 case 4: help = hg_mem_help_write_4; break;
sewardjf6374322002-11-13 22:35:55 +00002217 default:
njn67993252004-11-22 18:02:32 +00002218 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002219 }
2220
jsgfcb1d1c02003-10-14 21:55:10 +00002221 /* XXX all registers should be flushed to baseblock
2222 here */
sewardjf6374322002-11-13 22:35:55 +00002223 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2224 uCCall(cb, (Addr)help, 2, 2, False);
2225 } else
2226 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002227
2228 VG_(copy_UInstr)(cb, u_in);
2229 t_size = INVALID_TEMPREG;
2230 break;
2231 }
2232
fitzhardinge111c6072004-03-09 02:45:07 +00002233 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002234 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002235 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002236 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002237
2238 t_size = newTemp(cb);
2239 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2240 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002241 /* XXX all registers should be flushed to baseblock
2242 here */
sewardja5b3aec2002-10-22 05:09:36 +00002243 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002244 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
sewardja5b3aec2002-10-22 05:09:36 +00002245
2246 VG_(copy_UInstr)(cb, u_in);
2247 t_size = INVALID_TEMPREG;
2248 break;
2249 }
njn25e49d8e72002-09-23 09:36:25 +00002250
fitzhardinge111c6072004-03-09 02:45:07 +00002251 case SSE2a_MemWr:
2252 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002253 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002254 512 == u_in->size);
2255
2256 t_size = newTemp(cb);
2257 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2258 uLiteral(cb, (UInt)u_in->size);
2259 /* XXX all registers should be flushed to baseblock
2260 here */
2261 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002262 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002263
2264 VG_(copy_UInstr)(cb, u_in);
2265 t_size = INVALID_TEMPREG;
2266 break;
2267 }
sewardj3d7c9c82003-03-26 21:08:13 +00002268
njn25e49d8e72002-09-23 09:36:25 +00002269 default:
sewardjf6374322002-11-13 22:35:55 +00002270 /* conservative tromping */
2271 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2272 stackref[u_in->val1] = False;
2273 if (u_in->tag2 == TempReg)
2274 stackref[u_in->val2] = False;
2275 if (u_in->tag3 == TempReg)
2276 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002277 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002278 break;
2279 }
2280 }
2281
sewardjf6374322002-11-13 22:35:55 +00002282 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002283 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002284 return cb;
2285}
njn14d01ce2004-11-26 11:30:14 +00002286#endif
njn51d827b2005-05-09 01:02:08 +00002287static IRBB* hg_instrument ( IRBB* bb_in, VexGuestLayout* layout,
2288 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002289{
2290 VG_(message)(Vg_DebugMsg, "Helgrind is not yet ready to handle Vex IR");
2291 VG_(exit)(1);
2292}
njn25e49d8e72002-09-23 09:36:25 +00002293
2294/*--------------------------------------------------------------------*/
2295/*--- Error and suppression handling ---*/
2296/*--------------------------------------------------------------------*/
2297
2298typedef
2299 enum {
2300 /* Possible data race */
njnfbdcba92005-05-09 01:23:49 +00002301 RaceSupp
njn25e49d8e72002-09-23 09:36:25 +00002302 }
njnfbdcba92005-05-09 01:23:49 +00002303 RaceSuppKind;
njn25e49d8e72002-09-23 09:36:25 +00002304
2305/* What kind of error it is. */
2306typedef
2307 enum {
njnfbdcba92005-05-09 01:23:49 +00002308 RaceErr, /* data-race */
sewardj16748af2002-10-22 04:55:54 +00002309 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002310 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002311 }
njnfbdcba92005-05-09 01:23:49 +00002312 RaceErrorKind;
njn25e49d8e72002-09-23 09:36:25 +00002313
sewardj16748af2002-10-22 04:55:54 +00002314/* The classification of a faulting address. */
2315typedef
2316 enum { Undescribed, /* as-yet unclassified */
2317 Stack,
2318 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002319 Mallocd,
2320 Freed,
sewardj16748af2002-10-22 04:55:54 +00002321 Segment
2322 }
2323 AddrKind;
2324/* Records info about a faulting address. */
2325typedef
2326 struct {
2327 /* ALL */
2328 AddrKind akind;
2329 /* Freed, Mallocd */
2330 Int blksize;
2331 /* Freed, Mallocd */
2332 Int rwoffset;
2333 /* Freed, Mallocd */
2334 ExeContext* lastchange;
2335 ThreadId lasttid;
2336 /* Stack */
2337 ThreadId stack_tid;
2338 /* Segment */
2339 const Char* filename;
2340 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002341 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002342 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002343 /* symbolic address description */
2344 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002345 }
2346 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002347
sewardj16748af2002-10-22 04:55:54 +00002348/* What kind of memory access is involved in the error? */
2349typedef
2350 enum { ReadAxs, WriteAxs, ExecAxs }
2351 AxsKind;
2352
2353/* Extra context for memory errors */
2354typedef
2355 struct {
2356 AxsKind axskind;
2357 Int size;
2358 AddrInfo addrinfo;
2359 Bool isWrite;
2360 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002361 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002362 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002363 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002364 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002365 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002366 const LockSet *held_lockset;
2367 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002368 }
2369 HelgrindError;
2370
2371static __inline__
2372void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002373{
sewardj16748af2002-10-22 04:55:54 +00002374 ai->akind = Unknown;
2375 ai->blksize = 0;
2376 ai->rwoffset = 0;
2377 ai->lastchange = NULL;
2378 ai->lasttid = VG_INVALID_THREADID;
2379 ai->filename = NULL;
2380 ai->section = "???";
2381 ai->stack_tid = VG_INVALID_THREADID;
2382 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002383 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002384}
2385
sewardj16748af2002-10-22 04:55:54 +00002386static __inline__
2387void clear_HelgrindError ( HelgrindError* err_extra )
2388{
2389 err_extra->axskind = ReadAxs;
2390 err_extra->size = 0;
2391 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002392 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002393 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002394 err_extra->prev_lockset = 0;
2395 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002396 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002397 clear_AddrInfo ( &err_extra->addrinfo );
2398 err_extra->isWrite = False;
2399}
2400
2401
2402
2403/* Describe an address as best you can, for error messages,
2404 putting the result in ai. */
2405
thughes4ad52d02004-06-27 17:37:21 +00002406/* Callback for searching malloc'd and free'd lists */
2407static Bool addr_is_in_block(VgHashNode *node, void *ap)
2408{
2409 HG_Chunk* hc2 = (HG_Chunk*)node;
2410 Addr a = *(Addr *)ap;
2411
2412 return (hc2->data <= a && a < hc2->data + hc2->size);
2413}
2414
sewardj16748af2002-10-22 04:55:54 +00002415static void describe_addr ( Addr a, AddrInfo* ai )
2416{
njn3e884182003-04-15 13:03:23 +00002417 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002418 Int i;
sewardj16748af2002-10-22 04:55:54 +00002419
sewardj16748af2002-10-22 04:55:54 +00002420 /* Search for it in segments */
2421 {
njn36ef6ba2005-05-14 18:42:26 +00002422 const SegInfo *si;
sewardj16748af2002-10-22 04:55:54 +00002423
njn36ef6ba2005-05-14 18:42:26 +00002424 for (si = VG_(next_seginfo)(NULL);
2425 si != NULL;
2426 si = VG_(next_seginfo)(si))
2427 {
2428 Addr base = VG_(seg_start)(si);
2429 SizeT size = VG_(seg_size)(si);
2430 const UChar *filename = VG_(seg_filename)(si);
sewardj16748af2002-10-22 04:55:54 +00002431
2432 if (a >= base && a < base+size) {
2433 ai->akind = Segment;
2434 ai->blksize = size;
2435 ai->rwoffset = a - base;
2436 ai->filename = filename;
2437
2438 switch(VG_(seg_sect_kind)(a)) {
2439 case Vg_SectText: ai->section = "text"; break;
2440 case Vg_SectData: ai->section = "data"; break;
2441 case Vg_SectBSS: ai->section = "BSS"; break;
2442 case Vg_SectGOT: ai->section = "GOT"; break;
2443 case Vg_SectPLT: ai->section = "PLT"; break;
2444 case Vg_SectUnknown:
2445 default:
2446 ai->section = "???"; break;
2447 }
2448
2449 return;
2450 }
2451 }
2452 }
2453
2454 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002455 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002456 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002457 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002458 ai->blksize = hc->size;
2459 ai->rwoffset = (Int)a - (Int)(hc->data);
2460 ai->lastchange = hc->where;
2461 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002462 return;
2463 }
sewardjdac0a442002-11-13 22:08:40 +00002464
2465 /* Look in recently freed memory */
2466 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002467 hc = freechunks[i];
2468 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002469 continue;
2470
njn3e884182003-04-15 13:03:23 +00002471 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002472 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002473 ai->blksize = hc->size;
2474 ai->rwoffset = a - hc->data;
2475 ai->lastchange = hc->where;
2476 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002477 return;
2478 }
2479 }
2480
sewardj16748af2002-10-22 04:55:54 +00002481 /* Clueless ... */
2482 ai->akind = Unknown;
2483 return;
2484}
2485
2486
njn7e614812003-04-21 22:04:03 +00002487/* Updates the copy with address info if necessary. */
njn51d827b2005-05-09 01:02:08 +00002488static UInt hg_update_extra(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002489{
njn7e614812003-04-21 22:04:03 +00002490 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002491
njn7e614812003-04-21 22:04:03 +00002492 extra = (HelgrindError*)VG_(get_error_extra)(err);
2493 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2494 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2495 }
2496 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002497}
2498
njnfbdcba92005-05-09 01:23:49 +00002499static void record_race_error ( ThreadId tid, Addr a, Bool is_write,
2500 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002501{
sewardjc4a810d2002-11-13 22:25:51 +00002502 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002503 HelgrindError err_extra;
2504
njnfbdcba92005-05-09 01:23:49 +00002505 n_hg_warnings++;
sewardjff2c9232002-11-13 21:44:39 +00002506
sewardj16748af2002-10-22 04:55:54 +00002507 clear_HelgrindError(&err_extra);
2508 err_extra.isWrite = is_write;
2509 err_extra.addrinfo.akind = Undescribed;
2510 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002511 if (clo_execontext)
2512 err_extra.lasttouched = getExeContext(a);
jsgfcb1d1c02003-10-14 21:55:10 +00002513 err_extra.addrinfo.expr = VG_(describe_addr)(tid, a);
2514
njnfbdcba92005-05-09 01:23:49 +00002515 VG_(maybe_record_error)( tid, RaceErr, a,
sewardj16748af2002-10-22 04:55:54 +00002516 (is_write ? "writing" : "reading"),
2517 &err_extra);
2518
sewardjc4a810d2002-11-13 22:25:51 +00002519 sw = get_sword_addr(a);
2520 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2521 ThreadLifeSeg *tls = unpackTLS(sw->other);
2522 tls->refcount--;
2523 }
2524
sewardj7f3ad222002-11-13 22:11:53 +00002525 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002526}
2527
sewardj39a4d842002-11-13 22:14:30 +00002528static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002529 Char *str, ExeContext *ec)
2530{
2531 HelgrindError err_extra;
2532
2533 clear_HelgrindError(&err_extra);
2534 err_extra.addrinfo.akind = Undescribed;
2535 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002536 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002537 err_extra.lasttid = tid;
2538
njn72718642003-07-24 08:45:32 +00002539 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002540 (Addr)mutex->mutexp, str, &err_extra);
2541}
njn25e49d8e72002-09-23 09:36:25 +00002542
sewardj39a4d842002-11-13 22:14:30 +00002543static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002544 const LockSet *lockset_holding,
2545 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002546{
2547 HelgrindError err_extra;
2548
2549 n_lockorder_warnings++;
2550
2551 clear_HelgrindError(&err_extra);
2552 err_extra.addrinfo.akind = Undescribed;
2553 err_extra.mutex = mutex;
2554
sewardjc808ef52002-11-13 22:43:26 +00002555 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002556 err_extra.held_lockset = lockset_holding;
2557 err_extra.prev_lockset = lockset_prev;
2558
njn72718642003-07-24 08:45:32 +00002559 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002560}
2561
njn51d827b2005-05-09 01:02:08 +00002562static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002563{
njn810086f2002-11-14 12:42:47 +00002564 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002565
njnca82cc02004-11-22 17:18:48 +00002566 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002567
2568 switch (VG_(get_error_kind)(e1)) {
njnfbdcba92005-05-09 01:23:49 +00002569 case RaceErr:
njn810086f2002-11-14 12:42:47 +00002570 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002571
2572 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002573 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002574 }
2575
njn810086f2002-11-14 12:42:47 +00002576 e1s = VG_(get_error_string)(e1);
2577 e2s = VG_(get_error_string)(e2);
2578 if (e1s != e2s) return False;
2579 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002580 return True;
2581}
2582
sewardj16748af2002-10-22 04:55:54 +00002583static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002584{
jsgfcb1d1c02003-10-14 21:55:10 +00002585 if (ai->expr != NULL)
2586 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002587 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002588
sewardj16748af2002-10-22 04:55:54 +00002589 switch (ai->akind) {
2590 case Stack:
2591 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002592 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002593 a, ai->stack_tid);
2594 break;
2595 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002596 if (ai->expr != NULL)
2597 break;
2598
nethercote3b390c72003-11-13 17:53:43 +00002599 /* maybe_gcc is never set to True! This is a hangover from code
2600 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002601 if (ai->maybe_gcc) {
2602 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002603 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002604 a);
2605 VG_(message)(Vg_UserMsg,
2606 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2607 } else {
2608 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002609 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002610 }
2611 break;
2612 case Segment:
2613 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002614 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002615 a, ai->section, ai->filename);
2616 break;
sewardjdac0a442002-11-13 22:08:40 +00002617 case Mallocd:
2618 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002619 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002620 UChar* relative;
2621 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002622 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002623 relative = "before";
2624 } else if (ai->rwoffset >= ai->blksize) {
2625 delta = ai->rwoffset - ai->blksize;
2626 relative = "after";
2627 } else {
2628 delta = ai->rwoffset;
2629 relative = "inside";
2630 }
2631 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002632 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2633 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002634 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002635 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002636 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002637
sewardj16748af2002-10-22 04:55:54 +00002638 VG_(pp_ExeContext)(ai->lastchange);
2639 break;
2640 }
2641 default:
njn67993252004-11-22 18:02:32 +00002642 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002643 }
njn25e49d8e72002-09-23 09:36:25 +00002644}
2645
sewardj4bffb232002-11-13 21:46:34 +00002646static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002647{
sewardjff2c9232002-11-13 21:44:39 +00002648 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002649 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002650
sewardj4bffb232002-11-13 21:46:34 +00002651 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2652 lockset->setsize * 120 +
2653 1);
sewardjff2c9232002-11-13 21:44:39 +00002654
2655 cp = buf;
2656 if (prefix)
2657 cp += VG_(sprintf)(cp, "%s", prefix);
2658
sewardj4bffb232002-11-13 21:46:34 +00002659 for(i = 0; i < lockset->setsize; i++)
2660 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2661 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002662
sewardj4bffb232002-11-13 21:46:34 +00002663 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002664 cp[-2] = '\0';
2665 else
2666 *cp = '\0';
2667
2668 return buf;
2669}
njn25e49d8e72002-09-23 09:36:25 +00002670
njn51d827b2005-05-09 01:02:08 +00002671static void hg_pp_Error ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002672{
njn810086f2002-11-14 12:42:47 +00002673 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002674 Char buf[100];
2675 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002676 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002677
2678 *msg = '\0';
2679
njn810086f2002-11-14 12:42:47 +00002680 switch(VG_(get_error_kind)(err)) {
njnfbdcba92005-05-09 01:23:49 +00002681 case RaceErr: {
njn810086f2002-11-14 12:42:47 +00002682 Addr err_addr = VG_(get_error_address)(err);
2683
sewardj16748af2002-10-22 04:55:54 +00002684 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002685 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002686 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002687 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002688
2689 switch(extra->prevstate.state) {
2690 case Vge_Virgin:
2691 /* shouldn't be possible to go directly from virgin -> error */
2692 VG_(sprintf)(buf, "virgin!?");
2693 break;
2694
sewardjc4a810d2002-11-13 22:25:51 +00002695 case Vge_Excl: {
2696 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2697
njnca82cc02004-11-22 17:18:48 +00002698 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002699 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002700 break;
sewardjc4a810d2002-11-13 22:25:51 +00002701 }
sewardj16748af2002-10-22 04:55:54 +00002702
2703 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002704 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002705 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002706
2707 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002708 VG_(sprintf)(buf, "shared %s, no locks",
2709 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2710 break;
2711 }
2712
sewardjff2c9232002-11-13 21:44:39 +00002713 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2714 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002715 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002716
sewardj16748af2002-10-22 04:55:54 +00002717 break;
2718 }
sewardj16748af2002-10-22 04:55:54 +00002719
sewardj499e3de2002-11-13 22:22:25 +00002720 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002721 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002722
sewardj72baa7a2002-12-09 23:32:58 +00002723 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002724 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002725 Char file[100];
2726 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002727 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002728
nethercote3b390c72003-11-13 17:53:43 +00002729 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002730 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002731 pp_state(extra->lasttouched.state),
2732 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002733
sewardj7cee6f92005-06-13 17:39:06 +00002734 if (VG_(get_filename_linenum)(ip, file, sizeof(file),
2735 NULL, 0, NULL, &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002736 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002737 ip, ip, file, line);
2738 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002739 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002740 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002741 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002742 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002743 }
sewardj72baa7a2002-12-09 23:32:58 +00002744 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002745 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002746 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002747 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002748 pp_state(extra->lasttouched.state),
2749 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002750 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002751 }
sewardj16748af2002-10-22 04:55:54 +00002752 break;
njn810086f2002-11-14 12:42:47 +00002753 }
sewardj16748af2002-10-22 04:55:54 +00002754
2755 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002756 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002757 VG_(get_error_address)(err),
2758 VG_(get_error_address)(err),
2759 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002760 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002761 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002762 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002763 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002764 }
njn810086f2002-11-14 12:42:47 +00002765 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002766 break;
sewardjff2c9232002-11-13 21:44:39 +00002767
2768 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002769 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002770 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002771 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002772
2773 msg = lockset_str(NULL, heldset);
2774
2775 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002776 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002777 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002778 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2779
sewardj4bffb232002-11-13 21:46:34 +00002780 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002781 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002782
sewardj542494b2002-11-13 22:46:13 +00002783 /* needs to be a recursive search+display */
2784 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002785 continue;
2786
nethercote3b390c72003-11-13 17:53:43 +00002787 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002788 lsmx->mutexp, lsmx->mutexp);
2789 VG_(pp_ExeContext)(lsmx->location);
2790 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002791 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002792 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002793 }
2794
2795 break;
sewardj16748af2002-10-22 04:55:54 +00002796 }
sewardjff2c9232002-11-13 21:44:39 +00002797 }
2798
2799 if (msg != buf)
2800 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002801}
2802
2803
njn51d827b2005-05-09 01:02:08 +00002804static Bool hg_recognised_suppression ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002805{
2806 if (0 == VG_(strcmp)(name, "Eraser")) {
njnfbdcba92005-05-09 01:23:49 +00002807 VG_(set_supp_kind)(su, RaceSupp);
njn25e49d8e72002-09-23 09:36:25 +00002808 return True;
2809 } else {
2810 return False;
2811 }
2812}
2813
2814
njn51d827b2005-05-09 01:02:08 +00002815static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002816{
2817 /* do nothing -- no extra suppression info present. Return True to
2818 indicate nothing bad happened. */
2819 return True;
2820}
2821
2822
njn51d827b2005-05-09 01:02:08 +00002823static Bool hg_error_matches_suppression(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002824{
njnfbdcba92005-05-09 01:23:49 +00002825 tl_assert(VG_(get_supp_kind)(su) == RaceSupp);
nethercote64366b42003-12-01 13:11:47 +00002826
njnfbdcba92005-05-09 01:23:49 +00002827 return (VG_(get_error_kind)(err) == RaceErr);
njn25e49d8e72002-09-23 09:36:25 +00002828}
2829
njn51d827b2005-05-09 01:02:08 +00002830static Char* hg_get_error_name ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002831{
njnfbdcba92005-05-09 01:23:49 +00002832 if (RaceErr == VG_(get_error_kind)(err)) {
2833 return "Eraser"; // old name, required for backwards compatibility
njn43c799e2003-04-08 00:08:52 +00002834 } else {
2835 return NULL; /* Other errors types can't be suppressed */
2836 }
2837}
2838
njn51d827b2005-05-09 01:02:08 +00002839static void hg_print_extra_suppression_info ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002840{
2841 /* Do nothing */
2842}
njn25e49d8e72002-09-23 09:36:25 +00002843
njnfbdcba92005-05-09 01:23:49 +00002844static void hg_pre_mutex_lock(ThreadId tid, void* void_mutex)
sewardjdca84112002-11-13 22:29:34 +00002845{
2846 Mutex *mutex = get_mutex((Addr)void_mutex);
2847
njn72718642003-07-24 08:45:32 +00002848 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002849}
2850
njnfbdcba92005-05-09 01:23:49 +00002851static void hg_post_mutex_lock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002852{
sewardj4bffb232002-11-13 21:46:34 +00002853 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002854 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002855 const LockSet* ls;
2856
njn72718642003-07-24 08:45:32 +00002857 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002858
njn25e49d8e72002-09-23 09:36:25 +00002859# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002860 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002861# endif
2862
njn25e49d8e72002-09-23 09:36:25 +00002863 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2864# if LOCKSET_SANITY > 1
njnfbdcba92005-05-09 01:23:49 +00002865 sanity_check_locksets("hg_post_mutex_lock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002866# endif
2867
sewardj4bffb232002-11-13 21:46:34 +00002868 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002869
sewardj4bffb232002-11-13 21:46:34 +00002870 if (ls == NULL) {
2871 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2872 insert_LockSet(newset);
2873 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002874 }
sewardj4bffb232002-11-13 21:46:34 +00002875 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002876
sewardj4bffb232002-11-13 21:46:34 +00002877 if (debug || DEBUG_LOCKS)
2878 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002879
sewardj4bffb232002-11-13 21:46:34 +00002880 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002881 sanity_check_locksets("hg_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002882}
2883
2884
njnfbdcba92005-05-09 01:23:49 +00002885static void hg_post_mutex_unlock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002886{
sewardjc26cc252002-10-23 21:58:55 +00002887 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002888 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002889 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002890 const LockSet *ls;
2891
njn72718642003-07-24 08:45:32 +00002892 test_mutex_state(mutex, MxUnlocked, tid);
2893 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002894
sewardjdac0a442002-11-13 22:08:40 +00002895 if (!ismember(thread_locks[tid], mutex))
2896 return;
2897
sewardjc26cc252002-10-23 21:58:55 +00002898 if (debug || DEBUG_LOCKS)
2899 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002900
sewardjc26cc252002-10-23 21:58:55 +00002901 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002902 sanity_check_locksets("hg_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002903
sewardj4bffb232002-11-13 21:46:34 +00002904 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002905
sewardj4bffb232002-11-13 21:46:34 +00002906 if (ls == NULL) {
2907 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2908 insert_LockSet(newset);
2909 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002910 }
2911
2912 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002913 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002914 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002915 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002916
sewardj4bffb232002-11-13 21:46:34 +00002917 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002918
sewardjc26cc252002-10-23 21:58:55 +00002919 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002920 sanity_check_locksets("hg_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002921}
2922
2923
2924/* ---------------------------------------------------------------------
2925 Checking memory reads and writes
2926 ------------------------------------------------------------------ */
2927
2928/* Behaviour on reads and writes:
2929 *
2930 * VIR EXCL SHAR SH_MOD
2931 * ----------------------------------------------------------------
2932 * rd/wr, 1st thread | - EXCL - -
2933 * rd, new thread | - SHAR - -
2934 * wr, new thread | - SH_MOD - -
2935 * rd | error! - SHAR SH_MOD
2936 * wr | EXCL - SH_MOD SH_MOD
2937 * ----------------------------------------------------------------
2938 */
2939
sewardj8fac99a2002-11-13 22:31:26 +00002940static inline
njn25e49d8e72002-09-23 09:36:25 +00002941void dump_around_a(Addr a)
2942{
2943 UInt i;
2944 shadow_word* sword;
2945 VG_(printf)("NEARBY:\n");
2946 for (i = a - 12; i <= a + 12; i += 4) {
2947 sword = get_sword_addr(i);
2948 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2949 }
2950}
njn25e49d8e72002-09-23 09:36:25 +00002951
2952#if DEBUG_ACCESSES
2953 #define DEBUG_STATE(args...) \
2954 VG_(printf)("(%u) ", size), \
2955 VG_(printf)(args)
2956#else
2957 #define DEBUG_STATE(args...)
2958#endif
2959
njnfbdcba92005-05-09 01:23:49 +00002960static void hg_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002961{
sewardj72baa7a2002-12-09 23:32:58 +00002962 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002963 shadow_word prevstate;
2964 ThreadLifeSeg *tls;
2965 const LockSet *ls;
2966 Bool statechange = False;
2967
2968 static const void *const states[4] = {
2969 [Vge_Virgin] &&st_virgin,
2970 [Vge_Excl] &&st_excl,
2971 [Vge_Shar] &&st_shar,
2972 [Vge_SharMod] &&st_sharmod,
2973 };
2974
2975 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002976 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002977
2978 sword = get_sword_addr(a);
2979 if (sword == SEC_MAP_ACCESS) {
2980 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2981 return;
2982 }
2983
2984 prevstate = *sword;
2985
2986 goto *states[sword->state];
2987
2988 /* This looks like reading of unitialised memory, may be legit. Eg.
2989 * calloc() zeroes its values, so untouched memory may actually be
2990 * initialised. Leave that stuff to Valgrind. */
2991 st_virgin:
2992 if (TID_INDICATING_NONVIRGIN == sword->other) {
2993 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
2994 if (DEBUG_VIRGIN_READS)
2995 dump_around_a(a);
2996 } else {
2997 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
2998 }
2999 statechange = True;
3000 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
3001 tls->refcount++;
3002 goto done;
3003
3004 st_excl: {
3005 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3006
3007 if (tls == sw_tls) {
3008 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
3009 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3010 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
3011 } else if (tlsIsDisjoint(tls, sw_tls)) {
3012 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3013 statechange = True;
3014 sword->other = packTLS(tls);
3015 sw_tls->refcount--;
3016 tls->refcount++;
3017 } else {
3018 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3019 sw_tls->refcount--;
3020 statechange = True;
3021 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3022
3023 if (DEBUG_MEM_LOCKSET_CHANGES)
3024 print_LockSet("excl read locks", unpackLockSet(sword->other));
3025 }
3026 goto done;
3027 }
3028
3029 st_shar:
3030 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3031 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3032 thread_locks[tid]));
3033 statechange = sword->other != prevstate.other;
3034 goto done;
3035
3036 st_sharmod:
3037 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3038 ls = intersect(unpackLockSet(sword->other),
3039 thread_locks[tid]);
3040 sword->other = packLockSet(ls);
3041
3042 statechange = sword->other != prevstate.other;
3043
3044 if (isempty(ls)) {
njnfbdcba92005-05-09 01:23:49 +00003045 record_race_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003046 }
3047 goto done;
3048
3049 done:
3050 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003051 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003052
3053 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003054 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003055 else
njnd01fef72005-03-25 23:35:48 +00003056 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003057 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003058 }
3059}
njn25e49d8e72002-09-23 09:36:25 +00003060
njnfbdcba92005-05-09 01:23:49 +00003061static void hg_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003062{
njn72718642003-07-24 08:45:32 +00003063 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003064
njn13bfd852005-06-02 03:52:53 +00003065 end = VG_ROUNDUP(a+size, 4);
3066 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003067
sewardj18cd4a52002-11-13 22:37:41 +00003068 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003069 hg_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003070}
3071
njnfbdcba92005-05-09 01:23:49 +00003072static void hg_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003073{
3074 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003075 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003076 shadow_word prevstate;
3077 Bool statechange = False;
3078 static const void *const states[4] = {
3079 [Vge_Virgin] &&st_virgin,
3080 [Vge_Excl] &&st_excl,
3081 [Vge_Shar] &&st_shar,
3082 [Vge_SharMod] &&st_sharmod,
3083 };
3084
sewardjc4a810d2002-11-13 22:25:51 +00003085 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003086 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003087
sewardj18cd4a52002-11-13 22:37:41 +00003088 sword = get_sword_addr(a);
3089 if (sword == SEC_MAP_ACCESS) {
3090 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3091 return;
3092 }
njn25e49d8e72002-09-23 09:36:25 +00003093
sewardj18cd4a52002-11-13 22:37:41 +00003094 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003095
sewardj18cd4a52002-11-13 22:37:41 +00003096 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003097
sewardj18cd4a52002-11-13 22:37:41 +00003098 st_virgin:
3099 if (TID_INDICATING_NONVIRGIN == sword->other)
3100 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3101 else
3102 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3103 statechange = True;
3104 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3105 tls->refcount++;
3106 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003107
sewardj18cd4a52002-11-13 22:37:41 +00003108 st_excl: {
3109 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3110
3111 if (tls == sw_tls) {
3112 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3113 goto done;
3114 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3115 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3116 goto done;
3117 } else if (tlsIsDisjoint(tls, sw_tls)) {
3118 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3119 sword->other = packTLS(tls);
3120 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003121 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003122 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003123 } else {
3124 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3125 statechange = True;
3126 sw_tls->refcount--;
3127 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3128 if(DEBUG_MEM_LOCKSET_CHANGES)
3129 print_LockSet("excl write locks", unpackLockSet(sword->other));
3130 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003131 }
sewardj18cd4a52002-11-13 22:37:41 +00003132 }
njn25e49d8e72002-09-23 09:36:25 +00003133
sewardj18cd4a52002-11-13 22:37:41 +00003134 st_shar:
3135 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3136 sword->state = Vge_SharMod;
3137 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3138 thread_locks[tid]));
3139 statechange = True;
3140 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003141
sewardj18cd4a52002-11-13 22:37:41 +00003142 st_sharmod:
3143 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3144 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3145 thread_locks[tid]));
3146 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003147
sewardj18cd4a52002-11-13 22:37:41 +00003148 SHARED_MODIFIED:
3149 if (isempty(unpackLockSet(sword->other))) {
njnfbdcba92005-05-09 01:23:49 +00003150 record_race_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003151 }
3152 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003153
sewardj18cd4a52002-11-13 22:37:41 +00003154 done:
3155 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003156 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003157
sewardj18cd4a52002-11-13 22:37:41 +00003158 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003159 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003160 else
njnd01fef72005-03-25 23:35:48 +00003161 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003162 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003163 }
3164}
3165
njnfbdcba92005-05-09 01:23:49 +00003166static void hg_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003167{
sewardj8fac99a2002-11-13 22:31:26 +00003168 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003169
njn13bfd852005-06-02 03:52:53 +00003170 end = VG_ROUNDUP(a+size, 4);
3171 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003172
sewardj18cd4a52002-11-13 22:37:41 +00003173 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003174 hg_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003175}
3176
3177#undef DEBUG_STATE
3178
njnaf839f52005-06-23 03:27:57 +00003179VG_REGPARM(1) static void hg_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003180{
njnfbdcba92005-05-09 01:23:49 +00003181 hg_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003182}
3183
njnaf839f52005-06-23 03:27:57 +00003184VG_REGPARM(1) static void hg_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003185{
njnfbdcba92005-05-09 01:23:49 +00003186 hg_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003187}
3188
njnaf839f52005-06-23 03:27:57 +00003189VG_REGPARM(1) static void hg_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003190{
njnfbdcba92005-05-09 01:23:49 +00003191 hg_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003192}
3193
njnaf839f52005-06-23 03:27:57 +00003194VG_REGPARM(2) static void hg_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003195{
njnfbdcba92005-05-09 01:23:49 +00003196 hg_mem_read(a, size, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003197}
3198
njnaf839f52005-06-23 03:27:57 +00003199VG_REGPARM(2) static void hg_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003200{
3201 if (*(UChar *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003202 hg_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003203}
njnaf839f52005-06-23 03:27:57 +00003204VG_REGPARM(2) static void hg_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003205{
3206 if (*(UShort *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003207 hg_mem_write(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003208}
njnaf839f52005-06-23 03:27:57 +00003209VG_REGPARM(2) static void hg_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003210{
3211 if (*(UInt *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003212 hg_mem_write(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003213}
njnaf839f52005-06-23 03:27:57 +00003214VG_REGPARM(2) static void hg_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003215{
njnfbdcba92005-05-09 01:23:49 +00003216 hg_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003217}
njn25e49d8e72002-09-23 09:36:25 +00003218
sewardjc4a810d2002-11-13 22:25:51 +00003219static void hg_thread_create(ThreadId parent, ThreadId child)
3220{
3221 if (0)
3222 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3223
3224 newTLS(child);
3225 addPriorTLS(child, parent);
3226
3227 newTLS(parent);
3228}
3229
3230static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3231{
3232 if (0)
3233 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3234
3235 newTLS(joiner);
3236 addPriorTLS(joiner, joinee);
3237
3238 clearTLS(joinee);
3239}
3240
sewardj7a5ebcf2002-11-13 22:42:13 +00003241static Int __BUS_HARDWARE_LOCK__;
3242
3243static void bus_lock(void)
3244{
njn95e65f62005-03-30 04:13:56 +00003245 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003246 hg_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3247 hg_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003248}
3249
3250static void bus_unlock(void)
3251{
njn95e65f62005-03-30 04:13:56 +00003252 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003253 hg_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003254}
3255
njn25e49d8e72002-09-23 09:36:25 +00003256/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003257/*--- Client requests ---*/
3258/*--------------------------------------------------------------------*/
3259
njn51d827b2005-05-09 01:02:08 +00003260static Bool hg_handle_client_request(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003261{
njnfc26ff92004-11-22 19:12:49 +00003262 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003263 return False;
3264
3265 switch(args[0]) {
3266 case VG_USERREQ__HG_CLEAN_MEMORY:
3267 set_address_range_state(args[1], args[2], Vge_VirginInit);
3268 *ret = 0; /* meaningless */
3269 break;
3270
3271 case VG_USERREQ__HG_KNOWN_RACE:
3272 set_address_range_state(args[1], args[2], Vge_Error);
3273 *ret = 0; /* meaningless */
3274 break;
3275
3276 default:
3277 return False;
3278 }
3279
3280 return True;
3281}
3282
3283
3284/*--------------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00003285/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00003286/*--------------------------------------------------------------------*/
3287
njn51d827b2005-05-09 01:02:08 +00003288static Bool hg_process_cmd_line_option(Char* arg)
3289{
3290 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3291 clo_execontext = EC_None;
3292 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3293 clo_execontext = EC_Some;
3294 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3295 clo_execontext = EC_All;
3296
3297 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
3298
3299 else
3300 return VG_(replacement_malloc_process_cmd_line_option)(arg);
3301
3302 return True;
3303}
3304
3305static void hg_print_usage(void)
3306{
3307 VG_(printf)(
3308" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3309" --show-last-access=no|some|all\n"
3310" show location of last word access on error [no]\n"
3311 );
3312 VG_(replacement_malloc_print_usage)();
3313}
3314
3315static void hg_print_debug_usage(void)
3316{
3317 VG_(replacement_malloc_print_debug_usage)();
3318}
3319
3320static void hg_post_clo_init(void)
3321{
3322 void (*stack_tracker)(Addr a, SizeT len);
3323
3324 if (clo_execontext) {
3325 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3326 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3327 }
3328
3329 if (clo_priv_stacks)
njnfbdcba92005-05-09 01:23:49 +00003330 stack_tracker = & hg_new_mem_stack_private;
njn51d827b2005-05-09 01:02:08 +00003331 else
njnfbdcba92005-05-09 01:23:49 +00003332 stack_tracker = & hg_new_mem_stack;
njn51d827b2005-05-09 01:02:08 +00003333
3334 VG_(track_new_mem_stack) (stack_tracker);
3335 VG_(track_new_mem_stack_signal) (stack_tracker);
3336}
3337
3338
3339static void hg_fini(Int exitcode)
3340{
3341 if (DEBUG_LOCK_TABLE) {
3342 pp_all_LockSets();
3343 pp_all_mutexes();
3344 }
3345
3346 if (LOCKSET_SANITY)
3347 sanity_check_locksets("hg_fini");
3348
3349 if (VG_(clo_verbosity) > 0)
3350 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
njnfbdcba92005-05-09 01:23:49 +00003351 n_hg_warnings, n_lockorder_warnings);
njn51d827b2005-05-09 01:02:08 +00003352
3353 if (0)
3354 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3355 stk_ld, stk_st, stk_ld + stk_st,
3356 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3357 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
3358}
3359
3360static void hg_pre_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00003361{
3362 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003363 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003364
njn810086f2002-11-14 12:42:47 +00003365 VG_(details_name) ("Helgrind");
3366 VG_(details_version) (NULL);
3367 VG_(details_description) ("a data race detector");
3368 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +00003369 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003370 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003371 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003372
njn51d827b2005-05-09 01:02:08 +00003373 VG_(basic_tool_funcs) (hg_post_clo_init,
3374 hg_instrument,
3375 hg_fini);
tomc756a8e2005-03-31 07:59:35 +00003376
3377 VG_(needs_core_errors) ();
njn51d827b2005-05-09 01:02:08 +00003378 VG_(needs_tool_errors) (hg_eq_Error,
3379 hg_pp_Error,
3380 hg_update_extra,
3381 hg_recognised_suppression,
3382 hg_read_extra_suppression_info,
3383 hg_error_matches_suppression,
3384 hg_get_error_name,
3385 hg_print_extra_suppression_info);
tomc756a8e2005-03-31 07:59:35 +00003386 VG_(needs_data_syms) ();
njn51d827b2005-05-09 01:02:08 +00003387 VG_(needs_client_requests) (hg_handle_client_request);
3388 VG_(needs_sanity_checks) (hg_cheap_sanity_check,
3389 hg_expensive_sanity_check);
3390 VG_(needs_command_line_options)(hg_process_cmd_line_option,
3391 hg_print_usage,
3392 hg_print_debug_usage);
tomc756a8e2005-03-31 07:59:35 +00003393 VG_(needs_shadow_memory) ();
3394
njnfc51f8d2005-06-21 03:20:17 +00003395 VG_(needs_malloc_replacement) (hg_malloc,
njn51d827b2005-05-09 01:02:08 +00003396 hg___builtin_new,
3397 hg___builtin_vec_new,
3398 hg_memalign,
3399 hg_calloc,
3400 hg_free,
3401 hg___builtin_delete,
3402 hg___builtin_vec_delete,
3403 hg_realloc,
tomc756a8e2005-03-31 07:59:35 +00003404 8 );
njn25e49d8e72002-09-23 09:36:25 +00003405
njnfbdcba92005-05-09 01:23:49 +00003406 VG_(track_new_mem_startup) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003407
njn51d827b2005-05-09 01:02:08 +00003408 /* stack ones not decided until hg_post_clo_init() */
njn25e49d8e72002-09-23 09:36:25 +00003409
njn51d827b2005-05-09 01:02:08 +00003410 VG_(track_new_mem_brk) (& make_writable);
njnfbdcba92005-05-09 01:23:49 +00003411 VG_(track_new_mem_mmap) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003412
njnfbdcba92005-05-09 01:23:49 +00003413 VG_(track_change_mem_mprotect) (& hg_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003414
njn51d827b2005-05-09 01:02:08 +00003415 VG_(track_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003416
njn51d827b2005-05-09 01:02:08 +00003417 VG_(track_die_mem_stack) (NULL);
3418 VG_(track_die_mem_stack_signal)(NULL);
3419 VG_(track_die_mem_brk) (NULL);
3420 VG_(track_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003421
njnfbdcba92005-05-09 01:23:49 +00003422 VG_(track_pre_mem_read) (& hg_pre_mem_read);
3423 VG_(track_pre_mem_read_asciiz) (& hg_pre_mem_read_asciiz);
3424 VG_(track_pre_mem_write) (& hg_pre_mem_write);
njn51d827b2005-05-09 01:02:08 +00003425 VG_(track_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003426
njn51d827b2005-05-09 01:02:08 +00003427 VG_(track_post_thread_create) (& hg_thread_create);
3428 VG_(track_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003429
njnfbdcba92005-05-09 01:23:49 +00003430 VG_(track_pre_mutex_lock) (& hg_pre_mutex_lock);
3431 VG_(track_post_mutex_lock) (& hg_post_mutex_lock);
3432 VG_(track_post_mutex_unlock) (& hg_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003433
njn14d01ce2004-11-26 11:30:14 +00003434 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003435 lockset_hash[i] = NULL;
3436
3437 empty = alloc_LockSet(0);
3438 insert_LockSet(empty);
3439 emptyset = empty;
3440
sewardjc4a810d2002-11-13 22:25:51 +00003441 /* Init lock table and thread segments */
3442 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003443 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003444
sewardjc4a810d2002-11-13 22:25:51 +00003445 newTLS(i);
3446 }
3447
njn25e49d8e72002-09-23 09:36:25 +00003448 init_shadow_memory();
njn3e884182003-04-15 13:03:23 +00003449 hg_malloc_list = VG_(HT_construct)();
njn25e49d8e72002-09-23 09:36:25 +00003450}
3451
fitzhardinge98abfc72003-12-16 02:05:15 +00003452/* Uses a 1:1 mapping */
njn51d827b2005-05-09 01:02:08 +00003453VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init, 1.0)
fitzhardinge98abfc72003-12-16 02:05:15 +00003454
njn25e49d8e72002-09-23 09:36:25 +00003455/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003456/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003457/*--------------------------------------------------------------------*/