blob: 9263714e7a810d1a39452c1e05585e1c11913683 [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
njn8cdd1852005-08-30 19:47:32 +000032// For anyone wanting to understand race conditions better, this paper might
33// be instructive:
34//
35// S. Carr, J. Mayo and C.-K. Shene. Race Conditions: A Case Study, The
36// Journal of Computing in Small Colleges 17(1), September 2001.
37// http://www.cs.mtu.edu/~carr/papers/jcsc02.pdf
38//
39// It nicely describes several example race conditions, emphasising the
40// fundamentals in each case.
41
njnc7561b92005-06-19 01:24:32 +000042#include "pub_tool_basics.h"
43#include "pub_tool_threadstate.h"
njn4802b382005-06-11 04:58:29 +000044#include "pub_tool_aspacemgr.h"
njnea27e462005-05-31 02:38:09 +000045#include "pub_tool_debuginfo.h"
njn81c00df2005-05-14 21:28:43 +000046#include "pub_tool_hashtable.h"
njn97405b22005-06-02 03:39:33 +000047#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000048#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000049#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000050#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000051#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000052#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000053#include "pub_tool_options.h"
njn31513b42005-06-01 03:09:59 +000054#include "pub_tool_profile.h"
njn717cde52005-05-10 02:47:21 +000055#include "pub_tool_replacemalloc.h"
njn43b9a8a2005-05-10 04:37:01 +000056#include "pub_tool_tooliface.h"
njn717cde52005-05-10 02:47:21 +000057
sewardj7f3ad222002-11-13 22:11:53 +000058#include "helgrind.h"
njn25e49d8e72002-09-23 09:36:25 +000059
njnfbdcba92005-05-09 01:23:49 +000060static UInt n_hg_warnings = 0;
sewardjff2c9232002-11-13 21:44:39 +000061static UInt n_lockorder_warnings = 0;
njn25e49d8e72002-09-23 09:36:25 +000062
63/*------------------------------------------------------------*/
64/*--- Debug guff ---*/
65/*------------------------------------------------------------*/
66
sewardje11d6c82002-12-15 02:00:41 +000067#define DEBUG_LOCK_TABLE 0 /* Print lock table at end */
njn25e49d8e72002-09-23 09:36:25 +000068
69#define DEBUG_MAKE_ACCESSES 0 /* Print make_access() calls */
70#define DEBUG_LOCKS 0 /* Print lock()/unlock() calls and locksets */
71#define DEBUG_NEW_LOCKSETS 0 /* Print new locksets when created */
72#define DEBUG_ACCESSES 0 /* Print reads, writes */
73#define DEBUG_MEM_LOCKSET_CHANGES 0
74 /* Print when an address's lockset
75 changes; only useful with
76 DEBUG_ACCESSES */
sewardj8fac99a2002-11-13 22:31:26 +000077#define SLOW_ASSERTS 0 /* do expensive asserts */
njn25e49d8e72002-09-23 09:36:25 +000078#define DEBUG_VIRGIN_READS 0 /* Dump around address on VIRGIN reads */
79
sewardj8fac99a2002-11-13 22:31:26 +000080#if SLOW_ASSERTS
njn94065fd2004-11-22 19:26:27 +000081#define TL_ASSERT(x) tl_assert(x)
sewardj8fac99a2002-11-13 22:31:26 +000082#else
njn94065fd2004-11-22 19:26:27 +000083#define TL_ASSERT(x)
sewardj8fac99a2002-11-13 22:31:26 +000084#endif
85
njn25e49d8e72002-09-23 09:36:25 +000086/* heavyweight LockSet sanity checking:
87 0 == never
88 1 == after important ops
89 2 == As 1 and also after pthread_mutex_* ops (excessively slow)
90 */
91#define LOCKSET_SANITY 0
92
sewardj8fac99a2002-11-13 22:31:26 +000093/* Rotate an unsigned quantity left */
94#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x)*8)-(n))))
95
njn25e49d8e72002-09-23 09:36:25 +000096/*------------------------------------------------------------*/
sewardjf6374322002-11-13 22:35:55 +000097/*--- Command line options ---*/
98/*------------------------------------------------------------*/
99
100static enum {
101 EC_None,
102 EC_Some,
103 EC_All
104} clo_execontext = EC_None;
105
sewardje1a39f42002-12-15 01:56:17 +0000106static Bool clo_priv_stacks = False;
sewardjf6374322002-11-13 22:35:55 +0000107
108/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000109/*--- Crude profiling machinery. ---*/
110/*------------------------------------------------------------*/
111
112// PPP: work out if I want this
113
114#define PROF_EVENT(x)
115#if 0
116#ifdef VG_PROFILE_MEMORY
117
118#define N_PROF_EVENTS 150
119
120static UInt event_ctr[N_PROF_EVENTS];
121
122void VGE_(done_prof_mem) ( void )
123{
124 Int i;
125 for (i = 0; i < N_PROF_EVENTS; i++) {
126 if ((i % 10) == 0)
127 VG_(printf)("\n");
128 if (event_ctr[i] > 0)
129 VG_(printf)( "prof mem event %2d: %d\n", i, event_ctr[i] );
130 }
131 VG_(printf)("\n");
132}
133
134#define PROF_EVENT(ev) \
njnca82cc02004-11-22 17:18:48 +0000135 do { tl_assert((ev) >= 0 && (ev) < N_PROF_EVENTS); \
njn25e49d8e72002-09-23 09:36:25 +0000136 event_ctr[ev]++; \
137 } while (False);
138
139#else
140
141//static void init_prof_mem ( void ) { }
142// void VG_(done_prof_mem) ( void ) { }
143
144#define PROF_EVENT(ev) /* */
145
146#endif /* VG_PROFILE_MEMORY */
147
148/* Event index. If just the name of the fn is given, this means the
149 number of calls to the fn. Otherwise it is the specified event.
150
151 [PPP: snip event numbers...]
152*/
153#endif /* 0 */
154
155
156/*------------------------------------------------------------*/
157/*--- Data defns. ---*/
158/*------------------------------------------------------------*/
159
njn3e884182003-04-15 13:03:23 +0000160typedef
161 struct _HG_Chunk {
162 struct _HG_Chunk* next;
163 Addr data; /* ptr to actual block */
nethercote928a5f72004-11-03 18:10:37 +0000164 SizeT size; /* size requested */
njn3e884182003-04-15 13:03:23 +0000165 ExeContext* where; /* where it was allocated */
166 ThreadId tid; /* allocating thread */
167 }
168 HG_Chunk;
169
njn25e49d8e72002-09-23 09:36:25 +0000170typedef enum
sewardj7f3ad222002-11-13 22:11:53 +0000171 { Vge_VirginInit, Vge_NonVirginInit, Vge_SegmentInit, Vge_Error }
njn25e49d8e72002-09-23 09:36:25 +0000172 VgeInitStatus;
173
sewardjc808ef52002-11-13 22:43:26 +0000174
njnc6168192004-11-29 13:54:10 +0000175// XXX: not 64-bit clean!
njn25e49d8e72002-09-23 09:36:25 +0000176/* Should add up to 32 to fit in one word */
177#define OTHER_BITS 30
178#define STATE_BITS 2
179
180#define ESEC_MAP_WORDS 16384 /* Words per secondary map */
181
182/* This is for indicating that a memory block has been initialised but not
183 * really directly by a particular thread... (eg. text/data initialised
184 * automatically at startup).
185 * Must be different to virgin_word.other */
186#define TID_INDICATING_NONVIRGIN 1
187
sewardjc4a810d2002-11-13 22:25:51 +0000188/* Magic packed TLS used for error suppression; if word state is Excl
189 and tid is this, then it means all access are OK without changing
190 state and without raising any more errors */
191#define TLSP_INDICATING_ALL ((1 << OTHER_BITS) - 1)
sewardj16748af2002-10-22 04:55:54 +0000192
njn25e49d8e72002-09-23 09:36:25 +0000193/* Number of entries must fit in STATE_BITS bits */
194typedef enum { Vge_Virgin, Vge_Excl, Vge_Shar, Vge_SharMod } pth_state;
195
sewardjc808ef52002-11-13 22:43:26 +0000196static inline const Char *pp_state(pth_state st)
197{
198 const Char *ret;
199
200 switch(st) {
201 case Vge_Virgin: ret = "virgin"; break;
202 case Vge_Excl: ret = "exclusive"; break;
203 case Vge_Shar: ret = "shared RO"; break;
204 case Vge_SharMod: ret = "shared RW"; break;
205 default: ret = "???";
206 }
207 return ret;
208}
209
njn25e49d8e72002-09-23 09:36:25 +0000210typedef
211 struct {
sewardj8fac99a2002-11-13 22:31:26 +0000212 /* gcc arranges this bitfield with state in the 2LSB and other
213 in the 30MSB, which is what we want */
njn25e49d8e72002-09-23 09:36:25 +0000214 UInt state:STATE_BITS;
sewardj8fac99a2002-11-13 22:31:26 +0000215 UInt other:OTHER_BITS;
njn25e49d8e72002-09-23 09:36:25 +0000216 } shadow_word;
217
sewardj8fac99a2002-11-13 22:31:26 +0000218#define SW(st, other) ((shadow_word) { st, other })
219
njn25e49d8e72002-09-23 09:36:25 +0000220typedef
221 struct {
222 shadow_word swords[ESEC_MAP_WORDS];
223 }
224 ESecMap;
225
226static ESecMap* primary_map[ 65536 ];
227static ESecMap distinguished_secondary_map;
228
sewardj8fac99a2002-11-13 22:31:26 +0000229static const shadow_word virgin_sword = SW(Vge_Virgin, 0);
230static const shadow_word error_sword = SW(Vge_Excl, TLSP_INDICATING_ALL);
njn25e49d8e72002-09-23 09:36:25 +0000231
232#define VGE_IS_DISTINGUISHED_SM(smap) \
233 ((smap) == &distinguished_secondary_map)
234
235#define ENSURE_MAPPABLE(addr,caller) \
236 do { \
237 if (VGE_IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
238 primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
239 /*VG_(printf)("new 2map because of %p\n", addr);*/ \
240 } \
241 } while(0)
242
243
sewardjc808ef52002-11-13 22:43:26 +0000244/* Parallel map which contains execution contexts when words last
245 changed state (if required) */
sewardj499e3de2002-11-13 22:22:25 +0000246
nethercoteca788ff2004-10-20 10:58:09 +0000247typedef struct EC_IP {
248 union u_ec_ip {
249 Addr ip;
sewardjc808ef52002-11-13 22:43:26 +0000250 ExeContext *ec;
nethercoteca788ff2004-10-20 10:58:09 +0000251 } uu_ec_ip;
sewardjc808ef52002-11-13 22:43:26 +0000252 UInt state:STATE_BITS;
253 UInt tls:OTHER_BITS; /* packed TLS */
nethercoteca788ff2004-10-20 10:58:09 +0000254} EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000255
nethercoteca788ff2004-10-20 10:58:09 +0000256#define NULL_EC_IP ((EC_IP){ { 0 }, 0, 0})
sewardjc808ef52002-11-13 22:43:26 +0000257
nethercoteca788ff2004-10-20 10:58:09 +0000258#define IP(ip, prev, tls) ((EC_IP) { (union u_ec_ip)(ip), (prev).state, packTLS(tls) })
259#define EC(ec, prev, tls) ((EC_IP) { (union u_ec_ip)(ec), (prev).state, packTLS(tls) })
sewardjc808ef52002-11-13 22:43:26 +0000260
261static inline UInt packEC(ExeContext *ec)
262{
njn94065fd2004-11-22 19:26:27 +0000263 TL_ASSERT(((UWord)ec & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000264 return ((UWord)ec) >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000265}
266
nethercoteca788ff2004-10-20 10:58:09 +0000267/* Lose 2 LSB of IP */
268static inline UInt packIP(Addr ip)
sewardjc808ef52002-11-13 22:43:26 +0000269{
nethercote50397c22004-11-04 18:03:06 +0000270 return ip >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000271}
272
nethercoteca788ff2004-10-20 10:58:09 +0000273static inline Addr unpackIP(UInt i)
sewardjc808ef52002-11-13 22:43:26 +0000274{
275 return (Addr)(i << STATE_BITS);
276}
sewardj499e3de2002-11-13 22:22:25 +0000277
278typedef struct {
nethercoteca788ff2004-10-20 10:58:09 +0000279 EC_IP execontext[ESEC_MAP_WORDS];
sewardj499e3de2002-11-13 22:22:25 +0000280} ExeContextMap;
281
282static ExeContextMap** execontext_map;
283
nethercoteca788ff2004-10-20 10:58:09 +0000284static inline void setExeContext(Addr a, EC_IP ec)
sewardj499e3de2002-11-13 22:22:25 +0000285{
286 UInt idx = (a >> 16) & 0xffff;
287 UInt off = (a >> 2) & 0x3fff;
288
289 if (execontext_map[idx] == NULL) {
290 execontext_map[idx] = VG_(malloc)(sizeof(ExeContextMap));
291 VG_(memset)(execontext_map[idx], 0, sizeof(ExeContextMap));
292 }
293
294 execontext_map[idx]->execontext[off] = ec;
295}
296
nethercoteca788ff2004-10-20 10:58:09 +0000297static inline EC_IP getExeContext(Addr a)
sewardj499e3de2002-11-13 22:22:25 +0000298{
299 UInt idx = (a >> 16) & 0xffff;
300 UInt off = (a >> 2) & 0x3fff;
nethercoteca788ff2004-10-20 10:58:09 +0000301 EC_IP ec = NULL_EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000302
303 if (execontext_map[idx] != NULL)
304 ec = execontext_map[idx]->execontext[off];
305
306 return ec;
307}
308
njn25e49d8e72002-09-23 09:36:25 +0000309/*------------------------------------------------------------*/
sewardjc4a810d2002-11-13 22:25:51 +0000310/*--- Thread lifetime segments ---*/
311/*------------------------------------------------------------*/
312
313/*
314 * This mechanism deals with the common case of a parent thread
315 * creating a structure for a child thread, and then passing ownership
316 * of the structure to that thread. It similarly copes with a child
317 * thread passing information back to another thread waiting to join
318 * on it.
319 *
320 * Each thread's lifetime can be partitioned into segments. Those
321 * segments are arranged to form an interference graph which indicates
322 * whether two thread lifetime segments can possibly be concurrent.
323 * If not, then memory with is exclusively accessed by one TLS can be
daywalker7e73e5f2003-07-04 16:18:15 +0000324 * passed on to another TLS without an error occurring, and without
sewardjc4a810d2002-11-13 22:25:51 +0000325 * moving it from Excl state.
326 *
327 * At present this only considers thread creation and join as
328 * synchronisation events for creating new lifetime segments, but
329 * others may be possible (like mutex operations).
330 */
331
332typedef struct _ThreadLifeSeg ThreadLifeSeg;
333
334struct _ThreadLifeSeg {
335 ThreadId tid;
336 ThreadLifeSeg *prior[2]; /* Previous lifetime segments */
337 UInt refcount; /* Number of memory locations pointing here */
338 UInt mark; /* mark used for graph traversal */
339 ThreadLifeSeg *next; /* list of all TLS */
340};
341
342static ThreadLifeSeg *all_tls;
343static UInt tls_since_gc;
344#define TLS_SINCE_GC 10000
345
346/* current mark used for TLS graph traversal */
347static UInt tlsmark;
348
349static ThreadLifeSeg *thread_seg[VG_N_THREADS];
350
351
352static void tls_gc(void)
353{
354 /* XXX later. Walk through all TLSs and look for ones with 0
355 refcount and remove them from the structure and free them.
356 Could probably get rid of ThreadLifeSeg.refcount and simply use
357 mark-sweep from the shadow table. */
358 VG_(printf)("WRITEME: TLS GC\n");
359}
360
361static void newTLS(ThreadId tid)
362{
363 static const Bool debug = False;
364 ThreadLifeSeg *tls;
365
366 /* Initial NULL */
367 if (thread_seg[tid] == NULL) {
368 tls = VG_(malloc)(sizeof(*tls));
369 tls->tid = tid;
370 tls->prior[0] = tls->prior[1] = NULL;
371 tls->refcount = 0;
372 tls->mark = tlsmark-1;
373
374 tls->next = all_tls;
375 all_tls = tls;
376 tls_since_gc++;
377
378 thread_seg[tid] = tls;
379 return;
380 }
381
382 /* Previous TLS was unused, so just recycle */
383 if (thread_seg[tid]->refcount == 0) {
384 if (debug)
385 VG_(printf)("newTLS; recycling TLS %p for tid %u\n",
386 thread_seg[tid], tid);
387 return;
388 }
389
390 /* Use existing TLS for this tid as a prior for new TLS */
391 tls = VG_(malloc)(sizeof(*tls));
392 tls->tid = tid;
393 tls->prior[0] = thread_seg[tid];
394 tls->prior[1] = NULL;
395 tls->refcount = 0;
396 tls->mark = tlsmark-1;
397
398 tls->next = all_tls;
399 all_tls = tls;
400 if (++tls_since_gc > TLS_SINCE_GC) {
401 tls_gc();
402 tls_since_gc = 0;
403 }
404
405 if (debug)
406 VG_(printf)("newTLS: made new TLS %p for tid %u (prior %p(%u))\n",
407 tls, tid, tls->prior[0], tls->prior[0]->tid);
408
409 thread_seg[tid] = tls;
410}
411
412/* clear out a TLS for a thread that's died */
413static void clearTLS(ThreadId tid)
414{
415 newTLS(tid);
416
417 thread_seg[tid]->prior[0] = NULL;
418 thread_seg[tid]->prior[1] = NULL;
419}
420
421static void addPriorTLS(ThreadId tid, ThreadId prior)
422{
423 static const Bool debug = False;
424 ThreadLifeSeg *tls = thread_seg[tid];
425
426 if (debug)
427 VG_(printf)("making TLS %p(%u) prior to TLS %p(%u)\n",
428 thread_seg[prior], prior, tls, tid);
429
njnca82cc02004-11-22 17:18:48 +0000430 tl_assert(thread_seg[tid] != NULL);
431 tl_assert(thread_seg[prior] != NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000432
433 if (tls->prior[0] == NULL)
434 tls->prior[0] = thread_seg[prior];
435 else {
njnca82cc02004-11-22 17:18:48 +0000436 tl_assert(tls->prior[1] == NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000437 tls->prior[1] = thread_seg[prior];
438 }
439}
440
njnfbdcba92005-05-09 01:23:49 +0000441static Bool isPrior(const ThreadLifeSeg *t, const ThreadLifeSeg *prior)
442{
443 if (t == NULL || t->mark == tlsmark)
444 return False;
445
446 if (t == prior)
447 return True;
448
449 ((ThreadLifeSeg *)t)->mark = tlsmark;
450
451 return isPrior(t->prior[0], prior) || isPrior(t->prior[1], prior);
452}
453
sewardjc4a810d2002-11-13 22:25:51 +0000454/* Return True if prior is definitely not concurrent with tls */
455static Bool tlsIsDisjoint(const ThreadLifeSeg *tls,
456 const ThreadLifeSeg *prior)
457{
sewardjc4a810d2002-11-13 22:25:51 +0000458 tlsmark++; /* new traversal mark */
459
njnfbdcba92005-05-09 01:23:49 +0000460 return isPrior(tls, prior);
sewardjc4a810d2002-11-13 22:25:51 +0000461}
462
463static inline UInt packTLS(ThreadLifeSeg *tls)
464{
njn94065fd2004-11-22 19:26:27 +0000465 TL_ASSERT(((UWord)tls & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000466 return ((UWord)tls) >> STATE_BITS;
sewardjc4a810d2002-11-13 22:25:51 +0000467}
468
469static inline ThreadLifeSeg *unpackTLS(UInt i)
470{
sewardj29ef1c82005-06-11 10:33:35 +0000471 /* HACK ALERT -- DUBIOUS CAST */
472 return (ThreadLifeSeg *)ULong_to_Ptr(i << STATE_BITS);
sewardjc4a810d2002-11-13 22:25:51 +0000473}
474
475/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000476/*--- Low-level support for memory tracking. ---*/
477/*------------------------------------------------------------*/
478
479/*
480 All reads and writes are recorded in the memory map, which
481 records the state of all memory in the process. The memory map is
482 organised like that for normal Valgrind, except each that everything
483 is done at word-level instead of byte-level, and each word has only
484 one word of shadow (instead of 36 bits).
485
486 As for normal Valgrind there is a distinguished secondary map. But we're
487 working at word-granularity, so it has 16k word entries instead of 64k byte
488 entries. Lookup is done as follows:
489
490 bits 31..16: primary map lookup
491 bits 15.. 2: secondary map lookup
492 bits 1.. 0: ignored
493*/
494
495
496/*------------------------------------------------------------*/
497/*--- Basic bitmap management, reading and writing. ---*/
498/*------------------------------------------------------------*/
499
500/* Allocate and initialise a secondary map, marking all words as virgin. */
501
502/* Just a value that isn't a real pointer */
503#define SEC_MAP_ACCESS (shadow_word*)0x99
504
505
506static
507ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
508{
509 ESecMap* map;
510 UInt i;
511 //PROF_EVENT(10); PPP
512
nethercote1420ab22004-08-18 22:26:01 +0000513 // Mark all words as virgin.
sewardj45f4e7c2005-09-27 19:20:21 +0000514 map = (ESecMap *)VG_(am_shadow_alloc)(sizeof(ESecMap));
515 if (map == NULL)
516 VG_(out_of_memory_NORETURN)( "helgrind:allocate new ESecMap",
517 sizeof(ESecMap) );
njn25e49d8e72002-09-23 09:36:25 +0000518 for (i = 0; i < ESEC_MAP_WORDS; i++)
519 map->swords[i] = virgin_sword;
520
521 return map;
522}
523
524
525/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
526 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000527static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000528void set_sword ( Addr a, shadow_word sword )
529{
530 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000531 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000532
533 //PROF_EVENT(23); PPP
534 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
535
536 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
537 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000538 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000539 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
540 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
541 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
542 tls->refcount--;
543 }
544
545 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
546 ThreadLifeSeg *tls = unpackTLS(sword.other);
547 tls->refcount++;
548 }
549
njn25e49d8e72002-09-23 09:36:25 +0000550 sm->swords[(a & 0xFFFC) >> 2] = sword;
551
552 if (VGE_IS_DISTINGUISHED_SM(sm)) {
553 VG_(printf)("wrote to distinguished 2ndary map! 0x%x\n", a);
554 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000555 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000556 }
557}
558
559
560static __inline__
561shadow_word* get_sword_addr ( Addr a )
562{
563 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
564 ESecMap* sm = primary_map[a >> 16];
565 UInt sm_off = (a & 0xFFFC) >> 2;
566
567 if (VGE_IS_DISTINGUISHED_SM(sm)) {
568 VG_(printf)("accessed distinguished 2ndary map! 0x%x\n", a);
569 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000570 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000571 return SEC_MAP_ACCESS;
572 }
573
574 //PROF_EVENT(21); PPP
575 return & (sm->swords[sm_off]);
576}
577
578
579// SSS: rename these so they're not so similar to memcheck, unless it's
580// appropriate of course
581
582static __inline__
583void init_virgin_sword(Addr a)
584{
sewardj499e3de2002-11-13 22:22:25 +0000585 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000586 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000587 set_sword(a, virgin_sword);
588}
589
sewardj7f3ad222002-11-13 22:11:53 +0000590static __inline__
591void init_error_sword(Addr a)
592{
593 set_sword(a, error_sword);
594}
njn25e49d8e72002-09-23 09:36:25 +0000595
njn25e49d8e72002-09-23 09:36:25 +0000596static __inline__
597void init_nonvirgin_sword(Addr a)
598{
599 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000600 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000601 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000602
njn14d01ce2004-11-26 11:30:14 +0000603 // The tid must be passed in here now; this requires more events to be
604 // given the tid in the first place.
605 //
606 //tid = VG_(get_current_or_recent_tid)();
607 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
608 VG_(exit)(1);
609
njnca82cc02004-11-22 17:18:48 +0000610 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000611 tls = thread_seg[tid];
612
sewardj8fac99a2002-11-13 22:31:26 +0000613 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000614 set_sword(a, sword);
615}
616
617
njnfbdcba92005-05-09 01:23:49 +0000618/* In this case, we treat it for Helgrind's sake like virgin (it hasn't
njn25e49d8e72002-09-23 09:36:25 +0000619 * been inited by a particular thread, it's just done automatically upon
620 * startup), but we mark its .state specially so it doesn't look like an
621 * uninited read. */
622static __inline__
623void init_magically_inited_sword(Addr a)
624{
625 shadow_word sword;
626
sewardj8fac99a2002-11-13 22:31:26 +0000627 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
628
njn25e49d8e72002-09-23 09:36:25 +0000629 set_sword(a, virgin_sword);
630}
631
sewardjc26cc252002-10-23 21:58:55 +0000632
sewardj274c6012002-10-22 04:54:55 +0000633/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000634/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000635/*------------------------------------------------------------*/
636
sewardj39a4d842002-11-13 22:14:30 +0000637typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000638typedef struct _LockSet LockSet;
639
sewardj16748af2002-10-22 04:55:54 +0000640typedef enum MutexState {
641 MxUnknown, /* don't know */
642 MxUnlocked, /* unlocked */
643 MxLocked, /* locked */
644 MxDead /* destroyed */
645} MutexState;
646
sewardj39a4d842002-11-13 22:14:30 +0000647struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000648 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000649 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000650
651 MutexState state; /* mutex state */
652 ThreadId tid; /* owner */
653 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000654
sewardj4bffb232002-11-13 21:46:34 +0000655 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000656 UInt mark; /* mark for graph traversal */
657};
sewardj16748af2002-10-22 04:55:54 +0000658
sewardj39a4d842002-11-13 22:14:30 +0000659static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000660{
sewardjdac0a442002-11-13 22:08:40 +0000661 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000662}
njn25e49d8e72002-09-23 09:36:25 +0000663
sewardj274c6012002-10-22 04:54:55 +0000664struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000665 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000666 UInt hash; /* hash code */
667 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000668 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000669};
sewardj4bffb232002-11-13 21:46:34 +0000670
671static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000672
673/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000674static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000675
sewardjdac0a442002-11-13 22:08:40 +0000676#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000677
sewardj4bffb232002-11-13 21:46:34 +0000678static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000679
sewardj4bffb232002-11-13 21:46:34 +0000680/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000681static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000682{
sewardj4bffb232002-11-13 21:46:34 +0000683 UInt id;
684
njn94065fd2004-11-22 19:26:27 +0000685 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000686 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000687
688 return id;
njn25e49d8e72002-09-23 09:36:25 +0000689}
690
sewardj8fac99a2002-11-13 22:31:26 +0000691static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000692{
sewardj29ef1c82005-06-11 10:33:35 +0000693 /* HACK ALERT -- DUBIOUS CAST */
694 return (LockSet *)ULong_to_Ptr(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000695}
696
njn25e49d8e72002-09-23 09:36:25 +0000697static
sewardj4bffb232002-11-13 21:46:34 +0000698void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000699{
sewardj05bcdcb2003-05-18 10:05:38 +0000700 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000701 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000702 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000703 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000704
705 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000706 }
707 VG_(printf)("}\n");
708}
709
710
sewardj4bffb232002-11-13 21:46:34 +0000711static void print_LockSet(const Char *s, const LockSet *ls)
712{
713 VG_(printf)("%s: ", s);
714 pp_LockSet(ls);
715}
716
717/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000718static UInt hash_LockSet_w_wo(const LockSet *ls,
719 const Mutex *with,
720 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000721{
sewardj05bcdcb2003-05-18 10:05:38 +0000722 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000723 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000724
njnca82cc02004-11-22 17:18:48 +0000725 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000726
727 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000728 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000729
730 if (without && mutex_cmp(without, mx) == 0)
731 continue;
732
733 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
734 mx = with;
735 with = NULL;
736 i--;
737 }
738
sewardj8fac99a2002-11-13 22:31:26 +0000739 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000740 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000741 }
742
743 return hash % LOCKSET_HASH_SZ;
744}
745
sewardj39a4d842002-11-13 22:14:30 +0000746static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000747{
748 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
749
750 if (0)
751 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
752
753 return hash;
754}
755
sewardj39a4d842002-11-13 22:14:30 +0000756static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000757{
758 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
759
760 if (0)
761 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
762
763 return hash;
764}
765
766static inline UInt hash_LockSet(const LockSet *ls)
767{
768 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
769
770 if (0)
771 VG_(printf)("hash %p -> %d\n", ls, hash);
772
773 return hash;
774}
775
776static
777Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000778{
779 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000780
sewardj4bffb232002-11-13 21:46:34 +0000781 if (a == b)
782 return True;
783 if (a->setsize != b->setsize)
784 return False;
njn25e49d8e72002-09-23 09:36:25 +0000785
sewardj4bffb232002-11-13 21:46:34 +0000786 for(i = 0; i < a->setsize; i++) {
787 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000788 return False;
njn25e49d8e72002-09-23 09:36:25 +0000789 }
790
sewardj4bffb232002-11-13 21:46:34 +0000791 return True;
njn25e49d8e72002-09-23 09:36:25 +0000792}
793
794
795/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
796 * doesn't do the insertion. Returns True if they match.
797 */
798static Bool
sewardj4bffb232002-11-13 21:46:34 +0000799weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000800 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000801{
sewardjc26cc252002-10-23 21:58:55 +0000802 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000803 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000804
njn25e49d8e72002-09-23 09:36:25 +0000805 /* Idea is to try and match each element of b against either an
806 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000807
808 if (debug) {
809 print_LockSet("weird_LockSet_equals a", a);
810 print_LockSet(" b", b);
811 VG_(printf)( " missing: %p%(y\n",
812 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000813 }
sewardjc26cc252002-10-23 21:58:55 +0000814
sewardj4bffb232002-11-13 21:46:34 +0000815 if ((a->setsize + 1) != b->setsize) {
816 if (debug)
817 VG_(printf)(" fastpath length mismatch -> 0\n");
818 return False;
819 }
820
sewardjc26cc252002-10-23 21:58:55 +0000821 /* There are three phases to this compare:
822 1 the section from the start of a up to missing_mutex
823 2 missing mutex itself
824 3 the section after missing_mutex to the end of a
825 */
826
sewardj4bffb232002-11-13 21:46:34 +0000827 ia = 0;
828 ib = 0;
829
sewardjc26cc252002-10-23 21:58:55 +0000830 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000831 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000832 if (debug) {
833 print_LockSet(" 1:a", a);
834 print_LockSet(" 1:b", b);
835 }
sewardj4bffb232002-11-13 21:46:34 +0000836 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000837 return False;
sewardjc26cc252002-10-23 21:58:55 +0000838 }
839
840 /* 2: missing_mutex itself */
841 if (debug) {
842 VG_(printf)( " 2:missing: %p%(y\n",
843 missing_mutex->mutexp, missing_mutex->mutexp);
844 print_LockSet(" 2: b", b);
845 }
846
njnca82cc02004-11-22 17:18:48 +0000847 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000848
sewardj4bffb232002-11-13 21:46:34 +0000849 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000850 return False;
851
sewardj4bffb232002-11-13 21:46:34 +0000852 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000853
854 /* 3: after missing_mutex to end */
855
sewardj4bffb232002-11-13 21:46:34 +0000856 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000857 if (debug) {
858 print_LockSet(" 3:a", a);
859 print_LockSet(" 3:b", b);
860 }
sewardj4bffb232002-11-13 21:46:34 +0000861 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000862 return False;
sewardjc26cc252002-10-23 21:58:55 +0000863 }
864
865 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000866 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000867
sewardj4bffb232002-11-13 21:46:34 +0000868 return ia == a->setsize && ib == b->setsize;
869}
870
871
872
873static const LockSet *lookup_LockSet(const LockSet *set)
874{
875 UInt bucket = set->hash;
876 LockSet *ret;
877
878 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
879 if (set == ret || structural_eq_LockSet(set, ret))
880 return ret;
881
882 return NULL;
883}
884
sewardj39a4d842002-11-13 22:14:30 +0000885static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000886{
887 UInt bucket = hash_LockSet_with(set, mutex);
888 const LockSet *ret;
889
890 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
891 if (weird_LockSet_equals(set, ret, mutex))
892 return ret;
893
894 return NULL;
895}
896
sewardj39a4d842002-11-13 22:14:30 +0000897static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000898{
899 UInt bucket = hash_LockSet_without(set, mutex);
900 const LockSet *ret;
901
902 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
903 if (weird_LockSet_equals(ret, set, mutex))
904 return ret;
905
906 return NULL;
907}
908
909static void insert_LockSet(LockSet *set)
910{
911 UInt hash = hash_LockSet(set);
912
913 set->hash = hash;
914
njnca82cc02004-11-22 17:18:48 +0000915 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000916
917 set->next = lockset_hash[hash];
918 lockset_hash[hash] = set;
919}
920
921static inline
922LockSet *alloc_LockSet(UInt setsize)
923{
sewardj39a4d842002-11-13 22:14:30 +0000924 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000925 ret->setsize = setsize;
926 return ret;
927}
928
929static inline
930void free_LockSet(LockSet *p)
931{
932 /* assert: not present in hash */
933 VG_(free)(p);
934}
935
njnb4aee052003-04-15 14:09:58 +0000936static
sewardj4bffb232002-11-13 21:46:34 +0000937void pp_all_LockSets ( void )
938{
939 Int i;
940 Int sets, buckets;
941
942 sets = buckets = 0;
943 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
944 const LockSet *ls = lockset_hash[i];
945 Bool first = True;
946
sewardj4bffb232002-11-13 21:46:34 +0000947 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000948 if (first) {
949 buckets++;
950 VG_(printf)("[%4d] = ", i);
951 } else
952 VG_(printf)(" ");
953
sewardj4bffb232002-11-13 21:46:34 +0000954 sets++;
955 first = False;
956 pp_LockSet(ls);
957 }
958 }
959
960 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
961}
962
963static inline Bool isempty(const LockSet *ls)
964{
965 return ls == NULL || ls->setsize == 0;
966}
967
sewardj39a4d842002-11-13 22:14:30 +0000968static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000969{
970 Int i;
971
972 /* XXX use binary search */
973 for(i = 0; i < ls->setsize; i++)
974 if (mutex_cmp(mx, ls->mutex[i]) == 0)
975 return True;
976
977 return False;
978}
979
980/* Check invariants:
981 - all locksets are unique
982 - each set is an array in strictly increasing order of mutex addr
983*/
984static
985void sanity_check_locksets ( const Char* caller )
986{
987 Int i;
988 const Char *badness;
989 LockSet *ls;
990
991 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
992
993 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000994 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000995 Int j;
996
997 if (hash_LockSet(ls) != ls->hash) {
998 badness = "mismatched hash";
999 goto bad;
1000 }
sewardj05bcdcb2003-05-18 10:05:38 +00001001 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +00001002 badness = "wrong bucket";
1003 goto bad;
1004 }
1005 if (lookup_LockSet(ls) != ls) {
1006 badness = "non-unique set";
1007 goto bad;
1008 }
1009
1010 prev = ls->mutex[0];
1011 for(j = 1; j < ls->setsize; j++) {
1012 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
1013 badness = "mutexes out of order";
1014 goto bad;
1015 }
1016 }
1017 }
1018 }
1019 return;
1020
1021 bad:
1022 VG_(printf)("sanity_check_locksets: "
1023 "i = %d, ls=%p badness = %s, caller = %s\n",
1024 i, ls, badness, caller);
1025 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001026 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001027}
1028
1029static
sewardj39a4d842002-11-13 22:14:30 +00001030LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001031{
1032 static const Bool debug = False;
1033 LockSet *ret = NULL;
1034 Int i, j;
1035
1036 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1037 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1038 print_LockSet("add-IN", ls);
1039 }
1040
1041 if (debug || LOCKSET_SANITY)
1042 sanity_check_locksets("add-IN");
1043
njnca82cc02004-11-22 17:18:48 +00001044 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001045
1046 ret = alloc_LockSet(ls->setsize+1);
1047
1048 for(i = j = 0; i < ls->setsize; i++) {
1049 if (debug)
1050 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1051 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1052 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1053 ret->mutex[j++] = mx;
1054 mx = NULL;
1055 }
1056 ret->mutex[j++] = ls->mutex[i];
1057 }
1058
1059 /* not added in loop - must be after */
1060 if (mx)
1061 ret->mutex[j++] = mx;
1062
njnca82cc02004-11-22 17:18:48 +00001063 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001064
1065 if (debug || LOCKSET_SANITY) {
1066 print_LockSet("add-OUT", ret);
1067 sanity_check_locksets("add-OUT");
1068 }
1069 return ret;
1070}
1071
1072/* Builds ls with mx removed. mx should actually be in ls!
1073 (a checked assertion). Resulting set should not already
1074 exist in the table (unchecked).
1075*/
1076static
sewardj39a4d842002-11-13 22:14:30 +00001077LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001078{
1079 static const Bool debug = False;
1080 LockSet *ret = NULL;
1081 Int i, j;
1082
1083 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1084 print_LockSet("remove-IN", ls);
1085 }
1086
1087 if (debug || LOCKSET_SANITY)
1088 sanity_check_locksets("remove-IN");
1089
njnca82cc02004-11-22 17:18:48 +00001090 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001091
1092 ret = alloc_LockSet(ls->setsize-1);
1093
1094 for(i = j = 0; i < ls->setsize; i++) {
1095 if (mutex_cmp(ls->mutex[i], mx) == 0)
1096 continue;
1097 ret->mutex[j++] = ls->mutex[i];
1098 }
1099
njnca82cc02004-11-22 17:18:48 +00001100 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001101
1102 if (debug || LOCKSET_SANITY) {
1103 print_LockSet("remove-OUT", ret);
1104 sanity_check_locksets("remove-OUT");
1105 }
1106 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001107}
1108
1109
1110/* Builds the intersection, and then unbuilds it if it's already in the table.
1111 */
sewardj4bffb232002-11-13 21:46:34 +00001112static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001113{
sewardj4bffb232002-11-13 21:46:34 +00001114 static const Bool debug = False;
1115 Int iret;
1116 Int ia, ib;
1117 Int size;
1118 LockSet *ret;
1119 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001120
sewardj4bffb232002-11-13 21:46:34 +00001121 if (debug || LOCKSET_SANITY)
1122 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001123
sewardj4bffb232002-11-13 21:46:34 +00001124 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1125 print_LockSet("intersect a", a);
1126 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001127 }
1128
sewardj4bffb232002-11-13 21:46:34 +00001129 /* count the size of the new set */
1130 size = 0;
1131 ia = ib = 0;
1132 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1133 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1134 size++;
1135 ia++;
1136 ib++;
1137 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1138 ia++;
1139 } else {
njnca82cc02004-11-22 17:18:48 +00001140 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001141 ib++;
1142 }
njn25e49d8e72002-09-23 09:36:25 +00001143 }
1144
sewardj4bffb232002-11-13 21:46:34 +00001145 /* Build the intersection of the two sets */
1146 ret = alloc_LockSet(size);
1147 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1148 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001149 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001150 ret->mutex[iret++] = a->mutex[ia];
1151 ia++;
1152 ib++;
1153 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1154 ia++;
1155 } else {
njnca82cc02004-11-22 17:18:48 +00001156 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001157 ib++;
1158 }
1159 }
1160
1161 ret->hash = hash_LockSet(ret);
1162
njn25e49d8e72002-09-23 09:36:25 +00001163 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001164 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001165
sewardj4bffb232002-11-13 21:46:34 +00001166 if (found != NULL) {
1167 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001168 } else {
sewardj4bffb232002-11-13 21:46:34 +00001169 insert_LockSet(ret);
1170 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001171 }
1172
sewardj4bffb232002-11-13 21:46:34 +00001173 if (debug || LOCKSET_SANITY) {
1174 print_LockSet("intersect-OUT", found);
1175 sanity_check_locksets("intersect-OUT");
1176 }
njn25e49d8e72002-09-23 09:36:25 +00001177
sewardj4bffb232002-11-13 21:46:34 +00001178 return found;
njn25e49d8e72002-09-23 09:36:25 +00001179}
1180
sewardj4bffb232002-11-13 21:46:34 +00001181/* inline the fastpath */
1182static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001183{
sewardj4bffb232002-11-13 21:46:34 +00001184 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001185
1186 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001187 if (a == b) {
1188 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1189 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001190 }
sewardj4bffb232002-11-13 21:46:34 +00001191 return a;
sewardjc26cc252002-10-23 21:58:55 +00001192 }
1193
sewardj4bffb232002-11-13 21:46:34 +00001194 if (isempty(a) || isempty(b)) {
1195 if (debug)
1196 VG_(printf)("intersect empty fastpath\n");
1197 return emptyset;
1198 }
1199
1200 return _intersect(a, b);
1201}
1202
1203
1204static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1205{
1206 static const Bool debug = False;
1207 Int iret;
1208 Int ia, ib;
1209 Int size;
1210 LockSet *ret;
1211 const LockSet *found;
1212
1213 if (debug || LOCKSET_SANITY)
1214 sanity_check_locksets("union-IN");
1215
1216 /* Fast case -- when the two are the same */
1217 if (a == b) {
1218 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1219 print_LockSet("union-same fastpath", a);
1220 }
1221 return a;
1222 }
1223
1224 if (isempty(a)) {
1225 if (debug)
1226 print_LockSet("union a=empty b", b);
1227 return b;
1228 }
1229 if (isempty(b)) {
1230 if (debug)
1231 print_LockSet("union b=empty a", a);
1232 return a;
1233 }
1234
1235 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001236 print_LockSet("union a", a);
1237 print_LockSet("union b", b);
1238 }
1239
sewardj4bffb232002-11-13 21:46:34 +00001240 /* count the size of the new set */
1241 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1242 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001243
sewardj4bffb232002-11-13 21:46:34 +00001244 if ((ia < a->setsize) && (ib < b->setsize))
1245 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1246 else if (ia == a->setsize)
1247 cmp = 1;
1248 else
1249 cmp = -1;
1250
1251 if (cmp == 0) {
1252 size++;
1253 ia++;
1254 ib++;
1255 } else if (cmp < 0) {
1256 size++;
1257 ia++;
1258 } else {
njnca82cc02004-11-22 17:18:48 +00001259 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001260 size++;
1261 ib++;
1262 }
sewardjc26cc252002-10-23 21:58:55 +00001263 }
1264
sewardj4bffb232002-11-13 21:46:34 +00001265 /* Build the intersection of the two sets */
1266 ret = alloc_LockSet(size);
1267 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1268 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001269 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001270
1271 if ((ia < a->setsize) && (ib < b->setsize))
1272 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1273 else if (ia == a->setsize)
1274 cmp = 1;
1275 else
1276 cmp = -1;
1277
1278 if (cmp == 0) {
1279 ret->mutex[iret++] = a->mutex[ia];
1280 ia++;
1281 ib++;
1282 } else if (cmp < 0) {
1283 ret->mutex[iret++] = a->mutex[ia];
1284 ia++;
1285 } else {
njnca82cc02004-11-22 17:18:48 +00001286 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001287 ret->mutex[iret++] = b->mutex[ib];
1288 ib++;
1289 }
1290 }
1291
njnca82cc02004-11-22 17:18:48 +00001292 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001293
1294 ret->hash = hash_LockSet(ret);
1295
sewardjc26cc252002-10-23 21:58:55 +00001296 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001297 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001298
sewardj4bffb232002-11-13 21:46:34 +00001299 if (found != NULL) {
1300 if (debug)
1301 print_LockSet("union found existing set", found);
1302 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001303 } else {
sewardj4bffb232002-11-13 21:46:34 +00001304 if (debug)
1305 print_LockSet("union inserting new set", ret);
1306 insert_LockSet(ret);
1307 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001308 }
1309
sewardj4bffb232002-11-13 21:46:34 +00001310 if (debug || LOCKSET_SANITY) {
1311 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001312 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001313 }
sewardjc26cc252002-10-23 21:58:55 +00001314
sewardj4bffb232002-11-13 21:46:34 +00001315 return found;
sewardjc26cc252002-10-23 21:58:55 +00001316}
1317
1318/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001319/*--- Implementation of mutex structure. ---*/
1320/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001321
1322static UInt graph_mark; /* current mark we're using for graph traversal */
1323
sewardj39a4d842002-11-13 22:14:30 +00001324static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001325 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001326static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001327 const LockSet *lockset_holding,
1328 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001329
njn72718642003-07-24 08:45:32 +00001330static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001331
1332#define M_MUTEX_HASHSZ 1021
1333
sewardj39a4d842002-11-13 22:14:30 +00001334static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001335static UInt total_mutexes;
1336
1337static const Char *pp_MutexState(MutexState st)
1338{
1339 switch(st) {
1340 case MxLocked: return "Locked";
1341 case MxUnlocked: return "Unlocked";
1342 case MxDead: return "Dead";
1343 case MxUnknown: return "Unknown";
1344 }
1345 return "???";
1346}
1347
tom151a6392005-11-11 12:30:36 +00001348static void pp_all_mutexes(void)
sewardjdac0a442002-11-13 22:08:40 +00001349{
1350 Int i;
1351 Int locks, buckets;
1352
1353 locks = buckets = 0;
1354 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001355 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001356 Bool first = True;
1357
1358 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1359 if (first) {
1360 buckets++;
1361 VG_(printf)("[%4d] = ", i);
1362 } else
1363 VG_(printf)(" ");
1364 locks++;
1365 first = False;
1366 VG_(printf)("%p [%8s] -> %p%(y\n",
1367 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1368 }
1369 }
1370
1371 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1372 locks, buckets, total_mutexes);
1373}
sewardjc26cc252002-10-23 21:58:55 +00001374
sewardj39a4d842002-11-13 22:14:30 +00001375/* find or create a Mutex for a program's mutex use */
1376static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001377{
nethercote50397c22004-11-04 18:03:06 +00001378 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001379 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001380
1381 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1382 if (mp->mutexp == mutexp)
1383 return mp;
1384
sewardjdac0a442002-11-13 22:08:40 +00001385 total_mutexes++;
1386
sewardjc26cc252002-10-23 21:58:55 +00001387 mp = VG_(malloc)(sizeof(*mp));
1388 mp->mutexp = mutexp;
1389 mp->next = mutex_hash[bucket];
1390 mutex_hash[bucket] = mp;
1391
1392 mp->state = MxUnknown;
1393 mp->tid = VG_INVALID_THREADID;
1394 mp->location = NULL;
1395
sewardj4bffb232002-11-13 21:46:34 +00001396 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001397 mp->mark = graph_mark - 1;
1398
1399 return mp;
1400}
1401
sewardjdac0a442002-11-13 22:08:40 +00001402/* Find all mutexes in a range of memory, and call the callback.
1403 Remove the mutex from the hash if the callback returns True (mutex
1404 structure itself is not freed, because it may be pointed to by a
1405 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001406static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001407{
sewardjdac0a442002-11-13 22:08:40 +00001408 UInt first = start % M_MUTEX_HASHSZ;
1409 UInt last = (end+1) % M_MUTEX_HASHSZ;
1410 UInt i;
1411
1412 /* Single pass over the hash table, looking for likely hashes */
1413 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001414 Mutex *mx;
1415 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001416
1417 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1418 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1419 *prev = mx->next;
1420 }
1421
1422 if (++i == M_MUTEX_HASHSZ)
1423 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001424 }
sewardjc26cc252002-10-23 21:58:55 +00001425}
1426
1427#define MARK_LOOP (graph_mark+0)
1428#define MARK_DONE (graph_mark+1)
1429
thughes4ad52d02004-06-27 17:37:21 +00001430static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1431{
1432 static const Bool debug = False;
1433 Int i;
1434
1435 if (mutex->mark == MARK_LOOP)
1436 return True; /* found cycle */
1437 if (mutex->mark == MARK_DONE)
1438 return False; /* been here before, its OK */
1439
1440 ((Mutex*)mutex)->mark = MARK_LOOP;
1441
1442 if (debug)
1443 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1444 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1445 for(i = 0; i < ls->setsize; i++) {
1446 const Mutex *mx = ls->mutex[i];
1447
1448 if (debug)
1449 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1450 mutex->mutexp, ls,
1451 mx->mutexp, mx->mutexp);
1452 if (check_cycle_inner(mx, mx->lockdep))
1453 return True;
1454 }
1455 ((Mutex*)mutex)->mark = MARK_DONE;
1456
1457 return False;
1458}
1459
sewardj39a4d842002-11-13 22:14:30 +00001460static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001461{
sewardjff2c9232002-11-13 21:44:39 +00001462
sewardjc26cc252002-10-23 21:58:55 +00001463 graph_mark += 2; /* clear all marks */
1464
sewardj4bffb232002-11-13 21:46:34 +00001465 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001466}
1467
sewardjdca84112002-11-13 22:29:34 +00001468/* test to see if a mutex state change would be problematic; this
1469 makes no changes to the mutex state. This should be called before
1470 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001471static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001472{
1473 static const Bool debug = False;
1474
sewardjc26cc252002-10-23 21:58:55 +00001475 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001476 Char *str;
1477
1478 switch(state) {
1479 case MxLocked: str = "lock dead mutex"; break;
1480 case MxUnlocked: str = "unlock dead mutex"; break;
1481 default: str = "operate on dead mutex"; break;
1482 }
1483
sewardjc26cc252002-10-23 21:58:55 +00001484 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001485 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001486 return;
1487 }
1488
1489 switch(state) {
1490 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001491 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001492
1493 if (debug)
1494 print_LockSet("thread holding", thread_locks[tid]);
1495
1496 if (check_cycle(mutex, thread_locks[tid]))
1497 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1498 else {
1499 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1500
1501 if (debug) {
1502 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1503 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1504 print_LockSet("lockdep", mutex->lockdep);
1505 }
1506 }
1507 break;
1508
1509 case MxUnlocked:
1510 if (debug)
1511 print_LockSet("thread holding", thread_locks[tid]);
1512
1513 if (mutex->state != MxLocked) {
1514 record_mutex_error(tid, mutex,
1515 "unlock non-locked mutex", mutex->location);
1516 }
1517 if (mutex->tid != tid) {
1518 record_mutex_error(tid, mutex,
1519 "unlock someone else's mutex", mutex->location);
1520 }
1521 break;
1522
1523 case MxDead:
1524 break;
1525
1526 default:
1527 break;
1528 }
1529}
1530
1531/* Update a mutex state. Expects most error testing and reporting to
1532 have happened in test_mutex_state(). The assumption is that no
1533 client code is run by thread tid between test and set, either
1534 because it is blocked or test and set are called together
1535 atomically.
1536
1537 Setting state to MxDead is the exception, since that can happen as
1538 a result of any thread freeing memory; in this case set_mutex_state
1539 does all the error reporting as well.
1540*/
njn72718642003-07-24 08:45:32 +00001541static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001542{
1543 static const Bool debug = False;
1544
1545 if (debug)
1546 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1547 tid, mutex, mutex->mutexp, mutex->mutexp,
1548 pp_MutexState(mutex->state), pp_MutexState(state));
1549
1550 if (mutex->state == MxDead) {
1551 /* can't do anything legal to a destroyed mutex */
1552 return;
1553 }
1554
1555 switch(state) {
1556 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001557 if (mutex->state == MxLocked) {
1558 if (mutex->tid != tid)
1559 record_mutex_error(tid, mutex, "take lock held by someone else",
1560 mutex->location);
1561 else
1562 record_mutex_error(tid, mutex, "take lock we already hold",
1563 mutex->location);
1564
njn67993252004-11-22 18:02:32 +00001565 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001566 break;
1567 }
sewardjc26cc252002-10-23 21:58:55 +00001568
njnca82cc02004-11-22 17:18:48 +00001569 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001570
sewardjc26cc252002-10-23 21:58:55 +00001571 mutex->tid = tid;
1572 break;
1573
1574 case MxUnlocked:
1575 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001576 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001577
sewardjdca84112002-11-13 22:29:34 +00001578 if (mutex->state != MxLocked || mutex->tid != tid)
1579 break;
1580
sewardjc26cc252002-10-23 21:58:55 +00001581 mutex->tid = VG_INVALID_THREADID;
1582 break;
1583
sewardjdac0a442002-11-13 22:08:40 +00001584 case MxDead:
1585 if (mutex->state == MxLocked) {
1586 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001587 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001588 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1589 mutex->tid = VG_INVALID_THREADID;
1590
1591 record_mutex_error(tid, mutex,
1592 "free locked mutex", mutex->location);
1593 }
1594 break;
1595
sewardjc26cc252002-10-23 21:58:55 +00001596 default:
1597 break;
1598 }
1599
njnd01fef72005-03-25 23:35:48 +00001600 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001601 mutex->state = state;
1602}
njn25e49d8e72002-09-23 09:36:25 +00001603
1604/*------------------------------------------------------------*/
1605/*--- Setting and checking permissions. ---*/
1606/*------------------------------------------------------------*/
1607
thughes4ad52d02004-06-27 17:37:21 +00001608/* only clean up dead mutexes */
1609static
1610Bool cleanmx(Mutex *mx) {
1611 return mx->state == MxDead;
1612}
1613
njn25e49d8e72002-09-23 09:36:25 +00001614static
nethercote451eae92004-11-02 13:06:32 +00001615void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001616 VgeInitStatus status )
1617{
sewardj1806d7f2002-10-22 05:05:49 +00001618 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001619
1620# if DEBUG_MAKE_ACCESSES
1621 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1622# endif
1623 //PROF_EVENT(30); PPP
1624
1625 if (len == 0)
1626 return;
1627
1628 if (len > 100 * 1000 * 1000)
1629 VG_(message)(Vg_UserMsg,
1630 "Warning: set address range state: large range %d",
1631 len);
1632
njn31513b42005-06-01 03:09:59 +00001633 //VGP_PUSHCC(VgpSARP);
njn25e49d8e72002-09-23 09:36:25 +00001634
sewardjdac0a442002-11-13 22:08:40 +00001635 /* Remove mutexes in recycled memory range from hash */
1636 find_mutex_range(a, a+len, cleanmx);
1637
njn25e49d8e72002-09-23 09:36:25 +00001638 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1639 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1640 * len/4+1 words. This works out which it is by aligning the block and
1641 * seeing if the end byte is in the same word as it is for the unaligned
1642 * block; if not, it's the awkward case. */
njn13bfd852005-06-02 03:52:53 +00001643 end = VG_ROUNDUP(a + len, 4);
1644 a = VG_ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001645
1646 /* Do it ... */
1647 switch (status) {
1648 case Vge_VirginInit:
1649 for ( ; a < end; a += 4) {
1650 //PROF_EVENT(31); PPP
1651 init_virgin_sword(a);
1652 }
1653 break;
1654
1655 case Vge_NonVirginInit:
1656 for ( ; a < end; a += 4) {
1657 //PROF_EVENT(31); PPP
1658 init_nonvirgin_sword(a);
1659 }
1660 break;
1661
1662 case Vge_SegmentInit:
1663 for ( ; a < end; a += 4) {
1664 //PROF_EVENT(31); PPP
1665 init_magically_inited_sword(a);
1666 }
1667 break;
sewardj7f3ad222002-11-13 22:11:53 +00001668
1669 case Vge_Error:
1670 for ( ; a < end; a += 4) {
1671 //PROF_EVENT(31); PPP
1672 init_error_sword(a);
1673 }
1674 break;
njn25e49d8e72002-09-23 09:36:25 +00001675
1676 default:
1677 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001678 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001679 }
1680
njn31513b42005-06-01 03:09:59 +00001681 //VGP_POPCC(VgpSARP);
njn25e49d8e72002-09-23 09:36:25 +00001682}
1683
1684
nethercote451eae92004-11-02 13:06:32 +00001685static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001686{
1687 //PROF_EVENT(??); PPP
1688 set_address_range_state ( a, len, Vge_SegmentInit );
1689}
1690
nethercote451eae92004-11-02 13:06:32 +00001691static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001692{
1693 //PROF_EVENT(36); PPP
1694 set_address_range_state( a, len, Vge_VirginInit );
1695}
1696
nethercote451eae92004-11-02 13:06:32 +00001697static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001698{
1699 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001700 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001701}
1702
1703
njn25e49d8e72002-09-23 09:36:25 +00001704/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001705static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001706{
1707 UInt i;
1708
1709 //PROF_EVENT(40); PPP
1710 for (i = 0; i < len; i += 4) {
1711 shadow_word sword = *(get_sword_addr ( src+i ));
1712 //PROF_EVENT(41); PPP
1713 set_sword ( dst+i, sword );
1714 }
1715}
1716
1717// SSS: put these somewhere better
njnfbdcba92005-05-09 01:23:49 +00001718static void hg_mem_read (Addr a, SizeT data_size, ThreadId tid);
1719static void hg_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001720
njnadb7a752005-06-11 01:30:57 +00001721__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001722static void hg_mem_help_read_1(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001723__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001724static void hg_mem_help_read_2(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001725__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001726static void hg_mem_help_read_4(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001727__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001728static void hg_mem_help_read_N(Addr a, SizeT size) VG_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001729
njnadb7a752005-06-11 01:30:57 +00001730__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001731static void hg_mem_help_write_1(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001732__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001733static void hg_mem_help_write_2(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001734__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001735static void hg_mem_help_write_4(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001736__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001737static void hg_mem_help_write_N(Addr a, SizeT size) VG_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001738
njnadb7a752005-06-11 01:30:57 +00001739__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001740static void bus_lock(void);
njnadb7a752005-06-11 01:30:57 +00001741__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001742static void bus_unlock(void);
1743
njn25e49d8e72002-09-23 09:36:25 +00001744static
njnfbdcba92005-05-09 01:23:49 +00001745void hg_pre_mem_read(CorePart part, ThreadId tid,
1746 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001747{
njn02bc4b82005-05-15 17:28:26 +00001748 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 +00001749 hg_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001750}
1751
1752static
njnfbdcba92005-05-09 01:23:49 +00001753void hg_pre_mem_read_asciiz(CorePart part, ThreadId tid,
1754 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001755{
njnfbdcba92005-05-09 01:23:49 +00001756 hg_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001757}
1758
1759static
njnfbdcba92005-05-09 01:23:49 +00001760void hg_pre_mem_write(CorePart part, ThreadId tid,
1761 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001762{
njnfbdcba92005-05-09 01:23:49 +00001763 hg_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001764}
1765
1766
1767
1768static
njnfbdcba92005-05-09 01:23:49 +00001769void hg_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001770{
njn1f3a9092002-10-04 09:22:30 +00001771 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001772 make_segment_readable(a, len);
1773}
1774
1775
1776static
njnfbdcba92005-05-09 01:23:49 +00001777void hg_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001778{
1779 if (is_inited) {
1780 make_readable(a, len);
1781 } else {
1782 make_writable(a, len);
1783 }
1784}
1785
1786static
njnfbdcba92005-05-09 01:23:49 +00001787void hg_set_perms (Addr a, SizeT len,
1788 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001789{
1790 if (rr) make_readable(a, len);
1791 else if (ww) make_writable(a, len);
1792 /* else do nothing */
1793}
1794
sewardjf6374322002-11-13 22:35:55 +00001795static
njnfbdcba92005-05-09 01:23:49 +00001796void hg_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001797{
1798 set_address_range_state(a, len, Vge_NonVirginInit);
1799}
1800
1801static
njnfbdcba92005-05-09 01:23:49 +00001802void hg_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001803{
1804 set_address_range_state(a, len, Vge_VirginInit);
1805}
njn25e49d8e72002-09-23 09:36:25 +00001806
1807/*--------------------------------------------------------------*/
1808/*--- Initialise the memory audit system on program startup. ---*/
1809/*--------------------------------------------------------------*/
1810
1811static
1812void init_shadow_memory(void)
1813{
1814 Int i;
1815
1816 for (i = 0; i < ESEC_MAP_WORDS; i++)
1817 distinguished_secondary_map.swords[i] = virgin_sword;
1818
1819 /* These entries gradually get overwritten as the used address
1820 space expands. */
1821 for (i = 0; i < 65536; i++)
1822 primary_map[i] = &distinguished_secondary_map;
1823}
1824
1825
njn3e884182003-04-15 13:03:23 +00001826/*------------------------------------------------------------*/
1827/*--- malloc() et al replacements ---*/
1828/*------------------------------------------------------------*/
1829
njnb4aee052003-04-15 14:09:58 +00001830static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001831
1832#define N_FREED_CHUNKS 2
1833static Int freechunkptr = 0;
1834static HG_Chunk *freechunks[N_FREED_CHUNKS];
1835
njn3e884182003-04-15 13:03:23 +00001836
1837/* Allocate a user-chunk of size bytes. Also allocate its shadow
1838 block, make the shadow block point at the user block. Put the
1839 shadow chunk on the appropriate list, and set all memory
1840 protections correctly. */
1841
nethercote7ac7f7b2004-11-02 12:36:02 +00001842static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001843{
1844 HG_Chunk* hc;
1845
1846 hc = VG_(malloc)(sizeof(HG_Chunk));
1847 hc->data = p;
1848 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001849 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001850 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001851
1852 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1853}
1854
1855/* Allocate memory and note change in memory available */
1856static __inline__
njn14d01ce2004-11-26 11:30:14 +00001857void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1858 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001859{
1860 Addr p;
1861
njn34ac0272003-09-30 14:20:00 +00001862 if (size < 0) return NULL;
1863
njn3e884182003-04-15 13:03:23 +00001864 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001865 if (!p) {
1866 return NULL;
1867 }
njn34ac0272003-09-30 14:20:00 +00001868 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001869 add_HG_Chunk ( tid, p, size );
njnfbdcba92005-05-09 01:23:49 +00001870 hg_new_mem_heap( p, size, is_zeroed );
njn3e884182003-04-15 13:03:23 +00001871
1872 return (void*)p;
1873}
1874
njn51d827b2005-05-09 01:02:08 +00001875static void* hg_malloc ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001876{
njn14d01ce2004-11-26 11:30:14 +00001877 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001878}
1879
njn51d827b2005-05-09 01:02:08 +00001880static void* hg___builtin_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001881{
njn14d01ce2004-11-26 11:30:14 +00001882 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001883}
1884
njn51d827b2005-05-09 01:02:08 +00001885static void* hg___builtin_vec_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001886{
njn14d01ce2004-11-26 11:30:14 +00001887 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001888}
1889
njn51d827b2005-05-09 01:02:08 +00001890static void* hg_memalign ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001891{
njn14d01ce2004-11-26 11:30:14 +00001892 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001893}
1894
njn51d827b2005-05-09 01:02:08 +00001895static void* hg_calloc ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001896{
njn14d01ce2004-11-26 11:30:14 +00001897 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001898 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001899}
1900
thughes4ad52d02004-06-27 17:37:21 +00001901static ThreadId deadmx_tid;
1902
1903static
1904Bool deadmx(Mutex *mx) {
1905 if (mx->state != MxDead)
1906 set_mutex_state(mx, MxDead, deadmx_tid);
1907
1908 return False;
1909}
1910
njn3e884182003-04-15 13:03:23 +00001911static
njn72718642003-07-24 08:45:32 +00001912void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001913 HG_Chunk** prev_chunks_next_ptr )
1914{
njn72718642003-07-24 08:45:32 +00001915 Addr start = hc->data;
1916 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001917
njn3e884182003-04-15 13:03:23 +00001918 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1919 avoid repeating the hash table lookup. Can't remove until at least
1920 after free and free_mismatch errors are done because they use
1921 describe_addr() which looks for it in malloclist. */
1922 *prev_chunks_next_ptr = hc->next;
1923
1924 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001925 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001926
1927 /* maintain a small window so that the error reporting machinery
1928 knows about this memory */
1929 if (freechunks[freechunkptr] != NULL) {
1930 /* free HG_Chunk */
1931 HG_Chunk* sc1 = freechunks[freechunkptr];
1932 VG_(cli_free) ( (void*)(sc1->data) );
1933 VG_(free) ( sc1 );
1934 }
1935
1936 freechunks[freechunkptr] = hc;
1937
1938 if (++freechunkptr == N_FREED_CHUNKS)
1939 freechunkptr = 0;
1940
1941 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001942 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001943 find_mutex_range(start, end, deadmx);
1944}
1945
1946
1947static __inline__
njn14d01ce2004-11-26 11:30:14 +00001948void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001949{
1950 HG_Chunk* hc;
1951 HG_Chunk** prev_chunks_next_ptr;
1952
nethercote3d6b6112004-11-04 16:39:43 +00001953 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001954 (VgHashNode***)&prev_chunks_next_ptr );
1955 if (hc == NULL) {
1956 return;
1957 }
njn14d01ce2004-11-26 11:30:14 +00001958 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001959}
1960
njn51d827b2005-05-09 01:02:08 +00001961static void hg_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001962{
njn14d01ce2004-11-26 11:30:14 +00001963 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001964}
1965
njn51d827b2005-05-09 01:02:08 +00001966static void hg___builtin_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001967{
njn14d01ce2004-11-26 11:30:14 +00001968 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001969}
1970
njn51d827b2005-05-09 01:02:08 +00001971static void hg___builtin_vec_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001972{
njn14d01ce2004-11-26 11:30:14 +00001973 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001974}
1975
njn51d827b2005-05-09 01:02:08 +00001976static void* hg_realloc ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001977{
1978 HG_Chunk *hc;
1979 HG_Chunk **prev_chunks_next_ptr;
njn3e884182003-04-15 13:03:23 +00001980
1981 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001982 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001983 (VgHashNode***)&prev_chunks_next_ptr );
1984
1985 if (hc == NULL) {
1986 return NULL;
1987 }
1988
1989 if (hc->size == new_size) {
1990 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001991 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001992 return p;
1993
1994 } else if (hc->size > new_size) {
1995 /* new size is smaller */
1996 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001997 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001998 return p;
1999
2000 } else {
2001 /* new size is bigger */
2002 Addr p_new;
2003
2004 /* Get new memory */
2005 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
2006
tom0cd42f02005-10-06 09:00:17 +00002007 if (p_new) {
2008 /* First half kept and copied, second half new */
2009 copy_address_range_state( (Addr)p, p_new, hc->size );
2010 hg_new_mem_heap ( p_new+hc->size, new_size-hc->size,
2011 /*inited*/False );
njn3e884182003-04-15 13:03:23 +00002012
tom0cd42f02005-10-06 09:00:17 +00002013 /* Copy from old to new */
2014 VG_(memcpy)((void *)p_new, p, hc->size);
njn3e884182003-04-15 13:03:23 +00002015
tom0cd42f02005-10-06 09:00:17 +00002016 /* Free old memory */
2017 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00002018
tom0cd42f02005-10-06 09:00:17 +00002019 /* this has to be after die_and_free_mem, otherwise the
2020 former succeeds in shorting out the new block, not the
2021 old, in the case when both are on the same list. */
2022 add_HG_Chunk ( tid, p_new, new_size );
2023 }
njn3e884182003-04-15 13:03:23 +00002024
2025 return (void*)p_new;
2026 }
2027}
2028
njn25e49d8e72002-09-23 09:36:25 +00002029/*--------------------------------------------------------------*/
2030/*--- Machinery to support sanity checking ---*/
2031/*--------------------------------------------------------------*/
2032
njn51d827b2005-05-09 01:02:08 +00002033static Bool hg_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00002034{
jseward9800fd32004-01-04 23:08:04 +00002035 /* nothing useful we can rapidly check */
2036 return True;
njn25e49d8e72002-09-23 09:36:25 +00002037}
2038
njn51d827b2005-05-09 01:02:08 +00002039static Bool hg_expensive_sanity_check(void)
njn25e49d8e72002-09-23 09:36:25 +00002040{
2041 Int i;
2042
2043 /* Make sure nobody changed the distinguished secondary. */
2044 for (i = 0; i < ESEC_MAP_WORDS; i++)
2045 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2046 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2047 return False;
2048
2049 return True;
2050}
2051
2052
2053/*--------------------------------------------------------------*/
2054/*--- Instrumentation ---*/
2055/*--------------------------------------------------------------*/
2056
sewardjf6374322002-11-13 22:35:55 +00002057static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2058
njn14d01ce2004-11-26 11:30:14 +00002059#if 0
njn25e49d8e72002-09-23 09:36:25 +00002060/* Create and return an instrumented version of cb_in. Free cb_in
2061 before returning. */
njn26f02512004-11-22 18:33:15 +00002062UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002063{
2064 UCodeBlock* cb;
2065 Int i;
2066 UInstr* u_in;
2067 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002068 Int ntemps;
2069 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002070 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002071
njn810086f2002-11-14 12:42:47 +00002072 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002073
sewardjf6374322002-11-13 22:35:55 +00002074 /* stackref[] is used for super-simple value tracking to keep note
2075 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002076 the stack pointer or frame pointer, and is therefore likely
2077 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002078 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002079 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2080 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2081
njn810086f2002-11-14 12:42:47 +00002082 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2083 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002084
njn25e49d8e72002-09-23 09:36:25 +00002085 switch (u_in->opcode) {
2086
2087 case NOP: case CALLM_S: case CALLM_E:
2088 break;
sewardjf6374322002-11-13 22:35:55 +00002089
sewardj7a5ebcf2002-11-13 22:42:13 +00002090 case LOCK:
2091 locked = True;
2092 uInstr0(cb, CCALL, 0);
2093 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2094 break;
2095
2096 case JMP: case INCEIP:
2097 if (locked) {
2098 uInstr0(cb, CCALL, 0);
2099 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2100 }
2101 locked = False;
2102 VG_(copy_UInstr)(cb, u_in);
2103 break;
2104
sewardjf6374322002-11-13 22:35:55 +00002105 case GET:
njnca82cc02004-11-22 17:18:48 +00002106 tl_assert(u_in->tag1 == ArchReg);
2107 tl_assert(u_in->tag2 == TempReg);
2108 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002109
2110 stackref[u_in->val2] = (u_in->size == 4 &&
njnaf839f52005-06-23 03:27:57 +00002111 (u_in->val1 == VG_R_STACK_PTR ||
2112 u_in->val1 == VG_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002113 VG_(copy_UInstr)(cb, u_in);
2114 break;
2115
2116 case MOV:
2117 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002118 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002119 stackref[u_in->val2] = stackref[u_in->val1];
2120 }
2121 VG_(copy_UInstr)(cb, u_in);
2122 break;
2123
2124 case LEA1:
2125 case ADD: case SUB:
2126 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002127 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002128 stackref[u_in->val2] |= stackref[u_in->val1];
2129 }
2130 VG_(copy_UInstr)(cb, u_in);
2131 break;
njn25e49d8e72002-09-23 09:36:25 +00002132
sewardja5b3aec2002-10-22 05:09:36 +00002133 case LOAD: {
2134 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002135 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2136 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002137
2138 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2139 nonstk_ld++;
2140
2141 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002142 case 1: help = hg_mem_help_read_1; break;
2143 case 2: help = hg_mem_help_read_2; break;
2144 case 4: help = hg_mem_help_read_4; break;
sewardjf6374322002-11-13 22:35:55 +00002145 default:
njn67993252004-11-22 18:02:32 +00002146 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002147 }
jsgfcb1d1c02003-10-14 21:55:10 +00002148
2149 /* XXX all registers should be flushed to baseblock
2150 here */
sewardjf6374322002-11-13 22:35:55 +00002151 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2152 uCCall(cb, (Addr)help, 1, 1, False);
2153 } else
2154 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002155
sewardja5b3aec2002-10-22 05:09:36 +00002156 VG_(copy_UInstr)(cb, u_in);
2157 t_size = INVALID_TEMPREG;
2158 break;
2159 }
2160
fitzhardinge111c6072004-03-09 02:45:07 +00002161 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002162 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002163 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002164 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002165
fitzhardinge111c6072004-03-09 02:45:07 +00002166 t_size = newTemp(cb);
2167 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2168 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002169
fitzhardinge111c6072004-03-09 02:45:07 +00002170 /* XXX all registers should be flushed to baseblock
2171 here */
2172 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002173 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002174
2175 VG_(copy_UInstr)(cb, u_in);
2176 t_size = INVALID_TEMPREG;
2177 break;
sewardja5b3aec2002-10-22 05:09:36 +00002178 }
2179
thughes96b466a2004-03-15 16:43:58 +00002180 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002181 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002182
2183 t_size = newTemp(cb);
2184 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2185 uLiteral(cb, (UInt)u_in->size);
2186
2187 /* XXX all registers should be flushed to baseblock
2188 here */
2189 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002190 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
thughes96b466a2004-03-15 16:43:58 +00002191
2192 VG_(copy_UInstr)(cb, u_in);
2193 t_size = INVALID_TEMPREG;
2194 break;
2195 }
2196
fitzhardinge111c6072004-03-09 02:45:07 +00002197 case SSE2a_MemRd:
2198 case SSE2a1_MemRd:
2199 case SSE3a_MemRd:
2200 case SSE3a1_MemRd:
2201 case SSE3ag_MemRd_RegWr: {
2202 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2203
njnca82cc02004-11-22 17:18:48 +00002204 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002205
2206 t_size = newTemp(cb);
2207 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2208 uLiteral(cb, (UInt)u_in->size);
2209
2210 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002211 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002212
2213 VG_(copy_UInstr)(cb, u_in);
2214 t_size = INVALID_TEMPREG;
2215 break;
2216 }
2217
sewardja5b3aec2002-10-22 05:09:36 +00002218 case STORE: {
2219 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002220 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2221 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002222
sewardjf6374322002-11-13 22:35:55 +00002223 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2224 nonstk_st++;
2225
2226 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002227 case 1: help = hg_mem_help_write_1; break;
2228 case 2: help = hg_mem_help_write_2; break;
2229 case 4: help = hg_mem_help_write_4; break;
sewardjf6374322002-11-13 22:35:55 +00002230 default:
njn67993252004-11-22 18:02:32 +00002231 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002232 }
2233
jsgfcb1d1c02003-10-14 21:55:10 +00002234 /* XXX all registers should be flushed to baseblock
2235 here */
sewardjf6374322002-11-13 22:35:55 +00002236 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2237 uCCall(cb, (Addr)help, 2, 2, False);
2238 } else
2239 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002240
2241 VG_(copy_UInstr)(cb, u_in);
2242 t_size = INVALID_TEMPREG;
2243 break;
2244 }
2245
fitzhardinge111c6072004-03-09 02:45:07 +00002246 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002247 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002248 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002249 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002250
2251 t_size = newTemp(cb);
2252 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2253 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002254 /* XXX all registers should be flushed to baseblock
2255 here */
sewardja5b3aec2002-10-22 05:09:36 +00002256 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002257 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
sewardja5b3aec2002-10-22 05:09:36 +00002258
2259 VG_(copy_UInstr)(cb, u_in);
2260 t_size = INVALID_TEMPREG;
2261 break;
2262 }
njn25e49d8e72002-09-23 09:36:25 +00002263
fitzhardinge111c6072004-03-09 02:45:07 +00002264 case SSE2a_MemWr:
2265 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002266 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002267 512 == u_in->size);
2268
2269 t_size = newTemp(cb);
2270 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2271 uLiteral(cb, (UInt)u_in->size);
2272 /* XXX all registers should be flushed to baseblock
2273 here */
2274 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002275 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002276
2277 VG_(copy_UInstr)(cb, u_in);
2278 t_size = INVALID_TEMPREG;
2279 break;
2280 }
sewardj3d7c9c82003-03-26 21:08:13 +00002281
njn25e49d8e72002-09-23 09:36:25 +00002282 default:
sewardjf6374322002-11-13 22:35:55 +00002283 /* conservative tromping */
2284 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2285 stackref[u_in->val1] = False;
2286 if (u_in->tag2 == TempReg)
2287 stackref[u_in->val2] = False;
2288 if (u_in->tag3 == TempReg)
2289 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002290 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002291 break;
2292 }
2293 }
2294
sewardjf6374322002-11-13 22:35:55 +00002295 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002296 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002297 return cb;
2298}
njn14d01ce2004-11-26 11:30:14 +00002299#endif
sewardj4ba057c2005-10-18 12:04:18 +00002300static
2301IRBB* hg_instrument ( IRBB* bb_in, VexGuestLayout* layout,
2302 Addr64 orig_addr_noredir, VexGuestExtents* vge,
2303 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002304{
njn5db32122005-08-12 15:23:57 +00002305 tl_assert(0); // Need to convert to Vex
njn14d01ce2004-11-26 11:30:14 +00002306}
njn25e49d8e72002-09-23 09:36:25 +00002307
2308/*--------------------------------------------------------------------*/
2309/*--- Error and suppression handling ---*/
2310/*--------------------------------------------------------------------*/
2311
2312typedef
2313 enum {
2314 /* Possible data race */
njnfbdcba92005-05-09 01:23:49 +00002315 RaceSupp
njn25e49d8e72002-09-23 09:36:25 +00002316 }
njnfbdcba92005-05-09 01:23:49 +00002317 RaceSuppKind;
njn25e49d8e72002-09-23 09:36:25 +00002318
2319/* What kind of error it is. */
2320typedef
2321 enum {
njnfbdcba92005-05-09 01:23:49 +00002322 RaceErr, /* data-race */
sewardj16748af2002-10-22 04:55:54 +00002323 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002324 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002325 }
njnfbdcba92005-05-09 01:23:49 +00002326 RaceErrorKind;
njn25e49d8e72002-09-23 09:36:25 +00002327
sewardj16748af2002-10-22 04:55:54 +00002328/* The classification of a faulting address. */
2329typedef
2330 enum { Undescribed, /* as-yet unclassified */
2331 Stack,
2332 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002333 Mallocd,
2334 Freed,
sewardj16748af2002-10-22 04:55:54 +00002335 Segment
2336 }
2337 AddrKind;
2338/* Records info about a faulting address. */
2339typedef
2340 struct {
2341 /* ALL */
2342 AddrKind akind;
2343 /* Freed, Mallocd */
2344 Int blksize;
2345 /* Freed, Mallocd */
2346 Int rwoffset;
2347 /* Freed, Mallocd */
2348 ExeContext* lastchange;
2349 ThreadId lasttid;
2350 /* Stack */
2351 ThreadId stack_tid;
2352 /* Segment */
2353 const Char* filename;
2354 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002355 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002356 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002357 /* symbolic address description */
2358 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002359 }
2360 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002361
sewardj16748af2002-10-22 04:55:54 +00002362/* What kind of memory access is involved in the error? */
2363typedef
2364 enum { ReadAxs, WriteAxs, ExecAxs }
2365 AxsKind;
2366
2367/* Extra context for memory errors */
2368typedef
2369 struct {
2370 AxsKind axskind;
2371 Int size;
2372 AddrInfo addrinfo;
2373 Bool isWrite;
2374 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002375 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002376 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002377 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002378 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002379 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002380 const LockSet *held_lockset;
2381 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002382 }
2383 HelgrindError;
2384
2385static __inline__
2386void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002387{
sewardj16748af2002-10-22 04:55:54 +00002388 ai->akind = Unknown;
2389 ai->blksize = 0;
2390 ai->rwoffset = 0;
2391 ai->lastchange = NULL;
2392 ai->lasttid = VG_INVALID_THREADID;
2393 ai->filename = NULL;
2394 ai->section = "???";
2395 ai->stack_tid = VG_INVALID_THREADID;
2396 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002397 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002398}
2399
sewardj16748af2002-10-22 04:55:54 +00002400static __inline__
2401void clear_HelgrindError ( HelgrindError* err_extra )
2402{
2403 err_extra->axskind = ReadAxs;
2404 err_extra->size = 0;
2405 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002406 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002407 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002408 err_extra->prev_lockset = 0;
2409 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002410 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002411 clear_AddrInfo ( &err_extra->addrinfo );
2412 err_extra->isWrite = False;
2413}
2414
2415
2416
2417/* Describe an address as best you can, for error messages,
2418 putting the result in ai. */
2419
thughes4ad52d02004-06-27 17:37:21 +00002420/* Callback for searching malloc'd and free'd lists */
2421static Bool addr_is_in_block(VgHashNode *node, void *ap)
2422{
2423 HG_Chunk* hc2 = (HG_Chunk*)node;
2424 Addr a = *(Addr *)ap;
2425
2426 return (hc2->data <= a && a < hc2->data + hc2->size);
2427}
2428
sewardj16748af2002-10-22 04:55:54 +00002429static void describe_addr ( Addr a, AddrInfo* ai )
2430{
njn3e884182003-04-15 13:03:23 +00002431 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002432 Int i;
sewardj16748af2002-10-22 04:55:54 +00002433
sewardj16748af2002-10-22 04:55:54 +00002434 /* Search for it in segments */
2435 {
njn36ef6ba2005-05-14 18:42:26 +00002436 const SegInfo *si;
sewardj16748af2002-10-22 04:55:54 +00002437
njn36ef6ba2005-05-14 18:42:26 +00002438 for (si = VG_(next_seginfo)(NULL);
2439 si != NULL;
2440 si = VG_(next_seginfo)(si))
2441 {
njnd9e5fd72005-06-25 19:51:33 +00002442 Addr base = VG_(seginfo_start)(si);
2443 SizeT size = VG_(seginfo_size)(si);
2444 const UChar *filename = VG_(seginfo_filename)(si);
sewardj16748af2002-10-22 04:55:54 +00002445
2446 if (a >= base && a < base+size) {
2447 ai->akind = Segment;
2448 ai->blksize = size;
2449 ai->rwoffset = a - base;
2450 ai->filename = filename;
2451
njnd9e5fd72005-06-25 19:51:33 +00002452 switch(VG_(seginfo_sect_kind)(a)) {
sewardj16748af2002-10-22 04:55:54 +00002453 case Vg_SectText: ai->section = "text"; break;
2454 case Vg_SectData: ai->section = "data"; break;
2455 case Vg_SectBSS: ai->section = "BSS"; break;
2456 case Vg_SectGOT: ai->section = "GOT"; break;
2457 case Vg_SectPLT: ai->section = "PLT"; break;
2458 case Vg_SectUnknown:
2459 default:
2460 ai->section = "???"; break;
2461 }
2462
2463 return;
2464 }
2465 }
2466 }
2467
2468 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002469 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002470 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002471 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002472 ai->blksize = hc->size;
2473 ai->rwoffset = (Int)a - (Int)(hc->data);
2474 ai->lastchange = hc->where;
2475 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002476 return;
2477 }
sewardjdac0a442002-11-13 22:08:40 +00002478
2479 /* Look in recently freed memory */
2480 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002481 hc = freechunks[i];
2482 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002483 continue;
2484
njn3e884182003-04-15 13:03:23 +00002485 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002486 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002487 ai->blksize = hc->size;
2488 ai->rwoffset = a - hc->data;
2489 ai->lastchange = hc->where;
2490 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002491 return;
2492 }
2493 }
2494
sewardj16748af2002-10-22 04:55:54 +00002495 /* Clueless ... */
2496 ai->akind = Unknown;
2497 return;
2498}
2499
2500
njn7e614812003-04-21 22:04:03 +00002501/* Updates the copy with address info if necessary. */
njn51d827b2005-05-09 01:02:08 +00002502static UInt hg_update_extra(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002503{
njn7e614812003-04-21 22:04:03 +00002504 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002505
njn7e614812003-04-21 22:04:03 +00002506 extra = (HelgrindError*)VG_(get_error_extra)(err);
2507 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2508 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2509 }
2510 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002511}
2512
njnfbdcba92005-05-09 01:23:49 +00002513static void record_race_error ( ThreadId tid, Addr a, Bool is_write,
2514 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002515{
sewardjc4a810d2002-11-13 22:25:51 +00002516 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002517 HelgrindError err_extra;
2518
njnfbdcba92005-05-09 01:23:49 +00002519 n_hg_warnings++;
sewardjff2c9232002-11-13 21:44:39 +00002520
sewardj16748af2002-10-22 04:55:54 +00002521 clear_HelgrindError(&err_extra);
2522 err_extra.isWrite = is_write;
2523 err_extra.addrinfo.akind = Undescribed;
2524 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002525 if (clo_execontext)
2526 err_extra.lasttouched = getExeContext(a);
jsgfcb1d1c02003-10-14 21:55:10 +00002527 err_extra.addrinfo.expr = VG_(describe_addr)(tid, a);
2528
njnfbdcba92005-05-09 01:23:49 +00002529 VG_(maybe_record_error)( tid, RaceErr, a,
sewardj16748af2002-10-22 04:55:54 +00002530 (is_write ? "writing" : "reading"),
2531 &err_extra);
2532
sewardjc4a810d2002-11-13 22:25:51 +00002533 sw = get_sword_addr(a);
2534 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2535 ThreadLifeSeg *tls = unpackTLS(sw->other);
2536 tls->refcount--;
2537 }
2538
sewardj7f3ad222002-11-13 22:11:53 +00002539 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002540}
2541
sewardj39a4d842002-11-13 22:14:30 +00002542static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002543 Char *str, ExeContext *ec)
2544{
2545 HelgrindError err_extra;
2546
2547 clear_HelgrindError(&err_extra);
2548 err_extra.addrinfo.akind = Undescribed;
2549 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002550 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002551 err_extra.lasttid = tid;
2552
njn72718642003-07-24 08:45:32 +00002553 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002554 (Addr)mutex->mutexp, str, &err_extra);
2555}
njn25e49d8e72002-09-23 09:36:25 +00002556
sewardj39a4d842002-11-13 22:14:30 +00002557static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002558 const LockSet *lockset_holding,
2559 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002560{
2561 HelgrindError err_extra;
2562
2563 n_lockorder_warnings++;
2564
2565 clear_HelgrindError(&err_extra);
2566 err_extra.addrinfo.akind = Undescribed;
2567 err_extra.mutex = mutex;
2568
sewardjc808ef52002-11-13 22:43:26 +00002569 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002570 err_extra.held_lockset = lockset_holding;
2571 err_extra.prev_lockset = lockset_prev;
2572
njn72718642003-07-24 08:45:32 +00002573 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002574}
2575
njn51d827b2005-05-09 01:02:08 +00002576static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002577{
njn810086f2002-11-14 12:42:47 +00002578 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002579
njnca82cc02004-11-22 17:18:48 +00002580 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002581
2582 switch (VG_(get_error_kind)(e1)) {
njnfbdcba92005-05-09 01:23:49 +00002583 case RaceErr:
njn810086f2002-11-14 12:42:47 +00002584 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002585
2586 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002587 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002588 }
2589
njn810086f2002-11-14 12:42:47 +00002590 e1s = VG_(get_error_string)(e1);
2591 e2s = VG_(get_error_string)(e2);
2592 if (e1s != e2s) return False;
2593 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002594 return True;
2595}
2596
sewardj16748af2002-10-22 04:55:54 +00002597static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002598{
jsgfcb1d1c02003-10-14 21:55:10 +00002599 if (ai->expr != NULL)
2600 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002601 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002602
sewardj16748af2002-10-22 04:55:54 +00002603 switch (ai->akind) {
2604 case Stack:
2605 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002606 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002607 a, ai->stack_tid);
2608 break;
2609 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002610 if (ai->expr != NULL)
2611 break;
2612
nethercote3b390c72003-11-13 17:53:43 +00002613 /* maybe_gcc is never set to True! This is a hangover from code
2614 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002615 if (ai->maybe_gcc) {
2616 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002617 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002618 a);
2619 VG_(message)(Vg_UserMsg,
2620 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2621 } else {
2622 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002623 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002624 }
2625 break;
2626 case Segment:
2627 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002628 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002629 a, ai->section, ai->filename);
2630 break;
sewardjdac0a442002-11-13 22:08:40 +00002631 case Mallocd:
2632 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002633 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002634 UChar* relative;
2635 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002636 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002637 relative = "before";
2638 } else if (ai->rwoffset >= ai->blksize) {
2639 delta = ai->rwoffset - ai->blksize;
2640 relative = "after";
2641 } else {
2642 delta = ai->rwoffset;
2643 relative = "inside";
2644 }
2645 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002646 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2647 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002648 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002649 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002650 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002651
sewardj16748af2002-10-22 04:55:54 +00002652 VG_(pp_ExeContext)(ai->lastchange);
2653 break;
2654 }
2655 default:
njn67993252004-11-22 18:02:32 +00002656 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002657 }
njn25e49d8e72002-09-23 09:36:25 +00002658}
2659
sewardj4bffb232002-11-13 21:46:34 +00002660static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002661{
sewardjff2c9232002-11-13 21:44:39 +00002662 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002663 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002664
sewardj4bffb232002-11-13 21:46:34 +00002665 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2666 lockset->setsize * 120 +
2667 1);
sewardjff2c9232002-11-13 21:44:39 +00002668
2669 cp = buf;
2670 if (prefix)
2671 cp += VG_(sprintf)(cp, "%s", prefix);
2672
sewardj4bffb232002-11-13 21:46:34 +00002673 for(i = 0; i < lockset->setsize; i++)
2674 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2675 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002676
sewardj4bffb232002-11-13 21:46:34 +00002677 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002678 cp[-2] = '\0';
2679 else
2680 *cp = '\0';
2681
2682 return buf;
2683}
njn25e49d8e72002-09-23 09:36:25 +00002684
njn51d827b2005-05-09 01:02:08 +00002685static void hg_pp_Error ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002686{
njn810086f2002-11-14 12:42:47 +00002687 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002688 Char buf[100];
2689 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002690 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002691
2692 *msg = '\0';
2693
njn810086f2002-11-14 12:42:47 +00002694 switch(VG_(get_error_kind)(err)) {
njnfbdcba92005-05-09 01:23:49 +00002695 case RaceErr: {
njn810086f2002-11-14 12:42:47 +00002696 Addr err_addr = VG_(get_error_address)(err);
2697
sewardj16748af2002-10-22 04:55:54 +00002698 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002699 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002700 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002701 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002702
2703 switch(extra->prevstate.state) {
2704 case Vge_Virgin:
2705 /* shouldn't be possible to go directly from virgin -> error */
2706 VG_(sprintf)(buf, "virgin!?");
2707 break;
2708
sewardjc4a810d2002-11-13 22:25:51 +00002709 case Vge_Excl: {
2710 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2711
njnca82cc02004-11-22 17:18:48 +00002712 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002713 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002714 break;
sewardjc4a810d2002-11-13 22:25:51 +00002715 }
sewardj16748af2002-10-22 04:55:54 +00002716
2717 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002718 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002719 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002720
2721 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002722 VG_(sprintf)(buf, "shared %s, no locks",
2723 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2724 break;
2725 }
2726
sewardjff2c9232002-11-13 21:44:39 +00002727 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2728 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002729 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002730
sewardj16748af2002-10-22 04:55:54 +00002731 break;
2732 }
sewardj16748af2002-10-22 04:55:54 +00002733
sewardj499e3de2002-11-13 22:22:25 +00002734 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002735 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002736
sewardj72baa7a2002-12-09 23:32:58 +00002737 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002738 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002739 Char file[100];
2740 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002741 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002742
nethercote3b390c72003-11-13 17:53:43 +00002743 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002744 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002745 pp_state(extra->lasttouched.state),
2746 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002747
sewardj7cee6f92005-06-13 17:39:06 +00002748 if (VG_(get_filename_linenum)(ip, file, sizeof(file),
2749 NULL, 0, NULL, &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002750 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002751 ip, ip, file, line);
2752 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002753 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002754 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002755 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002756 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002757 }
sewardj72baa7a2002-12-09 23:32:58 +00002758 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002759 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002760 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002761 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002762 pp_state(extra->lasttouched.state),
2763 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002764 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002765 }
sewardj16748af2002-10-22 04:55:54 +00002766 break;
njn810086f2002-11-14 12:42:47 +00002767 }
sewardj16748af2002-10-22 04:55:54 +00002768
2769 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002770 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002771 VG_(get_error_address)(err),
2772 VG_(get_error_address)(err),
2773 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002774 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002775 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002776 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002777 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002778 }
njn810086f2002-11-14 12:42:47 +00002779 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002780 break;
sewardjff2c9232002-11-13 21:44:39 +00002781
2782 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002783 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002784 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002785 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002786
2787 msg = lockset_str(NULL, heldset);
2788
2789 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002790 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002791 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002792 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2793
sewardj4bffb232002-11-13 21:46:34 +00002794 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002795 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002796
sewardj542494b2002-11-13 22:46:13 +00002797 /* needs to be a recursive search+display */
2798 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002799 continue;
2800
nethercote3b390c72003-11-13 17:53:43 +00002801 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002802 lsmx->mutexp, lsmx->mutexp);
2803 VG_(pp_ExeContext)(lsmx->location);
2804 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002805 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002806 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002807 }
2808
2809 break;
sewardj16748af2002-10-22 04:55:54 +00002810 }
sewardjff2c9232002-11-13 21:44:39 +00002811 }
2812
2813 if (msg != buf)
2814 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002815}
2816
2817
njn51d827b2005-05-09 01:02:08 +00002818static Bool hg_recognised_suppression ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002819{
2820 if (0 == VG_(strcmp)(name, "Eraser")) {
njnfbdcba92005-05-09 01:23:49 +00002821 VG_(set_supp_kind)(su, RaceSupp);
njn25e49d8e72002-09-23 09:36:25 +00002822 return True;
2823 } else {
2824 return False;
2825 }
2826}
2827
2828
njn51d827b2005-05-09 01:02:08 +00002829static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002830{
2831 /* do nothing -- no extra suppression info present. Return True to
2832 indicate nothing bad happened. */
2833 return True;
2834}
2835
2836
njn51d827b2005-05-09 01:02:08 +00002837static Bool hg_error_matches_suppression(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002838{
njnfbdcba92005-05-09 01:23:49 +00002839 tl_assert(VG_(get_supp_kind)(su) == RaceSupp);
nethercote64366b42003-12-01 13:11:47 +00002840
njnfbdcba92005-05-09 01:23:49 +00002841 return (VG_(get_error_kind)(err) == RaceErr);
njn25e49d8e72002-09-23 09:36:25 +00002842}
2843
njn51d827b2005-05-09 01:02:08 +00002844static Char* hg_get_error_name ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002845{
njnfbdcba92005-05-09 01:23:49 +00002846 if (RaceErr == VG_(get_error_kind)(err)) {
2847 return "Eraser"; // old name, required for backwards compatibility
njn43c799e2003-04-08 00:08:52 +00002848 } else {
2849 return NULL; /* Other errors types can't be suppressed */
2850 }
2851}
2852
njn51d827b2005-05-09 01:02:08 +00002853static void hg_print_extra_suppression_info ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002854{
2855 /* Do nothing */
2856}
njn25e49d8e72002-09-23 09:36:25 +00002857
njnfbdcba92005-05-09 01:23:49 +00002858static void hg_pre_mutex_lock(ThreadId tid, void* void_mutex)
sewardjdca84112002-11-13 22:29:34 +00002859{
2860 Mutex *mutex = get_mutex((Addr)void_mutex);
2861
njn72718642003-07-24 08:45:32 +00002862 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002863}
2864
njnfbdcba92005-05-09 01:23:49 +00002865static void hg_post_mutex_lock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002866{
sewardj4bffb232002-11-13 21:46:34 +00002867 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002868 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002869 const LockSet* ls;
2870
njn72718642003-07-24 08:45:32 +00002871 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002872
njn25e49d8e72002-09-23 09:36:25 +00002873# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002874 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002875# endif
2876
njn25e49d8e72002-09-23 09:36:25 +00002877 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2878# if LOCKSET_SANITY > 1
njnfbdcba92005-05-09 01:23:49 +00002879 sanity_check_locksets("hg_post_mutex_lock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002880# endif
2881
sewardj4bffb232002-11-13 21:46:34 +00002882 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002883
sewardj4bffb232002-11-13 21:46:34 +00002884 if (ls == NULL) {
2885 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2886 insert_LockSet(newset);
2887 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002888 }
sewardj4bffb232002-11-13 21:46:34 +00002889 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002890
sewardj4bffb232002-11-13 21:46:34 +00002891 if (debug || DEBUG_LOCKS)
2892 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002893
sewardj4bffb232002-11-13 21:46:34 +00002894 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002895 sanity_check_locksets("hg_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002896}
2897
2898
njnfbdcba92005-05-09 01:23:49 +00002899static void hg_post_mutex_unlock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002900{
sewardjc26cc252002-10-23 21:58:55 +00002901 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002902 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002903 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002904 const LockSet *ls;
2905
njn72718642003-07-24 08:45:32 +00002906 test_mutex_state(mutex, MxUnlocked, tid);
2907 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002908
sewardjdac0a442002-11-13 22:08:40 +00002909 if (!ismember(thread_locks[tid], mutex))
2910 return;
2911
sewardjc26cc252002-10-23 21:58:55 +00002912 if (debug || DEBUG_LOCKS)
2913 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002914
sewardjc26cc252002-10-23 21:58:55 +00002915 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002916 sanity_check_locksets("hg_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002917
sewardj4bffb232002-11-13 21:46:34 +00002918 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002919
sewardj4bffb232002-11-13 21:46:34 +00002920 if (ls == NULL) {
2921 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2922 insert_LockSet(newset);
2923 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002924 }
2925
2926 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002927 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002928 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002929 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002930
sewardj4bffb232002-11-13 21:46:34 +00002931 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002932
sewardjc26cc252002-10-23 21:58:55 +00002933 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002934 sanity_check_locksets("hg_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002935}
2936
2937
2938/* ---------------------------------------------------------------------
2939 Checking memory reads and writes
2940 ------------------------------------------------------------------ */
2941
2942/* Behaviour on reads and writes:
2943 *
2944 * VIR EXCL SHAR SH_MOD
2945 * ----------------------------------------------------------------
2946 * rd/wr, 1st thread | - EXCL - -
2947 * rd, new thread | - SHAR - -
2948 * wr, new thread | - SH_MOD - -
2949 * rd | error! - SHAR SH_MOD
2950 * wr | EXCL - SH_MOD SH_MOD
2951 * ----------------------------------------------------------------
2952 */
2953
sewardj8fac99a2002-11-13 22:31:26 +00002954static inline
njn25e49d8e72002-09-23 09:36:25 +00002955void dump_around_a(Addr a)
2956{
2957 UInt i;
2958 shadow_word* sword;
2959 VG_(printf)("NEARBY:\n");
2960 for (i = a - 12; i <= a + 12; i += 4) {
2961 sword = get_sword_addr(i);
2962 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2963 }
2964}
njn25e49d8e72002-09-23 09:36:25 +00002965
2966#if DEBUG_ACCESSES
2967 #define DEBUG_STATE(args...) \
2968 VG_(printf)("(%u) ", size), \
2969 VG_(printf)(args)
2970#else
2971 #define DEBUG_STATE(args...)
2972#endif
2973
njnfbdcba92005-05-09 01:23:49 +00002974static void hg_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002975{
sewardj72baa7a2002-12-09 23:32:58 +00002976 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002977 shadow_word prevstate;
2978 ThreadLifeSeg *tls;
2979 const LockSet *ls;
2980 Bool statechange = False;
2981
2982 static const void *const states[4] = {
2983 [Vge_Virgin] &&st_virgin,
2984 [Vge_Excl] &&st_excl,
2985 [Vge_Shar] &&st_shar,
2986 [Vge_SharMod] &&st_sharmod,
2987 };
2988
2989 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002990 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002991
2992 sword = get_sword_addr(a);
2993 if (sword == SEC_MAP_ACCESS) {
2994 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2995 return;
2996 }
2997
2998 prevstate = *sword;
2999
3000 goto *states[sword->state];
3001
3002 /* This looks like reading of unitialised memory, may be legit. Eg.
3003 * calloc() zeroes its values, so untouched memory may actually be
3004 * initialised. Leave that stuff to Valgrind. */
3005 st_virgin:
3006 if (TID_INDICATING_NONVIRGIN == sword->other) {
3007 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
3008 if (DEBUG_VIRGIN_READS)
3009 dump_around_a(a);
3010 } else {
3011 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
3012 }
3013 statechange = True;
3014 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
3015 tls->refcount++;
3016 goto done;
3017
3018 st_excl: {
3019 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3020
3021 if (tls == sw_tls) {
3022 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
3023 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3024 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
3025 } else if (tlsIsDisjoint(tls, sw_tls)) {
3026 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3027 statechange = True;
3028 sword->other = packTLS(tls);
3029 sw_tls->refcount--;
3030 tls->refcount++;
3031 } else {
3032 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3033 sw_tls->refcount--;
3034 statechange = True;
3035 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3036
3037 if (DEBUG_MEM_LOCKSET_CHANGES)
3038 print_LockSet("excl read locks", unpackLockSet(sword->other));
3039 }
3040 goto done;
3041 }
3042
3043 st_shar:
3044 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3045 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3046 thread_locks[tid]));
3047 statechange = sword->other != prevstate.other;
3048 goto done;
3049
3050 st_sharmod:
3051 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3052 ls = intersect(unpackLockSet(sword->other),
3053 thread_locks[tid]);
3054 sword->other = packLockSet(ls);
3055
3056 statechange = sword->other != prevstate.other;
3057
3058 if (isempty(ls)) {
njnfbdcba92005-05-09 01:23:49 +00003059 record_race_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003060 }
3061 goto done;
3062
3063 done:
3064 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003065 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003066
3067 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003068 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003069 else
njnd01fef72005-03-25 23:35:48 +00003070 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003071 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003072 }
3073}
njn25e49d8e72002-09-23 09:36:25 +00003074
njnfbdcba92005-05-09 01:23:49 +00003075static void hg_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003076{
njn72718642003-07-24 08:45:32 +00003077 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003078
njn13bfd852005-06-02 03:52:53 +00003079 end = VG_ROUNDUP(a+size, 4);
3080 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003081
sewardj18cd4a52002-11-13 22:37:41 +00003082 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003083 hg_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003084}
3085
njnfbdcba92005-05-09 01:23:49 +00003086static void hg_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003087{
3088 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003089 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003090 shadow_word prevstate;
3091 Bool statechange = False;
3092 static const void *const states[4] = {
3093 [Vge_Virgin] &&st_virgin,
3094 [Vge_Excl] &&st_excl,
3095 [Vge_Shar] &&st_shar,
3096 [Vge_SharMod] &&st_sharmod,
3097 };
3098
sewardjc4a810d2002-11-13 22:25:51 +00003099 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003100 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003101
sewardj18cd4a52002-11-13 22:37:41 +00003102 sword = get_sword_addr(a);
3103 if (sword == SEC_MAP_ACCESS) {
3104 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3105 return;
3106 }
njn25e49d8e72002-09-23 09:36:25 +00003107
sewardj18cd4a52002-11-13 22:37:41 +00003108 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003109
sewardj18cd4a52002-11-13 22:37:41 +00003110 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003111
sewardj18cd4a52002-11-13 22:37:41 +00003112 st_virgin:
3113 if (TID_INDICATING_NONVIRGIN == sword->other)
3114 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3115 else
3116 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3117 statechange = True;
3118 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3119 tls->refcount++;
3120 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003121
sewardj18cd4a52002-11-13 22:37:41 +00003122 st_excl: {
3123 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3124
3125 if (tls == sw_tls) {
3126 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3127 goto done;
3128 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3129 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3130 goto done;
3131 } else if (tlsIsDisjoint(tls, sw_tls)) {
3132 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3133 sword->other = packTLS(tls);
3134 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003135 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003136 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003137 } else {
3138 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3139 statechange = True;
3140 sw_tls->refcount--;
3141 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3142 if(DEBUG_MEM_LOCKSET_CHANGES)
3143 print_LockSet("excl write locks", unpackLockSet(sword->other));
3144 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003145 }
sewardj18cd4a52002-11-13 22:37:41 +00003146 }
njn25e49d8e72002-09-23 09:36:25 +00003147
sewardj18cd4a52002-11-13 22:37:41 +00003148 st_shar:
3149 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3150 sword->state = Vge_SharMod;
3151 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3152 thread_locks[tid]));
3153 statechange = True;
3154 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003155
sewardj18cd4a52002-11-13 22:37:41 +00003156 st_sharmod:
3157 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3158 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3159 thread_locks[tid]));
3160 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003161
sewardj18cd4a52002-11-13 22:37:41 +00003162 SHARED_MODIFIED:
3163 if (isempty(unpackLockSet(sword->other))) {
njnfbdcba92005-05-09 01:23:49 +00003164 record_race_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003165 }
3166 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003167
sewardj18cd4a52002-11-13 22:37:41 +00003168 done:
3169 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003170 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003171
sewardj18cd4a52002-11-13 22:37:41 +00003172 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003173 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003174 else
njnd01fef72005-03-25 23:35:48 +00003175 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003176 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003177 }
3178}
3179
njnfbdcba92005-05-09 01:23:49 +00003180static void hg_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003181{
sewardj8fac99a2002-11-13 22:31:26 +00003182 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003183
njn13bfd852005-06-02 03:52:53 +00003184 end = VG_ROUNDUP(a+size, 4);
3185 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003186
sewardj18cd4a52002-11-13 22:37:41 +00003187 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003188 hg_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003189}
3190
3191#undef DEBUG_STATE
3192
njnaf839f52005-06-23 03:27:57 +00003193VG_REGPARM(1) static void hg_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003194{
njnfbdcba92005-05-09 01:23:49 +00003195 hg_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003196}
3197
njnaf839f52005-06-23 03:27:57 +00003198VG_REGPARM(1) static void hg_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003199{
njnfbdcba92005-05-09 01:23:49 +00003200 hg_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003201}
3202
njnaf839f52005-06-23 03:27:57 +00003203VG_REGPARM(1) static void hg_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003204{
njnfbdcba92005-05-09 01:23:49 +00003205 hg_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003206}
3207
njnaf839f52005-06-23 03:27:57 +00003208VG_REGPARM(2) static void hg_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003209{
njnfbdcba92005-05-09 01:23:49 +00003210 hg_mem_read(a, size, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003211}
3212
njnaf839f52005-06-23 03:27:57 +00003213VG_REGPARM(2) static void hg_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003214{
3215 if (*(UChar *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003216 hg_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003217}
njnaf839f52005-06-23 03:27:57 +00003218VG_REGPARM(2) static void hg_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003219{
3220 if (*(UShort *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003221 hg_mem_write(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003222}
njnaf839f52005-06-23 03:27:57 +00003223VG_REGPARM(2) static void hg_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003224{
3225 if (*(UInt *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003226 hg_mem_write(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003227}
njnaf839f52005-06-23 03:27:57 +00003228VG_REGPARM(2) static void hg_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003229{
njnfbdcba92005-05-09 01:23:49 +00003230 hg_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003231}
njn25e49d8e72002-09-23 09:36:25 +00003232
sewardjc4a810d2002-11-13 22:25:51 +00003233static void hg_thread_create(ThreadId parent, ThreadId child)
3234{
3235 if (0)
3236 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3237
3238 newTLS(child);
3239 addPriorTLS(child, parent);
3240
3241 newTLS(parent);
3242}
3243
3244static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3245{
3246 if (0)
3247 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3248
3249 newTLS(joiner);
3250 addPriorTLS(joiner, joinee);
3251
3252 clearTLS(joinee);
3253}
3254
sewardj7a5ebcf2002-11-13 22:42:13 +00003255static Int __BUS_HARDWARE_LOCK__;
3256
3257static void bus_lock(void)
3258{
njn95e65f62005-03-30 04:13:56 +00003259 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003260 hg_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3261 hg_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003262}
3263
3264static void bus_unlock(void)
3265{
njn95e65f62005-03-30 04:13:56 +00003266 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003267 hg_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003268}
3269
njn25e49d8e72002-09-23 09:36:25 +00003270/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003271/*--- Client requests ---*/
3272/*--------------------------------------------------------------------*/
3273
njn51d827b2005-05-09 01:02:08 +00003274static Bool hg_handle_client_request(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003275{
njnfc26ff92004-11-22 19:12:49 +00003276 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003277 return False;
3278
3279 switch(args[0]) {
3280 case VG_USERREQ__HG_CLEAN_MEMORY:
3281 set_address_range_state(args[1], args[2], Vge_VirginInit);
3282 *ret = 0; /* meaningless */
3283 break;
3284
3285 case VG_USERREQ__HG_KNOWN_RACE:
3286 set_address_range_state(args[1], args[2], Vge_Error);
3287 *ret = 0; /* meaningless */
3288 break;
3289
3290 default:
3291 return False;
3292 }
3293
3294 return True;
3295}
3296
3297
3298/*--------------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00003299/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00003300/*--------------------------------------------------------------------*/
3301
njn51d827b2005-05-09 01:02:08 +00003302static Bool hg_process_cmd_line_option(Char* arg)
3303{
3304 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3305 clo_execontext = EC_None;
3306 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3307 clo_execontext = EC_Some;
3308 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3309 clo_execontext = EC_All;
3310
3311 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
3312
3313 else
3314 return VG_(replacement_malloc_process_cmd_line_option)(arg);
3315
3316 return True;
3317}
3318
3319static void hg_print_usage(void)
3320{
3321 VG_(printf)(
3322" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3323" --show-last-access=no|some|all\n"
3324" show location of last word access on error [no]\n"
3325 );
3326 VG_(replacement_malloc_print_usage)();
3327}
3328
3329static void hg_print_debug_usage(void)
3330{
3331 VG_(replacement_malloc_print_debug_usage)();
3332}
3333
3334static void hg_post_clo_init(void)
3335{
3336 void (*stack_tracker)(Addr a, SizeT len);
3337
3338 if (clo_execontext) {
3339 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3340 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3341 }
3342
3343 if (clo_priv_stacks)
njnfbdcba92005-05-09 01:23:49 +00003344 stack_tracker = & hg_new_mem_stack_private;
njn51d827b2005-05-09 01:02:08 +00003345 else
njnfbdcba92005-05-09 01:23:49 +00003346 stack_tracker = & hg_new_mem_stack;
njn51d827b2005-05-09 01:02:08 +00003347
3348 VG_(track_new_mem_stack) (stack_tracker);
3349 VG_(track_new_mem_stack_signal) (stack_tracker);
3350}
3351
3352
3353static void hg_fini(Int exitcode)
3354{
3355 if (DEBUG_LOCK_TABLE) {
3356 pp_all_LockSets();
3357 pp_all_mutexes();
3358 }
3359
3360 if (LOCKSET_SANITY)
3361 sanity_check_locksets("hg_fini");
3362
3363 if (VG_(clo_verbosity) > 0)
3364 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
njnfbdcba92005-05-09 01:23:49 +00003365 n_hg_warnings, n_lockorder_warnings);
njn51d827b2005-05-09 01:02:08 +00003366
3367 if (0)
3368 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3369 stk_ld, stk_st, stk_ld + stk_st,
3370 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3371 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
3372}
3373
3374static void hg_pre_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00003375{
3376 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003377 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003378
njn810086f2002-11-14 12:42:47 +00003379 VG_(details_name) ("Helgrind");
3380 VG_(details_version) (NULL);
3381 VG_(details_description) ("a data race detector");
3382 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +00003383 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003384 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003385 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003386
njn51d827b2005-05-09 01:02:08 +00003387 VG_(basic_tool_funcs) (hg_post_clo_init,
3388 hg_instrument,
3389 hg_fini);
tomc756a8e2005-03-31 07:59:35 +00003390
njn5db32122005-08-12 15:23:57 +00003391 VG_(printf)(
3392"\n"
3393"Helgrind is currently not working, because:\n"
3394" (a) it is not yet ready to handle the Vex IR and the use with 64-bit\n"
3395" platforms introduced in Valgrind 3.0.0\n"
3396" (b) we need to get thread operation tracking working again after\n"
3397" the changes added in Valgrind 2.4.0\n"
3398"\n"
3399"Sorry for the inconvenience. Let us know if this is a problem for you.\n");
3400 VG_(exit)(1);
3401
tomc756a8e2005-03-31 07:59:35 +00003402 VG_(needs_core_errors) ();
njn51d827b2005-05-09 01:02:08 +00003403 VG_(needs_tool_errors) (hg_eq_Error,
3404 hg_pp_Error,
3405 hg_update_extra,
3406 hg_recognised_suppression,
3407 hg_read_extra_suppression_info,
3408 hg_error_matches_suppression,
3409 hg_get_error_name,
3410 hg_print_extra_suppression_info);
tomc756a8e2005-03-31 07:59:35 +00003411 VG_(needs_data_syms) ();
njn51d827b2005-05-09 01:02:08 +00003412 VG_(needs_client_requests) (hg_handle_client_request);
3413 VG_(needs_sanity_checks) (hg_cheap_sanity_check,
3414 hg_expensive_sanity_check);
3415 VG_(needs_command_line_options)(hg_process_cmd_line_option,
3416 hg_print_usage,
3417 hg_print_debug_usage);
tomc756a8e2005-03-31 07:59:35 +00003418
njnfc51f8d2005-06-21 03:20:17 +00003419 VG_(needs_malloc_replacement) (hg_malloc,
njn51d827b2005-05-09 01:02:08 +00003420 hg___builtin_new,
3421 hg___builtin_vec_new,
3422 hg_memalign,
3423 hg_calloc,
3424 hg_free,
3425 hg___builtin_delete,
3426 hg___builtin_vec_delete,
3427 hg_realloc,
tomc756a8e2005-03-31 07:59:35 +00003428 8 );
njn25e49d8e72002-09-23 09:36:25 +00003429
njnfbdcba92005-05-09 01:23:49 +00003430 VG_(track_new_mem_startup) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003431
njn51d827b2005-05-09 01:02:08 +00003432 /* stack ones not decided until hg_post_clo_init() */
njn25e49d8e72002-09-23 09:36:25 +00003433
njn51d827b2005-05-09 01:02:08 +00003434 VG_(track_new_mem_brk) (& make_writable);
njnfbdcba92005-05-09 01:23:49 +00003435 VG_(track_new_mem_mmap) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003436
njnfbdcba92005-05-09 01:23:49 +00003437 VG_(track_change_mem_mprotect) (& hg_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003438
njn51d827b2005-05-09 01:02:08 +00003439 VG_(track_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003440
njn51d827b2005-05-09 01:02:08 +00003441 VG_(track_die_mem_stack) (NULL);
3442 VG_(track_die_mem_stack_signal)(NULL);
3443 VG_(track_die_mem_brk) (NULL);
3444 VG_(track_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003445
njnfbdcba92005-05-09 01:23:49 +00003446 VG_(track_pre_mem_read) (& hg_pre_mem_read);
3447 VG_(track_pre_mem_read_asciiz) (& hg_pre_mem_read_asciiz);
3448 VG_(track_pre_mem_write) (& hg_pre_mem_write);
njn51d827b2005-05-09 01:02:08 +00003449 VG_(track_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003450
njn51d827b2005-05-09 01:02:08 +00003451 VG_(track_post_thread_create) (& hg_thread_create);
3452 VG_(track_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003453
njnfbdcba92005-05-09 01:23:49 +00003454 VG_(track_pre_mutex_lock) (& hg_pre_mutex_lock);
3455 VG_(track_post_mutex_lock) (& hg_post_mutex_lock);
3456 VG_(track_post_mutex_unlock) (& hg_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003457
njn14d01ce2004-11-26 11:30:14 +00003458 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003459 lockset_hash[i] = NULL;
3460
3461 empty = alloc_LockSet(0);
3462 insert_LockSet(empty);
3463 emptyset = empty;
3464
sewardjc4a810d2002-11-13 22:25:51 +00003465 /* Init lock table and thread segments */
3466 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003467 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003468
sewardjc4a810d2002-11-13 22:25:51 +00003469 newTLS(i);
3470 }
3471
njn25e49d8e72002-09-23 09:36:25 +00003472 init_shadow_memory();
njnf69f9452005-07-03 17:53:11 +00003473 hg_malloc_list = VG_(HT_construct)( 80021 ); // prime, big
njn25e49d8e72002-09-23 09:36:25 +00003474}
3475
sewardj45f4e7c2005-09-27 19:20:21 +00003476VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00003477
njn25e49d8e72002-09-23 09:36:25 +00003478/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003479/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003480/*--------------------------------------------------------------------*/