blob: 1b5a2ab2206ab3363c49582a8740b90f2742ce48 [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
sewardj9ebd6e02007-01-08 06:01:59 +000011 Copyright (C) 2002-2007 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn25e49d8e72002-09-23 09:36:25 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
njnb1489202006-04-23 10:51:48 +000032// *** WARNING ***
33// Helgrind is not 64-bit clean.
34
njn8cdd1852005-08-30 19:47:32 +000035// For anyone wanting to understand race conditions better, this paper might
36// be instructive:
37//
38// S. Carr, J. Mayo and C.-K. Shene. Race Conditions: A Case Study, The
39// Journal of Computing in Small Colleges 17(1), September 2001.
40// http://www.cs.mtu.edu/~carr/papers/jcsc02.pdf
41//
42// It nicely describes several example race conditions, emphasising the
43// fundamentals in each case.
44
njnc7561b92005-06-19 01:24:32 +000045#include "pub_tool_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000046#include "pub_tool_vki.h"
njnc7561b92005-06-19 01:24:32 +000047#include "pub_tool_threadstate.h"
njn4802b382005-06-11 04:58:29 +000048#include "pub_tool_aspacemgr.h"
njnea27e462005-05-31 02:38:09 +000049#include "pub_tool_debuginfo.h"
njn81c00df2005-05-14 21:28:43 +000050#include "pub_tool_hashtable.h"
njn97405b22005-06-02 03:39:33 +000051#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000052#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000053#include "pub_tool_libcprint.h"
njnf39e9a32005-06-12 02:43:17 +000054#include "pub_tool_libcproc.h"
njnf536bbb2005-06-13 04:21:38 +000055#include "pub_tool_machine.h"
njn717cde52005-05-10 02:47:21 +000056#include "pub_tool_mallocfree.h"
njn20242342005-05-16 23:31:24 +000057#include "pub_tool_options.h"
njn717cde52005-05-10 02:47:21 +000058#include "pub_tool_replacemalloc.h"
njn43b9a8a2005-05-10 04:37:01 +000059#include "pub_tool_tooliface.h"
njn717cde52005-05-10 02:47:21 +000060
sewardj7f3ad222002-11-13 22:11:53 +000061#include "helgrind.h"
njn25e49d8e72002-09-23 09:36:25 +000062
njnfbdcba92005-05-09 01:23:49 +000063static UInt n_hg_warnings = 0;
sewardjff2c9232002-11-13 21:44:39 +000064static UInt n_lockorder_warnings = 0;
njn25e49d8e72002-09-23 09:36:25 +000065
66/*------------------------------------------------------------*/
67/*--- Debug guff ---*/
68/*------------------------------------------------------------*/
69
sewardje11d6c82002-12-15 02:00:41 +000070#define DEBUG_LOCK_TABLE 0 /* Print lock table at end */
njn25e49d8e72002-09-23 09:36:25 +000071
72#define DEBUG_MAKE_ACCESSES 0 /* Print make_access() calls */
73#define DEBUG_LOCKS 0 /* Print lock()/unlock() calls and locksets */
74#define DEBUG_NEW_LOCKSETS 0 /* Print new locksets when created */
75#define DEBUG_ACCESSES 0 /* Print reads, writes */
76#define DEBUG_MEM_LOCKSET_CHANGES 0
77 /* Print when an address's lockset
78 changes; only useful with
79 DEBUG_ACCESSES */
sewardj8fac99a2002-11-13 22:31:26 +000080#define SLOW_ASSERTS 0 /* do expensive asserts */
njn25e49d8e72002-09-23 09:36:25 +000081#define DEBUG_VIRGIN_READS 0 /* Dump around address on VIRGIN reads */
82
sewardj8fac99a2002-11-13 22:31:26 +000083#if SLOW_ASSERTS
njn94065fd2004-11-22 19:26:27 +000084#define TL_ASSERT(x) tl_assert(x)
sewardj8fac99a2002-11-13 22:31:26 +000085#else
njn94065fd2004-11-22 19:26:27 +000086#define TL_ASSERT(x)
sewardj8fac99a2002-11-13 22:31:26 +000087#endif
88
njn25e49d8e72002-09-23 09:36:25 +000089/* heavyweight LockSet sanity checking:
90 0 == never
91 1 == after important ops
92 2 == As 1 and also after pthread_mutex_* ops (excessively slow)
93 */
94#define LOCKSET_SANITY 0
95
sewardj8fac99a2002-11-13 22:31:26 +000096/* Rotate an unsigned quantity left */
97#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x)*8)-(n))))
98
njn25e49d8e72002-09-23 09:36:25 +000099/*------------------------------------------------------------*/
sewardjf6374322002-11-13 22:35:55 +0000100/*--- Command line options ---*/
101/*------------------------------------------------------------*/
102
103static enum {
104 EC_None,
105 EC_Some,
106 EC_All
107} clo_execontext = EC_None;
108
sewardje1a39f42002-12-15 01:56:17 +0000109static Bool clo_priv_stacks = False;
sewardjf6374322002-11-13 22:35:55 +0000110
111/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000112/*--- Crude profiling machinery. ---*/
113/*------------------------------------------------------------*/
114
115// PPP: work out if I want this
116
117#define PROF_EVENT(x)
118#if 0
119#ifdef VG_PROFILE_MEMORY
120
121#define N_PROF_EVENTS 150
122
123static UInt event_ctr[N_PROF_EVENTS];
124
125void VGE_(done_prof_mem) ( void )
126{
127 Int i;
128 for (i = 0; i < N_PROF_EVENTS; i++) {
129 if ((i % 10) == 0)
130 VG_(printf)("\n");
131 if (event_ctr[i] > 0)
132 VG_(printf)( "prof mem event %2d: %d\n", i, event_ctr[i] );
133 }
134 VG_(printf)("\n");
135}
136
137#define PROF_EVENT(ev) \
njnca82cc02004-11-22 17:18:48 +0000138 do { tl_assert((ev) >= 0 && (ev) < N_PROF_EVENTS); \
njn25e49d8e72002-09-23 09:36:25 +0000139 event_ctr[ev]++; \
140 } while (False);
141
142#else
143
144//static void init_prof_mem ( void ) { }
145// void VG_(done_prof_mem) ( void ) { }
146
147#define PROF_EVENT(ev) /* */
148
149#endif /* VG_PROFILE_MEMORY */
150
151/* Event index. If just the name of the fn is given, this means the
152 number of calls to the fn. Otherwise it is the specified event.
153
154 [PPP: snip event numbers...]
155*/
156#endif /* 0 */
157
158
159/*------------------------------------------------------------*/
160/*--- Data defns. ---*/
161/*------------------------------------------------------------*/
162
njn3e884182003-04-15 13:03:23 +0000163typedef
164 struct _HG_Chunk {
165 struct _HG_Chunk* next;
166 Addr data; /* ptr to actual block */
nethercote928a5f72004-11-03 18:10:37 +0000167 SizeT size; /* size requested */
njn3e884182003-04-15 13:03:23 +0000168 ExeContext* where; /* where it was allocated */
169 ThreadId tid; /* allocating thread */
170 }
171 HG_Chunk;
172
njn25e49d8e72002-09-23 09:36:25 +0000173typedef enum
sewardj7f3ad222002-11-13 22:11:53 +0000174 { Vge_VirginInit, Vge_NonVirginInit, Vge_SegmentInit, Vge_Error }
njn25e49d8e72002-09-23 09:36:25 +0000175 VgeInitStatus;
176
sewardjc808ef52002-11-13 22:43:26 +0000177
njnc6168192004-11-29 13:54:10 +0000178// XXX: not 64-bit clean!
njn25e49d8e72002-09-23 09:36:25 +0000179/* Should add up to 32 to fit in one word */
180#define OTHER_BITS 30
181#define STATE_BITS 2
182
183#define ESEC_MAP_WORDS 16384 /* Words per secondary map */
184
185/* This is for indicating that a memory block has been initialised but not
186 * really directly by a particular thread... (eg. text/data initialised
187 * automatically at startup).
188 * Must be different to virgin_word.other */
189#define TID_INDICATING_NONVIRGIN 1
190
sewardjc4a810d2002-11-13 22:25:51 +0000191/* Magic packed TLS used for error suppression; if word state is Excl
192 and tid is this, then it means all access are OK without changing
193 state and without raising any more errors */
194#define TLSP_INDICATING_ALL ((1 << OTHER_BITS) - 1)
sewardj16748af2002-10-22 04:55:54 +0000195
njn25e49d8e72002-09-23 09:36:25 +0000196/* Number of entries must fit in STATE_BITS bits */
197typedef enum { Vge_Virgin, Vge_Excl, Vge_Shar, Vge_SharMod } pth_state;
198
sewardjc808ef52002-11-13 22:43:26 +0000199static inline const Char *pp_state(pth_state st)
200{
201 const Char *ret;
202
203 switch(st) {
204 case Vge_Virgin: ret = "virgin"; break;
205 case Vge_Excl: ret = "exclusive"; break;
206 case Vge_Shar: ret = "shared RO"; break;
207 case Vge_SharMod: ret = "shared RW"; break;
208 default: ret = "???";
209 }
210 return ret;
211}
212
njn25e49d8e72002-09-23 09:36:25 +0000213typedef
214 struct {
sewardj8fac99a2002-11-13 22:31:26 +0000215 /* gcc arranges this bitfield with state in the 2LSB and other
216 in the 30MSB, which is what we want */
njn25e49d8e72002-09-23 09:36:25 +0000217 UInt state:STATE_BITS;
sewardj8fac99a2002-11-13 22:31:26 +0000218 UInt other:OTHER_BITS;
njn25e49d8e72002-09-23 09:36:25 +0000219 } shadow_word;
220
sewardj8fac99a2002-11-13 22:31:26 +0000221#define SW(st, other) ((shadow_word) { st, other })
222
njn25e49d8e72002-09-23 09:36:25 +0000223typedef
224 struct {
225 shadow_word swords[ESEC_MAP_WORDS];
226 }
227 ESecMap;
228
229static ESecMap* primary_map[ 65536 ];
230static ESecMap distinguished_secondary_map;
231
sewardj8fac99a2002-11-13 22:31:26 +0000232static const shadow_word virgin_sword = SW(Vge_Virgin, 0);
233static const shadow_word error_sword = SW(Vge_Excl, TLSP_INDICATING_ALL);
njn25e49d8e72002-09-23 09:36:25 +0000234
235#define VGE_IS_DISTINGUISHED_SM(smap) \
236 ((smap) == &distinguished_secondary_map)
237
238#define ENSURE_MAPPABLE(addr,caller) \
239 do { \
240 if (VGE_IS_DISTINGUISHED_SM(primary_map[(addr) >> 16])) { \
241 primary_map[(addr) >> 16] = alloc_secondary_map(caller); \
242 /*VG_(printf)("new 2map because of %p\n", addr);*/ \
243 } \
244 } while(0)
245
246
sewardjc808ef52002-11-13 22:43:26 +0000247/* Parallel map which contains execution contexts when words last
248 changed state (if required) */
sewardj499e3de2002-11-13 22:22:25 +0000249
nethercoteca788ff2004-10-20 10:58:09 +0000250typedef struct EC_IP {
251 union u_ec_ip {
252 Addr ip;
sewardjc808ef52002-11-13 22:43:26 +0000253 ExeContext *ec;
nethercoteca788ff2004-10-20 10:58:09 +0000254 } uu_ec_ip;
sewardjc808ef52002-11-13 22:43:26 +0000255 UInt state:STATE_BITS;
256 UInt tls:OTHER_BITS; /* packed TLS */
nethercoteca788ff2004-10-20 10:58:09 +0000257} EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000258
nethercoteca788ff2004-10-20 10:58:09 +0000259#define NULL_EC_IP ((EC_IP){ { 0 }, 0, 0})
sewardjc808ef52002-11-13 22:43:26 +0000260
nethercoteca788ff2004-10-20 10:58:09 +0000261#define IP(ip, prev, tls) ((EC_IP) { (union u_ec_ip)(ip), (prev).state, packTLS(tls) })
262#define EC(ec, prev, tls) ((EC_IP) { (union u_ec_ip)(ec), (prev).state, packTLS(tls) })
sewardjc808ef52002-11-13 22:43:26 +0000263
264static inline UInt packEC(ExeContext *ec)
265{
njn94065fd2004-11-22 19:26:27 +0000266 TL_ASSERT(((UWord)ec & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000267 return ((UWord)ec) >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000268}
269
nethercoteca788ff2004-10-20 10:58:09 +0000270/* Lose 2 LSB of IP */
271static inline UInt packIP(Addr ip)
sewardjc808ef52002-11-13 22:43:26 +0000272{
nethercote50397c22004-11-04 18:03:06 +0000273 return ip >> STATE_BITS;
sewardjc808ef52002-11-13 22:43:26 +0000274}
275
nethercoteca788ff2004-10-20 10:58:09 +0000276static inline Addr unpackIP(UInt i)
sewardjc808ef52002-11-13 22:43:26 +0000277{
278 return (Addr)(i << STATE_BITS);
279}
sewardj499e3de2002-11-13 22:22:25 +0000280
281typedef struct {
nethercoteca788ff2004-10-20 10:58:09 +0000282 EC_IP execontext[ESEC_MAP_WORDS];
sewardj499e3de2002-11-13 22:22:25 +0000283} ExeContextMap;
284
285static ExeContextMap** execontext_map;
286
nethercoteca788ff2004-10-20 10:58:09 +0000287static inline void setExeContext(Addr a, EC_IP ec)
sewardj499e3de2002-11-13 22:22:25 +0000288{
289 UInt idx = (a >> 16) & 0xffff;
290 UInt off = (a >> 2) & 0x3fff;
291
292 if (execontext_map[idx] == NULL) {
293 execontext_map[idx] = VG_(malloc)(sizeof(ExeContextMap));
294 VG_(memset)(execontext_map[idx], 0, sizeof(ExeContextMap));
295 }
296
297 execontext_map[idx]->execontext[off] = ec;
298}
299
nethercoteca788ff2004-10-20 10:58:09 +0000300static inline EC_IP getExeContext(Addr a)
sewardj499e3de2002-11-13 22:22:25 +0000301{
302 UInt idx = (a >> 16) & 0xffff;
303 UInt off = (a >> 2) & 0x3fff;
nethercoteca788ff2004-10-20 10:58:09 +0000304 EC_IP ec = NULL_EC_IP;
sewardj499e3de2002-11-13 22:22:25 +0000305
306 if (execontext_map[idx] != NULL)
307 ec = execontext_map[idx]->execontext[off];
308
309 return ec;
310}
311
njn25e49d8e72002-09-23 09:36:25 +0000312/*------------------------------------------------------------*/
sewardjc4a810d2002-11-13 22:25:51 +0000313/*--- Thread lifetime segments ---*/
314/*------------------------------------------------------------*/
315
316/*
317 * This mechanism deals with the common case of a parent thread
318 * creating a structure for a child thread, and then passing ownership
319 * of the structure to that thread. It similarly copes with a child
320 * thread passing information back to another thread waiting to join
321 * on it.
322 *
323 * Each thread's lifetime can be partitioned into segments. Those
324 * segments are arranged to form an interference graph which indicates
325 * whether two thread lifetime segments can possibly be concurrent.
326 * If not, then memory with is exclusively accessed by one TLS can be
daywalker7e73e5f2003-07-04 16:18:15 +0000327 * passed on to another TLS without an error occurring, and without
sewardjc4a810d2002-11-13 22:25:51 +0000328 * moving it from Excl state.
329 *
330 * At present this only considers thread creation and join as
331 * synchronisation events for creating new lifetime segments, but
332 * others may be possible (like mutex operations).
333 */
334
335typedef struct _ThreadLifeSeg ThreadLifeSeg;
336
337struct _ThreadLifeSeg {
338 ThreadId tid;
339 ThreadLifeSeg *prior[2]; /* Previous lifetime segments */
340 UInt refcount; /* Number of memory locations pointing here */
341 UInt mark; /* mark used for graph traversal */
342 ThreadLifeSeg *next; /* list of all TLS */
343};
344
345static ThreadLifeSeg *all_tls;
346static UInt tls_since_gc;
347#define TLS_SINCE_GC 10000
348
349/* current mark used for TLS graph traversal */
350static UInt tlsmark;
351
352static ThreadLifeSeg *thread_seg[VG_N_THREADS];
353
354
355static void tls_gc(void)
356{
357 /* XXX later. Walk through all TLSs and look for ones with 0
358 refcount and remove them from the structure and free them.
359 Could probably get rid of ThreadLifeSeg.refcount and simply use
360 mark-sweep from the shadow table. */
361 VG_(printf)("WRITEME: TLS GC\n");
362}
363
364static void newTLS(ThreadId tid)
365{
366 static const Bool debug = False;
367 ThreadLifeSeg *tls;
368
369 /* Initial NULL */
370 if (thread_seg[tid] == NULL) {
371 tls = VG_(malloc)(sizeof(*tls));
372 tls->tid = tid;
373 tls->prior[0] = tls->prior[1] = NULL;
374 tls->refcount = 0;
375 tls->mark = tlsmark-1;
376
377 tls->next = all_tls;
378 all_tls = tls;
379 tls_since_gc++;
380
381 thread_seg[tid] = tls;
382 return;
383 }
384
385 /* Previous TLS was unused, so just recycle */
386 if (thread_seg[tid]->refcount == 0) {
387 if (debug)
388 VG_(printf)("newTLS; recycling TLS %p for tid %u\n",
389 thread_seg[tid], tid);
390 return;
391 }
392
393 /* Use existing TLS for this tid as a prior for new TLS */
394 tls = VG_(malloc)(sizeof(*tls));
395 tls->tid = tid;
396 tls->prior[0] = thread_seg[tid];
397 tls->prior[1] = NULL;
398 tls->refcount = 0;
399 tls->mark = tlsmark-1;
400
401 tls->next = all_tls;
402 all_tls = tls;
403 if (++tls_since_gc > TLS_SINCE_GC) {
404 tls_gc();
405 tls_since_gc = 0;
406 }
407
408 if (debug)
409 VG_(printf)("newTLS: made new TLS %p for tid %u (prior %p(%u))\n",
410 tls, tid, tls->prior[0], tls->prior[0]->tid);
411
412 thread_seg[tid] = tls;
413}
414
415/* clear out a TLS for a thread that's died */
416static void clearTLS(ThreadId tid)
417{
418 newTLS(tid);
419
420 thread_seg[tid]->prior[0] = NULL;
421 thread_seg[tid]->prior[1] = NULL;
422}
423
424static void addPriorTLS(ThreadId tid, ThreadId prior)
425{
426 static const Bool debug = False;
427 ThreadLifeSeg *tls = thread_seg[tid];
428
429 if (debug)
430 VG_(printf)("making TLS %p(%u) prior to TLS %p(%u)\n",
431 thread_seg[prior], prior, tls, tid);
432
njnca82cc02004-11-22 17:18:48 +0000433 tl_assert(thread_seg[tid] != NULL);
434 tl_assert(thread_seg[prior] != NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000435
436 if (tls->prior[0] == NULL)
437 tls->prior[0] = thread_seg[prior];
438 else {
njnca82cc02004-11-22 17:18:48 +0000439 tl_assert(tls->prior[1] == NULL);
sewardjc4a810d2002-11-13 22:25:51 +0000440 tls->prior[1] = thread_seg[prior];
441 }
442}
443
njnfbdcba92005-05-09 01:23:49 +0000444static Bool isPrior(const ThreadLifeSeg *t, const ThreadLifeSeg *prior)
445{
446 if (t == NULL || t->mark == tlsmark)
447 return False;
448
449 if (t == prior)
450 return True;
451
452 ((ThreadLifeSeg *)t)->mark = tlsmark;
453
454 return isPrior(t->prior[0], prior) || isPrior(t->prior[1], prior);
455}
456
sewardjc4a810d2002-11-13 22:25:51 +0000457/* Return True if prior is definitely not concurrent with tls */
458static Bool tlsIsDisjoint(const ThreadLifeSeg *tls,
459 const ThreadLifeSeg *prior)
460{
sewardjc4a810d2002-11-13 22:25:51 +0000461 tlsmark++; /* new traversal mark */
462
njnfbdcba92005-05-09 01:23:49 +0000463 return isPrior(tls, prior);
sewardjc4a810d2002-11-13 22:25:51 +0000464}
465
466static inline UInt packTLS(ThreadLifeSeg *tls)
467{
njn94065fd2004-11-22 19:26:27 +0000468 TL_ASSERT(((UWord)tls & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000469 return ((UWord)tls) >> STATE_BITS;
sewardjc4a810d2002-11-13 22:25:51 +0000470}
471
472static inline ThreadLifeSeg *unpackTLS(UInt i)
473{
sewardj29ef1c82005-06-11 10:33:35 +0000474 /* HACK ALERT -- DUBIOUS CAST */
475 return (ThreadLifeSeg *)ULong_to_Ptr(i << STATE_BITS);
sewardjc4a810d2002-11-13 22:25:51 +0000476}
477
478/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000479/*--- Low-level support for memory tracking. ---*/
480/*------------------------------------------------------------*/
481
482/*
483 All reads and writes are recorded in the memory map, which
484 records the state of all memory in the process. The memory map is
485 organised like that for normal Valgrind, except each that everything
486 is done at word-level instead of byte-level, and each word has only
487 one word of shadow (instead of 36 bits).
488
489 As for normal Valgrind there is a distinguished secondary map. But we're
490 working at word-granularity, so it has 16k word entries instead of 64k byte
491 entries. Lookup is done as follows:
492
493 bits 31..16: primary map lookup
494 bits 15.. 2: secondary map lookup
495 bits 1.. 0: ignored
496*/
497
498
499/*------------------------------------------------------------*/
500/*--- Basic bitmap management, reading and writing. ---*/
501/*------------------------------------------------------------*/
502
503/* Allocate and initialise a secondary map, marking all words as virgin. */
504
505/* Just a value that isn't a real pointer */
506#define SEC_MAP_ACCESS (shadow_word*)0x99
507
508
509static
510ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
511{
512 ESecMap* map;
513 UInt i;
514 //PROF_EVENT(10); PPP
515
nethercote1420ab22004-08-18 22:26:01 +0000516 // Mark all words as virgin.
sewardj45f4e7c2005-09-27 19:20:21 +0000517 map = (ESecMap *)VG_(am_shadow_alloc)(sizeof(ESecMap));
518 if (map == NULL)
519 VG_(out_of_memory_NORETURN)( "helgrind:allocate new ESecMap",
520 sizeof(ESecMap) );
njn25e49d8e72002-09-23 09:36:25 +0000521 for (i = 0; i < ESEC_MAP_WORDS; i++)
522 map->swords[i] = virgin_sword;
523
524 return map;
525}
526
527
528/* Set a word. The byte give by 'a' could be anywhere in the word -- the whole
529 * word gets set. */
sewardj56867352003-10-12 10:27:06 +0000530static /* __inline__ */
njn25e49d8e72002-09-23 09:36:25 +0000531void set_sword ( Addr a, shadow_word sword )
532{
533 ESecMap* sm;
sewardjc4a810d2002-11-13 22:25:51 +0000534 shadow_word *oldsw;
njn25e49d8e72002-09-23 09:36:25 +0000535
536 //PROF_EVENT(23); PPP
537 ENSURE_MAPPABLE(a, "VGE_(set_sword)");
538
539 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
540 sm = primary_map[a >> 16];
njnca82cc02004-11-22 17:18:48 +0000541 tl_assert(sm != &distinguished_secondary_map);
sewardjc4a810d2002-11-13 22:25:51 +0000542 oldsw = &sm->swords[(a & 0xFFFC) >> 2];
543 if (oldsw->state == Vge_Excl && oldsw->other != TLSP_INDICATING_ALL) {
544 ThreadLifeSeg *tls = unpackTLS(oldsw->other);
545 tls->refcount--;
546 }
547
548 if (sword.state == Vge_Excl && sword.other != TLSP_INDICATING_ALL) {
549 ThreadLifeSeg *tls = unpackTLS(sword.other);
550 tls->refcount++;
551 }
552
njn25e49d8e72002-09-23 09:36:25 +0000553 sm->swords[(a & 0xFFFC) >> 2] = sword;
554
555 if (VGE_IS_DISTINGUISHED_SM(sm)) {
njn8a7b41b2007-09-23 00:51:24 +0000556 VG_(printf)("wrote to distinguished 2ndary map! 0x%lx\n", a);
njn25e49d8e72002-09-23 09:36:25 +0000557 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000558 VG_(tool_panic)("wrote to distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000559 }
560}
561
562
563static __inline__
564shadow_word* get_sword_addr ( Addr a )
565{
566 /* Use bits 31..16 for primary, 15..2 for secondary lookup */
567 ESecMap* sm = primary_map[a >> 16];
568 UInt sm_off = (a & 0xFFFC) >> 2;
569
570 if (VGE_IS_DISTINGUISHED_SM(sm)) {
njn8a7b41b2007-09-23 00:51:24 +0000571 VG_(printf)("accessed distinguished 2ndary map! 0x%lx\n", a);
njn25e49d8e72002-09-23 09:36:25 +0000572 // XXX: may be legit, but I want to know when it happens --njn
njn67993252004-11-22 18:02:32 +0000573 //VG_(tool_panic)("accessed distinguished 2ndary map!");
njn25e49d8e72002-09-23 09:36:25 +0000574 return SEC_MAP_ACCESS;
575 }
576
577 //PROF_EVENT(21); PPP
578 return & (sm->swords[sm_off]);
579}
580
581
582// SSS: rename these so they're not so similar to memcheck, unless it's
583// appropriate of course
584
585static __inline__
586void init_virgin_sword(Addr a)
587{
sewardj499e3de2002-11-13 22:22:25 +0000588 if (clo_execontext != EC_None)
nethercoteca788ff2004-10-20 10:58:09 +0000589 setExeContext(a, NULL_EC_IP);
njn25e49d8e72002-09-23 09:36:25 +0000590 set_sword(a, virgin_sword);
591}
592
sewardj7f3ad222002-11-13 22:11:53 +0000593static __inline__
594void init_error_sword(Addr a)
595{
596 set_sword(a, error_sword);
597}
njn25e49d8e72002-09-23 09:36:25 +0000598
njn25e49d8e72002-09-23 09:36:25 +0000599static __inline__
600void init_nonvirgin_sword(Addr a)
601{
602 shadow_word sword;
njn14d01ce2004-11-26 11:30:14 +0000603 ThreadId tid;
sewardjc4a810d2002-11-13 22:25:51 +0000604 ThreadLifeSeg *tls;
njn25e49d8e72002-09-23 09:36:25 +0000605
njn14d01ce2004-11-26 11:30:14 +0000606 // The tid must be passed in here now; this requires more events to be
607 // given the tid in the first place.
608 //
609 //tid = VG_(get_current_or_recent_tid)();
610 VG_(message)(Vg_DebugMsg, "tid needs to be passed in here");
611 VG_(exit)(1);
612
njnca82cc02004-11-22 17:18:48 +0000613 tl_assert(tid != VG_INVALID_THREADID);
sewardjc4a810d2002-11-13 22:25:51 +0000614 tls = thread_seg[tid];
615
sewardj8fac99a2002-11-13 22:31:26 +0000616 sword = SW(Vge_Excl, packTLS(tls));
njn25e49d8e72002-09-23 09:36:25 +0000617 set_sword(a, sword);
618}
619
620
njnfbdcba92005-05-09 01:23:49 +0000621/* In this case, we treat it for Helgrind's sake like virgin (it hasn't
njn25e49d8e72002-09-23 09:36:25 +0000622 * been inited by a particular thread, it's just done automatically upon
623 * startup), but we mark its .state specially so it doesn't look like an
624 * uninited read. */
625static __inline__
626void init_magically_inited_sword(Addr a)
627{
628 shadow_word sword;
629
sewardj8fac99a2002-11-13 22:31:26 +0000630 sword = SW(Vge_Virgin, TID_INDICATING_NONVIRGIN);
631
njn25e49d8e72002-09-23 09:36:25 +0000632 set_sword(a, virgin_sword);
633}
634
sewardjc26cc252002-10-23 21:58:55 +0000635
sewardj274c6012002-10-22 04:54:55 +0000636/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +0000637/*--- Implementation of lock sets. ---*/
sewardj274c6012002-10-22 04:54:55 +0000638/*------------------------------------------------------------*/
639
sewardj39a4d842002-11-13 22:14:30 +0000640typedef struct _Mutex Mutex; /* forward decl */
sewardj4bffb232002-11-13 21:46:34 +0000641typedef struct _LockSet LockSet;
642
sewardj16748af2002-10-22 04:55:54 +0000643typedef enum MutexState {
644 MxUnknown, /* don't know */
645 MxUnlocked, /* unlocked */
646 MxLocked, /* locked */
647 MxDead /* destroyed */
648} MutexState;
649
sewardj39a4d842002-11-13 22:14:30 +0000650struct _Mutex {
sewardjdac0a442002-11-13 22:08:40 +0000651 Addr mutexp;
sewardj39a4d842002-11-13 22:14:30 +0000652 Mutex *next;
sewardj16748af2002-10-22 04:55:54 +0000653
654 MutexState state; /* mutex state */
655 ThreadId tid; /* owner */
656 ExeContext *location; /* where the last change happened */
sewardj274c6012002-10-22 04:54:55 +0000657
sewardj4bffb232002-11-13 21:46:34 +0000658 const LockSet *lockdep; /* set of locks we depend on */
sewardjc26cc252002-10-23 21:58:55 +0000659 UInt mark; /* mark for graph traversal */
660};
sewardj16748af2002-10-22 04:55:54 +0000661
sewardj39a4d842002-11-13 22:14:30 +0000662static inline Int mutex_cmp(const Mutex *a, const Mutex *b)
sewardj4bffb232002-11-13 21:46:34 +0000663{
sewardjdac0a442002-11-13 22:08:40 +0000664 return a->mutexp - b->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000665}
njn25e49d8e72002-09-23 09:36:25 +0000666
sewardj274c6012002-10-22 04:54:55 +0000667struct _LockSet {
sewardj05bcdcb2003-05-18 10:05:38 +0000668 Int setsize; /* number of members */
sewardj4bffb232002-11-13 21:46:34 +0000669 UInt hash; /* hash code */
670 LockSet *next; /* next in hash chain */
sewardj39a4d842002-11-13 22:14:30 +0000671 const Mutex *mutex[0]; /* locks */
sewardj274c6012002-10-22 04:54:55 +0000672};
sewardj4bffb232002-11-13 21:46:34 +0000673
674static const LockSet *emptyset;
njn25e49d8e72002-09-23 09:36:25 +0000675
676/* Each one is an index into the lockset table. */
sewardj4bffb232002-11-13 21:46:34 +0000677static const LockSet *thread_locks[VG_N_THREADS];
njn25e49d8e72002-09-23 09:36:25 +0000678
sewardjdac0a442002-11-13 22:08:40 +0000679#define LOCKSET_HASH_SZ 1021
njn25e49d8e72002-09-23 09:36:25 +0000680
sewardj4bffb232002-11-13 21:46:34 +0000681static LockSet *lockset_hash[LOCKSET_HASH_SZ];
njn25e49d8e72002-09-23 09:36:25 +0000682
sewardj4bffb232002-11-13 21:46:34 +0000683/* Pack and unpack a LockSet pointer into shadow_word.other */
sewardj8fac99a2002-11-13 22:31:26 +0000684static inline UInt packLockSet(const LockSet *p)
njn25e49d8e72002-09-23 09:36:25 +0000685{
sewardj4bffb232002-11-13 21:46:34 +0000686 UInt id;
687
njn94065fd2004-11-22 19:26:27 +0000688 TL_ASSERT(((UWord)p & ((1 << STATE_BITS)-1)) == 0);
nethercote50397c22004-11-04 18:03:06 +0000689 id = ((UWord)p) >> STATE_BITS;
sewardj4bffb232002-11-13 21:46:34 +0000690
691 return id;
njn25e49d8e72002-09-23 09:36:25 +0000692}
693
sewardj8fac99a2002-11-13 22:31:26 +0000694static inline const LockSet *unpackLockSet(UInt id)
njn25e49d8e72002-09-23 09:36:25 +0000695{
sewardj29ef1c82005-06-11 10:33:35 +0000696 /* HACK ALERT -- DUBIOUS CAST */
697 return (LockSet *)ULong_to_Ptr(id << STATE_BITS);
njn25e49d8e72002-09-23 09:36:25 +0000698}
699
njn25e49d8e72002-09-23 09:36:25 +0000700static
sewardj4bffb232002-11-13 21:46:34 +0000701void pp_LockSet(const LockSet* p)
njn25e49d8e72002-09-23 09:36:25 +0000702{
sewardj05bcdcb2003-05-18 10:05:38 +0000703 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000704 VG_(printf)("{ ");
sewardj4bffb232002-11-13 21:46:34 +0000705 for(i = 0; i < p->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000706 const Mutex *mx = p->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000707
708 VG_(printf)("%p%(y ", mx->mutexp, mx->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000709 }
710 VG_(printf)("}\n");
711}
712
713
sewardj4bffb232002-11-13 21:46:34 +0000714static void print_LockSet(const Char *s, const LockSet *ls)
715{
716 VG_(printf)("%s: ", s);
717 pp_LockSet(ls);
718}
719
720/* Compute the hash of a LockSet */
sewardj56867352003-10-12 10:27:06 +0000721static UInt hash_LockSet_w_wo(const LockSet *ls,
722 const Mutex *with,
723 const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000724{
sewardj05bcdcb2003-05-18 10:05:38 +0000725 Int i;
sewardj8fac99a2002-11-13 22:31:26 +0000726 UInt hash = ls->setsize + (with != NULL) - (without != NULL);
sewardj4bffb232002-11-13 21:46:34 +0000727
njnca82cc02004-11-22 17:18:48 +0000728 tl_assert(with == NULL || with != without);
sewardj4bffb232002-11-13 21:46:34 +0000729
730 for(i = 0; with != NULL || i < ls->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +0000731 const Mutex *mx = i >= ls->setsize ? NULL : ls->mutex[i];
sewardj4bffb232002-11-13 21:46:34 +0000732
733 if (without && mutex_cmp(without, mx) == 0)
734 continue;
735
736 if (with && (mx == NULL || mutex_cmp(with, mx) < 0)) {
737 mx = with;
738 with = NULL;
739 i--;
740 }
741
sewardj8fac99a2002-11-13 22:31:26 +0000742 hash = ROTL(hash, 17);
nethercote50397c22004-11-04 18:03:06 +0000743 hash ^= mx->mutexp;
sewardj4bffb232002-11-13 21:46:34 +0000744 }
745
746 return hash % LOCKSET_HASH_SZ;
747}
748
sewardj39a4d842002-11-13 22:14:30 +0000749static inline UInt hash_LockSet_with(const LockSet *ls, const Mutex *with)
sewardj4bffb232002-11-13 21:46:34 +0000750{
751 UInt hash = hash_LockSet_w_wo(ls, with, NULL);
752
753 if (0)
754 VG_(printf)("hash_with %p+%p -> %d\n", ls, with->mutexp, hash);
755
756 return hash;
757}
758
sewardj39a4d842002-11-13 22:14:30 +0000759static inline UInt hash_LockSet_without(const LockSet *ls, const Mutex *without)
sewardj4bffb232002-11-13 21:46:34 +0000760{
761 UInt hash = hash_LockSet_w_wo(ls, NULL, without);
762
763 if (0)
764 VG_(printf)("hash_with %p-%p -> %d\n", ls, without->mutexp, hash);
765
766 return hash;
767}
768
769static inline UInt hash_LockSet(const LockSet *ls)
770{
771 UInt hash = hash_LockSet_w_wo(ls, NULL, NULL);
772
773 if (0)
774 VG_(printf)("hash %p -> %d\n", ls, hash);
775
776 return hash;
777}
778
779static
780Bool structural_eq_LockSet(const LockSet* a, const LockSet* b)
njn25e49d8e72002-09-23 09:36:25 +0000781{
782 Int i;
njn25e49d8e72002-09-23 09:36:25 +0000783
sewardj4bffb232002-11-13 21:46:34 +0000784 if (a == b)
785 return True;
786 if (a->setsize != b->setsize)
787 return False;
njn25e49d8e72002-09-23 09:36:25 +0000788
sewardj4bffb232002-11-13 21:46:34 +0000789 for(i = 0; i < a->setsize; i++) {
790 if (mutex_cmp(a->mutex[i], b->mutex[i]) != 0)
njn25e49d8e72002-09-23 09:36:25 +0000791 return False;
njn25e49d8e72002-09-23 09:36:25 +0000792 }
793
sewardj4bffb232002-11-13 21:46:34 +0000794 return True;
njn25e49d8e72002-09-23 09:36:25 +0000795}
796
797
798/* Tricky: equivalent to (compare(insert(missing_elem, a), b)), but
799 * doesn't do the insertion. Returns True if they match.
800 */
801static Bool
sewardj4bffb232002-11-13 21:46:34 +0000802weird_LockSet_equals(const LockSet* a, const LockSet* b,
sewardj39a4d842002-11-13 22:14:30 +0000803 const Mutex *missing_mutex)
njn25e49d8e72002-09-23 09:36:25 +0000804{
sewardjc26cc252002-10-23 21:58:55 +0000805 static const Bool debug = False;
sewardj4bffb232002-11-13 21:46:34 +0000806 Int ia, ib;
sewardjc26cc252002-10-23 21:58:55 +0000807
njn25e49d8e72002-09-23 09:36:25 +0000808 /* Idea is to try and match each element of b against either an
809 element of a, or missing_mutex. */
sewardjc26cc252002-10-23 21:58:55 +0000810
811 if (debug) {
812 print_LockSet("weird_LockSet_equals a", a);
813 print_LockSet(" b", b);
814 VG_(printf)( " missing: %p%(y\n",
815 missing_mutex->mutexp, missing_mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +0000816 }
sewardjc26cc252002-10-23 21:58:55 +0000817
sewardj4bffb232002-11-13 21:46:34 +0000818 if ((a->setsize + 1) != b->setsize) {
819 if (debug)
820 VG_(printf)(" fastpath length mismatch -> 0\n");
821 return False;
822 }
823
sewardjc26cc252002-10-23 21:58:55 +0000824 /* There are three phases to this compare:
825 1 the section from the start of a up to missing_mutex
826 2 missing mutex itself
827 3 the section after missing_mutex to the end of a
828 */
829
sewardj4bffb232002-11-13 21:46:34 +0000830 ia = 0;
831 ib = 0;
832
sewardjc26cc252002-10-23 21:58:55 +0000833 /* 1: up to missing_mutex */
sewardj4bffb232002-11-13 21:46:34 +0000834 for(; ia < a->setsize && mutex_cmp(a->mutex[ia], missing_mutex) < 0; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000835 if (debug) {
836 print_LockSet(" 1:a", a);
837 print_LockSet(" 1:b", b);
838 }
sewardj4bffb232002-11-13 21:46:34 +0000839 if (ib == b->setsize || mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000840 return False;
sewardjc26cc252002-10-23 21:58:55 +0000841 }
842
843 /* 2: missing_mutex itself */
844 if (debug) {
845 VG_(printf)( " 2:missing: %p%(y\n",
846 missing_mutex->mutexp, missing_mutex->mutexp);
847 print_LockSet(" 2: b", b);
848 }
849
njnca82cc02004-11-22 17:18:48 +0000850 tl_assert(ia == a->setsize || mutex_cmp(a->mutex[ia], missing_mutex) >= 0);
sewardjc26cc252002-10-23 21:58:55 +0000851
sewardj4bffb232002-11-13 21:46:34 +0000852 if (ib == b->setsize || mutex_cmp(missing_mutex, b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000853 return False;
854
sewardj4bffb232002-11-13 21:46:34 +0000855 ib++;
sewardjc26cc252002-10-23 21:58:55 +0000856
857 /* 3: after missing_mutex to end */
858
sewardj4bffb232002-11-13 21:46:34 +0000859 for(; ia < a->setsize && ib < b->setsize; ia++, ib++) {
sewardjc26cc252002-10-23 21:58:55 +0000860 if (debug) {
861 print_LockSet(" 3:a", a);
862 print_LockSet(" 3:b", b);
863 }
sewardj4bffb232002-11-13 21:46:34 +0000864 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) != 0)
sewardjc26cc252002-10-23 21:58:55 +0000865 return False;
sewardjc26cc252002-10-23 21:58:55 +0000866 }
867
868 if (debug)
sewardj4bffb232002-11-13 21:46:34 +0000869 VG_(printf)(" ia=%d ib=%d --> %d\n", ia, ib, ia == a->setsize && ib == b->setsize);
sewardjc26cc252002-10-23 21:58:55 +0000870
sewardj4bffb232002-11-13 21:46:34 +0000871 return ia == a->setsize && ib == b->setsize;
872}
873
874
875
876static const LockSet *lookup_LockSet(const LockSet *set)
877{
878 UInt bucket = set->hash;
879 LockSet *ret;
880
881 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
882 if (set == ret || structural_eq_LockSet(set, ret))
883 return ret;
884
885 return NULL;
886}
887
sewardj39a4d842002-11-13 22:14:30 +0000888static const LockSet *lookup_LockSet_with(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000889{
890 UInt bucket = hash_LockSet_with(set, mutex);
891 const LockSet *ret;
892
893 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
894 if (weird_LockSet_equals(set, ret, mutex))
895 return ret;
896
897 return NULL;
898}
899
sewardj39a4d842002-11-13 22:14:30 +0000900static const LockSet *lookup_LockSet_without(const LockSet *set, Mutex *mutex)
sewardj4bffb232002-11-13 21:46:34 +0000901{
902 UInt bucket = hash_LockSet_without(set, mutex);
903 const LockSet *ret;
904
905 for(ret = lockset_hash[bucket]; ret != NULL; ret = ret->next)
906 if (weird_LockSet_equals(ret, set, mutex))
907 return ret;
908
909 return NULL;
910}
911
912static void insert_LockSet(LockSet *set)
913{
914 UInt hash = hash_LockSet(set);
915
916 set->hash = hash;
917
njnca82cc02004-11-22 17:18:48 +0000918 tl_assert(lookup_LockSet(set) == NULL);
sewardj4bffb232002-11-13 21:46:34 +0000919
920 set->next = lockset_hash[hash];
921 lockset_hash[hash] = set;
922}
923
924static inline
925LockSet *alloc_LockSet(UInt setsize)
926{
sewardj39a4d842002-11-13 22:14:30 +0000927 LockSet *ret = VG_(malloc)(sizeof(*ret) + sizeof(Mutex *) * setsize);
sewardj4bffb232002-11-13 21:46:34 +0000928 ret->setsize = setsize;
929 return ret;
930}
931
932static inline
933void free_LockSet(LockSet *p)
934{
935 /* assert: not present in hash */
936 VG_(free)(p);
937}
938
njnb4aee052003-04-15 14:09:58 +0000939static
sewardj4bffb232002-11-13 21:46:34 +0000940void pp_all_LockSets ( void )
941{
942 Int i;
943 Int sets, buckets;
944
945 sets = buckets = 0;
946 for (i = 0; i < LOCKSET_HASH_SZ; i++) {
947 const LockSet *ls = lockset_hash[i];
948 Bool first = True;
949
sewardj4bffb232002-11-13 21:46:34 +0000950 for(; ls != NULL; ls = ls->next) {
sewardjdac0a442002-11-13 22:08:40 +0000951 if (first) {
952 buckets++;
953 VG_(printf)("[%4d] = ", i);
954 } else
955 VG_(printf)(" ");
956
sewardj4bffb232002-11-13 21:46:34 +0000957 sets++;
958 first = False;
959 pp_LockSet(ls);
960 }
961 }
962
963 VG_(printf)("%d distinct LockSets in %d buckets\n", sets, buckets);
964}
965
966static inline Bool isempty(const LockSet *ls)
967{
968 return ls == NULL || ls->setsize == 0;
969}
970
sewardj39a4d842002-11-13 22:14:30 +0000971static Bool ismember(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +0000972{
973 Int i;
974
975 /* XXX use binary search */
976 for(i = 0; i < ls->setsize; i++)
977 if (mutex_cmp(mx, ls->mutex[i]) == 0)
978 return True;
979
980 return False;
981}
982
983/* Check invariants:
984 - all locksets are unique
985 - each set is an array in strictly increasing order of mutex addr
986*/
987static
988void sanity_check_locksets ( const Char* caller )
989{
990 Int i;
991 const Char *badness;
992 LockSet *ls;
993
994 for(i = 0; i < LOCKSET_HASH_SZ; i++) {
995
996 for(ls = lockset_hash[i]; ls != NULL; ls = ls->next) {
sewardj39a4d842002-11-13 22:14:30 +0000997 const Mutex *prev;
sewardj4bffb232002-11-13 21:46:34 +0000998 Int j;
999
1000 if (hash_LockSet(ls) != ls->hash) {
1001 badness = "mismatched hash";
1002 goto bad;
1003 }
sewardj05bcdcb2003-05-18 10:05:38 +00001004 if (ls->hash != (UInt)i) {
sewardj4bffb232002-11-13 21:46:34 +00001005 badness = "wrong bucket";
1006 goto bad;
1007 }
1008 if (lookup_LockSet(ls) != ls) {
1009 badness = "non-unique set";
1010 goto bad;
1011 }
1012
1013 prev = ls->mutex[0];
1014 for(j = 1; j < ls->setsize; j++) {
1015 if (mutex_cmp(prev, ls->mutex[j]) >= 0) {
1016 badness = "mutexes out of order";
1017 goto bad;
1018 }
1019 }
1020 }
1021 }
1022 return;
1023
1024 bad:
1025 VG_(printf)("sanity_check_locksets: "
1026 "i = %d, ls=%p badness = %s, caller = %s\n",
1027 i, ls, badness, caller);
1028 pp_all_LockSets();
njn67993252004-11-22 18:02:32 +00001029 VG_(tool_panic)("sanity_check_locksets");
sewardj4bffb232002-11-13 21:46:34 +00001030}
1031
1032static
sewardj39a4d842002-11-13 22:14:30 +00001033LockSet *add_LockSet(const LockSet *ls, const Mutex *mx)
sewardj4bffb232002-11-13 21:46:34 +00001034{
1035 static const Bool debug = False;
1036 LockSet *ret = NULL;
1037 Int i, j;
1038
1039 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1040 VG_(printf)("add-IN mutex %p%(y\n", mx->mutexp, mx->mutexp);
1041 print_LockSet("add-IN", ls);
1042 }
1043
1044 if (debug || LOCKSET_SANITY)
1045 sanity_check_locksets("add-IN");
1046
njnca82cc02004-11-22 17:18:48 +00001047 tl_assert(!ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001048
1049 ret = alloc_LockSet(ls->setsize+1);
1050
1051 for(i = j = 0; i < ls->setsize; i++) {
1052 if (debug)
1053 VG_(printf)("i=%d j=%d ls->mutex[i]=%p mx=%p\n",
1054 i, j, ls->mutex[i]->mutexp, mx ? mx->mutexp : 0);
1055 if (mx && mutex_cmp(mx, ls->mutex[i]) < 0) {
1056 ret->mutex[j++] = mx;
1057 mx = NULL;
1058 }
1059 ret->mutex[j++] = ls->mutex[i];
1060 }
1061
1062 /* not added in loop - must be after */
1063 if (mx)
1064 ret->mutex[j++] = mx;
1065
njnca82cc02004-11-22 17:18:48 +00001066 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001067
1068 if (debug || LOCKSET_SANITY) {
1069 print_LockSet("add-OUT", ret);
1070 sanity_check_locksets("add-OUT");
1071 }
1072 return ret;
1073}
1074
1075/* Builds ls with mx removed. mx should actually be in ls!
1076 (a checked assertion). Resulting set should not already
1077 exist in the table (unchecked).
1078*/
1079static
sewardj39a4d842002-11-13 22:14:30 +00001080LockSet *remove_LockSet ( const LockSet *ls, const Mutex *mx )
sewardj4bffb232002-11-13 21:46:34 +00001081{
1082 static const Bool debug = False;
1083 LockSet *ret = NULL;
1084 Int i, j;
1085
1086 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1087 print_LockSet("remove-IN", ls);
1088 }
1089
1090 if (debug || LOCKSET_SANITY)
1091 sanity_check_locksets("remove-IN");
1092
njnca82cc02004-11-22 17:18:48 +00001093 tl_assert(ismember(ls, mx));
sewardj4bffb232002-11-13 21:46:34 +00001094
1095 ret = alloc_LockSet(ls->setsize-1);
1096
1097 for(i = j = 0; i < ls->setsize; i++) {
1098 if (mutex_cmp(ls->mutex[i], mx) == 0)
1099 continue;
1100 ret->mutex[j++] = ls->mutex[i];
1101 }
1102
njnca82cc02004-11-22 17:18:48 +00001103 tl_assert(j == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001104
1105 if (debug || LOCKSET_SANITY) {
1106 print_LockSet("remove-OUT", ret);
1107 sanity_check_locksets("remove-OUT");
1108 }
1109 return ret;
njn25e49d8e72002-09-23 09:36:25 +00001110}
1111
1112
1113/* Builds the intersection, and then unbuilds it if it's already in the table.
1114 */
sewardj4bffb232002-11-13 21:46:34 +00001115static const LockSet *_intersect(const LockSet *a, const LockSet *b)
njn25e49d8e72002-09-23 09:36:25 +00001116{
sewardj4bffb232002-11-13 21:46:34 +00001117 static const Bool debug = False;
1118 Int iret;
1119 Int ia, ib;
1120 Int size;
1121 LockSet *ret;
1122 const LockSet *found;
njn25e49d8e72002-09-23 09:36:25 +00001123
sewardj4bffb232002-11-13 21:46:34 +00001124 if (debug || LOCKSET_SANITY)
1125 sanity_check_locksets("intersect-IN");
njn25e49d8e72002-09-23 09:36:25 +00001126
sewardj4bffb232002-11-13 21:46:34 +00001127 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1128 print_LockSet("intersect a", a);
1129 print_LockSet("intersect b", b);
njn25e49d8e72002-09-23 09:36:25 +00001130 }
1131
sewardj4bffb232002-11-13 21:46:34 +00001132 /* count the size of the new set */
1133 size = 0;
1134 ia = ib = 0;
1135 for(size = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1136 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
1137 size++;
1138 ia++;
1139 ib++;
1140 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1141 ia++;
1142 } else {
njnca82cc02004-11-22 17:18:48 +00001143 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001144 ib++;
1145 }
njn25e49d8e72002-09-23 09:36:25 +00001146 }
1147
sewardj4bffb232002-11-13 21:46:34 +00001148 /* Build the intersection of the two sets */
1149 ret = alloc_LockSet(size);
1150 for (iret = ia = ib = 0; ia < a->setsize && ib < b->setsize; ) {
1151 if (mutex_cmp(a->mutex[ia], b->mutex[ib]) == 0) {
njnca82cc02004-11-22 17:18:48 +00001152 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001153 ret->mutex[iret++] = a->mutex[ia];
1154 ia++;
1155 ib++;
1156 } else if (mutex_cmp(a->mutex[ia], b->mutex[ib]) < 0) {
1157 ia++;
1158 } else {
njnca82cc02004-11-22 17:18:48 +00001159 tl_assert(mutex_cmp(a->mutex[ia], b->mutex[ib]) > 0);
sewardj4bffb232002-11-13 21:46:34 +00001160 ib++;
1161 }
1162 }
1163
1164 ret->hash = hash_LockSet(ret);
1165
njn25e49d8e72002-09-23 09:36:25 +00001166 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001167 found = lookup_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001168
sewardj4bffb232002-11-13 21:46:34 +00001169 if (found != NULL) {
1170 free_LockSet(ret);
njn25e49d8e72002-09-23 09:36:25 +00001171 } else {
sewardj4bffb232002-11-13 21:46:34 +00001172 insert_LockSet(ret);
1173 found = ret;
njn25e49d8e72002-09-23 09:36:25 +00001174 }
1175
sewardj4bffb232002-11-13 21:46:34 +00001176 if (debug || LOCKSET_SANITY) {
1177 print_LockSet("intersect-OUT", found);
1178 sanity_check_locksets("intersect-OUT");
1179 }
njn25e49d8e72002-09-23 09:36:25 +00001180
sewardj4bffb232002-11-13 21:46:34 +00001181 return found;
njn25e49d8e72002-09-23 09:36:25 +00001182}
1183
sewardj4bffb232002-11-13 21:46:34 +00001184/* inline the fastpath */
1185static inline const LockSet *intersect(const LockSet *a, const LockSet *b)
sewardjc26cc252002-10-23 21:58:55 +00001186{
sewardj4bffb232002-11-13 21:46:34 +00001187 static const Bool debug = False;
sewardjc26cc252002-10-23 21:58:55 +00001188
1189 /* Fast case -- when the two are the same */
sewardj4bffb232002-11-13 21:46:34 +00001190 if (a == b) {
1191 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1192 print_LockSet("intersect-same fastpath", a);
sewardjc26cc252002-10-23 21:58:55 +00001193 }
sewardj4bffb232002-11-13 21:46:34 +00001194 return a;
sewardjc26cc252002-10-23 21:58:55 +00001195 }
1196
sewardj4bffb232002-11-13 21:46:34 +00001197 if (isempty(a) || isempty(b)) {
1198 if (debug)
1199 VG_(printf)("intersect empty fastpath\n");
1200 return emptyset;
1201 }
1202
1203 return _intersect(a, b);
1204}
1205
1206
1207static const LockSet *ls_union(const LockSet *a, const LockSet *b)
1208{
1209 static const Bool debug = False;
1210 Int iret;
1211 Int ia, ib;
1212 Int size;
1213 LockSet *ret;
1214 const LockSet *found;
1215
1216 if (debug || LOCKSET_SANITY)
1217 sanity_check_locksets("union-IN");
1218
1219 /* Fast case -- when the two are the same */
1220 if (a == b) {
1221 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
1222 print_LockSet("union-same fastpath", a);
1223 }
1224 return a;
1225 }
1226
1227 if (isempty(a)) {
1228 if (debug)
1229 print_LockSet("union a=empty b", b);
1230 return b;
1231 }
1232 if (isempty(b)) {
1233 if (debug)
1234 print_LockSet("union b=empty a", a);
1235 return a;
1236 }
1237
1238 if (debug || DEBUG_MEM_LOCKSET_CHANGES) {
sewardjc26cc252002-10-23 21:58:55 +00001239 print_LockSet("union a", a);
1240 print_LockSet("union b", b);
1241 }
1242
sewardj4bffb232002-11-13 21:46:34 +00001243 /* count the size of the new set */
1244 for(size = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1245 Int cmp;
sewardjc26cc252002-10-23 21:58:55 +00001246
sewardj4bffb232002-11-13 21:46:34 +00001247 if ((ia < a->setsize) && (ib < b->setsize))
1248 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1249 else if (ia == a->setsize)
1250 cmp = 1;
1251 else
1252 cmp = -1;
1253
1254 if (cmp == 0) {
1255 size++;
1256 ia++;
1257 ib++;
1258 } else if (cmp < 0) {
1259 size++;
1260 ia++;
1261 } else {
njnca82cc02004-11-22 17:18:48 +00001262 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001263 size++;
1264 ib++;
1265 }
sewardjc26cc252002-10-23 21:58:55 +00001266 }
1267
sewardj4bffb232002-11-13 21:46:34 +00001268 /* Build the intersection of the two sets */
1269 ret = alloc_LockSet(size);
1270 for (iret = ia = ib = 0; (ia < a->setsize) || (ib < b->setsize); ) {
1271 Int cmp;
njnca82cc02004-11-22 17:18:48 +00001272 tl_assert(iret < ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001273
1274 if ((ia < a->setsize) && (ib < b->setsize))
1275 cmp = mutex_cmp(a->mutex[ia], b->mutex[ib]);
1276 else if (ia == a->setsize)
1277 cmp = 1;
1278 else
1279 cmp = -1;
1280
1281 if (cmp == 0) {
1282 ret->mutex[iret++] = a->mutex[ia];
1283 ia++;
1284 ib++;
1285 } else if (cmp < 0) {
1286 ret->mutex[iret++] = a->mutex[ia];
1287 ia++;
1288 } else {
njnca82cc02004-11-22 17:18:48 +00001289 tl_assert(cmp > 0);
sewardj4bffb232002-11-13 21:46:34 +00001290 ret->mutex[iret++] = b->mutex[ib];
1291 ib++;
1292 }
1293 }
1294
njnca82cc02004-11-22 17:18:48 +00001295 tl_assert(iret == ret->setsize);
sewardj4bffb232002-11-13 21:46:34 +00001296
1297 ret->hash = hash_LockSet(ret);
1298
sewardjc26cc252002-10-23 21:58:55 +00001299 /* Now search for it in the table, adding it if not seen before */
sewardj4bffb232002-11-13 21:46:34 +00001300 found = lookup_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001301
sewardj4bffb232002-11-13 21:46:34 +00001302 if (found != NULL) {
1303 if (debug)
1304 print_LockSet("union found existing set", found);
1305 free_LockSet(ret);
sewardjc26cc252002-10-23 21:58:55 +00001306 } else {
sewardj4bffb232002-11-13 21:46:34 +00001307 if (debug)
1308 print_LockSet("union inserting new set", ret);
1309 insert_LockSet(ret);
1310 found = ret;
sewardjc26cc252002-10-23 21:58:55 +00001311 }
1312
sewardj4bffb232002-11-13 21:46:34 +00001313 if (debug || LOCKSET_SANITY) {
1314 print_LockSet("union-OUT", found);
sewardjc26cc252002-10-23 21:58:55 +00001315 sanity_check_locksets("union-OUT");
sewardj4bffb232002-11-13 21:46:34 +00001316 }
sewardjc26cc252002-10-23 21:58:55 +00001317
sewardj4bffb232002-11-13 21:46:34 +00001318 return found;
sewardjc26cc252002-10-23 21:58:55 +00001319}
1320
1321/*------------------------------------------------------------*/
sewardjdac0a442002-11-13 22:08:40 +00001322/*--- Implementation of mutex structure. ---*/
1323/*------------------------------------------------------------*/
sewardjc26cc252002-10-23 21:58:55 +00001324
1325static UInt graph_mark; /* current mark we're using for graph traversal */
1326
sewardj39a4d842002-11-13 22:14:30 +00001327static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardjc26cc252002-10-23 21:58:55 +00001328 Char *str, ExeContext *ec);
sewardj39a4d842002-11-13 22:14:30 +00001329static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00001330 const LockSet *lockset_holding,
1331 const LockSet *lockset_prev);
sewardjc26cc252002-10-23 21:58:55 +00001332
njn72718642003-07-24 08:45:32 +00001333static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid);
sewardjdac0a442002-11-13 22:08:40 +00001334
1335#define M_MUTEX_HASHSZ 1021
1336
sewardj39a4d842002-11-13 22:14:30 +00001337static Mutex *mutex_hash[M_MUTEX_HASHSZ];
sewardjdac0a442002-11-13 22:08:40 +00001338static UInt total_mutexes;
1339
1340static const Char *pp_MutexState(MutexState st)
1341{
1342 switch(st) {
1343 case MxLocked: return "Locked";
1344 case MxUnlocked: return "Unlocked";
1345 case MxDead: return "Dead";
1346 case MxUnknown: return "Unknown";
1347 }
1348 return "???";
1349}
1350
tom151a6392005-11-11 12:30:36 +00001351static void pp_all_mutexes(void)
sewardjdac0a442002-11-13 22:08:40 +00001352{
1353 Int i;
1354 Int locks, buckets;
1355
1356 locks = buckets = 0;
1357 for(i = 0; i < M_MUTEX_HASHSZ; i++) {
sewardj39a4d842002-11-13 22:14:30 +00001358 Mutex *mx;
sewardjdac0a442002-11-13 22:08:40 +00001359 Bool first = True;
1360
1361 for(mx = mutex_hash[i]; mx != NULL; mx = mx->next) {
1362 if (first) {
1363 buckets++;
1364 VG_(printf)("[%4d] = ", i);
1365 } else
1366 VG_(printf)(" ");
1367 locks++;
1368 first = False;
1369 VG_(printf)("%p [%8s] -> %p%(y\n",
1370 mx, pp_MutexState(mx->state), mx->mutexp, mx->mutexp);
1371 }
1372 }
1373
1374 VG_(printf)("%d locks in %d buckets (%d allocated)\n",
1375 locks, buckets, total_mutexes);
1376}
sewardjc26cc252002-10-23 21:58:55 +00001377
sewardj39a4d842002-11-13 22:14:30 +00001378/* find or create a Mutex for a program's mutex use */
1379static Mutex *get_mutex(Addr mutexp)
sewardjc26cc252002-10-23 21:58:55 +00001380{
nethercote50397c22004-11-04 18:03:06 +00001381 UInt bucket = mutexp % M_MUTEX_HASHSZ;
sewardj39a4d842002-11-13 22:14:30 +00001382 Mutex *mp;
sewardjc26cc252002-10-23 21:58:55 +00001383
1384 for(mp = mutex_hash[bucket]; mp != NULL; mp = mp->next)
1385 if (mp->mutexp == mutexp)
1386 return mp;
1387
sewardjdac0a442002-11-13 22:08:40 +00001388 total_mutexes++;
1389
sewardjc26cc252002-10-23 21:58:55 +00001390 mp = VG_(malloc)(sizeof(*mp));
1391 mp->mutexp = mutexp;
1392 mp->next = mutex_hash[bucket];
1393 mutex_hash[bucket] = mp;
1394
1395 mp->state = MxUnknown;
1396 mp->tid = VG_INVALID_THREADID;
1397 mp->location = NULL;
1398
sewardj4bffb232002-11-13 21:46:34 +00001399 mp->lockdep = emptyset;
sewardjc26cc252002-10-23 21:58:55 +00001400 mp->mark = graph_mark - 1;
1401
1402 return mp;
1403}
1404
sewardjdac0a442002-11-13 22:08:40 +00001405/* Find all mutexes in a range of memory, and call the callback.
1406 Remove the mutex from the hash if the callback returns True (mutex
1407 structure itself is not freed, because it may be pointed to by a
1408 LockSet. */
sewardj39a4d842002-11-13 22:14:30 +00001409static void find_mutex_range(Addr start, Addr end, Bool (*action)(Mutex *))
sewardjc26cc252002-10-23 21:58:55 +00001410{
sewardjdac0a442002-11-13 22:08:40 +00001411 UInt first = start % M_MUTEX_HASHSZ;
1412 UInt last = (end+1) % M_MUTEX_HASHSZ;
1413 UInt i;
1414
1415 /* Single pass over the hash table, looking for likely hashes */
1416 for(i = first; i != last; ) {
sewardj39a4d842002-11-13 22:14:30 +00001417 Mutex *mx;
1418 Mutex **prev = &mutex_hash[i];
sewardjdac0a442002-11-13 22:08:40 +00001419
1420 for(mx = mutex_hash[i]; mx != NULL; prev = &mx->next, mx = mx->next) {
1421 if (mx->mutexp >= start && mx->mutexp < end && (*action)(mx))
1422 *prev = mx->next;
1423 }
1424
1425 if (++i == M_MUTEX_HASHSZ)
1426 i = 0;
sewardjc26cc252002-10-23 21:58:55 +00001427 }
sewardjc26cc252002-10-23 21:58:55 +00001428}
1429
1430#define MARK_LOOP (graph_mark+0)
1431#define MARK_DONE (graph_mark+1)
1432
thughes4ad52d02004-06-27 17:37:21 +00001433static Bool check_cycle_inner(const Mutex *mutex, const LockSet *ls)
1434{
1435 static const Bool debug = False;
1436 Int i;
1437
1438 if (mutex->mark == MARK_LOOP)
1439 return True; /* found cycle */
1440 if (mutex->mark == MARK_DONE)
1441 return False; /* been here before, its OK */
1442
1443 ((Mutex*)mutex)->mark = MARK_LOOP;
1444
1445 if (debug)
1446 VG_(printf)("mark=%d visiting %p%(y mutex->lockset=%d\n",
1447 graph_mark, mutex->mutexp, mutex->mutexp, mutex->lockdep);
1448 for(i = 0; i < ls->setsize; i++) {
1449 const Mutex *mx = ls->mutex[i];
1450
1451 if (debug)
1452 VG_(printf)(" %y ls=%p (ls->mutex=%p%(y)\n",
1453 mutex->mutexp, ls,
1454 mx->mutexp, mx->mutexp);
1455 if (check_cycle_inner(mx, mx->lockdep))
1456 return True;
1457 }
1458 ((Mutex*)mutex)->mark = MARK_DONE;
1459
1460 return False;
1461}
1462
sewardj39a4d842002-11-13 22:14:30 +00001463static Bool check_cycle(const Mutex *start, const LockSet* lockset)
sewardjc26cc252002-10-23 21:58:55 +00001464{
sewardjff2c9232002-11-13 21:44:39 +00001465
sewardjc26cc252002-10-23 21:58:55 +00001466 graph_mark += 2; /* clear all marks */
1467
sewardj4bffb232002-11-13 21:46:34 +00001468 return check_cycle_inner(start, lockset);
sewardjc26cc252002-10-23 21:58:55 +00001469}
1470
sewardjdca84112002-11-13 22:29:34 +00001471/* test to see if a mutex state change would be problematic; this
1472 makes no changes to the mutex state. This should be called before
1473 the locking thread has actually blocked. */
njn72718642003-07-24 08:45:32 +00001474static void test_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjc26cc252002-10-23 21:58:55 +00001475{
1476 static const Bool debug = False;
1477
sewardjc26cc252002-10-23 21:58:55 +00001478 if (mutex->state == MxDead) {
sewardjdac0a442002-11-13 22:08:40 +00001479 Char *str;
1480
1481 switch(state) {
1482 case MxLocked: str = "lock dead mutex"; break;
1483 case MxUnlocked: str = "unlock dead mutex"; break;
1484 default: str = "operate on dead mutex"; break;
1485 }
1486
sewardjc26cc252002-10-23 21:58:55 +00001487 /* can't do anything legal to a destroyed mutex */
sewardjdac0a442002-11-13 22:08:40 +00001488 record_mutex_error(tid, mutex, str, mutex->location);
sewardjc26cc252002-10-23 21:58:55 +00001489 return;
1490 }
1491
1492 switch(state) {
1493 case MxLocked:
njnca82cc02004-11-22 17:18:48 +00001494 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjdca84112002-11-13 22:29:34 +00001495
1496 if (debug)
1497 print_LockSet("thread holding", thread_locks[tid]);
1498
1499 if (check_cycle(mutex, thread_locks[tid]))
1500 record_lockgraph_error(tid, mutex, thread_locks[tid], mutex->lockdep);
1501 else {
1502 mutex->lockdep = ls_union(mutex->lockdep, thread_locks[tid]);
1503
1504 if (debug) {
1505 VG_(printf)("giving mutex %p%(y lockdep = %p ",
1506 mutex->mutexp, mutex->mutexp, mutex->lockdep);
1507 print_LockSet("lockdep", mutex->lockdep);
1508 }
1509 }
1510 break;
1511
1512 case MxUnlocked:
1513 if (debug)
1514 print_LockSet("thread holding", thread_locks[tid]);
1515
1516 if (mutex->state != MxLocked) {
1517 record_mutex_error(tid, mutex,
1518 "unlock non-locked mutex", mutex->location);
1519 }
1520 if (mutex->tid != tid) {
1521 record_mutex_error(tid, mutex,
1522 "unlock someone else's mutex", mutex->location);
1523 }
1524 break;
1525
1526 case MxDead:
1527 break;
1528
1529 default:
1530 break;
1531 }
1532}
1533
1534/* Update a mutex state. Expects most error testing and reporting to
1535 have happened in test_mutex_state(). The assumption is that no
1536 client code is run by thread tid between test and set, either
1537 because it is blocked or test and set are called together
1538 atomically.
1539
1540 Setting state to MxDead is the exception, since that can happen as
1541 a result of any thread freeing memory; in this case set_mutex_state
1542 does all the error reporting as well.
1543*/
njn72718642003-07-24 08:45:32 +00001544static void set_mutex_state(Mutex *mutex, MutexState state, ThreadId tid)
sewardjdca84112002-11-13 22:29:34 +00001545{
1546 static const Bool debug = False;
1547
1548 if (debug)
1549 VG_(printf)("\ntid %d changing mutex (%p)->%p%(y state %s -> %s\n",
1550 tid, mutex, mutex->mutexp, mutex->mutexp,
1551 pp_MutexState(mutex->state), pp_MutexState(state));
1552
1553 if (mutex->state == MxDead) {
1554 /* can't do anything legal to a destroyed mutex */
1555 return;
1556 }
1557
1558 switch(state) {
1559 case MxLocked:
sewardj4bffb232002-11-13 21:46:34 +00001560 if (mutex->state == MxLocked) {
1561 if (mutex->tid != tid)
1562 record_mutex_error(tid, mutex, "take lock held by someone else",
1563 mutex->location);
1564 else
1565 record_mutex_error(tid, mutex, "take lock we already hold",
1566 mutex->location);
1567
njn67993252004-11-22 18:02:32 +00001568 VG_(tool_panic)("core should have checked this\n");
sewardj4bffb232002-11-13 21:46:34 +00001569 break;
1570 }
sewardjc26cc252002-10-23 21:58:55 +00001571
njnca82cc02004-11-22 17:18:48 +00001572 tl_assert(!check_cycle(mutex, mutex->lockdep));
sewardjc26cc252002-10-23 21:58:55 +00001573
sewardjc26cc252002-10-23 21:58:55 +00001574 mutex->tid = tid;
1575 break;
1576
1577 case MxUnlocked:
1578 if (debug)
sewardj4bffb232002-11-13 21:46:34 +00001579 print_LockSet("thread holding", thread_locks[tid]);
sewardjc26cc252002-10-23 21:58:55 +00001580
sewardjdca84112002-11-13 22:29:34 +00001581 if (mutex->state != MxLocked || mutex->tid != tid)
1582 break;
1583
sewardjc26cc252002-10-23 21:58:55 +00001584 mutex->tid = VG_INVALID_THREADID;
1585 break;
1586
sewardjdac0a442002-11-13 22:08:40 +00001587 case MxDead:
1588 if (mutex->state == MxLocked) {
1589 /* forcably remove offending lock from thread's lockset */
njnca82cc02004-11-22 17:18:48 +00001590 tl_assert(ismember(thread_locks[mutex->tid], mutex));
sewardjdac0a442002-11-13 22:08:40 +00001591 thread_locks[mutex->tid] = remove_LockSet(thread_locks[mutex->tid], mutex);
1592 mutex->tid = VG_INVALID_THREADID;
1593
1594 record_mutex_error(tid, mutex,
1595 "free locked mutex", mutex->location);
1596 }
1597 break;
1598
sewardjc26cc252002-10-23 21:58:55 +00001599 default:
1600 break;
1601 }
1602
njnd01fef72005-03-25 23:35:48 +00001603 mutex->location = VG_(record_ExeContext)(tid);
sewardjc26cc252002-10-23 21:58:55 +00001604 mutex->state = state;
1605}
njn25e49d8e72002-09-23 09:36:25 +00001606
1607/*------------------------------------------------------------*/
1608/*--- Setting and checking permissions. ---*/
1609/*------------------------------------------------------------*/
1610
thughes4ad52d02004-06-27 17:37:21 +00001611/* only clean up dead mutexes */
1612static
1613Bool cleanmx(Mutex *mx) {
1614 return mx->state == MxDead;
1615}
1616
njn25e49d8e72002-09-23 09:36:25 +00001617static
nethercote451eae92004-11-02 13:06:32 +00001618void set_address_range_state ( Addr a, SizeT len /* in bytes */,
njn25e49d8e72002-09-23 09:36:25 +00001619 VgeInitStatus status )
1620{
sewardj1806d7f2002-10-22 05:05:49 +00001621 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00001622
1623# if DEBUG_MAKE_ACCESSES
1624 VG_(printf)("make_access: 0x%x, %u, status=%u\n", a, len, status);
1625# endif
1626 //PROF_EVENT(30); PPP
1627
1628 if (len == 0)
1629 return;
1630
1631 if (len > 100 * 1000 * 1000)
1632 VG_(message)(Vg_UserMsg,
1633 "Warning: set address range state: large range %d",
1634 len);
1635
sewardjdac0a442002-11-13 22:08:40 +00001636 /* Remove mutexes in recycled memory range from hash */
1637 find_mutex_range(a, a+len, cleanmx);
1638
njn25e49d8e72002-09-23 09:36:25 +00001639 /* Memory block may not be aligned or a whole word multiple. In neat cases,
1640 * we have to init len/4 words (len is in bytes). In nasty cases, it's
1641 * len/4+1 words. This works out which it is by aligning the block and
1642 * seeing if the end byte is in the same word as it is for the unaligned
1643 * block; if not, it's the awkward case. */
njn13bfd852005-06-02 03:52:53 +00001644 end = VG_ROUNDUP(a + len, 4);
1645 a = VG_ROUNDDN(a, 4);
njn25e49d8e72002-09-23 09:36:25 +00001646
1647 /* Do it ... */
1648 switch (status) {
1649 case Vge_VirginInit:
1650 for ( ; a < end; a += 4) {
1651 //PROF_EVENT(31); PPP
1652 init_virgin_sword(a);
1653 }
1654 break;
1655
1656 case Vge_NonVirginInit:
1657 for ( ; a < end; a += 4) {
1658 //PROF_EVENT(31); PPP
1659 init_nonvirgin_sword(a);
1660 }
1661 break;
1662
1663 case Vge_SegmentInit:
1664 for ( ; a < end; a += 4) {
1665 //PROF_EVENT(31); PPP
1666 init_magically_inited_sword(a);
1667 }
1668 break;
sewardj7f3ad222002-11-13 22:11:53 +00001669
1670 case Vge_Error:
1671 for ( ; a < end; a += 4) {
1672 //PROF_EVENT(31); PPP
1673 init_error_sword(a);
1674 }
1675 break;
njn25e49d8e72002-09-23 09:36:25 +00001676
1677 default:
1678 VG_(printf)("init_status = %u\n", status);
njn67993252004-11-22 18:02:32 +00001679 VG_(tool_panic)("Unexpected Vge_InitStatus");
njn25e49d8e72002-09-23 09:36:25 +00001680 }
njn25e49d8e72002-09-23 09:36:25 +00001681}
1682
1683
nethercote451eae92004-11-02 13:06:32 +00001684static void make_segment_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001685{
1686 //PROF_EVENT(??); PPP
1687 set_address_range_state ( a, len, Vge_SegmentInit );
1688}
1689
nethercote451eae92004-11-02 13:06:32 +00001690static void make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001691{
1692 //PROF_EVENT(36); PPP
1693 set_address_range_state( a, len, Vge_VirginInit );
1694}
1695
nethercote451eae92004-11-02 13:06:32 +00001696static void make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001697{
1698 //PROF_EVENT(37); PPP
sewardj499e3de2002-11-13 22:22:25 +00001699 set_address_range_state( a, len, Vge_VirginInit );
njn25e49d8e72002-09-23 09:36:25 +00001700}
1701
1702
njn25e49d8e72002-09-23 09:36:25 +00001703/* Block-copy states (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +00001704static void copy_address_range_state(Addr src, Addr dst, SizeT len)
njn25e49d8e72002-09-23 09:36:25 +00001705{
1706 UInt i;
1707
1708 //PROF_EVENT(40); PPP
1709 for (i = 0; i < len; i += 4) {
1710 shadow_word sword = *(get_sword_addr ( src+i ));
1711 //PROF_EVENT(41); PPP
1712 set_sword ( dst+i, sword );
1713 }
1714}
1715
1716// SSS: put these somewhere better
njnfbdcba92005-05-09 01:23:49 +00001717static void hg_mem_read (Addr a, SizeT data_size, ThreadId tid);
1718static void hg_mem_write(Addr a, SizeT data_size, ThreadId tid);
sewardja5b3aec2002-10-22 05:09:36 +00001719
njnadb7a752005-06-11 01:30:57 +00001720__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001721static void hg_mem_help_read_1(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_2(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_4(Addr a) VG_REGPARM(1);
njnadb7a752005-06-11 01:30:57 +00001726__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001727static void hg_mem_help_read_N(Addr a, SizeT size) VG_REGPARM(2);
sewardja5b3aec2002-10-22 05:09:36 +00001728
njnadb7a752005-06-11 01:30:57 +00001729__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001730static void hg_mem_help_write_1(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_2(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_4(Addr a, UInt val) VG_REGPARM(2);
njnadb7a752005-06-11 01:30:57 +00001735__attribute__((unused))
njnaf839f52005-06-23 03:27:57 +00001736static void hg_mem_help_write_N(Addr a, SizeT size) VG_REGPARM(2);
njn25e49d8e72002-09-23 09:36:25 +00001737
njnadb7a752005-06-11 01:30:57 +00001738__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001739static void bus_lock(void);
njnadb7a752005-06-11 01:30:57 +00001740__attribute__((unused))
sewardj7a5ebcf2002-11-13 22:42:13 +00001741static void bus_unlock(void);
1742
njn25e49d8e72002-09-23 09:36:25 +00001743static
njnfbdcba92005-05-09 01:23:49 +00001744void hg_pre_mem_read(CorePart part, ThreadId tid,
1745 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001746{
njn02bc4b82005-05-15 17:28:26 +00001747 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 +00001748 hg_mem_read(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001749}
1750
1751static
njnfbdcba92005-05-09 01:23:49 +00001752void hg_pre_mem_read_asciiz(CorePart part, ThreadId tid,
1753 Char* s, Addr base )
njn25e49d8e72002-09-23 09:36:25 +00001754{
njnfbdcba92005-05-09 01:23:49 +00001755 hg_mem_read(base, VG_(strlen)((Char*)base), tid);
njn25e49d8e72002-09-23 09:36:25 +00001756}
1757
1758static
njnfbdcba92005-05-09 01:23:49 +00001759void hg_pre_mem_write(CorePart part, ThreadId tid,
1760 Char* s, Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00001761{
njnfbdcba92005-05-09 01:23:49 +00001762 hg_mem_write(base, size, tid);
njn25e49d8e72002-09-23 09:36:25 +00001763}
1764
1765
1766
1767static
njnfbdcba92005-05-09 01:23:49 +00001768void hg_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00001769{
njn1f3a9092002-10-04 09:22:30 +00001770 /* Ignore the permissions, just make it readable. Seems to work... */
njn25e49d8e72002-09-23 09:36:25 +00001771 make_segment_readable(a, len);
1772}
1773
1774
1775static
njnfbdcba92005-05-09 01:23:49 +00001776void hg_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +00001777{
1778 if (is_inited) {
1779 make_readable(a, len);
1780 } else {
1781 make_writable(a, len);
1782 }
1783}
1784
1785static
njnfbdcba92005-05-09 01:23:49 +00001786void hg_set_perms (Addr a, SizeT len,
1787 Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +00001788{
1789 if (rr) make_readable(a, len);
1790 else if (ww) make_writable(a, len);
1791 /* else do nothing */
1792}
1793
sewardjf6374322002-11-13 22:35:55 +00001794static
njnfbdcba92005-05-09 01:23:49 +00001795void hg_new_mem_stack_private(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001796{
1797 set_address_range_state(a, len, Vge_NonVirginInit);
1798}
1799
1800static
njnfbdcba92005-05-09 01:23:49 +00001801void hg_new_mem_stack(Addr a, SizeT len)
sewardjf6374322002-11-13 22:35:55 +00001802{
1803 set_address_range_state(a, len, Vge_VirginInit);
1804}
njn25e49d8e72002-09-23 09:36:25 +00001805
1806/*--------------------------------------------------------------*/
1807/*--- Initialise the memory audit system on program startup. ---*/
1808/*--------------------------------------------------------------*/
1809
1810static
1811void init_shadow_memory(void)
1812{
1813 Int i;
1814
1815 for (i = 0; i < ESEC_MAP_WORDS; i++)
1816 distinguished_secondary_map.swords[i] = virgin_sword;
1817
1818 /* These entries gradually get overwritten as the used address
1819 space expands. */
1820 for (i = 0; i < 65536; i++)
1821 primary_map[i] = &distinguished_secondary_map;
1822}
1823
1824
njn3e884182003-04-15 13:03:23 +00001825/*------------------------------------------------------------*/
1826/*--- malloc() et al replacements ---*/
1827/*------------------------------------------------------------*/
1828
njnb4aee052003-04-15 14:09:58 +00001829static VgHashTable hg_malloc_list = NULL;
njn3e884182003-04-15 13:03:23 +00001830
1831#define N_FREED_CHUNKS 2
1832static Int freechunkptr = 0;
1833static HG_Chunk *freechunks[N_FREED_CHUNKS];
1834
njn3e884182003-04-15 13:03:23 +00001835
1836/* Allocate a user-chunk of size bytes. Also allocate its shadow
1837 block, make the shadow block point at the user block. Put the
1838 shadow chunk on the appropriate list, and set all memory
1839 protections correctly. */
1840
nethercote7ac7f7b2004-11-02 12:36:02 +00001841static void add_HG_Chunk ( ThreadId tid, Addr p, SizeT size )
njn3e884182003-04-15 13:03:23 +00001842{
1843 HG_Chunk* hc;
1844
1845 hc = VG_(malloc)(sizeof(HG_Chunk));
1846 hc->data = p;
1847 hc->size = size;
njnd01fef72005-03-25 23:35:48 +00001848 hc->where = VG_(record_ExeContext)(tid);
njn72718642003-07-24 08:45:32 +00001849 hc->tid = tid;
njn3e884182003-04-15 13:03:23 +00001850
1851 VG_(HT_add_node)( hg_malloc_list, (VgHashNode*)hc );
1852}
1853
1854/* Allocate memory and note change in memory available */
1855static __inline__
njn14d01ce2004-11-26 11:30:14 +00001856void* alloc_and_new_mem ( ThreadId tid, SizeT size, SizeT alignment,
1857 Bool is_zeroed )
njn3e884182003-04-15 13:03:23 +00001858{
1859 Addr p;
1860
njn34ac0272003-09-30 14:20:00 +00001861 if (size < 0) return NULL;
1862
njn3e884182003-04-15 13:03:23 +00001863 p = (Addr)VG_(cli_malloc)(alignment, size);
nethercote57e36b32004-07-10 14:56:28 +00001864 if (!p) {
1865 return NULL;
1866 }
njn34ac0272003-09-30 14:20:00 +00001867 if (is_zeroed) VG_(memset)((void*)p, 0, size);
njn14d01ce2004-11-26 11:30:14 +00001868 add_HG_Chunk ( tid, p, size );
njnfbdcba92005-05-09 01:23:49 +00001869 hg_new_mem_heap( p, size, is_zeroed );
njn3e884182003-04-15 13:03:23 +00001870
1871 return (void*)p;
1872}
1873
njn51d827b2005-05-09 01:02:08 +00001874static void* hg_malloc ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001875{
njn14d01ce2004-11-26 11:30:14 +00001876 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001877}
1878
njn51d827b2005-05-09 01:02:08 +00001879static void* hg___builtin_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001880{
njn14d01ce2004-11-26 11:30:14 +00001881 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001882}
1883
njn51d827b2005-05-09 01:02:08 +00001884static void* hg___builtin_vec_new ( ThreadId tid, SizeT n )
njn3e884182003-04-15 13:03:23 +00001885{
njn14d01ce2004-11-26 11:30:14 +00001886 return alloc_and_new_mem ( tid, n, VG_(clo_alignment), /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001887}
1888
njn51d827b2005-05-09 01:02:08 +00001889static void* hg_memalign ( ThreadId tid, SizeT align, SizeT n )
njn3e884182003-04-15 13:03:23 +00001890{
njn14d01ce2004-11-26 11:30:14 +00001891 return alloc_and_new_mem ( tid, n, align, /*is_zeroed*/False );
njn3e884182003-04-15 13:03:23 +00001892}
1893
njn51d827b2005-05-09 01:02:08 +00001894static void* hg_calloc ( ThreadId tid, SizeT nmemb, SizeT size )
njn3e884182003-04-15 13:03:23 +00001895{
njn14d01ce2004-11-26 11:30:14 +00001896 return alloc_and_new_mem ( tid, nmemb*size, VG_(clo_alignment),
njn34ac0272003-09-30 14:20:00 +00001897 /*is_zeroed*/True );
njn3e884182003-04-15 13:03:23 +00001898}
1899
thughes4ad52d02004-06-27 17:37:21 +00001900static ThreadId deadmx_tid;
1901
1902static
1903Bool deadmx(Mutex *mx) {
1904 if (mx->state != MxDead)
1905 set_mutex_state(mx, MxDead, deadmx_tid);
1906
1907 return False;
1908}
1909
njn3e884182003-04-15 13:03:23 +00001910static
njn72718642003-07-24 08:45:32 +00001911void die_and_free_mem ( ThreadId tid, HG_Chunk* hc,
njn3e884182003-04-15 13:03:23 +00001912 HG_Chunk** prev_chunks_next_ptr )
1913{
njn72718642003-07-24 08:45:32 +00001914 Addr start = hc->data;
1915 Addr end = start + hc->size;
njn3e884182003-04-15 13:03:23 +00001916
njn3e884182003-04-15 13:03:23 +00001917 /* Remove hc from the malloclist using prev_chunks_next_ptr to
1918 avoid repeating the hash table lookup. Can't remove until at least
1919 after free and free_mismatch errors are done because they use
1920 describe_addr() which looks for it in malloclist. */
1921 *prev_chunks_next_ptr = hc->next;
1922
1923 /* Record where freed */
njnd01fef72005-03-25 23:35:48 +00001924 hc->where = VG_(record_ExeContext) ( tid );
njn3e884182003-04-15 13:03:23 +00001925
1926 /* maintain a small window so that the error reporting machinery
1927 knows about this memory */
1928 if (freechunks[freechunkptr] != NULL) {
1929 /* free HG_Chunk */
1930 HG_Chunk* sc1 = freechunks[freechunkptr];
1931 VG_(cli_free) ( (void*)(sc1->data) );
1932 VG_(free) ( sc1 );
1933 }
1934
1935 freechunks[freechunkptr] = hc;
1936
1937 if (++freechunkptr == N_FREED_CHUNKS)
1938 freechunkptr = 0;
1939
1940 /* mark all mutexes in range dead */
thughes4ad52d02004-06-27 17:37:21 +00001941 deadmx_tid = tid;
njn3e884182003-04-15 13:03:23 +00001942 find_mutex_range(start, end, deadmx);
1943}
1944
1945
1946static __inline__
njn14d01ce2004-11-26 11:30:14 +00001947void handle_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001948{
1949 HG_Chunk* hc;
1950 HG_Chunk** prev_chunks_next_ptr;
sewardj3f94a7d2007-08-25 07:19:08 +00001951 /* Commented out 25 Aug 07 as VG_(HT_get_node) no longer exists.
nethercote3d6b6112004-11-04 16:39:43 +00001952 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001953 (VgHashNode***)&prev_chunks_next_ptr );
sewardj3f94a7d2007-08-25 07:19:08 +00001954 */
njn3e884182003-04-15 13:03:23 +00001955 if (hc == NULL) {
1956 return;
1957 }
njn14d01ce2004-11-26 11:30:14 +00001958 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00001959}
1960
njn51d827b2005-05-09 01:02:08 +00001961static void hg_free ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001962{
njn14d01ce2004-11-26 11:30:14 +00001963 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001964}
1965
njn51d827b2005-05-09 01:02:08 +00001966static void hg___builtin_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001967{
njn14d01ce2004-11-26 11:30:14 +00001968 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001969}
1970
njn51d827b2005-05-09 01:02:08 +00001971static void hg___builtin_vec_delete ( ThreadId tid, void* p )
njn3e884182003-04-15 13:03:23 +00001972{
njn14d01ce2004-11-26 11:30:14 +00001973 handle_free(tid, p);
njn3e884182003-04-15 13:03:23 +00001974}
1975
njn51d827b2005-05-09 01:02:08 +00001976static void* hg_realloc ( ThreadId tid, void* p, SizeT new_size )
njn3e884182003-04-15 13:03:23 +00001977{
1978 HG_Chunk *hc;
1979 HG_Chunk **prev_chunks_next_ptr;
njn3e884182003-04-15 13:03:23 +00001980
1981 /* First try and find the block. */
sewardj3f94a7d2007-08-25 07:19:08 +00001982 /* Commented out 25 Aug 07 as VG_(HT_get_node) no longer exists.
nethercote3d6b6112004-11-04 16:39:43 +00001983 hc = (HG_Chunk*)VG_(HT_get_node) ( hg_malloc_list, (UWord)p,
njn3e884182003-04-15 13:03:23 +00001984 (VgHashNode***)&prev_chunks_next_ptr );
sewardj3f94a7d2007-08-25 07:19:08 +00001985 */
njn3e884182003-04-15 13:03:23 +00001986 if (hc == NULL) {
1987 return NULL;
1988 }
1989
1990 if (hc->size == new_size) {
1991 /* size unchanged */
njnd01fef72005-03-25 23:35:48 +00001992 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001993 return p;
1994
1995 } else if (hc->size > new_size) {
1996 /* new size is smaller */
1997 hc->size = new_size;
njnd01fef72005-03-25 23:35:48 +00001998 hc->where = VG_(record_ExeContext)(tid);
njn3e884182003-04-15 13:03:23 +00001999 return p;
2000
2001 } else {
2002 /* new size is bigger */
2003 Addr p_new;
2004
2005 /* Get new memory */
2006 p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
2007
tom0cd42f02005-10-06 09:00:17 +00002008 if (p_new) {
2009 /* First half kept and copied, second half new */
2010 copy_address_range_state( (Addr)p, p_new, hc->size );
2011 hg_new_mem_heap ( p_new+hc->size, new_size-hc->size,
2012 /*inited*/False );
njn3e884182003-04-15 13:03:23 +00002013
tom0cd42f02005-10-06 09:00:17 +00002014 /* Copy from old to new */
2015 VG_(memcpy)((void *)p_new, p, hc->size);
njn3e884182003-04-15 13:03:23 +00002016
tom0cd42f02005-10-06 09:00:17 +00002017 /* Free old memory */
2018 die_and_free_mem ( tid, hc, prev_chunks_next_ptr );
njn3e884182003-04-15 13:03:23 +00002019
tom0cd42f02005-10-06 09:00:17 +00002020 /* this has to be after die_and_free_mem, otherwise the
2021 former succeeds in shorting out the new block, not the
2022 old, in the case when both are on the same list. */
2023 add_HG_Chunk ( tid, p_new, new_size );
2024 }
njn3e884182003-04-15 13:03:23 +00002025
2026 return (void*)p_new;
2027 }
2028}
2029
njn25e49d8e72002-09-23 09:36:25 +00002030/*--------------------------------------------------------------*/
2031/*--- Machinery to support sanity checking ---*/
2032/*--------------------------------------------------------------*/
2033
njn51d827b2005-05-09 01:02:08 +00002034static Bool hg_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00002035{
jseward9800fd32004-01-04 23:08:04 +00002036 /* nothing useful we can rapidly check */
2037 return True;
njn25e49d8e72002-09-23 09:36:25 +00002038}
2039
njn51d827b2005-05-09 01:02:08 +00002040static Bool hg_expensive_sanity_check(void)
njn25e49d8e72002-09-23 09:36:25 +00002041{
2042 Int i;
2043
2044 /* Make sure nobody changed the distinguished secondary. */
2045 for (i = 0; i < ESEC_MAP_WORDS; i++)
2046 if (distinguished_secondary_map.swords[i].other != virgin_sword.other ||
2047 distinguished_secondary_map.swords[i].state != virgin_sword.state)
2048 return False;
2049
2050 return True;
2051}
2052
2053
2054/*--------------------------------------------------------------*/
2055/*--- Instrumentation ---*/
2056/*--------------------------------------------------------------*/
2057
sewardjf6374322002-11-13 22:35:55 +00002058static UInt stk_ld, nonstk_ld, stk_st, nonstk_st;
2059
njn14d01ce2004-11-26 11:30:14 +00002060#if 0
njn25e49d8e72002-09-23 09:36:25 +00002061/* Create and return an instrumented version of cb_in. Free cb_in
2062 before returning. */
njn26f02512004-11-22 18:33:15 +00002063UCodeBlock* TL_(instrument) ( UCodeBlock* cb_in, Addr not_used )
njn25e49d8e72002-09-23 09:36:25 +00002064{
2065 UCodeBlock* cb;
2066 Int i;
2067 UInstr* u_in;
2068 Int t_size = INVALID_TEMPREG;
sewardjf6374322002-11-13 22:35:55 +00002069 Int ntemps;
2070 Bool *stackref = NULL;
sewardj7a5ebcf2002-11-13 22:42:13 +00002071 Bool locked = False; /* lock prefix */
njn25e49d8e72002-09-23 09:36:25 +00002072
njn810086f2002-11-14 12:42:47 +00002073 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002074
sewardjf6374322002-11-13 22:35:55 +00002075 /* stackref[] is used for super-simple value tracking to keep note
2076 of which tempregs currently hold a value which is derived from
nethercoteca788ff2004-10-20 10:58:09 +00002077 the stack pointer or frame pointer, and is therefore likely
2078 stack-relative if used as the address for LOAD or STORE. */
njn810086f2002-11-14 12:42:47 +00002079 ntemps = VG_(get_num_temps)(cb);
sewardjf6374322002-11-13 22:35:55 +00002080 stackref = VG_(malloc)(sizeof(*stackref) * ntemps);
2081 VG_(memset)(stackref, 0, sizeof(*stackref) * ntemps);
2082
njn810086f2002-11-14 12:42:47 +00002083 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
2084 u_in = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +00002085
njn25e49d8e72002-09-23 09:36:25 +00002086 switch (u_in->opcode) {
2087
2088 case NOP: case CALLM_S: case CALLM_E:
2089 break;
sewardjf6374322002-11-13 22:35:55 +00002090
sewardj7a5ebcf2002-11-13 22:42:13 +00002091 case LOCK:
2092 locked = True;
2093 uInstr0(cb, CCALL, 0);
2094 uCCall(cb, (Addr)bus_lock, 0, 0, False);
2095 break;
2096
2097 case JMP: case INCEIP:
2098 if (locked) {
2099 uInstr0(cb, CCALL, 0);
2100 uCCall(cb, (Addr)bus_unlock, 0, 0, False);
2101 }
2102 locked = False;
2103 VG_(copy_UInstr)(cb, u_in);
2104 break;
2105
sewardjf6374322002-11-13 22:35:55 +00002106 case GET:
njnca82cc02004-11-22 17:18:48 +00002107 tl_assert(u_in->tag1 == ArchReg);
2108 tl_assert(u_in->tag2 == TempReg);
2109 tl_assert(u_in->val2 < ntemps);
sewardjf6374322002-11-13 22:35:55 +00002110
2111 stackref[u_in->val2] = (u_in->size == 4 &&
njnaf839f52005-06-23 03:27:57 +00002112 (u_in->val1 == VG_R_STACK_PTR ||
2113 u_in->val1 == VG_R_FRAME_PTR));
sewardjf6374322002-11-13 22:35:55 +00002114 VG_(copy_UInstr)(cb, u_in);
2115 break;
2116
2117 case MOV:
2118 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002119 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002120 stackref[u_in->val2] = stackref[u_in->val1];
2121 }
2122 VG_(copy_UInstr)(cb, u_in);
2123 break;
2124
2125 case LEA1:
2126 case ADD: case SUB:
2127 if (u_in->size == 4 && u_in->tag1 == TempReg) {
njnca82cc02004-11-22 17:18:48 +00002128 tl_assert(u_in->tag2 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002129 stackref[u_in->val2] |= stackref[u_in->val1];
2130 }
2131 VG_(copy_UInstr)(cb, u_in);
2132 break;
njn25e49d8e72002-09-23 09:36:25 +00002133
sewardja5b3aec2002-10-22 05:09:36 +00002134 case LOAD: {
2135 void (*help)(Addr);
njnca82cc02004-11-22 17:18:48 +00002136 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2137 tl_assert(u_in->tag1 == TempReg);
sewardjf6374322002-11-13 22:35:55 +00002138
2139 if (!clo_priv_stacks || !stackref[u_in->val1]) {
2140 nonstk_ld++;
2141
2142 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002143 case 1: help = hg_mem_help_read_1; break;
2144 case 2: help = hg_mem_help_read_2; break;
2145 case 4: help = hg_mem_help_read_4; break;
sewardjf6374322002-11-13 22:35:55 +00002146 default:
njn67993252004-11-22 18:02:32 +00002147 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002148 }
jsgfcb1d1c02003-10-14 21:55:10 +00002149
2150 /* XXX all registers should be flushed to baseblock
2151 here */
sewardjf6374322002-11-13 22:35:55 +00002152 uInstr1(cb, CCALL, 0, TempReg, u_in->val1);
2153 uCCall(cb, (Addr)help, 1, 1, False);
2154 } else
2155 stk_ld++;
njn25e49d8e72002-09-23 09:36:25 +00002156
sewardja5b3aec2002-10-22 05:09:36 +00002157 VG_(copy_UInstr)(cb, u_in);
2158 t_size = INVALID_TEMPREG;
2159 break;
2160 }
2161
fitzhardinge111c6072004-03-09 02:45:07 +00002162 case MMX2_MemRd:
sewardja5b3aec2002-10-22 05:09:36 +00002163 case FPU_R: {
njnca82cc02004-11-22 17:18:48 +00002164 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002165 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002166
fitzhardinge111c6072004-03-09 02:45:07 +00002167 t_size = newTemp(cb);
2168 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2169 uLiteral(cb, (UInt)u_in->size);
njn25e49d8e72002-09-23 09:36:25 +00002170
fitzhardinge111c6072004-03-09 02:45:07 +00002171 /* XXX all registers should be flushed to baseblock
2172 here */
2173 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002174 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002175
2176 VG_(copy_UInstr)(cb, u_in);
2177 t_size = INVALID_TEMPREG;
2178 break;
sewardja5b3aec2002-10-22 05:09:36 +00002179 }
2180
thughes96b466a2004-03-15 16:43:58 +00002181 case MMX2a1_MemRd: {
njnca82cc02004-11-22 17:18:48 +00002182 tl_assert(8 == u_in->size);
thughes96b466a2004-03-15 16:43:58 +00002183
2184 t_size = newTemp(cb);
2185 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2186 uLiteral(cb, (UInt)u_in->size);
2187
2188 /* XXX all registers should be flushed to baseblock
2189 here */
2190 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002191 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
thughes96b466a2004-03-15 16:43:58 +00002192
2193 VG_(copy_UInstr)(cb, u_in);
2194 t_size = INVALID_TEMPREG;
2195 break;
2196 }
2197
fitzhardinge111c6072004-03-09 02:45:07 +00002198 case SSE2a_MemRd:
2199 case SSE2a1_MemRd:
2200 case SSE3a_MemRd:
2201 case SSE3a1_MemRd:
2202 case SSE3ag_MemRd_RegWr: {
2203 Int addr = (u_in->opcode == SSE3ag_MemRd_RegWr) ? u_in->val1 : u_in->val3;
2204
njnca82cc02004-11-22 17:18:48 +00002205 tl_assert(u_in->size == 4 || u_in->size == 8 || u_in->size == 16 || u_in->size == 512);
fitzhardinge111c6072004-03-09 02:45:07 +00002206
2207 t_size = newTemp(cb);
2208 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2209 uLiteral(cb, (UInt)u_in->size);
2210
2211 uInstr2(cb, CCALL, 0, TempReg, addr, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002212 uCCall(cb, (Addr) & hg_mem_help_read_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002213
2214 VG_(copy_UInstr)(cb, u_in);
2215 t_size = INVALID_TEMPREG;
2216 break;
2217 }
2218
sewardja5b3aec2002-10-22 05:09:36 +00002219 case STORE: {
2220 void (*help)(Addr, UInt);
njnca82cc02004-11-22 17:18:48 +00002221 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size);
2222 tl_assert(u_in->tag2 == TempReg);
sewardja5b3aec2002-10-22 05:09:36 +00002223
sewardjf6374322002-11-13 22:35:55 +00002224 if (!clo_priv_stacks || !stackref[u_in->val2]) {
2225 nonstk_st++;
2226
2227 switch(u_in->size) {
njnfbdcba92005-05-09 01:23:49 +00002228 case 1: help = hg_mem_help_write_1; break;
2229 case 2: help = hg_mem_help_write_2; break;
2230 case 4: help = hg_mem_help_write_4; break;
sewardjf6374322002-11-13 22:35:55 +00002231 default:
njn67993252004-11-22 18:02:32 +00002232 VG_(tool_panic)("bad size");
sewardjf6374322002-11-13 22:35:55 +00002233 }
2234
jsgfcb1d1c02003-10-14 21:55:10 +00002235 /* XXX all registers should be flushed to baseblock
2236 here */
sewardjf6374322002-11-13 22:35:55 +00002237 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, u_in->val1);
2238 uCCall(cb, (Addr)help, 2, 2, False);
2239 } else
2240 stk_st++;
sewardja5b3aec2002-10-22 05:09:36 +00002241
2242 VG_(copy_UInstr)(cb, u_in);
2243 t_size = INVALID_TEMPREG;
2244 break;
2245 }
2246
fitzhardinge111c6072004-03-09 02:45:07 +00002247 case MMX2_MemWr:
sewardja5b3aec2002-10-22 05:09:36 +00002248 case FPU_W: {
njnca82cc02004-11-22 17:18:48 +00002249 tl_assert(1 == u_in->size || 2 == u_in->size || 4 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002250 8 == u_in->size || 10 == u_in->size || 108 == u_in->size);
sewardja5b3aec2002-10-22 05:09:36 +00002251
2252 t_size = newTemp(cb);
2253 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2254 uLiteral(cb, (UInt)u_in->size);
jsgfcb1d1c02003-10-14 21:55:10 +00002255 /* XXX all registers should be flushed to baseblock
2256 here */
sewardja5b3aec2002-10-22 05:09:36 +00002257 uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002258 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
sewardja5b3aec2002-10-22 05:09:36 +00002259
2260 VG_(copy_UInstr)(cb, u_in);
2261 t_size = INVALID_TEMPREG;
2262 break;
2263 }
njn25e49d8e72002-09-23 09:36:25 +00002264
fitzhardinge111c6072004-03-09 02:45:07 +00002265 case SSE2a_MemWr:
2266 case SSE3a_MemWr: {
njnca82cc02004-11-22 17:18:48 +00002267 tl_assert(4 == u_in->size || 8 == u_in->size || 16 == u_in->size ||
fitzhardinge111c6072004-03-09 02:45:07 +00002268 512 == u_in->size);
2269
2270 t_size = newTemp(cb);
2271 uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
2272 uLiteral(cb, (UInt)u_in->size);
2273 /* XXX all registers should be flushed to baseblock
2274 here */
2275 uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
njnfbdcba92005-05-09 01:23:49 +00002276 uCCall(cb, (Addr) & hg_mem_help_write_N, 2, 2, False);
fitzhardinge111c6072004-03-09 02:45:07 +00002277
2278 VG_(copy_UInstr)(cb, u_in);
2279 t_size = INVALID_TEMPREG;
2280 break;
2281 }
sewardj3d7c9c82003-03-26 21:08:13 +00002282
njn25e49d8e72002-09-23 09:36:25 +00002283 default:
sewardjf6374322002-11-13 22:35:55 +00002284 /* conservative tromping */
2285 if (0 && u_in->tag1 == TempReg) /* can val1 ever be dest? */
2286 stackref[u_in->val1] = False;
2287 if (u_in->tag2 == TempReg)
2288 stackref[u_in->val2] = False;
2289 if (u_in->tag3 == TempReg)
2290 stackref[u_in->val3] = False;
njn4ba5a792002-09-30 10:23:54 +00002291 VG_(copy_UInstr)(cb, u_in);
njn25e49d8e72002-09-23 09:36:25 +00002292 break;
2293 }
2294 }
2295
sewardjf6374322002-11-13 22:35:55 +00002296 VG_(free)(stackref);
njn4ba5a792002-09-30 10:23:54 +00002297 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +00002298 return cb;
2299}
njn14d01ce2004-11-26 11:30:14 +00002300#endif
sewardj4ba057c2005-10-18 12:04:18 +00002301static
sewardj0b9d74a2006-12-24 02:24:11 +00002302IRSB* hg_instrument ( VgCallbackClosure* closure,
2303 IRSB* bb,
sewardj461df9c2006-01-17 02:06:39 +00002304 VexGuestLayout* layout,
2305 VexGuestExtents* vge,
sewardj4ba057c2005-10-18 12:04:18 +00002306 IRType gWordTy, IRType hWordTy )
njn14d01ce2004-11-26 11:30:14 +00002307{
njn5db32122005-08-12 15:23:57 +00002308 tl_assert(0); // Need to convert to Vex
njn14d01ce2004-11-26 11:30:14 +00002309}
njn25e49d8e72002-09-23 09:36:25 +00002310
2311/*--------------------------------------------------------------------*/
2312/*--- Error and suppression handling ---*/
2313/*--------------------------------------------------------------------*/
2314
2315typedef
2316 enum {
2317 /* Possible data race */
njnfbdcba92005-05-09 01:23:49 +00002318 RaceSupp
njn25e49d8e72002-09-23 09:36:25 +00002319 }
njnfbdcba92005-05-09 01:23:49 +00002320 RaceSuppKind;
njn25e49d8e72002-09-23 09:36:25 +00002321
2322/* What kind of error it is. */
2323typedef
2324 enum {
njnfbdcba92005-05-09 01:23:49 +00002325 RaceErr, /* data-race */
sewardj16748af2002-10-22 04:55:54 +00002326 MutexErr, /* mutex operations */
sewardjff2c9232002-11-13 21:44:39 +00002327 LockGraphErr, /* mutex order error */
njn25e49d8e72002-09-23 09:36:25 +00002328 }
njnfbdcba92005-05-09 01:23:49 +00002329 RaceErrorKind;
njn25e49d8e72002-09-23 09:36:25 +00002330
sewardj16748af2002-10-22 04:55:54 +00002331/* The classification of a faulting address. */
2332typedef
2333 enum { Undescribed, /* as-yet unclassified */
2334 Stack,
2335 Unknown, /* classification yielded nothing useful */
sewardjdac0a442002-11-13 22:08:40 +00002336 Mallocd,
2337 Freed,
sewardj16748af2002-10-22 04:55:54 +00002338 Segment
2339 }
2340 AddrKind;
2341/* Records info about a faulting address. */
2342typedef
2343 struct {
2344 /* ALL */
2345 AddrKind akind;
2346 /* Freed, Mallocd */
2347 Int blksize;
2348 /* Freed, Mallocd */
2349 Int rwoffset;
2350 /* Freed, Mallocd */
2351 ExeContext* lastchange;
2352 ThreadId lasttid;
2353 /* Stack */
2354 ThreadId stack_tid;
2355 /* Segment */
2356 const Char* filename;
2357 const Char* section;
nethercoteca788ff2004-10-20 10:58:09 +00002358 /* True if is just-below the stack pointer -- could be a gcc bug. */
sewardj16748af2002-10-22 04:55:54 +00002359 Bool maybe_gcc;
jsgfcb1d1c02003-10-14 21:55:10 +00002360 /* symbolic address description */
2361 Char *expr;
sewardj16748af2002-10-22 04:55:54 +00002362 }
2363 AddrInfo;
njn25e49d8e72002-09-23 09:36:25 +00002364
sewardj16748af2002-10-22 04:55:54 +00002365/* What kind of memory access is involved in the error? */
2366typedef
2367 enum { ReadAxs, WriteAxs, ExecAxs }
2368 AxsKind;
2369
2370/* Extra context for memory errors */
2371typedef
2372 struct {
2373 AxsKind axskind;
2374 Int size;
2375 AddrInfo addrinfo;
2376 Bool isWrite;
2377 shadow_word prevstate;
sewardjff2c9232002-11-13 21:44:39 +00002378 /* MutexErr, LockGraphErr */
sewardj39a4d842002-11-13 22:14:30 +00002379 Mutex *mutex;
nethercoteca788ff2004-10-20 10:58:09 +00002380 EC_IP lasttouched;
sewardj16748af2002-10-22 04:55:54 +00002381 ThreadId lasttid;
sewardjff2c9232002-11-13 21:44:39 +00002382 /* LockGraphErr */
sewardj4bffb232002-11-13 21:46:34 +00002383 const LockSet *held_lockset;
2384 const LockSet *prev_lockset;
sewardj16748af2002-10-22 04:55:54 +00002385 }
2386 HelgrindError;
2387
2388static __inline__
2389void clear_AddrInfo ( AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002390{
sewardj16748af2002-10-22 04:55:54 +00002391 ai->akind = Unknown;
2392 ai->blksize = 0;
2393 ai->rwoffset = 0;
2394 ai->lastchange = NULL;
2395 ai->lasttid = VG_INVALID_THREADID;
2396 ai->filename = NULL;
2397 ai->section = "???";
2398 ai->stack_tid = VG_INVALID_THREADID;
2399 ai->maybe_gcc = False;
jsgfcb1d1c02003-10-14 21:55:10 +00002400 ai->expr = NULL;
njn25e49d8e72002-09-23 09:36:25 +00002401}
2402
sewardj16748af2002-10-22 04:55:54 +00002403static __inline__
2404void clear_HelgrindError ( HelgrindError* err_extra )
2405{
2406 err_extra->axskind = ReadAxs;
2407 err_extra->size = 0;
2408 err_extra->mutex = NULL;
nethercoteca788ff2004-10-20 10:58:09 +00002409 err_extra->lasttouched= NULL_EC_IP;
sewardj16748af2002-10-22 04:55:54 +00002410 err_extra->lasttid = VG_INVALID_THREADID;
sewardjff2c9232002-11-13 21:44:39 +00002411 err_extra->prev_lockset = 0;
2412 err_extra->held_lockset = 0;
sewardj8fac99a2002-11-13 22:31:26 +00002413 err_extra->prevstate = SW(Vge_Virgin, 0);
sewardj16748af2002-10-22 04:55:54 +00002414 clear_AddrInfo ( &err_extra->addrinfo );
2415 err_extra->isWrite = False;
2416}
2417
2418
2419
2420/* Describe an address as best you can, for error messages,
2421 putting the result in ai. */
2422
thughes4ad52d02004-06-27 17:37:21 +00002423/* Callback for searching malloc'd and free'd lists */
sewardj3f94a7d2007-08-25 07:19:08 +00002424/*
thughes4ad52d02004-06-27 17:37:21 +00002425static Bool addr_is_in_block(VgHashNode *node, void *ap)
2426{
2427 HG_Chunk* hc2 = (HG_Chunk*)node;
2428 Addr a = *(Addr *)ap;
2429
2430 return (hc2->data <= a && a < hc2->data + hc2->size);
2431}
sewardj3f94a7d2007-08-25 07:19:08 +00002432*/
thughes4ad52d02004-06-27 17:37:21 +00002433
sewardj16748af2002-10-22 04:55:54 +00002434static void describe_addr ( Addr a, AddrInfo* ai )
2435{
njn3e884182003-04-15 13:03:23 +00002436 HG_Chunk* hc;
sewardjdac0a442002-11-13 22:08:40 +00002437 Int i;
sewardj16748af2002-10-22 04:55:54 +00002438
sewardj16748af2002-10-22 04:55:54 +00002439 /* Search for it in segments */
2440 {
njn36ef6ba2005-05-14 18:42:26 +00002441 const SegInfo *si;
sewardj16748af2002-10-22 04:55:54 +00002442
njn36ef6ba2005-05-14 18:42:26 +00002443 for (si = VG_(next_seginfo)(NULL);
2444 si != NULL;
2445 si = VG_(next_seginfo)(si))
2446 {
njnd9e5fd72005-06-25 19:51:33 +00002447 Addr base = VG_(seginfo_start)(si);
2448 SizeT size = VG_(seginfo_size)(si);
2449 const UChar *filename = VG_(seginfo_filename)(si);
sewardj16748af2002-10-22 04:55:54 +00002450
2451 if (a >= base && a < base+size) {
2452 ai->akind = Segment;
2453 ai->blksize = size;
2454 ai->rwoffset = a - base;
2455 ai->filename = filename;
2456
njnd9e5fd72005-06-25 19:51:33 +00002457 switch(VG_(seginfo_sect_kind)(a)) {
sewardj16748af2002-10-22 04:55:54 +00002458 case Vg_SectText: ai->section = "text"; break;
2459 case Vg_SectData: ai->section = "data"; break;
2460 case Vg_SectBSS: ai->section = "BSS"; break;
2461 case Vg_SectGOT: ai->section = "GOT"; break;
2462 case Vg_SectPLT: ai->section = "PLT"; break;
2463 case Vg_SectUnknown:
2464 default:
2465 ai->section = "???"; break;
2466 }
2467
2468 return;
2469 }
2470 }
2471 }
2472
2473 /* Search for a currently malloc'd block which might bracket it. */
sewardj3f94a7d2007-08-25 07:19:08 +00002474 /* Commented out 25 Aug 07 as VG_(HT_first_match) no longer exists.
thughes4ad52d02004-06-27 17:37:21 +00002475 hc = (HG_Chunk*)VG_(HT_first_match)(hg_malloc_list, addr_is_in_block, &a);
sewardj3f94a7d2007-08-25 07:19:08 +00002476 */
njn3e884182003-04-15 13:03:23 +00002477 if (NULL != hc) {
sewardj16748af2002-10-22 04:55:54 +00002478 ai->akind = Mallocd;
njn3e884182003-04-15 13:03:23 +00002479 ai->blksize = hc->size;
2480 ai->rwoffset = (Int)a - (Int)(hc->data);
2481 ai->lastchange = hc->where;
2482 ai->lasttid = hc->tid;
sewardj16748af2002-10-22 04:55:54 +00002483 return;
2484 }
sewardjdac0a442002-11-13 22:08:40 +00002485
2486 /* Look in recently freed memory */
2487 for(i = 0; i < N_FREED_CHUNKS; i++) {
njn3e884182003-04-15 13:03:23 +00002488 hc = freechunks[i];
2489 if (hc == NULL)
sewardjdac0a442002-11-13 22:08:40 +00002490 continue;
2491
njn3e884182003-04-15 13:03:23 +00002492 if (a >= hc->data && a < hc->data + hc->size) {
sewardjdac0a442002-11-13 22:08:40 +00002493 ai->akind = Freed;
njn3e884182003-04-15 13:03:23 +00002494 ai->blksize = hc->size;
2495 ai->rwoffset = a - hc->data;
2496 ai->lastchange = hc->where;
2497 ai->lasttid = hc->tid;
sewardjdac0a442002-11-13 22:08:40 +00002498 return;
2499 }
2500 }
2501
sewardj16748af2002-10-22 04:55:54 +00002502 /* Clueless ... */
2503 ai->akind = Unknown;
2504 return;
2505}
2506
2507
njn7e614812003-04-21 22:04:03 +00002508/* Updates the copy with address info if necessary. */
njn51d827b2005-05-09 01:02:08 +00002509static UInt hg_update_extra(Error* err)
sewardj16748af2002-10-22 04:55:54 +00002510{
njn7e614812003-04-21 22:04:03 +00002511 HelgrindError* extra;
sewardj16748af2002-10-22 04:55:54 +00002512
njn7e614812003-04-21 22:04:03 +00002513 extra = (HelgrindError*)VG_(get_error_extra)(err);
2514 if (extra != NULL && Undescribed == extra->addrinfo.akind) {
2515 describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
2516 }
2517 return sizeof(HelgrindError);
sewardj16748af2002-10-22 04:55:54 +00002518}
2519
njnfbdcba92005-05-09 01:23:49 +00002520static void record_race_error ( ThreadId tid, Addr a, Bool is_write,
2521 shadow_word prevstate )
sewardj16748af2002-10-22 04:55:54 +00002522{
sewardjc4a810d2002-11-13 22:25:51 +00002523 shadow_word *sw;
sewardj16748af2002-10-22 04:55:54 +00002524 HelgrindError err_extra;
2525
njnfbdcba92005-05-09 01:23:49 +00002526 n_hg_warnings++;
sewardjff2c9232002-11-13 21:44:39 +00002527
sewardj16748af2002-10-22 04:55:54 +00002528 clear_HelgrindError(&err_extra);
2529 err_extra.isWrite = is_write;
2530 err_extra.addrinfo.akind = Undescribed;
2531 err_extra.prevstate = prevstate;
sewardj499e3de2002-11-13 22:22:25 +00002532 if (clo_execontext)
2533 err_extra.lasttouched = getExeContext(a);
sewardjeadcd862006-04-04 15:12:44 +00002534 /* JRS 4 Apr 06: VG_(describe_addr) disappeared from m_debuginfo,
2535 at least for the time being. */
2536 err_extra.addrinfo.expr = "???"; /* VG_(describe_addr)(tid, a); */
jsgfcb1d1c02003-10-14 21:55:10 +00002537
njnfbdcba92005-05-09 01:23:49 +00002538 VG_(maybe_record_error)( tid, RaceErr, a,
sewardj16748af2002-10-22 04:55:54 +00002539 (is_write ? "writing" : "reading"),
2540 &err_extra);
2541
sewardjc4a810d2002-11-13 22:25:51 +00002542 sw = get_sword_addr(a);
2543 if (sw->state == Vge_Excl && sw->other != TLSP_INDICATING_ALL) {
2544 ThreadLifeSeg *tls = unpackTLS(sw->other);
2545 tls->refcount--;
2546 }
2547
sewardj7f3ad222002-11-13 22:11:53 +00002548 set_sword(a, error_sword);
sewardj16748af2002-10-22 04:55:54 +00002549}
2550
sewardj39a4d842002-11-13 22:14:30 +00002551static void record_mutex_error(ThreadId tid, Mutex *mutex,
sewardj16748af2002-10-22 04:55:54 +00002552 Char *str, ExeContext *ec)
2553{
2554 HelgrindError err_extra;
2555
2556 clear_HelgrindError(&err_extra);
2557 err_extra.addrinfo.akind = Undescribed;
2558 err_extra.mutex = mutex;
sewardjc808ef52002-11-13 22:43:26 +00002559 err_extra.lasttouched = EC(ec, virgin_sword, thread_seg[tid]);
sewardj16748af2002-10-22 04:55:54 +00002560 err_extra.lasttid = tid;
2561
njn72718642003-07-24 08:45:32 +00002562 VG_(maybe_record_error)(tid, MutexErr,
sewardj16748af2002-10-22 04:55:54 +00002563 (Addr)mutex->mutexp, str, &err_extra);
2564}
njn25e49d8e72002-09-23 09:36:25 +00002565
sewardj39a4d842002-11-13 22:14:30 +00002566static void record_lockgraph_error(ThreadId tid, Mutex *mutex,
sewardj4bffb232002-11-13 21:46:34 +00002567 const LockSet *lockset_holding,
2568 const LockSet *lockset_prev)
sewardjff2c9232002-11-13 21:44:39 +00002569{
2570 HelgrindError err_extra;
2571
2572 n_lockorder_warnings++;
2573
2574 clear_HelgrindError(&err_extra);
2575 err_extra.addrinfo.akind = Undescribed;
2576 err_extra.mutex = mutex;
2577
sewardjc808ef52002-11-13 22:43:26 +00002578 err_extra.lasttouched = EC(mutex->location, virgin_sword, 0);
sewardjff2c9232002-11-13 21:44:39 +00002579 err_extra.held_lockset = lockset_holding;
2580 err_extra.prev_lockset = lockset_prev;
2581
njn72718642003-07-24 08:45:32 +00002582 VG_(maybe_record_error)(tid, LockGraphErr, mutex->mutexp, "", &err_extra);
sewardjff2c9232002-11-13 21:44:39 +00002583}
2584
njn51d827b2005-05-09 01:02:08 +00002585static Bool hg_eq_Error ( VgRes not_used, Error* e1, Error* e2 )
njn25e49d8e72002-09-23 09:36:25 +00002586{
njn810086f2002-11-14 12:42:47 +00002587 Char *e1s, *e2s;
sewardj16748af2002-10-22 04:55:54 +00002588
njnca82cc02004-11-22 17:18:48 +00002589 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
njn810086f2002-11-14 12:42:47 +00002590
2591 switch (VG_(get_error_kind)(e1)) {
njnfbdcba92005-05-09 01:23:49 +00002592 case RaceErr:
njn810086f2002-11-14 12:42:47 +00002593 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002594
2595 case MutexErr:
njn810086f2002-11-14 12:42:47 +00002596 return VG_(get_error_address)(e1) == VG_(get_error_address)(e2);
sewardj16748af2002-10-22 04:55:54 +00002597 }
2598
njn810086f2002-11-14 12:42:47 +00002599 e1s = VG_(get_error_string)(e1);
2600 e2s = VG_(get_error_string)(e2);
2601 if (e1s != e2s) return False;
2602 if (0 != VG_(strcmp)(e1s, e2s)) return False;
njn25e49d8e72002-09-23 09:36:25 +00002603 return True;
2604}
2605
sewardj16748af2002-10-22 04:55:54 +00002606static void pp_AddrInfo ( Addr a, AddrInfo* ai )
njn25e49d8e72002-09-23 09:36:25 +00002607{
jsgfcb1d1c02003-10-14 21:55:10 +00002608 if (ai->expr != NULL)
2609 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002610 " Address %p == %s", a, ai->expr);
jsgfcb1d1c02003-10-14 21:55:10 +00002611
sewardj16748af2002-10-22 04:55:54 +00002612 switch (ai->akind) {
2613 case Stack:
2614 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002615 " Address %p is on thread %d's stack",
sewardj16748af2002-10-22 04:55:54 +00002616 a, ai->stack_tid);
2617 break;
2618 case Unknown:
jsgfcb1d1c02003-10-14 21:55:10 +00002619 if (ai->expr != NULL)
2620 break;
2621
nethercote3b390c72003-11-13 17:53:43 +00002622 /* maybe_gcc is never set to True! This is a hangover from code
2623 in Memcheck */
sewardj16748af2002-10-22 04:55:54 +00002624 if (ai->maybe_gcc) {
2625 VG_(message)(Vg_UserMsg,
nethercoteca788ff2004-10-20 10:58:09 +00002626 " Address %p is just below the stack pointer. Possibly a bug in GCC/G++",
sewardj16748af2002-10-22 04:55:54 +00002627 a);
2628 VG_(message)(Vg_UserMsg,
2629 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
2630 } else {
2631 VG_(message)(Vg_UserMsg,
nethercotef798eee2004-04-13 08:36:35 +00002632 " Address %p is not stack'd, malloc'd or (recently) free'd", a);
sewardj16748af2002-10-22 04:55:54 +00002633 }
2634 break;
2635 case Segment:
2636 VG_(message)(Vg_UserMsg,
nethercote3b390c72003-11-13 17:53:43 +00002637 " Address %p is in %s section of %s",
sewardj16748af2002-10-22 04:55:54 +00002638 a, ai->section, ai->filename);
2639 break;
sewardjdac0a442002-11-13 22:08:40 +00002640 case Mallocd:
2641 case Freed: {
nethercote50397c22004-11-04 18:03:06 +00002642 SizeT delta;
sewardj16748af2002-10-22 04:55:54 +00002643 UChar* relative;
2644 if (ai->rwoffset < 0) {
nethercote50397c22004-11-04 18:03:06 +00002645 delta = (SizeT)(- ai->rwoffset);
sewardj16748af2002-10-22 04:55:54 +00002646 relative = "before";
2647 } else if (ai->rwoffset >= ai->blksize) {
2648 delta = ai->rwoffset - ai->blksize;
2649 relative = "after";
2650 } else {
2651 delta = ai->rwoffset;
2652 relative = "inside";
2653 }
2654 VG_(message)(Vg_UserMsg,
nethercote50397c22004-11-04 18:03:06 +00002655 " Address %p is %llu bytes %s a block of size %d %s by thread %d",
2656 a, (ULong)delta, relative,
sewardj16748af2002-10-22 04:55:54 +00002657 ai->blksize,
sewardjdac0a442002-11-13 22:08:40 +00002658 ai->akind == Mallocd ? "alloc'd" : "freed",
sewardj16748af2002-10-22 04:55:54 +00002659 ai->lasttid);
sewardj5481f8f2002-10-20 19:43:47 +00002660
sewardj16748af2002-10-22 04:55:54 +00002661 VG_(pp_ExeContext)(ai->lastchange);
2662 break;
2663 }
2664 default:
njn67993252004-11-22 18:02:32 +00002665 VG_(tool_panic)("pp_AddrInfo");
sewardj16748af2002-10-22 04:55:54 +00002666 }
njn25e49d8e72002-09-23 09:36:25 +00002667}
2668
sewardj4bffb232002-11-13 21:46:34 +00002669static Char *lockset_str(const Char *prefix, const LockSet *lockset)
sewardjff2c9232002-11-13 21:44:39 +00002670{
sewardjff2c9232002-11-13 21:44:39 +00002671 Char *buf, *cp;
sewardj4bffb232002-11-13 21:46:34 +00002672 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002673
sewardj4bffb232002-11-13 21:46:34 +00002674 buf = VG_(malloc)((prefix == NULL ? 0 : VG_(strlen)(prefix)) +
2675 lockset->setsize * 120 +
2676 1);
sewardjff2c9232002-11-13 21:44:39 +00002677
2678 cp = buf;
2679 if (prefix)
2680 cp += VG_(sprintf)(cp, "%s", prefix);
2681
sewardj4bffb232002-11-13 21:46:34 +00002682 for(i = 0; i < lockset->setsize; i++)
2683 cp += VG_(sprintf)(cp, "%p%(y, ", lockset->mutex[i]->mutexp,
2684 lockset->mutex[i]->mutexp);
sewardjff2c9232002-11-13 21:44:39 +00002685
sewardj4bffb232002-11-13 21:46:34 +00002686 if (lockset->setsize)
sewardjff2c9232002-11-13 21:44:39 +00002687 cp[-2] = '\0';
2688 else
2689 *cp = '\0';
2690
2691 return buf;
2692}
njn25e49d8e72002-09-23 09:36:25 +00002693
njn51d827b2005-05-09 01:02:08 +00002694static void hg_pp_Error ( Error* err )
njn25e49d8e72002-09-23 09:36:25 +00002695{
njn810086f2002-11-14 12:42:47 +00002696 HelgrindError *extra = (HelgrindError *)VG_(get_error_extra)(err);
sewardj16748af2002-10-22 04:55:54 +00002697 Char buf[100];
2698 Char *msg = buf;
sewardj4bffb232002-11-13 21:46:34 +00002699 const LockSet *ls;
sewardj16748af2002-10-22 04:55:54 +00002700
2701 *msg = '\0';
2702
njn810086f2002-11-14 12:42:47 +00002703 switch(VG_(get_error_kind)(err)) {
njnfbdcba92005-05-09 01:23:49 +00002704 case RaceErr: {
njn810086f2002-11-14 12:42:47 +00002705 Addr err_addr = VG_(get_error_address)(err);
2706
sewardj16748af2002-10-22 04:55:54 +00002707 VG_(message)(Vg_UserMsg, "Possible data race %s variable at %p %(y",
njn810086f2002-11-14 12:42:47 +00002708 VG_(get_error_string)(err), err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002709 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
njn810086f2002-11-14 12:42:47 +00002710 pp_AddrInfo(err_addr, &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002711
2712 switch(extra->prevstate.state) {
2713 case Vge_Virgin:
2714 /* shouldn't be possible to go directly from virgin -> error */
2715 VG_(sprintf)(buf, "virgin!?");
2716 break;
2717
sewardjc4a810d2002-11-13 22:25:51 +00002718 case Vge_Excl: {
2719 ThreadLifeSeg *tls = unpackTLS(extra->prevstate.other);
2720
njnca82cc02004-11-22 17:18:48 +00002721 tl_assert(tls != unpackTLS(TLSP_INDICATING_ALL));
sewardjc4a810d2002-11-13 22:25:51 +00002722 VG_(sprintf)(buf, "exclusively owned by thread %u", tls->tid);
sewardj16748af2002-10-22 04:55:54 +00002723 break;
sewardjc4a810d2002-11-13 22:25:51 +00002724 }
sewardj16748af2002-10-22 04:55:54 +00002725
2726 case Vge_Shar:
sewardjff2c9232002-11-13 21:44:39 +00002727 case Vge_SharMod:
sewardj8fac99a2002-11-13 22:31:26 +00002728 ls = unpackLockSet(extra->prevstate.other);
sewardj4bffb232002-11-13 21:46:34 +00002729
2730 if (isempty(ls)) {
sewardj16748af2002-10-22 04:55:54 +00002731 VG_(sprintf)(buf, "shared %s, no locks",
2732 extra->prevstate.state == Vge_Shar ? "RO" : "RW");
2733 break;
2734 }
2735
sewardjff2c9232002-11-13 21:44:39 +00002736 msg = lockset_str(extra->prevstate.state == Vge_Shar ?
2737 "shared RO, locked by:" :
sewardj4bffb232002-11-13 21:46:34 +00002738 "shared RW, locked by:", ls);
sewardj16748af2002-10-22 04:55:54 +00002739
sewardj16748af2002-10-22 04:55:54 +00002740 break;
2741 }
sewardj16748af2002-10-22 04:55:54 +00002742
sewardj499e3de2002-11-13 22:22:25 +00002743 if (*msg)
nethercote3b390c72003-11-13 17:53:43 +00002744 VG_(message)(Vg_UserMsg, " Previous state: %s", msg);
sewardj499e3de2002-11-13 22:22:25 +00002745
sewardj72baa7a2002-12-09 23:32:58 +00002746 if (clo_execontext == EC_Some
nethercoteca788ff2004-10-20 10:58:09 +00002747 && extra->lasttouched.uu_ec_ip.ip != 0) {
sewardj499e3de2002-11-13 22:22:25 +00002748 Char file[100];
2749 UInt line;
nethercoteca788ff2004-10-20 10:58:09 +00002750 Addr ip = extra->lasttouched.uu_ec_ip.ip;
sewardj499e3de2002-11-13 22:22:25 +00002751
nethercote3b390c72003-11-13 17:53:43 +00002752 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s by thread %u",
njn810086f2002-11-14 12:42:47 +00002753 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002754 pp_state(extra->lasttouched.state),
2755 unpackTLS(extra->lasttouched.tls)->tid);
sewardj499e3de2002-11-13 22:22:25 +00002756
sewardj7cee6f92005-06-13 17:39:06 +00002757 if (VG_(get_filename_linenum)(ip, file, sizeof(file),
2758 NULL, 0, NULL, &line)) {
sewardj499e3de2002-11-13 22:22:25 +00002759 VG_(message)(Vg_UserMsg, " at %p: %y (%s:%u)",
nethercoteca788ff2004-10-20 10:58:09 +00002760 ip, ip, file, line);
2761 } else if (VG_(get_objname)(ip, file, sizeof(file))) {
sewardj499e3de2002-11-13 22:22:25 +00002762 VG_(message)(Vg_UserMsg, " at %p: %y (in %s)",
nethercoteca788ff2004-10-20 10:58:09 +00002763 ip, ip, file);
sewardj499e3de2002-11-13 22:22:25 +00002764 } else {
nethercoteca788ff2004-10-20 10:58:09 +00002765 VG_(message)(Vg_UserMsg, " at %p: %y", ip, ip);
sewardj499e3de2002-11-13 22:22:25 +00002766 }
sewardj72baa7a2002-12-09 23:32:58 +00002767 } else if (clo_execontext == EC_All
nethercoteca788ff2004-10-20 10:58:09 +00002768 && extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002769 VG_(message)(Vg_UserMsg, " Word at %p last changed state from %s in tid %u",
njn810086f2002-11-14 12:42:47 +00002770 err_addr,
sewardjc808ef52002-11-13 22:43:26 +00002771 pp_state(extra->lasttouched.state),
2772 unpackTLS(extra->lasttouched.tls)->tid);
nethercoteca788ff2004-10-20 10:58:09 +00002773 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj499e3de2002-11-13 22:22:25 +00002774 }
sewardj16748af2002-10-22 04:55:54 +00002775 break;
njn810086f2002-11-14 12:42:47 +00002776 }
sewardj16748af2002-10-22 04:55:54 +00002777
2778 case MutexErr:
sewardj499e3de2002-11-13 22:22:25 +00002779 VG_(message)(Vg_UserMsg, "Mutex problem at %p%(y trying to %s",
njn810086f2002-11-14 12:42:47 +00002780 VG_(get_error_address)(err),
2781 VG_(get_error_address)(err),
2782 VG_(get_error_string)(err));
njn43c799e2003-04-08 00:08:52 +00002783 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
nethercoteca788ff2004-10-20 10:58:09 +00002784 if (extra->lasttouched.uu_ec_ip.ec != NULL) {
nethercote3b390c72003-11-13 17:53:43 +00002785 VG_(message)(Vg_UserMsg, " last touched by thread %d", extra->lasttid);
nethercoteca788ff2004-10-20 10:58:09 +00002786 VG_(pp_ExeContext)(extra->lasttouched.uu_ec_ip.ec);
sewardj16748af2002-10-22 04:55:54 +00002787 }
njn810086f2002-11-14 12:42:47 +00002788 pp_AddrInfo(VG_(get_error_address)(err), &extra->addrinfo);
sewardj16748af2002-10-22 04:55:54 +00002789 break;
sewardjff2c9232002-11-13 21:44:39 +00002790
2791 case LockGraphErr: {
sewardj4bffb232002-11-13 21:46:34 +00002792 const LockSet *heldset = extra->held_lockset;
njn810086f2002-11-14 12:42:47 +00002793 Addr err_addr = VG_(get_error_address)(err);
sewardj4bffb232002-11-13 21:46:34 +00002794 Int i;
sewardjff2c9232002-11-13 21:44:39 +00002795
2796 msg = lockset_str(NULL, heldset);
2797
2798 VG_(message)(Vg_UserMsg, "Mutex %p%(y locked in inconsistent order",
njn810086f2002-11-14 12:42:47 +00002799 err_addr, err_addr);
njn43c799e2003-04-08 00:08:52 +00002800 VG_(pp_ExeContext)( VG_(get_error_where)(err) );
sewardjff2c9232002-11-13 21:44:39 +00002801 VG_(message)(Vg_UserMsg, " while holding locks %s", msg);
2802
sewardj4bffb232002-11-13 21:46:34 +00002803 for(i = 0; i < heldset->setsize; i++) {
sewardj39a4d842002-11-13 22:14:30 +00002804 const Mutex *lsmx = heldset->mutex[i];
sewardjff2c9232002-11-13 21:44:39 +00002805
sewardj542494b2002-11-13 22:46:13 +00002806 /* needs to be a recursive search+display */
2807 if (0 && !ismember(lsmx->lockdep, extra->mutex))
sewardjff2c9232002-11-13 21:44:39 +00002808 continue;
2809
nethercote3b390c72003-11-13 17:53:43 +00002810 VG_(message)(Vg_UserMsg, " %p%(y last locked at",
sewardjff2c9232002-11-13 21:44:39 +00002811 lsmx->mutexp, lsmx->mutexp);
2812 VG_(pp_ExeContext)(lsmx->location);
2813 VG_(free)(msg);
sewardj4bffb232002-11-13 21:46:34 +00002814 msg = lockset_str(NULL, lsmx->lockdep);
nethercote3b390c72003-11-13 17:53:43 +00002815 VG_(message)(Vg_UserMsg, " while depending on locks %s", msg);
sewardjff2c9232002-11-13 21:44:39 +00002816 }
2817
2818 break;
sewardj16748af2002-10-22 04:55:54 +00002819 }
sewardjff2c9232002-11-13 21:44:39 +00002820 }
2821
2822 if (msg != buf)
2823 VG_(free)(msg);
njn25e49d8e72002-09-23 09:36:25 +00002824}
2825
2826
njn51d827b2005-05-09 01:02:08 +00002827static Bool hg_recognised_suppression ( Char* name, Supp *su )
njn25e49d8e72002-09-23 09:36:25 +00002828{
2829 if (0 == VG_(strcmp)(name, "Eraser")) {
njnfbdcba92005-05-09 01:23:49 +00002830 VG_(set_supp_kind)(su, RaceSupp);
njn25e49d8e72002-09-23 09:36:25 +00002831 return True;
2832 } else {
2833 return False;
2834 }
2835}
2836
2837
njn51d827b2005-05-09 01:02:08 +00002838static Bool hg_read_extra_suppression_info ( Int fd, Char* buf, Int nBuf, Supp* su )
njn25e49d8e72002-09-23 09:36:25 +00002839{
2840 /* do nothing -- no extra suppression info present. Return True to
2841 indicate nothing bad happened. */
2842 return True;
2843}
2844
2845
njn51d827b2005-05-09 01:02:08 +00002846static Bool hg_error_matches_suppression(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00002847{
njnfbdcba92005-05-09 01:23:49 +00002848 tl_assert(VG_(get_supp_kind)(su) == RaceSupp);
nethercote64366b42003-12-01 13:11:47 +00002849
njnfbdcba92005-05-09 01:23:49 +00002850 return (VG_(get_error_kind)(err) == RaceErr);
njn25e49d8e72002-09-23 09:36:25 +00002851}
2852
njn51d827b2005-05-09 01:02:08 +00002853static Char* hg_get_error_name ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002854{
njnfbdcba92005-05-09 01:23:49 +00002855 if (RaceErr == VG_(get_error_kind)(err)) {
2856 return "Eraser"; // old name, required for backwards compatibility
njn43c799e2003-04-08 00:08:52 +00002857 } else {
2858 return NULL; /* Other errors types can't be suppressed */
2859 }
2860}
2861
njn51d827b2005-05-09 01:02:08 +00002862static void hg_print_extra_suppression_info ( Error* err )
njn43c799e2003-04-08 00:08:52 +00002863{
2864 /* Do nothing */
2865}
njn25e49d8e72002-09-23 09:36:25 +00002866
dirkf8126e92006-11-14 14:32:46 +00002867static void hg_pre_mutex_lock(ThreadId tid, Addr client_mutex)
sewardjdca84112002-11-13 22:29:34 +00002868{
dirkf8126e92006-11-14 14:32:46 +00002869 Mutex *mutex = get_mutex(client_mutex);
sewardjdca84112002-11-13 22:29:34 +00002870
njn72718642003-07-24 08:45:32 +00002871 test_mutex_state(mutex, MxLocked, tid);
sewardjdca84112002-11-13 22:29:34 +00002872}
2873
dirkf8126e92006-11-14 14:32:46 +00002874static void hg_post_mutex_lock(ThreadId tid, Addr client_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002875{
sewardj4bffb232002-11-13 21:46:34 +00002876 static const Bool debug = False;
dirkf8126e92006-11-14 14:32:46 +00002877 Mutex *mutex = get_mutex(client_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002878 const LockSet* ls;
2879
njn72718642003-07-24 08:45:32 +00002880 set_mutex_state(mutex, MxLocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002881
njn25e49d8e72002-09-23 09:36:25 +00002882# if DEBUG_LOCKS
sewardjdac0a442002-11-13 22:08:40 +00002883 VG_(printf)("lock (%u, %p)\n", tid, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002884# endif
2885
njn25e49d8e72002-09-23 09:36:25 +00002886 /* VG_(printf)("LOCK: held %d, new %p\n", thread_locks[tid], mutex); */
2887# if LOCKSET_SANITY > 1
njnfbdcba92005-05-09 01:23:49 +00002888 sanity_check_locksets("hg_post_mutex_lock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002889# endif
2890
sewardj4bffb232002-11-13 21:46:34 +00002891 ls = lookup_LockSet_with(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002892
sewardj4bffb232002-11-13 21:46:34 +00002893 if (ls == NULL) {
2894 LockSet *newset = add_LockSet(thread_locks[tid], mutex);
2895 insert_LockSet(newset);
2896 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002897 }
sewardj4bffb232002-11-13 21:46:34 +00002898 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002899
sewardj4bffb232002-11-13 21:46:34 +00002900 if (debug || DEBUG_LOCKS)
2901 VG_(printf)("tid %u now has lockset %p\n", tid, ls);
njn25e49d8e72002-09-23 09:36:25 +00002902
sewardj4bffb232002-11-13 21:46:34 +00002903 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002904 sanity_check_locksets("hg_post_mutex_lock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002905}
2906
2907
dirkf8126e92006-11-14 14:32:46 +00002908static void hg_post_mutex_unlock(ThreadId tid, Addr client_mutex)
njn25e49d8e72002-09-23 09:36:25 +00002909{
sewardjc26cc252002-10-23 21:58:55 +00002910 static const Bool debug = False;
njn25e49d8e72002-09-23 09:36:25 +00002911 Int i = 0;
dirkf8126e92006-11-14 14:32:46 +00002912 Mutex *mutex = get_mutex(client_mutex);
sewardj4bffb232002-11-13 21:46:34 +00002913 const LockSet *ls;
2914
njn72718642003-07-24 08:45:32 +00002915 test_mutex_state(mutex, MxUnlocked, tid);
2916 set_mutex_state(mutex, MxUnlocked, tid);
sewardj16748af2002-10-22 04:55:54 +00002917
sewardjdac0a442002-11-13 22:08:40 +00002918 if (!ismember(thread_locks[tid], mutex))
2919 return;
2920
sewardjc26cc252002-10-23 21:58:55 +00002921 if (debug || DEBUG_LOCKS)
2922 VG_(printf)("unlock(%u, %p%(y)\n", tid, mutex->mutexp, mutex->mutexp);
njn25e49d8e72002-09-23 09:36:25 +00002923
sewardjc26cc252002-10-23 21:58:55 +00002924 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002925 sanity_check_locksets("hg_post_mutex_unlock-IN");
njn25e49d8e72002-09-23 09:36:25 +00002926
sewardj4bffb232002-11-13 21:46:34 +00002927 ls = lookup_LockSet_without(thread_locks[tid], mutex);
njn25e49d8e72002-09-23 09:36:25 +00002928
sewardj4bffb232002-11-13 21:46:34 +00002929 if (ls == NULL) {
2930 LockSet *newset = remove_LockSet(thread_locks[tid], mutex);
2931 insert_LockSet(newset);
2932 ls = newset;
njn25e49d8e72002-09-23 09:36:25 +00002933 }
2934
2935 /* Update the thread's lock vector */
sewardjc26cc252002-10-23 21:58:55 +00002936 if (debug || DEBUG_LOCKS)
sewardj4bffb232002-11-13 21:46:34 +00002937 VG_(printf)("tid %u reverts from %p to lockset %p\n",
sewardjc26cc252002-10-23 21:58:55 +00002938 tid, thread_locks[tid], i);
njn25e49d8e72002-09-23 09:36:25 +00002939
sewardj4bffb232002-11-13 21:46:34 +00002940 thread_locks[tid] = ls;
njn25e49d8e72002-09-23 09:36:25 +00002941
sewardjc26cc252002-10-23 21:58:55 +00002942 if (debug || LOCKSET_SANITY > 1)
njnfbdcba92005-05-09 01:23:49 +00002943 sanity_check_locksets("hg_post_mutex_unlock-OUT");
njn25e49d8e72002-09-23 09:36:25 +00002944}
2945
2946
2947/* ---------------------------------------------------------------------
2948 Checking memory reads and writes
2949 ------------------------------------------------------------------ */
2950
2951/* Behaviour on reads and writes:
2952 *
2953 * VIR EXCL SHAR SH_MOD
2954 * ----------------------------------------------------------------
2955 * rd/wr, 1st thread | - EXCL - -
2956 * rd, new thread | - SHAR - -
2957 * wr, new thread | - SH_MOD - -
2958 * rd | error! - SHAR SH_MOD
2959 * wr | EXCL - SH_MOD SH_MOD
2960 * ----------------------------------------------------------------
2961 */
2962
sewardj8fac99a2002-11-13 22:31:26 +00002963static inline
njn25e49d8e72002-09-23 09:36:25 +00002964void dump_around_a(Addr a)
2965{
2966 UInt i;
2967 shadow_word* sword;
2968 VG_(printf)("NEARBY:\n");
2969 for (i = a - 12; i <= a + 12; i += 4) {
2970 sword = get_sword_addr(i);
2971 VG_(printf)(" %x -- tid: %u, state: %u\n", i, sword->other, sword->state);
2972 }
2973}
njn25e49d8e72002-09-23 09:36:25 +00002974
2975#if DEBUG_ACCESSES
2976 #define DEBUG_STATE(args...) \
2977 VG_(printf)("(%u) ", size), \
2978 VG_(printf)(args)
2979#else
2980 #define DEBUG_STATE(args...)
2981#endif
2982
njnfbdcba92005-05-09 01:23:49 +00002983static void hg_mem_read_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00002984{
sewardj72baa7a2002-12-09 23:32:58 +00002985 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00002986 shadow_word prevstate;
2987 ThreadLifeSeg *tls;
2988 const LockSet *ls;
2989 Bool statechange = False;
2990
2991 static const void *const states[4] = {
2992 [Vge_Virgin] &&st_virgin,
2993 [Vge_Excl] &&st_excl,
2994 [Vge_Shar] &&st_shar,
2995 [Vge_SharMod] &&st_sharmod,
2996 };
2997
2998 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00002999 tl_assert(tls != NULL && tls->tid == tid);
sewardj18cd4a52002-11-13 22:37:41 +00003000
3001 sword = get_sword_addr(a);
3002 if (sword == SEC_MAP_ACCESS) {
njn8a7b41b2007-09-23 00:51:24 +00003003 VG_(printf)("read distinguished 2ndary map! 0x%lx\n", a);
sewardj18cd4a52002-11-13 22:37:41 +00003004 return;
3005 }
3006
3007 prevstate = *sword;
3008
3009 goto *states[sword->state];
3010
3011 /* This looks like reading of unitialised memory, may be legit. Eg.
3012 * calloc() zeroes its values, so untouched memory may actually be
3013 * initialised. Leave that stuff to Valgrind. */
3014 st_virgin:
3015 if (TID_INDICATING_NONVIRGIN == sword->other) {
3016 DEBUG_STATE("Read VIRGIN --> EXCL: %8x, %u\n", a, tid);
3017 if (DEBUG_VIRGIN_READS)
3018 dump_around_a(a);
3019 } else {
3020 DEBUG_STATE("Read SPECIAL --> EXCL: %8x, %u\n", a, tid);
3021 }
3022 statechange = True;
3023 *sword = SW(Vge_Excl, packTLS(tls)); /* remember exclusive owner */
3024 tls->refcount++;
3025 goto done;
3026
3027 st_excl: {
3028 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3029
3030 if (tls == sw_tls) {
3031 DEBUG_STATE("Read EXCL: %8x, %u\n", a, tid);
3032 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3033 DEBUG_STATE("Read EXCL/ERR: %8x, %u\n", a, tid);
3034 } else if (tlsIsDisjoint(tls, sw_tls)) {
3035 DEBUG_STATE("Read EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3036 statechange = True;
3037 sword->other = packTLS(tls);
3038 sw_tls->refcount--;
3039 tls->refcount++;
3040 } else {
3041 DEBUG_STATE("Read EXCL(%u) --> SHAR: %8x, %u\n", sw_tls->tid, a, tid);
3042 sw_tls->refcount--;
3043 statechange = True;
3044 *sword = SW(Vge_Shar, packLockSet(thread_locks[tid]));
3045
3046 if (DEBUG_MEM_LOCKSET_CHANGES)
3047 print_LockSet("excl read locks", unpackLockSet(sword->other));
3048 }
3049 goto done;
3050 }
3051
3052 st_shar:
3053 DEBUG_STATE("Read SHAR: %8x, %u\n", a, tid);
3054 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3055 thread_locks[tid]));
3056 statechange = sword->other != prevstate.other;
3057 goto done;
3058
3059 st_sharmod:
3060 DEBUG_STATE("Read SHAR_MOD: %8x, %u\n", a, tid);
3061 ls = intersect(unpackLockSet(sword->other),
3062 thread_locks[tid]);
3063 sword->other = packLockSet(ls);
3064
3065 statechange = sword->other != prevstate.other;
3066
3067 if (isempty(ls)) {
njnfbdcba92005-05-09 01:23:49 +00003068 record_race_error(tid, a, False /* !is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003069 }
3070 goto done;
3071
3072 done:
3073 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003074 EC_IP ecip;
sewardj18cd4a52002-11-13 22:37:41 +00003075
3076 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003077 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003078 else
njnd01fef72005-03-25 23:35:48 +00003079 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003080 setExeContext(a, ecip);
sewardj18cd4a52002-11-13 22:37:41 +00003081 }
3082}
njn25e49d8e72002-09-23 09:36:25 +00003083
njnfbdcba92005-05-09 01:23:49 +00003084static void hg_mem_read(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003085{
njn72718642003-07-24 08:45:32 +00003086 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003087
njn13bfd852005-06-02 03:52:53 +00003088 end = VG_ROUNDUP(a+size, 4);
3089 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003090
sewardj18cd4a52002-11-13 22:37:41 +00003091 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003092 hg_mem_read_word(a, tid);
sewardj18cd4a52002-11-13 22:37:41 +00003093}
3094
njnfbdcba92005-05-09 01:23:49 +00003095static void hg_mem_write_word(Addr a, ThreadId tid)
sewardj18cd4a52002-11-13 22:37:41 +00003096{
3097 ThreadLifeSeg *tls;
sewardj72baa7a2002-12-09 23:32:58 +00003098 shadow_word* sword /* egcs-2.91.66 complains uninit */ = NULL;
sewardj18cd4a52002-11-13 22:37:41 +00003099 shadow_word prevstate;
3100 Bool statechange = False;
3101 static const void *const states[4] = {
3102 [Vge_Virgin] &&st_virgin,
3103 [Vge_Excl] &&st_excl,
3104 [Vge_Shar] &&st_shar,
3105 [Vge_SharMod] &&st_sharmod,
3106 };
3107
sewardjc4a810d2002-11-13 22:25:51 +00003108 tls = thread_seg[tid];
njnca82cc02004-11-22 17:18:48 +00003109 tl_assert(tls != NULL && tls->tid == tid);
sewardjc4a810d2002-11-13 22:25:51 +00003110
sewardj18cd4a52002-11-13 22:37:41 +00003111 sword = get_sword_addr(a);
3112 if (sword == SEC_MAP_ACCESS) {
njn8a7b41b2007-09-23 00:51:24 +00003113 VG_(printf)("read distinguished 2ndary map! 0x%lx\n", a);
sewardj18cd4a52002-11-13 22:37:41 +00003114 return;
3115 }
njn25e49d8e72002-09-23 09:36:25 +00003116
sewardj18cd4a52002-11-13 22:37:41 +00003117 prevstate = *sword;
njn25e49d8e72002-09-23 09:36:25 +00003118
sewardj18cd4a52002-11-13 22:37:41 +00003119 goto *states[sword->state];
sewardj16748af2002-10-22 04:55:54 +00003120
sewardj18cd4a52002-11-13 22:37:41 +00003121 st_virgin:
3122 if (TID_INDICATING_NONVIRGIN == sword->other)
3123 DEBUG_STATE("Write VIRGIN --> EXCL: %8x, %u\n", a, tid);
3124 else
3125 DEBUG_STATE("Write SPECIAL --> EXCL: %8x, %u\n", a, tid);
3126 statechange = True;
3127 *sword = SW(Vge_Excl, packTLS(tls));/* remember exclusive owner */
3128 tls->refcount++;
3129 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003130
sewardj18cd4a52002-11-13 22:37:41 +00003131 st_excl: {
3132 ThreadLifeSeg *sw_tls = unpackTLS(sword->other);
3133
3134 if (tls == sw_tls) {
3135 DEBUG_STATE("Write EXCL: %8x, %u\n", a, tid);
3136 goto done;
3137 } else if (unpackTLS(TLSP_INDICATING_ALL) == sw_tls) {
3138 DEBUG_STATE("Write EXCL/ERR: %8x, %u\n", a, tid);
3139 goto done;
3140 } else if (tlsIsDisjoint(tls, sw_tls)) {
3141 DEBUG_STATE("Write EXCL(%u) --> EXCL: %8x, %u\n", sw_tls->tid, a, tid);
3142 sword->other = packTLS(tls);
3143 sw_tls->refcount--;
sewardjc4a810d2002-11-13 22:25:51 +00003144 tls->refcount++;
sewardj8fac99a2002-11-13 22:31:26 +00003145 goto done;
sewardj18cd4a52002-11-13 22:37:41 +00003146 } else {
3147 DEBUG_STATE("Write EXCL(%u) --> SHAR_MOD: %8x, %u\n", sw_tls->tid, a, tid);
3148 statechange = True;
3149 sw_tls->refcount--;
3150 *sword = SW(Vge_SharMod, packLockSet(thread_locks[tid]));
3151 if(DEBUG_MEM_LOCKSET_CHANGES)
3152 print_LockSet("excl write locks", unpackLockSet(sword->other));
3153 goto SHARED_MODIFIED;
sewardjc4a810d2002-11-13 22:25:51 +00003154 }
sewardj18cd4a52002-11-13 22:37:41 +00003155 }
njn25e49d8e72002-09-23 09:36:25 +00003156
sewardj18cd4a52002-11-13 22:37:41 +00003157 st_shar:
3158 DEBUG_STATE("Write SHAR --> SHAR_MOD: %8x, %u\n", a, tid);
3159 sword->state = Vge_SharMod;
3160 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3161 thread_locks[tid]));
3162 statechange = True;
3163 goto SHARED_MODIFIED;
njn25e49d8e72002-09-23 09:36:25 +00003164
sewardj18cd4a52002-11-13 22:37:41 +00003165 st_sharmod:
3166 DEBUG_STATE("Write SHAR_MOD: %8x, %u\n", a, tid);
3167 sword->other = packLockSet(intersect(unpackLockSet(sword->other),
3168 thread_locks[tid]));
3169 statechange = sword->other != prevstate.other;
njn25e49d8e72002-09-23 09:36:25 +00003170
sewardj18cd4a52002-11-13 22:37:41 +00003171 SHARED_MODIFIED:
3172 if (isempty(unpackLockSet(sword->other))) {
njnfbdcba92005-05-09 01:23:49 +00003173 record_race_error(tid, a, True /* is_write */, prevstate);
sewardj18cd4a52002-11-13 22:37:41 +00003174 }
3175 goto done;
njn25e49d8e72002-09-23 09:36:25 +00003176
sewardj18cd4a52002-11-13 22:37:41 +00003177 done:
3178 if (clo_execontext != EC_None && statechange) {
nethercoteca788ff2004-10-20 10:58:09 +00003179 EC_IP ecip;
sewardj499e3de2002-11-13 22:22:25 +00003180
sewardj18cd4a52002-11-13 22:37:41 +00003181 if (clo_execontext == EC_Some)
njn67516132005-03-22 04:02:43 +00003182 ecip = IP(VG_(get_IP)(tid), prevstate, tls);
sewardj18cd4a52002-11-13 22:37:41 +00003183 else
njnd01fef72005-03-25 23:35:48 +00003184 ecip = EC(VG_(record_ExeContext)(tid), prevstate, tls);
nethercoteca788ff2004-10-20 10:58:09 +00003185 setExeContext(a, ecip);
njn25e49d8e72002-09-23 09:36:25 +00003186 }
3187}
3188
njnfbdcba92005-05-09 01:23:49 +00003189static void hg_mem_write(Addr a, SizeT size, ThreadId tid)
njn25e49d8e72002-09-23 09:36:25 +00003190{
sewardj8fac99a2002-11-13 22:31:26 +00003191 Addr end;
njn25e49d8e72002-09-23 09:36:25 +00003192
njn13bfd852005-06-02 03:52:53 +00003193 end = VG_ROUNDUP(a+size, 4);
3194 a = VG_ROUNDDN(a, 4);
sewardj8fac99a2002-11-13 22:31:26 +00003195
sewardj18cd4a52002-11-13 22:37:41 +00003196 for ( ; a < end; a += 4)
njnfbdcba92005-05-09 01:23:49 +00003197 hg_mem_write_word(a, tid);
njn25e49d8e72002-09-23 09:36:25 +00003198}
3199
3200#undef DEBUG_STATE
3201
njnaf839f52005-06-23 03:27:57 +00003202VG_REGPARM(1) static void hg_mem_help_read_1(Addr a)
sewardj7ab2aca2002-10-20 19:40:32 +00003203{
njnfbdcba92005-05-09 01:23:49 +00003204 hg_mem_read(a, 1, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003205}
3206
njnaf839f52005-06-23 03:27:57 +00003207VG_REGPARM(1) static void hg_mem_help_read_2(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003208{
njnfbdcba92005-05-09 01:23:49 +00003209 hg_mem_read(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003210}
3211
njnaf839f52005-06-23 03:27:57 +00003212VG_REGPARM(1) static void hg_mem_help_read_4(Addr a)
sewardja5b3aec2002-10-22 05:09:36 +00003213{
njnfbdcba92005-05-09 01:23:49 +00003214 hg_mem_read(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003215}
3216
njnaf839f52005-06-23 03:27:57 +00003217VG_REGPARM(2) static void hg_mem_help_read_N(Addr a, SizeT size)
sewardja5b3aec2002-10-22 05:09:36 +00003218{
njnfbdcba92005-05-09 01:23:49 +00003219 hg_mem_read(a, size, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003220}
3221
njnaf839f52005-06-23 03:27:57 +00003222VG_REGPARM(2) static void hg_mem_help_write_1(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003223{
3224 if (*(UChar *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003225 hg_mem_write(a, 1, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003226}
njnaf839f52005-06-23 03:27:57 +00003227VG_REGPARM(2) static void hg_mem_help_write_2(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003228{
3229 if (*(UShort *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003230 hg_mem_write(a, 2, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003231}
njnaf839f52005-06-23 03:27:57 +00003232VG_REGPARM(2) static void hg_mem_help_write_4(Addr a, UInt val)
sewardja5b3aec2002-10-22 05:09:36 +00003233{
3234 if (*(UInt *)a != val)
njnfbdcba92005-05-09 01:23:49 +00003235 hg_mem_write(a, 4, VG_(get_running_tid)());
sewardja5b3aec2002-10-22 05:09:36 +00003236}
njnaf839f52005-06-23 03:27:57 +00003237VG_REGPARM(2) static void hg_mem_help_write_N(Addr a, SizeT size)
sewardj7ab2aca2002-10-20 19:40:32 +00003238{
njnfbdcba92005-05-09 01:23:49 +00003239 hg_mem_write(a, size, VG_(get_running_tid)());
sewardj7ab2aca2002-10-20 19:40:32 +00003240}
njn25e49d8e72002-09-23 09:36:25 +00003241
sewardjc4a810d2002-11-13 22:25:51 +00003242static void hg_thread_create(ThreadId parent, ThreadId child)
3243{
3244 if (0)
3245 VG_(printf)("CREATE: %u creating %u\n", parent, child);
3246
3247 newTLS(child);
3248 addPriorTLS(child, parent);
3249
3250 newTLS(parent);
3251}
3252
3253static void hg_thread_join(ThreadId joiner, ThreadId joinee)
3254{
3255 if (0)
3256 VG_(printf)("JOIN: %u joining on %u\n", joiner, joinee);
3257
3258 newTLS(joiner);
3259 addPriorTLS(joiner, joinee);
3260
3261 clearTLS(joinee);
3262}
3263
sewardj7a5ebcf2002-11-13 22:42:13 +00003264static Int __BUS_HARDWARE_LOCK__;
3265
3266static void bus_lock(void)
3267{
njn95e65f62005-03-30 04:13:56 +00003268 ThreadId tid = VG_(get_running_tid)();
dirkf8126e92006-11-14 14:32:46 +00003269 hg_pre_mutex_lock(tid, (Addr)&__BUS_HARDWARE_LOCK__);
3270 hg_post_mutex_lock(tid, (Addr)&__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003271}
3272
3273static void bus_unlock(void)
3274{
njn95e65f62005-03-30 04:13:56 +00003275 ThreadId tid = VG_(get_running_tid)();
dirkf8126e92006-11-14 14:32:46 +00003276 hg_post_mutex_unlock(tid, (Addr)&__BUS_HARDWARE_LOCK__);
sewardj7a5ebcf2002-11-13 22:42:13 +00003277}
3278
njn25e49d8e72002-09-23 09:36:25 +00003279/*--------------------------------------------------------------------*/
sewardj7f3ad222002-11-13 22:11:53 +00003280/*--- Client requests ---*/
3281/*--------------------------------------------------------------------*/
3282
njn51d827b2005-05-09 01:02:08 +00003283static Bool hg_handle_client_request(ThreadId tid, UWord *args, UWord *ret)
sewardj7f3ad222002-11-13 22:11:53 +00003284{
njnfc26ff92004-11-22 19:12:49 +00003285 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
sewardj7f3ad222002-11-13 22:11:53 +00003286 return False;
3287
3288 switch(args[0]) {
3289 case VG_USERREQ__HG_CLEAN_MEMORY:
3290 set_address_range_state(args[1], args[2], Vge_VirginInit);
3291 *ret = 0; /* meaningless */
3292 break;
3293
3294 case VG_USERREQ__HG_KNOWN_RACE:
3295 set_address_range_state(args[1], args[2], Vge_Error);
3296 *ret = 0; /* meaningless */
3297 break;
3298
3299 default:
3300 return False;
3301 }
3302
3303 return True;
3304}
3305
3306
3307/*--------------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00003308/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00003309/*--------------------------------------------------------------------*/
3310
njn51d827b2005-05-09 01:02:08 +00003311static Bool hg_process_cmd_line_option(Char* arg)
3312{
3313 if (VG_CLO_STREQ(arg, "--show-last-access=no"))
3314 clo_execontext = EC_None;
3315 else if (VG_CLO_STREQ(arg, "--show-last-access=some"))
3316 clo_execontext = EC_Some;
3317 else if (VG_CLO_STREQ(arg, "--show-last-access=all"))
3318 clo_execontext = EC_All;
3319
3320 else VG_BOOL_CLO(arg, "--private-stacks", clo_priv_stacks)
3321
3322 else
3323 return VG_(replacement_malloc_process_cmd_line_option)(arg);
3324
3325 return True;
3326}
3327
3328static void hg_print_usage(void)
3329{
3330 VG_(printf)(
3331" --private-stacks=yes|no assume thread stacks are used privately [no]\n"
3332" --show-last-access=no|some|all\n"
3333" show location of last word access on error [no]\n"
3334 );
3335 VG_(replacement_malloc_print_usage)();
3336}
3337
3338static void hg_print_debug_usage(void)
3339{
3340 VG_(replacement_malloc_print_debug_usage)();
3341}
3342
3343static void hg_post_clo_init(void)
3344{
3345 void (*stack_tracker)(Addr a, SizeT len);
3346
3347 if (clo_execontext) {
3348 execontext_map = VG_(malloc)(sizeof(ExeContextMap *) * 65536);
3349 VG_(memset)(execontext_map, 0, sizeof(ExeContextMap *) * 65536);
3350 }
3351
3352 if (clo_priv_stacks)
njnfbdcba92005-05-09 01:23:49 +00003353 stack_tracker = & hg_new_mem_stack_private;
njn51d827b2005-05-09 01:02:08 +00003354 else
njnfbdcba92005-05-09 01:23:49 +00003355 stack_tracker = & hg_new_mem_stack;
njn51d827b2005-05-09 01:02:08 +00003356
3357 VG_(track_new_mem_stack) (stack_tracker);
3358 VG_(track_new_mem_stack_signal) (stack_tracker);
3359}
3360
3361
3362static void hg_fini(Int exitcode)
3363{
3364 if (DEBUG_LOCK_TABLE) {
3365 pp_all_LockSets();
3366 pp_all_mutexes();
3367 }
3368
3369 if (LOCKSET_SANITY)
3370 sanity_check_locksets("hg_fini");
3371
3372 if (VG_(clo_verbosity) > 0)
3373 VG_(message)(Vg_UserMsg, "%u possible data races found; %u lock order problems",
njnfbdcba92005-05-09 01:23:49 +00003374 n_hg_warnings, n_lockorder_warnings);
njn51d827b2005-05-09 01:02:08 +00003375
3376 if (0)
3377 VG_(printf)("stk_ld:%u+stk_st:%u = %u nonstk_ld:%u+nonstk_st:%u = %u %u%%\n",
3378 stk_ld, stk_st, stk_ld + stk_st,
3379 nonstk_ld, nonstk_st, nonstk_ld + nonstk_st,
3380 ((stk_ld+stk_st)*100) / (stk_ld + stk_st + nonstk_ld + nonstk_st));
3381}
3382
3383static void hg_pre_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +00003384{
3385 Int i;
sewardj4bffb232002-11-13 21:46:34 +00003386 LockSet *empty;
njn25e49d8e72002-09-23 09:36:25 +00003387
njn810086f2002-11-14 12:42:47 +00003388 VG_(details_name) ("Helgrind");
3389 VG_(details_version) (NULL);
3390 VG_(details_description) ("a data race detector");
3391 VG_(details_copyright_author)(
sewardj9ebd6e02007-01-08 06:01:59 +00003392 "Copyright (C) 2002-2007, and GNU GPL'd, by Nicholas Nethercote et al.");
nethercote421281e2003-11-20 16:20:55 +00003393 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj40823562006-10-17 02:21:17 +00003394 VG_(details_avg_translation_sizeB) ( 300 );
njn25e49d8e72002-09-23 09:36:25 +00003395
njn51d827b2005-05-09 01:02:08 +00003396 VG_(basic_tool_funcs) (hg_post_clo_init,
3397 hg_instrument,
3398 hg_fini);
tomc756a8e2005-03-31 07:59:35 +00003399
njn5db32122005-08-12 15:23:57 +00003400 VG_(printf)(
3401"\n"
3402"Helgrind is currently not working, because:\n"
3403" (a) it is not yet ready to handle the Vex IR and the use with 64-bit\n"
3404" platforms introduced in Valgrind 3.0.0\n"
3405" (b) we need to get thread operation tracking working again after\n"
3406" the changes added in Valgrind 2.4.0\n"
njn5e0e9222006-04-12 22:53:23 +00003407" If you want to use Helgrind, you'll have to use Valgrind 2.2.0, which is\n"
3408" the most recent Valgrind release that contains a working Helgrind.\n"
njn5db32122005-08-12 15:23:57 +00003409"\n"
3410"Sorry for the inconvenience. Let us know if this is a problem for you.\n");
3411 VG_(exit)(1);
3412
tomc756a8e2005-03-31 07:59:35 +00003413 VG_(needs_core_errors) ();
njn51d827b2005-05-09 01:02:08 +00003414 VG_(needs_tool_errors) (hg_eq_Error,
3415 hg_pp_Error,
3416 hg_update_extra,
3417 hg_recognised_suppression,
3418 hg_read_extra_suppression_info,
3419 hg_error_matches_suppression,
3420 hg_get_error_name,
3421 hg_print_extra_suppression_info);
tomc756a8e2005-03-31 07:59:35 +00003422 VG_(needs_data_syms) ();
njn51d827b2005-05-09 01:02:08 +00003423 VG_(needs_client_requests) (hg_handle_client_request);
3424 VG_(needs_sanity_checks) (hg_cheap_sanity_check,
3425 hg_expensive_sanity_check);
3426 VG_(needs_command_line_options)(hg_process_cmd_line_option,
3427 hg_print_usage,
3428 hg_print_debug_usage);
tomc756a8e2005-03-31 07:59:35 +00003429
njnfc51f8d2005-06-21 03:20:17 +00003430 VG_(needs_malloc_replacement) (hg_malloc,
njn51d827b2005-05-09 01:02:08 +00003431 hg___builtin_new,
3432 hg___builtin_vec_new,
3433 hg_memalign,
3434 hg_calloc,
3435 hg_free,
3436 hg___builtin_delete,
3437 hg___builtin_vec_delete,
3438 hg_realloc,
tomc756a8e2005-03-31 07:59:35 +00003439 8 );
njn25e49d8e72002-09-23 09:36:25 +00003440
njnfbdcba92005-05-09 01:23:49 +00003441 VG_(track_new_mem_startup) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003442
njn51d827b2005-05-09 01:02:08 +00003443 /* stack ones not decided until hg_post_clo_init() */
njn25e49d8e72002-09-23 09:36:25 +00003444
njn51d827b2005-05-09 01:02:08 +00003445 VG_(track_new_mem_brk) (& make_writable);
njnfbdcba92005-05-09 01:23:49 +00003446 VG_(track_new_mem_mmap) (& hg_new_mem_startup);
njn25e49d8e72002-09-23 09:36:25 +00003447
njnfbdcba92005-05-09 01:23:49 +00003448 VG_(track_change_mem_mprotect) (& hg_set_perms);
njn25e49d8e72002-09-23 09:36:25 +00003449
njn51d827b2005-05-09 01:02:08 +00003450 VG_(track_ban_mem_stack) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003451
njn51d827b2005-05-09 01:02:08 +00003452 VG_(track_die_mem_stack) (NULL);
3453 VG_(track_die_mem_stack_signal)(NULL);
3454 VG_(track_die_mem_brk) (NULL);
3455 VG_(track_die_mem_munmap) (NULL);
njn25e49d8e72002-09-23 09:36:25 +00003456
njnfbdcba92005-05-09 01:23:49 +00003457 VG_(track_pre_mem_read) (& hg_pre_mem_read);
3458 VG_(track_pre_mem_read_asciiz) (& hg_pre_mem_read_asciiz);
3459 VG_(track_pre_mem_write) (& hg_pre_mem_write);
njn51d827b2005-05-09 01:02:08 +00003460 VG_(track_post_mem_write) (NULL);
njn810086f2002-11-14 12:42:47 +00003461
njn51d827b2005-05-09 01:02:08 +00003462 VG_(track_post_thread_create) (& hg_thread_create);
3463 VG_(track_post_thread_join) (& hg_thread_join);
njn810086f2002-11-14 12:42:47 +00003464
sewardjb5c75752006-12-28 20:26:08 +00003465 /* The core doesn't provide these events any more */
3466 /*
njnfbdcba92005-05-09 01:23:49 +00003467 VG_(track_pre_mutex_lock) (& hg_pre_mutex_lock);
3468 VG_(track_post_mutex_lock) (& hg_post_mutex_lock);
3469 VG_(track_post_mutex_unlock) (& hg_post_mutex_unlock);
sewardjb5c75752006-12-28 20:26:08 +00003470 */
sewardjc4a810d2002-11-13 22:25:51 +00003471
njn14d01ce2004-11-26 11:30:14 +00003472 for (i = 0; i < LOCKSET_HASH_SZ; i++)
sewardj4bffb232002-11-13 21:46:34 +00003473 lockset_hash[i] = NULL;
3474
3475 empty = alloc_LockSet(0);
3476 insert_LockSet(empty);
3477 emptyset = empty;
3478
sewardjc4a810d2002-11-13 22:25:51 +00003479 /* Init lock table and thread segments */
3480 for (i = 0; i < VG_N_THREADS; i++) {
sewardjdac0a442002-11-13 22:08:40 +00003481 thread_locks[i] = empty;
njn25e49d8e72002-09-23 09:36:25 +00003482
sewardjc4a810d2002-11-13 22:25:51 +00003483 newTLS(i);
3484 }
3485
njn25e49d8e72002-09-23 09:36:25 +00003486 init_shadow_memory();
sewardj3f94a7d2007-08-25 07:19:08 +00003487 hg_malloc_list = VG_(HT_construct)( "Helgrind's malloc list" );
njn25e49d8e72002-09-23 09:36:25 +00003488}
3489
sewardj45f4e7c2005-09-27 19:20:21 +00003490VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00003491
njn25e49d8e72002-09-23 09:36:25 +00003492/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00003493/*--- end hg_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00003494/*--------------------------------------------------------------------*/