blob: 2d708af53d04e258430f27e42f495a8d72f5385c [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.
fitzhardinge98abfc72003-12-16 02:05:15 +0000514 map = (ESecMap *)VG_(shadow_alloc)(sizeof(ESecMap));
njn25e49d8e72002-09-23 09:36:25 +0000515 for (i = 0; i < ESEC_MAP_WORDS; i++)
516 map->swords[i] = virgin_sword;
517
518 return map;
519}
520
521
522/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
523 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000524static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000525void set_sword ( Addr a, shadow_word sword )
526{
527 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000528 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000529
530 //PROF_EVENT(23); PPP
531 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
532
533 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
534 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000535 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000536 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
537 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
538 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
539 tls->refcount--;
540 }
541
542 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
543 ThreadLifeSeg *tls = unpackTLS(sword.other);
544 tls->refcount++;
545 }
546
njn25e49d8e72002-09-23 09:36:25 +0000547 sm->swords[(a & 0xFFFC) >> 2] = sword;
548
549 if (VGE_IS_DISTINGUISHED_SM(sm)) {
550 VG_(printf)("wrote to distinguished 2ndary map! 0x%x\n", a);
551 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000552 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000553 }
554}
555
556
557static __inline__
558shadow_word* get_sword_addr ( Addr a )
559{
560 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
561 ESecMap* sm = primary_map[a >> 16];
562 UInt sm_off = (a & 0xFFFC) >> 2;
563
564 if (VGE_IS_DISTINGUISHED_SM(sm)) {
565 VG_(printf)("accessed distinguished 2ndary map! 0x%x\n", a);
566 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000567 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000568 return SEC_MAP_ACCESS;
569 }
570
571 //PROF_EVENT(21); PPP
572 return & (sm->swords[sm_off]);
573}
574
575
576// SSS: rename these so they're not so similar to memcheck, unless it's
577// appropriate of course
578
579static __inline__
580void init_virgin_sword(Addr a)
581{
sewardj499e3de2002-11-13 22:22:25 +0000582 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000583 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000584 set_sword(a, virgin_sword);
585}
586
sewardj7f3ad222002-11-13 22:11:53 +0000587static __inline__
588void init_error_sword(Addr a)
589{
590 set_sword(a, error_sword);
591}
njn25e49d8e72002-09-23 09:36:25 +0000592
njn25e49d8e72002-09-23 09:36:25 +0000593static __inline__
594void init_nonvirgin_sword(Addr a)
595{
596 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000597 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000598 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000599
njn14d01ce2004-11-26 11:30:14 +0000600 // The tid must be passed in here now; this requires more events to be
601 // given the tid in the first place.
602 //
603 //tid = VG_(get_current_or_recent_tid)();
604 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
605 VG_(exit)(1);
606
njnca82cc02004-11-22 17:18:48 +0000607 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000608 tls = thread_seg[tid];
609
sewardj8fac99a2002-11-13 22:31:26 +0000610 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000611 set_sword(a, sword);
612}
613
614
njnfbdcba92005-05-09 01:23:49 +0000615/* In this case, we treat it for Helgrind's sake like virgin (it hasn't
njn25e49d8e72002-09-23 09:36:25 +0000616 * been inited by a particular thread, it's just done automatically upon
617 * startup), but we mark its .state specially so it doesn't look like an
618 * uninited read. */
619static __inline__
620void init_magically_inited_sword(Addr a)
621{
622 shadow_word sword;
623
sewardj8fac99a2002-11-13 22:31:26 +0000624 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
625
njn25e49d8e72002-09-23 09:36:25 +0000626 set_sword(a, virgin_sword);
627}
628
sewardjc26cc252002-10-23 21:58:55 +0000629
sewardj274c6012002-10-22 04:54:55 +0000630/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000631/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000632/*------------------------------------------------------------*/
633
sewardj39a4d842002-11-13 22:14:30 +0000634typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000635typedef struct _LockSet LockSet;
636
sewardj16748af2002-10-22 04:55:54 +0000637typedef enum MutexState {
638 MxUnknown, /* don't know */
639 MxUnlocked, /* unlocked */
640 MxLocked, /* locked */
641 MxDead /* destroyed */
642} MutexState;
643
sewardj39a4d842002-11-13 22:14:30 +0000644struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000645 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000646 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000647
648 MutexState state; /* mutex state */
649 ThreadId tid; /* owner */
650 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000651
sewardj4bffb232002-11-13 21:46:34 +0000652 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000653 UInt mark; /* mark for graph traversal */
654};
sewardj16748af2002-10-22 04:55:54 +0000655
sewardj39a4d842002-11-13 22:14:30 +0000656static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000657{
sewardjdac0a442002-11-13 22:08:40 +0000658 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000659}
njn25e49d8e72002-09-23 09:36:25 +0000660
sewardj274c6012002-10-22 04:54:55 +0000661struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000662 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000663 UInt hash; /* hash code */
664 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000665 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000666};
sewardj4bffb232002-11-13 21:46:34 +0000667
668static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000669
670/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000671static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000672
sewardjdac0a442002-11-13 22:08:40 +0000673#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000674
sewardj4bffb232002-11-13 21:46:34 +0000675static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000676
sewardj4bffb232002-11-13 21:46:34 +0000677/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000678static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000679{
sewardj4bffb232002-11-13 21:46:34 +0000680 UInt id;
681
njn94065fd2004-11-22 19:26:27 +0000682 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000683 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000684
685 return id;
njn25e49d8e72002-09-23 09:36:25 +0000686}
687
sewardj8fac99a2002-11-13 22:31:26 +0000688static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000689{
sewardj29ef1c82005-06-11 10:33:35 +0000690 /* HACK ALERT -- DUBIOUS CAST */
691 return (LockSet *)ULong_to_Ptr(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000692}
693
njn25e49d8e72002-09-23 09:36:25 +0000694static
sewardj4bffb232002-11-13 21:46:34 +0000695void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000696{
sewardj05bcdcb2003-05-18 10:05:38 +0000697 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000698 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000699 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000700 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000701
702 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000703 }
704 VG_(printf)("}\n");
705}
706
707
sewardj4bffb232002-11-13 21:46:34 +0000708static void print_LockSet(const Char *s, const LockSet *ls)
709{
710 VG_(printf)("%s: ", s);
711 pp_LockSet(ls);
712}
713
714/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000715static UInt hash_LockSet_w_wo(const LockSet *ls,
716 const Mutex *with,
717 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000718{
sewardj05bcdcb2003-05-18 10:05:38 +0000719 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000720 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000721
njnca82cc02004-11-22 17:18:48 +0000722 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000723
724 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000725 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000726
727 if (without && mutex_cmp(without, mx) == 0)
728 continue;
729
730 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
731 mx = with;
732 with = NULL;
733 i--;
734 }
735
sewardj8fac99a2002-11-13 22:31:26 +0000736 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000737 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000738 }
739
740 return hash % LOCKSET_HASH_SZ;
741}
742
sewardj39a4d842002-11-13 22:14:30 +0000743static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000744{
745 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
746
747 if (0)
748 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
749
750 return hash;
751}
752
sewardj39a4d842002-11-13 22:14:30 +0000753static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000754{
755 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
756
757 if (0)
758 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
759
760 return hash;
761}
762
763static inline UInt hash_LockSet(const LockSet *ls)
764{
765 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
766
767 if (0)
768 VG_(printf)("hash %p -> %d\n", ls, hash);
769
770 return hash;
771}
772
773static
774Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000775{
776 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000777
sewardj4bffb232002-11-13 21:46:34 +0000778 if (a == b)
779 return True;
780 if (a->setsize != b->setsize)
781 return False;
njn25e49d8e72002-09-23 09:36:25 +0000782
sewardj4bffb232002-11-13 21:46:34 +0000783 for(i = 0; i < a->setsize; i++) {
784 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000785 return False;
njn25e49d8e72002-09-23 09:36:25 +0000786 }
787
sewardj4bffb232002-11-13 21:46:34 +0000788 return True;
njn25e49d8e72002-09-23 09:36:25 +0000789}
790
791
792/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
793 * doesn't do the insertion. Returns True if they match.
794 */
795static Bool
sewardj4bffb232002-11-13 21:46:34 +0000796weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000797 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000798{
sewardjc26cc252002-10-23 21:58:55 +0000799 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000800 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000801
njn25e49d8e72002-09-23 09:36:25 +0000802 /* Idea is to try and match each element of b against either an
803 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000804
805 if (debug) {
806 print_LockSet("weird_LockSet_equals a", a);
807 print_LockSet(" b", b);
808 VG_(printf)( " missing: %p%(y\n",
809 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000810 }
sewardjc26cc252002-10-23 21:58:55 +0000811
sewardj4bffb232002-11-13 21:46:34 +0000812 if ((a->setsize + 1) != b->setsize) {
813 if (debug)
814 VG_(printf)(" fastpath length mismatch -> 0\n");
815 return False;
816 }
817
sewardjc26cc252002-10-23 21:58:55 +0000818 /* There are three phases to this compare:
819 1 the section from the start of a up to missing_mutex
820 2 missing mutex itself
821 3 the section after missing_mutex to the end of a
822 */
823
sewardj4bffb232002-11-13 21:46:34 +0000824 ia = 0;
825 ib = 0;
826
sewardjc26cc252002-10-23 21:58:55 +0000827 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000828 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000829 if (debug) {
830 print_LockSet(" 1:a", a);
831 print_LockSet(" 1:b", b);
832 }
sewardj4bffb232002-11-13 21:46:34 +0000833 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000834 return False;
sewardjc26cc252002-10-23 21:58:55 +0000835 }
836
837 /* 2: missing_mutex itself */
838 if (debug) {
839 VG_(printf)( " 2:missing: %p%(y\n",
840 missing_mutex->mutexp, missing_mutex->mutexp);
841 print_LockSet(" 2: b", b);
842 }
843
njnca82cc02004-11-22 17:18:48 +0000844 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000845
sewardj4bffb232002-11-13 21:46:34 +0000846 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000847 return False;
848
sewardj4bffb232002-11-13 21:46:34 +0000849 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000850
851 /* 3: after missing_mutex to end */
852
sewardj4bffb232002-11-13 21:46:34 +0000853 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000854 if (debug) {
855 print_LockSet(" 3:a", a);
856 print_LockSet(" 3:b", b);
857 }
sewardj4bffb232002-11-13 21:46:34 +0000858 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000859 return False;
sewardjc26cc252002-10-23 21:58:55 +0000860 }
861
862 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000863 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000864
sewardj4bffb232002-11-13 21:46:34 +0000865 return ia == a->setsize && ib == b->setsize;
866}
867
868
869
870static const LockSet *lookup_LockSet(const LockSet *set)
871{
872 UInt bucket = set->hash;
873 LockSet *ret;
874
875 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
876 if (set == ret || structural_eq_LockSet(set, ret))
877 return ret;
878
879 return NULL;
880}
881
sewardj39a4d842002-11-13 22:14:30 +0000882static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000883{
884 UInt bucket = hash_LockSet_with(set, mutex);
885 const LockSet *ret;
886
887 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
888 if (weird_LockSet_equals(set, ret, mutex))
889 return ret;
890
891 return NULL;
892}
893
sewardj39a4d842002-11-13 22:14:30 +0000894static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000895{
896 UInt bucket = hash_LockSet_without(set, mutex);
897 const LockSet *ret;
898
899 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
900 if (weird_LockSet_equals(ret, set, mutex))
901 return ret;
902
903 return NULL;
904}
905
906static void insert_LockSet(LockSet *set)
907{
908 UInt hash = hash_LockSet(set);
909
910 set->hash = hash;
911
njnca82cc02004-11-22 17:18:48 +0000912 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000913
914 set->next = lockset_hash[hash];
915 lockset_hash[hash] = set;
916}
917
918static inline
919LockSet *alloc_LockSet(UInt setsize)
920{
sewardj39a4d842002-11-13 22:14:30 +0000921 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000922 ret->setsize = setsize;
923 return ret;
924}
925
926static inline
927void free_LockSet(LockSet *p)
928{
929 /* assert: not present in hash */
930 VG_(free)(p);
931}
932
njnb4aee052003-04-15 14:09:58 +0000933static
sewardj4bffb232002-11-13 21:46:34 +0000934void pp_all_LockSets ( void )
935{
936 Int i;
937 Int sets, buckets;
938
939 sets = buckets = 0;
940 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
941 const LockSet *ls = lockset_hash[i];
942 Bool first = True;
943
sewardj4bffb232002-11-13 21:46:34 +0000944 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000945 if (first) {
946 buckets++;
947 VG_(printf)("[%4d] = ", i);
948 } else
949 VG_(printf)(" ");
950
sewardj4bffb232002-11-13 21:46:34 +0000951 sets++;
952 first = False;
953 pp_LockSet(ls);
954 }
955 }
956
957 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
958}
959
960static inline Bool isempty(const LockSet *ls)
961{
962 return ls == NULL || ls->setsize == 0;
963}
964
sewardj39a4d842002-11-13 22:14:30 +0000965static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000966{
967 Int i;
968
969 /* XXX use binary search */
970 for(i = 0; i < ls->setsize; i++)
971 if (mutex_cmp(mx, ls->mutex[i]) == 0)
972 return True;
973
974 return False;
975}
976
977/* Check invariants:
978 - all locksets are unique
979 - each set is an array in strictly increasing order of mutex addr
980*/
981static
982void sanity_check_locksets ( const Char* caller )
983{
984 Int i;
985 const Char *badness;
986 LockSet *ls;
987
988 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
989
990 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000991 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000992 Int j;
993
994 if (hash_LockSet(ls) != ls->hash) {
995 badness = "mismatched hash";
996 goto bad;
997 }
sewardj05bcdcb2003-05-18 10:05:38 +0000998 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +0000999 badness = "wrong bucket";
1000 goto bad;
1001 }
1002 if (lookup_LockSet(ls) != ls) {
1003 badness = "non-unique set";
1004 goto bad;
1005 }
1006
1007 prev = ls->mutex[0];
1008 for(j = 1; j < ls->setsize; j++) {
1009 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
1010 badness = "mutexes out of order";
1011 goto bad;
1012 }
1013 }
1014 }
1015 }
1016 return;
1017
1018 bad:
1019 VG_(printf)("sanity_check_locksets: "
1020 "i = %d, ls=%p badness = %s, caller = %s\n",
1021 i, ls, badness, caller);
1022 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001023 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001024}
1025
1026static
sewardj39a4d842002-11-13 22:14:30 +00001027LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001028{
1029 static const Bool debug = False;
1030 LockSet *ret = NULL;
1031 Int i, j;
1032
1033 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1034 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1035 print_LockSet("add-IN", ls);
1036 }
1037
1038 if (debug || LOCKSET_SANITY)
1039 sanity_check_locksets("add-IN");
1040
njnca82cc02004-11-22 17:18:48 +00001041 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001042
1043 ret = alloc_LockSet(ls->setsize+1);
1044
1045 for(i = j = 0; i < ls->setsize; i++) {
1046 if (debug)
1047 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1048 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1049 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1050 ret->mutex[j++] = mx;
1051 mx = NULL;
1052 }
1053 ret->mutex[j++] = ls->mutex[i];
1054 }
1055
1056 /* not added in loop - must be after */
1057 if (mx)
1058 ret->mutex[j++] = mx;
1059
njnca82cc02004-11-22 17:18:48 +00001060 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001061
1062 if (debug || LOCKSET_SANITY) {
1063 print_LockSet("add-OUT", ret);
1064 sanity_check_locksets("add-OUT");
1065 }
1066 return ret;
1067}
1068
1069/* Builds ls with mx removed. mx should actually be in ls!
1070 (a checked assertion). Resulting set should not already
1071 exist in the table (unchecked).
1072*/
1073static
sewardj39a4d842002-11-13 22:14:30 +00001074LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001075{
1076 static const Bool debug = False;
1077 LockSet *ret = NULL;
1078 Int i, j;
1079
1080 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1081 print_LockSet("remove-IN", ls);
1082 }
1083
1084 if (debug || LOCKSET_SANITY)
1085 sanity_check_locksets("remove-IN");
1086
njnca82cc02004-11-22 17:18:48 +00001087 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001088
1089 ret = alloc_LockSet(ls->setsize-1);
1090
1091 for(i = j = 0; i < ls->setsize; i++) {
1092 if (mutex_cmp(ls->mutex[i], mx) == 0)
1093 continue;
1094 ret->mutex[j++] = ls->mutex[i];
1095 }
1096
njnca82cc02004-11-22 17:18:48 +00001097 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001098
1099 if (debug || LOCKSET_SANITY) {
1100 print_LockSet("remove-OUT", ret);
1101 sanity_check_locksets("remove-OUT");
1102 }
1103 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001104}
1105
1106
1107/* Builds the intersection, and then unbuilds it if it's already in the table.
1108 */
sewardj4bffb232002-11-13 21:46:34 +00001109static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001110{
sewardj4bffb232002-11-13 21:46:34 +00001111 static const Bool debug = False;
1112 Int iret;
1113 Int ia, ib;
1114 Int size;
1115 LockSet *ret;
1116 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001117
sewardj4bffb232002-11-13 21:46:34 +00001118 if (debug || LOCKSET_SANITY)
1119 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001120
sewardj4bffb232002-11-13 21:46:34 +00001121 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1122 print_LockSet("intersect a", a);
1123 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001124 }
1125
sewardj4bffb232002-11-13 21:46:34 +00001126 /* count the size of the new set */
1127 size = 0;
1128 ia = ib = 0;
1129 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1130 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1131 size++;
1132 ia++;
1133 ib++;
1134 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1135 ia++;
1136 } else {
njnca82cc02004-11-22 17:18:48 +00001137 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001138 ib++;
1139 }
njn25e49d8e72002-09-23 09:36:25 +00001140 }
1141
sewardj4bffb232002-11-13 21:46:34 +00001142 /* Build the intersection of the two sets */
1143 ret = alloc_LockSet(size);
1144 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1145 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001146 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001147 ret->mutex[iret++] = a->mutex[ia];
1148 ia++;
1149 ib++;
1150 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1151 ia++;
1152 } else {
njnca82cc02004-11-22 17:18:48 +00001153 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001154 ib++;
1155 }
1156 }
1157
1158 ret->hash = hash_LockSet(ret);
1159
njn25e49d8e72002-09-23 09:36:25 +00001160 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001161 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001162
sewardj4bffb232002-11-13 21:46:34 +00001163 if (found != NULL) {
1164 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001165 } else {
sewardj4bffb232002-11-13 21:46:34 +00001166 insert_LockSet(ret);
1167 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001168 }
1169
sewardj4bffb232002-11-13 21:46:34 +00001170 if (debug || LOCKSET_SANITY) {
1171 print_LockSet("intersect-OUT", found);
1172 sanity_check_locksets("intersect-OUT");
1173 }
njn25e49d8e72002-09-23 09:36:25 +00001174
sewardj4bffb232002-11-13 21:46:34 +00001175 return found;
njn25e49d8e72002-09-23 09:36:25 +00001176}
1177
sewardj4bffb232002-11-13 21:46:34 +00001178/* inline the fastpath */
1179static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001180{
sewardj4bffb232002-11-13 21:46:34 +00001181 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001182
1183 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001184 if (a == b) {
1185 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1186 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001187 }
sewardj4bffb232002-11-13 21:46:34 +00001188 return a;
sewardjc26cc252002-10-23 21:58:55 +00001189 }
1190
sewardj4bffb232002-11-13 21:46:34 +00001191 if (isempty(a) || isempty(b)) {
1192 if (debug)
1193 VG_(printf)("intersect empty fastpath\n");
1194 return emptyset;
1195 }
1196
1197 return _intersect(a, b);
1198}
1199
1200
1201static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1202{
1203 static const Bool debug = False;
1204 Int iret;
1205 Int ia, ib;
1206 Int size;
1207 LockSet *ret;
1208 const LockSet *found;
1209
1210 if (debug || LOCKSET_SANITY)
1211 sanity_check_locksets("union-IN");
1212
1213 /* Fast case -- when the two are the same */
1214 if (a == b) {
1215 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1216 print_LockSet("union-same fastpath", a);
1217 }
1218 return a;
1219 }
1220
1221 if (isempty(a)) {
1222 if (debug)
1223 print_LockSet("union a=empty b", b);
1224 return b;
1225 }
1226 if (isempty(b)) {
1227 if (debug)
1228 print_LockSet("union b=empty a", a);
1229 return a;
1230 }
1231
1232 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001233 print_LockSet("union a", a);
1234 print_LockSet("union b", b);
1235 }
1236
sewardj4bffb232002-11-13 21:46:34 +00001237 /* count the size of the new set */
1238 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1239 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001240
sewardj4bffb232002-11-13 21:46:34 +00001241 if ((ia < a->setsize) && (ib < b->setsize))
1242 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1243 else if (ia == a->setsize)
1244 cmp = 1;
1245 else
1246 cmp = -1;
1247
1248 if (cmp == 0) {
1249 size++;
1250 ia++;
1251 ib++;
1252 } else if (cmp < 0) {
1253 size++;
1254 ia++;
1255 } else {
njnca82cc02004-11-22 17:18:48 +00001256 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001257 size++;
1258 ib++;
1259 }
sewardjc26cc252002-10-23 21:58:55 +00001260 }
1261
sewardj4bffb232002-11-13 21:46:34 +00001262 /* Build the intersection of the two sets */
1263 ret = alloc_LockSet(size);
1264 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1265 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001266 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001267
1268 if ((ia < a->setsize) && (ib < b->setsize))
1269 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1270 else if (ia == a->setsize)
1271 cmp = 1;
1272 else
1273 cmp = -1;
1274
1275 if (cmp == 0) {
1276 ret->mutex[iret++] = a->mutex[ia];
1277 ia++;
1278 ib++;
1279 } else if (cmp < 0) {
1280 ret->mutex[iret++] = a->mutex[ia];
1281 ia++;
1282 } else {
njnca82cc02004-11-22 17:18:48 +00001283 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001284 ret->mutex[iret++] = b->mutex[ib];
1285 ib++;
1286 }
1287 }
1288
njnca82cc02004-11-22 17:18:48 +00001289 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001290
1291 ret->hash = hash_LockSet(ret);
1292
sewardjc26cc252002-10-23 21:58:55 +00001293 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001294 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001295
sewardj4bffb232002-11-13 21:46:34 +00001296 if (found != NULL) {
1297 if (debug)
1298 print_LockSet("union found existing set", found);
1299 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001300 } else {
sewardj4bffb232002-11-13 21:46:34 +00001301 if (debug)
1302 print_LockSet("union inserting new set", ret);
1303 insert_LockSet(ret);
1304 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001305 }
1306
sewardj4bffb232002-11-13 21:46:34 +00001307 if (debug || LOCKSET_SANITY) {
1308 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001309 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001310 }
sewardjc26cc252002-10-23 21:58:55 +00001311
sewardj4bffb232002-11-13 21:46:34 +00001312 return found;
sewardjc26cc252002-10-23 21:58:55 +00001313}
1314
1315/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001316/*--- Implementation of mutex structure. ---*/
1317/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001318
1319static UInt graph_mark; /* current mark we're using for graph traversal */
1320
sewardj39a4d842002-11-13 22:14:30 +00001321static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001322 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001323static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001324 const LockSet *lockset_holding,
1325 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001326
njn72718642003-07-24 08:45:32 +00001327static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001328
1329#define M_MUTEX_HASHSZ 1021
1330
sewardj39a4d842002-11-13 22:14:30 +00001331static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001332static UInt total_mutexes;
1333
1334static const Char *pp_MutexState(MutexState st)
1335{
1336 switch(st) {
1337 case MxLocked: return "Locked";
1338 case MxUnlocked: return "Unlocked";
1339 case MxDead: return "Dead";
1340 case MxUnknown: return "Unknown";
1341 }
1342 return "???";
1343}
1344
1345static void pp_all_mutexes()
1346{
1347 Int i;
1348 Int locks, buckets;
1349
1350 locks = buckets = 0;
1351 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001352 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001353 Bool first = True;
1354
1355 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1356 if (first) {
1357 buckets++;
1358 VG_(printf)("[%4d] = ", i);
1359 } else
1360 VG_(printf)(" ");
1361 locks++;
1362 first = False;
1363 VG_(printf)("%p [%8s] -> %p%(y\n",
1364 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1365 }
1366 }
1367
1368 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1369 locks, buckets, total_mutexes);
1370}
sewardjc26cc252002-10-23 21:58:55 +00001371
sewardj39a4d842002-11-13 22:14:30 +00001372/* find or create a Mutex for a program's mutex use */
1373static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001374{
nethercote50397c22004-11-04 18:03:06 +00001375 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001376 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001377
1378 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1379 if (mp->mutexp == mutexp)
1380 return mp;
1381
sewardjdac0a442002-11-13 22:08:40 +00001382 total_mutexes++;
1383
sewardjc26cc252002-10-23 21:58:55 +00001384 mp = VG_(malloc)(sizeof(*mp));
1385 mp->mutexp = mutexp;
1386 mp->next = mutex_hash[bucket];
1387 mutex_hash[bucket] = mp;
1388
1389 mp->state = MxUnknown;
1390 mp->tid = VG_INVALID_THREADID;
1391 mp->location = NULL;
1392
sewardj4bffb232002-11-13 21:46:34 +00001393 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001394 mp->mark = graph_mark - 1;
1395
1396 return mp;
1397}
1398
sewardjdac0a442002-11-13 22:08:40 +00001399/* Find all mutexes in a range of memory, and call the callback.
1400 Remove the mutex from the hash if the callback returns True (mutex
1401 structure itself is not freed, because it may be pointed to by a
1402 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001403static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001404{
sewardjdac0a442002-11-13 22:08:40 +00001405 UInt first = start % M_MUTEX_HASHSZ;
1406 UInt last = (end+1) % M_MUTEX_HASHSZ;
1407 UInt i;
1408
1409 /* Single pass over the hash table, looking for likely hashes */
1410 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001411 Mutex *mx;
1412 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001413
1414 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1415 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1416 *prev = mx->next;
1417 }
1418
1419 if (++i == M_MUTEX_HASHSZ)
1420 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001421 }
sewardjc26cc252002-10-23 21:58:55 +00001422}
1423
1424#define MARK_LOOP (graph_mark+0)
1425#define MARK_DONE (graph_mark+1)
1426
thughes4ad52d02004-06-27 17:37:21 +00001427static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1428{
1429 static const Bool debug = False;
1430 Int i;
1431
1432 if (mutex->mark == MARK_LOOP)
1433 return True; /* found cycle */
1434 if (mutex->mark == MARK_DONE)
1435 return False; /* been here before, its OK */
1436
1437 ((Mutex*)mutex)->mark = MARK_LOOP;
1438
1439 if (debug)
1440 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1441 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1442 for(i = 0; i < ls->setsize; i++) {
1443 const Mutex *mx = ls->mutex[i];
1444
1445 if (debug)
1446 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1447 mutex->mutexp, ls,
1448 mx->mutexp, mx->mutexp);
1449 if (check_cycle_inner(mx, mx->lockdep))
1450 return True;
1451 }
1452 ((Mutex*)mutex)->mark = MARK_DONE;
1453
1454 return False;
1455}
1456
sewardj39a4d842002-11-13 22:14:30 +00001457static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001458{
sewardjff2c9232002-11-13 21:44:39 +00001459
sewardjc26cc252002-10-23 21:58:55 +00001460 graph_mark += 2; /* clear all marks */
1461
sewardj4bffb232002-11-13 21:46:34 +00001462 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001463}
1464
sewardjdca84112002-11-13 22:29:34 +00001465/* test to see if a mutex state change would be problematic; this
1466 makes no changes to the mutex state. This should be called before
1467 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001468static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001469{
1470 static const Bool debug = False;
1471
sewardjc26cc252002-10-23 21:58:55 +00001472 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001473 Char *str;
1474
1475 switch(state) {
1476 case MxLocked: str = "lock dead mutex"; break;
1477 case MxUnlocked: str = "unlock dead mutex"; break;
1478 default: str = "operate on dead mutex"; break;
1479 }
1480
sewardjc26cc252002-10-23 21:58:55 +00001481 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001482 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001483 return;
1484 }
1485
1486 switch(state) {
1487 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001488 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001489
1490 if (debug)
1491 print_LockSet("thread holding", thread_locks[tid]);
1492
1493 if (check_cycle(mutex, thread_locks[tid]))
1494 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1495 else {
1496 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1497
1498 if (debug) {
1499 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1500 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1501 print_LockSet("lockdep", mutex->lockdep);
1502 }
1503 }
1504 break;
1505
1506 case MxUnlocked:
1507 if (debug)
1508 print_LockSet("thread holding", thread_locks[tid]);
1509
1510 if (mutex->state != MxLocked) {
1511 record_mutex_error(tid, mutex,
1512 "unlock non-locked mutex", mutex->location);
1513 }
1514 if (mutex->tid != tid) {
1515 record_mutex_error(tid, mutex,
1516 "unlock someone else's mutex", mutex->location);
1517 }
1518 break;
1519
1520 case MxDead:
1521 break;
1522
1523 default:
1524 break;
1525 }
1526}
1527
1528/* Update a mutex state. Expects most error testing and reporting to
1529 have happened in test_mutex_state(). The assumption is that no
1530 client code is run by thread tid between test and set, either
1531 because it is blocked or test and set are called together
1532 atomically.
1533
1534 Setting state to MxDead is the exception, since that can happen as
1535 a result of any thread freeing memory; in this case set_mutex_state
1536 does all the error reporting as well.
1537*/
njn72718642003-07-24 08:45:32 +00001538static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001539{
1540 static const Bool debug = False;
1541
1542 if (debug)
1543 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1544 tid, mutex, mutex->mutexp, mutex->mutexp,
1545 pp_MutexState(mutex->state), pp_MutexState(state));
1546
1547 if (mutex->state == MxDead) {
1548 /* can't do anything legal to a destroyed mutex */
1549 return;
1550 }
1551
1552 switch(state) {
1553 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001554 if (mutex->state == MxLocked) {
1555 if (mutex->tid != tid)
1556 record_mutex_error(tid, mutex, "take lock held by someone else",
1557 mutex->location);
1558 else
1559 record_mutex_error(tid, mutex, "take lock we already hold",
1560 mutex->location);
1561
njn67993252004-11-22 18:02:32 +00001562 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001563 break;
1564 }
sewardjc26cc252002-10-23 21:58:55 +00001565
njnca82cc02004-11-22 17:18:48 +00001566 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001567
sewardjc26cc252002-10-23 21:58:55 +00001568 mutex->tid = tid;
1569 break;
1570
1571 case MxUnlocked:
1572 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001573 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001574
sewardjdca84112002-11-13 22:29:34 +00001575 if (mutex->state != MxLocked || mutex->tid != tid)
1576 break;
1577
sewardjc26cc252002-10-23 21:58:55 +00001578 mutex->tid = VG_INVALID_THREADID;
1579 break;
1580
sewardjdac0a442002-11-13 22:08:40 +00001581 case MxDead:
1582 if (mutex->state == MxLocked) {
1583 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001584 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001585 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1586 mutex->tid = VG_INVALID_THREADID;
1587
1588 record_mutex_error(tid, mutex,
1589 "free locked mutex", mutex->location);
1590 }
1591 break;
1592
sewardjc26cc252002-10-23 21:58:55 +00001593 default:
1594 break;
1595 }
1596
njnd01fef72005-03-25 23:35:48 +00001597 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001598 mutex->state = state;
1599}
njn25e49d8e72002-09-23 09:36:25 +00001600
1601/*------------------------------------------------------------*/
1602/*--- Setting and checking permissions. ---*/
1603/*------------------------------------------------------------*/
1604
thughes4ad52d02004-06-27 17:37:21 +00001605/* only clean up dead mutexes */
1606static
1607Bool cleanmx(Mutex *mx) {
1608 return mx->state == MxDead;
1609}
1610
njn25e49d8e72002-09-23 09:36:25 +00001611static
nethercote451eae92004-11-02 13:06:32 +00001612void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001613 VgeInitStatus status )
1614{
sewardj1806d7f2002-10-22 05:05:49 +00001615 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001616
1617# if DEBUG_MAKE_ACCESSES
1618 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1619# endif
1620 //PROF_EVENT(30); PPP
1621
1622 if (len == 0)
1623 return;
1624
1625 if (len > 100 * 1000 * 1000)
1626 VG_(message)(Vg_UserMsg,
1627 "Warning: set address range state: large range %d",
1628 len);
1629
njn31513b42005-06-01 03:09:59 +00001630 //VGP_PUSHCC(VgpSARP);
njn25e49d8e72002-09-23 09:36:25 +00001631
sewardjdac0a442002-11-13 22:08:40 +00001632 /* Remove mutexes in recycled memory range from hash */
1633 find_mutex_range(a, a+len, cleanmx);
1634
njn25e49d8e72002-09-23 09:36:25 +00001635 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1636 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1637 * len/4+1 words. This works out which it is by aligning the block and
1638 * seeing if the end byte is in the same word as it is for the unaligned
1639 * block; if not, it's the awkward case. */
njn13bfd852005-06-02 03:52:53 +00001640 end = VG_ROUNDUP(a + len, 4);
1641 a = VG_ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001642
1643 /* Do it ... */
1644 switch (status) {
1645 case Vge_VirginInit:
1646 for ( ; a < end; a += 4) {
1647 //PROF_EVENT(31); PPP
1648 init_virgin_sword(a);
1649 }
1650 break;
1651
1652 case Vge_NonVirginInit:
1653 for ( ; a < end; a += 4) {
1654 //PROF_EVENT(31); PPP
1655 init_nonvirgin_sword(a);
1656 }
1657 break;
1658
1659 case Vge_SegmentInit:
1660 for ( ; a < end; a += 4) {
1661 //PROF_EVENT(31); PPP
1662 init_magically_inited_sword(a);
1663 }
1664 break;
sewardj7f3ad222002-11-13 22:11:53 +00001665
1666 case Vge_Error:
1667 for ( ; a < end; a += 4) {
1668 //PROF_EVENT(31); PPP
1669 init_error_sword(a);
1670 }
1671 break;
njn25e49d8e72002-09-23 09:36:25 +00001672
1673 default:
1674 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001675 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001676 }
1677
njn31513b42005-06-01 03:09:59 +00001678 //VGP_POPCC(VgpSARP);
njn25e49d8e72002-09-23 09:36:25 +00001679}
1680
1681
nethercote451eae92004-11-02 13:06:32 +00001682static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001683{
1684 //PROF_EVENT(??); PPP
1685 set_address_range_state ( a, len, Vge_SegmentInit );
1686}
1687
nethercote451eae92004-11-02 13:06:32 +00001688static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001689{
1690 //PROF_EVENT(36); PPP
1691 set_address_range_state( a, len, Vge_VirginInit );
1692}
1693
nethercote451eae92004-11-02 13:06:32 +00001694static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001695{
1696 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001697 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001698}
1699
1700
njn25e49d8e72002-09-23 09:36:25 +00001701/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001702static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001703{
1704 UInt i;
1705
1706 //PROF_EVENT(40); PPP
1707 for (i = 0; i < len; i += 4) {
1708 shadow_word sword = *(get_sword_addr ( src+i ));
1709 //PROF_EVENT(41); PPP
1710 set_sword ( dst+i, sword );
1711 }
1712}
1713
1714// SSS: put these somewhere better
njnfbdcba92005-05-09 01:23:49 +00001715static void hg_mem_read (Addr a, SizeT data_size, ThreadId tid);
1716static void hg_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001717
njnadb7a752005-06-11 01:30:57 +00001718__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001719static void hg_mem_help_read_1(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001720__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001721static void hg_mem_help_read_2(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001722__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001723static void hg_mem_help_read_4(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001724__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001725static void hg_mem_help_read_N(Addr a, SizeT size) VG_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001726
njnadb7a752005-06-11 01:30:57 +00001727__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001728static void hg_mem_help_write_1(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001729__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001730static void hg_mem_help_write_2(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001731__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001732static void hg_mem_help_write_4(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001733__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001734static void hg_mem_help_write_N(Addr a, SizeT size) VG_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001735
njnadb7a752005-06-11 01:30:57 +00001736__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001737static void bus_lock(void);
njnadb7a752005-06-11 01:30:57 +00001738__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001739static void bus_unlock(void);
1740
njn25e49d8e72002-09-23 09:36:25 +00001741static
njnfbdcba92005-05-09 01:23:49 +00001742void hg_pre_mem_read(CorePart part, ThreadId tid,
1743 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001744{
njn02bc4b82005-05-15 17:28:26 +00001745 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 +00001746 hg_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001747}
1748
1749static
njnfbdcba92005-05-09 01:23:49 +00001750void hg_pre_mem_read_asciiz(CorePart part, ThreadId tid,
1751 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001752{
njnfbdcba92005-05-09 01:23:49 +00001753 hg_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001754}
1755
1756static
njnfbdcba92005-05-09 01:23:49 +00001757void hg_pre_mem_write(CorePart part, ThreadId tid,
1758 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001759{
njnfbdcba92005-05-09 01:23:49 +00001760 hg_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001761}
1762
1763
1764
1765static
njnfbdcba92005-05-09 01:23:49 +00001766void hg_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001767{
njn1f3a9092002-10-04 09:22:30 +00001768 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001769 make_segment_readable(a, len);
1770}
1771
1772
1773static
njnfbdcba92005-05-09 01:23:49 +00001774void hg_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001775{
1776 if (is_inited) {
1777 make_readable(a, len);
1778 } else {
1779 make_writable(a, len);
1780 }
1781}
1782
1783static
njnfbdcba92005-05-09 01:23:49 +00001784void hg_set_perms (Addr a, SizeT len,
1785 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001786{
1787 if (rr) make_readable(a, len);
1788 else if (ww) make_writable(a, len);
1789 /* else do nothing */
1790}
1791
sewardjf6374322002-11-13 22:35:55 +00001792static
njnfbdcba92005-05-09 01:23:49 +00001793void hg_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001794{
1795 set_address_range_state(a, len, Vge_NonVirginInit);
1796}
1797
1798static
njnfbdcba92005-05-09 01:23:49 +00001799void hg_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001800{
1801 set_address_range_state(a, len, Vge_VirginInit);
1802}
njn25e49d8e72002-09-23 09:36:25 +00001803
1804/*--------------------------------------------------------------*/
1805/*--- Initialise the memory audit system on program startup. ---*/
1806/*--------------------------------------------------------------*/
1807
1808static
1809void init_shadow_memory(void)
1810{
1811 Int i;
1812
1813 for (i = 0; i < ESEC_MAP_WORDS; i++)
1814 distinguished_secondary_map.swords[i] = virgin_sword;
1815
1816 /* These entries gradually get overwritten as the used address
1817 space expands. */
1818 for (i = 0; i < 65536; i++)
1819 primary_map[i] = &distinguished_secondary_map;
1820}
1821
1822
njn3e884182003-04-15 13:03:23 +00001823/*------------------------------------------------------------*/
1824/*--- malloc() et al replacements ---*/
1825/*------------------------------------------------------------*/
1826
njnb4aee052003-04-15 14:09:58 +00001827static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001828
1829#define N_FREED_CHUNKS 2
1830static Int freechunkptr = 0;
1831static HG_Chunk *freechunks[N_FREED_CHUNKS];
1832
njn3e884182003-04-15 13:03:23 +00001833
1834/* Allocate a user-chunk of size bytes. Also allocate its shadow
1835 block, make the shadow block point at the user block. Put the
1836 shadow chunk on the appropriate list, and set all memory
1837 protections correctly. */
1838
nethercote7ac7f7b2004-11-02 12:36:02 +00001839static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001840{
1841 HG_Chunk* hc;
1842
1843 hc = VG_(malloc)(sizeof(HG_Chunk));
1844 hc->data = p;
1845 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001846 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001847 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001848
1849 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1850}
1851
1852/* Allocate memory and note change in memory available */
1853static __inline__
njn14d01ce2004-11-26 11:30:14 +00001854void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1855 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001856{
1857 Addr p;
1858
njn34ac0272003-09-30 14:20:00 +00001859 if (size < 0) return NULL;
1860
njn3e884182003-04-15 13:03:23 +00001861 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001862 if (!p) {
1863 return NULL;
1864 }
njn34ac0272003-09-30 14:20:00 +00001865 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001866 add_HG_Chunk ( tid, p, size );
njnfbdcba92005-05-09 01:23:49 +00001867 hg_new_mem_heap( p, size, is_zeroed );
njn3e884182003-04-15 13:03:23 +00001868
1869 return (void*)p;
1870}
1871
njn51d827b2005-05-09 01:02:08 +00001872static void* hg_malloc ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001873{
njn14d01ce2004-11-26 11:30:14 +00001874 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001875}
1876
njn51d827b2005-05-09 01:02:08 +00001877static void* hg___builtin_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001878{
njn14d01ce2004-11-26 11:30:14 +00001879 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001880}
1881
njn51d827b2005-05-09 01:02:08 +00001882static void* hg___builtin_vec_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001883{
njn14d01ce2004-11-26 11:30:14 +00001884 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001885}
1886
njn51d827b2005-05-09 01:02:08 +00001887static void* hg_memalign ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001888{
njn14d01ce2004-11-26 11:30:14 +00001889 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001890}
1891
njn51d827b2005-05-09 01:02:08 +00001892static void* hg_calloc ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001893{
njn14d01ce2004-11-26 11:30:14 +00001894 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001895 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001896}
1897
thughes4ad52d02004-06-27 17:37:21 +00001898static ThreadId deadmx_tid;
1899
1900static
1901Bool deadmx(Mutex *mx) {
1902 if (mx->state != MxDead)
1903 set_mutex_state(mx, MxDead, deadmx_tid);
1904
1905 return False;
1906}
1907
njn3e884182003-04-15 13:03:23 +00001908static
njn72718642003-07-24 08:45:32 +00001909void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001910 HG_Chunk** prev_chunks_next_ptr )
1911{
njn72718642003-07-24 08:45:32 +00001912 Addr start = hc->data;
1913 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001914
njn3e884182003-04-15 13:03:23 +00001915 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1916 avoid repeating the hash table lookup. Can't remove until at least
1917 after free and free_mismatch errors are done because they use
1918 describe_addr() which looks for it in malloclist. */
1919 *prev_chunks_next_ptr = hc->next;
1920
1921 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001922 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001923
1924 /* maintain a small window so that the error reporting machinery
1925 knows about this memory */
1926 if (freechunks[freechunkptr] != NULL) {
1927 /* free HG_Chunk */
1928 HG_Chunk* sc1 = freechunks[freechunkptr];
1929 VG_(cli_free) ( (void*)(sc1->data) );
1930 VG_(free) ( sc1 );
1931 }
1932
1933 freechunks[freechunkptr] = hc;
1934
1935 if (++freechunkptr == N_FREED_CHUNKS)
1936 freechunkptr = 0;
1937
1938 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001939 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001940 find_mutex_range(start, end, deadmx);
1941}
1942
1943
1944static __inline__
njn14d01ce2004-11-26 11:30:14 +00001945void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001946{
1947 HG_Chunk* hc;
1948 HG_Chunk** prev_chunks_next_ptr;
1949
nethercote3d6b6112004-11-04 16:39:43 +00001950 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001951 (VgHashNode***)&prev_chunks_next_ptr );
1952 if (hc == NULL) {
1953 return;
1954 }
njn14d01ce2004-11-26 11:30:14 +00001955 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001956}
1957
njn51d827b2005-05-09 01:02:08 +00001958static void hg_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001959{
njn14d01ce2004-11-26 11:30:14 +00001960 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001961}
1962
njn51d827b2005-05-09 01:02:08 +00001963static void hg___builtin_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001964{
njn14d01ce2004-11-26 11:30:14 +00001965 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001966}
1967
njn51d827b2005-05-09 01:02:08 +00001968static void hg___builtin_vec_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001969{
njn14d01ce2004-11-26 11:30:14 +00001970 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001971}
1972
njn51d827b2005-05-09 01:02:08 +00001973static void* hg_realloc ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001974{
1975 HG_Chunk *hc;
1976 HG_Chunk **prev_chunks_next_ptr;
sewardj05bcdcb2003-05-18 10:05:38 +00001977 Int i;
njn3e884182003-04-15 13:03:23 +00001978
1979 /* First try and find the block. */
nethercote3d6b6112004-11-04 16:39:43 +00001980 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001981 (VgHashNode***)&prev_chunks_next_ptr );
1982
1983 if (hc == NULL) {
1984 return NULL;
1985 }
1986
1987 if (hc->size == new_size) {
1988 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001989 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001990 return p;
1991
1992 } else if (hc->size > new_size) {
1993 /* new size is smaller */
1994 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001995 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001996 return p;
1997
1998 } else {
1999 /* new size is bigger */
2000 Addr p_new;
2001
2002 /* Get new memory */
2003 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
2004
2005 /* First half kept and copied, second half new */
2006 copy_address_range_state( (Addr)p, p_new, hc->size );
njnfbdcba92005-05-09 01:23:49 +00002007 hg_new_mem_heap ( p_new+hc->size, new_size-hc->size,
2008 /*inited*/False );
njn3e884182003-04-15 13:03:23 +00002009
2010 /* Copy from old to new */
2011 for (i = 0; i < hc->size; i++)
2012 ((UChar*)p_new)[i] = ((UChar*)p)[i];
2013
2014 /* Free old memory */
njn72718642003-07-24 08:45:32 +00002015 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00002016
2017 /* this has to be after die_and_free_mem, otherwise the
2018 former succeeds in shorting out the new block, not the
2019 old, in the case when both are on the same list. */
njn72718642003-07-24 08:45:32 +00002020 add_HG_Chunk ( tid, p_new, new_size );
njn3e884182003-04-15 13:03:23 +00002021
2022 return (void*)p_new;
2023 }
2024}
2025
njn25e49d8e72002-09-23 09:36:25 +00002026/*--------------------------------------------------------------*/
2027/*--- Machinery to support sanity checking ---*/
2028/*--------------------------------------------------------------*/
2029
njn51d827b2005-05-09 01:02:08 +00002030static Bool hg_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00002031{
jseward9800fd32004-01-04 23:08:04 +00002032 /* nothing useful we can rapidly check */
2033 return True;
njn25e49d8e72002-09-23 09:36:25 +00002034}
2035
njn51d827b2005-05-09 01:02:08 +00002036static Bool hg_expensive_sanity_check(void)
njn25e49d8e72002-09-23 09:36:25 +00002037{
2038 Int i;
2039
2040 /* Make sure nobody changed the distinguished secondary. */
2041 for (i = 0; i < ESEC_MAP_WORDS; i++)
2042 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2043 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2044 return False;
2045
2046 return True;
2047}
2048
2049
2050/*--------------------------------------------------------------*/
2051/*--- Instrumentation ---*/
2052/*--------------------------------------------------------------*/
2053
sewardjf6374322002-11-13 22:35:55 +00002054static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2055
njn14d01ce2004-11-26 11:30:14 +00002056#if 0
njn25e49d8e72002-09-23 09:36:25 +00002057/* Create and return an instrumented version of cb_in. Free cb_in
2058 before returning. */
njn26f02512004-11-22 18:33:15 +00002059UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002060{
2061 UCodeBlock* cb;
2062 Int i;
2063 UInstr* u_in;
2064 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002065 Int ntemps;
2066 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002067 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002068
njn810086f2002-11-14 12:42:47 +00002069 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002070
sewardjf6374322002-11-13 22:35:55 +00002071 /* stackref[] is used for super-simple value tracking to keep note
2072 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002073 the stack pointer or frame pointer, and is therefore likely
2074 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002075 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002076 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2077 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2078
njn810086f2002-11-14 12:42:47 +00002079 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2080 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002081
njn25e49d8e72002-09-23 09:36:25 +00002082 switch (u_in->opcode) {
2083
2084 case NOP: case CALLM_S: case CALLM_E:
2085 break;
sewardjf6374322002-11-13 22:35:55 +00002086
sewardj7a5ebcf2002-11-13 22:42:13 +00002087 case LOCK:
2088 locked = True;
2089 uInstr0(cb, CCALL, 0);
2090 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2091 break;
2092
2093 case JMP: case INCEIP:
2094 if (locked) {
2095 uInstr0(cb, CCALL, 0);
2096 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2097 }
2098 locked = False;
2099 VG_(copy_UInstr)(cb, u_in);
2100 break;
2101
sewardjf6374322002-11-13 22:35:55 +00002102 case GET:
njnca82cc02004-11-22 17:18:48 +00002103 tl_assert(u_in->tag1 == ArchReg);
2104 tl_assert(u_in->tag2 == TempReg);
2105 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002106
2107 stackref[u_in->val2] = (u_in->size == 4 &&
njnaf839f52005-06-23 03:27:57 +00002108 (u_in->val1 == VG_R_STACK_PTR ||
2109 u_in->val1 == VG_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002110 VG_(copy_UInstr)(cb, u_in);
2111 break;
2112
2113 case MOV:
2114 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002115 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002116 stackref[u_in->val2] = stackref[u_in->val1];
2117 }
2118 VG_(copy_UInstr)(cb, u_in);
2119 break;
2120
2121 case LEA1:
2122 case ADD: case SUB:
2123 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002124 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002125 stackref[u_in->val2] |= stackref[u_in->val1];
2126 }
2127 VG_(copy_UInstr)(cb, u_in);
2128 break;
njn25e49d8e72002-09-23 09:36:25 +00002129
sewardja5b3aec2002-10-22 05:09:36 +00002130 case LOAD: {
2131 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002132 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2133 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002134
2135 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2136 nonstk_ld++;
2137
2138 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002139 case 1: help = hg_mem_help_read_1; break;
2140 case 2: help = hg_mem_help_read_2; break;
2141 case 4: help = hg_mem_help_read_4; break;
sewardjf6374322002-11-13 22:35:55 +00002142 default:
njn67993252004-11-22 18:02:32 +00002143 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002144 }
jsgfcb1d1c02003-10-14 21:55:10 +00002145
2146 /* XXX all registers should be flushed to baseblock
2147 here */
sewardjf6374322002-11-13 22:35:55 +00002148 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2149 uCCall(cb, (Addr)help, 1, 1, False);
2150 } else
2151 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002152
sewardja5b3aec2002-10-22 05:09:36 +00002153 VG_(copy_UInstr)(cb, u_in);
2154 t_size = INVALID_TEMPREG;
2155 break;
2156 }
2157
fitzhardinge111c6072004-03-09 02:45:07 +00002158 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002159 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002160 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002161 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002162
fitzhardinge111c6072004-03-09 02:45:07 +00002163 t_size = newTemp(cb);
2164 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2165 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002166
fitzhardinge111c6072004-03-09 02:45:07 +00002167 /* XXX all registers should be flushed to baseblock
2168 here */
2169 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002170 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002171
2172 VG_(copy_UInstr)(cb, u_in);
2173 t_size = INVALID_TEMPREG;
2174 break;
sewardja5b3aec2002-10-22 05:09:36 +00002175 }
2176
thughes96b466a2004-03-15 16:43:58 +00002177 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002178 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002179
2180 t_size = newTemp(cb);
2181 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2182 uLiteral(cb, (UInt)u_in->size);
2183
2184 /* XXX all registers should be flushed to baseblock
2185 here */
2186 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002187 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
thughes96b466a2004-03-15 16:43:58 +00002188
2189 VG_(copy_UInstr)(cb, u_in);
2190 t_size = INVALID_TEMPREG;
2191 break;
2192 }
2193
fitzhardinge111c6072004-03-09 02:45:07 +00002194 case SSE2a_MemRd:
2195 case SSE2a1_MemRd:
2196 case SSE3a_MemRd:
2197 case SSE3a1_MemRd:
2198 case SSE3ag_MemRd_RegWr: {
2199 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2200
njnca82cc02004-11-22 17:18:48 +00002201 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002202
2203 t_size = newTemp(cb);
2204 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2205 uLiteral(cb, (UInt)u_in->size);
2206
2207 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002208 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002209
2210 VG_(copy_UInstr)(cb, u_in);
2211 t_size = INVALID_TEMPREG;
2212 break;
2213 }
2214
sewardja5b3aec2002-10-22 05:09:36 +00002215 case STORE: {
2216 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002217 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2218 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002219
sewardjf6374322002-11-13 22:35:55 +00002220 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2221 nonstk_st++;
2222
2223 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002224 case 1: help = hg_mem_help_write_1; break;
2225 case 2: help = hg_mem_help_write_2; break;
2226 case 4: help = hg_mem_help_write_4; break;
sewardjf6374322002-11-13 22:35:55 +00002227 default:
njn67993252004-11-22 18:02:32 +00002228 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002229 }
2230
jsgfcb1d1c02003-10-14 21:55:10 +00002231 /* XXX all registers should be flushed to baseblock
2232 here */
sewardjf6374322002-11-13 22:35:55 +00002233 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2234 uCCall(cb, (Addr)help, 2, 2, False);
2235 } else
2236 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002237
2238 VG_(copy_UInstr)(cb, u_in);
2239 t_size = INVALID_TEMPREG;
2240 break;
2241 }
2242
fitzhardinge111c6072004-03-09 02:45:07 +00002243 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002244 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002245 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002246 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002247
2248 t_size = newTemp(cb);
2249 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2250 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002251 /* XXX all registers should be flushed to baseblock
2252 here */
sewardja5b3aec2002-10-22 05:09:36 +00002253 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002254 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
sewardja5b3aec2002-10-22 05:09:36 +00002255
2256 VG_(copy_UInstr)(cb, u_in);
2257 t_size = INVALID_TEMPREG;
2258 break;
2259 }
njn25e49d8e72002-09-23 09:36:25 +00002260
fitzhardinge111c6072004-03-09 02:45:07 +00002261 case SSE2a_MemWr:
2262 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002263 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002264 512 == u_in->size);
2265
2266 t_size = newTemp(cb);
2267 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2268 uLiteral(cb, (UInt)u_in->size);
2269 /* XXX all registers should be flushed to baseblock
2270 here */
2271 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002272 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002273
2274 VG_(copy_UInstr)(cb, u_in);
2275 t_size = INVALID_TEMPREG;
2276 break;
2277 }
sewardj3d7c9c82003-03-26 21:08:13 +00002278
njn25e49d8e72002-09-23 09:36:25 +00002279 default:
sewardjf6374322002-11-13 22:35:55 +00002280 /* conservative tromping */
2281 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2282 stackref[u_in->val1] = False;
2283 if (u_in->tag2 == TempReg)
2284 stackref[u_in->val2] = False;
2285 if (u_in->tag3 == TempReg)
2286 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002287 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002288 break;
2289 }
2290 }
2291
sewardjf6374322002-11-13 22:35:55 +00002292 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002293 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002294 return cb;
2295}
njn14d01ce2004-11-26 11:30:14 +00002296#endif
njn51d827b2005-05-09 01:02:08 +00002297static IRBB* hg_instrument ( IRBB* bb_in, VexGuestLayout* layout,
2298 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002299{
njn5db32122005-08-12 15:23:57 +00002300 tl_assert(0); // Need to convert to Vex
njn14d01ce2004-11-26 11:30:14 +00002301}
njn25e49d8e72002-09-23 09:36:25 +00002302
2303/*--------------------------------------------------------------------*/
2304/*--- Error and suppression handling ---*/
2305/*--------------------------------------------------------------------*/
2306
2307typedef
2308 enum {
2309 /* Possible data race */
njnfbdcba92005-05-09 01:23:49 +00002310 RaceSupp
njn25e49d8e72002-09-23 09:36:25 +00002311 }
njnfbdcba92005-05-09 01:23:49 +00002312 RaceSuppKind;
njn25e49d8e72002-09-23 09:36:25 +00002313
2314/* What kind of error it is. */
2315typedef
2316 enum {
njnfbdcba92005-05-09 01:23:49 +00002317 RaceErr, /* data-race */
sewardj16748af2002-10-22 04:55:54 +00002318 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002319 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002320 }
njnfbdcba92005-05-09 01:23:49 +00002321 RaceErrorKind;
njn25e49d8e72002-09-23 09:36:25 +00002322
sewardj16748af2002-10-22 04:55:54 +00002323/* The classification of a faulting address. */
2324typedef
2325 enum { Undescribed, /* as-yet unclassified */
2326 Stack,
2327 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002328 Mallocd,
2329 Freed,
sewardj16748af2002-10-22 04:55:54 +00002330 Segment
2331 }
2332 AddrKind;
2333/* Records info about a faulting address. */
2334typedef
2335 struct {
2336 /* ALL */
2337 AddrKind akind;
2338 /* Freed, Mallocd */
2339 Int blksize;
2340 /* Freed, Mallocd */
2341 Int rwoffset;
2342 /* Freed, Mallocd */
2343 ExeContext* lastchange;
2344 ThreadId lasttid;
2345 /* Stack */
2346 ThreadId stack_tid;
2347 /* Segment */
2348 const Char* filename;
2349 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002350 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002351 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002352 /* symbolic address description */
2353 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002354 }
2355 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002356
sewardj16748af2002-10-22 04:55:54 +00002357/* What kind of memory access is involved in the error? */
2358typedef
2359 enum { ReadAxs, WriteAxs, ExecAxs }
2360 AxsKind;
2361
2362/* Extra context for memory errors */
2363typedef
2364 struct {
2365 AxsKind axskind;
2366 Int size;
2367 AddrInfo addrinfo;
2368 Bool isWrite;
2369 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002370 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002371 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002372 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002373 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002374 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002375 const LockSet *held_lockset;
2376 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002377 }
2378 HelgrindError;
2379
2380static __inline__
2381void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002382{
sewardj16748af2002-10-22 04:55:54 +00002383 ai->akind = Unknown;
2384 ai->blksize = 0;
2385 ai->rwoffset = 0;
2386 ai->lastchange = NULL;
2387 ai->lasttid = VG_INVALID_THREADID;
2388 ai->filename = NULL;
2389 ai->section = "???";
2390 ai->stack_tid = VG_INVALID_THREADID;
2391 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002392 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002393}
2394
sewardj16748af2002-10-22 04:55:54 +00002395static __inline__
2396void clear_HelgrindError ( HelgrindError* err_extra )
2397{
2398 err_extra->axskind = ReadAxs;
2399 err_extra->size = 0;
2400 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002401 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002402 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002403 err_extra->prev_lockset = 0;
2404 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002405 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002406 clear_AddrInfo ( &err_extra->addrinfo );
2407 err_extra->isWrite = False;
2408}
2409
2410
2411
2412/* Describe an address as best you can, for error messages,
2413 putting the result in ai. */
2414
thughes4ad52d02004-06-27 17:37:21 +00002415/* Callback for searching malloc'd and free'd lists */
2416static Bool addr_is_in_block(VgHashNode *node, void *ap)
2417{
2418 HG_Chunk* hc2 = (HG_Chunk*)node;
2419 Addr a = *(Addr *)ap;
2420
2421 return (hc2->data <= a && a < hc2->data + hc2->size);
2422}
2423
sewardj16748af2002-10-22 04:55:54 +00002424static void describe_addr ( Addr a, AddrInfo* ai )
2425{
njn3e884182003-04-15 13:03:23 +00002426 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002427 Int i;
sewardj16748af2002-10-22 04:55:54 +00002428
sewardj16748af2002-10-22 04:55:54 +00002429 /* Search for it in segments */
2430 {
njn36ef6ba2005-05-14 18:42:26 +00002431 const SegInfo *si;
sewardj16748af2002-10-22 04:55:54 +00002432
njn36ef6ba2005-05-14 18:42:26 +00002433 for (si = VG_(next_seginfo)(NULL);
2434 si != NULL;
2435 si = VG_(next_seginfo)(si))
2436 {
njnd9e5fd72005-06-25 19:51:33 +00002437 Addr base = VG_(seginfo_start)(si);
2438 SizeT size = VG_(seginfo_size)(si);
2439 const UChar *filename = VG_(seginfo_filename)(si);
sewardj16748af2002-10-22 04:55:54 +00002440
2441 if (a >= base && a < base+size) {
2442 ai->akind = Segment;
2443 ai->blksize = size;
2444 ai->rwoffset = a - base;
2445 ai->filename = filename;
2446
njnd9e5fd72005-06-25 19:51:33 +00002447 switch(VG_(seginfo_sect_kind)(a)) {
sewardj16748af2002-10-22 04:55:54 +00002448 case Vg_SectText: ai->section = "text"; break;
2449 case Vg_SectData: ai->section = "data"; break;
2450 case Vg_SectBSS: ai->section = "BSS"; break;
2451 case Vg_SectGOT: ai->section = "GOT"; break;
2452 case Vg_SectPLT: ai->section = "PLT"; break;
2453 case Vg_SectUnknown:
2454 default:
2455 ai->section = "???"; break;
2456 }
2457
2458 return;
2459 }
2460 }
2461 }
2462
2463 /* Search for a currently malloc'd block which might bracket it. */
thughes4ad52d02004-06-27 17:37:21 +00002464 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
njn3e884182003-04-15 13:03:23 +00002465 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002466 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002467 ai->blksize = hc->size;
2468 ai->rwoffset = (Int)a - (Int)(hc->data);
2469 ai->lastchange = hc->where;
2470 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002471 return;
2472 }
sewardjdac0a442002-11-13 22:08:40 +00002473
2474 /* Look in recently freed memory */
2475 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002476 hc = freechunks[i];
2477 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002478 continue;
2479
njn3e884182003-04-15 13:03:23 +00002480 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002481 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002482 ai->blksize = hc->size;
2483 ai->rwoffset = a - hc->data;
2484 ai->lastchange = hc->where;
2485 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002486 return;
2487 }
2488 }
2489
sewardj16748af2002-10-22 04:55:54 +00002490 /* Clueless ... */
2491 ai->akind = Unknown;
2492 return;
2493}
2494
2495
njn7e614812003-04-21 22:04:03 +00002496/* Updates the copy with address info if necessary. */
njn51d827b2005-05-09 01:02:08 +00002497static UInt hg_update_extra(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002498{
njn7e614812003-04-21 22:04:03 +00002499 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002500
njn7e614812003-04-21 22:04:03 +00002501 extra = (HelgrindError*)VG_(get_error_extra)(err);
2502 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2503 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2504 }
2505 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002506}
2507
njnfbdcba92005-05-09 01:23:49 +00002508static void record_race_error ( ThreadId tid, Addr a, Bool is_write,
2509 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002510{
sewardjc4a810d2002-11-13 22:25:51 +00002511 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002512 HelgrindError err_extra;
2513
njnfbdcba92005-05-09 01:23:49 +00002514 n_hg_warnings++;
sewardjff2c9232002-11-13 21:44:39 +00002515
sewardj16748af2002-10-22 04:55:54 +00002516 clear_HelgrindError(&err_extra);
2517 err_extra.isWrite = is_write;
2518 err_extra.addrinfo.akind = Undescribed;
2519 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002520 if (clo_execontext)
2521 err_extra.lasttouched = getExeContext(a);
jsgfcb1d1c02003-10-14 21:55:10 +00002522 err_extra.addrinfo.expr = VG_(describe_addr)(tid, a);
2523
njnfbdcba92005-05-09 01:23:49 +00002524 VG_(maybe_record_error)( tid, RaceErr, a,
sewardj16748af2002-10-22 04:55:54 +00002525 (is_write ? "writing" : "reading"),
2526 &err_extra);
2527
sewardjc4a810d2002-11-13 22:25:51 +00002528 sw = get_sword_addr(a);
2529 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2530 ThreadLifeSeg *tls = unpackTLS(sw->other);
2531 tls->refcount--;
2532 }
2533
sewardj7f3ad222002-11-13 22:11:53 +00002534 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002535}
2536
sewardj39a4d842002-11-13 22:14:30 +00002537static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002538 Char *str, ExeContext *ec)
2539{
2540 HelgrindError err_extra;
2541
2542 clear_HelgrindError(&err_extra);
2543 err_extra.addrinfo.akind = Undescribed;
2544 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002545 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002546 err_extra.lasttid = tid;
2547
njn72718642003-07-24 08:45:32 +00002548 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002549 (Addr)mutex->mutexp, str, &err_extra);
2550}
njn25e49d8e72002-09-23 09:36:25 +00002551
sewardj39a4d842002-11-13 22:14:30 +00002552static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002553 const LockSet *lockset_holding,
2554 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002555{
2556 HelgrindError err_extra;
2557
2558 n_lockorder_warnings++;
2559
2560 clear_HelgrindError(&err_extra);
2561 err_extra.addrinfo.akind = Undescribed;
2562 err_extra.mutex = mutex;
2563
sewardjc808ef52002-11-13 22:43:26 +00002564 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002565 err_extra.held_lockset = lockset_holding;
2566 err_extra.prev_lockset = lockset_prev;
2567
njn72718642003-07-24 08:45:32 +00002568 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002569}
2570
njn51d827b2005-05-09 01:02:08 +00002571static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002572{
njn810086f2002-11-14 12:42:47 +00002573 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002574
njnca82cc02004-11-22 17:18:48 +00002575 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002576
2577 switch (VG_(get_error_kind)(e1)) {
njnfbdcba92005-05-09 01:23:49 +00002578 case RaceErr:
njn810086f2002-11-14 12:42:47 +00002579 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002580
2581 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002582 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002583 }
2584
njn810086f2002-11-14 12:42:47 +00002585 e1s = VG_(get_error_string)(e1);
2586 e2s = VG_(get_error_string)(e2);
2587 if (e1s != e2s) return False;
2588 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002589 return True;
2590}
2591
sewardj16748af2002-10-22 04:55:54 +00002592static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002593{
jsgfcb1d1c02003-10-14 21:55:10 +00002594 if (ai->expr != NULL)
2595 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002596 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002597
sewardj16748af2002-10-22 04:55:54 +00002598 switch (ai->akind) {
2599 case Stack:
2600 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002601 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002602 a, ai->stack_tid);
2603 break;
2604 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002605 if (ai->expr != NULL)
2606 break;
2607
nethercote3b390c72003-11-13 17:53:43 +00002608 /* maybe_gcc is never set to True! This is a hangover from code
2609 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002610 if (ai->maybe_gcc) {
2611 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002612 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002613 a);
2614 VG_(message)(Vg_UserMsg,
2615 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2616 } else {
2617 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002618 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002619 }
2620 break;
2621 case Segment:
2622 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002623 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002624 a, ai->section, ai->filename);
2625 break;
sewardjdac0a442002-11-13 22:08:40 +00002626 case Mallocd:
2627 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002628 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002629 UChar* relative;
2630 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002631 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002632 relative = "before";
2633 } else if (ai->rwoffset >= ai->blksize) {
2634 delta = ai->rwoffset - ai->blksize;
2635 relative = "after";
2636 } else {
2637 delta = ai->rwoffset;
2638 relative = "inside";
2639 }
2640 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002641 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2642 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002643 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002644 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002645 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002646
sewardj16748af2002-10-22 04:55:54 +00002647 VG_(pp_ExeContext)(ai->lastchange);
2648 break;
2649 }
2650 default:
njn67993252004-11-22 18:02:32 +00002651 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002652 }
njn25e49d8e72002-09-23 09:36:25 +00002653}
2654
sewardj4bffb232002-11-13 21:46:34 +00002655static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002656{
sewardjff2c9232002-11-13 21:44:39 +00002657 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002658 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002659
sewardj4bffb232002-11-13 21:46:34 +00002660 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2661 lockset->setsize * 120 +
2662 1);
sewardjff2c9232002-11-13 21:44:39 +00002663
2664 cp = buf;
2665 if (prefix)
2666 cp += VG_(sprintf)(cp, "%s", prefix);
2667
sewardj4bffb232002-11-13 21:46:34 +00002668 for(i = 0; i < lockset->setsize; i++)
2669 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2670 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002671
sewardj4bffb232002-11-13 21:46:34 +00002672 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002673 cp[-2] = '\0';
2674 else
2675 *cp = '\0';
2676
2677 return buf;
2678}
njn25e49d8e72002-09-23 09:36:25 +00002679
njn51d827b2005-05-09 01:02:08 +00002680static void hg_pp_Error ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002681{
njn810086f2002-11-14 12:42:47 +00002682 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002683 Char buf[100];
2684 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002685 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002686
2687 *msg = '\0';
2688
njn810086f2002-11-14 12:42:47 +00002689 switch(VG_(get_error_kind)(err)) {
njnfbdcba92005-05-09 01:23:49 +00002690 case RaceErr: {
njn810086f2002-11-14 12:42:47 +00002691 Addr err_addr = VG_(get_error_address)(err);
2692
sewardj16748af2002-10-22 04:55:54 +00002693 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002694 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002695 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002696 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002697
2698 switch(extra->prevstate.state) {
2699 case Vge_Virgin:
2700 /* shouldn't be possible to go directly from virgin -> error */
2701 VG_(sprintf)(buf, "virgin!?");
2702 break;
2703
sewardjc4a810d2002-11-13 22:25:51 +00002704 case Vge_Excl: {
2705 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2706
njnca82cc02004-11-22 17:18:48 +00002707 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002708 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002709 break;
sewardjc4a810d2002-11-13 22:25:51 +00002710 }
sewardj16748af2002-10-22 04:55:54 +00002711
2712 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002713 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002714 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002715
2716 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002717 VG_(sprintf)(buf, "shared %s, no locks",
2718 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2719 break;
2720 }
2721
sewardjff2c9232002-11-13 21:44:39 +00002722 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2723 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002724 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002725
sewardj16748af2002-10-22 04:55:54 +00002726 break;
2727 }
sewardj16748af2002-10-22 04:55:54 +00002728
sewardj499e3de2002-11-13 22:22:25 +00002729 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002730 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002731
sewardj72baa7a2002-12-09 23:32:58 +00002732 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002733 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002734 Char file[100];
2735 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002736 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002737
nethercote3b390c72003-11-13 17:53:43 +00002738 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002739 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002740 pp_state(extra->lasttouched.state),
2741 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002742
sewardj7cee6f92005-06-13 17:39:06 +00002743 if (VG_(get_filename_linenum)(ip, file, sizeof(file),
2744 NULL, 0, NULL, &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002745 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002746 ip, ip, file, line);
2747 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002748 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002749 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002750 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002751 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002752 }
sewardj72baa7a2002-12-09 23:32:58 +00002753 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002754 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002755 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002756 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002757 pp_state(extra->lasttouched.state),
2758 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002759 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002760 }
sewardj16748af2002-10-22 04:55:54 +00002761 break;
njn810086f2002-11-14 12:42:47 +00002762 }
sewardj16748af2002-10-22 04:55:54 +00002763
2764 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002765 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002766 VG_(get_error_address)(err),
2767 VG_(get_error_address)(err),
2768 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002769 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002770 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002771 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002772 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002773 }
njn810086f2002-11-14 12:42:47 +00002774 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002775 break;
sewardjff2c9232002-11-13 21:44:39 +00002776
2777 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002778 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002779 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002780 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002781
2782 msg = lockset_str(NULL, heldset);
2783
2784 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002785 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002786 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002787 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2788
sewardj4bffb232002-11-13 21:46:34 +00002789 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002790 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002791
sewardj542494b2002-11-13 22:46:13 +00002792 /* needs to be a recursive search+display */
2793 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002794 continue;
2795
nethercote3b390c72003-11-13 17:53:43 +00002796 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002797 lsmx->mutexp, lsmx->mutexp);
2798 VG_(pp_ExeContext)(lsmx->location);
2799 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002800 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002801 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002802 }
2803
2804 break;
sewardj16748af2002-10-22 04:55:54 +00002805 }
sewardjff2c9232002-11-13 21:44:39 +00002806 }
2807
2808 if (msg != buf)
2809 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002810}
2811
2812
njn51d827b2005-05-09 01:02:08 +00002813static Bool hg_recognised_suppression ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002814{
2815 if (0 == VG_(strcmp)(name, "Eraser")) {
njnfbdcba92005-05-09 01:23:49 +00002816 VG_(set_supp_kind)(su, RaceSupp);
njn25e49d8e72002-09-23 09:36:25 +00002817 return True;
2818 } else {
2819 return False;
2820 }
2821}
2822
2823
njn51d827b2005-05-09 01:02:08 +00002824static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002825{
2826 /* do nothing -- no extra suppression info present. Return True to
2827 indicate nothing bad happened. */
2828 return True;
2829}
2830
2831
njn51d827b2005-05-09 01:02:08 +00002832static Bool hg_error_matches_suppression(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002833{
njnfbdcba92005-05-09 01:23:49 +00002834 tl_assert(VG_(get_supp_kind)(su) == RaceSupp);
nethercote64366b42003-12-01 13:11:47 +00002835
njnfbdcba92005-05-09 01:23:49 +00002836 return (VG_(get_error_kind)(err) == RaceErr);
njn25e49d8e72002-09-23 09:36:25 +00002837}
2838
njn51d827b2005-05-09 01:02:08 +00002839static Char* hg_get_error_name ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002840{
njnfbdcba92005-05-09 01:23:49 +00002841 if (RaceErr == VG_(get_error_kind)(err)) {
2842 return "Eraser"; // old name, required for backwards compatibility
njn43c799e2003-04-08 00:08:52 +00002843 } else {
2844 return NULL; /* Other errors types can't be suppressed */
2845 }
2846}
2847
njn51d827b2005-05-09 01:02:08 +00002848static void hg_print_extra_suppression_info ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002849{
2850 /* Do nothing */
2851}
njn25e49d8e72002-09-23 09:36:25 +00002852
njnfbdcba92005-05-09 01:23:49 +00002853static void hg_pre_mutex_lock(ThreadId tid, void* void_mutex)
sewardjdca84112002-11-13 22:29:34 +00002854{
2855 Mutex *mutex = get_mutex((Addr)void_mutex);
2856
njn72718642003-07-24 08:45:32 +00002857 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002858}
2859
njnfbdcba92005-05-09 01:23:49 +00002860static void hg_post_mutex_lock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002861{
sewardj4bffb232002-11-13 21:46:34 +00002862 static const Bool debug = False;
sewardj39a4d842002-11-13 22:14:30 +00002863 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002864 const LockSet* ls;
2865
njn72718642003-07-24 08:45:32 +00002866 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002867
njn25e49d8e72002-09-23 09:36:25 +00002868# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002869 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002870# endif
2871
njn25e49d8e72002-09-23 09:36:25 +00002872 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2873# if LOCKSET_SANITY > 1
njnfbdcba92005-05-09 01:23:49 +00002874 sanity_check_locksets("hg_post_mutex_lock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002875# endif
2876
sewardj4bffb232002-11-13 21:46:34 +00002877 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002878
sewardj4bffb232002-11-13 21:46:34 +00002879 if (ls == NULL) {
2880 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2881 insert_LockSet(newset);
2882 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002883 }
sewardj4bffb232002-11-13 21:46:34 +00002884 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002885
sewardj4bffb232002-11-13 21:46:34 +00002886 if (debug || DEBUG_LOCKS)
2887 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002888
sewardj4bffb232002-11-13 21:46:34 +00002889 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002890 sanity_check_locksets("hg_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002891}
2892
2893
njnfbdcba92005-05-09 01:23:49 +00002894static void hg_post_mutex_unlock(ThreadId tid, void* void_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002895{
sewardjc26cc252002-10-23 21:58:55 +00002896 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002897 Int i = 0;
sewardj39a4d842002-11-13 22:14:30 +00002898 Mutex *mutex = get_mutex((Addr)void_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002899 const LockSet *ls;
2900
njn72718642003-07-24 08:45:32 +00002901 test_mutex_state(mutex, MxUnlocked, tid);
2902 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002903
sewardjdac0a442002-11-13 22:08:40 +00002904 if (!ismember(thread_locks[tid], mutex))
2905 return;
2906
sewardjc26cc252002-10-23 21:58:55 +00002907 if (debug || DEBUG_LOCKS)
2908 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002909
sewardjc26cc252002-10-23 21:58:55 +00002910 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002911 sanity_check_locksets("hg_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002912
sewardj4bffb232002-11-13 21:46:34 +00002913 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002914
sewardj4bffb232002-11-13 21:46:34 +00002915 if (ls == NULL) {
2916 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2917 insert_LockSet(newset);
2918 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002919 }
2920
2921 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002922 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002923 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002924 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002925
sewardj4bffb232002-11-13 21:46:34 +00002926 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002927
sewardjc26cc252002-10-23 21:58:55 +00002928 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002929 sanity_check_locksets("hg_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002930}
2931
2932
2933/* ---------------------------------------------------------------------
2934 Checking memory reads and writes
2935 ------------------------------------------------------------------ */
2936
2937/* Behaviour on reads and writes:
2938 *
2939 * VIR EXCL SHAR SH_MOD
2940 * ----------------------------------------------------------------
2941 * rd/wr, 1st thread | - EXCL - -
2942 * rd, new thread | - SHAR - -
2943 * wr, new thread | - SH_MOD - -
2944 * rd | error! - SHAR SH_MOD
2945 * wr | EXCL - SH_MOD SH_MOD
2946 * ----------------------------------------------------------------
2947 */
2948
sewardj8fac99a2002-11-13 22:31:26 +00002949static inline
njn25e49d8e72002-09-23 09:36:25 +00002950void dump_around_a(Addr a)
2951{
2952 UInt i;
2953 shadow_word* sword;
2954 VG_(printf)("NEARBY:\n");
2955 for (i = a - 12; i <= a + 12; i += 4) {
2956 sword = get_sword_addr(i);
2957 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2958 }
2959}
njn25e49d8e72002-09-23 09:36:25 +00002960
2961#if DEBUG_ACCESSES
2962 #define DEBUG_STATE(args...) \
2963 VG_(printf)("(%u) ", size), \
2964 VG_(printf)(args)
2965#else
2966 #define DEBUG_STATE(args...)
2967#endif
2968
njnfbdcba92005-05-09 01:23:49 +00002969static void hg_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002970{
sewardj72baa7a2002-12-09 23:32:58 +00002971 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002972 shadow_word prevstate;
2973 ThreadLifeSeg *tls;
2974 const LockSet *ls;
2975 Bool statechange = False;
2976
2977 static const void *const states[4] = {
2978 [Vge_Virgin] &&st_virgin,
2979 [Vge_Excl] &&st_excl,
2980 [Vge_Shar] &&st_shar,
2981 [Vge_SharMod] &&st_sharmod,
2982 };
2983
2984 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002985 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00002986
2987 sword = get_sword_addr(a);
2988 if (sword == SEC_MAP_ACCESS) {
2989 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
2990 return;
2991 }
2992
2993 prevstate = *sword;
2994
2995 goto *states[sword->state];
2996
2997 /* This looks like reading of unitialised memory, may be legit. Eg.
2998 * calloc() zeroes its values, so untouched memory may actually be
2999 * initialised. Leave that stuff to Valgrind. */
3000 st_virgin:
3001 if (TID_INDICATING_NONVIRGIN == sword->other) {
3002 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
3003 if (DEBUG_VIRGIN_READS)
3004 dump_around_a(a);
3005 } else {
3006 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
3007 }
3008 statechange = True;
3009 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
3010 tls->refcount++;
3011 goto done;
3012
3013 st_excl: {
3014 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3015
3016 if (tls == sw_tls) {
3017 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
3018 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3019 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
3020 } else if (tlsIsDisjoint(tls, sw_tls)) {
3021 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3022 statechange = True;
3023 sword->other = packTLS(tls);
3024 sw_tls->refcount--;
3025 tls->refcount++;
3026 } else {
3027 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3028 sw_tls->refcount--;
3029 statechange = True;
3030 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3031
3032 if (DEBUG_MEM_LOCKSET_CHANGES)
3033 print_LockSet("excl read locks", unpackLockSet(sword->other));
3034 }
3035 goto done;
3036 }
3037
3038 st_shar:
3039 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3040 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3041 thread_locks[tid]));
3042 statechange = sword->other != prevstate.other;
3043 goto done;
3044
3045 st_sharmod:
3046 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3047 ls = intersect(unpackLockSet(sword->other),
3048 thread_locks[tid]);
3049 sword->other = packLockSet(ls);
3050
3051 statechange = sword->other != prevstate.other;
3052
3053 if (isempty(ls)) {
njnfbdcba92005-05-09 01:23:49 +00003054 record_race_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003055 }
3056 goto done;
3057
3058 done:
3059 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003060 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003061
3062 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003063 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003064 else
njnd01fef72005-03-25 23:35:48 +00003065 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003066 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003067 }
3068}
njn25e49d8e72002-09-23 09:36:25 +00003069
njnfbdcba92005-05-09 01:23:49 +00003070static void hg_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003071{
njn72718642003-07-24 08:45:32 +00003072 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003073
njn13bfd852005-06-02 03:52:53 +00003074 end = VG_ROUNDUP(a+size, 4);
3075 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003076
sewardj18cd4a52002-11-13 22:37:41 +00003077 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003078 hg_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003079}
3080
njnfbdcba92005-05-09 01:23:49 +00003081static void hg_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003082{
3083 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003084 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003085 shadow_word prevstate;
3086 Bool statechange = False;
3087 static const void *const states[4] = {
3088 [Vge_Virgin] &&st_virgin,
3089 [Vge_Excl] &&st_excl,
3090 [Vge_Shar] &&st_shar,
3091 [Vge_SharMod] &&st_sharmod,
3092 };
3093
sewardjc4a810d2002-11-13 22:25:51 +00003094 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003095 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003096
sewardj18cd4a52002-11-13 22:37:41 +00003097 sword = get_sword_addr(a);
3098 if (sword == SEC_MAP_ACCESS) {
3099 VG_(printf)("read distinguished 2ndary map! 0x%x\n", a);
3100 return;
3101 }
njn25e49d8e72002-09-23 09:36:25 +00003102
sewardj18cd4a52002-11-13 22:37:41 +00003103 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003104
sewardj18cd4a52002-11-13 22:37:41 +00003105 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003106
sewardj18cd4a52002-11-13 22:37:41 +00003107 st_virgin:
3108 if (TID_INDICATING_NONVIRGIN == sword->other)
3109 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3110 else
3111 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3112 statechange = True;
3113 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3114 tls->refcount++;
3115 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003116
sewardj18cd4a52002-11-13 22:37:41 +00003117 st_excl: {
3118 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3119
3120 if (tls == sw_tls) {
3121 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3122 goto done;
3123 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3124 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3125 goto done;
3126 } else if (tlsIsDisjoint(tls, sw_tls)) {
3127 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3128 sword->other = packTLS(tls);
3129 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003130 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003131 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003132 } else {
3133 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3134 statechange = True;
3135 sw_tls->refcount--;
3136 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3137 if(DEBUG_MEM_LOCKSET_CHANGES)
3138 print_LockSet("excl write locks", unpackLockSet(sword->other));
3139 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003140 }
sewardj18cd4a52002-11-13 22:37:41 +00003141 }
njn25e49d8e72002-09-23 09:36:25 +00003142
sewardj18cd4a52002-11-13 22:37:41 +00003143 st_shar:
3144 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3145 sword->state = Vge_SharMod;
3146 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3147 thread_locks[tid]));
3148 statechange = True;
3149 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003150
sewardj18cd4a52002-11-13 22:37:41 +00003151 st_sharmod:
3152 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3153 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3154 thread_locks[tid]));
3155 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003156
sewardj18cd4a52002-11-13 22:37:41 +00003157 SHARED_MODIFIED:
3158 if (isempty(unpackLockSet(sword->other))) {
njnfbdcba92005-05-09 01:23:49 +00003159 record_race_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003160 }
3161 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003162
sewardj18cd4a52002-11-13 22:37:41 +00003163 done:
3164 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003165 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003166
sewardj18cd4a52002-11-13 22:37:41 +00003167 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003168 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003169 else
njnd01fef72005-03-25 23:35:48 +00003170 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003171 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003172 }
3173}
3174
njnfbdcba92005-05-09 01:23:49 +00003175static void hg_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003176{
sewardj8fac99a2002-11-13 22:31:26 +00003177 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003178
njn13bfd852005-06-02 03:52:53 +00003179 end = VG_ROUNDUP(a+size, 4);
3180 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003181
sewardj18cd4a52002-11-13 22:37:41 +00003182 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003183 hg_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003184}
3185
3186#undef DEBUG_STATE
3187
njnaf839f52005-06-23 03:27:57 +00003188VG_REGPARM(1) static void hg_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003189{
njnfbdcba92005-05-09 01:23:49 +00003190 hg_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003191}
3192
njnaf839f52005-06-23 03:27:57 +00003193VG_REGPARM(1) static void hg_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003194{
njnfbdcba92005-05-09 01:23:49 +00003195 hg_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003196}
3197
njnaf839f52005-06-23 03:27:57 +00003198VG_REGPARM(1) static void hg_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003199{
njnfbdcba92005-05-09 01:23:49 +00003200 hg_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003201}
3202
njnaf839f52005-06-23 03:27:57 +00003203VG_REGPARM(2) static void hg_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003204{
njnfbdcba92005-05-09 01:23:49 +00003205 hg_mem_read(a, size, 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_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003209{
3210 if (*(UChar *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003211 hg_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003212}
njnaf839f52005-06-23 03:27:57 +00003213VG_REGPARM(2) static void hg_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003214{
3215 if (*(UShort *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003216 hg_mem_write(a, 2, 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_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003219{
3220 if (*(UInt *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003221 hg_mem_write(a, 4, 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_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003224{
njnfbdcba92005-05-09 01:23:49 +00003225 hg_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003226}
njn25e49d8e72002-09-23 09:36:25 +00003227
sewardjc4a810d2002-11-13 22:25:51 +00003228static void hg_thread_create(ThreadId parent, ThreadId child)
3229{
3230 if (0)
3231 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3232
3233 newTLS(child);
3234 addPriorTLS(child, parent);
3235
3236 newTLS(parent);
3237}
3238
3239static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3240{
3241 if (0)
3242 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3243
3244 newTLS(joiner);
3245 addPriorTLS(joiner, joinee);
3246
3247 clearTLS(joinee);
3248}
3249
sewardj7a5ebcf2002-11-13 22:42:13 +00003250static Int __BUS_HARDWARE_LOCK__;
3251
3252static void bus_lock(void)
3253{
njn95e65f62005-03-30 04:13:56 +00003254 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003255 hg_pre_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
3256 hg_post_mutex_lock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003257}
3258
3259static void bus_unlock(void)
3260{
njn95e65f62005-03-30 04:13:56 +00003261 ThreadId tid = VG_(get_running_tid)();
njnfbdcba92005-05-09 01:23:49 +00003262 hg_post_mutex_unlock(tid, &__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003263}
3264
njn25e49d8e72002-09-23 09:36:25 +00003265/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003266/*--- Client requests ---*/
3267/*--------------------------------------------------------------------*/
3268
njn51d827b2005-05-09 01:02:08 +00003269static Bool hg_handle_client_request(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003270{
njnfc26ff92004-11-22 19:12:49 +00003271 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003272 return False;
3273
3274 switch(args[0]) {
3275 case VG_USERREQ__HG_CLEAN_MEMORY:
3276 set_address_range_state(args[1], args[2], Vge_VirginInit);
3277 *ret = 0; /* meaningless */
3278 break;
3279
3280 case VG_USERREQ__HG_KNOWN_RACE:
3281 set_address_range_state(args[1], args[2], Vge_Error);
3282 *ret = 0; /* meaningless */
3283 break;
3284
3285 default:
3286 return False;
3287 }
3288
3289 return True;
3290}
3291
3292
3293/*--------------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00003294/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00003295/*--------------------------------------------------------------------*/
3296
njn51d827b2005-05-09 01:02:08 +00003297static Bool hg_process_cmd_line_option(Char* arg)
3298{
3299 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3300 clo_execontext = EC_None;
3301 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3302 clo_execontext = EC_Some;
3303 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3304 clo_execontext = EC_All;
3305
3306 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
3307
3308 else
3309 return VG_(replacement_malloc_process_cmd_line_option)(arg);
3310
3311 return True;
3312}
3313
3314static void hg_print_usage(void)
3315{
3316 VG_(printf)(
3317" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3318" --show-last-access=no|some|all\n"
3319" show location of last word access on error [no]\n"
3320 );
3321 VG_(replacement_malloc_print_usage)();
3322}
3323
3324static void hg_print_debug_usage(void)
3325{
3326 VG_(replacement_malloc_print_debug_usage)();
3327}
3328
3329static void hg_post_clo_init(void)
3330{
3331 void (*stack_tracker)(Addr a, SizeT len);
3332
3333 if (clo_execontext) {
3334 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3335 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3336 }
3337
3338 if (clo_priv_stacks)
njnfbdcba92005-05-09 01:23:49 +00003339 stack_tracker = & hg_new_mem_stack_private;
njn51d827b2005-05-09 01:02:08 +00003340 else
njnfbdcba92005-05-09 01:23:49 +00003341 stack_tracker = & hg_new_mem_stack;
njn51d827b2005-05-09 01:02:08 +00003342
3343 VG_(track_new_mem_stack) (stack_tracker);
3344 VG_(track_new_mem_stack_signal) (stack_tracker);
3345}
3346
3347
3348static void hg_fini(Int exitcode)
3349{
3350 if (DEBUG_LOCK_TABLE) {
3351 pp_all_LockSets();
3352 pp_all_mutexes();
3353 }
3354
3355 if (LOCKSET_SANITY)
3356 sanity_check_locksets("hg_fini");
3357
3358 if (VG_(clo_verbosity) > 0)
3359 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
njnfbdcba92005-05-09 01:23:49 +00003360 n_hg_warnings, n_lockorder_warnings);
njn51d827b2005-05-09 01:02:08 +00003361
3362 if (0)
3363 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3364 stk_ld, stk_st, stk_ld + stk_st,
3365 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3366 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
3367}
3368
3369static void hg_pre_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00003370{
3371 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003372 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003373
njn810086f2002-11-14 12:42:47 +00003374 VG_(details_name) ("Helgrind");
3375 VG_(details_version) (NULL);
3376 VG_(details_description) ("a data race detector");
3377 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +00003378 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003379 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj78210aa2002-12-01 02:55:46 +00003380 VG_(details_avg_translation_sizeB) ( 115 );
njn25e49d8e72002-09-23 09:36:25 +00003381
njn51d827b2005-05-09 01:02:08 +00003382 VG_(basic_tool_funcs) (hg_post_clo_init,
3383 hg_instrument,
3384 hg_fini);
tomc756a8e2005-03-31 07:59:35 +00003385
njn5db32122005-08-12 15:23:57 +00003386 VG_(printf)(
3387"\n"
3388"Helgrind is currently not working, because:\n"
3389" (a) it is not yet ready to handle the Vex IR and the use with 64-bit\n"
3390" platforms introduced in Valgrind 3.0.0\n"
3391" (b) we need to get thread operation tracking working again after\n"
3392" the changes added in Valgrind 2.4.0\n"
3393"\n"
3394"Sorry for the inconvenience. Let us know if this is a problem for you.\n");
3395 VG_(exit)(1);
3396
tomc756a8e2005-03-31 07:59:35 +00003397 VG_(needs_core_errors) ();
njn51d827b2005-05-09 01:02:08 +00003398 VG_(needs_tool_errors) (hg_eq_Error,
3399 hg_pp_Error,
3400 hg_update_extra,
3401 hg_recognised_suppression,
3402 hg_read_extra_suppression_info,
3403 hg_error_matches_suppression,
3404 hg_get_error_name,
3405 hg_print_extra_suppression_info);
tomc756a8e2005-03-31 07:59:35 +00003406 VG_(needs_data_syms) ();
njn51d827b2005-05-09 01:02:08 +00003407 VG_(needs_client_requests) (hg_handle_client_request);
3408 VG_(needs_sanity_checks) (hg_cheap_sanity_check,
3409 hg_expensive_sanity_check);
3410 VG_(needs_command_line_options)(hg_process_cmd_line_option,
3411 hg_print_usage,
3412 hg_print_debug_usage);
tomc756a8e2005-03-31 07:59:35 +00003413 VG_(needs_shadow_memory) ();
3414
njnfc51f8d2005-06-21 03:20:17 +00003415 VG_(needs_malloc_replacement) (hg_malloc,
njn51d827b2005-05-09 01:02:08 +00003416 hg___builtin_new,
3417 hg___builtin_vec_new,
3418 hg_memalign,
3419 hg_calloc,
3420 hg_free,
3421 hg___builtin_delete,
3422 hg___builtin_vec_delete,
3423 hg_realloc,
tomc756a8e2005-03-31 07:59:35 +00003424 8 );
njn25e49d8e72002-09-23 09:36:25 +00003425
njnfbdcba92005-05-09 01:23:49 +00003426 VG_(track_new_mem_startup) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003427
njn51d827b2005-05-09 01:02:08 +00003428 /* stack ones not decided until hg_post_clo_init() */
njn25e49d8e72002-09-23 09:36:25 +00003429
njn51d827b2005-05-09 01:02:08 +00003430 VG_(track_new_mem_brk) (& make_writable);
njnfbdcba92005-05-09 01:23:49 +00003431 VG_(track_new_mem_mmap) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003432
njnfbdcba92005-05-09 01:23:49 +00003433 VG_(track_change_mem_mprotect) (& hg_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003434
njn51d827b2005-05-09 01:02:08 +00003435 VG_(track_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003436
njn51d827b2005-05-09 01:02:08 +00003437 VG_(track_die_mem_stack) (NULL);
3438 VG_(track_die_mem_stack_signal)(NULL);
3439 VG_(track_die_mem_brk) (NULL);
3440 VG_(track_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003441
njnfbdcba92005-05-09 01:23:49 +00003442 VG_(track_pre_mem_read) (& hg_pre_mem_read);
3443 VG_(track_pre_mem_read_asciiz) (& hg_pre_mem_read_asciiz);
3444 VG_(track_pre_mem_write) (& hg_pre_mem_write);
njn51d827b2005-05-09 01:02:08 +00003445 VG_(track_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003446
njn51d827b2005-05-09 01:02:08 +00003447 VG_(track_post_thread_create) (& hg_thread_create);
3448 VG_(track_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003449
njnfbdcba92005-05-09 01:23:49 +00003450 VG_(track_pre_mutex_lock) (& hg_pre_mutex_lock);
3451 VG_(track_post_mutex_lock) (& hg_post_mutex_lock);
3452 VG_(track_post_mutex_unlock) (& hg_post_mutex_unlock);
sewardjc4a810d2002-11-13 22:25:51 +00003453
njn14d01ce2004-11-26 11:30:14 +00003454 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003455 lockset_hash[i] = NULL;
3456
3457 empty = alloc_LockSet(0);
3458 insert_LockSet(empty);
3459 emptyset = empty;
3460
sewardjc4a810d2002-11-13 22:25:51 +00003461 /* Init lock table and thread segments */
3462 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003463 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003464
sewardjc4a810d2002-11-13 22:25:51 +00003465 newTLS(i);
3466 }
3467
njn25e49d8e72002-09-23 09:36:25 +00003468 init_shadow_memory();
njnf69f9452005-07-03 17:53:11 +00003469 hg_malloc_list = VG_(HT_construct)( 80021 ); // prime, big
njn25e49d8e72002-09-23 09:36:25 +00003470}
3471
fitzhardinge98abfc72003-12-16 02:05:15 +00003472/* Uses a 1:1 mapping */
njn51d827b2005-05-09 01:02:08 +00003473VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init, 1.0)
fitzhardinge98abfc72003-12-16 02:05:15 +00003474
njn25e49d8e72002-09-23 09:36:25 +00003475/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003476/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003477/*--------------------------------------------------------------------*/